Skip to content

Commit a75ac6b

Browse files
committed
Fixes in Integration and Unit Test to run with the new workspace structure
* In order to run cleaner tests, now the MLCLocal receives the scripts as a parameter when a new experiment is created. If no scripts are given, MLC will use the template scripts as it was working before #35
1 parent 0c92420 commit a75ac6b

18 files changed

+429
-58
lines changed

MLC/api/Experiment.py

Lines changed: 5 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -56,7 +56,8 @@ def set_configuration(self, new_configuration):
5656
Config.get_instance().read(self._config_file)
5757

5858
@staticmethod
59-
def make(working_dir, experiment_name, experiment_configuration):
59+
def make(working_dir, experiment_name, experiment_configuration,
60+
evaluation_script, preevaluation_script):
6061
# Obtain experiment filenames
6162
experiment_dir = os.path.join(working_dir, experiment_name)
6263
experiment_cf, experiment_db = Experiment.get_experiment_files(experiment_dir, experiment_name)
@@ -79,17 +80,14 @@ def make(working_dir, experiment_name, experiment_configuration):
7980
simulation = Simulation(experiment_name)
8081

8182
def folder_structure_creator(folder_to_create, file_to_copy):
82-
templates_dir = path_solver.get_templates_path()
83-
file_template = os.path.join(templates_dir, file_to_copy)
8483
folder_path = os.path.join(experiment_dir, folder_to_create)
85-
file_copied = os.path.join(folder_path, file_to_copy)
8684
os.makedirs(folder_path)
87-
shutil.copyfile(file_template, file_copied)
85+
shutil.copy(file_to_copy, folder_path)
8886
init_file = os.path.join(folder_path, "__init__.py")
8987
open(init_file, "w").close()
9088

91-
folder_structure_creator("Evaluation", "toy_problem.py")
92-
folder_structure_creator("Preevaluation", "default.py")
89+
folder_structure_creator("Evaluation", evaluation_script)
90+
folder_structure_creator("Preevaluation", preevaluation_script)
9391

9492
# Load experiment
9593
try:

MLC/api/MLCLocal.py

Lines changed: 28 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -14,6 +14,8 @@
1414
from MLC.api.mlc import ExperimentNotExistException
1515
from MLC.api.mlc import DuplicatedExperimentError
1616
from MLC.api.mlc import InvalidExperimentException
17+
from MLC.api.mlc import EvaluationScriptNotExistException
18+
from MLC.api.mlc import PreevaluationScriptNotExistException
1719
from MLC.Application import Application
1820
from MLC.config import get_templates_path
1921
from MLC.config import set_working_directory
@@ -27,6 +29,8 @@
2729

2830
class MLCLocal(MLC):
2931
DEFAULT_EXPERIMENT_CONFIG = os.path.join(get_templates_path(), "configuration.ini")
32+
DEFAULT_EVALUATION_SCRIPT = os.path.join(get_templates_path(), "toy_problem.py")
33+
DEFAULT_PREEVALUATION_SCRIPT = os.path.join(get_templates_path(), "default.py")
3034

3135
def __init__(self, working_dir):
3236
if not os.path.exists(working_dir):
@@ -85,14 +89,19 @@ def close_experiment(self, experiment_name):
8589
sys.path.remove(experiment_dir)
8690
del self._open_experiments[experiment_name]
8791

88-
def new_experiment(self, experiment_name, experiment_configuration=None):
92+
def new_experiment(self, experiment_name,
93+
experiment_configuration=None,
94+
evaluation_script=None,
95+
preevaluation_script=None):
8996
self._create_experiment_dir(experiment_name)
9097

9198
config = experiment_configuration
9299
if experiment_configuration is None:
93100
config = MLCLocal.DEFAULT_EXPERIMENT_CONFIG
94101

95-
self._load_new_experiment(experiment_name, config)
102+
self._load_new_experiment(experiment_name, config,
103+
evaluation_script,
104+
preevaluation_script)
96105

97106
def delete_experiment(self, experiment_name):
98107
if experiment_name not in self._experiments:
@@ -249,15 +258,30 @@ def _create_experiment_dir(self, experiment_name):
249258
"Experiment already exists".format(experiment_name))
250259
raise DuplicatedExperimentError(experiment_name)
251260

252-
def _load_new_experiment(self, experiment_name, config_path):
261+
def _load_new_experiment(self, experiment_name, config_path,
262+
evaluation_script, preevaluation_script):
253263
experiment_config = ConfigParser.ConfigParser()
254264
experiment_config.read(config_path)
255265
config = Config.to_dictionary(experiment_config)
256266

267+
if evaluation_script is None:
268+
evaluation_script = MLCLocal.DEFAULT_EVALUATION_SCRIPT
269+
270+
if preevaluation_script is None:
271+
preevaluation_script = MLCLocal.DEFAULT_PREEVALUATION_SCRIPT
272+
273+
if not os.path.exists(evaluation_script):
274+
raise EvaluationScriptNotExistException(experiment_name, evaluation_script)
275+
276+
if not os.path.exists(preevaluation_script):
277+
raise PreevaluationScriptNotExistException(experiment_name, evaluation_script)
278+
257279
try:
258280
self._experiments[experiment_name] = Experiment.make(self._working_dir,
259281
experiment_name,
260-
config)
282+
config,
283+
evaluation_script,
284+
preevaluation_script)
261285
except Exception, err:
262286
logger.error("Cannot create a new experiment. Error message: %s " % err)
263287
raise

MLC/api/mlc.py

Lines changed: 16 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -20,6 +20,22 @@ def __init__(self, experiment_name):
2020
MLCException.__init__(self, "Experiment '%s' already exists." % experiment_name)
2121

2222

23+
class EvaluationScriptNotExistException(MLCException):
24+
25+
def __init__(self, experiment_name, script_path):
26+
MLCException.__init__(self, "Experiment {0} is trying to use a non "
27+
"existent evaluation script. Script: {1}"
28+
.format(experiment_name, script_path))
29+
30+
31+
class PreevaluationScriptNotExistException(MLCException):
32+
33+
def __init__(self, experiment_name, script_path):
34+
MLCException.__init__(self, "Experiment {0} is trying to use a non "
35+
"existent evaluation script. Script: {1}"
36+
.format(experiment_name, script_path))
37+
38+
2339
class MLC:
2440

2541
def open_experiment(self, experiment_name):

MLC/db/sqlite/sqlite_repository.py

Lines changed: 0 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -12,7 +12,6 @@ class SQLiteRepository(MLCRepository):
1212
IN_MEMORY_DB = ":memory:"
1313

1414
def __init__(self, database, init_db=False):
15-
print database
1615
self._conn = sqlite3.connect(database)
1716
self._database = database
1817

tests/integration_tests/integration_tests.py

Lines changed: 38 additions & 31 deletions
Original file line numberDiff line numberDiff line change
@@ -1,10 +1,13 @@
1-
import sys, os
1+
import sys
2+
import os
23
sys.path.append("../..")
34
import matlab.engine
45
import numpy as np
6+
import shutil
57
import unittest
68
import yaml
79

10+
from MLC.api.MLCLocal import MLCLocal
811
from MLC.Application import Application
912
from MLC.Common.RandomManager import RandomManager
1013
from MLC.db.mlc_repository import MLCRepository
@@ -20,6 +23,8 @@
2023
class MLCIntegrationTest(unittest.TestCase):
2124
TEST_DIRECTORY = None
2225
GENERATIONS = None
26+
WORKSPACE_DIR = os.path.abspath("/tmp/mlc_workspace/")
27+
EXPERIMENT_NAME = "integration_tests"
2328

2429
@classmethod
2530
def _populate_indiv_dict(cls):
@@ -69,6 +74,8 @@ def _populate_pop_dict(cls):
6974
@classmethod
7075
def setUpClass(cls):
7176
config_file = os.path.join(MLCIntegrationTest.TEST_DIRECTORY, './configuration.ini')
77+
ev_script = os.path.join(MLCIntegrationTest.TEST_DIRECTORY, './default_evaluation_script.py')
78+
preev_script = os.path.join(MLCIntegrationTest.TEST_DIRECTORY, './default_preevaluation_script.py')
7279

7380
# Load the config
7481
config = Config.get_instance()
@@ -79,46 +86,47 @@ def setUpClass(cls):
7986
RandomManager.clear_random_values()
8087
RandomManager.load_random_values(random_file)
8188

82-
# clear state
83-
if Config.get_instance().getboolean("BEHAVIOUR", "save"):
84-
try:
85-
os.remove(Config.get_instance().get("BEHAVIOUR", "savedir"))
86-
except OSError:
87-
pass
89+
# Create the workspace directory
90+
try:
91+
os.makedirs(MLCIntegrationTest.WORKSPACE_DIR)
92+
except OSError:
93+
shutil.rmtree(MLCIntegrationTest.WORKSPACE_DIR)
94+
os.makedirs(MLCIntegrationTest.WORKSPACE_DIR)
95+
96+
# Create a new experiment, which will be used to
97+
cls._mlc = MLCLocal(working_dir=MLCIntegrationTest.WORKSPACE_DIR)
98+
cls._mlc.new_experiment(experiment_name=MLCIntegrationTest.EXPERIMENT_NAME,
99+
experiment_configuration=config_file,
100+
evaluation_script=ev_script,
101+
preevaluation_script=preev_script)
102+
cls._mlc.open_experiment(experiment_name=MLCIntegrationTest.EXPERIMENT_NAME)
88103

89104
for generation_params in MLCIntegrationTest.GENERATIONS:
90-
# clear static values
91-
if Config.get_instance().getboolean("BEHAVIOUR", "save"):
92-
MLCRepository._instance = None
93-
simulation = Simulation("integration_test")
94-
cls._app = Application(simulation)
95-
96105
if isinstance(generation_params, int):
97-
cls._app.go(to_generation=generation_params)
106+
cls._mlc.go(experiment_name=MLCIntegrationTest.EXPERIMENT_NAME,
107+
to_generation=generation_params)
98108

99109
elif isinstance(generation_params, list):
100-
cls._app.go(from_generation=generation_params[0],
110+
cls._mlc.go(experiment_name=MLCIntegrationTest.EXPERIMENT_NAME,
111+
from_generation=generation_params[0],
101112
to_generation=generation_params[1])
102113

103114
else:
104115
raise Exception("Integration test, bad value for generations param")
105116

106-
if Config.get_instance().getboolean("BEHAVIOUR", "save"):
107-
MLCRepository._instance._conn.close()
108-
MLCRepository._instance = None
109-
cls._app = Application(Simulation("integration_test"))
110-
111-
a = cls._app.get_simulation().number_of_generations()
112-
print "Number of populations: " + str(a)
113-
114117
# List with individuals data
115118
cls._indivs = []
116119
cls._populate_indiv_dict()
117120

118121
cls._pops = []
119122
cls ._populate_pop_dict()
120123

121-
## FIXME: Test methods should be cerated dynamically in the setUp method.
124+
@classmethod
125+
def tearDownClass(cls):
126+
cls._mlc.close_experiment(experiment_name=MLCIntegrationTest.EXPERIMENT_NAME)
127+
shutil.rmtree(MLCIntegrationTest.WORKSPACE_DIR)
128+
129+
# FIXME: Test methods should be crated dynamically in the setUp method.
122130
def test_generation_1(self):
123131
if max(MLCIntegrationTest.GENERATIONS) >= 1:
124132
self._run_x_generation(1)
@@ -160,7 +168,7 @@ def _run_x_generation(self, gen_number):
160168
self._check_indiv_values(gen_number)
161169

162170
print "Check Indvidual properties..."
163-
pop = self._app.get_simulation().get_generation(gen_number)
171+
pop = self._mlc.get_generation(MLCIntegrationTest.EXPERIMENT_NAME, gen_number)
164172
self._check_indiv_property(gen_number, pop.get_individuals(), 'index', 'int')
165173
self._check_indiv_property(gen_number, pop.get_costs(), 'cost', 'float')
166174

@@ -169,7 +177,7 @@ def _run_x_generation(self, gen_number):
169177

170178
def _check_indiv_values(self, gen_number):
171179
i = 1
172-
indexes = self._app.get_simulation().get_generation(gen_number).get_individuals()
180+
indexes = self._mlc.get_generation(MLCIntegrationTest.EXPERIMENT_NAME, gen_number).get_individuals()
173181
print "Check %s indviduals from generation %s" % (len(indexes), gen_number)
174182
for index in indexes:
175183
indiv = MLCRepository.get_instance().get_individual(index)
@@ -187,10 +195,6 @@ def _check_indiv_property(self, gen_number, values, map_property, type=None):
187195
# List of dictionaries with the values of every individual
188196
pop = self._pops[gen_number - 1]
189197
for i in range(len(pop)):
190-
# if str(values[i]) != str(pop[i][map_property]):
191-
# print "Indiv N#{0} - Value obtained: {1}".format(i + 1, values[i])
192-
# print "Indiv N#{0} - Value expected: {1}".format(i + 1, str(pop[i][map_property]))
193-
194198
if type == 'int':
195199
self.assertEqual(int(values[i]), int(pop[i][map_property]))
196200
elif type == 'float':
@@ -203,6 +207,7 @@ def _check_indiv_property(self, gen_number, values, map_property, type=None):
203207
else:
204208
self.assertEqual(values[i], pop[i][map_property])
205209

210+
206211
def get_test_class(test_dir, integration_test):
207212
generations = integration_test['generations']
208213
if isinstance(generations, int):
@@ -211,10 +216,12 @@ def get_test_class(test_dir, integration_test):
211216
class IntegrationTest(MLCIntegrationTest):
212217
MLCIntegrationTest.TEST_DIRECTORY = test_dir
213218
MLCIntegrationTest.GENERATIONS = generations
219+
MLCIntegrationTest.EXPERIMENT_NAME = test_dir
214220

215221
return IntegrationTest
216222

217-
def execute_integration_test(test_name, integration_test):
223+
224+
def execute_integration_test(test_dir, integration_test):
218225
print "Running '%s' with %s generations: %s" % (integration_test['name'],
219226
integration_test['generations'],
220227
integration_test['description'])

tests/integration_tests/test_basic/configuration.ini

Lines changed: 2 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -48,11 +48,8 @@ cascade = 1,1
4848

4949
[EVALUATOR]
5050
# Evaluator
51-
# evaluation_method = standalone_function
52-
# evaluation_method = standalone_files
5351
evaluation_method = mfile_standalone
54-
evaluation_function = toy_problem
55-
# evaluation_function = toy_problem_python_ev
52+
evaluation_function = default_evaluation_script
5653
indfile = ind.dat
5754
Jfile = J.dat
5855
# exchangedir = fullfile(pwd,evaluator0)
@@ -67,7 +64,7 @@ badvalues_elim = first
6764
%badvalues_elim = none
6865
%badvalues_elim = all
6966
preevaluation = false
70-
preev_function = default
67+
preev_function = default_preevaluation_script
7168
problem_variables.gamma = 0.1
7269

7370
[BEHAVIOUR]
Lines changed: 74 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,74 @@
1+
import numpy as np
2+
import MLC.Log.log as lg
3+
import matplotlib.pyplot as plt
4+
import sys
5+
6+
from MLC.matlab_engine import MatlabEngine
7+
from MLC.mlc_parameters.mlc_parameters import Config
8+
9+
10+
def individual_data(indiv):
11+
x = np.linspace(-10.0, 10.0, num=201)
12+
y = np.tanh(x**3 - x**2 - 1)
13+
14+
eng = MatlabEngine.engine()
15+
config = Config.get_instance()
16+
# artificial_noise = self._config.getint('EVALUATOR', 'artificialnoise')
17+
18+
# In this test we have no noise by config file. But, if this were the
19+
# case, we would a have problem because the random of MATLAB is not
20+
# the random of Python :(
21+
# WORKAROUND: Generate the noise in matlab and process it in python
22+
23+
# MAKE SOME NOISE!!!
24+
# noise = eng.eval('rand(length(zeros(1, ' + str(len(x)) + ')))-0.5')
25+
# np_noise = np.array([s for s in noise[0]])
26+
# y2 = y + np_noise * 500 * artificial_noise
27+
28+
y2 = y
29+
30+
if isinstance(indiv.get_formal(), str):
31+
formal = indiv.get_formal().replace('S0', 'x')
32+
else:
33+
# toy problem support for multiple controls
34+
formal = indiv.get_formal()[0].replace('S0', 'x')
35+
36+
eng.workspace['x'] = eng.eval('-10:0.1:10')
37+
eng.workspace['formal'] = formal
38+
39+
# Calculate J like the sum of the square difference of the
40+
# functions in every point
41+
42+
lg.logger_.debug('[POP][TOY_PROBLEM] Individual Formal: ' + formal)
43+
eng.workspace['y3'] = eng.eval('zeros(1, ' + str(len(x)) + ')')
44+
eng.eval('eval([formal])')
45+
y3 = eng.eval('eval([formal])')
46+
47+
try:
48+
np_y3 = np.array([s for s in y3[0]])
49+
except TypeError:
50+
np_y3 = np.repeat(y3, len(x))
51+
52+
return x, y, y2, np_y3
53+
54+
55+
def cost(indiv):
56+
x, y, y2, np_y3 = individual_data(indiv)
57+
cost_np_y3 = float(np.sum((np_y3 - y2)**2))
58+
return cost_np_y3
59+
60+
61+
def show_best(index, indiv, cost, block=True):
62+
x, y, y2, np_y3 = individual_data(indiv)
63+
# FIXME: Absolute only makes sense if we're working with complex numbers. It's not the case...
64+
y4 = np.sqrt((y - np_y3)**2 / (1 + np.absolute(x**2)))
65+
66+
plt.clf()
67+
plt.suptitle("Individual N#{0} - Cost: {1} \n Formal: {2}".format(index, cost, indiv.get_formal()))
68+
plt.subplot(2, 1, 1)
69+
plt.plot(x, y, x, y2, '*', x, np_y3)
70+
71+
plt.subplot(2, 1, 2)
72+
plt.plot(x, y4, '*r')
73+
plt.yscale('log')
74+
plt.show(block=block)
Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,8 @@
1+
import MLC.Log.log as lg
2+
from MLC.mlc_parameters.mlc_parameters import Config
3+
from MLC.individual.Individual import Individual
4+
5+
6+
def preev(indiv):
7+
# TODO: Do something
8+
return True

0 commit comments

Comments
 (0)