diff --git a/cache/__init__.py b/cache/__init__.py index b1868d2..bc2e286 100644 --- a/cache/__init__.py +++ b/cache/__init__.py @@ -20,6 +20,34 @@ from klepto import lru_cache, lfu_cache, mru_cache from klepto import rr_cache, inf_cache, no_cache +class _cached(object): + def __init__(self, func, multivalued=False): + self.func = func + self.multivalued = multivalued + def mvmodel(self, x, *argz, **kwdz): + axis = kwdz.pop('axis', None) + if axis is None: axis = slice(None) + return self.func(x, *argz, **kwdz)[axis] + def model(self, x, *argz, **kwdz): + axis = kwdz.pop('axis', None) + return self.func(x, *argz, **kwdz) + def __call__(self, x, *argz, **kwdz): + doit = self.mvmodel if self.multivalued else self.model + return doit(x, *argz, **kwdz) + +class _cache(object): + def __init__(self, func): + self.func = func + def __call__(self): + return self.func.__cache__() + +class _imodel(object): + def __init__(self, model): + self.model = model + def __call__(self, *args, **kwds): + return -self.model(*args, **kwds) + + def cached(**kwds): """build a caching archive for an objective function @@ -73,22 +101,13 @@ def _model(x, *args, **kwds): _model.__inner__ = inner # when caching, always cache the multi-valued tuple - if multivalued: - def model(x, *argz, **kwdz): - axis = kwdz.pop('axis', None) - if axis is None: axis = slice(None) - return _model(x, *argz, **kwdz)[axis] - else: - def model(x, *argz, **kwdz): - axis = kwdz.pop('axis', None) - return _model(x, *argz, **kwdz) + model = _cached(_model, multivalued) # produce objective function that caches multi-valued output - model.__cache__ = lambda : inner.__cache__() + model.__cache__ = _cache(inner) model.__doc__ = objective.__doc__ # produce model inverse with shared cache - imodel = lambda *args, **kwds: -model(*args, **kwds) - model.__inverse__ = imodel + model.__inverse__ = imodel = _imodel(model) imodel.__inverse__ = model imodel.__cache__ = model.__cache__ diff --git a/examples3/estimator.py b/examples3/estimator.py index 2feffc8..1f35039 100644 --- a/examples3/estimator.py +++ b/examples3/estimator.py @@ -213,18 +213,27 @@ def learn_ax(i): from mystic.math.interpolate import _getaxis from ml import Estimator as Learner func = Learner(estimator, transform) + _z = _getaxis(z, i) + #from ml import improve_score, MLData + #_z = MLData(x, x, _z, _z) + #kwds = dict(tries=10, verbose=True) with np.warnings.catch_warnings(): #FIXME: enable warn=True np.warnings.filterwarnings('ignore') - func = func.train(x, _getaxis(z, i)) + func = func.train(x, _z) + #func = improve_score(func, _z, **kwds) return func function.__axis__ = list(_map(learn_ax, range(len(z[0])))) return function else: from mystic.math.interpolate import _getaxis z = _getaxis(z, axis) + #from ml import improve_score, MLData + #_z = MLData(x, x, z, z) + #kwds = dict(tries=10, verbose=True) with np.warnings.catch_warnings(): #FIXME: enable warn=True np.warnings.filterwarnings('ignore') function = learner.train(x, z) + #function = improve_score(learner, _z, **kwds) function.__axis__ = axis return function diff --git a/examples3/ouq.py b/examples3/ouq.py index c204779..ab9607d 100644 --- a/examples3/ouq.py +++ b/examples3/ouq.py @@ -230,6 +230,7 @@ def solve(self, objective, **kwds): #NOTE: single axis only maxfun: max number of objective evaluations [default: defined in solver] evalmon: mystic.monitor instance [default: Monitor], for evaluations stepmon: mystic.monitor instance [default: Monitor], for iterations + save: iteration frequency to save solver [default: None] opts: dict of configuration options for solver.Solve [default: {}] Returns: @@ -251,6 +252,9 @@ def solve(self, objective, **kwds): #NOTE: single axis only else: # DiffEv/Nelder/Powell if x0 is None: solver.SetRandomInitialPoints(min=lb,max=ub) else: solver.SetInitialPoints(x0) + save = kwds.get('save', None) + if save is not None: + solver.SetSaveFrequency(save, 'Solver.pkl') #XXX: set name? mapper = kwds.get('pool', None) if mapper is not None: pool = mapper() #XXX: ThreadPool, ProcessPool, etc diff --git a/examples3/ouq_models.py b/examples3/ouq_models.py index 8c6b958..9f306ac 100644 --- a/examples3/ouq_models.py +++ b/examples3/ouq_models.py @@ -7,6 +7,11 @@ ''' model objects (and helper functions) to be used with OUQ classes ''' +def _modelaxis(model, axis=None): + def axmodel(x): + return model(x, axis=axis) + return axmodel + #FIXME: hardwired to multivalue function #FIXME: dict_archive('truth', cached=False) does not cache (is empty) #FIXME: option to cache w/o lookup (e.g. for model with randomness) @@ -85,7 +90,7 @@ def sample(model, bounds, pts=None, **kwds): elif pts > 0: # sample pts without optimizing pts = pts if _pts is None else _pts def doit(axis=None): - _model = lambda x: model(x, axis=axis) + _model = _modelaxis(model, axis) s = searcher(bounds, _model, npts=pts, dist=dist, **kwds) s.sample() return s @@ -97,12 +102,12 @@ def doit(axis=None): else: # search for minima until terminated pts = -pts if _pts is None else _pts def lower(axis=None): - _model = lambda x: model(x, axis=axis) + _model = _modelaxis(model, axis) s = searcher(bounds, _model, npts=pts, dist=dist, **kwds) s.sample_until(terminated=all) return s def upper(axis=None): - model_ = lambda x: imodel(x, axis=axis) + model_ = _modelaxis(imodel, axis) si = searcher(bounds, model_, npts=pts, dist=dist, **kwds) si.sample_until(terminated=all) return si