我曾经两次使用遗传算法,这是一个问候世界的教程 和一个tsp解算器。我试图复制haskell中的hello world教程, 并看看两者如何快速比较。 haskell实现是 相当慢,但让我感到烦恼的是C版汇聚了很多 更快(大约40代)没有任何突变。 haskell版本 AFAIK具有更好的配偶功能(倾向于更好的一面) 人口)并在大约60代收敛,但只有在有 涉及突变。如果没有突变,它很快会停在局部最大值。
haskell版本具有更好的配合功能,但需要突变 甚至收敛; C版本没有突变和更糟糕的配偶功能但是 收敛得更快。
randomSt :: (RandomGen g, Random a) => State g a
randomSt = state random
randomRSt :: (RandomGen g, Random a) => (a, a) -> State g a
randomRSt = state . randomR
wrandomRSt :: (RandomGen g) => Int -> State g Int
wrandomRSt n =
let s = liftM2 (+) (randomRSt (0.0, 1.0)) (randomRSt (0.0, 1.0)) :: (RandomGen g) => State g Float
n' = fromIntegral n
in liftM (flip div 2 . floor . abs . subtract (n' / 2) . (n' *)) s
mateCopy :: (RandomGen g) => StringVector -> State g (StringVector)
mateCopy xs = V.replicateM population (step xs)
where
step :: RandomGen g => StringVector -> State g (Vector Char)
step xs =
let mom = liftM (xs !) (randomRSt (0,population `div` 2))
dad = liftM (xs !) (randomRSt (0,population `div` 2))
split = randomRSt (0, V.length target - 1)
in do
m <- mom
d <- dad
s <- split
return (V.take s m V.++ V.drop s d)
mate :: (RandomGen g) => StringVector -> State g (StringVector)
mate xs = V.replicateM population (step xs)
where
step :: RandomGen g => StringVector -> State g (Vector Char)
step xs =
let mom = liftM (xs !) (wrandomRSt population)
dad = liftM (xs !) (wrandomRSt population)
split = randomRSt (0, V.length target - 1)
in do
m <- mom
d <- dad
s <- split
return (V.take s m V.++ V.drop s d)
elite = population `div` 10
elitism :: (RandomGen g) => StringVector -> State g StringVector
elitism xs = let
a = V.take (elite) xs
children = (V.take (population - elite)) `fmap` mate xs
in do
b' <- children >>= mutate
let xs' = (a V.++ b')
return xs'
unit_t *mate(unit_t *population)
{
int i;
size_t half_population = POPULATION >> 1;
size_t orig_size = strlen(TARGET);
int mum, dad, chromosomes;
char *child;
char *rest;
unit_t *children = malloc(sizeof(unit_t) * POPULATION);
elitism(population, children);
for(i = ELITE; i < POPULATION; i++)
{
mum = rand() % half_population;
dad = rand() % half_population;
chromosomes = rand() % orig_size;
child = malloc(sizeof(char) * (orig_size+1));
rest = population[dad].text + chromosomes;
sprintf(child, "%.*s%s", chromosomes, population[mum].text, rest);
children[i].text = strdup(child);
children[i].dist = -1;
if(will_mutate())
mutate(&children[i], orig_size);
free(child);
}
free_population(population);
population = children;
return population;
}
编辑:注意到C版本从同一半中获取父母。编辑了mateCopy来反映这个
答案 0 :(得分:3)
正如我在评论中指出的那样,当你的人口是同质的时候,你的人口就会趋同,而不是当你对最优秀的个人感到满意时。
您的Haskell版本可能会收敛太快。你的健身功能导致你的人口收敛的速度是“探索”和“剥削”之间的权衡。当人们“探索”时,您可以将其视为在寻找山丘的健身景观中快速移动。 “开拓”包括攀登已经找到的山丘。
如果您的健身功能具有很强的选择性(我假设您的意思是“更好”),那么它正在利用以牺牲的方式进行探索。您在Haskell中编写的解决方案可能过早地消除了它的多样性 - 并且没有突变它不能再创建它。
答案 1 :(得分:0)
更好/更差的伴侣功能是什么意思?
haskell版本具有更好的配合功能,但需要 变异甚至收敛
C版本没有变异 更糟糕的配偶功能但收敛速度更快
人们可以使用的唯一客观事实是,目前一个版本没有变异而另一个版本没有变异。
如果我们谈论GA,所使用的语言是无关紧要的,如果我们谈论性能并且实现具有可比性(即您使用两种语言或其他类型的数组),它就变得相关。