 
 
 
+(defn bioavailability-error-function
+  [program]
+    (doall
+      (for [fitness-case (:train bioavailability-fitness-cases)]
+        (let [input (butlast fitness-case)
+              output (last fitness-case)
+              state (run-push program
+                              (assoc (make-push-state)
+                                     :auxiliary
+                                     input))
+              top-float (top-item :float state)]
+          (if (number? top-float)
+            (abs (- output top-float))
+            10000.0)))))
+
+;(run-push '(4 5 integer_add x0 x1 x2 float_add x240)
+;          (assoc (make-push-state)
+;                 :auxiliary
+;                 (butlast (first (:train (define-fitness-cases))))))
+;
+;(evaluate-individual (make-individual :program (random-code 100 bioavailability-atom-generators))
+;                     bioavailability-error-function
+;                     (new java.util.Random))
+;
+;(evaluate-individual (make-individual :program '(x2 x19 float_mult))
+;                     bioavailability-error-function
+;                     (new java.util.Random))
+
+(pushgp
+  :error-function bioavailability-error-function
+  :atom-generators bioavailability-atom-generators
+  :max-points 500
+  :evalpush-limit 500
+  :population-size 200
+  :max-generations 50
+  :mutation-probability 0.1
+  :crossover-probability 0.8
+  :simplification-probability 0.05
+  :tournament-size 6
+  :trivial-geography-radius 10
+  :node-selection-method :size-tournament
+  :node-selection-tournament-size 2
+  :report-simplifications 0
+  :final-report-simplifications 1000
+  )

;; range [0.0, 100.0].
;;
;; The experimental procedure is copied from the paper below. This
;; procedure uses 70% of the test cases as a training set, and the
;; remaining 30% as a test set. Each time this file is run, it will
;; select random training (251 test cases) and test (108 test cases)
;; sets from the test cases to use throughout the entire run.
;;
;; See this paper for more information about this problem:
;; Sara Silva and Leonardo Vanneschi. 2009. Operator equalisation,


;(map last (read-data))


(defn define-fitness-cases
  "Returns a map with two keys: train and test. Train maps to a
   subset of 251 random fitness cases (70%), and test maps to the
   remaining 108 fitness cases (30%). These sets are different each
   time this is called."
  []
  (let [fitness-cases-shuffled (shuffle (read-data))
        train-num 251]
    {:train (subvec fitness-cases-shuffled 0 train-num)
     :test (subvec fitness-cases-shuffled train-num)}))

;; Define the fitness cases. Do this once per run, so that train and test
;; subsets stay the same throughout a run.
(def bioavailability-fitness-cases (define-fitness-cases))


;; Helper functions to get specific train and test cases
;(defn train-fitness-case
;  "Returns train fitness case number n for this run."
;  [n]
;  (nth (:train bioavailability-fitness-cases) n))
;
;(defn test-fitness-case
;  "Returns test fitness case number n for this run."
;  [n]
;  (nth (:test bioavailability-fitness-cases) n))


;; I want x0 through x240 to be instructions that, when executed, push
;; the float from that column onto the float stack.
(doseq [[numb symb] (map #(vector % (symbol (str "x" %))) (range 241))]
  (eval `(define-registered ~symb (fn [state#] (push-item (stack-ref :auxiliary ~numb state#) :float state#)))))
  
;(sort (map str (vec @registered-instructions)))


;; This definition of atom-generators makes it so that choosing a terminal
