Move tools module for ClojureScript compatibility, and style fixes

This commit is contained in:
mcgirjau 2020-06-25 12:57:20 -04:00
parent 64d43756b6
commit 4bd92503a3
20 changed files with 134 additions and 128 deletions

View File

@ -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 %)))))

View File

@ -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))]

View File

@ -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)

View File

@ -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

View File

@ -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})

View File

@ -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

View File

@ -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

View File

@ -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

View File

@ -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

View File

@ -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)

View File

@ -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)

View File

@ -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

View File

@ -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)

View File

@ -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

View File

@ -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})

View File

@ -1,4 +1,4 @@
(ns tools.calculus)
(ns propeller.tools.calculus)
(defonce ^:const dx 0.0001)

View File

@ -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."

View File

@ -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

View File

@ -1,4 +1,4 @@
(ns tools.math)
(ns propeller.tools.math)
(defonce PI #?(:clj Math/PI
:cljs js/Math.PI))

View File

@ -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."