Skip to content

Commit 009aec8

Browse files
committed
Remove MatlabEngine from entire project
* Now, the MatlabEngine is used only in the Evaluation and Preevaluation scripts * Decoupled randoms from MatlabEngine singleton. Now the random are managed in the singleton class RandomManager * Tests were modified to pass with the following changes * Issue #30
1 parent 6bf088f commit 009aec8

File tree

13 files changed

+114
-126
lines changed

13 files changed

+114
-126
lines changed

MLC/Application.py

Lines changed: 3 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,4 @@
11
from __builtin__ import staticmethod
2-
3-
import matlab.engine
42
import MLC.Log.log as lg
53

64
from MLC.Common.PreevaluationManager import PreevaluationManager
@@ -18,11 +16,11 @@ class Application(object):
1816

1917
def __init__(self, simulation, log_mode='console'):
2018
self._config = Config.get_instance()
19+
self._simulation = simulation
2120

2221
# Set logger mode of the App
2322
set_logger(log_mode)
2423
self._project_validations()
25-
self._simulation = simulation
2624

2725
# Gen creator
2826
gen_method = self._config.get('GP', 'generation_method')
@@ -161,12 +159,11 @@ def show_best(self, population):
161159
lg.logger_.debug("[APPLICATION] Individual N#{0} - Cost: {1}".format(best_index, best_indiv.get_cost()))
162160

163161
stop_no_graph = self._config.getboolean('BEHAVIOUR', 'stopongraph')
164-
EvaluatorFactory.get_ev_callback().show_best(best_index, best_indiv, stop_no_graph)
165-
162+
EvaluatorFactory.get_callback().show_best(best_index, best_indiv, stop_no_graph)
166163

167164
def _project_validations(self):
168165
# Check that the evaluation and preevaluation modules can be loaded
169-
EvaluatorFactory.get_ev_callback()
166+
EvaluatorFactory.get_callback()
170167
PreevaluationManager.get_callback()
171168

172169
# TODO: Add another validations

MLC/Common/RandomManager.py

Lines changed: 66 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,66 @@
1+
import os
2+
import MLC.Log.log as lg
3+
import random
4+
5+
6+
class RandomManager:
7+
"""
8+
Singleton class that manage the way in which the random numbers are generated.
9+
The options available at the moment are:
10+
* Load MATLAB generated randoms from a fike
11+
* Use Python randoms
12+
"""
13+
_rand_counter = 0
14+
_randoms = []
15+
16+
@staticmethod
17+
def rand():
18+
RandomManager._rand_counter += 1
19+
rand_value = None
20+
if not len(RandomManager._randoms):
21+
rand_value = random.random()
22+
else:
23+
try:
24+
rand_value = RandomManager._randoms.pop(0)
25+
except IndexError:
26+
lg.logger_.error("[RANDOM_MANAGER] Not enough random values. Aborting program.")
27+
raise
28+
29+
# lg.logger_.debug("[RANDOM_MANAGER] Rand #%d - Value: %.6f" % (RandomManager._rand_counter, rand_value))
30+
return rand_value
31+
32+
@staticmethod
33+
def randperm(n):
34+
"""
35+
This function throws as many rands as the value of n and return a
36+
list of the indexes of the ordered array of randoms.
37+
Example:
38+
If n == 5 and the randoms gathered are:
39+
0.1 0.9 0.2 0.6 0.3
40+
1 2 3 4 5
41+
The list returned by the method will be:
42+
0.1 0.2 0.3 0.6 0.9
43+
1 3 5 4 2
44+
[1,3,5,4,2]
45+
"""
46+
RandomManager._rand_counter += n
47+
rand_list = []
48+
49+
for _ in xrange(n):
50+
if not len(RandomManager._randoms):
51+
rand_list.append(random.random())
52+
else:
53+
rand_list.append(RandomManager._randoms.pop(0))
54+
55+
indexes = [x[0] for x in sorted(enumerate(rand_list), key=lambda x:x[1])]
56+
return indexes
57+
58+
@staticmethod
59+
def load_random_values(randoms_file):
60+
with open(randoms_file) as f:
61+
for line in f:
62+
RandomManager._randoms.append(float(line))
63+
64+
@staticmethod
65+
def clear_random_values():
66+
RandomManager._randoms = []

MLC/Population/Creation/BaseCreation.py

Lines changed: 0 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -3,15 +3,13 @@
33

44
from MLC.Common.PreevaluationManager import PreevaluationManager
55
from MLC.individual.Individual import Individual
6-
from MLC.matlab_engine import MatlabEngine
76
from MLC.mlc_table.MLCTable import MLCTable
87
from MLC.mlc_parameters.mlc_parameters import Config
98

109

1110
class BaseCreation(object):
1211

1312
def __init__(self):
14-
self._eng = MatlabEngine.engine()
1513
self._config = Config.get_instance()
1614

1715
# A list of tuples (index, number)

MLC/Population/Evaluation/EvaluatorFactory.py

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -8,7 +8,7 @@
88

99
class EvaluatorFactory(object):
1010
@staticmethod
11-
def get_ev_callback():
11+
def get_callback():
1212
module_name = Config.get_instance().get('EVALUATOR', 'evaluation_function')
1313
lg.logger_.debug('[EV_FACTORY] Importing module {0}'.format(module_name))
1414
try:
@@ -22,7 +22,7 @@ def get_ev_callback():
2222
@staticmethod
2323
def make(strategy):
2424
if strategy == "mfile_standalone":
25-
ev_callback = EvaluatorFactory.get_ev_callback()
25+
ev_callback = EvaluatorFactory.get_callback()
2626
return StandaloneEvaluator(ev_callback)
2727
else:
2828
lg.logger_.error("[EV_FACTORY] Evaluation method " +

MLC/Population/Evaluation/StandaloneEvaluator.py

Lines changed: 0 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,15 +1,13 @@
11
import sys
22
import MLC.Log.log as lg
33

4-
from MLC.matlab_engine import MatlabEngine
54
from MLC.mlc_parameters.mlc_parameters import Config
65
from MLC.mlc_table.MLCTable import MLCTable
76

87

98
class StandaloneEvaluator(object):
109

1110
def __init__(self, callback):
12-
self._eng = MatlabEngine.engine()
1311
self._config = Config.get_instance()
1412
self._callback = callback
1513

MLC/Population/Population.py

Lines changed: 5 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -2,12 +2,12 @@
22
import MLC.Log.log as lg
33
import sys
44

5-
from MLC.matlab_engine import MatlabEngine
5+
from MLC.Common.RandomManager import RandomManager
6+
from MLC.individual.Individual import OperationOverIndividualFail
67
from MLC.mlc_table.MLCTable import MLCTable
7-
from MLC.Population.Evaluation.EvaluatorFactory import EvaluatorFactory
88
from MLC.mlc_parameters.mlc_parameters import Config
9+
from MLC.Population.Evaluation.EvaluatorFactory import EvaluatorFactory
910
from MLC.Simulation import Simulation
10-
from MLC.individual.Individual import OperationOverIndividualFail
1111

1212

1313
class Population(object):
@@ -372,7 +372,7 @@ def choose_genetic_operation(amount_indivs_left):
372372
sys.exit(-1)
373373

374374
op = None
375-
rand_prob = MatlabEngine.rand()
375+
rand_prob = RandomManager.rand()
376376
if amount_indivs_left < 2:
377377
# Crossover is not possible
378378
rand_prob *= (prob_rep + prob_mut)
@@ -408,7 +408,7 @@ def _choose_individual(self, subgen_range):
408408
# subgeneration instead of the indexes
409409
random_indiv = -1
410410
while random_indiv == -1 or random_indiv in indivs_chosen:
411-
random_indiv = math.ceil(MatlabEngine.rand() * subgen_len) - 1
411+
random_indiv = math.ceil(RandomManager.rand() * subgen_len) - 1
412412
indivs_chosen.append(int(random_indiv))
413413

414414
# Got the random indivs. Grab the one with the minor cost

MLC/individual/Individual.py

Lines changed: 11 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -3,10 +3,10 @@
33

44
import MLC.Log.log as lg
55
from collections import Counter
6-
from MLC.matlab_engine import MatlabEngine
76
from MLC.mlc_parameters.mlc_parameters import Config
87
from MLC.Common.Operations import Operations
98
from MLC.Common.Lisp_Tree_Expr.Lisp_Tree_Expr import Lisp_Tree_Expr
9+
from MLC.Common.RandomManager import RandomManager
1010

1111
import re
1212

@@ -88,7 +88,6 @@ class MutationType:
8888
_maxdepthfirst = None
8989

9090
def __init__(self, value=None):
91-
self._eng = MatlabEngine.engine()
9291
self._config = Config.get_instance()
9392
self._tree = None
9493

@@ -285,22 +284,22 @@ def __generate_indiv_regressive_tree(self, value, indiv_type=None):
285284
elif (begin_depth < min_depth and end_str.find('@') == -1) or indiv_type == 3:
286285
leaf_node = False
287286
else:
288-
leaf_node = MatlabEngine.rand() < self._config.getfloat('POPULATION', 'leaf_prob')
287+
leaf_node = RandomManager.rand() < self._config.getfloat('POPULATION', 'leaf_prob')
289288

290289
if leaf_node:
291-
use_sensor = MatlabEngine.rand() < self._config.getfloat('POPULATION', 'sensor_prob')
290+
use_sensor = RandomManager.rand() < self._config.getfloat('POPULATION', 'sensor_prob')
292291
if use_sensor:
293-
sensor_number = math.ceil(MatlabEngine.rand() * self._config.getint('POPULATION', 'sensors')) - 1
292+
sensor_number = math.ceil(RandomManager.rand() * self._config.getint('POPULATION', 'sensors')) - 1
294293
new_value = begin_str + 'z' + str(sensor_number).rstrip('0').rstrip('.') + end_str
295294
else:
296295
range = self._config.getfloat('POPULATION', 'range')
297296
precision = self._config.get('POPULATION', 'precision')
298297
# Generate a float number between -range and +range with a precision of 'precision'
299-
new_exp = (("%." + precision + "f") % ((MatlabEngine.rand() - 0.5) * 2 * range))
298+
new_exp = (("%." + precision + "f") % ((RandomManager.rand() - 0.5) * 2 * range))
300299
new_value = begin_str + new_exp + end_str
301300
else:
302301
# Create a node
303-
op_num = math.ceil(MatlabEngine.rand() * Operations.get_instance().length())
302+
op_num = math.ceil(RandomManager.rand() * Operations.get_instance().length())
304303
op = Operations.get_instance().get_operation_from_op_num(op_num)
305304
if (op["nbarg"] == 1):
306305
new_value = begin_str + '(' + op["op"] + ' @)' + end_str
@@ -360,7 +359,7 @@ def __mutate_tree(self, expression_tree, mutation_type):
360359

361360
# equi probability for each mutation type selected.
362361
if mutation_type == Individual.MutationType.ANY:
363-
rand_number = MatlabEngine.rand()
362+
rand_number = RandomManager.rand()
364363
mutation_type = mutation_types[int(np.floor(rand_number * len(mutation_types)))]
365364

366365
if mutation_type in [Individual.MutationType.REMOVE_SUBTREE_AND_REPLACE, Individual.MutationType.SHRINK]:
@@ -408,10 +407,10 @@ def __mutate_tree(self, expression_tree, mutation_type):
408407
changed = False
409408
k = 0
410409

411-
for nc in MatlabEngine.randperm(controls):
410+
for nc in RandomManager.randperm(controls):
412411
k += 1
413412
# control law is cropped if it is the last one and no change happend before
414-
if (MatlabEngine.rand() < prob_threshold) or (k == controls and not changed):
413+
if (RandomManager.rand() < prob_threshold) or (k == controls and not changed):
415414

416415
try:
417416
_, sm, _ = self.__extract_subtree(Lisp_Tree_Expr('(root '+cl[nc - 1]+')'), mutmindepth+1, maxdepth, maxdepth+1)
@@ -439,7 +438,7 @@ def __extract_subtree(self, expression_tree, mindepth, subtreedepthmax, maxdepth
439438
(expression_tree, mindepth, maxdepth, subtreedepthmax))
440439

441440
candidates.sort(key=lambda x: x.get_expr_index(), reverse=False)
442-
n = int(np.ceil(MatlabEngine.rand() * len(candidates))) - 1
441+
n = int(np.ceil(RandomManager.rand() * len(candidates))) - 1
443442
extracted_node = candidates[n]
444443
index = extracted_node.get_expr_index()
445444
old_value = expression_tree.get_expanded_tree_as_string()
@@ -448,7 +447,7 @@ def __extract_subtree(self, expression_tree, mindepth, subtreedepthmax, maxdepth
448447

449448
def __reparam_tree(self, tree_expression):
450449
def leaf_value_generator():
451-
leaf_value = (MatlabEngine.rand() - 0.5) * 2 * self._range
450+
leaf_value = (RandomManager.rand() - 0.5) * 2 * self._range
452451
return "%0.*f" % (self._precision, leaf_value)
453452

454453
return self.__change_const_tree(tree_expression, leaf_value_generator)

MLC/matlab_engine.py

Lines changed: 3 additions & 59 deletions
Original file line numberDiff line numberDiff line change
@@ -4,6 +4,7 @@
44
import MLC.Log.log as lg
55
import random
66

7+
78
class MatlabEngine:
89
"""
910
Singleton class that allow to call matlab code from python using the
@@ -16,6 +17,7 @@ class MatlabEngine:
1617
@staticmethod
1718
def engine():
1819
if MatlabEngine._engine_instance is None:
20+
lg.logger_.info("[MATLAB_ENGINE] Loading MATLAB environment. Please wait...")
1921
matlab_code_dir = mlcv3_config.get_matlab_path()
2022

2123
# Check if a MATLAB session exists.
@@ -34,63 +36,5 @@ def engine():
3436
MatlabEngine._engine_instance.addpath(os.path.join(matlab_code_dir, "MLC_tools"))
3537
MatlabEngine._engine_instance.addpath(os.path.join(matlab_code_dir, "MLC_tools/Demo"))
3638

39+
lg.logger_.info("[MATLAB_ENGINE] MATLAB environment loaded succesfully.")
3740
return MatlabEngine._engine_instance
38-
39-
@staticmethod
40-
def rand():
41-
if MatlabEngine._engine_instance is None:
42-
raise UnboundLocalError('rand', 'Engine was not initialized')
43-
44-
MatlabEngine._rand_counter += 1
45-
rand_value = None
46-
if not len(MatlabEngine._randoms):
47-
rand_value = random.random()
48-
else:
49-
try:
50-
rand_value = MatlabEngine._randoms.pop(0)
51-
except IndexError:
52-
lg.logger_.error("[MATLAB_ENGINE] Not enough random values. Aborting program.")
53-
raise
54-
55-
# lg.logger_.debug("[ENGINE] Rand #%d - Value: %.6f" % (MatlabEngine._rand_counter, rand_value))
56-
return rand_value
57-
58-
@staticmethod
59-
def randperm(n):
60-
"""
61-
This function throws as many rands as the value of n and return a
62-
list of the indexes of the ordered array of randoms.
63-
Example:
64-
If n == 5 and the randoms gathered are:
65-
0.1 0.9 0.2 0.6 0.3
66-
1 2 3 4 5
67-
The list returned by the method will be:
68-
0.1 0.2 0.3 0.6 0.9
69-
1 3 5 4 2
70-
[1,3,5,4,2]
71-
"""
72-
73-
if MatlabEngine._engine_instance is None:
74-
raise UnboundLocalError('rand', 'Engine was not initialized')
75-
MatlabEngine._rand_counter += n
76-
77-
rand_list = []
78-
for _ in xrange(n):
79-
if not len(MatlabEngine._randoms):
80-
rand_list.append(random.random())
81-
else:
82-
rand_list.append(MatlabEngine._randoms.pop(0))
83-
84-
indexes = [x[0] for x in sorted(enumerate(rand_list), key=lambda x:x[1])]
85-
return indexes
86-
87-
88-
@staticmethod
89-
def load_random_values(randoms_file):
90-
with open(randoms_file) as f:
91-
for line in f:
92-
MatlabEngine._randoms.append(float(line))
93-
94-
@staticmethod
95-
def clear_random_values():
96-
MatlabEngine._randoms = []

MLC/mlc_parameters/mlc_parameters.py

Lines changed: 1 addition & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -1,10 +1,10 @@
11
import ConfigParser
22
import numpy as np
33
import MLC.Log.log as lg
4-
from MLC.matlab_engine import MatlabEngine
54

65

76
class saved():
7+
88
def __init__(self, cr):
99
self.cr = cr
1010

@@ -26,9 +26,6 @@ def __init__(self):
2626
ConfigParser.ConfigParser.__init__(self)
2727
self._log_prefix = '[CONFIG] '
2828

29-
def get_matlab_object(self):
30-
return MatlabEngine.engine().eval('wmlc.parameters')
31-
3229
def get_list(self, section, param, item_type=int):
3330
value = self.get(section, param)
3431

0 commit comments

Comments
 (0)