added fitness proportionate selection + tests

This commit is contained in:
Ryan Boldi 2023-01-05 12:40:15 +01:00
parent 2a76d32479
commit c40f1f70f4
2 changed files with 42 additions and 1 deletions

View File

@ -21,9 +21,27 @@
survivors)
(rest cases))))))
(defn fitness-proportionate-selection
"Selects an individual from the population using a fitness proportionate selection."
[pop argmap]
(let [pop-fits (->> pop ;convert from error to fitness, where fitness (probability) is (1/ (1+ tot_err))
(map #(assoc % :fitness (/ 1 (inc (:total-error %))))))
pop-total-fit (->> pop-fits
(map :fitness)
(reduce +))
random-num (* (rand) pop-total-fit)
sorted-by-fitness (->> pop-fits
(sort-by :fitness)
(reverse))]
(loop [tot (:fitness (first sorted-by-fitness)) individuals sorted-by-fitness]
(if (< random-num tot)
(first individuals)
(recur (+ tot (:fitness (first (rest individuals)))) (rest individuals))))))
(defn select-parent
"Selects a parent from the population using the specified method."
[pop argmap]
(case (:parent-selection argmap)
:tournament (tournament-selection pop argmap)
:lexicase (lexicase-selection pop argmap)))
:lexicase (lexicase-selection pop argmap)
:roulette (fitness-proportionate-selection pop argmap)))

View File

@ -0,0 +1,23 @@
(ns propeller.selection-test
(:require [clojure.test :as t]
[propeller.selection :as s]))
(t/deftest roulette-selection-test
(t/testing "fitness proportionate selection"
(t/testing "should correctly define the probabilities of selection"
(t/is (let [ret (s/fitness-proportionate-selection '({:index 0 :total-error 0}
{:index 1 :total-error 1}
{:index 2 :total-error 1}
{:index 3 :total-error 1}) {:empty :argmap})]
(case (:index ret)
0 (= (:fitness ret) 1) ;if we selected index 0, check that fitness is correctly calculated to 1
(= (:fitness ret) 1/2)
))))
(t/testing "should always return the same individual if there is only one"
(t/testing "desipte it having bad error"
(t/is (= (:index (s/fitness-proportionate-selection '({:index 99 :total-error 109012390123}) {:empty :argmap}))
99)))
(t/testing "when it has low error"
(t/is (= (:index (s/fitness-proportionate-selection '({:index 22 :total-error 0}) {:empty :argmap}))
22))))))