2

私はScalaでEA(evolutionary alg)プロジェクトのフレームワークに取り組んでいます。これには、一般的な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)
    */
}
4

3 に答える 3

1

抽象メソッドを定義しながら、同時にリフレクションによってインスタンス化できるかどうかはわかりません。または、少なくとも、簡単ではありません。

これらのメソッドを関数にしてみませんか? 私がそれについて行く方法は次のようなものです:

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。これはかなり単純で、 と を使用setSelectionStrategysetNextGenerationて関数を設定します。

于 2010-02-01T18:21:32.823 に答える
1
  1. 抽象クラスをインスタンス化できません
  2. 抽象クラスは必要ありません

フィットネス、selectionStrategy、nextGeneration - すべて「独立した」変数です。したがって、それらを 1 つのインターフェイスにまとめることは、問題の性質に反します。これを試して:

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などで

于 2010-02-01T20:09:00.517 に答える
0

このように(ランタイムコードのコンパイルで)リフレクションを本当に使用したい場合は、Pythonのような言語を使用したほうがよいと思います。しかし、私はあなたが本当にこのようにリフレクションを使いたいとは思わない。

あなたの最善の策は、フィットネス測定を実行するルーチンを含む特性ではなく、2番目のクラスを持つことだと思います。例えば、

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を介して文字列から提供できます。

于 2010-02-01T18:45:32.180 に答える