diff --git a/src/propeller/downsample.cljc b/src/propeller/downsample.cljc index 3bb7e65..151cec2 100644 --- a/src/propeller/downsample.cljc +++ b/src/propeller/downsample.cljc @@ -84,14 +84,14 @@ (do (if (sequential? (:input1 (first new-downsample))) (prn {:cases-in-ds (map #(first (:input1 %)) new-downsample) :cases-in-tourn (map #(first (:input1 %)) tournament)}) - (prn {:cases-in-ds (map #(:input1 %) new-downsample) :cases-in-tourn (map #(:input1 %) tournament)})) - ;(prn {:min-case-distances min-case-distances :selected-case-index selected-case-index}) + (prn {:cases-in-ds (map #(:input1 %) new-downsample) :cases-in-tourn (map #(:input1 %) tournament)})) + ;(prn {:min-case-distances min-case-distances :selected-case-index selected-case-index}) (recur (conj new-downsample (nth tournament selected-case-index)) (shuffle (utils/drop-nth selected-case-index tournament))))))))) (defn get-distance-between-cases "returns the distance between two cases given a list of individual error vectors, and the index these - cases exist in the error vector" + cases exist in the error vector. Only makes the distinction between zero and nonzero errors" [error-lists case-index-1 case-index-2] (if (or (< (count (first error-lists)) case-index-1) (< (count (first error-lists)) case-index-2) @@ -119,15 +119,34 @@ (if (nil? corresponding-small) % corresponding-small)) big-list)) +(defn replace-mins-with-zero + "replaces the minimum value(s) in a list with zero" + [coll] + (if (empty? coll) + '() + (let [m (apply min coll)] + (map #(if (= m %) 0 %) coll)))) + +(defn convert-to-elite-error + "converts a set of errors into a list where all the elite errors are replaced with 0s so that we can use + it in the selection of down-samples with elite/not-elite selection" + [errors] + (map #(replace-mins-with-zero %) errors)) + (defn update-case-distances "updates the case distance field of training-data list, should be called after evaluation of individuals evaluated-pop should be a list of individuals that all have the :errors field with a list of this - individuals performance on the each case in the ds-data, in order" - [evaluated-pop ds-data training-data] - (let [ds-indices (map #(:index %) ds-data) errors (map #(:errors %) evaluated-pop)] - (merge-map-lists-at-index + individuals performance on the each case in the training-data, in order. ids-type is :elite to use elite/not-elite + or :solved to use solve/not-solved" + + [evaluated-pop ds-data training-data ids-type] + (flush) + (let [ds-indices (map #(:index %) ds-data) + errors (map #(:errors %) evaluated-pop) + corr-errors (if (= ids-type :elite) (convert-to-elite-error errors) errors)] ;errors, including elite/not-elite distinction + (merge-map-lists-at-index training-data (map-indexed (fn [idx d-case] (update-in d-case [:distances] #(update-at-indices - % (map (fn [other] (get-distance-between-cases errors idx other)) - (range (count ds-indices))) ds-indices))) ds-data)))) + % (map (fn [other] (get-distance-between-cases corr-errors idx other)) + (range (count ds-indices))) ds-indices))) ds-data)))) \ No newline at end of file diff --git a/src/propeller/gp.cljc b/src/propeller/gp.cljc index 7ed61ea..ff4cea1 100644 --- a/src/propeller/gp.cljc +++ b/src/propeller/gp.cljc @@ -35,11 +35,12 @@ (defn gp "Main GP loop." [{:keys [population-size max-generations error-function instructions - max-initial-plushy-size solution-error-threshold mapper ds-parent-rate ds-parent-gens dont-end] + max-initial-plushy-size solution-error-threshold mapper ds-parent-rate ds-parent-gens dont-end ids-type] :or {solution-error-threshold 0.0 dont-end false ds-parent-rate 0 ds-parent-gens 1 + ids-type :solved ; :solved or :elite ;; The `mapper` will perform a `map`-like operation to apply a function to every individual ;; in the population. The default is `map` but other options include `mapv`, or `pmap`. mapper #?(:clj pmap :cljs map)} @@ -118,6 +119,6 @@ #(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 + (downsample/update-case-distances rep-evaluated-pop indexed-training-data indexed-training-data ids-type) ; update distances every ds-parent-gens generations indexed-training-data) indexed-training-data)))))) \ No newline at end of file diff --git a/test/propeller/push/downsample_test.cljc b/test/propeller/push/downsample_test.cljc new file mode 100644 index 0000000..6e3c4d0 --- /dev/null +++ b/test/propeller/push/downsample_test.cljc @@ -0,0 +1,155 @@ +(ns propeller.push.downsample-test + (:require [clojure.test :as t] + [propeller.utils :as u] + [propeller.simplification :as s] + [propeller.downsample :as ds] + [propeller.hyperselection :as hs])) + + +(t/deftest assign-indices-to-data-test + (t/testing "assign-indices-to-data" + (t/testing "should return a map of the same length" + (t/is (= (count (ds/assign-indices-to-data (range 10))) 10)) + (t/is (= (count (ds/assign-indices-to-data (range 0))) 0))) + (t/testing "should return a map where each element has an index key" + (t/is (every? #(:index %) (ds/assign-indices-to-data (map #(assoc {} :input %) (range 10)))))) + (t/testing "should return distinct indices" + (t/is (= (map #(:index %) (ds/assign-indices-to-data (range 10))) (range 10)))))) + +(t/deftest select-downsample-random-test + (t/testing "select-downsample-random" + (t/testing "should select the correct amount of elements" + (t/is (= (count (ds/select-downsample-random (range 10) {:downsample-rate 0.1})) 1)) + (t/is (= (count (ds/select-downsample-random (range 10) {:downsample-rate 0.2})) 2)) + (t/is (= (count (ds/select-downsample-random (range 10) {:downsample-rate 0.5})) 5))) + (t/testing "should not return duplicate items (when called with set of numbers)" + (t/is (= (count (set (ds/select-downsample-random (range 10) {:downsample-rate 0.1}))) 1)) + (t/is (= (count (set (ds/select-downsample-random (range 10) {:downsample-rate 0.2}))) 2)) + (t/is (= (count (set (ds/select-downsample-random (range 10) {:downsample-rate 0.5}))) 5))) + (t/testing "should round down the number of elements selected if not whole" + (t/is (= (count (ds/select-downsample-random (range 3) {:downsample-rate 0.5})) 1)) + (t/is (= (count (ds/select-downsample-random (range 1) {:downsample-rate 0.5})) 0))) + (t/testing "should not return more elements than available" + (t/is (= (count (ds/select-downsample-random (range 10) {:downsample-rate 2})) 10)) + (t/is (= (count (ds/select-downsample-random (range 10) {:downsample-rate 1.5})) 10))))) + +(t/deftest get-distance-between-cases-test + (t/testing "get-distance-between-cases" + (t/testing "should return correct distance" + (t/is (= 3 (ds/get-distance-between-cases '((0 1 1) (0 1 1) (1 0 1)) 0 1)))) + (t/testing "should return 0 for the distance of a case to itself" + (t/is (= 0 (ds/get-distance-between-cases '((0 1 1) (0 1 1) (1 0 1)) 0 0)))) + (t/testing "should work for non binary values (0 is solved)" + (t/is (= 1 (ds/get-distance-between-cases '((0 2 2) (0 2 2) (1 0 50)) 1 2)))) + (t/testing "should return the max distance if one of the cases does not exist" + (t/is (= 3 (ds/get-distance-between-cases '((0 1 1) (0 1 1) (1 0 1)) 0 4)))))) + +(t/deftest merge-map-lists-at-index-test + (t/testing "merge-map-lists-at-index" + (t/testing "works properly" + (t/is (= '({:index 0 :a 3 :b 2} {:index 1 :a 2 :b 3}) (ds/merge-map-lists-at-index '({:index 0 :a 3 :b 2} {:index 1 :a 1 :b 2}) '({:index 1 :a 2 :b 3}))))) + (t/testing "doesn't change big list if no indices match" + (t/is (= '({:index 0 :a 3 :b 2} {:index 1 :a 1 :b 2}) (ds/merge-map-lists-at-index '({:index 0 :a 3 :b 2} {:index 1 :a 1 :b 2}) '({:index 3 :a 2 :b 3}))))) + (t/testing "doesn't fail on empty list" + (t/is (= '() (ds/merge-map-lists-at-index '() '())))) + (t/testing "shouldn't fail merging non-empty with empty" + (t/is (= '({:index 0 :a 3 :b 2} {:index 1 :a 1 :b 2}) (ds/merge-map-lists-at-index '({:index 0 :a 3 :b 2} {:index 1 :a 1 :b 2}) '())))))) + +(t/deftest update-at-indices-test + (t/testing "update-at-indices" + (t/testing "should update at correct indices" + (t/is (= (ds/update-at-indices [1 2 3 4] [5] [0]) [5 2 3 4])) + (t/is (= (ds/update-at-indices [1 2 3 4] [5] [0]) [5 2 3 4]))) + (t/testing "should update nothing if index list is empty" + (t/is (= (ds/update-at-indices [6 5 4 0 0] [] []) [6 5 4 0 0]))) + (t/testing "should update nothing if index list is out of bounds" + (t/is (= (ds/update-at-indices [6 5 4 0 0] [4 5 1] [-1 5 6]) [6 5 4 0 0]))) + (t/testing "should update only when indices are available (length mismatch)" + (t/is (= (ds/update-at-indices [6 5 4 0 0] [1 2 3 4] [0 1]) [1 2 4 0 0]))) + (t/testing "should not care about index order" + (t/is (= (ds/update-at-indices [6 5 4 0 0] [2 1] [1 0]) [1 2 4 0 0]))) + (t/testing "should work when input is a list" + (t/is (= (ds/update-at-indices '(6 5 4 0 0) '(2 1) '(1 0)) [1 2 4 0 0]))))) + +(t/deftest update-case-distances-test + (t/testing "update-case-distances" + (t/testing "should update correctly when fewer errors than all" + (t/is (= (ds/update-case-distances '({:errors (0 0)} {:errors (0 0)}) + '({:index 3 :distances [2 2 2 2 2]} {:index 4 :distances [2 2 2 2 2]}) + '({:index 0 :distances [2 2 2 2 2]} {:index 1 :distances [2 2 2 2 2]} {:index 2 :distances [2 2 2 2 2]} {:index 3 :distances [2 2 2 2 2]} {:index 4 :distances [2 2 2 2 2]}) + :solved) + '({:index 0 :distances [2 2 2 2 2]} {:index 1 :distances [2 2 2 2 2]} {:index 2 :distances [2 2 2 2 2]} + {:index 3 :distances [2 2 2 0 0]} {:index 4 :distances [2 2 2 0 0]})))) + (t/testing "should update correctly when same errors as all" + (t/is (= (ds/update-case-distances '({:errors (0 0 0 0 0)} {:errors (0 0 0 0 0)}) + '({:index 0 :distances [2 2 2 2 2]} {:index 1 :distances [2 2 2 2 2]} {:index 2 :distances [2 2 2 2 2]} {:index 3 :distances [2 2 2 2 2]} {:index 4 :distances [2 2 2 2 2]}) + '({:index 0 :distances [2 2 2 2 2]} {:index 1 :distances [2 2 2 2 2]} {:index 2 :distances [2 2 2 2 2]} {:index 3 :distances [2 2 2 2 2]} {:index 4 :distances [2 2 2 2 2]}) + :solved) + '({:index 0 :distances [0 0 0 0 0]} {:index 1 :distances [0 0 0 0 0]} {:index 2 :distances [0 0 0 0 0]} + {:index 3 :distances [0 0 0 0 0]} {:index 4 :distances [0 0 0 0 0]})))) + (t/testing "should update correctly for elite/not-elite" + (t/is (= (ds/update-case-distances '({:errors (1 1 1 2 2)} {:errors (2 2 2 1 1)}) + '({:index 0 :distances [2 2 2 2 2]} {:index 1 :distances [2 2 2 2 2]} {:index 2 :distances [2 2 2 2 2]} {:index 3 :distances [2 2 2 2 2]} {:index 4 :distances [2 2 2 2 2]}) + '({:index 0 :distances [2 2 2 2 2]} {:index 1 :distances [2 2 2 2 2]} {:index 2 :distances [2 2 2 2 2]} {:index 3 :distances [2 2 2 2 2]} {:index 4 :distances [2 2 2 2 2]}) + :elite) + '({:index 0 :distances [0 0 0 2 2]} {:index 1 :distances [0 0 0 2 2]} {:index 2 :distances [0 0 0 2 2]} + {:index 3 :distances [2 2 2 0 0]} {:index 4 :distances [2 2 2 0 0]}))) + ))) + +(t/deftest case-maxmin-test + (t/testing "case-maxmin selects correct downsample" + (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 [5 0 5 5 5]} + {:input1 [2] :output1 [12] :index 2 :distances [0 5 0 0 0]} + {: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})] + (prn {:selected selected}) + (t/is (or (= (:index (first selected)) 1) (= (:index (second selected)) 1)))))) + +(t/deftest case-maxmin-adaptive + (t/testing "case-maxmin-adaptive selects correct downsample simple" + (let [selected (ds/select-downsample-maxmin-adaptive + '({:input1 [0] :output1 [10] :index 0 :distances [0 5 0 0 0]} + {:input1 [1] :output1 [11] :index 1 :distances [5 0 5 5 5]} + {:input1 [2] :output1 [12] :index 2 :distances [0 5 0 0 0]} + {:input1 [3] :output1 [13] :index 3 :distances [0 5 0 0 0]} + {:input1 [4] :output1 [14] :index 4 :distances [0 5 0 0 0]}) + {:case-delta 0})] + (prn {:selected selected}) + (t/is (or (= (:index (first selected)) 1) (= (:index (second selected)) 1))) + (t/is (= 2 (count selected))))) + (t/testing "case-maxmin-adaptive selects correct downsample when all identical" + (let [selected (ds/select-downsample-maxmin-adaptive + '({:input1 [0] :output1 [10] :index 0 :distances [0 0 0 0 0]} + {:input1 [1] :output1 [11] :index 1 :distances [0 0 0 0 0]} + {:input1 [2] :output1 [12] :index 2 :distances [0 0 0 0 0]} + {:input1 [3] :output1 [13] :index 3 :distances [0 0 0 0 0]} + {:input1 [4] :output1 [14] :index 4 :distances [0 0 0 0 0]}) + {:case-delta 0})] + (prn {:selected selected}) + (t/is (= 1 (count selected)))))) + + +(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)))))) diff --git a/test/propeller/utils_test.cljc b/test/propeller/utils_test.cljc index d909d52..cc36fec 100644 --- a/test/propeller/utils_test.cljc +++ b/test/propeller/utils_test.cljc @@ -82,136 +82,4 @@ (let [plushy '(:exec_dup 1 :integer_add close :in1 :integer_add 0 :in1 :in1 :integer_mult :integer_add)] (t/testing "should decrease size of plushy that always has perfect scores" (t/is (< (count (s/auto-simplify-plushy plushy (fn [argmap data plushy] 0) {:simplification-steps 100 :simplification-k 4 :simplification-verbose? false})) (count plushy))) - (t/is (< (count (s/auto-simplify-plushy plushy (fn [argmap data plushy] 0) {:simplification-steps 100 :simplification-k 10 :simplification-verbose? false})) (count plushy))))))) - -(t/deftest assign-indices-to-data-test - (t/testing "assign-indices-to-data" - (t/testing "should return a map of the same length" - (t/is (= (count (ds/assign-indices-to-data (range 10))) 10)) - (t/is (= (count (ds/assign-indices-to-data (range 0))) 0))) - (t/testing "should return a map where each element has an index key" - (t/is (every? #(:index %) (ds/assign-indices-to-data (map #(assoc {} :input %) (range 10)))))) - (t/testing "should return distinct indices" - (t/is (= (map #(:index %) (ds/assign-indices-to-data (range 10))) (range 10)))))) - -(t/deftest select-downsample-random-test - (t/testing "select-downsample-random" - (t/testing "should select the correct amount of elements" - (t/is (= (count (ds/select-downsample-random (range 10) {:downsample-rate 0.1})) 1)) - (t/is (= (count (ds/select-downsample-random (range 10) {:downsample-rate 0.2})) 2)) - (t/is (= (count (ds/select-downsample-random (range 10) {:downsample-rate 0.5})) 5))) - (t/testing "should not return duplicate items (when called with set of numbers)" - (t/is (= (count (set (ds/select-downsample-random (range 10) {:downsample-rate 0.1}))) 1)) - (t/is (= (count (set (ds/select-downsample-random (range 10) {:downsample-rate 0.2}))) 2)) - (t/is (= (count (set (ds/select-downsample-random (range 10) {:downsample-rate 0.5}))) 5))) - (t/testing "should round down the number of elements selected if not whole" - (t/is (= (count (ds/select-downsample-random (range 3) {:downsample-rate 0.5})) 1)) - (t/is (= (count (ds/select-downsample-random (range 1) {:downsample-rate 0.5})) 0))) - (t/testing "should not return more elements than available" - (t/is (= (count (ds/select-downsample-random (range 10) {:downsample-rate 2})) 10)) - (t/is (= (count (ds/select-downsample-random (range 10) {:downsample-rate 1.5})) 10))))) - -(t/deftest get-distance-between-cases-test - (t/testing "get-distance-between-cases" - (t/testing "should return correct distance" - (t/is (= 3 (ds/get-distance-between-cases '((0 1 1) (0 1 1) (1 0 1)) 0 1)))) - (t/testing "should return 0 for the distance of a case to itself" - (t/is (= 0 (ds/get-distance-between-cases '((0 1 1) (0 1 1) (1 0 1)) 0 0)))) - (t/testing "should work for non binary values (0 is solved)" - (t/is (= 1 (ds/get-distance-between-cases '((0 2 2) (0 2 2) (1 0 50)) 1 2)))) - (t/testing "should return the max distance if one of the cases does not exist" - (t/is (= 3 (ds/get-distance-between-cases '((0 1 1) (0 1 1) (1 0 1)) 0 4)))))) - -(t/deftest merge-map-lists-at-index-test - (t/testing "merge-map-lists-at-index" - (t/testing "works properly" - (t/is (= '({:index 0 :a 3 :b 2} {:index 1 :a 2 :b 3}) (ds/merge-map-lists-at-index '({:index 0 :a 3 :b 2} {:index 1 :a 1 :b 2}) '({:index 1 :a 2 :b 3}))))) - (t/testing "doesn't change big list if no indices match" - (t/is (= '({:index 0 :a 3 :b 2} {:index 1 :a 1 :b 2}) (ds/merge-map-lists-at-index '({:index 0 :a 3 :b 2} {:index 1 :a 1 :b 2}) '({:index 3 :a 2 :b 3}))))) - (t/testing "doesn't fail on empty list" - (t/is (= '() (ds/merge-map-lists-at-index '() '())))) - (t/testing "shouldn't fail merging non-empty with empty" - (t/is (= '({:index 0 :a 3 :b 2} {:index 1 :a 1 :b 2}) (ds/merge-map-lists-at-index '({:index 0 :a 3 :b 2} {:index 1 :a 1 :b 2}) '())))))) - -(t/deftest update-at-indices-test - (t/testing "update-at-indices" - (t/testing "should update at correct indices" - (t/is (= (ds/update-at-indices [1 2 3 4] [5] [0]) [5 2 3 4])) - (t/is (= (ds/update-at-indices [1 2 3 4] [5] [0]) [5 2 3 4]))) - (t/testing "should update nothing if index list is empty" - (t/is (= (ds/update-at-indices [6 5 4 0 0] [] []) [6 5 4 0 0]))) - (t/testing "should update nothing if index list is out of bounds" - (t/is (= (ds/update-at-indices [6 5 4 0 0] [4 5 1] [-1 5 6]) [6 5 4 0 0]))) - (t/testing "should update only when indices are available (length mismatch)" - (t/is (= (ds/update-at-indices [6 5 4 0 0] [1 2 3 4] [0 1]) [1 2 4 0 0]))) - (t/testing "should not care about index order" - (t/is (= (ds/update-at-indices [6 5 4 0 0] [2 1] [1 0]) [1 2 4 0 0]))) - (t/testing "should work when input is a list" - (t/is (= (ds/update-at-indices '(6 5 4 0 0) '(2 1) '(1 0)) [1 2 4 0 0]))))) - -(t/deftest update-case-distances-test - (t/testing "update-case-distances" - (t/testing "should ..." - (t/is (= (ds/update-case-distances '({:errors (0 0)} {:errors (0 0)}) - '({:index 3 :distances [2 2 2 2 2]} {:index 4 :distances [2 2 2 2 2]}) - '({:index 0 :distances [2 2 2 2 2]} {:index 1 :distances [2 2 2 2 2]} {:index 2 :distances [2 2 2 2 2]} {:index 3 :distances [2 2 2 2 2]} {:index 4 :distances [2 2 2 2 2]})) - '({:index 0 :distances [2 2 2 2 2]} {:index 1 :distances [2 2 2 2 2]} {:index 2 :distances [2 2 2 2 2]} - {:index 3 :distances [2 2 2 0 0]} {:index 4 :distances [2 2 2 0 0]})))))) - -(t/deftest case-maxmin-test - (t/testing "case-maxmin selects correct downsample" - (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 [5 0 5 5 5]} - {:input1 [2] :output1 [12] :index 2 :distances [0 5 0 0 0]} - {: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})] - (prn {:selected selected}) - (t/is (or (= (:index (first selected)) 1) (= (:index (second selected)) 1)))))) - -(t/deftest case-maxmin-adaptive - (t/testing "case-maxmin-adaptive selects correct downsample simple" - (let [selected (ds/select-downsample-maxmin-adaptive - '({:input1 [0] :output1 [10] :index 0 :distances [0 5 0 0 0]} - {:input1 [1] :output1 [11] :index 1 :distances [5 0 5 5 5]} - {:input1 [2] :output1 [12] :index 2 :distances [0 5 0 0 0]} - {:input1 [3] :output1 [13] :index 3 :distances [0 5 0 0 0]} - {:input1 [4] :output1 [14] :index 4 :distances [0 5 0 0 0]}) - {:case-delta 0})] - (prn {:selected selected}) - (t/is (or (= (:index (first selected)) 1) (= (:index (second selected)) 1))) - (t/is (= 2 (count selected))))) - (t/testing "case-maxmin-adaptive selects correct downsample when all identical" - (let [selected (ds/select-downsample-maxmin-adaptive - '({:input1 [0] :output1 [10] :index 0 :distances [0 0 0 0 0]} - {:input1 [1] :output1 [11] :index 1 :distances [0 0 0 0 0]} - {:input1 [2] :output1 [12] :index 2 :distances [0 0 0 0 0]} - {:input1 [3] :output1 [13] :index 3 :distances [0 0 0 0 0]} - {:input1 [4] :output1 [14] :index 4 :distances [0 0 0 0 0]}) - {:case-delta 0})] - (prn {:selected selected}) - (t/is (= 1 (count selected)))))) - - -(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)))))) + (t/is (< (count (s/auto-simplify-plushy plushy (fn [argmap data plushy] 0) {:simplification-steps 100 :simplification-k 10 :simplification-verbose? false})) (count plushy))))))) \ No newline at end of file