2012-11-29 16:39:20 +00:00
# Copyright (c) 2012, GPy authors (see AUTHORS.txt).
# Licensed under the BSD 3-clause license (see LICENSE.txt)
2013-10-22 13:39:58 +01:00
import numpy ; np = numpy
2012-11-29 16:25:27 +00:00
import copy
import cPickle
2013-10-22 13:39:58 +01:00
import transformations
2013-10-15 09:01:03 +01:00
import itertools
from re import compile , _pattern_type
2013-10-22 13:39:58 +01:00
import re
2013-10-25 15:29:04 +01:00
class Parentable ( object ) :
_direct_parent_ = None
_parent_index_ = None
def has_parent ( self ) :
return self . _direct_parent_ is not None
class Nameable ( Parentable ) :
_name = None
def __init__ ( self , name ) :
self . _name = name or self . __class__ . __name__
self . name = name
@property
def name ( self ) :
return self . _name
@name.setter
def name ( self , name ) :
from_name = self . name
self . _name = name
if self . has_parent ( ) :
self . _direct_parent_ . _name_changed ( self , from_name )
2013-10-27 17:04:46 +00:00
class Pickleable ( object ) :
def getstate ( self ) :
"""
Returns the state of this class in a memento pattern .
The state must be a list - like structure of all the fields
this class need to run
"""
raise NotImplementedError , " To be able to use pickling you need to implement this method "
def setstate ( self , state ) :
"""
Set the state ( memento pattern ) of this class to the given state .
Usually this is just the counterpart to getstate , such that
an object is a copy of another when calling
copy = < classname > . __new__ ( * args , * * kw ) . setstate ( < to_be_copied > . getstate ( ) )
"""
raise NotImplementedError , " To be able to use pickling you need to implement this method "
2013-11-06 11:40:54 +00:00
class Observable ( object ) :
_observers_ = { }
def add_observer ( self , observer , callble ) :
self . _observers_ [ observer ] = callble
callble ( self )
def remove_observer ( self , observer ) :
del self . _observers_ [ observer ]
def _notify_observers ( self ) :
[ callble ( self ) for callble in self . _observers_ . itervalues ( ) ]
def _adjust_name_for_printing ( name ) :
return name . replace ( " " , " _ " ) . replace ( " . " , " _ " )
from parameter import ParamConcatenation , Param
2013-10-25 15:29:04 +01:00
from index_operations import ParameterIndexOperations , \
index_empty
2012-11-29 16:25:27 +00:00
2013-10-15 09:01:03 +01:00
#===============================================================================
# Printing:
__fixed__ = " fixed "
#===============================================================================
2013-06-25 17:43:42 +01:00
2013-10-17 14:33:41 +01:00
#===============================================================================
# constants
2013-10-18 16:20:01 +01:00
FIXED = False
UNFIXED = True
2013-10-17 14:33:41 +01:00
#===============================================================================
2013-06-25 17:43:42 +01:00
2013-11-06 11:40:54 +00:00
class Parameterized ( Nameable , Pickleable , Observable ) :
2013-10-15 09:01:03 +01:00
"""
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 details for all the parameters
which start with name
- print m [ ' .*name ' ] : prints details for all the parameters
which contain " name "
- print m [ ' ' ] : prints details for all parameters
Fields :
Name : The name of the parameter , can be renamed !
Value : Shape or value , if one - valued
Constrain : constraint of the parameter , curly " {c} " brackets indicate
some parameters are constrained by c . See detailed print
to get exact constraints .
Tied_to : which paramter it is tied to .
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 :
You can constrain parameters by calling the constrain on the parameter itself , e . g :
- m . name [ : , 1 ] . constrain_positive ( )
- m . name [ 0 ] . tie_to ( m . name [ 1 ] )
Fixing parameters will fix them to the value they are right now . If you change
2013-10-25 15:29:04 +01:00
the parameters value , the parameter will be fixed to the new value !
2013-10-15 09:01:03 +01:00
If you want to operate on all parameters use m [ ' ' ] to wildcard select all paramters
and concatenate them . Printing m [ ' ' ] will result in printing of all parameters in detail .
"""
2013-10-25 15:29:04 +01:00
def __init__ ( self , name = None ) :
super ( Parameterized , self ) . __init__ ( name )
2013-10-16 21:08:35 +01:00
self . _in_init_ = True
2013-10-25 15:29:04 +01:00
self . _constraints_ = None #ParameterIndexOperations()
self . _fixes_ = None
2013-10-16 21:08:35 +01:00
if not hasattr ( self , " _parameters_ " ) :
self . _parameters_ = [ ]
2013-10-25 15:29:04 +01:00
#else:
# self._parameters_.extend(parameters)
2013-10-15 09:01:03 +01:00
self . _connect_parameters ( )
2013-10-25 15:29:04 +01:00
self . gradient_mapping = { }
2013-11-06 11:40:54 +00:00
self . _added_names_ = set ( )
2013-10-16 21:08:35 +01:00
del self . _in_init_
2013-10-25 15:29:04 +01:00
@property
def constraints ( self ) :
if self . _constraints_ is None :
self . _constraints_ = ParameterIndexOperations ( )
return self . _constraints_
2013-10-16 21:08:35 +01:00
#===========================================================================
# Parameter connection for model creation:
#===========================================================================
2013-10-25 15:29:04 +01:00
# def set_as_parameter(self, name, array, gradient, index=None, gradient_parent=None):
# """
# :param name: name of the parameter (in print and plots), can be callable without parameters
# :type name: str, callable
# :param array: array which the parameter consists of
# :type array: array-like
# :param gradient: gradient method of the parameter
# :type gradient: callable
# :param index: (optional) index of the parameter when printing
#
# (:param gradient_parent: connect these parameters to this class, but tell
# updates to highest_parent, this is needed when parameterized classes
# contain parameterized classes, but want to access the parameters
# of their children)
#
#
# Set array (e.g. self.X) as parameter with name and gradient.
# I.e: self.set_as_parameter('curvature', self.lengthscale, self.dK_dlengthscale)
#
# Note: the order in which parameters are added can be adjusted by
# giving an index, of where to put this parameter in printing
# """
# if index is None:
# self._parameters_.append(Param(name, array, gradient))
# else:
# self._parameters_.insert(index, Param(name, array, gradient))
# self._connect_parameters(gradient_parent=gradient_parent)
def add_parameter ( self , parameter , gradient = None , index = None ) :
2013-10-16 21:08:35 +01:00
"""
2013-10-25 15:29:04 +01:00
: param parameters : the parameters to add
: type parameters : list of or one : py : class : ` GPy . core . parameter . Param `
: param [ gradients ] : gradients for each parameter ,
one gradient per parameter
: param [ index ] : index of where to put parameters
2013-10-16 21:08:35 +01:00
2013-10-25 15:29:04 +01:00
Add all parameters to this parameter class , you can insert parameters
at any given index using the : py : func : ` list . insert ` syntax
2013-10-16 21:08:35 +01:00
"""
2013-11-03 13:58:15 +00:00
if parameter in self . _parameters_ and index is not None :
del self . _parameters_ [ parameter . _parent_index_ ]
2013-10-25 15:29:04 +01:00
self . _parameters_ . insert ( index , parameter )
2013-11-03 13:58:15 +00:00
elif parameter not in self . _parameters_ :
if index is None :
self . _parameters_ . append ( parameter )
else :
self . _parameters_ . insert ( index , parameter )
2013-10-25 15:29:04 +01:00
self . _connect_parameters ( )
if gradient :
self . gradient_mapping [ parameter ] = gradient
def add_parameters ( self , * parameters ) :
2013-10-16 21:08:35 +01:00
"""
2013-10-27 17:04:46 +00:00
convenience method for adding several
2013-10-25 15:29:04 +01:00
parameters without gradient specification
2013-10-16 21:08:35 +01:00
"""
2013-10-25 15:29:04 +01:00
[ self . add_parameter ( p ) for p in parameters ]
2013-11-06 11:40:54 +00:00
2013-11-06 15:15:13 +00:00
def remove_parameter ( self , * names_params_indices ) :
"""
: param names_params_indices : mix of parameter_names , parameter objects , or indices
to remove from being a parameter of this parameterized object .
note : if it is a string object it will be regexp - matched automatically
"""
self . _parameters_ = [ p for p in self . _parameters_
if not ( p . _parent_index_ in names_params_indices
or p . name in names_params_indices
or p in names_params_indices ) ]
self . _connect_parameters ( )
2013-10-16 21:08:35 +01:00
def parameters_changed ( self ) :
2013-10-27 17:04:46 +00:00
"""
This method gets called when parameters have changed .
Another way of listening to parameter changes is to
add self as a listener to the parameter , such that
updates get passed through . See : py : function : ` ` GPy . core . parameter . Observable . add_observer ` `
"""
2013-10-16 21:08:35 +01:00
# will be called as soon as paramters have changed
pass
2013-10-27 17:04:46 +00:00
2013-10-25 15:29:04 +01:00
def _connect_parameters ( self ) :
2013-10-15 09:01:03 +01:00
# connect parameterlist to this parameterized object
# This just sets up the right connection for the params objects
# to be used as parameters
2013-10-16 21:08:35 +01:00
if not hasattr ( self , " _parameters_ " ) or len ( self . _parameters_ ) < 1 :
# no parameters for this class
return
2013-10-22 16:16:54 +01:00
i = 0
for p in self . _parameters_ :
#if p._parent_ is None:
2013-10-25 15:29:04 +01:00
p . _direct_parent_ = self
2013-10-16 21:08:35 +01:00
p . _parent_index_ = i
2013-10-22 16:16:54 +01:00
i + = 1
2013-10-25 15:29:04 +01:00
for pi in p . flattened_parameters :
pi . _highest_parent_ = self
2013-10-15 09:01:03 +01:00
not_unique = [ ]
2013-10-22 16:16:54 +01:00
# for k,v in self.__dict__.iteritems():
# try:
# if fast_array_equal(v,p):
# self.__dict__[k] = p
# except: # parameter comparison, just for convenience
2013-11-03 13:58:15 +00:00
# pass
2013-11-06 11:40:54 +00:00
pname = _adjust_name_for_printing ( p . name )
2013-11-03 13:58:15 +00:00
if pname in self . __dict__ :
2013-11-06 11:40:54 +00:00
if isinstance ( self . __dict__ [ pname ] , ( Parameterized , Param ) ) :
if not p is self . __dict__ [ pname ] :
not_unique . append ( pname )
del self . __dict__ [ pname ]
2013-11-03 13:58:15 +00:00
elif not ( pname in not_unique ) :
self . __dict__ [ pname ] = p
2013-11-06 11:40:54 +00:00
self . _added_names_ . add ( pname )
2013-10-25 15:29:04 +01:00
sizes = numpy . cumsum ( [ 0 ] + self . _parameter_sizes_ )
self . size = sizes [ - 1 ]
self . _param_slices_ = [ slice ( start , stop ) for start , stop in zip ( sizes , sizes [ 1 : ] ) ]
2013-11-03 13:58:15 +00:00
# self.parameters_changed()
2013-10-16 21:08:35 +01:00
#===========================================================================
# Pickling operations
#===========================================================================
def pickle ( self , f , protocol = - 1 ) :
"""
: param f : either filename or open file object to write to .
if it is an open buffer , you have to make sure to close
it properly .
: param protocol : pickling protocol to use , python - pickle for details .
"""
if isinstance ( f , str ) :
with open ( f , ' w ' ) as f :
cPickle . dump ( self , f , protocol )
else :
cPickle . dump ( self , f , protocol )
def copy ( self ) :
""" Returns a (deep) copy of the current model """
return copy . deepcopy ( self )
def __getstate__ ( self ) :
if self . _has_get_set_state ( ) :
return self . getstate ( )
return self . __dict__
def __setstate__ ( self , state ) :
if self . _has_get_set_state ( ) :
self . setstate ( state ) # set state
#self._set_params(self._get_params()) # restore all values
return
self . __dict__ = state
def _has_get_set_state ( self ) :
return ' getstate ' in vars ( self . __class__ ) and ' setstate ' in vars ( self . __class__ )
def getstate ( self ) :
"""
Get the current state of the class ,
here just all the indices , rest can get recomputed
For inheriting from Parameterized :
Allways append the state of the inherited object
and call down to the inherited object in setstate ! !
"""
2013-10-22 13:39:58 +01:00
return [
self . _fixes_ ,
2013-10-16 21:08:35 +01:00
self . _constraints_ ,
2013-10-22 13:39:58 +01:00
self . _priors_ ,
2013-10-16 21:08:35 +01:00
self . _parameters_ ,
2013-10-25 15:29:04 +01:00
self . _name ,
self . gradient_mapping ,
2013-11-06 11:40:54 +00:00
self . _added_names_ ,
2013-10-16 21:08:35 +01:00
]
2013-10-22 13:39:58 +01:00
2013-10-16 21:08:35 +01:00
def setstate ( self , state ) :
2013-11-06 11:40:54 +00:00
self . _added_names_ = state . pop ( )
2013-10-25 15:29:04 +01:00
self . gradient_mapping = state . pop ( ) ,
self . _name = state . pop ( )
2013-10-16 21:08:35 +01:00
self . _parameters_ = state . pop ( )
self . _connect_parameters ( )
self . _priors = state . pop ( )
self . _constraints_ = state . pop ( )
2013-10-22 13:39:58 +01:00
self . _fixes_ = state . pop ( )
2013-10-16 21:08:35 +01:00
self . parameters_changed ( )
2013-10-15 09:01:03 +01:00
#===========================================================================
2013-10-25 15:29:04 +01:00
# Gradient control
#===========================================================================
def _transform_gradients ( self , g ) :
if self . has_parent ( ) :
return g
x = self . _get_params ( )
#g = g.copy()
#for constraint, index in self.constraints.iteritems():
# if constraint != __fixed__:
# g[index] = g[index] * constraint.gradfactor(x[index])
[ numpy . put ( g , i , g [ i ] * c . gradfactor ( x [ i ] ) ) for c , i in self . constraints . iteritems ( ) if c != __fixed__ ]
#[np.put(g, i, v) for i, v in [(t[0], np.sum(g[t])) for t in self.tied_indices]]
for p in self . flattened_parameters :
for t , i in p . _tied_to_me_ . iteritems ( ) :
g [ self . _offset_for ( p ) + numpy . array ( list ( i ) ) ] + = g [ self . _raveled_index_for ( t ) ]
#[g[self._offset_for(t) + numpy.array(list(i))].__iadd__(v) for i, v in [[i, g[self._raveled_index_for(p)].sum()] for p in self.flattened_parameters for t,i in p._tied_to_me_.iteritems()]]
# if len(self.tied_indices) or len(self.fixed_indices):
# to_remove = np.hstack((self.fixed_indices + [t[1:] for t in self.tied_indices]))
# return np.delete(g, to_remove)
# else:
if self . _fixes_ is not None : return g [ self . _fixes_ ]
return g
#===========================================================================
2013-10-15 09:01:03 +01:00
# Optimization handles:
#===========================================================================
2013-10-22 13:39:58 +01:00
def _get_param_names_transformed ( self ) :
2013-10-25 15:29:04 +01:00
n = numpy . array ( [ p . name_hirarchical + ' [ ' + str ( i ) + ' ] ' for p in self . flattened_parameters for i in p . _indices ( ) ] )
if self . _fixes_ is not None :
return n [ self . _fixes_ ]
return n
2013-10-15 09:01:03 +01:00
def _get_params ( self ) :
2013-10-16 21:08:35 +01:00
# don't overwrite this anymore!
return numpy . hstack ( [ x . _get_params ( ) for x in self . _parameters_ ] ) #numpy.fromiter(itertools.chain(*itertools.imap(lambda x: x._get_params(), self._parameters_)), dtype=numpy.float64, count=sum(self._parameter_sizes_))
2013-11-06 11:40:54 +00:00
def _set_params ( self , params , update = True ) :
2013-10-16 21:08:35 +01:00
# don't overwrite this anymore!
2013-11-06 11:40:54 +00:00
[ p . _set_params ( params [ s ] , update = update ) for p , s in itertools . izip ( self . _parameters_ , self . _param_slices_ ) ]
2013-10-16 21:08:35 +01:00
self . parameters_changed ( )
2013-01-18 13:37:17 +00:00
def _get_params_transformed ( self ) :
2013-10-15 09:01:03 +01:00
p = self . _get_params ( )
2013-10-25 15:29:04 +01:00
[ numpy . put ( p , ind , c . finv ( p [ ind ] ) ) for c , ind in self . constraints . iteritems ( ) if c != __fixed__ ]
2013-10-22 13:39:58 +01:00
if self . _fixes_ is not None :
return p [ self . _fixes_ ]
2013-10-15 09:01:03 +01:00
return p
def _set_params_transformed ( self , p ) :
2013-10-22 16:16:54 +01:00
p = p . copy ( )
2013-10-22 13:39:58 +01:00
if self . _fixes_ is not None : tmp = self . _get_params ( ) ; tmp [ self . _fixes_ ] = p ; p = tmp ; del tmp
2013-10-25 15:29:04 +01:00
[ numpy . put ( p , ind , c . f ( p [ ind ] ) ) for c , ind in self . constraints . iteritems ( ) if c != __fixed__ ]
2013-10-15 09:01:03 +01:00
self . _set_params ( p )
2013-10-16 21:08:35 +01:00
def _name_changed ( self , param , old_name ) :
2013-11-06 11:40:54 +00:00
if hasattr ( self , old_name ) and old_name in self . _added_names_ :
2013-10-16 21:08:35 +01:00
delattr ( self , old_name )
2013-11-06 11:40:54 +00:00
self . _added_names_ . remove ( old_name )
pname = _adjust_name_for_printing ( param . name )
if pname not in self . __dict__ :
self . _added_names_ . add ( pname )
self . __dict__ [ pname ] = param
2013-10-15 09:01:03 +01:00
#===========================================================================
# Index Handling
#===========================================================================
def _backtranslate_index ( self , param , ind ) :
# translate an index in parameterized indexing into the index of param
2013-10-22 13:39:58 +01:00
ind = ind - self . _offset_for ( param )
2013-10-15 09:01:03 +01:00
ind = ind [ ind > = 0 ]
2013-10-16 21:08:35 +01:00
internal_offset = param . _internal_offset ( )
2013-10-15 09:01:03 +01:00
ind = ind [ ind < param . size + internal_offset ]
return ind
2013-10-22 13:39:58 +01:00
def _offset_for ( self , param ) :
2013-10-15 09:01:03 +01:00
# get the offset in the parameterized index array for param
2013-10-25 15:29:04 +01:00
if param . _direct_parent_ . _get_original ( param ) in self . _parameters_ :
return self . _param_slices_ [ param . _direct_parent_ . _get_original ( param ) . _parent_index_ ] . start
if param . has_parent ( ) :
return self . _offset_for ( param . _direct_parent_ ) + param . _direct_parent_ . _offset_for ( param )
return 0
2013-10-17 14:33:41 +01:00
def _raveled_index_for ( self , param ) :
2013-10-22 13:39:58 +01:00
return param . _raveled_index ( ) + self . _offset_for ( param )
2013-10-15 09:01:03 +01:00
#===========================================================================
# Handle ties:
#===========================================================================
2013-10-17 20:47:41 +01:00
def _set_fixed ( self , param_or_index ) :
2013-10-25 15:29:04 +01:00
if self . _fixes_ is None : self . _fixes_ = numpy . ones ( self . size , dtype = bool )
2013-10-17 20:47:41 +01:00
try :
param_or_index = self . _raveled_index_for ( param_or_index )
except AttributeError :
2013-10-18 16:20:01 +01:00
pass
2013-10-22 13:39:58 +01:00
self . _fixes_ [ param_or_index ] = FIXED
if numpy . all ( self . _fixes_ ) : self . _fixes_ = None # ==UNFIXED
2013-10-17 20:47:41 +01:00
def _set_unfixed ( self , param_or_index ) :
2013-10-25 15:29:04 +01:00
if self . _fixes_ is None : self . _fixes_ = numpy . ones ( self . size , dtype = bool )
2013-10-17 20:47:41 +01:00
try :
param_or_index = self . _raveled_index_for ( param_or_index )
except AttributeError :
2013-10-18 16:20:01 +01:00
pass
2013-10-22 13:39:58 +01:00
self . _fixes_ [ param_or_index ] = UNFIXED
if numpy . all ( self . _fixes_ ) : self . _fixes_ = None # ==UNFIXED
2013-10-17 20:47:41 +01:00
# 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
2013-10-22 13:39:58 +01:00
# f, _ = self._fixes_.add(param, tied_to)
2013-10-25 15:29:04 +01:00
# if self._fixes_ is None: self._fixes_ = numpy.ones(self.size, dtype=bool)
2013-10-22 13:39:58 +01:00
# self._fixes_[f] = False
2013-10-17 20:47:41 +01:00
# 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:
2013-10-22 13:39:58 +01:00
# params = self._fixes_.properties()
2013-10-17 20:47:41 +01:00
# for p in params:
2013-10-22 13:39:58 +01:00
# _, t = self._fixes_.remove(param, p)
# self._fixes_[t] = True
# if numpy.all(self._fixes_): self._fixes_ = None # ==UNFIXED
2013-10-17 20:47:41 +01:00
# def _ties_iter_items(self, param):
2013-10-22 13:39:58 +01:00
# for tied_to, ind in self._fixes_.iter_from_items():
2013-10-17 20:47:41 +01:00
# 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):
2013-10-22 13:39:58 +01:00
# return self._fixes_.from_to_for(rav_index+self._offset_for(param))
2013-10-17 14:33:41 +01:00
#===========================================================================
2013-10-15 09:01:03 +01:00
# Fixing parameters:
#===========================================================================
def _fix ( self , param , warning = True ) :
2013-10-17 14:33:41 +01:00
f = self . _add_constrain ( param , __fixed__ , warning )
2013-10-17 20:47:41 +01:00
self . _set_fixed ( f )
2013-10-15 09:01:03 +01:00
def _unfix ( self , param ) :
2013-10-22 13:39:58 +01:00
if self . _fixes_ is not None :
2013-10-17 20:47:41 +01:00
f = self . _remove_constrain ( param , __fixed__ )
self . _set_unfixed ( f )
2013-10-17 14:33:41 +01:00
#===========================================================================
# Convenience for fixed, tied checking of parameter:
#===========================================================================
def _is_fixed ( self , param ) :
# returns if the whole parameter is fixed
2013-10-22 13:39:58 +01:00
if self . _fixes_ is None :
2013-10-17 14:33:41 +01:00
return False
2013-10-22 13:39:58 +01:00
return not self . _fixes_ [ self . _offset_for ( param ) : self . _offset_for ( param ) + param . _realsize_ ] . any ( )
2013-10-25 15:29:04 +01:00
@property
def is_fixed ( self ) :
for p in self . _parameters_ :
if not p . is_fixed : return False
return True
2013-10-17 14:33:41 +01:00
def _get_original ( self , param ) :
# if advanced indexing is activated it happens that the array is a copy
# you can retrieve the original parameter through this method, by passing
# the copy here
return self . _parameters_ [ param . _parent_index_ ]
2013-10-25 15:29:04 +01:00
def hirarchy_name ( self ) :
if self . has_parent ( ) :
2013-11-06 15:15:13 +00:00
return self . _direct_parent_ . hirarchy_name ( ) + _adjust_name_for_printing ( self . name ) + " . "
2013-10-25 15:29:04 +01:00
return ' '
2013-10-15 09:01:03 +01:00
#===========================================================================
# Constraint Handling:
#===========================================================================
def _add_constrain ( self , param , transform , warning = True ) :
2013-10-17 14:33:41 +01:00
rav_i = self . _raveled_index_for ( param )
reconstrained = self . _remove_constrain ( param , index = rav_i ) # remove constraints before
2013-10-22 13:39:58 +01:00
# if removing constraints before adding new is not wanted, just delete the above line!
2013-10-25 15:29:04 +01:00
self . constraints . add ( transform , rav_i )
2013-10-15 09:01:03 +01:00
if warning and any ( reconstrained ) :
# if you want to print the whole params object, which was reconstrained use:
# m = str(param[self._backtranslate_index(param, reconstrained)])
2013-10-16 21:08:35 +01:00
print " Warning: re-constraining parameters: \n {} " . format ( param . _short ( ) )
2013-10-17 14:33:41 +01:00
return rav_i
def _remove_constrain ( self , param , * transforms , * * kwargs ) :
2013-10-22 16:16:54 +01:00
if not transforms :
2013-10-25 15:29:04 +01:00
transforms = self . constraints . properties ( )
2013-10-15 09:01:03 +01:00
removed_indices = numpy . array ( [ ] ) . astype ( int )
2013-10-17 14:33:41 +01:00
if " index " in kwargs : index = kwargs [ ' index ' ]
else : index = self . _raveled_index_for ( param )
2013-10-15 09:01:03 +01:00
for constr in transforms :
2013-10-25 15:29:04 +01:00
removed = self . constraints . remove ( constr , index )
2013-10-22 16:16:54 +01:00
if constr is __fixed__ :
self . _set_unfixed ( removed )
2013-10-15 09:01:03 +01:00
removed_indices = numpy . union1d ( removed_indices , removed )
return removed_indices
# convienience for iterating over items
def _constraints_iter_items ( self , param ) :
2013-10-25 15:29:04 +01:00
for constr , ind in self . constraints . iteritems ( ) :
2013-10-15 09:01:03 +01:00
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 ) :
2013-10-25 15:29:04 +01:00
return self . _backtranslate_index ( param , self . constraints [ constraint ] )
2013-10-17 14:33:41 +01:00
def _constraints_for ( self , param , rav_index ) :
2013-10-25 15:29:04 +01:00
return self . constraints . properties_for ( rav_index + self . _offset_for ( param ) )
2013-10-15 09:01:03 +01:00
#===========================================================================
# Get/set parameters:
#===========================================================================
def grep_param_names ( self , regexp ) :
2012-11-29 16:25:27 +00:00
"""
2013-10-15 09:01:03 +01:00
create a list of parameters , matching regular expression regexp
2012-11-29 16:25:27 +00:00
"""
2013-10-15 09:01:03 +01:00
if not isinstance ( regexp , _pattern_type ) : regexp = compile ( regexp )
2013-10-25 15:29:04 +01:00
found_params = [ ]
for p in self . _parameters_ :
if regexp . match ( p . name ) is not None :
found_params . append ( p )
if isinstance ( p , Parameterized ) :
found_params . extend ( p . grep_param_names ( regexp ) )
return found_params
2013-10-16 21:08:35 +01:00
return [ param for param in self . _parameters_ if regexp . match ( param . name ) is not None ]
2013-10-15 09:01:03 +01:00
def __getitem__ ( self , name , paramlist = None ) :
if paramlist is None :
paramlist = self . grep_param_names ( name )
if len ( paramlist ) < 1 : raise AttributeError , name
2013-11-06 15:15:13 +00:00
if len ( paramlist ) == 1 :
if isinstance ( paramlist [ - 1 ] , Parameterized ) :
paramlist = paramlist [ - 1 ] . flattened_parameters
if len ( paramlist ) != 1 :
return ParamConcatenation ( paramlist )
return paramlist [ - 1 ]
2013-10-22 13:39:58 +01:00
return ParamConcatenation ( paramlist )
2013-10-15 09:01:03 +01:00
def __setitem__ ( self , name , value , paramlist = None ) :
try : param = self . __getitem__ ( name , paramlist )
except AttributeError as a : raise a
2013-10-16 21:08:35 +01:00
param [ : ] = value
2013-10-25 15:29:04 +01:00
# def __getattr__(self, name):
# return self.__getitem__(name)
2013-10-22 13:39:58 +01:00
# def __getattribute__(self, name):
# #try:
# return object.__getattribute__(self, name)
#except AttributeError:
# _, a, tb = sys.exc_info()
# try:
# return self.__getitem__(name)
# except AttributeError:
# raise AttributeError, a.message, tb
2013-10-15 09:01:03 +01:00
def __setattr__ ( self , name , val ) :
# override the default behaviour, if setting a parameter, so broadcasting can by used
2013-10-16 21:08:35 +01:00
if hasattr ( self , " _parameters_ " ) :
2013-10-15 09:01:03 +01:00
paramlist = self . grep_param_names ( name )
if len ( paramlist ) == 1 : self . __setitem__ ( name , val , paramlist ) ; return
object . __setattr__ ( self , name , val ) ;
#===========================================================================
2013-10-25 15:29:04 +01:00
# Printing:
2013-10-15 09:01:03 +01:00
#===========================================================================
2013-10-25 15:29:04 +01:00
def _parameter_names ( self , add_name = False ) :
if add_name :
2013-11-06 11:40:54 +00:00
return [ _adjust_name_for_printing ( self . name ) + " . " + xi for x in self . _parameters_ for xi in x . _parameter_names ( add_name = True ) ]
2013-10-25 15:29:04 +01:00
return [ xi for x in self . _parameters_ for xi in x . _parameter_names ( add_name = True ) ]
2013-11-06 11:40:54 +00:00
parameter_names = property ( _parameter_names , doc = " Names for all parameters handled by this parameterization object -- will add hirarchy name entries for printing " )
2013-10-15 09:01:03 +01:00
@property
2013-10-25 15:29:04 +01:00
def flattened_parameters ( self ) :
return [ xi for x in self . _parameters_ for xi in x . flattened_parameters ]
2013-10-15 09:01:03 +01:00
@property
2013-10-16 21:08:35 +01:00
def _parameter_sizes_ ( self ) :
return [ x . size for x in self . _parameters_ ]
2013-10-15 09:01:03 +01:00
@property
2013-10-25 15:29:04 +01:00
def size_transformed ( self ) :
if self . _fixes_ is not None :
return sum ( self . _fixes_ )
return self . size
2013-10-15 09:01:03 +01:00
@property
2013-10-25 15:29:04 +01:00
def parameter_shapes ( self ) :
return [ xi for x in self . _parameters_ for xi in x . parameter_shapes ]
2013-10-15 09:01:03 +01:00
@property
2013-10-25 15:29:04 +01:00
def _constraints_str ( self ) :
return [ cs for p in self . _parameters_ for cs in p . _constraints_str ]
2013-10-15 09:01:03 +01:00
@property
2013-10-25 15:29:04 +01:00
def _description_str ( self ) :
return [ xi for x in self . _parameters_ for xi in x . _description_str ]
2013-10-15 09:01:03 +01:00
@property
2013-10-25 15:29:04 +01:00
def _ties_str ( self ) :
return [ xi for x in self . _parameters_ for xi in x . _ties_str ]
2013-10-15 09:01:03 +01:00
def __str__ ( self , header = True ) :
2013-10-25 15:29:04 +01:00
constrs = self . _constraints_str ; ts = self . _ties_str
desc = self . _description_str ; names = self . parameter_names
nl = max ( [ len ( str ( x ) ) for x in names + [ " Name " ] ] )
sl = max ( [ len ( str ( x ) ) for x in desc + [ " Value " ] ] )
2013-10-16 21:08:35 +01:00
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 " ] ] )
2013-10-25 15:29:04 +01:00
format_spec = " \033 [1m {{ name:< {0} s}} \033 [0;0m | {{ desc:^ {1} s}} | {{ const:^ {2} s}} | {{ t:^ {3} s}} " . format ( nl , sl , cl , tl )
to_print = [ ]
for n , d , c , t in itertools . izip ( names , desc , constrs , ts ) :
to_print . append ( format_spec . format ( name = n , desc = d , const = c , t = t ) )
#to_print = [format_spec.format(p=p, const=c, t=t) if isinstance(p, Param) else p.__str__(header=False) for p, c, t in itertools.izip(self._parameters_, constrs, ts)]
2013-10-17 14:33:41 +01:00
sep = ' - ' * ( nl + sl + cl + tl + 8 * 2 + 3 )
2013-10-15 09:01:03 +01:00
if header :
2013-10-25 15:29:04 +01:00
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
2013-10-15 09:01:03 +01:00
to_print . insert ( 0 , header )
return ' \n ' . format ( sep ) . join ( to_print )
pass
2013-10-22 13:39:58 +01:00
class Parameterized_old ( object ) :
def __init__ ( self ) :
"""
This is the base class for model and kernel . Mostly just handles tieing and constraining of parameters
"""
self . tied_indices = [ ]
self . fixed_indices = [ ]
self . fixed_values = [ ]
self . constrained_indices = [ ]
self . constraints = [ ]
def _get_params ( self ) :
raise NotImplementedError , " this needs to be implemented to use the Parameterized class "
def _set_params ( self , x ) :
raise NotImplementedError , " this needs to be implemented to use the Parameterized class "
def _get_param_names ( self ) :
raise NotImplementedError , " this needs to be implemented to use the Parameterized class "
#def _get_print_names(self):
# """ Override for which parameter_names to print out, when using print m """
# return self._get_param_names()
def pickle ( self , filename , protocol = None ) :
if protocol is None :
if self . _has_get_set_state ( ) :
protocol = 0
else :
protocol = - 1
with open ( filename , ' w ' ) as f :
cPickle . dump ( self , f , protocol )
def copy ( self ) :
""" Returns a (deep) copy of the current model """
return copy . deepcopy ( self )
def __getstate__ ( self ) :
if self . _has_get_set_state ( ) :
return self . getstate ( )
return self . __dict__
def __setstate__ ( self , state ) :
if self . _has_get_set_state ( ) :
self . setstate ( state ) # set state
self . _set_params ( self . _get_params ( ) ) # restore all values
return
self . __dict__ = state
def _has_get_set_state ( self ) :
return ' getstate ' in vars ( self . __class__ ) and ' setstate ' in vars ( self . __class__ )
def getstate ( self ) :
"""
Get the current state of the class ,
here just all the indices , rest can get recomputed
For inheriting from Parameterized :
Allways append the state of the inherited object
and call down to the inherited object in setstate ! !
"""
return [ self . tied_indices ,
self . fixed_indices ,
self . fixed_values ,
self . constrained_indices ,
self . constraints ]
def setstate ( self , state ) :
self . constraints = state . pop ( )
self . constrained_indices = state . pop ( )
self . fixed_values = state . pop ( )
self . fixed_indices = state . pop ( )
self . tied_indices = state . pop ( )
def __getitem__ ( self , regexp , return_names = False ) :
"""
Get a model parameter by name . The name is applied as a regular
expression and all parameters that match that regular expression are
returned .
"""
matches = self . grep_param_names ( regexp )
if len ( matches ) :
if return_names :
return self . _get_params ( ) [ matches ] , np . asarray ( self . _get_param_names ( ) ) [ matches ] . tolist ( )
else :
return self . _get_params ( ) [ matches ]
else :
raise AttributeError , " no parameter matches %s " % regexp
def __setitem__ ( self , name , val ) :
"""
Set model parameter ( s ) by name . The name is provided as a regular
expression . All parameters matching that regular expression are set to
the given value .
"""
matches = self . grep_param_names ( name )
if len ( matches ) :
val = np . array ( val )
assert ( val . size == 1 ) or val . size == len ( matches ) , " Shape mismatch: {} :( {} ,) " . format ( val . size , len ( matches ) )
x = self . _get_params ( )
x [ matches ] = val
self . _set_params ( x )
else :
raise AttributeError , " no parameter matches %s " % name
def tie_params ( self , regexp ) :
"""
Tie ( all ! ) parameters matching the regular expression ` regexp ` .
"""
matches = self . grep_param_names ( regexp )
assert matches . size > 0 , " need at least something to tie together "
if len ( self . tied_indices ) :
assert not np . any ( matches [ : , None ] == np . hstack ( self . tied_indices ) ) , " Some indices are already tied! "
self . tied_indices . append ( matches )
# TODO only one of the priors will be evaluated. Give a warning message if the priors are not identical
if hasattr ( self , ' prior ' ) :
pass
self . _set_params_transformed ( self . _get_params_transformed ( ) ) # sets tied parameters to single value
def untie_everything ( self ) :
""" Unties all parameters by setting tied_indices to an empty list. """
self . tied_indices = [ ]
def grep_param_names ( self , regexp , transformed = False , search = False ) :
"""
: param regexp : regular expression to select parameter parameter_names
: type regexp : re | str | int
: rtype : the indices of self . _get_param_names which match the regular expression .
Note : -
Other objects are passed through - i . e . integers which weren ' t meant for grepping
"""
if transformed :
parameter_names = self . _get_param_names_transformed ( )
else :
parameter_names = self . _get_param_names ( )
if type ( regexp ) in [ str , np . string_ , np . str ] :
regexp = re . compile ( regexp )
elif type ( regexp ) is re . _pattern_type :
pass
else :
return regexp
if search :
return np . nonzero ( [ regexp . search ( name ) for name in parameter_names ] ) [ 0 ]
else :
return np . nonzero ( [ regexp . match ( name ) for name in parameter_names ] ) [ 0 ]
def num_params_transformed ( self ) :
removed = 0
for tie in self . tied_indices :
removed + = tie . size - 1
for fix in self . fixed_indices :
removed + = fix . size
return len ( self . _get_params ( ) ) - removed
def unconstrain ( self , regexp ) :
""" Unconstrain matching parameters. Does not untie parameters """
matches = self . grep_param_names ( regexp )
# tranformed contraints:
for match in matches :
self . constrained_indices = [ i [ i < > match ] for i in self . constrained_indices ]
# remove empty constraints
tmp = zip ( * [ ( i , t ) for i , t in zip ( self . constrained_indices , self . constraints ) if len ( i ) ] )
if tmp :
self . constrained_indices , self . constraints = zip ( * [ ( i , t ) for i , t in zip ( self . constrained_indices , self . constraints ) if len ( i ) ] )
self . constrained_indices , self . constraints = list ( self . constrained_indices ) , list ( self . constraints )
# fixed:
self . fixed_values = [ np . delete ( values , np . nonzero ( np . sum ( indices [ : , None ] == matches [ None , : ] , 1 ) ) [ 0 ] ) for indices , values in zip ( self . fixed_indices , self . fixed_values ) ]
self . fixed_indices = [ np . delete ( indices , np . nonzero ( np . sum ( indices [ : , None ] == matches [ None , : ] , 1 ) ) [ 0 ] ) for indices in self . fixed_indices ]
# remove empty elements
tmp = [ ( i , v ) for i , v in zip ( self . fixed_indices , self . fixed_values ) if len ( i ) ]
if tmp :
self . fixed_indices , self . fixed_values = zip ( * tmp )
self . fixed_indices , self . fixed_values = list ( self . fixed_indices ) , list ( self . fixed_values )
else :
self . fixed_indices , self . fixed_values = [ ] , [ ]
def constrain_negative ( self , regexp , warning = True ) :
""" Set negative constraints. """
self . constrain ( regexp , transformations . NegativeLogexp ( ) , warning )
def constrain_positive ( self , regexp , warning = True ) :
""" Set positive constraints. """
self . constrain ( regexp , transformations . Logexp ( ) , warning )
def constrain_bounded ( self , regexp , lower , upper , warning = True ) :
""" Set bounded constraints. """
self . constrain ( regexp , transformations . Logistic ( lower , upper ) , warning )
def all_constrained_indices ( self ) :
if len ( self . constrained_indices ) or len ( self . fixed_indices ) :
return np . hstack ( self . constrained_indices + self . fixed_indices )
else :
return np . empty ( shape = ( 0 , ) )
def constrain ( self , regexp , transform , warning = True ) :
assert isinstance ( transform , transformations . Transformation )
matches = self . grep_param_names ( regexp )
overlap = set ( matches ) . intersection ( set ( self . all_constrained_indices ( ) ) )
if overlap :
self . unconstrain ( np . asarray ( list ( overlap ) ) )
if warning :
print ' Warning: re-constraining these parameters '
pn = self . _get_param_names ( )
for i in overlap :
print pn [ i ]
self . constrained_indices . append ( matches )
self . constraints . append ( transform )
x = self . _get_params ( )
x [ matches ] = transform . initialize ( x [ matches ] )
self . _set_params ( x )
def constrain_fixed ( self , regexp , value = None , warning = True ) :
"""
: param regexp : which parameters need to be fixed .
: type regexp : ndarray ( dtype = int ) or regular expression object or string
: param value : the vlaue to fix the parameters to . If the value is not specified ,
the parameter is fixed to the current value
: type value : float
* * Notes * *
Fixing a parameter which is tied to another , or constrained in some way will result in an error .
To fix multiple parameters to the same value , simply pass a regular expression which matches both parameter parameter_names , or pass both of the indexes .
"""
matches = self . grep_param_names ( regexp )
overlap = set ( matches ) . intersection ( set ( self . all_constrained_indices ( ) ) )
if overlap :
self . unconstrain ( np . asarray ( list ( overlap ) ) )
if warning :
print ' Warning: re-constraining these parameters '
pn = self . _get_param_names ( )
for i in overlap :
print pn [ i ]
self . fixed_indices . append ( matches )
if value != None :
self . fixed_values . append ( value )
else :
self . fixed_values . append ( self . _get_params ( ) [ self . fixed_indices [ - 1 ] ] )
# self.fixed_values.append(value)
self . _set_params_transformed ( self . _get_params_transformed ( ) )
def _get_params_transformed ( self ) :
""" use self._get_params to get the ' true ' parameters of the model, which are then tied, constrained and fixed """
x = self . _get_params ( )
[ np . put ( x , i , t . finv ( x [ i ] ) ) for i , t in zip ( self . constrained_indices , self . constraints ) ]
to_remove = self . fixed_indices + [ t [ 1 : ] for t in self . tied_indices ]
if len ( to_remove ) :
return np . delete ( x , np . hstack ( to_remove ) )
else :
return x
def _set_params_transformed ( self , x ) :
""" takes the vector x, which is then modified (by untying, reparameterising or inserting fixed values), and then call self._set_params """
self . _set_params ( self . _untransform_params ( x ) )
def _untransform_params ( self , x ) :
"""
The Transformation required for _set_params_transformed .
This moves the vector x seen by the optimiser ( unconstrained ) to the
valid parameter vector seen by the model
Note :
- This function is separate from _set_params_transformed for downstream flexibility
"""
# work out how many places are fixed, and where they are. tricky logic!
fix_places = self . fixed_indices + [ t [ 1 : ] for t in self . tied_indices ]
if len ( fix_places ) :
fix_places = np . hstack ( fix_places )
Nfix_places = fix_places . size
else :
Nfix_places = 0
free_places = np . setdiff1d ( np . arange ( Nfix_places + x . size , dtype = np . int ) , fix_places )
# put the models values in the vector xx
xx = np . zeros ( Nfix_places + free_places . size , dtype = np . float64 )
xx [ free_places ] = x
[ np . put ( xx , i , v ) for i , v in zip ( self . fixed_indices , self . fixed_values ) ]
[ np . put ( xx , i , v ) for i , v in [ ( t [ 1 : ] , xx [ t [ 0 ] ] ) for t in self . tied_indices ] ]
[ np . put ( xx , i , t . f ( xx [ i ] ) ) for i , t in zip ( self . constrained_indices , self . constraints ) ]
if hasattr ( self , ' debug ' ) :
stop # @UndefinedVariable
return xx
def _get_param_names_transformed ( self ) :
"""
Returns the parameter parameter_names as propagated after constraining ,
tying or fixing , i . e . a list of the same length as _get_params_transformed ( )
"""
n = self . _get_param_names ( )
# remove/concatenate the tied parameter parameter_names
if len ( self . tied_indices ) :
for t in self . tied_indices :
n [ t [ 0 ] ] = " <tie> " . join ( [ n [ tt ] for tt in t ] )
remove = np . hstack ( [ t [ 1 : ] for t in self . tied_indices ] )
else :
remove = np . empty ( shape = ( 0 , ) , dtype = np . int )
# also remove the fixed params
if len ( self . fixed_indices ) :
remove = np . hstack ( ( remove , np . hstack ( self . fixed_indices ) ) )
# add markers to show that some variables are constrained
for i , t in zip ( self . constrained_indices , self . constraints ) :
for ii in i :
n [ ii ] = n [ ii ] + t . __str__ ( )
n = [ nn for i , nn in enumerate ( n ) if not i in remove ]
return n
#@property
#def all(self):
# return self.__str__(self._get_param_names())
#def __str__(self, parameter_names=None, nw=30):
def __str__ ( self , nw = 30 ) :
"""
Return a string describing the parameter parameter_names and their ties and constraints
"""
parameter_names = self . _get_param_names ( )
#if parameter_names is None:
# parameter_names = self._get_print_names()
#name_indices = self.grep_param_names("|".join(parameter_names))
N = len ( parameter_names )
if not N :
return " This object has no free parameters. "
header = [ ' Name ' , ' Value ' , ' Constraints ' , ' Ties ' ]
values = self . _get_params ( ) # map(str,self._get_params())
#values = self._get_params()[name_indices] # map(str,self._get_params())
# sort out the constraints
constraints = [ ' ' ] * len ( parameter_names )
#constraints = [''] * len(self._get_param_names())
for i , t in zip ( self . constrained_indices , self . constraints ) :
for ii in i :
constraints [ ii ] = t . __str__ ( )
for i in self . fixed_indices :
for ii in i :
constraints [ ii ] = ' Fixed '
# sort out the ties
ties = [ ' ' ] * len ( parameter_names )
for i , tie in enumerate ( self . tied_indices ) :
for j in tie :
ties [ j ] = ' ( ' + str ( i ) + ' ) '
if values . size == 1 :
values = [ ' %.4f ' % float ( values ) ]
else :
values = [ ' %.4f ' % float ( v ) for v in values ]
max_names = max ( [ len ( parameter_names [ i ] ) for i in range ( len ( parameter_names ) ) ] + [ len ( header [ 0 ] ) ] )
max_values = max ( [ len ( values [ i ] ) for i in range ( len ( values ) ) ] + [ len ( header [ 1 ] ) ] )
max_constraint = max ( [ len ( constraints [ i ] ) for i in range ( len ( constraints ) ) ] + [ len ( header [ 2 ] ) ] )
max_ties = max ( [ len ( ties [ i ] ) for i in range ( len ( ties ) ) ] + [ len ( header [ 3 ] ) ] )
cols = np . array ( [ max_names , max_values , max_constraint , max_ties ] ) + 4
# columns = cols.sum()
header_string = [ " { h:^ {col} } " . format ( h = header [ i ] , col = cols [ i ] ) for i in range ( len ( cols ) ) ]
header_string = map ( lambda x : ' | ' . join ( x ) , [ header_string ] )
separator = ' - ' * len ( header_string [ 0 ] )
param_string = [ " { n:^ {c0} }| { v:^ {c1} }| { c:^ {c2} }| { t:^ {c3} } " . format ( n = parameter_names [ i ] , v = values [ i ] , c = constraints [ i ] , t = ties [ i ] , c0 = cols [ 0 ] , c1 = cols [ 1 ] , c2 = cols [ 2 ] , c3 = cols [ 3 ] ) for i in range ( len ( values ) ) ]
return ( ' \n ' . join ( [ header_string [ 0 ] , separator ] + param_string ) ) + ' \n '
def grep_model ( self , regexp ) :
regexp_indices = self . grep_param_names ( regexp )
all_names = self . _get_param_names ( )
parameter_names = [ all_names [ pj ] for pj in regexp_indices ]
N = len ( parameter_names )
if not N :
return " Match not found. "
header = [ ' Name ' , ' Value ' , ' Constraints ' , ' Ties ' ]
all_values = self . _get_params ( )
values = np . array ( [ all_values [ pj ] for pj in regexp_indices ] )
constraints = [ ' ' ] * len ( parameter_names )
_constrained_indices , aux = self . _pick_elements ( regexp_indices , self . constrained_indices )
_constraints_ = [ self . constraints [ pj ] for pj in aux ]
for i , t in zip ( _constrained_indices , _constraints_ ) :
for ii in i :
iii = regexp_indices . tolist ( ) . index ( ii )
constraints [ iii ] = t . __str__ ( )
_fixed_indices , aux = self . _pick_elements ( regexp_indices , self . fixed_indices )
for i in _fixed_indices :
for ii in i :
iii = regexp_indices . tolist ( ) . index ( ii )
constraints [ ii ] = ' Fixed '
_tied_indices , aux = self . _pick_elements ( regexp_indices , self . tied_indices )
ties = [ ' ' ] * len ( parameter_names )
for i , ti in zip ( _tied_indices , aux ) :
for ii in i :
iii = regexp_indices . tolist ( ) . index ( ii )
ties [ iii ] = ' ( ' + str ( ti ) + ' ) '
if values . size == 1 :
values = [ ' %.4f ' % float ( values ) ]
else :
values = [ ' %.4f ' % float ( v ) for v in values ]
max_names = max ( [ len ( parameter_names [ i ] ) for i in range ( len ( parameter_names ) ) ] + [ len ( header [ 0 ] ) ] )
max_values = max ( [ len ( values [ i ] ) for i in range ( len ( values ) ) ] + [ len ( header [ 1 ] ) ] )
max_constraint = max ( [ len ( constraints [ i ] ) for i in range ( len ( constraints ) ) ] + [ len ( header [ 2 ] ) ] )
max_ties = max ( [ len ( ties [ i ] ) for i in range ( len ( ties ) ) ] + [ len ( header [ 3 ] ) ] )
cols = np . array ( [ max_names , max_values , max_constraint , max_ties ] ) + 4
header_string = [ " { h:^ {col} } " . format ( h = header [ i ] , col = cols [ i ] ) for i in range ( len ( cols ) ) ]
header_string = map ( lambda x : ' | ' . join ( x ) , [ header_string ] )
separator = ' - ' * len ( header_string [ 0 ] )
param_string = [ " { n:^ {c0} }| { v:^ {c1} }| { c:^ {c2} }| { t:^ {c3} } " . format ( n = parameter_names [ i ] , v = values [ i ] , c = constraints [ i ] , t = ties [ i ] , c0 = cols [ 0 ] , c1 = cols [ 1 ] , c2 = cols [ 2 ] , c3 = cols [ 3 ] ) for i in range ( len ( values ) ) ]
print header_string [ 0 ]
print separator
for string in param_string :
print string
def _pick_elements ( self , regexp_ind , array_list ) :
""" Removes from array_list the elements different from regexp_ind """
new_array_list = [ ] #New list with elements matching regexp_ind
array_indices = [ ] #Indices that matches the arrays in new_array_list and array_list
array_index = 0
for array in array_list :
_new = [ ]
for ai in array :
if ai in regexp_ind :
_new . append ( ai )
if len ( _new ) :
new_array_list . append ( np . array ( _new ) )
array_indices . append ( array_index )
array_index + = 1
return new_array_list , array_indices