hyperselection implementation and tests
really hacky implementation that only works with UMAD for now.
This commit is contained in:
parent
17f2676a47
commit
b591403fe8
@ -5,6 +5,7 @@
|
||||
[propeller.simplification :as simplification]
|
||||
[propeller.variation :as variation]
|
||||
[propeller.downsample :as downsample]
|
||||
[propeller.hyperselection :as hyperselection]
|
||||
[propeller.push.instructions.bool]
|
||||
[propeller.push.instructions.character]
|
||||
[propeller.push.instructions.code]
|
||||
@ -50,18 +51,18 @@
|
||||
indexed-training-data (downsample/assign-indices-to-data (downsample/initialize-case-distances argmap))]
|
||||
(prn {:ind-training-data (first indexed-training-data)})
|
||||
(let [training-data (if (= (:parent-selection argmap) :ds-lexicase)
|
||||
(case (:ds-function argmap)
|
||||
:case-avg (downsample/select-downsample-avg indexed-training-data argmap)
|
||||
:case-maxmin (downsample/select-downsample-maxmin indexed-training-data argmap)
|
||||
(downsample/select-downsample-random indexed-training-data argmap))
|
||||
(case (:ds-function argmap)
|
||||
:case-avg (downsample/select-downsample-avg indexed-training-data argmap)
|
||||
:case-maxmin (downsample/select-downsample-maxmin indexed-training-data argmap)
|
||||
(downsample/select-downsample-random indexed-training-data argmap))
|
||||
indexed-training-data) ;defaults to random
|
||||
parent-reps (if (zero? (mod generation ds-parent-gens)) ;every ds-parent-gens generations
|
||||
(take (* ds-parent-rate (count population)) (shuffle population))
|
||||
'()) ;else just empty list
|
||||
rep-evaluated-pop (sort-by :total-error
|
||||
(mapper
|
||||
(partial error-function argmap indexed-training-data)
|
||||
parent-reps))
|
||||
(mapper
|
||||
(partial error-function argmap indexed-training-data)
|
||||
parent-reps))
|
||||
ds-evaluated-pop (sort-by :total-error
|
||||
(mapper
|
||||
(partial error-function argmap training-data)
|
||||
@ -93,12 +94,13 @@
|
||||
nil
|
||||
;;
|
||||
:else (recur (inc generation)
|
||||
(if (:elitism argmap)
|
||||
(conj (repeatedly (dec population-size)
|
||||
#(variation/new-individual ds-evaluated-pop argmap))
|
||||
(first ds-evaluated-pop))
|
||||
(repeatedly population-size
|
||||
#(variation/new-individual ds-evaluated-pop argmap)))
|
||||
(let [reindexed-pop (hyperselection/reindex-pop ds-evaluated-pop)]
|
||||
(if (:elitism argmap)
|
||||
(hyperselection/log-hyperselection-and-ret (conj (repeatedly (dec population-size)
|
||||
#(variation/new-individual reindexed-pop argmap))
|
||||
(first reindexed-pop)))
|
||||
(hyperselection/log-hyperselection-and-ret (repeatedly population-size ;need to count occurance of each parent, and reset IDs
|
||||
#(variation/new-individual reindexed-pop argmap)))))
|
||||
(if (= (:parent-selection argmap) :ds-lexicase)
|
||||
(if (zero? (mod generation ds-parent-gens))
|
||||
(downsample/update-case-distances rep-evaluated-pop indexed-training-data indexed-training-data) ; update distances every ds-parent-gens generations
|
||||
|
35
src/propeller/hyperselection.cljc
Normal file
35
src/propeller/hyperselection.cljc
Normal file
@ -0,0 +1,35 @@
|
||||
(ns propeller.hyperselection)
|
||||
|
||||
(defn sum-list-map-indices
|
||||
"sums a list of maps that have the :index property's index multiplicity"
|
||||
[list-of-maps]
|
||||
(->> list-of-maps
|
||||
(map #(:index %))
|
||||
frequencies))
|
||||
|
||||
(defn ordered-freqs
|
||||
"takes a map from indices to frequencies, and returns a sorted list of the frequences is descencing order"
|
||||
[freqs]
|
||||
(->> freqs
|
||||
vals
|
||||
(sort >)))
|
||||
|
||||
(defn normalize-list-by-popsize [popsize lst]
|
||||
(map #(double (/ % popsize)) lst))
|
||||
|
||||
(defn hyperselection-track
|
||||
"outputs a normalized list of the hyperselection proportion for each parent"
|
||||
[new-pop]
|
||||
(->> new-pop
|
||||
sum-list-map-indices
|
||||
ordered-freqs
|
||||
(normalize-list-by-popsize (count new-pop))))
|
||||
|
||||
(defn log-hyperselection-and-ret [new-pop]
|
||||
(prn {:hyperselection (hyperselection-track new-pop)})
|
||||
new-pop)
|
||||
|
||||
(defn reindex-pop
|
||||
"assigns each member of the population a unique index before selection to track hyperselection"
|
||||
[pop]
|
||||
(map (fn [indiv index] (assoc indiv :index index)) pop (range (count pop))))
|
@ -130,6 +130,8 @@
|
||||
"Returns a new individual produced by selection and variation of
|
||||
individuals in the population."
|
||||
[pop argmap]
|
||||
(let [umad-parent (selection/select-parent pop argmap)
|
||||
parent-ind (:index umad-parent)] ;this is a hack to log hyperselection, only works for umad
|
||||
{:plushy
|
||||
(let [r (rand)
|
||||
op (loop [accum 0.0
|
||||
@ -153,7 +155,7 @@
|
||||
(:plushy (selection/select-parent pop argmap)))
|
||||
;
|
||||
:umad
|
||||
(-> (:plushy (selection/select-parent pop argmap))
|
||||
(-> (:plushy umad-parent)
|
||||
(uniform-addition (:instructions argmap) (:umad-rate argmap))
|
||||
(uniform-deletion (:umad-rate argmap)))
|
||||
;
|
||||
@ -216,4 +218,5 @@
|
||||
:else
|
||||
(throw #?(:clj (Exception. (str "No match in new-individual for " op))
|
||||
:cljs (js/Error
|
||||
(str "No match in new-individual for " op))))))})
|
||||
(str "No match in new-individual for " op))))))
|
||||
:index parent-ind}))
|
||||
|
@ -2,7 +2,8 @@
|
||||
(:require [clojure.test :as t]
|
||||
[propeller.utils :as u]
|
||||
[propeller.simplification :as s]
|
||||
[propeller.downsample :as ds]))
|
||||
[propeller.downsample :as ds]
|
||||
[propeller.hyperselection :as hs]))
|
||||
|
||||
(t/deftest first-non-nil-test
|
||||
(t/is (= 1 (u/first-non-nil '(1 2 3))))
|
||||
@ -159,10 +160,34 @@
|
||||
|
||||
(t/deftest case-maxmin-test
|
||||
(t/testing "case-maxmin selects correct downsample"
|
||||
(t/is (let [selected (ds/select-downsample-maxmin '({:input1 [0] :output1 [10] :index 0 :distances [0 5 0 0 0]}
|
||||
{:input1 [1] :output1 [11] :index 1 :distances [0 5 0 0 0]}
|
||||
{:input1 [2] :output1 [12] :index 2 :distances [5 5 5 5 5]}
|
||||
{:input1 [3] :output1 [13] :index 3 :distances [0 5 0 0 0]}
|
||||
{:input1 [4] :output1 [14] :index 4 :distances [0 5 0 0 0]})
|
||||
{:downsample-rate 0.4 :case-t-size 5})]
|
||||
(t/is (let [selected (ds/select-downsample-maxmin
|
||||
'({:input1 [0] :output1 [10] :index 0 :distances [0 5 0 0 0]}
|
||||
{:input1 [1] :output1 [11] :index 1 :distances [0 5 0 0 0]}
|
||||
{:input1 [2] :output1 [12] :index 2 :distances [5 5 5 5 5]}
|
||||
{:input1 [3] :output1 [13] :index 3 :distances [0 5 0 0 0]}
|
||||
{:input1 [4] :output1 [14] :index 4 :distances [0 5 0 0 0]})
|
||||
{:downsample-rate 0.4 :case-t-size 5})]
|
||||
(or (= (:index (first selected)) 1) (= (:index (second selected)) 1))))))
|
||||
|
||||
|
||||
(t/deftest hyperselection-test
|
||||
(let [parents1 '({:blah 3 :index 1} {:blah 3 :index 1}
|
||||
{:blah 3 :index 1} {:blah 3 :index 2})
|
||||
parents2 '({:plushy 2 :index 0} {:blah 3 :index 2}
|
||||
{:blah 3 :index 3} {:index 4})
|
||||
emptyparents '({:blah 1} {:blah 1} {:blah 1})]
|
||||
(t/testing "sum-list-map-indices function works correctly"
|
||||
(t/is (= {1 3, 2 1} (hs/sum-list-map-indices parents1)))
|
||||
(t/is (= {0 1, 2 1, 3 1, 4 1} (hs/sum-list-map-indices parents2))))
|
||||
(t/testing "ordered-freqs function works correctly"
|
||||
(t/is (= '(3 1) (hs/ordered-freqs (hs/sum-list-map-indices parents1))))
|
||||
(t/is (= '(1 1 1 1) (hs/ordered-freqs (hs/sum-list-map-indices parents2)))))
|
||||
(t/testing "hyperselection-track works correctly"
|
||||
(t/is (= '(0.75 0.25) (hs/hyperselection-track parents1)))
|
||||
(t/is (= '(0.25 0.25 0.25 0.25) (hs/hyperselection-track parents2))))
|
||||
(t/testing "reindex-pop works correctly"
|
||||
(t/is (= '({:blah 3 :index 0} {:blah 3 :index 1}
|
||||
{:blah 3 :index 2} {:blah 3 :index 3}) (hs/reindex-pop parents1)))
|
||||
(t/is (= '({:plushy 2 :index 0} {:blah 3 :index 1}
|
||||
{:blah 3 :index 2} {:index 3}) (hs/reindex-pop parents2)))
|
||||
(t/is (= '({:blah 1 :index 0} {:blah 1 :index 1} {:blah 1 :index 2}) (hs/reindex-pop emptyparents))))))
|
||||
|
Loading…
x
Reference in New Issue
Block a user