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
class ParamDict(defaultdict):
def __init__(self):
defaultdict.__init__(self, lambda: numpy.array([], dtype=int))
def __init__(self, default=lambda: numpy.array([], dtype=int)):
defaultdict.__init__(self, default)
def __getitem__(self, key):
try:
@ -120,47 +120,51 @@ class ParameterIndexOperations(object):
def __getitem__(self, prop):
return self._properties[prop]
class TieIndexOperations(object):
def __init__(self, params):
self.params = params
self.tied_from = ParameterIndexOperations()
self.tied_to = ParameterIndexOperations()
def add(self, tied_from, tied_to):
rav_from = self.params._raveled_index_for(tied_from)
rav_to = self.params._raveled_index_for(tied_to)
self.tied_from.add(tied_to, rav_from)
self.tied_to.add(tied_to, rav_to)
return rav_from, rav_to
def remove(self, tied_from, tied_to):
rav_from = self.params._raveled_index_for(tied_from)
rav_to = self.params._raveled_index_for(tied_to)
self.tied_from.remove(tied_to, rav_from)
self.tied_to.remove(tied_to, rav_to)
return rav_from, rav_to
def from_to_for(self, index):
return self.tied_from.properties_for(index), self.tied_to.properties_for(index)
def iter_from_to_indices(self):
for k, f in self.tied_from.iteritems():
yield f, self.tied_to[k]
def iter_to_indices(self):
return self.tied_to.iterindices()
def iter_from_indices(self):
return self.tied_from.iterindices()
def iter_from_items(self):
for f, i in self.tied_from.iteritems():
yield f, i
def iter_properties(self):
return self.tied_from.iter_properties()
def properties(self):
return self.tied_from.properties()
def from_to_indices(self, param):
return self.tied_from[param], self.tied_to[param]
# 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
# class TieIndexOperations(object):
# def __init__(self, params):
# self.params = params
# self.tied_from = ParameterIndexOperations()
# self.tied_to = ParameterIndexOperations()
# def add(self, tied_from, tied_to):
# rav_from = self.params._raveled_index_for(tied_from)
# rav_to = self.params._raveled_index_for(tied_to)
# self.tied_from.add(tied_to, rav_from)
# self.tied_to.add(tied_to, rav_to)
# return rav_from, rav_to
# def remove(self, tied_from, tied_to):
# rav_from = self.params._raveled_index_for(tied_from)
# rav_to = self.params._raveled_index_for(tied_to)
# rem_from = self.tied_from.remove(tied_to, rav_from)
# rem_to = self.tied_to.remove(tied_to, rav_to)
# left_from = self.tied_from._properties.pop(tied_to)
# left_to = self.tied_to._properties.pop(tied_to)
# self.tied_from[numpy.delete(tied_to, rem_from)] = left_from
# self.tied_to[numpy.delete(tied_to, rem_to)] = left_to
# return rav_from, rav_to
# def from_to_for(self, index):
# return self.tied_from.properties_for(index), self.tied_to.properties_for(index)
# def iter_from_to_indices(self):
# for k, f in self.tied_from.iteritems():
# yield f, self.tied_to[k]
# def iter_to_indices(self):
# return self.tied_to.iterindices()
# def iter_from_indices(self):
# return self.tied_from.iterindices()
# def iter_from_items(self):
# for f, i in self.tied_from.iteritems():
# yield f, i
# def iter_properties(self):
# return self.tied_from.iter_properties()
# def properties(self):
# return self.tied_from.properties()
# def from_to_indices(self, param):
# return self.tied_from[param], self.tied_to[param]
#
# # 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):
return numpy.union1d(arr1, arr2)

View file

@ -48,6 +48,9 @@ class Param(numpy.ndarray):
obj._realshape_ = obj.shape
obj._realsize_ = obj.size
obj._realndim_ = obj.ndim
from index_operations import ParamDict
obj._tied_to_me_ = ParamDict(set)
obj._tied_to_ = []
obj._original_ = True
return obj
def __array_finalize__(self, obj):
@ -58,6 +61,8 @@ class Param(numpy.ndarray):
self._parent_ = getattr(obj, '_parent_', None)
self._parent_index_ = getattr(obj, '_parent_index_', 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._realsize_ = getattr(obj, '_realsize_', None)
self._realndim_ = getattr(obj, '_realndim_', None)
@ -220,17 +225,37 @@ class Param(numpy.ndarray):
self._parent_._get_original(self)[self._current_slice_] = param
except ValueError:
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 ties to parameters given.
remove tie of this parameter to ties it was tied to.
"""
if len(params) == 0:
params = self._parent_._ties_.properties()
self._parent_._remove_tie(self, *params)
[t._remove_tie_listener(self) for t in self._tied_to_]
def set_index(tied_to,untie_from):
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
#===========================================================================
@ -266,6 +291,7 @@ class Param(numpy.ndarray):
return self.__getitem__(slice(start, stop))
def __setitem__(self, *args, **kwargs):
numpy.ndarray.__setitem__(self, *args, **kwargs)
self._fire_changed()
self._parent_.parameters_changed()
#===========================================================================
# Index Operations:
@ -330,7 +356,12 @@ class Param(numpy.ndarray):
def __repr__(self, *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):
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):
return self._parent_._constraints_for(self, rav_index)
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 lx is None: lx = self._max_len_values()
if li is None: li = self._max_len_index(self._indices())
if lt is None: lt = self._max_len_names(ties[0], __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
if lt is None: lt = self._max_len_names([t._short() for ti in ties for t in ti], __tie_name__)
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__()
class ParamConcatenation(object):
@ -480,7 +504,7 @@ if __name__ == '__main__':
m[".*variance"].constrain_positive()
print "constraining rbf"
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.rbf_l.tie_to(m.rbf_va)
# pt = numpy.array(params._get_params_transformed())

View file

@ -7,7 +7,7 @@ import copy
import cPickle
from parameter import ParamConcatenation, Param
from index_operations import ParameterIndexOperations,\
TieIndexOperations, index_empty
index_empty
import itertools
from re import compile, _pattern_type
import sys
@ -80,7 +80,7 @@ class Parameterized(object):
"""
def __init__(self):
self._constraints_ = ParameterIndexOperations()
self._ties_ = TieIndexOperations(self)
#self._ties_ = TieIndexOperations(self)
self._ties_fixes_ = None
self._in_init_ = True
if not hasattr(self, "_parameters_"):
@ -214,7 +214,7 @@ class Parameterized(object):
self._ties_fixes_[f] = FIXED
if fixed == __fixed__:
self._ties_fixes_[ind] = FIXED
if numpy.all(self._ties_fixes_):
if numpy.all(self._ties_fixes_): # ==UNFIXED
self._ties_fixes_ = None
self.parameters_changed()
#===========================================================================
@ -263,47 +263,55 @@ class Parameterized(object):
#===========================================================================
# Handle ties:
#===========================================================================
def _add_tie(self, param, tied_to):
# 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)
def _set_fixed(self, param_or_index):
if self._ties_fixes_ is None: self._ties_fixes_ = numpy.ones(self._parameter_size_, dtype=bool)
self._ties_fixes_[f] = False
def _remove_tie(self, param, *params):
# remove the tie from param to all *params (can be None, so all ties get deleted for param)
if len(params) == 0:
params = self._ties_.properties()
for p in params:
_, t = self._ties_.remove(param, p)
self._ties_fixes_[t] = True
if numpy.all(self._ties_fixes_): self._ties_fixes_ = None
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))
try:
param_or_index = self._raveled_index_for(param_or_index)
except AttributeError:
self._ties_fixes_[param_or_index] = FIXED
def _set_unfixed(self, param_or_index):
if self._ties_fixes_ is None: self._ties_fixes_ = numpy.ones(self._parameter_size_, dtype=bool)
try:
param_or_index = self._raveled_index_for(param_or_index)
except AttributeError:
self._ties_fixes_[param_or_index] = UNFIXED
# def _add_tie(self, param, tied_to):
# # 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)
# self._ties_fixes_[f] = False
# def _remove_tie(self, param, *params):
# # remove the tie from param to all *params (can be None, so all ties get deleted for param)
# if len(params) == 0:
# params = self._ties_.properties()
# for p in params:
# _, 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:
#===========================================================================
def _fix(self, param, warning=True):
f = self._add_constrain(param, __fixed__, warning)
if self._ties_fixes_ is None: self._ties_fixes_ = numpy.ones(self._parameter_size_, dtype=bool)
self._ties_fixes_[f] = False
self._set_fixed(f)
def _unfix(self, param):
if self._ties_fixes_ is not None:
self._remove_constrain(param, __fixed__)
ind = self._raveled_index_for(param)
self._ties_fixes_[ind] = UNFIXED
if numpy.all(self._ties_fixes_==UNFIXED): self._ties_fixes_ = None
self._handle_ties()
f = self._remove_constrain(param, __fixed__)
self._set_unfixed(f)
#===========================================================================
# Convenience for fixed, tied checking of parameter:
#===========================================================================
@ -424,7 +432,7 @@ class Parameterized(object):
constrs = self._constrs; ts = self._ts
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"]])
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)]
sep = '-'*(nl+sl+cl+tl+8*2+3)
if header: