pygradflow package

Subpackages

Submodules

pygradflow.active_set module

pygradflow.context module

pygradflow.controller module

class pygradflow.controller.Controller(settings: ControllerSettings, ref: float)

Bases: object

PI controller with given settings and reference value.

__init__(settings: ControllerSettings, ref: float) None
class pygradflow.controller.ControllerSettings(K_P: float = 0.0, K_I: float = 0.0, lamb_init: float = 0.0, lamb_red: float = 0.0)

Bases: object

__init__(K_P: float = 0.0, K_I: float = 0.0, lamb_init: float = 0.0, lamb_red: float = 0.0) None
class pygradflow.controller.LogController(settings: ControllerSettings, ref: float)

Bases: object

PI controller working on log scale.

__init__(settings: ControllerSettings, ref: float) None

pygradflow.deriv_check module

exception pygradflow.deriv_check.DerivError(expected_value, actual_value, col_index, atol)

Bases: ValueError

__init__(expected_value, actual_value, col_index, atol) None

pygradflow.display module

class pygradflow.display.ActiveSetColumn

Bases: Column

__init__()
class pygradflow.display.AttrColumn(name: str, width: int, format, attr)

Bases: Column

__init__(name: str, width: int, format, attr)
class pygradflow.display.Column(name: str, width: int)

Bases: ABC

__init__(name: str, width: int)
class pygradflow.display.FilterColumn

Bases: Column

__init__()
class pygradflow.display.StepTypeColumn

Bases: Column

__init__()

pygradflow.eval module

class pygradflow.eval.Component(value, names=<not given>, *values, module=None, qualname=None, type=None, start=1, boundary=None)

Bases: Enum

exception pygradflow.eval.EvalError(msg, x)

Bases: ValueError

__init__(msg, x)
class pygradflow.eval.Evaluator(problem, params)

Bases: ABC

__init__(problem, params)
class pygradflow.eval.SimpleEvaluator(problem, params)

Bases: Evaluator

class pygradflow.eval.ValidatingEvaluator(problem, params)

Bases: Evaluator

__init__(problem, params)

pygradflow.implicit_func module

class pygradflow.implicit_func.ImplicitFunc(problem: Problem, iterate: Iterate, dt: float)

Bases: StepFunc

Standard residual function for implicit Euler steps with the value

\[\begin{split}F(x, y; \hat{x}, \hat{y}) = \begin{pmatrix} x - P_{C} (\hat{x} - \Delta t \nabla_{x} \mathcal{L}^{\rho}(x, y)) \\ y - (\hat{y} + \Delta t \nabla_{y} \mathcal{L}^{\rho}(x, y) \end{pmatrix}\end{split}\]

The values \(\hat{x}\) and \(\hat{y}\) are obtained from the iteratre provided in the constructor

__init__(problem: Problem, iterate: Iterate, dt: float) None
class pygradflow.implicit_func.ScaledImplicitFunc(problem: Problem, iterate: Iterate, dt: float)

Bases: StepFunc

The scaled residual function for implicit Euler steps is defined as the normal residual function given by pygradflow.implicit_func.ImplicitFunc scaled by a factor of \(\lambda = 1 / \Delta t\).

__init__(problem: Problem, iterate: Iterate, dt: float) None
class pygradflow.implicit_func.StepFunc(problem: Problem, iterate: Iterate, dt: float)

Bases: ABC

__init__(problem: Problem, iterate: Iterate, dt: float) None
compute_active_set_box(x: ndarray, lb: ndarray, ub: ndarray)

Compute the active set at the given point with respect to the given bounds.

Parameters:
  • x (np.ndarray) – A primal point in \(\mathbb{R}^{n}\)

  • lb (np.ndarray) – Bounds in \(\mathbb{R}^{n}\)

  • ub (np.ndarray) – Bounds in \(\mathbb{R}^{n}\)

Returns:

A vector with boolean entries, where a value of True at index j indicates that \(x_j\) is outside the interval \([l_j, u_j]\) and should be clipped to it during the projection.

Return type:

np.ndarray

pygradflow.iterate module

pygradflow.log module

pygradflow.newton module

class pygradflow.newton.ActiveSetNewtonMethod(problem: Problem, orig_iterate: Iterate, dt: float, rho: float, step_solver: StepSolver, tau=None)

Bases: NewtonMethod

Computes step based on the matrix given in terms of the initial iterate with an active set based on the active set projection of the primal point of the current iterate. Requires a factorization at each step.

__init__(problem: Problem, orig_iterate: Iterate, dt: float, rho: float, step_solver: StepSolver, tau=None) None
class pygradflow.newton.FixedActiveSetNewtonMethod(problem, active_set, orig_iterate, dt, rho, tau=None)

Bases: NewtonMethod

Computes step based on the matrix given in terms of the current iterate. Requires evaluation of the derivative and a factorization at each step.

__init__(problem, active_set, orig_iterate, dt, rho, tau=None)
class pygradflow.newton.FullNewtonMethod(problem: Problem, orig_iterate: Iterate, dt: float, rho: float, step_solver: StepSolver, tau=None)

Bases: NewtonMethod

Computes step based on the matrix given in terms of the current iterate. Requires evaluation of the derivative and a factorization at each step.

__init__(problem: Problem, orig_iterate: Iterate, dt: float, rho: float, step_solver: StepSolver, tau=None) None
class pygradflow.newton.GlobalizedNewtonMethod(problem: Problem, orig_iterate: Iterate, dt: float, rho: float, step_solver: StepSolver, tau=None)

Bases: NewtonMethod

Globalized Newton method with Armijo line search. Globalization is based on the underlying function of the step solver.

__init__(problem: Problem, orig_iterate: Iterate, dt: float, rho: float, step_solver: StepSolver, tau=None) None
class pygradflow.newton.NewtonMethod(problem: Problem, orig_iterate: Iterate, dt: float, rho: float, tau=None)

Bases: ABC

__init__(problem: Problem, orig_iterate: Iterate, dt: float, rho: float, tau=None) None
class pygradflow.newton.SimplifiedNewtonMethod(problem: Problem, orig_iterate: Iterate, dt: float, rho: float, step_solver: StepSolver, tau=None)

Bases: NewtonMethod

Computes step based on the matrix given in terms of the initial iterate. Only requires a back-solve for each step.

__init__(problem: Problem, orig_iterate: Iterate, dt: float, rho: float, step_solver: StepSolver, tau=None) None

pygradflow.params module

class pygradflow.params.ActiveSetType(value, names=<not given>, *values, module=None, qualname=None, type=None, start=1, boundary=None)

Bases: Enum

class pygradflow.params.DerivCheck(value, names=<not given>, *values, module=None, qualname=None, type=None, start=1, boundary=None)

Bases: Flag

How to check for derivatives

CheckFirst = 1

Check first derivatives (objective gradient \(\nabla_{x} f(x)\) and \(J_c(x)\))

CheckSecond = 2

Check Hessian of Lagrangian (\(\nabla_{xx} \mathcal{L}(x, y)\))

NoCheck = 0

Disable checks

class pygradflow.params.LinearSolverType(value, names=<not given>, *values, module=None, qualname=None, type=None, start=1, boundary=None)

Bases: Enum

Linear solver to be used throughout the computations

Cholesky = 4

Cholesky factorization using scikit-sparse

GMRES = 3

Generalized minimal residual method (GMRES)

LU = 1

LU decomposition

MA57 = 5

HSL MA57 solver using pyomo

MINRES = 2

Minimal residual method (MINRES), only works with symmetric step solver pygradflow.params.StepSolverType.Symmetric

MUMPS = 6

MUMPS solver

SSIDS = 7

SPRAL / SSIDS solver

class pygradflow.params.NewtonType(value, names=<not given>, *values, module=None, qualname=None, type=None, start=1, boundary=None)

Bases: Enum

The Newton method to be used to solve the semi-smooth systems. Different methods have trade-offs in terms of computational complexity and convergence speed

ActiveSet = 3

Newton method with fixed derivative, but changing active sets. Requires refactorizations but no reevaluations of the derivatives

Full = 2

Full Newton method, using a new derivative at each step, (requiring new derivative evaluations and factorizations)

Globalized = 4

Globalizes the Newton method by using an Armijo line search

Simplified = 1

Simplified Newton method, using the same derivative and active set throughout computations (cheapest)

class pygradflow.params.Params(rho: float = 1e-08, theta_max: float = 0.9, theta_ref: float = 0.5, lamb_init: float = 1.0, lamb_min: float = 1e-12, lamb_max: float = 1000000000000.0, lamb_inc: float = 2.0, lamb_red: float = 0.5, K_P: float = 0.2, K_I: float = 0.005, opt_tol: float = 1e-06, lamb_term: float = 1e-08, active_tol: float = 1e-08, local_infeas_tol: float = 1e-08, active_set_type: ~pygradflow.params.ActiveSetType = ActiveSetType.Standard, active_set_method: ~typing.Callable[[...], float] | None = None, active_set_tau: float | None = None, newton_type: ~pygradflow.params.NewtonType = NewtonType.Simplified, newton_tol: float = 1e-08, step_control_type: ~pygradflow.params.StepControlType = StepControlType.DistanceRatio, step_solver: ~typing.Callable[[...], ~typing.Any] | None = None, step_solver_type: ~pygradflow.params.StepSolverType = StepSolverType.Symmetric, linear_solver_type: ~pygradflow.params.LinearSolverType = LinearSolverType.LU, penalty_update: ~pygradflow.params.PenaltyUpdate = PenaltyUpdate.DualNorm, deriv_check: ~pygradflow.params.DerivCheck = <DerivCheck.NoCheck: 0>, deriv_pert: float = 1e-08, deriv_tol: float = 0.0001, precision: ~pygradflow.params.Precision = Precision.Double, scaling_type: ~pygradflow.params.ScalingType = ScalingType.NoScaling, scaling_primal: ~numpy.ndarray | None = None, scaling_dual: ~numpy.ndarray | None = None, scaling: Scaling | None = None, validate_input: bool = True, iteration_limit: int | None = None, time_limit: float = inf, display_interval: float = 0.1, obj_lower_limit: float = -10000000000.0, report_rcond: bool = False, collect_path: bool = False, inertia_correction: bool = False)

Bases: object

Parameters used to solve a pygradflow.problem.Problem using a pygradflow.solver.Solver

__init__(rho: float = 1e-08, theta_max: float = 0.9, theta_ref: float = 0.5, lamb_init: float = 1.0, lamb_min: float = 1e-12, lamb_max: float = 1000000000000.0, lamb_inc: float = 2.0, lamb_red: float = 0.5, K_P: float = 0.2, K_I: float = 0.005, opt_tol: float = 1e-06, lamb_term: float = 1e-08, active_tol: float = 1e-08, local_infeas_tol: float = 1e-08, active_set_type: ~pygradflow.params.ActiveSetType = ActiveSetType.Standard, active_set_method: ~typing.Callable[[...], float] | None = None, active_set_tau: float | None = None, newton_type: ~pygradflow.params.NewtonType = NewtonType.Simplified, newton_tol: float = 1e-08, step_control_type: ~pygradflow.params.StepControlType = StepControlType.DistanceRatio, step_solver: ~typing.Callable[[...], ~typing.Any] | None = None, step_solver_type: ~pygradflow.params.StepSolverType = StepSolverType.Symmetric, linear_solver_type: ~pygradflow.params.LinearSolverType = LinearSolverType.LU, penalty_update: ~pygradflow.params.PenaltyUpdate = PenaltyUpdate.DualNorm, deriv_check: ~pygradflow.params.DerivCheck = <DerivCheck.NoCheck: 0>, deriv_pert: float = 1e-08, deriv_tol: float = 0.0001, precision: ~pygradflow.params.Precision = Precision.Double, scaling_type: ~pygradflow.params.ScalingType = ScalingType.NoScaling, scaling_primal: ~numpy.ndarray | None = None, scaling_dual: ~numpy.ndarray | None = None, scaling: Scaling | None = None, validate_input: bool = True, iteration_limit: int | None = None, time_limit: float = inf, display_interval: float = 0.1, obj_lower_limit: float = -10000000000.0, report_rcond: bool = False, collect_path: bool = False, inertia_correction: bool = False) None
class pygradflow.params.PenaltyUpdate(value, names=<not given>, *values, module=None, qualname=None, type=None, start=1, boundary=None)

Bases: Enum

class pygradflow.params.Precision(value, names=<not given>, *values, module=None, qualname=None, type=None, start=1, boundary=None)

Bases: Enum

Precision to be used in all calculations

Double = 2

Double precision (64 bit)

Single = 1

Single precision (32 bit)

class pygradflow.params.ScalingType(value, names=<not given>, *values, module=None, qualname=None, type=None, start=1, boundary=None)

Bases: Enum

How to scale the problem

Custom = 5

User-provided custom scaling

GradJac = 2

Scale based on gradient and equilibration of constraint Jacobian

KKT = 3

Compute scales based on the equilibration of the KKT matrix

NoScaling = 1

No scaling

Nominal = 4

Scaled based on values of the variable and constraint values

class pygradflow.params.StepControlType(value, names=<not given>, *values, module=None, qualname=None, type=None, start=1, boundary=None)

Bases: Enum

class pygradflow.params.StepSolverType(value, names=<not given>, *values, module=None, qualname=None, type=None, start=1, boundary=None)

Bases: Enum

Step solver type to be used throughout computations

Asymmetric = 4

Scaled solver with asymmetric matrix

Extended = 2

Scaled step solver with improved condition

Standard = 1

Unscaled and unsymmetric

Symmetric = 3

Scaled solver with symmetric matrix

pygradflow.penalty module

class pygradflow.penalty.ConstantPenalty(problem: Problem, params: Params)

Bases: PenaltyStrategy

__init__(problem: Problem, params: Params) None
class pygradflow.penalty.DualEquilibration(problem: Problem, params: Params)

Bases: PenaltyStrategy

Increase penalty such that the dual the violation is within a factor of the product of the dual variables and the constraint values

__init__(problem: Problem, params: Params)
class pygradflow.penalty.DualNormUpdate(problem: Problem, params: Params)

Bases: PenaltyStrategy

Increase penalty such that it is within a factor of the inf-norm of the dual variables

__init__(problem: Problem, params: Params) None
class pygradflow.penalty.LagrangianPenaltyFilter(problem: Problem, params: Params)

Bases: PenaltyFilter

__init__(problem: Problem, params: Params) None
class pygradflow.penalty.ObjectivePenaltyFilter(problem: Problem, params: Params)

Bases: PenaltyFilter

__init__(problem: Problem, params: Params) None
class pygradflow.penalty.ParetoDecrease(problem: Problem, params: Params)

Bases: PenaltyStrategy

Increase penalty such that at least one of objective and constraint violation is (weakly) reduced in the direction of the curve

__init__(problem: Problem, params: Params)
class pygradflow.penalty.PenaltyFilter(problem: Problem, params: Params)

Bases: PenaltyStrategy

Filter maintaining a set of Pareto optimal points of objective and constraint violation. The penalty is increased at a point if it is dominated by any other point in the filter.

Note: The running time is linear in the size of the filter, this could be improved to be logarithmic

__init__(problem: Problem, params: Params) None
class pygradflow.penalty.PenaltyStrategy(problem: Problem, params: Params)

Bases: ABC

__init__(problem: Problem, params: Params) None

pygradflow.problem module

class pygradflow.problem.Problem(var_lb: ndarray, var_ub: ndarray, **args)

Bases: ABC

Base class used to formulate the problem of minimizing a smooth objective \(f : \mathbb{R}^{n} \to \mathbb{R}\) over a set of smooth nonlinear constraints \(c : \mathbb{R}^{n} \to \mathbb{R}^{m}\) bounded by \(l, u \in \mathbb{R}^{m}\), and variable bounds \(x_l, x_u \in \mathbb{R}^{n}\), yielding the problem

\[\begin{split}\begin{align} \min_{x \in \mathbb{R}^{n}} \quad & f(x) \\ \text{s.t.} \quad & l \leq c(x) \leq u \\ & l^x \leq x \leq u^x \end{align}\end{split}\]
The Lagrangian of this problem is given by
\[\mathcal{L}(x, y) = f(x) + y^{T} c(x),\]

where \(y \in \mathbb{R}^{m}\) is a vector of Lagrange multipliers

__init__(var_lb: ndarray, var_ub: ndarray, **args) None

Creates the problem

Parameters:
  • var_lb (np.ndarray) – The variable bounds \(l^x, u^x \in \mathbb{R}^{n}\) constraining the problem

  • var_ub (np.ndarray) – The variable bounds \(l^x, u^x \in \mathbb{R}^{n}\) constraining the problem

  • **args (dict, optional) –

    Additional arguments to pass to the problem:

    • cons_lbnp.ndarray

      The lower bounds \(l \in \mathbb{R}^{m}\) on the constraints

    • cons_ubnp.ndarray

      The upper bounds \(u \in \mathbb{R}^{m}\) on the constraints

    • num_consint

      The number of constraints (if not given by cons_lb or cons_ub), defaults to 0 (no constraints)

cons(x: ndarray) ndarray
Parameters:

x (np.ndarray) – The primal point \(x \in \mathbb{R}^{n}\) at which to evaluate the constraint function \(c\)

Returns:

The constraint value \(c(x)\) at the given primal point \(x\)

Return type:

np.ndarray

cons_jac(x: ndarray) spmatrix
Parameters:

x (np.ndarray) – The primal point \(x \in \mathbb{R}^{n}\) at which to evaluate the constraint Jacobian \(J_c\)

Returns:

The constraint Jacobian \(J_c(x)\) at the given primal point \(x\)

Return type:

sp.sparse.spmatrix

abstract lag_hess(x: ndarray, y: ndarray) spmatrix
Parameters:
  • x (np.ndarray) – The primal / dual points \(x \in \mathbb{R}^{n}\) and \(y \in \mathbb{R}^{m}\) at which to evaluate the Hessian \(\nabla_{xx} \mathcal{L}(x, y)\)

  • y (np.ndarray) – The primal / dual points \(x \in \mathbb{R}^{n}\) and \(y \in \mathbb{R}^{m}\) at which to evaluate the Hessian \(\nabla_{xx} \mathcal{L}(x, y)\)

Returns:

The matrix \(\nabla_{xx} \mathcal{L}(x, y) \in \mathbb{R}^{n \times n}\) at the given primal / dual points \(x\) / \(y\)

Return type:

sp.sparse.spmatrix

property num_vars: int

The number of variables in the problem

abstract obj(x: ndarray) float
Parameters:

x (np.ndarray) – The primal point \(x \in \mathbb{R}^{n}\) at which to evaluate the objective function

Returns:

The objective function value \(f(x)\) at the given primal point \(x\)

Return type:

float

abstract obj_grad(x: ndarray) ndarray
Parameters:

x (np.ndarray) – The primal point \(x \in \mathbb{R}^{n}\) at which to evaluate the objective function gradient

Returns:

The objective function gradient \(\nabla f(x)\) at the given primal point \(x\)

Return type:

np.ndarray

property var_bounded

Whether of not the variable bounds are trivial (i.e., all infinte)

pygradflow.solver module

class pygradflow.solver.Solver(problem: ~pygradflow.problem.Problem, params: ~pygradflow.params.Params = Params(rho=1e-08, theta_max=0.9, theta_ref=0.5, lamb_init=1.0, lamb_min=1e-12, lamb_max=1000000000000.0, lamb_inc=2.0, lamb_red=0.5, K_P=0.2, K_I=0.005, opt_tol=1e-06, lamb_term=1e-08, active_tol=1e-08, local_infeas_tol=1e-08, active_set_type=<ActiveSetType.Standard: 1>, active_set_method=None, active_set_tau=None, newton_type=<NewtonType.Simplified: 1>, newton_tol=1e-08, step_control_type=<StepControlType.DistanceRatio: 6>, step_solver=None, step_solver_type=<StepSolverType.Symmetric: 3>, linear_solver_type=<LinearSolverType.LU: 1>, penalty_update=<PenaltyUpdate.DualNorm: 2>, deriv_check=<DerivCheck.NoCheck: 0>, deriv_pert=1e-08, deriv_tol=0.0001, precision=<Precision.Double: 2>, scaling_type=<ScalingType.NoScaling: 1>, scaling_primal=None, scaling_dual=None, scaling=None, validate_input=True, iteration_limit=None, time_limit=inf, display_interval=0.1, obj_lower_limit=-10000000000.0, report_rcond=False, collect_path=False, inertia_correction=False))

Bases: object

Solves a pygradflow.problem.Problem instance according to the given pygradflow.params.Params. The solver attempts to find a solution given by vectors \(x \in \mathbb{R}^{n}\), \(y \in \mathbb{R}^{m}\), and \(d \in \mathbb{R}^{n}\), approximately satisfying the stationarity

\[\begin{align} \nabla_x f(x) + y^{T} J_c(x) + d = 0, \end{align}\]

feasibility

\[\begin{split}\begin{align} \quad & l \leq c(x) \leq u \\ \quad & l^x \leq x \leq u^x \\ \end{align}\end{split}\]

and complementarity

\[\begin{split}\begin{align} y_i \begin{cases} \geq 0 & \text{ if } c(x)_i = u_i \\ \leq 0 & \text{ if } c(x)_i = l_i \\ = 0 & \text{ otherwise } \end{cases} \\ d_j \begin{cases} \geq 0 & \text{ if } x_j = u^x_j \\ \leq 0 & \text{ if } x_j = l^x_j \\ = 0 & \text{ otherwise } \end{cases} \end{align}\end{split}\]

conditions.

__init__(problem: ~pygradflow.problem.Problem, params: ~pygradflow.params.Params = Params(rho=1e-08, theta_max=0.9, theta_ref=0.5, lamb_init=1.0, lamb_min=1e-12, lamb_max=1000000000000.0, lamb_inc=2.0, lamb_red=0.5, K_P=0.2, K_I=0.005, opt_tol=1e-06, lamb_term=1e-08, active_tol=1e-08, local_infeas_tol=1e-08, active_set_type=<ActiveSetType.Standard: 1>, active_set_method=None, active_set_tau=None, newton_type=<NewtonType.Simplified: 1>, newton_tol=1e-08, step_control_type=<StepControlType.DistanceRatio: 6>, step_solver=None, step_solver_type=<StepSolverType.Symmetric: 3>, linear_solver_type=<LinearSolverType.LU: 1>, penalty_update=<PenaltyUpdate.DualNorm: 2>, deriv_check=<DerivCheck.NoCheck: 0>, deriv_pert=1e-08, deriv_tol=0.0001, precision=<Precision.Double: 2>, scaling_type=<ScalingType.NoScaling: 1>, scaling_primal=None, scaling_dual=None, scaling=None, validate_input=True, iteration_limit=None, time_limit=inf, display_interval=0.1, obj_lower_limit=-10000000000.0, report_rcond=False, collect_path=False, inertia_correction=False)) None

Creates a new solver

Parameters:
solve(x0: ndarray | float | None = None, y0: ndarray | float | None = None) SolverResult

Solves the problem starting from the given primal / dual point

Parameters:
  • x0 (np.ndarray | float | None) – The initial primal point \(x_0 \in \mathbb{R}^{n}\)

  • y0 (np.ndarray | float | None) – The initial dual point \(y_0 \in \mathbb{R}^{m}\)

Returns:

The result of the solving process, including primal and dual solutions

Return type:

pygradflow.solver.SolverResult

pygradflow.util module

Module contents