私は以前に遺伝的アルゴリズムを2回使いました。こんにちはワールドチュートリアル とtspソルバーです。私はhaskellのhello worldチュートリアルを複製しようとしました。 と2つのスピードを比較する方法を見てください。 haskellの実装は がかなり遅いですが、私の気になるのは、Cバージョンが突然変異のないより速く(約40世代)収束していることです。 haskellのバージョン はAFAIKがより良いメイト関数( のより良い側に傾く)を持っており、 突然変異が関与する場合に限り、約60世代に収束します。突然変異がなければ、すぐに極大値で停止する。どのようにして1つのメイト関数がソリューションに収束するのでしょうか?
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を編集しました
これは、コンパイラ固有のもので言語固有のものではないrandomize関数のコンパイラの実装に関連している可能性があります。別のCコンパイラでCバージョンをコンパイルして、それが結果に影響するかどうかを確認してください。 – Lundin
私は「収束」という言葉を慎重に使用しています。母集団は合理的に同質であると収束していると見なされます。選択アルゴリズムが何か良い場合は、**突然変異なしで収束します**収束したものが好きかどうかは関係ありません。 –