# AUTOGENERATED! DO NOT EDIT! File to edit: nbs/04_utils.ipynb (unless otherwise specified).

__all__ = ['ConcurrentMap', 'parameters2json', 'json2parameters']

# Internal Cell
from math import log, log10, log2
from concurrent.futures import ProcessPoolExecutor
import os
from deap.tools import Logbook, HallOfFame
from matplotlib import pylab

def logx(y, x=10):
    return log(y) / log(x)


def _logbook_plot(self, keys='all', ax=None):
    if keys=='all':
        keys= list(self.header)
        keys.remove('gen')
        keys.remove('nevals')
    if ax is None:
        figure = pylab.figure()
        ax = figure.add_subplot()
    for key in keys:
        ax.plot(self.select('gen'), self.select(key))
    pylab.title(f'EPTune with {sum(self.select("nevals"))} evaluations')
    ax.legend(keys)
    return ax.figure


Logbook.plot =  _logbook_plot

def _hof_repr(self):
    return str([(i,i.fitness.values) for i in self])

HallOfFame.__repr__ = _hof_repr

# Cell
class ConcurrentMap:
    """Helper class to provide `map` function using multiple cores."""
    def __init__(self, n_jobs):
        """Create a ConcurrentMap instance, the map attribute can be used as map function in toolbox.

        **Parameters**

        - n_jobs: number of cores to use. If n_jobs<0, the number will set to the number of cores available.
        """
        self.n_jobs = n_jobs
        if n_jobs < 0:
            self.n_jobs = os.cpu_count()
        if n_jobs == 1:
            self._executor = None
            self.map = map
        else:
            self._executor = ProcessPoolExecutor(n_jobs)
            self.map = self._executor.map

    def __enter__(self):
        if self.is_closed:
            self._executor = ProcessPoolExecutor(self.n_jobs)
            self.map = self._executor.map
        return self.map

    def __exit__(self, exc_type, exc_val, exc_tb):
        self.close()

    @property
    def is_closed(self):
        if self.n_jobs > 1:
            return self._executor._shutdown_thread
        else:
            return False

    def close(self):
        "Close the pool for the `map` function."
        if self._executor is not None:
            self._executor.shutdown()

# Cell
from .parameter import *
import json
def parameters2json(obj):
    if isinstance(obj, (tuple, list)):
        return json.dumps([repr(i) for i in obj])
    elif isinstance(obj, dict):
        return json.dumps({k:repr(v) for k,v in obj.items()})
    elif isinstance(obj, Parameter):
        return json.dumps(repr(obj))

def json2parameters(string):
    obj = json.loads(string)
    if isinstance(obj, list):
        return [eval(i) for i in obj]
    elif isinstance(obj, dict):
        return {k:eval(v) for k,v in obj.items()}
    else:
        return eval(obj)