1 """
2 crossover
3 =========
4 All crossover related operations. In the context of strongly-typed Genetic
5 Programming, this operator is heavily modified to produce offsprings that
6 are compliant with multiple rules and constraints set by the user.
7 In the present version, only a strongly-typed version of Koza 1 point
8 crossover is supported.
9
10 THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
11 IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
12 FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
13 AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
14 LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
15 OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
16 THE SOFTWARE.
17
18 @author: by Mehdi Khoury
19 @version: 1.20
20 @copyright: (c) 2009 Mehdi Khoury under the mit license
21 http://www.opensource.org/licenses/mit-license.html
22 @contact: mehdi.khoury at gmail.com
23
24 """
25 import psyco
26 import random
27 import crossutil
28 import treeutil
29 import buildtree
30 from copy import deepcopy
31
32 import evalfitness
33 import sys
34 from collections import deque
35 import timeit
36 import settings
37
38 psyco.profile()
39
40
41
42
44 """
45 Function: Koza1PointCrossover
46 ==============================
47 create 2 offsprings from 2 parents using a modified version of Koza-1-point
48 crossover. This version try to produce offsprings compliant with the
49 constraints and rules used to build an individual. If it does not manage,
50 it produce a report showing if the offsprings produced are compatible.
51
52 @param maxdepth: maximum depth of the mutated offspring
53 @param p1: parent tree 1 e.g. a=buildtree.buildTree().AddHalfNode((0,2,'root'),0,2,7)
54 @param p2: parent tree 2 e.g. a=buildtree.buildTree().AddHalfNode((0,2,'root'),0,2,7)
55 @param p1_mp: parent tree index mapping e.g a_map=crossutil.get_indices_mapping_from_tree(a)
56 @param p2_mp: parent tree index mapping e.g a_map=crossutil.get_indices_mapping_from_tree(a)
57 @param p1_depth: parent tree depth e.g. a_depth=crossutil.get_depth_from_indices_mapping(a_map)
58 @param p2_depth: parent tree depth e.g. a_depth=crossutil.get_depth_from_indices_mapping(a_map)
59
60 @return: a tuple containing 3 elements
61 - The first one is a list of 1 and 0 indicating if the first and second offspring are rule
62 compliant.
63 [1,1,1,1] frag2_leaf_compatible_p1 and frag1_leaf_compatible_p2 and frag2_branch_compatible_p1 and frag1_branch_compatible_p2
64 [1,0,1,1] frag2_leaf_compatible_p1 and not frag1_leaf_compatible_p2 and frag2_branch_compatible_p1 and frag1_branch_compatible_p2
65 [1,1,0,1] frag2_leaf_compatible_p1 and frag1_leaf_compatible_p2 and not frag2_branch_compatible_p1 and frag1_branch_compatible_p2
66 and so on... This information can be use to decide if we want to introduce non-compliant offsprings into the population.
67 - The second one is the first offspring
68 - The third one is the second offspring
69
70 """
71 p1_map=deepcopy(p1_mp)
72 p2_map=deepcopy(p2_mp)
73
74 p1_cross_depth=random.randint(1, p1_depth-1)
75
76
77 fragment_p1_depth= p1_depth-1-p1_cross_depth
78 if p2_depth > (maxdepth-fragment_p1_depth):
79 if maxdepth-fragment_p1_depth>0:
80 p2_cross_depth=random.randint(1,(maxdepth-fragment_p1_depth))
81 else:
82 p2_cross_depth=1
83 else:
84 p2_cross_depth=random.randint(1, p2_depth-1)
85 mychoice1=crossutil.UnpackIndicesFromList(\
86 crossutil.GetPackedListIndicesAtDepth(p1_map,p1_cross_depth))
87 p1_point=random.choice(mychoice1)
88
89 mychoice2=crossutil.UnpackIndicesFromList(\
90 crossutil.GetPackedListIndicesAtDepth(p2_map,p2_cross_depth))
91 p2_point=random.choice(mychoice2)
92
93 parent1_clone=deepcopy(p1)
94 parent2_clone=deepcopy(p2)
95 exec("fragment_p1=parent1_clone%s"%crossutil.IndexLstToIndexStr2(p1_point))
96 exec("fragment_p2=parent2_clone%s"%crossutil.IndexLstToIndexStr2(p2_point))
97
98
99
100
101
102
103 if isinstance(fragment_p1, list):
104 firstnode_p1= fragment_p1[0]
105
106 if isinstance(fragment_p1, tuple):
107 firstnode_p1=fragment_p1
108 if isinstance(fragment_p2, list):
109 firstnode_p2=fragment_p2[0]
110
111 if isinstance(fragment_p2, tuple):
112 firstnode_p2=fragment_p2
113
114
115 subtree1_parent_s = crossutil.IndexLstToIndexStr2(p1_point)
116 if firstnode_p1[0]!=2:
117 subtree1_parent_s= subtree1_parent_s[:-3]
118
119 subtree2_parent_s = crossutil.IndexLstToIndexStr2(p2_point)
120 if firstnode_p2[0]!=2:
121 subtree2_parent_s= subtree2_parent_s[:-3]
122
123 exec("subtree1_parent=parent1_clone%s"%subtree1_parent_s)
124
125 exec("subtree2_parent=parent2_clone%s"%subtree2_parent_s)
126
127
128
129
130 context_p1= settings.treeRules[subtree1_parent[0][2]]
131 context_p2= settings.treeRules[subtree2_parent[0][2]]
132
133
134 frag1_leaf_compatible_p2=True
135 frag2_leaf_compatible_p1=True
136 frag1_branch_compatible_p2=True
137 frag2_branch_compatible_p1=True
138
139 frag1, frag2 =[], []
140
141
142 if list(treeutil.LeafNodes_Search(fragment_p1)):
143 if isinstance(list(treeutil.LeafNodes_Search(fragment_p1))[0], tuple):
144 frag1=list(treeutil.LeafNodes_Search(fragment_p1))
145 else:
146 frag1=[tuple(fragment_p1)]
147 else:
148 frag1=fragment_p1
149 if list(treeutil.LeafNodes_Search(fragment_p2)):
150 if isinstance(list(treeutil.LeafNodes_Search(fragment_p2))[0], tuple):
151 frag2=list(treeutil.LeafNodes_Search(fragment_p2))
152 else:
153 frag2=[tuple(fragment_p2)]
154 else:
155 frag2=fragment_p2
156
157
158
159
160
161 for elem_frag2 in frag2:
162 if elem_frag2 not in context_p1[p1_point[-1]-1][1]:
163 frag2_leaf_compatible_p1=False
164 break
165 for elem_frag1 in frag1:
166 if elem_frag1 not in context_p2[p2_point[-1]-1][1]:
167 frag1_leaf_compatible_p2=False
168 break
169
170 frag1, frag2 =[], []
171 if isinstance(list(treeutil.BranchNodes_Search(fragment_p1))[0], tuple):
172 frag1=list(treeutil.BranchNodes_Search(fragment_p1))
173 else:
174 frag1=[tuple(fragment_p1)]
175 if isinstance(list(treeutil.BranchNodes_Search(fragment_p2))[0], tuple):
176 frag2=list(treeutil.BranchNodes_Search(fragment_p2))
177 else:
178 frag2=[tuple(fragment_p2)]
179
180 for elem_frag1 in frag1:
181 if len(frag1)==1 and frag1[0][0]!=1:
182 frag1_branch_compatible_p2=True
183 elif elem_frag1 not in context_p2[0]:
184 frag1_branch_compatible_p2=False
185 break
186 else:
187 frag1_branch_compatible_p2=True
188 for elem_frag2 in frag2:
189 if len(frag2)==1 and frag2[0][0]!=1:
190 frag2_branch_compatible_p1=True
191 elif elem_frag2 not in context_p1[0]:
192 frag2_branch_compatible_p1=False
193 break
194 else:
195 frag2_branch_compatible_p1=True
196
197
198
199
200
201
202
203
204 copy_fragment_p1 = deepcopy(fragment_p1)
205 copy_fragment_p2 = deepcopy(fragment_p2)
206 if frag1_branch_compatible_p2==False \
207 and frag1_leaf_compatible_p2==True \
208 and settings.Strongly_Typed_Crossover_degree>=1:
209
210
211 frag1=list(set(frag1))
212 temp1=str(copy_fragment_p1)
213
214 for elem_frag1 in frag1:
215 for elem_p2 in context_p2[p2_point[-1]-1][0]:
216 for elem_crossover_mapping in settings.crossover_mapping:
217 if elem_crossover_mapping[1]==str(elem_p2[2]) and elem_crossover_mapping[0]==str(elem_frag1[2]):
218 temp1=temp1.replace(elem_crossover_mapping[0], elem_crossover_mapping[1])
219
220 exec("copy_fragment_p1 =%s"%temp1)
221
222
223 if frag2_branch_compatible_p1==False \
224 and frag2_leaf_compatible_p1==True \
225 and settings.Strongly_Typed_Crossover_degree>=1:
226
227
228 frag2=list(set(frag2))
229 temp2=str(copy_fragment_p2)
230
231 for elem_frag2 in frag2:
232 for elem_p1 in context_p1[p1_point[-1]-1][0]:
233 for elem_crossover_mapping in settings.crossover_mapping:
234 if elem_crossover_mapping[1]==str(elem_p1[2]) and elem_crossover_mapping[0]==str(elem_frag2[2]):
235 temp2=temp2.replace(elem_crossover_mapping[0], elem_crossover_mapping[1])
236
237 exec("copy_fragment_p2 =%s"%temp2)
238
239
240 frag1_leaf_compatible_p2=True
241 frag2_leaf_compatible_p1=True
242 frag1_branch_compatible_p2=True
243 frag2_branch_compatible_p1=True
244
245 frag1, frag2 =[], []
246 if list(treeutil.LeafNodes_Search(fragment_p1)):
247 if isinstance(list(treeutil.LeafNodes_Search(fragment_p1))[0], tuple):
248 frag1=list(treeutil.LeafNodes_Search(fragment_p1))
249 else:
250 frag1=[tuple(fragment_p1)]
251 else:
252 frag1=fragment_p1
253 if list(treeutil.LeafNodes_Search(fragment_p2)):
254 if isinstance(list(treeutil.LeafNodes_Search(fragment_p2))[0], tuple):
255 frag2=list(treeutil.LeafNodes_Search(fragment_p2))
256 else:
257 frag2=[tuple(fragment_p2)]
258 else:
259 frag2=fragment_p2
260
261
262
263
264
265 for elem_frag2 in frag2:
266 if elem_frag2 not in context_p1[p1_point[-1]-1][1]:
267 frag2_leaf_compatible_p1=False
268 break
269 for elem_frag1 in frag1:
270 if elem_frag1 not in context_p2[p2_point[-1]-1][1]:
271 frag1_leaf_compatible_p2=False
272 break
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287 if frag2_leaf_compatible_p1 and frag1_leaf_compatible_p2 and frag2_branch_compatible_p1 and frag1_branch_compatible_p2:
288 exec("parent1_clone%s=copy_fragment_p2"%crossutil.IndexLstToIndexStr2(p1_point))
289 exec("parent2_clone%s=copy_fragment_p1"%crossutil.IndexLstToIndexStr2(p2_point))
290 return ([1,1,1,1],parent1_clone,parent2_clone)
291 elif frag2_leaf_compatible_p1 and not frag1_leaf_compatible_p2 and frag2_branch_compatible_p1 and frag1_branch_compatible_p2:
292
293 exec("parent1_clone%s=fragment_p2"%crossutil.IndexLstToIndexStr2(p1_point))
294 exec("parent2_clone%s=fragment_p1"%crossutil.IndexLstToIndexStr2(p2_point))
295 return ([1,0,1,1],parent1_clone,parent2_clone)
296 elif not frag2_leaf_compatible_p1 and frag1_leaf_compatible_p2 and frag2_branch_compatible_p1 and frag1_branch_compatible_p2:
297
298 exec("parent1_clone%s=fragment_p2"%crossutil.IndexLstToIndexStr2(p1_point))
299 exec("parent2_clone%s=fragment_p1"%crossutil.IndexLstToIndexStr2(p2_point))
300 return ([0,1,1,1],parent1_clone,parent2_clone)
301 elif not frag2_leaf_compatible_p1 and not frag1_leaf_compatible_p2 and frag2_branch_compatible_p1 and frag1_branch_compatible_p2:
302
303 exec("parent1_clone%s=fragment_p2"%crossutil.IndexLstToIndexStr2(p1_point))
304 exec("parent2_clone%s=fragment_p1"%crossutil.IndexLstToIndexStr2(p2_point))
305 return ([0,0,1,1],parent1_clone,parent2_clone)
306 elif frag2_leaf_compatible_p1 and frag1_leaf_compatible_p2 and not frag2_branch_compatible_p1 and frag1_branch_compatible_p2:
307
308 exec("parent1_clone%s=fragment_p2"%crossutil.IndexLstToIndexStr2(p1_point))
309 exec("parent2_clone%s=fragment_p1"%crossutil.IndexLstToIndexStr2(p2_point))
310 return ([1,1,0,1],parent1_clone,parent2_clone)
311 elif frag2_leaf_compatible_p1 and frag1_leaf_compatible_p2 and frag2_branch_compatible_p1 and not frag1_branch_compatible_p2:
312
313 exec("parent1_clone%s=fragment_p2"%crossutil.IndexLstToIndexStr2(p1_point))
314 exec("parent2_clone%s=fragment_p1"%crossutil.IndexLstToIndexStr2(p2_point))
315 return ([1,1,1,0],parent1_clone,parent2_clone)
316 elif frag2_leaf_compatible_p1 and frag1_leaf_compatible_p2 and not frag2_branch_compatible_p1 and not frag1_branch_compatible_p2 :
317
318 exec("parent1_clone%s=fragment_p2"%crossutil.IndexLstToIndexStr2(p1_point))
319 exec("parent2_clone%s=fragment_p1"%crossutil.IndexLstToIndexStr2(p2_point))
320 return ([1,1,0,0],parent1_clone,parent2_clone)
321 elif frag2_leaf_compatible_p1 and not frag1_leaf_compatible_p2 and not frag2_branch_compatible_p1 and not frag1_branch_compatible_p2 :
322
323 exec("parent1_clone%s=fragment_p2"%crossutil.IndexLstToIndexStr2(p1_point))
324 exec("parent2_clone%s=fragment_p1"%crossutil.IndexLstToIndexStr2(p2_point))
325 return ([1,0,0,0],parent1_clone,parent2_clone)
326 elif not frag2_leaf_compatible_p1 and frag1_leaf_compatible_p2 and not frag2_branch_compatible_p1 and not frag1_branch_compatible_p2 :
327
328 exec("parent1_clone%s=fragment_p2"%crossutil.IndexLstToIndexStr2(p1_point))
329 exec("parent2_clone%s=fragment_p1"%crossutil.IndexLstToIndexStr2(p2_point))
330 return ([0,1,0,0],parent1_clone,parent2_clone)
331 else:
332
333 exec("parent1_clone%s=fragment_p2"%crossutil.IndexLstToIndexStr2(p1_point))
334 exec("parent2_clone%s=fragment_p1"%crossutil.IndexLstToIndexStr2(p2_point))
335 return ([0,0,0,0],parent1_clone,parent2_clone)
336
337
338
339
340
341
342
343
344
346 first_p_cross=[]
347 for i in xrange(10):
348 cp1_copy_parent1=deepcopy(parent1)
349 cp1_copy_p1_map=deepcopy(p1_map)
350 cp1_copy_parent2=deepcopy(parent2)
351 cp1_copy_p2_map=deepcopy(p2_map)
352 first_p_cross=Koza1PointCrossover(maxdepth,cp1_copy_parent1,cp1_copy_parent2,cp1_copy_p1_map,cp1_copy_p2_map,p1_depth,p2_depth)
353 if first_p_cross[0]==[1,1,1,1]:
354 break
355 second_p_cross=[]
356 for i in xrange(10):
357 cp2_copy_parent1=deepcopy(first_p_cross[1])
358 cp2_copy_p1_map=crossutil.GetIndicesMappingFromTree(cp2_copy_parent1)
359 cp2_copy_p1_depth=crossutil.GetDepthFromIndicesMapping(cp2_copy_p1_map)
360 cp2_copy_parent2=deepcopy(first_p_cross[2])
361 cp2_copy_p2_map=crossutil.GetIndicesMappingFromTree(cp2_copy_parent2)
362 cp2_copy_p2_depth=crossutil.GetDepthFromIndicesMapping(cp2_copy_p2_map)
363 second_p_cross=Koza1PointCrossover(maxdepth,cp2_copy_parent1,cp2_copy_parent2,cp2_copy_p1_map,cp2_copy_p2_map,cp2_copy_p1_depth,cp2_copy_p2_depth)
364 if second_p_cross[0]==[1,1,1,1]:
365 break
366 return second_p_cross
367
368
369
370 if __name__ == '__main__':
371
372
373
374 for i in xrange(10000):
375 a=buildtree.buildTree().AddHalfNode((0,2,'root'),0,3,7)
376 b=buildtree.buildTree().AddHalfNode((0,2,'root'),0,3,7)
377 a_map=crossutil.GetIndicesMappingFromTree(a)
378 b_map=crossutil.GetIndicesMappingFromTree(b)
379 a_depth=crossutil.GetDepthFromIndicesMapping(a_map)
380 b_depth=crossutil.GetDepthFromIndicesMapping(b_map)
381
382
383
384
385
386
387 r2=Koza1PointCrossover(15,a,b,a_map,b_map,a_depth,b_depth)
388
389 print r2
390
391
392
393
394
395 if r2[0]==[1,1,1,1]:
396 print evalfitness.FinalFitness_tutorial8(evalfitness.EvalTreeForOneListInputSet_tutorial8(r2[1]))
397 print evalfitness.FinalFitness_tutorial8(evalfitness.EvalTreeForOneListInputSet_tutorial8(r2[2]))
398
399
400
401
402