Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
4 changes: 3 additions & 1 deletion .gitignore
Original file line number Diff line number Diff line change
Expand Up @@ -24,4 +24,6 @@ cov/*
out
.idea
clojush.iml
.gorilla-port
.gorilla-port
/clojush/
.ipynb_checkpoints/
8 changes: 4 additions & 4 deletions project.clj
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
(defproject clojush "2.32.0-1-SNAPSHOT"
:description "The Push programming language and the PushGP genetic programming
system implemented in Clojure. See http://pushlanguage.com"
system implemented in Clojure. See http://pushlanguage.com"
:license {:name "Eclipse Public License"
:url "http://www.eclipse.org/legal/epl-v10.html"}
:dependencies [[org.clojure/clojure "1.8.0"]
Expand All @@ -12,8 +12,9 @@
[clojure-csv "2.0.1"]
[org.clojure/data.json "0.2.6"]
[clj-random "0.1.7"]
;; https://mvnrepository.com/artifact/org.apache.commons/commons-math3
[org.apache.commons/commons-math3 "3.2"]]
;; https://mvnrepository.com/artifact/org.apache.commons/commons-math3
[org.apache.commons/commons-math3 "3.2"]
[cheshire "5.7.1"]]
:plugins [[lein-codox "0.9.1"]
[lein-shell "0.5.0"]
[lein-gorilla "0.4.0"]
Expand Down Expand Up @@ -53,4 +54,3 @@
;;"-XX:+UseG1GC"
;:jvm-opts ["-Xmx12g" "-Xms12g" "-XX:+UseParallelGC"]
:main clojush.core)

3 changes: 1 addition & 2 deletions run-fly
Original file line number Diff line number Diff line change
Expand Up @@ -25,7 +25,6 @@ homedir="/home/${fly_user}"
rundir="$homedir/runs/$label-$number"
repodir="$rundir/Clojush"
outputdir="$rundir/output"

ssh ${fly_user}@fly.hampshire.edu "mkdir -p $rundir"

rsync \
Expand All @@ -49,7 +48,7 @@ ssh ${fly_user}@fly.hampshire.edu /opt/pixar/tractor-blade-1.7.2/tractor-spool.p
--jobcwd="${repodir}" \
--priority=1 \
--range 1-${n} \
-c "bash -c 'env JAVA_CMD=/usr/java/latest/bin/java /share/apps/bin/lein run $lein_command > $outputdir/RANGE.out 2> $outputdir/RANGE.err'"
-c "bash -c 'env JAVA_CMD=/usr/java/latest/bin/java /share/apps/bin/lein run $lein_command :label $label > $outputdir/RANGE.out 2> $outputdir/RANGE.err'"


echo "Job ID: ${number}"
Expand Down
10 changes: 9 additions & 1 deletion src/clojush/args.clj
Original file line number Diff line number Diff line change
Expand Up @@ -411,7 +411,7 @@
;; When true, will exit the run when there is an individual with a zero-error vector

;;----------------------------------------
;; Arguments related to printing JSON, EDN, or CSV logs
;; Arguments related to printing JSON, EDN, CSV, and remote recording
;;----------------------------------------

:print-csv-logs false
Expand Down Expand Up @@ -450,6 +450,14 @@

:json-log-program-strings false
;; If true, JSON logs will include program strings for each individual.

:record-host nil
;; Should be in the format "<hostname>:<port>"
;; If set, will send logs of each run to a server running on this
;; host
:label nil
;; If set, will send this in the configuration of the run, to the
;; external record
)))

(defn load-push-argmap
Expand Down
4 changes: 3 additions & 1 deletion src/clojush/core.clj
Original file line number Diff line number Diff line change
Expand Up @@ -16,6 +16,7 @@
;; for more details.

(ns clojush.core
(:require [clojush.pushgp.record :as r])
(:use [clojush.pushgp pushgp report])
(:gen-class))

Expand All @@ -30,12 +31,13 @@
This allows one to run an example with a call from the OS shell prompt like:
lein run examples.simple-regression :population-size 3000"
[& args]
(r/new-run!)
(println "Command line args:" (apply str (interpose \space args)))
(let [param-list (map #(if (.endsWith % ".ser")
(str %)
(read-string %))
(rest args))]
(require (symbol (first args)))
(require (symbol (r/config-data! [:problem-file] (first args))))
(let [example-params (eval (symbol (str (first args) "/argmap")))
params (merge example-params (apply sorted-map param-list))]
(println "######################################")
Expand Down
2 changes: 2 additions & 0 deletions src/clojush/problems/software/replace_space_with_newline.clj
Original file line number Diff line number Diff line change
Expand Up @@ -160,6 +160,8 @@
(println "Outputs of best individual on training cases:")
(error-function best-program :train true)
(println ";;******************************")
;; return best individual with tests errors added so that those are recorded
(assoc best :test-errors best-test-errors)
)) ;; To do validation, could have this function return an altered best individual
;; with total-error > 0 if it had error of zero on train but not on validation
;; set. Would need a third category of data cases, or a defined split of training cases.
Expand Down
13 changes: 11 additions & 2 deletions src/clojush/pushgp/pushgp.clj
Original file line number Diff line number Diff line change
@@ -1,7 +1,8 @@
(ns clojush.pushgp.pushgp
(:require [clojure.java.io :as io]
[clj-random.core :as random]
[clojure.repl :as repl])
[clojure.repl :as repl]
[clojush.pushgp.record :as r])
(:use [clojush args globals util pushstate random individual evaluate simplification translate]
[clojush.instructions boolean code common numbers random-instructions string char vectors
tag zip return input-output genome]
Expand Down Expand Up @@ -144,13 +145,18 @@
([args]
(reset! timer-atom (System/currentTimeMillis))
(load-push-argmap args)
(when (some? (:record-host @push-argmap))
(r/host! (str (:record-host @push-argmap))))
(random/with-rng (random/make-mersennetwister-rng (:random-seed @push-argmap))
;; set globals from parameters
(reset-globals)
(initial-report @push-argmap) ;; Print the inital report
(print-params @push-argmap)
(r/uuid! (:run-uuid @push-argmap))
(print-params (r/config-data! [:argmap] (dissoc @push-argmap :run-uuid)))
(check-genetic-operator-probabilities-add-to-one @push-argmap)
(timer @push-argmap :initialization)
(when (:print-timings @push-argmap)
(r/config-data! [:initialization-ms] (:initialization @timer-atom)))
(println "\n;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;")
(println "\nGenerating initial population...") (flush)
(let [pop-agents (make-pop-agents @push-argmap)
Expand All @@ -161,6 +167,7 @@
;(println)
;; Main loop
(loop [generation 0]
(r/new-generation! generation)
(println "Processing generation:" generation) (flush)
(population-translate-plush-to-push pop-agents @push-argmap)
(timer @push-argmap :reproduction)
Expand All @@ -183,6 +190,8 @@
;; report and check for success
(let [[outcome best] (report-and-check-for-success (vec (doall (map deref pop-agents)))
generation @push-argmap)]
(r/generation-data! [:outcome] outcome)
(r/end-generation!)
(cond (= outcome :failure) (do (printf "\nFAILURE\n")
(if (:return-simplified-on-failure @push-argmap)
(auto-simplify best
Expand Down
114 changes: 114 additions & 0 deletions src/clojush/pushgp/record.clj
Original file line number Diff line number Diff line change
@@ -0,0 +1,114 @@
;;; Records the results of runs to an external server

;; Use documented in https://push-language.hampshire.edu/t/recording-and-analyzing-experimental-results/830

;; If `record-host` is set in the arguments, then we should send
;; send data about each run, as it progresses, to that host for archival
;; and monitoring purposes.

;; The functions in this file are stateful and should be called in this order:
;;
;; (new-run! uuid! config-data!* (new-generation! generation-data!* end-generation!)*)*
;;
;; Currently it doesn't enforce this and if you call a method when you shouldn't
;; the results are unkown.
;; Also it will not send anything over the network until `host!` is called,
;; before that, `end-generation!` will be a no-op.

(ns clojush.pushgp.record
(:require [clojure.java.io]
[cheshire.core]
[cheshire.generate]
[clojure.string]))

;; write functions as strings
(cheshire.generate/add-encoder
clojure.lang.AFunction
cheshire.generate/encode-str)

(def hostname-and-port (atom nil))
(def writer (atom nil))

(defn- ->writer
; https://github.com/clojure-cookbook/clojure-cookbook/blob/master/05_network-io/5-09_tcp-client.asciidoc
[]
(let [[hostname port] @hostname-and-port]
(-> (java.net.Socket. hostname port)
clojure.java.io/writer)))

(defn- set-writer!
; Tries to get a writer to send data on, and if it fails, retries every
; 5 seconds
[]
(println "Trying to connect to external server for recording at " @hostname-and-port "...")
(try
(reset! writer (->writer))
(catch java.net.ConnectException _
(Thread/sleep 5000)
(set-writer!))))

(defn host! [host-str]
(let [[hostname port-str] (clojure.string/split host-str #":")]
(reset! hostname-and-port [hostname (int (bigint port-str))])
(set-writer!)))

(defn- write-data! [data]
(when (some? @hostname-and-port)
(println "Trying to record data to external server...")
(try
(do
(cheshire.core/generate-stream data @writer)
(.newLine @writer)
(.flush @writer))
(catch java.net.SocketException _
(set-writer!)
(write-data! data)))))

(def data (atom {}))


;; Stores a configuration option for the run, for the sequence of `ks` and value `v`
;; i.e. (config-data! [:git-uuid] "abc-def")
(defn config-data! [ks v]
(swap! data assoc-in (cons :config ks) v)
v)

(defn seconds-since-epoch
;; http://stackoverflow.com/a/17432411
;; because Spark interprets numbers as dates in this format when in JSON
[]
(quot (System/currentTimeMillis) 1000))

;; Resets the run data and saves the start time. Should be called at the
;; begining of a run
(defn new-run! []
(reset! data {:config {:start-time (seconds-since-epoch)}}))

(defn uuid! [uuid]
(swap! data assoc :uuid uuid))

;; Resets the generation data and should be called at the begining of
;; each generation
(defn new-generation! [index]
(swap!
data
assoc
:index index
:generation {:start-time (seconds-since-epoch)}))


;; Stores data about the generation, i.e.
;; (generation-data! [:best :error] [1 2 3 10])
(defn generation-data! [ks v]
(swap! data assoc-in (cons :generation ks) v)
v)

;; Sends the data for the current generation over the network to be recorded
;; Also sends the configuration with each generation
(defn end-generation! []
(let [{:keys [generation uuid index config]} @data]
(write-data!
(assoc generation
:config-uuid uuid
:index index
:config config))))
Loading