lspector / Clojush

The Push programming language and the PushGP genetic programming system implemented in Clojure.
http://hampshire.edu/lspector/push.html
Eclipse Public License 1.0
330 stars 92 forks source link

Tutorial example throws `Undefined instruction: ...` exception #275

Closed jjttjj closed 5 years ago

jjttjj commented 5 years ago

Starting a fresh repl in my project (which depends on clojush 3.19.0) and inputting the following excerpt from the tutorial worksheet throws an exception:

(use 'clojush.ns)
(use-clojush)
(pushgp
 {:error-function
  (fn [{:keys [program] :as individual}]
    (assoc individual
           :errors (vec
                    (for [input (mapv float (range 10))]
                      (let [ouput (->> (make-push-state)
                                       (push-item input :input)
                                       (run-push program)
                                       (top-item :float))])))))
  :atom-generators (list 'in1
                         'float_div
                         'float_mult
                         'float_add
                         'float_sub)
  :population-size 100
  :parent-selection :tournament
  :use-single-thread true})
   Undefined instruction: ...

           interpreter.clj:   44  clojush.interpreter/execute-instruction
           interpreter.clj:    9  clojush.interpreter/execute-instruction
           interpreter.clj:   83  clojush.interpreter/eval-push
           interpreter.clj:   48  clojush.interpreter/eval-push
           interpreter.clj:  120  clojush.interpreter/run-push
           interpreter.clj:  102  clojush.interpreter/run-push
           interpreter.clj:  107  clojush.interpreter/run-push
           interpreter.clj:  102  clojush.interpreter/run-push
                      REPL:  136  myns.gptut/eval60944/fn/iter/fn/fn
                      REPL:  133  myns.gptut/eval60944/fn/iter/fn
              LazySeq.java:   42  clojure.lang.LazySeq/sval
              LazySeq.java:   51  clojure.lang.LazySeq/seq
                   RT.java:  531  clojure.lang.RT/seq
LazilyPersistentVector.java:   44  clojure.lang.LazilyPersistentVector/create
                  core.clj:  377  clojure.core/vec
                  core.clj:  367  clojure.core/vec
                      REPL:  132  myns.gptut/eval60944/fn
              evaluate.clj:   74  clojush.evaluate/evaluate-individual
              evaluate.clj:   57  clojush.evaluate/evaluate-individual
                  AFn.java:  165  clojure.lang.AFn/applyToHelper
                  AFn.java:  144  clojure.lang.AFn/applyTo
                 Atom.java:   79  clojure.lang.Atom/swap
                  core.clj: 2355  clojure.core/swap!
                  core.clj: 2345  clojure.core/swap!
               RestFn.java:  497  clojure.lang.RestFn/invoke
                pushgp.clj:   92  clojush.pushgp.pushgp/compute-errors/fn
                  core.clj: 2760  clojure.core/map/fn
              LazySeq.java:   42  clojure.lang.LazySeq/sval
              LazySeq.java:   51  clojure.lang.LazySeq/seq
                   RT.java:  531  clojure.lang.RT/seq
                  core.clj:  137  clojure.core/seq
                  core.clj: 3133  clojure.core/dorun
                  core.clj: 3133  clojure.core/dorun
                pushgp.clj:   92  clojush.pushgp.pushgp/compute-errors
                pushgp.clj:   89  clojush.pushgp.pushgp/compute-errors
                pushgp.clj:  195  clojush.pushgp.pushgp/process-generation
                pushgp.clj:  183  clojush.pushgp.pushgp/process-generation
                pushgp.clj:  301  clojush.pushgp.pushgp/pushgp
                pushgp.clj:  275  clojush.pushgp.pushgp/pushgp
                      REPL:  128  myns.gptut/eval60944
                      REPL:  128  myns.gptut/eval60944
             Compiler.java: 7176  clojure.lang.Compiler/eval
             Compiler.java: 7131  clojure.lang.Compiler/eval
                  core.clj: 3214  clojure.core/eval
                  core.clj: 3210  clojure.core/eval
                  main.clj:  414  clojure.main/repl/read-eval-print/fn
                  main.clj:  414  clojure.main/repl/read-eval-print
                  main.clj:  435  clojure.main/repl/fn
                  main.clj:  435  clojure.main/repl
                  main.clj:  345  clojure.main/repl
               RestFn.java: 1523  clojure.lang.RestFn/invoke
    interruptible_eval.clj:   83  nrepl.middleware.interruptible-eval/evaluate/fn
                  AFn.java:  152  clojure.lang.AFn/applyToHelper
                  AFn.java:  144  clojure.lang.AFn/applyTo
                  core.clj:  665  clojure.core/apply
                  core.clj: 1973  clojure.core/with-bindings*
                  core.clj: 1973  clojure.core/with-bindings*
               RestFn.java:  425  clojure.lang.RestFn/invoke
    interruptible_eval.clj:   81  nrepl.middleware.interruptible-eval/evaluate
    interruptible_eval.clj:   50  nrepl.middleware.interruptible-eval/evaluate
    interruptible_eval.clj:  221  nrepl.middleware.interruptible-eval/interruptible-eval/fn/fn
    interruptible_eval.clj:  189  nrepl.middleware.interruptible-eval/run-next/fn
                  AFn.java:   22  clojure.lang.AFn/run
   ThreadPoolExecutor.java: 1128  java.util.concurrent.ThreadPoolExecutor/runWorker
   ThreadPoolExecutor.java:  628  java.util.concurrent.ThreadPoolExecutor$Worker/run
               Thread.java:  834  java.lang.Thread/run
lspector commented 5 years ago

The error function here is problematic in a coupe of respects. The "let" binds a symbol (ouput, should probably be output) but doesn't return a value. It should return a value, and that value should be a number, which it won't be if the program leaves the :float stack empty, so you need to check for that and return some number (probably a high penalty error). The error for a particular input should reflect the difference between the top float and what it should be, which could come either from data or an equation that your are trying to "re-discover" with GP. In the code below, I've made it the difference between the top float and 3 times the input squared. I also increased the population size. I also added the number 1.0 for it to have as raw material. Anyway, try running this, and it should run without the error you were seeing:

(pushgp
 {:error-function
  (fn [{:keys [program] :as individual}]
    (assoc individual
           :errors (vec
                    (for [input (mapv float (range 10))]
                      (let [output (->> (make-push-state)
                                       (push-item input :input)
                                       (run-push program)
                                       (top-item :float))]
                        (if (number? output)
                          (Math/abs (- output (* input input 3)))
                          1000))))))
  :atom-generators (list 'in1
                         'float_div
                         'float_mult
                         'float_add
                         'float_sub
                         1.0)
  :population-size 1000
  :parent-selection :tournament
  :use-single-thread true})