diff --git a/.DS_Store b/.DS_Store deleted file mode 100644 index feca861..0000000 Binary files a/.DS_Store and /dev/null differ diff --git a/.gitignore b/.gitignore index 66b50af..a6b37b8 100644 --- a/.gitignore +++ b/.gitignore @@ -21,4 +21,5 @@ notes # Don't commit the data directory that we'll # use to hold the data from # https://github.com/thelmuth/program-synthesis-benchmark-datasets -/data \ No newline at end of file +/data +**/.DS_Store diff --git a/src/.DS_Store b/src/.DS_Store deleted file mode 100644 index bf7db11..0000000 Binary files a/src/.DS_Store and /dev/null differ diff --git a/src/propeller/.DS_Store b/src/propeller/.DS_Store deleted file mode 100644 index ed2fbb1..0000000 Binary files a/src/propeller/.DS_Store and /dev/null differ diff --git a/src/propeller/gp.cljc b/src/propeller/gp.cljc index 2a46aeb..0eb0426 100755 --- a/src/propeller/gp.cljc +++ b/src/propeller/gp.cljc @@ -25,8 +25,12 @@ (println "Best behaviors:" (:behaviors best)) (println "Genotypic diversity:" (float (/ (count (distinct (map :plushy pop))) (count pop)))) + (println "Behavioral diversity:" + (float (/ (count (distinct (map :behaviors pop))) (count pop)))) (println "Average genome length:" (float (/ (reduce + (map count (map :plushy pop))) (count pop)))) + (println "Average total error:" + (float (/ (reduce + (map :total-error pop)) (count pop)))) (println))) (defn gp diff --git a/src/propeller/problems/valiant.cljc b/src/propeller/problems/valiant.cljc new file mode 100644 index 0000000..f51d8b2 --- /dev/null +++ b/src/propeller/problems/valiant.cljc @@ -0,0 +1,62 @@ +(ns propeller.problems.valiant + (:require [propeller.genome :as genome] + [propeller.push.interpreter :as interpreter] + [propeller.push.state :as state])) + +(def num-vars 100) ;10) ;100) ;1000) +(def num-inputs 50) ;5) ; 50) ;500) +(def num-train 500) ;5000) +(def num-test 200) + +(def train-and-test-data + (let [input-indices (take num-inputs (shuffle (range num-vars))) + rand-vars (fn [] (vec (repeatedly num-vars #(< (rand) 0.5)))) + even-parity? (fn [vars] + (even? (count (filter #(= % true) + (map #(nth vars %) + input-indices))))) + train-inputs (repeatedly num-train rand-vars) + test-inputs (repeatedly num-test rand-vars)] + {:train {:inputs train-inputs + :outputs (map even-parity? train-inputs)} + :test {:inputs test-inputs + :outputs (map even-parity? test-inputs)}})) + +(def instructions + (vec (concat (for [i (range num-vars)] (keyword (str "in" i))) + (take num-inputs + (cycle [:boolean_xor + :boolean_or + :boolean_and + :boolean_not + :exec_if + 'close + ]))))) + +(defn error-function + ([argmap individual] + (error-function argmap individual :train)) + ([argmap individual subset] + (let [program (genome/plushy->push (:plushy individual) argmap) + data (get train-and-test-data subset) + inputs (:inputs data) + correct-outputs (:outputs data) + outputs (map (fn [input] + (state/peek-stack + (interpreter/interpret-program + program + (assoc state/empty-state + :input (zipmap (for [i (range (count input))] + (keyword (str "in" i))) + input)) + (:step-limit argmap)) + :boolean)) + inputs) + errors (map #(if (= %1 %2) 0 1) + correct-outputs + outputs)] + (assoc individual + :behaviors outputs + :errors errors + :total-error #?(:clj (apply +' errors) + :cljs (apply + errors)))))) diff --git a/src/propeller/session.cljc b/src/propeller/session.cljc index 7154b7e..c9f9e22 100755 --- a/src/propeller/session.cljc +++ b/src/propeller/session.cljc @@ -10,145 +10,146 @@ [propeller.push.state :as state] [propeller.push.utils.helpers :refer [get-stack-instructions]])) -#_(interpreter/interpret-program - '(1 2 :integer_add) state/empty-state 1000) - -#_(interpreter/interpret-program - '(3 3 :integer_eq :exec_if (1 "yes") (2 "no")) - state/empty-state - 1000) - -#_(interpreter/interpret-program - '(:in1 :string_reverse 1 :string_take "?" :string_eq :exec_if - (:in1 " I am asking." :string_concat) - (:in1 " I am saying." :string_concat)) - (assoc state/empty-state :input {:in1 "Can you hear me?"}) - 1000) - -#_(interpreter/interpret-program - '(:in1 :string_reverse 1 :string_take "?" :string_eq :exec_if - (:in1 " I am asking." :string_concat) - (:in1 " I am saying." :string_concat)) - (assoc state/empty-state :input {:in1 "I can hear you."}) - 1000) - -#_(genome/plushy->push - (genome/make-random-plushy (get-stack-instructions #{:float :integer :exec :boolean}) 20)) - -#_(gp/gp {:instructions propeller.problems.software.number-io/instructions - :error-function propeller.problems.software.number-io/error-function - :max-generations 500 - :population-size 500 - :max-initial-plushy-size 100 - :step-limit 200 - :parent-selection :lexicase - :tournament-size 5 - :umad-rate 0.1 - :variation {:umad 0.5 :crossover 0.5} - :elitism false}) - -#_(gp/gp {:instructions propeller.problems.simple-regression/instructions - :error-function propeller.problems.simple-regression/error-function - :max-generations 500 - :population-size 500 - :max-initial-plushy-size 100 - :step-limit 200 - :parent-selection :tournament - :tournament-size 5 - :umad-rate 0.01 - :variation {:umad 1.0 - :crossover 0.0} - :elitism false}) - -#_(gp/gp {:instructions propeller.problems.simple-regression/instructions - :error-function propeller.problems.simple-regression/error-function - :max-generations 500 - :population-size 500 - :max-initial-plushy-size 100 - :step-limit 200 - :parent-selection :tournament - :tournament-size 5 - :umad-rate 0.1 - :variation {:umad 1.0 - :crossover 0.0} - :elitism false}) - - -#_(gp/gp {:instructions propeller.problems.simple-regression/instructions - :error-function propeller.problems.simple-regression/error-function - :max-generations 500 - :population-size 500 - :max-initial-plushy-size 100 - :step-limit 200 - :parent-selection :lexicase - :tournament-size 5 - :umad-rate 0.1 - :variation {:umad 1.0 - :crossover 0.0} - :elitism false}) - -#_(gp/gp {:instructions propeller.problems.simple-regression/instructions - :error-function propeller.problems.simple-regression/error-function - :max-generations 500 - :population-size 500 - :max-initial-plushy-size 100 - :step-limit 200 - :parent-selection :lexicase - :tournament-size 5 - :umad-rate 0.1 - :diploid-flip-rate 0.1 - :variation {:umad 0.8 - :diploid-flip 0.2} - :elitism false - :diploid true}) - - -#_(gp/gp {:instructions propeller.problems.software.smallest/instructions - :error-function propeller.problems.software.smallest/error-function - :max-generations 500 - :population-size 500 - :max-initial-plushy-size 100 - :step-limit 200 - :parent-selection :lexicase - :tournament-size 5 - :umad-rate 0.1 - :diploid-flip-rate 0.1 - :variation {;:umad 0.8 - ;:diploid-flip 0.2 - :umad 1 - } - :elitism false - :diploid false}) - -#_(gp/gp {:instructions propeller.problems.software.smallest/instructions - :error-function propeller.problems.software.smallest/error-function - :max-generations 500 - :population-size 500 - :max-initial-plushy-size 200 ;100 - :step-limit 200 - :parent-selection :lexicase - :tournament-size 5 - :umad-rate 0.1 - :diploid-flip-rate 0.1 - :variation {:umad 0.8 - :diploid-flip 0.2 - ;:umad 1 - } - :elitism false - :diploid true}) - -#_(gp/gp {:instructions propeller.problems.string-classification/instructions - :error-function propeller.problems.string-classification/error-function - :max-generations 500 - :population-size 500 - :max-initial-plushy-size 100 - :step-limit 200 - :parent-selection :lexicase - :tournament-size 5 - :umad-rate 0.1 - :diploid-flip-rate 0.1 - :variation {:umad 0.8 - :diploid-flip 0.2 - } - :elitism false - :diploid true}) +;#_(interpreter/interpret-program +; '(1 2 :integer_add) state/empty-state 1000) +; +;#_(interpreter/interpret-program +; '(3 3 :integer_eq :exec_if (1 "yes") (2 "no")) +; state/empty-state +; 1000) +; +;#_(interpreter/interpret-program +; '(:in1 :string_reverse 1 :string_take "?" :string_eq :exec_if +; (:in1 " I am asking." :string_concat) +; (:in1 " I am saying." :string_concat)) +; (assoc state/empty-state :input {:in1 "Can you hear me?"}) +; 1000) +; +;#_(interpreter/interpret-program +; '(:in1 :string_reverse 1 :string_take "?" :string_eq :exec_if +; (:in1 " I am asking." :string_concat) +; (:in1 " I am saying." :string_concat)) +; (assoc state/empty-state :input {:in1 "I can hear you."}) +; 1000) +; +;#_(genome/plushy->push +; (genome/make-random-plushy (get-stack-instructions #{:float :integer :exec :boolean}) 20)) +; +;#_(gp/gp {:instructions propeller.problems.software.number-io/instructions +; :error-function propeller.problems.software.number-io/error-function +; :max-generations 500 +; :population-size 500 +; :max-initial-plushy-size 100 +; :step-limit 200 +; :parent-selection :lexicase +; :tournament-size 5 +; :umad-rate 0.1 +; :variation {:umad 0.5 :crossover 0.5} +; :elitism false}) +; +;#_(gp/gp {:instructions propeller.problems.simple-regression/instructions +; :error-function propeller.problems.simple-regression/error-function +; :max-generations 500 +; :population-size 500 +; :max-initial-plushy-size 100 +; :step-limit 200 +; :parent-selection :tournament +; :tournament-size 5 +; :umad-rate 0.01 +; :variation {:umad 1.0 +; :crossover 0.0} +; :elitism false}) +; +;#_(gp/gp {:instructions propeller.problems.simple-regression/instructions +; :error-function propeller.problems.simple-regression/error-function +; :max-generations 500 +; :population-size 500 +; :max-initial-plushy-size 100 +; :step-limit 200 +; :parent-selection :tournament +; :tournament-size 5 +; :umad-rate 0.1 +; :variation {:umad 1.0 +; :crossover 0.0} +; :elitism false}) +; +; +;#_(gp/gp {:instructions propeller.problems.simple-regression/instructions +; :error-function propeller.problems.simple-regression/error-function +; :max-generations 500 +; :population-size 500 +; :max-initial-plushy-size 100 +; :step-limit 200 +; :parent-selection :lexicase +; :tournament-size 5 +; :umad-rate 0.1 +; :variation {:umad 1.0 +; :crossover 0.0} +; :elitism false}) +; +;#_(gp/gp {:instructions propeller.problems.simple-regression/instructions +; :error-function propeller.problems.simple-regression/error-function +; :max-generations 500 +; :population-size 500 +; :max-initial-plushy-size 100 +; :step-limit 200 +; :parent-selection :lexicase +; :tournament-size 5 +; :umad-rate 0.1 +; :diploid-flip-rate 0.1 +; :variation {:umad 0.8 +; :diploid-flip 0.2} +; :elitism false +; :diploid true}) +; +; +;#_(gp/gp {:instructions propeller.problems.software.smallest/instructions +; :error-function propeller.problems.software.smallest/error-function +; :max-generations 500 +; :population-size 500 +; :max-initial-plushy-size 100 +; :step-limit 200 +; :parent-selection :lexicase +; :tournament-size 5 +; :umad-rate 0.1 +; :diploid-flip-rate 0.1 +; :variation {;:umad 0.8 +; ;:diploid-flip 0.2 +; :umad 1 +; } +; :elitism false +; :diploid false}) +; +;#_(gp/gp {:instructions propeller.problems.software.smallest/instructions +; :error-function propeller.problems.software.smallest/error-function +; :max-generations 500 +; :population-size 500 +; :max-initial-plushy-size 200 ;100 +; :step-limit 200 +; :parent-selection :lexicase +; :tournament-size 5 +; :umad-rate 0.1 +; :diploid-flip-rate 0.1 +; :variation {:umad 0.8 +; :diploid-flip 0.2 +; ;:umad 1 +; } +; :elitism false +; :diploid true}) +; +; +;(gp/gp {:instructions propeller.problems.string-classification/instructions +; :error-function propeller.problems.string-classification/error-function +; :max-generations 500 +; :population-size 500 +; :max-initial-plushy-size 100 +; :step-limit 200 +; :parent-selection :lexicase +; :tournament-size 5 +; :umad-rate 0.1 +; :diploid-flip-rate 0.1 +; :variation {:umad 0.8 +; :diploid-flip 0.2 +; } +; :elitism false +; :diploid true}) diff --git a/src/propeller/variation.cljc b/src/propeller/variation.cljc index d35c452..19578eb 100755 --- a/src/propeller/variation.cljc +++ b/src/propeller/variation.cljc @@ -16,6 +16,20 @@ shorter-padded longer)))) +(defn tail-aligned-crossover + "Crosses over two individuals using uniform crossover. Pads shorter one on the left." + [plushy-a plushy-b] + (let [shorter (min-key count plushy-a plushy-b) + longer (if (= shorter plushy-a) + plushy-b + plushy-a) + length-diff (- (count longer) (count shorter)) + shorter-padded (concat (repeat length-diff :crossover-padding) shorter)] + (remove #(= % :crossover-padding) + (map #(if (< (rand) 0.5) %1 %2) + shorter-padded + longer)))) + (defn diploid-crossover "Crosses over two individuals using uniform crossover. Pads shorter one." [plushy-a plushy-b] @@ -32,6 +46,22 @@ shorter-padded longer))))) +(defn tail-aligned-diploid-crossover + "Crosses over two individuals using uniform crossover. Pads shorter one on the left." + [plushy-a plushy-b] + (let [plushy-a (partition 2 plushy-a) + plushy-b (partition 2 plushy-b) + shorter (min-key count plushy-a plushy-b) + longer (if (= shorter plushy-a) + plushy-b + plushy-a) + length-diff (- (count longer) (count shorter)) + shorter-padded (concat (repeat length-diff :crossover-padding) shorter)] + (flatten (remove #(= % :crossover-padding) + (map #(if (< (rand) 0.5) %1 %2) + shorter-padded + longer))))) + (defn uniform-addition "Returns plushy with new instructions possibly added before or after each existing instruction." @@ -51,6 +81,16 @@ %) plushy)) +(defn diploid-uniform-silent-replacement + "Returns plushy with new instructions possibly replacing existing + instructions, but only among the silent member of each pair." + [plushy instructions replacement-rate] + (interleave (map first (partition 2 plushy)) + (map #(if (< (rand) replacement-rate) + (utils/random-instruction instructions) + %) + (map second (partition 2 plushy))))) + (defn diploid-uniform-addition "Returns plushy with new instructions possibly added before or after each existing instruction." @@ -105,6 +145,11 @@ (:plushy (selection/select-parent pop argmap)) (:plushy (selection/select-parent pop argmap))) ; + :tail-aligned-crossover + (tail-aligned-crossover + (:plushy (selection/select-parent pop argmap)) + (:plushy (selection/select-parent pop argmap))) + ; :umad (-> (:plushy (selection/select-parent pop argmap)) (uniform-addition (:instructions argmap) (:umad-rate argmap)) @@ -118,6 +163,10 @@ (-> (:plushy (selection/select-parent pop argmap)) (uniform-replacement (:instructions argmap) (:replacement-rate argmap))) ; + :diploid-uniform-silent-replacement + (-> (:plushy (selection/select-parent pop argmap)) + (diploid-uniform-silent-replacement (:instructions argmap) (:replacement-rate argmap))) + ; :uniform-deletion (-> (:plushy (selection/select-parent pop argmap)) (uniform-deletion (:umad-rate argmap))) @@ -127,6 +176,11 @@ (:plushy (selection/select-parent pop argmap)) (:plushy (selection/select-parent pop argmap))) ; + :tail-aligned-diploid-crossover + (tail-aligned-diploid-crossover + (:plushy (selection/select-parent pop argmap)) + (:plushy (selection/select-parent pop argmap))) + ; :diploid-umad (-> (:plushy (selection/select-parent pop argmap)) (diploid-uniform-addition (:instructions argmap) (:umad-rate argmap))