Resolve merge conflict
This commit is contained in:
commit
9dd95956cb
@ -6,6 +6,8 @@
|
|||||||
:dependencies [[org.clojure/clojure "1.10.0"]
|
:dependencies [[org.clojure/clojure "1.10.0"]
|
||||||
[org.clojure/clojurescript "1.9.946"]
|
[org.clojure/clojurescript "1.9.946"]
|
||||||
[org.clojure/test.check "1.1.0"]
|
[org.clojure/test.check "1.1.0"]
|
||||||
[net.clojars.schneau/psb2 "1.0.0"]]
|
[net.clojars.schneau/psb2 "1.1.0"]]
|
||||||
:main ^:skip-aot propeller.core
|
:main ^:skip-aot propeller.core
|
||||||
:repl-options {:init-ns propeller.core})
|
:repl-options {:init-ns propeller.core}
|
||||||
|
:jvm-opts ^:replace [])
|
||||||
|
|
||||||
|
@ -6,8 +6,8 @@
|
|||||||
<exclude-output />
|
<exclude-output />
|
||||||
<content url="file://$MODULE_DIR$">
|
<content url="file://$MODULE_DIR$">
|
||||||
<sourceFolder url="file://$MODULE_DIR$/resources" isTestSource="false" />
|
<sourceFolder url="file://$MODULE_DIR$/resources" isTestSource="false" />
|
||||||
<sourceFolder url="file://$MODULE_DIR$/dev-resources" isTestSource="false" />
|
|
||||||
<sourceFolder url="file://$MODULE_DIR$/src" isTestSource="false" />
|
<sourceFolder url="file://$MODULE_DIR$/src" isTestSource="false" />
|
||||||
|
<sourceFolder url="file://$MODULE_DIR$/dev-resources" isTestSource="false" />
|
||||||
<sourceFolder url="file://$MODULE_DIR$/test" isTestSource="true" />
|
<sourceFolder url="file://$MODULE_DIR$/test" isTestSource="true" />
|
||||||
<excludeFolder url="file://$MODULE_DIR$/target" />
|
<excludeFolder url="file://$MODULE_DIR$/target" />
|
||||||
</content>
|
</content>
|
||||||
@ -23,7 +23,7 @@
|
|||||||
<orderEntry type="library" name="Leiningen: com.google.javascript/closure-compiler-unshaded:v20170910" level="project" />
|
<orderEntry type="library" name="Leiningen: com.google.javascript/closure-compiler-unshaded:v20170910" level="project" />
|
||||||
<orderEntry type="library" name="Leiningen: com.google.jsinterop/jsinterop-annotations:1.0.0" level="project" />
|
<orderEntry type="library" name="Leiningen: com.google.jsinterop/jsinterop-annotations:1.0.0" level="project" />
|
||||||
<orderEntry type="library" name="Leiningen: com.google.protobuf/protobuf-java:3.0.2" level="project" />
|
<orderEntry type="library" name="Leiningen: com.google.protobuf/protobuf-java:3.0.2" level="project" />
|
||||||
<orderEntry type="library" name="Leiningen: net.clojars.schneau/psb2:1.0.0" level="project" />
|
<orderEntry type="library" name="Leiningen: net.clojars.schneau/psb2:1.1.0" level="project" />
|
||||||
<orderEntry type="library" name="Leiningen: nrepl:0.6.0" level="project" />
|
<orderEntry type="library" name="Leiningen: nrepl:0.6.0" level="project" />
|
||||||
<orderEntry type="library" name="Leiningen: org.clojure/clojure:1.10.0" level="project" />
|
<orderEntry type="library" name="Leiningen: org.clojure/clojure:1.10.0" level="project" />
|
||||||
<orderEntry type="library" name="Leiningen: org.clojure/clojurescript:1.9.946" level="project" />
|
<orderEntry type="library" name="Leiningen: org.clojure/clojurescript:1.9.946" level="project" />
|
||||||
|
@ -3,6 +3,7 @@
|
|||||||
(:require [propeller.gp :as gp]
|
(:require [propeller.gp :as gp]
|
||||||
[propeller.problems.simple-regression :as regression]
|
[propeller.problems.simple-regression :as regression]
|
||||||
[propeller.problems.string-classification :as string-classif]
|
[propeller.problems.string-classification :as string-classif]
|
||||||
|
[clojure.string :as string]
|
||||||
#?(:cljs [cljs.reader :refer [read-string]])))
|
#?(:cljs [cljs.reader :refer [read-string]])))
|
||||||
|
|
||||||
(defn eval-problem-var
|
(defn eval-problem-var
|
||||||
@ -12,11 +13,14 @@
|
|||||||
(defn -main
|
(defn -main
|
||||||
"Runs propel-gp, giving it a map of arguments."
|
"Runs propel-gp, giving it a map of arguments."
|
||||||
[& args]
|
[& args]
|
||||||
|
;; Exception for when no args were passed
|
||||||
(when (empty? args)
|
(when (empty? args)
|
||||||
(println "You must specify a problem to run.")
|
(println "You must specify a problem to run.")
|
||||||
(println "Try, for example:")
|
(println "Try, for example:")
|
||||||
(println " lein run software.smallest")
|
(println " lein run software.smallest")
|
||||||
(System/exit 1))
|
(System/exit 1))
|
||||||
|
|
||||||
|
;; Creates problems
|
||||||
(require (symbol (str "propeller.problems." (first args))))
|
(require (symbol (str "propeller.problems." (first args))))
|
||||||
(gp/gp
|
(gp/gp
|
||||||
(update-in
|
(update-in
|
||||||
@ -31,9 +35,11 @@
|
|||||||
:tournament-size 5
|
:tournament-size 5
|
||||||
:umad-rate 0.1
|
:umad-rate 0.1
|
||||||
:variation {:umad 0.5 :crossover 0.5}
|
:variation {:umad 0.5 :crossover 0.5}
|
||||||
:elitism false}
|
:elitism false
|
||||||
|
:PSB2-path ""
|
||||||
|
:PSB2-problem (clojure.string/replace (first args) #"PSB2." "")}
|
||||||
(apply hash-map
|
(apply hash-map
|
||||||
(map #(if (string? %) (read-string %) %)
|
(map #(if (and (string? %) (not (.contains % "/"))) (read-string %) %)
|
||||||
(rest args))))
|
(rest args))))
|
||||||
[:error-function]
|
[:error-function]
|
||||||
identity)))
|
identity)))
|
@ -10,7 +10,8 @@
|
|||||||
[propeller.push.instructions.numeric]
|
[propeller.push.instructions.numeric]
|
||||||
[propeller.push.instructions.polymorphic]
|
[propeller.push.instructions.polymorphic]
|
||||||
[propeller.push.instructions.string]
|
[propeller.push.instructions.string]
|
||||||
[propeller.push.instructions.vector]))
|
[propeller.push.instructions.vector]
|
||||||
|
[psb2.core :as psb2]))
|
||||||
|
|
||||||
(defn report
|
(defn report
|
||||||
"Reports information each generation."
|
"Reports information each generation."
|
||||||
@ -31,12 +32,17 @@
|
|||||||
(defn gp
|
(defn gp
|
||||||
"Main GP loop."
|
"Main GP loop."
|
||||||
[{:keys [population-size max-generations error-function instructions
|
[{:keys [population-size max-generations error-function instructions
|
||||||
max-initial-plushy-size]
|
max-initial-plushy-size PSB2-path PSB2-problem]
|
||||||
:as argmap}]
|
:as argmap}]
|
||||||
;;
|
;;
|
||||||
(println {:starting-args argmap})
|
(prn {:starting-args (update (update argmap :error-function str) :instructions str)})
|
||||||
(println)
|
(println)
|
||||||
;;
|
;;
|
||||||
|
(let [PSB2-data (if (= PSB2-path "")
|
||||||
|
#{}
|
||||||
|
(psb2/fetch-examples PSB2-path PSB2-problem 200 2000))
|
||||||
|
argmap (assoc argmap :train-and-test-data PSB2-data)]
|
||||||
|
|
||||||
(loop [generation 0
|
(loop [generation 0
|
||||||
population (repeatedly
|
population (repeatedly
|
||||||
population-size
|
population-size
|
||||||
@ -52,8 +58,8 @@
|
|||||||
(cond
|
(cond
|
||||||
;; Success on training cases is verified on testing cases
|
;; Success on training cases is verified on testing cases
|
||||||
(zero? (:total-error best-individual))
|
(zero? (:total-error best-individual))
|
||||||
(do (println {:success-generation generation})
|
(do (prn {:success-generation generation})
|
||||||
(println {:total-test-error (:total-error (error-function argmap best-individual :test))})
|
(prn {:total-test-error (:total-error (error-function argmap best-individual :test))})
|
||||||
(#?(:clj shutdown-agents))
|
(#?(:clj shutdown-agents))
|
||||||
)
|
)
|
||||||
;;
|
;;
|
||||||
@ -66,4 +72,4 @@
|
|||||||
#(variation/new-individual evaluated-pop argmap))
|
#(variation/new-individual evaluated-pop argmap))
|
||||||
(first evaluated-pop))
|
(first evaluated-pop))
|
||||||
(repeatedly population-size
|
(repeatedly population-size
|
||||||
#(variation/new-individual evaluated-pop argmap))))))))
|
#(variation/new-individual evaluated-pop argmap)))))))))
|
||||||
|
65
src/propeller/problems/PSB2/basement.cljc
Normal file
65
src/propeller/problems/PSB2/basement.cljc
Normal file
@ -0,0 +1,65 @@
|
|||||||
|
(ns propeller.problems.PSB2.basement
|
||||||
|
(: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]
|
||||||
|
[clojure.pprint :as pprint]
|
||||||
|
[propeller.tools.math :as math]))
|
||||||
|
|
||||||
|
; =========== PROBLEM DESCRIPTION ============================
|
||||||
|
; BASEMENT from PSB2
|
||||||
|
; Given a vector of integers, return the first
|
||||||
|
; index such that the sum of all integers from the start of the
|
||||||
|
; vector to that index (inclusive) is negative.
|
||||||
|
;
|
||||||
|
; Source: https://arxiv.org/pdf/2106.06086.pdf
|
||||||
|
; ===============================================================
|
||||||
|
|
||||||
|
|
||||||
|
; 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 -1 0 1 []))))
|
||||||
|
|
||||||
|
(defn error-function
|
||||||
|
([argmap individual]
|
||||||
|
(error-function argmap individual :train))
|
||||||
|
([argmap individual subset]
|
||||||
|
(let [program (genome/plushy->push (:plushy individual) argmap)
|
||||||
|
data (get (get argmap :train-and-test-data) subset)
|
||||||
|
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))))))
|
||||||
|
|
||||||
|
|
||||||
|
|
72
src/propeller/problems/PSB2/bouncing_balls.cljc
Normal file
72
src/propeller/problems/PSB2/bouncing_balls.cljc
Normal file
@ -0,0 +1,72 @@
|
|||||||
|
(ns propeller.problems.PSB2.bouncing-balls
|
||||||
|
(: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]
|
||||||
|
[clojure.pprint :as pprint]
|
||||||
|
[propeller.tools.math :as math]))
|
||||||
|
|
||||||
|
; =========== PROBLEM DESCRIPTION ===============================
|
||||||
|
; BOUNCING BALLS from PSB2
|
||||||
|
; Given a starting height and a height after the first bounce of a
|
||||||
|
; dropped ball, calculate the bounciness index
|
||||||
|
; (height of first bounce / starting height). Then, given a number
|
||||||
|
; of bounces, use the bounciness index to calculate the total
|
||||||
|
; distance that the ball travels across those bounces.
|
||||||
|
;
|
||||||
|
; Source: https://arxiv.org/pdf/2106.06086.pdf
|
||||||
|
; ==================================================================
|
||||||
|
|
||||||
|
(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])))
|
||||||
|
|
||||||
|
(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)
|
||||||
|
;;; close
|
||||||
|
(list 'close)
|
||||||
|
;;; ERCs (constants)
|
||||||
|
(list 0.0 1.0 2.0))))
|
||||||
|
|
||||||
|
(defn error-function
|
||||||
|
([argmap individual]
|
||||||
|
(error-function argmap individual :train))
|
||||||
|
([argmap individual subset]
|
||||||
|
(let [program (genome/plushy->push (:plushy individual) argmap)
|
||||||
|
data (get (get argmap :train-and-test-data) subset)
|
||||||
|
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)})
|
||||||
|
(: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))))))
|
60
src/propeller/problems/PSB2/bowling.cljc
Normal file
60
src/propeller/problems/PSB2/bowling.cljc
Normal file
@ -0,0 +1,60 @@
|
|||||||
|
(ns propeller.problems.PSB2.bowling
|
||||||
|
(: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]
|
||||||
|
[clojure.pprint :as pprint]
|
||||||
|
[propeller.tools.math :as math]))
|
||||||
|
|
||||||
|
; =========== PROBLEM DESCRIPTION ======================
|
||||||
|
; BOWLING from PSB2
|
||||||
|
; Given a string representing the individual
|
||||||
|
; bowls in a 10-frame round of 10 pin bowling, return the
|
||||||
|
; score of that round.
|
||||||
|
;
|
||||||
|
; Source: https://arxiv.org/pdf/2106.06086.pdf
|
||||||
|
; =========================================================
|
||||||
|
|
||||||
|
(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 \- \X \/ \1 \2 \3 \4 \5 \6 \7 \8 \9 10 random-int))))
|
||||||
|
|
||||||
|
(defn error-function
|
||||||
|
([argmap individual]
|
||||||
|
(error-function argmap individual :train))
|
||||||
|
([argmap individual subset]
|
||||||
|
(let [program (genome/plushy->push (:plushy individual) argmap)
|
||||||
|
data (get (get argmap :train-and-test-data) subset)
|
||||||
|
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))))))
|
98
src/propeller/problems/PSB2/camel_case.cljc
Normal file
98
src/propeller/problems/PSB2/camel_case.cljc
Normal file
@ -0,0 +1,98 @@
|
|||||||
|
(ns propeller.problems.PSB2.camel-case
|
||||||
|
(:require [psb2.core :as psb2]
|
||||||
|
[propeller.genome :as genome]
|
||||||
|
[propeller.push.interpreter :as interpreter]
|
||||||
|
[propeller.utils :as utils]
|
||||||
|
[propeller.push.utils.helpers :refer [get-stack-instructions]]
|
||||||
|
[propeller.push.state :as state]
|
||||||
|
[propeller.tools.math :as math]
|
||||||
|
[propeller.tools.metrics :as metrics]))
|
||||||
|
|
||||||
|
; =========== PROBLEM DESCRIPTION =====================================
|
||||||
|
; CAMEL CASE from PSB2
|
||||||
|
; Take a string in kebab-case and convert all of the words to camelCase.
|
||||||
|
; Each group of words to convert is delimited by "-", and each grouping
|
||||||
|
; is separated by a space. For example: "camel-case example-test-string"
|
||||||
|
; → "camelCase exampleTestString"
|
||||||
|
;
|
||||||
|
; Source: https://arxiv.org/pdf/2106.06086.pdf
|
||||||
|
; =======================================================================
|
||||||
|
|
||||||
|
; Visible character ERC
|
||||||
|
(defn random-char
|
||||||
|
[]
|
||||||
|
(rand-nth (map char (range 97 122))))
|
||||||
|
|
||||||
|
; Word generator for string ERC
|
||||||
|
(defn word-generator
|
||||||
|
[]
|
||||||
|
(let [chars-between #(map char (range (int %1) (inc (int %2))))
|
||||||
|
chars (chars-between \a \z)
|
||||||
|
word-len (inc (rand-int 5))]
|
||||||
|
(apply str (repeatedly word-len #(rand-nth chars)))))
|
||||||
|
|
||||||
|
(defn cleanup-length
|
||||||
|
[string len]
|
||||||
|
(let [result (take len string)]
|
||||||
|
(if (or (= (last result) \space)
|
||||||
|
(= (last result) \-))
|
||||||
|
(apply str (butlast result))
|
||||||
|
(apply str result))))
|
||||||
|
|
||||||
|
; String ERC
|
||||||
|
(defn random-input
|
||||||
|
[len]
|
||||||
|
(loop [result-string (word-generator)]
|
||||||
|
(if (>= (count result-string) len)
|
||||||
|
(cleanup-length result-string len)
|
||||||
|
(recur (str result-string
|
||||||
|
(if (< (rand) 0.66) \- \space)
|
||||||
|
(word-generator))))))
|
||||||
|
|
||||||
|
(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 \- \space random-char (fn [] (random-input 21))))))
|
||||||
|
|
||||||
|
|
||||||
|
(defn error-function
|
||||||
|
([argmap individual]
|
||||||
|
(error-function argmap individual :train))
|
||||||
|
([argmap individual subset]
|
||||||
|
(let [program (genome/plushy->push (:plushy individual) argmap)
|
||||||
|
data (get (get argmap :train-and-test-data) subset)
|
||||||
|
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))))))
|
||||||
|
|
||||||
|
|
69
src/propeller/problems/PSB2/dice_game.cljc
Normal file
69
src/propeller/problems/PSB2/dice_game.cljc
Normal file
@ -0,0 +1,69 @@
|
|||||||
|
(ns propeller.problems.PSB2.dice-game
|
||||||
|
(: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]
|
||||||
|
[clojure.pprint :as pprint]
|
||||||
|
[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
|
||||||
|
; ==================================================================
|
||||||
|
|
||||||
|
(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 1.0))))
|
||||||
|
|
||||||
|
(defn error-function
|
||||||
|
([argmap individual]
|
||||||
|
(error-function argmap individual :train))
|
||||||
|
([argmap individual subset]
|
||||||
|
(let [program (genome/plushy->push (:plushy individual) argmap)
|
||||||
|
data (get (get argmap :train-and-test-data) subset)
|
||||||
|
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))))))
|
63
src/propeller/problems/PSB2/fuel_cost.cljc
Normal file
63
src/propeller/problems/PSB2/fuel_cost.cljc
Normal file
@ -0,0 +1,63 @@
|
|||||||
|
(ns propeller.problems.PSB2.fuel-cost
|
||||||
|
(: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]
|
||||||
|
[clojure.pprint :as pprint]
|
||||||
|
[propeller.tools.math :as math]))
|
||||||
|
|
||||||
|
; =========== PROBLEM DESCRIPTION =========================
|
||||||
|
; FUEL COST from PSB2
|
||||||
|
; Given a vector of positive integers, divide
|
||||||
|
; each by 3, round the result down to the nearest integer, and
|
||||||
|
; subtract 2. Return the sum of all of the new integers in the
|
||||||
|
; vector
|
||||||
|
;
|
||||||
|
; Source: https://arxiv.org/pdf/2106.06086.pdf
|
||||||
|
; ============================================================
|
||||||
|
|
||||||
|
; 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 3))))
|
||||||
|
|
||||||
|
(defn error-function
|
||||||
|
([argmap individual]
|
||||||
|
(error-function argmap individual :train))
|
||||||
|
([argmap individual subset]
|
||||||
|
(let [program (genome/plushy->push (:plushy individual) argmap)
|
||||||
|
data (get (get argmap :train-and-test-data) subset)
|
||||||
|
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))))))
|
||||||
|
|
67
src/propeller/problems/PSB2/middle_character.cljc
Normal file
67
src/propeller/problems/PSB2/middle_character.cljc
Normal file
@ -0,0 +1,67 @@
|
|||||||
|
(ns propeller.problems.PSB2.middle-character
|
||||||
|
(:require [psb2.core :as psb2]
|
||||||
|
[propeller.genome :as genome]
|
||||||
|
[propeller.push.interpreter :as interpreter]
|
||||||
|
[propeller.utils :as utils]
|
||||||
|
[propeller.push.utils.helpers :refer [get-stack-instructions]]
|
||||||
|
[propeller.push.state :as state]
|
||||||
|
[propeller.tools.math :as math]
|
||||||
|
[propeller.tools.metrics :as metrics]))
|
||||||
|
|
||||||
|
; =========== PROBLEM DESCRIPTION =============================
|
||||||
|
; MIDDLE CHARACTER from PSB2
|
||||||
|
; Given a string, return the middle
|
||||||
|
; character as a string if it is odd length; return the two middle
|
||||||
|
; characters as a string if it is even length.
|
||||||
|
;
|
||||||
|
; Source: https://arxiv.org/pdf/2106.06086.pdf
|
||||||
|
; ===============================================================
|
||||||
|
|
||||||
|
(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 individual]
|
||||||
|
(error-function argmap individual :train))
|
||||||
|
([argmap individual subset]
|
||||||
|
(let [program (genome/plushy->push (:plushy individual) argmap)
|
||||||
|
data (get (get argmap :train-and-test-data) subset)
|
||||||
|
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))))))
|
||||||
|
|
||||||
|
|
77
src/propeller/problems/PSB2/substitution_cipher.cljc
Normal file
77
src/propeller/problems/PSB2/substitution_cipher.cljc
Normal file
@ -0,0 +1,77 @@
|
|||||||
|
(ns propeller.problems.PSB2.substitution-cipher
|
||||||
|
(:require [psb2.core :as psb2]
|
||||||
|
[propeller.genome :as genome]
|
||||||
|
[propeller.push.interpreter :as interpreter]
|
||||||
|
[propeller.utils :as utils]
|
||||||
|
[propeller.push.utils.helpers :refer [get-stack-instructions]]
|
||||||
|
[propeller.push.state :as state]
|
||||||
|
[propeller.tools.math :as math]
|
||||||
|
[propeller.tools.metrics :as metrics]))
|
||||||
|
|
||||||
|
; =========== PROBLEM DESCRIPTION =========================
|
||||||
|
; SUBSTITUTION CIPHER from PSB2
|
||||||
|
; This problem gives 3 strings.
|
||||||
|
; The first two represent a cipher, mapping each character in
|
||||||
|
; one string to the one at the same index in the other string.
|
||||||
|
; The program must apply this cipher to the third string and
|
||||||
|
; return the deciphered message.
|
||||||
|
;
|
||||||
|
; Source: https://arxiv.org/pdf/2106.06086.pdf
|
||||||
|
; ============================================================
|
||||||
|
|
||||||
|
(defn map-vals-input
|
||||||
|
"Returns all the input values of a map (specific helper method for substitution-cipher)"
|
||||||
|
[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)"
|
||||||
|
[i]
|
||||||
|
(vals (select-keys i [:output1])))
|
||||||
|
|
||||||
|
(def instructions
|
||||||
|
(utils/not-lazy
|
||||||
|
(concat
|
||||||
|
;;; stack-specific instructions
|
||||||
|
(get-stack-instructions #{:exec :integer :boolean :char :string :print})
|
||||||
|
;;; input instructions
|
||||||
|
(list :in1 :in2 :in3)
|
||||||
|
;;; close
|
||||||
|
(list 'close)
|
||||||
|
;;; ERCs (constants)
|
||||||
|
(list 0 ""))))
|
||||||
|
|
||||||
|
(defn error-function
|
||||||
|
([argmap individual]
|
||||||
|
(error-function argmap individual :train))
|
||||||
|
([argmap individual subset]
|
||||||
|
(let [program (genome/plushy->push (:plushy individual) argmap)
|
||||||
|
data (get (get argmap :train-and-test-data) subset)
|
||||||
|
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)})
|
||||||
|
(: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))))))
|
70
src/propeller/problems/PSB2/twitter.cljc
Normal file
70
src/propeller/problems/PSB2/twitter.cljc
Normal file
@ -0,0 +1,70 @@
|
|||||||
|
(ns propeller.problems.PSB2.twitter
|
||||||
|
(:require [psb2.core :as psb2]
|
||||||
|
[propeller.genome :as genome]
|
||||||
|
[propeller.push.interpreter :as interpreter]
|
||||||
|
[propeller.utils :as utils]
|
||||||
|
[propeller.push.utils.helpers :refer [get-stack-instructions]]
|
||||||
|
[propeller.push.state :as state]
|
||||||
|
[propeller.tools.math :as math]
|
||||||
|
[propeller.tools.metrics :as metrics]))
|
||||||
|
|
||||||
|
; =========== PROBLEM DESCRIPTION =============================
|
||||||
|
; TWITTER from PSB2
|
||||||
|
; Given a string representing a tweet, validate whether the tweet
|
||||||
|
; meets Twitter’s original character requirements. If the tweet
|
||||||
|
; has more than 140 characters, return the string "Too many characters".
|
||||||
|
; If the tweet is empty, return the string "You didn’t type anything".
|
||||||
|
; Otherwise, return "Your tweet has X characters", where
|
||||||
|
; the X is the number of characters in the tweet.
|
||||||
|
;
|
||||||
|
; Source: https://arxiv.org/pdf/2106.06086.pdf
|
||||||
|
; ===============================================================
|
||||||
|
|
||||||
|
(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 140 "Too many characters" "You didn't type anything" "your tweet has " " characters"))))
|
||||||
|
|
||||||
|
(defn error-function
|
||||||
|
([argmap individual]
|
||||||
|
(error-function argmap individual :train))
|
||||||
|
([argmap individual subset]
|
||||||
|
(let [program (genome/plushy->push (:plushy individual) argmap)
|
||||||
|
data (get (get argmap :train-and-test-data) subset)
|
||||||
|
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))))))
|
||||||
|
|
||||||
|
|
@ -18,7 +18,7 @@
|
|||||||
[x]
|
[x]
|
||||||
(+ (* x x x) x 3))
|
(+ (* x x x) x 3))
|
||||||
|
|
||||||
;; Set of original propel instructions
|
; Set of original propel instructions
|
||||||
(def instructions
|
(def instructions
|
||||||
(list :in1
|
(list :in1
|
||||||
:integer_add
|
:integer_add
|
||||||
|
BIN
src/propeller/push/.DS_Store
vendored
BIN
src/propeller/push/.DS_Store
vendored
Binary file not shown.
@ -8,7 +8,7 @@
|
|||||||
:float '()
|
:float '()
|
||||||
:input {}
|
:input {}
|
||||||
:integer '()
|
:integer '()
|
||||||
:output '()
|
:output '("")
|
||||||
:string '()
|
:string '()
|
||||||
:vector_boolean '()
|
:vector_boolean '()
|
||||||
:vector_float '()
|
:vector_float '()
|
||||||
|
@ -23,6 +23,37 @@
|
|||||||
[seq1 seq2]
|
[seq1 seq2]
|
||||||
(apply + (map #(if (= %1 %2) 0 1) seq1 seq2)))
|
(apply + (map #(if (= %1 %2) 0 1) seq1 seq2)))
|
||||||
|
|
||||||
|
;; helper method for levenshtein-distance
|
||||||
|
(defn compute-next-row
|
||||||
|
"computes the next row using the prev-row current-element and the other seq"
|
||||||
|
[prev-row current-element other-seq pred]
|
||||||
|
(reduce
|
||||||
|
(fn [row [diagonal above other-element]]
|
||||||
|
(let [update-val (if (pred other-element current-element)
|
||||||
|
;; if the elements are deemed equivalent according to the predicate
|
||||||
|
;; pred, then no change has taken place to the string, so we are
|
||||||
|
;; going to set it the same value as diagonal (which is the previous edit-distance)
|
||||||
|
diagonal
|
||||||
|
;; in the case where the elements are not considered equivalent, then we are going
|
||||||
|
;; to figure out if its a substitution (then there is a change of 1 from the previous
|
||||||
|
;; edit distance) thus the value is diagonal + 1 or if its a deletion, then the value
|
||||||
|
;; is present in the columns, but not in the rows, the edit distance is the edit-distance
|
||||||
|
;; of last of row + 1 (since we will be using vectors, peek is more efficient)
|
||||||
|
;; or it could be a case of insertion, then the value is above+1, and we chose
|
||||||
|
;; the minimum of the three
|
||||||
|
(inc (min diagonal above (peek row))))]
|
||||||
|
|
||||||
|
(conj row update-val)))
|
||||||
|
;; we need to initialize the reduce function with the value of a row, since we are
|
||||||
|
;; constructing this row from the previous one, the row is a vector of 1 element which
|
||||||
|
;; consists of 1 + the first element in the previous row (edit distance between the prefix so far
|
||||||
|
;; and an empty string)
|
||||||
|
[(inc (first prev-row))]
|
||||||
|
;; for the reduction to go over, we need to provide it with three values, the diagonal
|
||||||
|
;; which is the same as prev-row because it starts from 0, the above, which is the next element
|
||||||
|
;; from the list and finally the element from the other sequence itself.
|
||||||
|
(map vector prev-row (next prev-row) other-seq)))
|
||||||
|
|
||||||
(defn levenshtein-distance
|
(defn levenshtein-distance
|
||||||
"Levenshtein Distance - http://en.wikipedia.org/wiki/Levenshtein_distance
|
"Levenshtein Distance - http://en.wikipedia.org/wiki/Levenshtein_distance
|
||||||
In Information Theory and Computer Science, the Levenshtein distance is a
|
In Information Theory and Computer Science, the Levenshtein distance is a
|
||||||
@ -31,8 +62,8 @@
|
|||||||
little mutability as possible. Still maintains the O(nm) guarantee."
|
little mutability as possible. Still maintains the O(nm) guarantee."
|
||||||
[a b & {p :predicate :or {p =}}]
|
[a b & {p :predicate :or {p =}}]
|
||||||
(cond
|
(cond
|
||||||
(empty? a) (count b)
|
(empty? (str a)) (count (str b)) ;; sometimes stack pushes numbers, force
|
||||||
(empty? b) (count a)
|
(empty? (str b)) (count (str a)) ;; a and b to be strings
|
||||||
:else (peek
|
:else (peek
|
||||||
(reduce
|
(reduce
|
||||||
;; we use a simple reduction to convert the previous row into the
|
;; we use a simple reduction to convert the previous row into the
|
||||||
@ -40,11 +71,11 @@
|
|||||||
;; element, the previous-row computed so far, and the predicate
|
;; element, the previous-row computed so far, and the predicate
|
||||||
;; to compare for equality
|
;; to compare for equality
|
||||||
(fn [prev-row current-element]
|
(fn [prev-row current-element]
|
||||||
(compute-next-row prev-row current-element b p))
|
(compute-next-row prev-row current-element (str b) p))
|
||||||
;; we need to initialize the prev-row with the edit distance
|
;; we need to initialize the prev-row with the edit distance
|
||||||
;; between the various prefixes of b and the empty string
|
;; between the various prefixes of b and the empty string
|
||||||
(range (inc (count b)))
|
(range (inc (count (str b))))
|
||||||
a))))
|
(str a)))))
|
||||||
|
|
||||||
(defn sequence-similarity
|
(defn sequence-similarity
|
||||||
"Returns a number between 0 and 1, indicating how similar the sequences are
|
"Returns a number between 0 and 1, indicating how similar the sequences are
|
||||||
|
Loading…
x
Reference in New Issue
Block a user