parameterized first beta test

This commit is contained in:
Max Zwiessele 2013-10-11 16:44:34 +01:00
parent 4f56506aa6
commit 152f61acf0

View file

@ -7,7 +7,8 @@ import re
import itertools import itertools
import numpy import numpy
from GPy.core.transformations import Logexp, NegativeLogexp from GPy.core.transformations import Logexp, NegativeLogexp
from GPy.core.index_operations import ParameterIndexOperations from GPy.core.index_operations import ConstraintIndexOperations,\
create_raveled_indices, index_empty, TieIndexOperations
from types import FunctionType from types import FunctionType
from re import compile, _pattern_type from re import compile, _pattern_type
_index_re = re.compile('(?:_(\d+))+') # pattern match for indices _index_re = re.compile('(?:_(\d+))+') # pattern match for indices
@ -17,319 +18,440 @@ __constraints_name__ = "Constraint"
__index_name__ = "Index" __index_name__ = "Index"
__tie_name__ = "Tied to" __tie_name__ = "Tied to"
__precision__ = numpy.get_printoptions()['precision'] # numpy printing precision used, sublassing numpy ndarray after all __precision__ = numpy.get_printoptions()['precision'] # numpy printing precision used, sublassing numpy ndarray after all
__fixed__ = "fixed"
###### ######
def translate_param_names_to_parameters(param_names):
"""
Naive translation from _get_param_names return to Parameterized object.
Assumptions:
- array indices are at the and matching _\d+_\d+...
- names are in order and names match field names
"""
class Parameterized(object): class Parameterized(object):
"""
Parameterized class
Say m is a handle to a parameterized class.
Printing parameters:
>>> print m
# prints a nice summary over all parameters
>>> print m.name
# prints all the parameters which start with name
Getting and setting parameters:
Two ways to get parameters:
- m.name regular expression matches all parameters beginning with name
- m['name'] regular expression matches all parameters with name
Handling of constraining, fixing and tieing parameters together:
"""
def __init__(self, parameterlist, prefix=None, *args, **kwargs): def __init__(self, parameterlist, prefix=None, *args, **kwargs):
self._init = True
self._params = [] self._params = []
for p in parameterlist: for p in parameterlist:
if isinstance(p, Parameterized): if isinstance(p, Parameterized):
self._params.extend(p._params) self._params.extend(p._params)
else: else:
self._params.append(p) self._params.append(p)
sizes = numpy.cumsum([0] + self.sizes) self._constraints = ConstraintIndexOperations()
self._param_slices = itertools.starmap(lambda start,stop: slice(start, stop), zip(sizes, sizes[1:])) self._ties = TieIndexOperations(self)
for p in self._params: self._fixes = ConstraintIndexOperations
self._ties_fixes = None
self._connect_parameters()
self._init = False
def _connect_parameters(self):
sizes = numpy.cumsum([0] + self.parameter_sizes)
self._param_slices = [slice(start, stop) for start,stop in zip(sizes, sizes[1:])]
for i, p in enumerate(self._params):
p._parent = self p._parent = self
self.__setattr__(p.name, p) p._parent_index = i
not_unique = []
if p.name in self.__dict__:
not_unique.append(p.name)
del self.__dict__[p.name]
elif not (p.name in not_unique):
self.__dict__[p.name] = p
#===========================================================================
# Optimization handling:
#===========================================================================
def _get_params(self): def _get_params(self):
return numpy.hstack([x._get_params() for x in self._params])#numpy.fromiter(itertools.chain(*itertools.imap(lambda x: x._get_params(), self._params)), dtype=numpy.float64, count=sum(self.sizes)) return numpy.hstack([x._get_params() for x in self._params])#numpy.fromiter(itertools.chain(*itertools.imap(lambda x: x._get_params(), self._params)), dtype=numpy.float64, count=sum(self.parameter_sizes))
def _set_params(self, params): def _set_params(self, params):
[p._set_params(params[s]) for p,s in itertools.izip(self._params,self._param_slices)] [p._set_params(params[s]) for p,s in itertools.izip(self._params,self._param_slices)]
def _get_params_transformed(self): def _get_params_transformed(self):
return numpy.hstack([x._get_params_transformed() for x in self._params]) p = self._get_params()
return numpy.fromiter(itertools.chain(*itertools.imap(lambda x: x._get_params_transformed(), self._params)), dtype=numpy.float64, count=self.num_params_transformed) [numpy.put(p, ind, c.finv(p[ind])) for c,ind in self._constraints.iteritems() if c is not __fixed__]
if self._ties_fixes is not None:
return p[self._ties_fixes]
return p
def _set_params_transformed(self, params): def _set_params_transformed(self, p):
current_index = 0 if self._ties_fixes is not None: tmp = self._get_params(); tmp[self._ties_fixes] = p; p = tmp; del tmp
for p in self._params: [numpy.put(p, ind, c.f(p[ind])) for c,ind in self._constraints.iteritems() if c is not __fixed__]
s = p.num_params_transformed [numpy.put(p, f, p[t]) for f,t in self._ties.iter_from_to_indices()]
p._set_params_transformed(params[current_index:current_index+s]) self._set_params(p)
current_index += s
self._handle_ties()
def _handle_ties(self): def _handle_ties(self):
[p._handle_ties() for p in self._params] if not self._init:
self._set_params_transformed(self._get_params_transformed())
def __getitem__(self, name): #===========================================================================
return self.__getattr__(name) # Index Handling
#===========================================================================
def _backtranslate_index(self, param, ind):
ind = ind-self._offset(param)
ind = ind[ind >= 0]
internal_offset = (numpy.arange(param._realsize).reshape(param._realshape)[param._current_slice]).flat[0]
ind = ind[ind < param.size + internal_offset]
return ind - internal_offset
#===========================================================================
# Handle ties:
#===========================================================================
def _add_tie(self, param, tied_to):
try:
param[...] = tied_to
except ValueError:
raise ValueError("Trying to tie {} with shape {} to {} with shape {}".format(self.name, self.shape, param.name, param.shape))
self._ties.add(param, tied_to)
if self._ties_fixes is None: self._ties_fixes = numpy.ones(self.parameter_size, dtype=bool)
f = create_raveled_indices(param._current_slice, param._realshape, self._offset(param))
self._ties_fixes[f] = False
def _remove_tie(self, param, *params):
if len(params) == 0:
params = self._ties.properties()
for p in self._ties.properties():
if any((p == x).all() for x in params):
ind = create_raveled_indices(p._current_slice, param._realshape, self._offset(param))
self._ties.remove(param, p)
self._ties_fixes[ind] = 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
#===========================================================================
# Fixing parameters:
#===========================================================================
def _fix(self, param):
reconstrained = self._remove_constrain(param, None)
if any(reconstrained):
# to print whole params: m = str(param[self._backtranslate_index(param, reconstrained)])
m = param.name
if param._realsize > 1:
m += str("".join(map(str,param._indices()[self._backtranslate_index(param, reconstrained)])))
print "Reconstrained parameters:\n{}".format(m)
self._constraints.add(__fixed__, param._current_slice, param._realshape, self._offset(param))
if self._ties_fixes is None: self._ties_fixes = numpy.ones(self.parameter_size, dtype=bool)
f = create_raveled_indices(param._current_slice, param._realshape, self._offset(param))
self._ties_fixes[f] = False
def _unfix(self, param):
self._remove_constrain(param, __fixed__)
ind = create_raveled_indices(p._current_slice, param._realshape, self._offset(param))
self._ties_fixes[ind] = True
if numpy.all(self._ties_fixes): self._ties_fixes = None
#===========================================================================
# Constraint Handling:
#===========================================================================
def constrain(self, regexp, constraint):
self[regexp].constrain(constraint)
def _offset(self, param):
# offset = reduce(lambda a, b:a + (b.stop - b.start), self._param_slices[:param._parent_index], 0)
return self._param_slices[param._parent_index].start
def _add_constrain(self, param, transform):
reconstrained = self._remove_constrain(param, None)
self._constraints.add(transform, param._current_slice, param._realshape, self._offset(param))
if any(reconstrained):
# to print whole params: m = str(param[self._backtranslate_index(param, reconstrained)])
m = param.name + str("".join(map(str,param._indices()[self._backtranslate_index(param, reconstrained)])))
print "Reconstrained parameters:\n{}".format(m)
def _remove_constrain(self, param, transforms):
if transforms is None:
transforms = self._constraints.properties()
elif not isinstance(transforms, (tuple, list, numpy.ndarray)):
transforms = [transforms]
removed_indices = numpy.array([]).astype(int)
for constr in transforms:
removed = self._constraints.remove(constr, param._current_slice, param._realshape, self._offset(param))
removed_indices = numpy.union1d(removed_indices, removed)
return removed_indices
def _constraints_iter_items(self, param):
for constr, ind in self._constraints.iteritems():
ind = self._backtranslate_index(param, ind)
if not index_empty(ind):
yield constr, ind
def _constraints_iter(self, param):
for constr, _ in self._constraints_iter_items(param):
yield constr
def _contraints_iter_indices(self, param):
for _, ind in self._constraints_iter_items(param):
yield ind
def _constraint_indices(self, param, constraint):
return self._backtranslate_index(param, self._constraints[constraint])
#===========================================================================
# Get/set parameters:
#===========================================================================
def grep_param_names(self, regexp): def grep_param_names(self, regexp):
if not isinstance(regexp, _pattern_type): if not isinstance(regexp, _pattern_type): regexp = compile(regexp)
regexp = compile(regexp) paramlist = [param for param in self._params if regexp.match(param.name) is not None]
paramlist = [param for param in self._params if regexp.search(param.name) is not None]
return paramlist return paramlist
def __getitem__(self, name, paramlist=None):
def tie_params(self, regexp): if paramlist is None:
paramlist = self.grep_param_names(regexp)
def __getattr__(self, name, *args, **kwargs):
if name in self.__dict__:
return object.__getattribute__(self, name, *args, **kwargs)
else:
paramlist = self.grep_param_names(name) paramlist = self.grep_param_names(name)
if len(paramlist) < 1: if len(paramlist) < 1: raise AttributeError, name
raise AttributeError("'{:s}' object has no attribute '{:s}'".format(str(self.__class__.__name__), name)) if len(paramlist) == 1: return paramlist[-1]
if len(paramlist) == 1: return ParamConcatenation(paramlist)
return paramlist[-1] def __setitem__(self, name, value, paramlist=None):
return ParamConcatenation(paramlist) try: param = self.__getitem__(name, paramlist)
except AttributeError as a: raise a
param[...] = value
def __getattr__(self, name, *args, **kwargs):
return self.__getitem__(name)
def __setattr__(self, name, val):
if hasattr(self, "_params"):
paramlist = self.grep_param_names(name)
if len(paramlist) > 1: object.__setattr__(self, name, val); return# raise AttributeError("Non-unique params identified {}".format([p.name for p in paramlist]))
if len(paramlist) == 1: self.__setitem__(name, val, paramlist); return
object.__setattr__(self, name, val);
#===========================================================================
# Printing:
#===========================================================================
@property @property
def names(self): def names(self):
return [x.name for x in self._params] return [x.name for x in self._params]
@property @property
def size(self): def parameter_size(self):
return sum(self.sizes) return sum(self.parameter_sizes)
@property @property
def sizes(self): def parameter_sizes(self):
return [x.size for x in self._params] return [x.size for x in self._params]
@property @property
def sizes_transformed(self): def parameter_size_transformed(self):
return [x.num_params_transformed() for x in self._params] return sum(self._ties_fixes)
@property @property
def num_params_transformed(self): def parameter_shapes(self):
return reduce(lambda a,b: a+b.num_params_transformed, self._params, 0)
@property
def constraints(self):
return [x.constraints for x in self._params]
@property
def shapes(self):
return [x.shape for x in self._params] return [x.shape for x in self._params]
@property @property
def _constrs(self): def _constrs(self):
return [x._constr for x in self._params] return [p._constr for p in self._params]
@property @property
def _descs(self): def _descs(self):
return [x._desc for x in self._params] return [x._desc for x in self._params]
@property
def _ts(self):
return [x._t for x in self._params]
def __str__(self, header=True): def __str__(self, header=True):
nl = max([len(str(x)) for x in self.names + ["Name"]]) nl = max([len(str(x)) for x in self.names + ["Name"]])
sl = max([len(str(x)) for x in self._descs + ["Value"]]) sl = max([len(str(x)) for x in self._descs + ["Value"]])
cl = max([len(str(x)) if x else 0 for x in self._constrs + ["Constraint"]]) cl = max([len(str(x)) if x else 0 for x in self._constrs + ["Constraint"]])
format_spec = " \033[1m{{self.name:^{0}s}}\033[0;0m | {{self._desc:^{1}s}} | {{self._constr:^{2}s}} ".format(nl, sl, cl) tl = max([len(str(x)) if x else 0 for x in self._ts + ["Tied to"]])
format_spec = " \033[1m{{p.name:^{0}s}}\033[0;0m | {{p._desc:^{1}s}} | {{p._constr:^{2}s}} | {{p._t:^{2}s}}".format(nl, sl, cl)
to_print = [format_spec.format(p=p) for p in self._params]
sep = '-'*len(to_print[0])
if header: if header:
header = " {{0:^{0}s}} | {{1:^{1}s}} | {{2:^{2}s}} ".format(nl, sl, cl).format("Name", "Value", "Constraint") header = " {{0:^{0}s}} | {{1:^{1}s}} | {{2:^{2}s}} | {{3:^{3}s}}".format(nl, sl, cl, tl).format("Name", "Value", "Constraint", "Tied to")
header += '\n' + '-'*len(header) header += '\n' + sep
return '\n'.join([header]+[x.__str__(format_spec=format_spec) for x in self._params]) to_print.insert(0, header)
return '\n'.join([x.__str__(format_spec=format_spec) for x in self._params]) return '\n'.format(sep).join(to_print)
pass pass
class Param(numpy.ndarray): class Param(numpy.ndarray):
""" """
Parameter object for GPy models. Parameter object for GPy models.
- constraining singular entries:
- param[1:2,1:2].constrain{_..}() to keep the shape
- param[1,1,...].constrain{_..}(), which tells numpy to keep the shapes
- param[[1],[1]] to trigger advanced indexin, which keeps shapes
this is because of numpy's ndarray functionality:
it gives back a float, when indexing singular entries
we want a Param object though, with the right shape
workarounds:
- slice paramters and constrain the slices. - slice paramters and constrain the slices.
- unconstrain slices - unconstrain slices
""" """
fixed = False # if this parameter is fixed fixed = False # if this parameter is fixed
__array_priority__ = -1 # Only give back a param if slicing __array_priority__ = -1. # Allways give back Param
def __new__(cls, name, input_array):
def __new__(cls, name, input_array, constraints=None, ties=None):
obj = numpy.atleast_1d(numpy.array(input_array)).view(cls) obj = numpy.atleast_1d(numpy.array(input_array)).view(cls)
obj.name = name obj.name = name
obj._parent = None
obj._parent_index = None
obj._current_slice = slice(None) obj._current_slice = slice(None)
obj._realshape = obj.shape obj._realshape = obj.shape
#obj.parameters = parameters obj._realsize = obj.size
if constraints is None:
obj.constraints = ParameterIndexOperations(obj)
else:
obj.constraints = constraints
if ties is None:
obj.ties = ParameterIndexOperations(obj)
else:
obj.ties = ties
return obj return obj
def __array_finalize__(self, obj): def __array_finalize__(self, obj):
# see InfoArray.__array_finalize__ for comments # see InfoArray.__array_finalize__ for comments
if obj is None: return if obj is None: return
self.name = getattr(obj, 'name', None) self.name = getattr(obj, 'name', None)
self._realshape = getattr(obj, '_realshape', None)
self.constraints = getattr(obj, 'constraints', None)
self._parent = getattr(obj, '_parent', None)
self.ties = getattr(obj, 'ties', None)
self._current_slice = getattr(obj, '_current_slice', None) self._current_slice = getattr(obj, '_current_slice', None)
self._parent = getattr(obj, '_parent', None)
@property self._parent_index = getattr(obj, '_parent_index', None)
def value(self): self._realshape = getattr(obj, '_realshape', None)
return self#self.base[self._current_slice] self._realsize = getattr(obj, '_realsize', None)
#===========================================================================
@property # get/set parameters
def _desc(self): #===========================================================================
if self.size <= 1:
return "%f"%self.value
else:
return self.shape
@property
def _constr(self):
return ' '.join([str(c) if c else '' for c in self.constraints.properties()])
def _set_params(self, param): def _set_params(self, param):
self.value.flat = param self.flat = param
def _get_params(self): def _get_params(self):
return self.value.flat return self.flat
#===========================================================================
@property # Fixing Parameters:
def num_params_transformed(self): #===========================================================================
return self.size - self.ties.size() def constrain_fixed(self):
self._parent._fix(self)
def _get_params_transformed(self): def unconstrain_fixed(self):
params = self.base.flatten() self._parent._unfix(self)
[numpy.put(params, indices, constr.finv(params[indices])) for constr, indices in self.constraints.iteritems()] #===========================================================================
return numpy.delete(params, reduce(numpy.union1d, self.ties.iterindices(), numpy.array([],dtype=self.dtype))) # Constrain operations -> done
#===========================================================================
def _set_params_transformed(self, params): def constrain(self, transform):
numpy.put(self.base, numpy.setdiff1d(numpy.r_[:self.size],reduce(numpy.union1d, self.ties.iterindices(), numpy.array([],dtype=self.dtype))), params) self._parent._add_constrain(self, transform)
[numpy.put(self.base, indices, constraint.f(self.base.flat[indices])) for constraint, indices in self.constraints.iteritems()] self[...] = transform.initialize(self)
def constrain_positive(self):
def _handle_ties(self): self.constrain(Logexp())
# handle all tied values def constrain_negative(self):
for tie, indices in self.ties.iteritems(): self.constrain(NegativeLogexp())
self.base.flat[indices] = tie.flat def unconstrain(self, transforms=None):
self._parent._remove_constrain(self, transforms)
def unconstrain_positive(self):
self.unconstrain(Logexp())
def unconstrain_negative(self):
self.unconstrain(NegativeLogexp())
#===========================================================================
# Tying operations -> done
#===========================================================================
def tie_to(self, param): def tie_to(self, param):
assert isinstance(param, Param), "Argument {1} not of type {0}".format(Param,param.__class__) assert isinstance(param, Param), "Argument {1} not of type {0}".format(Param,param.__class__)
try: try:
rav_index = self.ties.create_raveled_indices(self._current_slice) self[...] = param
self.base.flat[rav_index] = param.flat self._parent._add_tie(self, param)
self.ties.add(param, self._current_slice)
self._handle_ties()
except ValueError: except ValueError:
raise ValueError("Trying to tie params with shape {} to params with shape {}".format(self.shape, param.shape)) raise ValueError("Trying to tie {} with shape {} to {} with shape {}".format(self.name, self.shape, param.name, param.shape))
def untie(self, *params): def untie(self, *params):
if len(params) == 0: if len(params) == 0:
params = self.ties.properties() params = self._parent._ties.properties()
for p in self.ties.properties(): for p in self._parent._ties.properties():
if any((p == x).all() for x in params): if any((p == x).all() for x in params):
self.ties.remove(p, self._current_slice) self._parent._remove_tie(self, params)
#===========================================================================
def constrain(self, transform): # Array operations -> done
self.constraints.add(transform, self._current_slice) #===========================================================================
self[:] = transform.initialize(self)
def constrain_positive(self):
self.constrain(Logexp())
def constrain_negative(self):
self.constrain(NegativeLogexp())
def unconstrain(self, transforms=None):
if transforms is None:
transforms = self.constraints.properties()
elif not isinstance(transforms, (tuple, list, numpy.ndarray)):
transforms = [transforms]
for constr in transforms:
self.constraints.remove(constr, self._current_slice)
def unconstrain_positive(self):
self.unconstrain(Logexp())
def unconstrain_negative(self):
self.unconstrain(NegativeLogexp())
def __getitem__(self, s, *args, **kwargs): def __getitem__(self, s, *args, **kwargs):
if not isinstance(s, tuple):
s = (s,)
if not( Ellipsis in s):
s = (s + (Ellipsis,))
new_arr = numpy.ndarray.__getitem__(self, s, *args, **kwargs) new_arr = numpy.ndarray.__getitem__(self, s, *args, **kwargs)
try: try: new_arr._current_slice = s
new_arr._current_slice = s except AttributeError: pass# returning 0d array or float, double etc
except AttributeError:
# returning 0d array or float, double etc:
pass
return new_arr return new_arr
def __getslice__(self, 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._parent._handle_ties() self._parent._handle_ties()
#===========================================================================
def __repr__(self, *args, **kwargs): # Printing ->
return super(Param, self).__repr__(*args, **kwargs) #===========================================================================
view = repr(self.value) @property
def _desc(self):
if self.size <= 1: return "%f"%self
else: return self.shape
@property
def _constr(self):
return ' '.join(map(lambda c: str(c[0]) if len(c[1])==self._realsize else "{"+str(c[0])+"}", self._parent._constraints_iter_items(self)))
@property
def _t(self):
# indices one by one: "".join(map(str,c[0]._indices()))
return ' '.join(map(lambda c: c[0].name if len(c[1])==self._realsize else c[0].name+"[...]", self._parent._ties_iter_items(self)))
def round(self, decimals=0, out=None):
view = super(Param, self).round(decimals, out).view(Param)
view.__array_finalize__(self)
return view return view
round.__doc__ = numpy.round.__doc__
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 _constr_matrix_str(self): def _constr_matrix_str(self):
constr_matrix = numpy.empty(self._realshape, dtype=object) # we need the whole constraints matrix constr_matrix = numpy.empty(self._realsize, dtype=object) # we need the whole constraints matrix
constr_matrix[:] = '' constr_matrix[:] = ''
for constr, indices in self.constraints.iteritems(): # put in all the constraints: for constr, indices in self._parent._constraints_iter_items(self): # put in all the constraints:
constr_matrix[indices] = numpy.vectorize(lambda x:" ".join([x, str(constr)]) if x else str(constr))(constr_matrix[indices]) cstr = ""+str(constr)+""
return constr_matrix.astype(numpy.string_)[self._current_slice] # and get the slice we did before constr_matrix[indices] = numpy.vectorize(lambda x:" ".join([x, cstr]) if x else cstr, otypes=[str])(constr_matrix[indices])
return constr_matrix.astype(numpy.string_).reshape(self._realshape)[self._current_slice].flatten() # and get the slice we did before
def _ties_matrix_str(self): def _ties_matrix_str(self):
ties_matr = numpy.empty(self._realshape, dtype=object) # we need the whole constraints matrix ties_matr = numpy.empty(self._realsize, dtype=object) # we need the whole constraints matrix
ties_matr[:] = '' ties_matr[:] = ''
for tie, indices in self.ties.iteritems(): # go through all ties: for tie, indices in self._parent._ties_iter_items(self): # go through all ties:
tie_cycle = itertools.cycle(tie._indices()) tie_cycle = itertools.cycle(tie._indices()) if tie._realsize > 1 else itertools.repeat('')
ties_matr[indices] = numpy.vectorize(lambda x:" ".join([x, str(tie.name) + str(str(tie_cycle.next()))]) if x else str(tie.name)+str(str(tie_cycle.next())), otypes=[str])(ties_matr[indices]) ties_matr[indices] = numpy.vectorize(lambda x:" ".join([x, str(tie.name) + str(str(tie_cycle.next()))]) if x else str(tie.name)+str(str(tie_cycle.next())), otypes=[str])(ties_matr[indices])
return ties_matr.astype(numpy.string_)[self._current_slice] # and get the slice we did before return ties_matr.astype(numpy.string_).reshape(*(self._realshape+(-1,)))[self._current_slice] # and get the slice we did before
def _indices(self): def _indices(self):
return numpy.array(list(itertools.product(*itertools.imap(range, self._realshape))))[self.constraints.create_raveled_indices(self._current_slice),...] # find out which indices to print flat_indices = numpy.array(list(itertools.product(*itertools.imap(range, self._realshape)))).reshape(self._realshape + (-1,))
return flat_indices[self._current_slice].reshape(self.size, -1) # find out which indices to print
def _max_len_names(self, constr_matrix, header): def _max_len_names(self, constr_matrix, header):
return max(reduce(lambda a, b:max(a, len(b)), constr_matrix.flat, 0), len(header)) return max(reduce(lambda a, b:max(a, len(b)), constr_matrix.flat, 0), len(header))
def _max_len_values(self): def _max_len_values(self):
return max(reduce(lambda a, b:max(a, len("{x:=.{0}G}".format(__precision__, x=b))), self.value.flat, 0), len(self.name)) return max(reduce(lambda a, b:max(a, len("{x:=.{0}G}".format(__precision__, x=b))), self.flat, 0), len(self.name))
def _max_len_index(self, ind): def _max_len_index(self, ind):
return max(reduce(lambda a, b:max(a, len(str(b))), ind, 0), len(__index_name__)) return max(reduce(lambda a, b:max(a, len(str(b))), ind, 0), len(__index_name__))
def __str__(self, format_spec=None, constr_matrix=None, indices=None, ties=None, lc=None, lx=None, li=None, lt=None): def __str__(self, constr_matrix=None, indices=None, ties=None, lc=None, lx=None, li=None, lt=None):
if format_spec is None: try:
if indices is None: if indices is None: indices = self._indices()
indices = self._indices() if constr_matrix is None: constr_matrix = self._constr_matrix_str()
if constr_matrix is None: if ties is None: ties = self._ties_matrix_str()
constr_matrix = self._constr_matrix_str() if lc is None: lc = self._max_len_names(constr_matrix, __constraints_name__)
if ties is None: if lx is None: lx = self._max_len_values()
ties = self._ties_matrix_str() if li is None: li = self._max_len_index(indices)
if lc is None: if lt is None: lt = self._max_len_names(ties, __tie_name__)
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(indices)
if lt is None:
lt = self._max_len_names(ties, __tie_name__)
constr = constr_matrix.flat constr = constr_matrix.flat
ties = ties.flat ties = ties.flat
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:^{3}s} | {x: >{1}.{2}G} | {c:^{0}s} | {t:^{4}} ".format(lc,lx,__precision__,li,lt, x=x, c=constr.next(), t=ties.next(), i=i) for i,x in itertools.izip(indices,self.value.flat)]) # return all the constraints with right indices return "\n".join([header]+[" {i:^{3}s} | {x: >{1}.{2}G} | {c:^{0}s} | {t:^{4}} ".format(lc,lx,__precision__,li,lt, x=x, c=constr.next(), t=ties.next(), i=i) for i,x in itertools.izip(indices,self.flat)]) # return all the constraints with right indices
return format_spec.format(self=self) except: return super(Param, self).__str__()
class ParamConcatenation(object): class ParamConcatenation(object):
def __init__(self, params): def __init__(self, params):
"""
Parameter concatenation for convienience of printing regular expression matched arrays
you can index this concatenation as if it was the flattened concatenation
of all the parameters it contains, same for setting parameters
"""
self.params = params self.params = params
self._param_sizes = [p.size for p in self.params]
startstops = numpy.cumsum([0] + self._param_sizes)
self._param_slices = [slice(start, stop) for start,stop in zip(startstops, startstops[1:])]
def __getitem__(self, s): def __getitem__(self, s):
raise AttributeError("Cannot index a concatenation of parameters!") ind = numpy.zeros(sum(self._param_sizes), dtype=bool); ind[s] = True;
params = [p.flatten()[ind[ps]] for p,ps in zip(self.params, self._param_slices) if numpy.any(p.flat[ind[ps]])]
if len(params)==1: return params[0]
return ParamConcatenation(params)
def __setitem__(self, s, val):
ind = numpy.zeros(sum(self._param_sizes), dtype=bool); ind[s] = True;
vals = self._vals(); vals[s] = val; del val
[numpy.place(p, ind[ps], vals[ps]) for p, ps in zip(self.params, self._param_slices)]
def _vals(self):
return numpy.hstack([p._get_params() for p in self.params])
def constrain(self, constraint): def constrain(self, constraint):
[param.constrain(constraint) for param in self.params] [param.constrain(constraint) for param in self.params]
def constrain_positive(self): def constrain_positive(self):
[param.constrain_positive() for param in self.params] [param.constrain_positive() for param in self.params]
def constrain_fixed(self):
[param.constrain_fixed() for param in self.params]
def constrain_negative(self): def constrain_negative(self):
[param.constrain_negative() for param in self.params] [param.constrain_negative() for param in self.params]
def unconstrain(self, constraints=None): def unconstrain(self, constraints=None):
[param.unconstrain(constraints) for param in self.params] [param.unconstrain(constraints) for param in self.params]
def unconstrain_negative(self): def unconstrain_negative(self):
[param.unconstrain_negative() for param in self.params] [param.unconstrain_negative() for param in self.params]
def unconstrain_positive(self):
[param.unconstrain_positive() for param in self.params]
def unconstrain_fixed(self):
[param.unconstrain_fixed() for param in self.params]
def __str__(self, *args, **kwargs): def __str__(self, *args, **kwargs):
constr_matrices = [p._constr_matrix_str() for p in self.params] constr_matrices = [p._constr_matrix_str() for p in self.params]
ties_matrices = [p._ties_matrix_str() for p in self.params] ties_matrices = [p._ties_matrix_str() for p in self.params]
@ -338,21 +460,23 @@ class ParamConcatenation(object):
lx = max([p._max_len_values() for p in self.params]) lx = max([p._max_len_values() for p in self.params])
li = max([p._max_len_index(i) for p, i in itertools.izip(self.params, indices)]) li = max([p._max_len_index(i) for p, i in itertools.izip(self.params, indices)])
lt = max([p._max_len_names(tm, __tie_name__) for p, tm in itertools.izip(self.params, ties_matrices)]) lt = max([p._max_len_names(tm, __tie_name__) for p, tm in itertools.izip(self.params, ties_matrices)])
return "\n".join([p.__str__(None, cm, i, tm, lc, lx, li, lt) for p, cm, i, tm in itertools.izip(self.params,constr_matrices,indices,ties_matrices)]) strings = [p.__str__(cm, i, tm, lc, lx, li, lt) for p, cm, i, tm in itertools.izip(self.params,constr_matrices,indices,ties_matrices)]
return "\n{}\n".format(" -"+"- | -".join(['-'*l for l in [li,lx,lc,lt]])).join(strings)
def __repr__(self): def __repr__(self):
return self.__str__() return "\n".join(map(repr,self.params))
if __name__ == '__main__': if __name__ == '__main__':
X = numpy.random.randn(100,8) X = numpy.random.randn(3,3,2)
p = Param("X", X) p = Param("q_mean", X)
p1 = Param("X_variance", numpy.random.rand(*X.shape)) p1 = Param("q_variance", numpy.random.rand(*p.shape))
p2 = Param("Y", numpy.random.randn(3,1)) p2 = Param("Y", numpy.random.randn(p.shape[0],1))
p3 = Param("rbf_variance", numpy.random.rand(1)) p3 = Param("rbf_variance", numpy.random.rand())
p4 = Param("rbf_lengthscale", numpy.random.rand(2)) p4 = Param("rbf_lengthscale", numpy.random.rand(2))
params = Parameterized([p,p1,p2,p3,p4]) m = Parameterized([p,p1,p2,p3,p4])
params.rbf.constrain_positive() m[".*variance"].constrain_positive()
params[".*variance"].constrain_positive() m.rbf.constrain_positive()
params.rbf_l.tie_to(params.rbf_va) m.q_v.tie_to(m.rbf_v)
pt = numpy.array(params._get_params_transformed()) # m.rbf_l.tie_to(m.rbf_va)
ptr = numpy.random.randn(*pt.shape) # pt = numpy.array(params._get_params_transformed())
# ptr = numpy.random.randn(*pt.shape)
# params.X.tie_to(params.rbf_v) # params.X.tie_to(params.rbf_v)