AutonLabTruth commited on
Commit
a1e832b
1 Parent(s): 32df36d

Refactored Till Random Mutations

Browse files
Files changed (3) hide show
  1. julia/eval.jl +82 -0
  2. julia/randomMutations.jl +230 -0
  3. julia/sr.jl +2 -311
julia/eval.jl ADDED
@@ -0,0 +1,82 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ # Evaluate an equation over an array of datapoints
2
+ function evalTreeArray(tree::Node)::Union{Array{Float32, 1}, Nothing}
3
+ return evalTreeArray(tree, X)
4
+ end
5
+
6
+
7
+ # Evaluate an equation over an array of datapoints
8
+ function evalTreeArray(tree::Node, cX::Array{Float32, 2})::Union{Array{Float32, 1}, Nothing}
9
+ clen = size(cX)[1]
10
+ if tree.degree == 0
11
+ if tree.constant
12
+ return fill(tree.val, clen)
13
+ else
14
+ return copy(cX[:, tree.val])
15
+ end
16
+ elseif tree.degree == 1
17
+ cumulator = evalTreeArray(tree.l, cX)
18
+ if cumulator === nothing
19
+ return nothing
20
+ end
21
+ op_idx = tree.op
22
+ UNAOP!(cumulator, op_idx, clen)
23
+ @inbounds for i=1:clen
24
+ if isinf(cumulator[i]) || isnan(cumulator[i])
25
+ return nothing
26
+ end
27
+ end
28
+ return cumulator
29
+ else
30
+ cumulator = evalTreeArray(tree.l, cX)
31
+ if cumulator === nothing
32
+ return nothing
33
+ end
34
+ array2 = evalTreeArray(tree.r, cX)
35
+ if array2 === nothing
36
+ return nothing
37
+ end
38
+ op_idx = tree.op
39
+ BINOP!(cumulator, array2, op_idx, clen)
40
+ @inbounds for i=1:clen
41
+ if isinf(cumulator[i]) || isnan(cumulator[i])
42
+ return nothing
43
+ end
44
+ end
45
+ return cumulator
46
+ end
47
+ end
48
+
49
+ # Score an equation
50
+ function scoreFunc(tree::Node)::Float32
51
+ prediction = evalTreeArray(tree)
52
+ if prediction === nothing
53
+ return 1f9
54
+ end
55
+ if weighted
56
+ mse = MSE(prediction, y, weights)
57
+ else
58
+ mse = MSE(prediction, y)
59
+ end
60
+ return mse / baselineMSE + countNodes(tree)*parsimony
61
+ end
62
+
63
+ # Score an equation with a small batch
64
+ function scoreFuncBatch(tree::Node)::Float32
65
+ # batchSize
66
+ batch_idx = randperm(len)[1:batchSize]
67
+ batch_X = X[batch_idx, :]
68
+ prediction = evalTreeArray(tree, batch_X)
69
+ if prediction === nothing
70
+ return 1f9
71
+ end
72
+ size_adjustment = 1f0
73
+ batch_y = y[batch_idx]
74
+ if weighted
75
+ batch_w = weights[batch_idx]
76
+ mse = MSE(prediction, batch_y, batch_w)
77
+ size_adjustment = 1f0 * len / batchSize
78
+ else
79
+ mse = MSE(prediction, batch_y)
80
+ end
81
+ return size_adjustment * mse / baselineMSE + countNodes(tree)*parsimony
82
+ end
julia/randomMutations.jl ADDED
@@ -0,0 +1,230 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ # Randomly convert an operator into another one (binary->binary;
2
+ # unary->unary)
3
+ function mutateOperator(tree::Node)::Node
4
+ if countOperators(tree) == 0
5
+ return tree
6
+ end
7
+ node = randomNode(tree)
8
+ while node.degree == 0
9
+ node = randomNode(tree)
10
+ end
11
+ if node.degree == 1
12
+ node.op = rand(1:length(unaops))
13
+ else
14
+ node.op = rand(1:length(binops))
15
+ end
16
+ return tree
17
+ end
18
+
19
+ # Randomly perturb a constant
20
+ function mutateConstant(
21
+ tree::Node, T::Float32,
22
+ probNegate::Float32=0.01f0)::Node
23
+ # T is between 0 and 1.
24
+
25
+ if countConstants(tree) == 0
26
+ return tree
27
+ end
28
+ node = randomNode(tree)
29
+ while node.degree != 0 || node.constant == false
30
+ node = randomNode(tree)
31
+ end
32
+
33
+ bottom = 0.1f0
34
+ maxChange = perturbationFactor * T + 1.0f0 + bottom
35
+ factor = maxChange^Float32(rand())
36
+ makeConstBigger = rand() > 0.5
37
+
38
+ if makeConstBigger
39
+ node.val *= factor
40
+ else
41
+ node.val /= factor
42
+ end
43
+
44
+ if rand() > probNegate
45
+ node.val *= -1
46
+ end
47
+
48
+ return tree
49
+ end
50
+
51
+ # Add a random unary/binary operation to the end of a tree
52
+ function appendRandomOp(tree::Node)::Node
53
+ node = randomNode(tree)
54
+ while node.degree != 0
55
+ node = randomNode(tree)
56
+ end
57
+
58
+ choice = rand()
59
+ makeNewBinOp = choice < nbin/nops
60
+ if rand() > 0.5
61
+ left = Float32(randn())
62
+ else
63
+ left = rand(1:nvar)
64
+ end
65
+ if rand() > 0.5
66
+ right = Float32(randn())
67
+ else
68
+ right = rand(1:nvar)
69
+ end
70
+
71
+ if makeNewBinOp
72
+ newnode = Node(
73
+ rand(1:length(binops)),
74
+ left,
75
+ right
76
+ )
77
+ else
78
+ newnode = Node(
79
+ rand(1:length(unaops)),
80
+ left
81
+ )
82
+ end
83
+ node.l = newnode.l
84
+ node.r = newnode.r
85
+ node.op = newnode.op
86
+ node.degree = newnode.degree
87
+ node.val = newnode.val
88
+ node.constant = newnode.constant
89
+ return tree
90
+ end
91
+
92
+ # Insert random node
93
+ function insertRandomOp(tree::Node)::Node
94
+ node = randomNode(tree)
95
+ choice = rand()
96
+ makeNewBinOp = choice < nbin/nops
97
+ left = copyNode(node)
98
+
99
+ if makeNewBinOp
100
+ right = randomConstantNode()
101
+ newnode = Node(
102
+ rand(1:length(binops)),
103
+ left,
104
+ right
105
+ )
106
+ else
107
+ newnode = Node(
108
+ rand(1:length(unaops)),
109
+ left
110
+ )
111
+ end
112
+ node.l = newnode.l
113
+ node.r = newnode.r
114
+ node.op = newnode.op
115
+ node.degree = newnode.degree
116
+ node.val = newnode.val
117
+ node.constant = newnode.constant
118
+ return tree
119
+ end
120
+
121
+ # Add random node to the top of a tree
122
+ function prependRandomOp(tree::Node)::Node
123
+ node = tree
124
+ choice = rand()
125
+ makeNewBinOp = choice < nbin/nops
126
+ left = copyNode(tree)
127
+
128
+ if makeNewBinOp
129
+ right = randomConstantNode()
130
+ newnode = Node(
131
+ rand(1:length(binops)),
132
+ left,
133
+ right
134
+ )
135
+ else
136
+ newnode = Node(
137
+ rand(1:length(unaops)),
138
+ left
139
+ )
140
+ end
141
+ node.l = newnode.l
142
+ node.r = newnode.r
143
+ node.op = newnode.op
144
+ node.degree = newnode.degree
145
+ node.val = newnode.val
146
+ node.constant = newnode.constant
147
+ return node
148
+ end
149
+
150
+ function randomConstantNode()::Node
151
+ if rand() > 0.5
152
+ val = Float32(randn())
153
+ else
154
+ val = rand(1:nvar)
155
+ end
156
+ newnode = Node(val)
157
+ return newnode
158
+ end
159
+
160
+ # Return a random node from the tree with parent
161
+ function randomNodeAndParent(tree::Node, parent::Union{Node, Nothing})::Tuple{Node, Union{Node, Nothing}}
162
+ if tree.degree == 0
163
+ return tree, parent
164
+ end
165
+ a = countNodes(tree)
166
+ b = 0
167
+ c = 0
168
+ if tree.degree >= 1
169
+ b = countNodes(tree.l)
170
+ end
171
+ if tree.degree == 2
172
+ c = countNodes(tree.r)
173
+ end
174
+
175
+ i = rand(1:1+b+c)
176
+ if i <= b
177
+ return randomNodeAndParent(tree.l, tree)
178
+ elseif i == b + 1
179
+ return tree, parent
180
+ end
181
+
182
+ return randomNodeAndParent(tree.r, tree)
183
+ end
184
+
185
+ # Select a random node, and replace it an the subtree
186
+ # with a variable or constant
187
+ function deleteRandomOp(tree::Node)::Node
188
+ node, parent = randomNodeAndParent(tree, nothing)
189
+ isroot = (parent === nothing)
190
+
191
+ if node.degree == 0
192
+ # Replace with new constant
193
+ newnode = randomConstantNode()
194
+ node.l = newnode.l
195
+ node.r = newnode.r
196
+ node.op = newnode.op
197
+ node.degree = newnode.degree
198
+ node.val = newnode.val
199
+ node.constant = newnode.constant
200
+ elseif node.degree == 1
201
+ # Join one of the children with the parent
202
+ if isroot
203
+ return node.l
204
+ elseif parent.l == node
205
+ parent.l = node.l
206
+ else
207
+ parent.r = node.l
208
+ end
209
+ else
210
+ # Join one of the children with the parent
211
+ if rand() < 0.5
212
+ if isroot
213
+ return node.l
214
+ elseif parent.l == node
215
+ parent.l = node.l
216
+ else
217
+ parent.r = node.l
218
+ end
219
+ else
220
+ if isroot
221
+ return node.r
222
+ elseif parent.l == node
223
+ parent.l = node.r
224
+ else
225
+ parent.r = node.r
226
+ end
227
+ end
228
+ end
229
+ return tree
230
+ end
julia/sr.jl CHANGED
@@ -19,319 +19,10 @@ include("utils.jl")
19
 
20
  include("Node.jl")
21
 
22
- # Randomly convert an operator into another one (binary->binary;
23
- # unary->unary)
24
- function mutateOperator(tree::Node)::Node
25
- if countOperators(tree) == 0
26
- return tree
27
- end
28
- node = randomNode(tree)
29
- while node.degree == 0
30
- node = randomNode(tree)
31
- end
32
- if node.degree == 1
33
- node.op = rand(1:length(unaops))
34
- else
35
- node.op = rand(1:length(binops))
36
- end
37
- return tree
38
- end
39
-
40
- # Randomly perturb a constant
41
- function mutateConstant(
42
- tree::Node, T::Float32,
43
- probNegate::Float32=0.01f0)::Node
44
- # T is between 0 and 1.
45
-
46
- if countConstants(tree) == 0
47
- return tree
48
- end
49
- node = randomNode(tree)
50
- while node.degree != 0 || node.constant == false
51
- node = randomNode(tree)
52
- end
53
-
54
- bottom = 0.1f0
55
- maxChange = perturbationFactor * T + 1.0f0 + bottom
56
- factor = maxChange^Float32(rand())
57
- makeConstBigger = rand() > 0.5
58
 
59
- if makeConstBigger
60
- node.val *= factor
61
- else
62
- node.val /= factor
63
- end
64
-
65
- if rand() > probNegate
66
- node.val *= -1
67
- end
68
-
69
- return tree
70
- end
71
-
72
- # Evaluate an equation over an array of datapoints
73
- function evalTreeArray(tree::Node)::Union{Array{Float32, 1}, Nothing}
74
- return evalTreeArray(tree, X)
75
- end
76
-
77
-
78
- # Evaluate an equation over an array of datapoints
79
- function evalTreeArray(tree::Node, cX::Array{Float32, 2})::Union{Array{Float32, 1}, Nothing}
80
- clen = size(cX)[1]
81
- if tree.degree == 0
82
- if tree.constant
83
- return fill(tree.val, clen)
84
- else
85
- return copy(cX[:, tree.val])
86
- end
87
- elseif tree.degree == 1
88
- cumulator = evalTreeArray(tree.l, cX)
89
- if cumulator === nothing
90
- return nothing
91
- end
92
- op_idx = tree.op
93
- UNAOP!(cumulator, op_idx, clen)
94
- @inbounds for i=1:clen
95
- if isinf(cumulator[i]) || isnan(cumulator[i])
96
- return nothing
97
- end
98
- end
99
- return cumulator
100
- else
101
- cumulator = evalTreeArray(tree.l, cX)
102
- if cumulator === nothing
103
- return nothing
104
- end
105
- array2 = evalTreeArray(tree.r, cX)
106
- if array2 === nothing
107
- return nothing
108
- end
109
- op_idx = tree.op
110
- BINOP!(cumulator, array2, op_idx, clen)
111
- @inbounds for i=1:clen
112
- if isinf(cumulator[i]) || isnan(cumulator[i])
113
- return nothing
114
- end
115
- end
116
- return cumulator
117
- end
118
- end
119
-
120
- # Score an equation
121
- function scoreFunc(tree::Node)::Float32
122
- prediction = evalTreeArray(tree)
123
- if prediction === nothing
124
- return 1f9
125
- end
126
- if weighted
127
- mse = MSE(prediction, y, weights)
128
- else
129
- mse = MSE(prediction, y)
130
- end
131
- return mse / baselineMSE + countNodes(tree)*parsimony
132
- end
133
-
134
- # Score an equation with a small batch
135
- function scoreFuncBatch(tree::Node)::Float32
136
- # batchSize
137
- batch_idx = randperm(len)[1:batchSize]
138
- batch_X = X[batch_idx, :]
139
- prediction = evalTreeArray(tree, batch_X)
140
- if prediction === nothing
141
- return 1f9
142
- end
143
- size_adjustment = 1f0
144
- batch_y = y[batch_idx]
145
- if weighted
146
- batch_w = weights[batch_idx]
147
- mse = MSE(prediction, batch_y, batch_w)
148
- size_adjustment = 1f0 * len / batchSize
149
- else
150
- mse = MSE(prediction, batch_y)
151
- end
152
- return size_adjustment * mse / baselineMSE + countNodes(tree)*parsimony
153
- end
154
-
155
- # Add a random unary/binary operation to the end of a tree
156
- function appendRandomOp(tree::Node)::Node
157
- node = randomNode(tree)
158
- while node.degree != 0
159
- node = randomNode(tree)
160
- end
161
 
162
- choice = rand()
163
- makeNewBinOp = choice < nbin/nops
164
- if rand() > 0.5
165
- left = Float32(randn())
166
- else
167
- left = rand(1:nvar)
168
- end
169
- if rand() > 0.5
170
- right = Float32(randn())
171
- else
172
- right = rand(1:nvar)
173
- end
174
-
175
- if makeNewBinOp
176
- newnode = Node(
177
- rand(1:length(binops)),
178
- left,
179
- right
180
- )
181
- else
182
- newnode = Node(
183
- rand(1:length(unaops)),
184
- left
185
- )
186
- end
187
- node.l = newnode.l
188
- node.r = newnode.r
189
- node.op = newnode.op
190
- node.degree = newnode.degree
191
- node.val = newnode.val
192
- node.constant = newnode.constant
193
- return tree
194
- end
195
-
196
- # Insert random node
197
- function insertRandomOp(tree::Node)::Node
198
- node = randomNode(tree)
199
- choice = rand()
200
- makeNewBinOp = choice < nbin/nops
201
- left = copyNode(node)
202
-
203
- if makeNewBinOp
204
- right = randomConstantNode()
205
- newnode = Node(
206
- rand(1:length(binops)),
207
- left,
208
- right
209
- )
210
- else
211
- newnode = Node(
212
- rand(1:length(unaops)),
213
- left
214
- )
215
- end
216
- node.l = newnode.l
217
- node.r = newnode.r
218
- node.op = newnode.op
219
- node.degree = newnode.degree
220
- node.val = newnode.val
221
- node.constant = newnode.constant
222
- return tree
223
- end
224
-
225
- # Add random node to the top of a tree
226
- function prependRandomOp(tree::Node)::Node
227
- node = tree
228
- choice = rand()
229
- makeNewBinOp = choice < nbin/nops
230
- left = copyNode(tree)
231
-
232
- if makeNewBinOp
233
- right = randomConstantNode()
234
- newnode = Node(
235
- rand(1:length(binops)),
236
- left,
237
- right
238
- )
239
- else
240
- newnode = Node(
241
- rand(1:length(unaops)),
242
- left
243
- )
244
- end
245
- node.l = newnode.l
246
- node.r = newnode.r
247
- node.op = newnode.op
248
- node.degree = newnode.degree
249
- node.val = newnode.val
250
- node.constant = newnode.constant
251
- return node
252
- end
253
-
254
- function randomConstantNode()::Node
255
- if rand() > 0.5
256
- val = Float32(randn())
257
- else
258
- val = rand(1:nvar)
259
- end
260
- newnode = Node(val)
261
- return newnode
262
- end
263
-
264
- # Return a random node from the tree with parent
265
- function randomNodeAndParent(tree::Node, parent::Union{Node, Nothing})::Tuple{Node, Union{Node, Nothing}}
266
- if tree.degree == 0
267
- return tree, parent
268
- end
269
- a = countNodes(tree)
270
- b = 0
271
- c = 0
272
- if tree.degree >= 1
273
- b = countNodes(tree.l)
274
- end
275
- if tree.degree == 2
276
- c = countNodes(tree.r)
277
- end
278
-
279
- i = rand(1:1+b+c)
280
- if i <= b
281
- return randomNodeAndParent(tree.l, tree)
282
- elseif i == b + 1
283
- return tree, parent
284
- end
285
-
286
- return randomNodeAndParent(tree.r, tree)
287
- end
288
-
289
- # Select a random node, and replace it an the subtree
290
- # with a variable or constant
291
- function deleteRandomOp(tree::Node)::Node
292
- node, parent = randomNodeAndParent(tree, nothing)
293
- isroot = (parent === nothing)
294
-
295
- if node.degree == 0
296
- # Replace with new constant
297
- newnode = randomConstantNode()
298
- node.l = newnode.l
299
- node.r = newnode.r
300
- node.op = newnode.op
301
- node.degree = newnode.degree
302
- node.val = newnode.val
303
- node.constant = newnode.constant
304
- elseif node.degree == 1
305
- # Join one of the children with the parent
306
- if isroot
307
- return node.l
308
- elseif parent.l == node
309
- parent.l = node.l
310
- else
311
- parent.r = node.l
312
- end
313
- else
314
- # Join one of the children with the parent
315
- if rand() < 0.5
316
- if isroot
317
- return node.l
318
- elseif parent.l == node
319
- parent.l = node.l
320
- else
321
- parent.r = node.l
322
- end
323
- else
324
- if isroot
325
- return node.r
326
- elseif parent.l == node
327
- parent.l = node.r
328
- else
329
- parent.r = node.r
330
- end
331
- end
332
- end
333
- return tree
334
- end
335
 
336
  # Simplify tree
337
  function combineOperators(tree::Node)::Node
 
19
 
20
  include("Node.jl")
21
 
22
+ include("eval.jl")
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
23
 
24
+ include("randomMutations.jl")
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
25
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
26
 
27
  # Simplify tree
28
  function combineOperators(tree::Node)::Node