diff --git a/src/propeller/core.clj b/src/propeller/core.clj index 2b57a8f..82cce94 100644 --- a/src/propeller/core.clj +++ b/src/propeller/core.clj @@ -2,24 +2,27 @@ (:gen-class) (:require [propeller.gp :as gp] [propeller.push.core :as push] - (propeller.problems [simple-regression :refer [regression-error-function]] - [string-classification :refer [string-classification-error-function]]))) + (propeller.problems [simple-regression :as regression] + [string-classification :as string-classif]))) (defn -main "Runs propel-gp, giving it a map of arguments." [& args] - (gp/gp (update-in (merge {:instructions push/default-instructions - :error-function regression-error-function - :max-generations 500 - :population-size 500 - :max-initial-plushy-size 50 - :step-limit 100 - :parent-selection :lexicase - :tournament-size 5 - :umad-rate 0.1 - :variation {:umad 0.5 :crossover 0.5} - :elitism false} - (apply hash-map - (map read-string args))) - [:error-function] - #(if (fn? %) % (eval %))))) + (gp/gp + (update-in + (merge + {:instructions push/default-instructions + :error-function regression/error-function + :max-generations 500 + :population-size 500 + :max-initial-plushy-size 50 + :step-limit 100 + :parent-selection :lexicase + :tournament-size 5 + :umad-rate 0.1 + :variation {:umad 0.5 :crossover 0.5} + :elitism false} + (apply hash-map + (map read-string args))) + [:error-function] + #(if (fn? %) % (eval %))))) diff --git a/src/propeller/gp.clj b/src/propeller/gp.clj index b782e46..eee2ecc 100644 --- a/src/propeller/gp.clj +++ b/src/propeller/gp.clj @@ -1,7 +1,7 @@ (ns propeller.gp - (:require [propeller.push.core :refer [instruction-table]] - (propeller [genome :as genome] - [variation :as variation]))) + (:require (propeller [genome :as genome] + [variation :as variation]) + [propeller.push.core :as push])) (defn report "Reports information each generation." @@ -33,14 +33,14 @@ (require '[propeller.push.instructions boolean char code input-output numeric polymorphic string]) (println "Done. Registered instructions:") - (println (sort (keys @instruction-table)))) + (println (sort (keys @push/instruction-table)))) ;; (loop [generation 0 population (repeatedly population-size #(hash-map :plushy (genome/make-random-plushy instructions - max-initial-plushy-size)))] + max-initial-plushy-size)))] (let [evaluated-pop (sort-by :total-error (map (partial error-function argmap) population))] diff --git a/src/propeller/problems/simple_regression.clj b/src/propeller/problems/simple_regression.clj index 2908f2f..5e569b4 100644 --- a/src/propeller/problems/simple_regression.clj +++ b/src/propeller/problems/simple_regression.clj @@ -1,9 +1,8 @@ (ns propeller.problems.simple-regression - (:require [propeller.genome :refer [plushy->push]] - [propeller.push.interpreter :refer [interpret-program]] - [propeller.push.state :refer [empty-state - peek-stack]] - [tools.math :as math])) + (:require [propeller.genome :as genome] + (propeller.push [interpreter :as interpreter] + [state :as state]) + [propeller.tools.math :as math])) ;; ============================================================================= ;; Problem: f(x) = 7x^2 - 20x + 13 @@ -19,20 +18,20 @@ [x] (+ (* x x x) x 3)) -(defn regression-error-function +(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 individual] - (let [program (plushy->push (:plushy individual)) + (let [program (genome/plushy->push (:plushy individual)) inputs (range -10 11) correct-outputs (map target-function inputs) outputs (map (fn [input] - (peek-stack - (interpret-program + (state/peek-stack + (interpreter/interpret-program program - (assoc empty-state :input {:in1 input}) + (assoc state/empty-state :input {:in1 input}) (:step-limit argmap)) :integer)) inputs) diff --git a/src/propeller/problems/string_classification.clj b/src/propeller/problems/string_classification.clj index 9381ca5..26ffded 100644 --- a/src/propeller/problems/string_classification.clj +++ b/src/propeller/problems/string_classification.clj @@ -1,13 +1,13 @@ (ns propeller.problems.string-classification (:require [propeller.genome :as genome] - (propeller.push [state :as state] - [interpreter :as interpreter]))) + (propeller.push [interpreter :as interpreter] + [state :as state]))) ;; ============================================================================= ;; String classification ;; ============================================================================= -(defn string-classification-error-function +(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 diff --git a/src/propeller/push/core.clj b/src/propeller/push/core.clj index c0b54d2..8834759 100644 --- a/src/propeller/push/core.clj +++ b/src/propeller/push/core.clj @@ -1,6 +1,4 @@ -(ns propeller.push.core - (:require [propeller.push.state :refer [get-args-from-stacks - push-to-stack]])) +(ns propeller.push.core) ;; ============================================================================= ;; PushGP Instructions @@ -13,6 +11,8 @@ ;; TMH: ERCs? ;; ============================================================================= +(def instruction-table (atom (hash-map))) + ;; Set of original propel instructions (def default-instructions (list :in1 @@ -46,12 +46,6 @@ "G" "T")) -(def instruction-table (atom (hash-map))) - -(defmacro def-instruction - [instruction definition] - `(swap! instruction-table assoc '~instruction ~definition)) - ;; Number of blocks opened by instructions (default = 0) (def opens {:exec_dup 1 :exec_if 2}) diff --git a/src/propeller/push/instructions/boolean.clj b/src/propeller/push/instructions/boolean.clj index cec31ad..c412c3e 100644 --- a/src/propeller/push/instructions/boolean.clj +++ b/src/propeller/push/instructions/boolean.clj @@ -1,6 +1,6 @@ (ns propeller.push.instructions.boolean - (:require [propeller.push.core :refer [def-instruction]] - [propeller.push.utils :refer [make-instruction]])) + (:require [propeller.push.utils :refer [def-instruction + make-instruction]])) ;; ============================================================================= ;; BOOLEAN Instructions diff --git a/src/propeller/push/instructions/char.clj b/src/propeller/push/instructions/char.clj index ece1d80..3078774 100644 --- a/src/propeller/push/instructions/char.clj +++ b/src/propeller/push/instructions/char.clj @@ -1,7 +1,7 @@ (ns propeller.push.instructions.char - (:require [propeller.push.core :refer [def-instruction]] - [propeller.push.utils :refer [make-instruction]] - [tools.character :as char])) + (:require [propeller.push.utils :refer [def-instruction + make-instruction]] + [propeller.tools.character :as char])) ;; ============================================================================= ;; CHAR Instructions diff --git a/src/propeller/push/instructions/code.clj b/src/propeller/push/instructions/code.clj index 86b4f32..9ff1236 100644 --- a/src/propeller/push/instructions/code.clj +++ b/src/propeller/push/instructions/code.clj @@ -1,7 +1,7 @@ (ns propeller.push.instructions.code - (:require [propeller.push.core :refer [def-instruction]] - [propeller.push.state :as state] - [propeller.push.utils :refer [make-instruction]])) + (:require (propeller.push [state :as state] + [utils :refer [def-instruction + make-instruction]]))) ;; ============================================================================= ;; CODE and EXEC Instructions diff --git a/src/propeller/push/instructions/input_output.clj b/src/propeller/push/instructions/input_output.clj index 5544f07..632b499 100644 --- a/src/propeller/push/instructions/input_output.clj +++ b/src/propeller/push/instructions/input_output.clj @@ -1,6 +1,6 @@ (ns propeller.push.instructions.input-output - (:require [propeller.push.state :as state] - [propeller.push.core :refer [def-instruction]])) + (:require (propeller.push [state :as state] + [utils :refer [def-instruction]]))) ;; ============================================================================= ;; INPUT and OUTPUT Instructions diff --git a/src/propeller/push/instructions/numeric.clj b/src/propeller/push/instructions/numeric.clj index 6610487..a91a87c 100644 --- a/src/propeller/push/instructions/numeric.clj +++ b/src/propeller/push/instructions/numeric.clj @@ -1,8 +1,8 @@ (ns propeller.push.instructions.numeric - (:require [propeller.push.core :refer [def-instruction]] - [propeller.push.utils :refer [generate-functions + (:require [propeller.push.utils :refer [def-instruction + generate-functions make-instruction]] - [tools.math :as math])) + [propeller.tools.math :as math])) ;; ============================================================================= ;; FLOAT and INTEGER Instructions (polymorphic) diff --git a/src/propeller/push/instructions/polymorphic.clj b/src/propeller/push/instructions/polymorphic.clj index b19d5b0..b878efd 100644 --- a/src/propeller/push/instructions/polymorphic.clj +++ b/src/propeller/push/instructions/polymorphic.clj @@ -1,11 +1,8 @@ (ns propeller.push.instructions.polymorphic - (:require [propeller.push.core :refer [def-instruction]] - [propeller.push.state :refer [empty-stack? - peek-stack - pop-stack - push-to-stack]] - [propeller.push.utils :refer [generate-functions - make-instruction]])) + (:require (propeller.push [state :as state] + [utils :refer [def-instruction + generate-functions + make-instruction]]))) ;; ============================================================================= ;; Polymorphic Instructions @@ -24,10 +21,10 @@ ;; would negate the effect of the duplication) (defn- _dup [stack state] - (let [top-item (peek-stack state stack)] - (if (empty-stack? state stack) + (let [top-item (state/peek-stack state stack)] + (if (state/empty-stack? state stack) state - (push-to-stack state stack top-item)))) + (state/push-to-stack state stack top-item)))) ;; Duplicates n copies of the top item (i.e leaves n copies there). Does not pop ;; its argument (since that would negate the effect of the duplication). The @@ -39,10 +36,10 @@ (if (or (and (= stack :integer) (>= (count (:integer state)) 2)) (and (not= stack :integer) - (not (empty-stack? state :integer)) - (not (empty-stack? state stack)))) - (let [n (peek-stack state :integer) - item-to-duplicate (peek-stack state stack)] + (not (state/empty-stack? state :integer)) + (not (state/empty-stack? state stack)))) + (let [n (state/peek-stack state :integer) + item-to-duplicate (state/peek-stack state stack)] nil) state)) @@ -54,7 +51,7 @@ ;; Pushes TRUE onto the BOOLEAN stack if the stack is empty. Otherwise FALSE (defn- _empty [stack state] - (push-to-stack state :boolean (empty-stack? state stack))) + (state/push-to-stack state :boolean (state/empty-stack? state stack))) ;; Empties the given stack (defn- _flush @@ -64,7 +61,7 @@ ;; Pops the given stack (defn- _pop [stack state] - (pop-stack state stack)) + (state/pop-stack state stack)) ;; Rotates the top three items on the stack (i.e. pulls the third item out and ;; pushes it on top). Equivalent to (yank state stack-type 2) diff --git a/src/propeller/push/instructions/string.clj b/src/propeller/push/instructions/string.clj index 789a2f6..16d28ad 100644 --- a/src/propeller/push/instructions/string.clj +++ b/src/propeller/push/instructions/string.clj @@ -1,6 +1,6 @@ (ns propeller.push.instructions.string - (:require [propeller.push.core :refer [def-instruction]] - [propeller.push.utils :refer [make-instruction]])) + (:require [propeller.push.utils :refer [def-instruction + make-instruction]])) ;; ============================================================================= ;; STRING Instructions diff --git a/src/propeller/push/interpreter.clj b/src/propeller/push/interpreter.clj index cccc4f1..1fdd5a6 100644 --- a/src/propeller/push/interpreter.clj +++ b/src/propeller/push/interpreter.clj @@ -1,6 +1,6 @@ (ns propeller.push.interpreter - (:require [propeller.push.core :refer [instruction-table]] - [propeller.push.state :as state])) + (:require (propeller.push [core :as push] + [state :as state]))) (defn interpret-one-step "Takes a Push state and executes the next instruction on the exec stack." @@ -8,7 +8,7 @@ (let [popped-state (state/pop-stack state :exec) first-instruction-raw (first (:exec state)) first-instruction (if (keyword? first-instruction-raw) - (first-instruction-raw @instruction-table) + (first-instruction-raw @push/instruction-table) first-instruction-raw)] (cond (fn? first-instruction) diff --git a/src/propeller/push/utils.clj b/src/propeller/push/utils.clj index 561bda1..1ab0aab 100644 --- a/src/propeller/push/utils.clj +++ b/src/propeller/push/utils.clj @@ -1,6 +1,10 @@ (ns propeller.push.utils - (:require [propeller.push.core :refer [def-instruction]] - [propeller.push.state :as state])) + (:require (propeller.push [core :as push] + [state :as state]))) + +(defmacro def-instruction + [instruction definition] + `(swap! push/instruction-table assoc '~instruction ~definition)) ;; A utility function for making Push instructions. Takes a state, a function ;; to apply to the args, the stacks to take the args from, and the stack to diff --git a/src/propeller/session.clj b/src/propeller/session.clj index e653159..31d98ad 100644 --- a/src/propeller/session.clj +++ b/src/propeller/session.clj @@ -1,53 +1,62 @@ (ns propeller.session - (:require (propeller [gp :as gp] - [variation :as variation] + (:require (propeller [genome :as genome] + [gp :as gp] [selection :as selection] - [genome :as genome]) - (propeller.push [interpreter :as interpreter] - [core :as push] + [variation :as variation]) + (propeller.push [core :as push] + [interpreter :as interpreter] [state :as state]) - (propeller.problems [simple-regression :refer [regression-error-function]] - [string-classification :refer [string-classification-error-function]]))) + (propeller.problems [simple-regression :as regression] + [string-classification :as string-classif]))) -#_(interpreter/interpret-program '(1 2 integer_+) empty-push-state 1000) +#_(interpreter/interpret-program + '(1 2 integer_add) state/empty-state 1000) -#_(interpreter/interpret-program '(3 5 integer_= exec_if (1 "yes") (2 "no")) - empty-push-state - 1000) +#_(interpreter/interpret-program + '(3 5 :integer_eq :exec_if (1 "yes") (2 "no")) + state/empty-state + 1000) -#_(interpreter/interpret-program '(in1 string_reverse 1 string_take "?" string_= exec_if - (in1 " I am asking." string_concat) - (in1 " I am saying." string_concat)) - (assoc empty-push-state :input {:in1 "Can you hear me?"}) - 1000) +#_(interpreter/interpret-program + '(in1 :string_reverse 1 :string_take "?" :string_eq :exec_if + (in1 " I am asking." :string_concat) + (in1 " I am saying." :string_concat)) + (assoc state/empty-state :input {:in1 "Can you hear me?"}) + 1000) -#_(interpreter/interpret-program '(in1 string_reverse 1 string_take "?" string_= exec_if - (in1 " I am asking." string_concat) - (in1 " I am saying." string_concat)) - (assoc empty-push-state :input {:in1 "I can hear you."}) - 1000) +#_(interpreter/interpret-program + '(in1 :string_reverse 1 :string_take "?" :string_eq :exec_if + (in1 " I am asking." :string_concat) + (in1 " I am saying." :string_concat)) + (assoc state/empty-state :input {:in1 "I can hear you."}) + 1000) -#_(genome/plushy->push (genome/make-random-plushy push/default-instructions 20)) +#_(genome/plushy->push + (genome/make-random-plushy push/default-instructions 20)) -#_(interpreter/interpret-program (genome/plushy->push (genome/make-random-plushy push/default-instructions 20)) - (assoc empty-push-state :input {:in1 "I can hear you."}) - 1000) +#_(interpreter/interpret-program + (genome/plushy->push + (genome/make-random-plushy push/default-instructions 20)) + (assoc state/empty-state :input {:in1 "I can hear you."}) + 1000) +;; ============================================================================= ;; Target function: f(x) = x^3 + x + 3 +;; ============================================================================= #_(gp/gp {:instructions push/default-instructions - :error-function regression-error-function - :max-generations 50 - :population-size 200 - :max-initial-plushy-size 50 - :step-limit 100 - :parent-selection :tournament - :tournament-size 5}) + :error-function regression/error-function + :max-generations 50 + :population-size 200 + :max-initial-plushy-size 50 + :step-limit 100 + :parent-selection :tournament + :tournament-size 5}) #_(gp/gp {:instructions push/default-instructions - :error-function string-classification-error-function - :max-generations 50 - :population-size 200 - :max-initial-plushy-size 50 - :step-limit 100 - :parent-selection :lexicase}) + :error-function string-classif/error-function + :max-generations 50 + :population-size 200 + :max-initial-plushy-size 50 + :step-limit 100 + :parent-selection :lexicase}) diff --git a/src/tools/calculus.cljc b/src/propeller/tools/calculus.cljc similarity index 96% rename from src/tools/calculus.cljc rename to src/propeller/tools/calculus.cljc index b090caf..19dfc4e 100644 --- a/src/tools/calculus.cljc +++ b/src/propeller/tools/calculus.cljc @@ -1,4 +1,4 @@ -(ns tools.calculus) +(ns propeller.tools.calculus) (defonce ^:const dx 0.0001) diff --git a/src/tools/character.clj b/src/propeller/tools/character.clj similarity index 92% rename from src/tools/character.clj rename to src/propeller/tools/character.clj index 689f866..32d64d3 100644 --- a/src/tools/character.clj +++ b/src/propeller/tools/character.clj @@ -1,4 +1,4 @@ -(ns tools.character) +(ns propeller.tools.character) (defn is-letter "Returns true if the given character is a letter, A-Z or a-z." diff --git a/src/tools/distributions.cljc b/src/propeller/tools/distributions.cljc similarity index 87% rename from src/tools/distributions.cljc rename to src/propeller/tools/distributions.cljc index 03fbe11..323a9d2 100644 --- a/src/tools/distributions.cljc +++ b/src/propeller/tools/distributions.cljc @@ -1,10 +1,10 @@ -(ns tools.distributions - (:require [tools.math :as math]) - (:require [tools.calculus :as calculus])) +(ns propeller.tools.distributions + (:require (propeller.tools [calculus :as calculus] + [math :as math]))) -;; ----------------------------------------------------------------------------- +;; ============================================================================= ;; NORMAL -;; ----------------------------------------------------------------------------- +;; ============================================================================= (defn- box-muller "Given two uniformly distributed random variables (from 0 to 1), returns a diff --git a/src/tools/math.cljc b/src/propeller/tools/math.cljc similarity index 98% rename from src/tools/math.cljc rename to src/propeller/tools/math.cljc index 48e3058..03ed549 100644 --- a/src/tools/math.cljc +++ b/src/propeller/tools/math.cljc @@ -1,4 +1,4 @@ -(ns tools.math) +(ns propeller.tools.math) (defonce PI #?(:clj Math/PI :cljs js/Math.PI)) diff --git a/src/tools/metrics.clj b/src/propeller/tools/metrics.clj similarity index 96% rename from src/tools/metrics.clj rename to src/propeller/tools/metrics.clj index b931c4a..7964add 100644 --- a/src/tools/metrics.clj +++ b/src/propeller/tools/metrics.clj @@ -1,5 +1,5 @@ -(ns tools.metrics - (:require [tools.math :as math])) +(ns propeller.tools.metrics + (:require [propeller.tools.math :as math])) (defn mean "Returns the mean of a collection."