Merge pull request #55 from ryanboldi/more-problems

Added ryan's propeller problems
This commit is contained in:
Lee Spector 2023-02-17 12:10:19 -05:00 committed by GitHub
commit 75aeeb0914
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
8 changed files with 738 additions and 0 deletions

View File

@ -0,0 +1,77 @@
(ns propeller.problems.PSB1.count-odds
(:require [psb2.core :as psb2]
[propeller.genome :as genome]
[propeller.push.interpreter :as interpreter]
[propeller.problems.data-creation :as dc]
[propeller.utils :as utils]
[propeller.push.instructions :refer [get-stack-instructions]]
[propeller.push.state :as state]
[propeller.tools.math :as math]
[propeller.gp :as gp]
#?(:cljs [cljs.reader :refer [read-string]])))
(def train-and-test-data (psb2/fetch-examples "data" "count-odds" 200 2000))
(def train-data (:train train-and-test-data))
(def test-data (:test train-and-test-data))
; Random integer between -100 and 100 (from smallest)
(defn random-int [] (- (rand-int 201) 100))
(def instructions
(utils/not-lazy
(concat
;;; stack-specific instructions
(get-stack-instructions #{:exec :integer :boolean :vector_integer :print})
;;; input instructions
(list :in1)
;;; close
(list 'close)
;;; ERCs (constants)
(list random-int 0 1 2))))
(defn error-function
[argmap data individual]
(let [program (genome/plushy->push (:plushy individual) argmap)
inputs (map (fn [i] (get i :input1)) data)
correct-outputs (map (fn [i] (get i :output1)) data)
outputs (map (fn [input]
(state/peek-stack
(interpreter/interpret-program
program
(assoc state/empty-state :input {:in1 input})
(:step-limit argmap))
:integer))
inputs)
errors (map (fn [correct-output output]
(if (= output :no-stack-item)
1000000
(math/abs (- correct-output output))))
correct-outputs
outputs)]
(assoc individual
:behaviors outputs
:errors errors
:total-error #?(:clj (apply +' errors)
:cljs (apply + errors)))))
(defn -main
"Runs propel-gp, giving it a map of arguments."
[& args]
(gp/gp
(merge
{:instructions instructions
:error-function error-function
:training-data train-data
:testing-data test-data
:max-generations 300
:population-size 1000
:max-initial-plushy-size 250
:step-limit 2000
:parent-selection :lexicase
:tournament-size 5
:umad-rate 0.1
:variation {:umad 1.0 :crossover 0.0}
:elitism false}
(apply hash-map (map #(if (string? %) (read-string %) %) args))))
(#?(:clj shutdown-agents)))

View File

@ -0,0 +1,95 @@
(ns propeller.problems.PSB1.grade
(:require
[psb2.core :as psb2]
[propeller.genome :as genome]
[propeller.push.interpreter :as interpreter]
[propeller.problems.data-creation :as dc]
[propeller.push.state :as state]
[propeller.push.instructions :refer [get-stack-instructions]]
[propeller.utils :as utils]
[propeller.tools.metrics :as metrics]
[propeller.gp :as gp]
#?(:cljs [cljs.reader :refer [read-string]])))
; Based on the grade PSB1 problem, this verion only requires an output of a single character
;"“Student has a ”, “ grade.”, “A”, “B”, “C”, “D”, “F”, integer ERC"
(def train-and-test-data (psb2/fetch-examples "data" "grade" 200 2000))
(def train-data (:train train-and-test-data))
(def test-data (:test train-and-test-data))
(defn map-vals-input
"Returns all the input values of a map"
[i]
(vals (select-keys i [:input1 :input2 :input3 :input4 :input5])))
(defn get-output
"returns the outputs of the grade function with JUST the letter grade"
[i]
(str (nth i 14)))
; Random integer between -100 and 100
(defn random-int [] (- (rand-int 201) 100))
(def instructions
(utils/not-lazy
(concat
;; stack-specific instructions
(get-stack-instructions #{:boolean :exec :integer :string :print})
;; input instructions
(list :in1 :in2 :in3 :in4 :in5)
;;close
(list 'close)
;; ERCs (constants)
(list "A" "B" "C" "D" "F" random-int))))
(defn error-function
[argmap data individual]
(let [program (genome/plushy->push (:plushy individual) argmap)
inputs (map (fn [i] (map-vals-input i)) data)
correct-outputs (map (fn [i] (get-output (get i :output1))) data)
outputs (map (fn [input]
(state/peek-stack
(interpreter/interpret-program
program
(assoc state/empty-state :input {:in1 (nth input 0)
:in2 (nth input 1)
:in3 (nth input 2)
:in4 (nth input 3)
:in5 (nth input 4)})
(:step-limit argmap))
:print))
inputs)
errors (map (fn [correct-output output]
(if (= output :no-stack-item)
1000000.0
(metrics/levenshtein-distance correct-output output)))
correct-outputs
outputs)]
(assoc individual
:behaviors outputs
:errors errors
:total-error #?(:clj (apply +' errors)
:cljs (apply + errors)))))
(defn -main
"Runs propel-gp, giving it a map of arguments."
[& args]
(gp/gp
(merge
{:instructions instructions
:error-function error-function
:training-data train-data
:testing-data test-data
:max-generations 300
:population-size 1000
:max-initial-plushy-size 250
:step-limit 2000
:parent-selection :lexicase
:tournament-size 5
:umad-rate 0.1
:variation {:umad 1.0 :crossover 0.0}
:elitism false}
(apply hash-map (map #(if (string? %) (read-string %) %) args))))
(#?(:clj shutdown-agents)))

View File

@ -0,0 +1,146 @@
(ns propeller.problems.PSB1.scrabble-score
(:require [psb2.core :as psb2]
[propeller.genome :as genome]
[propeller.push.interpreter :as interpreter]
[clojure.string :as string]
[propeller.tools.math :as math]
[propeller.problems.data-creation :as dc]
[propeller.utils :as utils]
[propeller.push.instructions :refer [get-stack-instructions]]
[propeller.push.state :as state]
[propeller.tools.metrics :as metrics]
[propeller.gp :as gp]
#?(:cljs [cljs.reader :refer [read-string]])))
(def train-and-test-data (psb2/fetch-examples "data" "scrabble-score" 200 2000))
(def train-data (:train train-and-test-data))
(def test-data (:test train-and-test-data))
(def scrabble-letter-values
(let [scrabble-map {\a 1
\b 3
\c 3
\d 2
\e 1
\f 4
\g 2
\h 4
\i 1
\j 8
\k 5
\l 1
\m 3
\n 1
\o 1
\p 3
\q 10
\r 1
\s 1
\t 1
\u 1
\v 4
\w 4
\x 8
\y 4
\z 10}
visible-chars (map char (range 0 127))]
(vec (for [c visible-chars]
(get scrabble-map (first (string/lower-case c)) 0)))))
;; scrabble-letter-values
;; (def program '(0 :in1 :string_iterate (:integer_from_char [0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 1 3 3 2 1 4 2 4 1 8 5 1 3 1 1 3 10 1 1 1 1 4 4 8 4 10 0 0 0 0 0 0 1 3 3 2 1 4 2 4 1 8 5 1 3 1 1 3 10 1 1 1 1 4 4 8 4 10 0 0 0 0] :vector_integer_nth :integer_add)))
;; (def inputs (map (fn [i] (get i :input1)) test-data))
;; test-data
;; (def correct-outputs (map (fn [i] (get i :output1)) test-data))
;; correct-outputs
;; inputs
;; (def outputs (map (fn [input]
;; (state/peek-stack
;; (interpreter/interpret-program
;; program
;; (assoc state/empty-state :input {:in1 input})
;; 200)
;; :integer))
;; inputs))
;; outputs
;; correct-outputs
;; (def errors (map (fn [correct-output output]
;; (if (= output :no-stack-item)
;; 1000000
;; (math/abs (- correct-output output))))
;; correct-outputs
;; outputs))
;; (apply + errors)
;; (defn index-of [item coll]
;; (count (take-while (partial not= item) coll)))
;; (index-of 1 errors)
;; (nth inputs 647)
;; (nth outputs 647)
;; (nth correct-outputs 647)
(def instructions
(utils/not-lazy
(concat
;;; stack-specific instructions
(get-stack-instructions #{:exec :integer :boolean :char :vector_integer :string})
;;; input instructions
(list :in1)
;;; close
(list 'close)
;;; ERCs (constants)
(list scrabble-letter-values))))
(defn error-function
[argmap data individual]
(let [program (genome/plushy->push (:plushy individual) argmap)
inputs (map (fn [i] (get i :input1)) data)
correct-outputs (map (fn [i] (get i :output1)) data)
outputs (map (fn [input]
(state/peek-stack
(interpreter/interpret-program
program
(assoc state/empty-state :input {:in1 input})
(:step-limit argmap))
:integer))
inputs)
errors (map (fn [correct-output output]
(if (= output :no-stack-item)
1000000
(math/abs (- correct-output output))))
correct-outputs
outputs)]
(assoc individual
:behaviors outputs
:errors errors
:total-error #?(:clj (apply +' errors)
:cljs (apply + errors)))))
(defn -main
"Runs propel-gp, giving it a map of arguments."
[& args]
(gp/gp
(merge
{:instructions instructions
:error-function error-function
:training-data train-data
:testing-data test-data
:max-generations 300
:population-size 1000
:max-initial-plushy-size 250
:step-limit 2000
:parent-selection :lexicase
:tournament-size 5
:umad-rate 0.1
:variation {:umad 1.0 :crossover 0.0}
:elitism false}
(apply hash-map (map #(if (string? %) (read-string %) %) args))))
(#?(:clj shutdown-agents)))

View File

@ -0,0 +1,78 @@
(ns propeller.problems.PSB1.small-or-large
(:require [psb2.core :as psb2]
[propeller.genome :as genome]
[propeller.push.interpreter :as interpreter]
[propeller.problems.data-creation :as dc]
[propeller.utils :as utils]
[propeller.push.instructions :refer [get-stack-instructions]]
[propeller.push.state :as state]
[propeller.tools.metrics :as metrics]
[propeller.gp :as gp]
#?(:cljs [cljs.reader :refer [read-string]])))
(def train-and-test-data (psb2/fetch-examples "data" "small-or-large" 200 2000))
(def train-data (:train train-and-test-data))
(def test-data (:test train-and-test-data))
; Random integer between -100 and 100
(defn random-int [] (- (rand-int 201) 100))
(def instructions
(utils/not-lazy
(concat
;;; stack-specific instructions
(get-stack-instructions #{:exec :integer :boolean :string :print})
;;; input instructions
(list :in1)
;;; close
(list 'close)
;;; ERCs (constants)
(list "" "small" "large" random-int))))
(defn error-function
[argmap data individual]
(let [program (genome/plushy->push (:plushy individual) argmap)
inputs (map (fn [i] (get i :input1)) data)
correct-outputs (map (fn [i] (get i :output1)) data)
outputs (map (fn [input]
(state/peek-stack
(interpreter/interpret-program
program
(assoc state/empty-state :input {:in1 input})
(:step-limit argmap))
:string))
inputs)
errors (map (fn [correct-output output]
(if (= output :no-stack-item)
10000
(metrics/levenshtein-distance correct-output output)))
correct-outputs
outputs)]
(assoc individual
:behaviors outputs
:errors errors
:total-error #?(:clj (apply +' errors)
:cljs (apply + errors)))))
(defn -main
"Runs propel-gp, giving it a map of arguments."
[& args]
(gp/gp
(merge
{:instructions instructions
:error-function error-function
:training-data train-data
:testing-data test-data
:max-generations 300
:population-size 1000
:max-initial-plushy-size 250
:step-limit 2000
:parent-selection :lexicase
:tournament-size 5
:umad-rate 0.1
:variation {:umad 1.0 :crossover 0.0}
:elitism false}
(apply hash-map (map #(if (string? %) (read-string %) %) args))))
(#?(:clj shutdown-agents)))

View File

@ -0,0 +1,81 @@
(ns propeller.problems.complex-regression
(:require [propeller.genome :as genome]
[propeller.push.interpreter :as interpreter]
[propeller.push.state :as state]
[propeller.tools.math :as math]
[propeller.gp :as gp]
#?(:cljs [cljs.reader :refer [read-string]])))
(defn- target-function
"Target function: f(x) = (x^3 + 1)^3 + 1"
[x]
(let [x-new (+ (* x x x) 1)]
(+ (* x-new x-new x-new) 1)))
(def train-and-test-data
(let [train-inputs (range -4.0 4.0 0.25)
test-inputs (range -4.125 4.125 0.25)]
{:train (map (fn [x] {:input1 (vector x) :output1 (vector (target-function x))}) train-inputs)
:test (map (fn [x] {:input1 (vector x) :output1 (vector (target-function x))}) test-inputs)}))
(def instructions
(list :in1
:float_add
:float_subtract
:float_mult
:float_quot
:float_eq
:exec_dup
:exec_if
'close
0
1))
(defn error-function
"Finds the behaviors and errors of an individual. The error is the absolute
deviation between the target output value and the program's selected behavior,
or 1000000 if no behavior is produced. The behavior is here defined as the
final top item on the FLOAT stack."
([argmap data individual]
(let [program (genome/plushy->push (:plushy individual) argmap)
inputs (map (fn [x] (first (:input1 x))) data)
correct-outputs (map (fn [x] (first (:output1 x))) data)
outputs (map (fn [input]
(state/peek-stack
(interpreter/interpret-program
program
(assoc state/empty-state :input {:in1 input})
(:step-limit argmap))
:float))
inputs)
errors (map (fn [correct-output output]
(if (= output :no-stack-item)
1000000
(math/abs (- correct-output output))))
correct-outputs
outputs)]
(assoc individual
:behaviors outputs
:errors errors
:total-error #?(:clj (apply +' errors)
:cljs (apply + errors))))))
(defn -main
"Runs propel-gp, giving it a map of arguments."
[& args]
(gp/gp
(merge
{:instructions instructions
:error-function error-function
:training-data (:train train-and-test-data)
:testing-data (:test train-and-test-data)
:max-generations 5000
:population-size 500
:max-initial-plushy-size 100
:step-limit 200
:parent-selection :lexicase
:umad-rate 0.1
:variation {:umad 1.0 :crossover 0.0}
:elitism false}
(apply hash-map (map #(if (string? %) (read-string %) %) args))))
(#?(:clj shutdown-agents)))

View File

@ -0,0 +1,82 @@
(ns propeller.problems.float-regression
(:require [propeller.genome :as genome]
[propeller.push.interpreter :as interpreter]
[propeller.push.state :as state]
[propeller.tools.math :as math]
[propeller.gp :as gp]
#?(:cljs [cljs.reader :refer [read-string]])))
(defn- target-function
"Target function: f(x) = (1+ x^3)^3 + 1"
[x]
(inc (* (inc (* x x x)) (inc (* x x x)) (inc (* x x x)))))
(def train-and-test-data
(let [train-inputs (range -1.5 1.5 0.1)
test-inputs (range -1.75 1.75 0.05)]
{:train (map (fn [x] {:input1 (vector x) :output1 (vector (target-function x))}) train-inputs)
:test (map (fn [x] {:input1 (vector x) :output1 (vector (target-function x))}) test-inputs)}))
(def instructions
(list :in1
:float_add
:float_subtract
:float_mult
:float_quot
:float_eq
:exec_dup
:exec_if
'close
0
1))
(defn error-function
"Finds the behaviors and errors of an individual. The error is the absolute
deviation between the target output value and the program's selected behavior,
or 1000000 if no behavior is produced. The behavior is here defined as the
final top item on the FLOAT stack."
([argmap data individual]
(let [program (genome/plushy->push (:plushy individual) argmap)
inputs (map (fn [x] (first (:input1 x))) data)
correct-outputs (map (fn [x] (first (:output1 x))) data)
outputs (map (fn [input]
(state/peek-stack
(interpreter/interpret-program
program
(assoc state/empty-state :input {:in1 input})
(:step-limit argmap))
:float))
inputs)
errors (map (fn [correct-output output]
(if (= output :no-stack-item)
1000000
(math/abs (- correct-output output))))
correct-outputs
outputs)]
(assoc individual
:behaviors outputs
:errors errors
:total-error #?(:clj (apply +' errors)
:cljs (apply + errors))))))
(defn -main
"Runs propel-gp, giving it a map of arguments."
[& args]
(gp/gp
(merge
{:instructions instructions
:error-function error-function
:training-data (:train train-and-test-data)
:testing-data (:test train-and-test-data)
:max-generations 300
:population-size 1000
:max-initial-plushy-size 100
:step-limit 200
:parent-selection :lexicase
:tournament-size 5
:umad-rate 0.1
:solution-error-threshold 0.5
:variation {:umad 1.0 :crossover 0.0}
:elitism false}
(apply hash-map (map #(if (string? %) (read-string %) %) args))))
(#?(:clj shutdown-agents)))

View File

@ -0,0 +1,81 @@
(ns propeller.problems.integer-regression
(:require [propeller.genome :as genome]
[propeller.push.interpreter :as interpreter]
[propeller.push.state :as state]
[propeller.tools.math :as math]
[propeller.gp :as gp]
#?(:cljs [cljs.reader :refer [read-string]])))
(defn- target-function
"Target function: f(x) = x^3 + 2*x^2 + x + 3"
[x]
(+ (* x x x) (* 2 x x) x 3))
(def train-and-test-data
(let [train-inputs (range -10 11)
test-inputs (concat (range -20 -10) (range 11 21))]
{:train (map (fn [x] {:input1 (vector x) :output1 (vector (target-function x))}) train-inputs)
:test (map (fn [x] {:input1 (vector x) :output1 (vector (target-function x))}) test-inputs)}))
(def instructions
(list :in1
:integer_add
:integer_subtract
:integer_mult
:integer_quot
:integer_eq
:exec_dup
:exec_if
'close
0
1))
(defn error-function
"Finds the behaviors and errors of an individual. The error is the absolute
deviation between the target output value and the program's selected behavior,
or 1000000 if no behavior is produced. The behavior is here defined as the
final top item on the INTEGER stack."
([argmap data individual]
(let [program (genome/plushy->push (:plushy individual) argmap)
inputs (map (fn [x] (first (:input1 x))) data)
correct-outputs (map (fn [x] (first (:output1 x))) data)
outputs (map (fn [input]
(state/peek-stack
(interpreter/interpret-program
program
(assoc state/empty-state :input {:in1 input})
(:step-limit argmap))
:integer))
inputs)
errors (map (fn [correct-output output]
(if (= output :no-stack-item)
1000000
(math/abs (- correct-output output))))
correct-outputs
outputs)]
(assoc individual
:behaviors outputs
:errors errors
:total-error #?(:clj (apply +' errors)
:cljs (apply + errors))))))
(defn -main
"Runs propel-gp, giving it a map of arguments."
[& args]
(gp/gp
(merge
{:instructions instructions
:error-function error-function
:training-data (:train train-and-test-data)
:testing-data (:test train-and-test-data)
:max-generations 300
:population-size 1000
:max-initial-plushy-size 100
:step-limit 200
:parent-selection :lexicase
:tournament-size 5
:umad-rate 0.1
:variation {:umad 1.0 :crossover 0.0}
:elitism false}
(apply hash-map (map #(if (string? %) (read-string %) %) args))))
(#?(:clj shutdown-agents)))

View File

@ -0,0 +1,98 @@
(ns propeller.problems.simple-classification
(:require [propeller.genome :as genome]
[propeller.push.interpreter :as interpreter]
[propeller.push.state :as state]
[propeller.gp :as gp]
#?(:cljs [cljs.reader :refer [read-string]])))
;; =============================================================================
;; Simple classification
;; =============================================================================
;; Set of original propel instructions
(def instructions
(list :in1
:integer_add
:integer_subtract
:integer_mult
:integer_quot
:integer_mod
:integer_eq
:boolean_and
:boolean_not
:boolean_invert_first_then_and
:boolean_invert_second_then_and
:boolean_from_integer
true
false
'close
0
1
3))
(defn- target-function
"If number is divisible by 3 but not 7, leave TRUE on the BOOLEAN stack else leave FALSE on the BOOLEAN stack"
[x]
(let [div-3 (= 0 (mod x 3))
div-7 (= 0 (mod x 7))]
(and div-3 (not div-7))))
(def train-and-test-data
(let [train-inputs (range 0 100)
test-inputs (range 100 300)
train-outputs (map target-function train-inputs)
test-outputs (map target-function test-inputs)]
{:train (map (fn [in out] {:input1 (vector in) :output1 (vector out)}) train-inputs train-outputs)
:test (map (fn [in out] {:input1 (vector in) :output1 (vector out)}) test-inputs test-outputs)}))
(defn error-function
"Finds the behaviors and errors of an individual: Error is 0 if the value and
the program's selected behavior match, or 1 if they differ, or 1000000 if no
behavior is produced. The behavior is here defined as the final top item on
the INTEGER stack."
[argmap data individual]
(let [program (genome/plushy->push (:plushy individual) argmap)
inputs (map (fn [x] (first (:input1 x))) data)
correct-outputs (map (fn [x] (first (:output1 x))) data)
outputs (map (fn [input]
(state/peek-stack
(interpreter/interpret-program
program
(assoc state/empty-state :input {:in1 input})
(:step-limit argmap))
:boolean))
inputs)
errors (map (fn [correct-output output]
(if (= output :no-stack-item)
1000000
(if (= correct-output output)
0
1)))
correct-outputs
outputs)]
(assoc individual
:behaviors outputs
:errors errors
:total-error #?(:clj (apply +' errors)
:cljs (apply + errors)))))
(defn -main
"Runs propel-gp, giving it a map of arguments."
[& args]
(gp/gp
(merge
{:instructions instructions
:error-function error-function
:training-data (:train train-and-test-data)
:testing-data (:test train-and-test-data)
:case-t-size (count (:train train-and-test-data))
:max-generations 500
:population-size 500
:max-initial-plushy-size 100
:step-limit 200
:parent-selection :lexicase
:umad-rate 0.1
:variation {:umad 1.0 :crossover 0.0}
:elitism false}
(apply hash-map (map #(if (string? %) (read-string %) %) args))))
(#?(:clj shutdown-agents)))