From f29670090b93d74b4554bd262b54e1f24509ec34 Mon Sep 17 00:00:00 2001 From: caglarcakan Date: Tue, 23 Mar 2021 11:54:57 +0100 Subject: [PATCH 1/4] supprt lists, clean code --- neurolib/optimize/evolution/evolution.py | 11 ++++++++--- neurolib/optimize/exploration/exploration.py | 15 +++++++++------ 2 files changed, 17 insertions(+), 9 deletions(-) diff --git a/neurolib/optimize/evolution/evolution.py b/neurolib/optimize/evolution/evolution.py index 8ae9ba37..17f9b55b 100644 --- a/neurolib/optimize/evolution/evolution.py +++ b/neurolib/optimize/evolution/evolution.py @@ -785,6 +785,11 @@ def _outputToDf(self, pop, df): :return: Dataframe with outputs :rtype: pandas.core.frame.DataFrame """ + # defines which variable types will be saved in the results dataframe + SUPPORTED_TYPES = (float, int, np.ndarray, list) + SCALAR_TYPES = (float, int) + ARRAY_TYPES = (np.ndarray, list) + assert len(pop) == len(df), "Dataframe and population do not have same length." nan_value = np.nan # load outputs into dataframe @@ -792,15 +797,15 @@ def _outputToDf(self, pop, df): if hasattr(p, "outputs"): for key, value in p.outputs.items(): # only save floats, ints and arrays - if isinstance(value, (float, int, np.ndarray)): + if isinstance(value, SUPPORTED_TYPES): # save 1-dim arrays - if isinstance(value, np.ndarray): + if isinstance(value, ARRAY_TYPES): # to save a numpy array, convert column to object type if key not in df: df[key] = None df[key] = df[key].astype(object) df.at[i, key] = value - elif isinstance(value, (float, int)): + elif isinstance(value, SCALAR_TYPES): # save numbers df.loc[i, key] = value else: diff --git a/neurolib/optimize/exploration/exploration.py b/neurolib/optimize/exploration/exploration.py index 7928a938..26e411d3 100644 --- a/neurolib/optimize/exploration/exploration.py +++ b/neurolib/optimize/exploration/exploration.py @@ -352,9 +352,12 @@ def aggregateResultsToDfResults(self, arrays=True, fillna=False): :type fillna: bool, optional """ nan_value = np.nan - logging.info("Aggregating results to `dfResults` ...") - # for i, result in tqdm.tqdm(self.results.items()): + # defines which variable types will be saved in the results dataframe + SUPPORTED_TYPES = (float, int, np.ndarray, list) + SCALAR_TYPES = (float, int) + ARRAY_TYPES = (np.ndarray, list) + logging.info("Aggregating results to `dfResults` ...") for runId, parameters in tqdm.tqdm(self.dfResults.iterrows(), total=len(self.dfResults)): # if the results were previously loaded into memory, use them if hasattr(self, "results"): @@ -370,16 +373,16 @@ def aggregateResultsToDfResults(self, arrays=True, fillna=False): for key, value in result.items(): # only save floats, ints and arrays - if isinstance(value, (float, int, np.ndarray)): + if isinstance(value, SUPPORTED_TYPES): # save 1-dim arrays - if isinstance(value, np.ndarray) and arrays: + if isinstance(value, ARRAY_TYPES) and arrays: # to save a numpy array, convert column to object type if key not in self.dfResults: self.dfResults[key] = None self.dfResults[key] = self.dfResults[key].astype(object) self.dfResults.at[runId, key] = value - elif isinstance(value, (float, int)): - # save numbers + elif isinstance(value, SCALAR_TYPES): + # save scalars self.dfResults.loc[runId, key] = value else: self.dfResults.loc[runId, key] = nan_value From 3244af9455435e2a58676ab38f830deb67900301 Mon Sep 17 00:00:00 2001 From: caglarcakan Date: Tue, 23 Mar 2021 12:07:11 +0100 Subject: [PATCH 2/4] tests --- tests/test_exploration.py | 13 +++++++++---- 1 file changed, 9 insertions(+), 4 deletions(-) diff --git a/tests/test_exploration.py b/tests/test_exploration.py index 2a12aade..509f500f 100644 --- a/tests/test_exploration.py +++ b/tests/test_exploration.py @@ -9,6 +9,7 @@ import neurolib.utils.pypetUtils as pu import numpy as np import xarray as xr + from neurolib.models.aln import ALNModel from neurolib.models.fhn import FHNModel from neurolib.models.multimodel import MultiModel @@ -151,7 +152,7 @@ def explore_me(traj): pars = search.getParametersFromTraj(traj) # let's calculate the distance to a circle computation_result = abs((pars["x"] ** 2 + pars["y"] ** 2) - 1) - result_dict = {"distance": computation_result} + result_dict = {"scalar_result": computation_result, "list_result": [1, 2, 3, 4], "array_result": np.ones(3)} search.saveToPypet(result_dict, traj) parameters = ParameterSpace({"x": np.linspace(-2, 2, 2), "y": np.linspace(-2, 2, 2)}) @@ -159,11 +160,15 @@ def explore_me(traj): search.run() search.loadResults(pypetShortNames=False) - for i in search.dfResults.index: - search.dfResults.loc[i, "distance"] = search.results[i]["distance"] - + # call the result dataframe search.dfResults + # test integrity of dataframe + for i in search.dfResults.index: + self.assertEqual(search.dfResults.loc[i, "scalar_result"], search.results[i]["scalar_result"]) + self.assertListEqual(search.dfResults.loc[i, "list_result"], search.results[i]["list_result"]) + np.testing.assert_array_equal(search.dfResults.loc[i, "array_result"], search.results[i]["array_result"]) + class TestExplorationMultiModel(unittest.TestCase): """ From 8747569d6a06a76c03504041bbe1e8467edb84c5 Mon Sep 17 00:00:00 2001 From: caglarcakan Date: Mon, 29 Mar 2021 11:30:53 +0200 Subject: [PATCH 3/4] evolution: plot_progress attribute --- neurolib/optimize/evolution/evolution.py | 8 +++++--- 1 file changed, 5 insertions(+), 3 deletions(-) diff --git a/neurolib/optimize/evolution/evolution.py b/neurolib/optimize/evolution/evolution.py index 17f9b55b..c976d2a7 100644 --- a/neurolib/optimize/evolution/evolution.py +++ b/neurolib/optimize/evolution/evolution.py @@ -147,6 +147,7 @@ def __init__( # -------- settings self.verbose = False + self.verbose_plotting = True self.plotColor = "C0" # -------- simulation @@ -235,7 +236,7 @@ def __init__( self.evaluationCounter = 0 self.last_id = 0 - def run(self, verbose=False): + def run(self, verbose=False, verbose_plotting=True): """Run the evolution or continue previous evolution. If evolution was not initialized first using `runInitial()`, this will be done. @@ -244,6 +245,7 @@ def run(self, verbose=False): """ self.verbose = verbose + self.verbose_plotting = verbose_plotting if not self._initialPopulationSimulated: self.runInitial() @@ -650,7 +652,7 @@ def runEvolution(self): # verbose output if self.verbose: - self.info(plot=True, info=True) + self.info(plot=self.verbose_plotting, info=True) logging.info("--- End of evolution ---") logging.info("Best individual is %s, %s" % (self.best_ind, self.best_ind.fitness.values)) @@ -710,7 +712,7 @@ def info(self, plot=True, bestN=5, info=True, reverse=False): print(f"Best {bestN} individuals:") eu.printIndividuals(self.toolbox.selBest(self.pop, bestN), self.paramInterval) print("--------------------") - # Plotting + # Plotting evolutionary progress if plot: # hack: during the evolution we need to use reverse=True # after the evolution (with evolution.info()), we need False From 885cea4aaad8577c44aa58e385fdd5acbda69b0a Mon Sep 17 00:00:00 2001 From: caglarcakan Date: Wed, 31 Mar 2021 08:50:12 +0200 Subject: [PATCH 4/4] bump version --- setup.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/setup.py b/setup.py index f1da6ef3..a4ca08bd 100644 --- a/setup.py +++ b/setup.py @@ -11,7 +11,7 @@ setuptools.setup( name="neurolib", - version="0.5.13", + version="0.5.14", description="Easy whole-brain neural mass modeling", long_description=long_description, long_description_content_type="text/markdown",