Namespace cleanup and add polymorphic instructions

This commit is contained in:
mcgirjau 2020-06-24 22:30:25 -04:00
parent 73b3963b90
commit f04804b00b
17 changed files with 233 additions and 85 deletions

View File

@ -1,9 +1,9 @@
(ns propeller.core (ns propeller.core
(:gen-class) (:gen-class)
(:require [propeller.push.instructions boolean char code input-output numeric random string]) (:require [propeller.gp :refer :all]
(:use propeller.gp [propeller.push.core :refer :all]
propeller.push.instructions (propeller.problems [simple-regression :refer :all]
[propeller.problems simple-regression string-classification])) [string-classification :refer :all])))
(defn -main (defn -main
"Runs propel-gp, giving it a map of arguments." "Runs propel-gp, giving it a map of arguments."

View File

@ -1,5 +1,5 @@
(ns propeller.genome (ns propeller.genome
(:use propeller.push.instructions)) (:require [propeller.push.core :refer :all]))
(defn plushy->push (defn plushy->push
"Returns the Push program expressed by the given plushy representation." "Returns the Push program expressed by the given plushy representation."

View File

@ -1,5 +1,7 @@
(ns propeller.gp (ns propeller.gp
(:use [propeller genome variation])) (:require [propeller.push.core :refer [instruction-table]]
(propeller [genome :refer :all]
[variation :refer :all])))
(defn report (defn report
"Reports information each generation." "Reports information each generation."
@ -24,7 +26,15 @@
[{:keys [population-size max-generations error-function instructions [{:keys [population-size max-generations error-function instructions
max-initial-plushy-size] max-initial-plushy-size]
:as argmap}] :as argmap}]
(println "Starting GP with args:" argmap) ;;
(println "Starting GP with args: " argmap)
;;
(do (print "Registering instructions... ")
(require '[propeller.push.instructions boolean char code input-output
numeric polymorphic string])
(println "Done. Registered instructions:")
(println (sort (keys @instruction-table))))
;;
(loop [generation 0 (loop [generation 0
population (repeatedly population (repeatedly
population-size population-size

View File

@ -1,6 +1,7 @@
(ns propeller.problems.string-classification (ns propeller.problems.string-classification
(:use propeller.genome (:require [propeller.genome :refer :all]
[propeller.push state interpreter])) (propeller.push [state :refer :all]
[interpreter :refer :all])))
;; ============================================================================= ;; =============================================================================
;; String classification ;; String classification

View File

@ -1,4 +1,4 @@
(ns propeller.push.instructions (ns propeller.push.core
(:require [propeller.push.state :refer [get-args-from-stacks (:require [propeller.push.state :refer [get-args-from-stacks
push-to-stack]])) push-to-stack]]))

View File

@ -1,12 +1,10 @@
(ns propeller.push.instructions.boolean (ns propeller.push.instructions.boolean
(:require [propeller.push.instructions :refer [def-instruction]] (:require [propeller.push.core :refer [def-instruction]]
[propeller.push.utils :refer [make-instruction]])) [propeller.push.utils :refer [make-instruction]]))
;; Pushes TRUE if the top two BOOLEANs are equal, and FALSE otherwise ;; =============================================================================
(def-instruction ;; BOOLEAN Instructions
:boolean_= ;; =============================================================================
(fn [state]
(make-instruction state = [:boolean :boolean] :boolean)))
;; Pushes the logical AND of the top two BOOLEANs ;; Pushes the logical AND of the top two BOOLEANs
(def-instruction (def-instruction

View File

@ -1,8 +1,12 @@
(ns propeller.push.instructions.char (ns propeller.push.instructions.char
(:require [propeller.push.instructions :refer [def-instruction]] (:require [propeller.push.core :refer [def-instruction]]
[propeller.push.utils :refer [make-instruction]] [propeller.push.utils :refer [make-instruction]]
[tools.character :as char])) [tools.character :as char]))
;; =============================================================================
;; CHAR Instructions
;; =============================================================================
;; 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
(def-instruction (def-instruction
:char_isletter :char_isletter
@ -22,13 +26,14 @@
(fn [state] (fn [state]
(make-instruction state char/is-whitespace [:char] :boolean))) (make-instruction state char/is-whitespace [:char] :boolean)))
;; Pops the STRING stack and pushes the top element's constituent characters ;; Pops the FLOAT stack, converts the top item to a whole number, and pushes
;; onto the CHAR stack, in order. For instance, "hello" will result in the ;; its corresponding ASCII value onto the CHAR stack. Whole numbers larger than
;; top of the CHAR stack being o l l e h ;; 128 will be reduced modulo 128. For instance, 248.45 will result in x being
;; pushed.
(def-instruction (def-instruction
:char_allfromstring :char_fromfloat
(fn [state] (fn [state]
(make-instruction state #(map char %) [:string] :char))) (make-instruction state #(char (mod (long %) 128)) [:float] :char)))
;; Pops the INTEGER stack and pushes the top element's corresponding ASCII ;; Pops the INTEGER stack and pushes the top element's corresponding ASCII
;; value onto the CHAR stack. Integers larger than 128 will be reduced modulo ;; value onto the CHAR stack. Integers larger than 128 will be reduced modulo
@ -38,11 +43,10 @@
(fn [state] (fn [state]
(make-instruction state #(char (mod % 128)) [:integer] :char))) (make-instruction state #(char (mod % 128)) [:integer] :char)))
;; Pops the FLOAT stack, converts the top item to a whole number, and pushes ;; Pops the STRING stack and pushes the top element's constituent characters
;; its corresponding ASCII value onto the CHAR stack. Whole numbers larger than ;; onto the CHAR stack, in order. For instance, "hello" will result in the
;; 128 will be reduced modulo 128. For instance, 248.45 will result in x being ;; top of the CHAR stack being o l l e h
;; pushed.
(def-instruction (def-instruction
:char_fromfloat :char_allfromstring
(fn [state] (fn [state]
(make-instruction state #(char (mod (long %) 128)) [:float] :char))) (make-instruction state #(map char %) [:string] :char)))

View File

@ -1,8 +1,12 @@
(ns propeller.push.instructions.code (ns propeller.push.instructions.code
(:require [propeller.push.instructions :refer [def-instruction]] (:require [propeller.push.core :refer [def-instruction]]
[propeller.push.state :as state] [propeller.push.state :as state]
[propeller.push.utils :refer [make-instruction]])) [propeller.push.utils :refer [make-instruction]]))
;; =============================================================================
;; CODE and EXEC Instructions
;; =============================================================================
(def-instruction (def-instruction
:exec_dup :exec_dup
(fn [state] (fn [state]

View File

@ -1,6 +1,10 @@
(ns propeller.push.instructions.input-output (ns propeller.push.instructions.input-output
(:require [propeller.push.state :as state] (:require [propeller.push.state :as state]
[propeller.push.instructions :refer [def-instruction]])) [propeller.push.core :refer [def-instruction]]))
;; =============================================================================
;; INPUT and OUTPUT Instructions
;; =============================================================================
;; Pushes the input labeled :in1 on the inputs map onto the :exec stack ;; Pushes the input labeled :in1 on the inputs map onto the :exec stack
(def-instruction (def-instruction

View File

@ -1,31 +1,37 @@
(ns propeller.push.instructions.numeric (ns propeller.push.instructions.numeric
(:require [propeller.push.instructions :refer [def-instruction]] (:require [propeller.push.core :refer [def-instruction]]
[propeller.push.utils :refer [generate-functions [propeller.push.utils :refer [generate-functions
make-instruction]] make-instruction]]
[tools.math :as math])) [tools.math :as math]))
;; ============================================================================= ;; =============================================================================
;; FLOAT and INTEGER (polymorphic) ;; FLOAT and INTEGER Instructions (polymorphic)
;; ============================================================================= ;; =============================================================================
;; Pushes TRUE onto the BOOLEAN stack if the top two items are equal, and
;; FALSE otherwise
(defn- _=
[stack state]
(make-instruction state = [stack stack] :boolean))
;; Pushes TRUE onto the BOOLEAN stack if the second item is greater than the top ;; Pushes TRUE onto the BOOLEAN stack if the second item is greater than the top
;; item, and FALSE otherwise ;; item, and FALSE otherwise
(defn- _> (defn- _>
[stack state] [stack state]
(make-instruction state > [stack stack] :boolean)) (make-instruction state > [stack stack] :boolean))
;; Pushes TRUE onto the BOOLEAN stack if the second item is greater than or
;; equal to the top item, and FALSE otherwise
(defn- _>=
[stack state]
(make-instruction state >= [stack stack] :boolean))
;; Pushes TRUE onto the BOOLEAN stack if the second item is less than the top ;; Pushes TRUE onto the BOOLEAN stack if the second item is less than the top
;; item, and FALSE otherwise ;; item, and FALSE otherwise
(defn- _< (defn- _<
[stack state] [stack state]
(make-instruction state < [stack stack] :boolean)) (make-instruction state < [stack stack] :boolean))
;; Pushes TRUE onto the BOOLEAN stack if the second item is less than or equal
;; to the top item, and FALSE otherwise
(defn- _<=
[stack state]
(make-instruction state <= [stack stack] :boolean))
;; Pushes the sum of the top two items onto the same stack ;; Pushes the sum of the top two items onto the same stack
(defn- _+ (defn- _+
[stack state] [stack state]
@ -48,7 +54,7 @@
[stack state] [stack state]
(make-instruction state (make-instruction state
#(if (zero? %2) #(if (zero? %2)
(list %1 %2) ; push both items back (list %1 %2) ; push both items back (NOOP)
(quot %1 %2)) (quot %1 %2))
[stack stack] [stack stack]
stack)) stack))
@ -61,7 +67,7 @@
[stack state] [stack state]
(make-instruction state (make-instruction state
#(if (zero? %2) #(if (zero? %2)
(list %1 %2) ; push both items back (list %1 %2) ; push both items back (NOOP)
(mod %1 %2)) (mod %1 %2))
[stack stack] [stack stack]
stack)) stack))
@ -80,21 +86,43 @@
(defn- _fromboolean (defn- _fromboolean
[stack state] [stack state]
(make-instruction state (make-instruction state
#((if (= stack :float) float int) (if % 1 0)) #((if (= stack :integer) int float) (if % 1 0))
[:boolean] [:boolean]
stack)) stack))
;; Automate type-specific function generation. All resulting functions take a ;; Pushes the ASCII value of the top CHAR
;; Push state as their only argument. For FLOAT and INTEGER, create one of each (defn- _fromchar
;; of the 11 following type-specific functions: =, >, <, +, -, *, QUOT, %, MAX, [stack state]
;; MIN, and FROMBOOLEAN. (22 functions total, with syntax e.g. integer_=, (make-instruction state (if (= stack :integer) int float) [:char] stack))
;; float_min etc.)
;; Pushes the value of the top STRING, if it can be parsed as a number.
;; Otherwise, acts as a NOOP
(defn- _fromstring
[stack state]
(make-instruction state
#(try ((if (= stack :integer) int float) (read-string %))
(catch Exception e))
[:string]
stack))
;; Pushes the increment (i.e. +1) of the top item of the stack
(defn- _inc
[stack state]
(make-instruction state inc [stack] stack))
;; Pushes the decrement (i.e. -1) of the top item of the stack
(defn- _dec
[stack state]
(make-instruction state dec [stack] stack))
;; 2 types x 16 functions = 32 instructions
(generate-functions (generate-functions
[:float :integer] [:float :integer]
[_=, _>, _<, _+, _-, _*, _quot, _%, _max, _min, _fromboolean]) [_> _>= _< _<= _+ _- _* _quot _% _max _min _inc _dec
_fromboolean _fromchar _fromstring])
;; ============================================================================= ;; =============================================================================
;; FLOAT only ;; FLOAT Instructions only
;; ============================================================================= ;; =============================================================================
;; Pushes the cosine of the top FLOAT ;; Pushes the cosine of the top FLOAT
@ -115,20 +143,14 @@
(fn [state] (fn [state]
(make-instruction state math/tan [:float] :float))) (make-instruction state math/tan [:float] :float)))
;; Pushes the tangent of the top FLOAT ;; Pushes the floating point version of the top INTEGER
(def-instruction
:float_tan
(fn [state]
(make-instruction state math/tan [:float] :float)))
;; Pushes a floating point version of the top INTEGER
(def-instruction (def-instruction
:float_frominteger :float_frominteger
(fn [state] (fn [state]
(make-instruction state math/tan [:float] :float))) (make-instruction state float [:integer] :float)))
;; ============================================================================= ;; =============================================================================
;; INTEGER only ;; INTEGER Instructions only
;; ============================================================================= ;; =============================================================================
;; Pushes the result of truncating the top FLOAT towards negative infinity ;; Pushes the result of truncating the top FLOAT towards negative infinity

View File

@ -0,0 +1,110 @@
(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]]))
;; =============================================================================
;; Polymorphic Instructions
;;
;; (for all types, with the exception of non-data stacks like auxiliary, tag,
;; input, and output)
;; =============================================================================
;; Pushes TRUE onto the BOOLEAN stack if the top two items are equal.
;; Otherwise FALSE
(defn- _=
[stack state]
(make-instruction state = [stack stack] :boolean))
;; Duplicates the top item of the stack. Does not pop its argument (since that
;; would negate the effect of the duplication)
(defn- _dup
[stack state]
(let [top-item (peek-stack state stack)]
(if (empty-stack? state stack)
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
;; number n is determined by the top INTEGER. For n = 0, equivalent to POP.
;; For n = 1, equivalent to NOOP. For n = 2, equivalent to DUP. Negative values
;; of n are treated as 0.
(defn- _duptimes
[stack state]
(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)]
nil)
state))
(defn- _dupitems
[stack state]
())
;; 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)))
;; Empties the given stack
(defn- _flush
[stack state]
())
;; Pops the given stack
(defn- _pop
[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)
(defn- _rot
[stack state]
())
;; Inserts the top item deeper into the stack, using the top INTEGER to
;; determine how deep
(defn- _shove
[stack state]
())
;; Pushes the given stack's depth onto the INTEGER stack
(defn- _stackdepth
[stack state]
())
;; Swaps the top two items on the stack
(defn- _swap
[stack state]
())
;; Removes an indexed item from deep in the stack. The top INTEGER is used to
;; determine how deep to yank from
(defn- _yank
[stack state]
())
;; Pushes a copy of an indexed item deep in the stack, without removing it.
;; The top INTEGER is used to determine how deep to yankdup from
(defn- _yankdup
[stack state]
())
;; 5 types x 1 function = 5 instructions
(generate-functions [:boolean :char :float :integer :string] [_=])
;; 8 types x 12 function = 96 instructions
(generate-functions
[:boolean :char :code :exec :float :integer :string :zip]
[_dup _duptimes _dupitems _empty _flush _pop _rot _shove _stackdepth
_swap _yank _yankdup])

View File

@ -1,17 +0,0 @@
(ns propeller.push.instructions.random
(:require [propeller.push.instructions :refer [def-instruction]]))
;;; Pushes a random BOOLEAN
;(def-instruction
; :boolean_rand
; (fn [state]
; (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)]
; ()))

View File

@ -1,7 +1,11 @@
(ns propeller.push.instructions.string (ns propeller.push.instructions.string
(:require [propeller.push.instructions :refer [def-instruction]] (:require [propeller.push.core :refer [def-instruction]]
[propeller.push.utils :refer [make-instruction]])) [propeller.push.utils :refer [make-instruction]]))
;; =============================================================================
;; STRING Instructions
;; =============================================================================
(def-instruction (def-instruction
:string_= :string_=
(fn [state] (fn [state]

View File

@ -1,5 +1,5 @@
(ns propeller.push.interpreter (ns propeller.push.interpreter
(:require [propeller.push.instructions :refer [instruction-table]]) (:require [propeller.push.core :refer [instruction-table]])
(:require [propeller.push.state :refer :all])) (:require [propeller.push.state :refer :all]))
(defn interpret-one-step (defn interpret-one-step

View File

@ -58,7 +58,9 @@
(defn push-to-stack (defn push-to-stack
"Pushes item(s) onto stack." "Pushes item(s) onto stack."
[state stack items] [state stack items]
(update state stack (if (seq? items) into conj) items)) (let [items-list (if (coll? items) items (list items))
items-list-no-nil (filter #(not (nil? %)) items-list)] ; do not push nil items
(update state stack into items-list-no-nil)))
(defn get-args-from-stacks (defn get-args-from-stacks
"Takes a state and a collection of stacks to take args from. If there are "Takes a state and a collection of stacks to take args from. If there are

View File

@ -1,6 +1,6 @@
(ns propeller.push.utils (ns propeller.push.utils
(:require [propeller.push.instructions :refer [def-instruction]] (:require [propeller.push.core :refer [def-instruction]]
[propeller.push.state :as push-state])) [propeller.push.state :refer :all]))
;; A utility function for making Push instructions. Takes a state, a function ;; 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 ;; to apply to the args, the stacks to take the args from, and the stack to
@ -8,12 +8,12 @@
;; given stacks), and pushes the result onto the return-stack ;; given stacks), and pushes the result onto the return-stack
(defn make-instruction (defn make-instruction
[state function arg-stacks return-stack] [state function arg-stacks return-stack]
(let [popped-args (push-state/get-args-from-stacks state arg-stacks)] (let [popped-args (get-args-from-stacks state arg-stacks)]
(if (= popped-args :not-enough-args) (if (= popped-args :not-enough-args)
state state
(let [result (apply function (:args popped-args)) (let [result (apply function (:args popped-args))
new-state (:state popped-args)] new-state (:state popped-args)]
(push-state/push-to-stack new-state return-stack result))))) (push-to-stack new-state return-stack result)))))
;; Given a sequence of stacks, e.g. [:float :integer], and a sequence of suffix ;; Given a sequence of stacks, e.g. [:float :integer], and a sequence of suffix
;; function strings, e.g. [_+, _*, _=], automates the generation of all possible ;; function strings, e.g. [_+, _*, _=], automates the generation of all possible
@ -28,7 +28,7 @@
;; Pretty-prints a Push state, for logging or debugging purposes ;; Pretty-prints a Push state, for logging or debugging purposes
(defn print-state (defn print-state
[state] [state]
(doseq [stack push-state/stacks] (doseq [stack stacks]
(printf "%-15s = " stack) (printf "%-15s = " stack)
(prn (if (get state stack) (get state stack) '())) (prn (if (get state stack) (get state stack) '()))
(flush))) (flush)))

View File

@ -1,7 +1,13 @@
(ns propeller.session (ns propeller.session
(:use [propeller core gp variation selection genome] (:require (propeller [gp :refer :all]
[propeller.push interpreter instructions state] [variation :refer :all]
[propeller.problems simple-regression string-classification])) [selection :refer :all]
[genome :refer :all])
(propeller.push [interpreter :refer :all]
[core :refer :all]
[state :refer :all])
(propeller.problems [simple-regression :refer :all]
[string-classification :refer :all])))
#_(interpret-program '(1 2 integer_+) empty-push-state 1000) #_(interpret-program '(1 2 integer_+) empty-push-state 1000)