mirror of
https://github.com/SheffieldML/GPy.git
synced 2026-06-02 14:45:15 +02:00
parameterized first beta test
This commit is contained in:
parent
4f56506aa6
commit
152f61acf0
1 changed files with 346 additions and 222 deletions
|
|
@ -7,7 +7,8 @@ import re
|
|||
import itertools
|
||||
import numpy
|
||||
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 re import compile, _pattern_type
|
||||
_index_re = re.compile('(?:_(\d+))+') # pattern match for indices
|
||||
|
|
@ -17,319 +18,440 @@ __constraints_name__ = "Constraint"
|
|||
__index_name__ = "Index"
|
||||
__tie_name__ = "Tied to"
|
||||
__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):
|
||||
"""
|
||||
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):
|
||||
self._init = True
|
||||
self._params = []
|
||||
for p in parameterlist:
|
||||
if isinstance(p, Parameterized):
|
||||
self._params.extend(p._params)
|
||||
else:
|
||||
self._params.append(p)
|
||||
sizes = numpy.cumsum([0] + self.sizes)
|
||||
self._param_slices = itertools.starmap(lambda start,stop: slice(start, stop), zip(sizes, sizes[1:]))
|
||||
for p in self._params:
|
||||
self._constraints = ConstraintIndexOperations()
|
||||
self._ties = TieIndexOperations(self)
|
||||
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
|
||||
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):
|
||||
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):
|
||||
[p._set_params(params[s]) for p,s in itertools.izip(self._params,self._param_slices)]
|
||||
|
||||
def _get_params_transformed(self):
|
||||
return numpy.hstack([x._get_params_transformed() for x in self._params])
|
||||
return numpy.fromiter(itertools.chain(*itertools.imap(lambda x: x._get_params_transformed(), self._params)), dtype=numpy.float64, count=self.num_params_transformed)
|
||||
p = self._get_params()
|
||||
[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):
|
||||
current_index = 0
|
||||
for p in self._params:
|
||||
s = p.num_params_transformed
|
||||
p._set_params_transformed(params[current_index:current_index+s])
|
||||
current_index += s
|
||||
self._handle_ties()
|
||||
def _set_params_transformed(self, p):
|
||||
if self._ties_fixes is not None: tmp = self._get_params(); tmp[self._ties_fixes] = p; p = tmp; del tmp
|
||||
[numpy.put(p, ind, c.f(p[ind])) for c,ind in self._constraints.iteritems() if c is not __fixed__]
|
||||
[numpy.put(p, f, p[t]) for f,t in self._ties.iter_from_to_indices()]
|
||||
self._set_params(p)
|
||||
|
||||
def _handle_ties(self):
|
||||
[p._handle_ties() for p in self._params]
|
||||
|
||||
def __getitem__(self, name):
|
||||
return self.__getattr__(name)
|
||||
|
||||
if not self._init:
|
||||
self._set_params_transformed(self._get_params_transformed())
|
||||
#===========================================================================
|
||||
# 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):
|
||||
if not isinstance(regexp, _pattern_type):
|
||||
regexp = compile(regexp)
|
||||
paramlist = [param for param in self._params if regexp.search(param.name) is not None]
|
||||
if not isinstance(regexp, _pattern_type): regexp = compile(regexp)
|
||||
paramlist = [param for param in self._params if regexp.match(param.name) is not None]
|
||||
return paramlist
|
||||
|
||||
def tie_params(self, regexp):
|
||||
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:
|
||||
def __getitem__(self, name, paramlist=None):
|
||||
if paramlist is None:
|
||||
paramlist = self.grep_param_names(name)
|
||||
if len(paramlist) < 1:
|
||||
raise AttributeError("'{:s}' object has no attribute '{:s}'".format(str(self.__class__.__name__), name))
|
||||
if len(paramlist) == 1:
|
||||
return paramlist[-1]
|
||||
return ParamConcatenation(paramlist)
|
||||
|
||||
if len(paramlist) < 1: raise AttributeError, name
|
||||
if len(paramlist) == 1: return paramlist[-1]
|
||||
return ParamConcatenation(paramlist)
|
||||
def __setitem__(self, name, value, paramlist=None):
|
||||
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
|
||||
def names(self):
|
||||
return [x.name for x in self._params]
|
||||
@property
|
||||
def size(self):
|
||||
return sum(self.sizes)
|
||||
def parameter_size(self):
|
||||
return sum(self.parameter_sizes)
|
||||
@property
|
||||
def sizes(self):
|
||||
def parameter_sizes(self):
|
||||
return [x.size for x in self._params]
|
||||
@property
|
||||
def sizes_transformed(self):
|
||||
return [x.num_params_transformed() for x in self._params]
|
||||
def parameter_size_transformed(self):
|
||||
return sum(self._ties_fixes)
|
||||
@property
|
||||
def num_params_transformed(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):
|
||||
def parameter_shapes(self):
|
||||
return [x.shape for x in self._params]
|
||||
@property
|
||||
def _constrs(self):
|
||||
return [x._constr for x in self._params]
|
||||
return [p._constr for p in self._params]
|
||||
@property
|
||||
def _descs(self):
|
||||
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):
|
||||
nl = max([len(str(x)) for x in self.names + ["Name"]])
|
||||
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"]])
|
||||
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:
|
||||
header = " {{0:^{0}s}} | {{1:^{1}s}} | {{2:^{2}s}} ".format(nl, sl, cl).format("Name", "Value", "Constraint")
|
||||
header += '\n' + '-'*len(header)
|
||||
return '\n'.join([header]+[x.__str__(format_spec=format_spec) for x in self._params])
|
||||
return '\n'.join([x.__str__(format_spec=format_spec) for x in self._params])
|
||||
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' + sep
|
||||
to_print.insert(0, header)
|
||||
return '\n'.format(sep).join(to_print)
|
||||
pass
|
||||
|
||||
class Param(numpy.ndarray):
|
||||
"""
|
||||
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.
|
||||
|
||||
- unconstrain slices
|
||||
|
||||
"""
|
||||
fixed = False # if this parameter is fixed
|
||||
__array_priority__ = -1 # Only give back a param if slicing
|
||||
|
||||
def __new__(cls, name, input_array, constraints=None, ties=None):
|
||||
__array_priority__ = -1. # Allways give back Param
|
||||
def __new__(cls, name, input_array):
|
||||
obj = numpy.atleast_1d(numpy.array(input_array)).view(cls)
|
||||
obj.name = name
|
||||
obj._parent = None
|
||||
obj._parent_index = None
|
||||
obj._current_slice = slice(None)
|
||||
obj._realshape = obj.shape
|
||||
#obj.parameters = parameters
|
||||
if constraints is None:
|
||||
obj.constraints = ParameterIndexOperations(obj)
|
||||
else:
|
||||
obj.constraints = constraints
|
||||
if ties is None:
|
||||
obj.ties = ParameterIndexOperations(obj)
|
||||
else:
|
||||
obj.ties = ties
|
||||
obj._realsize = obj.size
|
||||
return obj
|
||||
|
||||
def __array_finalize__(self, obj):
|
||||
# see InfoArray.__array_finalize__ for comments
|
||||
if obj is None: return
|
||||
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)
|
||||
|
||||
@property
|
||||
def value(self):
|
||||
return self#self.base[self._current_slice]
|
||||
|
||||
@property
|
||||
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()])
|
||||
|
||||
self._parent = getattr(obj, '_parent', None)
|
||||
self._parent_index = getattr(obj, '_parent_index', None)
|
||||
self._realshape = getattr(obj, '_realshape', None)
|
||||
self._realsize = getattr(obj, '_realsize', None)
|
||||
#===========================================================================
|
||||
# get/set parameters
|
||||
#===========================================================================
|
||||
def _set_params(self, param):
|
||||
self.value.flat = param
|
||||
|
||||
self.flat = param
|
||||
def _get_params(self):
|
||||
return self.value.flat
|
||||
|
||||
@property
|
||||
def num_params_transformed(self):
|
||||
return self.size - self.ties.size()
|
||||
|
||||
def _get_params_transformed(self):
|
||||
params = self.base.flatten()
|
||||
[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)))
|
||||
|
||||
def _set_params_transformed(self, params):
|
||||
numpy.put(self.base, numpy.setdiff1d(numpy.r_[:self.size],reduce(numpy.union1d, self.ties.iterindices(), numpy.array([],dtype=self.dtype))), params)
|
||||
[numpy.put(self.base, indices, constraint.f(self.base.flat[indices])) for constraint, indices in self.constraints.iteritems()]
|
||||
|
||||
def _handle_ties(self):
|
||||
# handle all tied values
|
||||
for tie, indices in self.ties.iteritems():
|
||||
self.base.flat[indices] = tie.flat
|
||||
|
||||
return self.flat
|
||||
#===========================================================================
|
||||
# Fixing Parameters:
|
||||
#===========================================================================
|
||||
def constrain_fixed(self):
|
||||
self._parent._fix(self)
|
||||
def unconstrain_fixed(self):
|
||||
self._parent._unfix(self)
|
||||
#===========================================================================
|
||||
# Constrain operations -> done
|
||||
#===========================================================================
|
||||
def constrain(self, transform):
|
||||
self._parent._add_constrain(self, transform)
|
||||
self[...] = transform.initialize(self)
|
||||
def constrain_positive(self):
|
||||
self.constrain(Logexp())
|
||||
def constrain_negative(self):
|
||||
self.constrain(NegativeLogexp())
|
||||
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):
|
||||
assert isinstance(param, Param), "Argument {1} not of type {0}".format(Param,param.__class__)
|
||||
try:
|
||||
rav_index = self.ties.create_raveled_indices(self._current_slice)
|
||||
self.base.flat[rav_index] = param.flat
|
||||
self.ties.add(param, self._current_slice)
|
||||
self._handle_ties()
|
||||
self[...] = param
|
||||
self._parent._add_tie(self, param)
|
||||
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):
|
||||
if len(params) == 0:
|
||||
params = self.ties.properties()
|
||||
for p in self.ties.properties():
|
||||
params = self._parent._ties.properties()
|
||||
for p in self._parent._ties.properties():
|
||||
if any((p == x).all() for x in params):
|
||||
self.ties.remove(p, self._current_slice)
|
||||
|
||||
def constrain(self, transform):
|
||||
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())
|
||||
|
||||
self._parent._remove_tie(self, params)
|
||||
#===========================================================================
|
||||
# Array operations -> done
|
||||
#===========================================================================
|
||||
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)
|
||||
try:
|
||||
new_arr._current_slice = s
|
||||
except AttributeError:
|
||||
# returning 0d array or float, double etc:
|
||||
pass
|
||||
try: new_arr._current_slice = s
|
||||
except AttributeError: pass# returning 0d array or float, double etc
|
||||
return new_arr
|
||||
|
||||
def __getslice__(self, start, stop):
|
||||
return self.__getitem__(slice(start, stop))
|
||||
def __setitem__(self, *args, **kwargs):
|
||||
numpy.ndarray.__setitem__(self, *args, **kwargs)
|
||||
self._parent._handle_ties()
|
||||
|
||||
def __repr__(self, *args, **kwargs):
|
||||
return super(Param, self).__repr__(*args, **kwargs)
|
||||
view = repr(self.value)
|
||||
#===========================================================================
|
||||
# Printing ->
|
||||
#===========================================================================
|
||||
@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
|
||||
|
||||
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):
|
||||
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[:] = ''
|
||||
for constr, indices in self.constraints.iteritems(): # put in all the constraints:
|
||||
constr_matrix[indices] = numpy.vectorize(lambda x:" ".join([x, str(constr)]) if x else str(constr))(constr_matrix[indices])
|
||||
return constr_matrix.astype(numpy.string_)[self._current_slice] # and get the slice we did before
|
||||
for constr, indices in self._parent._constraints_iter_items(self): # put in all the constraints:
|
||||
cstr = ""+str(constr)+""
|
||||
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):
|
||||
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[:] = ''
|
||||
for tie, indices in self.ties.iteritems(): # go through all ties:
|
||||
tie_cycle = itertools.cycle(tie._indices())
|
||||
for tie, indices in self._parent._ties_iter_items(self): # go through all ties:
|
||||
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])
|
||||
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):
|
||||
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):
|
||||
return max(reduce(lambda a, b:max(a, len(b)), constr_matrix.flat, 0), len(header))
|
||||
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):
|
||||
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):
|
||||
if format_spec is None:
|
||||
if indices is None:
|
||||
indices = self._indices()
|
||||
if constr_matrix is None:
|
||||
constr_matrix = self._constr_matrix_str()
|
||||
if ties is None:
|
||||
ties = self._ties_matrix_str()
|
||||
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(indices)
|
||||
if lt is None:
|
||||
lt = self._max_len_names(ties, __tie_name__)
|
||||
def __str__(self, constr_matrix=None, indices=None, ties=None, lc=None, lx=None, li=None, lt=None):
|
||||
try:
|
||||
if indices is None: indices = self._indices()
|
||||
if constr_matrix is None: constr_matrix = self._constr_matrix_str()
|
||||
if ties is None: ties = self._ties_matrix_str()
|
||||
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(indices)
|
||||
if lt is None: lt = self._max_len_names(ties, __tie_name__)
|
||||
constr = constr_matrix.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
|
||||
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 format_spec.format(self=self)
|
||||
|
||||
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
|
||||
except: return super(Param, self).__str__()
|
||||
class ParamConcatenation(object):
|
||||
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._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):
|
||||
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):
|
||||
[param.constrain(constraint) for param in self.params]
|
||||
def constrain_positive(self):
|
||||
[param.constrain_positive() for param in self.params]
|
||||
def constrain_fixed(self):
|
||||
[param.constrain_fixed() for param in self.params]
|
||||
def constrain_negative(self):
|
||||
[param.constrain_negative() for param in self.params]
|
||||
def unconstrain(self, constraints=None):
|
||||
[param.unconstrain(constraints) for param in self.params]
|
||||
def unconstrain_negative(self):
|
||||
[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):
|
||||
constr_matrices = [p._constr_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])
|
||||
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)])
|
||||
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):
|
||||
return self.__str__()
|
||||
return "\n".join(map(repr,self.params))
|
||||
|
||||
if __name__ == '__main__':
|
||||
X = numpy.random.randn(100,8)
|
||||
p = Param("X", X)
|
||||
p1 = Param("X_variance", numpy.random.rand(*X.shape))
|
||||
p2 = Param("Y", numpy.random.randn(3,1))
|
||||
p3 = Param("rbf_variance", numpy.random.rand(1))
|
||||
X = numpy.random.randn(3,3,2)
|
||||
p = Param("q_mean", X)
|
||||
p1 = Param("q_variance", numpy.random.rand(*p.shape))
|
||||
p2 = Param("Y", numpy.random.randn(p.shape[0],1))
|
||||
p3 = Param("rbf_variance", numpy.random.rand())
|
||||
p4 = Param("rbf_lengthscale", numpy.random.rand(2))
|
||||
params = Parameterized([p,p1,p2,p3,p4])
|
||||
params.rbf.constrain_positive()
|
||||
params[".*variance"].constrain_positive()
|
||||
params.rbf_l.tie_to(params.rbf_va)
|
||||
pt = numpy.array(params._get_params_transformed())
|
||||
ptr = numpy.random.randn(*pt.shape)
|
||||
m = Parameterized([p,p1,p2,p3,p4])
|
||||
m[".*variance"].constrain_positive()
|
||||
m.rbf.constrain_positive()
|
||||
m.q_v.tie_to(m.rbf_v)
|
||||
# m.rbf_l.tie_to(m.rbf_va)
|
||||
# pt = numpy.array(params._get_params_transformed())
|
||||
# ptr = numpy.random.randn(*pt.shape)
|
||||
# params.X.tie_to(params.rbf_v)
|
||||
Loading…
Add table
Add a link
Reference in a new issue