Resolve merge conflict
This commit is contained in:
commit
9dd95956cb
@ -6,6 +6,8 @@
|
||||
:dependencies [[org.clojure/clojure "1.10.0"]
|
||||
[org.clojure/clojurescript "1.9.946"]
|
||||
[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
|
||||
:repl-options {:init-ns propeller.core})
|
||||
:repl-options {:init-ns propeller.core}
|
||||
:jvm-opts ^:replace [])
|
||||
|
||||
|
@ -6,8 +6,8 @@
|
||||
<exclude-output />
|
||||
<content url="file://$MODULE_DIR$">
|
||||
<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$/dev-resources" isTestSource="false" />
|
||||
<sourceFolder url="file://$MODULE_DIR$/test" isTestSource="true" />
|
||||
<excludeFolder url="file://$MODULE_DIR$/target" />
|
||||
</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.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: 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: org.clojure/clojure:1.10.0" level="project" />
|
||||
<orderEntry type="library" name="Leiningen: org.clojure/clojurescript:1.9.946" level="project" />
|
||||
|
@ -3,6 +3,7 @@
|
||||
(:require [propeller.gp :as gp]
|
||||
[propeller.problems.simple-regression :as regression]
|
||||
[propeller.problems.string-classification :as string-classif]
|
||||
[clojure.string :as string]
|
||||
#?(:cljs [cljs.reader :refer [read-string]])))
|
||||
|
||||
(defn eval-problem-var
|
||||
@ -12,11 +13,14 @@
|
||||
(defn -main
|
||||
"Runs propel-gp, giving it a map of arguments."
|
||||
[& 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))
|
||||
|
||||
;; Creates problems
|
||||
(require (symbol (str "propeller.problems." (first args))))
|
||||
(gp/gp
|
||||
(update-in
|
||||
@ -31,9 +35,11 @@
|
||||
:tournament-size 5
|
||||
:umad-rate 0.1
|
||||
:variation {:umad 0.5 :crossover 0.5}
|
||||
:elitism false}
|
||||
:elitism false
|
||||
:PSB2-path ""
|
||||
:PSB2-problem (clojure.string/replace (first args) #"PSB2." "")}
|
||||
(apply hash-map
|
||||
(map #(if (string? %) (read-string %) %)
|
||||
(map #(if (and (string? %) (not (.contains % "/"))) (read-string %) %)
|
||||
(rest args))))
|
||||
[:error-function]
|
||||
identity)))
|
@ -10,7 +10,8 @@
|
||||
[propeller.push.instructions.numeric]
|
||||
[propeller.push.instructions.polymorphic]
|
||||
[propeller.push.instructions.string]
|
||||
[propeller.push.instructions.vector]))
|
||||
[propeller.push.instructions.vector]
|
||||
[psb2.core :as psb2]))
|
||||
|
||||
(defn report
|
||||
"Reports information each generation."
|
||||
@ -31,12 +32,17 @@
|
||||
(defn gp
|
||||
"Main GP loop."
|
||||
[{:keys [population-size max-generations error-function instructions
|
||||
max-initial-plushy-size]
|
||||
max-initial-plushy-size PSB2-path PSB2-problem]
|
||||
:as argmap}]
|
||||
;;
|
||||
(println {:starting-args argmap})
|
||||
(prn {:starting-args (update (update argmap :error-function str) :instructions str)})
|
||||
(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
|
||||
population (repeatedly
|
||||
population-size
|
||||
@ -52,8 +58,8 @@
|
||||
(cond
|
||||
;; Success on training cases is verified on testing cases
|
||||
(zero? (:total-error best-individual))
|
||||
(do (println {:success-generation generation})
|
||||
(println {:total-test-error (:total-error (error-function argmap best-individual :test))})
|
||||
(do (prn {:success-generation generation})
|
||||
(prn {:total-test-error (:total-error (error-function argmap best-individual :test))})
|
||||
(#?(:clj shutdown-agents))
|
||||
)
|
||||
;;
|
||||
@ -66,4 +72,4 @@
|
||||
#(variation/new-individual evaluated-pop argmap))
|
||||
(first evaluated-pop))
|
||||
(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 3))
|
||||
|
||||
;; Set of original propel instructions
|
||||
; Set of original propel instructions
|
||||
(def instructions
|
||||
(list :in1
|
||||
: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 '()
|
||||
:input {}
|
||||
:integer '()
|
||||
:output '()
|
||||
:output '("")
|
||||
:string '()
|
||||
:vector_boolean '()
|
||||
:vector_float '()
|
||||
|
@ -23,6 +23,37 @@
|
||||
[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
|
||||
"Levenshtein Distance - http://en.wikipedia.org/wiki/Levenshtein_distance
|
||||
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."
|
||||
[a b & {p :predicate :or {p =}}]
|
||||
(cond
|
||||
(empty? a) (count b)
|
||||
(empty? b) (count a)
|
||||
(empty? (str a)) (count (str b)) ;; sometimes stack pushes numbers, force
|
||||
(empty? (str b)) (count (str a)) ;; a and b to be strings
|
||||
:else (peek
|
||||
(reduce
|
||||
;; 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
|
||||
;; to compare for equality
|
||||
(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
|
||||
;; between the various prefixes of b and the empty string
|
||||
(range (inc (count b)))
|
||||
a))))
|
||||
(range (inc (count (str b))))
|
||||
(str a)))))
|
||||
|
||||
(defn sequence-similarity
|
||||
"Returns a number between 0 and 1, indicating how similar the sequences are
|
||||
|
Loading…
x
Reference in New Issue
Block a user