def __model(self): #XXX: deal w/ selector (2D)? ExtraArgs? # convert to 'model' format (i.e. takes a parameter vector) if self.function is None: return None from mystic.math.interpolate import _to_objective _objective = _to_objective(self.function) def objective(x, *args, **kwds): result = _objective(x, *args, **kwds) return result.tolist() if hasattr(result, 'tolist') else result objective.__doc__ = _objective.__doc__ return objective
def __set_function(self, function): #XXX: deal w/ selector (2D)? ExtraArgs? # convert to 'model' format (i.e. takes a parameter vector) from mystic.math.interpolate import _to_objective _objective = _to_objective(function) def objective(x, *args, **kwds): result = _objective(x, *args, **kwds) return result.tolist() if hasattr(result, 'tolist') else result self.objective = objective self.objective.__doc__ = function.__doc__ return
def interpolate(data, step=None, **kwds): """generate interpolated function y=f(x) from data (x,y) Inputs: data: mystic.math.legacydata.dataset of i points, M inputs, N outputs step: int, stepsize for interpolation (default: do not skip any points) Additional Inputs: method: string for kind of interpolator maxpts: int, maximum number of points (x,z) to use from the monitor noise: float, amplitude of gaussian noise to remove duplicate x extrap: if True, extrapolate a bounding box (can reduce # of nans) arrays: if True, return a numpy array; otherwise don't return arrays axis: int in [0,N], index of z on which to interpolate (all, by default) NOTE: if scipy is not installed, will use np.interp for 1D (non-rbf), or mystic's rbf otherwise. default method is 'nearest' for 1D and 'linear' otherwise. method can be one of ('rbf','linear', 'nearest','cubic','inverse','gaussian','quintic','thin_plate'). NOTE: additional keyword arguments (epsilon, smooth, norm) are avaiable for use with a Rbf interpolator. See mystic.math.interpolate.Rbf for more details. """ # interpolate for each member of tuple-valued data, unless axis provided axis = kwds.pop('axis', None) # axis for tuple-valued data if axis is None: if len(data.values) and type(data.values[0]) in (tuple, list): # iterate over each axis, build a 'combined' interpf def objective(x, axis=None): fs = objective.__axis__ if axis is None: return tuple(fi(x) for fi in fs) return fs[axis](x) objective.__axis__ = [ interpolate(data, axis=ax, **kwds) for ax, val in enumerate(data.values[0]) ] return objective # else: data is single-valued else: # axis is not None data = _getitem(data, axis) #XXX: what if dataset is empty? (i.e. len(data.values) == 0) from interpolator import interpolate as interp ii = interp(data.coords[::step], z=data.values[::step], **kwds) from mystic.math.interpolate import _to_objective function = _to_objective(ii.function) function.__axis__ = axis #XXX: bad idea: list of funcs, or int/None ? return function
def distance(data, function=None, hausdorff=True, **kwds): """get graphical distance between function y=f(x) and a dataset Inputs: data: a mystic.math.legacydata.dataset of i points, M inputs, N outputs function: a function y=f(*x) of data (x,y) hausdorff: if True, use Hausdorff norm Additional Inputs: method: string for kind of interpolator maxpts: int, maximum number of points (x,z) to use from the monitor noise: float, amplitude of gaussian noise to remove duplicate x extrap: if True, extrapolate a bounding box (can reduce # of nans) arrays: if True, return a numpy array; otherwise don't return arrays axis: int in [0,N], index of z on which to interpolate (all, by default) NOTE: if scipy is not installed, will use np.interp for 1D (non-rbf), or mystic's rbf otherwise. default method is 'nearest' for 1D and 'linear' otherwise. method can be one of ('rbf','linear', 'nearest','cubic','inverse','gaussian','quintic','thin_plate'). NOTE: data and function may provide tuple-valued or single-valued output. Distance will be measured component-wise, resulting in a tuple of distances, unless an 'axis' is selected. If an axis is selected, then return distance for the selected component (i.e. axis) only. """ """ #FIXME: the following is generally true (doesn't account for 'fax') # function is multi-value & has its components # data is multi-value # axis is None => apply function component-wise to data # axis is int => apply function component-wise to single axis # data is single-value # axis is None => ERROR: unknown which function component to apply # axis is int => apply selected function component to data # function is single-value (int or None) # data is multi-value # axis is None => ERROR: unknown which axis to apply function # axis is int => apply function to selected axis of data # data is single-value # axis is None => apply function to data # axis is int => ERROR: can't take axis of single-valued data # function is None # data is multi-value # axis is None => [fmv] => apply function component-wise to data # axis is int => [fsv] => apply function to selected axis of data # data is single-value # axis is None => [fsv] => apply function to data # axis is int => ERROR: can't take axis of single-valued data """ axis = kwds.get('axis', None) # axis for tuple-valued data and/or function if function is None: function = interpolate(data, **kwds) import mystic.math.distance as md #FIXME: simplify axis vs fax from mystic.math.interpolate import _to_objective fax = getattr(function, '__axis__', None) # axis for tuple-valued function if axis is None: if len(data.values) and type(data.values[0]) in (tuple,list): if type(fax) is list: # multi-value func, multi-value data import numpy as np return np.array([md.graphical_distance(_to_objective(j), _getitem(data, i), hausdorff=hausdorff) for i,j in enumerate(fax)]) elif type(fax) is int: # single-value func, multi-value data return md.graphical_distance(_to_objective(function), _getitem(data, fax), hausdorff=hausdorff) else: # single-value func, multi-value data msg = "axis required for multi-valued dataset.values" raise ValueError(msg) else: if type(fax) is list: # multi-value func, singe-value data msg = "axis required for multi-valued function" raise ValueError(msg) else: # single-value func, singe-value data return md.graphical_distance(_to_objective(function), data, hausdorff=hausdorff) else: if len(data.values) and type(data.values[0]) in (tuple,list): if type(fax) is list: # multi-value func, multi-value data return md.graphical_distance(_to_objective(fax[axis]), _getitem(data, axis), hausdorff=hausdorff) elif type(fax) is int and fax != axis: # single-value func, multi-value data msg = "inconsistent axis for multi-valued dataset.values" raise ValueError(msg) else: # single-value func, multi-value data return md.graphical_distance(_to_objective(function), _getitem(data, axis), hausdorff=hausdorff) else: if type(fax) is list: # multi-value func, singe-value data return md.graphical_distance(_to_objective(fax[axis]), data, hausdorff=hausdorff) elif type(fax) is int: if fax == axis: # single-value func, singe-value data return md.graphical_distance(_to_objective(function), data, hausdorff=hausdorff) msg = "inconsistent axis for multi-valued function" raise ValueError(msg) else: # single-value func, singe-value data _getitem(data, axis) # raise ValueError return NotImplemented # should never get here
""" import numpy as np x = np.random.rand(10,3) def cost(x): return sum(np.sin(x)**2) + 1 y = cost(x.T) import mystic.math.interpolate as ip fx = ip._to_function(cost) assert (fx(*x.T) - cost(x.T) ).sum() < 0.0001 f = ip.interpf(x, y, method='linear', arrays=True) cf = ip._to_objective(f) assert (f(*x.T) - cf(x.T) ).sum() < 0.0001 assert f(*x[0].T) == cf(x[0].T) assert fx(*x[0].T) == cost(x[0].T) assert ip.gradient(x, f, method='linear').shape \ == ip.gradient(x, fx, method='linear').shape from mystic.models import rosen0der as rosen y = rosen(x.T) f = ip.interpf(x, y, method='linear') fx = ip._to_function(rosen) cf = ip._to_objective(f)