Implements auto-simplification using k-annealing & tests

Select k random elements in plushy. Delete these, and see if the plushy's behaviors are still identical. If they are, this is now the current plushy. If not, decrease k with a certain prob, and try again.
This commit is contained in:
Ryan Boldi 2022-01-13 17:26:46 -05:00
parent a215c1c271
commit e25dab4798
3 changed files with 46 additions and 13 deletions

6
src/propeller/gp.cljc Executable file → Normal file
View File

@ -2,6 +2,7 @@
(:require [clojure.string] (:require [clojure.string]
[clojure.pprint] [clojure.pprint]
[propeller.genome :as genome] [propeller.genome :as genome]
[propeller.simplification :as simplification]
[propeller.variation :as variation] [propeller.variation :as variation]
[propeller.push.instructions.bool] [propeller.push.instructions.bool]
[propeller.push.instructions.character] [propeller.push.instructions.character]
@ -58,7 +59,10 @@
(<= (:total-error best-individual) solution-error-threshold) (<= (:total-error best-individual) solution-error-threshold)
(do (prn {:success-generation generation}) (do (prn {:success-generation generation})
(prn {:total-test-error (prn {:total-test-error
(:total-error (error-function argmap (:testing-data argmap) best-individual))})) (:total-error (error-function argmap (:testing-data argmap) best-individual))})
(if (:simplification? argmap)
(let [simplified-plushy (simplification/auto-simplify-plushy argmap (:plushy best-individual) (:simplification-steps argmap) error-function (:training-data argmap) (:simplification-k argmap) (:simplification-k-prob argmap) (:simplification-verbose? argmap))]
(prn {:total-test-error-simplified (:total-error (error-function argmap (:testing-data argmap) (hash-map :plushy simplified-plushy)))}))))
;; ;;
(>= generation max-generations) (>= generation max-generations)
nil nil

View File

@ -0,0 +1,37 @@
(ns propeller.simplification
(:require [propeller.genome :as genome]
[propeller.push.interpreter :as interpreter]
[propeller.push.state :as state]
[propeller.tools.math :as math]
))
(defn choose-random-k
[k indices]
(take k (shuffle indices)))
(defn delete-at-indices
"deletes the values at given set of indices"
[indices plushy]
(let [sorted-indices (sort > indices)]
(keep-indexed #(if (not (some #{%1} sorted-indices)) %2) plushy)))
(defn delete-k-random
[k plushy]
(delete-at-indices (choose-random-k k (range (count plushy))) plushy))
(defn auto-simplify-plushy
"naive auto-simplification with simple k annealing"
[argmap plushy steps error-function training-data start-k decrease-k-on-failure-prob verbose?]
(if verbose? (prn "Starting Auto-Simplification" {:current-plushy-length (count plushy) :k start-k :decrease-k-on-failure-prob decrease-k-on-failure-prob}))
(let [initial-errors (:errors (error-function argmap training-data {:plushy plushy}))]
(loop [step 0 curr-plushy plushy k start-k]
(if (and verbose? (= (mod step 50) 0)) (pr {:step step :k k} " "))
(if (< steps step)
(do (if verbose? (prn "Finished Auto-Simplification" {:final-plushy-length (count curr-plushy) :final-plushy curr-plushy})) curr-plushy)
(let [new-plushy (delete-k-random k curr-plushy)
new-plushy-errors (:errors (error-function argmap training-data {:plushy new-plushy}))
new-equal? (= new-plushy-errors initial-errors)]
(print-str new-plushy new-plushy-errors new-equal?)
(recur (inc step)
(if new-equal? new-plushy curr-plushy)
(if new-equal? k (if (and (> k 1) (< (rand) decrease-k-on-failure-prob)) (dec k) k))))))))

View File

@ -1,6 +1,8 @@
(ns propeller.utils-test (ns propeller.utils-test
(:require [clojure.test :as t] (:require [clojure.test :as t]
[propeller.utils :as u])) [propeller.utils :as u]
[propeller.simplification :as s]))
(t/deftest first-non-nil-test (t/deftest first-non-nil-test
(t/is (= 1 (u/first-non-nil '(1 2 3)))) (t/is (= 1 (u/first-non-nil '(1 2 3))))
(t/is (= nil (u/first-non-nil []))) (t/is (= nil (u/first-non-nil [])))
@ -26,20 +28,11 @@
true true
(= 2 test)))))) (= 2 test))))))
(t/deftest count-points-test (t/deftest count-points-test
(t/is (= 6 (u/count-points '(:a :b (:c :d))))) (t/is (= 6 (u/count-points '(:a :b (:c :d)))))
(t/is (= 1 (u/count-points '()))) (t/is (= 1 (u/count-points '())))
(t/is (= 2 (u/count-points '(:a))))) (t/is (= 2 (u/count-points '(:a)))))
<<<<<<< Updated upstream
;(t/deftest seq-zip-test
; (t/is ))
;(t/deftest depth-test
; (t/is (= 3 (u/depth ()))))
=======
(t/testing "choose-random-k" (t/testing "choose-random-k"
(t/testing "should return indices that are a member of the original array" (t/testing "should return indices that are a member of the original array"
(t/is (every? identity (map #(contains? (set (range 10)) %) (s/choose-random-k 3 (range 10)))))) (t/is (every? identity (map #(contains? (set (range 10)) %) (s/choose-random-k 3 (range 10))))))
@ -83,4 +76,3 @@
(t/testing "should decrease size of plushy that always has perfect scores" (t/testing "should decrease size of plushy that always has perfect scores"
(t/is (< (count (s/auto-simplify-plushy {} plushy 5 (fn [argmap data plushy] 0) {} 3 false)) (count plushy))) (t/is (< (count (s/auto-simplify-plushy {} plushy 5 (fn [argmap data plushy] 0) {} 3 false)) (count plushy)))
(t/is (< (count (s/auto-simplify-plushy {} plushy 1 (fn [argmap data plushy] 0) {} 10 false)) (count plushy)))))) (t/is (< (count (s/auto-simplify-plushy {} plushy 1 (fn [argmap data plushy] 0) {} 10 false)) (count plushy))))))
>>>>>>> Stashed changes