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]])}