Utilities.Model
MathOptInterface.Utilities.Model
— TypeMOI.Utilities.Model{T}() where {T}
An implementation of ModelLike
that supports all functions and sets defined in MOI. It is parameterized by the coefficient type.
Example
julia> import MathOptInterface as MOI
julia> model = MOI.Utilities.Model{Float64}()
MOIU.Model{Float64}
├ ObjectiveSense: FEASIBILITY_SENSE
├ ObjectiveFunctionType: MOI.ScalarAffineFunction{Float64}
├ NumberOfVariables: 0
└ NumberOfConstraints: 0
Utilities.UniversalFallback
MathOptInterface.Utilities.UniversalFallback
— TypeUniversalFallback
The UniversalFallback
can be applied on a MOI.ModelLike
model
to create the model UniversalFallback(model)
supporting any constraint and attribute. This allows to have a specialized implementation in model
for performance critical constraints and attributes while still supporting other attributes with a small performance penalty. Note that model
is unaware of constraints and attributes stored by UniversalFallback
so this is not appropriate if model
is an optimizer (for this reason, MOI.optimize!
has not been implemented). In that case, optimizer bridges should be used instead.
Utilities.@model
MathOptInterface.Utilities.@model
— Macromacro model(
model_name,
scalar_sets,
typed_scalar_sets,
vector_sets,
typed_vector_sets,
scalar_functions,
typed_scalar_functions,
vector_functions,
typed_vector_functions,
is_optimizer = false
)
Creates a type model_name
implementing the MOI model interface and supporting all combinations of the provided functions and sets.
Each typed_
scalar
/vector
sets
/functions
argument is a tuple of types. A type is "typed" if it has a coefficient {T}
as the first type parameter.
Tuple syntax
To give no set/function, write ()
. To give one set or function X
, write (X,)
.
is_optimizer
If is_optimizer = true
, the resulting struct is a of GenericOptimizer
, which is a subtype of MOI.AbstractOptimizer
, otherwise, it is a GenericModel
, which is a subtype of MOI.ModelLike
.
VariableIndex
- The function
MOI.VariableIndex
must not be given inscalar_functions
. - The model supports
MOI.VariableIndex
-in-S
constraints whereS
isMOI.EqualTo
,MOI.GreaterThan
,MOI.LessThan
,MOI.Interval
,MOI.Integer
,MOI.ZeroOne
,MOI.Semicontinuous
orMOI.Semiinteger
. - The sets supported with
MOI.VariableIndex
cannot be controlled from the macro; useUniversalFallback
to support more sets.
Example
The model describing a linear program would be:
@model(
LPModel, # model_name
(), # untyped scalar sets
(MOI.EqualTo, MOI.GreaterThan, MOI.LessThan, MOI.Interval), # typed scalar sets
(MOI.Zeros, MOI.Nonnegatives, MOI.Nonpositives), # untyped vector sets
(), # typed vector sets
(), # untyped scalar functions
(MOI.ScalarAffineFunction,), # typed scalar functions
(MOI.VectorOfVariables,), # untyped vector functions
(MOI.VectorAffineFunction,), # typed vector functions
false, # is_optimizer
)
MathOptInterface.Utilities.GenericModel
— Typemutable struct GenericModel{T,O,V,C} <: AbstractModelLike{T}
Implements a model supporting coefficients of type T
and:
- An objective function stored in
.objective::O
- Variables and
VariableIndex
constraints stored in.variable_bounds::V
F
-in-S
constraints (excludingVariableIndex
constraints) stored in.constraints::C
All interactions take place via the MOI interface, so the types O
, V
, and C
must implement the API as needed for their functionality.
MathOptInterface.Utilities.GenericOptimizer
— Typemutable struct GenericOptimizer{T,O,V,C} <: AbstractOptimizer{T}
Implements a model supporting coefficients of type T
and:
- An objective function stored in
.objective::O
- Variables and
VariableIndex
constraints stored in.variable_bounds::V
F
-in-S
constraints (excludingVariableIndex
constraints) stored in.constraints::C
All interactions take place via the MOI interface, so the types O
, V
, and C
must implement the API as needed for their functionality.
.objective
MathOptInterface.Utilities.ObjectiveContainer
— TypeObjectiveContainer{T}
A helper struct to simplify the handling of objective functions in Utilities.Model.
.variables
MathOptInterface.Utilities.VariablesContainer
— Typestruct VariablesContainer{T} <: AbstractVectorBounds
set_mask::Vector{UInt16}
lower::Vector{T}
upper::Vector{T}
end
A struct for storing variables and VariableIndex-related constraints. Used in MOI.Utilities.Model
by default.
MathOptInterface.Utilities.FreeVariables
— Typemutable struct FreeVariables <: MOI.ModelLike
n::Int64
FreeVariables() = new(0)
end
A struct for storing free variables that can be used as the variables
field of GenericModel
or GenericModel
. It represents a model that does not support any constraint nor objective function.
Example
The following model type represents a conic model in geometric form. As opposed to VariablesContainer
, FreeVariables
does not support constraint bounds so they are bridged into an affine constraint in the MOI.Nonnegatives
cone as expected for the geometric conic form.
julia> MOI.Utilities.@product_of_sets(
Cones,
MOI.Zeros,
MOI.Nonnegatives,
MOI.SecondOrderCone,
MOI.PositiveSemidefiniteConeTriangle,
);
julia> const ConicModel{T} = MOI.Utilities.GenericOptimizer{
T,
MOI.Utilities.ObjectiveContainer{T},
MOI.Utilities.FreeVariables,
MOI.Utilities.MatrixOfConstraints{
T,
MOI.Utilities.MutableSparseMatrixCSC{
T,
Int,
MOI.Utilities.OneBasedIndexing,
},
Vector{T},
Cones{T},
},
};
julia> model = MOI.instantiate(ConicModel{Float64}, with_bridge_type=Float64);
julia> x = MOI.add_variable(model)
MathOptInterface.VariableIndex(1)
julia> c = MOI.add_constraint(model, x, MOI.GreaterThan(1.0))
MathOptInterface.ConstraintIndex{MathOptInterface.VariableIndex, MathOptInterface.GreaterThan{Float64}}(1)
julia> MOI.Bridges.is_bridged(model, c)
true
julia> bridge = MOI.Bridges.bridge(model, c)
MathOptInterface.Bridges.Constraint.VectorizeBridge{Float64, MathOptInterface.VectorAffineFunction{Float64}, MathOptInterface.Nonnegatives, MathOptInterface.VariableIndex}(MathOptInterface.ConstraintIndex{MathOptInterface.VectorAffineFunction{Float64}, MathOptInterface.Nonnegatives}(1), 1.0)
julia> bridge.vector_constraint
MathOptInterface.ConstraintIndex{MathOptInterface.VectorAffineFunction{Float64}, MathOptInterface.Nonnegatives}(1)
julia> MOI.Bridges.is_bridged(model, bridge.vector_constraint)
false
.constraints
MathOptInterface.Utilities.VectorOfConstraints
— Typemutable struct VectorOfConstraints{
F<:MOI.AbstractFunction,
S<:MOI.AbstractSet,
} <: MOI.ModelLike
constraints::CleverDicts.CleverDict{
MOI.ConstraintIndex{F,S},
Tuple{F,S},
typeof(CleverDicts.key_to_index),
typeof(CleverDicts.index_to_key),
}
end
A struct storing F
-in-S
constraints as a mapping between the constraint indices to the corresponding tuple of function and set.
MathOptInterface.Utilities.StructOfConstraints
— Typeabstract type StructOfConstraints <: MOI.ModelLike end
A struct storing a subfields other structs storing constraints of different types.
See Utilities.@struct_of_constraints_by_function_types
and Utilities.@struct_of_constraints_by_set_types
.
MathOptInterface.Utilities.@struct_of_constraints_by_function_types
— MacroUtilities.@struct_of_constraints_by_function_types(name, func_types...)
Given a vector of n
function types (F1, F2,..., Fn)
in func_types
, defines a subtype of StructOfConstraints
of name name
and which type parameters {T, C1, C2, ..., Cn}
. It contains n
field where the i
th field has type Ci
and stores the constraints of function type Fi
.
The expression Fi
can also be a union in which case any constraint for which the function type is in the union is stored in the field with type Ci
.
MathOptInterface.Utilities.@struct_of_constraints_by_set_types
— MacroUtilities.@struct_of_constraints_by_set_types(name, func_types...)
Given a vector of n
set types (S1, S2,..., Sn)
in func_types
, defines a subtype of StructOfConstraints
of name name
and which type parameters {T, C1, C2, ..., Cn}
. It contains n
field where the i
th field has type Ci
and stores the constraints of set type Si
. The expression Si
can also be a union in which case any constraint for which the set type is in the union is stored in the field with type Ci
. This can be useful if Ci
is a MatrixOfConstraints
in order to concatenate the coefficients of constraints of several different set types in the same matrix.
MathOptInterface.Utilities.struct_of_constraint_code
— Functionstruct_of_constraint_code(struct_name, types, field_types = nothing)
Given a vector of n
Union{SymbolFun,_UnionSymbolFS{SymbolFun}}
or Union{SymbolSet,_UnionSymbolFS{SymbolSet}}
in types
, defines a subtype of StructOfConstraints
of name name
and which type parameters {T, F1, F2, ..., Fn}
if field_types
is nothing
and a {T}
otherwise. It contains n
field where the i
th field has type Ci
if field_types
is nothing
and type field_types[i]
otherwise. If types
is vector of Union{SymbolFun,_UnionSymbolFS{SymbolFun}}
(resp. Union{SymbolSet,_UnionSymbolFS{SymbolSet}}
) then the constraints of that function (resp. set) type are stored in the corresponding field.
This function is used by the macros @model
, @struct_of_constraints_by_function_types
and @struct_of_constraints_by_set_types
.
Caching optimizer
MathOptInterface.Utilities.CachingOptimizer
— TypeCachingOptimizer
CachingOptimizer
is an intermediate layer that stores a cache of the model and links it with an optimizer. It supports incremental model construction and modification even when the optimizer doesn't.
Constructors
CachingOptimizer(cache::MOI.ModelLike, optimizer::AbstractOptimizer)
Creates a CachingOptimizer
in AUTOMATIC
mode, with the optimizer optimizer
.
The type of the optimizer returned is CachingOptimizer{typeof(optimizer), typeof(cache)}
so it does not support the function reset_optimizer(::CachingOptimizer, new_optimizer)
if the type of new_optimizer
is different from the type of optimizer
.
CachingOptimizer(cache::MOI.ModelLike, mode::CachingOptimizerMode)
Creates a CachingOptimizer
in the NO_OPTIMIZER
state and mode mode
.
The type of the optimizer returned is CachingOptimizer{MOI.AbstractOptimizer,typeof(cache)}
so it does support the function reset_optimizer(::CachingOptimizer, new_optimizer)
if the type of new_optimizer
is different from the type of optimizer
.
About the type
States
A CachingOptimizer
may be in one of three possible states (CachingOptimizerState
):
NO_OPTIMIZER
: The CachingOptimizer does not have any optimizer.EMPTY_OPTIMIZER
: The CachingOptimizer has an empty optimizer. The optimizer is not synchronized with the cached model.ATTACHED_OPTIMIZER
: The CachingOptimizer has an optimizer, and it is synchronized with the cached model.
Modes
A CachingOptimizer
has two modes of operation (CachingOptimizerMode
):
MANUAL
: The only methods that change the state of theCachingOptimizer
areUtilities.reset_optimizer
,Utilities.drop_optimizer
, andUtilities.attach_optimizer
. Attempting to perform an operation in the incorrect state results in an error.AUTOMATIC
: TheCachingOptimizer
changes its state when necessary. For example,optimize!
will automatically callattach_optimizer
(an optimizer must have been previously set). Attempting to add a constraint or perform a modification not supported by the optimizer results in a drop toEMPTY_OPTIMIZER
mode.
MathOptInterface.Utilities.attach_optimizer
— Functionattach_optimizer(model::CachingOptimizer)
Attaches the optimizer to model
, copying all model data into it. Can be called only from the EMPTY_OPTIMIZER
state. If the copy succeeds, the CachingOptimizer
will be in state ATTACHED_OPTIMIZER
after the call, otherwise an error is thrown; see MOI.copy_to
for more details on which errors can be thrown.
MOIU.attach_optimizer(model::GenericModel)
Call MOIU.attach_optimizer
on the backend of model
.
Cannot be called in direct mode.
MathOptInterface.Utilities.reset_optimizer
— Functionreset_optimizer(m::CachingOptimizer, optimizer::MOI.AbstractOptimizer)
Sets or resets m
to have the given empty optimizer optimizer
.
Can be called from any state. An assertion error will be thrown if optimizer
is not empty.
The CachingOptimizer
m
will be in state EMPTY_OPTIMIZER
after the call.
reset_optimizer(m::CachingOptimizer)
Detaches and empties the current optimizer. Can be called from ATTACHED_OPTIMIZER
or EMPTY_OPTIMIZER
state. The CachingOptimizer
will be in state EMPTY_OPTIMIZER
after the call.
MOIU.reset_optimizer(model::GenericModel, optimizer::MOI.AbstractOptimizer)
Call MOIU.reset_optimizer
on the backend of model
.
Cannot be called in direct mode.
MOIU.reset_optimizer(model::GenericModel)
Call MOIU.reset_optimizer
on the backend of model
.
Cannot be called in direct mode.
MathOptInterface.Utilities.drop_optimizer
— Functiondrop_optimizer(m::CachingOptimizer)
Drops the optimizer, if one is present. Can be called from any state. The CachingOptimizer
will be in state NO_OPTIMIZER
after the call.
MOIU.drop_optimizer(model::GenericModel)
Call MOIU.drop_optimizer
on the backend of model
.
Cannot be called in direct mode.
MathOptInterface.Utilities.state
— Functionstate(m::CachingOptimizer)::CachingOptimizerState
Returns the state of the CachingOptimizer m
. See Utilities.CachingOptimizer
.
MathOptInterface.Utilities.mode
— Functionmode(m::CachingOptimizer)::CachingOptimizerMode
Returns the operating mode of the CachingOptimizer m
. See Utilities.CachingOptimizer
.
Mock optimizer
MathOptInterface.Utilities.MockOptimizer
— TypeMockOptimizer
MockOptimizer
is a fake optimizer especially useful for testing. Its main feature is that it can store the values that should be returned for each attribute.
Printing
MathOptInterface.Utilities.latex_formulation
— Functionlatex_formulation(model::MOI.ModelLike; kwargs...)
Wrap model
in a type so that it can be pretty-printed as text/latex
in a notebook like IJulia, or in Documenter.
To render the model, end the cell with latex_formulation(model)
, or call display(latex_formulation(model))
in to force the display of the model from inside a function.
Possible keyword arguments are:
simplify_coefficients
: Simplify coefficients if possible by omitting them or removing trailing zeros.default_name
: The name given to variables with an empty name.print_types
: Print the MOI type of each function and set for clarity.
Copy utilities
MathOptInterface.Utilities.default_copy_to
— Functiondefault_copy_to(dest::MOI.ModelLike, src::MOI.ModelLike)
A default implementation of MOI.copy_to(dest, src)
for models that implement the incremental interface, that is, MOI.supports_incremental_interface
returns true
.
MathOptInterface.Utilities.IndexMap
— TypeIndexMap()
The dictionary-like object returned by MOI.copy_to
.
MathOptInterface.Utilities.identity_index_map
— Functionidentity_index_map(model::MOI.ModelLike)
Return an IndexMap
that maps all variable and constraint indices of model
to themselves.
MathOptInterface.Utilities.ModelFilter
— TypeModelFilter(filter::Function, model::MOI.ModelLike)
A layer to filter out various components of model
.
The filter function takes a single argument, which is each element from the list returned by the attributes below. It returns true
if the element should be visible in the filtered model and false
otherwise.
The components that are filtered are:
- Entire constraint types via:
MOI.ListOfConstraintTypesPresent
- Individual constraints via:
MOI.ListOfConstraintIndices{F,S}
- Specific attributes via:
MOI.ListOfModelAttributesSet
MOI.ListOfConstraintAttributesSet
MOI.ListOfVariableAttributesSet
The list of attributes filtered may change in a future release. You should write functions that are generic and not limited to the five types listed above. Thus, you should probably define a fallback filter(::Any) = true
.
See below for examples of how this works.
This layer has a limited scope. It is intended by be used in conjunction with MOI.copy_to
.
Example: copy model excluding integer constraints
Use the do
syntax to provide a single function.
filtered_src = MOI.Utilities.ModelFilter(src) do item
return item != (MOI.VariableIndex, MOI.Integer)
end
MOI.copy_to(dest, filtered_src)
Example: copy model excluding names
Use type dispatch to simplify the implementation:
my_filter(::Any) = true # Note the generic fallback
my_filter(::MOI.VariableName) = false
my_filter(::MOI.ConstraintName) = false
filtered_src = MOI.Utilities.ModelFilter(my_filter, src)
MOI.copy_to(dest, filtered_src)
Example: copy irreducible infeasible subsystem
my_filter(::Any) = true # Note the generic fallback
function my_filter(ci::MOI.ConstraintIndex)
status = MOI.get(dest, MOI.ConstraintConflictStatus(), ci)
return status != MOI.NOT_IN_CONFLICT
end
filtered_src = MOI.Utilities.ModelFilter(my_filter, src)
MOI.copy_to(dest, filtered_src)
MathOptInterface.Utilities.loadfromstring!
— Functionloadfromstring!(model, s)
A utility function to aid writing tests.
This function is not intended for widespread use. It is mainly used as a tool to simplify writing tests in MathOptInterface. Do not use it as an exchange format for storing or transmitting problem instances. Use the FileFormats submodule instead.
Example
julia> model = MOI.Utilities.Model{Float64}();
julia> MOI.Utilities.loadfromstring!(model, """
variables: x, y, z
constrainedvariable: [a, b, c] in Nonnegatives(3)
minobjective::Float64: 2x + 3y
con1: x + y <= 1.0
con2: [x, y] in Nonnegatives(2)
x >= 0.0
""")
Notes
Special labels are:
- variables
- minobjective
- maxobjectives
Everything else denotes a constraint with a name.
Append ::T
to use an element type of T
when parsing the function.
Do not name VariableIndex
constraints.
Exceptions
x - y
does NOT currently parse. Instead, writex + -1.0 * y
.x^2
does NOT currently parse. Instead, writex * x
.
Penalty relaxation
MathOptInterface.Utilities.PenaltyRelaxation
— TypePenaltyRelaxation(
penalties = Dict{MOI.ConstraintIndex,Float64}();
default::Union{Nothing,T} = 1.0,
)
A problem modifier that, when passed to MOI.modify
, destructively modifies the model in-place to create a penalized relaxation of the constraints.
This is a destructive routine that modifies the model in-place. If you don't want to modify the original model, use JuMP.copy_model
to create a copy before calling MOI.modify
.
Reformulation
See Utilities.ScalarPenaltyRelaxation
for details of the reformulation.
For each constraint ci
, the penalty passed to Utilities.ScalarPenaltyRelaxation
is get(penalties, ci, default)
. If the value is nothing
, because ci
does not exist in penalties
and default = nothing
, then the constraint is skipped.
Return value
MOI.modify(model, PenaltyRelaxation())
returns a Dict{MOI.ConstraintIndex,MOI.ScalarAffineFunction}
that maps each constraint index to the corresponding y + z
as a MOI.ScalarAffineFunction
. In an optimal solution, query the value of these functions to compute the violation of each constraint.
Relax a subset of constraints
To relax a subset of constraints, pass a penalties
dictionary and set default = nothing
.
Supported constraint types
The penalty relaxation is currently limited to modifying MOI.ScalarAffineFunction
and MOI.ScalarQuadraticFunction
constraints in the linear sets MOI.LessThan
, MOI.GreaterThan
, MOI.EqualTo
and MOI.Interval
.
It does not include variable bound or integrality constraints, because these cannot be modified in-place.
To modify variable bounds, rewrite them as linear constraints.
Example
julia> model = MOI.Utilities.Model{Float64}();
julia> x = MOI.add_variable(model);
julia> c = MOI.add_constraint(model, 1.0 * x, MOI.LessThan(2.0));
julia> map = MOI.modify(model, MOI.Utilities.PenaltyRelaxation(default = 2.0));
julia> print(model)
Minimize ScalarAffineFunction{Float64}:
0.0 + 2.0 v[2]
Subject to:
ScalarAffineFunction{Float64}-in-LessThan{Float64}
0.0 + 1.0 v[1] - 1.0 v[2] <= 2.0
VariableIndex-in-GreaterThan{Float64}
v[2] >= 0.0
julia> map[c] isa MOI.ScalarAffineFunction{Float64}
true
julia> model = MOI.Utilities.Model{Float64}();
julia> x = MOI.add_variable(model);
julia> c = MOI.add_constraint(model, 1.0 * x, MOI.LessThan(2.0));
julia> map = MOI.modify(model, MOI.Utilities.PenaltyRelaxation(Dict(c => 3.0)));
julia> print(model)
Minimize ScalarAffineFunction{Float64}:
0.0 + 3.0 v[2]
Subject to:
ScalarAffineFunction{Float64}-in-LessThan{Float64}
0.0 + 1.0 v[1] - 1.0 v[2] <= 2.0
VariableIndex-in-GreaterThan{Float64}
v[2] >= 0.0
julia> map[c] isa MOI.ScalarAffineFunction{Float64}
true
MathOptInterface.Utilities.ScalarPenaltyRelaxation
— TypeScalarPenaltyRelaxation(penalty::T) where {T}
A problem modifier that, when passed to MOI.modify
, destructively modifies the constraint in-place to create a penalized relaxation of the constraint.
This is a destructive routine that modifies the constraint in-place. If you don't want to modify the original model, use JuMP.copy_model
to create a copy before calling MOI.modify
.
Reformulation
The penalty relaxation modifies constraints of the form $f(x) \in S$ into $f(x) + y - z \in S$, where $y, z \ge 0$, and then it introduces a penalty term into the objective of $a \times (y + z)$ (if minimizing, else $-a$), where $a$ is penalty
When S
is MOI.LessThan
or MOI.GreaterThan
, we omit y
or z
respectively as a performance optimization.
Return value
MOI.modify(model, ci, ScalarPenaltyRelaxation(penalty))
returns y + z
as a MOI.ScalarAffineFunction
. In an optimal solution, query the value of this function to compute the violation of the constraint.
Example
julia> model = MOI.Utilities.Model{Float64}();
julia> x = MOI.add_variable(model);
julia> c = MOI.add_constraint(model, 1.0 * x, MOI.LessThan(2.0));
julia> f = MOI.modify(model, c, MOI.Utilities.ScalarPenaltyRelaxation(2.0));
julia> print(model)
Minimize ScalarAffineFunction{Float64}:
0.0 + 2.0 v[2]
Subject to:
ScalarAffineFunction{Float64}-in-LessThan{Float64}
0.0 + 1.0 v[1] - 1.0 v[2] <= 2.0
VariableIndex-in-GreaterThan{Float64}
v[2] >= 0.0
julia> f isa MOI.ScalarAffineFunction{Float64}
true
MatrixOfConstraints
MathOptInterface.Utilities.MatrixOfConstraints
— Typemutable struct MatrixOfConstraints{T,AT,BT,ST} <: MOI.ModelLike
coefficients::AT
constants::BT
sets::ST
caches::Vector{Any}
are_indices_mapped::Vector{BitSet}
final_touch::Bool
end
Represent ScalarAffineFunction
and VectorAffinefunction
constraints in a matrix form where the linear coefficients of the functions are stored in the coefficients
field, the constants of the functions or sets are stored in the constants
field. Additional information about the sets are stored in the sets
field.
This model can only be used as the constraints
field of a MOI.Utilities.AbstractModel
.
When the constraints are added, they are stored in the caches
field. They are only loaded in the coefficients
and constants
fields once MOI.Utilities.final_touch
is called. For this reason, MatrixOfConstraints
should not be used by an incremental interface. Use MOI.copy_to
instead.
The constraints can be added in two different ways:
- With
add_constraint
, in which case a canonicalized copy of the function is stored incaches
. - With
pass_nonvariable_constraints
, in which case the functions and sets are stored themselves incaches
without mapping the variable indices. The corresponding index incaches
is added inare_indices_mapped
. This avoids doing a copy of the function in case the getter ofCanonicalConstraintFunction
does not make a copy for the source model, for example, this is the case ofVectorOfConstraints
.
We illustrate this with an example. Suppose a model is copied from a src::MOI.Utilities.Model
to a bridged model with a MatrixOfConstraints
. For all the types that are not bridged, the constraints will be copied with pass_nonvariable_constraints
. Hence the functions stored in caches
are exactly the same as the ones stored in src
. This is ok since this is only during the copy_to
operation during which src
cannot be modified. On the other hand, for the types that are bridged, the functions added may contain duplicates even if the functions did not contain duplicates in src
so duplicates are removed with MOI.Utilities.canonical
.
Interface
The .coefficients::AT
type must implement:
AT()
MOI.empty(::AT)!
MOI.Utilities.add_column
MOI.Utilities.set_number_of_rows
MOI.Utilities.allocate_terms
MOI.Utilities.load_terms
MOI.Utilities.final_touch
The .constants::BT
type must implement:
BT()
Base.empty!(::BT)
Base.resize(::BT)
MOI.Utilities.load_constants
MOI.Utilities.function_constants
MOI.Utilities.set_from_constants
The .sets::ST
type must implement:
ST()
MOI.is_empty(::ST)
MOI.empty(::ST)
MOI.dimension(::ST)
MOI.is_valid(::ST, ::MOI.ConstraintIndex)
MOI.get(::ST, ::MOI.ListOfConstraintTypesPresent)
MOI.get(::ST, ::MOI.NumberOfConstraints)
MOI.get(::ST, ::MOI.ListOfConstraintIndices)
MOI.Utilities.set_types
MOI.Utilities.set_index
MOI.Utilities.add_set
MOI.Utilities.rows
MOI.Utilities.final_touch
.coefficients
MathOptInterface.Utilities.add_column
— Functionadd_column(coefficients)::Nothing
Tell coefficients
to pre-allocate datastructures as needed to store one column.
MathOptInterface.Utilities.allocate_terms
— Functionallocate_terms(coefficients, index_map, func)::Nothing
Tell coefficients
that the terms of the function func
where the variable indices are mapped with index_map
will be loaded with load_terms
.
The function func
must be canonicalized before calling allocate_terms
. See is_canonical
.
MathOptInterface.Utilities.set_number_of_rows
— Functionset_number_of_rows(coefficients, n)::Nothing
Tell coefficients
to pre-allocate datastructures as needed to store n
rows.
MathOptInterface.Utilities.load_terms
— Functionload_terms(coefficients, index_map, func, offset)::Nothing
Loads the terms of func
to coefficients
, mapping the variable indices with index_map
.
The i
th dimension of func
is loaded at the (offset + i)
th row of coefficients
.
The function must be allocated first with allocate_terms
.
The function func
must be canonicalized, see is_canonical
.
MathOptInterface.Utilities.final_touch
— Functionfinal_touch(coefficients)::Nothing
Informs the coefficients
that all functions have been added with load_terms
. No more modification is allowed unless MOI.empty!
is called.
final_touch(sets)::Nothing
Informs the sets
that all functions have been added with add_set
. No more modification is allowed unless MOI.empty!
is called.
MathOptInterface.Utilities.extract_function
— Functionextract_function(coefficients, row::Integer, constant::T) where {T}
Return the MOI.ScalarAffineFunction{T}
function corresponding to row row
in coefficients
.
extract_function(
coefficients,
rows::UnitRange,
constants::Vector{T},
) where{T}
Return the MOI.VectorAffineFunction{T}
function corresponding to rows rows
in coefficients
.
MathOptInterface.Utilities.MutableSparseMatrixCSC
— Typemutable struct MutableSparseMatrixCSC{Tv,Ti<:Integer,I<:AbstractIndexing}
indexing::I
m::Int
n::Int
colptr::Vector{Ti}
rowval::Vector{Ti}
nzval::Vector{Tv}
nz_added::Vector{Ti}
end
Matrix type loading sparse matrices in the Compressed Sparse Column format. The indexing used is indexing
, see AbstractIndexing
. The other fields have the same meaning than for SparseArrays.SparseMatrixCSC
except that the indexing is different unless indexing
is OneBasedIndexing
. In addition, nz_added
is used to cache the number of non-zero terms that have been added to each column due to the incremental nature of load_terms
.
The matrix is loaded in 5 steps:
MOI.empty!
is called.MOI.Utilities.add_column
andMOI.Utilities.allocate_terms
are called in any order.MOI.Utilities.set_number_of_rows
is called.MOI.Utilities.load_terms
is called for each affine function.MOI.Utilities.final_touch
is called.
MathOptInterface.Utilities.AbstractIndexing
— Typeabstract type AbstractIndexing end
Indexing to be used for storing the row and column indices of MutableSparseMatrixCSC
. See ZeroBasedIndexing
and OneBasedIndexing
.
MathOptInterface.Utilities.ZeroBasedIndexing
— Typestruct ZeroBasedIndexing <: AbstractIndexing end
Zero-based indexing: the i
th row or column has index i - 1
. This is useful when the vectors of row and column indices need to be communicated to a library using zero-based indexing such as C libraries.
MathOptInterface.Utilities.OneBasedIndexing
— Typestruct ZeroBasedIndexing <: AbstractIndexing end
One-based indexing: the i
th row or column has index i
. This enables an allocation-free conversion of MutableSparseMatrixCSC
to SparseArrays.SparseMatrixCSC
.
.constants
MathOptInterface.Utilities.load_constants
— Functionload_constants(constants, offset, func_or_set)::Nothing
This function loads the constants of func_or_set
in constants
at an offset of offset
. Where offset
is the sum of the dimensions of the constraints already loaded. The storage should be preallocated with resize!
before calling this function.
This function should be implemented to be usable as storage of constants for MatrixOfConstraints
.
The constants are loaded in three steps:
Base.empty!
is called.Base.resize!
is called with the sum of the dimensions of all constraints.MOI.Utilities.load_constants
is called for each function for vector constraint or set for scalar constraint.
MathOptInterface.Utilities.function_constants
— Functionfunction_constants(constants, rows)
This function returns the function constants that were loaded with load_constants
at the rows rows
.
This function should be implemented to be usable as storage of constants for MatrixOfConstraints
.
MathOptInterface.Utilities.set_from_constants
— Functionset_from_constants(constants, S::Type, rows)::S
This function returns an instance of the set S
for which the constants where loaded with load_constants
at the rows rows
.
This function should be implemented to be usable as storage of constants for MatrixOfConstraints
.
MathOptInterface.Utilities.modify_constants
— Functionmodify_constants(constants, row::Integer, new_constant::T) where {T}
modify_constants(
constants,
rows::AbstractVector{<:Integer},
new_constants::AbstractVector{T},
) where {T}
Modify constants
in-place to store new_constant
in the row
row, or rows rows
.
This function must be implemented to enable MOI.ScalarConstantChange
and MOI.VectorConstantChange
for MatrixOfConstraints
.
MathOptInterface.Utilities.Hyperrectangle
— Typestruct Hyperrectangle{T} <: AbstractVectorBounds
lower::Vector{T}
upper::Vector{T}
end
A struct for the .constants field in MatrixOfConstraints.
.sets
MathOptInterface.Utilities.set_index
— Functionset_index(sets, ::Type{S})::Union{Int,Nothing} where {S<:MOI.AbstractSet}
Return an integer corresponding to the index of the set type in the list given by set_types
.
If S
is not part of the list, return nothing
.
MathOptInterface.Utilities.set_types
— Functionset_types(sets)::Vector{Type}
Return the list of the types of the sets allowed in sets
.
MathOptInterface.Utilities.add_set
— Functionadd_set(sets, i)::Int64
Add a scalar set of type index i
.
add_set(sets, i, dim)::Int64
Add a vector set of type index i
and dimension dim
.
Both methods return a unique Int64
of the set that can be used to reference this set.
MathOptInterface.Utilities.rows
— Functionrows(sets, ci::MOI.ConstraintIndex)::Union{Int,UnitRange{Int}}
Return the rows in 1:MOI.dimension(sets)
corresponding to the set of id ci.value
.
For scalar sets, this returns an Int
. For vector sets, this returns an UnitRange{Int}
.
MathOptInterface.Utilities.num_rows
— Functionnum_rows(sets::OrderedProductOfSets, ::Type{S}) where {S}
Return the number of rows corresponding to a set of type S
. That is, it is the sum of the dimensions of the sets of type S
.
MathOptInterface.Utilities.set_with_dimension
— Functionset_with_dimension(::Type{S}, dim) where {S<:MOI.AbstractVectorSet}
Returns the instance of S
of MOI.dimension
dim
. This needs to be implemented for sets of type S
to be useable with MatrixOfConstraints
.
MathOptInterface.Utilities.ProductOfSets
— Typeabstract type ProductOfSets{T} end
Represents a cartesian product of sets of given types.
MathOptInterface.Utilities.MixOfScalarSets
— Typeabstract type MixOfScalarSets{T} <: ProductOfSets{T} end
Product of scalar sets in the order the constraints are added, mixing the constraints of different types.
Use @mix_of_scalar_sets
to generate a new subtype.
MathOptInterface.Utilities.@mix_of_scalar_sets
— Macro@mix_of_scalar_sets(name, set_types...)
Generate a new MixOfScalarSets
subtype.
Example
julia> import MathOptInterface as MOI
julia> MOI.Utilities.@mix_of_scalar_sets(
MixedIntegerLinearProgramSets,
MOI.GreaterThan{T},
MOI.LessThan{T},
MOI.EqualTo{T},
MOI.Integer,
)
MathOptInterface.Utilities.OrderedProductOfSets
— Typeabstract type OrderedProductOfSets{T} <: ProductOfSets{T} end
Product of sets in the order the constraints are added, grouping the constraints of the same types contiguously.
Use @product_of_sets
to generate new subtypes.
MathOptInterface.Utilities.@product_of_sets
— Macro@product_of_sets(name, set_types...)
Generate a new OrderedProductOfSets
subtype.
Example
julia> import MathOptInterface as MOI
julia> MOI.Utilities.@product_of_sets(
LinearOrthants,
MOI.Zeros,
MOI.Nonnegatives,
MOI.Nonpositives,
MOI.ZeroOne,
)
Fallbacks
MathOptInterface.Utilities.get_fallback
— Functionget_fallback(model::MOI.ModelLike, ::MOI.ObjectiveValue)
Compute the objective function value using the VariablePrimal
results and the ObjectiveFunction
value.
get_fallback(
model::MOI.ModelLike,
::MOI.DualObjectiveValue,
::Type{T},
)::T where {T}
Compute the dual objective value of type T
using the ConstraintDual
results and the ConstraintFunction
and ConstraintSet
values.
Note that the nonlinear part of the model is ignored.
get_fallback(
model::MOI.ModelLike,
::MOI.ConstraintPrimal,
constraint_index::MOI.ConstraintIndex,
)
Compute the value of the function of the constraint of index constraint_index
using the VariablePrimal
results and the ConstraintFunction
values.
get_fallback(
model::MOI.ModelLike,
attr::MOI.ConstraintDual,
ci::MOI.ConstraintIndex{Union{MOI.VariableIndex,MOI.VectorOfVariables}},
::Type{T} = Float64,
) where {T}
Compute the dual of the constraint of index ci
using the ConstraintDual
of other constraints and the ConstraintFunction
values.
Throws an error if some constraints are quadratic or if there is one another MOI.VariableIndex
-in-S
or MOI.VectorOfVariables
-in-S
constraint with one of the variables in the function of the constraint ci
.
Function utilities
The following utilities are available for functions:
MathOptInterface.Utilities.eval_variables
— Functioneval_variables(value_fn::Function, f::MOI.AbstractFunction)
Returns the value of function f
if each variable index vi
is evaluated as value_fn(vi)
.
Note that value_fn
must return a Number. See substitute_variables
for a similar function where value_fn
returns an MOI.AbstractScalarFunction
.
The two-argument version of eval_variables
is deprecated and may be removed in MOI v2.0.0. Use the three-argument method eval_variables(::Function, ::MOI.ModelLike, ::MOI.AbstractFunction)
instead.
MathOptInterface.Utilities.map_indices
— Functionmap_indices(index_map::Function, attr::MOI.AnyAttribute, x::X)::X where {X}
Substitute any MOI.VariableIndex
(resp. MOI.ConstraintIndex
) in x
by the MOI.VariableIndex
(resp. MOI.ConstraintIndex
) of the same type given by index_map(x)
.
When to implement this method for new types X
This function is used by implementations of MOI.copy_to
on constraint functions, attribute values and submittable values. If you define a new attribute whose values x::X
contain variable or constraint indices, you must also implement this function.
map_indices(
variable_map::AbstractDict{T,T},
x::X,
)::X where {T<:MOI.Index,X}
Shortcut for map_indices(vi -> variable_map[vi], x)
.
MathOptInterface.Utilities.substitute_variables
— Functionsubstitute_variables(variable_map::Function, x)
Substitute any MOI.VariableIndex
in x
by variable_map(x)
. The variable_map
function returns either MOI.VariableIndex
or MOI.ScalarAffineFunction
, see eval_variables
for a similar function where variable_map
returns a number.
This function is used by bridge optimizers on constraint functions, attribute values and submittable values when at least one variable bridge is used hence it needs to be implemented for custom types that are meant to be used as attribute or submittable value.
When implementing a new method, don't use substitute_variables(::Function
, because Julia will not specialize on it. Use instead substitute_variables(::F, ...) where {F<:Function}
.
MathOptInterface.Utilities.filter_variables
— Functionfilter_variables(keep::Function, f::AbstractFunction)
Return a new function f
with the variable vi
such that !keep(vi)
removed.
WARNING: Don't define filter_variables(::Function, ...)
because Julia will not specialize on this. Define instead filter_variables(::F, ...) where {F<:Function}
.
MathOptInterface.Utilities.remove_variable
— Functionremove_variable(f::AbstractFunction, vi::VariableIndex)
Return a new function f
with the variable vi removed.
remove_variable(
f::MOI.AbstractFunction,
s::MOI.AbstractSet,
vi::MOI.VariableIndex,
)
Return a tuple (g, t)
representing the constraint f
-in-s
with the variable vi
removed. That is, the terms containing the variable vi
in the function f
are removed and the dimension of the set s
is updated if needed (for example, when f
is a VectorOfVariables
with vi
being one of the variables).
MathOptInterface.Utilities.all_coefficients
— Functionall_coefficients(p::Function, f::MOI.AbstractFunction)
Determine whether predicate p
returns true
for all coefficients of f
, returning false
as soon as the first coefficient of f
for which p
returns false
is encountered (short-circuiting). Similar to all
.
MathOptInterface.Utilities.unsafe_add
— Functionunsafe_add(t1::MOI.ScalarAffineTerm, t2::MOI.ScalarAffineTerm)
Sums the coefficients of t1
and t2
and returns an output MOI.ScalarAffineTerm
. It is unsafe because it uses the variable
of t1
as the variable
of the output without checking that it is equal to that of t2
.
unsafe_add(t1::MOI.ScalarQuadraticTerm, t2::MOI.ScalarQuadraticTerm)
Sums the coefficients of t1
and t2
and returns an output MOI.ScalarQuadraticTerm
. It is unsafe because it uses the variable
's of t1
as the variable
's of the output without checking that they are the same (up to permutation) to those of t2
.
unsafe_add(t1::MOI.VectorAffineTerm, t2::MOI.VectorAffineTerm)
Sums the coefficients of t1
and t2
and returns an output MOI.VectorAffineTerm
. It is unsafe because it uses the output_index
and variable
of t1
as the output_index
and variable
of the output term without checking that they are equal to those of t2
.
MathOptInterface.Utilities.isapprox_zero
— Functionisapprox_zero(f::MOI.AbstractFunction, tol)
Return a Bool
indicating whether the function f
is approximately zero using tol
as a tolerance.
Important note
This function assumes that f
does not contain any duplicate terms, you might want to first call canonical
if that is not guaranteed.
Example
julia> import MathOptInterface as MOI
julia> x = MOI.VariableIndex(1)
MOI.VariableIndex(1)
julia> f = MOI.ScalarAffineFunction(MOI.ScalarAffineTerm.([1, -1], [x, x]), 0)
(0) + (1) MOI.VariableIndex(1) - (1) MOI.VariableIndex(1)
julia> MOI.Utilities.isapprox_zero(f, 1e-8)
false
julia> MOI.Utilities.isapprox_zero(MOI.Utilities.canonical(f), 1e-8)
true
MathOptInterface.Utilities.modify_function
— Functionmodify_function(f::AbstractFunction, change::AbstractFunctionModification)
Return a copy of the function f
, modified according to change
.
MathOptInterface.Utilities.zero_with_output_dimension
— Functionzero_with_output_dimension(::Type{T}, output_dimension::Integer) where {T}
Create an instance of type T
with the output dimension output_dimension
.
This is mostly useful in Bridges, when code needs to be agnostic to the type of vector-valued function that is passed in.
The following functions can be used to canonicalize a function:
MathOptInterface.Utilities.is_canonical
— Functionis_canonical(f::Union{ScalarAffineFunction, VectorAffineFunction})
Returns a Bool indicating whether the function is in canonical form. See canonical
.
is_canonical(f::Union{ScalarQuadraticFunction, VectorQuadraticFunction})
Returns a Bool indicating whether the function is in canonical form. See canonical
.
MathOptInterface.Utilities.canonical
— Functioncanonical(f::MOI.AbstractFunction)
Returns the function in a canonical form, that is,
- A term appear only once.
- The coefficients are nonzero.
- The terms appear in increasing order of variable where there the order of the variables is the order of their value.
- For a
AbstractVectorFunction
, the terms are sorted in ascending order of output index.
The output of canonical
can be assumed to be a copy of f
, even for VectorOfVariables
.
Example
julia> import MathOptInterface as MOI
julia> x, y, z = MOI.VariableIndex.(1:3);
julia> f = MOI.ScalarAffineFunction(
MOI.ScalarAffineTerm.(Float64[2, 1, 3, -2, -3], [y, x, z, x, z]),
5.0,
)
5.0 + 2.0 MOI.VariableIndex(2) + 1.0 MOI.VariableIndex(1) + 3.0 MOI.VariableIndex(3) - 2.0 MOI.VariableIndex(1) - 3.0 MOI.VariableIndex(3)
julia> MOI.Utilities.canonical(f)
5.0 - 1.0 MOI.VariableIndex(1) + 2.0 MOI.VariableIndex(2)
MathOptInterface.Utilities.canonicalize!
— Functioncanonicalize!(f::Union{ScalarAffineFunction, VectorAffineFunction})
Convert a function to canonical form in-place, without allocating a copy to hold the result. See canonical
.
canonicalize!(f::Union{ScalarQuadraticFunction, VectorQuadraticFunction})
Convert a function to canonical form in-place, without allocating a copy to hold the result. See canonical
.
The following functions can be used to manipulate functions with basic algebra:
MathOptInterface.Utilities.scalar_type
— Functionscalar_type(F::Type{<:MOI.AbstractVectorFunction})
Type of functions obtained by indexing objects obtained by calling eachscalar
on functions of type F
.
MathOptInterface.Utilities.scalarize
— Functionscalarize(func::MOI.VectorOfVariables, ignore_constants::Bool = false)
Returns a vector of scalar functions making up the vector function in the form of a Vector{MOI.SingleVariable}
.
See also eachscalar
.
scalarize(func::MOI.VectorAffineFunction{T}, ignore_constants::Bool = false)
Returns a vector of scalar functions making up the vector function in the form of a Vector{MOI.ScalarAffineFunction{T}}
.
See also eachscalar
.
scalarize(func::MOI.VectorQuadraticFunction{T}, ignore_constants::Bool = false)
Returns a vector of scalar functions making up the vector function in the form of a Vector{MOI.ScalarQuadraticFunction{T}}
.
See also eachscalar
.
MathOptInterface.Utilities.eachscalar
— Functioneachscalar(f::MOI.AbstractVectorFunction)
Returns an iterator for the scalar components of the vector function.
See also scalarize
.
eachscalar(f::MOI.AbstractVector)
Returns an iterator for the scalar components of the vector.
MathOptInterface.Utilities.promote_operation
— Functionpromote_operation(
op::Function,
::Type{T},
ArgsTypes::Type{<:Union{T,AbstractVector{T},MOI.AbstractFunction}}...,
) where {T<:Number}
Compute the return type of the call operate(op, T, args...)
, where the types of the arguments args
are ArgsTypes
.
One assumption is that the element type T
is invariant under each operation. That is, op(::T, ::T)::T
where op
is a +
, -
, *
, and /
.
There are six methods for which we implement Utilities.promote_operation
:
+
a.promote_operation(::typeof(+), ::Type{T}, ::Type{F1}, ::Type{F2})
-
a.promote_operation(::typeof(-), ::Type{T}, ::Type{F})
b.promote_operation(::typeof(-), ::Type{T}, ::Type{F1}, ::Type{F2})
*
a.promote_operation(::typeof(*), ::Type{T}, ::Type{T}, ::Type{F})
b.promote_operation(::typeof(*), ::Type{T}, ::Type{F}, ::Type{T})
c.promote_operation(::typeof(*), ::Type{T}, ::Type{F1}, ::Type{F2})
whereF1
andF2
areVariableIndex
orScalarAffineFunction
d.promote_operation(::typeof(*), ::Type{T}, ::Type{<:Diagonal{T}}, ::Type{F}
/
a.promote_operation(::typeof(/), ::Type{T}, ::Type{F}, ::Type{T})
vcat
a.promote_operation(::typeof(vcat), ::Type{T}, ::Type{F}...)
imag
a.promote_operation(::typeof(imag), ::Type{T}, ::Type{F})
whereF
isVariableIndex
orVectorOfVariables
In each case, F
(or F1
and F2
) is one of the ten supported types, with a restriction that the mathematical operation makes sense, for example, we don't define promote_operation(-, T, F1, F2)
where F1
is a scalar-valued function and F2
is a vector-valued function. The ten supported types are:
- ::T
- ::VariableIndex
- ::ScalarAffineFunction{T}
- ::ScalarQuadraticFunction{T}
- ::ScalarNonlinearFunction
- ::AbstractVector{T}
- ::VectorOfVariables
- ::VectorAffineFunction{T}
- ::VectorQuadraticFunction{T}
- ::VectorNonlinearFunction
MathOptInterface.Utilities.operate
— Functionoperate(
op::Function,
::Type{T},
args::Union{T,MOI.AbstractFunction}...,
)::MOI.AbstractFunction where {T<:Number}
Returns an MOI.AbstractFunction
representing the function resulting from the operation op(args...)
on functions of coefficient type T
.
No argument can be modified.
Methods
+
a.operate(::typeof(+), ::Type{T}, ::F1)
b.operate(::typeof(+), ::Type{T}, ::F1, ::F2)
c.operate(::typeof(+), ::Type{T}, ::F1...)
-
a.operate(::typeof(-), ::Type{T}, ::F)
b.operate(::typeof(-), ::Type{T}, ::F1, ::F2)
*
a.operate(::typeof(*), ::Type{T}, ::T, ::F)
b.operate(::typeof(*), ::Type{T}, ::F, ::T)
c.operate(::typeof(*), ::Type{T}, ::F1, ::F2)
whereF1
andF2
areVariableIndex
orScalarAffineFunction
d.operate(::typeof(*), ::Type{T}, ::Diagonal{T}, ::F)
/
a.operate(::typeof(/), ::Type{T}, ::F, ::T)
vcat
a.operate(::typeof(vcat), ::Type{T}, ::F...)
imag
a.operate(::typeof(imag), ::Type{T}, ::F)
whereF
isVariableIndex
orVectorOfVariables
One assumption is that the element type T
is invariant under each operation. That is, op(::T, ::T)::T
where op
is a +
, -
, *
, and /
.
In each case, F
(or F1
and F2
) is one of the ten supported types, with a restriction that the mathematical operation makes sense, for example, we don't define promote_operation(-, T, F1, F2)
where F1
is a scalar-valued function and F2
is a vector-valued function. The ten supported types are:
- ::T
- ::VariableIndex
- ::ScalarAffineFunction{T}
- ::ScalarQuadraticFunction{T}
- ::ScalarNonlinearFunction
- ::AbstractVector{T}
- ::VectorOfVariables
- ::VectorAffineFunction{T}
- ::VectorQuadraticFunction{T}
- ::VectorNonlinearFunction
MathOptInterface.Utilities.operate!
— Functionoperate!(
op::Function,
::Type{T},
args::Union{T,MOI.AbstractFunction}...,
)::MOI.AbstractFunction where {T<:Number}
Returns an MOI.AbstractFunction
representing the function resulting from the operation op(args...)
on functions of coefficient type T
.
The first argument may be modified, in which case the return value is identical to the first argument. For operations which cannot be implemented in-place, this function returns a new object.
MathOptInterface.Utilities.operate_output_index!
— Functionoperate_output_index!(
op::Union{typeof(+),typeof(-)},
::Type{T},
output_index::Integer,
f::Union{AbstractVector{T},MOI.AbstractVectorFunction}
g::Union{T,MOI.AbstractScalarFunction}...
) where {T<:Number}
Return an MOI.AbstractVectorFunction
in which the scalar function in row output_index
is the result of op(f[output_index], g)
.
The functions at output index different to output_index
are the same as the functions at the same output index in func
. The first argument may be modified.
Methods
+
a.operate_output_index!(+, ::Type{T}, ::Int, ::VectorF, ::ScalarF)
-
a.operate_output_index!(-, ::Type{T}, ::Int, ::VectorF, ::ScalarF)
MathOptInterface.Utilities.vectorize
— Functionvectorize(x::AbstractVector{<:Number})
Returns x
.
vectorize(x::AbstractVector{MOI.VariableIndex})
Returns the vector of scalar affine functions in the form of a MOI.VectorAffineFunction{T}
.
vectorize(funcs::AbstractVector{MOI.ScalarAffineFunction{T}}) where T
Returns the vector of scalar affine functions in the form of a MOI.VectorAffineFunction{T}
.
vectorize(funcs::AbstractVector{MOI.ScalarQuadraticFunction{T}}) where T
Returns the vector of scalar quadratic functions in the form of a MOI.VectorQuadraticFunction{T}
.
Constraint utilities
The following utilities are available for moving the function constant to the set for scalar constraints:
MathOptInterface.Utilities.shift_constant
— Functionshift_constant(set::MOI.AbstractScalarSet, offset)
Returns a new scalar set new_set
such that func
-in-set
is equivalent to func + offset
-in-new_set
.
Use supports_shift_constant
to check if the set supports shifting:
if MOI.Utilities.supports_shift_constant(typeof(set))
new_set = MOI.Utilities.shift_constant(set, -func.constant)
func.constant = 0
MOI.add_constraint(model, func, new_set)
else
MOI.add_constraint(model, func, set)
end
Note for developers
Only define this function if it makes sense and you have implemented supports_shift_constant
to return true
.
Example
julia> import MathOptInterface as MOI
julia> set = MOI.Interval(-2.0, 3.0)
MathOptInterface.Interval{Float64}(-2.0, 3.0)
julia> MOI.Utilities.supports_shift_constant(typeof(set))
true
julia> MOI.Utilities.shift_constant(set, 1.0)
MathOptInterface.Interval{Float64}(-1.0, 4.0)
MathOptInterface.Utilities.supports_shift_constant
— Functionsupports_shift_constant(::Type{S}) where {S<:MOI.AbstractSet}
Return true
if shift_constant
is defined for set S
.
See also shift_constant
.
Example
julia> import MathOptInterface as MOI
julia> MOI.Utilities.supports_shift_constant(MOI.Interval{Float64})
true
julia> MOI.Utilities.supports_shift_constant(MOI.ZeroOne)
false
MathOptInterface.Utilities.normalize_and_add_constraint
— Functionnormalize_and_add_constraint(
model::MOI.ModelLike,
func::MOI.AbstractScalarFunction,
set::MOI.AbstractScalarSet;
allow_modify_function::Bool = false,
)
Adds the scalar constraint obtained by moving the constant term in func
to the set in model
. If allow_modify_function
is true
then the function func
can be modified.
MathOptInterface.Utilities.normalize_constant
— Functionnormalize_constant(
func::MOI.AbstractScalarFunction,
set::MOI.AbstractScalarSet;
allow_modify_function::Bool = false,
)
Return the func
-in-set
constraint in normalized form. That is, if func
is MOI.ScalarQuadraticFunction
or MOI.ScalarAffineFunction
, the constant is moved to the set. If allow_modify_function
is true
then the function func
can be modified.
The following utility identifies those constraints imposing bounds on a given variable, and returns those bound values:
MathOptInterface.Utilities.get_bounds
— Functionget_bounds(model::MOI.ModelLike, ::Type{T}, x::MOI.VariableIndex)
Return a tuple (lb, ub)
of type Tuple{T, T}
, where lb
and ub
are lower and upper bounds, respectively, imposed on x
in model
.
get_bounds(
model::MOI.ModelLike,
bounds_cache::Dict{MOI.VariableIndex,NTuple{2,T}},
f::MOI.ScalarAffineFunction{T},
) where {T} --> Union{Nothing,NTuple{2,T}}
Return the lower and upper bound of f
as a tuple. If the domain is not bounded, return nothing
.
get_bounds(
model::MOI.ModelLike,
bounds_cache::Dict{MOI.VariableIndex,NTuple{2,T}},
x::MOI.VariableIndex,
) where {T} --> Union{Nothing,NTuple{2,T}}
Return the lower and upper bound of x
as a tuple. If the domain is not bounded, return nothing
.
Similar to get_bounds(::MOI.ModelLike, ::Type{T}, ::MOI.VariableIndex)
, except that the second argument is a cache which maps variables to their bounds and avoids repeated lookups.
The following utilities are useful when working with symmetric matrix cones.
MathOptInterface.Utilities.is_diagonal_vectorized_index
— Functionis_diagonal_vectorized_index(index::Base.Integer)
Return whether index
is the index of a diagonal element in a MOI.AbstractSymmetricMatrixSetTriangle
set.
MathOptInterface.Utilities.side_dimension_for_vectorized_dimension
— Functionside_dimension_for_vectorized_dimension(n::Integer)
Return the dimension d
such that MOI.dimension(MOI.PositiveSemidefiniteConeTriangle(d))
is n
.
Set utilities
The following utilities are available for sets:
MathOptInterface.Utilities.AbstractDistance
— Typeabstract type AbstractDistance end
An abstract type used to enable dispatch of Utilities.distance_to_set
.
MathOptInterface.Utilities.ProjectionUpperBoundDistance
— TypeProjectionUpperBoundDistance() <: AbstractDistance
An upper bound on the minimum distance between point
and the closest feasible point in set
.
Definition of distance
The minimum distance is computed as:
\[d(x, \mathcal{K}) = \min_{y \in \mathcal{K}} || x - y ||\]
where $x$ is point
and $\mathcal{K}$ is set
. The norm is computed as:
\[||x|| = \sqrt{f(x, x, \mathcal{K})}\]
where $f$ is Utilities.set_dot
.
In the default case, where the set does not have a specialized method for Utilities.set_dot
, the norm is equivalent to the Euclidean norm $||x|| = \sqrt{\sum x_i^2}$.
Why an upper bound?
In most cases, distance_to_set
should return the smallest upper bound, but it may return a larger value if the smallest upper bound is expensive to compute.
For example, given an epigraph from of a conic set, $\{(t, x) | f(x) \le t\}$, it may be simpler to return $\delta$ such that $f(x) \le t + \delta$, rather than computing the nearest projection onto the set.
If the distance is not the smallest upper bound, the docstring of the appropriate distance_to_set
method must describe the way that the distance is computed.
MathOptInterface.Utilities.distance_to_set
— Functiondistance_to_set(
[d::AbstractDistance = ProjectionUpperBoundDistance()],]
point::T,
set::MOI.AbstractScalarSet,
) where {T}
distance_to_set(
[d::AbstractDistance = ProjectionUpperBoundDistance(),]
point::AbstractVector{T},
set::MOI.AbstractVectorSet,
) where {T}
Compute the distance between point
and set
using the distance metric d
. If point
is in the set set
, this function must return zero(T)
.
If d
is omitted, the default distance is Utilities.ProjectionUpperBoundDistance
.
distance_to_set(::ProjectionUpperBoundDistance, x, ::MOI.RotatedSecondOrderCone)
Let (t, u, y...) = x
. Return the 2-norm of the vector d
such that in x + d
, u
is projected to 1
if u <= 0
, and t
is increased such that x + d
belongs to the set.
distance_to_set(::ProjectionUpperBoundDistance, x, ::MOI.ExponentialCone)
Let (u, v, w) = x
. If v > 0
, return the epigraph distance d
such that (u, v, w + d)
belongs to the set.
If v <= 0
return the 2-norm of the vector d
such that x + d = (u, 1, z)
where z
satisfies the constraints.
distance_to_set(::ProjectionUpperBoundDistance, x, ::MOI.DualExponentialCone)
Let (u, v, w) = x
. If u < 0
, return the epigraph distance d
such that (u, v, w + d)
belongs to the set.
If u >= 0
return the 2-norm of the vector d
such that x + d = (u, -1, z)
where z
satisfies the constraints.
distance_to_set(::ProjectionUpperBoundDistance, x, ::MOI.GeometricMeanCone)
Let (t, y...) = x
. If all y
are non-negative, return the epigraph distance d
such that (t + d, y...)
belongs to the set.
If any y
are strictly negative, return the 2-norm of the vector d
that projects negative y
elements to 0
and t
to ℝ₋
.
distance_to_set(::ProjectionUpperBoundDistance, x, ::MOI.PowerCone)
Let (a, b, c) = x
. If a
and b
are non-negative, return the epigraph distance required to increase c
such that the constraint is satisfied.
If a
or b
is strictly negative, return the 2-norm of the vector d
such that in the vector x + d
: c
, and any negative a
and b
are projected to 0
.
distance_to_set(::ProjectionUpperBoundDistance, x, ::MOI.DualPowerCone)
Let (a, b, c) = x
. If a
and b
are non-negative, return the epigraph distance required to increase c
such that the constraint is satisfied.
If a
or b
is strictly negative, return the 2-norm of the vector d
such that in the vector x + d
: c
, and any negative a
and b
are projected to 0
.
distance_to_set(::ProjectionUpperBoundDistance, x, ::MOI.NormOneCone)
Let (t, y...) = x
. Return the epigraph distance d
such that (t + d, y...)
belongs to the set.
distance_to_set(::ProjectionUpperBoundDistance, x, ::MOI.NormInfinityCone)
Let (t, y...) = x
. Return the epigraph distance d
such that (t + d, y...)
belongs to the set.
distance_to_set(::ProjectionUpperBoundDistance, x, ::MOI.RelativeEntropyCone)
Let (u, v..., w...) = x
. If v
and w
are strictly positive, return the epigraph distance required to increase u
such that the constraint is satisfied.
If any elements in v
or w
are non-positive, return the 2-norm of the vector d
such that in the vector x + d
: any non-positive elements in v
and w
are projected to 1
, and u
is projected such that the epigraph constraint holds.
distance_to_set(::ProjectionUpperBoundDistance, x, set::MOI.NormCone)
Let (t, y...) = x
. Return the epigraph distance d
such that (t + d, y...)
belongs to the set.
MathOptInterface.Utilities.set_dot
— Functionset_dot(x::AbstractVector, y::AbstractVector, set::AbstractVectorSet)
Return the scalar product between a vector x
of the set set
and a vector y
of the dual of the set s
.
set_dot(x, y, set::AbstractScalarSet)
Return the scalar product between a number x
of the set set
and a number y
of the dual of the set s
.
DoubleDicts
MathOptInterface.Utilities.DoubleDicts.DoubleDict
— TypeDoubleDict{V}
An optimized dictionary to map MOI.ConstraintIndex
to values of type V
.
Works as a AbstractDict{MOI.ConstraintIndex,V}
with minimal differences.
If V
is also a MOI.ConstraintIndex
, use IndexDoubleDict
.
Note that MOI.ConstraintIndex
is not a concrete type, opposed to MOI.ConstraintIndex{MOI.VariableIndex, MOI.Integers}
, which is a concrete type.
When looping through multiple keys of the same Function-in-Set type, use
inner = dict[F, S]
to return a type-stable DoubleDictInner
.
MathOptInterface.Utilities.DoubleDicts.DoubleDictInner
— TypeDoubleDictInner{F,S,V}
A type stable inner dictionary of DoubleDict
.
MathOptInterface.Utilities.DoubleDicts.IndexDoubleDict
— TypeIndexDoubleDict
A specialized version of [DoubleDict
] in which the values are of type MOI.ConstraintIndex
When looping through multiple keys of the same Function-in-Set type, use
inner = dict[F, S]
to return a type-stable IndexDoubleDictInner
.
MathOptInterface.Utilities.DoubleDicts.IndexDoubleDictInner
— TypeIndexDoubleDictInner{F,S}
A type stable inner dictionary of IndexDoubleDict
.
MathOptInterface.Utilities.DoubleDicts.outer_keys
— Functionouter_keys(d::AbstractDoubleDict)
Return an iterator over the outer keys of the AbstractDoubleDict
d
. Each outer key is a Tuple{Type,Type}
so that a double loop can be easily used:
for (F, S) in DoubleDicts.outer_keys(dict)
for (k, v) in dict[F, S]
# ...
end
end
For performance, it is recommended that the inner loop lies in a separate function to guarantee type-stability. Some outer keys (F, S)
might lead to an empty dict[F, S]
. If you want only nonempty dict[F, S]
, use nonempty_outer_keys
.
MathOptInterface.Utilities.DoubleDicts.nonempty_outer_keys
— Functionnonempty_outer_keys(d::AbstractDoubleDict)
Return a vector of outer keys of the AbstractDoubleDict
d
.
Only outer keys that have a nonempty set of inner keys will be returned.
Each outer key is a Tuple{Type,Type}
so that a double loop can be easily used
for (F, S) in DoubleDicts.nonempty_outer_keys(dict)
for (k, v) in dict[F, S]
# ...
end
end
For performance, it is recommended that the inner loop lies in a separate
function to guarantee type-stability.
If you want an iterator of all current outer keys, use [`outer_keys`](@ref).