Nonlinear Modeling

More information can be found in the Nonlinear section of the manual.

MathOptInterface.Nonlinear.ModelType
Model()

The core datastructure for representing a nonlinear optimization problem.

It has the following fields:

  • objective::Union{Nothing,Expression} : holds the nonlinear objective function, if one exists, otherwise nothing.
  • expressions::Vector{Expression} : a vector of expressions in the model.
  • constraints::OrderedDict{ConstraintIndex,Constraint} : a map from ConstraintIndex to the corresponding Constraint. An OrderedDict is used instead of a Vector to support constraint deletion.
  • parameters::Vector{Float64} : holds the current values of the parameters.
  • operators::OperatorRegistry : stores the operators used in the model.
source

Expressions

MathOptInterface.Nonlinear.add_expressionFunction
add_expression(model::Model, expr)::ExpressionIndex

Parse expr into a Expression and add to model. Returns an ExpressionIndex that can be interpolated into other input expressions.

expr must be a type that is supported by parse_expression.

Example

julia> model = MOI.Nonlinear.Model();julia> x = MOI.VariableIndex(1);julia> ex = MOI.Nonlinear.add_expression(model, :($x^2 + 1))MathOptInterface.Nonlinear.ExpressionIndex(1)julia> MOI.Nonlinear.set_objective(model, :(sqrt($ex)))
source

Parameters

MathOptInterface.Nonlinear.add_parameterFunction
add_parameter(model::Model, value::Float64)::ParameterIndex

Add a new parameter to model with the default value value. Returns a ParameterIndex that can be interpolated into other input expressions and used to modify the value of the parameter.

Example

julia> model = MOI.Nonlinear.Model()A Nonlinear.Model with: 0 objectives 0 parameters 0 expressions 0 constraintsjulia> x = MOI.VariableIndex(1)MOI.VariableIndex(1)julia> p = MOI.Nonlinear.add_parameter(model, 1.2)MathOptInterface.Nonlinear.ParameterIndex(1)julia> c = MOI.Nonlinear.add_constraint(model, :($x^2 - $p), MOI.LessThan(0.0))MathOptInterface.Nonlinear.ConstraintIndex(1)
source

Objectives

MathOptInterface.Nonlinear.set_objectiveFunction
set_objective(model::Model, obj)::Nothing

Parse obj into a Expression and set as the objective function of model.

obj must be a type that is supported by parse_expression.

To remove the objective, pass nothing.

Example

julia> model = MOI.Nonlinear.Model()A Nonlinear.Model with: 0 objectives 0 parameters 0 expressions 0 constraintsjulia> x = MOI.VariableIndex(1)MOI.VariableIndex(1)julia> MOI.Nonlinear.set_objective(model, :($x^2 + 1))julia> MOI.Nonlinear.set_objective(model, x)julia> MOI.Nonlinear.set_objective(model, nothing)
source

Constraints

MathOptInterface.Nonlinear.add_constraintFunction
add_constraint(
    model::Model,
    func,
    set::Union{
        MOI.GreaterThan{Float64},
        MOI.LessThan{Float64},
        MOI.Interval{Float64},
        MOI.EqualTo{Float64},
    },
)

Parse func and set into a Constraint and add to model. Returns a ConstraintIndex that can be used to delete the constraint or query solution information.

Example

julia> model = MOI.Nonlinear.Model();julia> x = MOI.VariableIndex(1);julia> c = MOI.Nonlinear.add_constraint(model, :($x^2), MOI.LessThan(1.0))MathOptInterface.Nonlinear.ConstraintIndex(1)
source
MathOptInterface.Nonlinear.deleteFunction
delete(model::Model, c::ConstraintIndex)::Nothing

Delete the constraint index c from model.

Example

julia> model = MOI.Nonlinear.Model()A Nonlinear.Model with: 0 objectives 0 parameters 0 expressions 0 constraintsjulia> x = MOI.VariableIndex(1)MOI.VariableIndex(1)julia> c = MOI.Nonlinear.add_constraint(model, :($x^2), MOI.LessThan(1.0))MathOptInterface.Nonlinear.ConstraintIndex(1)julia> modelA Nonlinear.Model with: 0 objectives 0 parameters 0 expressions 1 constraintjulia> MOI.Nonlinear.delete(model, c)julia> modelA Nonlinear.Model with: 0 objectives 0 parameters 0 expressions 0 constraints
source

User-defined operators

MathOptInterface.Nonlinear.DEFAULT_UNIVARIATE_OPERATORSConstant
DEFAULT_UNIVARIATE_OPERATORS

The list of univariate operators that are supported by default.

Example

julia> MOI.Nonlinear.DEFAULT_UNIVARIATE_OPERATORS73-element Vector{Symbol}: :+ :- :abs :sign :sqrt :cbrt :abs2 :inv :log :log10 :airybi :airyaiprime :airybiprime :besselj0 :besselj1 :bessely0 :bessely1 :erfcx :dawson
source
MathOptInterface.Nonlinear.register_operatorFunction
register_operator(
    model::Model,
    op::Symbol,
    nargs::Int,
    f::Function,
    [∇f::Function],
    [∇²f::Function],
)

Register the user-defined operator op with nargs input arguments in model.

Univariate functions

  • f(x::T)::T must be a function that takes a single input argument x and returns the function evaluated at x. If ∇f and ∇²f are not provided, f must support any Real input type T.
  • ∇f(x::T)::T is a function that takes a single input argument x and returns the first derivative of f with respect to x. If ∇²f is not provided, ∇f must support any Real input type T.
  • ∇²f(x::T)::T is a function that takes a single input argument x and returns the second derivative of f with respect to x.

Multivariate functions

  • f(x::T...)::T must be a function that takes a nargs input arguments x and returns the function evaluated at x. If ∇f and ∇²f are not provided, f must support any Real input type T.
  • ∇f(g::AbstractVector{T}, x::T...)::T is a function that takes a cache vector g of length length(x), and fills each element g[i] with the partial derivative of f with respect to x[i].
  • ∇²f(H::AbstractMatrix, x::T...)::T is a function that takes a matrix H and fills the lower-triangular components H[i, j] with the Hessian of f with respect to x[i] and x[j] for i >= j.

Notes for multivariate Hessians

  • H has size(H) == (length(x), length(x)), but you must not access elements H[i, j] for i > j.
  • H is dense, but you do not need to fill structural zeros.
source
MathOptInterface.Nonlinear.eval_univariate_functionFunction
eval_univariate_function(
    registry::OperatorRegistry,
    op::Union{Symbol,Integer},
    x::T,
) where {T}

Evaluate the operator op(x)::T, where op is a univariate function in registry.

If op isa Integer, then op is the index in registry.univariate_operators[op].

Example

julia> r = MOI.Nonlinear.OperatorRegistry();julia> MOI.Nonlinear.eval_univariate_function(r, :abs, -1.2)1.2julia> r.univariate_operators[3]:absjulia> MOI.Nonlinear.eval_univariate_function(r, 3, -1.2)1.2
source
MathOptInterface.Nonlinear.eval_univariate_gradientFunction
eval_univariate_gradient(
    registry::OperatorRegistry,
    op::Union{Symbol,Integer},
    x::T,
) where {T}

Evaluate the first-derivative of the operator op(x)::T, where op is a univariate function in registry.

If op isa Integer, then op is the index in registry.univariate_operators[op].

Example

julia> r = MOI.Nonlinear.OperatorRegistry();julia> MOI.Nonlinear.eval_univariate_gradient(r, :abs, -1.2)-1.0julia> r.univariate_operators[3]:absjulia> MOI.Nonlinear.eval_univariate_gradient(r, 3, -1.2)-1.0
source
MathOptInterface.Nonlinear.eval_univariate_function_and_gradientFunction
eval_univariate_function_and_gradient(
    registry::OperatorRegistry,
    op::Union{Symbol,Integer},
    x::T,
)::Tuple{T,T} where {T}

Evaluate the function and first-derivative of the operator op(x)::T, where op is a univariate function in registry.

If op isa Integer, then op is the index in registry.univariate_operators[op].

Example

julia> r = MOI.Nonlinear.OperatorRegistry();julia> MOI.Nonlinear.eval_univariate_function_and_gradient(r, :abs, -1.2)(1.2, -1.0)julia> r.univariate_operators[3]:absjulia> MOI.Nonlinear.eval_univariate_function_and_gradient(r, 3, -1.2)(1.2, -1.0)
source
MathOptInterface.Nonlinear.eval_univariate_hessianFunction
eval_univariate_hessian(
    registry::OperatorRegistry,
    op::Union{Symbol,Integer},
    x::T,
) where {T}

Evaluate the second-derivative of the operator op(x)::T, where op is a univariate function in registry.

If op isa Integer, then op is the index in registry.univariate_operators[op].

Example

julia> r = MOI.Nonlinear.OperatorRegistry();julia> MOI.Nonlinear.eval_univariate_hessian(r, :sin, 1.0)-0.8414709848078965julia> r.univariate_operators[16]:sinjulia> MOI.Nonlinear.eval_univariate_hessian(r, 16, 1.0)-0.8414709848078965julia> -sin(1.0)-0.8414709848078965
source
MathOptInterface.Nonlinear.eval_multivariate_hessianFunction
eval_multivariate_hessian(
    registry::OperatorRegistry,
    op::Symbol,
    H::AbstractMatrix,
    x::AbstractVector{T},
)::Bool where {T}

Evaluate the Hessian of operator ∇²op(x), where op is a multivariate function in registry.

The Hessian is stored in the lower-triangular part of the matrix H.

Returns a Bool indicating whether non-zeros were stored in the matrix.

Note

Implementations of the Hessian operators will not fill structural zeros. Therefore, before calling this function you should pre-populate the matrix H with 0.

source

Automatic-differentiation backends

MathOptInterface.Nonlinear.SparseReverseModeType
SparseReverseMode() <: AbstractAutomaticDifferentiation

An implementation of AbstractAutomaticDifferentiation that uses sparse reverse-mode automatic differentiation to compute derivatives. Supports all features in the MOI nonlinear interface.

source
MathOptInterface.Nonlinear.SymbolicModeType
SymbolicMode() <: AbstractAutomaticDifferentiation

A type for setting as the value of the MOI.AutomaticDifferentiationBackend() attribute to enable symbolic automatic differentiation.

source

Data-structure

MathOptInterface.Nonlinear.NodeTypeType
NodeType

An enum describing the possible node types. Each Node has a .index field, which should be interpreted as follows:

  • NODE_CALL_MULTIVARIATE: the index into operators.multivariate_operators
  • NODE_CALL_UNIVARIATE: the index into operators.univariate_operators
  • NODE_LOGIC: the index into operators.logic_operators
  • NODE_COMPARISON: the index into operators.comparison_operators
  • NODE_MOI_VARIABLE: the value of MOI.VariableIndex(index) in the user's space of the model.
  • NODE_VARIABLE: the 1-based index of the internal vector
  • NODE_VALUE: the index into the .values field of Expression
  • NODE_PARAMETER: the index into data.parameters
  • NODE_SUBEXPRESSION: the index into data.expressions
source
MathOptInterface.Nonlinear.ExpressionType
struct Expression
    nodes::Vector{Node}
    values::Vector{Float64}
end

The core type that represents a nonlinear expression. See the MathOptInterface documentation for information on how the nodes and values form an expression tree.

source
MathOptInterface.Nonlinear.adjacency_matrixFunction
adjacency_matrix(nodes::Vector{Node})

Compute the sparse adjacency matrix describing the parent-child relationships in nodes.

The element (i, j) is true if there is an edge from node[j] to node[i]. Since we get a column-oriented matrix, this gives us a fast way to look up the edges leaving any node (that is, the children).

source
MathOptInterface.Nonlinear.parse_expressionFunction
parse_expression(data::Model, input)::Expression

Parse input into a Expression.

source
parse_expression(
    data::Model,
    expr::Expression,
    input::Any,
    parent_index::Int,
)::Expression

Parse input into a Expression, and add it to expr as a child of expr.nodes[parent_index]. Existing subexpressions and parameters are stored in data.

You can extend parsing support to new types of objects by overloading this method with a different type on input::Any.

source
MathOptInterface.Nonlinear.convert_to_exprFunction
convert_to_expr(data::Model, expr::Expression)

Convert the Expression expr into a Julia Expr.

source
convert_to_expr(
    evaluator::Evaluator,
    expr::Expression;
    moi_output_format::Bool,
)

Convert the Expression expr into a Julia Expr.

If moi_output_format = true:

  • subexpressions will be converted to Julia Expr and substituted into the output expression.
  • the current value of each parameter will be interpolated into the expression
  • variables will be represented in the form x[MOI.VariableIndex(i)]

If moi_output_format = false:

Warning

To use moi_output_format = true, you must have first called MOI.initialize with :ExprGraph as a requested feature.

source
MathOptInterface.Nonlinear.ordinal_indexFunction
ordinal_index(evaluator::Evaluator, c::ConstraintIndex)::Int

Return the 1-indexed value of the constraint index c in evaluator.

Example

julia> model = MOI.Nonlinear.Model()A Nonlinear.Model with: 0 objectives 0 parameters 0 expressions 0 constraintsjulia> x = MOI.VariableIndex(1)MOI.VariableIndex(1)julia> c1 = MOI.Nonlinear.add_constraint(model, :($x^2), MOI.LessThan(1.0))MathOptInterface.Nonlinear.ConstraintIndex(1)julia> c2 = MOI.Nonlinear.add_constraint(model, :($x^2), MOI.LessThan(1.0))MathOptInterface.Nonlinear.ConstraintIndex(2)julia> evaluator = MOI.Nonlinear.Evaluator(model)Nonlinear.Evaluator with available features:  * :ExprGraphjulia> MOI.initialize(evaluator, Symbol[])julia> MOI.Nonlinear.ordinal_index(evaluator, c2)  # Returns 22julia> MOI.Nonlinear.delete(model, c1)julia> evaluator = MOI.Nonlinear.Evaluator(model)Nonlinear.Evaluator with available features:  * :ExprGraphjulia> MOI.initialize(evaluator, Symbol[])julia> MOI.Nonlinear.ordinal_index(evaluator, c2)  # Returns 11
source

SymbolicAD

MathOptInterface.Nonlinear.SymbolicAD.simplify!Function
simplify!(f)

Simplify the function f in-place and return either the function f or a new object if f can be represented in a simpler type.

Warning

This function is not type stable by design.

Example

julia> x = MOI.VariableIndex(1)MOI.VariableIndex(1)julia> f = MOI.ScalarNonlinearFunction(           :+,           Any[MOI.ScalarNonlinearFunction(:+, Any[1.0, x]), 2.0 * x + 3.0],       )+(+(1.0, MOI.VariableIndex(1)), 3.0 + 2.0 MOI.VariableIndex(1))julia> MOI.Nonlinear.SymbolicAD.simplify!(f)4.0 + 3.0 MOI.VariableIndex(1)julia> f+(1.0, MOI.VariableIndex(1), 3.0 + 2.0 MOI.VariableIndex(1))
source
simplify!(::Val{head}, f::MOI.ScalarNonlinearFunction)

Simplify the function f in-place and return either the function f or a new object if f can be represented in a simpler type.

Val

The head in Val{head} is taken from f.head. This function should be called as:

f = simplify!(Val(f.head), f)

Implementing a method that dispatches on head enables custom simplification rules for different operators without needing a giant switch statement.

Note

It is important that this function does not recursively call simplify!. Deal only with the immediate operator. The children arguments will already be simplified.

source
MathOptInterface.Nonlinear.SymbolicAD.variablesFunction
variables(f::Union{Real,MOI.AbstractScalarFunction})

Return a sorted list of the MOI.VariableIndex present in the function f.

Example

julia> x = MOI.VariableIndex.(1:3)3-element Vector{MathOptInterface.VariableIndex}: MOI.VariableIndex(1) MOI.VariableIndex(2) MOI.VariableIndex(3)julia> f = MOI.ScalarNonlinearFunction(:atan, Any[x[3], 2.0 * x[1]])atan(MOI.VariableIndex(3), 0.0 + 2.0 MOI.VariableIndex(1))julia> MOI.Nonlinear.SymbolicAD.variables(f)2-element Vector{MathOptInterface.VariableIndex}: MOI.VariableIndex(1) MOI.VariableIndex(3)
source
MathOptInterface.Nonlinear.SymbolicAD.derivativeFunction
derivative(f::Union{Real,MOI.AbstractScalarFunction}, x::MOI.VariableIndex)

Return an expression representing the partial derivative of f with respect to x.

Expression swelling

With few exceptions, the algorithm used to compute the derivative does not perform simplications. As a result, the returned expression may contain terms like *(false, g) that can be trivially simplified to false.

In most cases, you should call simplify!(derivative(f, x)) to return a simplified expression of the derivative.

Example

julia> x = MOI.VariableIndex(1)MOI.VariableIndex(1)julia> f = MOI.ScalarNonlinearFunction(:sin, Any[x])sin(MOI.VariableIndex(1))julia> df_dx = MOI.Nonlinear.SymbolicAD.derivative(f, x)cos(MOI.VariableIndex(1))
source
MathOptInterface.Nonlinear.SymbolicAD.gradient_and_hessianFunction
gradient_and_hessian(
    [filter_fn::Function = x -> true,]
    f::MOI.AbstractScalarFunction,
)

Compute the symbolic gradient and Hessian of f, and return the result as a tuple of four elements:

  1. x::Vector{MOI.VariableIndex}: the list of variables that appear in f
  2. ∇f::Vector{Any}: a vector for the first partial derivative of f with respect to each element in x
  3. H::Vector{Tuple{Int,Int}}: a vector of (row, column) tuples that list the non-zero entries in the Hessian of f
  4. ∇²f::Vector{Any}: a vector of expressions, in the same order as H, for the non-zero entries in the Hessian of f

filter_fn

This argument is a function, filter_fn(::MOI.VariableIndex)::Bool that returns true if the gradient and Hessian of f should be computed with respect to it.

Use this argument to filter out constant parameters from decision variables.

source