 ; Define train and test cases
 (def mirror-image-train-and-test-cases
   (get-mirror-image-train-and-test mirror-image-data-domains))
+
+(defn mirror-image-evaluate-program-for-behaviors
+  "Evaluates the program on the given list of cases.
+   Returns the behaviors, a list of the outputs of the program on the inputs."
+  [program cases]
+  (doall
+   (for [[[input1 input2] output] cases]
+     (let [final-state (run-push program
+                                 (->> (make-push-state)
+                                      (push-item input2 :input)
+                                      (push-item input1 :input)))]
+       (top-item :boolean final-state)))))
+
+(defn mirror-image-errors-from-behaviors
+  "Takes a list of behaviors across the list of cases and finds the error
+   for each of those behaviors, returning an error vector."
+  [behaviors cases]
+  (map (fn [result correct-output]
+         (if (= result correct-output)
+           0
+           1))
+       behaviors
+       (map second cases)))
+
+(defn mirror-image-error-function
+  "The error function. Takes an individual as input,
+   and returns that individual with :errors and :behaviors set."
+  ([individual]
+   (mirror-image-error-function individual :train))
+  ([individual data-cases] ;; data-cases should be :train or :test
+   (let [cases (case data-cases
+                 :train (first mirror-image-train-and-test-cases)
+                 :test (second mirror-image-train-and-test-cases)
+                 [])
+         behaviors (mirror-image-evaluate-program-for-behaviors (:program individual)
+                                                                 cases)
+         errors (mirror-image-errors-from-behaviors behaviors cases)]
+     (cond
+       (= data-cases :train) (assoc individual :behaviors behaviors :errors errors)
+       (= data-cases :test) (assoc individual :test-errors errors)))))
 
 (defn mirror-image-initial-report
   [argmap]

  "Custom generational report."
  [best population generation error-function report-simplifications]
  (let [best-program (not-lazy (:program best))
        best-test-errors (error-function best-program :test)
        best-total-test-error (apply +' best-test-errors)]
    (println ";;******************************")
    (printf ";; -*- Mirror Image problem report - generation %s\n" generation)(flush)

        (println (format "Test Case  %3d | Error: %s" i (str error)))))
    (println ";;------------------------------")
    (println "Outputs of best individual on training cases:")
    (doseq [[correct-output result] (map vector
                                         (map second (first mirror-image-train-and-test-cases))
                                         (:behaviors best))]
      (println (format "Correct output: %5b | Program output: %s" correct-output (str result))))
    (println ";;******************************")
    )) ;; 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
