The pyoptgra module

class pyoptgra.optgra(*args)

This class is a user defined algorithm (UDA) providing a wrapper around OPTGRA, which is written in Fortran.

It is specifically designed for near-linear optimization problems with many constraints. When optimizing a problem, Optgra will first move towards satisfying the constraints, then move along the feasible region boundary to optimize the merit function, fixing constraint violations as they occur.

For this, constraints and the merit function are linearized. Optgra will perform less well on very non-linear merit functions or constraints.

Example:

>>> import pygmo
>>> import pyoptgra
>>> prob = pygmo.problem(pygmo.schwefel(30))
>>> pop = pygmo.population(prob, 1)
>>> algo = pygmo.algorithm(pyoptgra.optgra())
>>> pop = algo.evolve(pop)

Initialize a wrapper instance for the OPTGRA algorithm.

Some of the construction arguments, for example the scaling factors, depend on the dimension of the problem. Passing a problem with a different dimension to the instance’s evolve function will result in an error.

Some problem-specific options are deduced from the problem in the population given to the evolve function.

Parameters:
  • max_iterations – maximum number of total iterations

  • max_correction_iterations – number of constraint correction iterations in the beginning If no feasible solution is found within that many iterations, Optgra aborts

  • max_distance_per_iteration – maximum scaled distance traveled in each iteration

  • perturbation_for_snd_order_derivatives – Used as delta for numerically computing second order errors of the constraints in the optimization step

  • variable_scaling_factors – optional - Scaling factors for the input variables. If passed, must be positive and as many as there are variables

  • variable_types – optional - Flags to set variables to either free (0) or fixed (1). Fixed variables are also called parameters in sensitivity analysis. If passed, must be as many flags as there are variables

  • constraint_priorities – optional - lower constraint priorities are fulfilled earlier. During the initial constraint correction phase, only constraints with a priority at most k are considered in iteration k. Defaults to zero, so that all constraints are considered from the beginning.

  • bounds_to_constraints – optional - if true (default), translate box bounds of the given problems into inequality constraints for optgra. Note that when also passing constraint priorities, the original constraints of the problem come first, followed by those derived from the lower box bounds, then those from the upper box bounds. Infinite bounds are ignored and not counted.

  • bound_constraints_tolerance – optional - constraint tolerance for the constraints derived from bounds

  • merit_function_threshold – optional - convergence threshold for merit function

  • force_bounds – optional - whether to force the bounds given by the problem. If false (default), the fitness function might also be called with values of x that are outside of the bounds. Set to true if the fitness function cannot handle that. If active, the gradients evaluated near the bounds will be inacurate potentially leading to convergence issues.

  • khan_bounds

    optional - whether to gracefully enforce bounds on the decision vector using Michael Khan’s method, by default False.:

    \[x = \frac{x_{max} + x_{min}}{2} + \frac{x_{max} - x_{min}}{2} \cdot \sin(x_{Khan})\]

    Where \(x\) is the pagmo decision vector and \(x_{Khan}\) is the decision vector passed to OPTGRA. In this way parameter bounds are guaranteed to be satisfied, but the gradients near the bounds approach zero. Pyoptgra uses a variant of the above method that additionally scales the argument of the \(\sin\) function such that the derivatives \(\frac{d x_{Khan}}{d x}\) are unity in the center of the box bounds. Alternatively, to a \(\sin\) function, also a \(\tanh\) or Fourier expansion of a triangle wave can be used as a Khan function. Valid input values are: True (same as ‘sin’),’sin’, ‘tanh’, ‘triangle1’, ‘triangle2’, ‘triangle3’… and False.

  • optimization_method – select 0 for steepest descent, 1 for modified spectral conjugate gradient method, 2 for spectral conjugate gradient method and 3 for conjugate gradient method

  • log_level – Control the original screen output of OPTGRA. 0 has no output, 4 and higher have maximum output`. Set this to 0 if you want to use the pygmo logging system based on set_verbosity().

Raises:
  • ValueError – if optimization_method is not one of 0, 1, 2, or 3 ValueError: if any of

  • max_iterations, max_correction_iterations, max_distance_per_iteration, – or perturbation_for_snd_order_derivatives are negative

evolve(self, population pop)

Call OPTGRA with the best-fitness member of the population as start value.

Parameters:

population – The population containing the problem and a set of initial solutions.

Returns:

The changed population.

Raises:
  • ValueError – If the population is empty

  • ValueError – If the problem contains multiple objectives

  • ValueError – If the problem is stochastic

  • ValueError – If the problem dimensions don’t fit to constraint_priorities or variable_scaling_factors that were passed to the wrapper constructor

  • ValueError – If the problem has finite box bounds and bounds_to_constraints was set to True in the wrapper constructor (default), constraint_priorities were also passed but don’t cover the additional bound-derived constraints

prepare_sensitivity(self, problem, x)

Prepare OPTGRA for sensitivity analysis at x. This is independant from previous and later calls to evolve, but enables calls to sensitivity_matrices, linear_update_new_callable and linear_update_delta on this instance.

This works by creating a linearization of the problem’s fitness function around x.

Parameters:
  • problem – The problem being analyzed. x: The value of x around which linearization is

  • performed

Raises:
  • ValueError – If the problem contains multiple objectives ValueError: If the problem is

  • stochastic ValueError – If the problem dimensions don’t fit to constraint_priorities or variable_scaling_factors that were passed to the wrapper constructor

  • ValueError – If the problem has finite box bounds and bounds_to_constraints was set to True in the wrapper constructor (default), constraint_priorities were also passed but don’t cover the additional bound-derived constraints

sensitivity_matrices(self)

Get stored sensitivity matrices prepared by earlier call to prepare_sensivitity. Note that active constraints are constraints that are currently fulfilled, but could be violated in the next iteration. Parameters refer to variables whose variable type was declared as fixed.

Returns:

a boolean list of whether each constraint is active, the sensitivity of constraints + merit function with respect to active constraints, the sensitivity of constraints + merit function with respect to parameters, the sensitivity of variables with respect to active constraints, and the sensitivity of variables with respect to parameters.

Return type:

A tuple of one list and four matrices

Raises:

RuntimeError – If prepare_sensitivity has not been called on this instance

linear_update_new_callable(self, problem)

Perform a single optimization step on the stored value of x, but with a new callable

Parameters:

problem – A problem containing the new callable. Has to have same dimensions and types as the problem passed to prepare_sensitivity

Returns:

tuple of new_x, new_y

Raises:
  • RuntimeError – If prepare_sensitivity has not been called on this instance ValueError: If

  • number or type of constraints of the new problem are different from – those of the problem passed to prepare_sensitivity

linear_update_delta(self, constraint_delta)

Perform a single optimization step on the linear approximation prepared with prepare_sensitivity. For this, no new function calls to the problem callable are performed, making this potentially very fast.

Parameters:
  • constraint_delta – A list of deltas against the constraints. They are subtracted from the

  • values. (stored)

Returns:

tuple of new_x, new_y

Raises:
  • RuntimeError – If prepare_sensitivity has not been called on this instance ValueError: If

  • number of deltas does not fit number of constraints.

The optgra C++ wrapper

std::tuple<std::vector<double>, std::vector<double>, int> optgra::optimize(const std::vector<double> &initial_x, const std::vector<int> &constraint_types, fitness_callback fitness, gradient_callback gradient, bool has_gradient, int max_iterations = 150, int max_correction_iterations = 90, double max_distance_per_iteration = 10, double perturbation_for_snd_order_derivatives = 1, std::vector<double> convergence_thresholds = {}, std::vector<double> variable_scaling_factors = {}, std::vector<int> constraint_priorities = {}, std::vector<std::string> variable_names = {}, std::vector<std::string> constraint_names = {}, int optimization_method = 2, int derivatives_computation = 1, std::vector<double> autodiff_deltas = {}, std::vector<int> variable_types = {}, int log_level = 1, int verbosity = 0)

Main C++ wrapper function.

Call optgra to optimize a problem. Most of the parameters are identical to the constructor arguments of pyoptgra, but some additional ones are available.

Parameters:
  • initial_x – the initial guess for the decision vector

  • constraint_types – types of constraints. Set 0 for equality constraints, -1 for inequality constraints that should be negative, 1 for positive inequality constraints and -2 for unenforced constraints. Last element describes the merit function, with -1 for minimization problems and 1 for maximization problems.

  • fitness – a callable for the fitness values. It is called with the current x, expected output is an array of first all equality constraints, then all inequality constraints, and last the merit function

  • gradient – a callable for the gradient values, optional. It is called with the current x, expected output is a two-dimensional array g, with g_ij being the gradient of constraint i with respect to input variable j.

  • has_gradient – whether the problem has a gradient. If set to False, the gradient callable will not be called and numerical differentiation will be used instead.

  • max_iterations – the maximum number of iterations. Optional, defaults to 150.

  • max_correction_iterations – number of constraint correction iterations in the beginning. If no feasible solution is found within that many iterations, Optgra aborts. Optional, defaults to 90.

  • max_distance_per_iteration – maximum scaled distance traveled in each iteration. Optional, defaults to 10

  • perturbation_for_snd_order_derivatives – used as delta for numerically computing second order errors of the constraints in the optimization step. Parameter VARSND in Fortran. Optional, defaults to 1

  • convergence_thresholds – tolerance a constraint can deviate and still be considered fulfilled. Constraints with lower thresholds will be prioritized during optimization. Thresholds of 0 break the optimization process.

  • variable_scaling_factors – scaling factors for the input variables. If passed, must be positive and as many as there are variables

  • constraint_priorities – filter in which to consider constraints. Lower constraint priorities are fulfilled earlier. During the initial constraint correction phase, only constraints with a priority at most k are considered in iteration k. Defaults to zero, so that all constraints are considered from the beginning.

  • variable_names – Not yet implemented

  • constraint_names – Not yet implemented

  • optimization_method – select 0 for steepest descent, 1 for modified spectral conjugate gradient method, 2 for spectral conjugate gradient method and 3 for conjugate gradient method. Parameter OPTMET in Fortran.

  • derivatives_computation – method to compute gradients. 0 is no gradient, 1 is the user-defined gradient function, 2 is a numerical gradient with double differencing, 3 a numerical gradient with single differencing. Parameter VARDER in Fortran.

  • autodiff_deltas – deltas used for each variable when computing the gradient numerically. Optional, defaults to 0.001.

  • variable_types – Optional array, specifiying 0 (normal, default) or 1 (fixed, only used for sensitivity) for each variable.

  • log_level – original OPTGRA logging output: 0 has no output, 4 and higher have maximum output. Set this to 0 if you want to use the pygmo logging system based on set_verbosity().

  • verbosity – pygmo-style logging output: 0 has no output, N means an output every Nth cost function evaluation. Set log_level to zero to use this.

Throws:

unspecified – any exception thrown by memory errors in standard containers

Returns:

a tuple of the best value of x, the fitness of that x, and a status flag of optgra

std::tuple<std::vector<int>, std::vector<std::vector<double>>, std::vector<std::vector<double>>, std::vector<std::vector<double>>, std::vector<std::vector<double>>> optgra::compute_sensitivity_matrices(const std::vector<double> &x, const std::vector<int> &constraint_types, fitness_callback fitness, gradient_callback gradient, bool has_gradient, double max_distance_per_iteration = 10, double perturbation_for_snd_order_derivatives = 1, std::vector<double> variable_scaling_factors = {}, std::vector<std::string> variable_names = {}, std::vector<std::string> constraint_names = {}, int derivatives_computation = 1, std::vector<double> autodiff_deltas = {}, std::vector<int> variable_types = {}, int log_level = 1, int verbosity = 0)

Compute sensitivity state and matrices in one go, without creating a sensitivity state tuple.

Parameters:
  • x – the decision vector around which the sensitivity analysis is to be performed

  • constraint_types – types of constraints. Set 0 for equality constraints, -1 for inequality constraints that should be negative, 1 for positive inequality constraints and -2 for unenforced constraints Last element describes the merit function, with -1 for minimization problems and 1 for maximization problems.

  • fitness – a callable for the fitness values. It is called with the current x, expected output is an array of first all equality constraints, then all inequality constraints, and last the merit function

  • gradient – a callable for the gradient values, optional. It is called with the current x, expected output is a two-dimensional array g, with g_ij being the gradient of constraint i with respect to input variable j.

  • has_gradient – whether the problem has a gradient. If set to False, the gradient callable will not be called and numerical differentiation will be used instead.

  • max_distance_per_iteration – maximum scaled distance traveled in each iteration. Optional, defaults to 10

  • perturbation_for_snd_order_derivatives – used as delta for numerically computing second order errors of the constraints in the optimization step. Parameter VARSND in Fortran. Optional, defaults to 1

  • variable_scaling_factors – scaling factors for the input variables. If passed, must be positive and as many as there are variables

  • variable_names – Not yet implemented

  • constraint_names – Not yet implemented

  • derivatives_computation – method to compute gradients. 0 is no gradient, 1 is the user-defined gradient function, 2 is a numerical gradient with double differencing, 3 a numerical gradient with single differencing. Parameter VARDER in Fortran.

  • autodiff_deltas – deltas used for each variable when computing the gradient numerically. Optional, defaults to 0.001.

  • variable_types – Optional array, specifiying 0 (normal, default) or 1 (fixed, only used for sensitivity) for each variable.

  • log_level – original OPTGRA logging output: 0 has no output, 4 and higher have maximum output

  • verbosity – pygmo-style logging output: 0 has no output, N means an output every Nth cost function evaluation

Returns:

A tuple of one list and four matrices: a boolean list of whether each constraint is active, the sensitivity of constraints + merit function with respect to active constraints, the sensitivity of constraints + merit function with respect to parameters, the sensitivity of variables with respect to active constraints, and the sensitivity of variables with respect to parameters.

std::tuple<sensitivity_state, std::vector<double>> optgra::prepare_sensitivity_state(const std::vector<double> &x, const std::vector<int> &constraint_types, fitness_callback fitness, gradient_callback gradient, bool has_gradient, double max_distance_per_iteration = 10, double perturbation_for_snd_order_derivatives = 1, std::vector<double> variable_scaling_factors = {}, int derivatives_computation = 1, std::vector<double> autodiff_deltas = {}, std::vector<int> variable_types = {}, int log_level = 1, int verbosity = 0)

Create a state tuple usable for sensitivity updates.

Parameters:
  • x – the decision vector around which the sensitivity analysis is to be performed

  • constraint_types – types of constraints. Set 0 for equality constraints, -1 for inequality constraints that should be negative, 1 for positive inequality constraints and -2 for unenforced constraints Last element describes the merit function, with -1 for minimization problems and 1 for maximization problems.

  • fitness – a callable for the fitness values. It is called with the current x, expected output is an array of first all equality constraints, then all inequality constraints, and last the merit function

  • gradient – a callable for the gradient values, optional. It is called with the current x, expected output is a two-dimensional array g, with g_ij being the gradient of constraint i with respect to input variable j.

  • has_gradient – whether the problem has a gradient. If set to False, the gradient callable will not be called and numerical differentiation will be used instead.

  • max_distance_per_iteration – maximum scaled distance traveled in each iteration. Optional, defaults to 10

  • perturbation_for_snd_order_derivatives – used as delta for numerically computing second order errors of the constraints in the optimization step. Parameter VARSND in Fortran. Optional, defaults to 1

  • variable_scaling_factors – scaling factors for the input variables. If passed, must be positive and as many as there are variables

  • derivatives_computation – method to compute gradients. 0 is no gradient, 1 is the user-defined gradient function, 2 is a numerical gradient with double differencing, 3 a numerical gradient with single differencing. Parameter VARDER in Fortran.

  • autodiff_deltas – deltas used for each variable when computing the gradient numerically. Optional, defaults to 0.001.

  • variable_types – Optional array, specifiying 0 (normal, default) or 1 (fixed, only used for sensitivity) for each variable.

  • log_level – original OPTGRA logging output: 0 has no output, 4 and higher have maximum output

  • verbosity – pygmo-style logging output: 0 has no output, N means an output every Nth cost function evaluation

Returns:

A tuple of the current sensitivity state and the x for which the sensitivity analysis was performed. It may be different from the x given as argument, if optimization steps were performed in the meantime.

std::tuple<std::vector<int>, std::vector<std::vector<double>>, std::vector<std::vector<double>>, std::vector<std::vector<double>>, std::vector<std::vector<double>>> optgra::get_sensitivity_matrices(sensitivity_state state_tuple, const std::vector<int> &variable_types, vector<int> constraint_types, double max_distance_per_iteration = 10)

Compute sensitivity matrics from a sensitivity state tuple.

std::tuple<std::vector<double>, std::vector<double>, int> optgra::sensitivity_update_new_callable(sensitivity_state state_tuple, const std::vector<int> &variable_types, const std::vector<int> &constraint_types, fitness_callback fitness, gradient_callback gradient, bool has_gradient, double max_distance_per_iteration = 10, double perturbation_for_snd_order_derivatives = 1, std::vector<double> variable_scaling_factors = {}, int derivatives_computation = 1, std::vector<double> autodiff_deltas = {}, int log_level = 1, int verbosity = 0)

Perform one optimization step with a new fitness callable, starting from the value of x that was set with prepare_sensitivity_state.

std::tuple<std::vector<double>, std::vector<double>, int> optgra::sensitivity_update_constraint_delta(sensitivity_state state_tuple, const std::vector<int> &variable_types, const std::vector<int> &constraint_types, vector<double> &delta, double max_distance_per_iteration = 10, double perturbation_for_snd_order_derivatives = 1, std::vector<double> variable_scaling_factors = {}, int log_level = 1, int verbosity = 0)

Perform an update step based on the prepared sensitivity state, without any calls to the fitness callbacks.