diff --git a/src/propeller/problems/PSB1/count_odds.cljc b/src/propeller/problems/PSB1/count_odds.cljc new file mode 100644 index 0000000..4b42605 --- /dev/null +++ b/src/propeller/problems/PSB1/count_odds.cljc @@ -0,0 +1,77 @@ +(ns propeller.problems.PSB1.count-odds + (:require [psb2.core :as psb2] + [propeller.genome :as genome] + [propeller.push.interpreter :as interpreter] + [propeller.problems.data-creation :as dc] + [propeller.utils :as utils] + [propeller.push.instructions :refer [get-stack-instructions]] + [propeller.push.state :as state] + [propeller.tools.math :as math] + [propeller.gp :as gp] + #?(:cljs [cljs.reader :refer [read-string]]))) + + +(def train-and-test-data (psb2/fetch-examples "data" "count-odds" 200 2000)) +(def train-data (:train train-and-test-data)) +(def test-data (:test train-and-test-data)) + +; Random integer between -100 and 100 (from smallest) +(defn random-int [] (- (rand-int 201) 100)) + +(def instructions + (utils/not-lazy + (concat + ;;; stack-specific instructions + (get-stack-instructions #{:exec :integer :boolean :vector_integer :print}) + ;;; input instructions + (list :in1) + ;;; close + (list 'close) + ;;; ERCs (constants) + (list random-int 0 1 2)))) + +(defn error-function + [argmap data individual] + (let [program (genome/plushy->push (:plushy individual) argmap) + inputs (map (fn [i] (get i :input1)) data) + correct-outputs (map (fn [i] (get i :output1)) data) + outputs (map (fn [input] + (state/peek-stack + (interpreter/interpret-program + program + (assoc state/empty-state :input {:in1 input}) + (:step-limit argmap)) + :integer)) + inputs) + errors (map (fn [correct-output output] + (if (= output :no-stack-item) + 1000000 + (math/abs (- correct-output output)))) + correct-outputs + outputs)] + (assoc individual + :behaviors outputs + :errors errors + :total-error #?(:clj (apply +' errors) + :cljs (apply + errors))))) + +(defn -main + "Runs propel-gp, giving it a map of arguments." + [& args] + (gp/gp + (merge + {:instructions instructions + :error-function error-function + :training-data train-data + :testing-data test-data + :max-generations 300 + :population-size 1000 + :max-initial-plushy-size 250 + :step-limit 2000 + :parent-selection :lexicase + :tournament-size 5 + :umad-rate 0.1 + :variation {:umad 1.0 :crossover 0.0} + :elitism false} + (apply hash-map (map #(if (string? %) (read-string %) %) args)))) + (#?(:clj shutdown-agents))) diff --git a/src/propeller/problems/PSB1/grade.cljc b/src/propeller/problems/PSB1/grade.cljc new file mode 100644 index 0000000..a8961aa --- /dev/null +++ b/src/propeller/problems/PSB1/grade.cljc @@ -0,0 +1,95 @@ +(ns propeller.problems.PSB1.grade + (:require + [psb2.core :as psb2] + [propeller.genome :as genome] + [propeller.push.interpreter :as interpreter] + [propeller.problems.data-creation :as dc] + [propeller.push.state :as state] + [propeller.push.instructions :refer [get-stack-instructions]] + [propeller.utils :as utils] + [propeller.tools.metrics :as metrics] + [propeller.gp :as gp] + #?(:cljs [cljs.reader :refer [read-string]]))) + + +; Based on the grade PSB1 problem, this verion only requires an output of a single character +;"“Student has a ”, “ grade.”, “A”, “B”, “C”, “D”, “F”, integer ERC" + +(def train-and-test-data (psb2/fetch-examples "data" "grade" 200 2000)) +(def train-data (:train train-and-test-data)) +(def test-data (:test train-and-test-data)) + +(defn map-vals-input + "Returns all the input values of a map" + [i] + (vals (select-keys i [:input1 :input2 :input3 :input4 :input5]))) + +(defn get-output + "returns the outputs of the grade function with JUST the letter grade" + [i] + (str (nth i 14))) + +; Random integer between -100 and 100 +(defn random-int [] (- (rand-int 201) 100)) + +(def instructions + (utils/not-lazy + (concat + ;; stack-specific instructions + (get-stack-instructions #{:boolean :exec :integer :string :print}) + ;; input instructions + (list :in1 :in2 :in3 :in4 :in5) + ;;close + (list 'close) + ;; ERCs (constants) + (list "A" "B" "C" "D" "F" random-int)))) + +(defn error-function + [argmap data individual] + (let [program (genome/plushy->push (:plushy individual) argmap) + inputs (map (fn [i] (map-vals-input i)) data) + correct-outputs (map (fn [i] (get-output (get i :output1))) data) + outputs (map (fn [input] + (state/peek-stack + (interpreter/interpret-program + program + (assoc state/empty-state :input {:in1 (nth input 0) + :in2 (nth input 1) + :in3 (nth input 2) + :in4 (nth input 3) + :in5 (nth input 4)}) + (:step-limit argmap)) + :print)) + inputs) + errors (map (fn [correct-output output] + (if (= output :no-stack-item) + 1000000.0 + (metrics/levenshtein-distance correct-output output))) + correct-outputs + outputs)] + (assoc individual + :behaviors outputs + :errors errors + :total-error #?(:clj (apply +' errors) + :cljs (apply + errors))))) + +(defn -main + "Runs propel-gp, giving it a map of arguments." + [& args] + (gp/gp + (merge + {:instructions instructions + :error-function error-function + :training-data train-data + :testing-data test-data + :max-generations 300 + :population-size 1000 + :max-initial-plushy-size 250 + :step-limit 2000 + :parent-selection :lexicase + :tournament-size 5 + :umad-rate 0.1 + :variation {:umad 1.0 :crossover 0.0} + :elitism false} + (apply hash-map (map #(if (string? %) (read-string %) %) args)))) + (#?(:clj shutdown-agents))) \ No newline at end of file diff --git a/src/propeller/problems/PSB1/scrabble_score.cljc b/src/propeller/problems/PSB1/scrabble_score.cljc new file mode 100644 index 0000000..7339e74 --- /dev/null +++ b/src/propeller/problems/PSB1/scrabble_score.cljc @@ -0,0 +1,146 @@ +(ns propeller.problems.PSB1.scrabble-score + (:require [psb2.core :as psb2] + [propeller.genome :as genome] + [propeller.push.interpreter :as interpreter] + [clojure.string :as string] + [propeller.tools.math :as math] + [propeller.problems.data-creation :as dc] + [propeller.utils :as utils] + [propeller.push.instructions :refer [get-stack-instructions]] + [propeller.push.state :as state] + [propeller.tools.metrics :as metrics] + [propeller.gp :as gp] + #?(:cljs [cljs.reader :refer [read-string]]))) + +(def train-and-test-data (psb2/fetch-examples "data" "scrabble-score" 200 2000)) +(def train-data (:train train-and-test-data)) +(def test-data (:test train-and-test-data)) + +(def scrabble-letter-values + (let [scrabble-map {\a 1 + \b 3 + \c 3 + \d 2 + \e 1 + \f 4 + \g 2 + \h 4 + \i 1 + \j 8 + \k 5 + \l 1 + \m 3 + \n 1 + \o 1 + \p 3 + \q 10 + \r 1 + \s 1 + \t 1 + \u 1 + \v 4 + \w 4 + \x 8 + \y 4 + \z 10} + visible-chars (map char (range 0 127))] + (vec (for [c visible-chars] + (get scrabble-map (first (string/lower-case c)) 0))))) + +;; scrabble-letter-values + +;; (def program '(0 :in1 :string_iterate (:integer_from_char [0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 1 3 3 2 1 4 2 4 1 8 5 1 3 1 1 3 10 1 1 1 1 4 4 8 4 10 0 0 0 0 0 0 1 3 3 2 1 4 2 4 1 8 5 1 3 1 1 3 10 1 1 1 1 4 4 8 4 10 0 0 0 0] :vector_integer_nth :integer_add))) + +;; (def inputs (map (fn [i] (get i :input1)) test-data)) +;; test-data +;; (def correct-outputs (map (fn [i] (get i :output1)) test-data)) + +;; correct-outputs +;; inputs + +;; (def outputs (map (fn [input] +;; (state/peek-stack +;; (interpreter/interpret-program +;; program +;; (assoc state/empty-state :input {:in1 input}) +;; 200) +;; :integer)) +;; inputs)) + +;; outputs +;; correct-outputs + +;; (def errors (map (fn [correct-output output] +;; (if (= output :no-stack-item) +;; 1000000 +;; (math/abs (- correct-output output)))) +;; correct-outputs +;; outputs)) + +;; (apply + errors) + +;; (defn index-of [item coll] +;; (count (take-while (partial not= item) coll))) + +;; (index-of 1 errors) +;; (nth inputs 647) +;; (nth outputs 647) +;; (nth correct-outputs 647) + +(def instructions + (utils/not-lazy + (concat + ;;; stack-specific instructions + (get-stack-instructions #{:exec :integer :boolean :char :vector_integer :string}) + ;;; input instructions + (list :in1) + ;;; close + (list 'close) + ;;; ERCs (constants) + (list scrabble-letter-values)))) + +(defn error-function + [argmap data individual] + (let [program (genome/plushy->push (:plushy individual) argmap) + inputs (map (fn [i] (get i :input1)) data) + correct-outputs (map (fn [i] (get i :output1)) data) + outputs (map (fn [input] + (state/peek-stack + (interpreter/interpret-program + program + (assoc state/empty-state :input {:in1 input}) + (:step-limit argmap)) + :integer)) + inputs) + errors (map (fn [correct-output output] + (if (= output :no-stack-item) + 1000000 + (math/abs (- correct-output output)))) + correct-outputs + outputs)] + (assoc individual + :behaviors outputs + :errors errors + :total-error #?(:clj (apply +' errors) + :cljs (apply + errors))))) + +(defn -main + "Runs propel-gp, giving it a map of arguments." + [& args] + (gp/gp + (merge + {:instructions instructions + :error-function error-function + :training-data train-data + :testing-data test-data + :max-generations 300 + :population-size 1000 + :max-initial-plushy-size 250 + :step-limit 2000 + :parent-selection :lexicase + :tournament-size 5 + :umad-rate 0.1 + :variation {:umad 1.0 :crossover 0.0} + :elitism false} + (apply hash-map (map #(if (string? %) (read-string %) %) args)))) + (#?(:clj shutdown-agents))) diff --git a/src/propeller/problems/PSB1/small_or_large.cljc b/src/propeller/problems/PSB1/small_or_large.cljc new file mode 100644 index 0000000..bfc0dce --- /dev/null +++ b/src/propeller/problems/PSB1/small_or_large.cljc @@ -0,0 +1,78 @@ +(ns propeller.problems.PSB1.small-or-large + (:require [psb2.core :as psb2] + [propeller.genome :as genome] + [propeller.push.interpreter :as interpreter] + [propeller.problems.data-creation :as dc] + [propeller.utils :as utils] + [propeller.push.instructions :refer [get-stack-instructions]] + [propeller.push.state :as state] + [propeller.tools.metrics :as metrics] + [propeller.gp :as gp] + #?(:cljs [cljs.reader :refer [read-string]]))) + + +(def train-and-test-data (psb2/fetch-examples "data" "small-or-large" 200 2000)) +(def train-data (:train train-and-test-data)) +(def test-data (:test train-and-test-data)) + +; Random integer between -100 and 100 +(defn random-int [] (- (rand-int 201) 100)) + +(def instructions + (utils/not-lazy + (concat + ;;; stack-specific instructions + (get-stack-instructions #{:exec :integer :boolean :string :print}) + ;;; input instructions + (list :in1) + ;;; close + (list 'close) + ;;; ERCs (constants) + (list "" "small" "large" random-int)))) + +(defn error-function + [argmap data individual] + (let [program (genome/plushy->push (:plushy individual) argmap) + inputs (map (fn [i] (get i :input1)) data) + correct-outputs (map (fn [i] (get i :output1)) data) + outputs (map (fn [input] + (state/peek-stack + (interpreter/interpret-program + program + (assoc state/empty-state :input {:in1 input}) + (:step-limit argmap)) + :string)) + inputs) + errors (map (fn [correct-output output] + (if (= output :no-stack-item) + 10000 + (metrics/levenshtein-distance correct-output output))) + correct-outputs + outputs)] + (assoc individual + :behaviors outputs + :errors errors + :total-error #?(:clj (apply +' errors) + :cljs (apply + errors))))) + + +(defn -main + "Runs propel-gp, giving it a map of arguments." + [& args] + (gp/gp + (merge + {:instructions instructions + :error-function error-function + :training-data train-data + :testing-data test-data + :max-generations 300 + :population-size 1000 + :max-initial-plushy-size 250 + :step-limit 2000 + :parent-selection :lexicase + :tournament-size 5 + :umad-rate 0.1 + :variation {:umad 1.0 :crossover 0.0} + :elitism false} + (apply hash-map (map #(if (string? %) (read-string %) %) args)))) + (#?(:clj shutdown-agents))) diff --git a/src/propeller/problems/complex_regression.cljc b/src/propeller/problems/complex_regression.cljc new file mode 100644 index 0000000..f940f8c --- /dev/null +++ b/src/propeller/problems/complex_regression.cljc @@ -0,0 +1,81 @@ +(ns propeller.problems.complex-regression + (:require [propeller.genome :as genome] + [propeller.push.interpreter :as interpreter] + [propeller.push.state :as state] + [propeller.tools.math :as math] + [propeller.gp :as gp] + #?(:cljs [cljs.reader :refer [read-string]]))) + +(defn- target-function + "Target function: f(x) = (x^3 + 1)^3 + 1" + [x] + (let [x-new (+ (* x x x) 1)] + (+ (* x-new x-new x-new) 1))) + +(def train-and-test-data + (let [train-inputs (range -4.0 4.0 0.25) + test-inputs (range -4.125 4.125 0.25)] + {:train (map (fn [x] {:input1 (vector x) :output1 (vector (target-function x))}) train-inputs) + :test (map (fn [x] {:input1 (vector x) :output1 (vector (target-function x))}) test-inputs)})) + +(def instructions + (list :in1 + :float_add + :float_subtract + :float_mult + :float_quot + :float_eq + :exec_dup + :exec_if + 'close + 0 + 1)) + +(defn error-function + "Finds the behaviors and errors of an individual. The error is the absolute + deviation between the target output value and the program's selected behavior, + or 1000000 if no behavior is produced. The behavior is here defined as the + final top item on the FLOAT stack." + ([argmap data individual] + (let [program (genome/plushy->push (:plushy individual) argmap) + inputs (map (fn [x] (first (:input1 x))) data) + correct-outputs (map (fn [x] (first (:output1 x))) data) + outputs (map (fn [input] + (state/peek-stack + (interpreter/interpret-program + program + (assoc state/empty-state :input {:in1 input}) + (:step-limit argmap)) + :float)) + inputs) + errors (map (fn [correct-output output] + (if (= output :no-stack-item) + 1000000 + (math/abs (- correct-output output)))) + correct-outputs + outputs)] + (assoc individual + :behaviors outputs + :errors errors + :total-error #?(:clj (apply +' errors) + :cljs (apply + errors)))))) + +(defn -main + "Runs propel-gp, giving it a map of arguments." + [& args] + (gp/gp + (merge + {:instructions instructions + :error-function error-function + :training-data (:train train-and-test-data) + :testing-data (:test train-and-test-data) + :max-generations 5000 + :population-size 500 + :max-initial-plushy-size 100 + :step-limit 200 + :parent-selection :lexicase + :umad-rate 0.1 + :variation {:umad 1.0 :crossover 0.0} + :elitism false} + (apply hash-map (map #(if (string? %) (read-string %) %) args)))) + (#?(:clj shutdown-agents))) diff --git a/src/propeller/problems/float_regression.cljc b/src/propeller/problems/float_regression.cljc new file mode 100644 index 0000000..516e682 --- /dev/null +++ b/src/propeller/problems/float_regression.cljc @@ -0,0 +1,82 @@ +(ns propeller.problems.float-regression + (:require [propeller.genome :as genome] + [propeller.push.interpreter :as interpreter] + [propeller.push.state :as state] + [propeller.tools.math :as math] + [propeller.gp :as gp] + #?(:cljs [cljs.reader :refer [read-string]]))) + +(defn- target-function + "Target function: f(x) = (1+ x^3)^3 + 1" + [x] + (inc (* (inc (* x x x)) (inc (* x x x)) (inc (* x x x))))) + +(def train-and-test-data + (let [train-inputs (range -1.5 1.5 0.1) + test-inputs (range -1.75 1.75 0.05)] + {:train (map (fn [x] {:input1 (vector x) :output1 (vector (target-function x))}) train-inputs) + :test (map (fn [x] {:input1 (vector x) :output1 (vector (target-function x))}) test-inputs)})) + +(def instructions + (list :in1 + :float_add + :float_subtract + :float_mult + :float_quot + :float_eq + :exec_dup + :exec_if + 'close + 0 + 1)) + +(defn error-function + "Finds the behaviors and errors of an individual. The error is the absolute + deviation between the target output value and the program's selected behavior, + or 1000000 if no behavior is produced. The behavior is here defined as the + final top item on the FLOAT stack." + ([argmap data individual] + (let [program (genome/plushy->push (:plushy individual) argmap) + inputs (map (fn [x] (first (:input1 x))) data) + correct-outputs (map (fn [x] (first (:output1 x))) data) + outputs (map (fn [input] + (state/peek-stack + (interpreter/interpret-program + program + (assoc state/empty-state :input {:in1 input}) + (:step-limit argmap)) + :float)) + inputs) + errors (map (fn [correct-output output] + (if (= output :no-stack-item) + 1000000 + (math/abs (- correct-output output)))) + correct-outputs + outputs)] + (assoc individual + :behaviors outputs + :errors errors + :total-error #?(:clj (apply +' errors) + :cljs (apply + errors)))))) + +(defn -main + "Runs propel-gp, giving it a map of arguments." + [& args] + (gp/gp + (merge + {:instructions instructions + :error-function error-function + :training-data (:train train-and-test-data) + :testing-data (:test train-and-test-data) + :max-generations 300 + :population-size 1000 + :max-initial-plushy-size 100 + :step-limit 200 + :parent-selection :lexicase + :tournament-size 5 + :umad-rate 0.1 + :solution-error-threshold 0.5 + :variation {:umad 1.0 :crossover 0.0} + :elitism false} + (apply hash-map (map #(if (string? %) (read-string %) %) args)))) + (#?(:clj shutdown-agents))) diff --git a/src/propeller/problems/integer_regression.cljc b/src/propeller/problems/integer_regression.cljc new file mode 100644 index 0000000..ff60213 --- /dev/null +++ b/src/propeller/problems/integer_regression.cljc @@ -0,0 +1,81 @@ +(ns propeller.problems.integer-regression + (:require [propeller.genome :as genome] + [propeller.push.interpreter :as interpreter] + [propeller.push.state :as state] + [propeller.tools.math :as math] + [propeller.gp :as gp] + #?(:cljs [cljs.reader :refer [read-string]]))) + +(defn- target-function + "Target function: f(x) = x^3 + 2*x^2 + x + 3" + [x] + (+ (* x x x) (* 2 x x) x 3)) + +(def train-and-test-data + (let [train-inputs (range -10 11) + test-inputs (concat (range -20 -10) (range 11 21))] + {:train (map (fn [x] {:input1 (vector x) :output1 (vector (target-function x))}) train-inputs) + :test (map (fn [x] {:input1 (vector x) :output1 (vector (target-function x))}) test-inputs)})) + +(def instructions + (list :in1 + :integer_add + :integer_subtract + :integer_mult + :integer_quot + :integer_eq + :exec_dup + :exec_if + 'close + 0 + 1)) + +(defn error-function + "Finds the behaviors and errors of an individual. The error is the absolute + deviation between the target output value and the program's selected behavior, + or 1000000 if no behavior is produced. The behavior is here defined as the + final top item on the INTEGER stack." + ([argmap data individual] + (let [program (genome/plushy->push (:plushy individual) argmap) + inputs (map (fn [x] (first (:input1 x))) data) + correct-outputs (map (fn [x] (first (:output1 x))) data) + outputs (map (fn [input] + (state/peek-stack + (interpreter/interpret-program + program + (assoc state/empty-state :input {:in1 input}) + (:step-limit argmap)) + :integer)) + inputs) + errors (map (fn [correct-output output] + (if (= output :no-stack-item) + 1000000 + (math/abs (- correct-output output)))) + correct-outputs + outputs)] + (assoc individual + :behaviors outputs + :errors errors + :total-error #?(:clj (apply +' errors) + :cljs (apply + errors)))))) + +(defn -main + "Runs propel-gp, giving it a map of arguments." + [& args] + (gp/gp + (merge + {:instructions instructions + :error-function error-function + :training-data (:train train-and-test-data) + :testing-data (:test train-and-test-data) + :max-generations 300 + :population-size 1000 + :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} + (apply hash-map (map #(if (string? %) (read-string %) %) args)))) + (#?(:clj shutdown-agents))) diff --git a/src/propeller/problems/simple_classification.cljc b/src/propeller/problems/simple_classification.cljc new file mode 100644 index 0000000..643591f --- /dev/null +++ b/src/propeller/problems/simple_classification.cljc @@ -0,0 +1,98 @@ +(ns propeller.problems.simple-classification + (:require [propeller.genome :as genome] + [propeller.push.interpreter :as interpreter] + [propeller.push.state :as state] + [propeller.gp :as gp] + #?(:cljs [cljs.reader :refer [read-string]]))) + +;; ============================================================================= +;; Simple classification +;; ============================================================================= + +;; Set of original propel instructions +(def instructions + (list :in1 + :integer_add + :integer_subtract + :integer_mult + :integer_quot + :integer_mod + :integer_eq + :boolean_and + :boolean_not + :boolean_invert_first_then_and + :boolean_invert_second_then_and + :boolean_from_integer + true + false + 'close + 0 + 1 + 3)) + +(defn- target-function + "If number is divisible by 3 but not 7, leave TRUE on the BOOLEAN stack else leave FALSE on the BOOLEAN stack" + [x] + (let [div-3 (= 0 (mod x 3)) + div-7 (= 0 (mod x 7))] + (and div-3 (not div-7)))) + +(def train-and-test-data + (let [train-inputs (range 0 100) + test-inputs (range 100 300) + train-outputs (map target-function train-inputs) + test-outputs (map target-function test-inputs)] + {:train (map (fn [in out] {:input1 (vector in) :output1 (vector out)}) train-inputs train-outputs) + :test (map (fn [in out] {:input1 (vector in) :output1 (vector out)}) test-inputs test-outputs)})) + +(defn error-function + "Finds the behaviors and errors of an individual: Error is 0 if the value and + the program's selected behavior match, or 1 if they differ, or 1000000 if no + behavior is produced. The behavior is here defined as the final top item on + the INTEGER stack." + [argmap data individual] + (let [program (genome/plushy->push (:plushy individual) argmap) + inputs (map (fn [x] (first (:input1 x))) data) + correct-outputs (map (fn [x] (first (:output1 x))) data) + outputs (map (fn [input] + (state/peek-stack + (interpreter/interpret-program + program + (assoc state/empty-state :input {:in1 input}) + (:step-limit argmap)) + :boolean)) + inputs) + errors (map (fn [correct-output output] + (if (= output :no-stack-item) + 1000000 + (if (= correct-output output) + 0 + 1))) + correct-outputs + outputs)] + (assoc individual + :behaviors outputs + :errors errors + :total-error #?(:clj (apply +' errors) + :cljs (apply + errors))))) + +(defn -main + "Runs propel-gp, giving it a map of arguments." + [& args] + (gp/gp + (merge + {:instructions instructions + :error-function error-function + :training-data (:train train-and-test-data) + :testing-data (:test train-and-test-data) + :case-t-size (count (:train train-and-test-data)) + :max-generations 500 + :population-size 500 + :max-initial-plushy-size 100 + :step-limit 200 + :parent-selection :lexicase + :umad-rate 0.1 + :variation {:umad 1.0 :crossover 0.0} + :elitism false} + (apply hash-map (map #(if (string? %) (read-string %) %) args)))) + (#?(:clj shutdown-agents)))