mirror of
https://github.com/SheffieldML/GPy.git
synced 2026-06-11 15:15:15 +02:00
still todo: untie, gradients, priors, print ties
This commit is contained in:
parent
945f192ee2
commit
6be05de791
3 changed files with 135 additions and 99 deletions
|
|
@ -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)
|
||||
|
|
|
|||
|
|
@ -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())
|
||||
|
|
|
|||
|
|
@ -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:
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue