def bounded_mean(mean_x, samples, xmin, xmax, wts=None): from mystic.math.measures import impose_mean, impose_spread from mystic.math.measures import spread, mean from numpy import asarray a = impose_mean(mean_x, samples, wts) if min(a) < xmin: # maintain the bound #print "violate lo(a)" s = spread(a) - 2*(xmin - min(a)) #XXX: needs compensation (as below) ? a = impose_mean(mean_x, impose_spread(s, samples, wts), wts) if max(a) > xmax: # maintain the bound #print "violate hi(a)" s = spread(a) + 2*(xmax - max(a)) #XXX: needs compensation (as below) ? a = impose_mean(mean_x, impose_spread(s, samples, wts), wts) return asarray(a)
def test_constrain(): from mystic.math.measures import mean, spread from mystic.math.measures import impose_mean, impose_spread def mean_constraint(x, mean=0.0): return impose_mean(mean, x) def range_constraint(x, spread=1.0): return impose_spread(spread, x) @inner(inner=range_constraint, kwds={'spread': 5.0}) @inner(inner=mean_constraint, kwds={'mean': 5.0}) def constraints(x): return x def cost(x): return abs(sum(x) - 5.0) from mystic.solvers import fmin_powell from numpy import array x = array([1, 2, 3, 4, 5]) y = fmin_powell(cost, x, constraints=constraints, disp=False) assert mean(y) == 5.0 assert spread(y) == 5.0 assert almostEqual(cost(y), 4 * (5.0))
def test_inner_solver(nested, solver): from mystic.monitors import Monitor evalmon = Monitor() stepmon = Monitor() from mystic.math.measures import mean, spread @with_spread(5.0) @with_mean(5.0) def constraints(x): return x def cost(x): return abs(sum(x) - 5.0) from numpy import array solver = solver(5) lb, ub = [0, 0, 0, 0, 0], [100, 100, 100, 100, 100] solver.SetRandomInitialPoints(lb, ub) solver.SetConstraints(constraints) solver.SetStrictRanges(lb, ub) nested = nested(5, 4) nested.SetEvaluationMonitor(evalmon) nested.SetGenerationMonitor(stepmon) nested.SetNestedSolver(solver) nested.Solve(cost, disp=False) y = nested.Solution() assert almostEqual(mean(y), 5.0, tol=1e-15) assert almostEqual(spread(y), 5.0, tol=1e-15) assert almostEqual(cost(y), 4 * (5.0), tol=1e-6)
def test_multi_liner(solver): from mystic.monitors import Monitor evalmon = Monitor() stepmon = Monitor() from mystic.math.measures import mean, spread @with_spread(5.0) @with_mean(5.0) def constraints(x): return x def cost(x): return abs(sum(x) - 5.0) from numpy import array x = array([1, 2, 3, 4, 5]) solver = solver(len(x)) solver.SetInitialPoints(x) solver.SetEvaluationMonitor(evalmon) solver.SetGenerationMonitor(stepmon) solver.SetConstraints(constraints) solver.Solve(cost, disp=False) y = solver.Solution() assert almostEqual(mean(y), 5.0, tol=1e-15) assert almostEqual(spread(y), 5.0, tol=1e-15) assert almostEqual(cost(y), 4 * (5.0), tol=1e-6)
def test_inner_solver(nested, solver): from mystic.monitors import Monitor evalmon = Monitor() stepmon = Monitor() from mystic.math.measures import mean, spread @with_spread(5.0) @with_mean(5.0) def constraints(x): return x def cost(x): return abs(sum(x) - 5.0) from numpy import array solver = solver(5) lb,ub = [0,0,0,0,0],[100,100,100,100,100] solver.SetRandomInitialPoints(lb, ub) solver.SetConstraints(constraints) solver.SetStrictRanges(lb, ub) nested = nested(5, 4) nested.SetEvaluationMonitor(evalmon) nested.SetGenerationMonitor(stepmon) nested.SetNestedSolver(solver) nested.Solve(cost, disp=False) y = nested.Solution() assert almostEqual(mean(y), 5.0, tol=1e-15) assert almostEqual(spread(y), 5.0, tol=1e-15) assert almostEqual(cost(y), 4*(5.0), tol=1e-6)
def test_nested_solver(nested, solver): from mystic.monitors import Monitor evalmon = Monitor() stepmon = Monitor() from mystic.math.measures import mean, spread @with_spread(5.0) @with_mean(5.0) def constraints(x): return x def cost(x): return abs(sum(x) - 5.0) from numpy import array nested = nested(5, 4) nested.SetEvaluationMonitor(evalmon) nested.SetGenerationMonitor(stepmon) nested.SetConstraints(constraints) nested.SetNestedSolver(solver) nested.Solve(cost, disp=False) y = nested.Solution() assert almostEqual(mean(y), 5.0, tol=1e-15) assert almostEqual(spread(y), 5.0, tol=1e-15) assert almostEqual(cost(y), 4*(5.0), tol=1e-6)
def test_multi_liner(solver): from mystic.monitors import Monitor evalmon = Monitor() stepmon = Monitor() from mystic.math.measures import mean, spread @with_spread(5.0) @with_mean(5.0) def constraints(x): return x def cost(x): return abs(sum(x) - 5.0) from numpy import array x = array([1,2,3,4,5]) solver = solver(len(x)) solver.SetInitialPoints(x) solver.SetEvaluationMonitor(evalmon) solver.SetGenerationMonitor(stepmon) solver.SetConstraints(constraints) solver.Solve(cost, disp=False) y = solver.Solution() assert almostEqual(mean(y), 5.0, tol=1e-15) assert almostEqual(spread(y), 5.0, tol=1e-15) assert almostEqual(cost(y), 4*(5.0), tol=1e-6)
def test_nested_solver(nested, solver): from mystic.monitors import Monitor evalmon = Monitor() stepmon = Monitor() from mystic.math.measures import mean, spread @with_spread(5.0) @with_mean(5.0) def constraints(x): return x def cost(x): return abs(sum(x) - 5.0) from numpy import array nested = nested(5, 4) nested.SetEvaluationMonitor(evalmon) nested.SetGenerationMonitor(stepmon) nested.SetConstraints(constraints) nested.SetNestedSolver(solver) nested.Solve(cost, disp=False) y = nested.Solution() assert almostEqual(mean(y), 5.0, tol=1e-15) assert almostEqual(spread(y), 5.0, tol=1e-15) assert almostEqual(cost(y), 4 * (5.0), tol=1e-6)
def test_penalize(): from mystic.math.measures import mean, spread def mean_constraint(x, target): return mean(x) - target def range_constraint(x, target): return spread(x) - target @quadratic_equality(condition=range_constraint, kwds={'target': 5.0}) @quadratic_equality(condition=mean_constraint, kwds={'target': 5.0}) def penalty(x): return 0.0 def cost(x): return abs(sum(x) - 5.0) from mystic.solvers import fmin from numpy import array x = array([1, 2, 3, 4, 5]) y = fmin(cost, x, penalty=penalty, disp=False) assert round(mean(y)) == 5.0 assert round(spread(y)) == 5.0 assert round(cost(y)) == 4 * (5.0)
def test_penalize(): from mystic.math.measures import mean, spread def mean_constraint(x, target): return mean(x) - target def range_constraint(x, target): return spread(x) - target @quadratic_equality(condition=range_constraint, kwds={'target':5.0}) @quadratic_equality(condition=mean_constraint, kwds={'target':5.0}) def penalty(x): return 0.0 def cost(x): return abs(sum(x) - 5.0) from mystic.solvers import fmin from numpy import array x = array([1,2,3,4,5]) y = fmin(cost, x, penalty=penalty, disp=False) assert round(mean(y)) == 5.0 assert round(spread(y)) == 5.0 assert round(cost(y)) == 4*(5.0)
def test_constrain(): from mystic.math.measures import mean, spread from mystic.math.measures import impose_mean, impose_spread def mean_constraint(x, mean=0.0): return impose_mean(mean, x) def range_constraint(x, spread=1.0): return impose_spread(spread, x) @inner(inner=range_constraint, kwds={'spread':5.0}) @inner(inner=mean_constraint, kwds={'mean':5.0}) def constraints(x): return x def cost(x): return abs(sum(x) - 5.0) from mystic.solvers import fmin_powell from numpy import array x = array([1,2,3,4,5]) y = fmin_powell(cost, x, constraints=constraints, disp=False) assert mean(y) == 5.0 assert spread(y) == 5.0 assert almostEqual(cost(y), 4*(5.0))
def test_generate_constraint(): constraints = """ spread([x0, x1, x2]) = 10.0 mean([x0, x1, x2]) = 5.0""" from mystic.math.measures import mean, spread solv = generate_solvers(constraints) assert almostEqual(mean(solv[0]([1, 2, 3])), 5.0) assert almostEqual(spread(solv[1]([1, 2, 3])), 10.0) constraint = generate_constraint(solv) assert almostEqual(constraint([1, 2, 3]), [0.0, 5.0, 10.0], 1e-10)
def test_generate_constraint(): constraints = """ spread([x0, x1, x2]) = 10.0 mean([x0, x1, x2]) = 5.0""" from mystic.math.measures import mean, spread solv = generate_solvers(constraints) assert almostEqual(mean(solv[0]([1,2,3])), 5.0) assert almostEqual(spread(solv[1]([1,2,3])), 10.0) constraint = generate_constraint(solv) assert almostEqual(constraint([1,2,3]), [0.0,5.0,10.0], 1e-10)
def test_solve_constraint(): constraints = """ spread([x0,x1]) - 1.0 = mean([x0,x1]) mean([x0,x1,x2]) = x2""" from mystic.math.measures import mean, spread _constraints = solve(constraints) solv = generate_solvers(_constraints) constraint = generate_constraint(solv) x = constraint([1.0, 2.0, 3.0]) assert all(x) == all([1.0, 5.0, 3.0]) assert mean(x) == x[2] assert spread(x[:-1]) - 1.0 == mean(x[:-1])
def test_as_constraint(): from mystic.math.measures import mean, spread def mean_constraint(x, target): return mean(x) - target def range_constraint(x, target): return spread(x) - target @quadratic_equality(condition=range_constraint, kwds={'target': 5.0}) @quadratic_equality(condition=mean_constraint, kwds={'target': 5.0}) def penalty(x): return 0.0 ndim = 3 constraints = as_constraint(penalty) #, solver='fmin') #XXX: this is expensive to evaluate, as there are nested optimizations from numpy import arange x = arange(ndim) _x = constraints(x) assert round(mean(_x)) == 5.0 assert round(spread(_x)) == 5.0 assert round(penalty(_x)) == 0.0 def cost(x): return abs(sum(x) - 5.0) npop = ndim * 3 from mystic.solvers import diffev y = diffev(cost, x, npop, constraints=constraints, disp=False, gtol=10) assert round(mean(y)) == 5.0 assert round(spread(y)) == 5.0 assert round(cost(y)) == 5.0 * (ndim - 1)
def test_with_mean_spread(): from mystic.math.measures import mean, spread, impose_mean, impose_spread @with_spread(50.0) @with_mean(5.0) def constrained_squared(x): return [i**2 for i in x] from numpy import array x = array([1, 2, 3, 4, 5]) y = impose_spread(50.0, impose_mean(5.0, [i**2 for i in x])) assert almostEqual(mean(y), 5.0, tol=1e-15) assert almostEqual(spread(y), 50.0, tol=1e-15) assert constrained_squared(x) == y
def test_as_constraint(): from mystic.math.measures import mean, spread def mean_constraint(x, target): return mean(x) - target def range_constraint(x, target): return spread(x) - target @quadratic_equality(condition=range_constraint, kwds={'target':5.0}) @quadratic_equality(condition=mean_constraint, kwds={'target':5.0}) def penalty(x): return 0.0 ndim = 3 constraints = as_constraint(penalty, solver='fmin') #XXX: this is expensive to evaluate, as there are nested optimizations from numpy import arange x = arange(ndim) _x = constraints(x) assert round(mean(_x)) == 5.0 assert round(spread(_x)) == 5.0 assert round(penalty(_x)) == 0.0 def cost(x): return abs(sum(x) - 5.0) npop = ndim*3 from mystic.solvers import diffev y = diffev(cost, x, npop, constraints=constraints, disp=False, gtol=10) assert round(mean(y)) == 5.0 assert round(spread(y)) == 5.0 assert round(cost(y)) == 5.0*(ndim-1)
def test_with_mean_spread(): from mystic.math.measures import mean, spread, impose_mean, impose_spread @with_spread(50.0) @with_mean(5.0) def constrained_squared(x): return [i**2 for i in x] from numpy import array x = array([1,2,3,4,5]) y = impose_spread(50.0, impose_mean(5.0,[i**2 for i in x])) assert almostEqual(mean(y), 5.0, tol=1e-15) assert almostEqual(spread(y), 50.0, tol=1e-15) assert constrained_squared(x) == y
def test_one_liner(solver): from mystic.math.measures import mean, spread @with_spread(5.0) @with_mean(5.0) def constraints(x): return x def cost(x): return abs(sum(x) - 5.0) from numpy import array x = array([1,2,3,4,5]) y = solver(cost, x, constraints=constraints, disp=False) assert almostEqual(mean(y), 5.0, tol=1e-15) assert almostEqual(spread(y), 5.0, tol=1e-15) assert almostEqual(cost(y), 4*(5.0), tol=1e-6)
def test_as_penalty(): from mystic.math.measures import mean, spread @with_spread(5.0) @with_mean(5.0) def constraint(x): return x penalty = as_penalty(constraint) from numpy import array x = array([1,2,3,4,5]) def cost(x): return abs(sum(x) - 5.0) from mystic.solvers import fmin y = fmin(cost, x, penalty=penalty, disp=False) assert round(mean(y)) == 5.0 assert round(spread(y)) == 5.0 assert round(cost(y)) == 4*(5.0)
def graphical_distance(model, points, **kwds): """find the ``radius(x')`` that minimizes the graph between reality (data), ``y = G(x)``, and an approximating function, ``y' = F(x')``. Args: model (func): a model ``y' = F(x')`` that approximates reality ``y = G(x)`` points (mystic.math.legacydata.dataset): a dataset, defines ``y = G(x)`` ytol (float, default=0.0): maximum acceptable difference ``|y - F(x')|``. xtol (float, default=0.0): maximum acceptable difference ``|x - x'|``. cutoff (float, default=ytol): zero out distances less than cutoff. hausdorff (bool, default=False): hausdorff ``norm``, where if given, then ``ytol = |y - F(x')| + |x - x'|/norm``. Returns: the radius (the minimum distance ``x,G(x)`` to ``x',F(x')`` for each ``x``) Notes: *points* can be a ``mystic.math.legacydata.dataset`` or a list of ``mystic.math.legacydata.datapoint`` objects. *xtol* defines the n-dimensional base of a pilar of height *ytol*, centered at each point. The region inside the pilar defines the space where a "valid" model must intersect. If *xtol* is not specified, then the base of the pilar will be a dirac at ``x' = x``. This function performs an optimization for each ``x`` to find an appropriate ``x'``. *ytol* is a single value, while *xtol* is a single value or an iterable. *cutoff* takes a float or a boolean, where ``cutoff=True`` will set the value of *cutoff* to the default. Typically, the value of *cutoff* is *ytol*, 0.0, or None. *hausdorff* can be False (e.g. ``norm = 1.0``), True (e.g. ``norm = spread(x)``), or a list of points of ``len(x)``. While *cutoff* and *ytol* are very tightly related, they play a distinct role; *ytol* is used to set the optimization termination for an acceptable ``|y - F(x')|``, while *cutoff* is applied post-optimization. If we are using the hausdorff norm, then *ytol* will set the optimization termination for an acceptable ``|y - F(x')| + |x - x'|/norm``, where the ``x`` values are normalized by ``norm = hausdorff``. """ #FIXME: update docs to show normalization in y #NotImplemented: #L = list of lipschitz constants, for use when lipschitz metric is desired #constraints = constraints function for finding minimum distance from mystic.math.legacydata import dataset from numpy import asarray, sum, isfinite, zeros, seterr from mystic.solvers import diffev2, fmin_powell from mystic.monitors import Monitor, VerboseMonitor # ensure target xe and ye is a dataset target = dataset() target.load(*_get_xy(points)) nyi = target.npts # y's are target.values nxi = len(target.coords[-1]) # nxi = len(x) / len(y) # NOTE: the constraints function is a function over a single xe,ye # because each underlying optimization is over a single xe,ye. # thus, we 'pass' on using constraints at this time... constraints = None # default is no constraints if 'constraints' in kwds: constraints = kwds.pop('constraints') if not constraints: # if None (default), there are no constraints constraints = lambda x: x # get tolerance in y and wiggle room in x ytol = kwds.pop('ytol', 0.0) xtol = kwds.pop('xtol', 0.0) # default is to not allow 'wiggle room' in x cutoff = ytol # default is to zero out distances less than tolerance if 'cutoff' in kwds: cutoff = kwds.pop('cutoff') if cutoff is True: cutoff = ytol elif cutoff is False: cutoff = None ipop = kwds.pop('ipop', min(20, 3*nxi)) #XXX: tune ipop? imax = kwds.pop('imax', 1000) #XXX: tune imax? # get range for the dataset (normalization for hausdorff distance) hausdorff = kwds.pop('hausdorff', False) if not hausdorff: # False, (), None, ... ptp = [0.0]*nxi yptp = 1.0 elif hausdorff is True: from mystic.math.measures import spread ptp = [spread(xi) for xi in zip(*target.coords)] yptp = spread(target.values) #XXX: this can lead to bad bad things... else: try: #iterables if len(hausdorff) < nxi+1: hausdorff = list(hausdorff) + [0.0]*(nxi - len(hausdorff)) + [1.0] ptp = hausdorff[:-1] # all the x yptp = hausdorff[-1] # just the y except TypeError: #non-iterables ptp = [hausdorff]*nxi yptp = hausdorff ######################################################################### def radius(model, point, ytol=0.0, xtol=0.0, ipop=None, imax=None): """graphical distance between a single point x,y and a model F(x')""" # given a single point x,y: find the radius = |y - F(x')| + delta # radius is just a minimization over x' of |y - F(x')| + delta # where we apply a constraints function (of box constraints) of # |x - x'| <= xtol (for each i in x) # # if hausdorff = some iterable, delta = |x - x'|/hausdorff # if hausdorff = True, delta = |x - x'|/spread(x); using the dataset range # if hausdorff = False, delta = 0.0 # # if ipop, then DE else Powell; ytol is used in VTR(ytol) # and will terminate when cost <= ytol x,y = _get_xy(point) y = asarray(y) # catch cases where yptp or y will cause issues in normalization #if not isfinite(yptp): return 0.0 #FIXME: correct? shouldn't happen #if yptp == 0: from numpy import inf; return inf #FIXME: this is bad # build the cost function if hausdorff: # distance in all directions def cost(rv): '''cost = |y - F(x')| + |x - x'| for each x,y (point in dataset)''' _y = model(rv) if not isfinite(_y): return abs(_y) errs = seterr(invalid='ignore', divide='ignore') # turn off warning z = abs((asarray(x) - rv)/ptp) # normalize by range m = abs(y - _y)/yptp # normalize by range seterr(invalid=errs['invalid'], divide=errs['divide']) # turn on warning return m + sum(z[isfinite(z)]) else: # vertical distance only def cost(rv): '''cost = |y - F(x')| for each x,y (point in dataset)''' return abs(y - model(rv)) if debug: print("rv: %s" % str(x)) print("cost: %s" % cost(x)) # if xtol=0, radius is difference in x,y and x,F(x); skip the optimization try: if not imax or not max(xtol): #iterables return cost(x) except TypeError: if not xtol: #non-iterables return cost(x) # set the range constraints xtol = asarray(xtol) bounds = list(zip( x - xtol, x + xtol )) if debug: print("lower: %s" % str(zip(*bounds)[0])) print("upper: %s" % str(zip(*bounds)[1])) # optimize where initially x' = x stepmon = Monitor() if debug: stepmon = VerboseMonitor(1) #XXX: edit settings? MINMAX = 1 #XXX: confirm MINMAX=1 is minimization ftol = ytol gtol = None # use VTRCOG if ipop: results = diffev2(cost, bounds, ipop, ftol=ftol, gtol=gtol, \ itermon = stepmon, maxiter=imax, bounds=bounds, \ full_output=1, disp=0, handler=False) else: results = fmin_powell(cost, x, ftol=ftol, gtol=gtol, \ itermon = stepmon, maxiter=imax, bounds=bounds, \ full_output=1, disp=0, handler=False) #solved = results[0] # x' func_opt = MINMAX * results[1] # cost(x') if debug: print("solved: %s" % results[0]) print("cost: %s" % func_opt) # get the minimum distance |y - F(x')| return func_opt #return results[0], func_opt ######################################################################### #XXX: better to do a single optimization rather than for each point ??? d = [radius(model, point, ytol, xtol, ipop, imax) for point in target] return infeasibility(d, cutoff)
def __range(self): from mystic.math.measures import spread return spread(self.positions)
def range_constraint(x, target): return spread(x) - target
def graphical_distance(model, points, **kwds): """find the radius(x') that minimizes the graph between reality, y = G(x), and an approximating function, y' = F(x') Inputs: model = the model function, y' = F(x'), that approximates reality, y = G(x) points = object of type 'datapoint' to validate against; defines y = G(x) Additional Inputs: ytol = maximum acceptable difference |y - F(x')|; a single value xtol = maximum acceptable difference |x - x'|; an iterable or single value cutoff = zero out distances less than cutoff; typically: ytol, 0.0, or None hausdorff = norm; where if given, ytol = |y - F(x')| + |x - x'|/norm Returns: radius = minimum distance from x,G(x) to x',F(x') for each x Notes: xtol defines the n-dimensional base of a pilar of height ytol, centered at each point. The region inside the pilar defines the space where a "valid" model must intersect. If xtol is not specified, then the base of the pilar will be a dirac at x' = x. This function performs an optimization for each x to find an appropriate x'. While cutoff and ytol are very tightly related, they play a distinct role; ytol is used to set the optimization termination for an acceptable |y - F(x')|, while cutoff is applied post-optimization. If we are using the hausdorff norm, then ytol will set the optimization termination for an acceptable |y - F(x')| + |x - x'|/norm, where the x values are normalized by norm = hausdorff. """ #FIXME: update docs to show normalization in y #NotImplemented: #L = list of lipschitz constants, for use when lipschitz metric is desired #constraints = constraints function for finding minimum distance from mystic.math.legacydata import dataset from numpy import asarray, sum, isfinite, zeros, seterr from mystic.solvers import diffev2, fmin_powell from mystic.monitors import Monitor, VerboseMonitor # ensure target xe and ye is a dataset target = dataset() target.load(*_get_xy(points)) nyi = target.npts # y's are target.values nxi = len(target.coords[-1]) # nxi = len(x) / len(y) # NOTE: the constraints function is a function over a single xe,ye # because each underlying optimization is over a single xe,ye. # thus, we 'pass' on using constraints at this time... constraints = None # default is no constraints if 'constraints' in kwds: constraints = kwds.pop('constraints') if not constraints: # if None (default), there are no constraints constraints = lambda x: x # get tolerance in y and wiggle room in x ytol = kwds.pop('ytol', 0.0) xtol = kwds.pop('xtol', 0.0) # default is to not allow 'wiggle room' in x cutoff = ytol # default is to zero out distances less than tolerance if 'cutoff' in kwds: cutoff = kwds.pop('cutoff') if cutoff is True: cutoff = ytol elif cutoff is False: cutoff = None ipop = kwds.pop('ipop', min(20, 3*nxi)) #XXX: tune ipop? imax = kwds.pop('imax', 1000) #XXX: tune imax? # get range for the dataset (normalization for hausdorff distance) hausdorff = kwds.pop('hausdorff', False) if not hausdorff: # False, (), None, ... ptp = [0.0]*nxi yptp = 1.0 elif hausdorff is True: from mystic.math.measures import spread ptp = [spread(xi) for xi in zip(*target.coords)] yptp = spread(target.values) #XXX: this can lead to bad bad things... else: try: #iterables if len(hausdorff) < nxi+1: hausdorff = list(hausdorff) + [0.0]*(nxi - len(hausdorff)) + [1.0] ptp = hausdorff[:-1] # all the x yptp = hausdorff[-1] # just the y except TypeError: #non-iterables ptp = [hausdorff]*nxi yptp = hausdorff ######################################################################### def radius(model, point, ytol=0.0, xtol=0.0, ipop=None, imax=None): """graphical distance between a single point x,y and a model F(x')""" # given a single point x,y: find the radius = |y - F(x')| + delta # radius is just a minimization over x' of |y - F(x')| + delta # where we apply a constraints function (of box constraints) of # |x - x'| <= xtol (for each i in x) # # if hausdorff = some iterable, delta = |x - x'|/hausdorff # if hausdorff = True, delta = |x - x'|/spread(x); using the dataset range # if hausdorff = False, delta = 0.0 # # if ipop, then DE else Powell; ytol is used in VTR(ytol) # and will terminate when cost <= ytol x,y = _get_xy(point) y = asarray(y) # catch cases where yptp or y will cause issues in normalization #if not isfinite(yptp): return 0.0 #FIXME: correct? shouldn't happen #if yptp == 0: from numpy import inf; return inf #FIXME: this is bad # build the cost function if hausdorff: # distance in all directions def cost(rv): '''cost = |y - F(x')| + |x - x'| for each x,y (point in dataset)''' _y = model(rv) if not isfinite(_y): return abs(_y) errs = seterr(invalid='ignore', divide='ignore') # turn off warning z = abs((asarray(x) - rv)/ptp) # normalize by range m = abs(y - _y)/yptp # normalize by range seterr(invalid=errs['invalid'], divide=errs['divide']) # turn on warning return m + sum(z[isfinite(z)]) else: # vertical distance only def cost(rv): '''cost = |y - F(x')| for each x,y (point in dataset)''' return abs(y - model(rv)) if debug: print("rv: %s" % str(x)) print("cost: %s" % cost(x)) # if xtol=0, radius is difference in x,y and x,F(x); skip the optimization try: if not imax or not max(xtol): #iterables return cost(x) except TypeError: if not xtol: #non-iterables return cost(x) # set the range constraints xtol = asarray(xtol) bounds = list(zip( x - xtol, x + xtol )) if debug: print("lower: %s" % str(zip(*bounds)[0])) print("upper: %s" % str(zip(*bounds)[1])) # optimize where initially x' = x stepmon = Monitor() if debug: stepmon = VerboseMonitor(1) #XXX: edit settings? MINMAX = 1 #XXX: confirm MINMAX=1 is minimization ftol = ytol gtol = None # use VTRCOG if ipop: results = diffev2(cost, bounds, ipop, ftol=ftol, gtol=gtol, \ itermon = stepmon, maxiter=imax, bounds=bounds, \ full_output=1, disp=0, handler=False) else: results = fmin_powell(cost, x, ftol=ftol, gtol=gtol, \ itermon = stepmon, maxiter=imax, bounds=bounds, \ full_output=1, disp=0, handler=False) #solved = results[0] # x' func_opt = MINMAX * results[1] # cost(x') if debug: print("solved: %s" % results[0]) print("cost: %s" % func_opt) # get the minimum distance |y - F(x')| return func_opt #return results[0], func_opt ######################################################################### #XXX: better to do a single optimization rather than for each point ??? d = [radius(model, point, ytol, xtol, ipop, imax) for point in target] return infeasibility(d, cutoff)