Реализация / создание абстрактного класса через отражение в Scala - PullRequest
2 голосов
/ 01 февраля 2010

Я работаю над фреймворком для проекта EA (evolution alg) в Scala. В этом у меня есть черта, которая реализует общий EA-код и оставляет специфичный для проблемы код, такой как преобразование генотипа и фитнес-тестирование, классам, которые реализуют эту черту. Однако я не хочу полностью реализовывать эту черту до того, как она будет фактически запущена из-за тестирования различных протоколов / стратегий отбора населения. Это дает код

trait EAProblem{
// common code ...
   def fitness(ind:Individual):Double
   def selectionStrategy(p: Population): List[(Individual, Double)]
   def nextGeneration(p: Population): Population
}

/* Silly test problem */
abstract class OneMax(logPath: String) extends EAProblem {
  def phenotype(ind:Individual) = {
    ind.genotype
  }
  def fitness(ind: Individual): Double = {
    ind.genotype.size.toFloat / ind.genotype.capacity
  }
}

Во время выполнения выбирается протокол / стратегия:

object EASelectionStrategyProtocolDemo {
  def main(args: Array[String]) {

    val problem_impl = List[EAProblem](
      // Full replacement
      new OneMax("sigma_strat_full-rep_prot_onemax.log.dat") {
        def selectionStrategy(p: Population): List[(Individual, Double)] =
          SelectionStrategies.sigmaScalingMatingSelection(p)
        def nextGeneration(p: Population): Population = SelectionProtocols.fullReplacement(p)
      },
      new OneMax("boltz_strat_full-rep_prot_onemax.log.dat") {
        def selectionStrategy(p: Population): List[(Individual, Double)] =
          SelectionStrategies.boltzmannSelection(p)
        def nextGeneration(p: Population): Population = SelectionProtocols.fullReplacement(p)
      })
    for(problem <- problem_impl)
       new Simulator(problem)
}

Объекты SelectionStrategies / SelectionProtocols содержат кластеры со ссылками на другой код в EAProblem.

Сейчас мне нужен какой-то способ создания других абстрактных классов, таких как OneMax (у меня их много), с использованием отражения (или какого-то другого механизма). Псевдокод:

val listOfClassNames = List("OneMax", "classA", "classB", ...)
for(className <- listOfClassNames){
    class_sigma = Class.forname(className)
    /*
    Implement class_class with this code and instantiate it
    def selectionStrategy(p: Population): List[(Individual, Double)] =
          SelectionStrategies.sigmaScalingMatingSelection(p)
    def nextGeneration(p: Population): Population = SelectionProtocols.fullReplacement(p)
    */
    class_boltz = Class.forname(className)
    /*
    Implement class_boltz with this code and instantiate it
    def selectionStrategy(p: Population): List[(Individual, Double)] =
          SelectionStrategies.boltzmannSelection(p)
    def nextGeneration(p: Population): Population = SelectionProtocols.fullReplacement(p)
    */
}

Ответы [ 3 ]

1 голос
/ 01 февраля 2010
  1. вы не можете создать экземпляр абстрактного класса
  2. вам не нужен абстрактный класс

fitness, selectionStrategy, nextGeneration - все это «независимые» переменные. Таким образом, связывание их вместе в одном интерфейсе противоречит природе проблемы. Попробуйте это:

type Fitness = Individual => Double
type SelectionStrategy = Population = > List[(Individual, Double)]
type NextGeneration = Population => Population

case class EAProblem(
  fitness: Fitness, 
  selectionStrategy: SelectionStrategy, 
  nextGeneration: NextGeneration) { /* common code */ }

val fitnesses = List(OneMax, classA, classB, ...)
val strategies = List(
  SelectionStrategies.sigmaScalingMatingSelection, 
  SelectionStrategies.boltzmannSelection)

fitnesses.map ( fitness => 
  strategies.map ( strategy =>
    EAProblem(fitness, strategy, SelectionProtocols.fullReplacement)))

Редактировать: вы можете создать экземпляр абстрактного класса ... с помощью CGLib или такого

1 голос
/ 01 февраля 2010

Я не знаю, можете ли вы создать его путем отражения, в то же время определяя абстрактные методы. Или, по крайней мере, не легко.

Почему бы вам не превратить эти методы в функции? То, как я бы поступил, примерно так:

private var _selectionStrategy: Option[Population => List[(Individual, Double)]] = None
def selectionStrategy(p: Population) = _selectionStrategy.getOrElse(error("Uninitialized selection strategy!"))(p)
def setSelectionStrategy(f: Population => List[(Individual, Double)]) = if (_selectionStrategy.isEmpty)
  _selectionStrategy = f
else
  error("Selection strategy already initialized!")

// Same thing for nextGeneration

Конечно, OneMax тогда не будет абстрактным. Что, на самом деле, является своего рода точкой. Затем вы используете отражение для создания нового экземпляра OneMax, который достаточно прост, и используете setSelectionStrategy и setNextGeneration для установки функций.

0 голосов
/ 01 февраля 2010

Если вы действительно хотите использовать рефлексию (с компиляцией кода во время выполнения) таким образом, я думаю, вам лучше использовать такой язык, как Python. Но я не думаю, что вы действительно хотите использовать отражение таким образом.

Я думаю, что вам лучше всего иметь второй класс, а не черту, содержащую подпрограммы, которые выполняют измерение пригодности. Например,

abstract class Selector {
  def fitness(ind: Individual): Double
  def name: String
}
class Throughput extends Selector {
  def fitness(ind: Individual) = ind.fractionCorrect/ind.computeTime
  def name = "Throughput"
}

Тогда вы можете

val selectors = List(new Throughput, new ...)
val userInputMap = List.map( t => (t.name , t) ).toMap

и найдите правильный селектор по имени.

Затем OneMax (и другие) принимают селектор в качестве аргумента конструктора, который вы можете предоставить из строки через userInputMap.

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...