序列的通用操作
Generic operations on sequences
我正在做这个简单的项目,我想制作一个遗传算法来为某个适应度函数找到接近最优的值。简而言之,它看起来像这样:
class Individual[T](val underlying: T, val fitnessFunc: T => Double) {
lazy val fitness: Double = fitnessFunc(underlying)
def update(x: T): Individual[T] = new Individual[T](x, fitnessFunc)
}
class Population[T](individuals: Seq[Individual[T]]) {
def best: Individual[T] = individuals.tail.foldLeft(individuals.head)((b, a) => if(b.fitness > a.fitness) b else a) // not sure if this is the best way btw
}
trait GeneticAlgorithm[T] {
def select(p: Population[T]): Individual[T]
def crossover(i1: Individual[T], i2: Individual[T]): (Individual[T], Individual[T])
def mutate(i: Individual[T]): Individual[T]
def evolve(p: Population[T]): Population[T] {
...
}
}
通过这种方式,我可以专门为特定类型 T
创建 GeneticAlgorithm
的实现。我现在正忙于创建一些选择、交叉和变异策略的实现。
然而,当 T
是一个序列时,我 运行 遇到了问题。对于这种类型,我想要一个变异策略,例如,只是一个有一定机会的随机洗牌:
object Mutation {
def shuffleVector(p: Double): Individual[Vector[_]] => Individual[Vector[_] = (i: Individual[Vector[_]) => {
if (math.random < p) i.update(scala.util.Random.shuffle(i.underlying)) else i
}
}
除了它特定于 Vector 而不是任何序列这一事实之外,它编译得很好。我使用存在类型的原因是我不关心 Vector 是什么类型。
然而,当我想使用它时,我 运行 遇到了问题。例如,当我想优化一个整数向量时:
val ga = new GeneticAlgorithm[Vector[Int]] {
...
override def mutate(i: Individual[Vector[Int]]): Individual[Vector[Int]] = Mutation.shuffleVector(0.5)(i)
...
}
我收到错误:Expression of type Individual[Vector[_]] doesn't conform to expected type Individual[Vector[Int]]
。
除了一些其他可以解决的问题之外,解决这个问题的正确方法是什么?我怀疑它必须与 coveriancy 做一些事情,但还不确定。一直忙于学习 Scala 的方法...;-)
首先,不是你问的,而是...
individuals.tail.foldLeft(individuals.head)((b, a) => if(b.fitness > a.fitness) b else a)
something.tail.foldLeft(something.head)(f)
等同于something.reduce(f)
。
此外,您的代码片段实际上相当于 individuals.maxBy(_.fitness)
现在,要回答您的问题,解决方案很简单:只需将随机播放函数设为通用即可:
def maybeShuffle[T](p: Double, xs: Seq[T]): Seq[T] =
if(math.random < p) scala.util.Random.shuffle(xs) else xs
这实际上可能是使用下划线作为存在类型的 shorthand 实际上不会产生明显结果的情况之一。
Individual[Vector[_]]
翻译成
Individual[Vector[T]] forSome {type T}
不同于
Individual[Vector[T] forSome {type T}]
这可能就是您的想法。
我认为如果您更改方法的签名,错误就会消失。
我正在做这个简单的项目,我想制作一个遗传算法来为某个适应度函数找到接近最优的值。简而言之,它看起来像这样:
class Individual[T](val underlying: T, val fitnessFunc: T => Double) {
lazy val fitness: Double = fitnessFunc(underlying)
def update(x: T): Individual[T] = new Individual[T](x, fitnessFunc)
}
class Population[T](individuals: Seq[Individual[T]]) {
def best: Individual[T] = individuals.tail.foldLeft(individuals.head)((b, a) => if(b.fitness > a.fitness) b else a) // not sure if this is the best way btw
}
trait GeneticAlgorithm[T] {
def select(p: Population[T]): Individual[T]
def crossover(i1: Individual[T], i2: Individual[T]): (Individual[T], Individual[T])
def mutate(i: Individual[T]): Individual[T]
def evolve(p: Population[T]): Population[T] {
...
}
}
通过这种方式,我可以专门为特定类型 T
创建 GeneticAlgorithm
的实现。我现在正忙于创建一些选择、交叉和变异策略的实现。
然而,当 T
是一个序列时,我 运行 遇到了问题。对于这种类型,我想要一个变异策略,例如,只是一个有一定机会的随机洗牌:
object Mutation {
def shuffleVector(p: Double): Individual[Vector[_]] => Individual[Vector[_] = (i: Individual[Vector[_]) => {
if (math.random < p) i.update(scala.util.Random.shuffle(i.underlying)) else i
}
}
除了它特定于 Vector 而不是任何序列这一事实之外,它编译得很好。我使用存在类型的原因是我不关心 Vector 是什么类型。
然而,当我想使用它时,我 运行 遇到了问题。例如,当我想优化一个整数向量时:
val ga = new GeneticAlgorithm[Vector[Int]] {
...
override def mutate(i: Individual[Vector[Int]]): Individual[Vector[Int]] = Mutation.shuffleVector(0.5)(i)
...
}
我收到错误:Expression of type Individual[Vector[_]] doesn't conform to expected type Individual[Vector[Int]]
。
除了一些其他可以解决的问题之外,解决这个问题的正确方法是什么?我怀疑它必须与 coveriancy 做一些事情,但还不确定。一直忙于学习 Scala 的方法...;-)
首先,不是你问的,而是...
individuals.tail.foldLeft(individuals.head)((b, a) => if(b.fitness > a.fitness) b else a)
something.tail.foldLeft(something.head)(f)
等同于something.reduce(f)
。
此外,您的代码片段实际上相当于 individuals.maxBy(_.fitness)
现在,要回答您的问题,解决方案很简单:只需将随机播放函数设为通用即可:
def maybeShuffle[T](p: Double, xs: Seq[T]): Seq[T] =
if(math.random < p) scala.util.Random.shuffle(xs) else xs
这实际上可能是使用下划线作为存在类型的 shorthand 实际上不会产生明显结果的情况之一。
Individual[Vector[_]]
翻译成
Individual[Vector[T]] forSome {type T}
不同于
Individual[Vector[T] forSome {type T}]
这可能就是您的想法。
我认为如果您更改方法的签名,错误就会消失。