-
Notifications
You must be signed in to change notification settings - Fork 92
/
count_odds.clj
166 lines (155 loc) · 7.09 KB
/
count_odds.clj
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
;; count_odds.clj
;; Tom Helmuth, thelmuth@cs.umass.edu
;;
;; Problem Source: iJava (http://ijava.cs.umass.edu/)
;;
;; Given a vector of integers with length <= 50, with each
;; integer in [-1000,1000], return the number of integers that are odd.
;;
;; input stack has 1 input vector of integers
(ns clojush.problems.software.count-odds
(:use clojush.pushgp.pushgp
[clojush pushstate interpreter random util globals]
clojush.instructions.tag
[clojure.math numeric-tower combinatorics]
))
; Atom generators
(def count-odds-atom-generators
(concat (list
0
1
2
;;; end constants
(fn [] (- (lrand-int 2001) 1000)) ;Integer ERC
;;; end ERCs
(tag-instruction-erc [:integer :boolean :vector_integer :exec] 1000)
(tagged-instruction-erc 1000)
;;; end tag ERCs
'in1
;;; end input instructions
)
(registered-for-stacks [:integer :boolean :vector_integer :exec])))
;; Define test cases
(defn count-odds-input
"Makes a Count Odds input vector of length len with probability prob of being odd."
[len prob]
(vec (repeatedly len
#(if (< (lrand) prob)
(inc (* 2 (- (lrand-int 1000) 500)))
(* 2 (- (lrand-int 1001) 500))))))
;; A list of data domains for the problem. Each domain is a vector containing
;; a "set" of inputs and two integers representing how many cases from the set
;; should be used as training and testing cases respectively. Each "set" of
;; inputs is either a list or a function that, when called, will create a
;; random element of the set.
(def count-odds-data-domains
[[(list []) 1 0] ;; Empty vector
[(concat (map vector (range -10 11))
(list [-947] [-450] [303] [886])) 25 0] ;; Length 1 vectors
[(list [0 0]
[0 1]
[7 1]
[-9 -1]
[-11 40]
[944 77]) 6 0] ;; Length 2 vectors
[(fn [] (count-odds-input (inc (lrand-int 50)) 1.0)) 9 100] ;; Random length, all odd
[(fn [] (count-odds-input (inc (lrand-int 50)) 0.0)) 9 100] ;; Random length, all even
[(fn [] (count-odds-input (inc (lrand-int 50)) (lrand))) 150 1800] ;; Random length, random prob of odd
])
;;Can make Count Odds test data like this:
;(test-and-train-data-from-domains count-odds-data-domains)
; Helper function for error function
(defn count-odds-test-cases
"Takes a sequence of inputs and gives IO test cases of the form
[input output]."
[inputs]
(map #(vector %
(count (filter odd? %)))
inputs))
; Define error function. For now, each run uses different random inputs
(defn count-odds-error-function
"Returns the error function for the count-odds problem. Takes as
input Count Odds data domains."
[data-domains]
(let [[train-cases test-cases] (map count-odds-test-cases
(test-and-train-data-from-domains data-domains))]
(when true ;; Change to false to not print test cases
(doseq [[i case] (map vector (range) train-cases)]
(println (format "Train Case: %3d | Input/Output: %s" i (str case))))
(doseq [[i case] (map vector (range) test-cases)]
(println (format "Test Case: %3d | Input/Output: %s" i (str case)))))
(fn the-actual-count-odds-error-function
([program]
(the-actual-count-odds-error-function program :train))
([program data-cases] ;; data-cases should be :train or :test
(the-actual-count-odds-error-function program data-cases false))
([program data-cases print-outputs]
(let [behavior (atom '())
errors (doall
(for [[input1 correct-output] (case data-cases
:train train-cases
:test test-cases
[])]
(let [final-state (run-push program
(->> (make-push-state)
(push-item input1 :input)))
result (top-item :integer final-state)]
(when print-outputs
(println (format "Correct output: %2d | Program output: %s" correct-output (str result))))
; Record the behavior
(when @global-print-behavioral-diversity
(swap! behavior conj result))
; Error is integer error
(if (number? result)
(abs (- result correct-output)) ; distance from correct integer
1000) ; penalty for no return value
)))]
(when @global-print-behavioral-diversity
(swap! population-behaviors conj @behavior))
errors)))))
(defn count-odds-report
"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 ";; -*- Count Odds problem report - generation %s\n" generation)(flush)
(println "Test total error for best:" best-total-test-error)
(println (format "Test mean error for best: %.5f" (double (/ best-total-test-error (count best-test-errors)))))
(when (zero? (:total-error best))
(doseq [[i error] (map vector
(range)
best-test-errors)]
(println (format "Test Case %3d | Error: %s" i (str error)))))
(println ";;------------------------------")
(println "Outputs of best individual on training cases:")
(error-function best-program :train true)
(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
;; set. Would need a third category of data cases, or a defined split of training cases.
; Define the argmap
(def argmap
{:error-function (count-odds-error-function count-odds-data-domains)
:atom-generators count-odds-atom-generators
:max-points 1000
:max-genome-size-in-initial-program 250
:evalpush-limit 1500
:population-size 1000
:max-generations 300
:parent-selection :lexicase
:genetic-operator-probabilities {:alternation 0.2
:uniform-mutation 0.2
:uniform-close-mutation 0.1
[:alternation :uniform-mutation] 0.5
}
:alternation-rate 0.01
:alignment-deviation 10
:uniform-mutation-rate 0.01
:problem-specific-report count-odds-report
:print-behavioral-diversity true
:report-simplifications 0
:final-report-simplifications 5000
:max-error 1000
})