Skip to content

Tracing a Push program with Clojush

Lee Spector edited this page Feb 16, 2018 · 3 revisions

Evolved Push programs are often long, and certainly mysterious. If a (simplified) program is small, sometimes you can just work through it to figure out what it's doing. But, more often than not, this would take longer than it's worth, and going through them by hand is also quite error-prone.

Clojush provides a tracing facility that runs a specified program, printing the state of the stacks after every step of the interpreter.

To use this go into your Clojush top-level folder and start a REPL:

lein repl

First, you'll need to use some namespaces:

(use 'clojush.pushstate)
(use 'clojush.interpreter)

Then you need to set up the initial state of your interpreter. This typically just involves pushing your inputs onto a default state. If, for example, your program has two inputs, a boolean value in in1 and an integer value in in2, you might do something like this to push the inputs false and 60 onto the appropriate stacks:

(def start-state (push-item false :input (push-item 60 :input (make-push-state))))

Just to make things a little cleaner, I'm going to give a name to the program I want to run:

(def my-program '(integer_eq boolean_pop exec_y (in2 91 integer_lt exec_rot (boolean_dup integer_inc) (exec_y (exec_shove (exec_do*while (100 integer_lt exec_when () in2 integer_min integer_sub 59 boolean_xor in2 exec_s (integer_lt boolean_xor in2 exec_s (integer_lt integer_sub exec_dup integer_flush) (boolean_swap boolean_shove) (in1 integer_mult exec_yankdup exec_swap (boolean_eq boolean_rot in1 integer_fromboolean exec_swap (integer_stackdepth boolean_yank) ()) ())) () ())))) ())))

Then you can finally trace the program:

(run-push my-program start-state true)

The third argument (true) is optional. Without it run-push will simply run your program and return the final state. With it included and set to true, run-push prints out the contents of all the stacks (including quite a few you're probably not using) at every execution step so you can see what's going on.

Out of the box this is going to use the default values of globals like global-evalpush-limit and global-max-points. If you evolved this program in a setup that used different values for those you'll want to set them to "your" values before you call run-push. Otherwise you might get quite different behaviors, e.g., the program might "time out" earlier or later than it did in your evolutionary run, yielding totally different answers.

You can set these parameters to your values by calling reset-globals (which is in clojush.args) with a map of the parameter/value pairs that you want to set, such as:

(reset-globals {:evalpush-limit 100000 :max-points 2000})
Clone this wiki locally