From 883840a564d2984e837d8d623dbc053449ff66ab Mon Sep 17 00:00:00 2001 From: Shuzo Katayama Date: Wed, 14 Jul 2021 14:55:23 -0400 Subject: [PATCH 1/7] fizz buzz, gcd, and luhn added --- .idea/misc.xml | 2 +- src/propeller/gp.cljc | 22 ++++--- src/propeller/problems/PSB2/basement.cljc | 1 - src/propeller/problems/PSB2/fizz_buzz.cljc | 70 ++++++++++++++++++++ src/propeller/problems/PSB2/gcd.cljc | 75 ++++++++++++++++++++++ src/propeller/problems/PSB2/luhn.cljc | 69 ++++++++++++++++++++ 6 files changed, 227 insertions(+), 12 deletions(-) create mode 100644 src/propeller/problems/PSB2/fizz_buzz.cljc create mode 100644 src/propeller/problems/PSB2/gcd.cljc create mode 100644 src/propeller/problems/PSB2/luhn.cljc diff --git a/.idea/misc.xml b/.idea/misc.xml index 97e4469..bce9de7 100644 --- a/.idea/misc.xml +++ b/.idea/misc.xml @@ -7,7 +7,7 @@ - + \ No newline at end of file diff --git a/src/propeller/gp.cljc b/src/propeller/gp.cljc index 1ad3f71..55b026d 100755 --- a/src/propeller/gp.cljc +++ b/src/propeller/gp.cljc @@ -16,18 +16,20 @@ "Reports information each generation." [pop generation argmap] (let [best (first pop)] - (clojure.pprint/pprint {:generation generation - :best-plushy (:plushy best) - :best-program (genome/plushy->push (:plushy best) argmap) - :best-total-error (:total-error best) - :best-errors (:errors best) - :best-behaviors (:behaviors best) - :genotypic-diversity (float (/ (count (distinct (map :plushy pop))) (count pop))) - :behavioral-diversity (float (/ (count (distinct (map :behaviors pop))) (count pop))) - :average-genome-length (float (/ (reduce + (map count (map :plushy pop))) (count pop))) - :average-total-error (float (/ (reduce + (map :total-error pop)) (count pop)))}) + (println {:generation generation + :best-plushy (:plushy best) + :best-program (genome/plushy->push (:plushy best) argmap) + :best-total-error (:total-error best) + :best-errors (:errors best) + :best-behaviors (:behaviors best) + :genotypic-diversity (float (/ (count (distinct (map :plushy pop))) (count pop))) + :behavioral-diversity (float (/ (count (distinct (map :behaviors pop))) (count pop))) + :average-genome-length (float (/ (reduce + (map count (map :plushy pop))) (count pop))) + :average-total-error (float (/ (reduce + (map :total-error pop)) (count pop)))}) (println))) +;; clojure.pprint/pprint + (defn gp "Main GP loop." [{:keys [population-size max-generations error-function instructions diff --git a/src/propeller/problems/PSB2/basement.cljc b/src/propeller/problems/PSB2/basement.cljc index 608d4f3..c89d2ab 100644 --- a/src/propeller/problems/PSB2/basement.cljc +++ b/src/propeller/problems/PSB2/basement.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])) ; =========== PROBLEM DESCRIPTION ============================ diff --git a/src/propeller/problems/PSB2/fizz_buzz.cljc b/src/propeller/problems/PSB2/fizz_buzz.cljc new file mode 100644 index 0000000..33cbb09 --- /dev/null +++ b/src/propeller/problems/PSB2/fizz_buzz.cljc @@ -0,0 +1,70 @@ +(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])) + +; =========== 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))))) + + +(def arglist + {:instructions instructions + :error-function error-function + :training-data (:train train-and-test-data) + :testing-data (:test train-and-test-data)}) + diff --git a/src/propeller/problems/PSB2/gcd.cljc b/src/propeller/problems/PSB2/gcd.cljc new file mode 100644 index 0000000..5830c20 --- /dev/null +++ b/src/propeller/problems/PSB2/gcd.cljc @@ -0,0 +1,75 @@ +(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])) + +; =========== 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 (specific helper method for bouncing-balls)" + [i] + (vals (select-keys i [:input1 :input2]))) + +(defn map-vals-output + "Returns the output values of a map (specific helper method for bouncing-balls)" + [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))))) + +(def arglist + {:instructions instructions + :error-function error-function + :training-data (:train train-and-test-data) + :testing-data (:test train-and-test-data)}) + diff --git a/src/propeller/problems/PSB2/luhn.cljc b/src/propeller/problems/PSB2/luhn.cljc new file mode 100644 index 0000000..009cf18 --- /dev/null +++ b/src/propeller/problems/PSB2/luhn.cljc @@ -0,0 +1,69 @@ +(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])) + +; =========== 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))))) + +(def arglist + {:instructions instructions + :error-function error-function + :training-data (:train train-and-test-data) + :testing-data (:test train-and-test-data)}) + + From a32b3263c55cefdad5bb303ff4e13e14c8ea3652 Mon Sep 17 00:00:00 2001 From: Shuzo Katayama Date: Wed, 14 Jul 2021 14:55:45 -0400 Subject: [PATCH 2/7] fizz buzz, gcd, and luhn added --- src/propeller/gp.cljc | 22 ++++++++++------------ 1 file changed, 10 insertions(+), 12 deletions(-) diff --git a/src/propeller/gp.cljc b/src/propeller/gp.cljc index 55b026d..1ad3f71 100755 --- a/src/propeller/gp.cljc +++ b/src/propeller/gp.cljc @@ -16,20 +16,18 @@ "Reports information each generation." [pop generation argmap] (let [best (first pop)] - (println {:generation generation - :best-plushy (:plushy best) - :best-program (genome/plushy->push (:plushy best) argmap) - :best-total-error (:total-error best) - :best-errors (:errors best) - :best-behaviors (:behaviors best) - :genotypic-diversity (float (/ (count (distinct (map :plushy pop))) (count pop))) - :behavioral-diversity (float (/ (count (distinct (map :behaviors pop))) (count pop))) - :average-genome-length (float (/ (reduce + (map count (map :plushy pop))) (count pop))) - :average-total-error (float (/ (reduce + (map :total-error pop)) (count pop)))}) + (clojure.pprint/pprint {:generation generation + :best-plushy (:plushy best) + :best-program (genome/plushy->push (:plushy best) argmap) + :best-total-error (:total-error best) + :best-errors (:errors best) + :best-behaviors (:behaviors best) + :genotypic-diversity (float (/ (count (distinct (map :plushy pop))) (count pop))) + :behavioral-diversity (float (/ (count (distinct (map :behaviors pop))) (count pop))) + :average-genome-length (float (/ (reduce + (map count (map :plushy pop))) (count pop))) + :average-total-error (float (/ (reduce + (map :total-error pop)) (count pop)))}) (println))) -;; clojure.pprint/pprint - (defn gp "Main GP loop." [{:keys [population-size max-generations error-function instructions From ede1abe7c4fb9bebc7f2ba558b9af8a03ef91792 Mon Sep 17 00:00:00 2001 From: Shuzo Katayama Date: Wed, 14 Jul 2021 16:42:20 -0400 Subject: [PATCH 3/7] paired digits, shopping list, snow day --- .../problems/PSB2/paired_digits.cljc | 66 ++++++++++++++++ .../problems/PSB2/shopping_list.cljc | 75 ++++++++++++++++++ src/propeller/problems/PSB2/snow_day.cljc | 79 +++++++++++++++++++ 3 files changed, 220 insertions(+) create mode 100644 src/propeller/problems/PSB2/paired_digits.cljc create mode 100644 src/propeller/problems/PSB2/shopping_list.cljc create mode 100644 src/propeller/problems/PSB2/snow_day.cljc diff --git a/src/propeller/problems/PSB2/paired_digits.cljc b/src/propeller/problems/PSB2/paired_digits.cljc new file mode 100644 index 0000000..531ad78 --- /dev/null +++ b/src/propeller/problems/PSB2/paired_digits.cljc @@ -0,0 +1,66 @@ +(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])) + +; =========== 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))))) + +(def arglist + {:instructions instructions + :error-function error-function + :training-data (:train train-and-test-data) + :testing-data (:test train-and-test-data)}) + diff --git a/src/propeller/problems/PSB2/shopping_list.cljc b/src/propeller/problems/PSB2/shopping_list.cljc new file mode 100644 index 0000000..b62cb81 --- /dev/null +++ b/src/propeller/problems/PSB2/shopping_list.cljc @@ -0,0 +1,75 @@ +(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])) + +; =========== 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 (specific helper method for bouncing-balls)" + [i] + (vals (select-keys i [:input1 :input2]))) + +(defn map-vals-output + "Returns the output values of a map (specific helper method for bouncing-balls)" + [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))))) + +(def arglist + {:instructions instructions + :error-function error-function + :training-data (:train train-and-test-data) + :testing-data (:test train-and-test-data)}) diff --git a/src/propeller/problems/PSB2/snow_day.cljc b/src/propeller/problems/PSB2/snow_day.cljc new file mode 100644 index 0000000..8bab057 --- /dev/null +++ b/src/propeller/problems/PSB2/snow_day.cljc @@ -0,0 +1,79 @@ +(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])) + +; =========== 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 (specific helper method for bouncing-balls)" + [i] + (vals (select-keys i [:input1 :input2 :input3 :input4]))) + +(defn map-vals-output + "Returns the output values of a map (specific helper method for bouncing-balls)" + [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))))) + +(def arglist + {:instructions instructions + :error-function error-function + :training-data (:train train-and-test-data) + :testing-data (:test train-and-test-data)}) From 8441cfe8d3a1443899da5665bdd7819f7b04fc46 Mon Sep 17 00:00:00 2001 From: Shuzo Katayama Date: Wed, 14 Jul 2021 21:25:42 -0400 Subject: [PATCH 4/7] upstream update and new PSB2 problems --- README.md | 64 ++++++++++++--- src/propeller/core.cljc | 34 ++------ src/propeller/problems/PSB2/basement.cljc | 27 +++++-- .../problems/PSB2/bouncing_balls.cljc | 27 +++++-- src/propeller/problems/PSB2/bowling.cljc | 27 +++++-- src/propeller/problems/PSB2/camel_case.cljc | 27 +++++-- src/propeller/problems/PSB2/dice_game.cljc | 27 +++++-- src/propeller/problems/PSB2/fuel_cost.cljc | 27 +++++-- .../problems/PSB2/middle_character.cljc | 27 +++++-- .../problems/PSB2/solve_boolean.cljc | 70 ++++++++++++++++ src/propeller/problems/PSB2/spin_words.cljc | 77 ++++++++++++++++++ .../problems/PSB2/substitution_cipher.cljc | 27 +++++-- src/propeller/problems/PSB2/twitter.cljc | 27 +++++-- src/propeller/problems/simple_regression.cljc | 27 +++++-- .../problems/software/number_io.cljc | 80 ++++++++++++------- src/propeller/problems/software/smallest.cljc | 80 ++++++++++++------- .../problems/string_classification.cljc | 27 +++++-- src/propeller/problems/valiant.cljc | 27 +++++-- 18 files changed, 557 insertions(+), 172 deletions(-) create mode 100644 src/propeller/problems/PSB2/solve_boolean.cljc create mode 100644 src/propeller/problems/PSB2/spin_words.cljc diff --git a/README.md b/README.md index 56511eb..6debf61 100644 --- a/README.md +++ b/README.md @@ -4,16 +4,62 @@ Yet another Push-based genetic programming system in Clojure. ## Usage -To run PushGP from a REPL, load propel.core into your REPL (i.e. `lein repl`), -and run `-main` with arguments including, first, the problem name, for example: -`(-main 'simple-regression)` or `(-main 'simple-regression :population-size 100)`. +If you have installed [leiningen](https://leiningen.org), which is a tool +for running Clojure programs, then you can run Propeller on a genetic +programming problem that is defined within this project from the command +line with the command `lein run -m `, replacing `` +with the actual namespace that you will find at the top of the problem file. + +For example, you can run the simple-regression genetic programming problem with: + +``` +lein run -m propeller.problems.simple-regression +``` + +Additional command-line arguments may +be provided to override the default key/value pairs specified in the +problem file, for example: + + +``` +lein run -m propeller.problems.simple-regression :population-size 100 +``` + +On Unix operating systems, including MacOS, you can use something +like the following to send output both to the terminal +and to a text file (called `outfile` in this example): + +``` +lein run -m propeller.problems.simple-regression | tee outfile +``` + +If you want to provide command line arguments that include +characters that may be interpreted by your command line shell +before they get to Clojure, then enclose those in double +quotes, like in this example that provides a non-default +value for the `:variation` argument, which is a clojure map +containing curly brackets that may confuse your shell: + +``` +lein run -m propeller.problems.simple-regression :variation "{:umad 1.0}" +``` + +To run a genetic programming problem from a REPL, start +your REPL for the project (e.g. with `lein repl` at the +command line when in the project directory, or through your +IDE) and then do something like the following (which in +this case runs the simple-regression problem with +`:population-size` 100): + +``` +(require 'propeller.problems.simple-regression) +(in-ns 'propeller.problems.simple-regression) +(-main :population-size 100 :variation {:umad 1.0}) +``` + +If you want to run the problem with the default parameters, +then you should call `-main` without arguments, as `(-main)`. -To run PushGP on the genetic programming problem p from the -command line, execute `lein run p`. For example `lein run simple-regression`. Additional command-line arguments may -be provided to override the default key/value pairs specified in `-main`, for -example, `lein run simple-regression :population-size 100`. You can use something -like `lein run simple-regression | tee outfile` to send output both to the terminal -and to `outfile`. ## CLJS Usage diff --git a/src/propeller/core.cljc b/src/propeller/core.cljc index f33c73b..0023a41 100755 --- a/src/propeller/core.cljc +++ b/src/propeller/core.cljc @@ -1,34 +1,10 @@ (ns propeller.core - #?(:clj (:gen-class)) - (:require [propeller.gp :as gp] - #?(:cljs [cljs.reader :refer [read-string]]))) - -(defn eval-problem-var - [problem-name var-name] - (eval (symbol (str "propeller.problems." problem-name "/" var-name)))) + #?(:clj (:gen-class))) (defn -main - "Runs propel-gp, giving it a map of arguments." + "Not intended to be run; just print a message." [& args] ;; Exception for when no args were passed - (when (empty? args) - (println "You must specify a problem to run.") - (println "Try, for example:") - (println " lein run software.smallest") - (System/exit 1)) - (require (symbol (str "propeller.problems." (first args)))) - (gp/gp - (merge - {: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} - (eval-problem-var (first args) "arglist") - (apply hash-map - (map #(if (and (string? %) (not (.contains % "/"))) (read-string %) %) - (rest args)))))) \ No newline at end of file + (println "To run a genetic programming problem, provide a the problem's") + (println "namespace as specified in the Propeller README file at") + (println "https://github.com/lspector/propeller/blob/master/README.md")) \ No newline at end of file diff --git a/src/propeller/problems/PSB2/basement.cljc b/src/propeller/problems/PSB2/basement.cljc index c89d2ab..9143c0e 100644 --- a/src/propeller/problems/PSB2/basement.cljc +++ b/src/propeller/problems/PSB2/basement.cljc @@ -5,7 +5,8 @@ [propeller.utils :as utils] [propeller.push.utils.helpers :refer [get-stack-instructions]] [propeller.push.state :as state] - [propeller.tools.math :as math])) + [propeller.tools.math :as math] + [propeller.gp :as gp])) ; =========== PROBLEM DESCRIPTION ============================ ; BASEMENT from PSB2 @@ -58,9 +59,23 @@ :total-error #?(:clj (apply +' errors) :cljs (apply + errors))))) -(def arglist - {:instructions instructions - :error-function error-function - :training-data (:train train-and-test-data) - :testing-data (:test train-and-test-data)}) +(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 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} + (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 1a4f053..0cab515 100644 --- a/src/propeller/problems/PSB2/bouncing_balls.cljc +++ b/src/propeller/problems/PSB2/bouncing_balls.cljc @@ -6,7 +6,8 @@ [propeller.push.utils.helpers :refer [get-stack-instructions]] [propeller.push.state :as state] [clojure.pprint :as pprint] - [propeller.tools.math :as math])) + [propeller.tools.math :as math] + [propeller.gp :as gp])) ; =========== PROBLEM DESCRIPTION =============================== ; BOUNCING BALLS from PSB2 @@ -70,8 +71,22 @@ :total-error #?(:clj (apply +' errors) :cljs (apply + errors))))) -(def arglist - {:instructions instructions - :error-function error-function - :training-data (:train train-and-test-data) - :testing-data (:test train-and-test-data)}) +(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 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} + (apply hash-map (map #(if (string? %) (read-string %) %) args))))) diff --git a/src/propeller/problems/PSB2/bowling.cljc b/src/propeller/problems/PSB2/bowling.cljc index f0cdbc9..6fd63b8 100644 --- a/src/propeller/problems/PSB2/bowling.cljc +++ b/src/propeller/problems/PSB2/bowling.cljc @@ -6,7 +6,8 @@ [propeller.push.utils.helpers :refer [get-stack-instructions]] [propeller.push.state :as state] [clojure.pprint :as pprint] - [propeller.tools.math :as math])) + [propeller.tools.math :as math] + [propeller.gp :as gp])) ; =========== PROBLEM DESCRIPTION ====================== ; BOWLING from PSB2 @@ -58,8 +59,22 @@ :total-error #?(:clj (apply +' errors) :cljs (apply + errors))))) -(def arglist - {:instructions instructions - :error-function error-function - :training-data (:train train-and-test-data) - :testing-data (:test train-and-test-data)}) \ No newline at end of file +(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 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} + (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 ac6a04d..3bc2447 100644 --- a/src/propeller/problems/PSB2/camel_case.cljc +++ b/src/propeller/problems/PSB2/camel_case.cljc @@ -6,7 +6,8 @@ [propeller.push.utils.helpers :refer [get-stack-instructions]] [propeller.push.state :as state] [propeller.tools.math :as math] - [propeller.tools.metrics :as metrics])) + [propeller.tools.metrics :as metrics] + [propeller.gp :as gp])) ; =========== PROBLEM DESCRIPTION ===================================== ; CAMEL CASE from PSB2 @@ -94,8 +95,22 @@ :total-error #?(:clj (apply +' errors) :cljs (apply + errors))))) -(def arglist - {:instructions instructions - :error-function error-function - :training-data (:train train-and-test-data) - :testing-data (:test train-and-test-data)}) +(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 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} + (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 3de73f9..db669b5 100644 --- a/src/propeller/problems/PSB2/dice_game.cljc +++ b/src/propeller/problems/PSB2/dice_game.cljc @@ -6,7 +6,8 @@ [propeller.push.utils.helpers :refer [get-stack-instructions]] [propeller.push.state :as state] [clojure.pprint :as pprint] - [propeller.tools.math :as math])) + [propeller.tools.math :as math] + [propeller.gp :as gp])) ; =========== PROBLEM DESCRIPTION =============================== ; DICE GAME from PSB2 @@ -67,8 +68,22 @@ :total-error #?(:clj (apply +' errors) :cljs (apply + errors))))) -(def arglist - {:instructions instructions - :error-function error-function - :training-data (:train train-and-test-data) - :testing-data (:test train-and-test-data)}) +(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 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} + (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 9769fff..0f1592a 100644 --- a/src/propeller/problems/PSB2/fuel_cost.cljc +++ b/src/propeller/problems/PSB2/fuel_cost.cljc @@ -6,7 +6,8 @@ [propeller.push.utils.helpers :refer [get-stack-instructions]] [propeller.push.state :as state] [clojure.pprint :as pprint] - [propeller.tools.math :as math])) + [propeller.tools.math :as math] + [propeller.gp :as gp])) ; =========== PROBLEM DESCRIPTION ========================= ; FUEL COST from PSB2 @@ -60,9 +61,23 @@ :total-error #?(:clj (apply +' errors) :cljs (apply + errors))))) -(def arglist - {:instructions instructions - :error-function error-function - :training-data (:train train-and-test-data) - :testing-data (:test train-and-test-data)}) +(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 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} + (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 d023e52..8b7e123 100644 --- a/src/propeller/problems/PSB2/middle_character.cljc +++ b/src/propeller/problems/PSB2/middle_character.cljc @@ -6,7 +6,8 @@ [propeller.push.utils.helpers :refer [get-stack-instructions]] [propeller.push.state :as state] [propeller.tools.math :as math] - [propeller.tools.metrics :as metrics])) + [propeller.tools.metrics :as metrics] + [propeller.gp :as gp])) ; =========== PROBLEM DESCRIPTION ============================= ; MIDDLE CHARACTER from PSB2 @@ -63,8 +64,22 @@ :total-error #?(:clj (apply +' errors) :cljs (apply + errors))))) -(def arglist - {:instructions instructions - :error-function error-function - :training-data (:train train-and-test-data) - :testing-data (:test train-and-test-data)}) +(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 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} + (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..f6fd5cc --- /dev/null +++ b/src/propeller/problems/PSB2/solve_boolean.cljc @@ -0,0 +1,70 @@ +(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.tools.metrics :as metrics])) + +; =========== 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))))) + +(def arglist + {:instructions instructions + :error-function error-function + :training-data (:train train-and-test-data) + :testing-data (:test train-and-test-data)}) + diff --git a/src/propeller/problems/PSB2/spin_words.cljc b/src/propeller/problems/PSB2/spin_words.cljc new file mode 100644 index 0000000..43b04a3 --- /dev/null +++ b/src/propeller/problems/PSB2/spin_words.cljc @@ -0,0 +1,77 @@ +(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])) + +; =========== 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)))) + +;; WORK ON THIS TOMORROW; +;; SPIN WORDS STRING ERC; + +(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 )))) + + +(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))))) + +(def arglist + {:instructions instructions + :error-function error-function + :training-data (:train train-and-test-data) + :testing-data (:test train-and-test-data)}) + diff --git a/src/propeller/problems/PSB2/substitution_cipher.cljc b/src/propeller/problems/PSB2/substitution_cipher.cljc index 4798660..554c203 100644 --- a/src/propeller/problems/PSB2/substitution_cipher.cljc +++ b/src/propeller/problems/PSB2/substitution_cipher.cljc @@ -6,7 +6,8 @@ [propeller.push.utils.helpers :refer [get-stack-instructions]] [propeller.push.state :as state] [propeller.tools.math :as math] - [propeller.tools.metrics :as metrics])) + [propeller.tools.metrics :as metrics] + [propeller.gp :as gp])) ; =========== PROBLEM DESCRIPTION ========================= ; SUBSTITUTION CIPHER from PSB2 @@ -75,8 +76,22 @@ :total-error #?(:clj (apply +' errors) :cljs (apply + errors))))) -(def arglist - {:instructions instructions - :error-function error-function - :training-data (:train train-and-test-data) - :testing-data (:test train-and-test-data)}) \ No newline at end of file +(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 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} + (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 1a386ec..bdf35f7 100644 --- a/src/propeller/problems/PSB2/twitter.cljc +++ b/src/propeller/problems/PSB2/twitter.cljc @@ -6,7 +6,8 @@ [propeller.push.utils.helpers :refer [get-stack-instructions]] [propeller.push.state :as state] [propeller.tools.math :as math] - [propeller.tools.metrics :as metrics])) + [propeller.tools.metrics :as metrics] + [propeller.gp :as gp])) ; =========== PROBLEM DESCRIPTION ============================= ; TWITTER from PSB2 @@ -66,8 +67,22 @@ :total-error #?(:clj (apply +' errors) :cljs (apply + errors))))) -(def arglist - {:instructions instructions - :error-function error-function - :training-data (:train train-and-test-data) - :testing-data (:test train-and-test-data)}) \ No newline at end of file +(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 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} + (apply hash-map (map #(if (string? %) (read-string %) %) args))))) \ No newline at end of file diff --git a/src/propeller/problems/simple_regression.cljc b/src/propeller/problems/simple_regression.cljc index 6bcde53..e0ed37d 100755 --- a/src/propeller/problems/simple_regression.cljc +++ b/src/propeller/problems/simple_regression.cljc @@ -2,7 +2,8 @@ (:require [propeller.genome :as genome] [propeller.push.interpreter :as interpreter] [propeller.push.state :as state] - [propeller.tools.math :as math])) + [propeller.tools.math :as math] + [propeller.gp :as gp])) (defn- target-function "Target function: f(x) = x^3 + x + 3" @@ -59,8 +60,22 @@ :total-error #?(:clj (apply +' errors) :cljs (apply + errors)))))) -(def arglist - {:instructions instructions - :error-function error-function - :training-data (:train train-and-test-data) - :testing-data (:test train-and-test-data)}) \ No newline at end of file +(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 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} + (apply hash-map (map #(if (string? %) (read-string %) %) args))))) \ No newline at end of file diff --git a/src/propeller/problems/software/number_io.cljc b/src/propeller/problems/software/number_io.cljc index afc449d..2acae61 100755 --- a/src/propeller/problems/software/number_io.cljc +++ b/src/propeller/problems/software/number_io.cljc @@ -6,6 +6,7 @@ [propeller.utils :as utils] [propeller.push.state :as state] [propeller.tools.math :as math] + [propeller.gp :as gp] #?(:cljs [cljs.reader :refer [read-string]]))) ;; ============================================================================= @@ -60,34 +61,51 @@ :test test-set})) (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 {:in1 (first input) - :in2 (last input)} - :output '("")) - (:step-limit argmap)) - :output)) - 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] - (min 1000.0 (math/abs (- correct-output output)))) - correct-outputs - parsed-outputs)] - (assoc individual - :behaviors parsed-outputs - :errors errors - :total-error #?(:clj (apply +' errors) - :cljs (apply + errors)))))) + [argmap data individual] + (let [program (genome/plushy->push (:plushy individual) argmap) + inputs (:inputs data) + correct-outputs (:outputs data) + outputs (map (fn [input] + (state/peek-stack + (interpreter/interpret-program + program + (assoc state/empty-state :input {:in1 (first input) + :in2 (last input)} + :output '("")) + (:step-limit argmap)) + :output)) + 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] + (min 1000.0 (math/abs (- 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 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} + (apply hash-map (map #(if (string? %) (read-string %) %) args))))) \ No newline at end of file diff --git a/src/propeller/problems/software/smallest.cljc b/src/propeller/problems/software/smallest.cljc index c48876b..a70ac59 100755 --- a/src/propeller/problems/software/smallest.cljc +++ b/src/propeller/problems/software/smallest.cljc @@ -5,6 +5,7 @@ [propeller.push.utils.helpers :refer [get-stack-instructions]] [propeller.utils :as utils] [propeller.push.state :as state] + [propeller.gp :as gp] #?(:cljs [cljs.reader :refer [read-string]]))) ;; ============================================================================= @@ -62,34 +63,51 @@ :test test-set})) (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 {:in1 (get input 0) - :in2 (get input 1) - :in3 (get input 2) - :in4 (get input 3)} - :output '("")) - (:step-limit argmap)) - :output)) - inputs) - errors (map (fn [correct-output output] - (let [parsed-output (try (read-string output) - #?(:clj (catch Exception e 1000.0) - :cljs (catch js/Error. e 1000.0)))] - (if (= correct-output parsed-output) 0 1))) - correct-outputs - outputs)] - (assoc individual - :behaviors outputs - :errors errors - :total-error #?(:clj (apply +' errors) - :cljs (apply + errors)))))) + [argmap data individual] + (let [program (genome/plushy->push (:plushy individual) argmap) + inputs (:inputs data) + correct-outputs (:outputs data) + outputs (map (fn [input] + (state/peek-stack + (interpreter/interpret-program + program + (assoc state/empty-state :input {:in1 (get input 0) + :in2 (get input 1) + :in3 (get input 2) + :in4 (get input 3)} + :output '("")) + (:step-limit argmap)) + :output)) + inputs) + errors (map (fn [correct-output output] + (let [parsed-output (try (read-string output) + #?(:clj (catch Exception e 1000.0) + :cljs (catch js/Error. e 1000.0)))] + (if (= correct-output parsed-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) + :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} + (apply hash-map (map #(if (string? %) (read-string %) %) args))))) \ No newline at end of file diff --git a/src/propeller/problems/string_classification.cljc b/src/propeller/problems/string_classification.cljc index aa49c16..a06490d 100755 --- a/src/propeller/problems/string_classification.cljc +++ b/src/propeller/problems/string_classification.cljc @@ -1,7 +1,8 @@ (ns propeller.problems.string-classification (:require [propeller.genome :as genome] [propeller.push.interpreter :as interpreter] - [propeller.push.state :as state])) + [propeller.push.state :as state] + [propeller.gp :as gp])) ;; ============================================================================= ;; String classification @@ -79,8 +80,22 @@ :total-error #?(:clj (apply +' errors) :cljs (apply + errors))))) -(def arglist - {:instructions instructions - :error-function error-function - :training-data (:train train-and-test-data) - :testing-data (:test train-and-test-data)}) \ No newline at end of file +(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 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} + (apply hash-map (map #(if (string? %) (read-string %) %) args))))) \ No newline at end of file diff --git a/src/propeller/problems/valiant.cljc b/src/propeller/problems/valiant.cljc index 7cfc407..a98410a 100644 --- a/src/propeller/problems/valiant.cljc +++ b/src/propeller/problems/valiant.cljc @@ -1,7 +1,8 @@ (ns propeller.problems.valiant (:require [propeller.genome :as genome] [propeller.push.interpreter :as interpreter] - [propeller.push.state :as state])) + [propeller.push.state :as state] + [propeller.gp :as gp])) (def num-vars 100) ;10) ;100) ;1000) (def num-inputs 50) ;5) ; 50) ;500) @@ -58,8 +59,22 @@ :total-error #?(:clj (apply +' errors) :cljs (apply + errors))))) -(def arglist - {:instructions instructions - :error-function error-function - :training-data (:train train-and-test-data) - :testing-data (:test train-and-test-data)}) +(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 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} + (apply hash-map (map #(if (string? %) (read-string %) %) args))))) From b92fa491258f56f493e1006e82bfc64709f7895d Mon Sep 17 00:00:00 2001 From: Shuzo Katayama Date: Wed, 14 Jul 2021 21:40:01 -0400 Subject: [PATCH 5/7] deleted idea files --- .idea/.gitignore | 2 -- .idea/ClojureProjectResolveSettings.xml | 6 ------ .idea/compiler.xml | 18 ------------------ .../Leiningen__clojure_complete_0_2_5.xml | 9 --------- .idea/libraries/Leiningen__nrepl_0_6_0.xml | 9 --------- .../Leiningen__org_clojure_clojure_1_10_0.xml | 9 --------- ...en__org_clojure_core_specs_alpha_0_2_44.xml | 9 --------- ...iningen__org_clojure_spec_alpha_0_2_176.xml | 9 --------- .idea/misc.xml | 13 ------------- .idea/modules.xml | 8 -------- .idea/vcs.xml | 6 ------ 11 files changed, 98 deletions(-) delete mode 100644 .idea/.gitignore delete mode 100644 .idea/ClojureProjectResolveSettings.xml delete mode 100644 .idea/compiler.xml delete mode 100644 .idea/libraries/Leiningen__clojure_complete_0_2_5.xml delete mode 100644 .idea/libraries/Leiningen__nrepl_0_6_0.xml delete mode 100644 .idea/libraries/Leiningen__org_clojure_clojure_1_10_0.xml delete mode 100644 .idea/libraries/Leiningen__org_clojure_core_specs_alpha_0_2_44.xml delete mode 100644 .idea/libraries/Leiningen__org_clojure_spec_alpha_0_2_176.xml delete mode 100644 .idea/misc.xml delete mode 100644 .idea/modules.xml delete mode 100644 .idea/vcs.xml diff --git a/.idea/.gitignore b/.idea/.gitignore deleted file mode 100644 index 5c98b42..0000000 --- a/.idea/.gitignore +++ /dev/null @@ -1,2 +0,0 @@ -# Default ignored files -/workspace.xml \ No newline at end of file diff --git a/.idea/ClojureProjectResolveSettings.xml b/.idea/ClojureProjectResolveSettings.xml deleted file mode 100644 index df470b1..0000000 --- a/.idea/ClojureProjectResolveSettings.xml +++ /dev/null @@ -1,6 +0,0 @@ - - - - IDE - - \ No newline at end of file diff --git a/.idea/compiler.xml b/.idea/compiler.xml deleted file mode 100644 index 9deeaef..0000000 --- a/.idea/compiler.xml +++ /dev/null @@ -1,18 +0,0 @@ - - - - - - - - - - - - - - - - - - \ No newline at end of file diff --git a/.idea/libraries/Leiningen__clojure_complete_0_2_5.xml b/.idea/libraries/Leiningen__clojure_complete_0_2_5.xml deleted file mode 100644 index c6f5338..0000000 --- a/.idea/libraries/Leiningen__clojure_complete_0_2_5.xml +++ /dev/null @@ -1,9 +0,0 @@ - - - - - - - - - \ No newline at end of file diff --git a/.idea/libraries/Leiningen__nrepl_0_6_0.xml b/.idea/libraries/Leiningen__nrepl_0_6_0.xml deleted file mode 100644 index 5997b74..0000000 --- a/.idea/libraries/Leiningen__nrepl_0_6_0.xml +++ /dev/null @@ -1,9 +0,0 @@ - - - - - - - - - \ No newline at end of file diff --git a/.idea/libraries/Leiningen__org_clojure_clojure_1_10_0.xml b/.idea/libraries/Leiningen__org_clojure_clojure_1_10_0.xml deleted file mode 100644 index 513d335..0000000 --- a/.idea/libraries/Leiningen__org_clojure_clojure_1_10_0.xml +++ /dev/null @@ -1,9 +0,0 @@ - - - - - - - - - \ No newline at end of file diff --git a/.idea/libraries/Leiningen__org_clojure_core_specs_alpha_0_2_44.xml b/.idea/libraries/Leiningen__org_clojure_core_specs_alpha_0_2_44.xml deleted file mode 100644 index 0c20df3..0000000 --- a/.idea/libraries/Leiningen__org_clojure_core_specs_alpha_0_2_44.xml +++ /dev/null @@ -1,9 +0,0 @@ - - - - - - - - - \ No newline at end of file diff --git a/.idea/libraries/Leiningen__org_clojure_spec_alpha_0_2_176.xml b/.idea/libraries/Leiningen__org_clojure_spec_alpha_0_2_176.xml deleted file mode 100644 index 31c7656..0000000 --- a/.idea/libraries/Leiningen__org_clojure_spec_alpha_0_2_176.xml +++ /dev/null @@ -1,9 +0,0 @@ - - - - - - - - - \ No newline at end of file diff --git a/.idea/misc.xml b/.idea/misc.xml deleted file mode 100644 index bce9de7..0000000 --- a/.idea/misc.xml +++ /dev/null @@ -1,13 +0,0 @@ - - - - - - - - - \ No newline at end of file diff --git a/.idea/modules.xml b/.idea/modules.xml deleted file mode 100644 index acfd354..0000000 --- a/.idea/modules.xml +++ /dev/null @@ -1,8 +0,0 @@ - - - - - - - - \ No newline at end of file diff --git a/.idea/vcs.xml b/.idea/vcs.xml deleted file mode 100644 index 94a25f7..0000000 --- a/.idea/vcs.xml +++ /dev/null @@ -1,6 +0,0 @@ - - - - - - \ No newline at end of file From 8280c3c6d2689ae8c7e6faf1d80316be3eba7854 Mon Sep 17 00:00:00 2001 From: Shuzo Katayama <62683709+DuckNoodleSoup@users.noreply.github.com> Date: Wed, 14 Jul 2021 21:48:03 -0400 Subject: [PATCH 6/7] temporarily remove spin words I forgot to ignore this work in progress file from the last commit --- src/propeller/problems/PSB2/spin_words.cljc | 77 --------------------- 1 file changed, 77 deletions(-) delete mode 100644 src/propeller/problems/PSB2/spin_words.cljc diff --git a/src/propeller/problems/PSB2/spin_words.cljc b/src/propeller/problems/PSB2/spin_words.cljc deleted file mode 100644 index 43b04a3..0000000 --- a/src/propeller/problems/PSB2/spin_words.cljc +++ /dev/null @@ -1,77 +0,0 @@ -(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])) - -; =========== 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)))) - -;; WORK ON THIS TOMORROW; -;; SPIN WORDS STRING ERC; - -(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 )))) - - -(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))))) - -(def arglist - {:instructions instructions - :error-function error-function - :training-data (:train train-and-test-data) - :testing-data (:test train-and-test-data)}) - From 105e8faf4efc7c4e4829f45379532b3d913d4af7 Mon Sep 17 00:00:00 2001 From: Shuzo Katayama Date: Thu, 15 Jul 2021 11:37:43 -0400 Subject: [PATCH 7/7] single output PSB2 problems --- src/propeller/problems/PSB2/basement.cljc | 10 +-- .../problems/PSB2/bouncing_balls.cljc | 12 +-- src/propeller/problems/PSB2/bowling.cljc | 11 ++- src/propeller/problems/PSB2/camel_case.cljc | 11 ++- src/propeller/problems/PSB2/dice_game.cljc | 15 ++-- src/propeller/problems/PSB2/fizz_buzz.cljc | 27 ++++-- src/propeller/problems/PSB2/fuel_cost.cljc | 11 ++- src/propeller/problems/PSB2/gcd.cljc | 32 +++++-- src/propeller/problems/PSB2/luhn.cljc | 27 ++++-- .../problems/PSB2/middle_character.cljc | 11 ++- .../problems/PSB2/paired_digits.cljc | 27 ++++-- .../problems/PSB2/shopping_list.cljc | 31 +++++-- src/propeller/problems/PSB2/snow_day.cljc | 31 +++++-- .../problems/PSB2/solve_boolean.cljc | 27 ++++-- src/propeller/problems/PSB2/spin_words.cljc | 55 +++++++++--- .../problems/PSB2/square_digits.cljc | 86 +++++++++++++++++++ .../problems/PSB2/substitution_cipher.cljc | 14 +-- src/propeller/problems/PSB2/twitter.cljc | 10 +-- 18 files changed, 333 insertions(+), 115 deletions(-) create mode 100644 src/propeller/problems/PSB2/square_digits.cljc diff --git a/src/propeller/problems/PSB2/basement.cljc b/src/propeller/problems/PSB2/basement.cljc index 9143c0e..e7598eb 100644 --- a/src/propeller/problems/PSB2/basement.cljc +++ b/src/propeller/problems/PSB2/basement.cljc @@ -68,14 +68,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 0cab515..6625385 100644 --- a/src/propeller/problems/PSB2/bouncing_balls.cljc +++ b/src/propeller/problems/PSB2/bouncing_balls.cljc @@ -80,13 +80,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 6fd63b8..6c80629 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])) @@ -68,13 +67,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 3bc2447..08610b1 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])) @@ -104,13 +103,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 db669b5..96bed0f 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])) @@ -21,12 +20,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)) @@ -77,13 +76,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 index 33cbb09..3397851 100644 --- a/src/propeller/problems/PSB2/fizz_buzz.cljc +++ b/src/propeller/problems/PSB2/fizz_buzz.cljc @@ -5,7 +5,8 @@ [propeller.utils :as utils] [propeller.push.utils.helpers :refer [get-stack-instructions]] [propeller.push.state :as state] - [propeller.tools.metrics :as metrics])) + [propeller.tools.metrics :as metrics] + [propeller.gp :as gp])) ; =========== PROBLEM DESCRIPTION ========================= ; FIZZ BUZZ from PSB2 @@ -62,9 +63,23 @@ :cljs (apply + errors))))) -(def arglist - {:instructions instructions - :error-function error-function - :training-data (:train train-and-test-data) - :testing-data (:test train-and-test-data)}) +(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 0f1592a..dbd39af 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])) @@ -70,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/gcd.cljc b/src/propeller/problems/PSB2/gcd.cljc index 5830c20..079cfd3 100644 --- a/src/propeller/problems/PSB2/gcd.cljc +++ b/src/propeller/problems/PSB2/gcd.cljc @@ -5,7 +5,8 @@ [propeller.utils :as utils] [propeller.push.utils.helpers :refer [get-stack-instructions]] [propeller.push.state :as state] - [propeller.tools.math :as math])) + [propeller.tools.math :as math] + [propeller.gp :as gp])) ; =========== PROBLEM DESCRIPTION =============================== ; GCD [GREATEST COMMON DIVISOR] from PSB2 @@ -20,12 +21,12 @@ (defn random-int [] (- (rand-int 201) 100)) (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)) @@ -67,9 +68,22 @@ :total-error #?(:clj (apply +' errors) :cljs (apply + errors))))) -(def arglist - {:instructions instructions - :error-function error-function - :training-data (:train train-and-test-data) - :testing-data (:test train-and-test-data)}) - +(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 index 009cf18..9c2c6fe 100644 --- a/src/propeller/problems/PSB2/luhn.cljc +++ b/src/propeller/problems/PSB2/luhn.cljc @@ -5,7 +5,8 @@ [propeller.utils :as utils] [propeller.push.utils.helpers :refer [get-stack-instructions]] [propeller.push.state :as state] - [propeller.tools.math :as math])) + [propeller.tools.math :as math] + [propeller.gp :as gp])) ; =========== PROBLEM DESCRIPTION ============================ ; LUHN from PSB2 @@ -60,10 +61,24 @@ :total-error #?(:clj (apply +' errors) :cljs (apply + errors))))) -(def arglist - {:instructions instructions - :error-function error-function - :training-data (:train train-and-test-data) - :testing-data (:test train-and-test-data)}) +(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 8b7e123..f4d4a31 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])) @@ -73,13 +72,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 index 531ad78..bcccf73 100644 --- a/src/propeller/problems/PSB2/paired_digits.cljc +++ b/src/propeller/problems/PSB2/paired_digits.cljc @@ -5,7 +5,8 @@ [propeller.utils :as utils] [propeller.push.utils.helpers :refer [get-stack-instructions]] [propeller.push.state :as state] - [propeller.tools.math :as math])) + [propeller.tools.math :as math] + [propeller.gp :as gp])) ; =========== PROBLEM DESCRIPTION ============================= ; PAIRED DIGITS from PSB2 @@ -58,9 +59,23 @@ :total-error #?(:clj (apply +' errors) :cljs (apply + errors))))) -(def arglist - {:instructions instructions - :error-function error-function - :training-data (:train train-and-test-data) - :testing-data (:test train-and-test-data)}) +(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 index b62cb81..e3120bd 100644 --- a/src/propeller/problems/PSB2/shopping_list.cljc +++ b/src/propeller/problems/PSB2/shopping_list.cljc @@ -5,7 +5,8 @@ [propeller.utils :as utils] [propeller.push.utils.helpers :refer [get-stack-instructions]] [propeller.push.state :as state] - [propeller.tools.math :as math])) + [propeller.tools.math :as math] + [propeller.gp :as gp])) ; =========== PROBLEM DESCRIPTION =============================== ; DICE GAME from PSB2 @@ -21,12 +22,12 @@ (defn random-float [] (- (rand 201) 100)) (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)) @@ -68,8 +69,22 @@ :total-error #?(:clj (apply +' errors) :cljs (apply + errors))))) -(def arglist - {:instructions instructions - :error-function error-function - :training-data (:train train-and-test-data) - :testing-data (:test train-and-test-data)}) +(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 index 8bab057..b68c886 100644 --- a/src/propeller/problems/PSB2/snow_day.cljc +++ b/src/propeller/problems/PSB2/snow_day.cljc @@ -5,7 +5,8 @@ [propeller.utils :as utils] [propeller.push.utils.helpers :refer [get-stack-instructions]] [propeller.push.state :as state] - [propeller.tools.math :as math])) + [propeller.tools.math :as math] + [propeller.gp :as gp])) ; =========== PROBLEM DESCRIPTION =============================== ; SNOW DAY from PSB2 @@ -23,12 +24,12 @@ (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 (specific helper method for bouncing-balls)" + "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 (specific helper method for bouncing-balls)" + "Returns the output values of a map" [i] (get i :output1)) @@ -72,8 +73,22 @@ :total-error #?(:clj (apply +' errors) :cljs (apply + errors))))) -(def arglist - {:instructions instructions - :error-function error-function - :training-data (:train train-and-test-data) - :testing-data (:test train-and-test-data)}) +(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 index f6fd5cc..42c29ea 100644 --- a/src/propeller/problems/PSB2/solve_boolean.cljc +++ b/src/propeller/problems/PSB2/solve_boolean.cljc @@ -5,7 +5,7 @@ [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 ================================ ; SOLVE BOOLEAN from PSB2 @@ -62,9 +62,22 @@ :total-error #?(:clj (apply +' errors) :cljs (apply + errors))))) -(def arglist - {:instructions instructions - :error-function error-function - :training-data (:train train-and-test-data) - :testing-data (:test train-and-test-data)}) - +(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 index 43b04a3..c67328f 100644 --- a/src/propeller/problems/PSB2/spin_words.cljc +++ b/src/propeller/problems/PSB2/spin_words.cljc @@ -5,7 +5,8 @@ [propeller.utils :as utils] [propeller.push.utils.helpers :refer [get-stack-instructions]] [propeller.push.state :as state] - [propeller.tools.metrics :as metrics])) + [propeller.tools.metrics :as metrics] + [propeller.gp :as gp])) ; =========== PROBLEM DESCRIPTION ============================== ; SPIN WORDS from PSB2 @@ -23,8 +24,29 @@ [] (rand-nth (map char (range 97 122)))) -;; WORK ON THIS TOMORROW; -;; SPIN WORDS STRING ERC; +; 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 @@ -36,8 +58,7 @@ ;;; close (list 'close) ;;; ERCs (constants) - (list 4 5 \space random-char )))) - + (list 4 5 \space random-char (fn [] (random-input (rand-int 21))))))) (defn error-function [argmap data individual] @@ -69,9 +90,23 @@ :total-error #?(:clj (apply +' errors) :cljs (apply + errors))))) -(def arglist - {:instructions instructions - :error-function error-function - :training-data (:train train-and-test-data) - :testing-data (:test train-and-test-data)}) +(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 554c203..22ec93c 100644 --- a/src/propeller/problems/PSB2/substitution_cipher.cljc +++ b/src/propeller/problems/PSB2/substitution_cipher.cljc @@ -23,12 +23,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]))) @@ -85,13 +85,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 bdf35f7..7b85fc2 100644 --- a/src/propeller/problems/PSB2/twitter.cljc +++ b/src/propeller/problems/PSB2/twitter.cljc @@ -76,13 +76,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