1111import re
1212
1313
14+ class IndividualException (Exception ):
15+ pass
16+
17+
18+ class OperationOverIndividualFail (IndividualException ):
19+ def __init__ (self , individual_value , operation_name , cause ):
20+ IndividualException .__init__ (self , "Operation '%s' over individual '%s' fail due %s" % (operation_name , individual_value , cause ) )
21+
22+ class TreeException (Exception ):
23+ pass
24+
1425class Individual (object ):
1526 """
1627 MLCind constructor of the Machine Learning Control individual class.
@@ -130,32 +141,33 @@ def generate(self, value=None, individual_type=None):
130141 self ._complexity = self ._tree .complexity ()
131142
132143 def mutate (self , mutation_type = MutationType .ANY ):
133- new_value , fail = self .__mutate_tree (self .get_value (), mutation_type )
144+ try :
145+ new_value = self .__mutate_tree (self .get_value (), mutation_type )
146+ new_individual = Individual ()
147+ new_individual .generate (new_value )
148+ return new_individual
134149
135- if fail :
136- return None , fail
137-
138- new_individual = Individual ()
139- new_individual .generate (new_value )
140- return new_individual , fail
150+ except TreeException , ex :
151+ raise OperationOverIndividualFail (self ._value , "MUTATE" , str (ex ))
141152
142153 def crossover (self , other_individual ):
143154 """
144155 CROSSOVER crosses two MLCind individuals.
145156 [NEW_IND1,NEW_IND2,FAIL]=CROSSOVER(MLCIND1,MLCIND2,MLC_PARAMETERS)
146157 """
147- m1 , m2 , fail = self .__crossover_tree (self .get_value (), other_individual .get_value ())
158+ try :
159+ new_value_1 , new_value_2 = self .__crossover_tree (self .get_value (), other_individual .get_value ())
148160
149- if fail :
150- return None , None , fail
161+ new_ind1 = Individual ()
162+ new_ind1 . generate ( new_value_1 )
151163
152- new_ind1 = Individual ()
153- new_ind1 .generate (m1 )
164+ new_ind2 = Individual ()
165+ new_ind2 .generate (new_value_2 )
154166
155- new_ind2 = Individual ()
156- new_ind2 .generate (m2 )
167+ return new_ind1 , new_ind2
157168
158- return new_ind1 , new_ind2 , fail
169+ except TreeException , ex :
170+ raise OperationOverIndividualFail (self ._value , "CROSSOVER" , str (ex ))
159171
160172 def compare (self , other_individual ):
161173 return self .get_value () == other_individual .get_value ()
@@ -325,35 +337,29 @@ def __crossover_tree(self, value_1, value_2):
325337 tmp_value_2 = value_2
326338
327339 while not correct and count < maxtries :
328- # Extracting subtrees
329- value_1 , sm1 , n = self .__extract_subtree (tmp_value_1 , mutmindepth , maxdepth , maxdepth ) # check extract_subtree comments
330- value_2 , sm2 , n2 = self .__extract_subtree (tmp_value_2 , mutmindepth , n , maxdepth - n + 1 )
340+ try :
341+ # Extracting subtrees
342+ value_1 , sm1 , n = self .__extract_subtree (tmp_value_1 , mutmindepth , maxdepth , maxdepth )
343+ value_2 , sm2 , _ = self .__extract_subtree (tmp_value_2 , mutmindepth , n , maxdepth - n + 1 )
344+ correct = True
345+
346+ except TreeException , ex :
347+ pass
331348
332- # n or n2 < 0 indicates the extraction was not correct for any reason.
333- correct = n > 0 and n2 > 0
334349 count += 1
335350
336- if correct :
337- # Replacing subtrees
338- value_1 = value_1 .replace ('@' , sm2 )
339- value_2 = value_2 .replace ('@' , sm1 )
340- """
341- %if gen_param.preevaluation
342- % eval(['peval=@' gen_param.preev_function ';']);
343- % f=peval;
344- % preevok1=feval(f,m1);
345- % preevok2=feval(f,m2);
346- % fail=1-preevok1*preevok2;
347- %end
348- """
349- # correct == false means that we could not find a candidate substitution
350- # in maxtries tests. We will select other individuals.
351-
352- return value_1 , value_2 , not correct
351+ if not correct :
352+ raise TreeException ("we could not find a candidate substitution in %s tests" % maxtries )
353353
354- def __mutate_tree (self , value , mutation_type ):
355- fail = False
354+ # Replacing subtrees
355+ value_1 = value_1 .replace ('@' , sm2 )
356+ value_2 = value_2 .replace ('@' , sm1 )
357+
358+ # TODO preevaluation over value_1 and value_2
356359
360+ return value_1 , value_2
361+
362+ def __mutate_tree (self , value , mutation_type ):
357363 mutmindepth = self ._config .getint ("GP" , "mutmindepth" )
358364 maxdepth = self ._config .getint ("GP" , "maxdepth" )
359365 sensor_spec = self ._config .getboolean ("POPULATION" , "sensor_spec" )
@@ -369,7 +375,10 @@ def __mutate_tree(self, value, mutation_type):
369375 preevok = False
370376 while not preevok :
371377 # remove subtree and grow new subtree
372- value , _ , _ = self .__extract_subtree (value , mutmindepth , maxdepth , maxdepth )
378+ try :
379+ value , _ , _ = self .__extract_subtree (value , mutmindepth , maxdepth , maxdepth )
380+ except TreeException :
381+ pass
373382
374383 if mutation_type == Individual .MutationType .REMOVE_SUBTREE_AND_REPLACE :
375384 value = self .__generate_indiv_regressive_tree (value , 0 )
@@ -385,15 +394,6 @@ def __mutate_tree(self, value, mutation_type):
385394 for i in range (len (config_sensor_list )):
386395 value = value .replace ("z%d" % i , "S%d" % config_sensor_list [i ])
387396
388- """
389- if sensor_spec:
390- config_sensor_list = sorted(self._config.get_list('POPULATION', 'sensor_list'))
391- for i in range(len(config_sensor_list)):
392- value = value.replace("z%d" % i, "S%d" % config_sensor_list[i])
393- else:
394- for i in range(sensors, 0, -1):
395- value = value.replace("z%d" % (i - 1), "S%d" % (i - 1))
396- """
397397 preevok = True
398398 # if gen_param.preevaluation
399399 # eval(['peval=@' gen_param.preev_function ';']);
@@ -403,11 +403,13 @@ def __mutate_tree(self, value, mutation_type):
403403 else :
404404 preevok = True
405405
406- return value , not value
406+ if not value :
407+ raise TreeException ("Subtree cannot be generated" )
408+
409+ return value
407410
408411 elif mutation_type == Individual .MutationType .REPARAMETRIZATION :
409- value = self .__reparam_tree (value )
410- return value , False
412+ return self .__reparam_tree (value )
411413
412414 elif mutation_type == Individual .MutationType .HOIST :
413415 controls = self ._config .getint ("POPULATION" , "controls" )
@@ -423,15 +425,16 @@ def __mutate_tree(self, value, mutation_type):
423425 k += 1
424426 # control law is cropped if it is the last one and no change happend before
425427 if (MatlabEngine .rand () < prob_threshold ) or (k == controls and not changed ):
426- _ , sm , _ , = self .__extract_subtree ('(root ' + cl [nc - 1 ]+ ')' , mutmindepth + 1 , maxdepth , maxdepth + 1 )
427428
428- if sm :
429+ try :
430+ _ , sm , _ = self .__extract_subtree ('(root ' + cl [nc - 1 ]+ ')' , mutmindepth + 1 , maxdepth , maxdepth + 1 )
429431 cl [nc - 1 ] = sm
432+ changed = True
430433
431- changed = not sm is None
434+ except TreeException :
435+ changed = False
432436
433- value = "(root %s)" % " " .join (cl [:controls ])
434- return value , False
437+ return "(root %s)" % " " .join (cl [:controls ])
435438
436439 else :
437440 raise NotImplementedError ("Mutation type %s not implemented" % mutation_type )
@@ -444,15 +447,17 @@ def __extract_subtree(self, m, mindepth, subtreedepthmax, maxdepth):
444447 if node .get_subtreedepth () <= subtreedepthmax :
445448 candidates .append (node )
446449
447- if candidates :
448- candidates .sort (key = lambda x : x .get_expr_index (), reverse = False )
449- n = int (np .ceil (MatlabEngine .rand () * len (candidates ))) - 1
450- extracted_node = candidates [n ]
451- index = extracted_node .get_expr_index ()
452- new_value = m [:index ] + m [index :].replace (extracted_node .to_string (), '@' , 1 )
453- return new_value , extracted_node .to_string (), extracted_node .get_subtreedepth ()
454- else :
455- return [], [], - 1
450+ if not candidates :
451+ raise TreeException ("No subtrees to extract from '%s' "
452+ "with mindepth=%s, maxdepth=%s, subtreedepthmax=%s" %
453+ (m , mindepth , maxdepth , subtreedepthmax ))
454+
455+ candidates .sort (key = lambda x : x .get_expr_index (), reverse = False )
456+ n = int (np .ceil (MatlabEngine .rand () * len (candidates ))) - 1
457+ extracted_node = candidates [n ]
458+ index = extracted_node .get_expr_index ()
459+ new_value = m [:index ] + m [index :].replace (extracted_node .to_string (), '@' , 1 )
460+ return new_value , extracted_node .to_string (), extracted_node .get_subtreedepth ()
456461
457462 def __reparam_tree (self , value ):
458463 def leaf_value_generator ():
0 commit comments