Usage for Python#

General information#

PDFO provides a Python function pdfo, which can solve general constrained or unconstrained optimization problems without using derivatives.

The pdfo function can automatically identify the type of your problem and then call one of Powell’s solvers, namely COBYLA, UOBYQA, NEWUOA, BOBYQA, and LINCOA. The user can also specify the solver by setting the method argument of pdfo.

Attention

The pdfo method does not accept any 'solver' option. If you want to specify which solver to use, please use the method argument of the pdfo function.

The pdfo function is designed to be compatible with the scipy.optimize.minimize function of SciPy. You can call pdfo in exactly the same way as calling scipy.optimize.minimize except that pdfo does not accept derivative arguments.

For detailed syntax of pdfo, see Python API documentation.

An example#

The following code illustrates how to minimize the chained Rosenbrock function

(1)#\[f(x) = \sum_{i = 1}^2 4 (x_{i+1} - x_i^2)^2 + (1 - x_i)^2\]

subject to various constraints.

import numpy as np
from pdfo import pdfo
from scipy.optimize import Bounds, LinearConstraint, NonlinearConstraint


def chrosen(x):
    """Objective function"""
    return sum(4 * (x[1:] - x[:-1] ** 2) ** 2 + (1 - x[:-1]) ** 2)


def con_ineq(x):
    """Nonlinear inequality constraints"""
    return x[:-1] ** 2 - x[1:]


def con_eq(x):
    """Nonlinear equality constraints"""
    return sum(x ** 2) - 1


if __name__ == '__main__':
    print('\nMinimize the chained Rosenbrock function with three variables subject to various constraints:\n')
    x0 = [0, 0, 0]  # starting point

    print('\n1. Nonlinear constraints --- ||x||_2^2 = 1, x(i)^2 >= x(i+1) >= 0.5*x(i) >= 0 for i = 1, 2:\n')
    lb = [0, 0, 0]
    ub = [np.inf, np.inf, np.inf]
    bounds = Bounds(lb, ub)  # lb <= x <= ub
    # Alternative formulation:
    # bounds = [(lb[0], ub[0]), (lb[1], ub[1]), (lb[2], ub[2])]
    A = [[0.5, -1, 0], [0, 0.5, -1]]
    lin_lb = [-np.inf, -np.inf]
    lin_ub = [0, 0]
    lin_con = LinearConstraint(A, lin_lb, lin_ub)  # lin_lb <= A*x <= lin_ub
    nonlin_lb = [0, 0]
    nonlin_ub = [np.inf, np.inf]
    nonlin_con_ineq = NonlinearConstraint(con_ineq, nonlin_lb, nonlin_ub)  # nonlin_lb <= con_ineq(x) <= nonlin_ub
    nonlin_con_eq = NonlinearConstraint(con_eq, 0, 0)  # con_eq(x) = 0
    # Alternative formulation:
    # nonlin_con_ineq = {'type': 'ineq', 'fun': con_ineq}  # con_ineq(x) >= 0
    # nonlin_con_eq = {'type': 'eq', 'fun': con_eq}  # con_eq(x) = 0
    res = pdfo(chrosen, x0, bounds=bounds, constraints=[lin_con, nonlin_con_ineq, nonlin_con_eq])
    print(res)

    print('\n2. Linear constraints --- sum(x) = 1, x(i+1) <= x(i) <= 1 for i = 1, 2:\n')
    bounds = Bounds([-np.inf, -np.inf, -np.inf], [1, 1, 1])
    A = [[-1, 1, 0], [0, -1, 1], [1, 1, 1]]
    lin_con = LinearConstraint(A, [-np.inf, -np.inf, 1], [0, 0, 1])
    res = pdfo(chrosen, x0, bounds=bounds, constraints=lin_con)
    print(res)

    print('\n3. Bound constraints --- -0.5 <= x(1) <= 0.5, 0 <= x(2) <= 0.25:\n')
    bounds = Bounds([-0.5, 0, -np.inf], [0.5, 0.25, np.inf])
    res = pdfo(chrosen, x0, bounds=bounds)
    print(res)

    print('\n4. No constraints:\n')
    res = pdfo(chrosen, x0)
    print(res)