Haskell:抽象遗传算法

时间:2011-02-15 22:28:18

标签: haskell evolutionary-algorithm

我是Haskell编程世界的新手,我正在研究一种简单的遗传算法,以找到旅行商问题的良好解决方案。我将解决方案表示为整数上的排列,因此我有这种类型的同义词

type Genome = [Int]

算法本身是一组对解决方案起作用的函数:

mutation :: Genome -> Genome
selectParents :: [Genome] -> [Genome] -> [Genome]
crossover :: Genome -> Genome -> (Genome, Genome)
selectSurvivors :: [Genome] -> [Genome] -> [Genome]

我不确定我的代码中有多少与我的问题相关,因此请询问是否需要更多详细信息。值得一提的是,上面的类型签名实际上是简化的,我实际上使用State monad来携带StdGen所以所有这些函数实际上都返回有状态计算。

我想对此做几件事,但不能完全理解。我希望能够为解决方案选择不同的表示形式,在我看来,这将是一个使用类型类的自然场所,因此Genome将是类型类,[Int] a此Genome的特定实例。

现在,我希望能够试验这些实现,并希望能够在其他项目中使用该代码。使用这样的类型类需要我创建的每个新算法都要求我创建另一个Genome实例,这是创建库的好方法吗?

一个额外的问题,只是困扰我的事情,是否有任何方法可以创建类似函数的类型同义词,这样如果我正在编写一个函数,它将函数作为参数,我可以编写同义词而不是函数的整个类型签名,即以下类似的东西可以工作。

type someFunc = [Int] -> [Int] -> Int
someOtherFunc :: someFunc -> [Int] -> Int

是的,希望这是对问题的一个清晰的解释,感觉我错过了真正明显的答案,但它并没有跳出来。干杯

2 个答案:

答案 0 :(得分:7)

不幸的是,理想的解决方案通常取决于您的问题域。 This blog post讨论了类型类方法和按位方法。我个人认为如果你想要灵活性,混合方法是最好的。如果存在良好的按位映射,则可以对其进行定义,并从中派生实现,否则可以手动实现交叉和变异。

ja的方法实际上不起作用。你的一些基因组函数需要随机输入,你可以通过使用随机数生成器like this thread

在状态monad中运行来获得
class Genome a where
    fitness :: a -> Int
    breed :: (RandomGen g, MonadState g m) => a -> a -> m a
    mutate :: (RandomGen g, MonadState g m) => a -> m a

然后,无论实现如何,您都拥有对基因组进行操作的常用功能。

selectParents :: (Genome a, RandomGen g, MonadState g m) => [a] -> m [a]
selectSurvivors :: (Genome a, RandomGen g, MonadState g m) => [a] -> m [a]

如果你有一个好位映射,你可以在BitArrays上定义固定函数(注意每个都必须将适应度函数作为参数)

breed :: (RandomGen g, MonadState g m) => BitArray -> BitArray -> m BitArray
mutate :: (RandomGen g, MonadState g m) => BitArray -> m BitArray
selectParents :: (RandomGen g, MonadState g m) => (BitArray -> Int) -> [BitArray] -> m [BitArray]
selectSurvivors :: (RandomGen g, MonadState g m) => (BitArray -> Int) -> [BitArray] -> m [BitArray]

答案 1 :(得分:2)

是的,使用类型类来表示基因组是一个很好的方法。像这样:

class Genome a where
   mutation :: a -> a
   selectParents :: [a] -> [a] -> [a]
   crossover :: a -> a -> (a, a)
   selectSurvivors :: [a] -> [a] -> [a]
instance Genome [a] where
   mutation l = l
   selectParents l1 l2 = l1
   crossover g1 g2 = (g1,g2)
   selectSurvivors l1 l2 = l1
data Tree a = Leaf a | Branch [Tree a]   
instance Genome (Tree a) where
   mutation t = t
   selectParents l1 l2 = l1
   crossover g1 g2 = (g1,g2)
   selectSurvivors l1 l2 = l1

至于为每个算法实例化一个新的数据类型,你可以在你的库中包含一些实例,但实现新的实例是没有问题的 - 这就是重点!