Based on the implementation presented by Lee Spector.
(defn new-individual
"Function used for creating a new individual"
[genome-length]
{:genome (vec (repeatedly genome-length #(rand-int 2))) :fitness 0}
)
(defn fitness-function
[genome, target]
(Math/abs (- (reduce + genome) target))
)
(defn calculate-fitness
[population, target]
(letfn [(fitness-function-helper
[individual, target]
(assoc individual :fitness (fitness-function (individual :genome) target))
)]
(map (fn [individual] (#(fitness-function-helper individual target))) population)
)
)
(defn get-best-individual [population]
(letfn [(better [i1 i2]
(< (i1 :fitness) (i2 :fitness))
)]
(first (sort better population))
)
)
(defn crossover
[first-individual, second-individual, crossover-rate, target]
(let [new-genome (mapv (fn [i1,i2] (let [crossover-probability (rand)]
(cond
(<= crossover-probability crossover-rate) i1
:else i2
)
)
)
(first-individual :genome) (second-individual :genome)
)]
{:genome new-genome :fitness (fitness-function new-genome target)}
)
)
(defn mate-individuals [population, population-size, crossover-rate, target, tournament-size]
(letfn [(tournament-selection [population, population-size, tournament-size, target]
(loop [steps 0 new-population ()]
(if (< steps tournament-size)
(recur (inc steps) (conj new-population (nth population ((comp rand-int -) population-size 2))))
(get-best-individual (calculate-fitness new-population target))
)
)
)]
(loop [steps 0 new-population ()]
(if (< steps population-size)
(let [i1 (tournament-selection population population-size tournament-size target)]
(let [i2 (tournament-selection population population-size tournament-size target)]
(let [offs (crossover i1 i2 crossover-rate target)]
(recur (inc steps) (conj new-population offs))
)
)
)
new-population
)
)
)
)
(defn mutate-population [population, population-size, genome-length, target]
(letfn [(mutate [individual, genome-length, target]
(let [new-genome (assoc (individual :genome) (rand-int genome-length) (rand-int 2))]
{:genome new-genome :fitness (fitness-function new-genome target)}
)
)]
(loop [steps 0 new-population ()]
(if (< steps population-size)
(recur (inc steps) (conj new-population (mutate (nth population steps) genome-length target)))
new-population
)
)
)
)
(defn evolve [population-size, genome-length, target, number-of-generations, crossover-rate, tournament-size]
(loop [generation 0 population (calculate-fitness (repeatedly population-size #(new-individual genome-length)) target) best {}]
(if (and (< generation number-of-generations) (not= 0 (best :fitness)))
(let [offsprings (mate-individuals population population-size crossover-rate target tournament-size)]
(let [new-population (mutate-population offsprings population-size genome-length target)]
(let [best-individual (get-best-individual new-population)]
(do
(printf "Generation %s -> best individual %s%n" generation best-individual)
(recur (inc generation) new-population best-individual)
)
)
)
)
best
)
)
)
(println (evolve 100 100 1 100 0.3 10))