Skip to content

Commit d63bffa

Browse files
committed
Several bug fixes found today in the lab session with Thomas
1 parent e3dde16 commit d63bffa

File tree

8 files changed

+115
-42
lines changed

8 files changed

+115
-42
lines changed

MLC/Common/LispTreeExpr/LispTreeExpr.py

Lines changed: 11 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -20,6 +20,7 @@
2020
# along with this program. If not, see <http://www.gnu.org/licenses/>
2121

2222
import MLC.Log.log as lg
23+
import re
2324
from MLC.mlc_parameters.mlc_parameters import Config
2425
from MLC.Common.Operations import Operations
2526
from MLC.Common.LispTreeExpr.TreeNodes import LeafNode, InternalNode
@@ -108,6 +109,16 @@ def check_expression(expression):
108109
if expression.find("(root") != 0:
109110
raise RootNotFoundExprException(expression)
110111

112+
# Check that the expression is just a sensor
113+
r = re.compile("\(root S[0-9]*\)$")
114+
if r.match(expression) != None:
115+
return True
116+
117+
# Check that the expression is just a number
118+
r = re.compile("\(root [0-9,\-]*\.{0,1}[0-9]*\)$")
119+
if r.match(expression) != None:
120+
return True
121+
111122
# Check the amount of parenthesis to be balanced
112123
open_parenthesis = "("
113124
close_parenthesis = ")"

MLC/GUI/Experiment/ChartConfiguration.py

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -55,7 +55,7 @@ class ChartConfiguration():
5555

5656
# Min, Max, Step
5757
AMOUNT_POINTS = [100, 1000, 100]
58-
MAX_COST_VALUES = [50, 1000, 50]
58+
MAX_COST_VALUES = [50, 5000, 50]
5959
MIN_COST_VALUES = [-200, 0, 50]
6060
MARKER_SIZE_VALUES = [1, 10, 1]
6161

MLC/GUI/Experiment/ExperimentInProgress.py

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -26,6 +26,7 @@
2626
import os
2727
import sys
2828
import threading
29+
import traceback
2930
sys.path.append(os.path.abspath(".") + "/../..")
3031

3132
from MLC.Application import MLC_CALLBACKS
@@ -282,6 +283,11 @@ def run(self):
282283
logger.info('{0} [RUN] - Thread was cancelled by the user'
283284
.format(self._log_prefix))
284285
self._dialog.simulation_finished.emit()
286+
except Exception:
287+
logger.info('{0} [RUN] - Unknown Exception catch. Aborting experiment'
288+
.format(self._log_prefix))
289+
traceback.print_exc()
290+
sys.exit(-1)
285291

286292
def indiv_evaluated(self, individual_id, cost):
287293
logger.debug('{0} [INDIV_EV] - Executing indiv_evaluated callback. '

MLC/GUI/Experiment/ExperimentWindow.py

Lines changed: 3 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -94,9 +94,6 @@ def __init__(self, mlc_local,
9494
# Disable save_config_button until some change is made
9595
self._autogenerated_object.save_config_button.setDisabled(True)
9696

97-
if self._current_gen != 0:
98-
self._autogenerated_object.tabWidget.setTabEnabled(3, False)
99-
10097
# Connect the function that updates the graphics of the Window when the
10198
# experiment evaluation finished
10299
self.experiment_finished.connect(self._update_experiment)
@@ -235,7 +232,7 @@ def on_test_button_clicked(self):
235232
indiv_value=test_indiv_edit.text(),
236233
config=Config.get_instance())
237234

238-
if cost:
235+
if cost != None:
239236
test_label_result = self._autogenerated_object.test_label_result
240237
test_label_result.setText(str(cost))
241238

@@ -639,10 +636,12 @@ def _update_individuals_per_generation_list(self):
639636
# Disable Experiment tab buttons
640637
self._autogenerated_object.left_menu_frame.setDisabled(True)
641638
self._autogenerated_object.right_menu_frame.setDisabled(True)
639+
self._autogenerated_object.tabWidget.setTabEnabled(3, True)
642640
return
643641
else:
644642
self._autogenerated_object.left_menu_frame.setDisabled(False)
645643
self._autogenerated_object.right_menu_frame.setDisabled(False)
644+
self._autogenerated_object.tabWidget.setTabEnabled(3, False)
646645

647646
# Complete the list
648647
individuals = self._mlc_local.get_individuals(self._experiment_name)

MLC/GUI/mlc_gui.py

Lines changed: 6 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -117,7 +117,12 @@ def on_new_button_clicked(self):
117117
break
118118

119119
# Create the new experiment and refresh the View
120-
self._experiments_manager.add_experiment_even_if_repeated(experiment_name)
120+
if not self._experiments_manager.add_experiment(experiment_name):
121+
QMessageBox.critical(self, 'New Experiment',
122+
('Experiment {0} already exists but has errors. '
123+
'Check it to be correct in your workspace'
124+
.format(experiment_name)))
125+
return
121126
self._refresh_experiment_list_view()
122127
self._clean_experiment_selection()
123128

MLC/Population/Population.py

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -285,7 +285,7 @@ def evolve(self, next_population):
285285
new_ind = old_indiv.mutate()
286286

287287
except OperationOverIndividualFail, ex:
288-
pass
288+
lg.logger_.warn(str(ex))
289289

290290
number, repeated = self._mlc_repository.add_individual(new_ind)
291291
next_population.update_individual(dest_index=pop_idv_index_dest, rhs_pop=self,
@@ -326,7 +326,7 @@ def evolve(self, next_population):
326326
try:
327327
new_ind, new_ind2, fail = old_indiv.crossover(old_indiv2)
328328
except OperationOverIndividualFail, ex:
329-
lg.logger_.debug(str(ex))
329+
lg.logger_.warn(str(ex))
330330

331331
number, repeated = self._mlc_repository.add_individual(new_ind)
332332
next_population.update_individual(dest_index=pop_idv_index_dest, rhs_pop=self,

MLC/individual/Individual.py

Lines changed: 63 additions & 34 deletions
Original file line numberDiff line numberDiff line change
@@ -35,8 +35,9 @@ class IndividualException(Exception):
3535

3636

3737
class OperationOverIndividualFail(IndividualException):
38+
3839
def __init__(self, individual_value, operation_name, cause):
39-
IndividualException.__init__(self, "Operation '%s' over individual '%s' fail due %s" % (operation_name, individual_value, cause) )
40+
IndividualException.__init__(self, "Operation '%s' over individual '%s' fail due %s" % (operation_name, individual_value, cause))
4041

4142

4243
class TreeException(Exception):
@@ -146,7 +147,10 @@ def crossover(self, other_individual):
146147
# Check if the individual is valid
147148
preev_function = PreevaluationManager.get_callback()
148149
success = True
149-
if preev_function is not None:
150+
if preev_function is None:
151+
success = True
152+
else:
153+
preev_function = PreevaluationManager.get_callback()
150154
success = preev_function.preev(indiv1) and preev_function.preev(indiv2)
151155

152156
return Individual(new_value_1), Individual(new_value_2), not success
@@ -206,7 +210,8 @@ def __crossover_tree(self, other_individual):
206210
count += 1
207211

208212
if not correct:
209-
raise TreeException("we could not find a candidate substitution in %s tests" % maxtries)
213+
raise TreeException("[CROSSOVER] Candidate could not found a "
214+
"substitution {0} tests".format(maxtries))
210215

211216
# Replacing subtrees
212217
value_1 = value_1.replace('@', sm2)
@@ -249,48 +254,65 @@ def __mutate_tree(self, mutation_type):
249254
for i in range(len(config_sensor_list)):
250255
new_individual_value = new_individual_value.replace("z%d" % i, "S%d" % config_sensor_list[i])
251256

252-
except TreeException:
253-
pass
254-
255-
# Preevaluate the Individual
256-
preev_function = PreevaluationManager.get_callback()
257-
if preev_function is not None:
258-
preevok = preev_function.preev(Individual(new_individual_value))
259-
else:
260-
preevok = True
257+
# Preevaluate the Individual
258+
preevok = self._preevaluate_individual(new_individual_value)
259+
else:
260+
raise TreeException()
261261

262-
if not new_individual_value:
263-
raise TreeException("Subtree cannot be generated")
262+
except TreeException:
263+
raise TreeException("[MUTATE_TREE] A non subtractable Individual was generated. "
264+
"Individual: {0}".format(self._tree.get_expanded_tree_as_string()))
264265

265266
return new_individual_value
266267

267268
elif mutation_type == Individual.MutationType.REPARAMETRIZATION:
268-
return self.__reparam_tree(LispTreeExpr(self.get_value()))
269+
new_individual_value = None
270+
preevok = False
271+
while not preevok:
272+
new_individual_value = self.__reparam_tree(LispTreeExpr(self.get_value()))
273+
preevok = self._preevaluate_individual(new_individual_value)
274+
275+
return new_individual_value
269276

270277
elif mutation_type == Individual.MutationType.HOIST:
271-
controls = self._config.getint("POPULATION", "controls")
272-
prob_threshold = 1 / float(controls)
278+
preevok = False
279+
counter = 0
280+
maxtries = self._config.getint("GP", "maxtries")
281+
282+
while not preevok and counter < maxtries:
283+
counter += 1
284+
controls = self._config.getint("POPULATION", "controls")
285+
prob_threshold = 1 / float(controls)
273286

274-
cl = [stree.to_string() for stree in self.get_tree().get_root_node()._nodes]
287+
cl = [stree.to_string() for stree in self.get_tree().get_root_node()._nodes]
275288

276-
changed = False
277-
k = 0
289+
changed = False
290+
k = 0
278291

279-
for nc in RandomManager.randperm(controls):
280-
k += 1
281-
# control law is cropped if it is the last one and no change happend before
282-
if (RandomManager.rand() < prob_threshold) or (k == controls and not changed):
292+
for nc in RandomManager.randperm(controls):
293+
k += 1
294+
# control law is cropped if it is the last one and no change happend before
295+
if (RandomManager.rand() < prob_threshold) or (k == controls and not changed):
283296

284-
try:
285-
_, sm, _ = self.__extract_subtree(LispTreeExpr('(root '+cl[nc - 1]+')'), mutmindepth+1, maxdepth, maxdepth+1)
286-
cl[nc - 1] = sm
287-
changed = True
297+
try:
298+
_, sm, _ = self.__extract_subtree(LispTreeExpr('(root ' + cl[nc - 1] + ')'),
299+
mutmindepth + 1,
300+
maxdepth,
301+
maxdepth + 1)
302+
cl[nc - 1] = sm
303+
changed = True
288304

289-
except TreeException:
290-
changed = False
305+
except TreeException:
306+
changed = False
291307

292-
return "(root %s)" % " ".join(cl[:controls])
308+
new_individual_value = "(root %s)" % " ".join(cl[:controls])
309+
preevok = self._preevaluate_individual(new_individual_value)
293310

311+
if counter == maxtries:
312+
raise TreeException("[MUTATE HOIST] Candidate could not found a "
313+
"substitution {0} tests".format(maxtries))
314+
315+
return new_individual_value
294316
else:
295317
raise NotImplementedError("Mutation type %s not implemented" % mutation_type)
296318

@@ -381,7 +403,7 @@ def __generate_indiv_regressive_tree(value, config, indiv_type):
381403
# Check if the seed character is in the string
382404
index = value.find('@')
383405
if index == -1:
384-
return
406+
return None
385407

386408
# Split the value in two strings, not containing the first seed character
387409
begin_str = value[:index]
@@ -412,7 +434,7 @@ def __generate_indiv_regressive_tree(value, config, indiv_type):
412434
precision = config.get('POPULATION', 'precision')
413435
# Generate a float number between -range and +range with a precision of 'precision'
414436
new_exp = (("%." + precision + "f") % (
415-
(RandomManager.rand() - 0.5) * 2 * range))
437+
(RandomManager.rand() - 0.5) * 2 * range))
416438
new_value = begin_str + new_exp + end_str
417439
else:
418440
# Create a node
@@ -428,6 +450,13 @@ def __generate_indiv_regressive_tree(value, config, indiv_type):
428450
new_value = Individual.__generate_indiv_regressive_tree(new_value, config, indiv_type)
429451
return new_value
430452

453+
def _preevaluate_individual(self, new_indiv):
454+
preev_function = PreevaluationManager.get_callback()
455+
if preev_function is not None:
456+
return preev_function.preev(Individual(new_indiv))
457+
else:
458+
return True
459+
431460
@staticmethod
432461
def __simplify_and_sensors_tree(value, config):
433462
sensor_list = ()
@@ -455,4 +484,4 @@ def __cmp__(self, other):
455484
self._value == other.get_value()
456485

457486
def __hash__(self):
458-
return hash(self._value)
487+
return hash(self._value)

tests/mlc/common/LispTreeExpr/test_expression_tree.py

Lines changed: 23 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -85,6 +85,29 @@ def test_check_expression_complex_incorrect_plus_arguments_amount(self):
8585
expression = '(root (+ (* 2 3 5) 8))'
8686
self.assert_check_expression_with_exception(expression, OperationArgumentsAmountException)
8787

88+
def test_check_expression_with_just_a_sensor(self):
89+
expression = '(root S0)'
90+
self.assert_check_expression_without_exception(expression)
91+
92+
expression = '(root S1)'
93+
self.assert_check_expression_without_exception(expression)
94+
95+
expression = '(root S23)'
96+
self.assert_check_expression_without_exception(expression)
97+
98+
def test_check_expression_with_just_a_number(self):
99+
expression = '(root 4)'
100+
self.assert_check_expression_without_exception(expression)
101+
102+
expression = '(root -4)'
103+
self.assert_check_expression_without_exception(expression)
104+
105+
expression = '(root 4.23)'
106+
self.assert_check_expression_without_exception(expression)
107+
108+
expression = '(root -234.23)'
109+
self.assert_check_expression_without_exception(expression)
110+
88111
def test_check_expression_simple_correct_plus_arguments_amount(self):
89112
expression = '(root (+ 2 3))'
90113
self.assert_check_expression_without_exception(expression)

0 commit comments

Comments
 (0)