Port numeric instructions
This commit is contained in:
parent
bb5f74823c
commit
73b3963b90
@ -1,7 +1,7 @@
|
|||||||
(ns propeller.genome
|
(ns propeller.genome
|
||||||
(:use propeller.push.instructions))
|
(:use propeller.push.instructions))
|
||||||
|
|
||||||
(defn push-from-plushy
|
(defn plushy->push
|
||||||
"Returns the Push program expressed by the given plushy representation."
|
"Returns the Push program expressed by the given plushy representation."
|
||||||
[plushy]
|
[plushy]
|
||||||
(let [opener? #(and (vector? %) (= (first %) 'open))] ;; [open <n>] marks opens
|
(let [opener? #(and (vector? %) (= (first %) 'open))] ;; [open <n>] marks opens
|
||||||
|
@ -9,7 +9,7 @@
|
|||||||
(println " Report for Generation" generation)
|
(println " Report for Generation" generation)
|
||||||
(println "-------------------------------------------------------")
|
(println "-------------------------------------------------------")
|
||||||
(print "Best plushy: ") (prn (:plushy best))
|
(print "Best plushy: ") (prn (:plushy best))
|
||||||
(print "Best program: ") (prn (push-from-plushy (:plushy best)))
|
(print "Best program: ") (prn (plushy->push (:plushy best)))
|
||||||
(println "Best total error:" (:total-error best))
|
(println "Best total error:" (:total-error best))
|
||||||
(println "Best errors:" (:errors best))
|
(println "Best errors:" (:errors best))
|
||||||
(println "Best behaviors:" (:behaviors best))
|
(println "Best behaviors:" (:behaviors best))
|
||||||
|
@ -1,29 +1,31 @@
|
|||||||
(ns propeller.problems.simple-regression
|
(ns propeller.problems.simple-regression
|
||||||
(:use propeller.genome
|
(:require [propeller.genome :refer [plushy->push]]
|
||||||
[propeller.push state interpreter])
|
[propeller.push.interpreter :refer [interpret-program]]
|
||||||
(:require [tools.math :as math]))
|
[propeller.push.state :refer [empty-state
|
||||||
|
peek-stack]]
|
||||||
|
[tools.math :as math]))
|
||||||
|
|
||||||
;; =============================================================================
|
;; =============================================================================
|
||||||
;; Problem: f(x) = 7x^2 - 20x + 13
|
;; Problem: f(x) = 7x^2 - 20x + 13
|
||||||
;; =============================================================================
|
;; =============================================================================
|
||||||
|
|
||||||
(defn target-function-hard
|
(defn- target-function-hard
|
||||||
"Target function: f(x) = 7x^2 - 20x + 13"
|
"Target function: f(x) = 7x^2 - 20x + 13"
|
||||||
[x]
|
[x]
|
||||||
(+ (* 7 x x) (* -20 x) 13))
|
(+ (* 7 x x) (* -20 x) 13))
|
||||||
|
|
||||||
(defn target-function
|
(defn- target-function
|
||||||
"Target function: f(x) = x^3 + x + 3"
|
"Target function: f(x) = x^3 + x + 3"
|
||||||
[x]
|
[x]
|
||||||
(+ (* x x x) x 3))
|
(+ (* x x x) x 3))
|
||||||
|
|
||||||
(defn regression-error-function
|
(defn regression-error-function
|
||||||
"Finds the behaviors and errors of an individual: Error is the absolute
|
"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,
|
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
|
or 1000000 if no behavior is produced. The behavior is here defined as the
|
||||||
final top item on the INTEGER stack."
|
final top item on the INTEGER stack."
|
||||||
[argmap individual]
|
[argmap individual]
|
||||||
(let [program (push-from-plushy (:plushy individual))
|
(let [program (plushy->push (:plushy individual))
|
||||||
inputs (range -10 11)
|
inputs (range -10 11)
|
||||||
correct-outputs (map target-function inputs)
|
correct-outputs (map target-function inputs)
|
||||||
outputs (map (fn [input]
|
outputs (map (fn [input]
|
||||||
|
@ -12,7 +12,7 @@
|
|||||||
behavior is produced. The behavior is here defined as the final top item on
|
behavior is produced. The behavior is here defined as the final top item on
|
||||||
the BOOLEAN stack."
|
the BOOLEAN stack."
|
||||||
[argmap individual]
|
[argmap individual]
|
||||||
(let [program (push-from-plushy (:plushy individual))
|
(let [program (plushy->push (:plushy individual))
|
||||||
inputs ["GCG" "GACAG" "AGAAG" "CCCA" "GATTACA" "TAGG" "GACT"]
|
inputs ["GCG" "GACAG" "AGAAG" "CCCA" "GATTACA" "TAGG" "GACT"]
|
||||||
correct-outputs [false false false false true true true]
|
correct-outputs [false false false false true true true]
|
||||||
outputs (map (fn [input]
|
outputs (map (fn [input]
|
||||||
|
@ -55,16 +55,3 @@
|
|||||||
;; Number of blocks opened by instructions (default = 0)
|
;; Number of blocks opened by instructions (default = 0)
|
||||||
(def opens {:exec_dup 1
|
(def opens {:exec_dup 1
|
||||||
:exec_if 2})
|
:exec_if 2})
|
||||||
|
|
||||||
(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."
|
|
||||||
[state function arg-stacks return-stack]
|
|
||||||
(let [popped-args (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)]
|
|
||||||
(push-to-stack new-state return-stack result)))))
|
|
||||||
|
@ -1,6 +1,6 @@
|
|||||||
(ns propeller.push.instructions.boolean
|
(ns propeller.push.instructions.boolean
|
||||||
(:require [propeller.push.instructions :refer [make-instruction
|
(:require [propeller.push.instructions :refer [def-instruction]]
|
||||||
def-instruction]]))
|
[propeller.push.utils :refer [make-instruction]]))
|
||||||
|
|
||||||
;; Pushes TRUE if the top two BOOLEANs are equal, and FALSE otherwise
|
;; Pushes TRUE if the top two BOOLEANs are equal, and FALSE otherwise
|
||||||
(def-instruction
|
(def-instruction
|
||||||
|
@ -1,6 +1,6 @@
|
|||||||
(ns propeller.push.instructions.char
|
(ns propeller.push.instructions.char
|
||||||
(:require [propeller.push.instructions :refer [make-instruction
|
(:require [propeller.push.instructions :refer [def-instruction]]
|
||||||
def-instruction]]
|
[propeller.push.utils :refer [make-instruction]]
|
||||||
[tools.character :as char]))
|
[tools.character :as char]))
|
||||||
|
|
||||||
;; Pushes TRUE onto the BOOLEAN stack if the popped character is a letter
|
;; Pushes TRUE onto the BOOLEAN stack if the popped character is a letter
|
||||||
|
@ -1,7 +1,7 @@
|
|||||||
(ns propeller.push.instructions.code
|
(ns propeller.push.instructions.code
|
||||||
(:require [propeller.push.state :as state]
|
(:require [propeller.push.instructions :refer [def-instruction]]
|
||||||
[propeller.push.instructions :refer [make-instruction
|
[propeller.push.state :as state]
|
||||||
def-instruction]]))
|
[propeller.push.utils :refer [make-instruction]]))
|
||||||
|
|
||||||
(def-instruction
|
(def-instruction
|
||||||
:exec_dup
|
:exec_dup
|
||||||
|
@ -1,32 +1,138 @@
|
|||||||
(ns propeller.push.instructions.numeric
|
(ns propeller.push.instructions.numeric
|
||||||
(:require [propeller.push.instructions :refer [make-instruction
|
(:require [propeller.push.instructions :refer [def-instruction]]
|
||||||
def-instruction]]))
|
[propeller.push.utils :refer [generate-functions
|
||||||
|
make-instruction]]
|
||||||
|
[tools.math :as math]))
|
||||||
|
|
||||||
(def-instruction
|
;; =============================================================================
|
||||||
:integer_=
|
;; FLOAT and INTEGER (polymorphic)
|
||||||
(fn [state]
|
;; =============================================================================
|
||||||
(make-instruction state = [:integer :integer] :boolean)))
|
|
||||||
|
|
||||||
(def-instruction
|
;; Pushes TRUE onto the BOOLEAN stack if the top two items are equal, and
|
||||||
:integer_+
|
;; FALSE otherwise
|
||||||
(fn [state]
|
(defn- _=
|
||||||
(make-instruction state +' [:integer :integer] :integer)))
|
[stack state]
|
||||||
|
(make-instruction state = [stack stack] :boolean))
|
||||||
|
|
||||||
(def-instruction
|
;; Pushes TRUE onto the BOOLEAN stack if the second item is greater than the top
|
||||||
:integer_-
|
;; item, and FALSE otherwise
|
||||||
(fn [state]
|
(defn- _>
|
||||||
(make-instruction state -' [:integer :integer] :integer)))
|
[stack state]
|
||||||
|
(make-instruction state > [stack stack] :boolean))
|
||||||
|
|
||||||
(def-instruction
|
;; Pushes TRUE onto the BOOLEAN stack if the second item is less than the top
|
||||||
:integer_*
|
;; item, and FALSE otherwise
|
||||||
(fn [state]
|
(defn- _<
|
||||||
(make-instruction state *' [:integer :integer] :integer)))
|
[stack state]
|
||||||
|
(make-instruction state < [stack stack] :boolean))
|
||||||
|
|
||||||
(def-instruction
|
;; Pushes the sum of the top two items onto the same stack
|
||||||
:integer_%
|
(defn- _+
|
||||||
(fn [state]
|
[stack state]
|
||||||
|
(make-instruction state +' [stack stack] stack))
|
||||||
|
|
||||||
|
;; Pushes the difference of the top two items (i.e. the second item minus the
|
||||||
|
;; top item) onto the same stack
|
||||||
|
(defn- _-
|
||||||
|
[stack state]
|
||||||
|
(make-instruction state -' [stack stack] stack))
|
||||||
|
|
||||||
|
;; Pushes the product of the top two items onto the same stack
|
||||||
|
(defn- _*
|
||||||
|
[stack state]
|
||||||
|
(make-instruction state *' [stack stack] stack))
|
||||||
|
|
||||||
|
;; Pushes the quotient of the top two items (i.e. the second item divided by the
|
||||||
|
;; top item) onto the same stack. If the top item is zero, acts as a NOOP
|
||||||
|
(defn- _quot
|
||||||
|
[stack state]
|
||||||
(make-instruction state
|
(make-instruction state
|
||||||
(fn [int1 int2]
|
#(if (zero? %2)
|
||||||
(if (zero? int2) int1 (quot int1 int2)))
|
(list %1 %2) ; push both items back
|
||||||
[:integer :integer]
|
(quot %1 %2))
|
||||||
:integer)))
|
[stack stack]
|
||||||
|
stack))
|
||||||
|
|
||||||
|
;; Pushes the second item modulo the top item onto the same stack. If the top
|
||||||
|
;; item is zero, acts as a NOOP. The modulus is computed as the remainder of the
|
||||||
|
;; quotient, where the quotient has first been truncated towards negative
|
||||||
|
;; infinity.
|
||||||
|
(defn- _%
|
||||||
|
[stack state]
|
||||||
|
(make-instruction state
|
||||||
|
#(if (zero? %2)
|
||||||
|
(list %1 %2) ; push both items back
|
||||||
|
(mod %1 %2))
|
||||||
|
[stack stack]
|
||||||
|
stack))
|
||||||
|
|
||||||
|
;; Pushes the maximum of the top two items
|
||||||
|
(defn- _max
|
||||||
|
[stack state]
|
||||||
|
(make-instruction state max [stack stack] stack))
|
||||||
|
|
||||||
|
;; Pushes the minimum of the top two items
|
||||||
|
(defn- _min
|
||||||
|
[stack state]
|
||||||
|
(make-instruction state min [stack stack] stack))
|
||||||
|
|
||||||
|
;; Pushes 1 / 1.0 if the top BOOLEAN is TRUE, or 0 / 0.0 if FALSE
|
||||||
|
(defn- _fromboolean
|
||||||
|
[stack state]
|
||||||
|
(make-instruction state
|
||||||
|
#((if (= stack :float) float int) (if % 1 0))
|
||||||
|
[:boolean]
|
||||||
|
stack))
|
||||||
|
|
||||||
|
;; Automate type-specific function generation. All resulting functions take a
|
||||||
|
;; Push state as their only argument. For FLOAT and INTEGER, create one of each
|
||||||
|
;; of the 11 following type-specific functions: =, >, <, +, -, *, QUOT, %, MAX,
|
||||||
|
;; MIN, and FROMBOOLEAN. (22 functions total, with syntax e.g. integer_=,
|
||||||
|
;; float_min etc.)
|
||||||
|
(generate-functions
|
||||||
|
[:float :integer]
|
||||||
|
[_=, _>, _<, _+, _-, _*, _quot, _%, _max, _min, _fromboolean])
|
||||||
|
|
||||||
|
;; =============================================================================
|
||||||
|
;; FLOAT only
|
||||||
|
;; =============================================================================
|
||||||
|
|
||||||
|
;; Pushes the cosine of the top FLOAT
|
||||||
|
(def-instruction
|
||||||
|
:float_cos
|
||||||
|
(fn [state]
|
||||||
|
(make-instruction state math/cos [:float] :float)))
|
||||||
|
|
||||||
|
;; Pushes the sine of the top FLOAT
|
||||||
|
(def-instruction
|
||||||
|
:float_sin
|
||||||
|
(fn [state]
|
||||||
|
(make-instruction state math/sin [:float] :float)))
|
||||||
|
|
||||||
|
;; Pushes the tangent of the top FLOAT
|
||||||
|
(def-instruction
|
||||||
|
:float_tan
|
||||||
|
(fn [state]
|
||||||
|
(make-instruction state math/tan [:float] :float)))
|
||||||
|
|
||||||
|
;; Pushes the tangent of the top FLOAT
|
||||||
|
(def-instruction
|
||||||
|
:float_tan
|
||||||
|
(fn [state]
|
||||||
|
(make-instruction state math/tan [:float] :float)))
|
||||||
|
|
||||||
|
;; Pushes a floating point version of the top INTEGER
|
||||||
|
(def-instruction
|
||||||
|
:float_frominteger
|
||||||
|
(fn [state]
|
||||||
|
(make-instruction state math/tan [:float] :float)))
|
||||||
|
|
||||||
|
;; =============================================================================
|
||||||
|
;; INTEGER only
|
||||||
|
;; =============================================================================
|
||||||
|
|
||||||
|
;; Pushes the result of truncating the top FLOAT towards negative infinity
|
||||||
|
(def-instruction
|
||||||
|
:integer_fromfloat
|
||||||
|
(fn [state]
|
||||||
|
(make-instruction state int [:float] :integer)))
|
||||||
|
@ -1,9 +1,17 @@
|
|||||||
(ns propeller.push.instructions.random
|
(ns propeller.push.instructions.random
|
||||||
(:require [propeller.push.instructions :refer [def-instruction
|
(:require [propeller.push.instructions :refer [def-instruction]]))
|
||||||
make-instruction]]))
|
|
||||||
|
|
||||||
;; Pushes a random BOOLEAN
|
;;; Pushes a random BOOLEAN
|
||||||
(def-instruction
|
;(def-instruction
|
||||||
:boolean_rand
|
; :boolean_rand
|
||||||
(fn [state]
|
; (fn [state]
|
||||||
(make-instruction state #(rand-nth [true false]) [] :boolean)))
|
; (make-instruction state #(rand-nth [true false]) [] :boolean)))
|
||||||
|
;
|
||||||
|
;(defn- _rand
|
||||||
|
; "For an INTEGER stack type, pushes a newly generated random INTEGER that is
|
||||||
|
; greater than or equal to MIN-RANDOM-INTEGER and less than or equal to
|
||||||
|
; MAX-RANDOM-INTEGER. Analogous for a FLOAT stack type, with its corresponding
|
||||||
|
; MAX-RANDOM-FLOAT and MIN-RANDOM-FLOAT."
|
||||||
|
; [state stack-type]
|
||||||
|
; (let [data-type (keyword stack-type)]
|
||||||
|
; ()))
|
||||||
|
@ -1,6 +1,6 @@
|
|||||||
(ns propeller.push.instructions.string
|
(ns propeller.push.instructions.string
|
||||||
(:require [propeller.push.instructions :refer [def-instruction
|
(:require [propeller.push.instructions :refer [def-instruction]]
|
||||||
make-instruction]]))
|
[propeller.push.utils :refer [make-instruction]]))
|
||||||
|
|
||||||
(def-instruction
|
(def-instruction
|
||||||
:string_=
|
:string_=
|
||||||
|
@ -1,7 +1,7 @@
|
|||||||
(ns propeller.push.state)
|
(ns propeller.push.state)
|
||||||
|
|
||||||
;; Set of all stacks used by the Push interpreter
|
;; Set of all stacks used by the Push interpreter
|
||||||
(defonce ^:private stack-types #{:auxiliary
|
(defonce stacks #{:auxiliary
|
||||||
:boolean
|
:boolean
|
||||||
:char
|
:char
|
||||||
:code
|
:code
|
||||||
@ -24,7 +24,7 @@
|
|||||||
|
|
||||||
;; Record-based states for performance
|
;; Record-based states for performance
|
||||||
(defmacro define-push-state []
|
(defmacro define-push-state []
|
||||||
`(defrecord ~'State [~@(map #(symbol (name %)) stack-types)]))
|
`(defrecord ~'State [~@(map #(symbol (name %)) stacks)]))
|
||||||
|
|
||||||
(define-push-state)
|
(define-push-state)
|
||||||
|
|
||||||
@ -37,14 +37,6 @@
|
|||||||
:string '("abc")
|
:string '("abc")
|
||||||
:input {:in1 4}})
|
:input {:in1 4}})
|
||||||
|
|
||||||
(defn print-state
|
|
||||||
"Pretty-prints a Push state, for logging or debugging purposes."
|
|
||||||
[state]
|
|
||||||
(doseq [stack stack-types]
|
|
||||||
(printf "%-15s = " stack)
|
|
||||||
(prn (if (get state stack) (get state stack) '()))
|
|
||||||
(flush)))
|
|
||||||
|
|
||||||
(defn empty-stack?
|
(defn empty-stack?
|
||||||
"Returns true if the stack is empty."
|
"Returns true if the stack is empty."
|
||||||
[state stack]
|
[state stack]
|
||||||
|
@ -1 +1,34 @@
|
|||||||
(ns propeller.push.utils)
|
(ns propeller.push.utils
|
||||||
|
(:require [propeller.push.instructions :refer [def-instruction]]
|
||||||
|
[propeller.push.state :as push-state]))
|
||||||
|
|
||||||
|
;; 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
|
||||||
|
(defn make-instruction
|
||||||
|
[state function arg-stacks return-stack]
|
||||||
|
(let [popped-args (push-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)]
|
||||||
|
(push-state/push-to-stack new-state return-stack result)))))
|
||||||
|
|
||||||
|
;; Given a sequence of stacks, e.g. [:float :integer], and a sequence of suffix
|
||||||
|
;; function strings, e.g. [_+, _*, _=], automates the generation of all possible
|
||||||
|
;; combination instructions, which here would be :float_+, :float_*, :float_=,
|
||||||
|
;; :integer_+, :integer_*, and :integer_=
|
||||||
|
(defmacro generate-functions [stacks functions]
|
||||||
|
`(do ~@(for [stack stacks
|
||||||
|
function functions
|
||||||
|
:let [instruction-name (keyword (str (name stack) function))]]
|
||||||
|
`(def-instruction ~instruction-name (partial ~function ~stack)))))
|
||||||
|
|
||||||
|
;; Pretty-prints a Push state, for logging or debugging purposes
|
||||||
|
(defn print-state
|
||||||
|
[state]
|
||||||
|
(doseq [stack push-state/stacks]
|
||||||
|
(printf "%-15s = " stack)
|
||||||
|
(prn (if (get state stack) (get state stack) '()))
|
||||||
|
(flush)))
|
||||||
|
@ -21,9 +21,9 @@
|
|||||||
(assoc empty-push-state :input {:in1 "I can hear you."})
|
(assoc empty-push-state :input {:in1 "I can hear you."})
|
||||||
1000)
|
1000)
|
||||||
|
|
||||||
#_(push-from-plushy (make-random-plushy default-instructions 20))
|
#_(plushy->push (make-random-plushy default-instructions 20))
|
||||||
|
|
||||||
#_(interpret-program (push-from-plushy (make-random-plushy default-instructions 20))
|
#_(interpret-program (plushy->push (make-random-plushy default-instructions 20))
|
||||||
(assoc empty-push-state :input {:in1 "I can hear you."})
|
(assoc empty-push-state :input {:in1 "I can hear you."})
|
||||||
1000)
|
1000)
|
||||||
|
|
||||||
|
@ -1,5 +1,5 @@
|
|||||||
(ns propeller.variation
|
(ns propeller.variation
|
||||||
(:use [propeller selection]))
|
(:require [propeller.selection :refer :all]))
|
||||||
|
|
||||||
(defn crossover
|
(defn crossover
|
||||||
"Crosses over two individuals using uniform crossover. Pads shorter one."
|
"Crosses over two individuals using uniform crossover. Pads shorter one."
|
||||||
|
Loading…
x
Reference in New Issue
Block a user