Caching functions now take two arguments: self and which, which is the argument which started the update

This commit is contained in:
Max Zwiessele 2014-03-24 08:52:23 +00:00
parent 0b5f6ea7c6
commit a493dd085e
7 changed files with 114 additions and 44 deletions

View file

@ -368,26 +368,26 @@ class ParamConcatenation(object):
#===========================================================================
def __getitem__(self, s):
ind = numpy.zeros(sum(self._param_sizes), dtype=bool); ind[s] = True;
params = [p._get_params()[ind[ps]] for p,ps in zip(self.params, self._param_slices_) if numpy.any(p._get_params()[ind[ps]])]
params = [p._param_array_[ind[ps]] for p,ps in zip(self.params, self._param_slices_) if numpy.any(p._param_array_[ind[ps]])]
if len(params)==1: return params[0]
return ParamConcatenation(params)
def __setitem__(self, s, val, update=True):
if isinstance(val, ParamConcatenation):
val = val._vals()
val = val.values()
ind = numpy.zeros(sum(self._param_sizes), dtype=bool); ind[s] = True;
vals = self._vals(); vals[s] = val; del val
vals = self.values(); vals[s] = val; del val
[numpy.place(p, ind[ps], vals[ps])
for p, ps in zip(self.params, self._param_slices_)]
if update:
self.update_all_params()
def _vals(self):
def values(self):
return numpy.hstack([p._param_array_ for p in self.params])
#===========================================================================
# parameter operations:
#===========================================================================
def update_all_params(self):
for par in self.parents:
par.notify_observers(-numpy.inf)
par.notify_observers()
def constrain(self, constraint, warning=True):
[param.constrain(constraint, trigger_parent=False) for param in self.params]
@ -442,12 +442,12 @@ class ParamConcatenation(object):
return self.params[0]._highest_parent_._checkgrad(self, verbose, step, tolerance)
#checkgrad.__doc__ = Gradcheckable.checkgrad.__doc__
__lt__ = lambda self, val: self._vals() < val
__le__ = lambda self, val: self._vals() <= val
__eq__ = lambda self, val: self._vals() == val
__ne__ = lambda self, val: self._vals() != val
__gt__ = lambda self, val: self._vals() > val
__ge__ = lambda self, val: self._vals() >= val
__lt__ = lambda self, val: self.values() < val
__le__ = lambda self, val: self.values() <= val
__eq__ = lambda self, val: self.values() == val
__ne__ = lambda self, val: self.values() != val
__gt__ = lambda self, val: self.values() > val
__ge__ = lambda self, val: self.values() >= val
def __str__(self, *args, **kwargs):
def f(p):
ind = p._raveled_index()

View file

@ -16,7 +16,7 @@ Observable Pattern for patameterization
from transformations import Transformation, Logexp, NegativeLogexp, Logistic, __fixed__, FIXED, UNFIXED
import numpy as np
__updated__ = '2014-03-18'
__updated__ = '2014-03-24'
class HierarchyError(Exception):
"""
@ -28,7 +28,7 @@ def adjust_name_for_printing(name):
Make sure a name can be printed, alongside used as a variable name.
"""
if name is not None:
return name.replace(" ", "_").replace(".", "_").replace("-", "_m_").replace("+", "_p_").replace("!", "_I_").replace("**", "_xx_").replace("*", "_x_").replace("/", "_l_").replace("@",'_at_')
return name.replace(" ", "_").replace(".", "_").replace("-", "_m_").replace("+", "_p_").replace("!", "_I_").replace("**", "_xx_").replace("*", "_x_").replace("/", "_l_").replace("@", '_at_')
return ''
class InterfacePickleFunctions(object):
@ -126,24 +126,22 @@ class Observable(Pickleable):
def notify_observers(self, which=None, min_priority=None):
"""
Notifies all observers. Which is the element, which kicked off this
notification loop.
notification loop. The first argument will be self, the second `which`.
NOTE: notifies only observers with priority p > min_priority!
^^^^^^^^^^^^^^^^
:param which: object, which started this notification loop
:param min_priority: only notify observers with priority > min_priority
if min_priority is None, notify all observers in order
"""
if which is None:
which = self
if min_priority is None:
[callble(which) for _, _, callble in self._observer_callables_]
[callble(self, which=which) for _, _, callble in self._observer_callables_]
else:
for p, _, callble in self._observer_callables_:
if p <= min_priority:
break
callble(which)
callble(self, which=which)
def _insert_sorted(self, p, o, c):
ins = 0
@ -627,7 +625,7 @@ class OptimizationHandlable(Constrainable):
# else: min_priority = -np.inf
# self.notify_observers(None, min_priority)
# don't overwrite this anymore!
#raise NotImplementedError, "Abstract superclass: This needs to be implemented in Param and Parameterizable"
# raise NotImplementedError, "Abstract superclass: This needs to be implemented in Param and Parameterizable"
#===========================================================================
# Optimization handles:
@ -659,7 +657,7 @@ class OptimizationHandlable(Constrainable):
x = rand_gen(loc=loc, scale=scale, size=self._size_transformed(), *args, **kwargs)
# now draw from prior where possible
[np.put(x, ind, p.rvs(ind.size)) for p, ind in self.priors.iteritems() if not p is None]
self._set_params_transformed(x) # makes sure all of the tied parameters get the same init (since there's only one prior object...)
self._set_params_transformed(x) # makes sure all of the tied parameters get the same init (since there's only one prior object...)
#===========================================================================
# For shared memory arrays. This does nothing in Param, but sets the memory
@ -668,10 +666,10 @@ class OptimizationHandlable(Constrainable):
def _propagate_param_grad(self, parray, garray):
pi_old_size = 0
for pi in self._parameters_:
pislice = slice(pi_old_size, pi_old_size+pi.size)
pislice = slice(pi_old_size, pi_old_size + pi.size)
self._param_array_[pislice] = pi._param_array_.flat#, requirements=['C', 'W']).flat
self._gradient_array_[pislice] = pi._gradient_array_.flat#, requirements=['C', 'W']).flat
self._param_array_[pislice] = pi._param_array_.flat # , requirements=['C', 'W']).flat
self._gradient_array_[pislice] = pi._gradient_array_.flat # , requirements=['C', 'W']).flat
pi._param_array_.data = parray[pislice].data
pi._gradient_array_.data = garray[pislice].data
@ -723,7 +721,7 @@ class Parameterizable(OptimizationHandlable):
self.__dict__[pname] = param
self._added_names_.add(pname)
else:
print "WARNING: added a parameter with formatted name {}, which is already a member of {} object. Trying to change the parameter name to\n {}".format(pname, self.__class__, param.name+"_")
print "WARNING: added a parameter with formatted name {}, which is already a member of {} object. Trying to change the parameter name to\n {}".format(pname, self.__class__, param.name + "_")
param.name += "_"
self._add_parameter_name(param, ignore_added_names)
@ -781,7 +779,7 @@ class Parameterizable(OptimizationHandlable):
if param in self._parameters_ and index is not None:
self.remove_parameter(param)
self.add_parameter(param, index)
#elif param.has_parent():
# elif param.has_parent():
# raise HierarchyError, "parameter {} already in another model ({}), create new object (or copy) for adding".format(param._short(), param._highest_parent_._short())
elif param not in self._parameters_:
if param.has_parent():
@ -874,12 +872,12 @@ class Parameterizable(OptimizationHandlable):
p._parent_ = self
p._parent_index_ = i
pslice = slice(old_size, old_size+p.size)
pslice = slice(old_size, old_size + p.size)
# first connect all children
p._propagate_param_grad(self._param_array_[pslice], self._gradient_array_[pslice])
# then connect children to self
self._param_array_[pslice] = p._param_array_.flat#, requirements=['C', 'W']).ravel(order='C')
self._gradient_array_[pslice] = p._gradient_array_.flat#, requirements=['C', 'W']).ravel(order='C')
self._param_array_[pslice] = p._param_array_.flat # , requirements=['C', 'W']).ravel(order='C')
self._gradient_array_[pslice] = p._gradient_array_.flat # , requirements=['C', 'W']).ravel(order='C')
if not p._param_array_.flags['C_CONTIGUOUS']:
import ipdb;ipdb.set_trace()
@ -894,10 +892,10 @@ class Parameterizable(OptimizationHandlable):
#===========================================================================
# notification system
#===========================================================================
def _parameters_changed_notification(self, which):
def _parameters_changed_notification(self, me, which=None):
self.parameters_changed()
def _pass_through_notify_observers(self, which):
self.notify_observers(which)
def _pass_through_notify_observers(self, me, which=None):
self.notify_observers(which=which)
#===========================================================================
# TODO: not working yet

View file

@ -157,7 +157,7 @@ class Parameterized(Parameterizable, Pickleable):
return self._param_slices_[param._parent_._get_original(param)._parent_index_].start
return self._offset_for(param._parent_) + param._parent_._offset_for(param)
return 0
def _raveled_index_for(self, param):
"""
get the raveled index for a param
@ -167,7 +167,7 @@ class Parameterized(Parameterizable, Pickleable):
if isinstance(param, ParamConcatenation):
return numpy.hstack((self._raveled_index_for(p) for p in param.params))
return param._raveled_index() + self._offset_for(param)
def _raveled_index(self):
"""
get the raveled index for this object,
@ -218,14 +218,17 @@ class Parameterized(Parameterizable, Pickleable):
return ParamConcatenation(paramlist)
return paramlist[-1]
return ParamConcatenation(paramlist)
def __setitem__(self, name, value, paramlist=None):
if isinstance(name, (slice, tuple, np.ndarray)):
self._param_array_[name] = value
self.notify_observers()
try:
self._param_array_[name] = value
except:
raise ValueError, "Setting by slice or index only allowed with array-like"
self._trigger_params_changed()
else:
try: param = self.__getitem__(name, paramlist)
except AttributeError as a: raise a
except: raise
param[:] = value
def __setattr__(self, name, val):