Skip to content

Commit 8dd9e16

Browse files
committed
#24 use exceptions instead of return values for fail in individual
1 parent 18fc201 commit 8dd9e16

File tree

3 files changed

+125
-132
lines changed

3 files changed

+125
-132
lines changed

MLC/Population/Population.py

Lines changed: 19 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -7,6 +7,7 @@
77
from MLC.Population.Evaluation.EvaluatorFactory import EvaluatorFactory
88
from MLC.mlc_parameters.mlc_parameters import Config
99
from MLC.Simulation import Simulation
10+
from MLC.individual.Individual import OperationOverIndividualFail
1011

1112

1213
class Population(object):
@@ -240,18 +241,21 @@ def evolve(self, mlcpop2=None):
240241

241242
elif op == "mutation":
242243
new_ind = None
243-
fail = True
244-
while fail:
245-
pop_idv_index_orig = self._choose_individual(pop_subgen[i])
246-
pop_idv_index_dest = not_valid_indexes[individuals_created]
244+
while new_ind is None:
245+
try:
246+
pop_idv_index_orig = self._choose_individual(pop_subgen[i])
247+
pop_idv_index_dest = not_valid_indexes[individuals_created]
247248

248-
indiv_index = self._individuals[pop_idv_index_orig]
249-
lg.logger_.info("Individual {0}/{1}: Mutation - Orig indiv {2} - Dest indiv {3}"
250-
.format(individuals_created + 1, len(not_valid_indexes),
251-
indiv_index, pop_idv_index_dest + 1))
249+
indiv_index = self._individuals[pop_idv_index_orig]
250+
lg.logger_.info("Individual {0}/{1}: Mutation - Orig indiv {2} - Dest indiv {3}"
251+
.format(individuals_created+1, len(not_valid_indexes),
252+
indiv_index, pop_idv_index_dest + 1))
252253

253-
old_indiv = MLCTable.get_instance().get_individual(indiv_index)
254-
new_ind, fail = old_indiv.mutate()
254+
old_indiv = MLCTable.get_instance().get_individual(indiv_index)
255+
new_ind = old_indiv.mutate()
256+
257+
except OperationOverIndividualFail, ex:
258+
pass
255259

256260
number, repeated = MLCTable.get_instance().add_individual(new_ind)
257261
new_pop.update_individual(dest_index=pop_idv_index_dest, rhs_pop=self,
@@ -288,7 +292,11 @@ def evolve(self, mlcpop2=None):
288292
# Get the two individuals involved and call the crossover function
289293
old_indiv = MLCTable.get_instance().get_individual(indiv_index)
290294
old_indiv2 = MLCTable.get_instance().get_individual(indiv_index2)
291-
new_ind, new_ind2, fail = old_indiv.crossover(old_indiv2)
295+
try:
296+
new_ind, new_ind2 = old_indiv.crossover(old_indiv2)
297+
fail = False
298+
except OperationOverIndividualFail, ex:
299+
lg.logger_.debug(str(ex))
292300

293301
number, repeated = MLCTable.get_instance().add_individual(new_ind)
294302
new_pop.update_individual(dest_index=pop_idv_index_dest, rhs_pop=self,

MLC/individual/Individual.py

Lines changed: 71 additions & 66 deletions
Original file line numberDiff line numberDiff line change
@@ -11,6 +11,17 @@
1111
import 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+
1425
class 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

Comments
 (0)