Finished chapter 6. Super interesting and I appreciated the invitation to do implementations of other crossover strategies as an exercise. Here are my implementations for messy single point, multipoint, and cycle crossover strategies. Could do with some guards/specs because the implementations depend on the chromosome definition used in the book. Tips/critiques welcome!
def messy_single_point(p1, p2) do
cx1 = :rand.uniform(length(p1.genes) - 1)
cx2 = :rand.uniform(length(p2.genes) - 1)
{h1, t1} = Enum.split(p1.genes, cx1)
{h2, t2} = Enum.split(p2.genes, cx2)
c1 = h1 ++ t2
c2 = h2 ++ t1
{%Chromosome{genes: c1, size: length(c1)}, %Chromosome{genes: c2, size: length(c2)}}
end
def multipoint(p1, p2, k) do
cxs =
Stream.repeatedly(fn -> :rand.uniform(length(p1.genes) - 1) end)
|> Enum.take(k)
cxs
|> Enum.reduce({p1.genes, p2.genes}, fn cx, {c1, c2} ->
[{h1, t1}, {h2, t2}] = Enum.map([c1, c2], &Enum.split(&1, cx))
{h1 ++ t2, h2 ++ t1}
end)
|> Tuple.to_list()
|> Enum.map(fn genes -> %Chromosome{genes: genes, size: length(genes)} end)
|> List.to_tuple()
end
def cycle(p1, p2) do
[arr1, arr2] =
[p1.genes, p2.genes]
|> Enum.map(fn list ->
list |> Enum.with_index() |> Map.new(fn {v, k} -> {k, v} end)
end)
cycle_helper(arr1, arr2, 0, %{}, %{})
end
defp cycle_helper(arr1, arr2, ndx, c1, c2) do
if arr1[ndx] in Map.values(c1) do
cycle_completed(arr1, arr2, c1, c2)
else
v1 = Map.get(arr1, ndx)
v2 = Map.get(arr2, ndx)
c1 = Map.put(c1, ndx, v1)
c2 = Map.put(c2, ndx, v2)
ndx = find_index(v1, arr2)
cycle_helper(arr1, arr2, ndx, c1, c2)
end
end
defp cycle_completed(arr1, arr2, c1, c2) do
[{arr2, c1}, {arr1, c2}]
|> Enum.map(fn {p, c} ->
p
|> Enum.reduce(c, fn {k, v}, acc ->
Map.put_new(acc, k, v)
end)
end)
|> Enum.map(fn map -> map |> Enum.sort_by(fn {k, _v} -> k end) |> Enum.map(&elem(&1, 1)) end)
|> Enum.map(fn genes -> %Chromosome{genes: genes, size: length(genes)} end)
|> List.to_tuple()
end
defp find_index(val, arr) do
arr |> Enum.find(fn {_k, v} -> v == val end) |> elem(0)
end
I leaned heavily on this paper for the cycle implementation, and of course the author’s own Genex lib for the messy single point implementation.