Exemple #1
0
def minimize(func,
             x0,
             gradient=None,
             hessian=None,
             algorithm="default",
             **args):
    r"""
    This function is an interface to a variety of algorithms for computing
    the minimum of a function of several variables.


    INPUT:

    - ``func`` -- Either a symbolic function or a Python function whose
      argument is a tuple with `n` components

    - ``x0`` -- Initial point for finding minimum.

    - ``gradient`` -- Optional gradient function. This will be computed
      automatically for symbolic functions.  For Python functions, it allows
      the use of algorithms requiring derivatives.  It should accept a
      tuple of arguments and return a NumPy array containing the partial
      derivatives at that point.

    - ``hessian`` --  Optional hessian function. This will be computed
      automatically for symbolic functions. For Python functions, it allows
      the use of algorithms requiring derivatives. It should accept a tuple
      of arguments and return a NumPy array containing the second partial
      derivatives of the function.

    - ``algorithm`` -- String specifying algorithm to use. Options are
      ``'default'`` (for Python functions, the simplex method is the default)
      (for symbolic functions bfgs is the default):

       - ``'simplex'``

       - ``'powell'``

       - ``'bfgs'`` -- (Broyden-Fletcher-Goldfarb-Shanno) requires
         ``gradient``

       - ``'cg'`` -- (conjugate-gradient) requires gradient

       - ``'ncg'`` -- (newton-conjugate gradient) requires gradient and hessian


    EXAMPLES::

        sage: vars=var('x y z')
        sage: f=100*(y-x^2)^2+(1-x)^2+100*(z-y^2)^2+(1-y)^2
        sage: minimize(f,[.1,.3,.4],disp=0)
        (1.00..., 1.00..., 1.00...)

        sage: minimize(f,[.1,.3,.4],algorithm="ncg",disp=0)
        (0.9999999..., 0.999999..., 0.999999...)

    Same example with just Python functions::

        sage: def rosen(x): # The Rosenbrock function
        ...      return sum(100.0r*(x[1r:]-x[:-1r]**2.0r)**2.0r + (1r-x[:-1r])**2.0r)
        sage: minimize(rosen,[.1,.3,.4],disp=0)
        (1.00..., 1.00..., 1.00...)

    Same example with a pure Python function and a Python function to
    compute the gradient::

        sage: def rosen(x): # The Rosenbrock function
        ...      return sum(100.0r*(x[1r:]-x[:-1r]**2.0r)**2.0r + (1r-x[:-1r])**2.0r)
        sage: import numpy
        sage: from numpy import zeros
        sage: def rosen_der(x):
        ...      xm = x[1r:-1r]
        ...      xm_m1 = x[:-2r]
        ...      xm_p1 = x[2r:]
        ...      der = zeros(x.shape,dtype=float)
        ...      der[1r:-1r] = 200r*(xm-xm_m1**2r) - 400r*(xm_p1 - xm**2r)*xm - 2r*(1r-xm)
        ...      der[0] = -400r*x[0r]*(x[1r]-x[0r]**2r) - 2r*(1r-x[0])
        ...      der[-1] = 200r*(x[-1r]-x[-2r]**2r)
        ...      return der
        sage: minimize(rosen,[.1,.3,.4],gradient=rosen_der,algorithm="bfgs",disp=0)
        (1.00...,  1.00..., 1.00...)
    """
    from sage.symbolic.expression import Expression
    from sage.ext.fast_eval import fast_callable
    import scipy
    from scipy import optimize
    if isinstance(func, Expression):
        var_list = func.variables()
        var_names = map(str, var_list)
        fast_f = fast_callable(func, vars=var_names, domain=float)
        f = lambda p: fast_f(*p)
        gradient_list = func.gradient()
        fast_gradient_functions = [
            fast_callable(gradient_list[i], vars=var_names, domain=float)
            for i in xrange(len(gradient_list))
        ]
        gradient = lambda p: scipy.array(
            [a(*p) for a in fast_gradient_functions])
    else:
        f = func

    if algorithm == "default":
        if gradient == None:
            min = optimize.fmin(f, map(float, x0), **args)
        else:
            min = optimize.fmin_bfgs(f,
                                     map(float, x0),
                                     fprime=gradient,
                                     **args)
    else:
        if algorithm == "simplex":
            min = optimize.fmin(f, map(float, x0), **args)
        elif algorithm == "bfgs":
            min = optimize.fmin_bfgs(f,
                                     map(float, x0),
                                     fprime=gradient,
                                     **args)
        elif algorithm == "cg":
            min = optimize.fmin_cg(f, map(float, x0), fprime=gradient, **args)
        elif algorithm == "powell":
            min = optimize.fmin_powell(f, map(float, x0), **args)
        elif algorithm == "ncg":
            if isinstance(func, Expression):
                hess = func.hessian()
                hess_fast = [[
                    fast_callable(a, vars=var_names, domain=float) for a in row
                ] for row in hess]
                hessian = lambda p: [[a(*p) for a in row] for row in hess_fast]
                hessian_p = lambda p, v: scipy.dot(scipy.array(hessian(p)), v)
                min = optimize.fmin_ncg(f,
                                        map(float, x0),
                                        fprime=gradient,
                                        fhess=hessian,
                                        fhess_p=hessian_p,
                                        **args)
    return vector(RDF, min)
Exemple #2
0
def minimize(func,x0,gradient=None,hessian=None,algorithm="default",**args):
    r"""
    This function is an interface to a variety of algorithms for computing
    the minimum of a function of several variables.


    INPUT:

    - ``func`` -- Either a symbolic function or a Python function whose
      argument is a tuple with `n` components

    - ``x0`` -- Initial point for finding minimum.

    - ``gradient`` -- Optional gradient function. This will be computed
      automatically for symbolic functions.  For Python functions, it allows
      the use of algorithms requiring derivatives.  It should accept a
      tuple of arguments and return a NumPy array containing the partial
      derivatives at that point.

    - ``hessian`` --  Optional hessian function. This will be computed
      automatically for symbolic functions. For Python functions, it allows
      the use of algorithms requiring derivatives. It should accept a tuple
      of arguments and return a NumPy array containing the second partial
      derivatives of the function.

    - ``algorithm`` -- String specifying algorithm to use. Options are
      ``'default'`` (for Python functions, the simplex method is the default)
      (for symbolic functions bfgs is the default):

       - ``'simplex'``

       - ``'powell'``

       - ``'bfgs'`` -- (Broyden-Fletcher-Goldfarb-Shanno) requires
         ``gradient``

       - ``'cg'`` -- (conjugate-gradient) requires gradient

       - ``'ncg'`` -- (newton-conjugate gradient) requires gradient and hessian


    EXAMPLES::

        sage: vars=var('x y z')
        sage: f=100*(y-x^2)^2+(1-x)^2+100*(z-y^2)^2+(1-y)^2
        sage: minimize(f,[.1,.3,.4],disp=0)
        (1.00..., 1.00..., 1.00...)

        sage: minimize(f,[.1,.3,.4],algorithm="ncg",disp=0)
        (0.9999999..., 0.999999..., 0.999999...)

    Same example with just Python functions::

        sage: def rosen(x): # The Rosenbrock function
        ...      return sum(100.0r*(x[1r:]-x[:-1r]**2.0r)**2.0r + (1r-x[:-1r])**2.0r)
        sage: minimize(rosen,[.1,.3,.4],disp=0)
        (1.00..., 1.00..., 1.00...)

    Same example with a pure Python function and a Python function to
    compute the gradient::

        sage: def rosen(x): # The Rosenbrock function
        ...      return sum(100.0r*(x[1r:]-x[:-1r]**2.0r)**2.0r + (1r-x[:-1r])**2.0r)
        sage: import numpy
        sage: from numpy import zeros
        sage: def rosen_der(x):
        ...      xm = x[1r:-1r]
        ...      xm_m1 = x[:-2r]
        ...      xm_p1 = x[2r:]
        ...      der = zeros(x.shape,dtype=float)
        ...      der[1r:-1r] = 200r*(xm-xm_m1**2r) - 400r*(xm_p1 - xm**2r)*xm - 2r*(1r-xm)
        ...      der[0] = -400r*x[0r]*(x[1r]-x[0r]**2r) - 2r*(1r-x[0])
        ...      der[-1] = 200r*(x[-1r]-x[-2r]**2r)
        ...      return der
        sage: minimize(rosen,[.1,.3,.4],gradient=rosen_der,algorithm="bfgs",disp=0)
        (1.00...,  1.00..., 1.00...)
    """
    from sage.symbolic.expression import Expression
    from sage.ext.fast_eval import fast_callable
    import scipy
    from scipy import optimize
    if isinstance(func, Expression):
        var_list=func.variables()
        var_names=map(str,var_list)
        fast_f=fast_callable(func, vars=var_names, domain=float)
        f=lambda p: fast_f(*p)
        gradient_list=func.gradient()
        fast_gradient_functions=[fast_callable(gradient_list[i], vars=var_names, domain=float)  for i in xrange(len(gradient_list))]
        gradient=lambda p: scipy.array([ a(*p) for a in fast_gradient_functions])
    else:
        f=func

    if algorithm=="default":
        if gradient==None:
            min=optimize.fmin(f,map(float,x0),**args)
        else:
            min= optimize.fmin_bfgs(f,map(float,x0),fprime=gradient,**args)
    else:
        if algorithm=="simplex":
            min= optimize.fmin(f,map(float,x0),**args)
        elif algorithm=="bfgs":
            min= optimize.fmin_bfgs(f,map(float,x0),fprime=gradient,**args)
        elif algorithm=="cg":
            min= optimize.fmin_cg(f,map(float,x0),fprime=gradient,**args)
        elif algorithm=="powell":
            min= optimize.fmin_powell(f,map(float,x0),**args)
        elif algorithm=="ncg":
            if isinstance(func, Expression):
                hess=func.hessian()
                hess_fast= [ [fast_callable(a, vars=var_names, domain=float) for a in row] for row in hess]
                hessian=lambda p: [[a(*p) for a in row] for row in hess_fast]
                hessian_p=lambda p,v: scipy.dot(scipy.array(hessian(p)),v)
                min= optimize.fmin_ncg(f,map(float,x0),fprime=gradient,fhess=hessian,fhess_p=hessian_p,**args)
    return vector(RDF,min)
Exemple #3
0
def minimize(func,
             x0,
             gradient=None,
             hessian=None,
             algorithm="default",
             verbose=False,
             **args):
    r"""
    This function is an interface to a variety of algorithms for computing
    the minimum of a function of several variables.

    INPUT:

    - ``func`` -- Either a symbolic function or a Python function whose
      argument is a tuple with `n` components

    - ``x0`` -- Initial point for finding minimum.

    - ``gradient`` -- Optional gradient function. This will be computed
      automatically for symbolic functions.  For Python functions, it allows
      the use of algorithms requiring derivatives.  It should accept a
      tuple of arguments and return a NumPy array containing the partial
      derivatives at that point.

    - ``hessian`` --  Optional hessian function. This will be computed
      automatically for symbolic functions. For Python functions, it allows
      the use of algorithms requiring derivatives. It should accept a tuple
      of arguments and return a NumPy array containing the second partial
      derivatives of the function.

    - ``algorithm`` -- String specifying algorithm to use. Options are
      ``'default'`` (for Python functions, the simplex method is the default)
      (for symbolic functions bfgs is the default):

       - ``'simplex'`` -- using the downhill simplex algorithm

       - ``'powell'`` -- use the modified Powell algorithm

       - ``'bfgs'`` -- (Broyden-Fletcher-Goldfarb-Shanno) requires gradient

       - ``'cg'`` -- (conjugate-gradient) requires gradient

       - ``'ncg'`` -- (newton-conjugate gradient) requires gradient and hessian

    - ``verbose`` -- (optional, default: False) print convergence message

    .. NOTE::

        For additional information on the algorithms implemented in this function,
        consult SciPy's `documentation on optimization and root
        finding <https://docs.scipy.org/doc/scipy/reference/optimize.html>`_

    EXAMPLES:

    Minimize a fourth order polynomial in three variables (see the
    :wikipedia:`Rosenbrock_function`)::

        sage: vars = var('x y z')
        sage: f = 100*(y-x^2)^2+(1-x)^2+100*(z-y^2)^2+(1-y)^2
        sage: minimize(f, [.1,.3,.4]) # abs tol 1e-6
        (1.0, 1.0, 1.0)

    Try the newton-conjugate gradient method; the gradient and hessian are 
    computed automatically::

        sage: minimize(f, [.1, .3, .4], algorithm="ncg") # abs tol 1e-6
        (1.0, 1.0, 1.0)

    We get additional convergence information with the `verbose` option::

        sage: minimize(f, [.1, .3, .4], algorithm="ncg", verbose=True)
        Optimization terminated successfully.
        ...
        (0.9999999..., 0.999999..., 0.999999...)

    Same example with just Python functions::

        sage: def rosen(x): # The Rosenbrock function
        ....:    return sum(100.0r*(x[1r:]-x[:-1r]**2.0r)**2.0r + (1r-x[:-1r])**2.0r)
        sage: minimize(rosen, [.1,.3,.4]) # abs tol 3e-5
        (1.0, 1.0, 1.0)

    Same example with a pure Python function and a Python function to
    compute the gradient::

        sage: def rosen(x): # The Rosenbrock function
        ....:    return sum(100.0r*(x[1r:]-x[:-1r]**2.0r)**2.0r + (1r-x[:-1r])**2.0r)
        sage: import numpy
        sage: from numpy import zeros
        sage: def rosen_der(x):
        ....:    xm = x[1r:-1r]
        ....:    xm_m1 = x[:-2r]
        ....:    xm_p1 = x[2r:]
        ....:    der = zeros(x.shape, dtype=float)
        ....:    der[1r:-1r] = 200r*(xm-xm_m1**2r) - 400r*(xm_p1 - xm**2r)*xm - 2r*(1r-xm)
        ....:    der[0] = -400r*x[0r]*(x[1r]-x[0r]**2r) - 2r*(1r-x[0])
        ....:    der[-1] = 200r*(x[-1r]-x[-2r]**2r)
        ....:    return der
        sage: minimize(rosen, [.1,.3,.4], gradient=rosen_der, algorithm="bfgs") # abs tol 1e-6
        (1.0, 1.0, 1.0)
    """
    from sage.symbolic.expression import Expression
    from sage.ext.fast_eval import fast_callable
    import numpy
    from scipy import optimize
    if isinstance(func, Expression):
        var_list = func.variables()
        var_names = [str(_) for _ in var_list]
        fast_f = fast_callable(func, vars=var_names, domain=float)
        f = lambda p: fast_f(*p)
        gradient_list = func.gradient()
        fast_gradient_functions = [
            fast_callable(gradient_list[i], vars=var_names, domain=float)
            for i in range(len(gradient_list))
        ]
        gradient = lambda p: numpy.array(
            [a(*p) for a in fast_gradient_functions])
    else:
        f = func

    if algorithm == "default":
        if gradient is None:
            min = optimize.fmin(f, [float(_) for _ in x0],
                                disp=verbose,
                                **args)
        else:
            min = optimize.fmin_bfgs(f, [float(_) for _ in x0],
                                     fprime=gradient,
                                     disp=verbose,
                                     **args)
    else:
        if algorithm == "simplex":
            min = optimize.fmin(f, [float(_) for _ in x0],
                                disp=verbose,
                                **args)
        elif algorithm == "bfgs":
            min = optimize.fmin_bfgs(f, [float(_) for _ in x0],
                                     fprime=gradient,
                                     disp=verbose,
                                     **args)
        elif algorithm == "cg":
            min = optimize.fmin_cg(f, [float(_) for _ in x0],
                                   fprime=gradient,
                                   disp=verbose,
                                   **args)
        elif algorithm == "powell":
            min = optimize.fmin_powell(f, [float(_) for _ in x0],
                                       disp=verbose,
                                       **args)
        elif algorithm == "ncg":
            if isinstance(func, Expression):
                hess = func.hessian()
                hess_fast = [[
                    fast_callable(a, vars=var_names, domain=float) for a in row
                ] for row in hess]
                hessian = lambda p: [[a(*p) for a in row] for row in hess_fast]
                hessian_p = lambda p, v: scipy.dot(numpy.array(hessian(p)), v)
                min = optimize.fmin_ncg(f, [float(_) for _ in x0], fprime=gradient, \
                      fhess=hessian, fhess_p=hessian_p, disp=verbose, **args)
    return vector(RDF, min)
Exemple #4
0
def minimize(func, x0, gradient=None, hessian=None, algorithm="default", \
             verbose=False, **args):
    r"""
    This function is an interface to a variety of algorithms for computing
    the minimum of a function of several variables.

    INPUT:

    - ``func`` -- Either a symbolic function or a Python function whose
      argument is a tuple with `n` components

    - ``x0`` -- Initial point for finding minimum.

    - ``gradient`` -- Optional gradient function. This will be computed
      automatically for symbolic functions.  For Python functions, it allows
      the use of algorithms requiring derivatives.  It should accept a
      tuple of arguments and return a NumPy array containing the partial
      derivatives at that point.

    - ``hessian`` --  Optional hessian function. This will be computed
      automatically for symbolic functions. For Python functions, it allows
      the use of algorithms requiring derivatives. It should accept a tuple
      of arguments and return a NumPy array containing the second partial
      derivatives of the function.

    - ``algorithm`` -- String specifying algorithm to use. Options are
      ``'default'`` (for Python functions, the simplex method is the default)
      (for symbolic functions bfgs is the default):

       - ``'simplex'`` -- using the downhill simplex algorithm

       - ``'powell'`` -- use the modified Powell algorithm

       - ``'bfgs'`` -- (Broyden-Fletcher-Goldfarb-Shanno) requires gradient

       - ``'cg'`` -- (conjugate-gradient) requires gradient

       - ``'ncg'`` -- (newton-conjugate gradient) requires gradient and hessian

    - ``verbose`` -- (optional, default: False) print convergence message

    .. NOTE::

        For additional information on the algorithms implemented in this function,
        consult SciPy's `documentation on optimization and root
        finding <https://docs.scipy.org/doc/scipy/reference/optimize.html>`_

    EXAMPLES:

    Minimize a fourth order polynomial in three variables (see the
    :wikipedia:`Rosenbrock_function`)::

        sage: vars = var('x y z')
        sage: f = 100*(y-x^2)^2+(1-x)^2+100*(z-y^2)^2+(1-y)^2
        sage: minimize(f, [.1,.3,.4]) # abs tol 1e-6
        (1.0, 1.0, 1.0)

    Try the newton-conjugate gradient method; the gradient and hessian are 
    computed automatically::

        sage: minimize(f, [.1, .3, .4], algorithm="ncg") # abs tol 1e-6
        (1.0, 1.0, 1.0)

    We get additional convergence information with the `verbose` option::

        sage: minimize(f, [.1, .3, .4], algorithm="ncg", verbose=True)
        Optimization terminated successfully.
        ...
        (0.9999999..., 0.999999..., 0.999999...)

    Same example with just Python functions::

        sage: def rosen(x): # The Rosenbrock function
        ....:    return sum(100.0r*(x[1r:]-x[:-1r]**2.0r)**2.0r + (1r-x[:-1r])**2.0r)
        sage: minimize(rosen, [.1,.3,.4]) # abs tol 3e-5
        (1.0, 1.0, 1.0)

    Same example with a pure Python function and a Python function to
    compute the gradient::

        sage: def rosen(x): # The Rosenbrock function
        ....:    return sum(100.0r*(x[1r:]-x[:-1r]**2.0r)**2.0r + (1r-x[:-1r])**2.0r)
        sage: import numpy
        sage: from numpy import zeros
        sage: def rosen_der(x):
        ....:    xm = x[1r:-1r]
        ....:    xm_m1 = x[:-2r]
        ....:    xm_p1 = x[2r:]
        ....:    der = zeros(x.shape, dtype=float)
        ....:    der[1r:-1r] = 200r*(xm-xm_m1**2r) - 400r*(xm_p1 - xm**2r)*xm - 2r*(1r-xm)
        ....:    der[0] = -400r*x[0r]*(x[1r]-x[0r]**2r) - 2r*(1r-x[0])
        ....:    der[-1] = 200r*(x[-1r]-x[-2r]**2r)
        ....:    return der
        sage: minimize(rosen, [.1,.3,.4], gradient=rosen_der, algorithm="bfgs") # abs tol 1e-6
        (1.0, 1.0, 1.0)
    """
    from sage.symbolic.expression import Expression
    from sage.ext.fast_eval import fast_callable
    import scipy
    from scipy import optimize
    if isinstance(func, Expression):
        var_list=func.variables()
        var_names = [str(_) for _ in var_list]
        fast_f=fast_callable(func, vars=var_names, domain=float)
        f=lambda p: fast_f(*p)
        gradient_list=func.gradient()
        fast_gradient_functions=[fast_callable(gradient_list[i], vars=var_names, domain=float)  for i in range(len(gradient_list))]
        gradient=lambda p: scipy.array([ a(*p) for a in fast_gradient_functions])
    else:
        f=func

    if algorithm=="default":
        if gradient is None:
            min = optimize.fmin(f, [float(_) for _ in x0], disp=verbose, **args)
        else:
            min= optimize.fmin_bfgs(f, [float(_) for _ in x0],fprime=gradient, disp=verbose, **args)
    else:
        if algorithm=="simplex":
            min= optimize.fmin(f, [float(_) for _ in x0], disp=verbose, **args)
        elif algorithm=="bfgs":
            min= optimize.fmin_bfgs(f, [float(_) for _ in x0], fprime=gradient, disp=verbose, **args)
        elif algorithm=="cg":
            min= optimize.fmin_cg(f, [float(_) for _ in x0], fprime=gradient, disp=verbose, **args)
        elif algorithm=="powell":
            min= optimize.fmin_powell(f, [float(_) for _ in x0], disp=verbose, **args)
        elif algorithm=="ncg":
            if isinstance(func, Expression):
                hess=func.hessian()
                hess_fast= [ [fast_callable(a, vars=var_names, domain=float) for a in row] for row in hess]
                hessian=lambda p: [[a(*p) for a in row] for row in hess_fast]
                hessian_p=lambda p,v: scipy.dot(scipy.array(hessian(p)),v)
                min = optimize.fmin_ncg(f, [float(_) for _ in x0], fprime=gradient, \
                      fhess=hessian, fhess_p=hessian_p, disp=verbose, **args)
    return vector(RDF, min)