diff --git a/src/propeller/genome.cljc b/src/propeller/genome.cljc index d032081..cd71c8c 100755 --- a/src/propeller/genome.cljc +++ b/src/propeller/genome.cljc @@ -1,5 +1,5 @@ (ns propeller.genome - (:require [propeller.push.core :as push] + (:require [propeller.push.instructions :as instructions] [propeller.utils :as utils])) (defn make-random-plushy @@ -16,7 +16,12 @@ (let [plushy (if (:diploid argmap) (map first (partition 2 plushy)) plushy) opener? #(and (vector? %) (= (first %) 'open))] ;; [open ] marks opens (loop [push () ;; iteratively build the Push program from the plushy - plushy (mapcat #(if-let [n (get push/opens %)] [% ['open n]] [%]) plushy)] + plushy (mapcat #(let [n (get instructions/opens %)] + (if (and n + (> n 0)) + [% ['open n]] + [%])) + plushy)] (if (empty? plushy) ;; maybe we're done? (if (some opener? push) ;; done with plushy, but unclosed open (recur push '(close)) ;; recur with one more close diff --git a/src/propeller/problems/PSB2/basement.cljc b/src/propeller/problems/PSB2/basement.cljc index 9358220..2ac4248 100644 --- a/src/propeller/problems/PSB2/basement.cljc +++ b/src/propeller/problems/PSB2/basement.cljc @@ -3,7 +3,7 @@ [propeller.genome :as genome] [propeller.push.interpreter :as interpreter] [propeller.utils :as utils] - [propeller.push.utils.helpers :refer [get-stack-instructions]] + [propeller.push.instructions :refer [get-stack-instructions]] [propeller.push.state :as state] [propeller.tools.math :as math] [propeller.gp :as gp] diff --git a/src/propeller/problems/PSB2/bouncing_balls.cljc b/src/propeller/problems/PSB2/bouncing_balls.cljc index 4a9c599..f7e5c88 100644 --- a/src/propeller/problems/PSB2/bouncing_balls.cljc +++ b/src/propeller/problems/PSB2/bouncing_balls.cljc @@ -3,9 +3,8 @@ [propeller.genome :as genome] [propeller.push.interpreter :as interpreter] [propeller.utils :as utils] - [propeller.push.utils.helpers :refer [get-stack-instructions]] + [propeller.push.instructions :refer [get-stack-instructions]] [propeller.push.state :as state] - [clojure.pprint :as pprint] [propeller.tools.math :as math] [propeller.gp :as gp] #?(:cljs [cljs.reader :refer [read-string]]))) diff --git a/src/propeller/problems/PSB2/bowling.cljc b/src/propeller/problems/PSB2/bowling.cljc index 773fdff..70d4613 100644 --- a/src/propeller/problems/PSB2/bowling.cljc +++ b/src/propeller/problems/PSB2/bowling.cljc @@ -3,7 +3,7 @@ [propeller.genome :as genome] [propeller.push.interpreter :as interpreter] [propeller.utils :as utils] - [propeller.push.utils.helpers :refer [get-stack-instructions]] + [propeller.push.instructions :refer [get-stack-instructions]] [propeller.push.state :as state] [propeller.tools.math :as math] [propeller.gp :as gp] diff --git a/src/propeller/problems/PSB2/camel_case.cljc b/src/propeller/problems/PSB2/camel_case.cljc index 5348284..99b20be 100644 --- a/src/propeller/problems/PSB2/camel_case.cljc +++ b/src/propeller/problems/PSB2/camel_case.cljc @@ -3,7 +3,7 @@ [propeller.genome :as genome] [propeller.push.interpreter :as interpreter] [propeller.utils :as utils] - [propeller.push.utils.helpers :refer [get-stack-instructions]] + [propeller.push.instructions :refer [get-stack-instructions]] [propeller.push.state :as state] [propeller.tools.metrics :as metrics] [propeller.gp :as gp] diff --git a/src/propeller/problems/PSB2/dice_game.cljc b/src/propeller/problems/PSB2/dice_game.cljc index bce6587..ee1ec07 100644 --- a/src/propeller/problems/PSB2/dice_game.cljc +++ b/src/propeller/problems/PSB2/dice_game.cljc @@ -3,7 +3,7 @@ [propeller.genome :as genome] [propeller.push.interpreter :as interpreter] [propeller.utils :as utils] - [propeller.push.utils.helpers :refer [get-stack-instructions]] + [propeller.push.instructions :refer [get-stack-instructions]] [propeller.push.state :as state] [propeller.tools.math :as math] [propeller.gp :as gp] diff --git a/src/propeller/problems/PSB2/fizz_buzz.cljc b/src/propeller/problems/PSB2/fizz_buzz.cljc index 5a0182d..4b892e7 100644 --- a/src/propeller/problems/PSB2/fizz_buzz.cljc +++ b/src/propeller/problems/PSB2/fizz_buzz.cljc @@ -3,7 +3,7 @@ [propeller.genome :as genome] [propeller.push.interpreter :as interpreter] [propeller.utils :as utils] - [propeller.push.utils.helpers :refer [get-stack-instructions]] + [propeller.push.instructions :refer [get-stack-instructions]] [propeller.push.state :as state] [propeller.tools.metrics :as metrics] [propeller.gp :as gp] diff --git a/src/propeller/problems/PSB2/fuel_cost.cljc b/src/propeller/problems/PSB2/fuel_cost.cljc index 8ce4561..9d45455 100644 --- a/src/propeller/problems/PSB2/fuel_cost.cljc +++ b/src/propeller/problems/PSB2/fuel_cost.cljc @@ -3,7 +3,7 @@ [propeller.genome :as genome] [propeller.push.interpreter :as interpreter] [propeller.utils :as utils] - [propeller.push.utils.helpers :refer [get-stack-instructions]] + [propeller.push.instructions :refer [get-stack-instructions]] [propeller.push.state :as state] [propeller.tools.math :as math] [propeller.gp :as gp] diff --git a/src/propeller/problems/PSB2/gcd.cljc b/src/propeller/problems/PSB2/gcd.cljc index 3fc10d3..f835853 100644 --- a/src/propeller/problems/PSB2/gcd.cljc +++ b/src/propeller/problems/PSB2/gcd.cljc @@ -3,7 +3,7 @@ [propeller.genome :as genome] [propeller.push.interpreter :as interpreter] [propeller.utils :as utils] - [propeller.push.utils.helpers :refer [get-stack-instructions]] + [propeller.push.instructions :refer [get-stack-instructions]] [propeller.push.state :as state] [propeller.tools.math :as math] [propeller.gp :as gp] diff --git a/src/propeller/problems/PSB2/luhn.cljc b/src/propeller/problems/PSB2/luhn.cljc index 0e40a88..35f0b63 100644 --- a/src/propeller/problems/PSB2/luhn.cljc +++ b/src/propeller/problems/PSB2/luhn.cljc @@ -3,7 +3,7 @@ [propeller.genome :as genome] [propeller.push.interpreter :as interpreter] [propeller.utils :as utils] - [propeller.push.utils.helpers :refer [get-stack-instructions]] + [propeller.push.instructions :refer [get-stack-instructions]] [propeller.push.state :as state] [propeller.tools.math :as math] [propeller.gp :as gp] diff --git a/src/propeller/problems/PSB2/middle_character.cljc b/src/propeller/problems/PSB2/middle_character.cljc index 55925e4..f9a4b18 100644 --- a/src/propeller/problems/PSB2/middle_character.cljc +++ b/src/propeller/problems/PSB2/middle_character.cljc @@ -3,7 +3,7 @@ [propeller.genome :as genome] [propeller.push.interpreter :as interpreter] [propeller.utils :as utils] - [propeller.push.utils.helpers :refer [get-stack-instructions]] + [propeller.push.instructions :refer [get-stack-instructions]] [propeller.push.state :as state] [propeller.tools.metrics :as metrics] [propeller.gp :as gp] diff --git a/src/propeller/problems/PSB2/paired_digits.cljc b/src/propeller/problems/PSB2/paired_digits.cljc index 4936c8d..633effb 100644 --- a/src/propeller/problems/PSB2/paired_digits.cljc +++ b/src/propeller/problems/PSB2/paired_digits.cljc @@ -3,7 +3,7 @@ [propeller.genome :as genome] [propeller.push.interpreter :as interpreter] [propeller.utils :as utils] - [propeller.push.utils.helpers :refer [get-stack-instructions]] + [propeller.push.instructions :refer [get-stack-instructions]] [propeller.push.state :as state] [propeller.tools.math :as math] [propeller.gp :as gp] diff --git a/src/propeller/problems/PSB2/shopping_list.cljc b/src/propeller/problems/PSB2/shopping_list.cljc index f379f8d..7d922de 100644 --- a/src/propeller/problems/PSB2/shopping_list.cljc +++ b/src/propeller/problems/PSB2/shopping_list.cljc @@ -3,7 +3,7 @@ [propeller.genome :as genome] [propeller.push.interpreter :as interpreter] [propeller.utils :as utils] - [propeller.push.utils.helpers :refer [get-stack-instructions]] + [propeller.push.instructions :refer [get-stack-instructions]] [propeller.push.state :as state] [propeller.tools.math :as math] [propeller.gp :as gp] diff --git a/src/propeller/problems/PSB2/snow_day.cljc b/src/propeller/problems/PSB2/snow_day.cljc index 1346545..fd0f94c 100644 --- a/src/propeller/problems/PSB2/snow_day.cljc +++ b/src/propeller/problems/PSB2/snow_day.cljc @@ -3,7 +3,7 @@ [propeller.genome :as genome] [propeller.push.interpreter :as interpreter] [propeller.utils :as utils] - [propeller.push.utils.helpers :refer [get-stack-instructions]] + [propeller.push.instructions :refer [get-stack-instructions]] [propeller.push.state :as state] [propeller.tools.math :as math] [propeller.gp :as gp] diff --git a/src/propeller/problems/PSB2/solve_boolean.cljc b/src/propeller/problems/PSB2/solve_boolean.cljc index d9cf85b..12524d2 100644 --- a/src/propeller/problems/PSB2/solve_boolean.cljc +++ b/src/propeller/problems/PSB2/solve_boolean.cljc @@ -3,7 +3,7 @@ [propeller.genome :as genome] [propeller.push.interpreter :as interpreter] [propeller.utils :as utils] - [propeller.push.utils.helpers :refer [get-stack-instructions]] + [propeller.push.instructions :refer [get-stack-instructions]] [propeller.push.state :as state] [propeller.gp :as gp] #?(:cljs [cljs.reader :refer [read-string]]))) diff --git a/src/propeller/problems/PSB2/spin_words.cljc b/src/propeller/problems/PSB2/spin_words.cljc index ed37706..5698f7a 100644 --- a/src/propeller/problems/PSB2/spin_words.cljc +++ b/src/propeller/problems/PSB2/spin_words.cljc @@ -3,7 +3,7 @@ [propeller.genome :as genome] [propeller.push.interpreter :as interpreter] [propeller.utils :as utils] - [propeller.push.utils.helpers :refer [get-stack-instructions]] + [propeller.push.instructions :refer [get-stack-instructions]] [propeller.push.state :as state] [propeller.tools.metrics :as metrics] [propeller.gp :as gp] diff --git a/src/propeller/problems/PSB2/square_digits.cljc b/src/propeller/problems/PSB2/square_digits.cljc index 9aa44cd..bc3bc61 100644 --- a/src/propeller/problems/PSB2/square_digits.cljc +++ b/src/propeller/problems/PSB2/square_digits.cljc @@ -3,7 +3,7 @@ [propeller.genome :as genome] [propeller.push.interpreter :as interpreter] [propeller.utils :as utils] - [propeller.push.utils.helpers :refer [get-stack-instructions]] + [propeller.push.instructions :refer [get-stack-instructions]] [propeller.push.state :as state] [propeller.tools.metrics :as metrics] [propeller.gp :as gp] diff --git a/src/propeller/problems/PSB2/substitution_cipher.cljc b/src/propeller/problems/PSB2/substitution_cipher.cljc index d297c75..3f83e64 100644 --- a/src/propeller/problems/PSB2/substitution_cipher.cljc +++ b/src/propeller/problems/PSB2/substitution_cipher.cljc @@ -3,9 +3,8 @@ [propeller.genome :as genome] [propeller.push.interpreter :as interpreter] [propeller.utils :as utils] - [propeller.push.utils.helpers :refer [get-stack-instructions]] + [propeller.push.instructions :refer [get-stack-instructions]] [propeller.push.state :as state] - [propeller.tools.math :as math] [propeller.tools.metrics :as metrics] [propeller.gp :as gp] #?(:cljs [cljs.reader :refer [read-string]]))) diff --git a/src/propeller/problems/PSB2/twitter.cljc b/src/propeller/problems/PSB2/twitter.cljc index 2d95dee..3d70851 100644 --- a/src/propeller/problems/PSB2/twitter.cljc +++ b/src/propeller/problems/PSB2/twitter.cljc @@ -3,9 +3,8 @@ [propeller.genome :as genome] [propeller.push.interpreter :as interpreter] [propeller.utils :as utils] - [propeller.push.utils.helpers :refer [get-stack-instructions]] + [propeller.push.instructions :refer [get-stack-instructions]] [propeller.push.state :as state] - [propeller.tools.math :as math] [propeller.tools.metrics :as metrics] [propeller.gp :as gp] #?(:cljs [cljs.reader :refer [read-string]]))) diff --git a/src/propeller/problems/software/number_io.cljc b/src/propeller/problems/software/number_io.cljc index aefcc09..a434a44 100755 --- a/src/propeller/problems/software/number_io.cljc +++ b/src/propeller/problems/software/number_io.cljc @@ -2,9 +2,8 @@ (:require [propeller.genome :as genome] [propeller.push.interpreter :as interpreter] [propeller.push.state :as state] - [propeller.push.utils.helpers :refer [get-stack-instructions]] + [propeller.push.instructions :refer [get-stack-instructions]] [propeller.utils :as utils] - [propeller.push.state :as state] [propeller.tools.math :as math] [propeller.gp :as gp] #?(:cljs [cljs.reader :refer [read-string]]))) @@ -99,8 +98,8 @@ :error-function error-function :training-data (:train train-and-test-data) :testing-data (:test train-and-test-data) - :max-generations 500 - :population-size 500 + :max-generations 300 + :population-size 1000 :max-initial-plushy-size 100 :step-limit 200 :parent-selection :lexicase diff --git a/src/propeller/problems/software/smallest.cljc b/src/propeller/problems/software/smallest.cljc index 2ad5306..8c7a068 100755 --- a/src/propeller/problems/software/smallest.cljc +++ b/src/propeller/problems/software/smallest.cljc @@ -2,9 +2,8 @@ (:require [propeller.genome :as genome] [propeller.push.interpreter :as interpreter] [propeller.push.state :as state] - [propeller.push.utils.helpers :refer [get-stack-instructions]] + [propeller.push.instructions :refer [get-stack-instructions]] [propeller.utils :as utils] - [propeller.push.state :as state] [propeller.gp :as gp] #?(:cljs [cljs.reader :refer [read-string]]))) @@ -80,10 +79,7 @@ :print)) inputs) errors (map (fn [correct-output output] - (let [parsed-output (try (read-string output) - #?(:clj (catch Exception e 1000.0) - :cljs (catch js/Error. e 1000.0)))] - (if (= correct-output parsed-output) 0 1))) + (if (= (str correct-output) output) 0 1)) correct-outputs outputs)] (assoc individual @@ -101,8 +97,8 @@ :error-function error-function :training-data (:train train-and-test-data) :testing-data (:test train-and-test-data) - :max-generations 500 - :population-size 500 + :max-generations 300 + :population-size 1000 :max-initial-plushy-size 100 :step-limit 200 :parent-selection :lexicase diff --git a/src/propeller/push/.DS_Store b/src/propeller/push/.DS_Store deleted file mode 100644 index ac2df55..0000000 Binary files a/src/propeller/push/.DS_Store and /dev/null differ diff --git a/src/propeller/push/core.cljc b/src/propeller/push/core.cljc deleted file mode 100755 index f9d23bd..0000000 --- a/src/propeller/push/core.cljc +++ /dev/null @@ -1,15 +0,0 @@ -(ns propeller.push.core) - -;; PushGP instructions are represented as keywords, and stored in an atom. They -;; can be either constant literals or functions that take and return a Push state -(def instruction-table (atom (hash-map))) - -;; Number of blocks opened by instructions (default = 0) -(def opens {:exec_dup 1 - :exec_if 2 - :exec_when 1 - :exec_while 1 - :exec_do_while 1 - :exec_k 2 - :exec_s 3 - :exec_y 1}) diff --git a/src/propeller/push/instructions.cljc b/src/propeller/push/instructions.cljc new file mode 100644 index 0000000..361c28b --- /dev/null +++ b/src/propeller/push/instructions.cljc @@ -0,0 +1,154 @@ +(ns propeller.push.instructions + (:require [clojure.set] + [propeller.push.state :as state] + [propeller.utils :as u] + #?(:cljs [goog.string :as gstring]) + #?(:cljs [goog.string.format]))) + +;; PushGP instructions are represented as keywords, and stored in an atom. They +;; can be either constant literals or functions that take and return a Push state +(def instruction-table (atom (hash-map))) + +;; Number of blocks opened by instructions (default = 0) +(def opens {:exec_dup 1 + :exec_dup_times 1 + :exec_dup_items 0 ; explicitly set to 0 to make it clear that this is intended + :exec_eq 0 ; explicitly set to 0 to make it clear that this is intended + :exec_pop 1 + :exec_rot 3 + :exec_shove 1 + :exec_swap 2 + :exec_yank 0 ; explicitly set to 0 to make it clear that this is intended + :exec_yank_dup 0 ; explicitly set to 0 to make it clear that this is intended + :exec_deep_dup 0 ; explicitly set to 0 to make it clear that this is intended + :exec_print 1 + :exec_if 2 + :exec_when 1 + :exec_while 1 + :exec_do_while 1 + :exec_do_range 1 + :exec_do_count 1 + :exec_do_times 1 + :exec_k 2 + :exec_s 3 + :exec_y 1 + :string_iterate 1 + :vector_boolean_iterate 1 + :vector_string_iterate 1 + :vector_integer_iterate 1 + :vector_float_iterate 1 + }) + + +#?(:clj + (def cls->type + {Boolean :boolean + Short :integer + Integer :integer + Long :integer + BigInteger :integer + Double :float + BigDecimal :float + Float :float + Character :char + String :string})) + +#?(:cljs + (def pred->type + [[boolean? :boolean] + [int? :integer] + [float? :float] + [string? :string] + [char? :char]])) + +(defn get-literal-type + "If a piece of data is a literal, return its corresponding stack name + e.g. `:integer`. Otherwise, return `nil`." + [data] + (or (when (vector? data) + (if (empty? data) + :generic-vector + (keyword (str "vector_" (name (get-literal-type (u/first-non-nil data))))))) + #?(:clj (cls->type (type data)) + :cljs (loop [remaining pred->type] + (let [[pred d-type] (first remaining)] + (cond + (empty? remaining) nil + (pred data) d-type + :else (recur (rest remaining)))))))) + +(defn get-vector-literal-type + "Returns the literal stack corresponding to some vector stack." + [vector-stack] + (get state/vec-stacks vector-stack)) + +(defn def-instruction + "Defines a Push instruction as a keyword-function pair, and adds it to the + instruction table" + [instruction function] + (swap! instruction-table assoc instruction function)) + +(defn make-metadata + "Given a generic function, e.g. _dup, and a stack type to instantiate it for, + e.g. :char, returns the appropriate stack metadata for that function instance" + [function stack] + (->> (:stacks (meta function)) + (replace {:elem (get-vector-literal-type stack)}) + (cons stack) + set + (assoc-in (meta function) [:stacks]) + (#(dissoc % :name)))) + +(defn generate-instructions + "Given a sequence of stacks, e.g. [:float :integer], and a sequence of suffix + function strings, e.g. [_add, _mult, _eq], automates the generation of all + possible combination instructions, which here would be :float_add, :float_mult, + :float_eq, :integer_add, :integer_mult, and :integer_eq, also transferring + and updating the generic function's stack-type metadata. For some vector + instructions, the placeholder :elem will be replaced with the stack of the + corresponding element type (e.g. for :vector_integer, with :integer)" + [stacks functions] + (doseq [stack stacks + func functions] + (let [instruction-name (keyword (str (name stack) (:name (meta func)))) + metadata (make-metadata func stack) + new-func (with-meta (partial func stack) metadata)] + (def-instruction instruction-name new-func)))) + + +(defn make-instruction + "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 + return the result to. Applies the function to the args (popped from the + given stacks), and pushes the result onto the return-stack. + + If the function returns :ignore-instruction, then we will return the + initial state unchanged. This allows instructions to fail gracefully + without consuming stack values." + [state function arg-stacks return-stack] + (let [popped-args (state/get-args-from-stacks state arg-stacks)] + (if (= popped-args :not-enough-args) + state + (let [result (apply function (:args popped-args)) + new-state (:state popped-args)] + (if (= result :ignore-instruction) + state + (state/push-to-stack new-state return-stack result)))))) + +(defn get-stack-instructions + "Given a set of stacks, returns all instructions that operate on those stacks + only. Won't include random instructions unless :random is in the set as well" + [stacks] + (doseq [[instruction-name function] @instruction-table] + (assert + (:stacks (meta function)) + #?(:clj (format + "ERROR: Instruction %s does not have :stacks defined in metadata." + (name instruction-name)) + :cljs (gstring/format + "ERROR: Instruction %s does not have :stacks defined in metadata." + (name instruction-name))))) + (for [[instruction-name function] @instruction-table + :when (clojure.set/subset? (:stacks (meta function)) stacks)] + instruction-name)) + diff --git a/src/propeller/push/instructions/bool.cljc b/src/propeller/push/instructions/bool.cljc index 85a1ba2..620fcfa 100755 --- a/src/propeller/push/instructions/bool.cljc +++ b/src/propeller/push/instructions/bool.cljc @@ -1,7 +1,6 @@ (ns propeller.push.instructions.bool - #?(:cljs (:require-macros [propeller.push.utils.macros :refer [def-instruction]])) - (:require [propeller.push.utils.helpers :refer [make-instruction]] - #?(:clj [propeller.push.utils.macros :refer [def-instruction]]))) + (:require [propeller.push.instructions :refer [def-instruction + make-instruction]])) ;; ============================================================================= ;; BOOLEAN Instructions diff --git a/src/propeller/push/instructions/character.cljc b/src/propeller/push/instructions/character.cljc index 2f5d77b..33e064a 100755 --- a/src/propeller/push/instructions/character.cljc +++ b/src/propeller/push/instructions/character.cljc @@ -1,9 +1,8 @@ (ns propeller.push.instructions.character - #?(:cljs (:require-macros [propeller.push.utils.macros :refer [def-instruction]])) (:require [propeller.push.state :as state] - [propeller.push.utils.helpers :refer [make-instruction]] [propeller.tools.character :as char] - #?(:clj [propeller.push.utils.macros :refer [def-instruction]]))) + [propeller.push.instructions :refer [def-instruction + make-instruction]])) ;; ============================================================================= ;; CHAR Instructions diff --git a/src/propeller/push/instructions/code.cljc b/src/propeller/push/instructions/code.cljc index 86e0478..424e558 100755 --- a/src/propeller/push/instructions/code.cljc +++ b/src/propeller/push/instructions/code.cljc @@ -1,9 +1,8 @@ (ns propeller.push.instructions.code - #?(:cljs (:require-macros [propeller.push.utils.macros :refer [def-instruction]])) (:require [propeller.utils :as utils] [propeller.push.state :as state] - [propeller.push.utils.helpers :refer [make-instruction]] - #?(:clj [propeller.push.utils.macros :refer [def-instruction]]))) + [propeller.push.instructions :refer [def-instruction + make-instruction]])) ;; ============================================================================= ;; CODE Instructions diff --git a/src/propeller/push/instructions/input_output.cljc b/src/propeller/push/instructions/input_output.cljc index b597c7b..6dc4799 100755 --- a/src/propeller/push/instructions/input_output.cljc +++ b/src/propeller/push/instructions/input_output.cljc @@ -1,10 +1,6 @@ (ns propeller.push.instructions.input-output - #?(:cljs (:require-macros - [propeller.push.utils.macros :refer [def-instruction - generate-instructions]])) (:require [propeller.push.state :as state] - [propeller.push.utils.helpers :refer [make-instruction]] - [propeller.push.utils.macros :refer [def-instruction + [propeller.push.instructions :refer [def-instruction generate-instructions]])) ;; ============================================================================= diff --git a/src/propeller/push/instructions/numeric.cljc b/src/propeller/push/instructions/numeric.cljc index 8e5b6f9..b9cbf1f 100755 --- a/src/propeller/push/instructions/numeric.cljc +++ b/src/propeller/push/instructions/numeric.cljc @@ -1,12 +1,8 @@ (ns propeller.push.instructions.numeric - #?(:cljs (:require-macros - [propeller.push.utils.macros :refer [def-instruction - generate-instructions]])) - (:require [propeller.push.utils.helpers :refer [make-instruction]] - [propeller.tools.math :as math] - #?(:cljs [cljs.reader :refer [read-string]] - :clj [propeller.push.utils.macros :refer [def-instruction - generate-instructions]]))) + (:require [propeller.tools.math :as math] + [propeller.push.instructions :refer [def-instruction + generate-instructions + make-instruction]])) ;; ============================================================================= ;; FLOAT and INTEGER Instructions (polymorphic) diff --git a/src/propeller/push/instructions/polymorphic.cljc b/src/propeller/push/instructions/polymorphic.cljc index 4635cc4..d744f3c 100755 --- a/src/propeller/push/instructions/polymorphic.cljc +++ b/src/propeller/push/instructions/polymorphic.cljc @@ -1,13 +1,10 @@ (ns propeller.push.instructions.polymorphic - #?(:cljs (:require-macros - [propeller.push.utils.macros :refer [def-instruction - generate-instructions]])) (:require [propeller.utils :as utils] [propeller.push.state :as state] - [propeller.push.utils.helpers :refer [make-instruction]] - [propeller.push.utils.limits :as limit] - #?(:clj [propeller.push.utils.macros :refer [def-instruction - generate-instructions]]))) + [propeller.push.limits :as limit] + [propeller.push.instructions :refer [def-instruction + generate-instructions + make-instruction]])) ;; ============================================================================= ;; Polymorphic Instructions diff --git a/src/propeller/push/instructions/string.cljc b/src/propeller/push/instructions/string.cljc index d602430..b7450cd 100755 --- a/src/propeller/push/instructions/string.cljc +++ b/src/propeller/push/instructions/string.cljc @@ -1,10 +1,8 @@ (ns propeller.push.instructions.string - #?(:cljs (:require-macros - [propeller.push.utils.macros :refer [def-instruction]])) (:require [clojure.string :as string] - [propeller.push.utils.helpers :refer [make-instruction]] [propeller.push.state :as state] - #?(:clj [propeller.push.utils.macros :refer [def-instruction]]))) + [propeller.push.instructions :refer [def-instruction + make-instruction]])) ;; ============================================================================= ;; STRING Instructions diff --git a/src/propeller/push/instructions/vector.cljc b/src/propeller/push/instructions/vector.cljc index a8822f2..4e4687b 100755 --- a/src/propeller/push/instructions/vector.cljc +++ b/src/propeller/push/instructions/vector.cljc @@ -1,11 +1,10 @@ (ns propeller.push.instructions.vector - #?(:cljs (:require-macros [propeller.push.utils.macros :refer [generate-instructions]])) (:require [clojure.string] [propeller.utils :as utils] [propeller.push.state :as state] - [propeller.push.utils.helpers :refer [get-vector-literal-type - make-instruction]] - #?(:clj [propeller.push.utils.macros :refer [generate-instructions]]))) + [propeller.push.instructions :refer [generate-instructions + make-instruction + get-vector-literal-type]])) ;; ============================================================================= ;; VECTOR Instructions diff --git a/src/propeller/push/interpreter.cljc b/src/propeller/push/interpreter.cljc index 9941146..738537a 100755 --- a/src/propeller/push/interpreter.cljc +++ b/src/propeller/push/interpreter.cljc @@ -1,20 +1,19 @@ (ns propeller.push.interpreter - (:require [propeller.push.core :as push] + (:require [propeller.push.instructions :as instructions] [propeller.push.state :as state] - [propeller.push.instructions.input-output :as io] - [propeller.push.utils.helpers :refer [get-literal-type]])) + [propeller.push.instructions.input-output :as io])) (defn interpret-one-step "Takes a Push state and executes the next instruction on the exec stack." [state] (let [popped-state (state/pop-stack state :exec) instruction (first (:exec state)) - literal-type (get-literal-type instruction)] ; nil for non-literals + literal-type (instructions/get-literal-type instruction)] ; nil for non-literals (cond ;; ;; Recognize functional instruction or input instruction (keyword? instruction) - (if-let [function (instruction @push/instruction-table)] + (if-let [function (instruction @instructions/instruction-table)] (function popped-state) (io/handle-input-instruction popped-state instruction)) ;; diff --git a/src/propeller/push/utils/limits.cljc b/src/propeller/push/limits.cljc similarity index 98% rename from src/propeller/push/utils/limits.cljc rename to src/propeller/push/limits.cljc index 1e4c7c4..611b13e 100644 --- a/src/propeller/push/utils/limits.cljc +++ b/src/propeller/push/limits.cljc @@ -1,4 +1,4 @@ -(ns propeller.push.utils.limits +(ns propeller.push.limits (:require [propeller.utils :as u])) ;; ============================================================================= diff --git a/src/propeller/push/state.cljc b/src/propeller/push/state.cljc index 921e2eb..c211198 100755 --- a/src/propeller/push/state.cljc +++ b/src/propeller/push/state.cljc @@ -1,5 +1,5 @@ (ns propeller.push.state - (:require [propeller.push.utils.limits :as l] + (:require [propeller.push.limits :as l] #?(:cljs [goog.string :as gstring]))) ;; Empty push state - all available stacks are empty diff --git a/src/propeller/push/utils/helpers.cljc b/src/propeller/push/utils/helpers.cljc deleted file mode 100755 index 8de76be..0000000 --- a/src/propeller/push/utils/helpers.cljc +++ /dev/null @@ -1,86 +0,0 @@ -(ns propeller.push.utils.helpers - (:require [clojure.set] - [propeller.push.core :as push] - [propeller.push.state :as state] - [propeller.utils :as u] - #?(:cljs [goog.string :as gstring]) - #?(:cljs [goog.string.format]))) - -;; 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 -;; return the result to. Applies the function to the args (popped from the -;; given stacks), and pushes the result onto the return-stack. -;; -;; If the function returns :ignore-instruction, then we will return the -;; initial state unchanged. This allows instructions to fail gracefully -;; without consuming stack values. -(defn make-instruction - [state function arg-stacks return-stack] - (let [popped-args (state/get-args-from-stacks state arg-stacks)] - (if (= popped-args :not-enough-args) - state - (let [result (apply function (:args popped-args)) - new-state (:state popped-args)] - (if (= result :ignore-instruction) - state - (state/push-to-stack new-state return-stack result)))))) - -;; Given a set of stacks, returns all instructions that operate on those stacks -;; only. Won't include random instructions unless :random is in the set as well -(defn get-stack-instructions - [stacks] - (doseq [[instruction-name function] @push/instruction-table] - (assert - (:stacks (meta function)) - #?(:clj (format - "ERROR: Instruction %s does not have :stacks defined in metadata." - (name instruction-name)) - :cljs (gstring/format - "ERROR: Instruction %s does not have :stacks defined in metadata." - (name instruction-name))))) - (for [[instruction-name function] @push/instruction-table - :when (clojure.set/subset? (:stacks (meta function)) stacks)] - instruction-name)) - - -#?(:clj - (def cls->type - {Boolean :boolean - Short :integer - Integer :integer - Long :integer - BigInteger :integer - Double :float - BigDecimal :float - Float :float - Character :char - String :string})) - -#?(:cljs - (def pred->type - [[boolean? :boolean] - [int? :integer] - [float? :float] - [string? :string] - [char? :char]])) - -(defn get-literal-type - "If a piece of data is a literal, return its corresponding stack name - e.g. `:integer`. Otherwise, return `nil`." - [data] - (or (when (vector? data) - (if (empty? data) - :generic-vector - (keyword (str "vector_" (name (get-literal-type (u/first-non-nil data))))))) - #?(:clj (cls->type (type data)) - :cljs (loop [remaining pred->type] - (let [[pred d-type] (first remaining)] - (cond - (empty? remaining) nil - (pred data) d-type - :else (recur (rest remaining)))))))) - -(defn get-vector-literal-type - "Returns the literal stack corresponding to some vector stack." - [vector-stack] - (get state/vec-stacks vector-stack)) diff --git a/src/propeller/push/utils/macros.cljc b/src/propeller/push/utils/macros.cljc deleted file mode 100755 index f6dd102..0000000 --- a/src/propeller/push/utils/macros.cljc +++ /dev/null @@ -1,35 +0,0 @@ -(ns propeller.push.utils.macros - (:require [propeller.push.core :as push] - [propeller.push.utils.helpers :refer [get-vector-literal-type]])) - -;; Defines a Push instruction as a keyword-function pair, and adds it to the -;; instruction table -(defmacro def-instruction - [instruction definition] - `(swap! push/instruction-table assoc ~instruction ~definition)) - -;; Given a generic function, e.g. _dup, and a stack type to instantiate it for, -;; e.g. :char, returns the appropriate stack metadata for that function instance -(defmacro make-metadata - [function stack] - `(->> (:stacks (meta ~function)) - (replace {:elem (get-vector-literal-type ~stack)}) - (cons ~stack) - set - (assoc-in (meta ~function) [:stacks]) - (#(dissoc % :name)))) - -;; Given a sequence of stacks, e.g. [:float :integer], and a sequence of suffix -;; function strings, e.g. [_add, _mult, _eq], automates the generation of all -;; possible combination instructions, which here would be :float_add, :float_mult, -;; :float_eq, :integer_add, :integer_mult, and :integer_eq, also transferring -;; and updating the generic function's stack-type metadata. For some vector -;; instructions, the placeholder :elem will be replaced with the stack of the -;; corresponding element type (e.g. for :vector_integer, with :integer) -(defmacro generate-instructions [stacks functions] - `(doseq [stack# ~stacks - func# ~functions - :let [instruction-name# (keyword (str (name stack#) (:name (meta func#)))) - metadata# (make-metadata func# stack#) - new-func# (with-meta (partial func# stack#) metadata#)]] - (def-instruction instruction-name# new-func#))) diff --git a/src/propeller/session.cljc b/src/propeller/session.cljc index d949528..c9a159d 100755 --- a/src/propeller/session.cljc +++ b/src/propeller/session.cljc @@ -5,10 +5,9 @@ [propeller.variation :as variation] [propeller.problems.simple-regression :as regression] [propeller.problems.string-classification :as string-classif] - [propeller.push.core :as push] + [propeller.push.instructions :as instructions] [propeller.push.interpreter :as interpreter] - [propeller.push.state :as state] - [propeller.push.utils.helpers :refer [get-stack-instructions]])) + [propeller.push.state :as state])) #_(interpreter/interpret-program '(1 2 :integer_add) state/empty-state 1000) @@ -36,7 +35,7 @@ ; 1000) ; ;#_(genome/plushy->push -; (genome/make-random-plushy (get-stack-instructions #{:float :integer :exec :boolean}) 20)) +; (genome/make-random-plushy (instructions/get-stack-instructions #{:float :integer :exec :boolean}) 20)) ; ;#_(gp/gp {:instructions propeller.problems.software.number-io/instructions ; :error-function propeller.problems.software.number-io/error-function