Tutorial
Here are present examples of the use of openopt
Generic framework
We will use from optimizers import *, but on everyone installation, it will most likely be from scikits.openopt.solvers.optimizers import *
Simple use of the framework
Suppose you have a simple two argumnets functions with its gradient :
>>> class Function(object): def __call__(self, x): return (x[0] - 2) ** 2 + (2 * x[1] + 4) ** 2 def gradient(self, x): return numpy.array((2 * (x[0] - 2), 4 * (2 * x[1] + 4)))
You then must import the optimizers (suppose you are in the solvers folder) :
>>> import numpy >>> from optimizers import *
Then you can optimize your function :
>>> fun = Function()
>>> mystep = step.GradientStep()
>>> mylinesearch = line_search.GoldenSectionSearch(min_alpha_step = 0.0001)
>>> mycriterion = criterion.criterion(ftol = 0.0001, iterations_max = 100)
>>> myoptimizer = optimizer.StandardOptimizer(function = fun, step = mystep, line_search = mylinesearch, criterion = mycriterion, x0 = numpy.zeros((2)))
array([ 2., -2.])
>>> myoptimizer.state
{'function': <__main__.Function object at 0xc67e0c>, 'new_parameters': array([ 2., -2.]), 'gradient': array([ 0., 0.]), 'old_value': 0.0, 'iteration': 35, 'step': array([-0., -0.]), 'step_size': 4.0856349008447342e-05, 'old_parameters': array([ 2., -2.]), 'new_value': 0.0}
You can use an inexact line search with the Wolfe Powell strong rules exactly in the same way :
>>> fun = Function()
>>> mystep = step.FRConjugateGradientStep()
>>> mylinesearch = line_search.StrongWolfePowellRule()
>>> mycriterion = criterion.criterion(ftol = 0.0001, iterations_max = 100)
>>> myoptimizer = optimizer.StandardOptimizer(function = fun, step = mystep, line_search = mylinesearch, criterion = mycriterion, x0 = numpy.zeros((2)))
>>> myoptimizer.optimize()
array([ 2., -2.])
>>> myoptimizer.state
{'function': <__main__.Function object at 0x30d26c>, 'new_parameters': array([ 2., -2.]), 'gradient': array([ 0., 0.]), 'old_value': 0.0, 'iteration': 4, 'step': array([ 0., -0.]), 'step_size': 1.0, 'old_parameters': array([ 2., -2.]), 'step_modifier': 0.0, 'new_value': 0.0}
Use of helper functions
Fitting Data
Once the fit function returns the correct result, it can be used to create a Quadratic instance (for example) that can be optimized through the framework
>>> class F1(object): def __call__(self, x, params): return params[0] + params[1] * x def gradient(self, x, params): return numpy.array((numpy.ones(len(x)), x)).T def hessian(self, x, params): return numpy.zeros((len(x), 2, 2)) >>> x = numpy.random.random_sample((10)) >>> y = 3*x+4 >>> function = helpers.Quadratic(x, y, F1()) >>> x0 = numpy.zeros(2) >>> opt = optimizer.StandardOptimizer(function = function, x0 = x0, step = step.GradientStep(), line_search = line_search.FibonacciSectionSearch(min_alpha_step=0.000001), criterion = criterion.criterion(ftol = 0.00001, iterations_max = 1000)) >>> print opt.optimize() [ 4. 3.] >>> print opt.state {'function': <optimizers.helpers.quadratic.Quadratic object at 0xe7e50c>, 'direction': array([ 5.32907052e-15, 1.22827925e-15]), 'new_parameters': array([ 4., 3.]), 'gradient': array([ -5.32907052e-15, -1.22827925e-15]), 'old_value': 2.3665827156630354e-30, 'iteration': 10, 'alpha_step': 4.5907169276693443e-07, 'old_parameters': array([ 4., 3.]), 'new_value': 2.3665827156630354e-30}
Finite Differences
Finite differences helps computing numerical gradient and/or hessian. If the gradient is provided, then the hessian will take advantage of it.
>>> class Function(helpers.ForwardFiniteElementDerivatives): def __call__(self, x): return (x[0] - 2) ** 2 + (2 * x[1] + 4) ** 2 >>> startPoint = numpy.zeros(2, numpy.float) >>> optimi = optimizer.StandardOptimizer(function = Function(), step = step.FRConjugateGradientStep(), criterion = criterion.criterion(0.0000001, 100), x0 = startPoint, line_search = line_search.StrongWolfePowellRule()) >>> print optimi.optimize() [ 2. -2.00000004] >>> print optimi.state {'function': <__main__.Function object at 0xe7e8ac>, 'direction': array([ -1.13496692e-07, -1.37756364e-08]), 'new_parameters': array([ 2. , -2.00000004]), 'gradient': array([ 9.72597028e-08, 4.72195288e-08]), 'old_value': 7.7802561238186933e-15, 'iteration': 4, 'alpha_step': 0, 'old_parameters': array([ 2. , -2.00000004]), 'step_modifier': 0.11824091630690386, 'new_value': 7.7802561238186933e-15} >>> startPoint = numpy.zeros(2, numpy.float) >>> optimi = optimizer.StandardOptimizer(function = Function(), step = step.NewtonStep(), criterion = criterion.criterion(0.0000001, 100), x0 = startPoint, line_search = line_search.SimpleLineSearch()) >>> print optimi.optimize() [ 1.99999995 -2.00000005] >>> print optimi.state {'function': <__main__.Function object at 0xe7e98c>, 'direction': array([ -1.11022304e-16, 1.11022302e-16]), 'new_parameters': array([ 1.99999995, -2.00000005]), 'gradient': array([ 2.22044608e-16, -8.88178414e-16]), 'old_value': 1.2500000047903369e-14, 'iteration': 5, 'alpha_step': 1.0, 'old_parameters': array([ 1.99999995, -2.00000005]), 'new_value': 1.250000007010783e-14, 'hessian': array([[ 2.00000000e+00, -4.73316543e-16], [ -4.73316543e-16, 7.99999998e+00]])}
