More changes
This commit is contained in:
@@ -6,7 +6,7 @@ defmodule Genetic do
|
|||||||
for _ <- 1..population_size, do: genotype.()
|
for _ <- 1..population_size, do: genotype.()
|
||||||
end
|
end
|
||||||
|
|
||||||
def evaluate(population, fitness_function, opts \\ []) do
|
def evaluate(population, fitness_function, _opts \\ []) do
|
||||||
population
|
population
|
||||||
|> Enum.map(
|
|> Enum.map(
|
||||||
fn chromosome ->
|
fn chromosome ->
|
||||||
@@ -18,13 +18,13 @@ defmodule Genetic do
|
|||||||
|> Enum.sort_by(& &1.fitness, &>=/2)
|
|> Enum.sort_by(& &1.fitness, &>=/2)
|
||||||
end
|
end
|
||||||
|
|
||||||
def select(population, opts \\ []) do
|
def select(population, _opts \\ []) do
|
||||||
population
|
population
|
||||||
|> Enum.chunk_every(2)
|
|> Enum.chunk_every(2)
|
||||||
|> Enum.map(&List.to_tuple(&1))
|
|> Enum.map(&List.to_tuple(&1))
|
||||||
end
|
end
|
||||||
|
|
||||||
def crossover(population, opts \\ []) do
|
def crossover(population, _opts \\ []) do
|
||||||
population
|
population
|
||||||
|> Enum.reduce([],
|
|> Enum.reduce([],
|
||||||
fn {p1, p2}, acc ->
|
fn {p1, p2}, acc ->
|
||||||
@@ -38,12 +38,12 @@ defmodule Genetic do
|
|||||||
)
|
)
|
||||||
end
|
end
|
||||||
|
|
||||||
def mutation(population, opts \\ []) do
|
def mutation(population, _opts \\ []) do
|
||||||
population
|
population
|
||||||
|> Enum.map(
|
|> Enum.map(
|
||||||
fn chromosome ->
|
fn chromosome ->
|
||||||
if :rand.uniform() < 0.05 do
|
if :rand.uniform() < 0.05 do
|
||||||
%Chromosome{chromosome | genes: Enum.shuffle(chromosome)}
|
%Chromosome{chromosome | genes: Enum.shuffle(chromosome.genes)}
|
||||||
else
|
else
|
||||||
chromosome
|
chromosome
|
||||||
end
|
end
|
||||||
@@ -53,22 +53,24 @@ defmodule Genetic do
|
|||||||
|
|
||||||
def run(problem, opts \\ []) do
|
def run(problem, opts \\ []) do
|
||||||
population = initialize(&problem.genotype/0)
|
population = initialize(&problem.genotype/0)
|
||||||
|
first_generation = 0
|
||||||
|
|
||||||
population
|
population
|
||||||
|> evolve(problem, opts)
|
|> evolve(problem, first_generation, opts)
|
||||||
end
|
end
|
||||||
|
|
||||||
def evolve(population, problem, opts \\ []) do
|
def evolve(population, problem, generation, opts \\ []) do
|
||||||
population = evaluate(population, &problem.fitness_function/1, opts)
|
population = evaluate(population, &problem.fitness_function/1, opts)
|
||||||
best = hd(population)
|
best = hd(population)
|
||||||
IO.write("\rCurrent Best: #{best.fitness}")
|
IO.write("\rCurrent Best: #{best.fitness}")
|
||||||
if problem.terminate?(population) do
|
if problem.terminate?(population, generation) do
|
||||||
best
|
best
|
||||||
else
|
else
|
||||||
population
|
population
|
||||||
|> select(opts)
|
|> select(opts)
|
||||||
|> crossover(opts)
|
|> crossover(opts)
|
||||||
|> mutation(opts)
|
|> mutation(opts)
|
||||||
|> evolve(problem, opts)
|
|> evolve(problem, generation+1, opts)
|
||||||
end
|
end
|
||||||
|
|
||||||
|
|
||||||
|
@@ -5,5 +5,5 @@ defmodule Problem do
|
|||||||
|
|
||||||
@callback fitness_function(Chromosome.t) :: number()
|
@callback fitness_function(Chromosome.t) :: number()
|
||||||
|
|
||||||
@callback terminate?(Enum.t) :: boolean()
|
@callback terminate?(Enum.t, integer()) :: boolean()
|
||||||
end
|
end
|
50
scripts/cargo.exs
Normal file
50
scripts/cargo.exs
Normal file
@@ -0,0 +1,50 @@
|
|||||||
|
defmodule Cargo do
|
||||||
|
@behaviour Problem
|
||||||
|
alias Types.Chromosome
|
||||||
|
|
||||||
|
@impl true
|
||||||
|
def genotype do
|
||||||
|
genes = for _ <- 1..10, do: Enum.random(0..1)
|
||||||
|
%Chromosome{genes: genes, size: 10}
|
||||||
|
end
|
||||||
|
|
||||||
|
@impl true
|
||||||
|
def fitness_function(chromosome) do
|
||||||
|
profits = [6, 5, 8, 9, 6, 7, 3, 1, 2, 6]
|
||||||
|
weights = [10, 6, 8, 7, 10, 9, 7, 11, 6, 8]
|
||||||
|
weight_limit = 40
|
||||||
|
|
||||||
|
potential_profits =
|
||||||
|
chromosome.genes
|
||||||
|
|> Enum.zip(profits)
|
||||||
|
|> Enum.map(fn {g, p} -> g * p end)
|
||||||
|
|> Enum.sum()
|
||||||
|
|
||||||
|
over_limit? =
|
||||||
|
chromosome.genes
|
||||||
|
|> Enum.zip(weights)
|
||||||
|
|> Enum.map(fn {c, w} -> c * w end)
|
||||||
|
|> Enum.sum()
|
||||||
|
|> Kernel.>(weight_limit)
|
||||||
|
|
||||||
|
profits = if over_limit?, do: 0, else: potential_profits
|
||||||
|
profits
|
||||||
|
end
|
||||||
|
|
||||||
|
@impl true
|
||||||
|
def terminate?(population, _generation) do
|
||||||
|
Enum.max_by(population, &Cargo.fitness_function/1).fitness == 53
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
soln = Genetic.run(Cargo, population_size: 50)
|
||||||
|
|
||||||
|
IO.write("\n")
|
||||||
|
IO.inspect(soln)
|
||||||
|
|
||||||
|
weight = soln.genes
|
||||||
|
|> Enum.zip([10, 6, 8, 7, 10, 9, 7, 11, 6, 8])
|
||||||
|
|> Enum.map(fn {g, w} -> w*g end)
|
||||||
|
|> Enum.sum()
|
||||||
|
|
||||||
|
IO.write("\nWeight is: #{weight}\n")
|
@@ -1,23 +1,24 @@
|
|||||||
genotype = fn -> for _ <- 1..1000, do: Enum.random(0..1) end
|
|
||||||
|
|
||||||
fitness_function = fn chromosome -> Enum.sum(chromosome) end
|
|
||||||
max_fitness = 1000
|
|
||||||
|
|
||||||
defmodule OneMax do
|
defmodule OneMax do
|
||||||
|
alias Types.Chromosome
|
||||||
|
|
||||||
@behaviour Problem
|
@behaviour Problem
|
||||||
|
|
||||||
@impl Problem
|
@impl true
|
||||||
def genotype() do
|
def genotype() do
|
||||||
for _ <- 1..1000, do: Enum.random(0..
|
genes = for _ <- 1..1000, do: Enum.random(0..1)
|
||||||
|
%Chromosome{genes: genes}
|
||||||
end
|
end
|
||||||
|
|
||||||
@impl Problem
|
@impl true
|
||||||
def fitness_function(chromosome) do
|
def fitness_function(chromosome) do
|
||||||
Enum.sum(chromosome.genes)
|
Enum.sum(chromosome.genes)
|
||||||
end
|
end
|
||||||
|
|
||||||
|
@impl true
|
||||||
|
def terminate?(_population, generation), do: generation == 100
|
||||||
end
|
end
|
||||||
|
|
||||||
soln = Genetic.run(fitness_function, genotype, max_fitness)
|
soln = Genetic.run(OneMax)
|
||||||
|
|
||||||
IO.write("\n")
|
IO.write("\n")
|
||||||
IO.inspect(soln)
|
IO.inspect(soln.genes)
|
||||||
|
31
scripts/portfolio.exs
Normal file
31
scripts/portfolio.exs
Normal file
@@ -0,0 +1,31 @@
|
|||||||
|
defmodule Portfolio do
|
||||||
|
@behaviour Problem
|
||||||
|
alias Types.Chromosome
|
||||||
|
|
||||||
|
@target_fitness 180
|
||||||
|
|
||||||
|
@impl true
|
||||||
|
def genotype do
|
||||||
|
genes =
|
||||||
|
for _ <- 1..10, do:
|
||||||
|
{:rand.uniform(10), :rand.uniform(10)}
|
||||||
|
|
||||||
|
%Chromosome{genes: genes, size: 10}
|
||||||
|
end
|
||||||
|
|
||||||
|
@impl true
|
||||||
|
def fitness_function(chromosome) do
|
||||||
|
chromosome.genes
|
||||||
|
|> Enum.map(fn {roi, risk} -> 2 * roi - risk end)
|
||||||
|
|> Enum.sum()
|
||||||
|
end
|
||||||
|
|
||||||
|
@impl true
|
||||||
|
def terminate?(population, _generation) do
|
||||||
|
max_value = Enum.max_by(population, &Portfolio.fitness_function/1)
|
||||||
|
max_value > @target_fitness
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
|
||||||
|
soln = Genetic.run(Portfolio)
|
25
scripts/speller.exs
Normal file
25
scripts/speller.exs
Normal file
@@ -0,0 +1,25 @@
|
|||||||
|
defmodule Speller do
|
||||||
|
@behaviour Problem
|
||||||
|
alias Types.Chromosome
|
||||||
|
|
||||||
|
def genotype do
|
||||||
|
genes =
|
||||||
|
Stream.repeatedly(fn -> Enum.random(?a..?z) end)
|
||||||
|
|> Enum.take(34)
|
||||||
|
%Chromosome{genes: genes, size: 34}
|
||||||
|
end
|
||||||
|
|
||||||
|
def fitness_function(chromosome) do
|
||||||
|
target = "supercalifragilisticexpialidocious"
|
||||||
|
guess = List.to_string(chromosome.genes)
|
||||||
|
String.jaro_distance(target, guess)
|
||||||
|
end
|
||||||
|
|
||||||
|
def terminate?([best | _]), do: best.fitness == 1
|
||||||
|
|
||||||
|
end
|
||||||
|
|
||||||
|
soln = Genetic.run(Speller)
|
||||||
|
|
||||||
|
IO.write("\n")
|
||||||
|
IO.inspect(soln)
|
Reference in New Issue
Block a user