diff --git a/src/propeller/problems/PSB2/basement.cljc b/src/propeller/problems/PSB2/basement.cljc index 2e3ca1a..c80243c 100644 --- a/src/propeller/problems/PSB2/basement.cljc +++ b/src/propeller/problems/PSB2/basement.cljc @@ -69,14 +69,14 @@ :error-function error-function :training-data (:train train-and-test-data) :testing-data (:test train-and-test-data) - :max-generations 500 - :population-size 500 - :max-initial-plushy-size 100 - :step-limit 200 + :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 0.5 :crossover 0.5} + :variation {:umad 1.0 :crossover 0.0} :elitism false} (apply hash-map (map #(if (string? %) (read-string %) %) args))))) diff --git a/src/propeller/problems/PSB2/bouncing_balls.cljc b/src/propeller/problems/PSB2/bouncing_balls.cljc index 9984af6..f18bb16 100644 --- a/src/propeller/problems/PSB2/bouncing_balls.cljc +++ b/src/propeller/problems/PSB2/bouncing_balls.cljc @@ -81,13 +81,13 @@ :error-function error-function :training-data (:train train-and-test-data) :testing-data (:test train-and-test-data) - :max-generations 500 - :population-size 500 - :max-initial-plushy-size 100 - :step-limit 200 + :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 0.5 :crossover 0.5} + :variation {:umad 1.0 :crossover 0.0} :elitism false} - (apply hash-map (map #(if (string? %) (read-string %) %) args))))) + (apply hash-map (map #(if (string? %) (read-string %) %) args))))) \ No newline at end of file diff --git a/src/propeller/problems/PSB2/bowling.cljc b/src/propeller/problems/PSB2/bowling.cljc index 63e0423..045659c 100644 --- a/src/propeller/problems/PSB2/bowling.cljc +++ b/src/propeller/problems/PSB2/bowling.cljc @@ -5,7 +5,6 @@ [propeller.utils :as utils] [propeller.push.utils.helpers :refer [get-stack-instructions]] [propeller.push.state :as state] - [clojure.pprint :as pprint] [propeller.tools.math :as math] [propeller.gp :as gp] #?(:cljs [cljs.reader :refer [read-string]]))) @@ -69,13 +68,13 @@ :error-function error-function :training-data (:train train-and-test-data) :testing-data (:test train-and-test-data) - :max-generations 500 - :population-size 500 - :max-initial-plushy-size 100 - :step-limit 200 + :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 0.5 :crossover 0.5} + :variation {:umad 1.0 :crossover 0.0} :elitism false} (apply hash-map (map #(if (string? %) (read-string %) %) args))))) \ No newline at end of file diff --git a/src/propeller/problems/PSB2/camel_case.cljc b/src/propeller/problems/PSB2/camel_case.cljc index ee58f19..a5449e1 100644 --- a/src/propeller/problems/PSB2/camel_case.cljc +++ b/src/propeller/problems/PSB2/camel_case.cljc @@ -5,7 +5,6 @@ [propeller.utils :as utils] [propeller.push.utils.helpers :refer [get-stack-instructions]] [propeller.push.state :as state] - [propeller.tools.math :as math] [propeller.tools.metrics :as metrics] [propeller.gp :as gp] #?(:cljs [cljs.reader :refer [read-string]]))) @@ -105,13 +104,13 @@ :error-function error-function :training-data (:train train-and-test-data) :testing-data (:test train-and-test-data) - :max-generations 500 - :population-size 500 - :max-initial-plushy-size 100 - :step-limit 200 + :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 0.5 :crossover 0.5} + :variation {:umad 1.0 :crossover 0.0} :elitism false} (apply hash-map (map #(if (string? %) (read-string %) %) args))))) diff --git a/src/propeller/problems/PSB2/dice_game.cljc b/src/propeller/problems/PSB2/dice_game.cljc index 9b63f1c..285b652 100644 --- a/src/propeller/problems/PSB2/dice_game.cljc +++ b/src/propeller/problems/PSB2/dice_game.cljc @@ -5,7 +5,6 @@ [propeller.utils :as utils] [propeller.push.utils.helpers :refer [get-stack-instructions]] [propeller.push.state :as state] - [clojure.pprint :as pprint] [propeller.tools.math :as math] [propeller.gp :as gp] #?(:cljs [cljs.reader :refer [read-string]]))) @@ -22,12 +21,12 @@ (def train-and-test-data (psb2/fetch-examples "data" "dice-game" 200 2000)) (defn map-vals-input - "Returns all the input values of a map (specific helper method for bouncing-balls)" + "Returns all the input values of a map" [i] (vals (select-keys i [:input1 :input2]))) (defn map-vals-output - "Returns the output values of a map (specific helper method for bouncing-balls)" + "Returns the output values of a map" [i] (get i :output1)) @@ -78,13 +77,13 @@ :error-function error-function :training-data (:train train-and-test-data) :testing-data (:test train-and-test-data) - :max-generations 500 - :population-size 500 - :max-initial-plushy-size 100 - :step-limit 200 + :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 0.5 :crossover 0.5} + :variation {:umad 1.0 :crossover 0.0} :elitism false} (apply hash-map (map #(if (string? %) (read-string %) %) args))))) diff --git a/src/propeller/problems/PSB2/fizz_buzz.cljc b/src/propeller/problems/PSB2/fizz_buzz.cljc new file mode 100644 index 0000000..3397851 --- /dev/null +++ b/src/propeller/problems/PSB2/fizz_buzz.cljc @@ -0,0 +1,85 @@ +(ns propeller.problems.PSB2.fizz-buzz + (:require [psb2.core :as psb2] + [propeller.genome :as genome] + [propeller.push.interpreter :as interpreter] + [propeller.utils :as utils] + [propeller.push.utils.helpers :refer [get-stack-instructions]] + [propeller.push.state :as state] + [propeller.tools.metrics :as metrics] + [propeller.gp :as gp])) + +; =========== PROBLEM DESCRIPTION ========================= +; FIZZ BUZZ from PSB2 +; Given an integer x, return "Fizz" if x is +; divisible by 3, "Buzz" if x is divisible by 5, "FizzBuzz" if x +; is divisible by 3 and 5, and a string version of x if none of +; the above hold. +; +; Source: https://arxiv.org/pdf/2106.06086.pdf +; ============================================================ + +(def train-and-test-data (psb2/fetch-examples "data" "fizz-buzz" 200 2000)) + +(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 "Fizz" "Buzz" "FizzBuzz" 0 3 5)))) + +(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) + parsed-outputs (map (fn [output] + (try (read-string output) + #?(:clj (catch Exception e 1000.0) + :cljs (catch js/Error. e 1000.0)))) + outputs) + errors (map (fn [correct-output output] + (if (= output :no-stack-item) + 10000 + (metrics/levenshtein-distance (str correct-output) (str output)))) + correct-outputs + parsed-outputs)] + (assoc individual + :behaviors parsed-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 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))))) + diff --git a/src/propeller/problems/PSB2/fuel_cost.cljc b/src/propeller/problems/PSB2/fuel_cost.cljc index 2f556ac..fafda27 100644 --- a/src/propeller/problems/PSB2/fuel_cost.cljc +++ b/src/propeller/problems/PSB2/fuel_cost.cljc @@ -5,7 +5,6 @@ [propeller.utils :as utils] [propeller.push.utils.helpers :refer [get-stack-instructions]] [propeller.push.state :as state] - [clojure.pprint :as pprint] [propeller.tools.math :as math] [propeller.gp :as gp] #?(:cljs [cljs.reader :refer [read-string]]))) @@ -71,14 +70,14 @@ :error-function error-function :training-data (:train train-and-test-data) :testing-data (:test train-and-test-data) - :max-generations 500 - :population-size 500 - :max-initial-plushy-size 100 - :step-limit 200 + :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 0.5 :crossover 0.5} + :variation {:umad 1.0 :crossover 0.0} :elitism false} (apply hash-map (map #(if (string? %) (read-string %) %) args))))) diff --git a/src/propeller/problems/PSB2/gcd.cljc b/src/propeller/problems/PSB2/gcd.cljc new file mode 100644 index 0000000..079cfd3 --- /dev/null +++ b/src/propeller/problems/PSB2/gcd.cljc @@ -0,0 +1,89 @@ +(ns propeller.problems.PSB2.gcd + (:require [psb2.core :as psb2] + [propeller.genome :as genome] + [propeller.push.interpreter :as interpreter] + [propeller.utils :as utils] + [propeller.push.utils.helpers :refer [get-stack-instructions]] + [propeller.push.state :as state] + [propeller.tools.math :as math] + [propeller.gp :as gp])) + +; =========== PROBLEM DESCRIPTION =============================== +; GCD [GREATEST COMMON DIVISOR] from PSB2 +; Given two integers, return the largest integer that divides each +; of the integers evenly +; +; Source: https://arxiv.org/pdf/2106.06086.pdf +; ================================================================== + +(def train-and-test-data (psb2/fetch-examples "data" "gcd" 200 2000)) + +(defn random-int [] (- (rand-int 201) 100)) + +(defn map-vals-input + "Returns all the input values of a map" + [i] + (vals (select-keys i [:input1 :input2]))) + +(defn map-vals-output + "Returns the output values of a map" + [i] + (get i :output1)) + +(def instructions + (utils/not-lazy + (concat + ;;; stack-specific instructions + (get-stack-instructions #{:exec :integer :boolean :print}) + ;;; input instructions + (list :in1 :in2) + ;;; close + (list 'close) + ;;; ERCs (constants) + (list 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] (map-vals-output i)) 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)}) + (:step-limit argmap)) + :integer)) + inputs) + errors (map (fn [correct-output output] + (if (= output :no-stack-item) + 1000000.0 + (min 1000.0 (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 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))))) diff --git a/src/propeller/problems/PSB2/luhn.cljc b/src/propeller/problems/PSB2/luhn.cljc new file mode 100644 index 0000000..9c2c6fe --- /dev/null +++ b/src/propeller/problems/PSB2/luhn.cljc @@ -0,0 +1,84 @@ +(ns propeller.problems.PSB2.luhn + (:require [psb2.core :as psb2] + [propeller.genome :as genome] + [propeller.push.interpreter :as interpreter] + [propeller.utils :as utils] + [propeller.push.utils.helpers :refer [get-stack-instructions]] + [propeller.push.state :as state] + [propeller.tools.math :as math] + [propeller.gp :as gp])) + +; =========== PROBLEM DESCRIPTION ============================ +; LUHN from PSB2 +; Given a vector of 16 digits, implement Luhn’s +; algorithm to verify a credit card number, such that it follows +; the following rules: double every other digit starting with +; the second digit. If any of the results are over 9, subtract 9 +; from them. Return the sum of all of the new digits. +; +; Source: https://arxiv.org/pdf/2106.06086.pdf +; =============================================================== + +(def train-and-test-data (psb2/fetch-examples "data" "luhn" 200 2000)) + +; 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 0 2 9 10 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)) + :integer)) + inputs) + errors (map (fn [correct-output output] + (if (= output :no-stack-item) + 1000000 + (min 1000.0 (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 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))))) + + diff --git a/src/propeller/problems/PSB2/middle_character.cljc b/src/propeller/problems/PSB2/middle_character.cljc index de86325..55850a6 100644 --- a/src/propeller/problems/PSB2/middle_character.cljc +++ b/src/propeller/problems/PSB2/middle_character.cljc @@ -5,7 +5,6 @@ [propeller.utils :as utils] [propeller.push.utils.helpers :refer [get-stack-instructions]] [propeller.push.state :as state] - [propeller.tools.math :as math] [propeller.tools.metrics :as metrics] [propeller.gp :as gp] #?(:cljs [cljs.reader :refer [read-string]]))) @@ -74,13 +73,13 @@ :error-function error-function :training-data (:train train-and-test-data) :testing-data (:test train-and-test-data) - :max-generations 500 - :population-size 500 - :max-initial-plushy-size 100 - :step-limit 200 + :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 0.5 :crossover 0.5} + :variation {:umad 1.0 :crossover 0.0} :elitism false} (apply hash-map (map #(if (string? %) (read-string %) %) args))))) diff --git a/src/propeller/problems/PSB2/paired_digits.cljc b/src/propeller/problems/PSB2/paired_digits.cljc new file mode 100644 index 0000000..bcccf73 --- /dev/null +++ b/src/propeller/problems/PSB2/paired_digits.cljc @@ -0,0 +1,81 @@ +(ns propeller.problems.PSB2.paired-digits + (:require [psb2.core :as psb2] + [propeller.genome :as genome] + [propeller.push.interpreter :as interpreter] + [propeller.utils :as utils] + [propeller.push.utils.helpers :refer [get-stack-instructions]] + [propeller.push.state :as state] + [propeller.tools.math :as math] + [propeller.gp :as gp])) + +; =========== PROBLEM DESCRIPTION ============================= +; PAIRED DIGITS from PSB2 +; Given a string of digits, return the sum +; of the digits whose following digit is the same. +; +; Source: https://arxiv.org/pdf/2106.06086.pdf +; =============================================================== + +(def train-and-test-data (psb2/fetch-examples "data" "paired-digits" 200 2000)) + +(defn random-int [] (- (rand-int 201) 100)) + +(defn random-char [] (rand-nth '(\0 \1 \2 \3 \4 \5 \6 \7 \8 \9))) + +(def instructions + (utils/not-lazy + (concat + ;;; stack-specific instructions + (get-stack-instructions #{:exec :integer :boolean :char :string :print}) + ;;; input instructions + (list :in1) + ;;; close + (list 'close) + ;;; ERCs (constants) + (list 0 random-int random-char)))) + +(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 + (min 1000.0 (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 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))))) + diff --git a/src/propeller/problems/PSB2/shopping_list.cljc b/src/propeller/problems/PSB2/shopping_list.cljc new file mode 100644 index 0000000..e3120bd --- /dev/null +++ b/src/propeller/problems/PSB2/shopping_list.cljc @@ -0,0 +1,90 @@ +(ns propeller.problems.PSB2.shopping-list + (:require [psb2.core :as psb2] + [propeller.genome :as genome] + [propeller.push.interpreter :as interpreter] + [propeller.utils :as utils] + [propeller.push.utils.helpers :refer [get-stack-instructions]] + [propeller.push.state :as state] + [propeller.tools.math :as math] + [propeller.gp :as gp])) + +; =========== PROBLEM DESCRIPTION =============================== +; DICE GAME from PSB2 +; Peter has an n sided die and Colin has an m +; sided die. If they both roll their dice at the same time, return +; the probability that Peter rolls strictly higher than Colin. +; +; Source: https://arxiv.org/pdf/2106.06086.pdf +; ================================================================== + +(def train-and-test-data (psb2/fetch-examples "data" "shopping-list" 200 2000)) + +(defn random-float [] (- (rand 201) 100)) + +(defn map-vals-input + "Returns all the input values of a map" + [i] + (vals (select-keys i [:input1 :input2]))) + +(defn map-vals-output + "Returns the output values of a map " + [i] + (get i :output1)) + +(def instructions + (utils/not-lazy + (concat + ;;; stack-specific instructions + (get-stack-instructions #{:exec :integer :float :boolean :print}) + ;;; input instructions + (list :in1 :in2) + ;;; close + (list 'close) + ;;; ERCs (constants) + (list 0.0 100.0 random-float)))) + +(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] (map-vals-output i)) 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)}) + (:step-limit argmap)) + :float)) + inputs) + errors (map (fn [correct-output output] + (if (= output :no-stack-item) + 1000000.0 + (min 1000.0 (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 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))))) diff --git a/src/propeller/problems/PSB2/snow_day.cljc b/src/propeller/problems/PSB2/snow_day.cljc new file mode 100644 index 0000000..b68c886 --- /dev/null +++ b/src/propeller/problems/PSB2/snow_day.cljc @@ -0,0 +1,94 @@ +(ns propeller.problems.PSB2.snow-day + (:require [psb2.core :as psb2] + [propeller.genome :as genome] + [propeller.push.interpreter :as interpreter] + [propeller.utils :as utils] + [propeller.push.utils.helpers :refer [get-stack-instructions]] + [propeller.push.state :as state] + [propeller.tools.math :as math] + [propeller.gp :as gp])) + +; =========== PROBLEM DESCRIPTION =============================== +; SNOW DAY from PSB2 +; Given an integer representing a number +; of hours and 3 floats representing how much snow is on the +; ground, the rate of snow fall, and the proportion of snow +; melting per hour, return the amount of snow on the ground +; after the amount of hours given. Each hour is considered a +; discrete event of adding snow and then melting, not a continuous +; process. +; +; Source: https://arxiv.org/pdf/2106.06086.pdf +; ================================================================== + +(def train-and-test-data (psb2/fetch-examples "data" "snow-day" 200 2000)) + +(defn map-vals-input + "Returns all the input values of a map" + [i] + (vals (select-keys i [:input1 :input2 :input3 :input4]))) + +(defn map-vals-output + "Returns the output values of a map" + [i] + (get i :output1)) + +(def instructions + (utils/not-lazy + (concat + ;;; stack-specific instructions + (get-stack-instructions #{:exec :integer :float :boolean :print}) + ;;; input instructions + (list :in1 :in2 :in3 :in4) + ;;; close + (list 'close) + ;;; ERCs (constants) + (list 0 1 -1 0.0 1.0 -1.0)))) + +(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] (map-vals-output i)) 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)}) + (:step-limit argmap)) + :float)) + inputs) + errors (map (fn [correct-output output] + (if (= output :no-stack-item) + 1000000.0 + (min 1000.0 (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 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))))) diff --git a/src/propeller/problems/PSB2/solve_boolean.cljc b/src/propeller/problems/PSB2/solve_boolean.cljc new file mode 100644 index 0000000..42c29ea --- /dev/null +++ b/src/propeller/problems/PSB2/solve_boolean.cljc @@ -0,0 +1,83 @@ +(ns propeller.problems.PSB2.solve-boolean + (:require [psb2.core :as psb2] + [propeller.genome :as genome] + [propeller.push.interpreter :as interpreter] + [propeller.utils :as utils] + [propeller.push.utils.helpers :refer [get-stack-instructions]] + [propeller.push.state :as state] + [propeller.gp :as gp])) + +; =========== PROBLEM DESCRIPTION ================================ +; SOLVE BOOLEAN from PSB2 +; Given a string representing a Boolean +; expression consisting of T, F, |, and &, evaluate it and return +; the resulting Boolean. +; +; Source: https://arxiv.org/pdf/2106.06086.pdf +; ================================================================== + +(def train-and-test-data (psb2/fetch-examples "data" "solve-boolean" 200 2000)) + +(def instructions + (utils/not-lazy + (concat + ;;; stack-specific instructions + (get-stack-instructions #{:exec :integer :boolean :char :string :print}) + ;;; input instructions + (list :in1) + ;;; close + (list 'close) + ;;; ERCs (constants) + (list true false \t \f \& \|)))) + +(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)) + :boolean)) + inputs) + parsed-outputs (map (fn [output] + (try (read-string output) + #?(:clj (catch Exception e 1000.0) + :cljs (catch js/Error. e 1000.0)))) + outputs) + errors (map (fn [correct-output output] + (if (= output :no-stack-item) + 10000 + (if (= correct-output output) + 0 + 1))) + correct-outputs + parsed-outputs)] + (assoc individual + :behaviors parsed-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 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))))) diff --git a/src/propeller/problems/PSB2/spin_words.cljc b/src/propeller/problems/PSB2/spin_words.cljc new file mode 100644 index 0000000..c67328f --- /dev/null +++ b/src/propeller/problems/PSB2/spin_words.cljc @@ -0,0 +1,112 @@ +(ns propeller.problems.PSB2.spin-words + (:require [psb2.core :as psb2] + [propeller.genome :as genome] + [propeller.push.interpreter :as interpreter] + [propeller.utils :as utils] + [propeller.push.utils.helpers :refer [get-stack-instructions]] + [propeller.push.state :as state] + [propeller.tools.metrics :as metrics] + [propeller.gp :as gp])) + +; =========== PROBLEM DESCRIPTION ============================== +; SPIN WORDS from PSB2 +; Given a string of one or more words +; (separated by spaces), reverse all of the words that are five +; or more letters long and return the resulting string. +; +; Source: https://arxiv.org/pdf/2106.06086.pdf +; ================================================================ + +(def train-and-test-data (psb2/fetch-examples "data" "spin-words" 200 2000)) + +; Visible character ERC +(defn random-char + [] + (rand-nth (map char (range 97 122)))) + +; random word generator for ERC +; from https://github.com/thelmuth/Clojush/blob/psb2/src/clojush/problems/psb2/spin_words.clj +(defn word-generator + [] + (let [word-len (inc (rand-int (if (< (rand) 0.8) + 8 + 16)))] + (apply str (repeatedly word-len #(random-char))))) + +; String ERC; random word +; from https://github.com/thelmuth/Clojush/blob/psb2/src/clojush/problems/psb2/spin_words.clj +(defn random-input + "Makes a Spin Words input of length len, which is just a string of words, where the + words that are length 5 or greater are reversed" + [len] + (let [words (apply str + (take len ; This looks weird because str isn't lazy, so you + (apply str ; need to take len twice here. + (take len + (interpose " " (repeatedly word-generator))))))] + (if (not= (last words) \space) + words + (apply str (butlast words))))) + +(def instructions + (utils/not-lazy + (concat + ;;; stack-specific instructions + (get-stack-instructions #{:exec :integer :boolean :char :string :print}) + ;;; input instructions + (list :in1) + ;;; close + (list 'close) + ;;; ERCs (constants) + (list 4 5 \space random-char (fn [] (random-input (rand-int 21))))))) + +(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) + parsed-outputs (map (fn [output] + (try (read-string output) + #?(:clj (catch Exception e 1000.0) + :cljs (catch js/Error. e 1000.0)))) + outputs) + errors (map (fn [correct-output output] + (if (= output :no-stack-item) + 10000 + (metrics/levenshtein-distance correct-output output))) + correct-outputs + parsed-outputs)] + (assoc individual + :behaviors parsed-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 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))))) + diff --git a/src/propeller/problems/PSB2/square_digits.cljc b/src/propeller/problems/PSB2/square_digits.cljc new file mode 100644 index 0000000..bb242d4 --- /dev/null +++ b/src/propeller/problems/PSB2/square_digits.cljc @@ -0,0 +1,86 @@ +(ns propeller.problems.PSB2.square-digits + (:require [psb2.core :as psb2] + [propeller.genome :as genome] + [propeller.push.interpreter :as interpreter] + [propeller.utils :as utils] + [propeller.push.utils.helpers :refer [get-stack-instructions]] + [propeller.push.state :as state] + [propeller.tools.metrics :as metrics] + [propeller.gp :as gp])) + +; =========== PROBLEM DESCRIPTION ========================= +; SQUARE DIGITS from PSB2 +; Given a positive integer, square each +; digit and concatenate the squares into a returned string. +; +; Source: https://arxiv.org/pdf/2106.06086.pdf +; ============================================================ + +(def train-and-test-data (psb2/fetch-examples "data" "square-digits" 200 2000)) + +(defn random-int [] (- (rand-int 201) 100)) + +(def instructions + (utils/not-lazy + (concat + ;;; stack-specific instructions + (get-stack-instructions #{:exec :integer :boolean :char :string :print}) + ;;; input instructions + (list :in1) + ;;; close + (list 'close) + ;;; ERCs (constants) + (list "" 0 1 2 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) + parsed-outputs (map (fn [output] + (try (read-string output) + #?(:clj (catch Exception e 1000.0) + :cljs (catch js/Error. e 1000.0)))) + outputs) + errors (map (fn [correct-output output] + (if (= output :no-stack-item) + 10000 + (metrics/levenshtein-distance (str correct-output) (str output)))) + correct-outputs + parsed-outputs)] + (assoc individual + :behaviors parsed-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 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))))) + + diff --git a/src/propeller/problems/PSB2/substitution_cipher.cljc b/src/propeller/problems/PSB2/substitution_cipher.cljc index 9562a1c..13152c5 100644 --- a/src/propeller/problems/PSB2/substitution_cipher.cljc +++ b/src/propeller/problems/PSB2/substitution_cipher.cljc @@ -24,12 +24,12 @@ (def train-and-test-data (psb2/fetch-examples "data" "substitution-cipher" 200 2000)) (defn map-vals-input - "Returns all the input values of a map (specific helper method for substitution-cipher)" + "Returns all the input values of a map" [i] (vals (select-keys i [:input1 :input2 :input3]))) (defn map-vals-output - "Returns the output values of a map (specific helper method for substitution-cipher)" + "Returns the output values of a map" [i] (vals (select-keys i [:output1]))) @@ -86,13 +86,13 @@ :error-function error-function :training-data (:train train-and-test-data) :testing-data (:test train-and-test-data) - :max-generations 500 - :population-size 500 - :max-initial-plushy-size 100 - :step-limit 200 + :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 0.5 :crossover 0.5} + :variation {:umad 1.0 :crossover 0.0} :elitism false} (apply hash-map (map #(if (string? %) (read-string %) %) args))))) \ No newline at end of file diff --git a/src/propeller/problems/PSB2/twitter.cljc b/src/propeller/problems/PSB2/twitter.cljc index cd00b74..9c6acfa 100644 --- a/src/propeller/problems/PSB2/twitter.cljc +++ b/src/propeller/problems/PSB2/twitter.cljc @@ -77,13 +77,13 @@ :error-function error-function :training-data (:train train-and-test-data) :testing-data (:test train-and-test-data) - :max-generations 500 - :population-size 500 - :max-initial-plushy-size 100 - :step-limit 200 + :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 0.5 :crossover 0.5} + :variation {:umad 1.0 :crossover 0.0} :elitism false} (apply hash-map (map #(if (string? %) (read-string %) %) args))))) \ No newline at end of file