still todo: untie, gradients, priors, print ties

This commit is contained in:
Max Zwiessele 2013-10-17 20:47:41 +01:00
parent 945f192ee2
commit 6be05de791
3 changed files with 135 additions and 99 deletions

View file

@ -9,8 +9,8 @@ from parameter import Param
from collections import defaultdict from collections import defaultdict
class ParamDict(defaultdict): class ParamDict(defaultdict):
def __init__(self): def __init__(self, default=lambda: numpy.array([], dtype=int)):
defaultdict.__init__(self, lambda: numpy.array([], dtype=int)) defaultdict.__init__(self, default)
def __getitem__(self, key): def __getitem__(self, key):
try: try:
@ -120,47 +120,51 @@ class ParameterIndexOperations(object):
def __getitem__(self, prop): def __getitem__(self, prop):
return self._properties[prop] return self._properties[prop]
class TieIndexOperations(object): # class TieIndexOperations(object):
def __init__(self, params): # def __init__(self, params):
self.params = params # self.params = params
self.tied_from = ParameterIndexOperations() # self.tied_from = ParameterIndexOperations()
self.tied_to = ParameterIndexOperations() # self.tied_to = ParameterIndexOperations()
def add(self, tied_from, tied_to): # def add(self, tied_from, tied_to):
rav_from = self.params._raveled_index_for(tied_from) # rav_from = self.params._raveled_index_for(tied_from)
rav_to = self.params._raveled_index_for(tied_to) # rav_to = self.params._raveled_index_for(tied_to)
self.tied_from.add(tied_to, rav_from) # self.tied_from.add(tied_to, rav_from)
self.tied_to.add(tied_to, rav_to) # self.tied_to.add(tied_to, rav_to)
return rav_from, rav_to # return rav_from, rav_to
def remove(self, tied_from, tied_to): # def remove(self, tied_from, tied_to):
rav_from = self.params._raveled_index_for(tied_from) # rav_from = self.params._raveled_index_for(tied_from)
rav_to = self.params._raveled_index_for(tied_to) # rav_to = self.params._raveled_index_for(tied_to)
self.tied_from.remove(tied_to, rav_from) # rem_from = self.tied_from.remove(tied_to, rav_from)
self.tied_to.remove(tied_to, rav_to) # rem_to = self.tied_to.remove(tied_to, rav_to)
return rav_from, rav_to # left_from = self.tied_from._properties.pop(tied_to)
def from_to_for(self, index): # left_to = self.tied_to._properties.pop(tied_to)
return self.tied_from.properties_for(index), self.tied_to.properties_for(index) # self.tied_from[numpy.delete(tied_to, rem_from)] = left_from
def iter_from_to_indices(self): # self.tied_to[numpy.delete(tied_to, rem_to)] = left_to
for k, f in self.tied_from.iteritems(): # return rav_from, rav_to
yield f, self.tied_to[k] # def from_to_for(self, index):
def iter_to_indices(self): # return self.tied_from.properties_for(index), self.tied_to.properties_for(index)
return self.tied_to.iterindices() # def iter_from_to_indices(self):
def iter_from_indices(self): # for k, f in self.tied_from.iteritems():
return self.tied_from.iterindices() # yield f, self.tied_to[k]
def iter_from_items(self): # def iter_to_indices(self):
for f, i in self.tied_from.iteritems(): # return self.tied_to.iterindices()
yield f, i # def iter_from_indices(self):
def iter_properties(self): # return self.tied_from.iterindices()
return self.tied_from.iter_properties() # def iter_from_items(self):
def properties(self): # for f, i in self.tied_from.iteritems():
return self.tied_from.properties() # yield f, i
def from_to_indices(self, param): # def iter_properties(self):
return self.tied_from[param], self.tied_to[param] # return self.tied_from.iter_properties()
# def properties(self):
# def create_raveled_indices(index, shape, offset=0): # return self.tied_from.properties()
# if isinstance(index, (tuple, list)): i = [slice(None)] + list(index) # def from_to_indices(self, param):
# else: i = [slice(None), index] # return self.tied_from[param], self.tied_to[param]
# ind = numpy.array(numpy.ravel_multi_index(numpy.indices(shape)[i], shape)).flat + numpy.int_(offset) #
# return ind # # def create_raveled_indices(index, shape, offset=0):
# # if isinstance(index, (tuple, list)): i = [slice(None)] + list(index)
# # else: i = [slice(None), index]
# # ind = numpy.array(numpy.ravel_multi_index(numpy.indices(shape)[i], shape)).flat + numpy.int_(offset)
# # return ind
def combine_indices(arr1, arr2): def combine_indices(arr1, arr2):
return numpy.union1d(arr1, arr2) return numpy.union1d(arr1, arr2)

View file

@ -48,6 +48,9 @@ class Param(numpy.ndarray):
obj._realshape_ = obj.shape obj._realshape_ = obj.shape
obj._realsize_ = obj.size obj._realsize_ = obj.size
obj._realndim_ = obj.ndim obj._realndim_ = obj.ndim
from index_operations import ParamDict
obj._tied_to_me_ = ParamDict(set)
obj._tied_to_ = []
obj._original_ = True obj._original_ = True
return obj return obj
def __array_finalize__(self, obj): def __array_finalize__(self, obj):
@ -58,6 +61,8 @@ class Param(numpy.ndarray):
self._parent_ = getattr(obj, '_parent_', None) self._parent_ = getattr(obj, '_parent_', None)
self._parent_index_ = getattr(obj, '_parent_index_', None) self._parent_index_ = getattr(obj, '_parent_index_', None)
self._gradient_ = getattr(obj, '_gradient_', None) self._gradient_ = getattr(obj, '_gradient_', None)
self._tied_to_me_ = getattr(obj, '_tied_to_me_', None)
self._tied_to_ = getattr(obj, '_tied_to_', None)
self._realshape_ = getattr(obj, '_realshape_', None) self._realshape_ = getattr(obj, '_realshape_', None)
self._realsize_ = getattr(obj, '_realsize_', None) self._realsize_ = getattr(obj, '_realsize_', None)
self._realndim_ = getattr(obj, '_realndim_', None) self._realndim_ = getattr(obj, '_realndim_', None)
@ -220,17 +225,37 @@ class Param(numpy.ndarray):
self._parent_._get_original(self)[self._current_slice_] = param self._parent_._get_original(self)[self._current_slice_] = param
except ValueError: except ValueError:
raise ValueError("Trying to tie {} with shape {} to {} with shape {}".format(self.name, self.shape, param.name, param.shape)) raise ValueError("Trying to tie {} with shape {} to {} with shape {}".format(self.name, self.shape, param.name, param.shape))
self._parent_._add_tie(self, param)
self._parent_._get_original(self)._tied_to_ += [param]
param._add_tie_listener(self)
self._parent_._set_fixed(param)
# self._parent_._add_tie(self, param)
def untie(self, *params): def untie(self, *ties):
""" """
:param params: parameters to untie from remove tie of this parameter to ties it was tied to.
remove ties to parameters given.
""" """
if len(params) == 0: [t._remove_tie_listener(self) for t in self._tied_to_]
params = self._parent_._ties_.properties() def set_index(tied_to,untie_from):
self._parent_._remove_tie(self, *params) tied_to._current_slice_ = numpy.array(set(tied_to._raveled_index()) & set(untie_from._raveled_index()))
return tied_to
self._tied_to_ = [tied_to for tied_to in self._tied_to_ for untie_from in ties if tied_to._parent_index_ == untie_from._parent_index_ and set_index(tied_to)._current_slice_.size > 0]
self._parent_._set_unfixed(self)
# self._parent_._remove_tie(self, *params)
def _fire_changed(self):
for tied, ind in self._tied_to_me_.iteritems():
tied._on_change(self[list(ind)])
def _add_tie_listener(self, tied_to_me):
self._tied_to_me_[tied_to_me] |= set(self._raveled_index())
def _remove_tie_listener(self, to_remove):
for t in self._tied_to_me_.keys():
if t._parent_index_ == self._parent_index_:
self._tied_to_me_[t] &= set(t._raveled_index())
def _on_change(self, val):
if self._original_: # this happens when indexing created a copy of the array
self[:] = val
else:
self._parent_._get_original(self)[self._current_slice_] = val
#=========================================================================== #===========================================================================
# Prior Operations # Prior Operations
#=========================================================================== #===========================================================================
@ -266,6 +291,7 @@ class Param(numpy.ndarray):
return self.__getitem__(slice(start, stop)) return self.__getitem__(slice(start, stop))
def __setitem__(self, *args, **kwargs): def __setitem__(self, *args, **kwargs):
numpy.ndarray.__setitem__(self, *args, **kwargs) numpy.ndarray.__setitem__(self, *args, **kwargs)
self._fire_changed()
self._parent_.parameters_changed() self._parent_.parameters_changed()
#=========================================================================== #===========================================================================
# Index Operations: # Index Operations:
@ -330,7 +356,12 @@ class Param(numpy.ndarray):
def __repr__(self, *args, **kwargs): def __repr__(self, *args, **kwargs):
return "\033[1m{x:s}\033[0;0m:\n".format(x=self.name)+super(Param, self).__repr__(*args,**kwargs) return "\033[1m{x:s}\033[0;0m:\n".format(x=self.name)+super(Param, self).__repr__(*args,**kwargs)
def _ties_for(self, rav_index): def _ties_for(self, rav_index):
return self._parent_._ties_for(self, rav_index) ties = [[]] * numpy.size(rav_index)
for tied_to in self._tied_to_:
for t in tied_to._tied_to_me_.iterkeys():
if t._parent_index_ == self._parent_index_:
[ties.__setitem__(i, ties[i] + [tied_to]) for i in t._raveled_index()]
return ties
def _constraints_for(self, rav_index): def _constraints_for(self, rav_index):
return self._parent_._constraints_for(self, rav_index) return self._parent_._constraints_for(self, rav_index)
def _indices(self, slice_index=None): def _indices(self, slice_index=None):
@ -367,16 +398,9 @@ class Param(numpy.ndarray):
if lc is None: lc = self._max_len_names(constr_matrix, __constraints_name__) if lc is None: lc = self._max_len_names(constr_matrix, __constraints_name__)
if lx is None: lx = self._max_len_values() if lx is None: lx = self._max_len_values()
if li is None: li = self._max_len_index(self._indices()) if li is None: li = self._max_len_index(self._indices())
if lt is None: lt = self._max_len_names(ties[0], __tie_name__) if lt is None: lt = self._max_len_names([t._short() for ti in ties for t in ti], __tie_name__)
from index_operations import ParamDict
keep_track_of_broadcasting = ParamDict()
def tie_broadcasting(tie):
if tie in keep_track_of_broadcasting:
return keep_track_of_broadcasting[tie].next()
else:
pass
header = " {i:^{2}s} | \033[1m{x:^{1}s}\033[0;0m | {c:^{0}s} | {t:^{3}s}".format(lc,lx,li,lt, x=self.name, c=__constraints_name__, i=__index_name__, t=__tie_name__) # nice header for printing header = " {i:^{2}s} | \033[1m{x:^{1}s}\033[0;0m | {c:^{0}s} | {t:^{3}s}".format(lc,lx,li,lt, x=self.name, c=__constraints_name__, i=__index_name__, t=__tie_name__) # nice header for printing
return "\n".join([header]+[" {i!s:^{3}s} | {x: >{1}.{2}G} | {c:^{0}s} | {t:^{4}} ".format(lc,lx,__precision__,li,lt, x=x, c=" ".join(map(str,c)), t=" ".join([tie._short() for tie in t]), i=i) for i,x,c,t in itertools.izip(indices,self.flat,constr_matrix,ties[0])]) # return all the constraints with right indices return "\n".join([header]+[" {i!s:^{3}s} | {x: >{1}.{2}G} | {c:^{0}s} | {t:^{4}} ".format(lc,lx,__precision__,li,lt, x=x, c=" ".join(map(str,c)), t=" ".join([tie._short() for tie in t]), i=i) for i,x,c,t in itertools.izip(indices,self.flat,constr_matrix,ties)]) # return all the constraints with right indices
#except: return super(Param, self).__str__() #except: return super(Param, self).__str__()
class ParamConcatenation(object): class ParamConcatenation(object):
@ -480,7 +504,7 @@ if __name__ == '__main__':
m[".*variance"].constrain_positive() m[".*variance"].constrain_positive()
print "constraining rbf" print "constraining rbf"
m.rbf.constrain_positive() m.rbf.constrain_positive()
m.q_variance[:,[0,2]].tie_to(m.rbf_l) m.q_variance[:,:2].tie_to(m.rbf_l)
#m.q_v.tie_to(m.rbf_v) #m.q_v.tie_to(m.rbf_v)
# m.rbf_l.tie_to(m.rbf_va) # m.rbf_l.tie_to(m.rbf_va)
# pt = numpy.array(params._get_params_transformed()) # pt = numpy.array(params._get_params_transformed())

View file

@ -7,7 +7,7 @@ import copy
import cPickle import cPickle
from parameter import ParamConcatenation, Param from parameter import ParamConcatenation, Param
from index_operations import ParameterIndexOperations,\ from index_operations import ParameterIndexOperations,\
TieIndexOperations, index_empty index_empty
import itertools import itertools
from re import compile, _pattern_type from re import compile, _pattern_type
import sys import sys
@ -80,7 +80,7 @@ class Parameterized(object):
""" """
def __init__(self): def __init__(self):
self._constraints_ = ParameterIndexOperations() self._constraints_ = ParameterIndexOperations()
self._ties_ = TieIndexOperations(self) #self._ties_ = TieIndexOperations(self)
self._ties_fixes_ = None self._ties_fixes_ = None
self._in_init_ = True self._in_init_ = True
if not hasattr(self, "_parameters_"): if not hasattr(self, "_parameters_"):
@ -214,7 +214,7 @@ class Parameterized(object):
self._ties_fixes_[f] = FIXED self._ties_fixes_[f] = FIXED
if fixed == __fixed__: if fixed == __fixed__:
self._ties_fixes_[ind] = FIXED self._ties_fixes_[ind] = FIXED
if numpy.all(self._ties_fixes_): if numpy.all(self._ties_fixes_): # ==UNFIXED
self._ties_fixes_ = None self._ties_fixes_ = None
self.parameters_changed() self.parameters_changed()
#=========================================================================== #===========================================================================
@ -263,47 +263,55 @@ class Parameterized(object):
#=========================================================================== #===========================================================================
# Handle ties: # Handle ties:
#=========================================================================== #===========================================================================
def _add_tie(self, param, tied_to): def _set_fixed(self, param_or_index):
# tie param to tie_to, if the values match (with broadcasting)
self._remove_tie(param) # delete if multiple ties should be allowed
f, _ = self._ties_.add(param, tied_to)
if self._ties_fixes_ is None: self._ties_fixes_ = numpy.ones(self._parameter_size_, dtype=bool) if self._ties_fixes_ is None: self._ties_fixes_ = numpy.ones(self._parameter_size_, dtype=bool)
self._ties_fixes_[f] = False try:
def _remove_tie(self, param, *params): param_or_index = self._raveled_index_for(param_or_index)
# remove the tie from param to all *params (can be None, so all ties get deleted for param) except AttributeError:
if len(params) == 0: self._ties_fixes_[param_or_index] = FIXED
params = self._ties_.properties() def _set_unfixed(self, param_or_index):
for p in params: if self._ties_fixes_ is None: self._ties_fixes_ = numpy.ones(self._parameter_size_, dtype=bool)
_, t = self._ties_.remove(param, p) try:
self._ties_fixes_[t] = True param_or_index = self._raveled_index_for(param_or_index)
if numpy.all(self._ties_fixes_): self._ties_fixes_ = None except AttributeError:
def _ties_iter_items(self, param): self._ties_fixes_[param_or_index] = UNFIXED
for tied_to, ind in self._ties_.iter_from_items(): # def _add_tie(self, param, tied_to):
ind = self._backtranslate_index(param, ind) # # tie param to tie_to, if the values match (with broadcasting)
if not index_empty(ind): # self._remove_tie(param) # delete if multiple ties should be allowed
yield tied_to, ind # f, _ = self._ties_.add(param, tied_to)
def _ties_iter(self, param): # if self._ties_fixes_ is None: self._ties_fixes_ = numpy.ones(self._parameter_size_, dtype=bool)
for constr, _ in self._ties_iter_items(param): # self._ties_fixes_[f] = False
yield constr # def _remove_tie(self, param, *params):
def _ties_iter_indices(self, param): # # remove the tie from param to all *params (can be None, so all ties get deleted for param)
for _, ind in self._ties_iter_items(param): # if len(params) == 0:
yield ind # params = self._ties_.properties()
def _ties_for(self, param, rav_index): # for p in params:
return self._ties_.from_to_for(rav_index+self._offset(param)) # _, t = self._ties_.remove(param, p)
# self._ties_fixes_[t] = True
# if numpy.all(self._ties_fixes_): self._ties_fixes_ = None # ==UNFIXED
# def _ties_iter_items(self, param):
# for tied_to, ind in self._ties_.iter_from_items():
# ind = self._backtranslate_index(param, ind)
# if not index_empty(ind):
# yield tied_to, ind
# def _ties_iter(self, param):
# for constr, _ in self._ties_iter_items(param):
# yield constr
# def _ties_iter_indices(self, param):
# for _, ind in self._ties_iter_items(param):
# yield ind
# def _ties_for(self, param, rav_index):
# return self._ties_.from_to_for(rav_index+self._offset(param))
#=========================================================================== #===========================================================================
# Fixing parameters: # Fixing parameters:
#=========================================================================== #===========================================================================
def _fix(self, param, warning=True): def _fix(self, param, warning=True):
f = self._add_constrain(param, __fixed__, warning) f = self._add_constrain(param, __fixed__, warning)
if self._ties_fixes_ is None: self._ties_fixes_ = numpy.ones(self._parameter_size_, dtype=bool) self._set_fixed(f)
self._ties_fixes_[f] = False
def _unfix(self, param): def _unfix(self, param):
if self._ties_fixes_ is not None: if self._ties_fixes_ is not None:
self._remove_constrain(param, __fixed__) f = self._remove_constrain(param, __fixed__)
ind = self._raveled_index_for(param) self._set_unfixed(f)
self._ties_fixes_[ind] = UNFIXED
if numpy.all(self._ties_fixes_==UNFIXED): self._ties_fixes_ = None
self._handle_ties()
#=========================================================================== #===========================================================================
# Convenience for fixed, tied checking of parameter: # Convenience for fixed, tied checking of parameter:
#=========================================================================== #===========================================================================
@ -424,7 +432,7 @@ class Parameterized(object):
constrs = self._constrs; ts = self._ts constrs = self._constrs; ts = self._ts
cl = max([len(str(x)) if x else 0 for x in constrs + ["Constraint"]]) cl = max([len(str(x)) if x else 0 for x in constrs + ["Constraint"]])
tl = max([len(str(x)) if x else 0 for x in ts + ["Tied to"]]) tl = max([len(str(x)) if x else 0 for x in ts + ["Tied to"]])
format_spec = " \033[1m{{p.name:^{0}s}}\033[0;0m | {{p._desc:^{1}s}} | {{const:^{2}s}} | {{t:^{2}s}}".format(nl, sl, cl) format_spec = " \033[1m{{p.name:^{0}s}}\033[0;0m | {{p._desc:^{1}s}} | {{const:^{2}s}} | {{t:^{3}s}}".format(nl, sl, cl, tl)
to_print = [format_spec.format(p=p, const=c, t=t) for p, c, t in itertools.izip(self._parameters_, constrs, ts)] to_print = [format_spec.format(p=p, const=c, t=t) for p, c, t in itertools.izip(self._parameters_, constrs, ts)]
sep = '-'*(nl+sl+cl+tl+8*2+3) sep = '-'*(nl+sl+cl+tl+8*2+3)
if header: if header: