From 512b391be673db9dbf8bb4ce0268c25aae951d77 Mon Sep 17 00:00:00 2001 From: "Documenter.jl" Date: Wed, 13 Sep 2023 08:57:52 +0000 Subject: [PATCH] build based on 2e39090 --- dev/MathOptInterface.pdf | Bin 1237952 -> 1237679 bytes dev/background/duality/index.html | 2 +- .../infeasibility_certificates/index.html | 2 +- dev/background/motivation/index.html | 2 +- dev/background/naming_conventions/index.html | 2 +- dev/changelog/index.html | 2 +- dev/developer/checklists/index.html | 2 +- dev/index.html | 2 +- dev/manual/constraints/index.html | 2 +- dev/manual/models/index.html | 2 +- dev/manual/modification/index.html | 2 +- dev/manual/solutions/index.html | 2 +- dev/manual/standard_form/index.html | 2 +- dev/manual/variables/index.html | 2 +- dev/reference/callbacks/index.html | 12 +- dev/reference/constraints/index.html | 16 +- dev/reference/errors/index.html | 32 ++-- dev/reference/models/index.html | 38 ++--- dev/reference/modification/index.html | 4 +- dev/reference/nonlinear/index.html | 36 ++--- dev/reference/standard_form/index.html | 140 +++++++++--------- dev/reference/variables/index.html | 12 +- dev/release_notes/index.html | 2 +- dev/search/index.html | 2 +- dev/search_index.js | 2 +- dev/submodules/Benchmarks/overview/index.html | 2 +- .../Benchmarks/reference/index.html | 6 +- .../Bridges/list_of_bridges/index.html | 30 ++-- dev/submodules/Bridges/overview/index.html | 2 +- dev/submodules/Bridges/reference/index.html | 70 ++++----- .../FileFormats/overview/index.html | 2 +- .../FileFormats/reference/index.html | 6 +- dev/submodules/Nonlinear/overview/index.html | 2 +- dev/submodules/Nonlinear/reference/index.html | 50 +++---- dev/submodules/Test/overview/index.html | 2 +- dev/submodules/Test/reference/index.html | 8 +- dev/submodules/Utilities/overview/index.html | 2 +- dev/submodules/Utilities/reference/index.html | 54 +++---- dev/tutorials/bridging_constraint/index.html | 2 +- dev/tutorials/example/index.html | 2 +- dev/tutorials/implementing/index.html | 2 +- dev/tutorials/latency/index.html | 2 +- .../manipulating_expressions/index.html | 2 +- dev/tutorials/mathprogbase/index.html | 2 +- 44 files changed, 285 insertions(+), 285 deletions(-) diff --git a/dev/MathOptInterface.pdf b/dev/MathOptInterface.pdf index abba623b04f14d7443ca284a574c856203b539b1..196b34cae9aabf198ea6b915bf754deadaf6abbf 100644 GIT binary patch delta 554389 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

2&*Ge}Ch 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

>w0;jh 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

Y-0%-q^Ez_*F39)Oe-Ob?EFCRL=k>T1zCHW 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 wyk7+uZWODz?A0MHfG*OjJmm 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%0D)s!z|xsp6EW@@Ni2uR^o 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 B^xpsg delta 554581 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

CbnnULQ4=HXENlCWaEqj7FsAX$mt$g*W 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%0A{CAs-jX9;S3E>BYC0#?xj?~>_I4gO? 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

~VB3YQ9o;RPt%BtjK( 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%0AaH6D{u04#1F7=~4!#uQlWV=o^@Ww~z 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Ⓢ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 z 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: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 diff --git a/dev/background/duality/index.html b/dev/background/duality/index.html index cb56f70b74..b911addb02 100644 --- a/dev/background/duality/index.html +++ b/dev/background/duality/index.html @@ -77,4 +77,4 @@ \max & \sum b_k y_k \\ \text{s.t.} \;\; & C+C^\top - \sum (A_k+A_k^\top) y_k \in \mathcal{S}_+ \\ & C-C^\top - \sum(A_k-A_k^\top) y_k = 0 -\end{align}\]

and we recover $Z = X + X^\top$.

+\end{align}\]

and we recover $Z = X + X^\top$.

diff --git a/dev/background/infeasibility_certificates/index.html b/dev/background/infeasibility_certificates/index.html index 59321024ef..f6aac3818d 100644 --- a/dev/background/infeasibility_certificates/index.html +++ b/dev/background/infeasibility_certificates/index.html @@ -25,4 +25,4 @@ \end{align}\]

and:

\[-\sum_{i=1}^m b_i^\top (y_i + \eta d_i) > -\sum_{i=1}^m b_i^\top y_i,\]

for any feasible dual solution $y$. The latter simplifies to $-\sum_{i=1}^m b_i^\top d_i > 0$. For a maximization problem, the inequality is $\sum_{i=1}^m b_i^\top d_i < 0$. (Note that these are the same inequality, modulo a - sign.)

If the solver has found a certificate of primal infeasibility:

Note

The choice of whether to scale the ray $d$ to have magnitude 1 is left to the solver.

Infeasibility certificates of variable bounds

Many linear solvers (for example, Gurobi) do not provide explicit access to the primal infeasibility certificate of a variable bound. However, given a set of linear constraints:

\[\begin{align} l_A \le A x \le u_A \\ l_x \le x \le u_x, -\end{align}\]

the primal certificate of the variable bounds can be computed using the primal certificate associated with the affine constraints, $d$. (Note that $d$ will have one element for each row of the $A$ matrix, and that some or all of the elements in the vectors $l_A$ and $u_A$ may be $\pm \infty$. If both $l_A$ and $u_A$ are finite for some row, the corresponding element in `d must be 0.)

Given $d$, compute $\bar{d} = d^\top A$. If the bound is finite, a certificate for the lower variable bound of $x_i$ is $\max\{\bar{d}_i, 0\}$, and a certificate for the upper variable bound is $\min\{\bar{d}_i, 0\}$.

+\end{align}\]

the primal certificate of the variable bounds can be computed using the primal certificate associated with the affine constraints, $d$. (Note that $d$ will have one element for each row of the $A$ matrix, and that some or all of the elements in the vectors $l_A$ and $u_A$ may be $\pm \infty$. If both $l_A$ and $u_A$ are finite for some row, the corresponding element in `d must be 0.)

Given $d$, compute $\bar{d} = d^\top A$. If the bound is finite, a certificate for the lower variable bound of $x_i$ is $\max\{\bar{d}_i, 0\}$, and a certificate for the upper variable bound is $\min\{\bar{d}_i, 0\}$.

diff --git a/dev/background/motivation/index.html b/dev/background/motivation/index.html index 5b4b3af5bc..fc30b3a059 100644 --- a/dev/background/motivation/index.html +++ b/dev/background/motivation/index.html @@ -1,2 +1,2 @@ -Motivation · MathOptInterface

Motivation

MathOptInterface (MOI) is a replacement for MathProgBase, the first-generation abstraction layer for mathematical optimization previously used by JuMP and Convex.jl.

To address a number of limitations of MathProgBase, MOI is designed to:

  • Be simple and extensible
    • unifying linear, quadratic, and conic optimization,
    • seamlessly facilitating extensions to essentially arbitrary constraints and functions (for example, indicator constraints, complementarity constraints, and piecewise-linear functions)
  • Be fast
    • by allowing access to a solver's in-memory representation of a problem without writing intermediate files (when possible)
    • by using multiple dispatch and avoiding requiring containers of non-concrete types
  • Allow a solver to return multiple results (for example, a pool of solutions)
  • Allow a solver to return extra arbitrary information via attributes (for example, variable- and constraint-wise membership in an irreducible inconsistent subset for infeasibility analysis)
  • Provide a greatly expanded set of status codes explaining what happened during the optimization procedure
  • Enable a solver to more precisely specify which problem classes it supports
  • Enable both primal and dual warm starts
  • Enable adding and removing both variables and constraints by indices that are not required to be consecutive
  • Enable any modification that the solver supports to an existing model
  • Avoid requiring the solver wrapper to store an additional copy of the problem data
+Motivation · MathOptInterface

Motivation

MathOptInterface (MOI) is a replacement for MathProgBase, the first-generation abstraction layer for mathematical optimization previously used by JuMP and Convex.jl.

To address a number of limitations of MathProgBase, MOI is designed to:

  • Be simple and extensible
    • unifying linear, quadratic, and conic optimization,
    • seamlessly facilitating extensions to essentially arbitrary constraints and functions (for example, indicator constraints, complementarity constraints, and piecewise-linear functions)
  • Be fast
    • by allowing access to a solver's in-memory representation of a problem without writing intermediate files (when possible)
    • by using multiple dispatch and avoiding requiring containers of non-concrete types
  • Allow a solver to return multiple results (for example, a pool of solutions)
  • Allow a solver to return extra arbitrary information via attributes (for example, variable- and constraint-wise membership in an irreducible inconsistent subset for infeasibility analysis)
  • Provide a greatly expanded set of status codes explaining what happened during the optimization procedure
  • Enable a solver to more precisely specify which problem classes it supports
  • Enable both primal and dual warm starts
  • Enable adding and removing both variables and constraints by indices that are not required to be consecutive
  • Enable any modification that the solver supports to an existing model
  • Avoid requiring the solver wrapper to store an additional copy of the problem data
diff --git a/dev/background/naming_conventions/index.html b/dev/background/naming_conventions/index.html index 98ebe6ca97..daf72d6e65 100644 --- a/dev/background/naming_conventions/index.html +++ b/dev/background/naming_conventions/index.html @@ -1,2 +1,2 @@ -Naming conventions · MathOptInterface

Naming conventions

MOI follows several conventions for naming functions and structures. These should also be followed by packages extending MOI.

Sets

Sets encode the structure of constraints. Their names should follow the following conventions:

  • Abstract types in the set hierarchy should begin with Abstract and end in Set, for example, AbstractScalarSet, AbstractVectorSet.
  • Vector-valued conic sets should end with Cone, for example, NormInfinityCone, SecondOrderCone.
  • Vector-valued Cartesian products should be plural and not end in Cone, for example, Nonnegatives, not NonnegativeCone.
  • Matrix-valued conic sets should provide two representations: ConeSquare and ConeTriangle, for example, RootDetConeTriangle and RootDetConeSquare. See Matrix cones for more details.
  • Scalar sets should be singular, not plural, for example, Integer, not Integers.
  • As much as possible, the names should follow established conventions in the domain where this set is used: for instance, convex sets should have names close to those of CVX, and constraint-programming sets should follow MiniZinc's constraints.
+Naming conventions · MathOptInterface

Naming conventions

MOI follows several conventions for naming functions and structures. These should also be followed by packages extending MOI.

Sets

Sets encode the structure of constraints. Their names should follow the following conventions:

  • Abstract types in the set hierarchy should begin with Abstract and end in Set, for example, AbstractScalarSet, AbstractVectorSet.
  • Vector-valued conic sets should end with Cone, for example, NormInfinityCone, SecondOrderCone.
  • Vector-valued Cartesian products should be plural and not end in Cone, for example, Nonnegatives, not NonnegativeCone.
  • Matrix-valued conic sets should provide two representations: ConeSquare and ConeTriangle, for example, RootDetConeTriangle and RootDetConeSquare. See Matrix cones for more details.
  • Scalar sets should be singular, not plural, for example, Integer, not Integers.
  • As much as possible, the names should follow established conventions in the domain where this set is used: for instance, convex sets should have names close to those of CVX, and constraint-programming sets should follow MiniZinc's constraints.
diff --git a/dev/changelog/index.html b/dev/changelog/index.html index cd7de85d91..b61b6812a2 100644 --- a/dev/changelog/index.html +++ b/dev/changelog/index.html @@ -27,4 +27,4 @@ end write(path, s) end -end

v0.9.22 (May 22, 2021)

This release contains backports from the ongoing development of the v0.10 release.

  • Improved type inference in Utilities, Bridges and FileFormats submodules to reduce latency.
  • Improved performance of Utilities.is_canonical.
  • Fixed Utilities.pass_nonvariable_constraints with bridged variables.
  • Fixed performance regression of Utilities.Model.
  • Fixed ordering of objective setting in parser.

v0.9.21 (April 23, 2021)

  • Added supports_shift_constant.
  • Improve performance of bridging quadratic constraints.
  • Add precompilation statements.
  • Large improvements to the documentation.
  • Fix a variety of inference issues, benefiting precompilation and reducing initial latency.
  • RawParameters are now ignored when resetting a CachingOptimizer. Previously, changing the underlying optimizer after RawParameters were set would throw an error.
  • Utilities.AbstractModel is being refactored. This may break users interacting with private fields of a model generated using @model.

v0.9.20 (February 20, 2021)

  • Improved performance of Utilities.ScalarFunctionIterator
  • Added support for compute_conflict to MOI layers
  • Added test with zero off-diagonal quadratic term in objective
  • Fixed double deletion of nested bridged SingleVariable/VectorOfVariables constraints
  • Fixed modification of un-set objective
  • Fixed function modification with duplicate terms
  • Made unit tests abort without failing if the problem class is not supported
  • Formatted code with JuliaFormatter
  • Clarified BasisStatusCode's docstring

v0.9.19 (December 1, 2020)

  • Added CallbackNodeStatus attribute
  • Added bridge from GreaterThan or LessThan to Interval
  • Added tests for infeasibility certificates and double optimize
  • Fixed support for Julia v1.6
  • Re-organized MOI docs and added documentation for adding a test

v0.9.18 (November 3, 2020)

  • Various improvements for working with complex numbers
  • Added GeoMeantoRelEntrBridge to bridge a GeometricMeanCone constraint to a relative entropy constraint

v0.9.17 (September 21, 2020)

  • Fixed CleverDict with variable of negative index value
  • Implement supports_add_constrained_variable for MockOptimizer

v0.9.16 (September 17, 2020)

  • Various fixes:
    • 32-bit support
    • CleverDict with abstract value type
    • Checks in test suite

v0.9.15 (September 14, 2020)

  • Bridges improvements:
    • (R)SOCtoNonConvexQuad bridge
    • ZeroOne bridge
    • Use supports_add_constrained_variable in LazyBridgeOptimizer
    • Exposed VariableBridgeCost and ConstraintBridgeCost attributes
    • Prioritize constraining variables on creation according to these costs
    • Refactor bridge debugging
  • Large performance improvements across all submodules
  • Lots of documentation improvements
  • FileFormats improvements:
    • Update MathOptFormat to v0.5
    • Fix supported objectives in FileFormats
  • Testing improvements:
    • Add name option for basic_constraint_test
  • Bug fixes and missing methods
    • Add length for iterators
    • Fix bug with duplicate terms
    • Fix order of LinearOfConstraintIndices

v0.9.14 (May 30, 2020)

  • Add a solver-independent interface for accessing the set of conflicting constraints an Irreducible Inconsistent Subsystem (#1056).
  • Bump JSONSchema dependency from v0.2 to v0.3 (#1090).
  • Documentation improvements:
    • Fix typos (#1054, #1060, #1061, #1064, #1069, #1070).
    • Remove the outdated recommendation for a package implementing MOI for a solver XXX to be called MathOptInterfaceXXX (#1087).
  • Utilities improvements:
    • Fix is_canonical for quadratic functions (#1081, #1089).
    • Implement add_constrained_variable[s] for CachingOptimizer so that it is added as constrained variables to the underlying optimizer (#1084).
    • Add support for custom objective functions for UniversalFallback (#1086).
    • Deterministic ordering of constraints in UniversalFallback (#1088).
  • Testing improvements:
    • Add NormOneCone/NormInfinityCone tests (#1045).
  • Bridges improvements:
    • Add bridges from Semiinteger and Semicontinuous (#1059).
    • Implement getting ConstraintSet for Variable.FlipSignBridge (#1066).
    • Fix setting ConstraintFunction for Constraint.ScalarizeBridge (#1093).
    • Fix NormOne/NormInf bridges with nonzero constants (#1045).
    • Fix StackOverflow in debug (#1063).
  • FileFormats improvements:
    • [SDPA] Implement the extension for integer variables (#1079).
    • [SDPA] Ignore comments after m and nblocks and detect dat-s extension (#1077).
    • [SDPA] No scaling of off-diagonal coefficient (#1076).
    • [SDPA] Add missing negation of constant (#1075).

v0.9.13 (March 24, 2020)

  • Added tests for Semicontinuous and Semiinteger variables (#1033).
  • Added tests for using ExprGraphs from NLP evaluators (#1043).
  • Update version compatibilities of dependencies (#1034, #1051, #1052).
  • Fixed typos in documentation (#1044).

v0.9.12 (February 28, 2020)

  • Fixed writing NLPBlock in MathOptFormat (#1037).
  • Fixed MockOptimizer for result attributes with non-one result index (#1039).
  • Updated test template with instantiate (#1032).

v0.9.11 (February 21, 2020)

  • Add an option for the model created by Utilities.@model to be a subtype of AbstractOptimizer (#1031).
  • Described dual cone in docstrings of GeoMeanCone and RelativeEntropyCone (#1018, #1028).
  • Fixed typos in documentation (#1022, #1024).
  • Fixed warning of unsupported attribute (#1027).
  • Added more rootdet/logdet conic tests (#1026).
  • Implemented ConstraintDual for Constraint.GeoMeanBridge, Constraint.RootDetBridge and Constraint.LogDetBridge and test duals in tests with GeoMeanCone and RootDetConeTriangle and LogDetConeTriangle cones (#1025, #1026).

v0.9.10 (January 31, 2020)

  • Added OptimizerWithAttributes grouping an optimizer constructor and a list of optimizer attributes (#1008).
  • Added RelativeEntropyCone with corresponding bridge into exponential cone constraints (#993).
  • Added NormSpectralCone and NormNuclearCone with corresponding bridges into positive semidefinite constraints (#976).
  • Added supports_constrained_variable(s) (#1004).
  • Added dual_set_type (#1002).
  • Added tests for vector specialized version of delete (#989, #1011).
  • Added PSD3 test (#1007).
  • Clarified dual solution of Tests.pow1v and Tests.pow1f (#1013).
  • Added support for EqualTo and Zero in Bridges.Constraint.SplitIntervalBridge (#1005).
  • Fixed Utilities.vectorize for empty vector (#1003).
  • Fixed free variables in LP writer (#1006).

v0.9.9 (December 29, 2019)

  • Incorporated MathOptFormat.jl as the FileFormats submodule. FileFormats provides readers and writers for a number of standard file formats and MOF, a file format specialized for MOI (#969).
  • Improved performance of deletion of vector of variables in MOI.Utilities.Model (#983).
  • Updated to MutableArithmetics v0.2 (#981).
  • Added MutableArithmetics.promote_operation allocation tests (#975).
  • Fixed inference issue on Julia v1.1 (#982).

v0.9.8 (December 19, 2019)

  • Implemented MutableArithmetics API (#924).
  • Fixed callbacks with CachingOptimizer (#959).
  • Fixed MOI.dimension for MOI.Complements (#948).
  • Added fallback for add_variables (#972).
  • Added is_diagonal_vectorized_index utility (#965).
  • Improved linear constraints display in manual (#963, #964).
  • Bridges improvements:
    • Added IndicatorSet to SOS1 bridge (#877).
    • Added support for starting values for Variable.VectorizeBridge (#944).
    • Fixed MOI.add_constraints with non-bridged variable constraint on bridged variable (#951).
    • Fixed corner cases and docstring of GeoMeanBridge (#961, #962, #966).
    • Fixed choice between variable or constraint bridges for constrained variables (#973).
    • Improve performance of bridge shortest path (#945, #946, #956).
    • Added docstring for test_delete_bridge (#954).
    • Added Variable bridge tests (#952).

v0.9.7 (October 30, 2019)

  • Implemented _result_index_field for NLPBlockDual (#934).
  • Fixed copy of model with starting values for vector constraints (#941).
  • Bridges improvements:
    • Improved performance of add_bridge and added has_bridge (#935).
    • Added AbstractSetMapBridge for bridges between sets S1, S2 such that there is a linear map A such that A*S1 = S2 (#933).
    • Added support for starting values for FlipSignBridge, VectorizeBridge, ScalarizeBridge, SlackBridge, SplitIntervalBridge, RSOCBridge, SOCRBridge NormInfinityBridge, SOCtoPSDBridge and RSOCtoPSDBridge (#933, #936, #937, #938, #939).

v0.9.6 (October 25, 2019)

  • Added complementarity constraints (#913).
  • Allowed ModelLike objects as value of attributes (#928).
  • Testing improvements:
    • Added dual_objective_value option to MOI.Test.TestConfig (#922).
    • Added InvalidIndex tests in basic_constraint_tests (#921).
    • Added tests for the constant term in indicator constraint (#929).
  • Bridges improvements:
    • Added support for starting values for Functionize bridges (#923).
    • Added variable indices context to variable bridges (#920).
    • Fixed a typo in printing o debug_supports (#927).

v0.9.5 (October 9, 2019)

  • Clarified PrimalStatus/DualStatus to be NO_SOLUTION if result_index is out of bounds (#912).
  • Added tolerance for checks and use ResultCount + 1 for the result_index in MOI.Test.solve_result_status (#910, #917).
  • Use 0.5 instead of 2.0 for power in PowerCone in basic_constraint_test (#916).
  • Bridges improvements:
    • Added debug utilities for unsupported variable/constraint/objective (#861).
    • Fixed deletion of variables in bridged VectorOfVariables constraints (#909).
    • Fixed result_index with objective bridges (#911).

v0.9.4 (October 2, 2019)

  • Added solver-independent MIP callbacks (#782).
  • Implements submit for Utilities.CachingOptimizer and Bridges.AbstractBridgeOptimizer (#906).
  • Added tests for result count of solution attributes (#901, #904).
  • Added NumberOfThreads attribute (#892).
  • Added Utilities.get_bounds to get the bounds on a variable (#890).
  • Added a note on duplicate coefficients in documentation (#581).
  • Added result index in ConstraintBasisStatus (#898).
  • Added extension dictionary to Utilities.Model (#884, #895).
  • Fixed deletion of constrained variables for CachingOptimizer (#905).
  • Implemented Utilities.shift_constraint for Test.UnknownScalarSet (#896).
  • Bridges improvements:
    • Added Variable.RSOCtoSOCBridge (#907).
    • Implemented MOI.get for ConstraintFunction/ConstraintSet for Bridges.Constraint.SquareBridge (#899).

v0.9.3 (September 20, 2019)

  • Fixed ambiguity detected in Julia v1.3 (#891, #893).
  • Fixed missing sets from ListOfSupportedConstraints (#880).
  • Fixed copy of VectorOfVariables constraints with duplicate indices (#886).
  • Added extension dictionary to MOIU.Model (#884).
  • Implemented MOI.get for function and set for GeoMeanBridge (#888).
  • Updated documentation for SingleVariable indices and bridges (#885).
  • Testing improvements:
    • Added more comprehensive tests for names (#882).
    • Added tests for SingleVariable duals (#883).
    • Added tests for DualExponentialCone and DualPowerCone (#873).
  • Improvements for arbitrary coefficient type:
    • Fixed == for sets with mutable fields (#887).
    • Removed some Float64 assumptions in bridges (#878).
    • Automatic selection of Constraint.[Scalar|Vector]FunctionizeBridge (#889).

v0.9.2 (September 5, 2019)

  • Implemented model printing for MOI.ModelLike and specialized it for models defined in MOI (864).
  • Generalized contlinear tests for arbitrary coefficient type (#855).
  • Fixed supports_constraint for Semiinteger and Semicontinuous and supports for ObjectiveFunction (#859).
  • Fixed Allocate-Load copy for single variable constraints (#856).
  • Bridges improvements:
    • Add objective bridges (#789).
    • Fixed Variable.RSOCtoPSDBridge for dimension 2 (#869).
    • Added Variable.SOCtoRSOCBridge (#865).
    • Added Constraint.SOCRBridge and disable MOI.Bridges.Constraint.SOCtoPSDBridge (#751).
    • Fixed added_constraint_types for Contraint.LogDetBridge and Constraint.RootDetBridge (#870).

v0.9.1 (August 22, 2019)

  • Fix support for Julia v1.2 (#834).
  • L1 and L∞ norm epigraph cones and corresponding bridges to LP were added (#818).
  • Added tests to MOI.Test.nametest (#833).
  • Fix MOI.Test.soc3test for solvers not supporting infeasibility certificates (#839).
  • Implements operate for operators * and / between vector function and constant (#837).
  • Implements show for MOI.Utilities.IndexMap (#847).
  • Fix corner cases for mapping of variables in MOI.Utilities.CachingOptimizer and substitution of variables in MOI.Bridges.AbstractBridgeOptimizer (#848).
  • Fix transformation of constant terms for MOI.Bridges.Constraint.SOCtoPSDBridge and MOI.Bridges.Constraint.RSOCtoPSDBridge (#840).

v0.9.0 (August 13, 2019)

  • Support for Julia v0.6 and v0.7 was dropped (#714, #717).
  • A MOI.Utilities.Model implementation of ModelLike, this should replace most use cases of MOI.Utilities.@model (#781).
  • add_constrained_variable and add_constrained_variables were added (#759).
  • Support for indicator constraints was added (#709, #712).
  • DualObjectiveValue attribute was added (#473).
  • RawParameter attribute was added (#733).
  • A dual_set function was added (#804).
  • A Benchmarks submodule was added to facilitate solver benchmarking (#769).
  • A submit function was added, this may for instance allow the user to submit solutions or cuts to the solver from a callback (#775).
  • The field of ObjectiveValue was renamed to result_index (#729).
  • The _constant and Utilities.getconstant function were renamed to constant
  • REDUCTION_CERTIFICATE result status was added (#734).
  • Abstract matrix sets were added (#731).
  • Testing improvements:
    • The testing guideline was updated (#728).
    • Quadratic tests were added (#697).
    • Unit tests for RawStatusString, SolveTime, Silent and SolverName were added (#726, #741).
    • A rotated second-order cone test was added (#759).
    • A power cone test was added (#768).
    • Tests for ZeroOne variables with variable bounds were added (#772).
    • An unbounded test was added (#773).
    • Existing tests had a few updates (#702, #703, #763).
  • Documentation improvements:
    • Added a section on CachingOptimizer (#777).
    • Added a section on UniversalFallback, Model and @model (#762).
    • Transition the knapsack example to a doctest with MockOptimizer (#786).
  • Utilities improvements:
    • A CleverDict utility was added for a vector that automatically transform into a dictionary once a first index is removed (#767).
    • The Utilities.constant function was renamed to Utilities.constant_vector (#740).
    • Implement optimizer attributes for CachingOptimizer (#745).
    • Rename Utilities.add_scalar_constraint to Utilities.normalize_and_add_constraint (#801).
    • operate with vcat, SingleVariable and VectorOfVariables now returns a VectorOfVariables (#616).
    • Fix a type piracy of operate (#784).
    • The load_constraint fallback signature was fixed (#760).
    • The set_dot function was extended to work with sparse arrays (#805).
  • Bridges improvements:
    • The bridges no longer store the constraint function and set before it is bridged, the bridges now have to implement ConstraintFunction and ConstraintSet if the user wants to recover them. As a consequence, the @bridge macro was removed (#722).
    • Bridge are now instantiated with a bridge_constraint function instead of using a constructor (#730).
    • Fix constraint attributes for bridges (#699).
    • Constraint bridges were moved to the Bridges/Constraint submodule so they should now inherit from MOI.Bridges.Constraint.Abstract and should implement MOI.Bridges.Constraint.concrete_bridge_type instead of MOI.Bridges.concrete_bridge_type (#756).
    • Variable bridges were added in (#759).
    • Various improvements (#746, #747).

v0.8.4 (March 13, 2019)

  • Performance improvement in default_copy_to and bridge optimizer (#696).
  • Add Silent and implement setting optimizer attributes in caching and mock optimizers (#695).
  • Add Functionize bridges (SingleVariable and VectorOfVariables) (#659).
  • Minor typo fixes (#694).

v0.8.3 (March 6, 2019)

  • Use zero constant in scalar constraint function of MOI.Test.copytest (#691).
  • Fix variable deletion with SingleVariable objective function (#690).
  • Fix LazyBridgeOptimizer with bridges that add no constraints (#689).
  • Error message improvements (#673, #685, #686, #688).
  • Documentation improvements (#682, #683, #687).
  • Basis status:
    • Remove VariableBasisStatus (#679).
    • Test ConstraintBasisStatus and implement it in bridges (#678).
  • Fix inference of NumberOfVariables and NumberOfConstraints (#677).
  • Implement division between a quadratic function and a number (#675).

v0.8.2 (February 7, 2019)

  • Add RawStatusString attribute (#629).
  • Do not set names to the optimizer but only to the cache in CachingOptimizer (#638).
  • Make scalar MOI functions act as scalars in broadcast (#646).
  • Add function utilities:
    • Implement Base.zero (#634), Base.iszero (#643), add missing arithmetic operations (#644, #645) and fix division (#648).
    • Add a vectorize function that turns a vector of ScalarAffineFunction into a VectorAffineFunction (#642).
  • Improve support for starting values:
    • Show a warning in copy when starting values are not supported instead of throwing an error (#630).
    • Fix UniversalFallback for getting an variable or constraint attribute set to no indices (#623).
    • Add a test in contlineartest with partially set VariablePrimalStart.
  • Bridges improvements:
    • Fix StackOverFlow in LazyBridgeOptimizer when there is a cycle in the graph of bridges.
    • Add Slack bridges (#610, #650).
    • Add FlipSign bridges (#658).
  • Add tests with duplicate coefficients in ScalarAffineFunction and VectorAffineFunction (#639).
  • Use tolerance to compare VariablePrimal in rotatedsoc1 test (#632).
  • Use a zero constant in ScalarAffineFunction of constraints in psdt2 (#622).

v0.8.1 (January 7, 2019)

  • Adding an NLP objective now overrides any objective set using the ObjectiveFunction attribute (#619).
  • Rename fullbridgeoptimizer into full_bridge_optimizer (#621).
  • Allow custom constraint types with full_bridge_optimizer (#617).
  • Add Vectorize bridge which transforms scalar linear constraints into vector linear constraints (#615).

v0.8.0 (December 18, 2018)

  • Rename all enum values to follow the JuMP naming guidelines for constants, for example, Optimal becomes OPTIMAL, and DualInfeasible becomes DUAL_INFEASIBLE.
  • Rename CachingOptimizer methods for style compliance.
  • Add an MOI.TerminationStatusCode called ALMOST_DUAL_INFEASIBLE.

v0.7.0 (December 13, 2018)

  • Test that MOI.TerminationStatus is MOI.OptimizeNotCalled before MOI.optimize! is called.
  • Check supports_default_copy_to in tests (#594).
  • Key pieces of information like optimality, infeasibility, etc., are now reported through TerminationStatusCode. It is typically no longer necessary to check the result statuses in addition to the termination status.
  • Add perspective dimension to log-det cone (#593).

v0.6.4 (November 27, 2018)

  • Add OptimizeNotCalled termination status (#577) and improve documentation of other statuses (#575).
  • Add a solver naming guideline (#578).
  • Make FeasibilitySense the default ObjectiveSense (#579).
  • Fix Utilities.@model and Bridges.@bridge macros for functions and sets defined outside MOI (#582).
  • Document solver-specific attributes (#580) and implement them in Utilities.CachingOptimizer (#565).

v0.6.3 (November 16, 2018)

  • Variables and constraints are now allowed to have duplicate names. An error is thrown only on lookup. This change breaks some existing tests. (#549)
  • Attributes may now be partially set (some values could be nothing). (#563)
  • Performance improvements in Utilities.Model (#549, #567, #568)
  • Fix bug in QuadtoSOC (#558).
  • New supports_default_copy_to method that optimizers should implement to control caching behavior.
  • Documentation improvements.

v0.6.2 (October 26, 2018)

  • Improve hygiene of @model macro (#544).
  • Fix bug in copy tests (#543).
  • Fix bug in UniversalFallback attribute getter (#540).
  • Allow all correct solutions for solve_blank_obj unit test (#537).
  • Add errors for Allocate-Load and bad constraints (#534).
  • [performance] Add specialized implementation of hash for VariableIndex (#533).
  • [performance] Construct the name to object dictionaries lazily in model (#535).
  • Add the QuadtoSOC bridge which transforms ScalarQuadraticFunction constraints into RotatedSecondOrderCone (#483).

v0.6.1 (September 22, 2018)

  • Enable PositiveSemidefiniteConeSquare set and quadratic functions in MOIB.fullbridgeoptimizer (#524).
  • Add warning in the bridge between PositiveSemidefiniteConeSquare and PositiveSemidefiniteConeTriangle when the matrix is almost symmetric (#522).
  • Modify MOIT.copytest to not add multiples constraints on the same variable (#521).
  • Add missing keyword argument in one of MOIU.add_scalar_constraint methods (#520).

v0.6.0 (August 30, 2018)

  • The MOIU.@model and MOIB.@bridge macros now support functions and sets defined in external modules. As a consequence, function and set names in the macro arguments need to be prefixed by module name.
  • Rename functions according to the JuMP style guide:
    • copy! with keyword arguments copynames and warnattributes -> copy_to with keyword arguments copy_names and warn_attributes;
    • set! -> set;
    • addvariable[s]! -> add_variable[s];
    • supportsconstraint -> supports_constraint;
    • addconstraint[s]! -> add_constraint[s];
    • isvalid -> is_valid;
    • isempty -> is_empty;
    • Base.delete! -> delete;
    • modify! -> modify;
    • transform! -> transform;
    • initialize! -> initialize;
    • write -> write_to_file; and
    • read! -> read_from_file.
  • Remove free! (use Base.finalize instead).
  • Add the SquarePSD bridge which transforms PositiveSemidefiniteConeTriangle constraints into PositiveSemidefiniteConeTriangle.
  • Add result fallback for ConstraintDual of variable-wise constraint, ConstraintPrimal and ObjectiveValue.
  • Add tests for ObjectiveBound.
  • Add test for empty rows in vector linear constraint.
  • Rework errors: CannotError has been renamed NotAllowedError and the distinction between UnsupportedError and NotAllowedError is now about whether the element is not supported (for example, it cannot be copied a model containing this element) or the operation is not allowed (either because it is not implemented, because it cannot be performed in the current state of the model, or because it cannot be performed for a specific index)
  • canget is removed. NoSolution is added as a result status to indicate that the solver does not have either a primal or dual solution available (See #479).

v0.5.0 (August 5, 2018)

  • Fix names with CachingOptimizer.
  • Cleanup thanks to @mohamed82008.
  • Added a universal fallback for constraints.
  • Fast utilities for function canonicalization thanks to @rdeits.
  • Renamed dimension field to side_dimension in the context of matrix-like sets.
  • New and improved tests for cases like duplicate terms and ObjectiveBound.
  • Removed cantransform, canaddconstraint, canaddvariable, canset, canmodify, and candelete functions from the API. They are replaced by a new set of errors that are thrown: Subtypes of UnsupportedError indicate unsupported operations, while subtypes of CannotError indicate operations that cannot be performed in the current state.
  • The API for copy! is updated to remove the CopyResult type.
  • Updates for the new JuMP style guide.

v0.4.1 (June 28, 2018)

  • Fixes vector function modification on 32 bits.
  • Fixes Bellman-Ford algorithm for bridges.
  • Added an NLP test with FeasibilitySense.
  • Update modification documentation.

v0.4.0 (June 23, 2018)

  • Helper constructors for VectorAffineTerm and VectorQuadraticTerm.
  • Added modify_lhs to TestConfig.
  • Additional unit tests for optimizers.
  • Added a type parameter to CachingOptimizer for the optimizer field.
  • New API for problem modification (#388)
  • Tests pass without deprecation warnings on Julia 0.7.
  • Small fixes and documentation updates.

v0.3.0 (May 25, 2018)

  • Functions have been redefined to use arrays-of-structs instead of structs-of-arrays.
  • Improvements to MockOptimizer.
  • Significant changes to Bridges.
  • New and improved unit tests.
  • Fixes for Julia 0.7.

v0.2.0 (April 24, 2018)

  • Improvements to and better coverage of Tests.
  • Documentation fixes.
  • SolverName attribute.
  • Changes to the NLP interface (new definition of variable order and arrays of structs for bound pairs and sparsity patterns).
  • Addition of NLP tests.
  • Introduction of UniversalFallback.
  • copynames keyword argument to MOI.copy!.
  • Add Bridges submodule.

v0.1.0 (February 28, 2018)

  • Initial public release.
  • The framework for MOI was developed at the JuMP-dev workshop at MIT in June 2017 as a sorely needed replacement for MathProgBase.
+end

v0.9.22 (May 22, 2021)

This release contains backports from the ongoing development of the v0.10 release.

  • Improved type inference in Utilities, Bridges and FileFormats submodules to reduce latency.
  • Improved performance of Utilities.is_canonical.
  • Fixed Utilities.pass_nonvariable_constraints with bridged variables.
  • Fixed performance regression of Utilities.Model.
  • Fixed ordering of objective setting in parser.

v0.9.21 (April 23, 2021)

  • Added supports_shift_constant.
  • Improve performance of bridging quadratic constraints.
  • Add precompilation statements.
  • Large improvements to the documentation.
  • Fix a variety of inference issues, benefiting precompilation and reducing initial latency.
  • RawParameters are now ignored when resetting a CachingOptimizer. Previously, changing the underlying optimizer after RawParameters were set would throw an error.
  • Utilities.AbstractModel is being refactored. This may break users interacting with private fields of a model generated using @model.

v0.9.20 (February 20, 2021)

  • Improved performance of Utilities.ScalarFunctionIterator
  • Added support for compute_conflict to MOI layers
  • Added test with zero off-diagonal quadratic term in objective
  • Fixed double deletion of nested bridged SingleVariable/VectorOfVariables constraints
  • Fixed modification of un-set objective
  • Fixed function modification with duplicate terms
  • Made unit tests abort without failing if the problem class is not supported
  • Formatted code with JuliaFormatter
  • Clarified BasisStatusCode's docstring

v0.9.19 (December 1, 2020)

  • Added CallbackNodeStatus attribute
  • Added bridge from GreaterThan or LessThan to Interval
  • Added tests for infeasibility certificates and double optimize
  • Fixed support for Julia v1.6
  • Re-organized MOI docs and added documentation for adding a test

v0.9.18 (November 3, 2020)

  • Various improvements for working with complex numbers
  • Added GeoMeantoRelEntrBridge to bridge a GeometricMeanCone constraint to a relative entropy constraint

v0.9.17 (September 21, 2020)

  • Fixed CleverDict with variable of negative index value
  • Implement supports_add_constrained_variable for MockOptimizer

v0.9.16 (September 17, 2020)

  • Various fixes:
    • 32-bit support
    • CleverDict with abstract value type
    • Checks in test suite

v0.9.15 (September 14, 2020)

  • Bridges improvements:
    • (R)SOCtoNonConvexQuad bridge
    • ZeroOne bridge
    • Use supports_add_constrained_variable in LazyBridgeOptimizer
    • Exposed VariableBridgeCost and ConstraintBridgeCost attributes
    • Prioritize constraining variables on creation according to these costs
    • Refactor bridge debugging
  • Large performance improvements across all submodules
  • Lots of documentation improvements
  • FileFormats improvements:
    • Update MathOptFormat to v0.5
    • Fix supported objectives in FileFormats
  • Testing improvements:
    • Add name option for basic_constraint_test
  • Bug fixes and missing methods
    • Add length for iterators
    • Fix bug with duplicate terms
    • Fix order of LinearOfConstraintIndices

v0.9.14 (May 30, 2020)

  • Add a solver-independent interface for accessing the set of conflicting constraints an Irreducible Inconsistent Subsystem (#1056).
  • Bump JSONSchema dependency from v0.2 to v0.3 (#1090).
  • Documentation improvements:
    • Fix typos (#1054, #1060, #1061, #1064, #1069, #1070).
    • Remove the outdated recommendation for a package implementing MOI for a solver XXX to be called MathOptInterfaceXXX (#1087).
  • Utilities improvements:
    • Fix is_canonical for quadratic functions (#1081, #1089).
    • Implement add_constrained_variable[s] for CachingOptimizer so that it is added as constrained variables to the underlying optimizer (#1084).
    • Add support for custom objective functions for UniversalFallback (#1086).
    • Deterministic ordering of constraints in UniversalFallback (#1088).
  • Testing improvements:
    • Add NormOneCone/NormInfinityCone tests (#1045).
  • Bridges improvements:
    • Add bridges from Semiinteger and Semicontinuous (#1059).
    • Implement getting ConstraintSet for Variable.FlipSignBridge (#1066).
    • Fix setting ConstraintFunction for Constraint.ScalarizeBridge (#1093).
    • Fix NormOne/NormInf bridges with nonzero constants (#1045).
    • Fix StackOverflow in debug (#1063).
  • FileFormats improvements:
    • [SDPA] Implement the extension for integer variables (#1079).
    • [SDPA] Ignore comments after m and nblocks and detect dat-s extension (#1077).
    • [SDPA] No scaling of off-diagonal coefficient (#1076).
    • [SDPA] Add missing negation of constant (#1075).

v0.9.13 (March 24, 2020)

  • Added tests for Semicontinuous and Semiinteger variables (#1033).
  • Added tests for using ExprGraphs from NLP evaluators (#1043).
  • Update version compatibilities of dependencies (#1034, #1051, #1052).
  • Fixed typos in documentation (#1044).

v0.9.12 (February 28, 2020)

  • Fixed writing NLPBlock in MathOptFormat (#1037).
  • Fixed MockOptimizer for result attributes with non-one result index (#1039).
  • Updated test template with instantiate (#1032).

v0.9.11 (February 21, 2020)

  • Add an option for the model created by Utilities.@model to be a subtype of AbstractOptimizer (#1031).
  • Described dual cone in docstrings of GeoMeanCone and RelativeEntropyCone (#1018, #1028).
  • Fixed typos in documentation (#1022, #1024).
  • Fixed warning of unsupported attribute (#1027).
  • Added more rootdet/logdet conic tests (#1026).
  • Implemented ConstraintDual for Constraint.GeoMeanBridge, Constraint.RootDetBridge and Constraint.LogDetBridge and test duals in tests with GeoMeanCone and RootDetConeTriangle and LogDetConeTriangle cones (#1025, #1026).

v0.9.10 (January 31, 2020)

  • Added OptimizerWithAttributes grouping an optimizer constructor and a list of optimizer attributes (#1008).
  • Added RelativeEntropyCone with corresponding bridge into exponential cone constraints (#993).
  • Added NormSpectralCone and NormNuclearCone with corresponding bridges into positive semidefinite constraints (#976).
  • Added supports_constrained_variable(s) (#1004).
  • Added dual_set_type (#1002).
  • Added tests for vector specialized version of delete (#989, #1011).
  • Added PSD3 test (#1007).
  • Clarified dual solution of Tests.pow1v and Tests.pow1f (#1013).
  • Added support for EqualTo and Zero in Bridges.Constraint.SplitIntervalBridge (#1005).
  • Fixed Utilities.vectorize for empty vector (#1003).
  • Fixed free variables in LP writer (#1006).

v0.9.9 (December 29, 2019)

  • Incorporated MathOptFormat.jl as the FileFormats submodule. FileFormats provides readers and writers for a number of standard file formats and MOF, a file format specialized for MOI (#969).
  • Improved performance of deletion of vector of variables in MOI.Utilities.Model (#983).
  • Updated to MutableArithmetics v0.2 (#981).
  • Added MutableArithmetics.promote_operation allocation tests (#975).
  • Fixed inference issue on Julia v1.1 (#982).

v0.9.8 (December 19, 2019)

  • Implemented MutableArithmetics API (#924).
  • Fixed callbacks with CachingOptimizer (#959).
  • Fixed MOI.dimension for MOI.Complements (#948).
  • Added fallback for add_variables (#972).
  • Added is_diagonal_vectorized_index utility (#965).
  • Improved linear constraints display in manual (#963, #964).
  • Bridges improvements:
    • Added IndicatorSet to SOS1 bridge (#877).
    • Added support for starting values for Variable.VectorizeBridge (#944).
    • Fixed MOI.add_constraints with non-bridged variable constraint on bridged variable (#951).
    • Fixed corner cases and docstring of GeoMeanBridge (#961, #962, #966).
    • Fixed choice between variable or constraint bridges for constrained variables (#973).
    • Improve performance of bridge shortest path (#945, #946, #956).
    • Added docstring for test_delete_bridge (#954).
    • Added Variable bridge tests (#952).

v0.9.7 (October 30, 2019)

  • Implemented _result_index_field for NLPBlockDual (#934).
  • Fixed copy of model with starting values for vector constraints (#941).
  • Bridges improvements:
    • Improved performance of add_bridge and added has_bridge (#935).
    • Added AbstractSetMapBridge for bridges between sets S1, S2 such that there is a linear map A such that A*S1 = S2 (#933).
    • Added support for starting values for FlipSignBridge, VectorizeBridge, ScalarizeBridge, SlackBridge, SplitIntervalBridge, RSOCBridge, SOCRBridge NormInfinityBridge, SOCtoPSDBridge and RSOCtoPSDBridge (#933, #936, #937, #938, #939).

v0.9.6 (October 25, 2019)

  • Added complementarity constraints (#913).
  • Allowed ModelLike objects as value of attributes (#928).
  • Testing improvements:
    • Added dual_objective_value option to MOI.Test.TestConfig (#922).
    • Added InvalidIndex tests in basic_constraint_tests (#921).
    • Added tests for the constant term in indicator constraint (#929).
  • Bridges improvements:
    • Added support for starting values for Functionize bridges (#923).
    • Added variable indices context to variable bridges (#920).
    • Fixed a typo in printing o debug_supports (#927).

v0.9.5 (October 9, 2019)

  • Clarified PrimalStatus/DualStatus to be NO_SOLUTION if result_index is out of bounds (#912).
  • Added tolerance for checks and use ResultCount + 1 for the result_index in MOI.Test.solve_result_status (#910, #917).
  • Use 0.5 instead of 2.0 for power in PowerCone in basic_constraint_test (#916).
  • Bridges improvements:
    • Added debug utilities for unsupported variable/constraint/objective (#861).
    • Fixed deletion of variables in bridged VectorOfVariables constraints (#909).
    • Fixed result_index with objective bridges (#911).

v0.9.4 (October 2, 2019)

  • Added solver-independent MIP callbacks (#782).
  • Implements submit for Utilities.CachingOptimizer and Bridges.AbstractBridgeOptimizer (#906).
  • Added tests for result count of solution attributes (#901, #904).
  • Added NumberOfThreads attribute (#892).
  • Added Utilities.get_bounds to get the bounds on a variable (#890).
  • Added a note on duplicate coefficients in documentation (#581).
  • Added result index in ConstraintBasisStatus (#898).
  • Added extension dictionary to Utilities.Model (#884, #895).
  • Fixed deletion of constrained variables for CachingOptimizer (#905).
  • Implemented Utilities.shift_constraint for Test.UnknownScalarSet (#896).
  • Bridges improvements:
    • Added Variable.RSOCtoSOCBridge (#907).
    • Implemented MOI.get for ConstraintFunction/ConstraintSet for Bridges.Constraint.SquareBridge (#899).

v0.9.3 (September 20, 2019)

  • Fixed ambiguity detected in Julia v1.3 (#891, #893).
  • Fixed missing sets from ListOfSupportedConstraints (#880).
  • Fixed copy of VectorOfVariables constraints with duplicate indices (#886).
  • Added extension dictionary to MOIU.Model (#884).
  • Implemented MOI.get for function and set for GeoMeanBridge (#888).
  • Updated documentation for SingleVariable indices and bridges (#885).
  • Testing improvements:
    • Added more comprehensive tests for names (#882).
    • Added tests for SingleVariable duals (#883).
    • Added tests for DualExponentialCone and DualPowerCone (#873).
  • Improvements for arbitrary coefficient type:
    • Fixed == for sets with mutable fields (#887).
    • Removed some Float64 assumptions in bridges (#878).
    • Automatic selection of Constraint.[Scalar|Vector]FunctionizeBridge (#889).

v0.9.2 (September 5, 2019)

  • Implemented model printing for MOI.ModelLike and specialized it for models defined in MOI (864).
  • Generalized contlinear tests for arbitrary coefficient type (#855).
  • Fixed supports_constraint for Semiinteger and Semicontinuous and supports for ObjectiveFunction (#859).
  • Fixed Allocate-Load copy for single variable constraints (#856).
  • Bridges improvements:
    • Add objective bridges (#789).
    • Fixed Variable.RSOCtoPSDBridge for dimension 2 (#869).
    • Added Variable.SOCtoRSOCBridge (#865).
    • Added Constraint.SOCRBridge and disable MOI.Bridges.Constraint.SOCtoPSDBridge (#751).
    • Fixed added_constraint_types for Contraint.LogDetBridge and Constraint.RootDetBridge (#870).

v0.9.1 (August 22, 2019)

  • Fix support for Julia v1.2 (#834).
  • L1 and L∞ norm epigraph cones and corresponding bridges to LP were added (#818).
  • Added tests to MOI.Test.nametest (#833).
  • Fix MOI.Test.soc3test for solvers not supporting infeasibility certificates (#839).
  • Implements operate for operators * and / between vector function and constant (#837).
  • Implements show for MOI.Utilities.IndexMap (#847).
  • Fix corner cases for mapping of variables in MOI.Utilities.CachingOptimizer and substitution of variables in MOI.Bridges.AbstractBridgeOptimizer (#848).
  • Fix transformation of constant terms for MOI.Bridges.Constraint.SOCtoPSDBridge and MOI.Bridges.Constraint.RSOCtoPSDBridge (#840).

v0.9.0 (August 13, 2019)

  • Support for Julia v0.6 and v0.7 was dropped (#714, #717).
  • A MOI.Utilities.Model implementation of ModelLike, this should replace most use cases of MOI.Utilities.@model (#781).
  • add_constrained_variable and add_constrained_variables were added (#759).
  • Support for indicator constraints was added (#709, #712).
  • DualObjectiveValue attribute was added (#473).
  • RawParameter attribute was added (#733).
  • A dual_set function was added (#804).
  • A Benchmarks submodule was added to facilitate solver benchmarking (#769).
  • A submit function was added, this may for instance allow the user to submit solutions or cuts to the solver from a callback (#775).
  • The field of ObjectiveValue was renamed to result_index (#729).
  • The _constant and Utilities.getconstant function were renamed to constant
  • REDUCTION_CERTIFICATE result status was added (#734).
  • Abstract matrix sets were added (#731).
  • Testing improvements:
    • The testing guideline was updated (#728).
    • Quadratic tests were added (#697).
    • Unit tests for RawStatusString, SolveTime, Silent and SolverName were added (#726, #741).
    • A rotated second-order cone test was added (#759).
    • A power cone test was added (#768).
    • Tests for ZeroOne variables with variable bounds were added (#772).
    • An unbounded test was added (#773).
    • Existing tests had a few updates (#702, #703, #763).
  • Documentation improvements:
    • Added a section on CachingOptimizer (#777).
    • Added a section on UniversalFallback, Model and @model (#762).
    • Transition the knapsack example to a doctest with MockOptimizer (#786).
  • Utilities improvements:
    • A CleverDict utility was added for a vector that automatically transform into a dictionary once a first index is removed (#767).
    • The Utilities.constant function was renamed to Utilities.constant_vector (#740).
    • Implement optimizer attributes for CachingOptimizer (#745).
    • Rename Utilities.add_scalar_constraint to Utilities.normalize_and_add_constraint (#801).
    • operate with vcat, SingleVariable and VectorOfVariables now returns a VectorOfVariables (#616).
    • Fix a type piracy of operate (#784).
    • The load_constraint fallback signature was fixed (#760).
    • The set_dot function was extended to work with sparse arrays (#805).
  • Bridges improvements:
    • The bridges no longer store the constraint function and set before it is bridged, the bridges now have to implement ConstraintFunction and ConstraintSet if the user wants to recover them. As a consequence, the @bridge macro was removed (#722).
    • Bridge are now instantiated with a bridge_constraint function instead of using a constructor (#730).
    • Fix constraint attributes for bridges (#699).
    • Constraint bridges were moved to the Bridges/Constraint submodule so they should now inherit from MOI.Bridges.Constraint.Abstract and should implement MOI.Bridges.Constraint.concrete_bridge_type instead of MOI.Bridges.concrete_bridge_type (#756).
    • Variable bridges were added in (#759).
    • Various improvements (#746, #747).

v0.8.4 (March 13, 2019)

  • Performance improvement in default_copy_to and bridge optimizer (#696).
  • Add Silent and implement setting optimizer attributes in caching and mock optimizers (#695).
  • Add Functionize bridges (SingleVariable and VectorOfVariables) (#659).
  • Minor typo fixes (#694).

v0.8.3 (March 6, 2019)

  • Use zero constant in scalar constraint function of MOI.Test.copytest (#691).
  • Fix variable deletion with SingleVariable objective function (#690).
  • Fix LazyBridgeOptimizer with bridges that add no constraints (#689).
  • Error message improvements (#673, #685, #686, #688).
  • Documentation improvements (#682, #683, #687).
  • Basis status:
    • Remove VariableBasisStatus (#679).
    • Test ConstraintBasisStatus and implement it in bridges (#678).
  • Fix inference of NumberOfVariables and NumberOfConstraints (#677).
  • Implement division between a quadratic function and a number (#675).

v0.8.2 (February 7, 2019)

  • Add RawStatusString attribute (#629).
  • Do not set names to the optimizer but only to the cache in CachingOptimizer (#638).
  • Make scalar MOI functions act as scalars in broadcast (#646).
  • Add function utilities:
    • Implement Base.zero (#634), Base.iszero (#643), add missing arithmetic operations (#644, #645) and fix division (#648).
    • Add a vectorize function that turns a vector of ScalarAffineFunction into a VectorAffineFunction (#642).
  • Improve support for starting values:
    • Show a warning in copy when starting values are not supported instead of throwing an error (#630).
    • Fix UniversalFallback for getting an variable or constraint attribute set to no indices (#623).
    • Add a test in contlineartest with partially set VariablePrimalStart.
  • Bridges improvements:
    • Fix StackOverFlow in LazyBridgeOptimizer when there is a cycle in the graph of bridges.
    • Add Slack bridges (#610, #650).
    • Add FlipSign bridges (#658).
  • Add tests with duplicate coefficients in ScalarAffineFunction and VectorAffineFunction (#639).
  • Use tolerance to compare VariablePrimal in rotatedsoc1 test (#632).
  • Use a zero constant in ScalarAffineFunction of constraints in psdt2 (#622).

v0.8.1 (January 7, 2019)

  • Adding an NLP objective now overrides any objective set using the ObjectiveFunction attribute (#619).
  • Rename fullbridgeoptimizer into full_bridge_optimizer (#621).
  • Allow custom constraint types with full_bridge_optimizer (#617).
  • Add Vectorize bridge which transforms scalar linear constraints into vector linear constraints (#615).

v0.8.0 (December 18, 2018)

  • Rename all enum values to follow the JuMP naming guidelines for constants, for example, Optimal becomes OPTIMAL, and DualInfeasible becomes DUAL_INFEASIBLE.
  • Rename CachingOptimizer methods for style compliance.
  • Add an MOI.TerminationStatusCode called ALMOST_DUAL_INFEASIBLE.

v0.7.0 (December 13, 2018)

  • Test that MOI.TerminationStatus is MOI.OptimizeNotCalled before MOI.optimize! is called.
  • Check supports_default_copy_to in tests (#594).
  • Key pieces of information like optimality, infeasibility, etc., are now reported through TerminationStatusCode. It is typically no longer necessary to check the result statuses in addition to the termination status.
  • Add perspective dimension to log-det cone (#593).

v0.6.4 (November 27, 2018)

  • Add OptimizeNotCalled termination status (#577) and improve documentation of other statuses (#575).
  • Add a solver naming guideline (#578).
  • Make FeasibilitySense the default ObjectiveSense (#579).
  • Fix Utilities.@model and Bridges.@bridge macros for functions and sets defined outside MOI (#582).
  • Document solver-specific attributes (#580) and implement them in Utilities.CachingOptimizer (#565).

v0.6.3 (November 16, 2018)

  • Variables and constraints are now allowed to have duplicate names. An error is thrown only on lookup. This change breaks some existing tests. (#549)
  • Attributes may now be partially set (some values could be nothing). (#563)
  • Performance improvements in Utilities.Model (#549, #567, #568)
  • Fix bug in QuadtoSOC (#558).
  • New supports_default_copy_to method that optimizers should implement to control caching behavior.
  • Documentation improvements.

v0.6.2 (October 26, 2018)

  • Improve hygiene of @model macro (#544).
  • Fix bug in copy tests (#543).
  • Fix bug in UniversalFallback attribute getter (#540).
  • Allow all correct solutions for solve_blank_obj unit test (#537).
  • Add errors for Allocate-Load and bad constraints (#534).
  • [performance] Add specialized implementation of hash for VariableIndex (#533).
  • [performance] Construct the name to object dictionaries lazily in model (#535).
  • Add the QuadtoSOC bridge which transforms ScalarQuadraticFunction constraints into RotatedSecondOrderCone (#483).

v0.6.1 (September 22, 2018)

  • Enable PositiveSemidefiniteConeSquare set and quadratic functions in MOIB.fullbridgeoptimizer (#524).
  • Add warning in the bridge between PositiveSemidefiniteConeSquare and PositiveSemidefiniteConeTriangle when the matrix is almost symmetric (#522).
  • Modify MOIT.copytest to not add multiples constraints on the same variable (#521).
  • Add missing keyword argument in one of MOIU.add_scalar_constraint methods (#520).

v0.6.0 (August 30, 2018)

  • The MOIU.@model and MOIB.@bridge macros now support functions and sets defined in external modules. As a consequence, function and set names in the macro arguments need to be prefixed by module name.
  • Rename functions according to the JuMP style guide:
    • copy! with keyword arguments copynames and warnattributes -> copy_to with keyword arguments copy_names and warn_attributes;
    • set! -> set;
    • addvariable[s]! -> add_variable[s];
    • supportsconstraint -> supports_constraint;
    • addconstraint[s]! -> add_constraint[s];
    • isvalid -> is_valid;
    • isempty -> is_empty;
    • Base.delete! -> delete;
    • modify! -> modify;
    • transform! -> transform;
    • initialize! -> initialize;
    • write -> write_to_file; and
    • read! -> read_from_file.
  • Remove free! (use Base.finalize instead).
  • Add the SquarePSD bridge which transforms PositiveSemidefiniteConeTriangle constraints into PositiveSemidefiniteConeTriangle.
  • Add result fallback for ConstraintDual of variable-wise constraint, ConstraintPrimal and ObjectiveValue.
  • Add tests for ObjectiveBound.
  • Add test for empty rows in vector linear constraint.
  • Rework errors: CannotError has been renamed NotAllowedError and the distinction between UnsupportedError and NotAllowedError is now about whether the element is not supported (for example, it cannot be copied a model containing this element) or the operation is not allowed (either because it is not implemented, because it cannot be performed in the current state of the model, or because it cannot be performed for a specific index)
  • canget is removed. NoSolution is added as a result status to indicate that the solver does not have either a primal or dual solution available (See #479).

v0.5.0 (August 5, 2018)

  • Fix names with CachingOptimizer.
  • Cleanup thanks to @mohamed82008.
  • Added a universal fallback for constraints.
  • Fast utilities for function canonicalization thanks to @rdeits.
  • Renamed dimension field to side_dimension in the context of matrix-like sets.
  • New and improved tests for cases like duplicate terms and ObjectiveBound.
  • Removed cantransform, canaddconstraint, canaddvariable, canset, canmodify, and candelete functions from the API. They are replaced by a new set of errors that are thrown: Subtypes of UnsupportedError indicate unsupported operations, while subtypes of CannotError indicate operations that cannot be performed in the current state.
  • The API for copy! is updated to remove the CopyResult type.
  • Updates for the new JuMP style guide.

v0.4.1 (June 28, 2018)

  • Fixes vector function modification on 32 bits.
  • Fixes Bellman-Ford algorithm for bridges.
  • Added an NLP test with FeasibilitySense.
  • Update modification documentation.

v0.4.0 (June 23, 2018)

  • Helper constructors for VectorAffineTerm and VectorQuadraticTerm.
  • Added modify_lhs to TestConfig.
  • Additional unit tests for optimizers.
  • Added a type parameter to CachingOptimizer for the optimizer field.
  • New API for problem modification (#388)
  • Tests pass without deprecation warnings on Julia 0.7.
  • Small fixes and documentation updates.

v0.3.0 (May 25, 2018)

  • Functions have been redefined to use arrays-of-structs instead of structs-of-arrays.
  • Improvements to MockOptimizer.
  • Significant changes to Bridges.
  • New and improved unit tests.
  • Fixes for Julia 0.7.

v0.2.0 (April 24, 2018)

  • Improvements to and better coverage of Tests.
  • Documentation fixes.
  • SolverName attribute.
  • Changes to the NLP interface (new definition of variable order and arrays of structs for bound pairs and sparsity patterns).
  • Addition of NLP tests.
  • Introduction of UniversalFallback.
  • copynames keyword argument to MOI.copy!.
  • Add Bridges submodule.

v0.1.0 (February 28, 2018)

  • Initial public release.
  • The framework for MOI was developed at the JuMP-dev workshop at MIT in June 2017 as a sorely needed replacement for MathProgBase.
diff --git a/dev/developer/checklists/index.html b/dev/developer/checklists/index.html index 4dbbc62ad2..b2f7263c64 100644 --- a/dev/developer/checklists/index.html +++ b/dev/developer/checklists/index.html @@ -109,4 +109,4 @@ ## Documentation - - [ ] The version fields are updated in `docs/src/submodules/FileFormats/overview.md` + - [ ] The version fields are updated in `docs/src/submodules/FileFormats/overview.md` diff --git a/dev/index.html b/dev/index.html index f256417eea..7221c9b4a6 100644 --- a/dev/index.html +++ b/dev/index.html @@ -6,4 +6,4 @@ year={2021}, doi={10.1287/ijoc.2021.1067}, publisher={INFORMS} -} +} diff --git a/dev/manual/constraints/index.html b/dev/manual/constraints/index.html index c0ce7cc683..9dc6b13f1e 100644 --- a/dev/manual/constraints/index.html +++ b/dev/manual/constraints/index.html @@ -19,4 +19,4 @@ false

Constraint attributes

The following attributes are available for constraints:

Get and set these attributes using get and set.

julia> MOI.set(model, MOI.ConstraintName(), c, "con_c")
 
 julia> MOI.get(model, MOI.ConstraintName(), c)
-"con_c"

Constraints by function-set pairs

Below is a list of common constraint types and how they are represented as function-set pairs in MOI. In the notation below, $x$ is a vector of decision variables, $x_i$ is a scalar decision variable, $\alpha, \beta$ are scalar constants, $a, b$ are constant vectors, A is a constant matrix and $\mathbb{R}_+$ (resp. $\mathbb{R}_-$) is the set of non-negative (resp. non-positive) real numbers.

Linear constraints

Mathematical ConstraintMOI FunctionMOI Set
$a^Tx \le \beta$ScalarAffineFunctionLessThan
$a^Tx \ge \alpha$ScalarAffineFunctionGreaterThan
$a^Tx = \beta$ScalarAffineFunctionEqualTo
$\alpha \le a^Tx \le \beta$ScalarAffineFunctionInterval
$x_i \le \beta$VariableIndexLessThan
$x_i \ge \alpha$VariableIndexGreaterThan
$x_i = \beta$VariableIndexEqualTo
$\alpha \le x_i \le \beta$VariableIndexInterval
$Ax + b \in \mathbb{R}_+^n$VectorAffineFunctionNonnegatives
$Ax + b \in \mathbb{R}_-^n$VectorAffineFunctionNonpositives
$Ax + b = 0$VectorAffineFunctionZeros

By convention, solvers are not expected to support nonzero constant terms in the ScalarAffineFunctions the first four rows of the preceding table because they are redundant with the parameters of the sets. For example, encode $2x + 1 \le 2$ as $2x \le 1$.

Constraints with VariableIndex in LessThan, GreaterThan, EqualTo, or Interval sets have a natural interpretation as variable bounds. As such, it is typically not natural to impose multiple lower- or upper-bounds on the same variable, and the solver interfaces will throw respectively LowerBoundAlreadySet or UpperBoundAlreadySet.

Moreover, adding two VariableIndex constraints on the same variable with the same set is impossible because they share the same index as it is the index of the variable, see ConstraintIndex.

It is natural, however, to impose upper- and lower-bounds separately as two different constraints on a single variable. The difference between imposing bounds by using a single Interval constraint and by using separate LessThan and GreaterThan constraints is that the latter will allow the solver to return separate dual multipliers for the two bounds, while the former will allow the solver to return only a single dual for the interval constraint.

Conic constraints

Mathematical ConstraintMOI FunctionMOI Set
$\lVert Ax + b\rVert_2 \le c^Tx + d$VectorAffineFunctionSecondOrderCone
$y \ge \lVert x \rVert_2$VectorOfVariablesSecondOrderCone
$2yz \ge \lVert x \rVert_2^2, y,z \ge 0$VectorOfVariablesRotatedSecondOrderCone
$(a_1^Tx + b_1,a_2^Tx + b_2,a_3^Tx + b_3) \in \mathcal{E}$VectorAffineFunctionExponentialCone
$A(x) \in \mathcal{S}_+$VectorAffineFunctionPositiveSemidefiniteConeTriangle
$B(x) \in \mathcal{S}_+$VectorAffineFunctionPositiveSemidefiniteConeSquare
$x \in \mathcal{S}_+$VectorOfVariablesPositiveSemidefiniteConeTriangle
$x \in \mathcal{S}_+$VectorOfVariablesPositiveSemidefiniteConeSquare

where $\mathcal{E}$ is the exponential cone (see ExponentialCone), $\mathcal{S}_+$ is the set of positive semidefinite symmetric matrices, $A$ is an affine map that outputs symmetric matrices and $B$ is an affine map that outputs square matrices.

Quadratic constraints

Mathematical ConstraintMOI FunctionMOI Set
$\frac{1}{2}x^TQx + a^Tx + b \ge 0$ScalarQuadraticFunctionGreaterThan
$\frac{1}{2}x^TQx + a^Tx + b \le 0$ScalarQuadraticFunctionLessThan
$\frac{1}{2}x^TQx + a^Tx + b = 0$ScalarQuadraticFunctionEqualTo
Bilinear matrix inequalityVectorQuadraticFunctionPositiveSemidefiniteCone...
Note

For more details on the internal format of the quadratic functions see ScalarQuadraticFunction or VectorQuadraticFunction.

Discrete and logical constraints

Mathematical ConstraintMOI FunctionMOI Set
$x_i \in \mathbb{Z}$VariableIndexInteger
$x_i \in \{0,1\}$VariableIndexZeroOne
$x_i \in \{0\} \cup [l,u]$VariableIndexSemicontinuous
$x_i \in \{0\} \cup \{l,l+1,\ldots,u-1,u\}$VariableIndexSemiinteger
At most one component of $x$ can be nonzeroVectorOfVariablesSOS1
At most two components of $x$ can be nonzero, and if so they must be adjacent componentsVectorOfVariablesSOS2
$y = 1 \implies a^T x \in S$VectorAffineFunctionIndicator

JuMP mapping

The following bullet points show examples of how JuMP constraints are translated into MOI function-set pairs:

  • @constraint(m, 2x + y <= 10) becomes ScalarAffineFunction-in-LessThan
  • @constraint(m, 2x + y >= 10) becomes ScalarAffineFunction-in-GreaterThan
  • @constraint(m, 2x + y == 10) becomes ScalarAffineFunction-in-EqualTo
  • @constraint(m, 0 <= 2x + y <= 10) becomes ScalarAffineFunction-in-Interval
  • @constraint(m, 2x + y in ArbitrarySet()) becomes ScalarAffineFunction-in-ArbitrarySet.

Variable bounds are handled in a similar fashion:

  • @variable(m, x <= 1) becomes VariableIndex-in-LessThan
  • @variable(m, x >= 1) becomes VariableIndex-in-GreaterThan

One notable difference is that a variable with an upper and lower bound is translated into two constraints, rather than an interval, that is:

  • @variable(m, 0 <= x <= 1) becomes VariableIndex-in-LessThan and VariableIndex-in-GreaterThan.
+"con_c"

Constraints by function-set pairs

Below is a list of common constraint types and how they are represented as function-set pairs in MOI. In the notation below, $x$ is a vector of decision variables, $x_i$ is a scalar decision variable, $\alpha, \beta$ are scalar constants, $a, b$ are constant vectors, A is a constant matrix and $\mathbb{R}_+$ (resp. $\mathbb{R}_-$) is the set of non-negative (resp. non-positive) real numbers.

Linear constraints

Mathematical ConstraintMOI FunctionMOI Set
$a^Tx \le \beta$ScalarAffineFunctionLessThan
$a^Tx \ge \alpha$ScalarAffineFunctionGreaterThan
$a^Tx = \beta$ScalarAffineFunctionEqualTo
$\alpha \le a^Tx \le \beta$ScalarAffineFunctionInterval
$x_i \le \beta$VariableIndexLessThan
$x_i \ge \alpha$VariableIndexGreaterThan
$x_i = \beta$VariableIndexEqualTo
$\alpha \le x_i \le \beta$VariableIndexInterval
$Ax + b \in \mathbb{R}_+^n$VectorAffineFunctionNonnegatives
$Ax + b \in \mathbb{R}_-^n$VectorAffineFunctionNonpositives
$Ax + b = 0$VectorAffineFunctionZeros

By convention, solvers are not expected to support nonzero constant terms in the ScalarAffineFunctions the first four rows of the preceding table because they are redundant with the parameters of the sets. For example, encode $2x + 1 \le 2$ as $2x \le 1$.

Constraints with VariableIndex in LessThan, GreaterThan, EqualTo, or Interval sets have a natural interpretation as variable bounds. As such, it is typically not natural to impose multiple lower- or upper-bounds on the same variable, and the solver interfaces will throw respectively LowerBoundAlreadySet or UpperBoundAlreadySet.

Moreover, adding two VariableIndex constraints on the same variable with the same set is impossible because they share the same index as it is the index of the variable, see ConstraintIndex.

It is natural, however, to impose upper- and lower-bounds separately as two different constraints on a single variable. The difference between imposing bounds by using a single Interval constraint and by using separate LessThan and GreaterThan constraints is that the latter will allow the solver to return separate dual multipliers for the two bounds, while the former will allow the solver to return only a single dual for the interval constraint.

Conic constraints

Mathematical ConstraintMOI FunctionMOI Set
$\lVert Ax + b\rVert_2 \le c^Tx + d$VectorAffineFunctionSecondOrderCone
$y \ge \lVert x \rVert_2$VectorOfVariablesSecondOrderCone
$2yz \ge \lVert x \rVert_2^2, y,z \ge 0$VectorOfVariablesRotatedSecondOrderCone
$(a_1^Tx + b_1,a_2^Tx + b_2,a_3^Tx + b_3) \in \mathcal{E}$VectorAffineFunctionExponentialCone
$A(x) \in \mathcal{S}_+$VectorAffineFunctionPositiveSemidefiniteConeTriangle
$B(x) \in \mathcal{S}_+$VectorAffineFunctionPositiveSemidefiniteConeSquare
$x \in \mathcal{S}_+$VectorOfVariablesPositiveSemidefiniteConeTriangle
$x \in \mathcal{S}_+$VectorOfVariablesPositiveSemidefiniteConeSquare

where $\mathcal{E}$ is the exponential cone (see ExponentialCone), $\mathcal{S}_+$ is the set of positive semidefinite symmetric matrices, $A$ is an affine map that outputs symmetric matrices and $B$ is an affine map that outputs square matrices.

Quadratic constraints

Mathematical ConstraintMOI FunctionMOI Set
$\frac{1}{2}x^TQx + a^Tx + b \ge 0$ScalarQuadraticFunctionGreaterThan
$\frac{1}{2}x^TQx + a^Tx + b \le 0$ScalarQuadraticFunctionLessThan
$\frac{1}{2}x^TQx + a^Tx + b = 0$ScalarQuadraticFunctionEqualTo
Bilinear matrix inequalityVectorQuadraticFunctionPositiveSemidefiniteCone...
Note

For more details on the internal format of the quadratic functions see ScalarQuadraticFunction or VectorQuadraticFunction.

Discrete and logical constraints

Mathematical ConstraintMOI FunctionMOI Set
$x_i \in \mathbb{Z}$VariableIndexInteger
$x_i \in \{0,1\}$VariableIndexZeroOne
$x_i \in \{0\} \cup [l,u]$VariableIndexSemicontinuous
$x_i \in \{0\} \cup \{l,l+1,\ldots,u-1,u\}$VariableIndexSemiinteger
At most one component of $x$ can be nonzeroVectorOfVariablesSOS1
At most two components of $x$ can be nonzero, and if so they must be adjacent componentsVectorOfVariablesSOS2
$y = 1 \implies a^T x \in S$VectorAffineFunctionIndicator

JuMP mapping

The following bullet points show examples of how JuMP constraints are translated into MOI function-set pairs:

  • @constraint(m, 2x + y <= 10) becomes ScalarAffineFunction-in-LessThan
  • @constraint(m, 2x + y >= 10) becomes ScalarAffineFunction-in-GreaterThan
  • @constraint(m, 2x + y == 10) becomes ScalarAffineFunction-in-EqualTo
  • @constraint(m, 0 <= 2x + y <= 10) becomes ScalarAffineFunction-in-Interval
  • @constraint(m, 2x + y in ArbitrarySet()) becomes ScalarAffineFunction-in-ArbitrarySet.

Variable bounds are handled in a similar fashion:

  • @variable(m, x <= 1) becomes VariableIndex-in-LessThan
  • @variable(m, x >= 1) becomes VariableIndex-in-GreaterThan

One notable difference is that a variable with an upper and lower bound is translated into two constraints, rather than an interval, that is:

  • @variable(m, 0 <= x <= 1) becomes VariableIndex-in-LessThan and VariableIndex-in-GreaterThan.
diff --git a/dev/manual/models/index.html b/dev/manual/models/index.html index 6fd6ea2419..90d4cd13d5 100644 --- a/dev/manual/models/index.html +++ b/dev/manual/models/index.html @@ -1,2 +1,2 @@ -Models · MathOptInterface

Models

The most significant part of MOI is the definition of the model API that is used to specify an instance of an optimization problem (for example, by adding variables and constraints). Objects that implement the model API must inherit from the ModelLike abstract type.

Notably missing from the model API is the method to solve an optimization problem. ModelLike objects may store an instance (for example, in memory or backed by a file format) without being linked to a particular solver. In addition to the model API, MOI defines AbstractOptimizer and provides methods to solve the model and interact with solutions. See the Solutions section for more details.

Info

Throughout the rest of the manual, model is used as a generic ModelLike, and optimizer is used as a generic AbstractOptimizer.

Tip

MOI does not export functions, but for brevity we often omit qualifying names with the MOI module. Best practice is to have

import MathOptInterface as MOI

and prefix all MOI methods with MOI. in user code. If a name is also available in base Julia, we always explicitly use the module prefix, for example, with MOI.get.

Attributes

Attributes are properties of the model that can be queried and modified. These include constants such as the number of variables in a model NumberOfVariables), and properties of variables and constraints such as the name of a variable (VariableName).

There are four types of attributes:

Some attributes are values that can be queried by the user but not modified, while other attributes can be modified by the user.

All interactions with attributes occur through the get and set functions.

Consult the docstrings of each attribute for information on what it represents.

ModelLike API

The following attributes are available:

AbstractOptimizer API

The following attributes are available:

+Models · MathOptInterface

Models

The most significant part of MOI is the definition of the model API that is used to specify an instance of an optimization problem (for example, by adding variables and constraints). Objects that implement the model API must inherit from the ModelLike abstract type.

Notably missing from the model API is the method to solve an optimization problem. ModelLike objects may store an instance (for example, in memory or backed by a file format) without being linked to a particular solver. In addition to the model API, MOI defines AbstractOptimizer and provides methods to solve the model and interact with solutions. See the Solutions section for more details.

Info

Throughout the rest of the manual, model is used as a generic ModelLike, and optimizer is used as a generic AbstractOptimizer.

Tip

MOI does not export functions, but for brevity we often omit qualifying names with the MOI module. Best practice is to have

import MathOptInterface as MOI

and prefix all MOI methods with MOI. in user code. If a name is also available in base Julia, we always explicitly use the module prefix, for example, with MOI.get.

Attributes

Attributes are properties of the model that can be queried and modified. These include constants such as the number of variables in a model NumberOfVariables), and properties of variables and constraints such as the name of a variable (VariableName).

There are four types of attributes:

Some attributes are values that can be queried by the user but not modified, while other attributes can be modified by the user.

All interactions with attributes occur through the get and set functions.

Consult the docstrings of each attribute for information on what it represents.

ModelLike API

The following attributes are available:

AbstractOptimizer API

The following attributes are available:

diff --git a/dev/manual/modification/index.html b/dev/manual/modification/index.html index 0526d8d9bc..2019b187cd 100644 --- a/dev/manual/modification/index.html +++ b/dev/manual/modification/index.html @@ -122,4 +122,4 @@ ); julia> MOI.get(model, MOI.ConstraintFunction(), c) ≈ new_f -true +true diff --git a/dev/manual/solutions/index.html b/dev/manual/solutions/index.html index 63d2e61d3c..66ad6be9cd 100644 --- a/dev/manual/solutions/index.html +++ b/dev/manual/solutions/index.html @@ -32,4 +32,4 @@ end rethrow(err) # Something else went wrong. Rethrow the error end -end +end diff --git a/dev/manual/standard_form/index.html b/dev/manual/standard_form/index.html index 77d83f9d1c..d6a23dba1d 100644 --- a/dev/manual/standard_form/index.html +++ b/dev/manual/standard_form/index.html @@ -3,4 +3,4 @@ & \min_{x \in \mathbb{R}^n} & f_0(x) \\ & \;\;\text{s.t.} & f_i(x) & \in \mathcal{S}_i & i = 1 \ldots m -\end{align}\]

where:

  • the functions $f_0, f_1, \ldots, f_m$ are specified by AbstractFunction objects
  • the sets $\mathcal{S}_1, \ldots, \mathcal{S}_m$ are specified by AbstractSet objects
Tip

For more information on this standard form, read our paper.

MOI defines some commonly used functions and sets, but the interface is extensible to other sets recognized by the solver.

Functions

The function types implemented in MathOptInterface.jl are:

FunctionDescription
VariableIndex$x_j$, the projection onto a single coordinate defined by a variable index $j$.
VectorOfVariablesThe projection onto multiple coordinates (that is, extracting a sub-vector).
ScalarAffineFunction$a^T x + b$, where $a$ is a vector and $b$ scalar.
ScalarNonlinearFunction$f(x)$, where $f$ is a nonlinear function.
VectorAffineFunction$A x + b$, where $A$ is a matrix and $b$ is a vector.
ScalarQuadraticFunction$\frac{1}{2} x^T Q x + a^T x + b$, where $Q$ is a symmetric matrix, $a$ is a vector, and $b$ is a constant.
VectorQuadraticFunctionA vector of scalar-valued quadratic functions.
VectorNonlinearFunction$f(x)$, where $f$ is a vector-valued nonlinear function.

Extensions for nonlinear programming are present but not yet well documented.

One-dimensional sets

The one-dimensional set types implemented in MathOptInterface.jl are:

SetDescription
LessThan(u)$(-\infty, u]$
GreaterThan(l)$[l, \infty)$
EqualTo(v)$\{v\}$
Interval(l, u)$[l, u]$
Integer()$\mathbb{Z}$
ZeroOne()$\{ 0, 1 \}$
Semicontinuous(l, u)$\{ 0\} \cup [l, u]$
Semiinteger(l, u)$\{ 0\} \cup \{l,l+1,\ldots,u-1,u\}$

Vector cones

The vector-valued set types implemented in MathOptInterface.jl are:

SetDescription
Reals(d)$\mathbb{R}^{d}$
Zeros(d)$0^{d}$
Nonnegatives(d)$\{ x \in \mathbb{R}^{d} : x \ge 0 \}$
Nonpositives(d)$\{ x \in \mathbb{R}^{d} : x \le 0 \}$
SecondOrderCone(d)$\{ (t,x) \in \mathbb{R}^{d} : t \ge \lVert x \rVert_2 \}$
RotatedSecondOrderCone(d)$\{ (t,u,x) \in \mathbb{R}^{d} : 2tu \ge \lVert x \rVert_2^2, t \ge 0,u \ge 0 \}$
ExponentialCone()$\{ (x,y,z) \in \mathbb{R}^3 : y \exp (x/y) \le z, y > 0 \}$
DualExponentialCone()$\{ (u,v,w) \in \mathbb{R}^3 : -u \exp (v/u) \le \exp(1) w, u < 0 \}$
GeometricMeanCone(d)$\{ (t,x) \in \mathbb{R}^{1+n} : x \ge 0, t \le \sqrt[n]{x_1 x_2 \cdots x_n} \}$ where $n$ is $d - 1$
PowerCone(α)$\{ (x,y,z) \in \mathbb{R}^3 : x^{\alpha} y^{1-\alpha} \ge |z|, x \ge 0,y \ge 0 \}$
DualPowerCone(α)$\{ (u,v,w) \in \mathbb{R}^3 : \left(\frac{u}{\alpha}\right(^{\alpha}\left(\frac{v}{1-\alpha}\right)^{1-\alpha} \ge |w|, u,v \ge 0 \}$
NormOneCone(d)$\{ (t,x) \in \mathbb{R}^{d} : t \ge \sum_i \lvert x_i \rvert \}$
NormInfinityCone(d)$\{ (t,x) \in \mathbb{R}^{d} : t \ge \max_i \lvert x_i \rvert \}$
RelativeEntropyCone(d)$\{ (u, v, w) \in \mathbb{R}^{d} : u \ge \sum_i w_i \log (\frac{w_i}{v_i}), v_i \ge 0, w_i \ge 0 \}$
HyperRectangle(l, u)$\{x \in \bar{\mathbb{R}}^d: x_i \in [l_i, u_i] \forall i=1,\ldots,d\}$
NormCone(p, d)``{ (t,x) \in \mathbb{R}^{d} : t \ge \left(\sum\limits_i

Matrix cones

The matrix-valued set types implemented in MathOptInterface.jl are:

SetDescription
RootDetConeTriangle(d)$\{ (t,X) \in \mathbb{R}^{1+d(1+d)/2} : t \le \det(X)^{1/d}, X \mbox{ is the upper triangle of a PSD matrix} \}$
RootDetConeSquare(d)$\{ (t,X) \in \mathbb{R}^{1+d^2} : t \le \det(X)^{1/d}, X \mbox{ is a PSD matrix} \}$
PositiveSemidefiniteConeTriangle(d)$\{ X \in \mathbb{R}^{d(d+1)/2} : X \mbox{ is the upper triangle of a PSD matrix} \}$
PositiveSemidefiniteConeSquare(d)$\{ X \in \mathbb{R}^{d^2} : X \mbox{ is a PSD matrix} \}$
LogDetConeTriangle(d)$\{ (t,u,X) \in \mathbb{R}^{2+d(1+d)/2} : t \le u\log(\det(X/u)), X \mbox{ is the upper triangle of a PSD matrix}, u > 0 \}$
LogDetConeSquare(d)$\{ (t,u,X) \in \mathbb{R}^{2+d^2} : t \le u \log(\det(X/u)), X \mbox{ is a PSD matrix}, u > 0 \}$
NormSpectralCone(r, c)$\{ (t, X) \in \mathbb{R}^{1 + r \times c} : t \ge \sigma_1(X), X \mbox{ is a } r\times c\mbox{ matrix} \}$
NormNuclearCone(r, c)$\{ (t, X) \in \mathbb{R}^{1 + r \times c} : t \ge \sum_i \sigma_i(X), X \mbox{ is a } r\times c\mbox{ matrix} \}$
HermitianPositiveSemidefiniteConeTriangle(d)The cone of Hermitian positive semidefinite matrices, with
side_dimension rows and columns.
Scaled(S)The set S scaled so that Utilities.set_dot corresponds to LinearAlgebra.dot

Some of these cones can take two forms: XXXConeTriangle and XXXConeSquare.

In XXXConeTriangle sets, the matrix is assumed to be symmetric, and the elements are provided by a vector, in which the entries of the upper-right triangular part of the matrix are given column by column (or equivalently, the entries of the lower-left triangular part are given row by row).

In XXXConeSquare sets, the entries of the matrix are given column by column (or equivalently, row by row), and the matrix is constrained to be symmetric. As an example, given a 2-by-2 matrix of variables X and a one-dimensional variable t, we can specify a root-det constraint as [t, X11, X12, X22] ∈ RootDetConeTriangle or [t, X11, X12, X21, X22] ∈ RootDetConeSquare.

We provide both forms to enable flexibility for solvers who may natively support one or the other. Transformations between XXXConeTriangle and XXXConeSquare are handled by bridges, which removes the chance of conversion mistakes by users or solver developers.

Multi-dimensional sets with combinatorial structure

Other sets are vector-valued, with a particular combinatorial structure. Read their docstrings for more information on how to interpret them.

SetDescription
SOS1A Special Ordered Set (SOS) of Type I
SOS2A Special Ordered Set (SOS) of Type II
IndicatorA set to specify an indicator constraint
ComplementsA set to specify a mixed complementarity constraint
AllDifferentThe all_different global constraint
BinPackingThe bin_packing global constraint
CircuitThe circuit global constraint
CountAtLeastThe at_least global constraint
CountBelongsThe nvalue global constraint
CountDistinctThe distinct global constraint
CountGreaterThanThe count_gt global constraint
CumulativeThe cumulative global constraint
PathThe path global constraint
TableThe table global constraint
+\end{align}\]

where:

  • the functions $f_0, f_1, \ldots, f_m$ are specified by AbstractFunction objects
  • the sets $\mathcal{S}_1, \ldots, \mathcal{S}_m$ are specified by AbstractSet objects
Tip

For more information on this standard form, read our paper.

MOI defines some commonly used functions and sets, but the interface is extensible to other sets recognized by the solver.

Functions

The function types implemented in MathOptInterface.jl are:

FunctionDescription
VariableIndex$x_j$, the projection onto a single coordinate defined by a variable index $j$.
VectorOfVariablesThe projection onto multiple coordinates (that is, extracting a sub-vector).
ScalarAffineFunction$a^T x + b$, where $a$ is a vector and $b$ scalar.
ScalarNonlinearFunction$f(x)$, where $f$ is a nonlinear function.
VectorAffineFunction$A x + b$, where $A$ is a matrix and $b$ is a vector.
ScalarQuadraticFunction$\frac{1}{2} x^T Q x + a^T x + b$, where $Q$ is a symmetric matrix, $a$ is a vector, and $b$ is a constant.
VectorQuadraticFunctionA vector of scalar-valued quadratic functions.
VectorNonlinearFunction$f(x)$, where $f$ is a vector-valued nonlinear function.

Extensions for nonlinear programming are present but not yet well documented.

One-dimensional sets

The one-dimensional set types implemented in MathOptInterface.jl are:

SetDescription
LessThan(u)$(-\infty, u]$
GreaterThan(l)$[l, \infty)$
EqualTo(v)$\{v\}$
Interval(l, u)$[l, u]$
Integer()$\mathbb{Z}$
ZeroOne()$\{ 0, 1 \}$
Semicontinuous(l, u)$\{ 0\} \cup [l, u]$
Semiinteger(l, u)$\{ 0\} \cup \{l,l+1,\ldots,u-1,u\}$

Vector cones

The vector-valued set types implemented in MathOptInterface.jl are:

SetDescription
Reals(d)$\mathbb{R}^{d}$
Zeros(d)$0^{d}$
Nonnegatives(d)$\{ x \in \mathbb{R}^{d} : x \ge 0 \}$
Nonpositives(d)$\{ x \in \mathbb{R}^{d} : x \le 0 \}$
SecondOrderCone(d)$\{ (t,x) \in \mathbb{R}^{d} : t \ge \lVert x \rVert_2 \}$
RotatedSecondOrderCone(d)$\{ (t,u,x) \in \mathbb{R}^{d} : 2tu \ge \lVert x \rVert_2^2, t \ge 0,u \ge 0 \}$
ExponentialCone()$\{ (x,y,z) \in \mathbb{R}^3 : y \exp (x/y) \le z, y > 0 \}$
DualExponentialCone()$\{ (u,v,w) \in \mathbb{R}^3 : -u \exp (v/u) \le \exp(1) w, u < 0 \}$
GeometricMeanCone(d)$\{ (t,x) \in \mathbb{R}^{1+n} : x \ge 0, t \le \sqrt[n]{x_1 x_2 \cdots x_n} \}$ where $n$ is $d - 1$
PowerCone(α)$\{ (x,y,z) \in \mathbb{R}^3 : x^{\alpha} y^{1-\alpha} \ge |z|, x \ge 0,y \ge 0 \}$
DualPowerCone(α)$\{ (u,v,w) \in \mathbb{R}^3 : \left(\frac{u}{\alpha}\right(^{\alpha}\left(\frac{v}{1-\alpha}\right)^{1-\alpha} \ge |w|, u,v \ge 0 \}$
NormOneCone(d)$\{ (t,x) \in \mathbb{R}^{d} : t \ge \sum_i \lvert x_i \rvert \}$
NormInfinityCone(d)$\{ (t,x) \in \mathbb{R}^{d} : t \ge \max_i \lvert x_i \rvert \}$
RelativeEntropyCone(d)$\{ (u, v, w) \in \mathbb{R}^{d} : u \ge \sum_i w_i \log (\frac{w_i}{v_i}), v_i \ge 0, w_i \ge 0 \}$
HyperRectangle(l, u)$\{x \in \bar{\mathbb{R}}^d: x_i \in [l_i, u_i] \forall i=1,\ldots,d\}$
NormCone(p, d)``{ (t,x) \in \mathbb{R}^{d} : t \ge \left(\sum\limits_i

Matrix cones

The matrix-valued set types implemented in MathOptInterface.jl are:

SetDescription
RootDetConeTriangle(d)$\{ (t,X) \in \mathbb{R}^{1+d(1+d)/2} : t \le \det(X)^{1/d}, X \mbox{ is the upper triangle of a PSD matrix} \}$
RootDetConeSquare(d)$\{ (t,X) \in \mathbb{R}^{1+d^2} : t \le \det(X)^{1/d}, X \mbox{ is a PSD matrix} \}$
PositiveSemidefiniteConeTriangle(d)$\{ X \in \mathbb{R}^{d(d+1)/2} : X \mbox{ is the upper triangle of a PSD matrix} \}$
PositiveSemidefiniteConeSquare(d)$\{ X \in \mathbb{R}^{d^2} : X \mbox{ is a PSD matrix} \}$
LogDetConeTriangle(d)$\{ (t,u,X) \in \mathbb{R}^{2+d(1+d)/2} : t \le u\log(\det(X/u)), X \mbox{ is the upper triangle of a PSD matrix}, u > 0 \}$
LogDetConeSquare(d)$\{ (t,u,X) \in \mathbb{R}^{2+d^2} : t \le u \log(\det(X/u)), X \mbox{ is a PSD matrix}, u > 0 \}$
NormSpectralCone(r, c)$\{ (t, X) \in \mathbb{R}^{1 + r \times c} : t \ge \sigma_1(X), X \mbox{ is a } r\times c\mbox{ matrix} \}$
NormNuclearCone(r, c)$\{ (t, X) \in \mathbb{R}^{1 + r \times c} : t \ge \sum_i \sigma_i(X), X \mbox{ is a } r\times c\mbox{ matrix} \}$
HermitianPositiveSemidefiniteConeTriangle(d)The cone of Hermitian positive semidefinite matrices, with
side_dimension rows and columns.
Scaled(S)The set S scaled so that Utilities.set_dot corresponds to LinearAlgebra.dot

Some of these cones can take two forms: XXXConeTriangle and XXXConeSquare.

In XXXConeTriangle sets, the matrix is assumed to be symmetric, and the elements are provided by a vector, in which the entries of the upper-right triangular part of the matrix are given column by column (or equivalently, the entries of the lower-left triangular part are given row by row).

In XXXConeSquare sets, the entries of the matrix are given column by column (or equivalently, row by row), and the matrix is constrained to be symmetric. As an example, given a 2-by-2 matrix of variables X and a one-dimensional variable t, we can specify a root-det constraint as [t, X11, X12, X22] ∈ RootDetConeTriangle or [t, X11, X12, X21, X22] ∈ RootDetConeSquare.

We provide both forms to enable flexibility for solvers who may natively support one or the other. Transformations between XXXConeTriangle and XXXConeSquare are handled by bridges, which removes the chance of conversion mistakes by users or solver developers.

Multi-dimensional sets with combinatorial structure

Other sets are vector-valued, with a particular combinatorial structure. Read their docstrings for more information on how to interpret them.

SetDescription
SOS1A Special Ordered Set (SOS) of Type I
SOS2A Special Ordered Set (SOS) of Type II
IndicatorA set to specify an indicator constraint
ComplementsA set to specify a mixed complementarity constraint
AllDifferentThe all_different global constraint
BinPackingThe bin_packing global constraint
CircuitThe circuit global constraint
CountAtLeastThe at_least global constraint
CountBelongsThe nvalue global constraint
CountDistinctThe distinct global constraint
CountGreaterThanThe count_gt global constraint
CumulativeThe cumulative global constraint
PathThe path global constraint
TableThe table global constraint
diff --git a/dev/manual/variables/index.html b/dev/manual/variables/index.html index 81b59f9c42..cffc49cbc2 100644 --- a/dev/manual/variables/index.html +++ b/dev/manual/variables/index.html @@ -10,4 +10,4 @@ false
Warning

Not all ModelLike models support deleting variables. A DeleteNotAllowed error is thrown if this is not supported.

Variable attributes

The following attributes are available for variables:

Get and set these attributes using get and set.

julia> MOI.set(model, MOI.VariableName(), x, "var_x")
 
 julia> MOI.get(model, MOI.VariableName(), x)
-"var_x"
+"var_x" diff --git a/dev/reference/callbacks/index.html b/dev/reference/callbacks/index.html index 26e0e38a2b..1dca863416 100644 --- a/dev/reference/callbacks/index.html +++ b/dev/reference/callbacks/index.html @@ -1,9 +1,9 @@ -Callbacks · MathOptInterface

Callbacks

MathOptInterface.AbstractCallbackType
abstract type AbstractCallback <: AbstractModelAttribute end

Abstract type for a model attribute representing a callback function. The value set to subtypes of AbstractCallback is a function that may be called during optimize!. As optimize! is in progress, the result attributes (i.e, the attributes attr such that is_set_by_optimize(attr)) may not be accessible from the callback, hence trying to get result attributes might throw a OptimizeInProgress error.

At most one callback of each type can be registered. If an optimizer already has a function for a callback type, and the user registers a new function, then the old one is replaced.

The value of the attribute should be a function taking only one argument, commonly called callback_data, that can be used for instance in LazyConstraintCallback, HeuristicCallback and UserCutCallback.

source
MathOptInterface.submitFunction
submit(
+Callbacks · MathOptInterface

Callbacks

MathOptInterface.AbstractCallbackType
abstract type AbstractCallback <: AbstractModelAttribute end

Abstract type for a model attribute representing a callback function. The value set to subtypes of AbstractCallback is a function that may be called during optimize!. As optimize! is in progress, the result attributes (i.e, the attributes attr such that is_set_by_optimize(attr)) may not be accessible from the callback, hence trying to get result attributes might throw a OptimizeInProgress error.

At most one callback of each type can be registered. If an optimizer already has a function for a callback type, and the user registers a new function, then the old one is replaced.

The value of the attribute should be a function taking only one argument, commonly called callback_data, that can be used for instance in LazyConstraintCallback, HeuristicCallback and UserCutCallback.

source
MathOptInterface.submitFunction
submit(
     optimizer::AbstractOptimizer,
     sub::AbstractSubmittable,
     values...,
-)::Nothing

Submit values to the submittable sub of the optimizer optimizer.

An UnsupportedSubmittable error is thrown if model does not support the attribute attr (see supports) and a SubmitNotAllowed error is thrown if it supports the submittable sub but it cannot be submitted.

source

Attributes

MathOptInterface.CallbackNodeStatusCodeType
CallbackNodeStatusCode

An Enum of possible return values from calling get with CallbackNodeStatus.

Values

Possible values are:

source

Lazy constraints

MathOptInterface.LazyConstraintCallbackType
LazyConstraintCallback() <: AbstractCallback

The callback can be used to reduce the feasible set given the current primal solution by submitting a LazyConstraint. For instance, it may be called at an incumbent of a mixed-integer problem. Note that there is no guarantee that the callback is called at every feasible primal solution.

The current primal solution is accessed through CallbackVariablePrimal. Trying to access other result attributes will throw OptimizeInProgress as discussed in AbstractCallback.

Examples

x = MOI.add_variables(optimizer, 8)
+)::Nothing

Submit values to the submittable sub of the optimizer optimizer.

An UnsupportedSubmittable error is thrown if model does not support the attribute attr (see supports) and a SubmitNotAllowed error is thrown if it supports the submittable sub but it cannot be submitted.

source

Attributes

MathOptInterface.CallbackNodeStatusCodeType
CallbackNodeStatusCode

An Enum of possible return values from calling get with CallbackNodeStatus.

Values

Possible values are:

source

Lazy constraints

MathOptInterface.LazyConstraintCallbackType
LazyConstraintCallback() <: AbstractCallback

The callback can be used to reduce the feasible set given the current primal solution by submitting a LazyConstraint. For instance, it may be called at an incumbent of a mixed-integer problem. Note that there is no guarantee that the callback is called at every feasible primal solution.

The current primal solution is accessed through CallbackVariablePrimal. Trying to access other result attributes will throw OptimizeInProgress as discussed in AbstractCallback.

Examples

x = MOI.add_variables(optimizer, 8)
 MOI.set(optimizer, MOI.LazyConstraintCallback(), callback_data -> begin
     sol = MOI.get(optimizer, MOI.CallbackVariablePrimal(callback_data), x)
     if # should add a lazy constraint
@@ -11,9 +11,9 @@
         set = # computes set
         MOI.submit(optimizer, MOI.LazyConstraint(callback_data), func, set)
     end
-end)
source
MathOptInterface.LazyConstraintType
LazyConstraint(callback_data)

Lazy constraint func-in-set submitted as func, set. The optimal solution returned by VariablePrimal will satisfy all lazy constraints that have been submitted.

This can be submitted only from the LazyConstraintCallback. The field callback_data is a solver-specific callback type that is passed as the argument to the feasible solution callback.

Examples

Suppose x and y are VariableIndexs of optimizer. To add a LazyConstraint for 2x + 3y <= 1, write

func = 2.0x + 3.0y
+end)
source
MathOptInterface.LazyConstraintType
LazyConstraint(callback_data)

Lazy constraint func-in-set submitted as func, set. The optimal solution returned by VariablePrimal will satisfy all lazy constraints that have been submitted.

This can be submitted only from the LazyConstraintCallback. The field callback_data is a solver-specific callback type that is passed as the argument to the feasible solution callback.

Examples

Suppose x and y are VariableIndexs of optimizer. To add a LazyConstraint for 2x + 3y <= 1, write

func = 2.0x + 3.0y
 set = MOI.LessThan(1.0)
-MOI.submit(optimizer, MOI.LazyConstraint(callback_data), func, set)

inside a LazyConstraintCallback of data callback_data.

source

User cuts

MathOptInterface.UserCutCallbackType
UserCutCallback() <: AbstractCallback

The callback can be used to submit UserCut given the current primal solution. For instance, it may be called at fractional (i.e., non-integer) nodes in the branch and bound tree of a mixed-integer problem. Note that there is not guarantee that the callback is called everytime the solver has an infeasible solution.

The infeasible solution is accessed through CallbackVariablePrimal. Trying to access other result attributes will throw OptimizeInProgress as discussed in AbstractCallback.

Examples

x = MOI.add_variables(optimizer, 8)
+MOI.submit(optimizer, MOI.LazyConstraint(callback_data), func, set)

inside a LazyConstraintCallback of data callback_data.

source

User cuts

MathOptInterface.UserCutCallbackType
UserCutCallback() <: AbstractCallback

The callback can be used to submit UserCut given the current primal solution. For instance, it may be called at fractional (i.e., non-integer) nodes in the branch and bound tree of a mixed-integer problem. Note that there is not guarantee that the callback is called everytime the solver has an infeasible solution.

The infeasible solution is accessed through CallbackVariablePrimal. Trying to access other result attributes will throw OptimizeInProgress as discussed in AbstractCallback.

Examples

x = MOI.add_variables(optimizer, 8)
 MOI.set(optimizer, MOI.UserCutCallback(), callback_data -> begin
     sol = MOI.get(optimizer, MOI.CallbackVariablePrimal(callback_data), x)
     if # can find a user cut
@@ -21,7 +21,7 @@
         set = # computes set
         MOI.submit(optimizer, MOI.UserCut(callback_data), func, set)
     end
-end
source
MathOptInterface.UserCutType
UserCut(callback_data)

Constraint func-to-set suggested to help the solver detect the solution given by CallbackVariablePrimal as infeasible. The cut is submitted as func, set. Typically CallbackVariablePrimal will violate integrality constraints, and a cut would be of the form ScalarAffineFunction-in-LessThan or ScalarAffineFunction-in-GreaterThan. Note that, as opposed to LazyConstraint, the provided constraint cannot modify the feasible set, the constraint should be redundant, e.g., it may be a consequence of affine and integrality constraints.

This can be submitted only from the UserCutCallback. The field callback_data is a solver-specific callback type that is passed as the argument to the infeasible solution callback.

Note that the solver may silently ignore the provided constraint.

source

Heuristic solutions

MathOptInterface.HeuristicCallbackType
HeuristicCallback() <: AbstractCallback

The callback can be used to submit HeuristicSolution given the current primal solution. For example, it may be called at fractional (i.e., non-integer) nodes in the branch and bound tree of a mixed-integer problem. Note that there is no guarantee that the callback is called every time the solver has an infeasible solution.

The current primal solution is accessed through CallbackVariablePrimal. Trying to access other result attributes will throw OptimizeInProgress as discussed in AbstractCallback.

Examples

x = MOI.add_variables(optimizer, 8)
+end
source
MathOptInterface.UserCutType
UserCut(callback_data)

Constraint func-to-set suggested to help the solver detect the solution given by CallbackVariablePrimal as infeasible. The cut is submitted as func, set. Typically CallbackVariablePrimal will violate integrality constraints, and a cut would be of the form ScalarAffineFunction-in-LessThan or ScalarAffineFunction-in-GreaterThan. Note that, as opposed to LazyConstraint, the provided constraint cannot modify the feasible set, the constraint should be redundant, e.g., it may be a consequence of affine and integrality constraints.

This can be submitted only from the UserCutCallback. The field callback_data is a solver-specific callback type that is passed as the argument to the infeasible solution callback.

Note that the solver may silently ignore the provided constraint.

source

Heuristic solutions

MathOptInterface.HeuristicCallbackType
HeuristicCallback() <: AbstractCallback

The callback can be used to submit HeuristicSolution given the current primal solution. For example, it may be called at fractional (i.e., non-integer) nodes in the branch and bound tree of a mixed-integer problem. Note that there is no guarantee that the callback is called every time the solver has an infeasible solution.

The current primal solution is accessed through CallbackVariablePrimal. Trying to access other result attributes will throw OptimizeInProgress as discussed in AbstractCallback.

Examples

x = MOI.add_variables(optimizer, 8)
 MOI.set(optimizer, MOI.HeuristicCallback(), callback_data -> begin
     sol = MOI.get(optimizer, MOI.CallbackVariablePrimal(callback_data), x)
     if # can find a heuristic solution
@@ -29,4 +29,4 @@
         MOI.submit(optimizer, MOI.HeuristicSolution(callback_data), x,
                    values)
     end
-end
source
MathOptInterface.HeuristicSolutionType
HeuristicSolution(callback_data)

Heuristically obtained feasible solution. The solution is submitted as variables, values where values[i] gives the value of variables[i], similarly to set. The submit call returns a HeuristicSolutionStatus indicating whether the provided solution was accepted or rejected.

This can be submitted only from the HeuristicCallback. The field callback_data is a solver-specific callback type that is passed as the argument to the heuristic callback.

Some solvers require a complete solution, others only partial solutions.

source
+end
source
MathOptInterface.HeuristicSolutionType
HeuristicSolution(callback_data)

Heuristically obtained feasible solution. The solution is submitted as variables, values where values[i] gives the value of variables[i], similarly to set. The submit call returns a HeuristicSolutionStatus indicating whether the provided solution was accepted or rejected.

This can be submitted only from the HeuristicCallback. The field callback_data is a solver-specific callback type that is passed as the argument to the heuristic callback.

Some solvers require a complete solution, others only partial solutions.

source
diff --git a/dev/reference/constraints/index.html b/dev/reference/constraints/index.html index 0fc4c85baa..2598a9c5fb 100644 --- a/dev/reference/constraints/index.html +++ b/dev/reference/constraints/index.html @@ -1,12 +1,12 @@ -Constraints · MathOptInterface

Constraints

Types

MathOptInterface.ConstraintIndexType
ConstraintIndex{F, S}

A type-safe wrapper for Int64 for use in referencing F-in-S constraints in a model. The parameter F is the type of the function in the constraint, and the parameter S is the type of set in the constraint. To allow for deletion, indices need not be consecutive. Indices within a constraint type (i.e. F-in-S) must be unique, but non-unique indices across different constraint types are allowed. If F is VariableIndex then the index is equal to the index of the variable. That is for an index::ConstraintIndex{VariableIndex}, we always have

index.value == MOI.get(model, MOI.ConstraintFunction(), index).value
source

Functions

MathOptInterface.is_validMethod
is_valid(model::ModelLike, index::Index)::Bool

Return a Bool indicating whether this index refers to a valid object in the model model.

source
MathOptInterface.add_constraintFunction
add_constraint(model::ModelLike, func::F, set::S)::ConstraintIndex{F,S} where {F,S}

Add the constraint $f(x) \in \mathcal{S}$ where $f$ is defined by func, and $\mathcal{S}$ is defined by set.

add_constraint(model::ModelLike, v::VariableIndex, set::S)::ConstraintIndex{VariableIndex,S} where {S}
-add_constraint(model::ModelLike, vec::Vector{VariableIndex}, set::S)::ConstraintIndex{VectorOfVariables,S} where {S}

Add the constraint $v \in \mathcal{S}$ where $v$ is the variable (or vector of variables) referenced by v and $\mathcal{S}$ is defined by set.

source
MathOptInterface.add_constraintsFunction
add_constraints(model::ModelLike, funcs::Vector{F}, sets::Vector{S})::Vector{ConstraintIndex{F,S}} where {F,S}

Add the set of constraints specified by each function-set pair in funcs and sets. F and S should be concrete types. This call is equivalent to add_constraint.(model, funcs, sets) but may be more efficient.

source
MathOptInterface.transformFunction

Transform Constraint Set

transform(model::ModelLike, c::ConstraintIndex{F,S1}, newset::S2)::ConstraintIndex{F,S2}

Replace the set in constraint c with newset. The constraint index c will no longer be valid, and the function returns a new constraint index with the correct type.

Solvers may only support a subset of constraint transforms that they perform efficiently (for example, changing from a LessThan to GreaterThan set). In addition, set modification (where S1 = S2) should be performed via the modify function.

Typically, the user should delete the constraint and add a new one.

Examples

If c is a ConstraintIndex{ScalarAffineFunction{Float64},LessThan{Float64}},

c2 = transform(model, c, GreaterThan(0.0))
-transform(model, c, LessThan(0.0)) # errors
source
MathOptInterface.supports_constraintFunction
supports_constraint(
-    model::ModelLike,
-    ::Type{F},
-    ::Type{S},
-)::Bool where {F<:AbstractFunction,S<:AbstractSet}

Return a Bool indicating whether model supports F-in-S constraints, that is, copy_to(model, src) does not throw UnsupportedConstraint when src contains F-in-S constraints. If F-in-S constraints are only not supported in specific circumstances, e.g. F-in-S constraints cannot be combined with another type of constraint, it should still return true.

source
MOI.supports_constraint(
+Constraints · MathOptInterface

Constraints

Types

MathOptInterface.ConstraintIndexType
ConstraintIndex{F, S}

A type-safe wrapper for Int64 for use in referencing F-in-S constraints in a model. The parameter F is the type of the function in the constraint, and the parameter S is the type of set in the constraint. To allow for deletion, indices need not be consecutive. Indices within a constraint type (i.e. F-in-S) must be unique, but non-unique indices across different constraint types are allowed. If F is VariableIndex then the index is equal to the index of the variable. That is for an index::ConstraintIndex{VariableIndex}, we always have

index.value == MOI.get(model, MOI.ConstraintFunction(), index).value
source

Functions

MathOptInterface.is_validMethod
is_valid(model::ModelLike, index::Index)::Bool

Return a Bool indicating whether this index refers to a valid object in the model model.

source
MathOptInterface.add_constraintFunction
add_constraint(model::ModelLike, func::F, set::S)::ConstraintIndex{F,S} where {F,S}

Add the constraint $f(x) \in \mathcal{S}$ where $f$ is defined by func, and $\mathcal{S}$ is defined by set.

add_constraint(model::ModelLike, v::VariableIndex, set::S)::ConstraintIndex{VariableIndex,S} where {S}
+add_constraint(model::ModelLike, vec::Vector{VariableIndex}, set::S)::ConstraintIndex{VectorOfVariables,S} where {S}

Add the constraint $v \in \mathcal{S}$ where $v$ is the variable (or vector of variables) referenced by v and $\mathcal{S}$ is defined by set.

source
MathOptInterface.add_constraintsFunction
add_constraints(model::ModelLike, funcs::Vector{F}, sets::Vector{S})::Vector{ConstraintIndex{F,S}} where {F,S}

Add the set of constraints specified by each function-set pair in funcs and sets. F and S should be concrete types. This call is equivalent to add_constraint.(model, funcs, sets) but may be more efficient.

source
MathOptInterface.transformFunction

Transform Constraint Set

transform(model::ModelLike, c::ConstraintIndex{F,S1}, newset::S2)::ConstraintIndex{F,S2}

Replace the set in constraint c with newset. The constraint index c will no longer be valid, and the function returns a new constraint index with the correct type.

Solvers may only support a subset of constraint transforms that they perform efficiently (for example, changing from a LessThan to GreaterThan set). In addition, set modification (where S1 = S2) should be performed via the modify function.

Typically, the user should delete the constraint and add a new one.

Examples

If c is a ConstraintIndex{ScalarAffineFunction{Float64},LessThan{Float64}},

c2 = transform(model, c, GreaterThan(0.0))
+transform(model, c, LessThan(0.0)) # errors
source
MathOptInterface.supports_constraintFunction
MOI.supports_constraint(
     BT::Type{<:AbstractBridge},
     F::Type{<:MOI.AbstractFunction},
     S::Type{<:MOI.AbstractSet},
-)::Bool

Return a Bool indicating whether the bridges of type BT support bridging F-in-S constraints.

Implementation notes

  • This method depends only on the type of the inputs, not the runtime values.
  • There is a default fallback, so you need only implement this method for constraint types that the bridge implements.
source

Attributes

MathOptInterface.ConstraintNameType
ConstraintName()

A constraint attribute for a string identifying the constraint.

It is valid for constraints variables to have the same name; however, constraints with duplicate names cannot be looked up using get, regardless of whether they have the same F-in-S type.

ConstraintName has a default value of "" if not set.

Notes

You should not implement ConstraintName for VariableIndex constraints.

source
MathOptInterface.ConstraintPrimalType
ConstraintPrimal(result_index::Int = 1)

A constraint attribute for the assignment to some constraint's primal value(s) in result result_index.

If the constraint is f(x) in S, then in most cases the ConstraintPrimal is the value of f, evaluated at the correspondng VariablePrimal solution.

However, some conic solvers reformulate b - Ax in S to s = b - Ax, s in S. These solvers may return the value of s for ConstraintPrimal, rather than b - Ax. (Although these are constrained by an equality constraint, due to numerical tolerances they may not be identical.)

If the solver does not have a primal value for the constraint because the result_index is beyond the available solutions (whose number is indicated by the ResultCount attribute), getting this attribute must throw a ResultIndexBoundsError. Otherwise, if the result is unavailable for another reason (for instance, only a dual solution is available), the result is undefined. Users should first check PrimalStatus before accessing the ConstraintPrimal attribute.

If result_index is omitted, it is 1 by default. See ResultCount for information on how the results are ordered.

source
MathOptInterface.ConstraintDualType
ConstraintDual(result_index::Int = 1)

A constraint attribute for the assignment to some constraint's dual value(s) in result result_index. If result_index is omitted, it is 1 by default.

If the solver does not have a dual value for the variable because the result_index is beyond the available solutions (whose number is indicated by the ResultCount attribute), getting this attribute must throw a ResultIndexBoundsError. Otherwise, if the result is unavailable for another reason (for instance, only a primal solution is available), the result is undefined. Users should first check DualStatus before accessing the ConstraintDual attribute.

See ResultCount for information on how the results are ordered.

source
MathOptInterface.ConstraintBasisStatusType
ConstraintBasisStatus(result_index::Int = 1)

A constraint attribute for the BasisStatusCode of some constraint in result result_index, with respect to an available optimal solution basis. If result_index is omitted, it is 1 by default.

If the solver does not have a basis statue for the constraint because the result_index is beyond the available solutions (whose number is indicated by the ResultCount attribute), getting this attribute must throw a ResultIndexBoundsError. Otherwise, if the result is unavailable for another reason (for instance, only a dual solution is available), the result is undefined. Users should first check PrimalStatus before accessing the ConstraintBasisStatus attribute.

See ResultCount for information on how the results are ordered.

Notes

For the basis status of a variable, query VariableBasisStatus.

ConstraintBasisStatus does not apply to VariableIndex constraints. You can infer the basis status of a VariableIndex constraint by looking at the result of VariableBasisStatus.

source
MathOptInterface.ConstraintFunctionType
ConstraintFunction()

A constraint attribute for the AbstractFunction object used to define the constraint.

It is guaranteed to be equivalent but not necessarily identical to the function provided by the user.

source
MathOptInterface.CanonicalConstraintFunctionType
CanonicalConstraintFunction()

A constraint attribute for a canonical representation of the AbstractFunction object used to define the constraint.

Getting this attribute is guaranteed to return a function that is equivalent but not necessarily identical to the function provided by the user.

By default, MOI.get(model, MOI.CanonicalConstraintFunction(), ci) fallbacks to MOI.Utilities.canonical(MOI.get(model, MOI.ConstraintFunction(), ci)). However, if model knows that the constraint function is canonical then it can implement a specialized method that directly return the function without calling Utilities.canonical. Therefore, the value returned cannot be assumed to be a copy of the function stored in model. Moreover, Utilities.Model checks with Utilities.is_canonical whether the function stored internally is already canonical and if it's the case, then it returns the function stored internally instead of a copy.

source
MathOptInterface.BasisStatusCodeType
BasisStatusCode

An Enum of possible values for the ConstraintBasisStatus and VariableBasisStatus attributes, explaining the status of a given element with respect to an optimal solution basis.

Notes

  • NONBASIC_AT_LOWER and NONBASIC_AT_UPPER should be used only for

constraints with the Interval set. In this case, they are necessary to distinguish which side of the constraint is active. One-sided constraints (e.g., LessThan and GreaterThan) should use NONBASIC instead of the NONBASIC_AT_* values. This restriction does not apply to VariableBasisStatus, which should return NONBASIC_AT_* regardless of whether the alternative bound exists.

  • In linear programs, SUPER_BASIC occurs when a variable with no bounds is not

in the basis.

Values

Possible values are:

source
+)::Bool

Return a Bool indicating whether the bridges of type BT support bridging F-in-S constraints.

Implementation notes

  • This method depends only on the type of the inputs, not the runtime values.
  • There is a default fallback, so you need only implement this method for constraint types that the bridge implements.
source
supports_constraint(
+    model::ModelLike,
+    ::Type{F},
+    ::Type{S},
+)::Bool where {F<:AbstractFunction,S<:AbstractSet}

Return a Bool indicating whether model supports F-in-S constraints, that is, copy_to(model, src) does not throw UnsupportedConstraint when src contains F-in-S constraints. If F-in-S constraints are only not supported in specific circumstances, e.g. F-in-S constraints cannot be combined with another type of constraint, it should still return true.

source

Attributes

MathOptInterface.ConstraintNameType
ConstraintName()

A constraint attribute for a string identifying the constraint.

It is valid for constraints variables to have the same name; however, constraints with duplicate names cannot be looked up using get, regardless of whether they have the same F-in-S type.

ConstraintName has a default value of "" if not set.

Notes

You should not implement ConstraintName for VariableIndex constraints.

source
MathOptInterface.ConstraintPrimalType
ConstraintPrimal(result_index::Int = 1)

A constraint attribute for the assignment to some constraint's primal value(s) in result result_index.

If the constraint is f(x) in S, then in most cases the ConstraintPrimal is the value of f, evaluated at the correspondng VariablePrimal solution.

However, some conic solvers reformulate b - Ax in S to s = b - Ax, s in S. These solvers may return the value of s for ConstraintPrimal, rather than b - Ax. (Although these are constrained by an equality constraint, due to numerical tolerances they may not be identical.)

If the solver does not have a primal value for the constraint because the result_index is beyond the available solutions (whose number is indicated by the ResultCount attribute), getting this attribute must throw a ResultIndexBoundsError. Otherwise, if the result is unavailable for another reason (for instance, only a dual solution is available), the result is undefined. Users should first check PrimalStatus before accessing the ConstraintPrimal attribute.

If result_index is omitted, it is 1 by default. See ResultCount for information on how the results are ordered.

source
MathOptInterface.ConstraintDualType
ConstraintDual(result_index::Int = 1)

A constraint attribute for the assignment to some constraint's dual value(s) in result result_index. If result_index is omitted, it is 1 by default.

If the solver does not have a dual value for the variable because the result_index is beyond the available solutions (whose number is indicated by the ResultCount attribute), getting this attribute must throw a ResultIndexBoundsError. Otherwise, if the result is unavailable for another reason (for instance, only a primal solution is available), the result is undefined. Users should first check DualStatus before accessing the ConstraintDual attribute.

See ResultCount for information on how the results are ordered.

source
MathOptInterface.ConstraintBasisStatusType
ConstraintBasisStatus(result_index::Int = 1)

A constraint attribute for the BasisStatusCode of some constraint in result result_index, with respect to an available optimal solution basis. If result_index is omitted, it is 1 by default.

If the solver does not have a basis statue for the constraint because the result_index is beyond the available solutions (whose number is indicated by the ResultCount attribute), getting this attribute must throw a ResultIndexBoundsError. Otherwise, if the result is unavailable for another reason (for instance, only a dual solution is available), the result is undefined. Users should first check PrimalStatus before accessing the ConstraintBasisStatus attribute.

See ResultCount for information on how the results are ordered.

Notes

For the basis status of a variable, query VariableBasisStatus.

ConstraintBasisStatus does not apply to VariableIndex constraints. You can infer the basis status of a VariableIndex constraint by looking at the result of VariableBasisStatus.

source
MathOptInterface.ConstraintFunctionType
ConstraintFunction()

A constraint attribute for the AbstractFunction object used to define the constraint.

It is guaranteed to be equivalent but not necessarily identical to the function provided by the user.

source
MathOptInterface.CanonicalConstraintFunctionType
CanonicalConstraintFunction()

A constraint attribute for a canonical representation of the AbstractFunction object used to define the constraint.

Getting this attribute is guaranteed to return a function that is equivalent but not necessarily identical to the function provided by the user.

By default, MOI.get(model, MOI.CanonicalConstraintFunction(), ci) fallbacks to MOI.Utilities.canonical(MOI.get(model, MOI.ConstraintFunction(), ci)). However, if model knows that the constraint function is canonical then it can implement a specialized method that directly return the function without calling Utilities.canonical. Therefore, the value returned cannot be assumed to be a copy of the function stored in model. Moreover, Utilities.Model checks with Utilities.is_canonical whether the function stored internally is already canonical and if it's the case, then it returns the function stored internally instead of a copy.

source
MathOptInterface.BasisStatusCodeType
BasisStatusCode

An Enum of possible values for the ConstraintBasisStatus and VariableBasisStatus attributes, explaining the status of a given element with respect to an optimal solution basis.

Notes

  • NONBASIC_AT_LOWER and NONBASIC_AT_UPPER should be used only for

constraints with the Interval set. In this case, they are necessary to distinguish which side of the constraint is active. One-sided constraints (e.g., LessThan and GreaterThan) should use NONBASIC instead of the NONBASIC_AT_* values. This restriction does not apply to VariableBasisStatus, which should return NONBASIC_AT_* regardless of whether the alternative bound exists.

  • In linear programs, SUPER_BASIC occurs when a variable with no bounds is not

in the basis.

Values

Possible values are:

source
diff --git a/dev/reference/errors/index.html b/dev/reference/errors/index.html index 4aacfac74c..9f41d1b9e6 100644 --- a/dev/reference/errors/index.html +++ b/dev/reference/errors/index.html @@ -1,48 +1,48 @@ Errors · MathOptInterface

Errors

When an MOI call fails on a model, precise errors should be thrown when possible instead of simply calling error with a message. The docstrings for the respective methods describe the errors that the implementation should throw in certain situations. This error-reporting system allows code to distinguish between internal errors (that should be shown to the user) and unsupported operations which may have automatic workarounds.

When an invalid index is used in an MOI call, an InvalidIndex is thrown:

When an invalid result index is used to retrieve an attribute, a ResultIndexBoundsError is thrown:

When an invalid result index is used to retrieve an attribute, a ResultIndexBoundsError is thrown:

MathOptInterface.ResultIndexBoundsErrorType
struct ResultIndexBoundsError{AttrType} <: Exception
     attr::AttrType
     result_count::Int
-end

An error indicating that the requested attribute attr could not be retrieved, because the solver returned too few results compared to what was requested. For instance, the user tries to retrieve VariablePrimal(2) when only one solution is available, or when the model is infeasible and has no solution.

See also: check_result_index_bounds.

source

As discussed in JuMP mapping, for scalar constraint with a nonzero function constant, a ScalarFunctionConstantNotZero exception may be thrown:

MathOptInterface.ScalarFunctionConstantNotZeroType
struct ScalarFunctionConstantNotZero{T, F, S} <: Exception
+end

An error indicating that the requested attribute attr could not be retrieved, because the solver returned too few results compared to what was requested. For instance, the user tries to retrieve VariablePrimal(2) when only one solution is available, or when the model is infeasible and has no solution.

See also: check_result_index_bounds.

source

As discussed in JuMP mapping, for scalar constraint with a nonzero function constant, a ScalarFunctionConstantNotZero exception may be thrown:

Some VariableIndex constraints cannot be combined on the same variable:

As discussed in AbstractCallback, trying to get attributes inside a callback may throw:

MathOptInterface.OptimizeInProgressType
struct OptimizeInProgress{AttrType<:AnyAttribute} <: Exception
+end

An error indicating that the constant part of the function in the constraint F-in-S is nonzero.

source

Some VariableIndex constraints cannot be combined on the same variable:

As discussed in AbstractCallback, trying to get attributes inside a callback may throw:

MathOptInterface.OptimizeInProgressType
struct OptimizeInProgress{AttrType<:AnyAttribute} <: Exception
     attr::AttrType
-end

Error thrown from optimizer when MOI.get(optimizer, attr) is called inside an AbstractCallback while it is only defined once optimize! has completed. This can only happen when is_set_by_optimize(attr) is true.

source

Trying to submit the wrong type of AbstractSubmittable inside an AbstractCallback (for example, a UserCut inside a LazyConstraintCallback) will throw:

Trying to submit the wrong type of AbstractSubmittable inside an AbstractCallback (for example, a UserCut inside a LazyConstraintCallback) will throw:

The rest of the errors defined in MOI fall in two categories represented by the following two abstract types:

MathOptInterface.NotAllowedErrorType
NotAllowedError <: Exception

Abstract type for error thrown when an operation is supported but cannot be applied in the current state of the model.

source

The different UnsupportedError and NotAllowedError are the following errors:

The rest of the errors defined in MOI fall in two categories represented by the following two abstract types:

MathOptInterface.NotAllowedErrorType
NotAllowedError <: Exception

Abstract type for error thrown when an operation is supported but cannot be applied in the current state of the model.

source

The different UnsupportedError and NotAllowedError are the following errors:

MathOptInterface.SetAttributeNotAllowedType
struct SetAttributeNotAllowed{AttrType} <: NotAllowedError
     attr::AttrType
     message::String
-end

An error indicating that the attribute attr is supported (see supports) but cannot be set for some reason (see the error string).

source
MathOptInterface.AddVariableNotAllowedType
struct AddVariableNotAllowed <: NotAllowedError
     message::String # Human-friendly explanation why the attribute cannot be set
-end

An error indicating that variables cannot be added to the model.

source
MathOptInterface.UnsupportedConstraintType
struct UnsupportedConstraint{F<:AbstractFunction, S<:AbstractSet} <: UnsupportedError
     message::String # Human-friendly explanation why the attribute cannot be set
-end

An error indicating that constraints of type F-in-S are not supported by the model, i.e. that supports_constraint returns false.

source
MathOptInterface.AddConstraintNotAllowedType
struct AddConstraintNotAllowed{F<:AbstractFunction, S<:AbstractSet} <: NotAllowedError
     message::String # Human-friendly explanation why the attribute cannot be set
-end

An error indicating that constraints of type F-in-S are supported (see supports_constraint) but cannot be added.

source
MathOptInterface.ModifyConstraintNotAllowedType
struct ModifyConstraintNotAllowed{F<:AbstractFunction, S<:AbstractSet,
                                   C<:AbstractFunctionModification} <: NotAllowedError
     constraint_index::ConstraintIndex{F, S}
     change::C
     message::String
-end

An error indicating that the constraint modification change cannot be applied to the constraint of index ci.

source
MathOptInterface.ModifyObjectiveNotAllowedType
struct ModifyObjectiveNotAllowed{C<:AbstractFunctionModification} <: NotAllowedError
+end

An error indicating that the constraint modification change cannot be applied to the constraint of index ci.

source
MathOptInterface.ModifyObjectiveNotAllowedType
struct ModifyObjectiveNotAllowed{C<:AbstractFunctionModification} <: NotAllowedError
     change::C
     message::String
-end

An error indicating that the objective modification change cannot be applied to the objective.

source
MathOptInterface.DeleteNotAllowedType
struct DeleteNotAllowed{IndexType <: Index} <: NotAllowedError
+end

An error indicating that the objective modification change cannot be applied to the objective.

source
MathOptInterface.DeleteNotAllowedType
struct DeleteNotAllowed{IndexType <: Index} <: NotAllowedError
     index::IndexType
     message::String
-end

An error indicating that the index index cannot be deleted.

source
MathOptInterface.SubmitNotAllowedType
struct SubmitNotAllowed{SubmitTyp<:AbstractSubmittable} <: NotAllowedError
+end

An error indicating that the submittable sub is not supported by the model, i.e. that supports returns false.

source
MathOptInterface.SubmitNotAllowedType
struct SubmitNotAllowed{SubmitTyp<:AbstractSubmittable} <: NotAllowedError
     sub::SubmitType
     message::String
-end

An error indicating that the submittable sub is supported (see supports) but cannot be added for some reason (see the error string).

source
MathOptInterface.UnsupportedNonlinearOperatorType
UnsupportedNonlinearOperator(head::Symbol[, message::String]) <: UnsupportedError

An error thrown by optimizers if they do not support the operator head in a ScalarNonlinearFunction.

Example

julia> import MathOptInterface as MOI
+end

An error indicating that the submittable sub is supported (see supports) but cannot be added for some reason (see the error string).

source
MathOptInterface.UnsupportedNonlinearOperatorType
UnsupportedNonlinearOperator(head::Symbol[, message::String]) <: UnsupportedError

An error thrown by optimizers if they do not support the operator head in a ScalarNonlinearFunction.

Example

julia> import MathOptInterface as MOI
 
 julia> throw(MOI.UnsupportedNonlinearOperator(:black_box))
 ERROR: MathOptInterface.UnsupportedNonlinearOperator: The nonlinear operator `:black_box` is not supported by the model.
 Stacktrace:
-[...]
source

Note that setting the ConstraintFunction of a VariableIndex constraint is not allowed:

+[...]source

Note that setting the ConstraintFunction of a VariableIndex constraint is not allowed:

diff --git a/dev/reference/models/index.html b/dev/reference/models/index.html index bd92cac9a2..605b808e1d 100644 --- a/dev/reference/models/index.html +++ b/dev/reference/models/index.html @@ -1,5 +1,9 @@ -Models · MathOptInterface

Models

Attribute interface

MathOptInterface.is_set_by_optimizeFunction
is_set_by_optimize(::AnyAttribute)

Return a Bool indicating whether the value of the attribute is modified during an optimize! call, that is, the attribute is used to query the result of the optimization.

Important note when defining new attributes

This function returns false by default so it should be implemented for attributes that are modified by optimize!.

source
MathOptInterface.is_copyableFunction
is_copyable(::AnyAttribute)

Return a Bool indicating whether the value of the attribute may be copied during copy_to using set.

Important note when defining new attributes

By default is_copyable(attr) returns !is_set_by_optimize(attr). A specific method should be defined for attributes which are copied indirectly during copy_to. For instance, both is_copyable and is_set_by_optimize return false for the following attributes:

source
MathOptInterface.getFunction
get(optimizer::AbstractOptimizer, attr::AbstractOptimizerAttribute)

Return an attribute attr of the optimizer optimizer.

get(model::ModelLike, attr::AbstractModelAttribute)

Return an attribute attr of the model model.

get(model::ModelLike, attr::AbstractVariableAttribute, v::VariableIndex)

If the attribute attr is set for the variable v in the model model, return its value, return nothing otherwise. If the attribute attr is not supported by model then an error should be thrown instead of returning nothing.

get(model::ModelLike, attr::AbstractVariableAttribute, v::Vector{VariableIndex})

Return a vector of attributes corresponding to each variable in the collection v in the model model.

get(model::ModelLike, attr::AbstractConstraintAttribute, c::ConstraintIndex)

If the attribute attr is set for the constraint c in the model model, return its value, return nothing otherwise. If the attribute attr is not supported by model then an error should be thrown instead of returning nothing.

get(
+Models · MathOptInterface

Models

Attribute interface

MathOptInterface.is_set_by_optimizeFunction
is_set_by_optimize(::AnyAttribute)

Return a Bool indicating whether the value of the attribute is modified during an optimize! call, that is, the attribute is used to query the result of the optimization.

Important note when defining new attributes

This function returns false by default so it should be implemented for attributes that are modified by optimize!.

source
MathOptInterface.is_copyableFunction
is_copyable(::AnyAttribute)

Return a Bool indicating whether the value of the attribute may be copied during copy_to using set.

Important note when defining new attributes

By default is_copyable(attr) returns !is_set_by_optimize(attr). A specific method should be defined for attributes which are copied indirectly during copy_to. For instance, both is_copyable and is_set_by_optimize return false for the following attributes:

source
MathOptInterface.getFunction
MOI.get(b::AbstractBridge, ::MOI.NumberOfVariables)::Int64

Return the number of variables created by the bridge b in the model.

See also MOI.NumberOfConstraints.

Implementation notes

  • There is a default fallback, so you need only implement this if the bridge adds new variables.
source
MOI.get(b::AbstractBridge, ::MOI.ListOfVariableIndices)

Return the list of variables created by the bridge b.

See also MOI.ListOfVariableIndices.

Implementation notes

  • There is a default fallback, so you need only implement this if the bridge adds new variables.
source
MOI.get(b::AbstractBridge, ::MOI.NumberOfConstraints{F,S})::Int64 where {F,S}

Return the number of constraints of the type F-in-S created by the bridge b.

See also MOI.NumberOfConstraints.

Implementation notes

  • There is a default fallback, so you need only implement this for the constraint types returned by added_constraint_types.
source
MOI.get(b::AbstractBridge, ::MOI.ListOfConstraintIndices{F,S}) where {F,S}

Return a Vector{ConstraintIndex{F,S}} with indices of all constraints of type F-in-S created by the bride b.

See also MOI.ListOfConstraintIndices.

Implementation notes

  • There is a default fallback, so you need only implement this for the constraint types returned by added_constraint_types.
source
function MOI.get(
+    model::MOI.ModelLike,
+    attr::MOI.AbstractConstraintAttribute,
+    bridge::AbstractBridge,
+)

Return the value of the attribute attr of the model model for the constraint bridged by bridge.

source
get(optimizer::AbstractOptimizer, attr::AbstractOptimizerAttribute)

Return an attribute attr of the optimizer optimizer.

get(model::ModelLike, attr::AbstractModelAttribute)

Return an attribute attr of the model model.

get(model::ModelLike, attr::AbstractVariableAttribute, v::VariableIndex)

If the attribute attr is set for the variable v in the model model, return its value, return nothing otherwise. If the attribute attr is not supported by model then an error should be thrown instead of returning nothing.

get(model::ModelLike, attr::AbstractVariableAttribute, v::Vector{VariableIndex})

Return a vector of attributes corresponding to each variable in the collection v in the model model.

get(model::ModelLike, attr::AbstractConstraintAttribute, c::ConstraintIndex)

If the attribute attr is set for the constraint c in the model model, return its value, return nothing otherwise. If the attribute attr is not supported by model then an error should be thrown instead of returning nothing.

get(
     model::ModelLike,
     attr::AbstractConstraintAttribute,
     c::Vector{ConstraintIndex{F,S}},
@@ -7,11 +11,12 @@
     model::ModelLike,
     ::Type{ConstraintIndex{F,S}},
     name::String,
-) where {F,S}

If an F-in-S constraint with name name exists in the model model, return the corresponding index, otherwise return nothing. Errors if two constraints have the same name.

get(model::ModelLike, ::Type{ConstraintIndex}, name::String)

If any constraint with name name exists in the model model, return the corresponding index, otherwise return nothing. This version is available for convenience but may incur a performance penalty because it is not type stable. Errors if two constraints have the same name.

source
MOI.get(b::AbstractBridge, ::MOI.NumberOfVariables)::Int64

Return the number of variables created by the bridge b in the model.

See also MOI.NumberOfConstraints.

Implementation notes

  • There is a default fallback, so you need only implement this if the bridge adds new variables.
source
MOI.get(b::AbstractBridge, ::MOI.ListOfVariableIndices)

Return the list of variables created by the bridge b.

See also MOI.ListOfVariableIndices.

Implementation notes

  • There is a default fallback, so you need only implement this if the bridge adds new variables.
source
MOI.get(b::AbstractBridge, ::MOI.NumberOfConstraints{F,S})::Int64 where {F,S}

Return the number of constraints of the type F-in-S created by the bridge b.

See also MOI.NumberOfConstraints.

Implementation notes

  • There is a default fallback, so you need only implement this for the constraint types returned by added_constraint_types.
source
MOI.get(b::AbstractBridge, ::MOI.ListOfConstraintIndices{F,S}) where {F,S}

Return a Vector{ConstraintIndex{F,S}} with indices of all constraints of type F-in-S created by the bride b.

See also MOI.ListOfConstraintIndices.

Implementation notes

  • There is a default fallback, so you need only implement this for the constraint types returned by added_constraint_types.
source
function MOI.get(
+) where {F,S}

If an F-in-S constraint with name name exists in the model model, return the corresponding index, otherwise return nothing. Errors if two constraints have the same name.

get(model::ModelLike, ::Type{ConstraintIndex}, name::String)

If any constraint with name name exists in the model model, return the corresponding index, otherwise return nothing. This version is available for convenience but may incur a performance penalty because it is not type stable. Errors if two constraints have the same name.

source
MathOptInterface.get!Function
get!(output, model::ModelLike, args...)

An in-place version of get.

The signature matches that of get except that the the result is placed in the vector output.

source
MathOptInterface.setFunction
function MOI.set(
     model::MOI.ModelLike,
     attr::MOI.AbstractConstraintAttribute,
     bridge::AbstractBridge,
-)

Return the value of the attribute attr of the model model for the constraint bridged by bridge.

source
MathOptInterface.get!Function
get!(output, model::ModelLike, args...)

An in-place version of get.

The signature matches that of get except that the the result is placed in the vector output.

source
MathOptInterface.setFunction
set(optimizer::AbstractOptimizer, attr::AbstractOptimizerAttribute, value)

Assign value to the attribute attr of the optimizer optimizer.

set(model::ModelLike, attr::AbstractModelAttribute, value)

Assign value to the attribute attr of the model model.

set(model::ModelLike, attr::AbstractVariableAttribute, v::VariableIndex, value)

Assign value to the attribute attr of variable v in model model.

set(
+    value,
+)

Set the value of the attribute attr of the model model for the constraint bridged by bridge.

source
set(optimizer::AbstractOptimizer, attr::AbstractOptimizerAttribute, value)

Assign value to the attribute attr of the optimizer optimizer.

set(model::ModelLike, attr::AbstractModelAttribute, value)

Assign value to the attribute attr of the model model.

set(model::ModelLike, attr::AbstractVariableAttribute, v::VariableIndex, value)

Assign value to the attribute attr of variable v in model model.

set(
     model::ModelLike,
     attr::AbstractVariableAttribute,
     v::Vector{VariableIndex},
@@ -36,12 +41,11 @@
     ::ConstraintFunction,
     c::ConstraintIndex{F,S},
     func::F,
-) where {F,S}

Replace the function in constraint c with func. F must match the original function type used to define the constraint.

Note

Setting the constraint function is not allowed if F is VariableIndex; a SettingVariableIndexNotAllowed error is thrown instead. This is because, it would require changing the index c since the index of VariableIndex constraints must be the same as the index of the variable.

source
function MOI.set(
+) where {F,S}

Replace the function in constraint c with func. F must match the original function type used to define the constraint.

Note

Setting the constraint function is not allowed if F is VariableIndex; a SettingVariableIndexNotAllowed error is thrown instead. This is because, it would require changing the index c since the index of VariableIndex constraints must be the same as the index of the variable.

source
MathOptInterface.supportsFunction
MOI.supports(
     model::MOI.ModelLike,
     attr::MOI.AbstractConstraintAttribute,
-    bridge::AbstractBridge,
-    value,
-)

Set the value of the attribute attr of the model model for the constraint bridged by bridge.

source
MathOptInterface.supportsFunction
supports(model::ModelLike, sub::AbstractSubmittable)::Bool

Return a Bool indicating whether model supports the submittable sub.

supports(model::ModelLike, attr::AbstractOptimizerAttribute)::Bool

Return a Bool indicating whether model supports the optimizer attribute attr. That is, it returns false if copy_to(model, src) shows a warning in case attr is in the ListOfOptimizerAttributesSet of src; see copy_to for more details on how unsupported optimizer attributes are handled in copy.

supports(model::ModelLike, attr::AbstractModelAttribute)::Bool

Return a Bool indicating whether model supports the model attribute attr. That is, it returns false if copy_to(model, src) cannot be performed in case attr is in the ListOfModelAttributesSet of src.

supports(
+    BT::Type{<:AbstractBridge},
+)

Return a Bool indicating whether BT supports setting attr to model.

source
supports(model::ModelLike, sub::AbstractSubmittable)::Bool

Return a Bool indicating whether model supports the submittable sub.

supports(model::ModelLike, attr::AbstractOptimizerAttribute)::Bool

Return a Bool indicating whether model supports the optimizer attribute attr. That is, it returns false if copy_to(model, src) shows a warning in case attr is in the ListOfOptimizerAttributesSet of src; see copy_to for more details on how unsupported optimizer attributes are handled in copy.

supports(model::ModelLike, attr::AbstractModelAttribute)::Bool

Return a Bool indicating whether model supports the model attribute attr. That is, it returns false if copy_to(model, src) cannot be performed in case attr is in the ListOfModelAttributesSet of src.

supports(
     model::ModelLike,
     attr::AbstractVariableAttribute,
     ::Type{VariableIndex},
@@ -49,11 +53,7 @@
     model::ModelLike,
     attr::AbstractConstraintAttribute,
     ::Type{ConstraintIndex{F,S}},
-)::Bool where {F,S}

Return a Bool indicating whether model supports the constraint attribute attr applied to an F-in-S constraint. That is, it returns false if copy_to(model, src) cannot be performed in case attr is in the ListOfConstraintAttributesSet of src.

For all five methods, if the attribute is only not supported in specific circumstances, it should still return true.

Note that supports is only defined for attributes for which is_copyable returns true as other attributes do not appear in the list of attributes set obtained by ListOf...AttributesSet.

source
MOI.supports(
-    model::MOI.ModelLike,
-    attr::MOI.AbstractConstraintAttribute,
-    BT::Type{<:AbstractBridge},
-)

Return a Bool indicating whether BT supports setting attr to model.

source
MathOptInterface.attribute_value_typeFunction
attribute_value_type(attr::AnyAttribute)

Given an attribute attr, return the type of value expected by get, or returned by set.

Notes

  • Only implement this if it make sense to do so. If un-implemented, the default is Any.
source

Model interface

MathOptInterface.is_emptyFunction
is_empty(model::ModelLike)

Returns false if the model has any model attribute set or has any variables or constraints.

Note that an empty model can have optimizer attributes set.

source
MathOptInterface.empty!Function
empty!(model::ModelLike)

Empty the model, that is, remove all variables, constraints and model attributes but not optimizer attributes.

source
MathOptInterface.write_to_fileFunction
write_to_file(model::ModelLike, filename::String)

Write the current model to the file at filename.

Supported file types depend on the model type.

source
MathOptInterface.read_from_fileFunction
read_from_file(model::ModelLike, filename::String)

Read the file filename into the model model. If model is non-empty, this may throw an error.

Supported file types depend on the model type.

Note

Once the contents of the file are loaded into the model, users can query the variables via get(model, ListOfVariableIndices()). However, some filetypes, such as LP files, do not maintain an explicit ordering of the variables. Therefore, the returned list may be in an arbitrary order.

To avoid depending on the order of the indices, look up each variable index by name using get(model, VariableIndex, "name").

source
MathOptInterface.copy_toFunction
copy_to(dest::ModelLike, src::ModelLike)::IndexMap

Copy the model from src into dest.

The target dest is emptied, and all previous indices to variables and constraints in dest are invalidated.

Returns an IndexMap object that translates variable and constraint indices from the src model to the corresponding indices in the dest model.

Notes

AbstractOptimizerAttributes are not copied to the dest model.

IndexMap

Implementations of copy_to must return an IndexMap. For technical reasons, this type is defined in the Utilities submodule as MOI.Utilities.IndexMap. However, since it is an integral part of the MOI API, we provide MOI.IndexMap as an alias.

Example

# Given empty `ModelLike` objects `src` and `dest`.
+)::Bool where {F,S}

Return a Bool indicating whether model supports the constraint attribute attr applied to an F-in-S constraint. That is, it returns false if copy_to(model, src) cannot be performed in case attr is in the ListOfConstraintAttributesSet of src.

For all five methods, if the attribute is only not supported in specific circumstances, it should still return true.

Note that supports is only defined for attributes for which is_copyable returns true as other attributes do not appear in the list of attributes set obtained by ListOf...AttributesSet.

source
MathOptInterface.attribute_value_typeFunction
attribute_value_type(attr::AnyAttribute)

Given an attribute attr, return the type of value expected by get, or returned by set.

Notes

  • Only implement this if it make sense to do so. If un-implemented, the default is Any.
source

Model interface

MathOptInterface.is_emptyFunction
is_empty(model::ModelLike)

Returns false if the model has any model attribute set or has any variables or constraints.

Note that an empty model can have optimizer attributes set.

source
MathOptInterface.empty!Function
empty!(model::ModelLike)

Empty the model, that is, remove all variables, constraints and model attributes but not optimizer attributes.

source
MathOptInterface.write_to_fileFunction
write_to_file(model::ModelLike, filename::String)

Write the current model to the file at filename.

Supported file types depend on the model type.

source
MathOptInterface.read_from_fileFunction
read_from_file(model::ModelLike, filename::String)

Read the file filename into the model model. If model is non-empty, this may throw an error.

Supported file types depend on the model type.

Note

Once the contents of the file are loaded into the model, users can query the variables via get(model, ListOfVariableIndices()). However, some filetypes, such as LP files, do not maintain an explicit ordering of the variables. Therefore, the returned list may be in an arbitrary order.

To avoid depending on the order of the indices, look up each variable index by name using get(model, VariableIndex, "name").

source
MathOptInterface.copy_toFunction
copy_to(dest::ModelLike, src::ModelLike)::IndexMap

Copy the model from src into dest.

The target dest is emptied, and all previous indices to variables and constraints in dest are invalidated.

Returns an IndexMap object that translates variable and constraint indices from the src model to the corresponding indices in the dest model.

Notes

AbstractOptimizerAttributes are not copied to the dest model.

IndexMap

Implementations of copy_to must return an IndexMap. For technical reasons, this type is defined in the Utilities submodule as MOI.Utilities.IndexMap. However, since it is an integral part of the MOI API, we provide MOI.IndexMap as an alias.

Example

# Given empty `ModelLike` objects `src` and `dest`.
 
 x = add_variable(src)
 
@@ -62,9 +62,9 @@
 
 index_map = copy_to(dest, src)
 is_valid(dest, x) # false (unless index_map[x] == x)
-is_valid(dest, index_map[x]) # true
source
MathOptInterface.IndexMapType
IndexMap()

The dictionary-like object returned by copy_to.

IndexMap

Implementations of copy_to must return an IndexMap. For technical reasons, the IndexMap type is defined in the Utilities submodule as MOI.Utilities.IndexMap. However, since it is an integral part of the MOI API, we provide this MOI.IndexMap as an alias.

source

Model attributes

MathOptInterface.NameType
Name()

A model attribute for the string identifying the model. It has a default value of "" if not set`.

source
MathOptInterface.ObjectiveFunctionType
ObjectiveFunction{F<:AbstractScalarFunction}()

A model attribute for the objective function which has a type F<:AbstractScalarFunction.

F should be guaranteed to be equivalent but not necessarily identical to the function type provided by the user.

Throws an InexactError if the objective function cannot be converted to F, e.g., the objective function is quadratic and F is ScalarAffineFunction{Float64} or it has non-integer coefficient and F is ScalarAffineFunction{Int}.

source
MathOptInterface.IndexMapType
IndexMap()

The dictionary-like object returned by copy_to.

IndexMap

Implementations of copy_to must return an IndexMap. For technical reasons, the IndexMap type is defined in the Utilities submodule as MOI.Utilities.IndexMap. However, since it is an integral part of the MOI API, we provide this MOI.IndexMap as an alias.

source

Model attributes

MathOptInterface.NameType
Name()

A model attribute for the string identifying the model. It has a default value of "" if not set`.

source
MathOptInterface.ObjectiveFunctionType
ObjectiveFunction{F<:AbstractScalarFunction}()

A model attribute for the objective function which has a type F<:AbstractScalarFunction.

F should be guaranteed to be equivalent but not necessarily identical to the function type provided by the user.

Throws an InexactError if the objective function cannot be converted to F, e.g., the objective function is quadratic and F is ScalarAffineFunction{Float64} or it has non-integer coefficient and F is ScalarAffineFunction{Int}.

source
MathOptInterface.ObjectiveFunctionTypeType
ObjectiveFunctionType()

A model attribute for the type F of the objective function set using the ObjectiveFunction{F} attribute.

Examples

In the following code, attr should be equal to MOI.VariableIndex:

x = MOI.add_variable(model)
 MOI.set(model, MOI.ObjectiveFunction{MOI.VariableIndex}(), x)
-attr = MOI.get(model, MOI.ObjectiveFunctionType())
source
MathOptInterface.ObjectiveSenseType
ObjectiveSense()

A model attribute for the objective sense of the objective function, which must be an OptimizationSense: MIN_SENSE, MAX_SENSE, or FEASIBILITY_SENSE. The default is FEASIBILITY_SENSE.

Interaction with ObjectiveFunction

Setting the sense to FEASIBILITY_SENSE unsets the ObjectiveFunction attribute. That is, if you first set ObjectiveFunction and then set ObjectiveSense to be FEASIBILITY_SENSE, no objective function will be passed to the solver.

In addition, some reformulations of ObjectiveFunction via bridges rely on the value of ObjectiveSense. Therefore, you should set ObjectiveSense before setting ObjectiveFunction.

source
MathOptInterface.ListOfModelAttributesSetType
ListOfModelAttributesSet()

A model attribute for the Vector{AbstractModelAttribute} of all model attributes attr such that:

  1. is_copyable(attr) returns true, and
  2. the attribute was set to the model
source
MathOptInterface.ListOfVariableAttributesSetType
ListOfVariableAttributesSet()

A model attribute for the Vector{AbstractVariableAttribute} of all variable attributes attr such that 1) is_copyable(attr) returns true and 2) the attribute was set to variables.

source
MathOptInterface.UserDefinedFunctionType
UserDefinedFunction(name::Symbol, arity::Int) <: AbstractModelAttribute

Set this attribute to register a user-defined function by the name of name with arity arguments.

Once registered, name will appear in ListOfSupportedNonlinearOperators.

You cannot register multiple UserDefinedFunctions with the same name but different arity.

Value type

The value to be set is a tuple containing one, two, or three functions to evaluate the function, the first-order derivative, and the second-order derivative respectively. Both derivatives are optional, but if you pass the second-order derivative you must also pass the first-order derivative.

For univariate functions with arity == 1, the functions in the tuple must have the form:

  • f(x::T)::T: returns the value of the function at x
  • ∇f(x::T)::T: returns the first-order derivative of f with respect to x
  • ∇²f(x::T)::T: returns the second-order derivative of f with respect to x.

For multivariate functions with arity > 1, the functions in the tuple must have the form:

  • f(x::T...)::T: returns the value of the function at x
  • ∇f(g::AbstractVector{T}, x::T...)::Nothing: fills the components of g, with g[i] being the first-order partial derivative of f with respect to x[i]
  • ∇²f(H::AbstractMatrix{T}, x::T...)::Nothing: fills the non-zero components of H, with H[i, j] being the second-order partial derivative of f with respect to x[i] and then x[j]. H is initialized to the zero matrix, so you do not need to set any zero elements.

Examples

julia> import MathOptInterface as MOI
+attr = MOI.get(model, MOI.ObjectiveFunctionType())
source
MathOptInterface.ObjectiveSenseType
ObjectiveSense()

A model attribute for the objective sense of the objective function, which must be an OptimizationSense: MIN_SENSE, MAX_SENSE, or FEASIBILITY_SENSE. The default is FEASIBILITY_SENSE.

Interaction with ObjectiveFunction

Setting the sense to FEASIBILITY_SENSE unsets the ObjectiveFunction attribute. That is, if you first set ObjectiveFunction and then set ObjectiveSense to be FEASIBILITY_SENSE, no objective function will be passed to the solver.

In addition, some reformulations of ObjectiveFunction via bridges rely on the value of ObjectiveSense. Therefore, you should set ObjectiveSense before setting ObjectiveFunction.

source
MathOptInterface.ListOfModelAttributesSetType
ListOfModelAttributesSet()

A model attribute for the Vector{AbstractModelAttribute} of all model attributes attr such that:

  1. is_copyable(attr) returns true, and
  2. the attribute was set to the model
source
MathOptInterface.ListOfVariableAttributesSetType
ListOfVariableAttributesSet()

A model attribute for the Vector{AbstractVariableAttribute} of all variable attributes attr such that 1) is_copyable(attr) returns true and 2) the attribute was set to variables.

source
MathOptInterface.UserDefinedFunctionType
UserDefinedFunction(name::Symbol, arity::Int) <: AbstractModelAttribute

Set this attribute to register a user-defined function by the name of name with arity arguments.

Once registered, name will appear in ListOfSupportedNonlinearOperators.

You cannot register multiple UserDefinedFunctions with the same name but different arity.

Value type

The value to be set is a tuple containing one, two, or three functions to evaluate the function, the first-order derivative, and the second-order derivative respectively. Both derivatives are optional, but if you pass the second-order derivative you must also pass the first-order derivative.

For univariate functions with arity == 1, the functions in the tuple must have the form:

  • f(x::T)::T: returns the value of the function at x
  • ∇f(x::T)::T: returns the first-order derivative of f with respect to x
  • ∇²f(x::T)::T: returns the second-order derivative of f with respect to x.

For multivariate functions with arity > 1, the functions in the tuple must have the form:

  • f(x::T...)::T: returns the value of the function at x
  • ∇f(g::AbstractVector{T}, x::T...)::Nothing: fills the components of g, with g[i] being the first-order partial derivative of f with respect to x[i]
  • ∇²f(H::AbstractMatrix{T}, x::T...)::Nothing: fills the non-zero components of H, with H[i, j] being the second-order partial derivative of f with respect to x[i] and then x[j]. H is initialized to the zero matrix, so you do not need to set any zero elements.

Examples

julia> import MathOptInterface as MOI
 
 julia> f(x, y) = x^2 + y^2
 f (generic function with 1 method)
@@ -108,18 +108,18 @@
  f(v[1], v[2])
 
 Subject to:
-
source

Optimizer interface

MathOptInterface.AbstractOptimizerType
AbstractOptimizer <: ModelLike

Abstract supertype for objects representing an instance of an optimization problem tied to a particular solver. This is typically a solver's in-memory representation. In addition to ModelLike, AbstractOptimizer objects let you solve the model and query the solution.

source

Optimizer interface

MathOptInterface.AbstractOptimizerType
AbstractOptimizer <: ModelLike

Abstract supertype for objects representing an instance of an optimization problem tied to a particular solver. This is typically a solver's in-memory representation. In addition to ModelLike, AbstractOptimizer objects let you solve the model and query the solution.

source
MathOptInterface.optimize!Method
optimize!(dest::AbstractOptimizer, src::ModelLike)::Tuple{IndexMap,Bool}

A "one-shot" call that copies the problem from src into dest and then uses dest to optimize the problem.

Returns a tuple of an IndexMap and a Bool copied.

  • The IndexMap object translates variable and constraint indices from the src model to the corresponding indices in the dest optimizer. See copy_to for details.
  • If copied == true, src was copied to dest and then cached, allowing incremental modification if supported by the solver.
  • If copied == false, a cache of the model was not kept in dest. Therefore, only the solution information (attributes for which is_set_by_optimize is true) is available to query.
Note

The main purpose of optimize! method with two arguments is for use in Utilities.CachingOptimizer.

Relationship to the single-argument optimize!

The default fallback of optimize!(dest::AbstractOptimizer, src::ModelLike) is

function optimize!(dest::AbstractOptimizer, src::ModelLike)
+end

Object grouping an optimizer constructor and a list of optimizer attributes. Instances are created with instantiate.

source
MathOptInterface.optimize!Method
optimize!(dest::AbstractOptimizer, src::ModelLike)::Tuple{IndexMap,Bool}

A "one-shot" call that copies the problem from src into dest and then uses dest to optimize the problem.

Returns a tuple of an IndexMap and a Bool copied.

  • The IndexMap object translates variable and constraint indices from the src model to the corresponding indices in the dest optimizer. See copy_to for details.
  • If copied == true, src was copied to dest and then cached, allowing incremental modification if supported by the solver.
  • If copied == false, a cache of the model was not kept in dest. Therefore, only the solution information (attributes for which is_set_by_optimize is true) is available to query.
Note

The main purpose of optimize! method with two arguments is for use in Utilities.CachingOptimizer.

Relationship to the single-argument optimize!

The default fallback of optimize!(dest::AbstractOptimizer, src::ModelLike) is

function optimize!(dest::AbstractOptimizer, src::ModelLike)
     index_map = copy_to(dest, src)
     optimize!(dest)
     return index_map, true
-end

Therefore, subtypes of AbstractOptimizer should either implement this two-argument method, or implement both copy_to(::Optimizer, ::ModelLike) and optimize!(::Optimizer).

source
MathOptInterface.instantiateFunction
instantiate(
     optimizer_constructor,
     with_cache_type::Union{Nothing,Type} = nothing,
     with_bridge_type::Union{Nothing,Type} = nothing,
-)

Create an instance of an optimizer by either:

  • calling optimizer_constructor.optimizer_constructor() and setting the parameters in optimizer_constructor.params if optimizer_constructor is a OptimizerWithAttributes
  • calling optimizer_constructor() if optimizer_constructor is callable.

withcachetype

If with_cache_type is not nothing, then the optimizer is wrapped in a Utilities.CachingOptimizer to store a cache of the model. This is most useful if the optimizer you are constructing does not support the incremental interface (see supports_incremental_interface).

withbridgetype

If with_bridge_type is not nothing, the optimizer is wrapped in a Bridges.full_bridge_optimizer, enabling all the bridges defined in the MOI.Bridges submodule with coefficient type with_bridge_type.

In addition, if the optimizer created by optimizer_constructor does not support the incremental interface (see supports_incremental_interface), then, irrespective of with_cache_type, the optimizer is wrapped in a Utilities.CachingOptimizer to store a cache of the bridged model.

If with_cache_type and with_bridge_type are both not nothing, then they must be the same type.

source
MathOptInterface.default_cacheFunction
default_cache(optimizer::ModelLike, ::Type{T}) where {T}

Return a new instance of the default model type to be used as cache for optimizer in a Utilities.CachingOptimizer for holding constraints of coefficient type T. By default, this returns Utilities.UniversalFallback(Utilities.Model{T}()). If copying from a instance of a given model type is faster for optimizer then a new method returning an instance of this model type should be defined.

source

Optimizer attributes

MathOptInterface.SolverVersionType
SolverVersion()

An optimizer attribute for the string identifying the version of the solver.

Note

For solvers supporting semantic versioning, the SolverVersion should be a string of the form "vMAJOR.MINOR.PATCH", so that it can be converted to a Julia VersionNumber (e.g., `VersionNumber("v1.2.3")).

We do not require Semantic Versioning because some solvers use alternate versioning systems. For example, CPLEX uses Calendar Versioning, so SolverVersion will return a string like "202001".

source
MathOptInterface.SilentType
Silent()

An optimizer attribute for silencing the output of an optimizer. When set to true, it takes precedence over any other attribute controlling verbosity and requires the solver to produce no output. The default value is false which has no effect. In this case the verbosity is controlled by other attributes.

Note

Every optimizer should have verbosity on by default. For instance, if a solver has a solver-specific log level attribute, the MOI implementation should set it to 1 by default. If the user sets Silent to true, then the log level should be set to 0, even if the user specifically sets a value of log level. If the value of Silent is false then the log level set to the solver is the value given by the user for this solver-specific parameter or 1 if none is given.

source
MathOptInterface.TimeLimitSecType
TimeLimitSec()

An optimizer attribute for setting a time limit (in seconnds) for an optimization. When set to nothing, it deactivates the solver time limit. The default value is nothing.

source
MathOptInterface.ObjectiveLimitType
ObjectiveLimit()

An optimizer attribute for setting a limit on the objective value.

The provided limit must be a Union{Real,Nothing}.

When set to nothing, the limit reverts to the solver's default.

The default value is nothing.

The solver may stop when the ObjectiveValue is better (lower for minimization, higher for maximization) than the ObjectiveLimit. If stopped, the TerminationStatus should be OBJECTIVE_LIMIT.

source
MathOptInterface.NumberOfThreadsType
NumberOfThreads()

An optimizer attribute for setting the number of threads used for an optimization. When set to nothing uses solver default. Values are positive integers. The default value is nothing.

source
MathOptInterface.AbsoluteGapToleranceType
AbsoluteGapTolerance()

An optimizer attribute for setting the absolute gap tolerance for an optimization. This is an optimizer attribute, and should be set before calling optimize!. When set to nothing (if supported), uses solver default.

To set a relative gap tolerance, see RelativeGapTolerance.

Warning

The mathematical definition of "absolute gap", and its treatment during the optimization, are solver-dependent. However, assuming no other limit nor issue is encountered during the optimization, most solvers that implement this attribute will stop once $|f - b| ≤ g_{abs}$, where $b$ is the best bound, $f$ is the best feasible objective value, and $g_{abs}$ is the absolute gap.

source
MathOptInterface.RelativeGapToleranceType
RelativeGapTolerance()

An optimizer attribute for setting the relative gap tolerance for an optimization. This is an optimizer attribute, and should be set before calling optimize!. When set to nothing (if supported), uses solver default.

If you are looking for the relative gap of the current best solution, see RelativeGap. If no limit nor issue is encountered during the optimization, the value of RelativeGap should be at most as large as RelativeGapTolerance.

# Before optimizing: set relative gap tolerance
+)

Create an instance of an optimizer by either:

  • calling optimizer_constructor.optimizer_constructor() and setting the parameters in optimizer_constructor.params if optimizer_constructor is a OptimizerWithAttributes
  • calling optimizer_constructor() if optimizer_constructor is callable.

withcachetype

If with_cache_type is not nothing, then the optimizer is wrapped in a Utilities.CachingOptimizer to store a cache of the model. This is most useful if the optimizer you are constructing does not support the incremental interface (see supports_incremental_interface).

withbridgetype

If with_bridge_type is not nothing, the optimizer is wrapped in a Bridges.full_bridge_optimizer, enabling all the bridges defined in the MOI.Bridges submodule with coefficient type with_bridge_type.

In addition, if the optimizer created by optimizer_constructor does not support the incremental interface (see supports_incremental_interface), then, irrespective of with_cache_type, the optimizer is wrapped in a Utilities.CachingOptimizer to store a cache of the bridged model.

If with_cache_type and with_bridge_type are both not nothing, then they must be the same type.

source
MathOptInterface.default_cacheFunction
default_cache(optimizer::ModelLike, ::Type{T}) where {T}

Return a new instance of the default model type to be used as cache for optimizer in a Utilities.CachingOptimizer for holding constraints of coefficient type T. By default, this returns Utilities.UniversalFallback(Utilities.Model{T}()). If copying from a instance of a given model type is faster for optimizer then a new method returning an instance of this model type should be defined.

source

Optimizer attributes

MathOptInterface.SolverVersionType
SolverVersion()

An optimizer attribute for the string identifying the version of the solver.

Note

For solvers supporting semantic versioning, the SolverVersion should be a string of the form "vMAJOR.MINOR.PATCH", so that it can be converted to a Julia VersionNumber (e.g., `VersionNumber("v1.2.3")).

We do not require Semantic Versioning because some solvers use alternate versioning systems. For example, CPLEX uses Calendar Versioning, so SolverVersion will return a string like "202001".

source
MathOptInterface.SilentType
Silent()

An optimizer attribute for silencing the output of an optimizer. When set to true, it takes precedence over any other attribute controlling verbosity and requires the solver to produce no output. The default value is false which has no effect. In this case the verbosity is controlled by other attributes.

Note

Every optimizer should have verbosity on by default. For instance, if a solver has a solver-specific log level attribute, the MOI implementation should set it to 1 by default. If the user sets Silent to true, then the log level should be set to 0, even if the user specifically sets a value of log level. If the value of Silent is false then the log level set to the solver is the value given by the user for this solver-specific parameter or 1 if none is given.

source
MathOptInterface.TimeLimitSecType
TimeLimitSec()

An optimizer attribute for setting a time limit (in seconnds) for an optimization. When set to nothing, it deactivates the solver time limit. The default value is nothing.

source
MathOptInterface.ObjectiveLimitType
ObjectiveLimit()

An optimizer attribute for setting a limit on the objective value.

The provided limit must be a Union{Real,Nothing}.

When set to nothing, the limit reverts to the solver's default.

The default value is nothing.

The solver may stop when the ObjectiveValue is better (lower for minimization, higher for maximization) than the ObjectiveLimit. If stopped, the TerminationStatus should be OBJECTIVE_LIMIT.

source
MathOptInterface.NumberOfThreadsType
NumberOfThreads()

An optimizer attribute for setting the number of threads used for an optimization. When set to nothing uses solver default. Values are positive integers. The default value is nothing.

source
MathOptInterface.AbsoluteGapToleranceType
AbsoluteGapTolerance()

An optimizer attribute for setting the absolute gap tolerance for an optimization. This is an optimizer attribute, and should be set before calling optimize!. When set to nothing (if supported), uses solver default.

To set a relative gap tolerance, see RelativeGapTolerance.

Warning

The mathematical definition of "absolute gap", and its treatment during the optimization, are solver-dependent. However, assuming no other limit nor issue is encountered during the optimization, most solvers that implement this attribute will stop once $|f - b| ≤ g_{abs}$, where $b$ is the best bound, $f$ is the best feasible objective value, and $g_{abs}$ is the absolute gap.

source
MathOptInterface.RelativeGapToleranceType
RelativeGapTolerance()

An optimizer attribute for setting the relative gap tolerance for an optimization. This is an optimizer attribute, and should be set before calling optimize!. When set to nothing (if supported), uses solver default.

If you are looking for the relative gap of the current best solution, see RelativeGap. If no limit nor issue is encountered during the optimization, the value of RelativeGap should be at most as large as RelativeGapTolerance.

# Before optimizing: set relative gap tolerance
 # set 0.1% relative gap tolerance
 MOI.set(model, MOI.RelativeGapTolerance(), 1e-3)
 MOI.optimize!(model)
@@ -129,4 +129,4 @@
 MOI.get(model, MOI.RelativeGapTolerance())  # returns 1e-3
 # ... and the relative gap of the obtained solution is smaller or equal to the
 # tolerance
-MOI.get(model, MOI.RelativeGap())  # should return something ≤ 1e-3
Warning

The mathematical definition of "relative gap", and its allowed range, are solver-dependent. Typically, solvers expect a value between 0.0 and 1.0.

source

List of attributes useful for optimizers

MathOptInterface.TerminationStatusCodeType
TerminationStatusCode

An Enum of possible values for the TerminationStatus attribute. This attribute is meant to explain the reason why the optimizer stopped executing in the most recent call to optimize!.

Values

Possible values are:

  • OPTIMIZE_NOT_CALLED: The algorithm has not started.
  • OPTIMAL: The algorithm found a globally optimal solution.
  • INFEASIBLE: The algorithm concluded that no feasible solution exists.
  • DUAL_INFEASIBLE: The algorithm concluded that no dual bound exists for the problem. If, additionally, a feasible (primal) solution is known to exist, this status typically implies that the problem is unbounded, with some technical exceptions.
  • LOCALLY_SOLVED: The algorithm converged to a stationary point, local optimal solution, could not find directions for improvement, or otherwise completed its search without global guarantees.
  • LOCALLY_INFEASIBLE: The algorithm converged to an infeasible point or otherwise completed its search without finding a feasible solution, without guarantees that no feasible solution exists.
  • INFEASIBLE_OR_UNBOUNDED: The algorithm stopped because it decided that the problem is infeasible or unbounded; this occasionally happens during MIP presolve.
  • ALMOST_OPTIMAL: The algorithm found a globally optimal solution to relaxed tolerances.
  • ALMOST_INFEASIBLE: The algorithm concluded that no feasible solution exists within relaxed tolerances.
  • ALMOST_DUAL_INFEASIBLE: The algorithm concluded that no dual bound exists for the problem within relaxed tolerances.
  • ALMOST_LOCALLY_SOLVED: The algorithm converged to a stationary point, local optimal solution, or could not find directions for improvement within relaxed tolerances.
  • ITERATION_LIMIT: An iterative algorithm stopped after conducting the maximum number of iterations.
  • TIME_LIMIT: The algorithm stopped after a user-specified computation time.
  • NODE_LIMIT: A branch-and-bound algorithm stopped because it explored a maximum number of nodes in the branch-and-bound tree.
  • SOLUTION_LIMIT: The algorithm stopped because it found the required number of solutions. This is often used in MIPs to get the solver to return the first feasible solution it encounters.
  • MEMORY_LIMIT: The algorithm stopped because it ran out of memory.
  • OBJECTIVE_LIMIT: The algorithm stopped because it found a solution better than a minimum limit set by the user.
  • NORM_LIMIT: The algorithm stopped because the norm of an iterate became too large.
  • OTHER_LIMIT: The algorithm stopped due to a limit not covered by one of the _LIMIT_ statuses above.
  • SLOW_PROGRESS: The algorithm stopped because it was unable to continue making progress towards the solution.
  • NUMERICAL_ERROR: The algorithm stopped because it encountered unrecoverable numerical error.
  • INVALID_MODEL: The algorithm stopped because the model is invalid.
  • INVALID_OPTION: The algorithm stopped because it was provided an invalid option.
  • INTERRUPTED: The algorithm stopped because of an interrupt signal.
  • OTHER_ERROR: The algorithm stopped because of an error not covered by one of the statuses defined above.
source
MathOptInterface.DUAL_INFEASIBLEConstant
DUAL_INFEASIBLE::TerminationStatusCode

An instance of the TerminationStatusCode enum.

DUAL_INFEASIBLE: The algorithm concluded that no dual bound exists for the problem. If, additionally, a feasible (primal) solution is known to exist, this status typically implies that the problem is unbounded, with some technical exceptions.

source
MathOptInterface.LOCALLY_SOLVEDConstant
LOCALLY_SOLVED::TerminationStatusCode

An instance of the TerminationStatusCode enum.

LOCALLY_SOLVED: The algorithm converged to a stationary point, local optimal solution, could not find directions for improvement, or otherwise completed its search without global guarantees.

source
MathOptInterface.LOCALLY_INFEASIBLEConstant
LOCALLY_INFEASIBLE::TerminationStatusCode

An instance of the TerminationStatusCode enum.

LOCALLY_INFEASIBLE: The algorithm converged to an infeasible point or otherwise completed its search without finding a feasible solution, without guarantees that no feasible solution exists.

source
MathOptInterface.SOLUTION_LIMITConstant
SOLUTION_LIMIT::TerminationStatusCode

An instance of the TerminationStatusCode enum.

SOLUTION_LIMIT: The algorithm stopped because it found the required number of solutions. This is often used in MIPs to get the solver to return the first feasible solution it encounters.

source
MathOptInterface.DualStatusType
DualStatus(result_index::Int = 1)

A model attribute for the ResultStatusCode of the dual result result_index. If result_index is omitted, it defaults to 1.

See ResultCount for information on how the results are ordered.

If result_index is larger than the value of ResultCount then NO_SOLUTION is returned.

source
MathOptInterface.ResultCountType
ResultCount()

A model attribute for the number of results available.

Order of solutions

A number of attributes contain an index, result_index, which is used to refer to one of the available results. Thus, result_index must be an integer between 1 and the number of available results.

As a general rule, the first result (result_index=1) is the most important result (e.g., an optimal solution or an infeasibility certificate). Other results will typically be alternate solutions that the solver found during the search for the first result.

If a (local) optimal solution is available, i.e., TerminationStatus is OPTIMAL or LOCALLY_SOLVED, the first result must correspond to the (locally) optimal solution. Other results may be alternative optimal solutions, or they may be other suboptimal solutions; use ObjectiveValue to distingiush between them.

If a primal or dual infeasibility certificate is available, i.e., TerminationStatus is INFEASIBLE or DUAL_INFEASIBLE and the corresponding PrimalStatus or DualStatus is INFEASIBILITY_CERTIFICATE, then the first result must be a certificate. Other results may be alternate certificates, or infeasible points.

source
MathOptInterface.ObjectiveValueType
ObjectiveValue(result_index::Int = 1)

A model attribute for the objective value of the primal solution result_index.

If the solver does not have a primal value for the objective because the result_index is beyond the available solutions (whose number is indicated by the ResultCount attribute), getting this attribute must throw a ResultIndexBoundsError. Otherwise, if the result is unavailable for another reason (for instance, only a dual solution is available), the result is undefined. Users should first check PrimalStatus before accessing the ObjectiveValue attribute.

See ResultCount for information on how the results are ordered.

source
MathOptInterface.DualObjectiveValueType
DualObjectiveValue(result_index::Int = 1)

A model attribute for the value of the objective function of the dual problem for the result_indexth dual result.

If the solver does not have a dual value for the objective because the result_index is beyond the available solutions (whose number is indicated by the ResultCount attribute), getting this attribute must throw a ResultIndexBoundsError. Otherwise, if the result is unavailable for another reason (for instance, only a primal solution is available), the result is undefined. Users should first check DualStatus before accessing the DualObjectiveValue attribute.

See ResultCount for information on how the results are ordered.

source
MathOptInterface.RelativeGapType
RelativeGap()

A model attribute for the final relative optimality gap.

Warning

The definition of this gap is solver-dependent. However, most solvers implementing this attribute define the relative gap as some variation of $\frac{|b-f|}{|f|}$, where $b$ is the best bound and $f$ is the best feasible objective value.

source
MathOptInterface.SimplexIterationsType
SimplexIterations()

A model attribute for the cumulative number of simplex iterations during the optimization process.

For a mixed-integer program (MIP), the return value is the total simplex iterations for all nodes.

source
MathOptInterface.NodeCountType
NodeCount()

A model attribute for the total number of branch-and-bound nodes explored while solving a mixed-integer program (MIP).

source

ResultStatusCode

MathOptInterface.ResultStatusCodeType
ResultStatusCode

An Enum of possible values for the PrimalStatus and DualStatus attributes.

The values indicate how to interpret the result vector.

Values

Possible values are:

  • NO_SOLUTION: the result vector is empty.
  • FEASIBLE_POINT: the result vector is a feasible point.
  • NEARLY_FEASIBLE_POINT: the result vector is feasible if some constraint tolerances are relaxed.
  • INFEASIBLE_POINT: the result vector is an infeasible point.
  • INFEASIBILITY_CERTIFICATE: the result vector is an infeasibility certificate. If the PrimalStatus is INFEASIBILITY_CERTIFICATE, then the primal result vector is a certificate of dual infeasibility. If the DualStatus is INFEASIBILITY_CERTIFICATE, then the dual result vector is a proof of primal infeasibility.
  • NEARLY_INFEASIBILITY_CERTIFICATE: the result satisfies a relaxed criterion for a certificate of infeasibility.
  • REDUCTION_CERTIFICATE: the result vector is an ill-posed certificate; see this article for details. If the PrimalStatus is REDUCTION_CERTIFICATE, then the primal result vector is a proof that the dual problem is ill-posed. If the DualStatus is REDUCTION_CERTIFICATE, then the dual result vector is a proof that the primal is ill-posed.
  • NEARLY_REDUCTION_CERTIFICATE: the result satisfies a relaxed criterion for an ill-posed certificate.
  • UNKNOWN_RESULT_STATUS: the result vector contains a solution with an unknown interpretation.
  • OTHER_RESULT_STATUS: the result vector contains a solution with an interpretation not covered by one of the statuses defined above
source
MathOptInterface.INFEASIBILITY_CERTIFICATEConstant
INFEASIBILITY_CERTIFICATE::ResultStatusCode

An instance of the ResultStatusCode enum.

INFEASIBILITY_CERTIFICATE: the result vector is an infeasibility certificate. If the PrimalStatus is INFEASIBILITY_CERTIFICATE, then the primal result vector is a certificate of dual infeasibility. If the DualStatus is INFEASIBILITY_CERTIFICATE, then the dual result vector is a proof of primal infeasibility.

source
MathOptInterface.REDUCTION_CERTIFICATEConstant
REDUCTION_CERTIFICATE::ResultStatusCode

An instance of the ResultStatusCode enum.

REDUCTION_CERTIFICATE: the result vector is an ill-posed certificate; see this article for details. If the PrimalStatus is REDUCTION_CERTIFICATE, then the primal result vector is a proof that the dual problem is ill-posed. If the DualStatus is REDUCTION_CERTIFICATE, then the dual result vector is a proof that the primal is ill-posed.

source

Conflict Status

MathOptInterface.compute_conflict!Function
compute_conflict!(optimizer::AbstractOptimizer)

Computes a minimal subset of constraints such that the model with the other constraint removed is still infeasible.

Some solvers call a set of conflicting constraints an Irreducible Inconsistent Subsystem (IIS).

See also ConflictStatus and ConstraintConflictStatus.

Note

If the model is modified after a call to compute_conflict!, the implementor is not obliged to purge the conflict. Any calls to the above attributes may return values for the original conflict without a warning. Similarly, when modifying the model, the conflict can be discarded.

source
MathOptInterface.ConflictStatusCodeType
ConflictStatusCode

An Enum of possible values for the ConflictStatus attribute. This attribute is meant to explain the reason why the conflict finder stopped executing in the most recent call to compute_conflict!.

Possible values are:

  • COMPUTE_CONFLICT_NOT_CALLED: the function compute_conflict! has not yet been called
  • NO_CONFLICT_EXISTS: there is no conflict because the problem is feasible
  • NO_CONFLICT_FOUND: the solver could not find a conflict
  • CONFLICT_FOUND: at least one conflict could be found
source
MathOptInterface.ConflictParticipationStatusCodeType
ConflictParticipationStatusCode

An Enum of possible values for the ConstraintConflictStatus attribute. This attribute is meant to indicate whether a given constraint participates or not in the last computed conflict.

Values

Possible values are:

  • NOT_IN_CONFLICT: the constraint does not participate in the conflict
  • IN_CONFLICT: the constraint participates in the conflict
  • MAYBE_IN_CONFLICT: the constraint may participate in the conflict, the solver was not able to prove that the constraint can be excluded from the conflict
source
+MOI.get(model, MOI.RelativeGap()) # should return something ≤ 1e-3
Warning

The mathematical definition of "relative gap", and its allowed range, are solver-dependent. Typically, solvers expect a value between 0.0 and 1.0.

source

List of attributes useful for optimizers

MathOptInterface.TerminationStatusCodeType
TerminationStatusCode

An Enum of possible values for the TerminationStatus attribute. This attribute is meant to explain the reason why the optimizer stopped executing in the most recent call to optimize!.

Values

Possible values are:

  • OPTIMIZE_NOT_CALLED: The algorithm has not started.
  • OPTIMAL: The algorithm found a globally optimal solution.
  • INFEASIBLE: The algorithm concluded that no feasible solution exists.
  • DUAL_INFEASIBLE: The algorithm concluded that no dual bound exists for the problem. If, additionally, a feasible (primal) solution is known to exist, this status typically implies that the problem is unbounded, with some technical exceptions.
  • LOCALLY_SOLVED: The algorithm converged to a stationary point, local optimal solution, could not find directions for improvement, or otherwise completed its search without global guarantees.
  • LOCALLY_INFEASIBLE: The algorithm converged to an infeasible point or otherwise completed its search without finding a feasible solution, without guarantees that no feasible solution exists.
  • INFEASIBLE_OR_UNBOUNDED: The algorithm stopped because it decided that the problem is infeasible or unbounded; this occasionally happens during MIP presolve.
  • ALMOST_OPTIMAL: The algorithm found a globally optimal solution to relaxed tolerances.
  • ALMOST_INFEASIBLE: The algorithm concluded that no feasible solution exists within relaxed tolerances.
  • ALMOST_DUAL_INFEASIBLE: The algorithm concluded that no dual bound exists for the problem within relaxed tolerances.
  • ALMOST_LOCALLY_SOLVED: The algorithm converged to a stationary point, local optimal solution, or could not find directions for improvement within relaxed tolerances.
  • ITERATION_LIMIT: An iterative algorithm stopped after conducting the maximum number of iterations.
  • TIME_LIMIT: The algorithm stopped after a user-specified computation time.
  • NODE_LIMIT: A branch-and-bound algorithm stopped because it explored a maximum number of nodes in the branch-and-bound tree.
  • SOLUTION_LIMIT: The algorithm stopped because it found the required number of solutions. This is often used in MIPs to get the solver to return the first feasible solution it encounters.
  • MEMORY_LIMIT: The algorithm stopped because it ran out of memory.
  • OBJECTIVE_LIMIT: The algorithm stopped because it found a solution better than a minimum limit set by the user.
  • NORM_LIMIT: The algorithm stopped because the norm of an iterate became too large.
  • OTHER_LIMIT: The algorithm stopped due to a limit not covered by one of the _LIMIT_ statuses above.
  • SLOW_PROGRESS: The algorithm stopped because it was unable to continue making progress towards the solution.
  • NUMERICAL_ERROR: The algorithm stopped because it encountered unrecoverable numerical error.
  • INVALID_MODEL: The algorithm stopped because the model is invalid.
  • INVALID_OPTION: The algorithm stopped because it was provided an invalid option.
  • INTERRUPTED: The algorithm stopped because of an interrupt signal.
  • OTHER_ERROR: The algorithm stopped because of an error not covered by one of the statuses defined above.
source
MathOptInterface.DUAL_INFEASIBLEConstant
DUAL_INFEASIBLE::TerminationStatusCode

An instance of the TerminationStatusCode enum.

DUAL_INFEASIBLE: The algorithm concluded that no dual bound exists for the problem. If, additionally, a feasible (primal) solution is known to exist, this status typically implies that the problem is unbounded, with some technical exceptions.

source
MathOptInterface.LOCALLY_SOLVEDConstant
LOCALLY_SOLVED::TerminationStatusCode

An instance of the TerminationStatusCode enum.

LOCALLY_SOLVED: The algorithm converged to a stationary point, local optimal solution, could not find directions for improvement, or otherwise completed its search without global guarantees.

source
MathOptInterface.LOCALLY_INFEASIBLEConstant
LOCALLY_INFEASIBLE::TerminationStatusCode

An instance of the TerminationStatusCode enum.

LOCALLY_INFEASIBLE: The algorithm converged to an infeasible point or otherwise completed its search without finding a feasible solution, without guarantees that no feasible solution exists.

source
MathOptInterface.SOLUTION_LIMITConstant
SOLUTION_LIMIT::TerminationStatusCode

An instance of the TerminationStatusCode enum.

SOLUTION_LIMIT: The algorithm stopped because it found the required number of solutions. This is often used in MIPs to get the solver to return the first feasible solution it encounters.

source
MathOptInterface.DualStatusType
DualStatus(result_index::Int = 1)

A model attribute for the ResultStatusCode of the dual result result_index. If result_index is omitted, it defaults to 1.

See ResultCount for information on how the results are ordered.

If result_index is larger than the value of ResultCount then NO_SOLUTION is returned.

source
MathOptInterface.ResultCountType
ResultCount()

A model attribute for the number of results available.

Order of solutions

A number of attributes contain an index, result_index, which is used to refer to one of the available results. Thus, result_index must be an integer between 1 and the number of available results.

As a general rule, the first result (result_index=1) is the most important result (e.g., an optimal solution or an infeasibility certificate). Other results will typically be alternate solutions that the solver found during the search for the first result.

If a (local) optimal solution is available, i.e., TerminationStatus is OPTIMAL or LOCALLY_SOLVED, the first result must correspond to the (locally) optimal solution. Other results may be alternative optimal solutions, or they may be other suboptimal solutions; use ObjectiveValue to distingiush between them.

If a primal or dual infeasibility certificate is available, i.e., TerminationStatus is INFEASIBLE or DUAL_INFEASIBLE and the corresponding PrimalStatus or DualStatus is INFEASIBILITY_CERTIFICATE, then the first result must be a certificate. Other results may be alternate certificates, or infeasible points.

source
MathOptInterface.ObjectiveValueType
ObjectiveValue(result_index::Int = 1)

A model attribute for the objective value of the primal solution result_index.

If the solver does not have a primal value for the objective because the result_index is beyond the available solutions (whose number is indicated by the ResultCount attribute), getting this attribute must throw a ResultIndexBoundsError. Otherwise, if the result is unavailable for another reason (for instance, only a dual solution is available), the result is undefined. Users should first check PrimalStatus before accessing the ObjectiveValue attribute.

See ResultCount for information on how the results are ordered.

source
MathOptInterface.DualObjectiveValueType
DualObjectiveValue(result_index::Int = 1)

A model attribute for the value of the objective function of the dual problem for the result_indexth dual result.

If the solver does not have a dual value for the objective because the result_index is beyond the available solutions (whose number is indicated by the ResultCount attribute), getting this attribute must throw a ResultIndexBoundsError. Otherwise, if the result is unavailable for another reason (for instance, only a primal solution is available), the result is undefined. Users should first check DualStatus before accessing the DualObjectiveValue attribute.

See ResultCount for information on how the results are ordered.

source
MathOptInterface.RelativeGapType
RelativeGap()

A model attribute for the final relative optimality gap.

Warning

The definition of this gap is solver-dependent. However, most solvers implementing this attribute define the relative gap as some variation of $\frac{|b-f|}{|f|}$, where $b$ is the best bound and $f$ is the best feasible objective value.

source
MathOptInterface.SimplexIterationsType
SimplexIterations()

A model attribute for the cumulative number of simplex iterations during the optimization process.

For a mixed-integer program (MIP), the return value is the total simplex iterations for all nodes.

source
MathOptInterface.NodeCountType
NodeCount()

A model attribute for the total number of branch-and-bound nodes explored while solving a mixed-integer program (MIP).

source

ResultStatusCode

MathOptInterface.ResultStatusCodeType
ResultStatusCode

An Enum of possible values for the PrimalStatus and DualStatus attributes.

The values indicate how to interpret the result vector.

Values

Possible values are:

  • NO_SOLUTION: the result vector is empty.
  • FEASIBLE_POINT: the result vector is a feasible point.
  • NEARLY_FEASIBLE_POINT: the result vector is feasible if some constraint tolerances are relaxed.
  • INFEASIBLE_POINT: the result vector is an infeasible point.
  • INFEASIBILITY_CERTIFICATE: the result vector is an infeasibility certificate. If the PrimalStatus is INFEASIBILITY_CERTIFICATE, then the primal result vector is a certificate of dual infeasibility. If the DualStatus is INFEASIBILITY_CERTIFICATE, then the dual result vector is a proof of primal infeasibility.
  • NEARLY_INFEASIBILITY_CERTIFICATE: the result satisfies a relaxed criterion for a certificate of infeasibility.
  • REDUCTION_CERTIFICATE: the result vector is an ill-posed certificate; see this article for details. If the PrimalStatus is REDUCTION_CERTIFICATE, then the primal result vector is a proof that the dual problem is ill-posed. If the DualStatus is REDUCTION_CERTIFICATE, then the dual result vector is a proof that the primal is ill-posed.
  • NEARLY_REDUCTION_CERTIFICATE: the result satisfies a relaxed criterion for an ill-posed certificate.
  • UNKNOWN_RESULT_STATUS: the result vector contains a solution with an unknown interpretation.
  • OTHER_RESULT_STATUS: the result vector contains a solution with an interpretation not covered by one of the statuses defined above
source
MathOptInterface.INFEASIBILITY_CERTIFICATEConstant
INFEASIBILITY_CERTIFICATE::ResultStatusCode

An instance of the ResultStatusCode enum.

INFEASIBILITY_CERTIFICATE: the result vector is an infeasibility certificate. If the PrimalStatus is INFEASIBILITY_CERTIFICATE, then the primal result vector is a certificate of dual infeasibility. If the DualStatus is INFEASIBILITY_CERTIFICATE, then the dual result vector is a proof of primal infeasibility.

source
MathOptInterface.REDUCTION_CERTIFICATEConstant
REDUCTION_CERTIFICATE::ResultStatusCode

An instance of the ResultStatusCode enum.

REDUCTION_CERTIFICATE: the result vector is an ill-posed certificate; see this article for details. If the PrimalStatus is REDUCTION_CERTIFICATE, then the primal result vector is a proof that the dual problem is ill-posed. If the DualStatus is REDUCTION_CERTIFICATE, then the dual result vector is a proof that the primal is ill-posed.

source

Conflict Status

MathOptInterface.compute_conflict!Function
compute_conflict!(optimizer::AbstractOptimizer)

Computes a minimal subset of constraints such that the model with the other constraint removed is still infeasible.

Some solvers call a set of conflicting constraints an Irreducible Inconsistent Subsystem (IIS).

See also ConflictStatus and ConstraintConflictStatus.

Note

If the model is modified after a call to compute_conflict!, the implementor is not obliged to purge the conflict. Any calls to the above attributes may return values for the original conflict without a warning. Similarly, when modifying the model, the conflict can be discarded.

source
MathOptInterface.ConflictStatusCodeType
ConflictStatusCode

An Enum of possible values for the ConflictStatus attribute. This attribute is meant to explain the reason why the conflict finder stopped executing in the most recent call to compute_conflict!.

Possible values are:

  • COMPUTE_CONFLICT_NOT_CALLED: the function compute_conflict! has not yet been called
  • NO_CONFLICT_EXISTS: there is no conflict because the problem is feasible
  • NO_CONFLICT_FOUND: the solver could not find a conflict
  • CONFLICT_FOUND: at least one conflict could be found
source
MathOptInterface.ConflictParticipationStatusCodeType
ConflictParticipationStatusCode

An Enum of possible values for the ConstraintConflictStatus attribute. This attribute is meant to indicate whether a given constraint participates or not in the last computed conflict.

Values

Possible values are:

  • NOT_IN_CONFLICT: the constraint does not participate in the conflict
  • IN_CONFLICT: the constraint participates in the conflict
  • MAYBE_IN_CONFLICT: the constraint may participate in the conflict, the solver was not able to prove that the constraint can be excluded from the conflict
source
diff --git a/dev/reference/modification/index.html b/dev/reference/modification/index.html index bc65b1fd47..79ecbf098a 100644 --- a/dev/reference/modification/index.html +++ b/dev/reference/modification/index.html @@ -21,7 +21,7 @@ ScalarCoefficientChange{Float64}(VariableIndex(1), 1.0), ScalarCoefficientChange{Float64}(VariableIndex(2), 0.5), ], -)source
MathOptInterface.AbstractFunctionModificationType
AbstractFunctionModification

An abstract supertype for structs which specify partial modifications to functions, to be used for making small modifications instead of replacing the functions entirely.

source
MathOptInterface.AbstractFunctionModificationType
AbstractFunctionModification

An abstract supertype for structs which specify partial modifications to functions, to be used for making small modifications instead of replacing the functions entirely.

source
+) where {T}

A struct used to request a change in the linear coefficients of a single variable in a vector-valued function.

New coefficients are specified by (output_index, coefficient) tuples.

Applicable to VectorAffineFunction and VectorQuadraticFunction.

source diff --git a/dev/reference/nonlinear/index.html b/dev/reference/nonlinear/index.html index 6c1e4c03ad..9deb66c9b5 100644 --- a/dev/reference/nonlinear/index.html +++ b/dev/reference/nonlinear/index.html @@ -1,68 +1,68 @@ -Nonlinear programming · MathOptInterface

Nonlinear programming

Types

MathOptInterface.NLPBoundsPairType
NLPBoundsPair(lower::Float64, upper::Float64)

A struct holding a pair of lower and upper bounds.

-Inf and Inf can be used to indicate no lower or upper bound, respectively.

source
MathOptInterface.NLPBlockDataType
struct NLPBlockData
+Nonlinear programming · MathOptInterface

Nonlinear programming

Types

MathOptInterface.NLPBoundsPairType
NLPBoundsPair(lower::Float64, upper::Float64)

A struct holding a pair of lower and upper bounds.

-Inf and Inf can be used to indicate no lower or upper bound, respectively.

source
MathOptInterface.NLPBlockDataType
struct NLPBlockData
     constraint_bounds::Vector{NLPBoundsPair}
     evaluator::AbstractNLPEvaluator
     has_objective::Bool
-end

A struct encoding a set of nonlinear constraints of the form $lb \le g(x) \le ub$ and, if has_objective == true, a nonlinear objective function $f(x)$.

Nonlinear objectives override any objective set by using the ObjectiveFunction attribute.

The evaluator is a callback object that is used to query function values, derivatives, and expression graphs. If has_objective == false, then it is an error to query properties of the objective function, and in Hessian-of-the-Lagrangian queries, σ must be set to zero.

Note

Throughout the evaluator, all variables are ordered according to ListOfVariableIndices. Hence, MOI copies of nonlinear problems must not re-order variables.

source

Attributes

Functions

MathOptInterface.initializeFunction
initialize(
+end

A struct encoding a set of nonlinear constraints of the form $lb \le g(x) \le ub$ and, if has_objective == true, a nonlinear objective function $f(x)$.

Nonlinear objectives override any objective set by using the ObjectiveFunction attribute.

The evaluator is a callback object that is used to query function values, derivatives, and expression graphs. If has_objective == false, then it is an error to query properties of the objective function, and in Hessian-of-the-Lagrangian queries, σ must be set to zero.

Note

Throughout the evaluator, all variables are ordered according to ListOfVariableIndices. Hence, MOI copies of nonlinear problems must not re-order variables.

source

Attributes

Functions

MathOptInterface.initializeFunction
initialize(
     d::AbstractNLPEvaluator,
     requested_features::Vector{Symbol},
 )::Nothing

Initialize d with the set of features in requested_features. Check features_available before calling initialize to see what features are supported by d.

Warning

This method must be called before any other methods.

Features

The following features are defined:

In all cases, including when requested_features is empty, eval_objective and eval_constraint are supported.

Examples

MOI.initialize(d, Symbol[])
 MOI.initialize(d, [:ExprGraph])
-MOI.initialize(d, MOI.features_available(d))
source
MathOptInterface.eval_constraintFunction
eval_constraint(d::AbstractNLPEvaluator,
     g::AbstractVector{T},
     x::AbstractVector{T},
-)::Nothing where {T}

Given a set of vector-valued constraints $l \le g(x) \le u$, evaluate the constraint function $g(x)$, storing the result in the vector g.

Implementation notes

When implementing this method, you must not assume that g is Vector{Float64}, but you may assume that it supports setindex! and length. For example, it may be the view of a vector.

source
MathOptInterface.eval_objective_gradientFunction
eval_objective_gradient(
+)::Nothing where {T}

Given a set of vector-valued constraints $l \le g(x) \le u$, evaluate the constraint function $g(x)$, storing the result in the vector g.

Implementation notes

When implementing this method, you must not assume that g is Vector{Float64}, but you may assume that it supports setindex! and length. For example, it may be the view of a vector.

source
MathOptInterface.eval_objective_gradientFunction
eval_objective_gradient(
     d::AbstractNLPEvaluator,
     grad::AbstractVector{T},
     x::AbstractVector{T},
-)::Nothing where {T}

Evaluate the gradient of the objective function $grad = \nabla f(x)$ as a dense vector, storing the result in the vector grad.

Implementation notes

When implementing this method, you must not assume that grad is Vector{Float64}, but you may assume that it supports setindex! and length. For example, it may be the view of a vector.

source
MathOptInterface.jacobian_structureFunction
jacobian_structure(d::AbstractNLPEvaluator)::Vector{Tuple{Int64,Int64}}

Returns a vector of tuples, (row, column), where each indicates the position of a structurally nonzero element in the Jacobian matrix: $J_g(x) = \left[ \begin{array}{c} \nabla g_1(x) \\ \nabla g_2(x) \\ \vdots \\ \nabla g_m(x) \end{array}\right],$ where $g_i$ is the $i\text{th}$ component of the nonlinear constraints $g(x)$.

The indices are not required to be sorted and can contain duplicates, in which case the solver should combine the corresponding elements by adding them together.

The sparsity structure is assumed to be independent of the point $x$.

source
MathOptInterface.eval_constraint_gradientFunction
eval_constraint_gradient(
+)::Nothing where {T}

Evaluate the gradient of the objective function $grad = \nabla f(x)$ as a dense vector, storing the result in the vector grad.

Implementation notes

When implementing this method, you must not assume that grad is Vector{Float64}, but you may assume that it supports setindex! and length. For example, it may be the view of a vector.

source
MathOptInterface.jacobian_structureFunction
jacobian_structure(d::AbstractNLPEvaluator)::Vector{Tuple{Int64,Int64}}

Returns a vector of tuples, (row, column), where each indicates the position of a structurally nonzero element in the Jacobian matrix: $J_g(x) = \left[ \begin{array}{c} \nabla g_1(x) \\ \nabla g_2(x) \\ \vdots \\ \nabla g_m(x) \end{array}\right],$ where $g_i$ is the $i\text{th}$ component of the nonlinear constraints $g(x)$.

The indices are not required to be sorted and can contain duplicates, in which case the solver should combine the corresponding elements by adding them together.

The sparsity structure is assumed to be independent of the point $x$.

source
MathOptInterface.eval_constraint_gradientFunction
eval_constraint_gradient(
     d::AbstractNLPEvaluator,
     ∇g::AbstractVector{T},
     x::AbstractVector{T},
     i::Int,
-)::Nothing where {T}

Evaluate the gradient of constraint i, $\nabla g_i(x)$, and store the non-zero values in ∇g, corresponding to the structure returned by constraint_gradient_structure.

Implementation notes

When implementing this method, you must not assume that ∇g is Vector{Float64}, but you may assume that it supports setindex! and length. For example, it may be the view of a vector.

source
MathOptInterface.constraint_gradient_structureFunction
constraint_gradient_structure(d::AbstractNLPEvaluator, i::Int)::Vector{Int64}

Returns a vector of indices, where each element indicates the position of a structurally nonzero element in the gradient of constraint $\nabla g_i(x)$.

The indices are not required to be sorted and can contain duplicates, in which case the solver should combine the corresponding elements by adding them together.

The sparsity structure is assumed to be independent of the point $x$.

source
MathOptInterface.eval_constraint_jacobianFunction
eval_constraint_jacobian(d::AbstractNLPEvaluator,
+)::Nothing where {T}

Evaluate the gradient of constraint i, $\nabla g_i(x)$, and store the non-zero values in ∇g, corresponding to the structure returned by constraint_gradient_structure.

Implementation notes

When implementing this method, you must not assume that ∇g is Vector{Float64}, but you may assume that it supports setindex! and length. For example, it may be the view of a vector.

source
MathOptInterface.constraint_gradient_structureFunction
constraint_gradient_structure(d::AbstractNLPEvaluator, i::Int)::Vector{Int64}

Returns a vector of indices, where each element indicates the position of a structurally nonzero element in the gradient of constraint $\nabla g_i(x)$.

The indices are not required to be sorted and can contain duplicates, in which case the solver should combine the corresponding elements by adding them together.

The sparsity structure is assumed to be independent of the point $x$.

source
MathOptInterface.eval_constraint_jacobianFunction
eval_constraint_jacobian(d::AbstractNLPEvaluator,
     J::AbstractVector{T},
     x::AbstractVector{T},
-)::Nothing where {T}

Evaluates the sparse Jacobian matrix $J_g(x) = \left[ \begin{array}{c} \nabla g_1(x) \\ \nabla g_2(x) \\ \vdots \\ \nabla g_m(x) \end{array}\right]$.

The result is stored in the vector J in the same order as the indices returned by jacobian_structure.

Implementation notes

When implementing this method, you must not assume that J is Vector{Float64}, but you may assume that it supports setindex! and length. For example, it may be the view of a vector.

source
MathOptInterface.eval_constraint_jacobian_productFunction
eval_constraint_jacobian_product(
+)::Nothing where {T}

Evaluates the sparse Jacobian matrix $J_g(x) = \left[ \begin{array}{c} \nabla g_1(x) \\ \nabla g_2(x) \\ \vdots \\ \nabla g_m(x) \end{array}\right]$.

The result is stored in the vector J in the same order as the indices returned by jacobian_structure.

Implementation notes

When implementing this method, you must not assume that J is Vector{Float64}, but you may assume that it supports setindex! and length. For example, it may be the view of a vector.

source
MathOptInterface.eval_constraint_jacobian_productFunction
eval_constraint_jacobian_product(
     d::AbstractNLPEvaluator,
     y::AbstractVector{T},
     x::AbstractVector{T},
     w::AbstractVector{T},
-)::Nothing where {T}

Computes the Jacobian-vector product $y = J_g(x)w$, storing the result in the vector y.

The vectors have dimensions such that length(w) == length(x), and length(y) is the number of nonlinear constraints.

Implementation notes

When implementing this method, you must not assume that y is Vector{Float64}, but you may assume that it supports setindex! and length. For example, it may be the view of a vector.

source
MathOptInterface.eval_constraint_jacobian_transpose_productFunction
eval_constraint_jacobian_transpose_product(
+)::Nothing where {T}

Computes the Jacobian-vector product $y = J_g(x)w$, storing the result in the vector y.

The vectors have dimensions such that length(w) == length(x), and length(y) is the number of nonlinear constraints.

Implementation notes

When implementing this method, you must not assume that y is Vector{Float64}, but you may assume that it supports setindex! and length. For example, it may be the view of a vector.

source
MathOptInterface.eval_constraint_jacobian_transpose_productFunction
eval_constraint_jacobian_transpose_product(
     d::AbstractNLPEvaluator,
     y::AbstractVector{T},
     x::AbstractVector{T},
     w::AbstractVector{T},
-)::Nothing where {T}

Computes the Jacobian-transpose-vector product $y = J_g(x)^Tw$, storing the result in the vector y.

The vectors have dimensions such that length(y) == length(x), and length(w) is the number of nonlinear constraints.

Implementation notes

When implementing this method, you must not assume that y is Vector{Float64}, but you may assume that it supports setindex! and length. For example, it may be the view of a vector.

source
MathOptInterface.hessian_lagrangian_structureFunction
hessian_lagrangian_structure(
+)::Nothing where {T}

Computes the Jacobian-transpose-vector product $y = J_g(x)^Tw$, storing the result in the vector y.

The vectors have dimensions such that length(y) == length(x), and length(w) is the number of nonlinear constraints.

Implementation notes

When implementing this method, you must not assume that y is Vector{Float64}, but you may assume that it supports setindex! and length. For example, it may be the view of a vector.

source
MathOptInterface.hessian_lagrangian_structureFunction
hessian_lagrangian_structure(
     d::AbstractNLPEvaluator,
-)::Vector{Tuple{Int64,Int64}}

Returns a vector of tuples, (row, column), where each indicates the position of a structurally nonzero element in the Hessian-of-the-Lagrangian matrix: $\nabla^2 f(x) + \sum_{i=1}^m \nabla^2 g_i(x)$.

The indices are not required to be sorted and can contain duplicates, in which case the solver should combine the corresponding elements by adding them together.

Any mix of lower and upper-triangular indices is valid. Elements (i,j) and (j,i), if both present, should be treated as duplicates.

The sparsity structure is assumed to be independent of the point $x$.

source
MathOptInterface.hessian_objective_structureFunction
hessian_objective_structure(
+)::Vector{Tuple{Int64,Int64}}

Returns a vector of tuples, (row, column), where each indicates the position of a structurally nonzero element in the Hessian-of-the-Lagrangian matrix: $\nabla^2 f(x) + \sum_{i=1}^m \nabla^2 g_i(x)$.

The indices are not required to be sorted and can contain duplicates, in which case the solver should combine the corresponding elements by adding them together.

Any mix of lower and upper-triangular indices is valid. Elements (i,j) and (j,i), if both present, should be treated as duplicates.

The sparsity structure is assumed to be independent of the point $x$.

source
MathOptInterface.hessian_objective_structureFunction
hessian_objective_structure(
     d::AbstractNLPEvaluator,
-)::Vector{Tuple{Int64,Int64}}

Returns a vector of tuples, (row, column), where each indicates the position of a structurally nonzero element in the Hessian matrix: $\nabla^2 f(x)$.

The indices are not required to be sorted and can contain duplicates, in which case the solver should combine the corresponding elements by adding them together.

Any mix of lower and upper-triangular indices is valid. Elements (i,j) and (j,i), if both present, should be treated as duplicates.

The sparsity structure is assumed to be independent of the point $x$.

source
MathOptInterface.hessian_constraint_structureFunction
hessian_constraint_structure(
+)::Vector{Tuple{Int64,Int64}}

Returns a vector of tuples, (row, column), where each indicates the position of a structurally nonzero element in the Hessian matrix: $\nabla^2 f(x)$.

The indices are not required to be sorted and can contain duplicates, in which case the solver should combine the corresponding elements by adding them together.

Any mix of lower and upper-triangular indices is valid. Elements (i,j) and (j,i), if both present, should be treated as duplicates.

The sparsity structure is assumed to be independent of the point $x$.

source
MathOptInterface.hessian_constraint_structureFunction
hessian_constraint_structure(
     d::AbstractNLPEvaluator,
     i::Int64,
-)::Vector{Tuple{Int64,Int64}}

Returns a vector of tuples, (row, column), where each indicates the position of a structurally nonzero element in the Hessian matrix: $\nabla^2 g_i(x)$.

The indices are not required to be sorted and can contain duplicates, in which case the solver should combine the corresponding elements by adding them together.

Any mix of lower and upper-triangular indices is valid. Elements (i,j) and (j,i), if both present, should be treated as duplicates.

The sparsity structure is assumed to be independent of the point $x$.

source
MathOptInterface.eval_hessian_objectiveFunction
eval_hessian_objective(
+)::Vector{Tuple{Int64,Int64}}

Returns a vector of tuples, (row, column), where each indicates the position of a structurally nonzero element in the Hessian matrix: $\nabla^2 g_i(x)$.

The indices are not required to be sorted and can contain duplicates, in which case the solver should combine the corresponding elements by adding them together.

Any mix of lower and upper-triangular indices is valid. Elements (i,j) and (j,i), if both present, should be treated as duplicates.

The sparsity structure is assumed to be independent of the point $x$.

source
MathOptInterface.eval_hessian_objectiveFunction
eval_hessian_objective(
     d::AbstractNLPEvaluator,
     H::AbstractVector{T},
     x::AbstractVector{T},
-)::Nothing where {T}

This function computes the sparse Hessian matrix: $\nabla^2 f(x)$, storing the result in the vector H in the same order as the indices returned by hessian_objective_structure.

Implementation notes

When implementing this method, you must not assume that H is Vector{Float64}, but you may assume that it supports setindex! and length. For example, it may be the view of a vector.

source
MathOptInterface.eval_hessian_constraintFunction
eval_hessian_constraint(
+)::Nothing where {T}

This function computes the sparse Hessian matrix: $\nabla^2 f(x)$, storing the result in the vector H in the same order as the indices returned by hessian_objective_structure.

Implementation notes

When implementing this method, you must not assume that H is Vector{Float64}, but you may assume that it supports setindex! and length. For example, it may be the view of a vector.

source
MathOptInterface.eval_hessian_constraintFunction
eval_hessian_constraint(
     d::AbstractNLPEvaluator,
     H::AbstractVector{T},
     x::AbstractVector{T},
     i::Int64,
-)::Nothing where {T}

This function computes the sparse Hessian matrix: $\nabla^2 g_i(x)$, storing the result in the vector H in the same order as the indices returned by hessian_constraint_structure.

Implementation notes

When implementing this method, you must not assume that H is Vector{Float64}, but you may assume that it supports setindex! and length. For example, it may be the view of a vector.

source
MathOptInterface.eval_hessian_lagrangianFunction
eval_hessian_lagrangian(
+)::Nothing where {T}

This function computes the sparse Hessian matrix: $\nabla^2 g_i(x)$, storing the result in the vector H in the same order as the indices returned by hessian_constraint_structure.

Implementation notes

When implementing this method, you must not assume that H is Vector{Float64}, but you may assume that it supports setindex! and length. For example, it may be the view of a vector.

source
MathOptInterface.eval_hessian_lagrangianFunction
eval_hessian_lagrangian(
     d::AbstractNLPEvaluator,
     H::AbstractVector{T},
     x::AbstractVector{T},
     σ::T,
     μ::AbstractVector{T},
-)::Nothing where {T}

Given scalar weight σ and vector of constraint weights μ, this function computes the sparse Hessian-of-the-Lagrangian matrix: $\sigma\nabla^2 f(x) + \sum_{i=1}^m \mu_i \nabla^2 g_i(x)$, storing the result in the vector H in the same order as the indices returned by hessian_lagrangian_structure.

Implementation notes

When implementing this method, you must not assume that H is Vector{Float64}, but you may assume that it supports setindex! and length. For example, it may be the view of a vector.

source
MathOptInterface.eval_hessian_lagrangian_productFunction
eval_hessian_lagrangian_product(
+)::Nothing where {T}

Given scalar weight σ and vector of constraint weights μ, this function computes the sparse Hessian-of-the-Lagrangian matrix: $\sigma\nabla^2 f(x) + \sum_{i=1}^m \mu_i \nabla^2 g_i(x)$, storing the result in the vector H in the same order as the indices returned by hessian_lagrangian_structure.

Implementation notes

When implementing this method, you must not assume that H is Vector{Float64}, but you may assume that it supports setindex! and length. For example, it may be the view of a vector.

source
MathOptInterface.eval_hessian_lagrangian_productFunction
eval_hessian_lagrangian_product(
     d::AbstractNLPEvaluator,
     h::AbstractVector{T},
     x::AbstractVector{T},
     v::AbstractVector{T},
     σ::T,
     μ::AbstractVector{T},
-)::Nothing where {T}

Given scalar weight σ and vector of constraint weights μ, computes the Hessian-of-the-Lagrangian-vector product $h = \left(\sigma\nabla^2 f(x) + \sum_{i=1}^m \mu_i \nabla^2 g_i(x)\right)v$, storing the result in the vector h.

The vectors have dimensions such that length(h) == length(x) == length(v).

Implementation notes

When implementing this method, you must not assume that h is Vector{Float64}, but you may assume that it supports setindex! and length. For example, it may be the view of a vector.

source
MathOptInterface.objective_exprFunction
objective_expr(d::AbstractNLPEvaluator)::Expr

Returns a Julia Expr object representing the expression graph of the objective function.

Format

The expression has a number of limitations, compared with arbitrary Julia expressions:

  • All sums and products are flattened out as simple Expr(:+, ...) and Expr(:*, ...) objects.
  • All decision variables must be of the form Expr(:ref, :x, MOI.VariableIndex(i)), where i is the $i$th variable in ListOfVariableIndices.
  • There are currently no restrictions on recognized functions; typically these will be built-in Julia functions like ^, exp, log, cos, tan, sqrt, etc., but modeling interfaces may choose to extend these basic functions, or error if they encounter unsupported functions.

Examples

The expression $x_1+\sin(x_2/\exp(x_3))$ is represented as

:(x[MOI.VariableIndex(1)] + sin(x[MOI.VariableIndex(2)] / exp(x[MOI.VariableIndex[3]])))

or equivalently

Expr(
+)::Nothing where {T}

Given scalar weight σ and vector of constraint weights μ, computes the Hessian-of-the-Lagrangian-vector product $h = \left(\sigma\nabla^2 f(x) + \sum_{i=1}^m \mu_i \nabla^2 g_i(x)\right)v$, storing the result in the vector h.

The vectors have dimensions such that length(h) == length(x) == length(v).

Implementation notes

When implementing this method, you must not assume that h is Vector{Float64}, but you may assume that it supports setindex! and length. For example, it may be the view of a vector.

source
MathOptInterface.objective_exprFunction
objective_expr(d::AbstractNLPEvaluator)::Expr

Returns a Julia Expr object representing the expression graph of the objective function.

Format

The expression has a number of limitations, compared with arbitrary Julia expressions:

  • All sums and products are flattened out as simple Expr(:+, ...) and Expr(:*, ...) objects.
  • All decision variables must be of the form Expr(:ref, :x, MOI.VariableIndex(i)), where i is the $i$th variable in ListOfVariableIndices.
  • There are currently no restrictions on recognized functions; typically these will be built-in Julia functions like ^, exp, log, cos, tan, sqrt, etc., but modeling interfaces may choose to extend these basic functions, or error if they encounter unsupported functions.

Examples

The expression $x_1+\sin(x_2/\exp(x_3))$ is represented as

:(x[MOI.VariableIndex(1)] + sin(x[MOI.VariableIndex(2)] / exp(x[MOI.VariableIndex[3]])))

or equivalently

Expr(
     :call,
     :+,
     Expr(:ref, :x, MOI.VariableIndex(1)),
@@ -72,7 +72,7 @@
         Expr(:call, :sin, Expr(:ref, :x, MOI.VariableIndex(2))),
         Expr(:call, :exp, Expr(:ref, :x, MOI.VariableIndex(3))),
     ),
-)
source
MathOptInterface.constraint_exprFunction
constraint_expr(d::AbstractNLPEvaluator, i::Integer)::Expr

Returns a Julia Expr object representing the expression graph for the $i\text{th}$ nonlinear constraint.

Format

The format is the same as objective_expr, with an additional comparison operator indicating the sense of and bounds on the constraint.

For single-sided comparisons, the body of the constraint must be on the left-hand side, and the right-hand side must be a constant.

For double-sided comparisons (that is, $l \le f(x) \le u$), the body of the constraint must be in the middle, and the left- and right-hand sides must be constants.

The bounds on the constraints must match the NLPBoundsPairs passed to NLPBlockData.

Examples

:(x[MOI.VariableIndex(1)]^2 <= 1.0)
+)
source
MathOptInterface.constraint_exprFunction
constraint_expr(d::AbstractNLPEvaluator, i::Integer)::Expr

Returns a Julia Expr object representing the expression graph for the $i\text{th}$ nonlinear constraint.

Format

The format is the same as objective_expr, with an additional comparison operator indicating the sense of and bounds on the constraint.

For single-sided comparisons, the body of the constraint must be on the left-hand side, and the right-hand side must be a constant.

For double-sided comparisons (that is, $l \le f(x) \le u$), the body of the constraint must be in the middle, and the left- and right-hand sides must be constants.

The bounds on the constraints must match the NLPBoundsPairs passed to NLPBlockData.

Examples

:(x[MOI.VariableIndex(1)]^2 <= 1.0)
 :(x[MOI.VariableIndex(1)]^2 >= 2.0)
 :(x[MOI.VariableIndex(1)]^2 == 3.0)
-:(4.0 <= x[MOI.VariableIndex(1)]^2 <= 5.0)
source
+:(4.0 <= x[MOI.VariableIndex(1)]^2 <= 5.0)
source
diff --git a/dev/reference/standard_form/index.html b/dev/reference/standard_form/index.html index d5eb0f576e..a606d05e39 100644 --- a/dev/reference/standard_form/index.html +++ b/dev/reference/standard_form/index.html @@ -1,5 +1,5 @@ -Standard form · MathOptInterface

Standard form

Functions

MathOptInterface.AbstractFunctionType
AbstractFunction

Abstract supertype for function objects.

Required methods

All functions must implement:

Abstract subtypes of AbstractFunction may require additional methods to be implemented.

source
MathOptInterface.constantFunction
constant(f::AbstractFunction[, ::Type{T}]) where {T}

Returns the constant term of a scalar-valued function, or the constant vector of a vector-valued function.

If f is untyped and T is provided, returns zero(T).

source
constant(set::Union{EqualTo,GreaterThan,LessThan,Parameter})

Returns the constant term of the set set.

Example

julia> import MathOptInterface as MOI
+Standard form · MathOptInterface

Standard form

Functions

MathOptInterface.AbstractFunctionType
AbstractFunction

Abstract supertype for function objects.

Required methods

All functions must implement:

Abstract subtypes of AbstractFunction may require additional methods to be implemented.

source
MathOptInterface.constantFunction
constant(f::AbstractFunction[, ::Type{T}]) where {T}

Returns the constant term of a scalar-valued function, or the constant vector of a vector-valued function.

If f is untyped and T is provided, returns zero(T).

source
constant(set::Union{EqualTo,GreaterThan,LessThan,Parameter})

Returns the constant term of the set set.

Example

julia> import MathOptInterface as MOI
 
 julia> MOI.constant(MOI.GreaterThan(1.0))
 1.0
@@ -11,13 +11,13 @@
 3
 
 julia> MOI.constant(MOI.Parameter(4.5))
-4.5
source

Scalar functions

MathOptInterface.VariableIndexType
VariableIndex

A type-safe wrapper for Int64 for use in referencing variables in a model. To allow for deletion, indices need not be consecutive.

source
MathOptInterface.ScalarAffineTermType
ScalarAffineTerm{T}(coefficient::T, variable::VariableIndex) where {T}

Represents the scalar-valued term coefficient * variable.

Example

julia> import MathOptInterface as MOI
+4.5
source

Scalar functions

MathOptInterface.VariableIndexType
VariableIndex

A type-safe wrapper for Int64 for use in referencing variables in a model. To allow for deletion, indices need not be consecutive.

source
MathOptInterface.ScalarAffineTermType
ScalarAffineTerm{T}(coefficient::T, variable::VariableIndex) where {T}

Represents the scalar-valued term coefficient * variable.

Example

julia> import MathOptInterface as MOI
 
 julia> x = MOI.VariableIndex(1)
 MOI.VariableIndex(1)
 
 julia> MOI.ScalarAffineTerm(2.0, x)
-MathOptInterface.ScalarAffineTerm{Float64}(2.0, MOI.VariableIndex(1))
source
MathOptInterface.ScalarAffineFunctionType
ScalarAffineFunction{T}(terms::ScalarAffineTerm{T}, constant::T) where {T}

Represents the scalar-valued affine function $a^\top x + b$, where:

  • $a^\top x$ is represented by the vector of ScalarAffineTerms
  • $b$ is a scalar constant::T

Duplicates

Duplicate variable indices in terms are accepted, and the corresponding coefficients are summed together.

Example

julia> import MathOptInterface as MOI
+MathOptInterface.ScalarAffineTerm{Float64}(2.0, MOI.VariableIndex(1))
source
MathOptInterface.ScalarAffineFunctionType
ScalarAffineFunction{T}(terms::ScalarAffineTerm{T}, constant::T) where {T}

Represents the scalar-valued affine function $a^\top x + b$, where:

  • $a^\top x$ is represented by the vector of ScalarAffineTerms
  • $b$ is a scalar constant::T

Duplicates

Duplicate variable indices in terms are accepted, and the corresponding coefficients are summed together.

Example

julia> import MathOptInterface as MOI
 
 julia> x = MOI.VariableIndex(1)
 MOI.VariableIndex(1)
@@ -28,7 +28,7 @@
  MathOptInterface.ScalarAffineTerm{Float64}(3.0, MOI.VariableIndex(1))
 
 julia> f = MOI.ScalarAffineFunction(terms, 4.0)
-4.0 + 2.0 MOI.VariableIndex(1) + 3.0 MOI.VariableIndex(1)
source
MathOptInterface.ScalarQuadraticTermType
ScalarQuadraticTerm{T}(
     coefficient::T,
     variable_1::VariableIndex,
     variable_2::VariableIndex,
@@ -38,7 +38,7 @@
 MOI.VariableIndex(1)
 
 julia> MOI.ScalarQuadraticTerm(2.0, x, x)
-MathOptInterface.ScalarQuadraticTerm{Float64}(2.0, MOI.VariableIndex(1), MOI.VariableIndex(1))
source
MathOptInterface.ScalarQuadraticFunctionType
ScalarQuadraticFunction{T}(
     quadratic_terms::Vector{ScalarQuadraticTerm{T}},
     affine_terms::Vector{ScalarAffineTerm{T}},
     constant::T,
@@ -61,7 +61,7 @@
  MathOptInterface.ScalarQuadraticTerm{Float64}(3.0, MOI.VariableIndex(1), MOI.VariableIndex(2))
 
 julia> f = MOI.ScalarQuadraticFunction(quadratic_terms, affine_terms, constant)
-5.0 + 4.0 MOI.VariableIndex(1) + 2.0 MOI.VariableIndex(1)² + 3.0 MOI.VariableIndex(1)*MOI.VariableIndex(2)
source
MathOptInterface.ScalarNonlinearFunctionType
ScalarNonlinearFunction(head::Symbol, args::Vector{Any})

The scalar-valued nonlinear function head(args...), represented as a symbolic expression tree, with the call operator head and ordered arguments in args.

head

The head::Symbol must be an operator supported by the model.

The default list of supported univariate operators is given by:

and the default list of supported multivariate operators is given by:

Additional operators can be registered by setting a UserDefinedFunction attribute.

See the full list of operators supported by a ModelLike by querying ListOfSupportedNonlinearOperators.

args

The vector args contains the arguments to the nonlinear function. If the operator is univariate, it must contain one element. Otherwise, it may contain multiple elements.

Each element must be one of the following:

Unsupported operators

If the optimizer does not support head, an UnsupportedNonlinearOperator error will be thrown.

There is no guarantee about when this error will be thrown; it may be thrown when the function is first added to the model, or it may be thrown when optimize! is called.

Example

To represent the function $f(x) = sin(x)^2$, do:

julia> import MathOptInterface as MOI
+5.0 + 4.0 MOI.VariableIndex(1) + 2.0 MOI.VariableIndex(1)² + 3.0 MOI.VariableIndex(1)*MOI.VariableIndex(2)
source
MathOptInterface.ScalarNonlinearFunctionType
ScalarNonlinearFunction(head::Symbol, args::Vector{Any})

The scalar-valued nonlinear function head(args...), represented as a symbolic expression tree, with the call operator head and ordered arguments in args.

head

The head::Symbol must be an operator supported by the model.

The default list of supported univariate operators is given by:

and the default list of supported multivariate operators is given by:

Additional operators can be registered by setting a UserDefinedFunction attribute.

See the full list of operators supported by a ModelLike by querying ListOfSupportedNonlinearOperators.

args

The vector args contains the arguments to the nonlinear function. If the operator is univariate, it must contain one element. Otherwise, it may contain multiple elements.

Each element must be one of the following:

Unsupported operators

If the optimizer does not support head, an UnsupportedNonlinearOperator error will be thrown.

There is no guarantee about when this error will be thrown; it may be thrown when the function is first added to the model, or it may be thrown when optimize! is called.

Example

To represent the function $f(x) = sin(x)^2$, do:

julia> import MathOptInterface as MOI
 
 julia> x = MOI.VariableIndex(1)
 MOI.VariableIndex(1)
@@ -70,7 +70,7 @@
            :^,
            Any[MOI.ScalarNonlinearFunction(:sin, Any[x]), 2],
        )
-^(sin(MOI.VariableIndex(1)), (2))
source

Vector functions

MathOptInterface.VectorOfVariablesType
VectorOfVariables(variables::Vector{VariableIndex}) <: AbstractVectorFunction

The vector-valued function f(x) = variables, where variables is a subset of VariableIndexes in the model.

The list of variables may contain duplicates.

Example

julia> import MathOptInterface as MOI
+^(sin(MOI.VariableIndex(1)), (2))
source

Vector functions

MathOptInterface.VectorOfVariablesType
VectorOfVariables(variables::Vector{VariableIndex}) <: AbstractVectorFunction

The vector-valued function f(x) = variables, where variables is a subset of VariableIndexes in the model.

The list of variables may contain duplicates.

Example

julia> import MathOptInterface as MOI
 
 julia> x = MOI.VariableIndex.(1:2)
 2-element Vector{MathOptInterface.VariableIndex}:
@@ -85,7 +85,7 @@
 └                    ┘
 
 julia> MOI.output_dimension(f)
-3
source
MathOptInterface.VectorAffineTermType
VectorAffineTerm{T}(
     output_index::Int64,
     scalar_term::ScalarAffineTerm{T},
 ) where {T}

A VectorAffineTerm is a scalar_term that appears in the output_index row of the vector-valued VectorAffineFunction or VectorQuadraticFunction.

Example

julia> import MathOptInterface as MOI
@@ -93,7 +93,7 @@
 julia> x = MOI.VariableIndex(1);
 
 julia> MOI.VectorAffineTerm(Int64(2), MOI.ScalarAffineTerm(3.0, x))
-MathOptInterface.VectorAffineTerm{Float64}(2, MathOptInterface.ScalarAffineTerm{Float64}(3.0, MOI.VariableIndex(1)))
source
MathOptInterface.VectorAffineFunctionType
VectorAffineFunction{T}(
     terms::Vector{VectorAffineTerm{T}},
     constants::Vector{T},
 ) where {T}

The vector-valued affine function $A x + b$, where:

  • $A x$ is the sparse matrix given by the vector of VectorAffineTerms
  • $b$ is the vector constants

Duplicates

Duplicate indices in the $A$ are accepted, and the corresponding coefficients are summed together.

Example

julia> import MathOptInterface as MOI
@@ -112,7 +112,7 @@
 └                              ┘
 
 julia> MOI.output_dimension(f)
-2
source
MathOptInterface.VectorQuadraticTermType
VectorQuadraticTerm{T}(
     output_index::Int64,
     scalar_term::ScalarQuadraticTerm{T},
 ) where {T}

A VectorQuadraticTerm is a ScalarQuadraticTerm scalar_term that appears in the output_index row of the vector-valued VectorQuadraticFunction.

Example

julia> import MathOptInterface as MOI
@@ -120,7 +120,7 @@
 julia> x = MOI.VariableIndex(1);
 
 julia> MOI.VectorQuadraticTerm(Int64(2), MOI.ScalarQuadraticTerm(3.0, x, x))
-MathOptInterface.VectorQuadraticTerm{Float64}(2, MathOptInterface.ScalarQuadraticTerm{Float64}(3.0, MOI.VariableIndex(1), MOI.VariableIndex(1)))
source
MathOptInterface.VectorQuadraticFunctionType
VectorQuadraticFunction{T}(
     quadratic_terms::Vector{VectorQuadraticTerm{T}},
     affine_terms::Vector{VectorAffineTerm{T}},
     constants::Vector{T},
@@ -149,7 +149,7 @@
 └                                                                              ┘
 
 julia> MOI.output_dimension(f)
-2
source
MathOptInterface.VectorNonlinearFunctionType
VectorNonlinearFunction(args::Vector{ScalarNonlinearFunction})

The vector-valued nonlinear function composed of a vector of ScalarNonlinearFunction.

args

The vector args contains the scalar elements of the nonlinear function. Each element must be a ScalarNonlinearFunction, but if you pass a Vector{Any}, the elements can be automatically converted from one of the following:

Example

To represent the function $f(x) = [sin(x)^2, x]$, do:

julia> import MathOptInterface as MOI
+2
source
MathOptInterface.VectorNonlinearFunctionType
VectorNonlinearFunction(args::Vector{ScalarNonlinearFunction})

The vector-valued nonlinear function composed of a vector of ScalarNonlinearFunction.

args

The vector args contains the scalar elements of the nonlinear function. Each element must be a ScalarNonlinearFunction, but if you pass a Vector{Any}, the elements can be automatically converted from one of the following:

Example

To represent the function $f(x) = [sin(x)^2, x]$, do:

julia> import MathOptInterface as MOI
 
 julia> x = MOI.VariableIndex(1)
 MOI.VariableIndex(1)
@@ -164,7 +164,7 @@
 ┌                                 ┐
 │^(sin(MOI.VariableIndex(1)), 2.0)│
 │+(MOI.VariableIndex(1))          │
-└                                 ┘

Note the automatic conversion from x to +(x).

source

Sets

MathOptInterface.AbstractSetType
AbstractSet

Abstract supertype for set objects used to encode constraints.

Required methods

For sets of type S with isbitstype(S) == false, you must implement:

  • Base.copy(set::S)
  • Base.:(==)(x::S, y::S)

Subtypes of AbstractSet such as AbstractScalarSet and AbstractVectorSet may prescribe additional required methods.

Optional methods

You may optionally implement:

Note for developers

When creating a new set, the set struct must not contain any VariableIndex or ConstraintIndex objects.

source
MathOptInterface.AbstractVectorSetType
AbstractVectorSet

Abstract supertype for subsets of $\mathbb{R}^n$ for some $n$.

Required methods

All AbstractVectorSets of type S must implement:

  • dimension, unless the dimension is stored in the set.dimension field
  • Utilities.set_dot, unless the dot product between two vectors in the set is equivalent to LinearAlgebra.dot.
source

Utilities

Sets

MathOptInterface.AbstractSetType
AbstractSet

Abstract supertype for set objects used to encode constraints.

Required methods

For sets of type S with isbitstype(S) == false, you must implement:

  • Base.copy(set::S)
  • Base.:(==)(x::S, y::S)

Subtypes of AbstractSet such as AbstractScalarSet and AbstractVectorSet may prescribe additional required methods.

Optional methods

You may optionally implement:

Note for developers

When creating a new set, the set struct must not contain any VariableIndex or ConstraintIndex objects.

source
MathOptInterface.AbstractVectorSetType
AbstractVectorSet

Abstract supertype for subsets of $\mathbb{R}^n$ for some $n$.

Required methods

All AbstractVectorSets of type S must implement:

  • dimension, unless the dimension is stored in the set.dimension field
  • Utilities.set_dot, unless the dot product between two vectors in the set is equivalent to LinearAlgebra.dot.
source

Utilities

MathOptInterface.dimensionFunction
dimension(set::AbstractSet)

Return the output_dimension that an AbstractFunction should have to be used with the set set.

Example

julia> import MathOptInterface as MOI
 
 julia> MOI.dimension(MOI.Reals(4))
 4
@@ -173,7 +173,7 @@
 1
 
 julia> MOI.dimension(MOI.PositiveSemidefiniteConeTriangle(2))
-3
source
MathOptInterface.dual_setFunction
dual_set(set::AbstractSet)

Return the dual set of set, that is the dual cone of the set. This follows the definition of duality discussed in Duality.

See Dual cone for more information.

If the dual cone is not defined it returns an error.

Example

julia> import MathOptInterface as MOI
+3
source
MathOptInterface.dual_setFunction
dual_set(set::AbstractSet)

Return the dual set of set, that is the dual cone of the set. This follows the definition of duality discussed in Duality.

See Dual cone for more information.

If the dual cone is not defined it returns an error.

Example

julia> import MathOptInterface as MOI
 
 julia> MOI.dual_set(MOI.Reals(4))
 MathOptInterface.Zeros(4)
@@ -182,7 +182,7 @@
 MathOptInterface.SecondOrderCone(5)
 
 julia> MOI.dual_set(MOI.ExponentialCone())
-MathOptInterface.DualExponentialCone()
source
MathOptInterface.dual_set_typeFunction
dual_set_type(S::Type{<:AbstractSet})

Return the type of dual set of sets of type S, as returned by dual_set. If the dual cone is not defined it returns an error.

Example

julia> import MathOptInterface as MOI
+MathOptInterface.DualExponentialCone()
source
MathOptInterface.dual_set_typeFunction
dual_set_type(S::Type{<:AbstractSet})

Return the type of dual set of sets of type S, as returned by dual_set. If the dual cone is not defined it returns an error.

Example

julia> import MathOptInterface as MOI
 
 julia> MOI.dual_set_type(MOI.Reals)
 MathOptInterface.Zeros
@@ -191,7 +191,7 @@
 MathOptInterface.SecondOrderCone
 
 julia> MOI.dual_set_type(MOI.ExponentialCone)
-MathOptInterface.DualExponentialCone
source
MathOptInterface.constantMethod
constant(set::Union{EqualTo,GreaterThan,LessThan,Parameter})

Returns the constant term of the set set.

Example

julia> import MathOptInterface as MOI
+MathOptInterface.DualExponentialCone
source
MathOptInterface.constantMethod
constant(set::Union{EqualTo,GreaterThan,LessThan,Parameter})

Returns the constant term of the set set.

Example

julia> import MathOptInterface as MOI
 
 julia> MOI.constant(MOI.GreaterThan(1.0))
 1.0
@@ -203,7 +203,7 @@
 3
 
 julia> MOI.constant(MOI.Parameter(4.5))
-4.5
source
MathOptInterface.supports_dimension_updateFunction
supports_dimension_update(S::Type{<:MOI.AbstractVectorSet})

Return a Bool indicating whether the elimination of any dimension of n-dimensional sets of type S give an n-1-dimensional set S. By default, this function returns false so it should only be implemented for sets that supports dimension update.

For instance, supports_dimension_update(MOI.Nonnegatives) is true because the elimination of any dimension of the n-dimensional nonnegative orthant gives the n-1-dimensional nonnegative orthant. However supports_dimension_update(MOI.ExponentialCone) is false.

source

Scalar sets

List of recognized scalar sets.

MathOptInterface.supports_dimension_updateFunction
supports_dimension_update(S::Type{<:MOI.AbstractVectorSet})

Return a Bool indicating whether the elimination of any dimension of n-dimensional sets of type S give an n-1-dimensional set S. By default, this function returns false so it should only be implemented for sets that supports dimension update.

For instance, supports_dimension_update(MOI.Nonnegatives) is true because the elimination of any dimension of the n-dimensional nonnegative orthant gives the n-1-dimensional nonnegative orthant. However supports_dimension_update(MOI.ExponentialCone) is false.

source

Scalar sets

List of recognized scalar sets.

MathOptInterface.GreaterThanType
GreaterThan{T<:Real}(lower::T)

The set $[lower, \infty) \subseteq \mathbb{R}$.

Example

julia> import MathOptInterface as MOI
 
 julia> model = MOI.Utilities.Model{Float64}()
 MOIU.Model{Float64}
@@ -212,7 +212,7 @@
 MOI.VariableIndex(1)
 
 julia> MOI.add_constraint(model, x, MOI.GreaterThan(0.0))
-MathOptInterface.ConstraintIndex{MathOptInterface.VariableIndex, MathOptInterface.GreaterThan{Float64}}(1)
source
MathOptInterface.LessThanType
LessThan{T<:Real}(upper::T)

The set $(-\infty, upper] \subseteq \mathbb{R}$.

Example

julia> import MathOptInterface as MOI
+MathOptInterface.ConstraintIndex{MathOptInterface.VariableIndex, MathOptInterface.GreaterThan{Float64}}(1)
source
MathOptInterface.LessThanType
LessThan{T<:Real}(upper::T)

The set $(-\infty, upper] \subseteq \mathbb{R}$.

Example

julia> import MathOptInterface as MOI
 
 julia> model = MOI.Utilities.Model{Float64}()
 MOIU.Model{Float64}
@@ -221,7 +221,7 @@
 MOI.VariableIndex(1)
 
 julia> MOI.add_constraint(model, x, MOI.LessThan(2.0))
-MathOptInterface.ConstraintIndex{MathOptInterface.VariableIndex, MathOptInterface.LessThan{Float64}}(1)
source
MathOptInterface.EqualToType
EqualTo{T<:Number}(value::T)

The set containing the single point $\{value\} \subseteq \mathbb{R}$.

Example

julia> import MathOptInterface as MOI
+MathOptInterface.ConstraintIndex{MathOptInterface.VariableIndex, MathOptInterface.LessThan{Float64}}(1)
source
MathOptInterface.EqualToType
EqualTo{T<:Number}(value::T)

The set containing the single point $\{value\} \subseteq \mathbb{R}$.

Example

julia> import MathOptInterface as MOI
 
 julia> model = MOI.Utilities.Model{Float64}()
 MOIU.Model{Float64}
@@ -230,7 +230,7 @@
 MOI.VariableIndex(1)
 
 julia> MOI.add_constraint(model, x, MOI.EqualTo(2.0))
-MathOptInterface.ConstraintIndex{MathOptInterface.VariableIndex, MathOptInterface.EqualTo{Float64}}(1)
source
MathOptInterface.IntervalType
Interval{T<:Real}(lower::T, upper::T)

The interval $[lower, upper] \subseteq \mathbb{R} \cup \{-\infty, +\infty\}$.

If lower or upper is -Inf or Inf, respectively, the set is interpreted as a one-sided interval.

Example

julia> import MathOptInterface as MOI
+MathOptInterface.ConstraintIndex{MathOptInterface.VariableIndex, MathOptInterface.EqualTo{Float64}}(1)
source
MathOptInterface.IntervalType
Interval{T<:Real}(lower::T, upper::T)

The interval $[lower, upper] \subseteq \mathbb{R} \cup \{-\infty, +\infty\}$.

If lower or upper is -Inf or Inf, respectively, the set is interpreted as a one-sided interval.

Example

julia> import MathOptInterface as MOI
 
 julia> model = MOI.Utilities.Model{Float64}()
 MOIU.Model{Float64}
@@ -239,7 +239,7 @@
 MOI.VariableIndex(1)
 
 julia> MOI.add_constraint(model, x, MOI.Interval(1.0, 2.0))
-MathOptInterface.ConstraintIndex{MathOptInterface.VariableIndex, MathOptInterface.Interval{Float64}}(1)
source
MathOptInterface.IntegerType
Integer()

The set of integers, $\mathbb{Z}$.

Example

julia> import MathOptInterface as MOI
+MathOptInterface.ConstraintIndex{MathOptInterface.VariableIndex, MathOptInterface.Interval{Float64}}(1)
source
MathOptInterface.IntegerType
Integer()

The set of integers, $\mathbb{Z}$.

Example

julia> import MathOptInterface as MOI
 
 julia> model = MOI.Utilities.Model{Float64}()
 MOIU.Model{Float64}
@@ -248,7 +248,7 @@
 MOI.VariableIndex(1)
 
 julia> MOI.add_constraint(model, x, MOI.Integer())
-MathOptInterface.ConstraintIndex{MathOptInterface.VariableIndex, MathOptInterface.Integer}(1)
source
MathOptInterface.ZeroOneType
ZeroOne()

The set $\{0, 1\}$.

Variables belonging to the ZeroOne set are also known as "binary" variables.

Example

julia> import MathOptInterface as MOI
+MathOptInterface.ConstraintIndex{MathOptInterface.VariableIndex, MathOptInterface.Integer}(1)
source
MathOptInterface.ZeroOneType
ZeroOne()

The set $\{0, 1\}$.

Variables belonging to the ZeroOne set are also known as "binary" variables.

Example

julia> import MathOptInterface as MOI
 
 julia> model = MOI.Utilities.Model{Float64}()
 MOIU.Model{Float64}
@@ -257,7 +257,7 @@
 MOI.VariableIndex(1)
 
 julia> MOI.add_constraint(model, x, MOI.ZeroOne())
-MathOptInterface.ConstraintIndex{MathOptInterface.VariableIndex, MathOptInterface.ZeroOne}(1)
source
MathOptInterface.SemicontinuousType
Semicontinuous{T<:Real}(lower::T, upper::T)

The set $\{0\} \cup [lower, upper]$.

Example

julia> import MathOptInterface as MOI
+MathOptInterface.ConstraintIndex{MathOptInterface.VariableIndex, MathOptInterface.ZeroOne}(1)
source
MathOptInterface.SemicontinuousType
Semicontinuous{T<:Real}(lower::T, upper::T)

The set $\{0\} \cup [lower, upper]$.

Example

julia> import MathOptInterface as MOI
 
 julia> model = MOI.Utilities.Model{Float64}()
 MOIU.Model{Float64}
@@ -266,7 +266,7 @@
 MOI.VariableIndex(1)
 
 julia> MOI.add_constraint(model, x, MOI.Semicontinuous(2.0, 3.0))
-MathOptInterface.ConstraintIndex{MathOptInterface.VariableIndex, MathOptInterface.Semicontinuous{Float64}}(1)
source
MathOptInterface.SemiintegerType
Semiinteger{T<:Real}(lower::T, upper::T)

The set $\{0\} \cup \{lower, lower+1, \ldots, upper-1, upper\}$.

Note that if lower and upper are not equivalent to an integer, then the solver may throw an error, or it may round up lower and round down upper to the nearest integers.

Example

julia> import MathOptInterface as MOI
+MathOptInterface.ConstraintIndex{MathOptInterface.VariableIndex, MathOptInterface.Semicontinuous{Float64}}(1)
source
MathOptInterface.SemiintegerType
Semiinteger{T<:Real}(lower::T, upper::T)

The set $\{0\} \cup \{lower, lower+1, \ldots, upper-1, upper\}$.

Note that if lower and upper are not equivalent to an integer, then the solver may throw an error, or it may round up lower and round down upper to the nearest integers.

Example

julia> import MathOptInterface as MOI
 
 julia> model = MOI.Utilities.Model{Float64}()
 MOIU.Model{Float64}
@@ -275,7 +275,7 @@
 MOI.VariableIndex(1)
 
 julia> MOI.add_constraint(model, x, MOI.Semiinteger(2.0, 3.0))
-MathOptInterface.ConstraintIndex{MathOptInterface.VariableIndex, MathOptInterface.Semiinteger{Float64}}(1)
source
MathOptInterface.ParameterType
Parameter{T<:Number}(value::T)

The set containing the single point $\{value\} \subseteq \mathbb{R}$.

The Parameter set is conceptually similar to the EqualTo set, except that a variable constrained to the Parameter set cannot have other constraints added to it, and the Parameter set can never be deleted. Thus, solvers are free to treat the variable as a constant, and they need not add it as a decision variable to the model.

Because of this behavior, you must add parameters using add_constrained_variable, and solvers should declare supports_add_constrained_variable and not supports_constraint for the Parameter set.

Example

julia> import MathOptInterface as MOI
+MathOptInterface.ConstraintIndex{MathOptInterface.VariableIndex, MathOptInterface.Semiinteger{Float64}}(1)
source
MathOptInterface.ParameterType
Parameter{T<:Number}(value::T)

The set containing the single point $\{value\} \subseteq \mathbb{R}$.

The Parameter set is conceptually similar to the EqualTo set, except that a variable constrained to the Parameter set cannot have other constraints added to it, and the Parameter set can never be deleted. Thus, solvers are free to treat the variable as a constant, and they need not add it as a decision variable to the model.

Because of this behavior, you must add parameters using add_constrained_variable, and solvers should declare supports_add_constrained_variable and not supports_constraint for the Parameter set.

Example

julia> import MathOptInterface as MOI
 
 julia> model = MOI.Utilities.Model{Float64}()
 MOIU.Model{Float64}
@@ -286,7 +286,7 @@
 julia> MOI.set(model, MOI.ConstraintSet(), ci, MOI.Parameter(3.0))
 
 julia> MOI.get(model, MOI.ConstraintSet(), ci)
-MathOptInterface.Parameter{Float64}(3.0)
source

Vector sets

List of recognized vector sets.

MathOptInterface.RealsType
Reals(dimension::Int)

The set $\mathbb{R}^{dimension}$ (containing all points) of non-negative dimension dimension.

Example

julia> import MathOptInterface as MOI
+MathOptInterface.Parameter{Float64}(3.0)
source

Vector sets

List of recognized vector sets.

MathOptInterface.RealsType
Reals(dimension::Int)

The set $\mathbb{R}^{dimension}$ (containing all points) of non-negative dimension dimension.

Example

julia> import MathOptInterface as MOI
 
 julia> model = MOI.Utilities.Model{Float64}()
 MOIU.Model{Float64}
@@ -294,7 +294,7 @@
 julia> x = MOI.add_variables(model, 3);
 
 julia> MOI.add_constraint(model, MOI.VectorOfVariables(x), MOI.Reals(3))
-MathOptInterface.ConstraintIndex{MathOptInterface.VectorOfVariables, MathOptInterface.Reals}(1)
source
MathOptInterface.ZerosType
Zeros(dimension::Int)

The set $\{ 0 \}^{dimension}$ (containing only the origin) of non-negative dimension dimension.

Example

julia> import MathOptInterface as MOI
+MathOptInterface.ConstraintIndex{MathOptInterface.VectorOfVariables, MathOptInterface.Reals}(1)
source
MathOptInterface.ZerosType
Zeros(dimension::Int)

The set $\{ 0 \}^{dimension}$ (containing only the origin) of non-negative dimension dimension.

Example

julia> import MathOptInterface as MOI
 
 julia> model = MOI.Utilities.Model{Float64}()
 MOIU.Model{Float64}
@@ -302,7 +302,7 @@
 julia> x = MOI.add_variables(model, 3);
 
 julia> MOI.add_constraint(model, MOI.VectorOfVariables(x), MOI.Zeros(3))
-MathOptInterface.ConstraintIndex{MathOptInterface.VectorOfVariables, MathOptInterface.Zeros}(1)
source
MathOptInterface.NonnegativesType
Nonnegatives(dimension::Int)

The nonnegative orthant $\{ x \in \mathbb{R}^{dimension} : x \ge 0 \}$ of non-negative dimension dimension.

Example

julia> import MathOptInterface as MOI
+MathOptInterface.ConstraintIndex{MathOptInterface.VectorOfVariables, MathOptInterface.Zeros}(1)
source
MathOptInterface.NonnegativesType
Nonnegatives(dimension::Int)

The nonnegative orthant $\{ x \in \mathbb{R}^{dimension} : x \ge 0 \}$ of non-negative dimension dimension.

Example

julia> import MathOptInterface as MOI
 
 julia> model = MOI.Utilities.Model{Float64}()
 MOIU.Model{Float64}
@@ -310,7 +310,7 @@
 julia> x = MOI.add_variables(model, 3);
 
 julia> MOI.add_constraint(model, MOI.VectorOfVariables(x), MOI.Nonnegatives(3))
-MathOptInterface.ConstraintIndex{MathOptInterface.VectorOfVariables, MathOptInterface.Nonnegatives}(1)
source
MathOptInterface.NonpositivesType
Nonpositives(dimension::Int)

The nonpositive orthant $\{ x \in \mathbb{R}^{dimension} : x \le 0 \}$ of non-negative dimension dimension.

Example

julia> import MathOptInterface as MOI
+MathOptInterface.ConstraintIndex{MathOptInterface.VectorOfVariables, MathOptInterface.Nonnegatives}(1)
source
MathOptInterface.NonpositivesType
Nonpositives(dimension::Int)

The nonpositive orthant $\{ x \in \mathbb{R}^{dimension} : x \le 0 \}$ of non-negative dimension dimension.

Example

julia> import MathOptInterface as MOI
 
 julia> model = MOI.Utilities.Model{Float64}()
 MOIU.Model{Float64}
@@ -318,7 +318,7 @@
 julia> x = MOI.add_variables(model, 3);
 
 julia> MOI.add_constraint(model, MOI.VectorOfVariables(x), MOI.Nonpositives(3))
-MathOptInterface.ConstraintIndex{MathOptInterface.VectorOfVariables, MathOptInterface.Nonpositives}(1)
source
MathOptInterface.NormInfinityConeType
NormInfinityCone(dimension::Int)

The $\ell_\infty$-norm cone $\{ (t,x) \in \mathbb{R}^{dimension} : t \ge \lVert x \rVert_\infty = \max_i \lvert x_i \rvert \}$ of dimension dimension.

The dimension must be at least 1.

Example

julia> import MathOptInterface as MOI
+MathOptInterface.ConstraintIndex{MathOptInterface.VectorOfVariables, MathOptInterface.Nonpositives}(1)
source
MathOptInterface.NormInfinityConeType
NormInfinityCone(dimension::Int)

The $\ell_\infty$-norm cone $\{ (t,x) \in \mathbb{R}^{dimension} : t \ge \lVert x \rVert_\infty = \max_i \lvert x_i \rvert \}$ of dimension dimension.

The dimension must be at least 1.

Example

julia> import MathOptInterface as MOI
 
 julia> model = MOI.Utilities.Model{Float64}()
 MOIU.Model{Float64}
@@ -329,7 +329,7 @@
 julia> x = MOI.add_variables(model, 3);
 
 julia> MOI.add_constraint(model, MOI.VectorOfVariables([t; x]), MOI.NormInfinityCone(4))
-MathOptInterface.ConstraintIndex{MathOptInterface.VectorOfVariables, MathOptInterface.NormInfinityCone}(1)
source
MathOptInterface.NormOneConeType
NormOneCone(dimension::Int)

The $\ell_1$-norm cone $\{ (t,x) \in \mathbb{R}^{dimension} : t \ge \lVert x \rVert_1 = \sum_i \lvert x_i \rvert \}$ of dimension dimension.

The dimension must be at least 1.

Example

julia> import MathOptInterface as MOI
+MathOptInterface.ConstraintIndex{MathOptInterface.VectorOfVariables, MathOptInterface.NormInfinityCone}(1)
source
MathOptInterface.NormOneConeType
NormOneCone(dimension::Int)

The $\ell_1$-norm cone $\{ (t,x) \in \mathbb{R}^{dimension} : t \ge \lVert x \rVert_1 = \sum_i \lvert x_i \rvert \}$ of dimension dimension.

The dimension must be at least 1.

Example

julia> import MathOptInterface as MOI
 
 julia> model = MOI.Utilities.Model{Float64}()
 MOIU.Model{Float64}
@@ -340,7 +340,7 @@
 julia> x = MOI.add_variables(model, 3);
 
 julia> MOI.add_constraint(model, MOI.VectorOfVariables([t; x]), MOI.NormOneCone(4))
-MathOptInterface.ConstraintIndex{MathOptInterface.VectorOfVariables, MathOptInterface.NormOneCone}(1)
source
MathOptInterface.NormConeType
NormCone(p::Float64, dimension::Int)

The $\ell_p$-norm cone $\{ (t,x) \in \mathbb{R}^{dimension} : t \ge \left(\sum\limits_i |x_i|^p\right)^{\frac{1}{p}} \}$ of dimension dimension.

The dimension must be at least 1.

Example

julia> import MathOptInterface as MOI
+MathOptInterface.ConstraintIndex{MathOptInterface.VectorOfVariables, MathOptInterface.NormOneCone}(1)
source
MathOptInterface.NormConeType
NormCone(p::Float64, dimension::Int)

The $\ell_p$-norm cone $\{ (t,x) \in \mathbb{R}^{dimension} : t \ge \left(\sum\limits_i |x_i|^p\right)^{\frac{1}{p}} \}$ of dimension dimension.

The dimension must be at least 1.

Example

julia> import MathOptInterface as MOI
 
 julia> model = MOI.Utilities.Model{Float64}()
 MOIU.Model{Float64}
@@ -351,7 +351,7 @@
 julia> x = MOI.add_variables(model, 3);
 
 julia> MOI.add_constraint(model, MOI.VectorOfVariables([t; x]), MOI.NormCone(3, 4))
-MathOptInterface.ConstraintIndex{MathOptInterface.VectorOfVariables, MathOptInterface.NormCone}(1)
source
MathOptInterface.SecondOrderConeType
SecondOrderCone(dimension::Int)

The second-order cone (or Lorenz cone or $\ell_2$-norm cone) $\{ (t,x) \in \mathbb{R}^{dimension} : t \ge \lVert x \rVert_2 \}$ of dimension dimension.

The dimension must be at least 1.

Example

julia> import MathOptInterface as MOI
+MathOptInterface.ConstraintIndex{MathOptInterface.VectorOfVariables, MathOptInterface.NormCone}(1)
source
MathOptInterface.SecondOrderConeType
SecondOrderCone(dimension::Int)

The second-order cone (or Lorenz cone or $\ell_2$-norm cone) $\{ (t,x) \in \mathbb{R}^{dimension} : t \ge \lVert x \rVert_2 \}$ of dimension dimension.

The dimension must be at least 1.

Example

julia> import MathOptInterface as MOI
 
 julia> model = MOI.Utilities.Model{Float64}()
 MOIU.Model{Float64}
@@ -362,7 +362,7 @@
 julia> x = MOI.add_variables(model, 3);
 
 julia> MOI.add_constraint(model, MOI.VectorOfVariables([t; x]), MOI.SecondOrderCone(4))
-MathOptInterface.ConstraintIndex{MathOptInterface.VectorOfVariables, MathOptInterface.SecondOrderCone}(1)
source
MathOptInterface.RotatedSecondOrderConeType
RotatedSecondOrderCone(dimension::Int)

The rotated second-order cone $\{ (t,u,x) \in \mathbb{R}^{dimension} : 2tu \ge \lVert x \rVert_2^2, t,u \ge 0 \}$ of dimension dimension.

The dimension must be at least 2.

Example

julia> import MathOptInterface as MOI
+MathOptInterface.ConstraintIndex{MathOptInterface.VectorOfVariables, MathOptInterface.SecondOrderCone}(1)
source
MathOptInterface.RotatedSecondOrderConeType
RotatedSecondOrderCone(dimension::Int)

The rotated second-order cone $\{ (t,u,x) \in \mathbb{R}^{dimension} : 2tu \ge \lVert x \rVert_2^2, t,u \ge 0 \}$ of dimension dimension.

The dimension must be at least 2.

Example

julia> import MathOptInterface as MOI
 
 julia> model = MOI.Utilities.Model{Float64}()
 MOIU.Model{Float64}
@@ -380,7 +380,7 @@
            MOI.VectorOfVariables([t; u; x]),
            MOI.RotatedSecondOrderCone(5),
        )
-MathOptInterface.ConstraintIndex{MathOptInterface.VectorOfVariables, MathOptInterface.RotatedSecondOrderCone}(1)
source
MathOptInterface.GeometricMeanConeType
GeometricMeanCone(dimension::Int)

The geometric mean cone $\{ (t,x) \in \mathbb{R}^{n+1} : x \ge 0, t \le \sqrt[n]{x_1 x_2 \cdots x_n} \}$, where dimension = n + 1 >= 2.

Duality note

The dual of the geometric mean cone is $\{ (u, v) \in \mathbb{R}^{n+1} : u \le 0, v \ge 0, -u \le n \sqrt[n]{\prod_i v_i} \}$, where dimension = n + 1 >= 2.

Example

julia> import MathOptInterface as MOI
+MathOptInterface.ConstraintIndex{MathOptInterface.VectorOfVariables, MathOptInterface.RotatedSecondOrderCone}(1)
source
MathOptInterface.GeometricMeanConeType
GeometricMeanCone(dimension::Int)

The geometric mean cone $\{ (t,x) \in \mathbb{R}^{n+1} : x \ge 0, t \le \sqrt[n]{x_1 x_2 \cdots x_n} \}$, where dimension = n + 1 >= 2.

Duality note

The dual of the geometric mean cone is $\{ (u, v) \in \mathbb{R}^{n+1} : u \le 0, v \ge 0, -u \le n \sqrt[n]{\prod_i v_i} \}$, where dimension = n + 1 >= 2.

Example

julia> import MathOptInterface as MOI
 
 julia> model = MOI.Utilities.Model{Float64}()
 MOIU.Model{Float64}
@@ -395,7 +395,7 @@
            MOI.VectorOfVariables([t; x]),
            MOI.GeometricMeanCone(4),
        )
-MathOptInterface.ConstraintIndex{MathOptInterface.VectorOfVariables, MathOptInterface.GeometricMeanCone}(1)
source
MathOptInterface.ExponentialConeType
ExponentialCone()

The 3-dimensional exponential cone $\{ (x,y,z) \in \mathbb{R}^3 : y \exp (x/y) \le z, y > 0 \}$.

Example

julia> import MathOptInterface as MOI
+MathOptInterface.ConstraintIndex{MathOptInterface.VectorOfVariables, MathOptInterface.GeometricMeanCone}(1)
source
MathOptInterface.ExponentialConeType
ExponentialCone()

The 3-dimensional exponential cone $\{ (x,y,z) \in \mathbb{R}^3 : y \exp (x/y) \le z, y > 0 \}$.

Example

julia> import MathOptInterface as MOI
 
 julia> model = MOI.Utilities.Model{Float64}()
 MOIU.Model{Float64}
@@ -403,7 +403,7 @@
 julia> x = MOI.add_variables(model, 3);
 
 julia> MOI.add_constraint(model, MOI.VectorOfVariables(x), MOI.ExponentialCone())
-MathOptInterface.ConstraintIndex{MathOptInterface.VectorOfVariables, MathOptInterface.ExponentialCone}(1)
source
MathOptInterface.DualExponentialConeType
DualExponentialCone()

The 3-dimensional dual exponential cone $\{ (u,v,w) \in \mathbb{R}^3 : -u \exp (v/u) \le \exp(1) w, u < 0 \}$.

Example

julia> import MathOptInterface as MOI
+MathOptInterface.ConstraintIndex{MathOptInterface.VectorOfVariables, MathOptInterface.ExponentialCone}(1)
source
MathOptInterface.DualExponentialConeType
DualExponentialCone()

The 3-dimensional dual exponential cone $\{ (u,v,w) \in \mathbb{R}^3 : -u \exp (v/u) \le \exp(1) w, u < 0 \}$.

Example

julia> import MathOptInterface as MOI
 
 julia> model = MOI.Utilities.Model{Float64}()
 MOIU.Model{Float64}
@@ -411,7 +411,7 @@
 julia> x = MOI.add_variables(model, 3);
 
 julia> MOI.add_constraint(model, MOI.VectorOfVariables(x), MOI.DualExponentialCone())
-MathOptInterface.ConstraintIndex{MathOptInterface.VectorOfVariables, MathOptInterface.DualExponentialCone}(1)
source
MathOptInterface.PowerConeType
PowerCone{T<:Real}(exponent::T)

The 3-dimensional power cone $\{ (x,y,z) \in \mathbb{R}^3 : x^{exponent} y^{1-exponent} \ge |z|, x \ge 0, y \ge 0 \}$ with parameter exponent.

Example

julia> import MathOptInterface as MOI
+MathOptInterface.ConstraintIndex{MathOptInterface.VectorOfVariables, MathOptInterface.DualExponentialCone}(1)
source
MathOptInterface.PowerConeType
PowerCone{T<:Real}(exponent::T)

The 3-dimensional power cone $\{ (x,y,z) \in \mathbb{R}^3 : x^{exponent} y^{1-exponent} \ge |z|, x \ge 0, y \ge 0 \}$ with parameter exponent.

Example

julia> import MathOptInterface as MOI
 
 julia> model = MOI.Utilities.Model{Float64}()
 MOIU.Model{Float64}
@@ -419,7 +419,7 @@
 julia> x = MOI.add_variables(model, 3);
 
 julia> MOI.add_constraint(model, MOI.VectorOfVariables(x), MOI.PowerCone(0.5))
-MathOptInterface.ConstraintIndex{MathOptInterface.VectorOfVariables, MathOptInterface.PowerCone{Float64}}(1)
source
MathOptInterface.DualPowerConeType
DualPowerCone{T<:Real}(exponent::T)

The 3-dimensional power cone $\{ (u,v,w) \in \mathbb{R}^3 : (\frac{u}{exponent})^{exponent} (\frac{v}{1-exponent})^{1-exponent} \ge |w|, u \ge 0, v \ge 0 \}$ with parameter exponent.

Example

julia> import MathOptInterface as MOI
+MathOptInterface.ConstraintIndex{MathOptInterface.VectorOfVariables, MathOptInterface.PowerCone{Float64}}(1)
source
MathOptInterface.DualPowerConeType
DualPowerCone{T<:Real}(exponent::T)

The 3-dimensional power cone $\{ (u,v,w) \in \mathbb{R}^3 : (\frac{u}{exponent})^{exponent} (\frac{v}{1-exponent})^{1-exponent} \ge |w|, u \ge 0, v \ge 0 \}$ with parameter exponent.

Example

julia> import MathOptInterface as MOI
 
 julia> model = MOI.Utilities.Model{Float64}()
 MOIU.Model{Float64}
@@ -427,7 +427,7 @@
 julia> x = MOI.add_variables(model, 3);
 
 julia> MOI.add_constraint(model, MOI.VectorOfVariables(x), MOI.DualPowerCone(0.5))
-MathOptInterface.ConstraintIndex{MathOptInterface.VectorOfVariables, MathOptInterface.DualPowerCone{Float64}}(1)
source
MathOptInterface.RelativeEntropyConeType
RelativeEntropyCone(dimension::Int)

The relative entropy cone $\{ (u, v, w) \in \mathbb{R}^{1+2n} : u \ge \sum_{i=1}^n w_i \log(\frac{w_i}{v_i}), v_i \ge 0, w_i \ge 0 \}$, where dimension = 2n + 1 >= 1.

Duality note

The dual of the relative entropy cone is $\{ (u, v, w) \in \mathbb{R}^{1+2n} : \forall i, w_i \ge u (\log (\frac{u}{v_i}) - 1), v_i \ge 0, u > 0 \}$ of dimension dimension${}=2n+1$.

Example

julia> import MathOptInterface as MOI
+MathOptInterface.ConstraintIndex{MathOptInterface.VectorOfVariables, MathOptInterface.DualPowerCone{Float64}}(1)
source
MathOptInterface.RelativeEntropyConeType
RelativeEntropyCone(dimension::Int)

The relative entropy cone $\{ (u, v, w) \in \mathbb{R}^{1+2n} : u \ge \sum_{i=1}^n w_i \log(\frac{w_i}{v_i}), v_i \ge 0, w_i \ge 0 \}$, where dimension = 2n + 1 >= 1.

Duality note

The dual of the relative entropy cone is $\{ (u, v, w) \in \mathbb{R}^{1+2n} : \forall i, w_i \ge u (\log (\frac{u}{v_i}) - 1), v_i \ge 0, u > 0 \}$ of dimension dimension${}=2n+1$.

Example

julia> import MathOptInterface as MOI
 
 julia> model = MOI.Utilities.Model{Float64}()
 MOIU.Model{Float64}
@@ -443,7 +443,7 @@
            MOI.VectorOfVariables([u; v; w]),
            MOI.RelativeEntropyCone(7),
        )
-MathOptInterface.ConstraintIndex{MathOptInterface.VectorOfVariables, MathOptInterface.RelativeEntropyCone}(1)
source
MathOptInterface.NormSpectralConeType
NormSpectralCone(row_dim::Int, column_dim::Int)

The epigraph of the matrix spectral norm (maximum singular value function) $\{ (t, X) \in \mathbb{R}^{1 + row_dim \times column_dim} : t \ge \sigma_1(X) \}$, where $\sigma_i$ is the $i$th singular value of the matrix $X$ of non-negative row dimension row_dim and column dimension column_dim.

The matrix X is vectorized by stacking the columns, matching the behavior of Julia's vec function.

Example

julia> import MathOptInterface as MOI
+MathOptInterface.ConstraintIndex{MathOptInterface.VectorOfVariables, MathOptInterface.RelativeEntropyCone}(1)
source
MathOptInterface.NormSpectralConeType
NormSpectralCone(row_dim::Int, column_dim::Int)

The epigraph of the matrix spectral norm (maximum singular value function) $\{ (t, X) \in \mathbb{R}^{1 + row_dim \times column_dim} : t \ge \sigma_1(X) \}$, where $\sigma_i$ is the $i$th singular value of the matrix $X$ of non-negative row dimension row_dim and column dimension column_dim.

The matrix X is vectorized by stacking the columns, matching the behavior of Julia's vec function.

Example

julia> import MathOptInterface as MOI
 
 julia> model = MOI.Utilities.Model{Float64}()
 MOIU.Model{Float64}
@@ -461,7 +461,7 @@
            MOI.VectorOfVariables([t; vec(X)]),
            MOI.NormSpectralCone(2, 3),
        )
-MathOptInterface.ConstraintIndex{MathOptInterface.VectorOfVariables, MathOptInterface.NormSpectralCone}(1)
source
MathOptInterface.NormNuclearConeType
NormNuclearCone(row_dim::Int, column_dim::Int)

The epigraph of the matrix nuclear norm (sum of singular values function) $\{ (t, X) \in \mathbb{R}^{1 + row_dim \times column_dim} : t \ge \sum_i \sigma_i(X) \}$, where $\sigma_i$ is the $i$th singular value of the matrix $X$ of non-negative row dimension row_dim and column dimension column_dim.

The matrix X is vectorized by stacking the columns, matching the behavior of Julia's vec function.

Example

julia> import MathOptInterface as MOI
+MathOptInterface.ConstraintIndex{MathOptInterface.VectorOfVariables, MathOptInterface.NormSpectralCone}(1)
source
MathOptInterface.NormNuclearConeType
NormNuclearCone(row_dim::Int, column_dim::Int)

The epigraph of the matrix nuclear norm (sum of singular values function) $\{ (t, X) \in \mathbb{R}^{1 + row_dim \times column_dim} : t \ge \sum_i \sigma_i(X) \}$, where $\sigma_i$ is the $i$th singular value of the matrix $X$ of non-negative row dimension row_dim and column dimension column_dim.

The matrix X is vectorized by stacking the columns, matching the behavior of Julia's vec function.

Example

julia> import MathOptInterface as MOI
 
 julia> model = MOI.Utilities.Model{Float64}()
 MOIU.Model{Float64}
@@ -479,7 +479,7 @@
            MOI.VectorOfVariables([t; vec(X)]),
            MOI.NormNuclearCone(2, 3),
        )
-MathOptInterface.ConstraintIndex{MathOptInterface.VectorOfVariables, MathOptInterface.NormNuclearCone}(1)
source
MathOptInterface.SOS1Type
SOS1{T<:Real}(weights::Vector{T})

The set corresponding to the Special Ordered Set (SOS) constraint of Type I.

Of the variables in the set, at most one can be nonzero.

The weights induce an ordering of the variables such that the kth element in the set corresponds to the kth weight in weights. Solvers may use these weights to improve the efficiency of the solution process, but the ordering does not change the set of feasible solutions.

Example

julia> import MathOptInterface as MOI
+MathOptInterface.ConstraintIndex{MathOptInterface.VectorOfVariables, MathOptInterface.NormNuclearCone}(1)
source
MathOptInterface.SOS1Type
SOS1{T<:Real}(weights::Vector{T})

The set corresponding to the Special Ordered Set (SOS) constraint of Type I.

Of the variables in the set, at most one can be nonzero.

The weights induce an ordering of the variables such that the kth element in the set corresponds to the kth weight in weights. Solvers may use these weights to improve the efficiency of the solution process, but the ordering does not change the set of feasible solutions.

Example

julia> import MathOptInterface as MOI
 
 julia> model = MOI.Utilities.Model{Float64}()
 MOIU.Model{Float64}
@@ -491,7 +491,7 @@
            MOI.VectorOfVariables(x),
            MOI.SOS1([1.0, 3.0, 2.5]),
        )
-MathOptInterface.ConstraintIndex{MathOptInterface.VectorOfVariables, MathOptInterface.SOS1{Float64}}(1)
source
MathOptInterface.SOS2Type
SOS2{T<:Real}(weights::Vector{T})

The set corresponding to the Special Ordered Set (SOS) constraint of Type II.

The weights induce an ordering of the variables such that the kth element in the set corresponds to the kth weight in weights. Therefore, the weights must be unique.

Of the variables in the set, at most two can be nonzero, and if two are nonzero, they must be adjacent in the ordering of the set.

Example

julia> import MathOptInterface as MOI
+MathOptInterface.ConstraintIndex{MathOptInterface.VectorOfVariables, MathOptInterface.SOS1{Float64}}(1)
source
MathOptInterface.SOS2Type
SOS2{T<:Real}(weights::Vector{T})

The set corresponding to the Special Ordered Set (SOS) constraint of Type II.

The weights induce an ordering of the variables such that the kth element in the set corresponds to the kth weight in weights. Therefore, the weights must be unique.

Of the variables in the set, at most two can be nonzero, and if two are nonzero, they must be adjacent in the ordering of the set.

Example

julia> import MathOptInterface as MOI
 
 julia> model = MOI.Utilities.Model{Float64}()
 MOIU.Model{Float64}
@@ -503,7 +503,7 @@
            MOI.VectorOfVariables(x),
            MOI.SOS2([1.0, 3.0, 2.5]),
        )
-MathOptInterface.ConstraintIndex{MathOptInterface.VectorOfVariables, MathOptInterface.SOS2{Float64}}(1)
source
MathOptInterface.IndicatorType
Indicator{A<:ActivationCondition,S<:AbstractScalarSet}(set::S)

The set corresponding to an indicator constraint.

When A is ACTIVATE_ON_ZERO, this means: $\{(y, x) \in \{0, 1\} \times \mathbb{R}^n : y = 0 \implies x \in set\}$

When A is ACTIVATE_ON_ONE, this means: $\{(y, x) \in \{0, 1\} \times \mathbb{R}^n : y = 1 \implies x \in set\}$

Notes

Most solvers expect that the first row of the function is interpretable as a variable index x_i (e.g., 1.0 * x + 0.0). An error will be thrown if this is not the case.

Example

The constraint $\{(y, x) \in \{0, 1\} \times \mathbb{R}^2 : y = 1 \implies x_1 + x_2 \leq 9 \}$ is defined as

julia> import MathOptInterface as MOI
+MathOptInterface.ConstraintIndex{MathOptInterface.VectorOfVariables, MathOptInterface.SOS2{Float64}}(1)
source
MathOptInterface.IndicatorType
Indicator{A<:ActivationCondition,S<:AbstractScalarSet}(set::S)

The set corresponding to an indicator constraint.

When A is ACTIVATE_ON_ZERO, this means: $\{(y, x) \in \{0, 1\} \times \mathbb{R}^n : y = 0 \implies x \in set\}$

When A is ACTIVATE_ON_ONE, this means: $\{(y, x) \in \{0, 1\} \times \mathbb{R}^n : y = 1 \implies x \in set\}$

Notes

Most solvers expect that the first row of the function is interpretable as a variable index x_i (e.g., 1.0 * x + 0.0). An error will be thrown if this is not the case.

Example

The constraint $\{(y, x) \in \{0, 1\} \times \mathbb{R}^2 : y = 1 \implies x_1 + x_2 \leq 9 \}$ is defined as

julia> import MathOptInterface as MOI
 
 julia> model = MOI.Utilities.Model{Float64}()
 MOIU.Model{Float64}
@@ -533,7 +533,7 @@
 MathOptInterface.Indicator{MathOptInterface.ACTIVATE_ON_ONE, MathOptInterface.LessThan{Float64}}(MathOptInterface.LessThan{Float64}(9.0))
 
 julia> MOI.add_constraint(model, f, s)
-MathOptInterface.ConstraintIndex{MathOptInterface.VectorAffineFunction{Float64}, MathOptInterface.Indicator{MathOptInterface.ACTIVATE_ON_ONE, MathOptInterface.LessThan{Float64}}}(1)
source
MathOptInterface.ComplementsType
Complements(dimension::Base.Integer)

The set corresponding to a mixed complementarity constraint.

Complementarity constraints should be specified with an AbstractVectorFunction-in-Complements(dimension) constraint.

The dimension of the vector-valued function F must be dimension. This defines a complementarity constraint between the scalar function F[i] and the variable in F[i + dimension/2]. Thus, F[i + dimension/2] must be interpretable as a single variable x_i (e.g., 1.0 * x + 0.0), and dimension must be even.

The mixed complementarity problem consists of finding x_i in the interval [lb, ub] (i.e., in the set Interval(lb, ub)), such that the following holds:

  1. F_i(x) == 0 if lb_i < x_i < ub_i
  2. F_i(x) >= 0 if lb_i == x_i
  3. F_i(x) <= 0 if x_i == ub_i

Classically, the bounding set for x_i is Interval(0, Inf), which recovers: 0 <= F_i(x) ⟂ x_i >= 0, where the operator implies F_i(x) * x_i = 0.

Example

The problem:

x -in- Interval(-1, 1)
+MathOptInterface.ConstraintIndex{MathOptInterface.VectorAffineFunction{Float64}, MathOptInterface.Indicator{MathOptInterface.ACTIVATE_ON_ONE, MathOptInterface.LessThan{Float64}}}(1)
source
MathOptInterface.ComplementsType
Complements(dimension::Base.Integer)

The set corresponding to a mixed complementarity constraint.

Complementarity constraints should be specified with an AbstractVectorFunction-in-Complements(dimension) constraint.

The dimension of the vector-valued function F must be dimension. This defines a complementarity constraint between the scalar function F[i] and the variable in F[i + dimension/2]. Thus, F[i + dimension/2] must be interpretable as a single variable x_i (e.g., 1.0 * x + 0.0), and dimension must be even.

The mixed complementarity problem consists of finding x_i in the interval [lb, ub] (i.e., in the set Interval(lb, ub)), such that the following holds:

  1. F_i(x) == 0 if lb_i < x_i < ub_i
  2. F_i(x) >= 0 if lb_i == x_i
  3. F_i(x) <= 0 if x_i == ub_i

Classically, the bounding set for x_i is Interval(0, Inf), which recovers: 0 <= F_i(x) ⟂ x_i >= 0, where the operator implies F_i(x) * x_i = 0.

Example

The problem:

x -in- Interval(-1, 1)
 [-4 * x - 3, x] -in- Complements(2)

defines the mixed complementarity problem where the following holds:

  1. -4 * x - 3 == 0 if -1 < x < 1
  2. -4 * x - 3 >= 0 if x == -1
  3. -4 * x - 3 <= 0 if x == 1

There are three solutions:

  1. x = -3/4 with F(x) = 0
  2. x = -1 with F(x) = 1
  3. x = 1 with F(x) = -7
julia> import MathOptInterface as MOI
 
 julia> model = MOI.Utilities.Model{Float64}()
@@ -562,7 +562,7 @@
             MOI.VectorOfVariables(x),
             MOI.Complements(4),
         )
-MathOptInterface.ConstraintIndex{MathOptInterface.VectorOfVariables, MathOptInterface.Complements}(1)
source
MathOptInterface.HyperRectangleType
HyperRectangle(lower::Vector{T}, upper::Vector{T}) where {T}

The set $\{x \in \bar{\mathbb{R}}^d: x_i \in [lower_i, upper_i] \forall i=1,\ldots,d\}$.

Example

julia> import MathOptInterface as MOI
+MathOptInterface.ConstraintIndex{MathOptInterface.VectorOfVariables, MathOptInterface.Complements}(1)
source
MathOptInterface.HyperRectangleType
HyperRectangle(lower::Vector{T}, upper::Vector{T}) where {T}

The set $\{x \in \bar{\mathbb{R}}^d: x_i \in [lower_i, upper_i] \forall i=1,\ldots,d\}$.

Example

julia> import MathOptInterface as MOI
 
 julia> model = MOI.Utilities.Model{Float64}()
 MOIU.Model{Float64}
@@ -578,7 +578,7 @@
            MOI.VectorOfVariables(x),
            MOI.HyperRectangle(zeros(3), ones(3)),
        )
-MathOptInterface.ConstraintIndex{MathOptInterface.VectorOfVariables, MathOptInterface.HyperRectangle{Float64}}(1)
source
MathOptInterface.ScaledType
struct Scaled{S<:AbstractVectorSet} <: AbstractVectorSet
+MathOptInterface.ConstraintIndex{MathOptInterface.VectorOfVariables, MathOptInterface.HyperRectangle{Float64}}(1)
source
MathOptInterface.ScaledType
struct Scaled{S<:AbstractVectorSet} <: AbstractVectorSet
     set::S
 end

Given a vector $a \in \mathbb{R}^d$ and a set representing the set $\mathcal{S} \in \mathbb{R}^d$ such that Utilities.set_dot for $x \in \mathcal{S}$ and $y \in \mathcal{S}^*$ is

\[\sum_{i=1}^d a_i x_i y_i\]

the set Scaled(set) is defined as

\[\{ (\sqrt{a_1} x_1, \sqrt{a_2} x_2, \ldots, \sqrt{a_d} x_d) : x \in S \}\]

Example

This can be used to scale a vector of numbers

julia> import MathOptInterface as MOI
 
@@ -617,7 +617,7 @@
 │0.0 + 1.0 MOI.VariableIndex(1)               │
 │0.0 + 1.4142135623730951 MOI.VariableIndex(2)│
 │0.0 + 1.0 MOI.VariableIndex(3)               │
-└                                             ┘
source

Constraint programming sets

MathOptInterface.AllDifferentType
AllDifferent(dimension::Int)

The set $\{x \in \mathbb{Z}^{d}\}$ such that no two elements in $x$ take the same value and dimension = d.

Also known as

This constraint is called all_different in MiniZinc, and is sometimes also called distinct.

Example

To enforce x[1] != x[2] AND x[1] != x[3] AND x[2] != x[3]:

julia> import MathOptInterface as MOI
+└                                             ┘
source

Constraint programming sets

MathOptInterface.AllDifferentType
AllDifferent(dimension::Int)

The set $\{x \in \mathbb{Z}^{d}\}$ such that no two elements in $x$ take the same value and dimension = d.

Also known as

This constraint is called all_different in MiniZinc, and is sometimes also called distinct.

Example

To enforce x[1] != x[2] AND x[1] != x[3] AND x[2] != x[3]:

julia> import MathOptInterface as MOI
 
 julia> model = MOI.Utilities.Model{Float64}()
 MOIU.Model{Float64}
@@ -629,7 +629,7 @@
  MOI.VariableIndex(3)
 
 julia> MOI.add_constraint(model, MOI.VectorOfVariables(x), MOI.AllDifferent(3))
-MathOptInterface.ConstraintIndex{MathOptInterface.VectorOfVariables, MathOptInterface.AllDifferent}(1)
source
MathOptInterface.BinPackingType
BinPacking(c::T, w::Vector{T}) where {T}

The set $\{x \in \mathbb{Z}^d\}$ where d = length(w), such that each item i in 1:d of weight w[i] is put into bin x[i], and the total weight of each bin does not exceed c.

There are additional assumptions that the capacity, c, and the weights, w, must all be non-negative.

The bin numbers depend on the bounds of x, so they may be something other than the integers 1:d.

Also known as

This constraint is called bin_packing in MiniZinc.

Example

julia> import MathOptInterface as MOI
+MathOptInterface.ConstraintIndex{MathOptInterface.VectorOfVariables, MathOptInterface.AllDifferent}(1)
source
MathOptInterface.BinPackingType
BinPacking(c::T, w::Vector{T}) where {T}

The set $\{x \in \mathbb{Z}^d\}$ where d = length(w), such that each item i in 1:d of weight w[i] is put into bin x[i], and the total weight of each bin does not exceed c.

There are additional assumptions that the capacity, c, and the weights, w, must all be non-negative.

The bin numbers depend on the bounds of x, so they may be something other than the integers 1:d.

Also known as

This constraint is called bin_packing in MiniZinc.

Example

julia> import MathOptInterface as MOI
 
 julia> model = MOI.Utilities.Model{Float64}()
 MOIU.Model{Float64}
@@ -667,7 +667,7 @@
  MathOptInterface.ConstraintIndex{MathOptInterface.VariableIndex, MathOptInterface.Interval{Float64}}(5)
 
 julia> MOI.add_constraint(model, MOI.VectorOfVariables(bins), MOI.BinPacking(3.0, weights))
-MathOptInterface.ConstraintIndex{MathOptInterface.VectorOfVariables, MathOptInterface.BinPacking{Float64}}(1)
source
MathOptInterface.CircuitType
Circuit(dimension::Int)

The set $\{x \in \{1..d\}^d\}$ that constraints $x$ to be a circuit, such that $x_i = j$ means that $j$ is the successor of $i$, and dimension = d.

Graphs with multiple independent circuits, such as [2, 1, 3] and [2, 1, 4, 3], are not valid.

Also known as

This constraint is called circuit in MiniZinc, and it is equivalent to forming a (potentially sub-optimal) tour in the travelling salesperson problem.

Example

julia> import MathOptInterface as MOI
+MathOptInterface.ConstraintIndex{MathOptInterface.VectorOfVariables, MathOptInterface.BinPacking{Float64}}(1)
source
MathOptInterface.CircuitType
Circuit(dimension::Int)

The set $\{x \in \{1..d\}^d\}$ that constraints $x$ to be a circuit, such that $x_i = j$ means that $j$ is the successor of $i$, and dimension = d.

Graphs with multiple independent circuits, such as [2, 1, 3] and [2, 1, 4, 3], are not valid.

Also known as

This constraint is called circuit in MiniZinc, and it is equivalent to forming a (potentially sub-optimal) tour in the travelling salesperson problem.

Example

julia> import MathOptInterface as MOI
 
 julia> model = MOI.Utilities.Model{Float64}()
 MOIU.Model{Float64}
@@ -679,7 +679,7 @@
  MOI.VariableIndex(3)
 
 julia> MOI.add_constraint(model, MOI.VectorOfVariables(x), MOI.Circuit(3))
-MathOptInterface.ConstraintIndex{MathOptInterface.VectorOfVariables, MathOptInterface.Circuit}(1)
source
MathOptInterface.CountAtLeastType
CountAtLeast(n::Int, d::Vector{Int}, set::Set{Int})

The set $\{x \in \mathbb{Z}^{d_1 + d_2 + \ldots d_N}\}$, where x is partitioned into N subsets ($\{x_1, \ldots, x_{d_1}\}$, $\{x_{d_1 + 1}, \ldots, x_{d_1 + d_2}\}$ and so on), and at least $n$ elements of each subset take one of the values in set.

Also known as

This constraint is called at_least in MiniZinc.

Example

To ensure that 3 appears at least once in each of the subsets {a, b} and {b, c}:

julia> import MathOptInterface as MOI
+MathOptInterface.ConstraintIndex{MathOptInterface.VectorOfVariables, MathOptInterface.Circuit}(1)
source
MathOptInterface.CountAtLeastType
CountAtLeast(n::Int, d::Vector{Int}, set::Set{Int})

The set $\{x \in \mathbb{Z}^{d_1 + d_2 + \ldots d_N}\}$, where x is partitioned into N subsets ($\{x_1, \ldots, x_{d_1}\}$, $\{x_{d_1 + 1}, \ldots, x_{d_1 + d_2}\}$ and so on), and at least $n$ elements of each subset take one of the values in set.

Also known as

This constraint is called at_least in MiniZinc.

Example

To ensure that 3 appears at least once in each of the subsets {a, b} and {b, c}:

julia> import MathOptInterface as MOI
 
 julia> model = MOI.Utilities.Model{Float64}()
 MOIU.Model{Float64}
@@ -697,7 +697,7 @@
 (MathOptInterface.VariableIndex[MOI.VariableIndex(1), MOI.VariableIndex(2), MOI.VariableIndex(2), MOI.VariableIndex(3)], [2, 2], [3])
 
 julia> MOI.add_constraint(model, MOI.VectorOfVariables(x), MOI.CountAtLeast(1, d, Set(set)))
-MathOptInterface.ConstraintIndex{MathOptInterface.VectorOfVariables, MathOptInterface.CountAtLeast}(1)
source
MathOptInterface.CountBelongsType
CountBelongs(dimenson::Int, set::Set{Int})

The set $\{(n, x) \in \mathbb{Z}^{1+d}\}$, such that n elements of the vector x take on of the values in set and dimension = 1 + d.

Also known as

This constraint is called among by MiniZinc.

Example

julia> import MathOptInterface as MOI
+MathOptInterface.ConstraintIndex{MathOptInterface.VectorOfVariables, MathOptInterface.CountAtLeast}(1)
source
MathOptInterface.CountBelongsType
CountBelongs(dimenson::Int, set::Set{Int})

The set $\{(n, x) \in \mathbb{Z}^{1+d}\}$, such that n elements of the vector x take on of the values in set and dimension = 1 + d.

Also known as

This constraint is called among by MiniZinc.

Example

julia> import MathOptInterface as MOI
 
 julia> model = MOI.Utilities.Model{Float64}()
 MOIU.Model{Float64}
@@ -718,7 +718,7 @@
   3
 
 julia> MOI.add_constraint(model, MOI.VectorOfVariables([n; x]), MOI.CountBelongs(4, set))
-MathOptInterface.ConstraintIndex{MathOptInterface.VectorOfVariables, MathOptInterface.CountBelongs}(1)
source
MathOptInterface.CountDistinctType
CountDistinct(dimension::Int)

The set $\{(n, x) \in \mathbb{Z}^{1+d}\}$, such that the number of distinct values in x is n and dimension = 1 + d.

Also known as

This constraint is called nvalues in MiniZinc.

Example

To model:

  • if n == 1`, thenx[1] == x[2] == x[3]`
  • if n == 2, then
    • x[1] == x[2] != x[3] or
    • x[1] != x[2] == x[3] or
    • x[1] == x[3] != x[2]
  • if n == 3, then x[1] != x[2], x[2] != x[3] and x[3] != x[1]
julia> import MathOptInterface as MOI
+MathOptInterface.ConstraintIndex{MathOptInterface.VectorOfVariables, MathOptInterface.CountBelongs}(1)
source
MathOptInterface.CountDistinctType
CountDistinct(dimension::Int)

The set $\{(n, x) \in \mathbb{Z}^{1+d}\}$, such that the number of distinct values in x is n and dimension = 1 + d.

Also known as

This constraint is called nvalues in MiniZinc.

Example

To model:

  • if n == 1`, thenx[1] == x[2] == x[3]`
  • if n == 2, then
    • x[1] == x[2] != x[3] or
    • x[1] != x[2] == x[3] or
    • x[1] == x[3] != x[2]
  • if n == 3, then x[1] != x[2], x[2] != x[3] and x[3] != x[1]
julia> import MathOptInterface as MOI
 
 julia> model = MOI.Utilities.Model{Float64}()
 MOIU.Model{Float64}
@@ -733,7 +733,7 @@
  MOI.VariableIndex(4)
 
 julia> MOI.add_constraint(model, MOI.VectorOfVariables(vcat(n, x)), MOI.CountDistinct(4))
-MathOptInterface.ConstraintIndex{MathOptInterface.VectorOfVariables, MathOptInterface.CountDistinct}(1)

Relationship to AllDifferent

When the first element is d, CountDistinct is equivalent to an AllDifferent constraint.

source
MathOptInterface.CountGreaterThanType
CountGreaterThan(dimension::Int)

The set $\{(c, y, x) \in \mathbb{Z}^{1+1+d}\}$, such that c is strictly greater than the number of occurances of y in x and dimension = 1 + 1 + d.

Also known as

This constraint is called count_gt in MiniZinc.

Example

julia> import MathOptInterface as MOI
+MathOptInterface.ConstraintIndex{MathOptInterface.VectorOfVariables, MathOptInterface.CountDistinct}(1)

Relationship to AllDifferent

When the first element is d, CountDistinct is equivalent to an AllDifferent constraint.

source
MathOptInterface.CountGreaterThanType
CountGreaterThan(dimension::Int)

The set $\{(c, y, x) \in \mathbb{Z}^{1+1+d}\}$, such that c is strictly greater than the number of occurances of y in x and dimension = 1 + 1 + d.

Also known as

This constraint is called count_gt in MiniZinc.

Example

julia> import MathOptInterface as MOI
 
 julia> model = MOI.Utilities.Model{Float64}()
 MOIU.Model{Float64}
@@ -751,7 +751,7 @@
  MOI.VariableIndex(5)
 
 julia> MOI.add_constraint(model, MOI.VectorOfVariables([c; y; x]), MOI.CountGreaterThan(5))
-MathOptInterface.ConstraintIndex{MathOptInterface.VectorOfVariables, MathOptInterface.CountGreaterThan}(1)
source
MathOptInterface.CumulativeType
Cumulative(dimension::Int)

The set $\{(s, d, r, b) \in \mathbb{Z}^{3n+1}\}$, representing the cumulative global constraint, where n == length(s) == length(r) == length(b) and dimension = 3n + 1.

Cumulative requires that a set of tasks given by start times $s$, durations $d$, and resource requirements $r$, never requires more than the global resource bound $b$ at any one time.

Also known as

This constraint is called cumulative in MiniZinc.

Example

julia> import MathOptInterface as MOI
+MathOptInterface.ConstraintIndex{MathOptInterface.VectorOfVariables, MathOptInterface.CountGreaterThan}(1)
source
MathOptInterface.CumulativeType
Cumulative(dimension::Int)

The set $\{(s, d, r, b) \in \mathbb{Z}^{3n+1}\}$, representing the cumulative global constraint, where n == length(s) == length(r) == length(b) and dimension = 3n + 1.

Cumulative requires that a set of tasks given by start times $s$, durations $d$, and resource requirements $r$, never requires more than the global resource bound $b$ at any one time.

Also known as

This constraint is called cumulative in MiniZinc.

Example

julia> import MathOptInterface as MOI
 
 julia> model = MOI.Utilities.Model{Float64}()
 MOIU.Model{Float64}
@@ -778,7 +778,7 @@
 (MOI.VariableIndex(10), MathOptInterface.ConstraintIndex{MathOptInterface.VariableIndex, MathOptInterface.Integer}(10))
 
 julia> MOI.add_constraint(model, MOI.VectorOfVariables([s; d; r; b]), MOI.Cumulative(10))
-MathOptInterface.ConstraintIndex{MathOptInterface.VectorOfVariables, MathOptInterface.Cumulative}(1)
source
MathOptInterface.PathType
Path(from::Vector{Int}, to::Vector{Int})

Given a graph comprised of a set of nodes 1..N and a set of arcs 1..E represented by an edge from node from[i] to node to[i], Path constrains the set $(s, t, ns, es) \in (1..N)\times(1..E)\times\{0,1\}^N\times\{0,1\}^E$, to form subgraph that is a path from node s to node t, where node n is in the path if ns[n] is 1, and edge e is in the path if es[e] is 1.

The path must be acyclic, and it must traverse all nodes n for which ns[n] is 1, and all edges e for which es[e] is 1.

Also known as

This constraint is called path in MiniZinc.

Example

julia> import MathOptInterface as MOI
+MathOptInterface.ConstraintIndex{MathOptInterface.VectorOfVariables, MathOptInterface.Cumulative}(1)
source
MathOptInterface.PathType
Path(from::Vector{Int}, to::Vector{Int})

Given a graph comprised of a set of nodes 1..N and a set of arcs 1..E represented by an edge from node from[i] to node to[i], Path constrains the set $(s, t, ns, es) \in (1..N)\times(1..E)\times\{0,1\}^N\times\{0,1\}^E$, to form subgraph that is a path from node s to node t, where node n is in the path if ns[n] is 1, and edge e is in the path if es[e] is 1.

The path must be acyclic, and it must traverse all nodes n for which ns[n] is 1, and all edges e for which es[e] is 1.

Also known as

This constraint is called path in MiniZinc.

Example

julia> import MathOptInterface as MOI
 
 julia> model = MOI.Utilities.Model{Float64}()
 MOIU.Model{Float64}
@@ -839,7 +839,7 @@
  MathOptInterface.ConstraintIndex{MathOptInterface.VariableIndex, MathOptInterface.ZeroOne}(11)
 
 julia> MOI.add_constraint(model, MOI.VectorOfVariables([s; t; ns; es]), MOI.Path(from, to))
-MathOptInterface.ConstraintIndex{MathOptInterface.VectorOfVariables, MathOptInterface.Path}(1)
source
MathOptInterface.ReifiedType
Reified(set::AbstractSet)

The constraint $[z; f(x)] \in Reified(S)$ ensures that $f(x) \in S$ if and only if $z == 1$, where $z \in \{0, 1\}$.

julia> import MathOptInterface as MOI
+MathOptInterface.ConstraintIndex{MathOptInterface.VectorOfVariables, MathOptInterface.Path}(1)
source
MathOptInterface.ReifiedType
Reified(set::AbstractSet)

The constraint $[z; f(x)] \in Reified(S)$ ensures that $f(x) \in S$ if and only if $z == 1$, where $z \in \{0, 1\}$.

julia> import MathOptInterface as MOI
 
 julia> model = MOI.Utilities.UniversalFallback(MOI.Utilities.Model{Float64}())
 MOIU.UniversalFallback{MOIU.Model{Float64}}
@@ -856,7 +856,7 @@
            MOI.Utilities.vectorize([z, 2.0 * x]),
            MOI.Reified(MOI.GreaterThan(1.0)),
        )
-MathOptInterface.ConstraintIndex{MathOptInterface.VectorAffineFunction{Float64}, MathOptInterface.Reified{MathOptInterface.GreaterThan{Float64}}}(1)
source
MathOptInterface.TableType
Table(table::Matrix{T}) where {T}

The set $\{x \in \mathbb{R}^d\}$ where d = size(table, 2), such that x belongs to one row of table. That is, there exists some j in 1:size(table, 1), such that x[i] = table[j, i] for all i=1:size(table, 2).

Also known as

This constraint is called table in MiniZinc.

Example

julia> import MathOptInterface as MOI
+MathOptInterface.ConstraintIndex{MathOptInterface.VectorAffineFunction{Float64}, MathOptInterface.Reified{MathOptInterface.GreaterThan{Float64}}}(1)
source
MathOptInterface.TableType
Table(table::Matrix{T}) where {T}

The set $\{x \in \mathbb{R}^d\}$ where d = size(table, 2), such that x belongs to one row of table. That is, there exists some j in 1:size(table, 1), such that x[i] = table[j, i] for all i=1:size(table, 2).

Also known as

This constraint is called table in MiniZinc.

Example

julia> import MathOptInterface as MOI
 
 julia> model = MOI.Utilities.Model{Float64}()
 MOIU.Model{Float64}
@@ -875,7 +875,7 @@
  1.0  1.0  1.0
 
 julia> MOI.add_constraint(model, MOI.VectorOfVariables(x), MOI.Table(table))
-MathOptInterface.ConstraintIndex{MathOptInterface.VectorOfVariables, MathOptInterface.Table{Float64}}(1)
source

Matrix sets

Matrix sets are vectorized to be subtypes of AbstractVectorSet.

For sets of symmetric matrices, storing both the (i, j) and (j, i) elements is redundant. Use the AbstractSymmetricMatrixSetTriangle set to represent only the vectorization of the upper triangular part of the matrix.

When the matrix of expressions constrained to be in the set is not symmetric, and hence additional constraints are needed to force the equality of the (i, j) and (j, i) elements, use the AbstractSymmetricMatrixSetSquare set.

The Bridges.Constraint.SquareBridge can transform a set from the square form to the triangular_form by adding appropriate constraints if the (i, j) and (j, i) expressions are different.

MathOptInterface.AbstractSymmetricMatrixSetTriangleType
abstract type AbstractSymmetricMatrixSetTriangle <: AbstractVectorSet end

Abstract supertype for subsets of the (vectorized) cone of symmetric matrices, with side_dimension rows and columns. The entries of the upper-right triangular part of the matrix are given column by column (or equivalently, the entries of the lower-left triangular part are given row by row). A vectorized cone of dimension $n$ corresponds to a square matrix with side dimension $\sqrt{1/4 + 2 n} - 1/2$. (Because a $d \times d$ matrix has $d(d + 1) / 2$ elements in the upper or lower triangle.)

Example

The matrix

\[\begin{bmatrix} +MathOptInterface.ConstraintIndex{MathOptInterface.VectorOfVariables, MathOptInterface.Table{Float64}}(1)

source

Matrix sets

Matrix sets are vectorized to be subtypes of AbstractVectorSet.

For sets of symmetric matrices, storing both the (i, j) and (j, i) elements is redundant. Use the AbstractSymmetricMatrixSetTriangle set to represent only the vectorization of the upper triangular part of the matrix.

When the matrix of expressions constrained to be in the set is not symmetric, and hence additional constraints are needed to force the equality of the (i, j) and (j, i) elements, use the AbstractSymmetricMatrixSetSquare set.

The Bridges.Constraint.SquareBridge can transform a set from the square form to the triangular_form by adding appropriate constraints if the (i, j) and (j, i) expressions are different.

MathOptInterface.AbstractSymmetricMatrixSetTriangleType
abstract type AbstractSymmetricMatrixSetTriangle <: AbstractVectorSet end

Abstract supertype for subsets of the (vectorized) cone of symmetric matrices, with side_dimension rows and columns. The entries of the upper-right triangular part of the matrix are given column by column (or equivalently, the entries of the lower-left triangular part are given row by row). A vectorized cone of dimension $n$ corresponds to a square matrix with side dimension $\sqrt{1/4 + 2 n} - 1/2$. (Because a $d \times d$ matrix has $d(d + 1) / 2$ elements in the upper or lower triangle.)

Example

The matrix

\[\begin{bmatrix} 1 & 2 & 4\\ 2 & 3 & 5\\ 4 & 5 & 6 @@ -903,24 +903,24 @@ y_1 & y_2\\ y_2 & y_3 \end{pmatrix} -= 2y_2.\]

References

[1] Boyd, S. and Vandenberghe, L.. Convex optimization. Cambridge university press, 2004.

source
MathOptInterface.AbstractSymmetricMatrixSetSquareType
abstract type AbstractSymmetricMatrixSetSquare <: AbstractVectorSet end

Abstract supertype for subsets of the (vectorized) cone of symmetric matrices, with side_dimension rows and columns. The entries of the matrix are given column by column (or equivalently, row by row). The matrix is both constrained to be symmetric and to have its triangular_form belong to the corresponding set. That is, if the functions in entries $(i, j)$ and $(j, i)$ are different, then a constraint will be added to make sure that the entries are equal.

Example

PositiveSemidefiniteConeSquare is a subtype of AbstractSymmetricMatrixSetSquare and constraining the matrix

\[\begin{bmatrix} += 2y_2.\]

References

[1] Boyd, S. and Vandenberghe, L.. Convex optimization. Cambridge university press, 2004.

source
MathOptInterface.AbstractSymmetricMatrixSetSquareType
abstract type AbstractSymmetricMatrixSetSquare <: AbstractVectorSet end

Abstract supertype for subsets of the (vectorized) cone of symmetric matrices, with side_dimension rows and columns. The entries of the matrix are given column by column (or equivalently, row by row). The matrix is both constrained to be symmetric and to have its triangular_form belong to the corresponding set. That is, if the functions in entries $(i, j)$ and $(j, i)$ are different, then a constraint will be added to make sure that the entries are equal.

Example

PositiveSemidefiniteConeSquare is a subtype of AbstractSymmetricMatrixSetSquare and constraining the matrix

\[\begin{bmatrix} 1 & -y\\ -z & 0\\ -\end{bmatrix}\]

to be symmetric positive semidefinite can be achieved by constraining the vector $(1, -z, -y, 0)$ (or $(1, -y, -z, 0)$) to belong to the PositiveSemidefiniteConeSquare(2). It both constrains $y = z$ and $(1, -y, 0)$ (or $(1, -z, 0)$) to be in PositiveSemidefiniteConeTriangle(2), since triangular_form(PositiveSemidefiniteConeSquare) is PositiveSemidefiniteConeTriangle.

source
MathOptInterface.side_dimensionFunction
side_dimension(
+\end{bmatrix}\]

to be symmetric positive semidefinite can be achieved by constraining the vector $(1, -z, -y, 0)$ (or $(1, -y, -z, 0)$) to belong to the PositiveSemidefiniteConeSquare(2). It both constrains $y = z$ and $(1, -y, 0)$ (or $(1, -z, 0)$) to be in PositiveSemidefiniteConeTriangle(2), since triangular_form(PositiveSemidefiniteConeSquare) is PositiveSemidefiniteConeTriangle.

source

List of recognized matrix sets.

MathOptInterface.PositiveSemidefiniteConeSquareType
PositiveSemidefiniteConeSquare(side_dimension::Int) <: AbstractSymmetricMatrixSetSquare

The cone of symmetric positive semidefinite matrices, with non-negative side length side_dimension.

See AbstractSymmetricMatrixSetSquare for more details on the vectorized form.

The entries of the matrix are given column by column (or equivalently, row by row).

The matrix is both constrained to be symmetric and to be positive semidefinite. That is, if the functions in entries $(i, j)$ and $(j, i)$ are different, then a constraint will be added to make sure that the entries are equal.

Example

Constraining the matrix

\[\begin{bmatrix} +)

Side dimension of the matrices in set.

Convention

By convention, the side dimension should be stored in the side_dimension field. If this is not the case for a subtype of AbstractSymmetricMatrixSetTriangle, or AbstractSymmetricMatrixSetSquare you must implement this method.

source

List of recognized matrix sets.

MathOptInterface.PositiveSemidefiniteConeSquareType
PositiveSemidefiniteConeSquare(side_dimension::Int) <: AbstractSymmetricMatrixSetSquare

The cone of symmetric positive semidefinite matrices, with non-negative side length side_dimension.

See AbstractSymmetricMatrixSetSquare for more details on the vectorized form.

The entries of the matrix are given column by column (or equivalently, row by row).

The matrix is both constrained to be symmetric and to be positive semidefinite. That is, if the functions in entries $(i, j)$ and $(j, i)$ are different, then a constraint will be added to make sure that the entries are equal.

Example

Constraining the matrix

\[\begin{bmatrix} 1 & -y\\ -z & 0\\ -\end{bmatrix}\]

to be symmetric positive semidefinite can be achieved by constraining the vector $(1, -z, -y, 0)$ (or $(1, -y, -z, 0)$) to belong to the PositiveSemidefiniteConeSquare(2).

It both constrains $y = z$ and $(1, -y, 0)$ (or $(1, -z, 0)$) to be in PositiveSemidefiniteConeTriangle(2).

source
MathOptInterface.HermitianPositiveSemidefiniteConeTriangleType
HermitianPositiveSemidefiniteConeTriangle(side_dimension::Int) <: AbstractVectorSet

The (vectorized) cone of Hermitian positive semidefinite matrices, with non-negative side_dimension rows and columns.

Becaue the matrix is Hermitian, the diagonal elements are real, and the complex-valued lower triangular entries are obtained as the conjugate of corresponding upper triangular entries.

Vectorization format

The vectorized form starts with real part of the entries of the upper triangular part of the matrix, given column by column as explained in AbstractSymmetricMatrixSetSquare.

It is then followed by the imaginary part of the off-diagonal entries of the upper triangular part, also given column by column.

For example, the matrix

\[\begin{bmatrix} +\end{bmatrix}\]

to be symmetric positive semidefinite can be achieved by constraining the vector $(1, -z, -y, 0)$ (or $(1, -y, -z, 0)$) to belong to the PositiveSemidefiniteConeSquare(2).

It both constrains $y = z$ and $(1, -y, 0)$ (or $(1, -z, 0)$) to be in PositiveSemidefiniteConeTriangle(2).

source
MathOptInterface.HermitianPositiveSemidefiniteConeTriangleType
HermitianPositiveSemidefiniteConeTriangle(side_dimension::Int) <: AbstractVectorSet

The (vectorized) cone of Hermitian positive semidefinite matrices, with non-negative side_dimension rows and columns.

Becaue the matrix is Hermitian, the diagonal elements are real, and the complex-valued lower triangular entries are obtained as the conjugate of corresponding upper triangular entries.

Vectorization format

The vectorized form starts with real part of the entries of the upper triangular part of the matrix, given column by column as explained in AbstractSymmetricMatrixSetSquare.

It is then followed by the imaginary part of the off-diagonal entries of the upper triangular part, also given column by column.

For example, the matrix

\[\begin{bmatrix} 1 & 2 + 7im & 4 + 8im\\ 2 - 7im & 3 & 5 + 9im\\ 4 - 8im & 5 - 9im & 6 -\end{bmatrix}\]

has side_dimension 3 and is represented as the vector $[1, 2, 3, 4, 5, 6, 7, 8, 9]$.

source
MathOptInterface.LogDetConeTriangleType
LogDetConeTriangle(side_dimension::Int)

The log-determinant cone $\{ (t, u, X) \in \mathbb{R}^{2 + d(d+1)/2} : t \le u \log(\det(X/u)), u > 0 \}$, where the matrix X is represented in the same symmetric packed format as in the PositiveSemidefiniteConeTriangle.

The non-negative argument side_dimension is the side dimension of the matrix X, i.e., its number of rows or columns.

Example

julia> import MathOptInterface as MOI
+\end{bmatrix}\]

has side_dimension 3 and is represented as the vector $[1, 2, 3, 4, 5, 6, 7, 8, 9]$.

source
MathOptInterface.LogDetConeTriangleType
LogDetConeTriangle(side_dimension::Int)

The log-determinant cone $\{ (t, u, X) \in \mathbb{R}^{2 + d(d+1)/2} : t \le u \log(\det(X/u)), u > 0 \}$, where the matrix X is represented in the same symmetric packed format as in the PositiveSemidefiniteConeTriangle.

The non-negative argument side_dimension is the side dimension of the matrix X, i.e., its number of rows or columns.

Example

julia> import MathOptInterface as MOI
 
 julia> model = MOI.Utilities.Model{Float64}()
 MOIU.Model{Float64}
@@ -935,7 +935,7 @@
            MOI.VectorOfVariables([t; X]),
            MOI.LogDetConeTriangle(2),
        )
-MathOptInterface.ConstraintIndex{MathOptInterface.VectorOfVariables, MathOptInterface.LogDetConeTriangle}(1)
source
MathOptInterface.LogDetConeSquareType
LogDetConeSquare(side_dimension::Int)

The log-determinant cone $\{ (t, u, X) \in \mathbb{R}^{2 + d^2} : t \le u \log(\det(X/u)), X \text{ symmetric}, u > 0 \}$, where the matrix X is represented in the same format as in the PositiveSemidefiniteConeSquare.

Similarly to PositiveSemidefiniteConeSquare, constraints are added to ensure that X is symmetric.

The non-negative argument side_dimension is the side dimension of the matrix X, i.e., its number of rows or columns.

Example

julia> import MathOptInterface as MOI
+MathOptInterface.ConstraintIndex{MathOptInterface.VectorOfVariables, MathOptInterface.LogDetConeTriangle}(1)
source
MathOptInterface.LogDetConeSquareType
LogDetConeSquare(side_dimension::Int)

The log-determinant cone $\{ (t, u, X) \in \mathbb{R}^{2 + d^2} : t \le u \log(\det(X/u)), X \text{ symmetric}, u > 0 \}$, where the matrix X is represented in the same format as in the PositiveSemidefiniteConeSquare.

Similarly to PositiveSemidefiniteConeSquare, constraints are added to ensure that X is symmetric.

The non-negative argument side_dimension is the side dimension of the matrix X, i.e., its number of rows or columns.

Example

julia> import MathOptInterface as MOI
 
 julia> model = MOI.Utilities.Model{Float64}()
 MOIU.Model{Float64}
@@ -953,7 +953,7 @@
            MOI.VectorOfVariables([t; vec(X)]),
            MOI.LogDetConeSquare(2),
        )
-MathOptInterface.ConstraintIndex{MathOptInterface.VectorOfVariables, MathOptInterface.LogDetConeSquare}(1)
source
MathOptInterface.RootDetConeTriangleType
RootDetConeTriangle(side_dimension::Int)

The root-determinant cone $\{ (t, X) \in \mathbb{R}^{1 + d(d+1)/2} : t \le \det(X)^{1/d} \}$, where the matrix X is represented in the same symmetric packed format as in the PositiveSemidefiniteConeTriangle.

The non-negative argument side_dimension is the side dimension of the matrix X, i.e., its number of rows or columns.

Example

julia> import MathOptInterface as MOI
+MathOptInterface.ConstraintIndex{MathOptInterface.VectorOfVariables, MathOptInterface.LogDetConeSquare}(1)
source
MathOptInterface.RootDetConeTriangleType
RootDetConeTriangle(side_dimension::Int)

The root-determinant cone $\{ (t, X) \in \mathbb{R}^{1 + d(d+1)/2} : t \le \det(X)^{1/d} \}$, where the matrix X is represented in the same symmetric packed format as in the PositiveSemidefiniteConeTriangle.

The non-negative argument side_dimension is the side dimension of the matrix X, i.e., its number of rows or columns.

Example

julia> import MathOptInterface as MOI
 
 julia> model = MOI.Utilities.Model{Float64}()
 MOIU.Model{Float64}
@@ -968,7 +968,7 @@
            MOI.VectorOfVariables([t; X]),
            MOI.RootDetConeTriangle(2),
        )
-MathOptInterface.ConstraintIndex{MathOptInterface.VectorOfVariables, MathOptInterface.RootDetConeTriangle}(1)
source
MathOptInterface.RootDetConeSquareType
RootDetConeSquare(side_dimension::Int)

The root-determinant cone $\{ (t, X) \in \mathbb{R}^{1 + d^2} : t \le \det(X)^{1/d}, X \text{ symmetric} \}$, where the matrix X is represented in the same format as PositiveSemidefiniteConeSquare.

Similarly to PositiveSemidefiniteConeSquare, constraints are added to ensure that X is symmetric.

The non-negative argument side_dimension is the side dimension of the matrix X, i.e., its number of rows or columns.

Example

julia> import MathOptInterface as MOI
+MathOptInterface.ConstraintIndex{MathOptInterface.VectorOfVariables, MathOptInterface.RootDetConeTriangle}(1)
source
MathOptInterface.RootDetConeSquareType
RootDetConeSquare(side_dimension::Int)

The root-determinant cone $\{ (t, X) \in \mathbb{R}^{1 + d^2} : t \le \det(X)^{1/d}, X \text{ symmetric} \}$, where the matrix X is represented in the same format as PositiveSemidefiniteConeSquare.

Similarly to PositiveSemidefiniteConeSquare, constraints are added to ensure that X is symmetric.

The non-negative argument side_dimension is the side dimension of the matrix X, i.e., its number of rows or columns.

Example

julia> import MathOptInterface as MOI
 
 julia> model = MOI.Utilities.Model{Float64}()
 MOIU.Model{Float64}
@@ -986,4 +986,4 @@
            MOI.VectorOfVariables([t; vec(X)]),
            MOI.RootDetConeSquare(2),
        )
-MathOptInterface.ConstraintIndex{MathOptInterface.VectorOfVariables, MathOptInterface.RootDetConeSquare}(1)
source
+MathOptInterface.ConstraintIndex{MathOptInterface.VectorOfVariables, MathOptInterface.RootDetConeSquare}(1)source diff --git a/dev/reference/variables/index.html b/dev/reference/variables/index.html index 62e459af95..85d53077a0 100644 --- a/dev/reference/variables/index.html +++ b/dev/reference/variables/index.html @@ -1,24 +1,24 @@ -Variables · MathOptInterface

Variables

Functions

MathOptInterface.add_variablesFunction
add_variables(model::ModelLike, n::Int)::Vector{VariableIndex}

Add n scalar variables to the model, returning a vector of variable indices.

A AddVariableNotAllowed error is thrown if adding variables cannot be done in the current state of the model model.

source
MathOptInterface.add_constrained_variableFunction
add_constrained_variable(
+Variables · MathOptInterface

Variables

Functions

MathOptInterface.add_variablesFunction
add_variables(model::ModelLike, n::Int)::Vector{VariableIndex}

Add n scalar variables to the model, returning a vector of variable indices.

A AddVariableNotAllowed error is thrown if adding variables cannot be done in the current state of the model model.

source
MathOptInterface.add_constrained_variableFunction
add_constrained_variable(
     model::ModelLike,
     set::AbstractScalarSet
 )::Tuple{MOI.VariableIndex,
-         MOI.ConstraintIndex{MOI.VariableIndex, typeof(set)}}

Add to model a scalar variable constrained to belong to set, returning the index of the variable created and the index of the constraint constraining the variable to belong to set.

By default, this function falls back to creating a free variable with add_variable and then constraining it to belong to set with add_constraint.

source
MathOptInterface.add_constrained_variablesFunction
add_constrained_variables(
+         MOI.ConstraintIndex{MOI.VariableIndex, typeof(set)}}

Add to model a scalar variable constrained to belong to set, returning the index of the variable created and the index of the constraint constraining the variable to belong to set.

By default, this function falls back to creating a free variable with add_variable and then constraining it to belong to set with add_constraint.

source
MathOptInterface.add_constrained_variablesFunction
add_constrained_variables(
     model::ModelLike,
     sets::AbstractVector{<:AbstractScalarSet}
 )::Tuple{
     Vector{MOI.VariableIndex},
     Vector{MOI.ConstraintIndex{MOI.VariableIndex,eltype(sets)}},
-}

Add to model scalar variables constrained to belong to sets, returning the indices of the variables created and the indices of the constraints constraining the variables to belong to each set in sets. That is, if it returns variables and constraints, constraints[i] is the index of the constraint constraining variable[i] to belong to sets[i].

By default, this function falls back to calling add_constrained_variable on each set.

source
add_constrained_variables(
+}

Add to model scalar variables constrained to belong to sets, returning the indices of the variables created and the indices of the constraints constraining the variables to belong to each set in sets. That is, if it returns variables and constraints, constraints[i] is the index of the constraint constraining variable[i] to belong to sets[i].

By default, this function falls back to calling add_constrained_variable on each set.

source
add_constrained_variables(
     model::ModelLike,
     set::AbstractVectorSet,
 )::Tuple{
     Vector{MOI.VariableIndex},
     MOI.ConstraintIndex{MOI.VectorOfVariables,typeof(set)},
-}

Add to model a vector of variables constrained to belong to set, returning the indices of the variables created and the index of the constraint constraining the vector of variables to belong to set.

By default, this function falls back to creating free variables with add_variables and then constraining it to belong to set with add_constraint.

source
MathOptInterface.supports_add_constrained_variableFunction
supports_add_constrained_variable(
+}

Add to model a vector of variables constrained to belong to set, returning the indices of the variables created and the index of the constraint constraining the vector of variables to belong to set.

By default, this function falls back to creating free variables with add_variables and then constraining it to belong to set with add_constraint.

source
MathOptInterface.supports_add_constrained_variableFunction
supports_add_constrained_variable(
     model::ModelLike,
     S::Type{<:AbstractScalarSet}
-)::Bool

Return a Bool indicating whether model supports constraining a variable to belong to a set of type S either on creation of the variable with add_constrained_variable or after the variable is created with add_constraint.

By default, this function falls back to supports_add_constrained_variables(model, Reals) && supports_constraint(model, MOI.VariableIndex, S) which is the correct definition for most models.

Example

Suppose that a solver supports only two kind of variables: binary variables and continuous variables with a lower bound. If the solver decides not to support VariableIndex-in-Binary and VariableIndex-in-GreaterThan constraints, it only has to implement add_constrained_variable for these two sets which prevents the user to add both a binary constraint and a lower bound on the same variable. Moreover, if the user adds a VariableIndex-in-GreaterThan constraint, implementing this interface (i.e., supports_add_constrained_variables) enables the constraint to be transparently bridged into a supported constraint.

source
MathOptInterface.supports_add_constrained_variablesFunction
supports_add_constrained_variables(
+)::Bool

Return a Bool indicating whether model supports constraining a variable to belong to a set of type S either on creation of the variable with add_constrained_variable or after the variable is created with add_constraint.

By default, this function falls back to supports_add_constrained_variables(model, Reals) && supports_constraint(model, MOI.VariableIndex, S) which is the correct definition for most models.

Example

Suppose that a solver supports only two kind of variables: binary variables and continuous variables with a lower bound. If the solver decides not to support VariableIndex-in-Binary and VariableIndex-in-GreaterThan constraints, it only has to implement add_constrained_variable for these two sets which prevents the user to add both a binary constraint and a lower bound on the same variable. Moreover, if the user adds a VariableIndex-in-GreaterThan constraint, implementing this interface (i.e., supports_add_constrained_variables) enables the constraint to be transparently bridged into a supported constraint.

source
MathOptInterface.supports_add_constrained_variablesFunction
supports_add_constrained_variables(
     model::ModelLike,
     S::Type{<:AbstractVectorSet}
-)::Bool

Return a Bool indicating whether model supports constraining a vector of variables to belong to a set of type S either on creation of the vector of variables with add_constrained_variables or after the variable is created with add_constraint.

By default, if S is Reals then this function returns true and otherwise, it falls back to supports_add_constrained_variables(model, Reals) && supports_constraint(model, MOI.VectorOfVariables, S) which is the correct definition for most models.

Example

In the standard conic form (see Duality), the variables are grouped into several cones and the constraints are affine equality constraints. If Reals is not one of the cones supported by the solvers then it needs to implement supports_add_constrained_variables(::Optimizer, ::Type{Reals}) = false as free variables are not supported. The solvers should then implement supports_add_constrained_variables(::Optimizer, ::Type{<:SupportedCones}) = true where SupportedCones is the union of all cone types that are supported; it does not have to implement the method supports_constraint(::Type{VectorOfVariables}, Type{<:SupportedCones}) as it should return false and it's the default. This prevents the user to constrain the same variable in two different cones. When a VectorOfVariables-in-S is added, the variables of the vector have already been created so they already belong to given cones. If bridges are enabled, the constraint will therefore be bridged by adding slack variables in S and equality constraints ensuring that the slack variables are equal to the corresponding variables of the given constraint function.

Note that there may also be sets for which !supports_add_constrained_variables(model, S) and supports_constraint(model, MOI.VectorOfVariables, S). For instance, suppose a solver supports positive semidefinite variable constraints and two types of variables: binary variables and nonnegative variables. Then the solver should support adding VectorOfVariables-in-PositiveSemidefiniteConeTriangle constraints, but it should not support creating variables constrained to belong to the PositiveSemidefiniteConeTriangle because the variables in PositiveSemidefiniteConeTriangle should first be created as either binary or non-negative.

source
MathOptInterface.is_validMethod
is_valid(model::ModelLike, index::Index)::Bool

Return a Bool indicating whether this index refers to a valid object in the model model.

source
MathOptInterface.deleteMethod
delete(model::ModelLike, index::Index)

Delete the referenced object from the model. Throw DeleteNotAllowed if if index cannot be deleted.

The following modifications also take effect if Index is VariableIndex:

  • If index used in the objective function, it is removed from the function, i.e., it is substituted for zero.
  • For each func-in-set constraint of the model:
    • If func isa VariableIndex and func == index then the constraint is deleted.
    • If func isa VectorOfVariables and index in func.variables then
      • if length(func.variables) == 1 is one, the constraint is deleted;
      • if length(func.variables) > 1 and supports_dimension_update(set) then then the variable is removed from func and set is replaced by update_dimension(set, MOI.dimension(set) - 1).
      • Otherwise, a DeleteNotAllowed error is thrown.
    • Otherwise, the variable is removed from func, i.e., it is substituted for zero.
source
MathOptInterface.deleteMethod
delete(model::ModelLike, indices::Vector{R<:Index}) where {R}

Delete the referenced objects in the vector indices from the model. It may be assumed that R is a concrete type. The default fallback sequentially deletes the individual items in indices, although specialized implementations may be more efficient.

source

Attributes

MathOptInterface.VariableNameType
VariableName()

A variable attribute for a string identifying the variable. It is valid for two variables to have the same name; however, variables with duplicate names cannot be looked up using get. It has a default value of "" if not set`.

source
MathOptInterface.VariablePrimalStartType
VariablePrimalStart()

A variable attribute for the initial assignment to some primal variable's value that the optimizer may use to warm-start the solve. May be a number or nothing (unset).

source
MathOptInterface.VariablePrimalType
VariablePrimal(result_index::Int = 1)

A variable attribute for the assignment to some primal variable's value in result result_index. If result_index is omitted, it is 1 by default.

If the solver does not have a primal value for the variable because the result_index is beyond the available solutions (whose number is indicated by the ResultCount attribute), getting this attribute must throw a ResultIndexBoundsError. Otherwise, if the result is unavailable for another reason (for instance, only a dual solution is available), the result is undefined. Users should first check PrimalStatus before accessing the VariablePrimal attribute.

See ResultCount for information on how the results are ordered.

source
MathOptInterface.VariableBasisStatusType
VariableBasisStatus(result_index::Int = 1)

A variable attribute for the BasisStatusCode of a variable in result result_index, with respect to an available optimal solution basis.

If the solver does not have a basis statue for the variable because the result_index is beyond the available solutions (whose number is indicated by the ResultCount attribute), getting this attribute must throw a ResultIndexBoundsError. Otherwise, if the result is unavailable for another reason (for instance, only a dual solution is available), the result is undefined. Users should first check PrimalStatus before accessing the VariableBasisStatus attribute.

See ResultCount for information on how the results are ordered.

source
+)::Bool

Return a Bool indicating whether model supports constraining a vector of variables to belong to a set of type S either on creation of the vector of variables with add_constrained_variables or after the variable is created with add_constraint.

By default, if S is Reals then this function returns true and otherwise, it falls back to supports_add_constrained_variables(model, Reals) && supports_constraint(model, MOI.VectorOfVariables, S) which is the correct definition for most models.

Example

In the standard conic form (see Duality), the variables are grouped into several cones and the constraints are affine equality constraints. If Reals is not one of the cones supported by the solvers then it needs to implement supports_add_constrained_variables(::Optimizer, ::Type{Reals}) = false as free variables are not supported. The solvers should then implement supports_add_constrained_variables(::Optimizer, ::Type{<:SupportedCones}) = true where SupportedCones is the union of all cone types that are supported; it does not have to implement the method supports_constraint(::Type{VectorOfVariables}, Type{<:SupportedCones}) as it should return false and it's the default. This prevents the user to constrain the same variable in two different cones. When a VectorOfVariables-in-S is added, the variables of the vector have already been created so they already belong to given cones. If bridges are enabled, the constraint will therefore be bridged by adding slack variables in S and equality constraints ensuring that the slack variables are equal to the corresponding variables of the given constraint function.

Note that there may also be sets for which !supports_add_constrained_variables(model, S) and supports_constraint(model, MOI.VectorOfVariables, S). For instance, suppose a solver supports positive semidefinite variable constraints and two types of variables: binary variables and nonnegative variables. Then the solver should support adding VectorOfVariables-in-PositiveSemidefiniteConeTriangle constraints, but it should not support creating variables constrained to belong to the PositiveSemidefiniteConeTriangle because the variables in PositiveSemidefiniteConeTriangle should first be created as either binary or non-negative.

source
MathOptInterface.is_validMethod
is_valid(model::ModelLike, index::Index)::Bool

Return a Bool indicating whether this index refers to a valid object in the model model.

source
MathOptInterface.deleteMethod
delete(model::ModelLike, index::Index)

Delete the referenced object from the model. Throw DeleteNotAllowed if if index cannot be deleted.

The following modifications also take effect if Index is VariableIndex:

  • If index used in the objective function, it is removed from the function, i.e., it is substituted for zero.
  • For each func-in-set constraint of the model:
    • If func isa VariableIndex and func == index then the constraint is deleted.
    • If func isa VectorOfVariables and index in func.variables then
      • if length(func.variables) == 1 is one, the constraint is deleted;
      • if length(func.variables) > 1 and supports_dimension_update(set) then then the variable is removed from func and set is replaced by update_dimension(set, MOI.dimension(set) - 1).
      • Otherwise, a DeleteNotAllowed error is thrown.
    • Otherwise, the variable is removed from func, i.e., it is substituted for zero.
source
MathOptInterface.deleteMethod
delete(model::ModelLike, indices::Vector{R<:Index}) where {R}

Delete the referenced objects in the vector indices from the model. It may be assumed that R is a concrete type. The default fallback sequentially deletes the individual items in indices, although specialized implementations may be more efficient.

source

Attributes

MathOptInterface.VariableNameType
VariableName()

A variable attribute for a string identifying the variable. It is valid for two variables to have the same name; however, variables with duplicate names cannot be looked up using get. It has a default value of "" if not set`.

source
MathOptInterface.VariablePrimalStartType
VariablePrimalStart()

A variable attribute for the initial assignment to some primal variable's value that the optimizer may use to warm-start the solve. May be a number or nothing (unset).

source
MathOptInterface.VariablePrimalType
VariablePrimal(result_index::Int = 1)

A variable attribute for the assignment to some primal variable's value in result result_index. If result_index is omitted, it is 1 by default.

If the solver does not have a primal value for the variable because the result_index is beyond the available solutions (whose number is indicated by the ResultCount attribute), getting this attribute must throw a ResultIndexBoundsError. Otherwise, if the result is unavailable for another reason (for instance, only a dual solution is available), the result is undefined. Users should first check PrimalStatus before accessing the VariablePrimal attribute.

See ResultCount for information on how the results are ordered.

source
MathOptInterface.VariableBasisStatusType
VariableBasisStatus(result_index::Int = 1)

A variable attribute for the BasisStatusCode of a variable in result result_index, with respect to an available optimal solution basis.

If the solver does not have a basis statue for the variable because the result_index is beyond the available solutions (whose number is indicated by the ResultCount attribute), getting this attribute must throw a ResultIndexBoundsError. Otherwise, if the result is unavailable for another reason (for instance, only a dual solution is available), the result is undefined. Users should first check PrimalStatus before accessing the VariableBasisStatus attribute.

See ResultCount for information on how the results are ordered.

source
diff --git a/dev/release_notes/index.html b/dev/release_notes/index.html index 0fcad860fb..bb8bc3b3ce 100644 --- a/dev/release_notes/index.html +++ b/dev/release_notes/index.html @@ -27,4 +27,4 @@ end write(path, s) end -end

v0.9.22 (May 22, 2021)

This release contains backports from the ongoing development of the v0.10 release.

  • Improved type inference in Utilities, Bridges and FileFormats submodules to reduce latency.
  • Improved performance of Utilities.is_canonical.
  • Fixed Utilities.pass_nonvariable_constraints with bridged variables.
  • Fixed performance regression of Utilities.Model.
  • Fixed ordering of objective setting in parser.

v0.9.21 (April 23, 2021)

  • Added supports_shift_constant.
  • Improve performance of bridging quadratic constraints.
  • Add precompilation statements.
  • Large improvements to the documentation.
  • Fix a variety of inference issues, benefiting precompilation and reducing initial latency.
  • RawParameters are now ignored when resetting a CachingOptimizer. Previously, changing the underlying optimizer after RawParameters were set would throw an error.
  • Utilities.AbstractModel is being refactored. This may break users interacting with private fields of a model generated using @model.

v0.9.20 (February 20, 2021)

  • Improved performance of Utilities.ScalarFunctionIterator
  • Added support for compute_conflict to MOI layers
  • Added test with zero off-diagonal quadratic term in objective
  • Fixed double deletion of nested bridged SingleVariable/VectorOfVariables constraints
  • Fixed modification of un-set objective
  • Fixed function modification with duplicate terms
  • Made unit tests abort without failing if the problem class is not supported
  • Formatted code with JuliaFormatter
  • Clarified BasisStatusCode's docstring

v0.9.19 (December 1, 2020)

  • Added CallbackNodeStatus attribute
  • Added bridge from GreaterThan or LessThan to Interval
  • Added tests for infeasibility certificates and double optimize
  • Fixed support for Julia v1.6
  • Re-organized MOI docs and added documentation for adding a test

v0.9.18 (November 3, 2020)

  • Various improvements for working with complex numbers
  • Added GeoMeantoRelEntrBridge to bridge a GeometricMeanCone constraint to a relative entropy constraint

v0.9.17 (September 21, 2020)

  • Fixed CleverDict with variable of negative index value
  • Implement supports_add_constrained_variable for MockOptimizer

v0.9.16 (September 17, 2020)

  • Various fixes:
    • 32-bit support
    • CleverDict with abstract value type
    • Checks in test suite

v0.9.15 (September 14, 2020)

  • Bridges improvements:
    • (R)SOCtoNonConvexQuad bridge
    • ZeroOne bridge
    • Use supports_add_constrained_variable in LazyBridgeOptimizer
    • Exposed VariableBridgeCost and ConstraintBridgeCost attributes
    • Prioritize constraining variables on creation according to these costs
    • Refactor bridge debugging
  • Large performance improvements across all submodules
  • Lots of documentation improvements
  • FileFormats improvements:
    • Update MathOptFormat to v0.5
    • Fix supported objectives in FileFormats
  • Testing improvements:
    • Add name option for basic_constraint_test
  • Bug fixes and missing methods
    • Add length for iterators
    • Fix bug with duplicate terms
    • Fix order of LinearOfConstraintIndices

v0.9.14 (May 30, 2020)

  • Add a solver-independent interface for accessing the set of conflicting constraints an Irreducible Inconsistent Subsystem (#1056).
  • Bump JSONSchema dependency from v0.2 to v0.3 (#1090).
  • Documentation improvements:
    • Fix typos (#1054, #1060, #1061, #1064, #1069, #1070).
    • Remove the outdated recommendation for a package implementing MOI for a solver XXX to be called MathOptInterfaceXXX (#1087).
  • Utilities improvements:
    • Fix is_canonical for quadratic functions (#1081, #1089).
    • Implement add_constrained_variable[s] for CachingOptimizer so that it is added as constrained variables to the underlying optimizer (#1084).
    • Add support for custom objective functions for UniversalFallback (#1086).
    • Deterministic ordering of constraints in UniversalFallback (#1088).
  • Testing improvements:
    • Add NormOneCone/NormInfinityCone tests (#1045).
  • Bridges improvements:
    • Add bridges from Semiinteger and Semicontinuous (#1059).
    • Implement getting ConstraintSet for Variable.FlipSignBridge (#1066).
    • Fix setting ConstraintFunction for Constraint.ScalarizeBridge (#1093).
    • Fix NormOne/NormInf bridges with nonzero constants (#1045).
    • Fix StackOverflow in debug (#1063).
  • FileFormats improvements:
    • [SDPA] Implement the extension for integer variables (#1079).
    • [SDPA] Ignore comments after m and nblocks and detect dat-s extension (#1077).
    • [SDPA] No scaling of off-diagonal coefficient (#1076).
    • [SDPA] Add missing negation of constant (#1075).

v0.9.13 (March 24, 2020)

  • Added tests for Semicontinuous and Semiinteger variables (#1033).
  • Added tests for using ExprGraphs from NLP evaluators (#1043).
  • Update version compatibilities of dependencies (#1034, #1051, #1052).
  • Fixed typos in documentation (#1044).

v0.9.12 (February 28, 2020)

  • Fixed writing NLPBlock in MathOptFormat (#1037).
  • Fixed MockOptimizer for result attributes with non-one result index (#1039).
  • Updated test template with instantiate (#1032).

v0.9.11 (February 21, 2020)

  • Add an option for the model created by Utilities.@model to be a subtype of AbstractOptimizer (#1031).
  • Described dual cone in docstrings of GeoMeanCone and RelativeEntropyCone (#1018, #1028).
  • Fixed typos in documentation (#1022, #1024).
  • Fixed warning of unsupported attribute (#1027).
  • Added more rootdet/logdet conic tests (#1026).
  • Implemented ConstraintDual for Constraint.GeoMeanBridge, Constraint.RootDetBridge and Constraint.LogDetBridge and test duals in tests with GeoMeanCone and RootDetConeTriangle and LogDetConeTriangle cones (#1025, #1026).

v0.9.10 (January 31, 2020)

  • Added OptimizerWithAttributes grouping an optimizer constructor and a list of optimizer attributes (#1008).
  • Added RelativeEntropyCone with corresponding bridge into exponential cone constraints (#993).
  • Added NormSpectralCone and NormNuclearCone with corresponding bridges into positive semidefinite constraints (#976).
  • Added supports_constrained_variable(s) (#1004).
  • Added dual_set_type (#1002).
  • Added tests for vector specialized version of delete (#989, #1011).
  • Added PSD3 test (#1007).
  • Clarified dual solution of Tests.pow1v and Tests.pow1f (#1013).
  • Added support for EqualTo and Zero in Bridges.Constraint.SplitIntervalBridge (#1005).
  • Fixed Utilities.vectorize for empty vector (#1003).
  • Fixed free variables in LP writer (#1006).

v0.9.9 (December 29, 2019)

  • Incorporated MathOptFormat.jl as the FileFormats submodule. FileFormats provides readers and writers for a number of standard file formats and MOF, a file format specialized for MOI (#969).
  • Improved performance of deletion of vector of variables in MOI.Utilities.Model (#983).
  • Updated to MutableArithmetics v0.2 (#981).
  • Added MutableArithmetics.promote_operation allocation tests (#975).
  • Fixed inference issue on Julia v1.1 (#982).

v0.9.8 (December 19, 2019)

  • Implemented MutableArithmetics API (#924).
  • Fixed callbacks with CachingOptimizer (#959).
  • Fixed MOI.dimension for MOI.Complements (#948).
  • Added fallback for add_variables (#972).
  • Added is_diagonal_vectorized_index utility (#965).
  • Improved linear constraints display in manual (#963, #964).
  • Bridges improvements:
    • Added IndicatorSet to SOS1 bridge (#877).
    • Added support for starting values for Variable.VectorizeBridge (#944).
    • Fixed MOI.add_constraints with non-bridged variable constraint on bridged variable (#951).
    • Fixed corner cases and docstring of GeoMeanBridge (#961, #962, #966).
    • Fixed choice between variable or constraint bridges for constrained variables (#973).
    • Improve performance of bridge shortest path (#945, #946, #956).
    • Added docstring for test_delete_bridge (#954).
    • Added Variable bridge tests (#952).

v0.9.7 (October 30, 2019)

  • Implemented _result_index_field for NLPBlockDual (#934).
  • Fixed copy of model with starting values for vector constraints (#941).
  • Bridges improvements:
    • Improved performance of add_bridge and added has_bridge (#935).
    • Added AbstractSetMapBridge for bridges between sets S1, S2 such that there is a linear map A such that A*S1 = S2 (#933).
    • Added support for starting values for FlipSignBridge, VectorizeBridge, ScalarizeBridge, SlackBridge, SplitIntervalBridge, RSOCBridge, SOCRBridge NormInfinityBridge, SOCtoPSDBridge and RSOCtoPSDBridge (#933, #936, #937, #938, #939).

v0.9.6 (October 25, 2019)

  • Added complementarity constraints (#913).
  • Allowed ModelLike objects as value of attributes (#928).
  • Testing improvements:
    • Added dual_objective_value option to MOI.Test.TestConfig (#922).
    • Added InvalidIndex tests in basic_constraint_tests (#921).
    • Added tests for the constant term in indicator constraint (#929).
  • Bridges improvements:
    • Added support for starting values for Functionize bridges (#923).
    • Added variable indices context to variable bridges (#920).
    • Fixed a typo in printing o debug_supports (#927).

v0.9.5 (October 9, 2019)

  • Clarified PrimalStatus/DualStatus to be NO_SOLUTION if result_index is out of bounds (#912).
  • Added tolerance for checks and use ResultCount + 1 for the result_index in MOI.Test.solve_result_status (#910, #917).
  • Use 0.5 instead of 2.0 for power in PowerCone in basic_constraint_test (#916).
  • Bridges improvements:
    • Added debug utilities for unsupported variable/constraint/objective (#861).
    • Fixed deletion of variables in bridged VectorOfVariables constraints (#909).
    • Fixed result_index with objective bridges (#911).

v0.9.4 (October 2, 2019)

  • Added solver-independent MIP callbacks (#782).
  • Implements submit for Utilities.CachingOptimizer and Bridges.AbstractBridgeOptimizer (#906).
  • Added tests for result count of solution attributes (#901, #904).
  • Added NumberOfThreads attribute (#892).
  • Added Utilities.get_bounds to get the bounds on a variable (#890).
  • Added a note on duplicate coefficients in documentation (#581).
  • Added result index in ConstraintBasisStatus (#898).
  • Added extension dictionary to Utilities.Model (#884, #895).
  • Fixed deletion of constrained variables for CachingOptimizer (#905).
  • Implemented Utilities.shift_constraint for Test.UnknownScalarSet (#896).
  • Bridges improvements:
    • Added Variable.RSOCtoSOCBridge (#907).
    • Implemented MOI.get for ConstraintFunction/ConstraintSet for Bridges.Constraint.SquareBridge (#899).

v0.9.3 (September 20, 2019)

  • Fixed ambiguity detected in Julia v1.3 (#891, #893).
  • Fixed missing sets from ListOfSupportedConstraints (#880).
  • Fixed copy of VectorOfVariables constraints with duplicate indices (#886).
  • Added extension dictionary to MOIU.Model (#884).
  • Implemented MOI.get for function and set for GeoMeanBridge (#888).
  • Updated documentation for SingleVariable indices and bridges (#885).
  • Testing improvements:
    • Added more comprehensive tests for names (#882).
    • Added tests for SingleVariable duals (#883).
    • Added tests for DualExponentialCone and DualPowerCone (#873).
  • Improvements for arbitrary coefficient type:
    • Fixed == for sets with mutable fields (#887).
    • Removed some Float64 assumptions in bridges (#878).
    • Automatic selection of Constraint.[Scalar|Vector]FunctionizeBridge (#889).

v0.9.2 (September 5, 2019)

  • Implemented model printing for MOI.ModelLike and specialized it for models defined in MOI (864).
  • Generalized contlinear tests for arbitrary coefficient type (#855).
  • Fixed supports_constraint for Semiinteger and Semicontinuous and supports for ObjectiveFunction (#859).
  • Fixed Allocate-Load copy for single variable constraints (#856).
  • Bridges improvements:
    • Add objective bridges (#789).
    • Fixed Variable.RSOCtoPSDBridge for dimension 2 (#869).
    • Added Variable.SOCtoRSOCBridge (#865).
    • Added Constraint.SOCRBridge and disable MOI.Bridges.Constraint.SOCtoPSDBridge (#751).
    • Fixed added_constraint_types for Contraint.LogDetBridge and Constraint.RootDetBridge (#870).

v0.9.1 (August 22, 2019)

  • Fix support for Julia v1.2 (#834).
  • L1 and L∞ norm epigraph cones and corresponding bridges to LP were added (#818).
  • Added tests to MOI.Test.nametest (#833).
  • Fix MOI.Test.soc3test for solvers not supporting infeasibility certificates (#839).
  • Implements operate for operators * and / between vector function and constant (#837).
  • Implements show for MOI.Utilities.IndexMap (#847).
  • Fix corner cases for mapping of variables in MOI.Utilities.CachingOptimizer and substitution of variables in MOI.Bridges.AbstractBridgeOptimizer (#848).
  • Fix transformation of constant terms for MOI.Bridges.Constraint.SOCtoPSDBridge and MOI.Bridges.Constraint.RSOCtoPSDBridge (#840).

v0.9.0 (August 13, 2019)

  • Support for Julia v0.6 and v0.7 was dropped (#714, #717).
  • A MOI.Utilities.Model implementation of ModelLike, this should replace most use cases of MOI.Utilities.@model (#781).
  • add_constrained_variable and add_constrained_variables were added (#759).
  • Support for indicator constraints was added (#709, #712).
  • DualObjectiveValue attribute was added (#473).
  • RawParameter attribute was added (#733).
  • A dual_set function was added (#804).
  • A Benchmarks submodule was added to facilitate solver benchmarking (#769).
  • A submit function was added, this may for instance allow the user to submit solutions or cuts to the solver from a callback (#775).
  • The field of ObjectiveValue was renamed to result_index (#729).
  • The _constant and Utilities.getconstant function were renamed to constant
  • REDUCTION_CERTIFICATE result status was added (#734).
  • Abstract matrix sets were added (#731).
  • Testing improvements:
    • The testing guideline was updated (#728).
    • Quadratic tests were added (#697).
    • Unit tests for RawStatusString, SolveTime, Silent and SolverName were added (#726, #741).
    • A rotated second-order cone test was added (#759).
    • A power cone test was added (#768).
    • Tests for ZeroOne variables with variable bounds were added (#772).
    • An unbounded test was added (#773).
    • Existing tests had a few updates (#702, #703, #763).
  • Documentation improvements:
    • Added a section on CachingOptimizer (#777).
    • Added a section on UniversalFallback, Model and @model (#762).
    • Transition the knapsack example to a doctest with MockOptimizer (#786).
  • Utilities improvements:
    • A CleverDict utility was added for a vector that automatically transform into a dictionary once a first index is removed (#767).
    • The Utilities.constant function was renamed to Utilities.constant_vector (#740).
    • Implement optimizer attributes for CachingOptimizer (#745).
    • Rename Utilities.add_scalar_constraint to Utilities.normalize_and_add_constraint (#801).
    • operate with vcat, SingleVariable and VectorOfVariables now returns a VectorOfVariables (#616).
    • Fix a type piracy of operate (#784).
    • The load_constraint fallback signature was fixed (#760).
    • The set_dot function was extended to work with sparse arrays (#805).
  • Bridges improvements:
    • The bridges no longer store the constraint function and set before it is bridged, the bridges now have to implement ConstraintFunction and ConstraintSet if the user wants to recover them. As a consequence, the @bridge macro was removed (#722).
    • Bridge are now instantiated with a bridge_constraint function instead of using a constructor (#730).
    • Fix constraint attributes for bridges (#699).
    • Constraint bridges were moved to the Bridges/Constraint submodule so they should now inherit from MOI.Bridges.Constraint.Abstract and should implement MOI.Bridges.Constraint.concrete_bridge_type instead of MOI.Bridges.concrete_bridge_type (#756).
    • Variable bridges were added in (#759).
    • Various improvements (#746, #747).

v0.8.4 (March 13, 2019)

  • Performance improvement in default_copy_to and bridge optimizer (#696).
  • Add Silent and implement setting optimizer attributes in caching and mock optimizers (#695).
  • Add Functionize bridges (SingleVariable and VectorOfVariables) (#659).
  • Minor typo fixes (#694).

v0.8.3 (March 6, 2019)

  • Use zero constant in scalar constraint function of MOI.Test.copytest (#691).
  • Fix variable deletion with SingleVariable objective function (#690).
  • Fix LazyBridgeOptimizer with bridges that add no constraints (#689).
  • Error message improvements (#673, #685, #686, #688).
  • Documentation improvements (#682, #683, #687).
  • Basis status:
    • Remove VariableBasisStatus (#679).
    • Test ConstraintBasisStatus and implement it in bridges (#678).
  • Fix inference of NumberOfVariables and NumberOfConstraints (#677).
  • Implement division between a quadratic function and a number (#675).

v0.8.2 (February 7, 2019)

  • Add RawStatusString attribute (#629).
  • Do not set names to the optimizer but only to the cache in CachingOptimizer (#638).
  • Make scalar MOI functions act as scalars in broadcast (#646).
  • Add function utilities:
    • Implement Base.zero (#634), Base.iszero (#643), add missing arithmetic operations (#644, #645) and fix division (#648).
    • Add a vectorize function that turns a vector of ScalarAffineFunction into a VectorAffineFunction (#642).
  • Improve support for starting values:
    • Show a warning in copy when starting values are not supported instead of throwing an error (#630).
    • Fix UniversalFallback for getting an variable or constraint attribute set to no indices (#623).
    • Add a test in contlineartest with partially set VariablePrimalStart.
  • Bridges improvements:
    • Fix StackOverFlow in LazyBridgeOptimizer when there is a cycle in the graph of bridges.
    • Add Slack bridges (#610, #650).
    • Add FlipSign bridges (#658).
  • Add tests with duplicate coefficients in ScalarAffineFunction and VectorAffineFunction (#639).
  • Use tolerance to compare VariablePrimal in rotatedsoc1 test (#632).
  • Use a zero constant in ScalarAffineFunction of constraints in psdt2 (#622).

v0.8.1 (January 7, 2019)

  • Adding an NLP objective now overrides any objective set using the ObjectiveFunction attribute (#619).
  • Rename fullbridgeoptimizer into full_bridge_optimizer (#621).
  • Allow custom constraint types with full_bridge_optimizer (#617).
  • Add Vectorize bridge which transforms scalar linear constraints into vector linear constraints (#615).

v0.8.0 (December 18, 2018)

  • Rename all enum values to follow the JuMP naming guidelines for constants, for example, Optimal becomes OPTIMAL, and DualInfeasible becomes DUAL_INFEASIBLE.
  • Rename CachingOptimizer methods for style compliance.
  • Add an MOI.TerminationStatusCode called ALMOST_DUAL_INFEASIBLE.

v0.7.0 (December 13, 2018)

  • Test that MOI.TerminationStatus is MOI.OptimizeNotCalled before MOI.optimize! is called.
  • Check supports_default_copy_to in tests (#594).
  • Key pieces of information like optimality, infeasibility, etc., are now reported through TerminationStatusCode. It is typically no longer necessary to check the result statuses in addition to the termination status.
  • Add perspective dimension to log-det cone (#593).

v0.6.4 (November 27, 2018)

  • Add OptimizeNotCalled termination status (#577) and improve documentation of other statuses (#575).
  • Add a solver naming guideline (#578).
  • Make FeasibilitySense the default ObjectiveSense (#579).
  • Fix Utilities.@model and Bridges.@bridge macros for functions and sets defined outside MOI (#582).
  • Document solver-specific attributes (#580) and implement them in Utilities.CachingOptimizer (#565).

v0.6.3 (November 16, 2018)

  • Variables and constraints are now allowed to have duplicate names. An error is thrown only on lookup. This change breaks some existing tests. (#549)
  • Attributes may now be partially set (some values could be nothing). (#563)
  • Performance improvements in Utilities.Model (#549, #567, #568)
  • Fix bug in QuadtoSOC (#558).
  • New supports_default_copy_to method that optimizers should implement to control caching behavior.
  • Documentation improvements.

v0.6.2 (October 26, 2018)

  • Improve hygiene of @model macro (#544).
  • Fix bug in copy tests (#543).
  • Fix bug in UniversalFallback attribute getter (#540).
  • Allow all correct solutions for solve_blank_obj unit test (#537).
  • Add errors for Allocate-Load and bad constraints (#534).
  • [performance] Add specialized implementation of hash for VariableIndex (#533).
  • [performance] Construct the name to object dictionaries lazily in model (#535).
  • Add the QuadtoSOC bridge which transforms ScalarQuadraticFunction constraints into RotatedSecondOrderCone (#483).

v0.6.1 (September 22, 2018)

  • Enable PositiveSemidefiniteConeSquare set and quadratic functions in MOIB.fullbridgeoptimizer (#524).
  • Add warning in the bridge between PositiveSemidefiniteConeSquare and PositiveSemidefiniteConeTriangle when the matrix is almost symmetric (#522).
  • Modify MOIT.copytest to not add multiples constraints on the same variable (#521).
  • Add missing keyword argument in one of MOIU.add_scalar_constraint methods (#520).

v0.6.0 (August 30, 2018)

  • The MOIU.@model and MOIB.@bridge macros now support functions and sets defined in external modules. As a consequence, function and set names in the macro arguments need to be prefixed by module name.
  • Rename functions according to the JuMP style guide:
    • copy! with keyword arguments copynames and warnattributes -> copy_to with keyword arguments copy_names and warn_attributes;
    • set! -> set;
    • addvariable[s]! -> add_variable[s];
    • supportsconstraint -> supports_constraint;
    • addconstraint[s]! -> add_constraint[s];
    • isvalid -> is_valid;
    • isempty -> is_empty;
    • Base.delete! -> delete;
    • modify! -> modify;
    • transform! -> transform;
    • initialize! -> initialize;
    • write -> write_to_file; and
    • read! -> read_from_file.
  • Remove free! (use Base.finalize instead).
  • Add the SquarePSD bridge which transforms PositiveSemidefiniteConeTriangle constraints into PositiveSemidefiniteConeTriangle.
  • Add result fallback for ConstraintDual of variable-wise constraint, ConstraintPrimal and ObjectiveValue.
  • Add tests for ObjectiveBound.
  • Add test for empty rows in vector linear constraint.
  • Rework errors: CannotError has been renamed NotAllowedError and the distinction between UnsupportedError and NotAllowedError is now about whether the element is not supported (for example, it cannot be copied a model containing this element) or the operation is not allowed (either because it is not implemented, because it cannot be performed in the current state of the model, or because it cannot be performed for a specific index)
  • canget is removed. NoSolution is added as a result status to indicate that the solver does not have either a primal or dual solution available (See #479).

v0.5.0 (August 5, 2018)

  • Fix names with CachingOptimizer.
  • Cleanup thanks to @mohamed82008.
  • Added a universal fallback for constraints.
  • Fast utilities for function canonicalization thanks to @rdeits.
  • Renamed dimension field to side_dimension in the context of matrix-like sets.
  • New and improved tests for cases like duplicate terms and ObjectiveBound.
  • Removed cantransform, canaddconstraint, canaddvariable, canset, canmodify, and candelete functions from the API. They are replaced by a new set of errors that are thrown: Subtypes of UnsupportedError indicate unsupported operations, while subtypes of CannotError indicate operations that cannot be performed in the current state.
  • The API for copy! is updated to remove the CopyResult type.
  • Updates for the new JuMP style guide.

v0.4.1 (June 28, 2018)

  • Fixes vector function modification on 32 bits.
  • Fixes Bellman-Ford algorithm for bridges.
  • Added an NLP test with FeasibilitySense.
  • Update modification documentation.

v0.4.0 (June 23, 2018)

  • Helper constructors for VectorAffineTerm and VectorQuadraticTerm.
  • Added modify_lhs to TestConfig.
  • Additional unit tests for optimizers.
  • Added a type parameter to CachingOptimizer for the optimizer field.
  • New API for problem modification (#388)
  • Tests pass without deprecation warnings on Julia 0.7.
  • Small fixes and documentation updates.

v0.3.0 (May 25, 2018)

  • Functions have been redefined to use arrays-of-structs instead of structs-of-arrays.
  • Improvements to MockOptimizer.
  • Significant changes to Bridges.
  • New and improved unit tests.
  • Fixes for Julia 0.7.

v0.2.0 (April 24, 2018)

  • Improvements to and better coverage of Tests.
  • Documentation fixes.
  • SolverName attribute.
  • Changes to the NLP interface (new definition of variable order and arrays of structs for bound pairs and sparsity patterns).
  • Addition of NLP tests.
  • Introduction of UniversalFallback.
  • copynames keyword argument to MOI.copy!.
  • Add Bridges submodule.

v0.1.0 (February 28, 2018)

  • Initial public release.
  • The framework for MOI was developed at the JuMP-dev workshop at MIT in June 2017 as a sorely needed replacement for MathProgBase.
+end

v0.9.22 (May 22, 2021)

This release contains backports from the ongoing development of the v0.10 release.

  • Improved type inference in Utilities, Bridges and FileFormats submodules to reduce latency.
  • Improved performance of Utilities.is_canonical.
  • Fixed Utilities.pass_nonvariable_constraints with bridged variables.
  • Fixed performance regression of Utilities.Model.
  • Fixed ordering of objective setting in parser.

v0.9.21 (April 23, 2021)

  • Added supports_shift_constant.
  • Improve performance of bridging quadratic constraints.
  • Add precompilation statements.
  • Large improvements to the documentation.
  • Fix a variety of inference issues, benefiting precompilation and reducing initial latency.
  • RawParameters are now ignored when resetting a CachingOptimizer. Previously, changing the underlying optimizer after RawParameters were set would throw an error.
  • Utilities.AbstractModel is being refactored. This may break users interacting with private fields of a model generated using @model.

v0.9.20 (February 20, 2021)

  • Improved performance of Utilities.ScalarFunctionIterator
  • Added support for compute_conflict to MOI layers
  • Added test with zero off-diagonal quadratic term in objective
  • Fixed double deletion of nested bridged SingleVariable/VectorOfVariables constraints
  • Fixed modification of un-set objective
  • Fixed function modification with duplicate terms
  • Made unit tests abort without failing if the problem class is not supported
  • Formatted code with JuliaFormatter
  • Clarified BasisStatusCode's docstring

v0.9.19 (December 1, 2020)

  • Added CallbackNodeStatus attribute
  • Added bridge from GreaterThan or LessThan to Interval
  • Added tests for infeasibility certificates and double optimize
  • Fixed support for Julia v1.6
  • Re-organized MOI docs and added documentation for adding a test

v0.9.18 (November 3, 2020)

  • Various improvements for working with complex numbers
  • Added GeoMeantoRelEntrBridge to bridge a GeometricMeanCone constraint to a relative entropy constraint

v0.9.17 (September 21, 2020)

  • Fixed CleverDict with variable of negative index value
  • Implement supports_add_constrained_variable for MockOptimizer

v0.9.16 (September 17, 2020)

  • Various fixes:
    • 32-bit support
    • CleverDict with abstract value type
    • Checks in test suite

v0.9.15 (September 14, 2020)

  • Bridges improvements:
    • (R)SOCtoNonConvexQuad bridge
    • ZeroOne bridge
    • Use supports_add_constrained_variable in LazyBridgeOptimizer
    • Exposed VariableBridgeCost and ConstraintBridgeCost attributes
    • Prioritize constraining variables on creation according to these costs
    • Refactor bridge debugging
  • Large performance improvements across all submodules
  • Lots of documentation improvements
  • FileFormats improvements:
    • Update MathOptFormat to v0.5
    • Fix supported objectives in FileFormats
  • Testing improvements:
    • Add name option for basic_constraint_test
  • Bug fixes and missing methods
    • Add length for iterators
    • Fix bug with duplicate terms
    • Fix order of LinearOfConstraintIndices

v0.9.14 (May 30, 2020)

  • Add a solver-independent interface for accessing the set of conflicting constraints an Irreducible Inconsistent Subsystem (#1056).
  • Bump JSONSchema dependency from v0.2 to v0.3 (#1090).
  • Documentation improvements:
    • Fix typos (#1054, #1060, #1061, #1064, #1069, #1070).
    • Remove the outdated recommendation for a package implementing MOI for a solver XXX to be called MathOptInterfaceXXX (#1087).
  • Utilities improvements:
    • Fix is_canonical for quadratic functions (#1081, #1089).
    • Implement add_constrained_variable[s] for CachingOptimizer so that it is added as constrained variables to the underlying optimizer (#1084).
    • Add support for custom objective functions for UniversalFallback (#1086).
    • Deterministic ordering of constraints in UniversalFallback (#1088).
  • Testing improvements:
    • Add NormOneCone/NormInfinityCone tests (#1045).
  • Bridges improvements:
    • Add bridges from Semiinteger and Semicontinuous (#1059).
    • Implement getting ConstraintSet for Variable.FlipSignBridge (#1066).
    • Fix setting ConstraintFunction for Constraint.ScalarizeBridge (#1093).
    • Fix NormOne/NormInf bridges with nonzero constants (#1045).
    • Fix StackOverflow in debug (#1063).
  • FileFormats improvements:
    • [SDPA] Implement the extension for integer variables (#1079).
    • [SDPA] Ignore comments after m and nblocks and detect dat-s extension (#1077).
    • [SDPA] No scaling of off-diagonal coefficient (#1076).
    • [SDPA] Add missing negation of constant (#1075).

v0.9.13 (March 24, 2020)

  • Added tests for Semicontinuous and Semiinteger variables (#1033).
  • Added tests for using ExprGraphs from NLP evaluators (#1043).
  • Update version compatibilities of dependencies (#1034, #1051, #1052).
  • Fixed typos in documentation (#1044).

v0.9.12 (February 28, 2020)

  • Fixed writing NLPBlock in MathOptFormat (#1037).
  • Fixed MockOptimizer for result attributes with non-one result index (#1039).
  • Updated test template with instantiate (#1032).

v0.9.11 (February 21, 2020)

  • Add an option for the model created by Utilities.@model to be a subtype of AbstractOptimizer (#1031).
  • Described dual cone in docstrings of GeoMeanCone and RelativeEntropyCone (#1018, #1028).
  • Fixed typos in documentation (#1022, #1024).
  • Fixed warning of unsupported attribute (#1027).
  • Added more rootdet/logdet conic tests (#1026).
  • Implemented ConstraintDual for Constraint.GeoMeanBridge, Constraint.RootDetBridge and Constraint.LogDetBridge and test duals in tests with GeoMeanCone and RootDetConeTriangle and LogDetConeTriangle cones (#1025, #1026).

v0.9.10 (January 31, 2020)

  • Added OptimizerWithAttributes grouping an optimizer constructor and a list of optimizer attributes (#1008).
  • Added RelativeEntropyCone with corresponding bridge into exponential cone constraints (#993).
  • Added NormSpectralCone and NormNuclearCone with corresponding bridges into positive semidefinite constraints (#976).
  • Added supports_constrained_variable(s) (#1004).
  • Added dual_set_type (#1002).
  • Added tests for vector specialized version of delete (#989, #1011).
  • Added PSD3 test (#1007).
  • Clarified dual solution of Tests.pow1v and Tests.pow1f (#1013).
  • Added support for EqualTo and Zero in Bridges.Constraint.SplitIntervalBridge (#1005).
  • Fixed Utilities.vectorize for empty vector (#1003).
  • Fixed free variables in LP writer (#1006).

v0.9.9 (December 29, 2019)

  • Incorporated MathOptFormat.jl as the FileFormats submodule. FileFormats provides readers and writers for a number of standard file formats and MOF, a file format specialized for MOI (#969).
  • Improved performance of deletion of vector of variables in MOI.Utilities.Model (#983).
  • Updated to MutableArithmetics v0.2 (#981).
  • Added MutableArithmetics.promote_operation allocation tests (#975).
  • Fixed inference issue on Julia v1.1 (#982).

v0.9.8 (December 19, 2019)

  • Implemented MutableArithmetics API (#924).
  • Fixed callbacks with CachingOptimizer (#959).
  • Fixed MOI.dimension for MOI.Complements (#948).
  • Added fallback for add_variables (#972).
  • Added is_diagonal_vectorized_index utility (#965).
  • Improved linear constraints display in manual (#963, #964).
  • Bridges improvements:
    • Added IndicatorSet to SOS1 bridge (#877).
    • Added support for starting values for Variable.VectorizeBridge (#944).
    • Fixed MOI.add_constraints with non-bridged variable constraint on bridged variable (#951).
    • Fixed corner cases and docstring of GeoMeanBridge (#961, #962, #966).
    • Fixed choice between variable or constraint bridges for constrained variables (#973).
    • Improve performance of bridge shortest path (#945, #946, #956).
    • Added docstring for test_delete_bridge (#954).
    • Added Variable bridge tests (#952).

v0.9.7 (October 30, 2019)

  • Implemented _result_index_field for NLPBlockDual (#934).
  • Fixed copy of model with starting values for vector constraints (#941).
  • Bridges improvements:
    • Improved performance of add_bridge and added has_bridge (#935).
    • Added AbstractSetMapBridge for bridges between sets S1, S2 such that there is a linear map A such that A*S1 = S2 (#933).
    • Added support for starting values for FlipSignBridge, VectorizeBridge, ScalarizeBridge, SlackBridge, SplitIntervalBridge, RSOCBridge, SOCRBridge NormInfinityBridge, SOCtoPSDBridge and RSOCtoPSDBridge (#933, #936, #937, #938, #939).

v0.9.6 (October 25, 2019)

  • Added complementarity constraints (#913).
  • Allowed ModelLike objects as value of attributes (#928).
  • Testing improvements:
    • Added dual_objective_value option to MOI.Test.TestConfig (#922).
    • Added InvalidIndex tests in basic_constraint_tests (#921).
    • Added tests for the constant term in indicator constraint (#929).
  • Bridges improvements:
    • Added support for starting values for Functionize bridges (#923).
    • Added variable indices context to variable bridges (#920).
    • Fixed a typo in printing o debug_supports (#927).

v0.9.5 (October 9, 2019)

  • Clarified PrimalStatus/DualStatus to be NO_SOLUTION if result_index is out of bounds (#912).
  • Added tolerance for checks and use ResultCount + 1 for the result_index in MOI.Test.solve_result_status (#910, #917).
  • Use 0.5 instead of 2.0 for power in PowerCone in basic_constraint_test (#916).
  • Bridges improvements:
    • Added debug utilities for unsupported variable/constraint/objective (#861).
    • Fixed deletion of variables in bridged VectorOfVariables constraints (#909).
    • Fixed result_index with objective bridges (#911).

v0.9.4 (October 2, 2019)

  • Added solver-independent MIP callbacks (#782).
  • Implements submit for Utilities.CachingOptimizer and Bridges.AbstractBridgeOptimizer (#906).
  • Added tests for result count of solution attributes (#901, #904).
  • Added NumberOfThreads attribute (#892).
  • Added Utilities.get_bounds to get the bounds on a variable (#890).
  • Added a note on duplicate coefficients in documentation (#581).
  • Added result index in ConstraintBasisStatus (#898).
  • Added extension dictionary to Utilities.Model (#884, #895).
  • Fixed deletion of constrained variables for CachingOptimizer (#905).
  • Implemented Utilities.shift_constraint for Test.UnknownScalarSet (#896).
  • Bridges improvements:
    • Added Variable.RSOCtoSOCBridge (#907).
    • Implemented MOI.get for ConstraintFunction/ConstraintSet for Bridges.Constraint.SquareBridge (#899).

v0.9.3 (September 20, 2019)

  • Fixed ambiguity detected in Julia v1.3 (#891, #893).
  • Fixed missing sets from ListOfSupportedConstraints (#880).
  • Fixed copy of VectorOfVariables constraints with duplicate indices (#886).
  • Added extension dictionary to MOIU.Model (#884).
  • Implemented MOI.get for function and set for GeoMeanBridge (#888).
  • Updated documentation for SingleVariable indices and bridges (#885).
  • Testing improvements:
    • Added more comprehensive tests for names (#882).
    • Added tests for SingleVariable duals (#883).
    • Added tests for DualExponentialCone and DualPowerCone (#873).
  • Improvements for arbitrary coefficient type:
    • Fixed == for sets with mutable fields (#887).
    • Removed some Float64 assumptions in bridges (#878).
    • Automatic selection of Constraint.[Scalar|Vector]FunctionizeBridge (#889).

v0.9.2 (September 5, 2019)

  • Implemented model printing for MOI.ModelLike and specialized it for models defined in MOI (864).
  • Generalized contlinear tests for arbitrary coefficient type (#855).
  • Fixed supports_constraint for Semiinteger and Semicontinuous and supports for ObjectiveFunction (#859).
  • Fixed Allocate-Load copy for single variable constraints (#856).
  • Bridges improvements:
    • Add objective bridges (#789).
    • Fixed Variable.RSOCtoPSDBridge for dimension 2 (#869).
    • Added Variable.SOCtoRSOCBridge (#865).
    • Added Constraint.SOCRBridge and disable MOI.Bridges.Constraint.SOCtoPSDBridge (#751).
    • Fixed added_constraint_types for Contraint.LogDetBridge and Constraint.RootDetBridge (#870).

v0.9.1 (August 22, 2019)

  • Fix support for Julia v1.2 (#834).
  • L1 and L∞ norm epigraph cones and corresponding bridges to LP were added (#818).
  • Added tests to MOI.Test.nametest (#833).
  • Fix MOI.Test.soc3test for solvers not supporting infeasibility certificates (#839).
  • Implements operate for operators * and / between vector function and constant (#837).
  • Implements show for MOI.Utilities.IndexMap (#847).
  • Fix corner cases for mapping of variables in MOI.Utilities.CachingOptimizer and substitution of variables in MOI.Bridges.AbstractBridgeOptimizer (#848).
  • Fix transformation of constant terms for MOI.Bridges.Constraint.SOCtoPSDBridge and MOI.Bridges.Constraint.RSOCtoPSDBridge (#840).

v0.9.0 (August 13, 2019)

  • Support for Julia v0.6 and v0.7 was dropped (#714, #717).
  • A MOI.Utilities.Model implementation of ModelLike, this should replace most use cases of MOI.Utilities.@model (#781).
  • add_constrained_variable and add_constrained_variables were added (#759).
  • Support for indicator constraints was added (#709, #712).
  • DualObjectiveValue attribute was added (#473).
  • RawParameter attribute was added (#733).
  • A dual_set function was added (#804).
  • A Benchmarks submodule was added to facilitate solver benchmarking (#769).
  • A submit function was added, this may for instance allow the user to submit solutions or cuts to the solver from a callback (#775).
  • The field of ObjectiveValue was renamed to result_index (#729).
  • The _constant and Utilities.getconstant function were renamed to constant
  • REDUCTION_CERTIFICATE result status was added (#734).
  • Abstract matrix sets were added (#731).
  • Testing improvements:
    • The testing guideline was updated (#728).
    • Quadratic tests were added (#697).
    • Unit tests for RawStatusString, SolveTime, Silent and SolverName were added (#726, #741).
    • A rotated second-order cone test was added (#759).
    • A power cone test was added (#768).
    • Tests for ZeroOne variables with variable bounds were added (#772).
    • An unbounded test was added (#773).
    • Existing tests had a few updates (#702, #703, #763).
  • Documentation improvements:
    • Added a section on CachingOptimizer (#777).
    • Added a section on UniversalFallback, Model and @model (#762).
    • Transition the knapsack example to a doctest with MockOptimizer (#786).
  • Utilities improvements:
    • A CleverDict utility was added for a vector that automatically transform into a dictionary once a first index is removed (#767).
    • The Utilities.constant function was renamed to Utilities.constant_vector (#740).
    • Implement optimizer attributes for CachingOptimizer (#745).
    • Rename Utilities.add_scalar_constraint to Utilities.normalize_and_add_constraint (#801).
    • operate with vcat, SingleVariable and VectorOfVariables now returns a VectorOfVariables (#616).
    • Fix a type piracy of operate (#784).
    • The load_constraint fallback signature was fixed (#760).
    • The set_dot function was extended to work with sparse arrays (#805).
  • Bridges improvements:
    • The bridges no longer store the constraint function and set before it is bridged, the bridges now have to implement ConstraintFunction and ConstraintSet if the user wants to recover them. As a consequence, the @bridge macro was removed (#722).
    • Bridge are now instantiated with a bridge_constraint function instead of using a constructor (#730).
    • Fix constraint attributes for bridges (#699).
    • Constraint bridges were moved to the Bridges/Constraint submodule so they should now inherit from MOI.Bridges.Constraint.Abstract and should implement MOI.Bridges.Constraint.concrete_bridge_type instead of MOI.Bridges.concrete_bridge_type (#756).
    • Variable bridges were added in (#759).
    • Various improvements (#746, #747).

v0.8.4 (March 13, 2019)

  • Performance improvement in default_copy_to and bridge optimizer (#696).
  • Add Silent and implement setting optimizer attributes in caching and mock optimizers (#695).
  • Add Functionize bridges (SingleVariable and VectorOfVariables) (#659).
  • Minor typo fixes (#694).

v0.8.3 (March 6, 2019)

  • Use zero constant in scalar constraint function of MOI.Test.copytest (#691).
  • Fix variable deletion with SingleVariable objective function (#690).
  • Fix LazyBridgeOptimizer with bridges that add no constraints (#689).
  • Error message improvements (#673, #685, #686, #688).
  • Documentation improvements (#682, #683, #687).
  • Basis status:
    • Remove VariableBasisStatus (#679).
    • Test ConstraintBasisStatus and implement it in bridges (#678).
  • Fix inference of NumberOfVariables and NumberOfConstraints (#677).
  • Implement division between a quadratic function and a number (#675).

v0.8.2 (February 7, 2019)

  • Add RawStatusString attribute (#629).
  • Do not set names to the optimizer but only to the cache in CachingOptimizer (#638).
  • Make scalar MOI functions act as scalars in broadcast (#646).
  • Add function utilities:
    • Implement Base.zero (#634), Base.iszero (#643), add missing arithmetic operations (#644, #645) and fix division (#648).
    • Add a vectorize function that turns a vector of ScalarAffineFunction into a VectorAffineFunction (#642).
  • Improve support for starting values:
    • Show a warning in copy when starting values are not supported instead of throwing an error (#630).
    • Fix UniversalFallback for getting an variable or constraint attribute set to no indices (#623).
    • Add a test in contlineartest with partially set VariablePrimalStart.
  • Bridges improvements:
    • Fix StackOverFlow in LazyBridgeOptimizer when there is a cycle in the graph of bridges.
    • Add Slack bridges (#610, #650).
    • Add FlipSign bridges (#658).
  • Add tests with duplicate coefficients in ScalarAffineFunction and VectorAffineFunction (#639).
  • Use tolerance to compare VariablePrimal in rotatedsoc1 test (#632).
  • Use a zero constant in ScalarAffineFunction of constraints in psdt2 (#622).

v0.8.1 (January 7, 2019)

  • Adding an NLP objective now overrides any objective set using the ObjectiveFunction attribute (#619).
  • Rename fullbridgeoptimizer into full_bridge_optimizer (#621).
  • Allow custom constraint types with full_bridge_optimizer (#617).
  • Add Vectorize bridge which transforms scalar linear constraints into vector linear constraints (#615).

v0.8.0 (December 18, 2018)

  • Rename all enum values to follow the JuMP naming guidelines for constants, for example, Optimal becomes OPTIMAL, and DualInfeasible becomes DUAL_INFEASIBLE.
  • Rename CachingOptimizer methods for style compliance.
  • Add an MOI.TerminationStatusCode called ALMOST_DUAL_INFEASIBLE.

v0.7.0 (December 13, 2018)

  • Test that MOI.TerminationStatus is MOI.OptimizeNotCalled before MOI.optimize! is called.
  • Check supports_default_copy_to in tests (#594).
  • Key pieces of information like optimality, infeasibility, etc., are now reported through TerminationStatusCode. It is typically no longer necessary to check the result statuses in addition to the termination status.
  • Add perspective dimension to log-det cone (#593).

v0.6.4 (November 27, 2018)

  • Add OptimizeNotCalled termination status (#577) and improve documentation of other statuses (#575).
  • Add a solver naming guideline (#578).
  • Make FeasibilitySense the default ObjectiveSense (#579).
  • Fix Utilities.@model and Bridges.@bridge macros for functions and sets defined outside MOI (#582).
  • Document solver-specific attributes (#580) and implement them in Utilities.CachingOptimizer (#565).

v0.6.3 (November 16, 2018)

  • Variables and constraints are now allowed to have duplicate names. An error is thrown only on lookup. This change breaks some existing tests. (#549)
  • Attributes may now be partially set (some values could be nothing). (#563)
  • Performance improvements in Utilities.Model (#549, #567, #568)
  • Fix bug in QuadtoSOC (#558).
  • New supports_default_copy_to method that optimizers should implement to control caching behavior.
  • Documentation improvements.

v0.6.2 (October 26, 2018)

  • Improve hygiene of @model macro (#544).
  • Fix bug in copy tests (#543).
  • Fix bug in UniversalFallback attribute getter (#540).
  • Allow all correct solutions for solve_blank_obj unit test (#537).
  • Add errors for Allocate-Load and bad constraints (#534).
  • [performance] Add specialized implementation of hash for VariableIndex (#533).
  • [performance] Construct the name to object dictionaries lazily in model (#535).
  • Add the QuadtoSOC bridge which transforms ScalarQuadraticFunction constraints into RotatedSecondOrderCone (#483).

v0.6.1 (September 22, 2018)

  • Enable PositiveSemidefiniteConeSquare set and quadratic functions in MOIB.fullbridgeoptimizer (#524).
  • Add warning in the bridge between PositiveSemidefiniteConeSquare and PositiveSemidefiniteConeTriangle when the matrix is almost symmetric (#522).
  • Modify MOIT.copytest to not add multiples constraints on the same variable (#521).
  • Add missing keyword argument in one of MOIU.add_scalar_constraint methods (#520).

v0.6.0 (August 30, 2018)

  • The MOIU.@model and MOIB.@bridge macros now support functions and sets defined in external modules. As a consequence, function and set names in the macro arguments need to be prefixed by module name.
  • Rename functions according to the JuMP style guide:
    • copy! with keyword arguments copynames and warnattributes -> copy_to with keyword arguments copy_names and warn_attributes;
    • set! -> set;
    • addvariable[s]! -> add_variable[s];
    • supportsconstraint -> supports_constraint;
    • addconstraint[s]! -> add_constraint[s];
    • isvalid -> is_valid;
    • isempty -> is_empty;
    • Base.delete! -> delete;
    • modify! -> modify;
    • transform! -> transform;
    • initialize! -> initialize;
    • write -> write_to_file; and
    • read! -> read_from_file.
  • Remove free! (use Base.finalize instead).
  • Add the SquarePSD bridge which transforms PositiveSemidefiniteConeTriangle constraints into PositiveSemidefiniteConeTriangle.
  • Add result fallback for ConstraintDual of variable-wise constraint, ConstraintPrimal and ObjectiveValue.
  • Add tests for ObjectiveBound.
  • Add test for empty rows in vector linear constraint.
  • Rework errors: CannotError has been renamed NotAllowedError and the distinction between UnsupportedError and NotAllowedError is now about whether the element is not supported (for example, it cannot be copied a model containing this element) or the operation is not allowed (either because it is not implemented, because it cannot be performed in the current state of the model, or because it cannot be performed for a specific index)
  • canget is removed. NoSolution is added as a result status to indicate that the solver does not have either a primal or dual solution available (See #479).

v0.5.0 (August 5, 2018)

  • Fix names with CachingOptimizer.
  • Cleanup thanks to @mohamed82008.
  • Added a universal fallback for constraints.
  • Fast utilities for function canonicalization thanks to @rdeits.
  • Renamed dimension field to side_dimension in the context of matrix-like sets.
  • New and improved tests for cases like duplicate terms and ObjectiveBound.
  • Removed cantransform, canaddconstraint, canaddvariable, canset, canmodify, and candelete functions from the API. They are replaced by a new set of errors that are thrown: Subtypes of UnsupportedError indicate unsupported operations, while subtypes of CannotError indicate operations that cannot be performed in the current state.
  • The API for copy! is updated to remove the CopyResult type.
  • Updates for the new JuMP style guide.

v0.4.1 (June 28, 2018)

  • Fixes vector function modification on 32 bits.
  • Fixes Bellman-Ford algorithm for bridges.
  • Added an NLP test with FeasibilitySense.
  • Update modification documentation.

v0.4.0 (June 23, 2018)

  • Helper constructors for VectorAffineTerm and VectorQuadraticTerm.
  • Added modify_lhs to TestConfig.
  • Additional unit tests for optimizers.
  • Added a type parameter to CachingOptimizer for the optimizer field.
  • New API for problem modification (#388)
  • Tests pass without deprecation warnings on Julia 0.7.
  • Small fixes and documentation updates.

v0.3.0 (May 25, 2018)

  • Functions have been redefined to use arrays-of-structs instead of structs-of-arrays.
  • Improvements to MockOptimizer.
  • Significant changes to Bridges.
  • New and improved unit tests.
  • Fixes for Julia 0.7.

v0.2.0 (April 24, 2018)

  • Improvements to and better coverage of Tests.
  • Documentation fixes.
  • SolverName attribute.
  • Changes to the NLP interface (new definition of variable order and arrays of structs for bound pairs and sparsity patterns).
  • Addition of NLP tests.
  • Introduction of UniversalFallback.
  • copynames keyword argument to MOI.copy!.
  • Add Bridges submodule.

v0.1.0 (February 28, 2018)

  • Initial public release.
  • The framework for MOI was developed at the JuMP-dev workshop at MIT in June 2017 as a sorely needed replacement for MathProgBase.
diff --git a/dev/search/index.html b/dev/search/index.html index caf3312818..481d00ccb4 100644 --- a/dev/search/index.html +++ b/dev/search/index.html @@ -1,2 +1,2 @@ -Search · MathOptInterface +Search · MathOptInterface diff --git a/dev/search_index.js b/dev/search_index.js index 4eaccb9c0c..7d2c8298c3 100644 --- a/dev/search_index.js +++ b/dev/search_index.js @@ -1,3 +1,3 @@ var documenterSearchIndex = {"docs": -[{"location":"background/motivation/#Motivation","page":"Motivation","title":"Motivation","text":"","category":"section"},{"location":"background/motivation/","page":"Motivation","title":"Motivation","text":"MathOptInterface (MOI) is a replacement for MathProgBase, the first-generation abstraction layer for mathematical optimization previously used by JuMP and Convex.jl.","category":"page"},{"location":"background/motivation/","page":"Motivation","title":"Motivation","text":"To address a number of limitations of MathProgBase, MOI is designed to:","category":"page"},{"location":"background/motivation/","page":"Motivation","title":"Motivation","text":"Be simple and extensible\nunifying linear, quadratic, and conic optimization,\nseamlessly facilitating extensions to essentially arbitrary constraints and functions (for example, indicator constraints, complementarity constraints, and piecewise-linear functions)\nBe fast\nby allowing access to a solver's in-memory representation of a problem without writing intermediate files (when possible)\nby using multiple dispatch and avoiding requiring containers of non-concrete types\nAllow a solver to return multiple results (for example, a pool of solutions)\nAllow a solver to return extra arbitrary information via attributes (for example, variable- and constraint-wise membership in an irreducible inconsistent subset for infeasibility analysis)\nProvide a greatly expanded set of status codes explaining what happened during the optimization procedure\nEnable a solver to more precisely specify which problem classes it supports\nEnable both primal and dual warm starts\nEnable adding and removing both variables and constraints by indices that are not required to be consecutive\nEnable any modification that the solver supports to an existing model\nAvoid requiring the solver wrapper to store an additional copy of the problem data","category":"page"},{"location":"reference/constraints/","page":"Constraints","title":"Constraints","text":"CurrentModule = MathOptInterface\nDocTestSetup = quote\n import MathOptInterface as MOI\nend\nDocTestFilters = [r\"MathOptInterface|MOI\"]","category":"page"},{"location":"reference/constraints/#constraints_ref","page":"Constraints","title":"Constraints","text":"","category":"section"},{"location":"reference/constraints/#Types","page":"Constraints","title":"Types","text":"","category":"section"},{"location":"reference/constraints/","page":"Constraints","title":"Constraints","text":"ConstraintIndex","category":"page"},{"location":"reference/constraints/#MathOptInterface.ConstraintIndex","page":"Constraints","title":"MathOptInterface.ConstraintIndex","text":"ConstraintIndex{F, S}\n\nA type-safe wrapper for Int64 for use in referencing F-in-S constraints in a model. The parameter F is the type of the function in the constraint, and the parameter S is the type of set in the constraint. To allow for deletion, indices need not be consecutive. Indices within a constraint type (i.e. F-in-S) must be unique, but non-unique indices across different constraint types are allowed. If F is VariableIndex then the index is equal to the index of the variable. That is for an index::ConstraintIndex{VariableIndex}, we always have\n\nindex.value == MOI.get(model, MOI.ConstraintFunction(), index).value\n\n\n\n\n\n","category":"type"},{"location":"reference/constraints/#Functions","page":"Constraints","title":"Functions","text":"","category":"section"},{"location":"reference/constraints/","page":"Constraints","title":"Constraints","text":"is_valid(::ModelLike,::ConstraintIndex)\nadd_constraint\nadd_constraints\ntransform\nsupports_constraint","category":"page"},{"location":"reference/constraints/#MathOptInterface.is_valid-Tuple{MathOptInterface.ModelLike, MathOptInterface.ConstraintIndex}","page":"Constraints","title":"MathOptInterface.is_valid","text":"is_valid(model::ModelLike, index::Index)::Bool\n\nReturn a Bool indicating whether this index refers to a valid object in the model model.\n\n\n\n\n\n","category":"method"},{"location":"reference/constraints/#MathOptInterface.add_constraint","page":"Constraints","title":"MathOptInterface.add_constraint","text":"add_constraint(model::ModelLike, func::F, set::S)::ConstraintIndex{F,S} where {F,S}\n\nAdd the constraint f(x) in mathcalS where f is defined by func, and mathcalS is defined by set.\n\nadd_constraint(model::ModelLike, v::VariableIndex, set::S)::ConstraintIndex{VariableIndex,S} where {S}\nadd_constraint(model::ModelLike, vec::Vector{VariableIndex}, set::S)::ConstraintIndex{VectorOfVariables,S} where {S}\n\nAdd the constraint v in mathcalS where v is the variable (or vector of variables) referenced by v and mathcalS is defined by set.\n\nAn UnsupportedConstraint error is thrown if model does not support F-in-S constraints,\na AddConstraintNotAllowed error is thrown if it supports F-in-S constraints but it cannot add the constraint(s) in its current state and\na ScalarFunctionConstantNotZero error may be thrown if func is an AbstractScalarFunction with nonzero constant and set is EqualTo, GreaterThan, LessThan or Interval.\na LowerBoundAlreadySet error is thrown if F is a VariableIndex and a constraint was already added to this variable that sets a lower bound.\na UpperBoundAlreadySet error is thrown if F is a VariableIndex and a constraint was already added to this variable that sets an upper bound.\n\n\n\n\n\n","category":"function"},{"location":"reference/constraints/#MathOptInterface.add_constraints","page":"Constraints","title":"MathOptInterface.add_constraints","text":"add_constraints(model::ModelLike, funcs::Vector{F}, sets::Vector{S})::Vector{ConstraintIndex{F,S}} where {F,S}\n\nAdd the set of constraints specified by each function-set pair in funcs and sets. F and S should be concrete types. This call is equivalent to add_constraint.(model, funcs, sets) but may be more efficient.\n\n\n\n\n\n","category":"function"},{"location":"reference/constraints/#MathOptInterface.transform","page":"Constraints","title":"MathOptInterface.transform","text":"Transform Constraint Set\n\ntransform(model::ModelLike, c::ConstraintIndex{F,S1}, newset::S2)::ConstraintIndex{F,S2}\n\nReplace the set in constraint c with newset. The constraint index c will no longer be valid, and the function returns a new constraint index with the correct type.\n\nSolvers may only support a subset of constraint transforms that they perform efficiently (for example, changing from a LessThan to GreaterThan set). In addition, set modification (where S1 = S2) should be performed via the modify function.\n\nTypically, the user should delete the constraint and add a new one.\n\nExamples\n\nIf c is a ConstraintIndex{ScalarAffineFunction{Float64},LessThan{Float64}},\n\nc2 = transform(model, c, GreaterThan(0.0))\ntransform(model, c, LessThan(0.0)) # errors\n\n\n\n\n\n","category":"function"},{"location":"reference/constraints/#MathOptInterface.supports_constraint","page":"Constraints","title":"MathOptInterface.supports_constraint","text":"supports_constraint(\n model::ModelLike,\n ::Type{F},\n ::Type{S},\n)::Bool where {F<:AbstractFunction,S<:AbstractSet}\n\nReturn a Bool indicating whether model supports F-in-S constraints, that is, copy_to(model, src) does not throw UnsupportedConstraint when src contains F-in-S constraints. If F-in-S constraints are only not supported in specific circumstances, e.g. F-in-S constraints cannot be combined with another type of constraint, it should still return true.\n\n\n\n\n\nMOI.supports_constraint(\n BT::Type{<:AbstractBridge},\n F::Type{<:MOI.AbstractFunction},\n S::Type{<:MOI.AbstractSet},\n)::Bool\n\nReturn a Bool indicating whether the bridges of type BT support bridging F-in-S constraints.\n\nImplementation notes\n\nThis method depends only on the type of the inputs, not the runtime values.\nThere is a default fallback, so you need only implement this method for constraint types that the bridge implements.\n\n\n\n\n\n","category":"function"},{"location":"reference/constraints/#Attributes","page":"Constraints","title":"Attributes","text":"","category":"section"},{"location":"reference/constraints/","page":"Constraints","title":"Constraints","text":"AbstractConstraintAttribute\nConstraintName\nConstraintPrimalStart\nConstraintDualStart\nConstraintPrimal\nConstraintDual\nConstraintBasisStatus\nConstraintFunction\nCanonicalConstraintFunction\nConstraintSet\nBasisStatusCode\nBASIC\nNONBASIC\nNONBASIC_AT_LOWER\nNONBASIC_AT_UPPER\nSUPER_BASIC","category":"page"},{"location":"reference/constraints/#MathOptInterface.AbstractConstraintAttribute","page":"Constraints","title":"MathOptInterface.AbstractConstraintAttribute","text":"AbstractConstraintAttribute\n\nAbstract supertype for attribute objects that can be used to set or get attributes (properties) of constraints in the model.\n\n\n\n\n\n","category":"type"},{"location":"reference/constraints/#MathOptInterface.ConstraintName","page":"Constraints","title":"MathOptInterface.ConstraintName","text":"ConstraintName()\n\nA constraint attribute for a string identifying the constraint.\n\nIt is valid for constraints variables to have the same name; however, constraints with duplicate names cannot be looked up using get, regardless of whether they have the same F-in-S type.\n\nConstraintName has a default value of \"\" if not set.\n\nNotes\n\nYou should not implement ConstraintName for VariableIndex constraints.\n\n\n\n\n\n","category":"type"},{"location":"reference/constraints/#MathOptInterface.ConstraintPrimalStart","page":"Constraints","title":"MathOptInterface.ConstraintPrimalStart","text":"ConstraintPrimalStart()\n\nA constraint attribute for the initial assignment to some constraint's ConstraintPrimal that the optimizer may use to warm-start the solve.\n\nMay be nothing (unset), a number for AbstractScalarFunction, or a vector for AbstractVectorFunction.\n\n\n\n\n\n","category":"type"},{"location":"reference/constraints/#MathOptInterface.ConstraintDualStart","page":"Constraints","title":"MathOptInterface.ConstraintDualStart","text":"ConstraintDualStart()\n\nA constraint attribute for the initial assignment to some constraint's ConstraintDual that the optimizer may use to warm-start the solve.\n\nMay be nothing (unset), a number for AbstractScalarFunction, or a vector for AbstractVectorFunction.\n\n\n\n\n\n","category":"type"},{"location":"reference/constraints/#MathOptInterface.ConstraintPrimal","page":"Constraints","title":"MathOptInterface.ConstraintPrimal","text":"ConstraintPrimal(result_index::Int = 1)\n\nA constraint attribute for the assignment to some constraint's primal value(s) in result result_index.\n\nIf the constraint is f(x) in S, then in most cases the ConstraintPrimal is the value of f, evaluated at the correspondng VariablePrimal solution.\n\nHowever, some conic solvers reformulate b - Ax in S to s = b - Ax, s in S. These solvers may return the value of s for ConstraintPrimal, rather than b - Ax. (Although these are constrained by an equality constraint, due to numerical tolerances they may not be identical.)\n\nIf the solver does not have a primal value for the constraint because the result_index is beyond the available solutions (whose number is indicated by the ResultCount attribute), getting this attribute must throw a ResultIndexBoundsError. Otherwise, if the result is unavailable for another reason (for instance, only a dual solution is available), the result is undefined. Users should first check PrimalStatus before accessing the ConstraintPrimal attribute.\n\nIf result_index is omitted, it is 1 by default. See ResultCount for information on how the results are ordered.\n\n\n\n\n\n","category":"type"},{"location":"reference/constraints/#MathOptInterface.ConstraintDual","page":"Constraints","title":"MathOptInterface.ConstraintDual","text":"ConstraintDual(result_index::Int = 1)\n\nA constraint attribute for the assignment to some constraint's dual value(s) in result result_index. If result_index is omitted, it is 1 by default.\n\nIf the solver does not have a dual value for the variable because the result_index is beyond the available solutions (whose number is indicated by the ResultCount attribute), getting this attribute must throw a ResultIndexBoundsError. Otherwise, if the result is unavailable for another reason (for instance, only a primal solution is available), the result is undefined. Users should first check DualStatus before accessing the ConstraintDual attribute.\n\nSee ResultCount for information on how the results are ordered.\n\n\n\n\n\n","category":"type"},{"location":"reference/constraints/#MathOptInterface.ConstraintBasisStatus","page":"Constraints","title":"MathOptInterface.ConstraintBasisStatus","text":"ConstraintBasisStatus(result_index::Int = 1)\n\nA constraint attribute for the BasisStatusCode of some constraint in result result_index, with respect to an available optimal solution basis. If result_index is omitted, it is 1 by default.\n\nIf the solver does not have a basis statue for the constraint because the result_index is beyond the available solutions (whose number is indicated by the ResultCount attribute), getting this attribute must throw a ResultIndexBoundsError. Otherwise, if the result is unavailable for another reason (for instance, only a dual solution is available), the result is undefined. Users should first check PrimalStatus before accessing the ConstraintBasisStatus attribute.\n\nSee ResultCount for information on how the results are ordered.\n\nNotes\n\nFor the basis status of a variable, query VariableBasisStatus.\n\nConstraintBasisStatus does not apply to VariableIndex constraints. You can infer the basis status of a VariableIndex constraint by looking at the result of VariableBasisStatus.\n\n\n\n\n\n","category":"type"},{"location":"reference/constraints/#MathOptInterface.ConstraintFunction","page":"Constraints","title":"MathOptInterface.ConstraintFunction","text":"ConstraintFunction()\n\nA constraint attribute for the AbstractFunction object used to define the constraint.\n\nIt is guaranteed to be equivalent but not necessarily identical to the function provided by the user.\n\n\n\n\n\n","category":"type"},{"location":"reference/constraints/#MathOptInterface.CanonicalConstraintFunction","page":"Constraints","title":"MathOptInterface.CanonicalConstraintFunction","text":"CanonicalConstraintFunction()\n\nA constraint attribute for a canonical representation of the AbstractFunction object used to define the constraint.\n\nGetting this attribute is guaranteed to return a function that is equivalent but not necessarily identical to the function provided by the user.\n\nBy default, MOI.get(model, MOI.CanonicalConstraintFunction(), ci) fallbacks to MOI.Utilities.canonical(MOI.get(model, MOI.ConstraintFunction(), ci)). However, if model knows that the constraint function is canonical then it can implement a specialized method that directly return the function without calling Utilities.canonical. Therefore, the value returned cannot be assumed to be a copy of the function stored in model. Moreover, Utilities.Model checks with Utilities.is_canonical whether the function stored internally is already canonical and if it's the case, then it returns the function stored internally instead of a copy.\n\n\n\n\n\n","category":"type"},{"location":"reference/constraints/#MathOptInterface.ConstraintSet","page":"Constraints","title":"MathOptInterface.ConstraintSet","text":"ConstraintSet()\n\nA constraint attribute for the AbstractSet object used to define the constraint.\n\n\n\n\n\n","category":"type"},{"location":"reference/constraints/#MathOptInterface.BasisStatusCode","page":"Constraints","title":"MathOptInterface.BasisStatusCode","text":"BasisStatusCode\n\nAn Enum of possible values for the ConstraintBasisStatus and VariableBasisStatus attributes, explaining the status of a given element with respect to an optimal solution basis.\n\nNotes\n\nNONBASIC_AT_LOWER and NONBASIC_AT_UPPER should be used only for\n\nconstraints with the Interval set. In this case, they are necessary to distinguish which side of the constraint is active. One-sided constraints (e.g., LessThan and GreaterThan) should use NONBASIC instead of the NONBASIC_AT_* values. This restriction does not apply to VariableBasisStatus, which should return NONBASIC_AT_* regardless of whether the alternative bound exists.\n\nIn linear programs, SUPER_BASIC occurs when a variable with no bounds is not\n\nin the basis.\n\nValues\n\nPossible values are:\n\nBASIC: element is in the basis\nNONBASIC: element is not in the basis\nNONBASIC_AT_LOWER: element is not in the basis and is at its lower bound\nNONBASIC_AT_UPPER: element is not in the basis and is at its upper bound\nSUPER_BASIC: element is not in the basis but is also not at one of its bounds\n\n\n\n\n\n","category":"type"},{"location":"reference/constraints/#MathOptInterface.BASIC","page":"Constraints","title":"MathOptInterface.BASIC","text":"BASIC::BasisStatusCode\n\nAn instance of the BasisStatusCode enum.\n\nBASIC: element is in the basis\n\n\n\n\n\n","category":"constant"},{"location":"reference/constraints/#MathOptInterface.NONBASIC","page":"Constraints","title":"MathOptInterface.NONBASIC","text":"NONBASIC::BasisStatusCode\n\nAn instance of the BasisStatusCode enum.\n\nNONBASIC: element is not in the basis\n\n\n\n\n\n","category":"constant"},{"location":"reference/constraints/#MathOptInterface.NONBASIC_AT_LOWER","page":"Constraints","title":"MathOptInterface.NONBASIC_AT_LOWER","text":"NONBASIC_AT_LOWER::BasisStatusCode\n\nAn instance of the BasisStatusCode enum.\n\nNONBASIC_AT_LOWER: element is not in the basis and is at its lower bound\n\n\n\n\n\n","category":"constant"},{"location":"reference/constraints/#MathOptInterface.NONBASIC_AT_UPPER","page":"Constraints","title":"MathOptInterface.NONBASIC_AT_UPPER","text":"NONBASIC_AT_UPPER::BasisStatusCode\n\nAn instance of the BasisStatusCode enum.\n\nNONBASIC_AT_UPPER: element is not in the basis and is at its upper bound\n\n\n\n\n\n","category":"constant"},{"location":"reference/constraints/#MathOptInterface.SUPER_BASIC","page":"Constraints","title":"MathOptInterface.SUPER_BASIC","text":"SUPER_BASIC::BasisStatusCode\n\nAn instance of the BasisStatusCode enum.\n\nSUPER_BASIC: element is not in the basis but is also not at one of its bounds\n\n\n\n\n\n","category":"constant"},{"location":"tutorials/implementing/","page":"Implementing a solver interface","title":"Implementing a solver interface","text":"CurrentModule = MathOptInterface\nDocTestSetup = quote\n import MathOptInterface as MOI\nend\nDocTestFilters = [r\"MathOptInterface|MOI\"]","category":"page"},{"location":"tutorials/implementing/#Implementing-a-solver-interface","page":"Implementing a solver interface","title":"Implementing a solver interface","text":"","category":"section"},{"location":"tutorials/implementing/","page":"Implementing a solver interface","title":"Implementing a solver interface","text":"This guide outlines the basic steps to implement an interface to MathOptInterface for a new solver.","category":"page"},{"location":"tutorials/implementing/","page":"Implementing a solver interface","title":"Implementing a solver interface","text":"danger: Danger\nImplementing an interface to MathOptInterface for a new solver is a lot of work. Before starting, we recommend that you join the Developer chatroom and explain a little bit about the solver you are wrapping. If you have questions that are not answered by this guide, please ask them in the Developer chatroom so we can improve this guide.","category":"page"},{"location":"tutorials/implementing/#A-note-on-the-API","page":"Implementing a solver interface","title":"A note on the API","text":"","category":"section"},{"location":"tutorials/implementing/","page":"Implementing a solver interface","title":"Implementing a solver interface","text":"The API of MathOptInterface is large and varied. In order to support the diversity of solvers and use-cases, we make heavy use of duck-typing. That is, solvers are not expected to implement the full API, nor is there a well-defined minimal subset of what must be implemented. Instead, you should implement the API as necessary to make the solver function as you require.","category":"page"},{"location":"tutorials/implementing/","page":"Implementing a solver interface","title":"Implementing a solver interface","text":"The main reason for using duck-typing is that solvers work in different ways and target different use-cases.","category":"page"},{"location":"tutorials/implementing/","page":"Implementing a solver interface","title":"Implementing a solver interface","text":"For example:","category":"page"},{"location":"tutorials/implementing/","page":"Implementing a solver interface","title":"Implementing a solver interface","text":"Some solvers support incremental problem construction, support modification after a solve, and have native support for things like variable names.\nOther solvers are \"one-shot\" solvers that require all of the problem data to construct and solve the problem in a single function call. They do not support modification or things like variable names.\nOther \"solvers\" are not solvers at all, but things like file readers. These may only support functions like read_from_file, and may not even support the ability to add variables or constraints directly.\nFinally, some \"solvers\" are layers which take a problem as input, transform it according to some rules, and pass the transformed problem to an inner solver.","category":"page"},{"location":"tutorials/implementing/#Preliminaries","page":"Implementing a solver interface","title":"Preliminaries","text":"","category":"section"},{"location":"tutorials/implementing/","page":"Implementing a solver interface","title":"Implementing a solver interface","text":"Before starting on your wrapper, you should do some background research and make the solver accessible via Julia.","category":"page"},{"location":"tutorials/implementing/#Decide-if-MathOptInterface-is-right-for-you","page":"Implementing a solver interface","title":"Decide if MathOptInterface is right for you","text":"","category":"section"},{"location":"tutorials/implementing/","page":"Implementing a solver interface","title":"Implementing a solver interface","text":"The first step in writing a wrapper is to decide whether implementing an interface is the right thing to do.","category":"page"},{"location":"tutorials/implementing/","page":"Implementing a solver interface","title":"Implementing a solver interface","text":"MathOptInterface is an abstraction layer for unifying constrained mathematical optimization solvers. If your solver doesn't fit in the category, for example, it implements a derivative-free algorithm for unconstrained objective functions, MathOptInterface may not be the right tool for the job.","category":"page"},{"location":"tutorials/implementing/","page":"Implementing a solver interface","title":"Implementing a solver interface","text":"tip: Tip\nIf you're not sure whether you should write an interface, ask in the Developer chatroom.","category":"page"},{"location":"tutorials/implementing/#Find-a-similar-solver-already-wrapped","page":"Implementing a solver interface","title":"Find a similar solver already wrapped","text":"","category":"section"},{"location":"tutorials/implementing/","page":"Implementing a solver interface","title":"Implementing a solver interface","text":"The next step is to find (if possible) a similar solver that is already wrapped. Although not strictly necessary, this will be a good place to look for inspiration when implementing your wrapper.","category":"page"},{"location":"tutorials/implementing/","page":"Implementing a solver interface","title":"Implementing a solver interface","text":"The JuMP documentation has a good list of solvers, along with the problem classes they support.","category":"page"},{"location":"tutorials/implementing/","page":"Implementing a solver interface","title":"Implementing a solver interface","text":"tip: Tip\nIf you're not sure which solver is most similar, ask in the Developer chatroom.","category":"page"},{"location":"tutorials/implementing/#Create-a-low-level-interface","page":"Implementing a solver interface","title":"Create a low-level interface","text":"","category":"section"},{"location":"tutorials/implementing/","page":"Implementing a solver interface","title":"Implementing a solver interface","text":"Before writing a MathOptInterface wrapper, you first need to be able to call the solver from Julia.","category":"page"},{"location":"tutorials/implementing/#Wrapping-solvers-written-in-Julia","page":"Implementing a solver interface","title":"Wrapping solvers written in Julia","text":"","category":"section"},{"location":"tutorials/implementing/","page":"Implementing a solver interface","title":"Implementing a solver interface","text":"If your solver is written in Julia, there's nothing to do here. Go to the next section.","category":"page"},{"location":"tutorials/implementing/#Wrapping-solvers-written-in-C","page":"Implementing a solver interface","title":"Wrapping solvers written in C","text":"","category":"section"},{"location":"tutorials/implementing/","page":"Implementing a solver interface","title":"Implementing a solver interface","text":"Julia is well suited to wrapping solvers written in C.","category":"page"},{"location":"tutorials/implementing/","page":"Implementing a solver interface","title":"Implementing a solver interface","text":"info: Info\nThis is not true for C++. If you have a solver written in C++, first write a C interface, then wrap the C interface.","category":"page"},{"location":"tutorials/implementing/","page":"Implementing a solver interface","title":"Implementing a solver interface","text":"Before writing a MathOptInterface wrapper, there are a few extra steps.","category":"page"},{"location":"tutorials/implementing/#Create-a-JLL","page":"Implementing a solver interface","title":"Create a JLL","text":"","category":"section"},{"location":"tutorials/implementing/","page":"Implementing a solver interface","title":"Implementing a solver interface","text":"If the C code is publicly available under an open source license, create a JLL package via Yggdrasil. The easiest way to do this is to copy an existing solver. Good examples to follow are the COIN-OR solvers.","category":"page"},{"location":"tutorials/implementing/","page":"Implementing a solver interface","title":"Implementing a solver interface","text":"warning: Warning\nBuilding the solver via Yggdrasil is non-trivial. Please ask the Developer chatroom for help.","category":"page"},{"location":"tutorials/implementing/","page":"Implementing a solver interface","title":"Implementing a solver interface","text":"If the code is commercial or not publicly available, the user will need to manually install the solver. See Gurobi.jl or CPLEX.jl for examples of how to structure this.","category":"page"},{"location":"tutorials/implementing/#implement_clang","page":"Implementing a solver interface","title":"Use Clang.jl to wrap the C API","text":"","category":"section"},{"location":"tutorials/implementing/","page":"Implementing a solver interface","title":"Implementing a solver interface","text":"The next step is to use Clang.jl to automatically wrap the C API. The easiest way to do this is to follow an example. Good examples to follow are Cbc.jl and HiGHS.jl.","category":"page"},{"location":"tutorials/implementing/","page":"Implementing a solver interface","title":"Implementing a solver interface","text":"Sometimes, you will need to make manual modifications to the resulting files.","category":"page"},{"location":"tutorials/implementing/#Solvers-written-in-other-languages","page":"Implementing a solver interface","title":"Solvers written in other languages","text":"","category":"section"},{"location":"tutorials/implementing/","page":"Implementing a solver interface","title":"Implementing a solver interface","text":"Ask the Developer chatroom for advice. You may be able to use one of the JuliaInterop packages to call out to the solver.","category":"page"},{"location":"tutorials/implementing/","page":"Implementing a solver interface","title":"Implementing a solver interface","text":"For example, SeDuMi.jl uses MATLAB.jl to call the SeDuMi solver written in MATLAB.","category":"page"},{"location":"tutorials/implementing/#Structuring-the-package","page":"Implementing a solver interface","title":"Structuring the package","text":"","category":"section"},{"location":"tutorials/implementing/","page":"Implementing a solver interface","title":"Implementing a solver interface","text":"Structure your wrapper as a Julia package. Consult the Julia documentation if you haven't done this before.","category":"page"},{"location":"tutorials/implementing/","page":"Implementing a solver interface","title":"Implementing a solver interface","text":"MOI solver interfaces may be in the same package as the solver itself (either the C wrapper if the solver is accessible through C, or the Julia code if the solver is written in Julia, for example), or in a separate package which depends on the solver package.","category":"page"},{"location":"tutorials/implementing/","page":"Implementing a solver interface","title":"Implementing a solver interface","text":"note: Note\nThe JuMP core contributors request that you do not use \"JuMP\" in the name of your package without prior consent.","category":"page"},{"location":"tutorials/implementing/","page":"Implementing a solver interface","title":"Implementing a solver interface","text":"Your package should have the following structure:","category":"page"},{"location":"tutorials/implementing/","page":"Implementing a solver interface","title":"Implementing a solver interface","text":"/.github\n /workflows\n ci.yml\n format_check.yml\n TagBot.yml\n/gen\n gen.jl # Code to wrap the C API\n/src\n NewSolver.jl\n /gen\n libnewsolver_api.jl\n libnewsolver_common.jl\n /MOI_wrapper\n MOI_wrapper.jl\n other_files.jl\n/test\n runtests.jl\n /MOI_wrapper\n MOI_wrapper.jl\n.gitignore\n.JuliaFormatter.toml\nREADME.md\nLICENSE.md\nProject.toml","category":"page"},{"location":"tutorials/implementing/","page":"Implementing a solver interface","title":"Implementing a solver interface","text":"The /.github folder contains the scripts for GitHub actions. The easiest way to write these is to copy the ones from an existing solver.\nThe /gen and /src/gen folders are only needed if you are wrapping a solver written in C.\nThe /src/MOI_wrapper folder contains the Julia code for the MOI wrapper.\nThe /test folder contains code for testing your package. See Setup tests for more information.\nThe .JuliaFormatter.toml and .github/workflows/format_check.yml enforce code formatting using JuliaFormatter.jl. Check existing solvers or JuMP.jl for details.","category":"page"},{"location":"tutorials/implementing/#Documentation","page":"Implementing a solver interface","title":"Documentation","text":"","category":"section"},{"location":"tutorials/implementing/","page":"Implementing a solver interface","title":"Implementing a solver interface","text":"Your package must include documentation explaining how to use the package. The easiest approach is to include documentation in your README.md. A more involved option is to use Documenter.jl.","category":"page"},{"location":"tutorials/implementing/","page":"Implementing a solver interface","title":"Implementing a solver interface","text":"Examples of packages with README-based documentation include:","category":"page"},{"location":"tutorials/implementing/","page":"Implementing a solver interface","title":"Implementing a solver interface","text":"Cbc.jl\nHiGHS.jl\nSCS.jl","category":"page"},{"location":"tutorials/implementing/","page":"Implementing a solver interface","title":"Implementing a solver interface","text":"Examples of packages with Documenter-based documentation include:","category":"page"},{"location":"tutorials/implementing/","page":"Implementing a solver interface","title":"Implementing a solver interface","text":"Alpine.jl\nCOSMO.jl\nJuniper.jl","category":"page"},{"location":"tutorials/implementing/#Setup-tests","page":"Implementing a solver interface","title":"Setup tests","text":"","category":"section"},{"location":"tutorials/implementing/","page":"Implementing a solver interface","title":"Implementing a solver interface","text":"The best way to implement an interface to MathOptInterface is via test-driven development.","category":"page"},{"location":"tutorials/implementing/","page":"Implementing a solver interface","title":"Implementing a solver interface","text":"The MOI.Test submodule contains a large test suite to help check that you have implemented things correctly.","category":"page"},{"location":"tutorials/implementing/","page":"Implementing a solver interface","title":"Implementing a solver interface","text":"Follow the guide How to test a solver to set up the tests for your package.","category":"page"},{"location":"tutorials/implementing/","page":"Implementing a solver interface","title":"Implementing a solver interface","text":"tip: Tip\nRun the tests frequently when developing. However, at the start there is going to be a lot of errors. Start by excluding large classes of tests (for example, exclude = [\"test_basic_\", \"test_model_\"], implement any missing methods until the tests pass, then remove an exclusion and repeat.","category":"page"},{"location":"tutorials/implementing/#Initial-code","page":"Implementing a solver interface","title":"Initial code","text":"","category":"section"},{"location":"tutorials/implementing/","page":"Implementing a solver interface","title":"Implementing a solver interface","text":"By this point, you should have a package setup with tests, formatting, and access to the underlying solver. Now it's time to start writing the wrapper.","category":"page"},{"location":"tutorials/implementing/#The-Optimizer-object","page":"Implementing a solver interface","title":"The Optimizer object","text":"","category":"section"},{"location":"tutorials/implementing/","page":"Implementing a solver interface","title":"Implementing a solver interface","text":"The first object to create is a subtype of AbstractOptimizer. This type is going to store everything related to the problem.","category":"page"},{"location":"tutorials/implementing/","page":"Implementing a solver interface","title":"Implementing a solver interface","text":"By convention, these optimizers should not be exported and should be named PackageName.Optimizer.","category":"page"},{"location":"tutorials/implementing/","page":"Implementing a solver interface","title":"Implementing a solver interface","text":"import MathOptInterface as MOI\n\nstruct Optimizer <: MOI.AbstractOptimizer\n # Fields go here\nend","category":"page"},{"location":"tutorials/implementing/#Optimizer-objects-for-C-solvers","page":"Implementing a solver interface","title":"Optimizer objects for C solvers","text":"","category":"section"},{"location":"tutorials/implementing/","page":"Implementing a solver interface","title":"Implementing a solver interface","text":"warning: Warning\nThis section is important if you wrap a solver written in C.","category":"page"},{"location":"tutorials/implementing/","page":"Implementing a solver interface","title":"Implementing a solver interface","text":"Wrapping a solver written in C will require the use of pointers, and for you to manually free the solver's memory when the Optimizer is garbage collected by Julia.","category":"page"},{"location":"tutorials/implementing/","page":"Implementing a solver interface","title":"Implementing a solver interface","text":"Never pass a pointer directly to a Julia ccall function.","category":"page"},{"location":"tutorials/implementing/","page":"Implementing a solver interface","title":"Implementing a solver interface","text":"Instead, store the pointer as a field in your Optimizer, and implement Base.cconvert and Base.unsafe_convert. Then you can pass Optimizer to any ccall function that expects the pointer.","category":"page"},{"location":"tutorials/implementing/","page":"Implementing a solver interface","title":"Implementing a solver interface","text":"In addition, make sure you implement a finalizer for each model you create.","category":"page"},{"location":"tutorials/implementing/","page":"Implementing a solver interface","title":"Implementing a solver interface","text":"If newsolver_createProblem() is the low-level function that creates the problem pointer in C, and newsolver_freeProblem(::Ptr{Cvoid}) is the low-level function that frees memory associated with the pointer, your Optimizer() function should look like this:","category":"page"},{"location":"tutorials/implementing/","page":"Implementing a solver interface","title":"Implementing a solver interface","text":"struct Optimizer <: MOI.AbstractOptimizer\n ptr::Ptr{Cvoid}\n\n function Optimizer()\n ptr = newsolver_createProblem()\n model = Optimizer(ptr)\n finalizer(model) do m\n newsolver_freeProblem(m)\n return\n end\n return model\n end\nend\n\nBase.cconvert(::Type{Ptr{Cvoid}}, model::Optimizer) = model\nBase.unsafe_convert(::Type{Ptr{Cvoid}}, model::Optimizer) = model.ptr","category":"page"},{"location":"tutorials/implementing/#Implement-methods-for-Optimizer","page":"Implementing a solver interface","title":"Implement methods for Optimizer","text":"","category":"section"},{"location":"tutorials/implementing/","page":"Implementing a solver interface","title":"Implementing a solver interface","text":"All Optimizers must implement the following methods:","category":"page"},{"location":"tutorials/implementing/","page":"Implementing a solver interface","title":"Implementing a solver interface","text":"empty!\nis_empty","category":"page"},{"location":"tutorials/implementing/","page":"Implementing a solver interface","title":"Implementing a solver interface","text":"Other methods, detailed below, are optional or depend on how you implement the interface.","category":"page"},{"location":"tutorials/implementing/","page":"Implementing a solver interface","title":"Implementing a solver interface","text":"tip: Tip\nFor this and all future methods, read the docstrings to understand what each method does, what it expects as input, and what it produces as output. If it isn't clear, let us know and we will improve the docstrings. It is also very helpful to look at an existing wrapper for a similar solver.","category":"page"},{"location":"tutorials/implementing/","page":"Implementing a solver interface","title":"Implementing a solver interface","text":"You should also implement Base.show(::IO, ::Optimizer) to print a nice string when someone prints your model. For example","category":"page"},{"location":"tutorials/implementing/","page":"Implementing a solver interface","title":"Implementing a solver interface","text":"function Base.show(io::IO, model::Optimizer)\n return print(io, \"NewSolver with the pointer $(model.ptr)\")\nend","category":"page"},{"location":"tutorials/implementing/#Implement-attributes","page":"Implementing a solver interface","title":"Implement attributes","text":"","category":"section"},{"location":"tutorials/implementing/","page":"Implementing a solver interface","title":"Implementing a solver interface","text":"MathOptInterface uses attributes to manage different aspects of the problem.","category":"page"},{"location":"tutorials/implementing/","page":"Implementing a solver interface","title":"Implementing a solver interface","text":"For each attribute","category":"page"},{"location":"tutorials/implementing/","page":"Implementing a solver interface","title":"Implementing a solver interface","text":"get gets the current value of the attribute\nset sets a new value of the attribute. Not all attributes can be set. For example, the user can't modify the SolverName.\nsupports returns a Bool indicating whether the solver supports the attribute.","category":"page"},{"location":"tutorials/implementing/","page":"Implementing a solver interface","title":"Implementing a solver interface","text":"info: Info\nUse attribute_value_type to check the value expected by a given attribute. You should make sure that your get function correctly infers to this type (or a subtype of it).","category":"page"},{"location":"tutorials/implementing/","page":"Implementing a solver interface","title":"Implementing a solver interface","text":"Each column in the table indicates whether you need to implement the particular method for each attribute.","category":"page"},{"location":"tutorials/implementing/","page":"Implementing a solver interface","title":"Implementing a solver interface","text":"Attribute get set supports\nSolverName Yes No No\nSolverVersion Yes No No\nRawSolver Yes No No\nName Yes Yes Yes\nSilent Yes Yes Yes\nTimeLimitSec Yes Yes Yes\nObjectiveLimit Yes Yes Yes\nRawOptimizerAttribute Yes Yes Yes\nNumberOfThreads Yes Yes Yes\nAbsoluteGapTolerance Yes Yes Yes\nRelativeGapTolerance Yes Yes Yes","category":"page"},{"location":"tutorials/implementing/","page":"Implementing a solver interface","title":"Implementing a solver interface","text":"For example:","category":"page"},{"location":"tutorials/implementing/","page":"Implementing a solver interface","title":"Implementing a solver interface","text":"function MOI.get(model::Optimizer, ::MOI.Silent)\n return # true if MOI.Silent is set\nend\n\nfunction MOI.set(model::Optimizer, ::MOI.Silent, v::Bool)\n if v\n # Set a parameter to turn off printing\n else\n # Restore the default printing\n end\n return\nend\n\nMOI.supports(::Optimizer, ::MOI.Silent) = true","category":"page"},{"location":"tutorials/implementing/#Define-supports_constraint","page":"Implementing a solver interface","title":"Define supports_constraint","text":"","category":"section"},{"location":"tutorials/implementing/","page":"Implementing a solver interface","title":"Implementing a solver interface","text":"The next step is to define which constraints and objective functions you plan to support.","category":"page"},{"location":"tutorials/implementing/","page":"Implementing a solver interface","title":"Implementing a solver interface","text":"For each function-set constraint pair, define supports_constraint:","category":"page"},{"location":"tutorials/implementing/","page":"Implementing a solver interface","title":"Implementing a solver interface","text":"function MOI.supports_constraint(\n ::Optimizer,\n ::Type{MOI.VariableIndex},\n ::Type{MOI.ZeroOne},\n)\n return true\nend","category":"page"},{"location":"tutorials/implementing/","page":"Implementing a solver interface","title":"Implementing a solver interface","text":"To make this easier, you may want to use Unions:","category":"page"},{"location":"tutorials/implementing/","page":"Implementing a solver interface","title":"Implementing a solver interface","text":"function MOI.supports_constraint(\n ::Optimizer,\n ::Type{MOI.VariableIndex},\n ::Type{<:Union{MOI.LessThan,MOI.GreaterThan,MOI.EqualTo}},\n)\n return true\nend","category":"page"},{"location":"tutorials/implementing/","page":"Implementing a solver interface","title":"Implementing a solver interface","text":"tip: Tip\nOnly support a constraint if your solver has native support for it.","category":"page"},{"location":"tutorials/implementing/#The-big-decision:-incremental-modification?","page":"Implementing a solver interface","title":"The big decision: incremental modification?","text":"","category":"section"},{"location":"tutorials/implementing/","page":"Implementing a solver interface","title":"Implementing a solver interface","text":"Now you need to decide whether to support incremental modification or not.","category":"page"},{"location":"tutorials/implementing/","page":"Implementing a solver interface","title":"Implementing a solver interface","text":"Incremental modification means that the user can add variables and constraints one-by-one without needing to rebuild the entire problem, and they can modify the problem data after an optimize! call. Supporting incremental modification means implementing functions like add_variable and add_constraint.","category":"page"},{"location":"tutorials/implementing/","page":"Implementing a solver interface","title":"Implementing a solver interface","text":"The alternative is to accept the problem data in a single optimize! or copy_to function call. Because these functions see all of the data at once, it can typically call a more efficient function to load data into the underlying solver.","category":"page"},{"location":"tutorials/implementing/","page":"Implementing a solver interface","title":"Implementing a solver interface","text":"Good examples of solvers supporting incremental modification are MILP solvers like GLPK.jl and Gurobi.jl. Examples of non-incremental solvers are AmplNLWriter.jl and SCS.jl","category":"page"},{"location":"tutorials/implementing/","page":"Implementing a solver interface","title":"Implementing a solver interface","text":"It is possible for a solver to implement both approaches, but you should probably start with one for simplicity.","category":"page"},{"location":"tutorials/implementing/","page":"Implementing a solver interface","title":"Implementing a solver interface","text":"tip: Tip\nOnly support incremental modification if your solver has native support for it.","category":"page"},{"location":"tutorials/implementing/","page":"Implementing a solver interface","title":"Implementing a solver interface","text":"In general, supporting incremental modification is more work, and it usually requires some extra book-keeping. However, it provides a more efficient interface to the solver if the problem is going to be resolved multiple times with small modifications. Moreover, once you've implemented incremental modification, it's usually not much extra work to add a copy_to interface. The converse is not true.","category":"page"},{"location":"tutorials/implementing/","page":"Implementing a solver interface","title":"Implementing a solver interface","text":"tip: Tip\nIf this is your first time writing an interface, start with the one-shot optimize!.","category":"page"},{"location":"tutorials/implementing/#The-non-incremental-interface","page":"Implementing a solver interface","title":"The non-incremental interface","text":"","category":"section"},{"location":"tutorials/implementing/","page":"Implementing a solver interface","title":"Implementing a solver interface","text":"There are two ways to implement the non-incremental interface. The first uses a two-argument version of optimize!, the second implements copy_to followed by the one-argument version of optimize!.","category":"page"},{"location":"tutorials/implementing/","page":"Implementing a solver interface","title":"Implementing a solver interface","text":"If your solver does not support modification, and requires all data to solve the problem in a single function call, you should implement the \"one-shot\" optimize!.","category":"page"},{"location":"tutorials/implementing/","page":"Implementing a solver interface","title":"Implementing a solver interface","text":"optimize!(::ModelLike, ::ModelLike)","category":"page"},{"location":"tutorials/implementing/","page":"Implementing a solver interface","title":"Implementing a solver interface","text":"If your solver separates data loading and the actual optimization into separate steps, implement the copy_to interface.","category":"page"},{"location":"tutorials/implementing/","page":"Implementing a solver interface","title":"Implementing a solver interface","text":"copy_to(::ModelLike, ::ModelLike)\noptimize!(::ModelLike)","category":"page"},{"location":"tutorials/implementing/#The-incremental-interface","page":"Implementing a solver interface","title":"The incremental interface","text":"","category":"section"},{"location":"tutorials/implementing/","page":"Implementing a solver interface","title":"Implementing a solver interface","text":"warning: Warning\nWriting this interface is a lot of work. The easiest way is to consult the source code of a similar solver.","category":"page"},{"location":"tutorials/implementing/","page":"Implementing a solver interface","title":"Implementing a solver interface","text":"To implement the incremental interface, implement the following functions:","category":"page"},{"location":"tutorials/implementing/","page":"Implementing a solver interface","title":"Implementing a solver interface","text":"add_variable\nadd_variables\nadd_constraint\nadd_constraints\nis_valid\ndelete\noptimize!(::ModelLike)","category":"page"},{"location":"tutorials/implementing/","page":"Implementing a solver interface","title":"Implementing a solver interface","text":"info: Info\nSolvers do not have to support AbstractScalarFunction in GreaterThan, LessThan, EqualTo, or Interval with a nonzero constant in the function. Throw ScalarFunctionConstantNotZero if the function constant is not zero.","category":"page"},{"location":"tutorials/implementing/","page":"Implementing a solver interface","title":"Implementing a solver interface","text":"In addition, you should implement the following model attributes:","category":"page"},{"location":"tutorials/implementing/","page":"Implementing a solver interface","title":"Implementing a solver interface","text":"Attribute get set supports\nListOfModelAttributesSet Yes No No\nObjectiveFunctionType Yes No No\nObjectiveFunction Yes Yes Yes\nObjectiveSense Yes Yes Yes\nName Yes Yes Yes","category":"page"},{"location":"tutorials/implementing/","page":"Implementing a solver interface","title":"Implementing a solver interface","text":"Variable-related attributes:","category":"page"},{"location":"tutorials/implementing/","page":"Implementing a solver interface","title":"Implementing a solver interface","text":"Attribute get set supports\nListOfVariableAttributesSet Yes No No\nNumberOfVariables Yes No No\nListOfVariableIndices Yes No No","category":"page"},{"location":"tutorials/implementing/","page":"Implementing a solver interface","title":"Implementing a solver interface","text":"Constraint-related attributes:","category":"page"},{"location":"tutorials/implementing/","page":"Implementing a solver interface","title":"Implementing a solver interface","text":"Attribute get set supports\nListOfConstraintAttributesSet Yes No No\nNumberOfConstraints Yes No No\nListOfConstraintTypesPresent Yes No No\nConstraintFunction Yes Yes No\nConstraintSet Yes Yes No","category":"page"},{"location":"tutorials/implementing/#Modifications","page":"Implementing a solver interface","title":"Modifications","text":"","category":"section"},{"location":"tutorials/implementing/","page":"Implementing a solver interface","title":"Implementing a solver interface","text":"If your solver supports modifying data in-place, implement modify for the following AbstractModifications:","category":"page"},{"location":"tutorials/implementing/","page":"Implementing a solver interface","title":"Implementing a solver interface","text":"ScalarConstantChange\nScalarCoefficientChange\nVectorConstantChange\nMultirowChange","category":"page"},{"location":"tutorials/implementing/#Variables-constrained-on-creation","page":"Implementing a solver interface","title":"Variables constrained on creation","text":"","category":"section"},{"location":"tutorials/implementing/","page":"Implementing a solver interface","title":"Implementing a solver interface","text":"Some solvers require variables be associated with a set when they are created. This conflicts with the incremental modification approach, since you cannot first add a free variable and then constrain it to the set.","category":"page"},{"location":"tutorials/implementing/","page":"Implementing a solver interface","title":"Implementing a solver interface","text":"If this is the case, implement:","category":"page"},{"location":"tutorials/implementing/","page":"Implementing a solver interface","title":"Implementing a solver interface","text":"add_constrained_variable\nadd_constrained_variables\nsupports_add_constrained_variables","category":"page"},{"location":"tutorials/implementing/","page":"Implementing a solver interface","title":"Implementing a solver interface","text":"By default, MathOptInterface assumes solvers support free variables. If your solver does not support free variables, define:","category":"page"},{"location":"tutorials/implementing/","page":"Implementing a solver interface","title":"Implementing a solver interface","text":"MOI.supports_add_constrained_variables(::Optimizer, ::Type{Reals}) = false","category":"page"},{"location":"tutorials/implementing/#Incremental-and-copy_to","page":"Implementing a solver interface","title":"Incremental and copy_to","text":"","category":"section"},{"location":"tutorials/implementing/","page":"Implementing a solver interface","title":"Implementing a solver interface","text":"If you implement the incremental interface, you have the option of also implementing copy_to.","category":"page"},{"location":"tutorials/implementing/","page":"Implementing a solver interface","title":"Implementing a solver interface","text":"If you don't want to implement copy_to, for example, because the solver has no API for building the problem in a single function call, define the following fallback:","category":"page"},{"location":"tutorials/implementing/","page":"Implementing a solver interface","title":"Implementing a solver interface","text":"MOI.supports_incremental_interface(::Optimizer) = true\n\nfunction MOI.copy_to(dest::Optimizer, src::MOI.ModelLike)\n return MOI.Utilities.default_copy_to(dest, src)\nend","category":"page"},{"location":"tutorials/implementing/#implement_names","page":"Implementing a solver interface","title":"Names","text":"","category":"section"},{"location":"tutorials/implementing/","page":"Implementing a solver interface","title":"Implementing a solver interface","text":"Regardless of which interface you implement, you have the option of implementing the Name attribute for variables and constraints:","category":"page"},{"location":"tutorials/implementing/","page":"Implementing a solver interface","title":"Implementing a solver interface","text":"Attribute get set supports\nVariableName Yes Yes Yes\nConstraintName Yes Yes Yes","category":"page"},{"location":"tutorials/implementing/","page":"Implementing a solver interface","title":"Implementing a solver interface","text":"If you implement names, you must also implement the following three methods:","category":"page"},{"location":"tutorials/implementing/","page":"Implementing a solver interface","title":"Implementing a solver interface","text":"function MOI.get(model::Optimizer, ::Type{MOI.VariableIndex}, name::String)\n return # The variable named `name`.\nend\n\nfunction MOI.get(model::Optimizer, ::Type{MOI.ConstraintIndex}, name::String)\n return # The constraint any type named `name`.\nend\n\nfunction MOI.get(\n model::Optimizer,\n ::Type{MOI.ConstraintIndex{F,S}},\n name::String,\n) where {F,S}\n return # The constraint of type F-in-S named `name`.\nend","category":"page"},{"location":"tutorials/implementing/","page":"Implementing a solver interface","title":"Implementing a solver interface","text":"These methods have the following rules:","category":"page"},{"location":"tutorials/implementing/","page":"Implementing a solver interface","title":"Implementing a solver interface","text":"If there is no variable or constraint with the name, return nothing\nIf there is a single variable or constraint with that name, return the variable or constraint\nIf there are multiple variables or constraints with the name, throw an error.","category":"page"},{"location":"tutorials/implementing/","page":"Implementing a solver interface","title":"Implementing a solver interface","text":"warning: Warning\nYou should not implement ConstraintName for VariableIndex constraints. If you implement ConstraintName for other constraints, you can add the following two methods to disable ConstraintName for VariableIndex constraints.function MOI.supports(\n ::Optimizer,\n ::MOI.ConstraintName,\n ::Type{<:MOI.ConstraintIndex{MOI.VariableIndex,<:MOI.AbstractScalarSet}},\n)\n return throw(MOI.VariableIndexConstraintNameError())\nend\nfunction MOI.set(\n ::Optimizer,\n ::MOI.ConstraintName,\n ::MOI.ConstraintIndex{MOI.VariableIndex,<:MOI.AbstractScalarSet},\n ::String,\n)\n return throw(MOI.VariableIndexConstraintNameError())\nend","category":"page"},{"location":"tutorials/implementing/#Solutions","page":"Implementing a solver interface","title":"Solutions","text":"","category":"section"},{"location":"tutorials/implementing/","page":"Implementing a solver interface","title":"Implementing a solver interface","text":"Implement optimize! to solve the model:","category":"page"},{"location":"tutorials/implementing/","page":"Implementing a solver interface","title":"Implementing a solver interface","text":"optimize!","category":"page"},{"location":"tutorials/implementing/","page":"Implementing a solver interface","title":"Implementing a solver interface","text":"All Optimizers must implement the following attributes:","category":"page"},{"location":"tutorials/implementing/","page":"Implementing a solver interface","title":"Implementing a solver interface","text":"DualStatus\nPrimalStatus\nRawStatusString\nResultCount\nTerminationStatus","category":"page"},{"location":"tutorials/implementing/","page":"Implementing a solver interface","title":"Implementing a solver interface","text":"info: Info\nYou only need to implement get for solution attributes. Don't implement set or supports.","category":"page"},{"location":"tutorials/implementing/","page":"Implementing a solver interface","title":"Implementing a solver interface","text":"note: Note\nSolver wrappers should document how the low-level statuses map to the MOI statuses. Statuses like NEARLY_FEASIBLE_POINT and INFEASIBLE_POINT, are designed to be used when the solver explicitly indicates that relaxed tolerances are satisfied or the returned point is infeasible, respectively.","category":"page"},{"location":"tutorials/implementing/","page":"Implementing a solver interface","title":"Implementing a solver interface","text":"You should also implement the following attributes:","category":"page"},{"location":"tutorials/implementing/","page":"Implementing a solver interface","title":"Implementing a solver interface","text":"ObjectiveValue\nSolveTimeSec\nVariablePrimal","category":"page"},{"location":"tutorials/implementing/","page":"Implementing a solver interface","title":"Implementing a solver interface","text":"tip: Tip\nAttributes like VariablePrimal and ObjectiveValue are indexed by the result count. Use MOI.check_result_index_bounds(model, attr) to throw an error if the attribute is not available.","category":"page"},{"location":"tutorials/implementing/","page":"Implementing a solver interface","title":"Implementing a solver interface","text":"If your solver returns dual solutions, implement:","category":"page"},{"location":"tutorials/implementing/","page":"Implementing a solver interface","title":"Implementing a solver interface","text":"ConstraintDual\nDualObjectiveValue","category":"page"},{"location":"tutorials/implementing/","page":"Implementing a solver interface","title":"Implementing a solver interface","text":"For integer solvers, implement:","category":"page"},{"location":"tutorials/implementing/","page":"Implementing a solver interface","title":"Implementing a solver interface","text":"ObjectiveBound\nRelativeGap","category":"page"},{"location":"tutorials/implementing/","page":"Implementing a solver interface","title":"Implementing a solver interface","text":"If applicable, implement:","category":"page"},{"location":"tutorials/implementing/","page":"Implementing a solver interface","title":"Implementing a solver interface","text":"SimplexIterations\nBarrierIterations\nNodeCount","category":"page"},{"location":"tutorials/implementing/","page":"Implementing a solver interface","title":"Implementing a solver interface","text":"If your solver uses the Simplex method, implement:","category":"page"},{"location":"tutorials/implementing/","page":"Implementing a solver interface","title":"Implementing a solver interface","text":"ConstraintBasisStatus","category":"page"},{"location":"tutorials/implementing/","page":"Implementing a solver interface","title":"Implementing a solver interface","text":"If your solver accepts primal or dual warm-starts, implement:","category":"page"},{"location":"tutorials/implementing/","page":"Implementing a solver interface","title":"Implementing a solver interface","text":"VariablePrimalStart\nConstraintDualStart","category":"page"},{"location":"tutorials/implementing/#Other-tips","page":"Implementing a solver interface","title":"Other tips","text":"","category":"section"},{"location":"tutorials/implementing/","page":"Implementing a solver interface","title":"Implementing a solver interface","text":"Here are some other points to be aware of when writing your wrapper.","category":"page"},{"location":"tutorials/implementing/#Unsupported-constraints-at-runtime","page":"Implementing a solver interface","title":"Unsupported constraints at runtime","text":"","category":"section"},{"location":"tutorials/implementing/","page":"Implementing a solver interface","title":"Implementing a solver interface","text":"In some cases, your solver may support a particular type of constraint (for example, quadratic constraints), but only if the data meets some condition (for example, it is convex).","category":"page"},{"location":"tutorials/implementing/","page":"Implementing a solver interface","title":"Implementing a solver interface","text":"In this case, declare that you support the constraint, and throw AddConstraintNotAllowed.","category":"page"},{"location":"tutorials/implementing/#Dealing-with-multiple-variable-bounds","page":"Implementing a solver interface","title":"Dealing with multiple variable bounds","text":"","category":"section"},{"location":"tutorials/implementing/","page":"Implementing a solver interface","title":"Implementing a solver interface","text":"MathOptInterface uses VariableIndex constraints to represent variable bounds. Defining multiple variable bounds on a single variable is not allowed.","category":"page"},{"location":"tutorials/implementing/","page":"Implementing a solver interface","title":"Implementing a solver interface","text":"Throw LowerBoundAlreadySet or UpperBoundAlreadySet if the user adds a constraint that results in multiple bounds.","category":"page"},{"location":"tutorials/implementing/","page":"Implementing a solver interface","title":"Implementing a solver interface","text":"Only throw if the constraints conflict. It is okay to add VariableIndex-in-GreaterThan and then VariableIndex-in-LessThan, but not VariableIndex-in-Interval and then VariableIndex-in-LessThan,","category":"page"},{"location":"tutorials/implementing/#Expect-duplicate-coefficients","page":"Implementing a solver interface","title":"Expect duplicate coefficients","text":"","category":"section"},{"location":"tutorials/implementing/","page":"Implementing a solver interface","title":"Implementing a solver interface","text":"Solvers must expect that functions such as ScalarAffineFunction and VectorQuadraticFunction may contain duplicate coefficients.","category":"page"},{"location":"tutorials/implementing/","page":"Implementing a solver interface","title":"Implementing a solver interface","text":"For example, ScalarAffineFunction([ScalarAffineTerm(x, 1), ScalarAffineTerm(x, 1)], 0.0).","category":"page"},{"location":"tutorials/implementing/","page":"Implementing a solver interface","title":"Implementing a solver interface","text":"Use Utilities.canonical to return a new function with the duplicate coefficients aggregated together.","category":"page"},{"location":"tutorials/implementing/#Don't-modify-user-data","page":"Implementing a solver interface","title":"Don't modify user-data","text":"","category":"section"},{"location":"tutorials/implementing/","page":"Implementing a solver interface","title":"Implementing a solver interface","text":"All data passed to the solver must be copied immediately to internal data structures. Solvers may not modify any input vectors and must assume that input vectors will not be modified by users in the future.","category":"page"},{"location":"tutorials/implementing/","page":"Implementing a solver interface","title":"Implementing a solver interface","text":"This applies, for example, to the terms vector in ScalarAffineFunction. Vectors returned to the user, for example, via ObjectiveFunction or ConstraintFunction attributes, must not be modified by the solver afterwards. The in-place version of get! can be used by users to avoid extra copies in this case.","category":"page"},{"location":"tutorials/implementing/#Column-Generation","page":"Implementing a solver interface","title":"Column Generation","text":"","category":"section"},{"location":"tutorials/implementing/","page":"Implementing a solver interface","title":"Implementing a solver interface","text":"There is no special interface for column generation. If the solver has a special API for setting coefficients in existing constraints when adding a new variable, it is possible to queue modifications and new variables and then call the solver's API once all of the new coefficients are known.","category":"page"},{"location":"tutorials/implementing/#Solver-specific-attributes","page":"Implementing a solver interface","title":"Solver-specific attributes","text":"","category":"section"},{"location":"tutorials/implementing/","page":"Implementing a solver interface","title":"Implementing a solver interface","text":"You don't need to restrict yourself to the attributes defined in the MathOptInterface.jl package.","category":"page"},{"location":"tutorials/implementing/","page":"Implementing a solver interface","title":"Implementing a solver interface","text":"Solver-specific attributes should be specified by creating an appropriate subtype of AbstractModelAttribute, AbstractOptimizerAttribute, AbstractVariableAttribute, or AbstractConstraintAttribute.","category":"page"},{"location":"tutorials/implementing/","page":"Implementing a solver interface","title":"Implementing a solver interface","text":"For example, Gurobi.jl adds attributes for multiobjective optimization by defining:","category":"page"},{"location":"tutorials/implementing/","page":"Implementing a solver interface","title":"Implementing a solver interface","text":"struct NumberOfObjectives <: MOI.AbstractModelAttribute end\n\nfunction MOI.set(model::Optimizer, ::NumberOfObjectives, n::Integer)\n # Code to set NumberOfObjectives\n return\nend\n\nfunction MOI.get(model::Optimizer, ::NumberOfObjectives)\n n = # Code to get NumberOfObjectives\n return n\nend","category":"page"},{"location":"tutorials/implementing/","page":"Implementing a solver interface","title":"Implementing a solver interface","text":"Then, the user can write:","category":"page"},{"location":"tutorials/implementing/","page":"Implementing a solver interface","title":"Implementing a solver interface","text":"model = Gurobi.Optimizer()\nMOI.set(model, Gurobi.NumberofObjectives(), 3)","category":"page"},{"location":"submodules/Nonlinear/reference/","page":"API Reference","title":"API Reference","text":"CurrentModule = MathOptInterface\nDocTestSetup = quote\n import MathOptInterface as MOI\nend\nDocTestFilters = [r\"MathOptInterface|MOI\"]","category":"page"},{"location":"submodules/Nonlinear/reference/#NonlinearAPI","page":"API Reference","title":"Nonlinear Modeling","text":"","category":"section"},{"location":"submodules/Nonlinear/reference/","page":"API Reference","title":"API Reference","text":"More information can be found in the Nonlinear section of the manual.","category":"page"},{"location":"submodules/Nonlinear/reference/","page":"API Reference","title":"API Reference","text":"Nonlinear\nNonlinear.Model","category":"page"},{"location":"submodules/Nonlinear/reference/#MathOptInterface.Nonlinear","page":"API Reference","title":"MathOptInterface.Nonlinear","text":"Nonlinear\n\nwarning: Warning\nThe Nonlinear submodule is experimental. Until this message is removed, breaking changes may be introduced in any minor or patch release of MathOptInterface.\n\n\n\n\n\n","category":"module"},{"location":"submodules/Nonlinear/reference/#MathOptInterface.Nonlinear.Model","page":"API Reference","title":"MathOptInterface.Nonlinear.Model","text":"Model()\n\nThe core datastructure for representing a nonlinear optimization problem.\n\nIt has the following fields:\n\nobjective::Union{Nothing,Expression} : holds the nonlinear objective function, if one exists, otherwise nothing.\nexpressions::Vector{Expression} : a vector of expressions in the model.\nconstraints::OrderedDict{ConstraintIndex,Constraint} : a map from ConstraintIndex to the corresponding Constraint. An OrderedDict is used instead of a Vector to support constraint deletion.\nparameters::Vector{Float64} : holds the current values of the parameters.\noperators::OperatorRegistry : stores the operators used in the model.\n\n\n\n\n\n","category":"type"},{"location":"submodules/Nonlinear/reference/#nonlinear_api_expressions","page":"API Reference","title":"Expressions","text":"","category":"section"},{"location":"submodules/Nonlinear/reference/","page":"API Reference","title":"API Reference","text":"Nonlinear.ExpressionIndex\nNonlinear.add_expression","category":"page"},{"location":"submodules/Nonlinear/reference/#MathOptInterface.Nonlinear.ExpressionIndex","page":"API Reference","title":"MathOptInterface.Nonlinear.ExpressionIndex","text":"ExpressionIndex\n\nAn index to a nonlinear expression that is returned by add_expression.\n\nGiven data::Model and ex::ExpressionIndex, use data[ex] to retrieve the corresponding Expression.\n\n\n\n\n\n","category":"type"},{"location":"submodules/Nonlinear/reference/#MathOptInterface.Nonlinear.add_expression","page":"API Reference","title":"MathOptInterface.Nonlinear.add_expression","text":"add_expression(model::Model, expr)::ExpressionIndex\n\nParse expr into a Expression and add to model. Returns an ExpressionIndex that can be interpolated into other input expressions.\n\nexpr must be a type that is supported by parse_expression.\n\nExamples\n\nmodel = Model()\nx = MOI.VariableIndex(1)\nex = add_expression(model, :($x^2 + 1))\nset_objective(model, :(sqrt($ex)))\n\n\n\n\n\n","category":"function"},{"location":"submodules/Nonlinear/reference/#nonlinear_api_parameters","page":"API Reference","title":"Parameters","text":"","category":"section"},{"location":"submodules/Nonlinear/reference/","page":"API Reference","title":"API Reference","text":"Nonlinear.ParameterIndex\nNonlinear.add_parameter","category":"page"},{"location":"submodules/Nonlinear/reference/#MathOptInterface.Nonlinear.ParameterIndex","page":"API Reference","title":"MathOptInterface.Nonlinear.ParameterIndex","text":"ParameterIndex\n\nAn index to a nonlinear parameter that is returned by add_parameter. Given data::Model and p::ParameterIndex, use data[p] to retrieve the current value of the parameter and data[p] = value to set a new value.\n\n\n\n\n\n","category":"type"},{"location":"submodules/Nonlinear/reference/#MathOptInterface.Nonlinear.add_parameter","page":"API Reference","title":"MathOptInterface.Nonlinear.add_parameter","text":"add_parameter(model::Model, value::Float64)::ParameterIndex\n\nAdd 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.\n\nExamples\n\nmodel = Model()\nx = MOI.VariableIndex(1)\np = add_parameter(model, 1.2)\nc = add_constraint(model, :($x^2 - $p), MOI.LessThan(0.0))\n\n\n\n\n\n","category":"function"},{"location":"submodules/Nonlinear/reference/#nonlinear_api_objectives","page":"API Reference","title":"Objectives","text":"","category":"section"},{"location":"submodules/Nonlinear/reference/","page":"API Reference","title":"API Reference","text":"Nonlinear.set_objective","category":"page"},{"location":"submodules/Nonlinear/reference/#MathOptInterface.Nonlinear.set_objective","page":"API Reference","title":"MathOptInterface.Nonlinear.set_objective","text":"set_objective(model::Model, obj)::Nothing\n\nParse obj into a Expression and set as the objective function of model.\n\nobj must be a type that is supported by parse_expression.\n\nTo remove the objective, pass nothing.\n\nExamples\n\nmodel = Model()\nx = MOI.VariableIndex(1)\nset_objective(model, :($x^2 + 1))\nset_objective(model, x)\nset_objective(model, nothing)\n\n\n\n\n\n","category":"function"},{"location":"submodules/Nonlinear/reference/#nonlinear_api_constraints","page":"API Reference","title":"Constraints","text":"","category":"section"},{"location":"submodules/Nonlinear/reference/","page":"API Reference","title":"API Reference","text":"Nonlinear.ConstraintIndex\nNonlinear.add_constraint\nNonlinear.delete","category":"page"},{"location":"submodules/Nonlinear/reference/#MathOptInterface.Nonlinear.ConstraintIndex","page":"API Reference","title":"MathOptInterface.Nonlinear.ConstraintIndex","text":"ConstraintIndex\n\nAn index to a nonlinear constraint that is returned by add_constraint.\n\nGiven data::Model and c::ConstraintIndex, use data[c] to retrieve the corresponding Constraint.\n\n\n\n\n\n","category":"type"},{"location":"submodules/Nonlinear/reference/#MathOptInterface.Nonlinear.add_constraint","page":"API Reference","title":"MathOptInterface.Nonlinear.add_constraint","text":"add_constraint(\n model::Model,\n func,\n set::Union{\n MOI.GreaterThan{Float64},\n MOI.LessThan{Float64},\n MOI.Interval{Float64},\n MOI.EqualTo{Float64},\n },\n)\n\nParse 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.\n\nExamples\n\nmodel = Model()\nx = MOI.VariableIndex(1)\nc = add_constraint(model, :($x^2), MOI.LessThan(1.0))\n\n\n\n\n\n","category":"function"},{"location":"submodules/Nonlinear/reference/#MathOptInterface.Nonlinear.delete","page":"API Reference","title":"MathOptInterface.Nonlinear.delete","text":"delete(model::Model, c::ConstraintIndex)::Nothing\n\nDelete the constraint index c from model.\n\nExamples\n\nmodel = Model()\nx = MOI.VariableIndex(1)\nc = add_constraint(model, :($x^2), MOI.LessThan(1.0))\ndelete(model, c)\n\n\n\n\n\n","category":"function"},{"location":"submodules/Nonlinear/reference/#nonlinear_api_operators","page":"API Reference","title":"User-defined operators","text":"","category":"section"},{"location":"submodules/Nonlinear/reference/","page":"API Reference","title":"API Reference","text":"Nonlinear.OperatorRegistry\nNonlinear.DEFAULT_UNIVARIATE_OPERATORS\nNonlinear.DEFAULT_MULTIVARIATE_OPERATORS\nNonlinear.register_operator\nNonlinear.register_operator_if_needed\nNonlinear.assert_registered\nNonlinear.check_return_type\nNonlinear.eval_univariate_function\nNonlinear.eval_univariate_gradient\nNonlinear.eval_univariate_hessian\nNonlinear.eval_multivariate_function\nNonlinear.eval_multivariate_gradient\nNonlinear.eval_multivariate_hessian\nNonlinear.eval_logic_function\nNonlinear.eval_comparison_function","category":"page"},{"location":"submodules/Nonlinear/reference/#MathOptInterface.Nonlinear.OperatorRegistry","page":"API Reference","title":"MathOptInterface.Nonlinear.OperatorRegistry","text":"OperatorRegistry()\n\nCreate a new OperatorRegistry to store and evaluate univariate and multivariate operators.\n\n\n\n\n\n","category":"type"},{"location":"submodules/Nonlinear/reference/#MathOptInterface.Nonlinear.DEFAULT_UNIVARIATE_OPERATORS","page":"API Reference","title":"MathOptInterface.Nonlinear.DEFAULT_UNIVARIATE_OPERATORS","text":"DEFAULT_UNIVARIATE_OPERATORS\n\nThe list of univariate operators that are supported by default.\n\nExample\n\njulia> import MathOptInterface as MOI\n\njulia> MOI.Nonlinear.DEFAULT_UNIVARIATE_OPERATORS\n72-element Vector{Symbol}:\n :+\n :-\n :abs\n :sqrt\n :cbrt\n :abs2\n :inv\n :log\n :log10\n :log2\n ⋮\n :airybi\n :airyaiprime\n :airybiprime\n :besselj0\n :besselj1\n :bessely0\n :bessely1\n :erfcx\n :dawson\n\n\n\n\n\n","category":"constant"},{"location":"submodules/Nonlinear/reference/#MathOptInterface.Nonlinear.DEFAULT_MULTIVARIATE_OPERATORS","page":"API Reference","title":"MathOptInterface.Nonlinear.DEFAULT_MULTIVARIATE_OPERATORS","text":"DEFAULT_MULTIVARIATE_OPERATORS\n\nThe list of multivariate operators that are supported by default.\n\nExample\n\njulia> import MathOptInterface as MOI\n\njulia> MOI.Nonlinear.DEFAULT_MULTIVARIATE_OPERATORS\n9-element Vector{Symbol}:\n :+\n :-\n :*\n :^\n :/\n :ifelse\n :atan\n :min\n :max\n\n\n\n\n\n","category":"constant"},{"location":"submodules/Nonlinear/reference/#MathOptInterface.Nonlinear.register_operator","page":"API Reference","title":"MathOptInterface.Nonlinear.register_operator","text":"register_operator(\n model::Model,\n op::Symbol,\n nargs::Int,\n f::Function,\n [∇f::Function],\n [∇²f::Function],\n)\n\nRegister the user-defined operator op with nargs input arguments in model.\n\nUnivariate functions\n\nf(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.\n∇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.\n∇²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.\n\nMultivariate functions\n\nf(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.\n∇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].\n∇²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.\n\nNotes for multivariate Hessians\n\nH has size(H) == (length(x), length(x)), but you must not access elements H[i, j] for i > j.\nH is dense, but you do not need to fill structural zeros.\n\n\n\n\n\n","category":"function"},{"location":"submodules/Nonlinear/reference/#MathOptInterface.Nonlinear.register_operator_if_needed","page":"API Reference","title":"MathOptInterface.Nonlinear.register_operator_if_needed","text":"register_operator_if_needed(\n registry::OperatorRegistry,\n op::Symbol,\n nargs::Int,\n f::Function;\n)\n\nSimilar to register_operator, but this function warns if the function is not registered, and skips silently if it already is.\n\n\n\n\n\n","category":"function"},{"location":"submodules/Nonlinear/reference/#MathOptInterface.Nonlinear.assert_registered","page":"API Reference","title":"MathOptInterface.Nonlinear.assert_registered","text":"assert_registered(registry::OperatorRegistry, op::Symbol, nargs::Int)\n\nThrow an error if op is not registered in registry with nargs arguments.\n\n\n\n\n\n","category":"function"},{"location":"submodules/Nonlinear/reference/#MathOptInterface.Nonlinear.check_return_type","page":"API Reference","title":"MathOptInterface.Nonlinear.check_return_type","text":"check_return_type(::Type{T}, ret::S) where {T,S}\n\nOverload this method for new types S to throw an informative error if a user-defined function returns the type S instead of T.\n\n\n\n\n\n","category":"function"},{"location":"submodules/Nonlinear/reference/#MathOptInterface.Nonlinear.eval_univariate_function","page":"API Reference","title":"MathOptInterface.Nonlinear.eval_univariate_function","text":"eval_univariate_function(\n registry::OperatorRegistry,\n op::Symbol,\n x::T,\n) where {T}\n\nEvaluate the operator op(x)::T, where op is a univariate function in registry.\n\n\n\n\n\n","category":"function"},{"location":"submodules/Nonlinear/reference/#MathOptInterface.Nonlinear.eval_univariate_gradient","page":"API Reference","title":"MathOptInterface.Nonlinear.eval_univariate_gradient","text":"eval_univariate_gradient(\n registry::OperatorRegistry,\n op::Symbol,\n x::T,\n) where {T}\n\nEvaluate the first-derivative of the operator op(x)::T, where op is a univariate function in registry.\n\n\n\n\n\n","category":"function"},{"location":"submodules/Nonlinear/reference/#MathOptInterface.Nonlinear.eval_univariate_hessian","page":"API Reference","title":"MathOptInterface.Nonlinear.eval_univariate_hessian","text":"eval_univariate_hessian(\n registry::OperatorRegistry,\n op::Symbol,\n x::T,\n) where {T}\n\nEvaluate the second-derivative of the operator op(x)::T, where op is a univariate function in registry.\n\n\n\n\n\n","category":"function"},{"location":"submodules/Nonlinear/reference/#MathOptInterface.Nonlinear.eval_multivariate_function","page":"API Reference","title":"MathOptInterface.Nonlinear.eval_multivariate_function","text":"eval_multivariate_function(\n registry::OperatorRegistry,\n op::Symbol,\n x::AbstractVector{T},\n) where {T}\n\nEvaluate the operator op(x)::T, where op is a multivariate function in registry.\n\n\n\n\n\n","category":"function"},{"location":"submodules/Nonlinear/reference/#MathOptInterface.Nonlinear.eval_multivariate_gradient","page":"API Reference","title":"MathOptInterface.Nonlinear.eval_multivariate_gradient","text":"eval_multivariate_gradient(\n registry::OperatorRegistry,\n op::Symbol,\n g::AbstractVector{T},\n x::AbstractVector{T},\n) where {T}\n\nEvaluate the gradient of operator g .= ∇op(x), where op is a multivariate function in registry.\n\n\n\n\n\n","category":"function"},{"location":"submodules/Nonlinear/reference/#MathOptInterface.Nonlinear.eval_multivariate_hessian","page":"API Reference","title":"MathOptInterface.Nonlinear.eval_multivariate_hessian","text":"eval_multivariate_hessian(\n registry::OperatorRegistry,\n op::Symbol,\n H::AbstractMatrix,\n x::AbstractVector{T},\n) where {T}\n\nEvaluate the Hessian of operator ∇²op(x), where op is a multivariate function in registry.\n\nThe Hessian is stored in the lower-triangular part of the matrix H.\n\nnote: Note\nImplementations of the Hessian operators will not fill structural zeros. Therefore, before calling this function you should pre-populate the matrix H with 0.\n\n\n\n\n\n","category":"function"},{"location":"submodules/Nonlinear/reference/#MathOptInterface.Nonlinear.eval_logic_function","page":"API Reference","title":"MathOptInterface.Nonlinear.eval_logic_function","text":"eval_logic_function(\n registry::OperatorRegistry,\n op::Symbol,\n lhs::T,\n rhs::T,\n)::Bool where {T}\n\nEvaluate (lhs op rhs)::Bool, where op is a logic operator in registry.\n\n\n\n\n\n","category":"function"},{"location":"submodules/Nonlinear/reference/#MathOptInterface.Nonlinear.eval_comparison_function","page":"API Reference","title":"MathOptInterface.Nonlinear.eval_comparison_function","text":"eval_comparison_function(\n registry::OperatorRegistry,\n op::Symbol,\n lhs::T,\n rhs::T,\n)::Bool where {T}\n\nEvaluate (lhs op rhs)::Bool, where op is a comparison operator in registry.\n\n\n\n\n\n","category":"function"},{"location":"submodules/Nonlinear/reference/#Automatic-differentiation-backends","page":"API Reference","title":"Automatic-differentiation backends","text":"","category":"section"},{"location":"submodules/Nonlinear/reference/","page":"API Reference","title":"API Reference","text":"Nonlinear.Evaluator\nNonlinear.AbstractAutomaticDifferentiation\nNonlinear.ExprGraphOnly\nNonlinear.SparseReverseMode","category":"page"},{"location":"submodules/Nonlinear/reference/#MathOptInterface.Nonlinear.Evaluator","page":"API Reference","title":"MathOptInterface.Nonlinear.Evaluator","text":"Evaluator(\n model::Model,\n backend::AbstractAutomaticDifferentiation,\n ordered_variables::Vector{MOI.VariableIndex},\n)\n\nCreate Evaluator, a subtype of MOI.AbstractNLPEvaluator, from Model.\n\n\n\n\n\n","category":"type"},{"location":"submodules/Nonlinear/reference/#MathOptInterface.Nonlinear.AbstractAutomaticDifferentiation","page":"API Reference","title":"MathOptInterface.Nonlinear.AbstractAutomaticDifferentiation","text":"AbstractAutomaticDifferentiation\n\nAn abstract type for extending Evaluator.\n\n\n\n\n\n","category":"type"},{"location":"submodules/Nonlinear/reference/#MathOptInterface.Nonlinear.ExprGraphOnly","page":"API Reference","title":"MathOptInterface.Nonlinear.ExprGraphOnly","text":"ExprGraphOnly() <: AbstractAutomaticDifferentiation\n\nThe default implementation of AbstractAutomaticDifferentiation. The only supported feature is :ExprGraph.\n\n\n\n\n\n","category":"type"},{"location":"submodules/Nonlinear/reference/#MathOptInterface.Nonlinear.SparseReverseMode","page":"API Reference","title":"MathOptInterface.Nonlinear.SparseReverseMode","text":"SparseReverseMode() <: AbstractAutomaticDifferentiation\n\nAn implementation of AbstractAutomaticDifferentiation that uses sparse reverse-mode automatic differentiation to compute derivatives. Supports all features in the MOI nonlinear interface.\n\n\n\n\n\n","category":"type"},{"location":"submodules/Nonlinear/reference/#Data-structure","page":"API Reference","title":"Data-structure","text":"","category":"section"},{"location":"submodules/Nonlinear/reference/","page":"API Reference","title":"API Reference","text":"Nonlinear.Node\nNonlinear.NodeType\nNonlinear.Expression\nNonlinear.Constraint\nNonlinear.adjacency_matrix\nNonlinear.parse_expression\nNonlinear.convert_to_expr\nNonlinear.ordinal_index","category":"page"},{"location":"submodules/Nonlinear/reference/#MathOptInterface.Nonlinear.Node","page":"API Reference","title":"MathOptInterface.Nonlinear.Node","text":"struct Node\n type::NodeType\n index::Int\n parent::Int\nend\n\nA single node in a nonlinear expression tree. Used by Expression.\n\nSee the MathOptInterface documentation for information on how the nodes and values form an expression tree.\n\n\n\n\n\n","category":"type"},{"location":"submodules/Nonlinear/reference/#MathOptInterface.Nonlinear.NodeType","page":"API Reference","title":"MathOptInterface.Nonlinear.NodeType","text":"NodeType\n\nAn enum describing the possible node types. Each Node has a .index field, which should be interpreted as follows:\n\nNODE_CALL_MULTIVARIATE: the index into operators.multivariate_operators\nNODE_CALL_UNIVARIATE: the index into operators.univariate_operators\nNODE_LOGIC: the index into operators.logic_operators\nNODE_COMPARISON: the index into operators.comparison_operators\nNODE_MOI_VARIABLE: the value of MOI.VariableIndex(index) in the user's space of the model.\nNODE_VARIABLE: the 1-based index of the internal vector\nNODE_VALUE: the index into the .values field of Expression\nNODE_PARAMETER: the index into data.parameters\nNODE_SUBEXPRESSION: the index into data.expressions\n\n\n\n\n\n","category":"type"},{"location":"submodules/Nonlinear/reference/#MathOptInterface.Nonlinear.Expression","page":"API Reference","title":"MathOptInterface.Nonlinear.Expression","text":"struct Expression\n nodes::Vector{Node}\n values::Vector{Float64}\nend\n\nThe core type that represents a nonlinear expression. See the MathOptInterface documentation for information on how the nodes and values form an expression tree.\n\n\n\n\n\n","category":"type"},{"location":"submodules/Nonlinear/reference/#MathOptInterface.Nonlinear.Constraint","page":"API Reference","title":"MathOptInterface.Nonlinear.Constraint","text":"struct Constraint\n expression::Expression\n set::Union{\n MOI.LessThan{Float64},\n MOI.GreaterThan{Float64},\n MOI.EqualTo{Float64},\n MOI.Interval{Float64},\n }\nend\n\nA type to hold information relating to the nonlinear constraint f(x) in S, where f(x) is defined by .expression, and S is .set.\n\n\n\n\n\n","category":"type"},{"location":"submodules/Nonlinear/reference/#MathOptInterface.Nonlinear.adjacency_matrix","page":"API Reference","title":"MathOptInterface.Nonlinear.adjacency_matrix","text":"adjacency_matrix(nodes::Vector{Node})\n\nCompute the sparse adjacency matrix describing the parent-child relationships in nodes.\n\nThe 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 (i.e., the children).\n\n\n\n\n\n","category":"function"},{"location":"submodules/Nonlinear/reference/#MathOptInterface.Nonlinear.parse_expression","page":"API Reference","title":"MathOptInterface.Nonlinear.parse_expression","text":"parse_expression(data::Model, input)::Expression\n\nParse input into a Expression.\n\n\n\n\n\nparse_expression(\n data::Model,\n expr::Expression,\n input::Any,\n parent_index::Int,\n)::Expression\n\nParse 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.\n\nYou can extend parsing support to new types of objects by overloading this method with a different type on input::Any.\n\n\n\n\n\n","category":"function"},{"location":"submodules/Nonlinear/reference/#MathOptInterface.Nonlinear.convert_to_expr","page":"API Reference","title":"MathOptInterface.Nonlinear.convert_to_expr","text":"convert_to_expr(data::Model, expr::Expression)\n\nConvert the Expression expr into a Julia Expr.\n\nsubexpressions are represented by a ExpressionIndex object.\nparameters are represented by a ParameterIndex object.\nvariables are represennted by an MOI.VariableIndex object.\n\n\n\n\n\nconvert_to_expr(\n evaluator::Evaluator,\n expr::Expression;\n moi_output_format::Bool,\n)\n\nConvert the Expression expr into a Julia Expr.\n\nIf moi_output_format = true:\n\nsubexpressions will be converted to Julia Expr and substituted into the output expression.\nthe current value of each parameter will be interpolated into the expression\nvariables will be represented in the form x[MOI.VariableIndex(i)]\n\nIf moi_output_format = false:\n\nsubexpressions will be represented by a ExpressionIndex object.\nparameters will be represented by a ParameterIndex object.\nvariables will be represennted by an MOI.VariableIndex object.\n\nwarning: Warning\nTo use moi_output_format = true, you must have first called MOI.initialize with :ExprGraph as a requested feature.\n\n\n\n\n\n","category":"function"},{"location":"submodules/Nonlinear/reference/#MathOptInterface.Nonlinear.ordinal_index","page":"API Reference","title":"MathOptInterface.Nonlinear.ordinal_index","text":"ordinal_index(evaluator::Evaluator, c::ConstraintIndex)::Int\n\nReturn the 1-indexed value of the constraint index c in evaluator.\n\nExamples\n\nmodel = Model()\nx = MOI.VariableIndex(1)\nc1 = add_constraint(model, :($x^2), MOI.LessThan(1.0))\nc2 = add_constraint(model, :($x^2), MOI.LessThan(1.0))\nevaluator = Evaluator(model)\nMOI.initialize(evaluator, Symbol[])\nordinal_index(evaluator, c2) # Returns 2\ndelete(model, c1)\nevaluator = Evaluator(model)\nMOI.initialize(evaluator, Symbol[])\nordinal_index(model, c2) # Returns 1\n\n\n\n\n\n","category":"function"},{"location":"manual/models/","page":"Models","title":"Models","text":"CurrentModule = MathOptInterface\nDocTestSetup = quote\n import MathOptInterface as MOI\nend\nDocTestFilters = [r\"MathOptInterface|MOI\"]","category":"page"},{"location":"manual/models/#Models","page":"Models","title":"Models","text":"","category":"section"},{"location":"manual/models/","page":"Models","title":"Models","text":"The most significant part of MOI is the definition of the model API that is used to specify an instance of an optimization problem (for example, by adding variables and constraints). Objects that implement the model API must inherit from the ModelLike abstract type.","category":"page"},{"location":"manual/models/","page":"Models","title":"Models","text":"Notably missing from the model API is the method to solve an optimization problem. ModelLike objects may store an instance (for example, in memory or backed by a file format) without being linked to a particular solver. In addition to the model API, MOI defines AbstractOptimizer and provides methods to solve the model and interact with solutions. See the Solutions section for more details.","category":"page"},{"location":"manual/models/","page":"Models","title":"Models","text":"info: Info\nThroughout the rest of the manual, model is used as a generic ModelLike, and optimizer is used as a generic AbstractOptimizer.","category":"page"},{"location":"manual/models/","page":"Models","title":"Models","text":"tip: Tip\nMOI does not export functions, but for brevity we often omit qualifying names with the MOI module. Best practice is to haveimport MathOptInterface as MOIand prefix all MOI methods with MOI. in user code. If a name is also available in base Julia, we always explicitly use the module prefix, for example, with MOI.get.","category":"page"},{"location":"manual/models/#Attributes","page":"Models","title":"Attributes","text":"","category":"section"},{"location":"manual/models/","page":"Models","title":"Models","text":"Attributes are properties of the model that can be queried and modified. These include constants such as the number of variables in a model NumberOfVariables), and properties of variables and constraints such as the name of a variable (VariableName).","category":"page"},{"location":"manual/models/","page":"Models","title":"Models","text":"There are four types of attributes:","category":"page"},{"location":"manual/models/","page":"Models","title":"Models","text":"Model attributes (subtypes of AbstractModelAttribute) refer to properties of a model.\nOptimizer attributes (subtypes of AbstractOptimizerAttribute) refer to properties of an optimizer.\nConstraint attributes (subtypes of AbstractConstraintAttribute) refer to properties of an individual constraint.\nVariable attributes (subtypes of AbstractVariableAttribute) refer to properties of an individual variable.","category":"page"},{"location":"manual/models/","page":"Models","title":"Models","text":"Some attributes are values that can be queried by the user but not modified, while other attributes can be modified by the user.","category":"page"},{"location":"manual/models/","page":"Models","title":"Models","text":"All interactions with attributes occur through the get and set functions.","category":"page"},{"location":"manual/models/","page":"Models","title":"Models","text":"Consult the docstrings of each attribute for information on what it represents.","category":"page"},{"location":"manual/models/#ModelLike-API","page":"Models","title":"ModelLike API","text":"","category":"section"},{"location":"manual/models/","page":"Models","title":"Models","text":"The following attributes are available:","category":"page"},{"location":"manual/models/","page":"Models","title":"Models","text":"ListOfConstraintAttributesSet\nListOfConstraintIndices\nListOfConstraintTypesPresent\nListOfModelAttributesSet\nListOfVariableAttributesSet\nListOfVariableIndices\nNumberOfConstraints\nNumberOfVariables\nName\nObjectiveFunction\nObjectiveFunctionType\nObjectiveSense","category":"page"},{"location":"manual/models/#AbstractOptimizer-API","page":"Models","title":"AbstractOptimizer API","text":"","category":"section"},{"location":"manual/models/","page":"Models","title":"Models","text":"The following attributes are available:","category":"page"},{"location":"manual/models/","page":"Models","title":"Models","text":"DualStatus\nPrimalStatus\nRawStatusString\nResultCount\nTerminationStatus\nBarrierIterations\nDualObjectiveValue\nNodeCount\nNumberOfThreads\nObjectiveBound\nObjectiveValue\nRelativeGap\nRawOptimizerAttribute\nRawSolver\nSilent\nSimplexIterations\nSolverName\nSolverVersion\nSolveTimeSec\nTimeLimitSec\nObjectiveLimit","category":"page"},{"location":"tutorials/mathprogbase/#Transitioning-from-MathProgBase","page":"Transitioning from MathProgBase","title":"Transitioning from MathProgBase","text":"","category":"section"},{"location":"tutorials/mathprogbase/","page":"Transitioning from MathProgBase","title":"Transitioning from MathProgBase","text":"MathOptInterface is a replacement for MathProgBase.jl. However, it is not a direct replacement.","category":"page"},{"location":"tutorials/mathprogbase/#Transitioning-a-solver-interface","page":"Transitioning from MathProgBase","title":"Transitioning a solver interface","text":"","category":"section"},{"location":"tutorials/mathprogbase/","page":"Transitioning from MathProgBase","title":"Transitioning from MathProgBase","text":"MathOptInterface is more extensive than MathProgBase which may make its implementation seem daunting at first. There are however numerous utilities in MathOptInterface that the simplify implementation process.","category":"page"},{"location":"tutorials/mathprogbase/","page":"Transitioning from MathProgBase","title":"Transitioning from MathProgBase","text":"For more information, read Implementing a solver interface.","category":"page"},{"location":"tutorials/mathprogbase/#Transitioning-the-high-level-functions","page":"Transitioning from MathProgBase","title":"Transitioning the high-level functions","text":"","category":"section"},{"location":"tutorials/mathprogbase/","page":"Transitioning from MathProgBase","title":"Transitioning from MathProgBase","text":"MathOptInterface doesn't provide replacements for the high-level interfaces in MathProgBase. We recommend you use JuMP as a modeling interface instead.","category":"page"},{"location":"tutorials/mathprogbase/","page":"Transitioning from MathProgBase","title":"Transitioning from MathProgBase","text":"tip: Tip\nIf you haven't used JuMP before, start with the tutorial Getting started with JuMP","category":"page"},{"location":"tutorials/mathprogbase/#linprog","page":"Transitioning from MathProgBase","title":"linprog","text":"","category":"section"},{"location":"tutorials/mathprogbase/","page":"Transitioning from MathProgBase","title":"Transitioning from MathProgBase","text":"Here is one way of transitioning from linprog:","category":"page"},{"location":"tutorials/mathprogbase/","page":"Transitioning from MathProgBase","title":"Transitioning from MathProgBase","text":"using JuMP\n\nfunction linprog(c, A, sense, b, l, u, solver)\n N = length(c)\n model = Model(solver)\n @variable(model, l[i] <= x[i=1:N] <= u[i])\n @objective(model, Min, c' * x)\n eq_rows, ge_rows, le_rows = sense .== '=', sense .== '>', sense .== '<'\n @constraint(model, A[eq_rows, :] * x .== b[eq_rows])\n @constraint(model, A[ge_rows, :] * x .>= b[ge_rows])\n @constraint(model, A[le_rows, :] * x .<= b[le_rows])\n optimize!(model)\n return (\n status = termination_status(model),\n objval = objective_value(model),\n sol = value.(x)\n )\nend","category":"page"},{"location":"tutorials/mathprogbase/#mixintprog","page":"Transitioning from MathProgBase","title":"mixintprog","text":"","category":"section"},{"location":"tutorials/mathprogbase/","page":"Transitioning from MathProgBase","title":"Transitioning from MathProgBase","text":"Here is one way of transitioning from mixintprog:","category":"page"},{"location":"tutorials/mathprogbase/","page":"Transitioning from MathProgBase","title":"Transitioning from MathProgBase","text":"using JuMP\n\nfunction mixintprog(c, A, rowlb, rowub, vartypes, lb, ub, solver)\n N = length(c)\n model = Model(solver)\n @variable(model, lb[i] <= x[i=1:N] <= ub[i])\n for i in 1:N\n if vartypes[i] == :Bin\n set_binary(x[i])\n elseif vartypes[i] == :Int\n set_integer(x[i])\n end\n end\n @objective(model, Min, c' * x)\n @constraint(model, rowlb .<= A * x .<= rowub)\n optimize!(model)\n return (\n status = termination_status(model),\n objval = objective_value(model),\n sol = value.(x)\n )\nend","category":"page"},{"location":"tutorials/mathprogbase/#quadprog","page":"Transitioning from MathProgBase","title":"quadprog","text":"","category":"section"},{"location":"tutorials/mathprogbase/","page":"Transitioning from MathProgBase","title":"Transitioning from MathProgBase","text":"Here is one way of transitioning from quadprog:","category":"page"},{"location":"tutorials/mathprogbase/","page":"Transitioning from MathProgBase","title":"Transitioning from MathProgBase","text":"using JuMP\n\nfunction quadprog(c, Q, A, rowlb, rowub, lb, ub, solver)\n N = length(c)\n model = Model(solver)\n @variable(model, lb[i] <= x[i=1:N] <= ub[i])\n @objective(model, Min, c' * x + 0.5 * x' * Q * x)\n @constraint(model, rowlb .<= A * x .<= rowub)\n optimize!(model)\n return (\n status = termination_status(model),\n objval = objective_value(model),\n sol = value.(x)\n )\nend","category":"page"},{"location":"submodules/Test/reference/","page":"API Reference","title":"API Reference","text":"CurrentModule = MathOptInterface\nDocTestSetup = quote\n import MathOptInterface as MOI\nend\nDocTestFilters = [r\"MathOptInterface|MOI\"]","category":"page"},{"location":"submodules/Test/reference/#test_reference","page":"API Reference","title":"The Test submodule","text":"","category":"section"},{"location":"submodules/Test/reference/","page":"API Reference","title":"API Reference","text":"Functions to help test implementations of MOI. See The Test submodule for more details.","category":"page"},{"location":"submodules/Test/reference/","page":"API Reference","title":"API Reference","text":"Test.Config\nTest.runtests\nTest.setup_test\nTest.version_added\nTest.@requires\nTest.RequirementUnmet","category":"page"},{"location":"submodules/Test/reference/#MathOptInterface.Test.Config","page":"API Reference","title":"MathOptInterface.Test.Config","text":"Config(\n ::Type{T} = Float64;\n atol::Real = Base.rtoldefault(T),\n rtol::Real = Base.rtoldefault(T),\n optimal_status::MOI.TerminationStatusCode = MOI.OPTIMAL,\n infeasible_status::MOI.TerminationStatusCode = MOI.INFEASIBLE,\n exclude::Vector{Any} = Any[],\n) where {T}\n\nReturn an object that is used to configure various tests.\n\nConfiguration arguments\n\natol::Real = Base.rtoldefault(T): Control the absolute tolerance used when comparing solutions.\nrtol::Real = Base.rtoldefault(T): Control the relative tolerance used when comparing solutions.\noptimal_status = MOI.OPTIMAL: Set to MOI.LOCALLY_SOLVED if the solver cannot prove global optimality.\ninfeasible_status = MOI.INFEASIBLE: Set to MOI.LOCALLY_INFEASIBLE if the solver cannot prove global infeasibility.\nexclude = Vector{Any}: Pass attributes or functions to exclude to skip parts of tests that require certain functionality. Common arguments include:\nMOI.delete to skip deletion-related tests\nMOI.optimize! to skip optimize-related tests\nMOI.ConstraintDual to skip dual-related tests\nMOI.VariableName to skip setting variable names\nMOI.ConstraintName to skip setting constraint names\n\nExamples\n\nFor a nonlinear solver that finds local optima and does not support finding dual variables or constraint names:\n\nConfig(\n Float64;\n optimal_status = MOI.LOCALLY_SOLVED,\n exclude = Any[\n MOI.ConstraintDual,\n MOI.VariableName,\n MOI.ConstraintName,\n MOI.delete,\n ],\n)\n\n\n\n\n\n","category":"type"},{"location":"submodules/Test/reference/#MathOptInterface.Test.runtests","page":"API Reference","title":"MathOptInterface.Test.runtests","text":"runtests(\n model::MOI.ModelLike,\n config::Config;\n include::Vector{Union{String,Regex}} = String[],\n exclude::Vector{Union{String,Regex}} = String[],\n warn_unsupported::Bool = false,\n exclude_tests_after::VersionNumber = v\"999.0.0\",\n)\n\nRun all tests in MathOptInterface.Test on model.\n\nConfiguration arguments\n\nconfig is a Test.Config object that can be used to modify the behavior of tests.\nIf include is not empty, only run tests if an element from include occursin the name of the test.\nIf exclude is not empty, skip tests if an element from exclude occursin the name of the test.\nexclude takes priority over include.\nIf warn_unsupported is false, runtests will silently skip tests that fail with a MOI.NotAllowedError, MOI.UnsupportedError, or RequirementUnmet error. (The latter is thrown when an @requires statement returns false.) When warn_unsupported is true, a warning will be printed. For most cases the default behavior, false, is what you want, since these tests likely test functionality that is not supported by model. However, it can be useful to run warn_unsupported = true to check you are not skipping tests due to a missing supports_constraint method or equivalent.\nexclude_tests_after is a version number that excludes any tests to MOI added after that version number. This is useful for solvers who can declare a fixed set of tests, and not cause their tests to break if a new patch of MOI is released with a new test.\n\nSee also: setup_test.\n\nExample\n\nconfig = MathOptInterface.Test.Config()\nMathOptInterface.Test.runtests(\n model,\n config;\n include = [\"test_linear_\", r\"^test_model_Name$\"],\n exclude = [\"VariablePrimalStart\"],\n warn_unsupported = true,\n exclude_tests_after = v\"0.10.5\",\n)\n\n\n\n\n\n","category":"function"},{"location":"submodules/Test/reference/#MathOptInterface.Test.setup_test","page":"API Reference","title":"MathOptInterface.Test.setup_test","text":"setup_test(::typeof(f), model::MOI.ModelLike, config::Config)\n\nOverload this method to modify model before running the test function f on model with config. You can also modify the fields in config (e.g., to loosen the default tolerances).\n\nThis function should either return nothing, or return a function which, when called with zero arguments, undoes the setup to return the model to its previous state. You do not need to undo any modifications to config.\n\nThis function is most useful when writing new tests of the tests for MOI, but it can also be used to set test-specific tolerances, etc.\n\nSee also: runtests\n\nExample\n\nfunction MOI.Test.setup_test(\n ::typeof(MOI.Test.test_linear_VariablePrimalStart_partial),\n mock::MOIU.MockOptimizer,\n ::MOI.Test.Config,\n)\n MOIU.set_mock_optimize!(\n mock,\n (mock::MOIU.MockOptimizer) -> MOIU.mock_optimize!(mock, [1.0, 0.0]),\n )\n mock.eval_variable_constraint_dual = false\n\n function reset_function()\n mock.eval_variable_constraint_dual = true\n return\n end\n return reset_function\nend\n\n\n\n\n\n","category":"function"},{"location":"submodules/Test/reference/#MathOptInterface.Test.version_added","page":"API Reference","title":"MathOptInterface.Test.version_added","text":"version_added(::typeof(function_name))\n\nReturns the version of MOI in which the test function_name was added.\n\nThis method should be implemented for all new tests.\n\nSee the exclude_tests_after keyword of runtests for more details.\n\n\n\n\n\n","category":"function"},{"location":"submodules/Test/reference/#MathOptInterface.Test.@requires","page":"API Reference","title":"MathOptInterface.Test.@requires","text":"@requires(x)\n\nCheck that the condition x is true. Otherwise, throw an RequirementUnmet error to indicate that the model does not support something required by the test function.\n\nExamples\n\n@requires MOI.supports(model, MOI.Silent())\n@test MOI.get(model, MOI.Silent())\n\n\n\n\n\n","category":"macro"},{"location":"submodules/Test/reference/#MathOptInterface.Test.RequirementUnmet","page":"API Reference","title":"MathOptInterface.Test.RequirementUnmet","text":"RequirementUnmet(msg::String) <: Exception\n\nAn error for throwing in tests to indicate that the model does not support some requirement expected by the test function.\n\n\n\n\n\n","category":"type"},{"location":"submodules/Benchmarks/overview/","page":"Overview","title":"Overview","text":"CurrentModule = MathOptInterface\nDocTestSetup = quote\n import MathOptInterface as MOI\nend\nDocTestFilters = [r\"MathOptInterface|MOI\"]","category":"page"},{"location":"submodules/Benchmarks/overview/#The-Benchmarks-submodule","page":"Overview","title":"The Benchmarks submodule","text":"","category":"section"},{"location":"submodules/Benchmarks/overview/","page":"Overview","title":"Overview","text":"To aid the development of efficient solver wrappers, MathOptInterface provides benchmarking capability. Benchmarking a wrapper follows a two-step process.","category":"page"},{"location":"submodules/Benchmarks/overview/","page":"Overview","title":"Overview","text":"First, prior to making changes, create a baseline for the benchmark results on a given benchmark suite as follows:","category":"page"},{"location":"submodules/Benchmarks/overview/","page":"Overview","title":"Overview","text":"using SolverPackage # Replace with your choice of solver.\nimport MathOptInterface as MOI\n\nsuite = MOI.Benchmarks.suite() do\n SolverPackage.Optimizer()\nend\n\nMOI.Benchmarks.create_baseline(\n suite, \"current\"; directory = \"/tmp\", verbose = true\n)","category":"page"},{"location":"submodules/Benchmarks/overview/","page":"Overview","title":"Overview","text":"Use the exclude argument to Benchmarks.suite to exclude benchmarks that the solver doesn't support.","category":"page"},{"location":"submodules/Benchmarks/overview/","page":"Overview","title":"Overview","text":"Second, after making changes to the package, re-run the benchmark suite and compare to the prior saved results:","category":"page"},{"location":"submodules/Benchmarks/overview/","page":"Overview","title":"Overview","text":"using SolverPackage\nimport MathOptInterface as MOI\n\nsuite = MOI.Benchmarks.suite() do\n SolverPackage.Optimizer()\nend\n\nMOI.Benchmarks.compare_against_baseline(\n suite, \"current\"; directory = \"/tmp\", verbose = true\n)","category":"page"},{"location":"submodules/Benchmarks/overview/","page":"Overview","title":"Overview","text":"This comparison will create a report detailing improvements and regressions.","category":"page"},{"location":"submodules/FileFormats/overview/","page":"Overview","title":"Overview","text":"CurrentModule = MathOptInterface\nDocTestSetup = quote\n import MathOptInterface as MOI\nend\nDocTestFilters = [r\"MathOptInterface|MOI\"]","category":"page"},{"location":"submodules/FileFormats/overview/#The-FileFormats-submodule","page":"Overview","title":"The FileFormats submodule","text":"","category":"section"},{"location":"submodules/FileFormats/overview/","page":"Overview","title":"Overview","text":"The FileFormats module provides functions for reading and writing MOI models using write_to_file and read_from_file.","category":"page"},{"location":"submodules/FileFormats/overview/#Supported-file-types","page":"Overview","title":"Supported file types","text":"","category":"section"},{"location":"submodules/FileFormats/overview/","page":"Overview","title":"Overview","text":"You must read and write files to a FileFormats.Model object. Specific the file-type by passing a FileFormats.FileFormat enum. For example:","category":"page"},{"location":"submodules/FileFormats/overview/","page":"Overview","title":"Overview","text":"The Conic Benchmark Format","category":"page"},{"location":"submodules/FileFormats/overview/","page":"Overview","title":"Overview","text":"julia> model = MOI.FileFormats.Model(format = MOI.FileFormats.FORMAT_CBF)\nA Conic Benchmark Format (CBF) model","category":"page"},{"location":"submodules/FileFormats/overview/","page":"Overview","title":"Overview","text":"The LP file format","category":"page"},{"location":"submodules/FileFormats/overview/","page":"Overview","title":"Overview","text":"julia> model = MOI.FileFormats.Model(format = MOI.FileFormats.FORMAT_LP)\nA .LP-file model","category":"page"},{"location":"submodules/FileFormats/overview/","page":"Overview","title":"Overview","text":"The MathOptFormat file format","category":"page"},{"location":"submodules/FileFormats/overview/","page":"Overview","title":"Overview","text":"julia> model = MOI.FileFormats.Model(format = MOI.FileFormats.FORMAT_MOF)\nA MathOptFormat Model","category":"page"},{"location":"submodules/FileFormats/overview/","page":"Overview","title":"Overview","text":"The MPS file format","category":"page"},{"location":"submodules/FileFormats/overview/","page":"Overview","title":"Overview","text":"julia> model = MOI.FileFormats.Model(format = MOI.FileFormats.FORMAT_MPS)\nA Mathematical Programming System (MPS) model","category":"page"},{"location":"submodules/FileFormats/overview/","page":"Overview","title":"Overview","text":"The NL file format","category":"page"},{"location":"submodules/FileFormats/overview/","page":"Overview","title":"Overview","text":"julia> model = MOI.FileFormats.Model(format = MOI.FileFormats.FORMAT_NL)\nAn AMPL (.nl) model","category":"page"},{"location":"submodules/FileFormats/overview/","page":"Overview","title":"Overview","text":"The REW file format","category":"page"},{"location":"submodules/FileFormats/overview/","page":"Overview","title":"Overview","text":"julia> model = MOI.FileFormats.Model(format = MOI.FileFormats.FORMAT_REW)\nA Mathematical Programming System (MPS) model","category":"page"},{"location":"submodules/FileFormats/overview/","page":"Overview","title":"Overview","text":"Note that the REW format is identical to the MPS file format, except that all names are replaced with generic identifiers.","category":"page"},{"location":"submodules/FileFormats/overview/","page":"Overview","title":"Overview","text":"The SDPA file format","category":"page"},{"location":"submodules/FileFormats/overview/","page":"Overview","title":"Overview","text":"julia> model = MOI.FileFormats.Model(format = MOI.FileFormats.FORMAT_SDPA)\nA SemiDefinite Programming Algorithm Format (SDPA) model","category":"page"},{"location":"submodules/FileFormats/overview/#Write-to-file","page":"Overview","title":"Write to file","text":"","category":"section"},{"location":"submodules/FileFormats/overview/","page":"Overview","title":"Overview","text":"To write a model src to a MathOptFormat file, use:","category":"page"},{"location":"submodules/FileFormats/overview/","page":"Overview","title":"Overview","text":"julia> src = MOI.Utilities.Model{Float64}()\nMOIU.Model{Float64}\n\njulia> MOI.add_variable(src)\nMOI.VariableIndex(1)\n\njulia> dest = MOI.FileFormats.Model(format = MOI.FileFormats.FORMAT_MOF)\nA MathOptFormat Model\n\njulia> MOI.copy_to(dest, src)\nMathOptInterface.Utilities.IndexMap with 1 entry:\n MOI.VariableIndex(1) => MOI.VariableIndex(1)\n\njulia> MOI.write_to_file(dest, \"file.mof.json\")\n\njulia> print(read(\"file.mof.json\", String))\n{\n \"name\": \"MathOptFormat Model\",\n \"version\": {\n \"major\": 1,\n \"minor\": 5\n },\n \"variables\": [\n {\n \"name\": \"x1\"\n }\n ],\n \"objective\": {\n \"sense\": \"feasibility\"\n },\n \"constraints\": []\n}","category":"page"},{"location":"submodules/FileFormats/overview/#Read-from-file","page":"Overview","title":"Read from file","text":"","category":"section"},{"location":"submodules/FileFormats/overview/","page":"Overview","title":"Overview","text":"To read a MathOptFormat file, use:","category":"page"},{"location":"submodules/FileFormats/overview/","page":"Overview","title":"Overview","text":"julia> dest = MOI.FileFormats.Model(format = MOI.FileFormats.FORMAT_MOF)\nA MathOptFormat Model\n\njulia> MOI.read_from_file(dest, \"file.mof.json\")\n\njulia> MOI.get(dest, MOI.ListOfVariableIndices())\n1-element Vector{MathOptInterface.VariableIndex}:\n MOI.VariableIndex(1)\n\njulia> rm(\"file.mof.json\") # Clean up after ourselves.","category":"page"},{"location":"submodules/FileFormats/overview/#Detecting-the-file-type-automatically","page":"Overview","title":"Detecting the file-type automatically","text":"","category":"section"},{"location":"submodules/FileFormats/overview/","page":"Overview","title":"Overview","text":"Instead of the format keyword, you can also use the filename keyword argument to FileFormats.Model. This will attempt to automatically guess the format from the file extension. For example:","category":"page"},{"location":"submodules/FileFormats/overview/","page":"Overview","title":"Overview","text":"julia> src = MOI.Utilities.Model{Float64}()\nMOIU.Model{Float64}\n\njulia> dest = MOI.FileFormats.Model(filename = \"file.cbf.gz\")\nA Conic Benchmark Format (CBF) model\n\njulia> MOI.copy_to(dest, src)\nMathOptInterface.Utilities.IndexMap()\n\njulia> MOI.write_to_file(dest, \"file.cbf.gz\")\n\njulia> src_2 = MOI.FileFormats.Model(filename = \"file.cbf.gz\")\nA Conic Benchmark Format (CBF) model\n\njulia> src = MOI.Utilities.Model{Float64}()\nMOIU.Model{Float64}\n\njulia> dest = MOI.FileFormats.Model(filename = \"file.cbf.gz\")\nA Conic Benchmark Format (CBF) model\n\njulia> MOI.copy_to(dest, src)\nMathOptInterface.Utilities.IndexMap()\n\njulia> MOI.write_to_file(dest, \"file.cbf.gz\")\n\njulia> src_2 = MOI.FileFormats.Model(filename = \"file.cbf.gz\")\nA Conic Benchmark Format (CBF) model\n\njulia> MOI.read_from_file(src_2, \"file.cbf.gz\")\n\njulia> rm(\"file.cbf.gz\") # Clean up after ourselves.","category":"page"},{"location":"submodules/FileFormats/overview/","page":"Overview","title":"Overview","text":"Note how the compression format (GZip) is also automatically detected from the filename.","category":"page"},{"location":"submodules/FileFormats/overview/#Unsupported-constraints","page":"Overview","title":"Unsupported constraints","text":"","category":"section"},{"location":"submodules/FileFormats/overview/","page":"Overview","title":"Overview","text":"In some cases src may contain constraints that are not supported by the file format (for example, the CBF format supports integer variables but not binary). If so, copy src to a bridged model using Bridges.full_bridge_optimizer:","category":"page"},{"location":"submodules/FileFormats/overview/","page":"Overview","title":"Overview","text":"src = MOI.Utilities.Model{Float64}()\nx = MOI.add_variable(model)\nMOI.add_constraint(model, x, MOI.ZeroOne())\ndest = MOI.FileFormats.Model(format = MOI.FileFormats.FORMAT_CBF)\nbridged = MOI.Bridges.full_bridge_optimizer(dest, Float64)\nMOI.copy_to(bridged, src)\nMOI.write_to_file(dest, \"my_model.cbf\")","category":"page"},{"location":"submodules/FileFormats/overview/","page":"Overview","title":"Overview","text":"note: Note\nEven after bridging, it may still not be possible to write the model to file because of unsupported constraints (for example, PSD variables in the LP file format).","category":"page"},{"location":"submodules/FileFormats/overview/#Read-and-write-to-io","page":"Overview","title":"Read and write to io","text":"","category":"section"},{"location":"submodules/FileFormats/overview/","page":"Overview","title":"Overview","text":"In addition to write_to_file and read_from_file, you can read and write directly from IO streams using Base.write and Base.read!:","category":"page"},{"location":"submodules/FileFormats/overview/","page":"Overview","title":"Overview","text":"julia> src = MOI.Utilities.Model{Float64}()\nMOIU.Model{Float64}\n\njulia> dest = MOI.FileFormats.Model(format = MOI.FileFormats.FORMAT_MPS)\nA Mathematical Programming System (MPS) model\n\njulia> MOI.copy_to(dest, src)\nMathOptInterface.Utilities.IndexMap()\n\njulia> io = IOBuffer();\n\njulia> write(io, dest)\n\njulia> seekstart(io);\n\njulia> src_2 = MOI.FileFormats.Model(format = MOI.FileFormats.FORMAT_MPS)\nA Mathematical Programming System (MPS) model\n\njulia> read!(io, src_2);","category":"page"},{"location":"submodules/FileFormats/overview/#Validating-MOF-files","page":"Overview","title":"Validating MOF files","text":"","category":"section"},{"location":"submodules/FileFormats/overview/","page":"Overview","title":"Overview","text":"MathOptFormat files are governed by a schema. Use JSONSchema.jl to check if a .mof.json file satisfies the schema.","category":"page"},{"location":"submodules/FileFormats/overview/","page":"Overview","title":"Overview","text":"First, construct the schema object as follows:","category":"page"},{"location":"submodules/FileFormats/overview/","page":"Overview","title":"Overview","text":"julia> import JSON, JSONSchema\n\njulia> schema = JSONSchema.Schema(JSON.parsefile(MOI.FileFormats.MOF.SCHEMA_PATH))\nA JSONSchema","category":"page"},{"location":"submodules/FileFormats/overview/","page":"Overview","title":"Overview","text":"Then, check if a model file is valid using isvalid:","category":"page"},{"location":"submodules/FileFormats/overview/","page":"Overview","title":"Overview","text":"julia> good_model = JSON.parse(\"\"\"\n {\n \"version\": {\n \"major\": 1,\n \"minor\": 5\n },\n \"variables\": [{\"name\": \"x\"}],\n \"objective\": {\"sense\": \"feasibility\"},\n \"constraints\": []\n }\n \"\"\");\n\njulia> isvalid(schema, good_model)\ntrue","category":"page"},{"location":"submodules/FileFormats/overview/","page":"Overview","title":"Overview","text":"If we construct an invalid file, for example by mis-typing name as NaMe, the validation fails:","category":"page"},{"location":"submodules/FileFormats/overview/","page":"Overview","title":"Overview","text":"julia> bad_model = JSON.parse(\"\"\"\n {\n \"version\": {\n \"major\": 1,\n \"minor\": 5\n },\n \"variables\": [{\"NaMe\": \"x\"}],\n \"objective\": {\"sense\": \"feasibility\"},\n \"constraints\": []\n }\n \"\"\");\n\njulia> isvalid(schema, bad_model)\nfalse","category":"page"},{"location":"submodules/FileFormats/overview/","page":"Overview","title":"Overview","text":"Use JSONSchema.validate to obtain more insight into why the validation failed:","category":"page"},{"location":"submodules/FileFormats/overview/","page":"Overview","title":"Overview","text":"julia> JSONSchema.validate(schema, bad_model)\nValidation failed:\npath: [variables][1]\ninstance: Dict{String, Any}(\"NaMe\" => \"x\")\nschema key: required\nschema value: Any[\"name\"]","category":"page"},{"location":"tutorials/example/","page":"Solving a problem using MathOptInterface","title":"Solving a problem using MathOptInterface","text":"CurrentModule = MathOptInterface\nDocTestSetup = quote\n import MathOptInterface as MOI\nend\nDocTestFilters = [r\"MathOptInterface|MOI\"]","category":"page"},{"location":"tutorials/example/#Solving-a-problem-using-MathOptInterface","page":"Solving a problem using MathOptInterface","title":"Solving a problem using MathOptInterface","text":"","category":"section"},{"location":"tutorials/example/","page":"Solving a problem using MathOptInterface","title":"Solving a problem using MathOptInterface","text":"In this tutorial we demonstrate how to use MathOptInterface to solve the binary-constrained knapsack problem:","category":"page"},{"location":"tutorials/example/","page":"Solving a problem using MathOptInterface","title":"Solving a problem using MathOptInterface","text":"beginaligned\nmax c^top x \nst w^top x le C \n x_i in 01quad forall i=1ldotsn\nendaligned","category":"page"},{"location":"tutorials/example/#Required-packages","page":"Solving a problem using MathOptInterface","title":"Required packages","text":"","category":"section"},{"location":"tutorials/example/","page":"Solving a problem using MathOptInterface","title":"Solving a problem using MathOptInterface","text":"Load the MathOptInterface module and define the shorthand MOI:","category":"page"},{"location":"tutorials/example/","page":"Solving a problem using MathOptInterface","title":"Solving a problem using MathOptInterface","text":"import MathOptInterface as MOI","category":"page"},{"location":"tutorials/example/","page":"Solving a problem using MathOptInterface","title":"Solving a problem using MathOptInterface","text":"As an optimizer, we choose GLPK:","category":"page"},{"location":"tutorials/example/","page":"Solving a problem using MathOptInterface","title":"Solving a problem using MathOptInterface","text":"using GLPK\noptimizer = GLPK.Optimizer()","category":"page"},{"location":"tutorials/example/#Define-the-data","page":"Solving a problem using MathOptInterface","title":"Define the data","text":"","category":"section"},{"location":"tutorials/example/","page":"Solving a problem using MathOptInterface","title":"Solving a problem using MathOptInterface","text":"We first define the constants of the problem:","category":"page"},{"location":"tutorials/example/","page":"Solving a problem using MathOptInterface","title":"Solving a problem using MathOptInterface","text":"julia> c = [1.0, 2.0, 3.0]\n3-element Vector{Float64}:\n 1.0\n 2.0\n 3.0\n\njulia> w = [0.3, 0.5, 1.0]\n3-element Vector{Float64}:\n 0.3\n 0.5\n 1.0\n\njulia> C = 3.2\n3.2","category":"page"},{"location":"tutorials/example/#Add-the-variables","page":"Solving a problem using MathOptInterface","title":"Add the variables","text":"","category":"section"},{"location":"tutorials/example/","page":"Solving a problem using MathOptInterface","title":"Solving a problem using MathOptInterface","text":"julia> x = MOI.add_variables(optimizer, length(c));","category":"page"},{"location":"tutorials/example/#set_objective_example","page":"Solving a problem using MathOptInterface","title":"Set the objective","text":"","category":"section"},{"location":"tutorials/example/","page":"Solving a problem using MathOptInterface","title":"Solving a problem using MathOptInterface","text":"julia> MOI.set(\n optimizer,\n MOI.ObjectiveFunction{MOI.ScalarAffineFunction{Float64}}(),\n MOI.ScalarAffineFunction(MOI.ScalarAffineTerm.(c, x), 0.0),\n );\n\njulia> MOI.set(optimizer, MOI.ObjectiveSense(), MOI.MAX_SENSE)","category":"page"},{"location":"tutorials/example/","page":"Solving a problem using MathOptInterface","title":"Solving a problem using MathOptInterface","text":"tip: Tip\nMOI.ScalarAffineTerm.(c, x) is a shortcut for [MOI.ScalarAffineTerm(c[i], x[i]) for i = 1:3]. This is Julia's broadcast syntax in action, and is used quite often throughout MOI.","category":"page"},{"location":"tutorials/example/#Add-the-constraints","page":"Solving a problem using MathOptInterface","title":"Add the constraints","text":"","category":"section"},{"location":"tutorials/example/","page":"Solving a problem using MathOptInterface","title":"Solving a problem using MathOptInterface","text":"We add the knapsack constraint and integrality constraints:","category":"page"},{"location":"tutorials/example/","page":"Solving a problem using MathOptInterface","title":"Solving a problem using MathOptInterface","text":"julia> MOI.add_constraint(\n optimizer,\n MOI.ScalarAffineFunction(MOI.ScalarAffineTerm.(w, x), 0.0),\n MOI.LessThan(C),\n );","category":"page"},{"location":"tutorials/example/","page":"Solving a problem using MathOptInterface","title":"Solving a problem using MathOptInterface","text":"Add integrality constraints:","category":"page"},{"location":"tutorials/example/","page":"Solving a problem using MathOptInterface","title":"Solving a problem using MathOptInterface","text":"julia> for x_i in x\n MOI.add_constraint(optimizer, x_i, MOI.ZeroOne())\n end","category":"page"},{"location":"tutorials/example/#Optimize-the-model","page":"Solving a problem using MathOptInterface","title":"Optimize the model","text":"","category":"section"},{"location":"tutorials/example/","page":"Solving a problem using MathOptInterface","title":"Solving a problem using MathOptInterface","text":"julia> MOI.optimize!(optimizer)","category":"page"},{"location":"tutorials/example/#Understand-why-the-solver-stopped","page":"Solving a problem using MathOptInterface","title":"Understand why the solver stopped","text":"","category":"section"},{"location":"tutorials/example/","page":"Solving a problem using MathOptInterface","title":"Solving a problem using MathOptInterface","text":"The first thing to check after optimization is why the solver stopped, for example, did it stop because of a time limit or did it stop because it found the optimal solution?","category":"page"},{"location":"tutorials/example/","page":"Solving a problem using MathOptInterface","title":"Solving a problem using MathOptInterface","text":"julia> MOI.get(optimizer, MOI.TerminationStatus())\nOPTIMAL::TerminationStatusCode = 1","category":"page"},{"location":"tutorials/example/","page":"Solving a problem using MathOptInterface","title":"Solving a problem using MathOptInterface","text":"Looks like we found an optimal solution.","category":"page"},{"location":"tutorials/example/#Understand-what-solution-was-returned","page":"Solving a problem using MathOptInterface","title":"Understand what solution was returned","text":"","category":"section"},{"location":"tutorials/example/","page":"Solving a problem using MathOptInterface","title":"Solving a problem using MathOptInterface","text":"julia> MOI.get(optimizer, MOI.ResultCount())\n1\n\njulia> MOI.get(optimizer, MOI.PrimalStatus())\nFEASIBLE_POINT::ResultStatusCode = 1\n\njulia> MOI.get(optimizer, MOI.DualStatus())\nNO_SOLUTION::ResultStatusCode = 0","category":"page"},{"location":"tutorials/example/#Query-the-objective","page":"Solving a problem using MathOptInterface","title":"Query the objective","text":"","category":"section"},{"location":"tutorials/example/","page":"Solving a problem using MathOptInterface","title":"Solving a problem using MathOptInterface","text":"What is its objective value?","category":"page"},{"location":"tutorials/example/","page":"Solving a problem using MathOptInterface","title":"Solving a problem using MathOptInterface","text":"julia> MOI.get(optimizer, MOI.ObjectiveValue())\n6.0","category":"page"},{"location":"tutorials/example/#Query-the-primal-solution","page":"Solving a problem using MathOptInterface","title":"Query the primal solution","text":"","category":"section"},{"location":"tutorials/example/","page":"Solving a problem using MathOptInterface","title":"Solving a problem using MathOptInterface","text":"And what is the value of the variables x?","category":"page"},{"location":"tutorials/example/","page":"Solving a problem using MathOptInterface","title":"Solving a problem using MathOptInterface","text":"julia> MOI.get(optimizer, MOI.VariablePrimal(), x)\n3-element Vector{Float64}:\n 1.0\n 1.0\n 1.0","category":"page"},{"location":"submodules/Utilities/reference/","page":"API Reference","title":"API Reference","text":"CurrentModule = MathOptInterface\nDocTestSetup = quote\n import MathOptInterface as MOI\nend\nDocTestFilters = [r\"MathOptInterface|MOI\"]","category":"page"},{"location":"submodules/Utilities/reference/#Utilities.Model","page":"API Reference","title":"Utilities.Model","text":"","category":"section"},{"location":"submodules/Utilities/reference/","page":"API Reference","title":"API Reference","text":"Utilities.Model","category":"page"},{"location":"submodules/Utilities/reference/#MathOptInterface.Utilities.Model","page":"API Reference","title":"MathOptInterface.Utilities.Model","text":"An implementation of ModelLike that supports all functions and sets defined in MOI. It is parameterized by the coefficient type.\n\nExamples\n\nmodel = Model{Float64}()\nx = add_variable(model)\n\n\n\n\n\n","category":"type"},{"location":"submodules/Utilities/reference/#Utilities.UniversalFallback","page":"API Reference","title":"Utilities.UniversalFallback","text":"","category":"section"},{"location":"submodules/Utilities/reference/","page":"API Reference","title":"API Reference","text":"Utilities.UniversalFallback","category":"page"},{"location":"submodules/Utilities/reference/#MathOptInterface.Utilities.UniversalFallback","page":"API Reference","title":"MathOptInterface.Utilities.UniversalFallback","text":"UniversalFallback\n\nThe 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.\n\n\n\n\n\n","category":"type"},{"location":"submodules/Utilities/reference/#Utilities.@model","page":"API Reference","title":"Utilities.@model","text":"","category":"section"},{"location":"submodules/Utilities/reference/","page":"API Reference","title":"API Reference","text":"Utilities.@model\nUtilities.GenericModel\nUtilities.GenericOptimizer","category":"page"},{"location":"submodules/Utilities/reference/#MathOptInterface.Utilities.@model","page":"API Reference","title":"MathOptInterface.Utilities.@model","text":"macro model(\n model_name,\n scalar_sets,\n typed_scalar_sets,\n vector_sets,\n typed_vector_sets,\n scalar_functions,\n typed_scalar_functions,\n vector_functions,\n typed_vector_functions,\n is_optimizer = false\n)\n\nCreates a type model_name implementing the MOI model interface and containing scalar_sets scalar sets typed_scalar_sets typed scalar sets, vector_sets vector sets, typed_vector_sets typed vector sets, scalar_functions scalar functions, typed_scalar_functions typed scalar functions, vector_functions vector functions and typed_vector_functions typed vector functions. To give no set/function, write (), to give one set S, write (S,).\n\nThe function MOI.VariableIndex should not be given in scalar_functions. The model supports MOI.VariableIndex-in-S constraints where S is MOI.EqualTo, MOI.GreaterThan, MOI.LessThan, MOI.Interval, MOI.Integer, MOI.ZeroOne, MOI.Semicontinuous or MOI.Semiinteger. The sets supported with the MOI.VariableIndex cannot be controlled from the macro, use the UniversalFallback to support more sets.\n\nThis macro creates a model specialized for specific types of constraint, by defining specialized structures and methods. To create a model that, in addition to be optimized for specific constraints, also support arbitrary constraints and attributes, use UniversalFallback.\n\nIf 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.\n\nExamples\n\nThe model describing an linear program would be:\n\n@model(LPModel, # Name of model\n (), # untyped scalar sets\n (MOI.EqualTo, MOI.GreaterThan, MOI.LessThan, MOI.Interval), # typed scalar sets\n (MOI.Zeros, MOI.Nonnegatives, MOI.Nonpositives), # untyped vector sets\n (), # typed vector sets\n (), # untyped scalar functions\n (MOI.ScalarAffineFunction,), # typed scalar functions\n (MOI.VectorOfVariables,), # untyped vector functions\n (MOI.VectorAffineFunction,), # typed vector functions\n false\n )\n\nLet MOI denote MathOptInterface, MOIU denote MOI.Utilities. The macro would create the following types with struct_of_constraint_code:\n\nstruct LPModelScalarConstraints{T, C1, C2, C3, C4} <: MOIU.StructOfConstraints\n moi_equalto::C1\n moi_greaterthan::C2\n moi_lessthan::C3\n moi_interval::C4\nend\nstruct LPModelVectorConstraints{T, C1, C2, C3} <: MOIU.StructOfConstraints\n moi_zeros::C1\n moi_nonnegatives::C2\n moi_nonpositives::C3\nend\nstruct LPModelFunctionConstraints{T} <: MOIU.StructOfConstraints\n moi_scalaraffinefunction::LPModelScalarConstraints{\n T,\n MOIU.VectorOfConstraints{MOI.ScalarAffineFunction{T}, MOI.EqualTo{T}},\n MOIU.VectorOfConstraints{MOI.ScalarAffineFunction{T}, MOI.GreaterThan{T}},\n MOIU.VectorOfConstraints{MOI.ScalarAffineFunction{T}, MOI.LessThan{T}},\n MOIU.VectorOfConstraints{MOI.ScalarAffineFunction{T}, MOI.Interval{T}}\n }\n moi_vectorofvariables::LPModelVectorConstraints{\n T,\n MOIU.VectorOfConstraints{MOI.VectorOfVariables, MOI.Zeros},\n MOIU.VectorOfConstraints{MOI.VectorOfVariables, MOI.Nonnegatives},\n MOIU.VectorOfConstraints{MOI.VectorOfVariables, MOI.Nonpositives}\n }\n moi_vectoraffinefunction::LPModelVectorConstraints{\n T,\n MOIU.VectorOfConstraints{MOI.VectorAffineFunction{T}, MOI.Zeros},\n MOIU.VectorOfConstraints{MOI.VectorAffineFunction{T}, MOI.Nonnegatives},\n MOIU.VectorOfConstraints{MOI.VectorAffineFunction{T}, MOI.Nonpositives}\n }\nend\nconst LPModel{T} = MOIU.GenericModel{T,MOIU.ObjectiveContainer{T},MOIU.VariablesContainer{T},LPModelFunctionConstraints{T}}\n\nThe type LPModel implements the MathOptInterface API except methods specific to optimizers like optimize! or get with VariablePrimal.\n\n\n\n\n\n","category":"macro"},{"location":"submodules/Utilities/reference/#MathOptInterface.Utilities.GenericModel","page":"API Reference","title":"MathOptInterface.Utilities.GenericModel","text":"mutable struct GenericModel{T,O,V,C} <: AbstractModelLike{T}\n\nImplements a model supporting coefficients of type T and:\n\nAn objective function stored in .objective::O\nVariables and VariableIndex constraints stored in .variable_bounds::V\nF-in-S constraints (excluding VariableIndex constraints) stored in .constraints::C\n\nAll interactions should take place via the MOI interface, so the types O, V, and C should implement the API as needed for their functionality.\n\n\n\n\n\n","category":"type"},{"location":"submodules/Utilities/reference/#MathOptInterface.Utilities.GenericOptimizer","page":"API Reference","title":"MathOptInterface.Utilities.GenericOptimizer","text":"mutable struct GenericOptimizer{T,O,V,C} <: AbstractOptimizer{T}\n\nImplements a model supporting coefficients of type T and:\n\nAn objective function stored in .objective::O\nVariables and VariableIndex constraints stored in .variable_bounds::V\nF-in-S constraints (excluding VariableIndex constraints) stored in .constraints::C\n\nAll interactions should take place via the MOI interface, so the types O, V, and C should implement the API as needed for their functionality.\n\n\n\n\n\n","category":"type"},{"location":"submodules/Utilities/reference/#.objective","page":"API Reference","title":".objective","text":"","category":"section"},{"location":"submodules/Utilities/reference/","page":"API Reference","title":"API Reference","text":"Utilities.ObjectiveContainer","category":"page"},{"location":"submodules/Utilities/reference/#MathOptInterface.Utilities.ObjectiveContainer","page":"API Reference","title":"MathOptInterface.Utilities.ObjectiveContainer","text":"ObjectiveContainer{T}\n\nA helper struct to simplify the handling of objective functions in Utilities.Model.\n\n\n\n\n\n","category":"type"},{"location":"submodules/Utilities/reference/#.variables","page":"API Reference","title":".variables","text":"","category":"section"},{"location":"submodules/Utilities/reference/","page":"API Reference","title":"API Reference","text":"Utilities.VariablesContainer\nUtilities.FreeVariables","category":"page"},{"location":"submodules/Utilities/reference/#MathOptInterface.Utilities.VariablesContainer","page":"API Reference","title":"MathOptInterface.Utilities.VariablesContainer","text":"struct VariablesContainer{T} <: AbstractVectorBounds\n set_mask::Vector{UInt16}\n lower::Vector{T}\n upper::Vector{T}\nend\n\nA struct for storing variables and VariableIndex-related constraints. Used in MOI.Utilities.Model by default.\n\n\n\n\n\n","category":"type"},{"location":"submodules/Utilities/reference/#MathOptInterface.Utilities.FreeVariables","page":"API Reference","title":"MathOptInterface.Utilities.FreeVariables","text":"mutable struct FreeVariables <: MOI.ModelLike\n n::Int64\n FreeVariables() = new(0)\nend\n\nA 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.\n\nExample\n\nThe 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.\n\njulia> MOI.Utilities.@product_of_sets(\n Cones,\n MOI.Zeros,\n MOI.Nonnegatives,\n MOI.SecondOrderCone,\n MOI.PositiveSemidefiniteConeTriangle,\n);\n\njulia> const ConicModel{T} = MOI.Utilities.GenericOptimizer{\n T,\n MOI.Utilities.ObjectiveContainer{T},\n MOI.Utilities.FreeVariables,\n MOI.Utilities.MatrixOfConstraints{\n T,\n MOI.Utilities.MutableSparseMatrixCSC{\n T,\n Int,\n MOI.Utilities.OneBasedIndexing,\n },\n Vector{T},\n Cones{T},\n },\n};\n\njulia> model = MOI.instantiate(ConicModel{Float64}, with_bridge_type=Float64);\n\njulia> x = MOI.add_variable(model)\nMathOptInterface.VariableIndex(1)\n\njulia> c = MOI.add_constraint(model, x, MOI.GreaterThan(1.0))\nMathOptInterface.ConstraintIndex{MathOptInterface.VariableIndex, MathOptInterface.GreaterThan{Float64}}(1)\n\njulia> MOI.Bridges.is_bridged(model, c)\ntrue\n\njulia> bridge = MOI.Bridges.bridge(model, c)\nMathOptInterface.Bridges.Constraint.VectorizeBridge{Float64, MathOptInterface.VectorAffineFunction{Float64}, MathOptInterface.Nonnegatives, MathOptInterface.VariableIndex}(MathOptInterface.ConstraintIndex{MathOptInterface.VectorAffineFunction{Float64}, MathOptInterface.Nonnegatives}(1), 1.0)\n\njulia> bridge.vector_constraint\nMathOptInterface.ConstraintIndex{MathOptInterface.VectorAffineFunction{Float64}, MathOptInterface.Nonnegatives}(1)\n\njulia> MOI.Bridges.is_bridged(model, bridge.vector_constraint)\nfalse\n\n\n\n\n\n","category":"type"},{"location":"submodules/Utilities/reference/#.constraints","page":"API Reference","title":".constraints","text":"","category":"section"},{"location":"submodules/Utilities/reference/","page":"API Reference","title":"API Reference","text":"Utilities.VectorOfConstraints\nUtilities.StructOfConstraints\nUtilities.@struct_of_constraints_by_function_types\nUtilities.@struct_of_constraints_by_set_types\nUtilities.struct_of_constraint_code","category":"page"},{"location":"submodules/Utilities/reference/#MathOptInterface.Utilities.VectorOfConstraints","page":"API Reference","title":"MathOptInterface.Utilities.VectorOfConstraints","text":"mutable struct VectorOfConstraints{\n F<:MOI.AbstractFunction,\n S<:MOI.AbstractSet,\n} <: MOI.ModelLike\n constraints::CleverDicts.CleverDict{\n MOI.ConstraintIndex{F,S},\n Tuple{F,S},\n typeof(CleverDicts.key_to_index),\n typeof(CleverDicts.index_to_key),\n }\nend\n\nA struct storing F-in-S constraints as a mapping between the constraint indices to the corresponding tuple of function and set.\n\n\n\n\n\n","category":"type"},{"location":"submodules/Utilities/reference/#MathOptInterface.Utilities.StructOfConstraints","page":"API Reference","title":"MathOptInterface.Utilities.StructOfConstraints","text":"abstract type StructOfConstraints <: MOI.ModelLike end\n\nA struct storing a subfields other structs storing constraints of different types.\n\nSee Utilities.@struct_of_constraints_by_function_types and Utilities.@struct_of_constraints_by_set_types.\n\n\n\n\n\n","category":"type"},{"location":"submodules/Utilities/reference/#MathOptInterface.Utilities.@struct_of_constraints_by_function_types","page":"API Reference","title":"MathOptInterface.Utilities.@struct_of_constraints_by_function_types","text":"Utilities.@struct_of_constraints_by_function_types(name, func_types...)\n\nGiven 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 ith field has type Ci and stores the constraints of function type Fi.\n\nThe 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.\n\n\n\n\n\n","category":"macro"},{"location":"submodules/Utilities/reference/#MathOptInterface.Utilities.@struct_of_constraints_by_set_types","page":"API Reference","title":"MathOptInterface.Utilities.@struct_of_constraints_by_set_types","text":"Utilities.@struct_of_constraints_by_set_types(name, func_types...)\n\nGiven 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 ith 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.\n\n\n\n\n\n","category":"macro"},{"location":"submodules/Utilities/reference/#MathOptInterface.Utilities.struct_of_constraint_code","page":"API Reference","title":"MathOptInterface.Utilities.struct_of_constraint_code","text":"struct_of_constraint_code(struct_name, types, field_types = nothing)\n\nGiven 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 ith 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.\n\nThis function is used by the macros @model, @struct_of_constraints_by_function_types and @struct_of_constraints_by_set_types.\n\n\n\n\n\n","category":"function"},{"location":"submodules/Utilities/reference/#Caching-optimizer","page":"API Reference","title":"Caching optimizer","text":"","category":"section"},{"location":"submodules/Utilities/reference/","page":"API Reference","title":"API Reference","text":"Utilities.CachingOptimizer\nUtilities.attach_optimizer\nUtilities.reset_optimizer\nUtilities.drop_optimizer\nUtilities.state\nUtilities.mode","category":"page"},{"location":"submodules/Utilities/reference/#MathOptInterface.Utilities.CachingOptimizer","page":"API Reference","title":"MathOptInterface.Utilities.CachingOptimizer","text":"CachingOptimizer\n\nCachingOptimizer 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.\n\nConstructors\n\n CachingOptimizer(cache::MOI.ModelLike, optimizer::AbstractOptimizer)\n\nCreates a CachingOptimizer in AUTOMATIC mode, with the optimizer optimizer.\n\nThe 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.\n\n CachingOptimizer(cache::MOI.ModelLike, mode::CachingOptimizerMode)\n\nCreates a CachingOptimizer in the NO_OPTIMIZER state and mode mode.\n\nThe 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.\n\nAbout the type\n\nStates\n\nA CachingOptimizer may be in one of three possible states (CachingOptimizerState):\n\nNO_OPTIMIZER: The CachingOptimizer does not have any optimizer.\nEMPTY_OPTIMIZER: The CachingOptimizer has an empty optimizer. The optimizer is not synchronized with the cached model.\nATTACHED_OPTIMIZER: The CachingOptimizer has an optimizer, and it is synchronized with the cached model.\n\nModes\n\nA CachingOptimizer has two modes of operation (CachingOptimizerMode):\n\nMANUAL: The only methods that change the state of the CachingOptimizer are Utilities.reset_optimizer, Utilities.drop_optimizer, and Utilities.attach_optimizer. Attempting to perform an operation in the incorrect state results in an error.\nAUTOMATIC: The CachingOptimizer changes its state when necessary. For example, optimize! will automatically call attach_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 to EMPTY_OPTIMIZER mode.\n\n\n\n\n\n","category":"type"},{"location":"submodules/Utilities/reference/#MathOptInterface.Utilities.attach_optimizer","page":"API Reference","title":"MathOptInterface.Utilities.attach_optimizer","text":"attach_optimizer(model::CachingOptimizer)\n\nAttaches 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.\n\n\n\n\n\n","category":"function"},{"location":"submodules/Utilities/reference/#MathOptInterface.Utilities.reset_optimizer","page":"API Reference","title":"MathOptInterface.Utilities.reset_optimizer","text":"reset_optimizer(m::CachingOptimizer, optimizer::MOI.AbstractOptimizer)\n\nSets or resets m to have the given empty optimizer optimizer.\n\nCan be called from any state. An assertion error will be thrown if optimizer is not empty.\n\nThe CachingOptimizer m will be in state EMPTY_OPTIMIZER after the call.\n\n\n\n\n\nreset_optimizer(m::CachingOptimizer)\n\nDetaches 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.\n\n\n\n\n\n","category":"function"},{"location":"submodules/Utilities/reference/#MathOptInterface.Utilities.drop_optimizer","page":"API Reference","title":"MathOptInterface.Utilities.drop_optimizer","text":"drop_optimizer(m::CachingOptimizer)\n\nDrops the optimizer, if one is present. Can be called from any state. The CachingOptimizer will be in state NO_OPTIMIZER after the call.\n\n\n\n\n\n","category":"function"},{"location":"submodules/Utilities/reference/#MathOptInterface.Utilities.state","page":"API Reference","title":"MathOptInterface.Utilities.state","text":"state(m::CachingOptimizer)::CachingOptimizerState\n\nReturns the state of the CachingOptimizer m. See Utilities.CachingOptimizer.\n\n\n\n\n\n","category":"function"},{"location":"submodules/Utilities/reference/#MathOptInterface.Utilities.mode","page":"API Reference","title":"MathOptInterface.Utilities.mode","text":"mode(m::CachingOptimizer)::CachingOptimizerMode\n\nReturns the operating mode of the CachingOptimizer m. See Utilities.CachingOptimizer.\n\n\n\n\n\n","category":"function"},{"location":"submodules/Utilities/reference/#Mock-optimizer","page":"API Reference","title":"Mock optimizer","text":"","category":"section"},{"location":"submodules/Utilities/reference/","page":"API Reference","title":"API Reference","text":"Utilities.MockOptimizer","category":"page"},{"location":"submodules/Utilities/reference/#MathOptInterface.Utilities.MockOptimizer","page":"API Reference","title":"MathOptInterface.Utilities.MockOptimizer","text":"MockOptimizer\n\nMockOptimizer 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.\n\n\n\n\n\n","category":"type"},{"location":"submodules/Utilities/reference/#Printing","page":"API Reference","title":"Printing","text":"","category":"section"},{"location":"submodules/Utilities/reference/","page":"API Reference","title":"API Reference","text":"Utilities.latex_formulation","category":"page"},{"location":"submodules/Utilities/reference/#MathOptInterface.Utilities.latex_formulation","page":"API Reference","title":"MathOptInterface.Utilities.latex_formulation","text":"latex_formulation(model::MOI.ModelLike; kwargs...)\n\nWrap model in a type so that it can be pretty-printed as text/latex in a notebook like IJulia, or in Documenter.\n\nTo 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.\n\nPossible keyword arguments are:\n\nsimplify_coefficients : Simplify coefficients if possible by omitting them or removing trailing zeros.\ndefault_name : The name given to variables with an empty name.\nprint_types : Print the MOI type of each function and set for clarity.\n\n\n\n\n\n","category":"function"},{"location":"submodules/Utilities/reference/#Copy-utilities","page":"API Reference","title":"Copy utilities","text":"","category":"section"},{"location":"submodules/Utilities/reference/","page":"API Reference","title":"API Reference","text":"Utilities.default_copy_to\nUtilities.IndexMap\nUtilities.identity_index_map\nUtilities.ModelFilter","category":"page"},{"location":"submodules/Utilities/reference/#MathOptInterface.Utilities.default_copy_to","page":"API Reference","title":"MathOptInterface.Utilities.default_copy_to","text":"default_copy_to(dest::MOI.ModelLike, src::MOI.ModelLike)\n\nA default implementation of MOI.copy_to(dest, src) for models that implement the incremental interface, i.e., MOI.supports_incremental_interface returns true.\n\n\n\n\n\n","category":"function"},{"location":"submodules/Utilities/reference/#MathOptInterface.Utilities.IndexMap","page":"API Reference","title":"MathOptInterface.Utilities.IndexMap","text":"IndexMap()\n\nThe dictionary-like object returned by MOI.copy_to.\n\n\n\n\n\n","category":"type"},{"location":"submodules/Utilities/reference/#MathOptInterface.Utilities.identity_index_map","page":"API Reference","title":"MathOptInterface.Utilities.identity_index_map","text":"identity_index_map(model::MOI.ModelLike)\n\nReturn an IndexMap that maps all variable and constraint indices of model to themselves.\n\n\n\n\n\n","category":"function"},{"location":"submodules/Utilities/reference/#MathOptInterface.Utilities.ModelFilter","page":"API Reference","title":"MathOptInterface.Utilities.ModelFilter","text":"ModelFilter(filter::Function, model::MOI.ModelLike)\n\nA layer to filter out various components of model.\n\nThe 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.\n\nThe components that are filtered are:\n\nEntire constraint types via:\nMOI.ListOfConstraintTypesPresent\nIndividual constraints via:\nMOI.ListOfConstraintIndices{F,S}\nSpecific attributes via:\nMOI.ListOfModelAttributesSet\nMOI.ListOfConstraintAttributesSet\nMOI.ListOfVariableAttributesSet\n\nwarning: Warning\nThe 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.\n\nSee below for examples of how this works.\n\nnote: Note\nThis layer has a limited scope. It is intended by be used in conjunction with MOI.copy_to.\n\nExample: copy model excluding integer constraints\n\nUse the do syntax to provide a single function.\n\nfiltered_src = MOI.Utilities.ModelFilter(src) do item\n return item != (MOI.VariableIndex, MOI.Integer)\nend\nMOI.copy_to(dest, filtered_src)\n\nExample: copy model excluding names\n\nUse type dispatch to simplify the implementation:\n\nmy_filter(::Any) = true # Note the generic fallback!\nmy_filter(::MOI.VariableName) = false\nmy_filter(::MOI.ConstraintName) = false\nfiltered_src = MOI.Utilities.ModelFilter(my_filter, src)\nMOI.copy_to(dest, filtered_src)\n\nExample: copy irreducible infeasible subsystem\n\nmy_filter(::Any) = true # Note the generic fallback!\nfunction my_filter(ci::MOI.ConstraintIndex)\n status = MOI.get(dest, MOI.ConstraintConflictStatus(), ci)\n return status != MOI.NOT_IN_CONFLICT\nend\nfiltered_src = MOI.Utilities.ModelFilter(my_filter, src)\nMOI.copy_to(dest, filtered_src)\n\n\n\n\n\n","category":"type"},{"location":"submodules/Utilities/reference/#Penalty-relaxation","page":"API Reference","title":"Penalty relaxation","text":"","category":"section"},{"location":"submodules/Utilities/reference/","page":"API Reference","title":"API Reference","text":"Utilities.PenaltyRelaxation\nUtilities.ScalarPenaltyRelaxation","category":"page"},{"location":"submodules/Utilities/reference/#MathOptInterface.Utilities.PenaltyRelaxation","page":"API Reference","title":"MathOptInterface.Utilities.PenaltyRelaxation","text":"PenaltyRelaxation(\n penalties = Dict{MOI.ConstraintIndex,Float64}();\n default::Union{Nothing,T} = 1.0,\n)\n\nA problem modifier that, when passed to MOI.modify, destructively modifies the model in-place to create a penalized relaxation of the constraints.\n\nwarning: Warning\nThis 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.\n\nReformulation\n\nSee Utilities.ScalarPenaltyRelaxation for details of the reformulation.\n\nFor 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.\n\nReturn value\n\nMOI.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.\n\nRelax a subset of constraints\n\nTo relax a subset of constraints, pass a penalties dictionary and set default = nothing.\n\nSupported constraint types\n\nThe 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.\n\nIt does not include variable bound or integrality constraints, because these cannot be modified in-place.\n\nTo modify variable bounds, rewrite them as linear constraints.\n\nExamples\n\njulia> model = MOI.Utilities.Model{Float64}();\n\njulia> x = MOI.add_variable(model);\n\njulia> c = MOI.add_constraint(model, 1.0 * x, MOI.LessThan(2.0));\n\njulia> map = MOI.modify(model, MOI.Utilities.PenaltyRelaxation(default = 2.0));\n\njulia> print(model)\nMinimize ScalarAffineFunction{Float64}:\n 0.0 + 2.0 v[2]\n\nSubject to:\n\nScalarAffineFunction{Float64}-in-LessThan{Float64}\n 0.0 + 1.0 v[1] - 1.0 v[2] <= 2.0\n\nVariableIndex-in-GreaterThan{Float64}\n v[2] >= 0.0\n\njulia> map[c] isa MOI.ScalarAffineFunction{Float64}\ntrue\n\njulia> model = MOI.Utilities.Model{Float64}();\n\njulia> x = MOI.add_variable(model);\n\njulia> c = MOI.add_constraint(model, 1.0 * x, MOI.LessThan(2.0));\n\njulia> map = MOI.modify(model, MOI.Utilities.PenaltyRelaxation(Dict(c => 3.0)));\n\njulia> print(model)\nMinimize ScalarAffineFunction{Float64}:\n 0.0 + 3.0 v[2]\n\nSubject to:\n\nScalarAffineFunction{Float64}-in-LessThan{Float64}\n 0.0 + 1.0 v[1] - 1.0 v[2] <= 2.0\n\nVariableIndex-in-GreaterThan{Float64}\n v[2] >= 0.0\n\njulia> map[c] isa MOI.ScalarAffineFunction{Float64}\ntrue\n\n\n\n\n\n","category":"type"},{"location":"submodules/Utilities/reference/#MathOptInterface.Utilities.ScalarPenaltyRelaxation","page":"API Reference","title":"MathOptInterface.Utilities.ScalarPenaltyRelaxation","text":"ScalarPenaltyRelaxation(penalty::T) where {T}\n\nA problem modifier that, when passed to MOI.modify, destructively modifies the constraint in-place to create a penalized relaxation of the constraint.\n\nwarning: Warning\nThis 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.\n\nReformulation\n\nThe 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\n\nWhen S is MOI.LessThan or MOI.GreaterThan, we omit y or z respectively as a performance optimization.\n\nReturn value\n\nMOI.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.\n\nExamples\n\njulia> model = MOI.Utilities.Model{Float64}();\n\njulia> x = MOI.add_variable(model);\n\njulia> c = MOI.add_constraint(model, 1.0 * x, MOI.LessThan(2.0));\n\njulia> f = MOI.modify(model, c, MOI.Utilities.ScalarPenaltyRelaxation(2.0));\n\njulia> print(model)\nMinimize ScalarAffineFunction{Float64}:\n 0.0 + 2.0 v[2]\n\nSubject to:\n\nScalarAffineFunction{Float64}-in-LessThan{Float64}\n 0.0 + 1.0 v[1] - 1.0 v[2] <= 2.0\n\nVariableIndex-in-GreaterThan{Float64}\n v[2] >= 0.0\n\njulia> f isa MOI.ScalarAffineFunction{Float64}\ntrue\n\n\n\n\n\n","category":"type"},{"location":"submodules/Utilities/reference/#MatrixOfConstraints","page":"API Reference","title":"MatrixOfConstraints","text":"","category":"section"},{"location":"submodules/Utilities/reference/","page":"API Reference","title":"API Reference","text":"Utilities.MatrixOfConstraints","category":"page"},{"location":"submodules/Utilities/reference/#MathOptInterface.Utilities.MatrixOfConstraints","page":"API Reference","title":"MathOptInterface.Utilities.MatrixOfConstraints","text":"mutable struct MatrixOfConstraints{T,AT,BT,ST} <: MOI.ModelLike\n coefficients::AT\n constants::BT\n sets::ST\n caches::Vector{Any}\n are_indices_mapped::Vector{BitSet}\n final_touch::Bool\nend\n\nRepresent 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.\n\nThis model can only be used as the constraints field of a MOI.Utilities.AbstractModel.\n\nWhen 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.\n\nThe constraints can be added in two different ways:\n\nWith add_constraint, in which case a canonicalized copy of the function is stored in caches.\nWith pass_nonvariable_constraints, in which case the functions and sets are stored themselves in caches without mapping the variable indices. The corresponding index in caches is added in are_indices_mapped. This avoids doing a copy of the function in case the getter of CanonicalConstraintFunction does not make a copy for the source model, e.g., this is the case of VectorOfConstraints.\n\nWe 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.\n\nInterface\n\nThe .coefficients::AT type must implement:\n\nAT()\nMOI.empty(::AT)!\nMOI.Utilities.add_column\nMOI.Utilities.set_number_of_rows\nMOI.Utilities.allocate_terms\nMOI.Utilities.load_terms\nMOI.Utilities.final_touch\n\nThe .constants::BT type must implement:\n\nBT()\nBase.empty!(::BT)\nBase.resize(::BT)\nMOI.Utilities.load_constants\nMOI.Utilities.function_constants\nMOI.Utilities.set_from_constants\n\nThe .sets::ST type must implement:\n\nST()\nMOI.is_empty(::ST)\nMOI.empty(::ST)\nMOI.dimension(::ST)\nMOI.is_valid(::ST, ::MOI.ConstraintIndex)\nMOI.get(::ST, ::MOI.ListOfConstraintTypesPresent)\nMOI.get(::ST, ::MOI.NumberOfConstraints)\nMOI.get(::ST, ::MOI.ListOfConstraintIndices)\nMOI.Utilities.set_types\nMOI.Utilities.set_index\nMOI.Utilities.add_set\nMOI.Utilities.rows\nMOI.Utilities.final_touch\n\n\n\n\n\n","category":"type"},{"location":"submodules/Utilities/reference/#.coefficients","page":"API Reference","title":".coefficients","text":"","category":"section"},{"location":"submodules/Utilities/reference/","page":"API Reference","title":"API Reference","text":"Utilities.add_column\nUtilities.allocate_terms\nUtilities.set_number_of_rows\nUtilities.load_terms\nUtilities.final_touch\nUtilities.extract_function","category":"page"},{"location":"submodules/Utilities/reference/#MathOptInterface.Utilities.add_column","page":"API Reference","title":"MathOptInterface.Utilities.add_column","text":"add_column(coefficients)::Nothing\n\nTell coefficients to pre-allocate datastructures as needed to store one column.\n\n\n\n\n\n","category":"function"},{"location":"submodules/Utilities/reference/#MathOptInterface.Utilities.allocate_terms","page":"API Reference","title":"MathOptInterface.Utilities.allocate_terms","text":"allocate_terms(coefficients, index_map, func)::Nothing\n\nTell coefficients that the terms of the function func where the variable indices are mapped with index_map will be loaded with load_terms.\n\nThe function func must be canonicalized before calling allocate_terms. See is_canonical.\n\n\n\n\n\n","category":"function"},{"location":"submodules/Utilities/reference/#MathOptInterface.Utilities.set_number_of_rows","page":"API Reference","title":"MathOptInterface.Utilities.set_number_of_rows","text":"set_number_of_rows(coefficients, n)::Nothing\n\nTell coefficients to pre-allocate datastructures as needed to store n rows.\n\n\n\n\n\n","category":"function"},{"location":"submodules/Utilities/reference/#MathOptInterface.Utilities.load_terms","page":"API Reference","title":"MathOptInterface.Utilities.load_terms","text":"load_terms(coefficients, index_map, func, offset)::Nothing\n\nLoads the terms of func to coefficients, mapping the variable indices with index_map.\n\nThe ith dimension of func is loaded at the (offset + i)th row of coefficients.\n\nThe function must be allocated first with allocate_terms.\n\nThe function func must be canonicalized, see is_canonical.\n\n\n\n\n\n","category":"function"},{"location":"submodules/Utilities/reference/#MathOptInterface.Utilities.final_touch","page":"API Reference","title":"MathOptInterface.Utilities.final_touch","text":"final_touch(coefficients)::Nothing\n\nInforms the coefficients that all functions have been added with load_terms. No more modification is allowed unless MOI.empty! is called.\n\nfinal_touch(sets)::Nothing\n\nInforms the sets that all functions have been added with add_set. No more modification is allowed unless MOI.empty! is called.\n\n\n\n\n\n","category":"function"},{"location":"submodules/Utilities/reference/#MathOptInterface.Utilities.extract_function","page":"API Reference","title":"MathOptInterface.Utilities.extract_function","text":"extract_function(coefficients, row::Integer, constant::T) where {T}\n\nReturn the MOI.ScalarAffineFunction{T} function corresponding to row row in coefficients.\n\nextract_function(\n coefficients,\n rows::UnitRange,\n constants::Vector{T},\n) where{T}\n\nReturn the MOI.VectorAffineFunction{T} function corresponding to rows rows in coefficients.\n\n\n\n\n\n","category":"function"},{"location":"submodules/Utilities/reference/","page":"API Reference","title":"API Reference","text":"Utilities.MutableSparseMatrixCSC\nUtilities.AbstractIndexing\nUtilities.ZeroBasedIndexing\nUtilities.OneBasedIndexing","category":"page"},{"location":"submodules/Utilities/reference/#MathOptInterface.Utilities.MutableSparseMatrixCSC","page":"API Reference","title":"MathOptInterface.Utilities.MutableSparseMatrixCSC","text":"mutable struct MutableSparseMatrixCSC{Tv,Ti<:Integer,I<:AbstractIndexing}\n indexing::I\n m::Int\n n::Int\n colptr::Vector{Ti}\n rowval::Vector{Ti}\n nzval::Vector{Tv}\n nz_added::Vector{Ti}\nend\n\nMatrix 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.\n\nThe matrix is loaded in 5 steps:\n\nMOI.empty! is called.\nMOI.Utilities.add_column and MOI.Utilities.allocate_terms are called in any order.\nMOI.Utilities.set_number_of_rows is called.\nMOI.Utilities.load_terms is called for each affine function.\nMOI.Utilities.final_touch is called.\n\n\n\n\n\n","category":"type"},{"location":"submodules/Utilities/reference/#MathOptInterface.Utilities.AbstractIndexing","page":"API Reference","title":"MathOptInterface.Utilities.AbstractIndexing","text":"abstract type AbstractIndexing end\n\nIndexing to be used for storing the row and column indices of MutableSparseMatrixCSC. See ZeroBasedIndexing and OneBasedIndexing.\n\n\n\n\n\n","category":"type"},{"location":"submodules/Utilities/reference/#MathOptInterface.Utilities.ZeroBasedIndexing","page":"API Reference","title":"MathOptInterface.Utilities.ZeroBasedIndexing","text":"struct ZeroBasedIndexing <: AbstractIndexing end\n\nZero-based indexing: the ith 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.\n\n\n\n\n\n","category":"type"},{"location":"submodules/Utilities/reference/#MathOptInterface.Utilities.OneBasedIndexing","page":"API Reference","title":"MathOptInterface.Utilities.OneBasedIndexing","text":"struct ZeroBasedIndexing <: AbstractIndexing end\n\nOne-based indexing: the ith row or column has index i. This enables an allocation-free conversion of MutableSparseMatrixCSC to SparseArrays.SparseMatrixCSC.\n\n\n\n\n\n","category":"type"},{"location":"submodules/Utilities/reference/#.constants","page":"API Reference","title":".constants","text":"","category":"section"},{"location":"submodules/Utilities/reference/","page":"API Reference","title":"API Reference","text":"Utilities.load_constants\nUtilities.function_constants\nUtilities.set_from_constants","category":"page"},{"location":"submodules/Utilities/reference/#MathOptInterface.Utilities.load_constants","page":"API Reference","title":"MathOptInterface.Utilities.load_constants","text":"load_constants(constants, offset, func_or_set)::Nothing\n\nThis 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.\n\nThis function should be implemented to be usable as storage of constants for MatrixOfConstraints.\n\nThe constants are loaded in three steps:\n\nBase.empty! is called.\nBase.resize! is called with the sum of the dimensions of all constraints.\nMOI.Utilities.load_constants is called for each function for vector constraint or set for scalar constraint.\n\n\n\n\n\n","category":"function"},{"location":"submodules/Utilities/reference/#MathOptInterface.Utilities.function_constants","page":"API Reference","title":"MathOptInterface.Utilities.function_constants","text":"function_constants(constants, rows)\n\nThis function returns the function constants that were loaded with load_constants at the rows rows.\n\nThis function should be implemented to be usable as storage of constants for MatrixOfConstraints.\n\n\n\n\n\n","category":"function"},{"location":"submodules/Utilities/reference/#MathOptInterface.Utilities.set_from_constants","page":"API Reference","title":"MathOptInterface.Utilities.set_from_constants","text":"set_from_constants(constants, S::Type, rows)::S\n\nThis function returns an instance of the set S for which the constants where loaded with load_constants at the rows rows.\n\nThis function should be implemented to be usable as storage of constants for MatrixOfConstraints.\n\n\n\n\n\n","category":"function"},{"location":"submodules/Utilities/reference/","page":"API Reference","title":"API Reference","text":"Utilities.Hyperrectangle","category":"page"},{"location":"submodules/Utilities/reference/#MathOptInterface.Utilities.Hyperrectangle","page":"API Reference","title":"MathOptInterface.Utilities.Hyperrectangle","text":"struct Hyperrectangle{T} <: AbstractVectorBounds\n lower::Vector{T}\n upper::Vector{T}\nend\n\nA struct for the .constants field in MatrixOfConstraints.\n\n\n\n\n\n","category":"type"},{"location":"submodules/Utilities/reference/#.sets","page":"API Reference","title":".sets","text":"","category":"section"},{"location":"submodules/Utilities/reference/","page":"API Reference","title":"API Reference","text":"Utilities.set_index\nUtilities.set_types\nUtilities.add_set\nUtilities.rows\nUtilities.num_rows\nUtilities.set_with_dimension","category":"page"},{"location":"submodules/Utilities/reference/#MathOptInterface.Utilities.set_index","page":"API Reference","title":"MathOptInterface.Utilities.set_index","text":"set_index(sets, ::Type{S})::Union{Int,Nothing} where {S<:MOI.AbstractSet}\n\nReturn an integer corresponding to the index of the set type in the list given by set_types.\n\nIf S is not part of the list, return nothing.\n\n\n\n\n\n","category":"function"},{"location":"submodules/Utilities/reference/#MathOptInterface.Utilities.set_types","page":"API Reference","title":"MathOptInterface.Utilities.set_types","text":"set_types(sets)::Vector{Type}\n\nReturn the list of the types of the sets allowed in sets.\n\n\n\n\n\n","category":"function"},{"location":"submodules/Utilities/reference/#MathOptInterface.Utilities.add_set","page":"API Reference","title":"MathOptInterface.Utilities.add_set","text":"add_set(sets, i)::Int64\n\nAdd a scalar set of type index i.\n\nadd_set(sets, i, dim)::Int64\n\nAdd a vector set of type index i and dimension dim.\n\nBoth methods return a unique Int64 of the set that can be used to reference this set.\n\n\n\n\n\n","category":"function"},{"location":"submodules/Utilities/reference/#MathOptInterface.Utilities.rows","page":"API Reference","title":"MathOptInterface.Utilities.rows","text":"rows(sets, ci::MOI.ConstraintIndex)::Union{Int,UnitRange{Int}}\n\nReturn the rows in 1:MOI.dimension(sets) corresponding to the set of id ci.value.\n\nFor scalar sets, this returns an Int. For vector sets, this returns an UnitRange{Int}.\n\n\n\n\n\n","category":"function"},{"location":"submodules/Utilities/reference/#MathOptInterface.Utilities.num_rows","page":"API Reference","title":"MathOptInterface.Utilities.num_rows","text":"num_rows(sets::OrderedProductOfSets, ::Type{S}) where {S}\n\nReturn 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.\n\n\n\n\n\n","category":"function"},{"location":"submodules/Utilities/reference/#MathOptInterface.Utilities.set_with_dimension","page":"API Reference","title":"MathOptInterface.Utilities.set_with_dimension","text":"set_with_dimension(::Type{S}, dim) where {S<:MOI.AbstractVectorSet}\n\nReturns the instance of S of MOI.dimension dim. This needs to be implemented for sets of type S to be useable with MatrixOfConstraints.\n\n\n\n\n\n","category":"function"},{"location":"submodules/Utilities/reference/","page":"API Reference","title":"API Reference","text":"Utilities.ProductOfSets\nUtilities.MixOfScalarSets\nUtilities.@mix_of_scalar_sets\nUtilities.OrderedProductOfSets\nUtilities.@product_of_sets","category":"page"},{"location":"submodules/Utilities/reference/#MathOptInterface.Utilities.ProductOfSets","page":"API Reference","title":"MathOptInterface.Utilities.ProductOfSets","text":"abstract type ProductOfSets{T} end\n\nRepresents a cartesian product of sets of given types.\n\n\n\n\n\n","category":"type"},{"location":"submodules/Utilities/reference/#MathOptInterface.Utilities.MixOfScalarSets","page":"API Reference","title":"MathOptInterface.Utilities.MixOfScalarSets","text":"abstract type MixOfScalarSets{T} <: ProductOfSets{T} end\n\nProduct of scalar sets in the order the constraints are added, mixing the constraints of different types.\n\nUse @mix_of_scalar_sets to generate a new subtype.\n\n\n\n\n\n","category":"type"},{"location":"submodules/Utilities/reference/#MathOptInterface.Utilities.@mix_of_scalar_sets","page":"API Reference","title":"MathOptInterface.Utilities.@mix_of_scalar_sets","text":"@mix_of_scalar_sets(name, set_types...)\n\nGenerate a new MixOfScalarSets subtype.\n\nExample\n\n@mix_of_scalar_sets(\n MixedIntegerLinearProgramSets,\n MOI.GreaterThan{T},\n MOI.LessThan{T},\n MOI.EqualTo{T},\n MOI.Integer,\n)\n\n\n\n\n\n","category":"macro"},{"location":"submodules/Utilities/reference/#MathOptInterface.Utilities.OrderedProductOfSets","page":"API Reference","title":"MathOptInterface.Utilities.OrderedProductOfSets","text":"abstract type OrderedProductOfSets{T} <: ProductOfSets{T} end\n\nProduct of sets in the order the constraints are added, grouping the constraints of the same types contiguously.\n\nUse @product_of_sets to generate new subtypes.\n\n\n\n\n\n","category":"type"},{"location":"submodules/Utilities/reference/#MathOptInterface.Utilities.@product_of_sets","page":"API Reference","title":"MathOptInterface.Utilities.@product_of_sets","text":"@product_of_sets(name, set_types...)\n\nGenerate a new OrderedProductOfSets subtype.\n\nExample\n\n@product_of_sets(\n LinearOrthants,\n MOI.Zeros,\n MOI.Nonnegatives,\n MOI.Nonpositives,\n MOI.ZeroOne,\n)\n\n\n\n\n\n","category":"macro"},{"location":"submodules/Utilities/reference/#Fallbacks","page":"API Reference","title":"Fallbacks","text":"","category":"section"},{"location":"submodules/Utilities/reference/","page":"API Reference","title":"API Reference","text":"Utilities.get_fallback","category":"page"},{"location":"submodules/Utilities/reference/#MathOptInterface.Utilities.get_fallback","page":"API Reference","title":"MathOptInterface.Utilities.get_fallback","text":"get_fallback(model::MOI.ModelLike, ::MOI.ObjectiveValue)\n\nCompute the objective function value using the VariablePrimal results and the ObjectiveFunction value.\n\n\n\n\n\nget_fallback(model::MOI.ModelLike, ::MOI.DualObjectiveValue, T::Type)::T\n\nCompute 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.\n\n\n\n\n\nget_fallback(model::MOI.ModelLike, ::MOI.ConstraintPrimal,\n constraint_index::MOI.ConstraintIndex)\n\nCompute the value of the function of the constraint of index constraint_index using the VariablePrimal results and the ConstraintFunction values.\n\n\n\n\n\nget_fallback(model::MOI.ModelLike, attr::MOI.ConstraintDual,\n ci::MOI.ConstraintIndex{Union{MOI.VariableIndex,\n MOI.VectorOfVariables}})\n\nCompute 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.\n\n\n\n\n\n","category":"function"},{"location":"submodules/Utilities/reference/#Function-utilities","page":"API Reference","title":"Function utilities","text":"","category":"section"},{"location":"submodules/Utilities/reference/","page":"API Reference","title":"API Reference","text":"The following utilities are available for functions:","category":"page"},{"location":"submodules/Utilities/reference/","page":"API Reference","title":"API Reference","text":"Utilities.eval_variables\nUtilities.map_indices\nUtilities.substitute_variables\nUtilities.filter_variables\nUtilities.remove_variable\nUtilities.all_coefficients\nUtilities.unsafe_add\nUtilities.isapprox_zero\nUtilities.modify_function\nUtilities.zero_with_output_dimension","category":"page"},{"location":"submodules/Utilities/reference/#MathOptInterface.Utilities.eval_variables","page":"API Reference","title":"MathOptInterface.Utilities.eval_variables","text":"eval_variables(value_fn::Function, f::MOI.AbstractFunction)\n\nReturns the value of function f if each variable index vi is evaluated as value_fn(vi).\n\nNote that value_fn must return a Number. See substitute_variables for a similar function where value_fn returns an MOI.AbstractScalarFunction.\n\nwarning: Warning\nThe 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.\n\n\n\n\n\n","category":"function"},{"location":"submodules/Utilities/reference/#MathOptInterface.Utilities.map_indices","page":"API Reference","title":"MathOptInterface.Utilities.map_indices","text":"map_indices(index_map::Function, attr::MOI.AnyAttribute, x::X)::X where {X}\n\nSubstitute any MOI.VariableIndex (resp. MOI.ConstraintIndex) in x by the MOI.VariableIndex (resp. MOI.ConstraintIndex) of the same type given by index_map(x).\n\nWhen to implement this method for new types X\n\nThis 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.\n\n\n\n\n\nmap_indices(\n variable_map::AbstractDict{T,T},\n x::X,\n)::X where {T<:MOI.Index,X}\n\nShortcut for map_indices(vi -> variable_map[vi], x).\n\n\n\n\n\n","category":"function"},{"location":"submodules/Utilities/reference/#MathOptInterface.Utilities.substitute_variables","page":"API Reference","title":"MathOptInterface.Utilities.substitute_variables","text":"substitute_variables(variable_map::Function, x)\n\nSubstitute 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.\n\nThis 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.\n\nnote: Note\nWhen 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}.\n\n\n\n\n\n","category":"function"},{"location":"submodules/Utilities/reference/#MathOptInterface.Utilities.filter_variables","page":"API Reference","title":"MathOptInterface.Utilities.filter_variables","text":"filter_variables(keep::Function, f::AbstractFunction)\n\nReturn a new function f with the variable vi such that !keep(vi) removed.\n\nWARNING: Don't define filter_variables(::Function, ...) because Julia will not specialize on this. Define instead filter_variables(::F, ...) where {F<:Function}.\n\n\n\n\n\n","category":"function"},{"location":"submodules/Utilities/reference/#MathOptInterface.Utilities.remove_variable","page":"API Reference","title":"MathOptInterface.Utilities.remove_variable","text":"remove_variable(f::AbstractFunction, vi::VariableIndex)\n\nReturn a new function f with the variable vi removed.\n\n\n\n\n\nremove_variable(f::MOI.AbstractFunction, s::MOI.AbstractSet, vi::MOI.VariableIndex)\n\nReturn 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 (e.g. when f is a VectorOfVariables with vi being one of the variables).\n\n\n\n\n\n","category":"function"},{"location":"submodules/Utilities/reference/#MathOptInterface.Utilities.all_coefficients","page":"API Reference","title":"MathOptInterface.Utilities.all_coefficients","text":"all_coefficients(p::Function, f::MOI.AbstractFunction)\n\nDetermine 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.\n\n\n\n\n\n","category":"function"},{"location":"submodules/Utilities/reference/#MathOptInterface.Utilities.unsafe_add","page":"API Reference","title":"MathOptInterface.Utilities.unsafe_add","text":"unsafe_add(t1::MOI.ScalarAffineTerm, t2::MOI.ScalarAffineTerm)\n\nSums 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.\n\n\n\n\n\nunsafe_add(t1::MOI.ScalarQuadraticTerm, t2::MOI.ScalarQuadraticTerm)\n\nSums 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.\n\n\n\n\n\nunsafe_add(t1::MOI.VectorAffineTerm, t2::MOI.VectorAffineTerm)\n\nSums 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.\n\n\n\n\n\n","category":"function"},{"location":"submodules/Utilities/reference/#MathOptInterface.Utilities.isapprox_zero","page":"API Reference","title":"MathOptInterface.Utilities.isapprox_zero","text":"isapprox_zero(f::MOI.AbstractFunction, tol)\n\nReturn a Bool indicating whether the function f is approximately zero using tol as a tolerance.\n\nImportant note\n\nThis function assumes that f does not contain any duplicate terms, you might want to first call canonical if that is not guaranteed. For instance, given\n\nf = MOI.ScalarAffineFunction(MOI.ScalarAffineTerm.([1, -1], [x, x]), 0)\n\nthen isapprox_zero(f) is false but isapprox_zero(MOIU.canonical(f)) is true.\n\n\n\n\n\n","category":"function"},{"location":"submodules/Utilities/reference/#MathOptInterface.Utilities.modify_function","page":"API Reference","title":"MathOptInterface.Utilities.modify_function","text":"modify_function(f::AbstractFunction, change::AbstractFunctionModification)\n\nReturn a copy of the function f, modified according to change.\n\n\n\n\n\n","category":"function"},{"location":"submodules/Utilities/reference/#MathOptInterface.Utilities.zero_with_output_dimension","page":"API Reference","title":"MathOptInterface.Utilities.zero_with_output_dimension","text":"zero_with_output_dimension(::Type{T}, output_dimension::Integer) where {T}\n\nCreate an instance of type T with the output dimension output_dimension.\n\nThis is mostly useful in Bridges, when code needs to be agnostic to the type of vector-valued function that is passed in.\n\n\n\n\n\n","category":"function"},{"location":"submodules/Utilities/reference/","page":"API Reference","title":"API Reference","text":"The following functions can be used to canonicalize a function:","category":"page"},{"location":"submodules/Utilities/reference/","page":"API Reference","title":"API Reference","text":"Utilities.is_canonical\nUtilities.canonical\nUtilities.canonicalize!","category":"page"},{"location":"submodules/Utilities/reference/#MathOptInterface.Utilities.is_canonical","page":"API Reference","title":"MathOptInterface.Utilities.is_canonical","text":"is_canonical(f::Union{ScalarAffineFunction, VectorAffineFunction})\n\nReturns a Bool indicating whether the function is in canonical form. See canonical.\n\n\n\n\n\nis_canonical(f::Union{ScalarQuadraticFunction, VectorQuadraticFunction})\n\nReturns a Bool indicating whether the function is in canonical form. See canonical.\n\n\n\n\n\n","category":"function"},{"location":"submodules/Utilities/reference/#MathOptInterface.Utilities.canonical","page":"API Reference","title":"MathOptInterface.Utilities.canonical","text":"canonical(f::MOI.AbstractFunction)\n\nReturns the function in a canonical form, i.e.\n\nA term appear only once.\nThe coefficients are nonzero.\nThe terms appear in increasing order of variable where there the order of the variables is the order of their value.\nFor a AbstractVectorFunction, the terms are sorted in ascending order of output index.\n\nThe output of canonical can be assumed to be a copy of f, even for VectorOfVariables.\n\nExamples\n\nIf x (resp. y, z) is VariableIndex(1) (resp. 2, 3). The canonical representation of ScalarAffineFunction([y, x, z, x, z], [2, 1, 3, -2, -3], 5) is ScalarAffineFunction([x, y], [-1, 2], 5).\n\n\n\n\n\n","category":"function"},{"location":"submodules/Utilities/reference/#MathOptInterface.Utilities.canonicalize!","page":"API Reference","title":"MathOptInterface.Utilities.canonicalize!","text":"canonicalize!(f::Union{ScalarAffineFunction, VectorAffineFunction})\n\nConvert a function to canonical form in-place, without allocating a copy to hold the result. See canonical.\n\n\n\n\n\ncanonicalize!(f::Union{ScalarQuadraticFunction, VectorQuadraticFunction})\n\nConvert a function to canonical form in-place, without allocating a copy to hold the result. See canonical.\n\n\n\n\n\n","category":"function"},{"location":"submodules/Utilities/reference/","page":"API Reference","title":"API Reference","text":"The following functions can be used to manipulate functions with basic algebra:","category":"page"},{"location":"submodules/Utilities/reference/","page":"API Reference","title":"API Reference","text":"Utilities.scalar_type\nUtilities.scalarize\nUtilities.eachscalar\nUtilities.promote_operation\nUtilities.operate\nUtilities.operate!\nUtilities.operate_output_index!\nUtilities.vectorize","category":"page"},{"location":"submodules/Utilities/reference/#MathOptInterface.Utilities.scalar_type","page":"API Reference","title":"MathOptInterface.Utilities.scalar_type","text":"scalar_type(F::Type{<:MOI.AbstractVectorFunction})\n\nType of functions obtained by indexing objects obtained by calling eachscalar on functions of type F.\n\n\n\n\n\n","category":"function"},{"location":"submodules/Utilities/reference/#MathOptInterface.Utilities.scalarize","page":"API Reference","title":"MathOptInterface.Utilities.scalarize","text":"scalarize(func::MOI.VectorOfVariables, ignore_constants::Bool = false)\n\nReturns a vector of scalar functions making up the vector function in the form of a Vector{MOI.SingleVariable}.\n\nSee also eachscalar.\n\n\n\n\n\nscalarize(func::MOI.VectorAffineFunction{T}, ignore_constants::Bool = false)\n\nReturns a vector of scalar functions making up the vector function in the form of a Vector{MOI.ScalarAffineFunction{T}}.\n\nSee also eachscalar.\n\n\n\n\n\nscalarize(func::MOI.VectorQuadraticFunction{T}, ignore_constants::Bool = false)\n\nReturns a vector of scalar functions making up the vector function in the form of a Vector{MOI.ScalarQuadraticFunction{T}}.\n\nSee also eachscalar.\n\n\n\n\n\n","category":"function"},{"location":"submodules/Utilities/reference/#MathOptInterface.Utilities.eachscalar","page":"API Reference","title":"MathOptInterface.Utilities.eachscalar","text":"eachscalar(f::MOI.AbstractVectorFunction)\n\nReturns an iterator for the scalar components of the vector function.\n\nSee also scalarize.\n\n\n\n\n\neachscalar(f::MOI.AbstractVector)\n\nReturns an iterator for the scalar components of the vector.\n\n\n\n\n\n","category":"function"},{"location":"submodules/Utilities/reference/#MathOptInterface.Utilities.promote_operation","page":"API Reference","title":"MathOptInterface.Utilities.promote_operation","text":"promote_operation(\n op::Function,\n ::Type{T},\n ArgsTypes::Type{<:Union{T,AbstractVector{T},MOI.AbstractFunction}}...,\n) where {T<:Number}\n\nCompute the return type of the call operate(op, T, args...), where the types of the arguments args are ArgsTypes.\n\nOne assumption is that the element type T is invariant under each operation. That is, op(::T, ::T)::T where op is a +, -, *, and /.\n\nThere are six methods for which we implement Utilities.promote_operation:\n\n+ a. promote_operation(::typeof(+), ::Type{T}, ::Type{F1}, ::Type{F2})\n- a. promote_operation(::typeof(-), ::Type{T}, ::Type{F}) b. promote_operation(::typeof(-), ::Type{T}, ::Type{F1}, ::Type{F2})\n* 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}) where F1 and F2 are VariableIndex or ScalarAffineFunction d. promote_operation(::typeof(*), ::Type{T}, ::Type{<:Diagonal{T}}, ::Type{F}\n/ a. promote_operation(::typeof(/), ::Type{T}, ::Type{F}, ::Type{T})\nvcat a. promote_operation(::typeof(vcat), ::Type{T}, ::Type{F}...)\nimag a. promote_operation(::typeof(imag), ::Type{T}, ::Type{F}) where F is VariableIndex or VectorOfVariables\n\nIn 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:\n\n::T\n::VariableIndex\n::ScalarAffineFunction{T}\n::ScalarQuadraticFunction{T}\n::ScalarNonlinearFunction\n::AbstractVector{T}\n::VectorOfVariables\n::VectorAffineFunction{T}\n::VectorQuadraticFunction{T}\n::VectorNonlinearFunction\n\n\n\n\n\n","category":"function"},{"location":"submodules/Utilities/reference/#MathOptInterface.Utilities.operate","page":"API Reference","title":"MathOptInterface.Utilities.operate","text":"operate(\n op::Function,\n ::Type{T},\n args::Union{T,MOI.AbstractFunction}...,\n)::MOI.AbstractFunction where {T<:Number}\n\nReturns an MOI.AbstractFunction representing the function resulting from the operation op(args...) on functions of coefficient type T.\n\nNo argument can be modified.\n\nMethods\n\n+ a. operate(::typeof(+), ::Type{T}, ::F1) b. operate(::typeof(+), ::Type{T}, ::F1, ::F2) c. operate(::typeof(+), ::Type{T}, ::F1...)\n- a. operate(::typeof(-), ::Type{T}, ::F) b. operate(::typeof(-), ::Type{T}, ::F1, ::F2)\n* a. operate(::typeof(*), ::Type{T}, ::T, ::F) b. operate(::typeof(*), ::Type{T}, ::F, ::T) c. operate(::typeof(*), ::Type{T}, ::F1, ::F2) where F1 and F2 are VariableIndex or ScalarAffineFunction d. operate(::typeof(*), ::Type{T}, ::Diagonal{T}, ::F)\n/ a. operate(::typeof(/), ::Type{T}, ::F, ::T)\nvcat a. operate(::typeof(vcat), ::Type{T}, ::F...)\nimag a. operate(::typeof(imag), ::Type{T}, ::F) where F is VariableIndex or VectorOfVariables\n\nOne assumption is that the element type T is invariant under each operation. That is, op(::T, ::T)::T where op is a +, -, *, and /.\n\nIn 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:\n\n::T\n::VariableIndex\n::ScalarAffineFunction{T}\n::ScalarQuadraticFunction{T}\n::ScalarNonlinearFunction\n::AbstractVector{T}\n::VectorOfVariables\n::VectorAffineFunction{T}\n::VectorQuadraticFunction{T}\n::VectorNonlinearFunction\n\n\n\n\n\n","category":"function"},{"location":"submodules/Utilities/reference/#MathOptInterface.Utilities.operate!","page":"API Reference","title":"MathOptInterface.Utilities.operate!","text":"operate!(\n op::Function,\n ::Type{T},\n args::Union{T,MOI.AbstractFunction}...,\n)::MOI.AbstractFunction where {T<:Number}\n\nReturns an MOI.AbstractFunction representing the function resulting from the operation op(args...) on functions of coefficient type T.\n\nThe 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.\n\n\n\n\n\n","category":"function"},{"location":"submodules/Utilities/reference/#MathOptInterface.Utilities.operate_output_index!","page":"API Reference","title":"MathOptInterface.Utilities.operate_output_index!","text":"operate_output_index!(\n op::Union{typeof(+),typeof(-)},\n ::Type{T},\n output_index::Integer,\n f::Union{AbstractVector{T},MOI.AbstractVectorFunction}\n g::Union{T,MOI.AbstractScalarFunction}...\n) where {T<:Number}\n\nReturn an MOI.AbstractVectorFunction in which the scalar function in row output_index is the result of op(f[output_index], g).\n\nThe 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.\n\nMethods\n\n+ a. operate_output_index!(+, ::Type{T}, ::Int, ::VectorF, ::ScalarF)\n- a. operate_output_index!(-, ::Type{T}, ::Int, ::VectorF, ::ScalarF)\n\n\n\n\n\n","category":"function"},{"location":"submodules/Utilities/reference/#MathOptInterface.Utilities.vectorize","page":"API Reference","title":"MathOptInterface.Utilities.vectorize","text":"vectorize(x::AbstractVector{<:Number})\n\nReturns x.\n\n\n\n\n\nvectorize(x::AbstractVector{MOI.VariableIndex})\n\nReturns the vector of scalar affine functions in the form of a MOI.VectorAffineFunction{T}.\n\n\n\n\n\nvectorize(funcs::AbstractVector{MOI.ScalarAffineFunction{T}}) where T\n\nReturns the vector of scalar affine functions in the form of a MOI.VectorAffineFunction{T}.\n\n\n\n\n\nvectorize(funcs::AbstractVector{MOI.ScalarQuadraticFunction{T}}) where T\n\nReturns the vector of scalar quadratic functions in the form of a MOI.VectorQuadraticFunction{T}.\n\n\n\n\n\n","category":"function"},{"location":"submodules/Utilities/reference/#Constraint-utilities","page":"API Reference","title":"Constraint utilities","text":"","category":"section"},{"location":"submodules/Utilities/reference/","page":"API Reference","title":"API Reference","text":"The following utilities are available for moving the function constant to the set for scalar constraints:","category":"page"},{"location":"submodules/Utilities/reference/","page":"API Reference","title":"API Reference","text":"Utilities.shift_constant\nUtilities.supports_shift_constant\nUtilities.normalize_and_add_constraint\nUtilities.normalize_constant","category":"page"},{"location":"submodules/Utilities/reference/#MathOptInterface.Utilities.shift_constant","page":"API Reference","title":"MathOptInterface.Utilities.shift_constant","text":"shift_constant(set::MOI.AbstractScalarSet, offset)\n\nReturns a new scalar set new_set such that func-in-set is equivalent to func + offset-in-new_set.\n\nOnly define this function if it makes sense to!\n\nUse supports_shift_constant to check if the set supports shifting:\n\nif supports_shift_constant(typeof(old_set))\n new_set = shift_constant(old_set, offset)\n f.constant = 0\n add_constraint(model, f, new_set)\nelse\n add_constraint(model, f, old_set)\nend\n\nSee also supports_shift_constant.\n\nExamples\n\nThe call shift_constant(MOI.Interval(-2, 3), 1) is equal to MOI.Interval(-1, 4).\n\n\n\n\n\n","category":"function"},{"location":"submodules/Utilities/reference/#MathOptInterface.Utilities.supports_shift_constant","page":"API Reference","title":"MathOptInterface.Utilities.supports_shift_constant","text":"supports_shift_constant(::Type{S}) where {S<:MOI.AbstractSet}\n\nReturn true if shift_constant is defined for set S.\n\nSee also shift_constant.\n\n\n\n\n\n","category":"function"},{"location":"submodules/Utilities/reference/#MathOptInterface.Utilities.normalize_and_add_constraint","page":"API Reference","title":"MathOptInterface.Utilities.normalize_and_add_constraint","text":"normalize_and_add_constraint(\n model::MOI.ModelLike,\n func::MOI.AbstractScalarFunction,\n set::MOI.AbstractScalarSet;\n allow_modify_function::Bool = false,\n)\n\nAdds 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.\n\n\n\n\n\n","category":"function"},{"location":"submodules/Utilities/reference/#MathOptInterface.Utilities.normalize_constant","page":"API Reference","title":"MathOptInterface.Utilities.normalize_constant","text":"normalize_constant(\n func::MOI.AbstractScalarFunction,\n set::MOI.AbstractScalarSet;\n allow_modify_function::Bool = false,\n)\n\nReturn 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.\n\n\n\n\n\n","category":"function"},{"location":"submodules/Utilities/reference/","page":"API Reference","title":"API Reference","text":"The following utility identifies those constraints imposing bounds on a given variable, and returns those bound values:","category":"page"},{"location":"submodules/Utilities/reference/","page":"API Reference","title":"API Reference","text":"Utilities.get_bounds","category":"page"},{"location":"submodules/Utilities/reference/#MathOptInterface.Utilities.get_bounds","page":"API Reference","title":"MathOptInterface.Utilities.get_bounds","text":"get_bounds(model::MOI.ModelLike, ::Type{T}, x::MOI.VariableIndex)\n\nReturn a tuple (lb, ub) of type Tuple{T, T}, where lb and ub are lower and upper bounds, respectively, imposed on x in model.\n\n\n\n\n\n","category":"function"},{"location":"submodules/Utilities/reference/","page":"API Reference","title":"API Reference","text":"The following utilities are useful when working with symmetric matrix cones.","category":"page"},{"location":"submodules/Utilities/reference/","page":"API Reference","title":"API Reference","text":"Utilities.is_diagonal_vectorized_index\nUtilities.side_dimension_for_vectorized_dimension","category":"page"},{"location":"submodules/Utilities/reference/#MathOptInterface.Utilities.is_diagonal_vectorized_index","page":"API Reference","title":"MathOptInterface.Utilities.is_diagonal_vectorized_index","text":"is_diagonal_vectorized_index(index::Base.Integer)\n\nReturn whether index is the index of a diagonal element in a MOI.AbstractSymmetricMatrixSetTriangle set.\n\n\n\n\n\n","category":"function"},{"location":"submodules/Utilities/reference/#MathOptInterface.Utilities.side_dimension_for_vectorized_dimension","page":"API Reference","title":"MathOptInterface.Utilities.side_dimension_for_vectorized_dimension","text":"side_dimension_for_vectorized_dimension(n::Integer)\n\nReturn the dimension d such that MOI.dimension(MOI.PositiveSemidefiniteConeTriangle(d)) is n.\n\n\n\n\n\n","category":"function"},{"location":"submodules/Utilities/reference/#Set-utilities","page":"API Reference","title":"Set utilities","text":"","category":"section"},{"location":"submodules/Utilities/reference/","page":"API Reference","title":"API Reference","text":"The following utilities are available for sets:","category":"page"},{"location":"submodules/Utilities/reference/","page":"API Reference","title":"API Reference","text":"Utilities.AbstractDistance\nUtilities.ProjectionUpperBoundDistance\nUtilities.distance_to_set\nUtilities.set_dot","category":"page"},{"location":"submodules/Utilities/reference/#MathOptInterface.Utilities.AbstractDistance","page":"API Reference","title":"MathOptInterface.Utilities.AbstractDistance","text":"abstract type AbstractDistance end\n\nAn abstract type used to enabble dispatch of Utilities.distance_to_set.\n\n\n\n\n\n","category":"type"},{"location":"submodules/Utilities/reference/#MathOptInterface.Utilities.ProjectionUpperBoundDistance","page":"API Reference","title":"MathOptInterface.Utilities.ProjectionUpperBoundDistance","text":"ProjectionUpperBoundDistance() <: AbstractDistance\n\nAn upper bound on the minimum distance between point and the closest feasible point in set.\n\nDefinition of distance\n\nThe minimum distance is computed as:\n\nd(x mathcalK) = min_y in mathcalK x - y \n\nwhere x is point and mathcalK is set. The norm is computed as:\n\nx = sqrtf(x x mathcalK)\n\nwhere f is Utilities.set_dot.\n\nIn 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 = sqrtsum x_i^2.\n\nWhy an upper bound?\n\nIn 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.\n\nFor 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.\n\nIf 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.\n\n\n\n\n\n","category":"type"},{"location":"submodules/Utilities/reference/#MathOptInterface.Utilities.distance_to_set","page":"API Reference","title":"MathOptInterface.Utilities.distance_to_set","text":"distance_to_set(\n [d::AbstractDistance = ProjectionUpperBoundDistance()],]\n point::T,\n set::MOI.AbstractScalarSet,\n) where {T}\n\ndistance_to_set(\n [d::AbstractDistance = ProjectionUpperBoundDistance(),]\n point::AbstractVector{T},\n set::MOI.AbstractVectorSet,\n) where {T}\n\nCompute the distance between point and set using the distance metric d. If point is in the set set, this function must return zero(T).\n\nIf d is omitted, the default distance is Utilities.ProjectionUpperBoundDistance.\n\n\n\n\n\n","category":"function"},{"location":"submodules/Utilities/reference/#MathOptInterface.Utilities.set_dot","page":"API Reference","title":"MathOptInterface.Utilities.set_dot","text":"set_dot(x::AbstractVector, y::AbstractVector, set::AbstractVectorSet)\n\nReturn the scalar product between a vector x of the set set and a vector y of the dual of the set s.\n\n\n\n\n\nset_dot(x, y, set::AbstractScalarSet)\n\nReturn the scalar product between a number x of the set set and a number y of the dual of the set s.\n\n\n\n\n\n","category":"function"},{"location":"submodules/Utilities/reference/#DoubleDicts","page":"API Reference","title":"DoubleDicts","text":"","category":"section"},{"location":"submodules/Utilities/reference/","page":"API Reference","title":"API Reference","text":"Utilities.DoubleDicts.DoubleDict\nUtilities.DoubleDicts.DoubleDictInner\nUtilities.DoubleDicts.IndexDoubleDict\nUtilities.DoubleDicts.IndexDoubleDictInner\nUtilities.DoubleDicts.outer_keys\nUtilities.DoubleDicts.nonempty_outer_keys","category":"page"},{"location":"submodules/Utilities/reference/#MathOptInterface.Utilities.DoubleDicts.DoubleDict","page":"API Reference","title":"MathOptInterface.Utilities.DoubleDicts.DoubleDict","text":"DoubleDict{V}\n\nAn optimized dictionary to map MOI.ConstraintIndex to values of type V.\n\nWorks as a AbstractDict{MOI.ConstraintIndex,V} with minimal differences.\n\nIf V is also a MOI.ConstraintIndex, use IndexDoubleDict.\n\nNote that MOI.ConstraintIndex is not a concrete type, opposed to MOI.ConstraintIndex{MOI.VariableIndex, MOI.Integers}, which is a concrete type.\n\nWhen looping through multiple keys of the same Function-in-Set type, use\n\ninner = dict[F, S]\n\nto return a type-stable DoubleDictInner.\n\n\n\n\n\n","category":"type"},{"location":"submodules/Utilities/reference/#MathOptInterface.Utilities.DoubleDicts.DoubleDictInner","page":"API Reference","title":"MathOptInterface.Utilities.DoubleDicts.DoubleDictInner","text":"DoubleDictInner{F,S,V}\n\nA type stable inner dictionary of DoubleDict.\n\n\n\n\n\n","category":"type"},{"location":"submodules/Utilities/reference/#MathOptInterface.Utilities.DoubleDicts.IndexDoubleDict","page":"API Reference","title":"MathOptInterface.Utilities.DoubleDicts.IndexDoubleDict","text":"IndexDoubleDict\n\nA specialized version of [DoubleDict] in which the values are of type MOI.ConstraintIndex\n\nWhen looping through multiple keys of the same Function-in-Set type, use\n\ninner = dict[F, S]\n\nto return a type-stable IndexDoubleDictInner.\n\n\n\n\n\n","category":"type"},{"location":"submodules/Utilities/reference/#MathOptInterface.Utilities.DoubleDicts.IndexDoubleDictInner","page":"API Reference","title":"MathOptInterface.Utilities.DoubleDicts.IndexDoubleDictInner","text":"IndexDoubleDictInner{F,S}\n\nA type stable inner dictionary of IndexDoubleDict.\n\n\n\n\n\n","category":"type"},{"location":"submodules/Utilities/reference/#MathOptInterface.Utilities.DoubleDicts.outer_keys","page":"API Reference","title":"MathOptInterface.Utilities.DoubleDicts.outer_keys","text":"outer_keys(d::AbstractDoubleDict)\n\nReturn 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:\n\nfor (F, S) in DoubleDicts.outer_keys(dict)\n for (k, v) in dict[F, S]\n # ...\n end\nend\n\nFor performance, it is recommended that the inner loop lies in a separate function to gurantee 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.\n\n\n\n\n\n","category":"function"},{"location":"submodules/Utilities/reference/#MathOptInterface.Utilities.DoubleDicts.nonempty_outer_keys","page":"API Reference","title":"MathOptInterface.Utilities.DoubleDicts.nonempty_outer_keys","text":"nonempty_outer_keys(d::AbstractDoubleDict)\n\nReturn a vector of outer keys of the AbstractDoubleDict d.\n\nOnly outer keys that have a nonempty set of inner keys will be returned.\n\nEach outer key is a Tuple{Type,Type} so that a double loop can be easily used\n\nfor (F, S) in DoubleDicts.nonempty_outer_keys(dict)\n for (k, v) in dict[F, S]\n # ...\n end\nend\nFor performance, it is recommended that the inner loop lies in a separate\nfunction to gurantee type-stability.\n\nIf you want an iterator of all current outer keys, use [`outer_keys`](@ref).\n\n\n\n\n\n","category":"function"},{"location":"background/infeasibility_certificates/","page":"Infeasibility certificates","title":"Infeasibility certificates","text":"CurrentModule = MathOptInterface\nDocTestSetup = quote\n import MathOptInterface as MOI\nend\nDocTestFilters = [r\"MathOptInterface|MOI\"]","category":"page"},{"location":"background/infeasibility_certificates/#Infeasibility-certificates","page":"Infeasibility certificates","title":"Infeasibility certificates","text":"","category":"section"},{"location":"background/infeasibility_certificates/","page":"Infeasibility certificates","title":"Infeasibility certificates","text":"When given a conic problem that is infeasible or unbounded, some solvers can produce a certificate of infeasibility. This page explains what a certificate of infeasibility is, and the related conventions that MathOptInterface adopts.","category":"page"},{"location":"background/infeasibility_certificates/#Conic-duality","page":"Infeasibility certificates","title":"Conic duality","text":"","category":"section"},{"location":"background/infeasibility_certificates/","page":"Infeasibility certificates","title":"Infeasibility certificates","text":"MathOptInterface uses conic duality to define infeasibility certificates. A full explanation is given in the section Duality, but here is a brief overview.","category":"page"},{"location":"background/infeasibility_certificates/#Minimization-problems","page":"Infeasibility certificates","title":"Minimization problems","text":"","category":"section"},{"location":"background/infeasibility_certificates/","page":"Infeasibility certificates","title":"Infeasibility certificates","text":"For a minimization problem in geometric conic form, the primal is:","category":"page"},{"location":"background/infeasibility_certificates/","page":"Infeasibility certificates","title":"Infeasibility certificates","text":"beginalign\n min_x in mathbbR^n a_0^top x + b_0\n\n textst A_i x + b_i in mathcalC_i i = 1 ldots m\nendalign","category":"page"},{"location":"background/infeasibility_certificates/","page":"Infeasibility certificates","title":"Infeasibility certificates","text":"and the dual is a maximization problem in standard conic form:","category":"page"},{"location":"background/infeasibility_certificates/","page":"Infeasibility certificates","title":"Infeasibility certificates","text":"beginalign\n max_y_1 ldots y_m -sum_i=1^m b_i^top y_i + b_0\n\n textst a_0 - sum_i=1^m A_i^top y_i = 0\n\n y_i in mathcalC_i^* i = 1 ldots m\nendalign","category":"page"},{"location":"background/infeasibility_certificates/","page":"Infeasibility certificates","title":"Infeasibility certificates","text":"where each mathcalC_i is a closed convex cone and mathcalC_i^* is its dual cone.","category":"page"},{"location":"background/infeasibility_certificates/#Maximization-problems","page":"Infeasibility certificates","title":"Maximization problems","text":"","category":"section"},{"location":"background/infeasibility_certificates/","page":"Infeasibility certificates","title":"Infeasibility certificates","text":"For a maximization problem in geometric conic form, the primal is:","category":"page"},{"location":"background/infeasibility_certificates/","page":"Infeasibility certificates","title":"Infeasibility certificates","text":"beginalign\n max_x in mathbbR^n a_0^top x + b_0\n\n textst A_i x + b_i in mathcalC_i i = 1 ldots m\nendalign","category":"page"},{"location":"background/infeasibility_certificates/","page":"Infeasibility certificates","title":"Infeasibility certificates","text":"and the dual is a minimization problem in standard conic form:","category":"page"},{"location":"background/infeasibility_certificates/","page":"Infeasibility certificates","title":"Infeasibility certificates","text":"beginalign\n min_y_1 ldots y_m sum_i=1^m b_i^top y_i + b_0\n\n textst a_0 + sum_i=1^m A_i^top y_i = 0\n\n y_i in mathcalC_i^* i = 1 ldots m\nendalign","category":"page"},{"location":"background/infeasibility_certificates/#Unbounded-problems","page":"Infeasibility certificates","title":"Unbounded problems","text":"","category":"section"},{"location":"background/infeasibility_certificates/","page":"Infeasibility certificates","title":"Infeasibility certificates","text":"A problem is unbounded if and only if:","category":"page"},{"location":"background/infeasibility_certificates/","page":"Infeasibility certificates","title":"Infeasibility certificates","text":"there exists a feasible primal solution\nthe dual is infeasible.","category":"page"},{"location":"background/infeasibility_certificates/","page":"Infeasibility certificates","title":"Infeasibility certificates","text":"A feasible primal solution—if one exists—can be obtained by setting ObjectiveSense to FEASIBILITY_SENSE before optimizing. Therefore, most solvers stop after they prove the dual is infeasible via a certificate of dual infeasibility, but before they have found a feasible primal solution. This is also the reason that MathOptInterface defines the DUAL_INFEASIBLE status instead of UNBOUNDED.","category":"page"},{"location":"background/infeasibility_certificates/","page":"Infeasibility certificates","title":"Infeasibility certificates","text":"A certificate of dual infeasibility is an improving ray of the primal problem. That is, there exists some vector d such that for all eta 0:","category":"page"},{"location":"background/infeasibility_certificates/","page":"Infeasibility certificates","title":"Infeasibility certificates","text":"A_i (x + eta d) + b_i in mathcalC_i i = 1 ldots m","category":"page"},{"location":"background/infeasibility_certificates/","page":"Infeasibility certificates","title":"Infeasibility certificates","text":"and (for minimization problems):","category":"page"},{"location":"background/infeasibility_certificates/","page":"Infeasibility certificates","title":"Infeasibility certificates","text":"a_0^top (x + eta d) + b_0 a_0^top x + b_0","category":"page"},{"location":"background/infeasibility_certificates/","page":"Infeasibility certificates","title":"Infeasibility certificates","text":"for any feasible point x. The latter simplifies to a_0^top d 0. For maximization problems, the inequality is reversed, so that a_0^top d 0.","category":"page"},{"location":"background/infeasibility_certificates/","page":"Infeasibility certificates","title":"Infeasibility certificates","text":"If the solver has found a certificate of dual infeasibility:","category":"page"},{"location":"background/infeasibility_certificates/","page":"Infeasibility certificates","title":"Infeasibility certificates","text":"TerminationStatus must be DUAL_INFEASIBLE\nPrimalStatus must be INFEASIBILITY_CERTIFICATE\nVariablePrimal must be the corresponding value of d\nConstraintPrimal must be the corresponding value of A_i d\nObjectiveValue must be the value a_0^top d. Note that this is the value of the objective function at d, ignoring the constant b_0.","category":"page"},{"location":"background/infeasibility_certificates/","page":"Infeasibility certificates","title":"Infeasibility certificates","text":"note: Note\nThe choice of whether to scale the ray d to have magnitude 1 is left to the solver.","category":"page"},{"location":"background/infeasibility_certificates/#Infeasible-problems","page":"Infeasibility certificates","title":"Infeasible problems","text":"","category":"section"},{"location":"background/infeasibility_certificates/","page":"Infeasibility certificates","title":"Infeasibility certificates","text":"A certificate of primal infeasibility is an improving ray of the dual problem. However, because infeasibility is independent of the objective function, we first homogenize the primal problem by removing its objective.","category":"page"},{"location":"background/infeasibility_certificates/","page":"Infeasibility certificates","title":"Infeasibility certificates","text":"For a minimization problem, a dual improving ray is some vector d such that for all eta 0:","category":"page"},{"location":"background/infeasibility_certificates/","page":"Infeasibility certificates","title":"Infeasibility certificates","text":"beginalign\n-sum_i=1^m A_i^top (y_i + eta d_i) = 0 \n(y_i + eta d_i) in mathcalC_i^* i = 1 ldots m\nendalign","category":"page"},{"location":"background/infeasibility_certificates/","page":"Infeasibility certificates","title":"Infeasibility certificates","text":"and:","category":"page"},{"location":"background/infeasibility_certificates/","page":"Infeasibility certificates","title":"Infeasibility certificates","text":"-sum_i=1^m b_i^top (y_i + eta d_i) -sum_i=1^m b_i^top y_i","category":"page"},{"location":"background/infeasibility_certificates/","page":"Infeasibility certificates","title":"Infeasibility certificates","text":"for any feasible dual solution y. The latter simplifies to -sum_i=1^m b_i^top d_i 0. For a maximization problem, the inequality is sum_i=1^m b_i^top d_i 0. (Note that these are the same inequality, modulo a - sign.)","category":"page"},{"location":"background/infeasibility_certificates/","page":"Infeasibility certificates","title":"Infeasibility certificates","text":"If the solver has found a certificate of primal infeasibility:","category":"page"},{"location":"background/infeasibility_certificates/","page":"Infeasibility certificates","title":"Infeasibility certificates","text":"TerminationStatus must be INFEASIBLE\nDualStatus must be INFEASIBILITY_CERTIFICATE\nConstraintDual must be the corresponding value of d\nDualObjectiveValue must be the value -sum_i=1^m b_i^top d_i for minimization problems and sum_i=1^m b_i^top d_i for maximization problems.","category":"page"},{"location":"background/infeasibility_certificates/","page":"Infeasibility certificates","title":"Infeasibility certificates","text":"note: Note\nThe choice of whether to scale the ray d to have magnitude 1 is left to the solver.","category":"page"},{"location":"background/infeasibility_certificates/#Infeasibility-certificates-of-variable-bounds","page":"Infeasibility certificates","title":"Infeasibility certificates of variable bounds","text":"","category":"section"},{"location":"background/infeasibility_certificates/","page":"Infeasibility certificates","title":"Infeasibility certificates","text":"Many linear solvers (for example, Gurobi) do not provide explicit access to the primal infeasibility certificate of a variable bound. However, given a set of linear constraints:","category":"page"},{"location":"background/infeasibility_certificates/","page":"Infeasibility certificates","title":"Infeasibility certificates","text":"beginalign\nl_A le A x le u_A \nl_x le x le u_x\nendalign","category":"page"},{"location":"background/infeasibility_certificates/","page":"Infeasibility certificates","title":"Infeasibility certificates","text":"the primal certificate of the variable bounds can be computed using the primal certificate associated with the affine constraints, d. (Note that d will have one element for each row of the A matrix, and that some or all of the elements in the vectors l_A and u_A may be pm infty. If both l_A and u_A are finite for some row, the corresponding element in `d must be 0.)","category":"page"},{"location":"background/infeasibility_certificates/","page":"Infeasibility certificates","title":"Infeasibility certificates","text":"Given d, compute bard = d^top A. If the bound is finite, a certificate for the lower variable bound of x_i is maxbard_i 0, and a certificate for the upper variable bound is minbard_i 0.","category":"page"},{"location":"manual/modification/","page":"Problem modification","title":"Problem modification","text":"CurrentModule = MathOptInterface\nDocTestSetup = quote\n import MathOptInterface as MOI\nend\nDocTestFilters = [r\"MathOptInterface|MOI\"]","category":"page"},{"location":"manual/modification/#Problem-modification","page":"Problem modification","title":"Problem modification","text":"","category":"section"},{"location":"manual/modification/","page":"Problem modification","title":"Problem modification","text":"In addition to adding and deleting constraints and variables, MathOptInterface supports modifying, in-place, coefficients in the constraints and the objective function of a model.","category":"page"},{"location":"manual/modification/","page":"Problem modification","title":"Problem modification","text":"These modifications can be grouped into two categories:","category":"page"},{"location":"manual/modification/","page":"Problem modification","title":"Problem modification","text":"modifications which replace the set of function of a constraint with a new set or function\nmodifications which change, in-place, a component of a function","category":"page"},{"location":"manual/modification/","page":"Problem modification","title":"Problem modification","text":"warning: Warning\nSome ModelLike objects do not support problem modification.","category":"page"},{"location":"manual/modification/#Modify-the-set-of-a-constraint","page":"Problem modification","title":"Modify the set of a constraint","text":"","category":"section"},{"location":"manual/modification/","page":"Problem modification","title":"Problem modification","text":"Use set and ConstraintSet to modify the set of a constraint by replacing it with a new instance of the same type.","category":"page"},{"location":"manual/modification/","page":"Problem modification","title":"Problem modification","text":"julia> c = MOI.add_constraint(\n model,\n MOI.ScalarAffineFunction([MOI.ScalarAffineTerm(1.0, x)], 0.0),\n MOI.EqualTo(1.0),\n )\nMathOptInterface.ConstraintIndex{MathOptInterface.ScalarAffineFunction{Float64}, MathOptInterface.EqualTo{Float64}}(1)\n\njulia> MOI.set(model, MOI.ConstraintSet(), c, MOI.EqualTo(2.0));\n\njulia> MOI.get(model, MOI.ConstraintSet(), c) == MOI.EqualTo(2.0)\ntrue","category":"page"},{"location":"manual/modification/","page":"Problem modification","title":"Problem modification","text":"However, the following will fail as the new set is of a different type to the original set:","category":"page"},{"location":"manual/modification/","page":"Problem modification","title":"Problem modification","text":"julia> MOI.set(model, MOI.ConstraintSet(), c, MOI.GreaterThan(2.0))\nERROR: [...]","category":"page"},{"location":"manual/modification/#Special-cases:-set-transforms","page":"Problem modification","title":"Special cases: set transforms","text":"","category":"section"},{"location":"manual/modification/","page":"Problem modification","title":"Problem modification","text":"If our constraint is an affine inequality, then this corresponds to modifying the right-hand side of a constraint in linear programming.","category":"page"},{"location":"manual/modification/","page":"Problem modification","title":"Problem modification","text":"In some special cases, solvers may support efficiently changing the set of a constraint (for example, from LessThan to GreaterThan). For these cases, MathOptInterface provides the transform method.","category":"page"},{"location":"manual/modification/","page":"Problem modification","title":"Problem modification","text":"The transform function returns a new constraint index, and the old constraint index (that is, c) is no longer valid.","category":"page"},{"location":"manual/modification/","page":"Problem modification","title":"Problem modification","text":"julia> c = MOI.add_constraint(\n model,\n MOI.ScalarAffineFunction([MOI.ScalarAffineTerm(1.0, x)], 0.0),\n MOI.LessThan(1.0),\n )\nMathOptInterface.ConstraintIndex{MathOptInterface.ScalarAffineFunction{Float64}, MathOptInterface.LessThan{Float64}}(1)\n\njulia> new_c = MOI.transform(model, c, MOI.GreaterThan(2.0));\n\njulia> MOI.is_valid(model, c)\nfalse\n\njulia> MOI.is_valid(model, new_c)\ntrue","category":"page"},{"location":"manual/modification/","page":"Problem modification","title":"Problem modification","text":"note: Note\ntransform cannot be called with a set of the same type. Use set instead.","category":"page"},{"location":"manual/modification/#Modify-the-function-of-a-constraint","page":"Problem modification","title":"Modify the function of a constraint","text":"","category":"section"},{"location":"manual/modification/","page":"Problem modification","title":"Problem modification","text":"Use set and ConstraintFunction to modify the function of a constraint by replacing it with a new instance of the same type.","category":"page"},{"location":"manual/modification/","page":"Problem modification","title":"Problem modification","text":"julia> c = MOI.add_constraint(\n model,\n MOI.ScalarAffineFunction([MOI.ScalarAffineTerm(1.0, x)], 0.0),\n MOI.EqualTo(1.0),\n )\nMathOptInterface.ConstraintIndex{MathOptInterface.ScalarAffineFunction{Float64}, MathOptInterface.EqualTo{Float64}}(1)\n\njulia> new_f = MOI.ScalarAffineFunction([MOI.ScalarAffineTerm(2.0, x)], 1.0);\n\njulia> MOI.set(model, MOI.ConstraintFunction(), c, new_f);\n\njulia> MOI.get(model, MOI.ConstraintFunction(), c) ≈ new_f\ntrue","category":"page"},{"location":"manual/modification/","page":"Problem modification","title":"Problem modification","text":"However, the following will fail as the new function is of a different type to the original function:","category":"page"},{"location":"manual/modification/","page":"Problem modification","title":"Problem modification","text":"julia> MOI.set(model, MOI.ConstraintFunction(), c, x)\nERROR: [...]","category":"page"},{"location":"manual/modification/#Modify-constant-term-in-a-scalar-function","page":"Problem modification","title":"Modify constant term in a scalar function","text":"","category":"section"},{"location":"manual/modification/","page":"Problem modification","title":"Problem modification","text":"Use modify and ScalarConstantChange to modify the constant term in a ScalarAffineFunction or ScalarQuadraticFunction.","category":"page"},{"location":"manual/modification/","page":"Problem modification","title":"Problem modification","text":"julia> c = MOI.add_constraint(\n model,\n MOI.ScalarAffineFunction([MOI.ScalarAffineTerm(1.0, x)], 0.0),\n MOI.EqualTo(1.0),\n )\nMathOptInterface.ConstraintIndex{MathOptInterface.ScalarAffineFunction{Float64}, MathOptInterface.EqualTo{Float64}}(1)\n\njulia> MOI.modify(model, c, MOI.ScalarConstantChange(1.0));\n\njulia> new_f = MOI.ScalarAffineFunction([MOI.ScalarAffineTerm(1.0, x)], 1.0);\n\njulia> MOI.get(model, MOI.ConstraintFunction(), c) ≈ new_f\ntrue","category":"page"},{"location":"manual/modification/","page":"Problem modification","title":"Problem modification","text":"ScalarConstantChange can also be used to modify the objective function by passing an instance of ObjectiveFunction:","category":"page"},{"location":"manual/modification/","page":"Problem modification","title":"Problem modification","text":"julia> MOI.set(\n model,\n MOI.ObjectiveFunction{MOI.ScalarAffineFunction{Float64}}(),\n new_f,\n );\n\njulia> MOI.modify(\n model,\n MOI.ObjectiveFunction{MOI.ScalarAffineFunction{Float64}}(),\n MOI.ScalarConstantChange(-1.0)\n );\n\njulia> MOI.get(\n model,\n MOI.ObjectiveFunction{MOI.ScalarAffineFunction{Float64}}(),\n ) ≈ MOI.ScalarAffineFunction([MOI.ScalarAffineTerm(1.0, x)], -1.0)\ntrue","category":"page"},{"location":"manual/modification/#Modify-constant-terms-in-a-vector-function","page":"Problem modification","title":"Modify constant terms in a vector function","text":"","category":"section"},{"location":"manual/modification/","page":"Problem modification","title":"Problem modification","text":"Use modify and VectorConstantChange to modify the constant vector in a VectorAffineFunction or VectorQuadraticFunction.","category":"page"},{"location":"manual/modification/","page":"Problem modification","title":"Problem modification","text":"julia> c = MOI.add_constraint(\n model,\n MOI.VectorAffineFunction([\n MOI.VectorAffineTerm(1, MOI.ScalarAffineTerm(1.0, x)),\n MOI.VectorAffineTerm(2, MOI.ScalarAffineTerm(2.0, x)),\n ],\n [0.0, 0.0],\n ),\n MOI.Nonnegatives(2),\n )\nMathOptInterface.ConstraintIndex{MathOptInterface.VectorAffineFunction{Float64}, MathOptInterface.Nonnegatives}(1)\n\njulia> MOI.modify(model, c, MOI.VectorConstantChange([3.0, 4.0]));\n\njulia> new_f = MOI.VectorAffineFunction(\n [\n MOI.VectorAffineTerm(1, MOI.ScalarAffineTerm(1.0, x)),\n MOI.VectorAffineTerm(2, MOI.ScalarAffineTerm(2.0, x)),\n ],\n [3.0, 4.0],\n );\n\njulia> MOI.get(model, MOI.ConstraintFunction(), c) ≈ new_f\ntrue","category":"page"},{"location":"manual/modification/#Modify-affine-coefficients-in-a-scalar-function","page":"Problem modification","title":"Modify affine coefficients in a scalar function","text":"","category":"section"},{"location":"manual/modification/","page":"Problem modification","title":"Problem modification","text":"Use modify and ScalarCoefficientChange to modify the affine coefficient of a ScalarAffineFunction or ScalarQuadraticFunction.","category":"page"},{"location":"manual/modification/","page":"Problem modification","title":"Problem modification","text":"julia> c = MOI.add_constraint(\n model,\n MOI.ScalarAffineFunction([MOI.ScalarAffineTerm(1.0, x)], 0.0),\n MOI.EqualTo(1.0),\n )\nMathOptInterface.ConstraintIndex{MathOptInterface.ScalarAffineFunction{Float64}, MathOptInterface.EqualTo{Float64}}(1)\n\njulia> MOI.modify(model, c, MOI.ScalarCoefficientChange(x, 2.0));\n\njulia> new_f = MOI.ScalarAffineFunction([MOI.ScalarAffineTerm(2.0, x)], 0.0);\n\njulia> MOI.get(model, MOI.ConstraintFunction(), c) ≈ new_f\ntrue","category":"page"},{"location":"manual/modification/","page":"Problem modification","title":"Problem modification","text":"ScalarCoefficientChange can also be used to modify the objective function by passing an instance of ObjectiveFunction.","category":"page"},{"location":"manual/modification/#Modify-affine-coefficients-in-a-vector-function","page":"Problem modification","title":"Modify affine coefficients in a vector function","text":"","category":"section"},{"location":"manual/modification/","page":"Problem modification","title":"Problem modification","text":"Use modify and MultirowChange to modify a vector of affine coefficients in a VectorAffineFunction or a VectorQuadraticFunction.","category":"page"},{"location":"manual/modification/","page":"Problem modification","title":"Problem modification","text":"julia> c = MOI.add_constraint(\n model,\n MOI.VectorAffineFunction([\n MOI.VectorAffineTerm(1, MOI.ScalarAffineTerm(1.0, x)),\n MOI.VectorAffineTerm(2, MOI.ScalarAffineTerm(2.0, x)),\n ],\n [0.0, 0.0],\n ),\n MOI.Nonnegatives(2),\n )\nMathOptInterface.ConstraintIndex{MathOptInterface.VectorAffineFunction{Float64}, MathOptInterface.Nonnegatives}(1)\n\njulia> MOI.modify(model, c, MOI.MultirowChange(x, [(1, 3.0), (2, 4.0)]));\n\njulia> new_f = MOI.VectorAffineFunction(\n [\n MOI.VectorAffineTerm(1, MOI.ScalarAffineTerm(3.0, x)),\n MOI.VectorAffineTerm(2, MOI.ScalarAffineTerm(4.0, x)),\n ],\n [0.0, 0.0],\n );\n\njulia> MOI.get(model, MOI.ConstraintFunction(), c) ≈ new_f\ntrue","category":"page"},{"location":"manual/variables/","page":"Variables","title":"Variables","text":"CurrentModule = MathOptInterface\nDocTestSetup = quote\n import MathOptInterface as MOI\nend\nDocTestFilters = [r\"MathOptInterface|MOI\"]","category":"page"},{"location":"manual/variables/#Variables","page":"Variables","title":"Variables","text":"","category":"section"},{"location":"manual/variables/#Add-a-variable","page":"Variables","title":"Add a variable","text":"","category":"section"},{"location":"manual/variables/","page":"Variables","title":"Variables","text":"Use add_variable to add a single variable.","category":"page"},{"location":"manual/variables/","page":"Variables","title":"Variables","text":"julia> x = MOI.add_variable(model)\nMOI.VariableIndex(1)","category":"page"},{"location":"manual/variables/","page":"Variables","title":"Variables","text":"add_variable returns a VariableIndex type, which is used to refer to the added variable in other calls.","category":"page"},{"location":"manual/variables/","page":"Variables","title":"Variables","text":"Check if a VariableIndex is valid using is_valid.","category":"page"},{"location":"manual/variables/","page":"Variables","title":"Variables","text":"julia> MOI.is_valid(model, x)\ntrue","category":"page"},{"location":"manual/variables/","page":"Variables","title":"Variables","text":"Use add_variables to add a number of variables.","category":"page"},{"location":"manual/variables/","page":"Variables","title":"Variables","text":"julia> y = MOI.add_variables(model, 2)\n2-element Vector{MathOptInterface.VariableIndex}:\n MOI.VariableIndex(2)\n MOI.VariableIndex(3)","category":"page"},{"location":"manual/variables/","page":"Variables","title":"Variables","text":"warning: Warning\nThe integer does not necessarily correspond to the column inside an optimizer.","category":"page"},{"location":"manual/variables/#Delete-a-variable","page":"Variables","title":"Delete a variable","text":"","category":"section"},{"location":"manual/variables/","page":"Variables","title":"Variables","text":"Delete a variable using delete.","category":"page"},{"location":"manual/variables/","page":"Variables","title":"Variables","text":"julia> MOI.delete(model, x)\n\njulia> MOI.is_valid(model, x)\nfalse","category":"page"},{"location":"manual/variables/","page":"Variables","title":"Variables","text":"warning: Warning\nNot all ModelLike models support deleting variables. A DeleteNotAllowed error is thrown if this is not supported.","category":"page"},{"location":"manual/variables/#Variable-attributes","page":"Variables","title":"Variable attributes","text":"","category":"section"},{"location":"manual/variables/","page":"Variables","title":"Variables","text":"The following attributes are available for variables:","category":"page"},{"location":"manual/variables/","page":"Variables","title":"Variables","text":"VariableName\nVariablePrimalStart\nVariablePrimal","category":"page"},{"location":"manual/variables/","page":"Variables","title":"Variables","text":"Get and set these attributes using get and set.","category":"page"},{"location":"manual/variables/","page":"Variables","title":"Variables","text":"julia> MOI.set(model, MOI.VariableName(), x, \"var_x\")\n\njulia> MOI.get(model, MOI.VariableName(), x)\n\"var_x\"","category":"page"},{"location":"submodules/FileFormats/reference/","page":"API Reference","title":"API Reference","text":"CurrentModule = MathOptInterface\nDocTestSetup = quote\n import MathOptInterface as MOI\nend\nDocTestFilters = [r\"MathOptInterface|MOI\"]","category":"page"},{"location":"submodules/FileFormats/reference/#File-Formats","page":"API Reference","title":"File Formats","text":"","category":"section"},{"location":"submodules/FileFormats/reference/","page":"API Reference","title":"API Reference","text":"Functions to help read and write MOI models to/from various file formats. See The FileFormats submodule for more details.","category":"page"},{"location":"submodules/FileFormats/reference/","page":"API Reference","title":"API Reference","text":"FileFormats.Model\nFileFormats.FileFormat\nFileFormats.CBF.Model\nFileFormats.LP.Model\nFileFormats.MOF.Model\nFileFormats.MPS.Model\nFileFormats.NL.Model\nFileFormats.SDPA.Model","category":"page"},{"location":"submodules/FileFormats/reference/#MathOptInterface.FileFormats.Model","page":"API Reference","title":"MathOptInterface.FileFormats.Model","text":"Model(\n ;\n format::FileFormat = FORMAT_AUTOMATIC,\n filename::Union{Nothing, String} = nothing,\n kwargs...\n)\n\nReturn model corresponding to the FileFormat format, or, if format == FORMAT_AUTOMATIC, guess the format from filename.\n\nThe filename argument is only needed if format == FORMAT_AUTOMATIC.\n\nkwargs are passed to the underlying model constructor.\n\n\n\n\n\n","category":"function"},{"location":"submodules/FileFormats/reference/#MathOptInterface.FileFormats.FileFormat","page":"API Reference","title":"MathOptInterface.FileFormats.FileFormat","text":"FileFormat\n\nList of accepted export formats.\n\nFORMAT_AUTOMATIC: try to detect the file format based on the file name\nFORMAT_CBF: the Conic Benchmark format\nFORMAT_LP: the LP file format\nFORMAT_MOF: the MathOptFormat file format\nFORMAT_MPS: the MPS file format\nFORMAT_NL: the AMPL .nl file format\nFORMAT_REW: the .rew file format, which is MPS with generic names\nFORMAT_SDPA: the SemiDefinite Programming Algorithm format\n\n\n\n\n\n","category":"type"},{"location":"submodules/FileFormats/reference/#MathOptInterface.FileFormats.CBF.Model","page":"API Reference","title":"MathOptInterface.FileFormats.CBF.Model","text":"Model()\n\nCreate an empty instance of FileFormats.CBF.Model.\n\n\n\n\n\n","category":"type"},{"location":"submodules/FileFormats/reference/#MathOptInterface.FileFormats.LP.Model","page":"API Reference","title":"MathOptInterface.FileFormats.LP.Model","text":"Model(; kwargs...)\n\nCreate an empty instance of FileFormats.LP.Model.\n\nKeyword arguments are:\n\nmaximum_length::Int=255: the maximum length for the name of a variable. lp_solve 5.0 allows only 16 characters, while CPLEX 12.5+ allow 255.\nwarn::Bool=false: print a warning when variables or constraints are renamed.\n\n\n\n\n\n","category":"type"},{"location":"submodules/FileFormats/reference/#MathOptInterface.FileFormats.MOF.Model","page":"API Reference","title":"MathOptInterface.FileFormats.MOF.Model","text":"Model(; kwargs...)\n\nCreate an empty instance of FileFormats.MOF.Model.\n\nKeyword arguments are:\n\nprint_compact::Bool=false: print the JSON file in a compact format without spaces or newlines.\nwarn::Bool=false: print a warning when variables or constraints are renamed\ndifferentiation_backend::MOI.Nonlinear.AbstractAutomaticDifferentiation = MOI.Nonlinear.SparseReverseMode(): automatic differentiation backend to use when reading models with nonlinear constraints and objectives.\n\n\n\n\n\n","category":"type"},{"location":"submodules/FileFormats/reference/#MathOptInterface.FileFormats.MPS.Model","page":"API Reference","title":"MathOptInterface.FileFormats.MPS.Model","text":"Model(; kwargs...)\n\nCreate an empty instance of FileFormats.MPS.Model.\n\nKeyword arguments are:\n\nwarn::Bool=false: print a warning when variables or constraints are renamed.\nprint_objsense::Bool=false: print the OBJSENSE section when writing\ngeneric_names::Bool=false: strip all names in the model and replace them with the generic names C$i and R$i for the i'th column and row respectively.\nquadratic_format::QuadraticFormat = kQuadraticFormatGurobi: specify the solver-specific extension used when writing the quadratic components of the model. Options are kQuadraticFormatGurobi, kQuadraticFormatCPLEX, and kQuadraticFormatMosek.\n\n\n\n\n\n","category":"type"},{"location":"submodules/FileFormats/reference/#MathOptInterface.FileFormats.NL.Model","page":"API Reference","title":"MathOptInterface.FileFormats.NL.Model","text":"Model(; use_nlp_block::Bool = true)\n\nCreate a new Optimizer object.\n\n\n\n\n\n","category":"type"},{"location":"submodules/FileFormats/reference/#MathOptInterface.FileFormats.SDPA.Model","page":"API Reference","title":"MathOptInterface.FileFormats.SDPA.Model","text":"Model(; number_type::Type = Float64)\n\nCreate an empty instance of FileFormats.SDPA.Model{number_type}.\n\nIt is important to be aware that the SDPA file format is interpreted in geometric form and not standard conic form. The standard conic form and geometric conic form are two dual standard forms for semidefinite programs (SDPs). The geometric conic form of an SDP is as follows:\n\nbeginalign\n min_y in mathbbR^m b^T y\n\n textst sum_i=1^m A_i y_i - C in mathbbK\nendalign\n\nwhere mathcalK is a cartesian product of nonnegative orthant and positive semidefinite matrices that align with a block diagonal structure shared with the matrices A_i and C.\n\nIn other words, the geometric conic form contains free variables and affine constraints in either the nonnegative orthant or the positive semidefinite cone. That is, in the MathOptInterface's terminology, MOI.VectorAffineFunction-in-MOI.Nonnegatives and MOI.VectorAffineFunction-in-MOI.PositiveSemidefiniteConeTriangle constraints.\n\nThe corresponding standard conic form of the dual SDP is as follows:\n\nbeginalign\n max_X in mathbbK texttr(CX)\n\n textst texttr(A_iX) = b_i i = 1 ldots m\nendalign\n\nIn other words, the standard conic form contains nonnegative and positive semidefinite variables with equality constraints. That is, in the MathOptInterface's terminology, MOI.VectorOfVariables-in-MOI.Nonnegatives, MOI.VectorOfVariables-in-MOI.PositiveSemidefiniteConeTriangle and MOI.ScalarAffineFunction-in-MOI.EqualTo constraints.\n\nIf a model is in standard conic form, use Dualization.jl to transform it into the geometric conic form before writting it. Otherwise, the nonnegative (resp. positive semidefinite) variables will be bridged into free variables with affine constraints constraining them to belong to the nonnegative orthant (resp. positive semidefinite cone) by the MOI.Bridges.Constraint.VectorFunctionizeBridge. Moreover, equality constraints will be bridged into pairs of affine constraints in the nonnegative orthant by the MOI.Bridges.Constraint.SplitIntervalBridge and then the MOI.Bridges.Constraint.VectorizeBridge.\n\nIf a solver is in standard conic form, use Dualization.jl to transform the model read into standard conic form before copying it to the solver. Otherwise, the free variables will be bridged into pairs of variables in the nonnegative orthant by the MOI.Bridges.Variable.FreeBridge and affine constraints will be bridged into equality constraints by creating a slack variable by the MOI.Bridges.Constraint.VectorSlackBridge.\n\n\n\n\n\n","category":"type"},{"location":"submodules/FileFormats/reference/#Other-helpers","page":"API Reference","title":"Other helpers","text":"","category":"section"},{"location":"submodules/FileFormats/reference/","page":"API Reference","title":"API Reference","text":"FileFormats.NL.SolFileResults","category":"page"},{"location":"submodules/FileFormats/reference/#MathOptInterface.FileFormats.NL.SolFileResults","page":"API Reference","title":"MathOptInterface.FileFormats.NL.SolFileResults","text":"SolFileResults(filename::String, model::Model)\n\nParse the .sol file filename created by solving model and return a SolFileResults struct.\n\nThe returned struct supports the MOI.get API for querying result attributes such as MOI.TerminationStatus, MOI.VariablePrimal, and MOI.ConstraintDual.\n\n\n\n\n\nSolFileResults(\n raw_status::String,\n termination_status::MOI.TerminationStatusCode,\n)\n\nReturn a SolFileResults struct with MOI.RawStatusString set to raw_status, MOI.TerminationStatus set to termination_status, and MOI.PrimalStatus and MOI.DualStatus set to NO_SOLUTION.\n\nAll other attributes are un-set.\n\n\n\n\n\n","category":"type"},{"location":"submodules/Benchmarks/reference/","page":"API Reference","title":"API Reference","text":"CurrentModule = MathOptInterface\nDocTestSetup = quote\n import MathOptInterface as MOI\nend\nDocTestFilters = [r\"MathOptInterface|MOI\"]","category":"page"},{"location":"submodules/Benchmarks/reference/#Benchmarks","page":"API Reference","title":"Benchmarks","text":"","category":"section"},{"location":"submodules/Benchmarks/reference/","page":"API Reference","title":"API Reference","text":"Functions to help benchmark the performance of solver wrappers. See The Benchmarks submodule for more details.","category":"page"},{"location":"submodules/Benchmarks/reference/","page":"API Reference","title":"API Reference","text":"Benchmarks.suite\nBenchmarks.create_baseline\nBenchmarks.compare_against_baseline","category":"page"},{"location":"submodules/Benchmarks/reference/#MathOptInterface.Benchmarks.suite","page":"API Reference","title":"MathOptInterface.Benchmarks.suite","text":"suite(\n new_model::Function;\n exclude::Vector{Regex} = Regex[]\n)\n\nCreate a suite of benchmarks. new_model should be a function that takes no arguments, and returns a new instance of the optimizer you wish to benchmark.\n\nUse exclude to exclude a subset of benchmarks.\n\nExamples\n\nsuite() do\n GLPK.Optimizer()\nend\nsuite(exclude = [r\"delete\"]) do\n Gurobi.Optimizer(OutputFlag=0)\nend\n\n\n\n\n\n","category":"function"},{"location":"submodules/Benchmarks/reference/#MathOptInterface.Benchmarks.create_baseline","page":"API Reference","title":"MathOptInterface.Benchmarks.create_baseline","text":"create_baseline(suite, name::String; directory::String = \"\"; kwargs...)\n\nRun all benchmarks in suite and save to files called name in directory.\n\nExtra kwargs are based to BenchmarkTools.run.\n\nExamples\n\nmy_suite = suite(() -> GLPK.Optimizer())\ncreate_baseline(my_suite, \"glpk_master\"; directory = \"/tmp\", verbose = true)\n\n\n\n\n\n","category":"function"},{"location":"submodules/Benchmarks/reference/#MathOptInterface.Benchmarks.compare_against_baseline","page":"API Reference","title":"MathOptInterface.Benchmarks.compare_against_baseline","text":"compare_against_baseline(\n suite, name::String; directory::String = \"\",\n report_filename::String = \"report.txt\"\n)\n\nRun all benchmarks in suite and compare against files called name in directory that were created by a call to create_baseline.\n\nA report summarizing the comparison is written to report_filename in directory.\n\nExtra kwargs are based to BenchmarkTools.run.\n\nExamples\n\nmy_suite = suite(() -> GLPK.Optimizer())\ncompare_against_baseline(\n my_suite, \"glpk_master\"; directory = \"/tmp\", verbose = true\n)\n\n\n\n\n\n","category":"function"},{"location":"submodules/Test/overview/","page":"Overview","title":"Overview","text":"CurrentModule = MathOptInterface\nDocTestSetup = quote\n import MathOptInterface as MOI\nend\nDocTestFilters = [r\"MathOptInterface|MOI\"]","category":"page"},{"location":"submodules/Test/overview/#test_module","page":"Overview","title":"The Test submodule","text":"","category":"section"},{"location":"submodules/Test/overview/","page":"Overview","title":"Overview","text":"The Test submodule provides tools to help solvers implement unit tests in order to ensure they implement the MathOptInterface API correctly, and to check for solver-correctness.","category":"page"},{"location":"submodules/Test/overview/","page":"Overview","title":"Overview","text":"We use a centralized repository of tests, so that if we find a bug in one solver, instead of adding a test to that particular repository, we add it here so that all solvers can benefit.","category":"page"},{"location":"submodules/Test/overview/#How-to-test-a-solver","page":"Overview","title":"How to test a solver","text":"","category":"section"},{"location":"submodules/Test/overview/","page":"Overview","title":"Overview","text":"The skeleton below can be used for the wrapper test file of a solver named FooBar.","category":"page"},{"location":"submodules/Test/overview/","page":"Overview","title":"Overview","text":"# ============================ /test/MOI_wrapper.jl ============================\nmodule TestFooBar\n\nimport FooBar\nusing Test\n\nimport MathOptInterface as MOI\n\nconst OPTIMIZER = MOI.instantiate(\n MOI.OptimizerWithAttributes(FooBar.Optimizer, MOI.Silent() => true),\n)\n\nconst BRIDGED = MOI.instantiate(\n MOI.OptimizerWithAttributes(FooBar.Optimizer, MOI.Silent() => true),\n with_bridge_type = Float64,\n)\n\n# See the docstring of MOI.Test.Config for other arguments.\nconst CONFIG = MOI.Test.Config(\n # Modify tolerances as necessary.\n atol = 1e-6,\n rtol = 1e-6,\n # Use MOI.LOCALLY_SOLVED for local solvers.\n optimal_status = MOI.OPTIMAL,\n # Pass attributes or MOI functions to `exclude` to skip tests that\n # rely on this functionality.\n exclude = Any[MOI.VariableName, MOI.delete],\n)\n\n\"\"\"\n runtests()\n\nThis function runs all functions in the this Module starting with `test_`.\n\"\"\"\nfunction runtests()\n for name in names(@__MODULE__; all = true)\n if startswith(\"$(name)\", \"test_\")\n @testset \"$(name)\" begin\n getfield(@__MODULE__, name)()\n end\n end\n end\nend\n\n\"\"\"\n test_runtests()\n\nThis function runs all the tests in MathOptInterface.Test.\n\nPass arguments to `exclude` to skip tests for functionality that is not\nimplemented or that your solver doesn't support.\n\"\"\"\nfunction test_runtests()\n MOI.Test.runtests(\n BRIDGED,\n CONFIG,\n exclude = [\n \"test_attribute_NumberOfThreads\",\n \"test_quadratic_\",\n ],\n # This argument is useful to prevent tests from failing on future\n # releases of MOI that add new tests. Don't let this number get too far\n # behind the current MOI release though. You should periodically check\n # for new tests to fix bugs and implement new features.\n exclude_tests_after = v\"0.10.5\",\n )\n return\nend\n\n\"\"\"\n test_SolverName()\n\nYou can also write new tests for solver-specific functionality. Write each new\ntest as a function with a name beginning with `test_`.\n\"\"\"\nfunction test_SolverName()\n @test MOI.get(FooBar.Optimizer(), MOI.SolverName()) == \"FooBar\"\n return\nend\n\nend # module TestFooBar\n\n# This line at tne end of the file runs all the tests!\nTestFooBar.runtests()","category":"page"},{"location":"submodules/Test/overview/","page":"Overview","title":"Overview","text":"Then modify your runtests.jl file to include the MOI_wrapper.jl file:","category":"page"},{"location":"submodules/Test/overview/","page":"Overview","title":"Overview","text":"# ============================ /test/runtests.jl ============================\n\nusing Test\n\n@testset \"MOI\" begin\n include(\"test/MOI_wrapper.jl\")\nend","category":"page"},{"location":"submodules/Test/overview/","page":"Overview","title":"Overview","text":"info: Info\nThe optimizer BRIDGED constructed with instantiate automatically bridges constraints that are not supported by OPTIMIZER using the bridges listed in Bridges. It is recommended for an implementation of MOI to only support constraints that are natively supported by the solver and let bridges transform the constraint to the appropriate form. For this reason it is expected that tests may not pass if OPTIMIZER is used instead of BRIDGED.","category":"page"},{"location":"submodules/Test/overview/#How-to-debug-a-failing-test","page":"Overview","title":"How to debug a failing test","text":"","category":"section"},{"location":"submodules/Test/overview/","page":"Overview","title":"Overview","text":"When writing a solver, it's likely that you will initially fail many tests. Some failures will be bugs, but other failures you may choose to exclude.","category":"page"},{"location":"submodules/Test/overview/","page":"Overview","title":"Overview","text":"There are two ways to exclude tests:","category":"page"},{"location":"submodules/Test/overview/","page":"Overview","title":"Overview","text":"Exclude tests whose names contain a string using:\nMOI.Test.runtests(\n model,\n config;\n exclude = String[\"test_to_exclude\", \"test_conic_\"],\n)\nThis will exclude tests whose name contains either of the two strings provided.\nExclude tests which rely on specific functionality using:\nMOI.Test.Config(exclude = Any[MOI.VariableName, MOI.optimize!])\nThis will exclude tests which use the MOI.VariableName attribute, or which call MOI.optimize!.","category":"page"},{"location":"submodules/Test/overview/","page":"Overview","title":"Overview","text":"Each test that fails can be independently called as:","category":"page"},{"location":"submodules/Test/overview/","page":"Overview","title":"Overview","text":"model = FooBar.Optimizer()\nconfig = MOI.Test.Config()\nMOI.empty!(model)\nMOI.Test.test_category_name_that_failed(model, config)","category":"page"},{"location":"submodules/Test/overview/","page":"Overview","title":"Overview","text":"You can look-up the source code of the test that failed by searching for it in the src/Test/test_category.jl file.","category":"page"},{"location":"submodules/Test/overview/","page":"Overview","title":"Overview","text":"tip: Tip\nEach test function also has a docstring that explains what the test is for. Use ? MOI.Test.test_category_name_that_failed from the REPL to read it.","category":"page"},{"location":"submodules/Test/overview/","page":"Overview","title":"Overview","text":"Periodically, you should re-run excluded tests to see if they now pass. The easiest way to do this is to swap the exclude keyword argument of runtests to include. For example:","category":"page"},{"location":"submodules/Test/overview/","page":"Overview","title":"Overview","text":"MOI.Test.runtests(\n model,\n config;\n exclude = String[\"test_to_exclude\", \"test_conic_\"],\n)","category":"page"},{"location":"submodules/Test/overview/","page":"Overview","title":"Overview","text":"becomes","category":"page"},{"location":"submodules/Test/overview/","page":"Overview","title":"Overview","text":"MOI.Test.runtests(\n model,\n config;\n include = String[\"test_to_exclude\", \"test_conic_\"],\n)","category":"page"},{"location":"submodules/Test/overview/#How-to-add-a-test","page":"Overview","title":"How to add a test","text":"","category":"section"},{"location":"submodules/Test/overview/","page":"Overview","title":"Overview","text":"To detect bugs in solvers, we add new tests to MOI.Test.","category":"page"},{"location":"submodules/Test/overview/","page":"Overview","title":"Overview","text":"As an example, ECOS errored calling optimize! twice in a row. (See ECOS.jl PR #72.) We could add a test to ECOS.jl, but that would only stop us from re-introducing the bug to ECOS.jl in the future, but it would not catch other solvers in the ecosystem with the same bug. Instead, if we add a test to MOI.Test, then all solvers will also check that they handle a double optimize call.","category":"page"},{"location":"submodules/Test/overview/","page":"Overview","title":"Overview","text":"For this test, we care about correctness, rather than performance. therefore, we don't expect solvers to efficiently decide that they have already solved the problem, only that calling optimize! twice doesn't throw an error or give the wrong answer.","category":"page"},{"location":"submodules/Test/overview/","page":"Overview","title":"Overview","text":"Step 1","category":"page"},{"location":"submodules/Test/overview/","page":"Overview","title":"Overview","text":"Install the MathOptInterface julia package in dev mode:","category":"page"},{"location":"submodules/Test/overview/","page":"Overview","title":"Overview","text":"julia> ]\n(@v1.6) pkg> dev MathOptInterface","category":"page"},{"location":"submodules/Test/overview/","page":"Overview","title":"Overview","text":"Step 2","category":"page"},{"location":"submodules/Test/overview/","page":"Overview","title":"Overview","text":"From here on, proceed with making the following changes in the ~/.julia/dev/MathOptInterface folder (or equivalent dev path on your machine).","category":"page"},{"location":"submodules/Test/overview/","page":"Overview","title":"Overview","text":"Step 3","category":"page"},{"location":"submodules/Test/overview/","page":"Overview","title":"Overview","text":"Since the double-optimize error involves solving an optimization problem, add a new test to src/Test/test_solve.jl:","category":"page"},{"location":"submodules/Test/overview/","page":"Overview","title":"Overview","text":"\"\"\"\n test_unit_optimize!_twice(model::MOI.ModelLike, config::Config)\n\nTest that calling `MOI.optimize!` twice does not error.\n\nThis problem was first detected in ECOS.jl PR#72:\nhttps://github.com/jump-dev/ECOS.jl/pull/72\n\"\"\"\nfunction test_unit_optimize!_twice(\n model::MOI.ModelLike,\n config::Config{T},\n) where {T}\n # Use the `@requires` macro to check conditions that the test function\n # requires to run. Models failing this `@requires` check will silently skip\n # the test.\n @requires MOI.supports_constraint(\n model,\n MOI.VariableIndex,\n MOI.GreaterThan{Float64},\n )\n @requires _supports(config, MOI.optimize!)\n # If needed, you can test that the model is empty at the start of the test.\n # You can assume that this will be the case for tests run via `runtests`.\n # User's calling tests individually need to call `MOI.empty!` themselves.\n @test MOI.is_empty(model)\n # Create a simple model. Try to make this as simple as possible so that the\n # majority of solvers can run the test.\n x = MOI.add_variable(model)\n MOI.add_constraint(model, x, MOI.GreaterThan(one(T)))\n MOI.set(model, MOI.ObjectiveSense(), MOI.MIN_SENSE)\n MOI.set(\n model,\n MOI.ObjectiveFunction{MOI.VariableIndex}(),\n x,\n )\n # The main component of the test: does calling `optimize!` twice error?\n MOI.optimize!(model)\n MOI.optimize!(model)\n # Check we have a solution.\n @test MOI.get(model, MOI.TerminationStatus()) == MOI.OPTIMAL\n # There is a three-argument version of `Base.isapprox` for checking\n # approximate equality based on the tolerances defined in `config`:\n @test isapprox(MOI.get(model, MOI.VariablePrimal(), x), one(T), config)\n # For code-style, these tests should always `return` `nothing`.\n return\nend","category":"page"},{"location":"submodules/Test/overview/","page":"Overview","title":"Overview","text":"info: Info\nMake sure the function is agnostic to the number type T; don't assume it is a Float64 capable solver.","category":"page"},{"location":"submodules/Test/overview/","page":"Overview","title":"Overview","text":"We also need to write a test for the test. Place this function immediately below the test you just wrote in the same file:","category":"page"},{"location":"submodules/Test/overview/","page":"Overview","title":"Overview","text":"function setup_test(\n ::typeof(test_unit_optimize!_twice),\n model::MOI.Utilities.MockOptimizer,\n ::Config,\n)\n MOI.Utilities.set_mock_optimize!(\n model,\n (mock::MOI.Utilities.MockOptimizer) -> MOIU.mock_optimize!(\n mock,\n MOI.OPTIMAL,\n (MOI.FEASIBLE_POINT, [1.0]),\n ),\n )\n return\nend","category":"page"},{"location":"submodules/Test/overview/","page":"Overview","title":"Overview","text":"Finally, you also need to implement Test.version_added. If we added this test when the latest released version of MOI was v0.10.5, define:","category":"page"},{"location":"submodules/Test/overview/","page":"Overview","title":"Overview","text":"version_added(::typeof(test_unit_optimize!_twice)) = v\"0.10.6\"","category":"page"},{"location":"submodules/Test/overview/","page":"Overview","title":"Overview","text":"Step 6","category":"page"},{"location":"submodules/Test/overview/","page":"Overview","title":"Overview","text":"Commit the changes to git from ~/.julia/dev/MathOptInterface and submit the PR for review.","category":"page"},{"location":"submodules/Test/overview/","page":"Overview","title":"Overview","text":"tip: Tip\nIf you need help writing a test, open an issue on GitHub, or ask the Developer Chatroom.","category":"page"},{"location":"reference/errors/","page":"Errors","title":"Errors","text":"CurrentModule = MathOptInterface\nDocTestSetup = quote\n import MathOptInterface as MOI\nend\nDocTestFilters = [r\"MathOptInterface|MOI\"]","category":"page"},{"location":"reference/errors/#Errors","page":"Errors","title":"Errors","text":"","category":"section"},{"location":"reference/errors/","page":"Errors","title":"Errors","text":"When an MOI call fails on a model, precise errors should be thrown when possible instead of simply calling error with a message. The docstrings for the respective methods describe the errors that the implementation should throw in certain situations. This error-reporting system allows code to distinguish between internal errors (that should be shown to the user) and unsupported operations which may have automatic workarounds.","category":"page"},{"location":"reference/errors/","page":"Errors","title":"Errors","text":"When an invalid index is used in an MOI call, an InvalidIndex is thrown:","category":"page"},{"location":"reference/errors/","page":"Errors","title":"Errors","text":"InvalidIndex","category":"page"},{"location":"reference/errors/#MathOptInterface.InvalidIndex","page":"Errors","title":"MathOptInterface.InvalidIndex","text":"struct InvalidIndex{IndexType<:Index} <: Exception\n index::IndexType\nend\n\nAn error indicating that the index index is invalid.\n\n\n\n\n\n","category":"type"},{"location":"reference/errors/","page":"Errors","title":"Errors","text":"When an invalid result index is used to retrieve an attribute, a ResultIndexBoundsError is thrown:","category":"page"},{"location":"reference/errors/","page":"Errors","title":"Errors","text":"ResultIndexBoundsError\ncheck_result_index_bounds","category":"page"},{"location":"reference/errors/#MathOptInterface.ResultIndexBoundsError","page":"Errors","title":"MathOptInterface.ResultIndexBoundsError","text":"struct ResultIndexBoundsError{AttrType} <: Exception\n attr::AttrType\n result_count::Int\nend\n\nAn error indicating that the requested attribute attr could not be retrieved, because the solver returned too few results compared to what was requested. For instance, the user tries to retrieve VariablePrimal(2) when only one solution is available, or when the model is infeasible and has no solution.\n\nSee also: check_result_index_bounds.\n\n\n\n\n\n","category":"type"},{"location":"reference/errors/#MathOptInterface.check_result_index_bounds","page":"Errors","title":"MathOptInterface.check_result_index_bounds","text":"check_result_index_bounds(model::ModelLike, attr)\n\nThis function checks whether enough results are available in the model for the requested attr, using its result_index field. If the model does not have sufficient results to answer the query, it throws a ResultIndexBoundsError.\n\n\n\n\n\n","category":"function"},{"location":"reference/errors/","page":"Errors","title":"Errors","text":"As discussed in JuMP mapping, for scalar constraint with a nonzero function constant, a ScalarFunctionConstantNotZero exception may be thrown:","category":"page"},{"location":"reference/errors/","page":"Errors","title":"Errors","text":"ScalarFunctionConstantNotZero","category":"page"},{"location":"reference/errors/#MathOptInterface.ScalarFunctionConstantNotZero","page":"Errors","title":"MathOptInterface.ScalarFunctionConstantNotZero","text":"struct ScalarFunctionConstantNotZero{T, F, S} <: Exception\n constant::T\nend\n\nAn error indicating that the constant part of the function in the constraint F-in-S is nonzero.\n\n\n\n\n\n","category":"type"},{"location":"reference/errors/","page":"Errors","title":"Errors","text":"Some VariableIndex constraints cannot be combined on the same variable:","category":"page"},{"location":"reference/errors/","page":"Errors","title":"Errors","text":"LowerBoundAlreadySet\nUpperBoundAlreadySet","category":"page"},{"location":"reference/errors/#MathOptInterface.LowerBoundAlreadySet","page":"Errors","title":"MathOptInterface.LowerBoundAlreadySet","text":"LowerBoundAlreadySet{S1, S2}\n\nError thrown when setting a VariableIndex-in-S2 when a VariableIndex-in-S1 has already been added and the sets S1, S2 both set a lower bound, i.e. they are EqualTo, GreaterThan, Interval, Semicontinuous or Semiinteger.\n\n\n\n\n\n","category":"type"},{"location":"reference/errors/#MathOptInterface.UpperBoundAlreadySet","page":"Errors","title":"MathOptInterface.UpperBoundAlreadySet","text":"UpperBoundAlreadySet{S1, S2}\n\nError thrown when setting a VariableIndex-in-S2 when a VariableIndex-in-S1 has already been added and the sets S1, S2 both set an upper bound, i.e. they are EqualTo, LessThan, Interval, Semicontinuous or Semiinteger.\n\n\n\n\n\n","category":"type"},{"location":"reference/errors/","page":"Errors","title":"Errors","text":"As discussed in AbstractCallback, trying to get attributes inside a callback may throw:","category":"page"},{"location":"reference/errors/","page":"Errors","title":"Errors","text":"OptimizeInProgress","category":"page"},{"location":"reference/errors/#MathOptInterface.OptimizeInProgress","page":"Errors","title":"MathOptInterface.OptimizeInProgress","text":"struct OptimizeInProgress{AttrType<:AnyAttribute} <: Exception\n attr::AttrType\nend\n\nError thrown from optimizer when MOI.get(optimizer, attr) is called inside an AbstractCallback while it is only defined once optimize! has completed. This can only happen when is_set_by_optimize(attr) is true.\n\n\n\n\n\n","category":"type"},{"location":"reference/errors/","page":"Errors","title":"Errors","text":"Trying to submit the wrong type of AbstractSubmittable inside an AbstractCallback (for example, a UserCut inside a LazyConstraintCallback) will throw:","category":"page"},{"location":"reference/errors/","page":"Errors","title":"Errors","text":"InvalidCallbackUsage","category":"page"},{"location":"reference/errors/#MathOptInterface.InvalidCallbackUsage","page":"Errors","title":"MathOptInterface.InvalidCallbackUsage","text":"struct InvalidCallbackUsage{C, S} <: Exception\n callback::C\n submittable::S\nend\n\nAn error indicating that submittable cannot be submitted inside callback.\n\nFor example, UserCut cannot be submitted inside LazyConstraintCallback.\n\n\n\n\n\n","category":"type"},{"location":"reference/errors/","page":"Errors","title":"Errors","text":"The rest of the errors defined in MOI fall in two categories represented by the following two abstract types:","category":"page"},{"location":"reference/errors/","page":"Errors","title":"Errors","text":"UnsupportedError\nNotAllowedError","category":"page"},{"location":"reference/errors/#MathOptInterface.UnsupportedError","page":"Errors","title":"MathOptInterface.UnsupportedError","text":"UnsupportedError <: Exception\n\nAbstract type for error thrown when an element is not supported by the model.\n\n\n\n\n\n","category":"type"},{"location":"reference/errors/#MathOptInterface.NotAllowedError","page":"Errors","title":"MathOptInterface.NotAllowedError","text":"NotAllowedError <: Exception\n\nAbstract type for error thrown when an operation is supported but cannot be applied in the current state of the model.\n\n\n\n\n\n","category":"type"},{"location":"reference/errors/","page":"Errors","title":"Errors","text":"The different UnsupportedError and NotAllowedError are the following errors:","category":"page"},{"location":"reference/errors/","page":"Errors","title":"Errors","text":"UnsupportedAttribute\nSetAttributeNotAllowed\nAddVariableNotAllowed\nUnsupportedConstraint\nAddConstraintNotAllowed\nModifyConstraintNotAllowed\nModifyObjectiveNotAllowed\nDeleteNotAllowed\nUnsupportedSubmittable\nSubmitNotAllowed\nUnsupportedNonlinearOperator","category":"page"},{"location":"reference/errors/#MathOptInterface.UnsupportedAttribute","page":"Errors","title":"MathOptInterface.UnsupportedAttribute","text":"struct UnsupportedAttribute{AttrType} <: UnsupportedError\n attr::AttrType\n message::String\nend\n\nAn error indicating that the attribute attr is not supported by the model, i.e. that supports returns false.\n\n\n\n\n\n","category":"type"},{"location":"reference/errors/#MathOptInterface.SetAttributeNotAllowed","page":"Errors","title":"MathOptInterface.SetAttributeNotAllowed","text":"struct SetAttributeNotAllowed{AttrType} <: NotAllowedError\n attr::AttrType\n message::String\nend\n\nAn error indicating that the attribute attr is supported (see supports) but cannot be set for some reason (see the error string).\n\n\n\n\n\n","category":"type"},{"location":"reference/errors/#MathOptInterface.AddVariableNotAllowed","page":"Errors","title":"MathOptInterface.AddVariableNotAllowed","text":"struct AddVariableNotAllowed <: NotAllowedError\n message::String # Human-friendly explanation why the attribute cannot be set\nend\n\nAn error indicating that variables cannot be added to the model.\n\n\n\n\n\n","category":"type"},{"location":"reference/errors/#MathOptInterface.UnsupportedConstraint","page":"Errors","title":"MathOptInterface.UnsupportedConstraint","text":"struct UnsupportedConstraint{F<:AbstractFunction, S<:AbstractSet} <: UnsupportedError\n message::String # Human-friendly explanation why the attribute cannot be set\nend\n\nAn error indicating that constraints of type F-in-S are not supported by the model, i.e. that supports_constraint returns false.\n\n\n\n\n\n","category":"type"},{"location":"reference/errors/#MathOptInterface.AddConstraintNotAllowed","page":"Errors","title":"MathOptInterface.AddConstraintNotAllowed","text":"struct AddConstraintNotAllowed{F<:AbstractFunction, S<:AbstractSet} <: NotAllowedError\n message::String # Human-friendly explanation why the attribute cannot be set\nend\n\nAn error indicating that constraints of type F-in-S are supported (see supports_constraint) but cannot be added.\n\n\n\n\n\n","category":"type"},{"location":"reference/errors/#MathOptInterface.ModifyConstraintNotAllowed","page":"Errors","title":"MathOptInterface.ModifyConstraintNotAllowed","text":"struct ModifyConstraintNotAllowed{F<:AbstractFunction, S<:AbstractSet,\n C<:AbstractFunctionModification} <: NotAllowedError\n constraint_index::ConstraintIndex{F, S}\n change::C\n message::String\nend\n\nAn error indicating that the constraint modification change cannot be applied to the constraint of index ci.\n\n\n\n\n\n","category":"type"},{"location":"reference/errors/#MathOptInterface.ModifyObjectiveNotAllowed","page":"Errors","title":"MathOptInterface.ModifyObjectiveNotAllowed","text":"struct ModifyObjectiveNotAllowed{C<:AbstractFunctionModification} <: NotAllowedError\n change::C\n message::String\nend\n\nAn error indicating that the objective modification change cannot be applied to the objective.\n\n\n\n\n\n","category":"type"},{"location":"reference/errors/#MathOptInterface.DeleteNotAllowed","page":"Errors","title":"MathOptInterface.DeleteNotAllowed","text":"struct DeleteNotAllowed{IndexType <: Index} <: NotAllowedError\n index::IndexType\n message::String\nend\n\nAn error indicating that the index index cannot be deleted.\n\n\n\n\n\n","category":"type"},{"location":"reference/errors/#MathOptInterface.UnsupportedSubmittable","page":"Errors","title":"MathOptInterface.UnsupportedSubmittable","text":"struct UnsupportedSubmittable{SubmitType} <: UnsupportedError\n sub::SubmitType\n message::String\nend\n\nAn error indicating that the submittable sub is not supported by the model, i.e. that supports returns false.\n\n\n\n\n\n","category":"type"},{"location":"reference/errors/#MathOptInterface.SubmitNotAllowed","page":"Errors","title":"MathOptInterface.SubmitNotAllowed","text":"struct SubmitNotAllowed{SubmitTyp<:AbstractSubmittable} <: NotAllowedError\n sub::SubmitType\n message::String\nend\n\nAn error indicating that the submittable sub is supported (see supports) but cannot be added for some reason (see the error string).\n\n\n\n\n\n","category":"type"},{"location":"reference/errors/#MathOptInterface.UnsupportedNonlinearOperator","page":"Errors","title":"MathOptInterface.UnsupportedNonlinearOperator","text":"UnsupportedNonlinearOperator(head::Symbol[, message::String]) <: UnsupportedError\n\nAn error thrown by optimizers if they do not support the operator head in a ScalarNonlinearFunction.\n\nExample\n\njulia> import MathOptInterface as MOI\n\njulia> throw(MOI.UnsupportedNonlinearOperator(:black_box))\nERROR: MathOptInterface.UnsupportedNonlinearOperator: The nonlinear operator `:black_box` is not supported by the model.\nStacktrace:\n[...]\n\n\n\n\n\n","category":"type"},{"location":"reference/errors/","page":"Errors","title":"Errors","text":"Note that setting the ConstraintFunction of a VariableIndex constraint is not allowed:","category":"page"},{"location":"reference/errors/","page":"Errors","title":"Errors","text":"SettingVariableIndexNotAllowed","category":"page"},{"location":"reference/errors/#MathOptInterface.SettingVariableIndexNotAllowed","page":"Errors","title":"MathOptInterface.SettingVariableIndexNotAllowed","text":"SettingVariableIndexNotAllowed()\n\nError type that should be thrown when the user calls set to change the ConstraintFunction of a VariableIndex constraint.\n\n\n\n\n\n","category":"type"},{"location":"reference/variables/","page":"Variables","title":"Variables","text":"CurrentModule = MathOptInterface\nDocTestSetup = quote\n import MathOptInterface as MOI\nend\nDocTestFilters = [r\"MathOptInterface|MOI\"]","category":"page"},{"location":"reference/variables/#Variables","page":"Variables","title":"Variables","text":"","category":"section"},{"location":"reference/variables/#Functions","page":"Variables","title":"Functions","text":"","category":"section"},{"location":"reference/variables/","page":"Variables","title":"Variables","text":"add_variable\nadd_variables\nadd_constrained_variable\nadd_constrained_variables\nsupports_add_constrained_variable\nsupports_add_constrained_variables\nis_valid(::ModelLike,::VariableIndex)\ndelete(::ModelLike, ::VariableIndex)\ndelete(::ModelLike, ::Vector{VariableIndex})","category":"page"},{"location":"reference/variables/#MathOptInterface.add_variable","page":"Variables","title":"MathOptInterface.add_variable","text":"add_variable(model::ModelLike)::VariableIndex\n\nAdd a scalar variable to the model, returning a variable index.\n\nA AddVariableNotAllowed error is thrown if adding variables cannot be done in the current state of the model model.\n\n\n\n\n\n","category":"function"},{"location":"reference/variables/#MathOptInterface.add_variables","page":"Variables","title":"MathOptInterface.add_variables","text":"add_variables(model::ModelLike, n::Int)::Vector{VariableIndex}\n\nAdd n scalar variables to the model, returning a vector of variable indices.\n\nA AddVariableNotAllowed error is thrown if adding variables cannot be done in the current state of the model model.\n\n\n\n\n\n","category":"function"},{"location":"reference/variables/#MathOptInterface.add_constrained_variable","page":"Variables","title":"MathOptInterface.add_constrained_variable","text":"add_constrained_variable(\n model::ModelLike,\n set::AbstractScalarSet\n)::Tuple{MOI.VariableIndex,\n MOI.ConstraintIndex{MOI.VariableIndex, typeof(set)}}\n\nAdd to model a scalar variable constrained to belong to set, returning the index of the variable created and the index of the constraint constraining the variable to belong to set.\n\nBy default, this function falls back to creating a free variable with add_variable and then constraining it to belong to set with add_constraint.\n\n\n\n\n\n","category":"function"},{"location":"reference/variables/#MathOptInterface.add_constrained_variables","page":"Variables","title":"MathOptInterface.add_constrained_variables","text":"add_constrained_variables(\n model::ModelLike,\n sets::AbstractVector{<:AbstractScalarSet}\n)::Tuple{\n Vector{MOI.VariableIndex},\n Vector{MOI.ConstraintIndex{MOI.VariableIndex,eltype(sets)}},\n}\n\nAdd to model scalar variables constrained to belong to sets, returning the indices of the variables created and the indices of the constraints constraining the variables to belong to each set in sets. That is, if it returns variables and constraints, constraints[i] is the index of the constraint constraining variable[i] to belong to sets[i].\n\nBy default, this function falls back to calling add_constrained_variable on each set.\n\n\n\n\n\nadd_constrained_variables(\n model::ModelLike,\n set::AbstractVectorSet,\n)::Tuple{\n Vector{MOI.VariableIndex},\n MOI.ConstraintIndex{MOI.VectorOfVariables,typeof(set)},\n}\n\nAdd to model a vector of variables constrained to belong to set, returning the indices of the variables created and the index of the constraint constraining the vector of variables to belong to set.\n\nBy default, this function falls back to creating free variables with add_variables and then constraining it to belong to set with add_constraint.\n\n\n\n\n\n","category":"function"},{"location":"reference/variables/#MathOptInterface.supports_add_constrained_variable","page":"Variables","title":"MathOptInterface.supports_add_constrained_variable","text":"supports_add_constrained_variable(\n model::ModelLike,\n S::Type{<:AbstractScalarSet}\n)::Bool\n\nReturn a Bool indicating whether model supports constraining a variable to belong to a set of type S either on creation of the variable with add_constrained_variable or after the variable is created with add_constraint.\n\nBy default, this function falls back to supports_add_constrained_variables(model, Reals) && supports_constraint(model, MOI.VariableIndex, S) which is the correct definition for most models.\n\nExample\n\nSuppose that a solver supports only two kind of variables: binary variables and continuous variables with a lower bound. If the solver decides not to support VariableIndex-in-Binary and VariableIndex-in-GreaterThan constraints, it only has to implement add_constrained_variable for these two sets which prevents the user to add both a binary constraint and a lower bound on the same variable. Moreover, if the user adds a VariableIndex-in-GreaterThan constraint, implementing this interface (i.e., supports_add_constrained_variables) enables the constraint to be transparently bridged into a supported constraint.\n\n\n\n\n\n","category":"function"},{"location":"reference/variables/#MathOptInterface.supports_add_constrained_variables","page":"Variables","title":"MathOptInterface.supports_add_constrained_variables","text":"supports_add_constrained_variables(\n model::ModelLike,\n S::Type{<:AbstractVectorSet}\n)::Bool\n\nReturn a Bool indicating whether model supports constraining a vector of variables to belong to a set of type S either on creation of the vector of variables with add_constrained_variables or after the variable is created with add_constraint.\n\nBy default, if S is Reals then this function returns true and otherwise, it falls back to supports_add_constrained_variables(model, Reals) && supports_constraint(model, MOI.VectorOfVariables, S) which is the correct definition for most models.\n\nExample\n\nIn the standard conic form (see Duality), the variables are grouped into several cones and the constraints are affine equality constraints. If Reals is not one of the cones supported by the solvers then it needs to implement supports_add_constrained_variables(::Optimizer, ::Type{Reals}) = false as free variables are not supported. The solvers should then implement supports_add_constrained_variables(::Optimizer, ::Type{<:SupportedCones}) = true where SupportedCones is the union of all cone types that are supported; it does not have to implement the method supports_constraint(::Type{VectorOfVariables}, Type{<:SupportedCones}) as it should return false and it's the default. This prevents the user to constrain the same variable in two different cones. When a VectorOfVariables-in-S is added, the variables of the vector have already been created so they already belong to given cones. If bridges are enabled, the constraint will therefore be bridged by adding slack variables in S and equality constraints ensuring that the slack variables are equal to the corresponding variables of the given constraint function.\n\nNote that there may also be sets for which !supports_add_constrained_variables(model, S) and supports_constraint(model, MOI.VectorOfVariables, S). For instance, suppose a solver supports positive semidefinite variable constraints and two types of variables: binary variables and nonnegative variables. Then the solver should support adding VectorOfVariables-in-PositiveSemidefiniteConeTriangle constraints, but it should not support creating variables constrained to belong to the PositiveSemidefiniteConeTriangle because the variables in PositiveSemidefiniteConeTriangle should first be created as either binary or non-negative.\n\n\n\n\n\n","category":"function"},{"location":"reference/variables/#MathOptInterface.is_valid-Tuple{MathOptInterface.ModelLike, MathOptInterface.VariableIndex}","page":"Variables","title":"MathOptInterface.is_valid","text":"is_valid(model::ModelLike, index::Index)::Bool\n\nReturn a Bool indicating whether this index refers to a valid object in the model model.\n\n\n\n\n\n","category":"method"},{"location":"reference/variables/#MathOptInterface.delete-Tuple{MathOptInterface.ModelLike, MathOptInterface.VariableIndex}","page":"Variables","title":"MathOptInterface.delete","text":"delete(model::ModelLike, index::Index)\n\nDelete the referenced object from the model. Throw DeleteNotAllowed if if index cannot be deleted.\n\nThe following modifications also take effect if Index is VariableIndex:\n\nIf index used in the objective function, it is removed from the function, i.e., it is substituted for zero.\nFor each func-in-set constraint of the model:\nIf func isa VariableIndex and func == index then the constraint is deleted.\nIf func isa VectorOfVariables and index in func.variables then\nif length(func.variables) == 1 is one, the constraint is deleted;\nif length(func.variables) > 1 and supports_dimension_update(set) then then the variable is removed from func and set is replaced by update_dimension(set, MOI.dimension(set) - 1).\nOtherwise, a DeleteNotAllowed error is thrown.\nOtherwise, the variable is removed from func, i.e., it is substituted for zero.\n\n\n\n\n\n","category":"method"},{"location":"reference/variables/#MathOptInterface.delete-Tuple{MathOptInterface.ModelLike, Vector{MathOptInterface.VariableIndex}}","page":"Variables","title":"MathOptInterface.delete","text":"delete(model::ModelLike, indices::Vector{R<:Index}) where {R}\n\nDelete the referenced objects in the vector indices from the model. It may be assumed that R is a concrete type. The default fallback sequentially deletes the individual items in indices, although specialized implementations may be more efficient.\n\n\n\n\n\n","category":"method"},{"location":"reference/variables/#Attributes","page":"Variables","title":"Attributes","text":"","category":"section"},{"location":"reference/variables/","page":"Variables","title":"Variables","text":"AbstractVariableAttribute\nVariableName\nVariablePrimalStart\nVariablePrimal\nVariableBasisStatus","category":"page"},{"location":"reference/variables/#MathOptInterface.AbstractVariableAttribute","page":"Variables","title":"MathOptInterface.AbstractVariableAttribute","text":"AbstractVariableAttribute\n\nAbstract supertype for attribute objects that can be used to set or get attributes (properties) of variables in the model.\n\n\n\n\n\n","category":"type"},{"location":"reference/variables/#MathOptInterface.VariableName","page":"Variables","title":"MathOptInterface.VariableName","text":"VariableName()\n\nA variable attribute for a string identifying the variable. It is valid for two variables to have the same name; however, variables with duplicate names cannot be looked up using get. It has a default value of \"\" if not set`.\n\n\n\n\n\n","category":"type"},{"location":"reference/variables/#MathOptInterface.VariablePrimalStart","page":"Variables","title":"MathOptInterface.VariablePrimalStart","text":"VariablePrimalStart()\n\nA variable attribute for the initial assignment to some primal variable's value that the optimizer may use to warm-start the solve. May be a number or nothing (unset).\n\n\n\n\n\n","category":"type"},{"location":"reference/variables/#MathOptInterface.VariablePrimal","page":"Variables","title":"MathOptInterface.VariablePrimal","text":"VariablePrimal(result_index::Int = 1)\n\nA variable attribute for the assignment to some primal variable's value in result result_index. If result_index is omitted, it is 1 by default.\n\nIf the solver does not have a primal value for the variable because the result_index is beyond the available solutions (whose number is indicated by the ResultCount attribute), getting this attribute must throw a ResultIndexBoundsError. Otherwise, if the result is unavailable for another reason (for instance, only a dual solution is available), the result is undefined. Users should first check PrimalStatus before accessing the VariablePrimal attribute.\n\nSee ResultCount for information on how the results are ordered.\n\n\n\n\n\n","category":"type"},{"location":"reference/variables/#MathOptInterface.VariableBasisStatus","page":"Variables","title":"MathOptInterface.VariableBasisStatus","text":"VariableBasisStatus(result_index::Int = 1)\n\nA variable attribute for the BasisStatusCode of a variable in result result_index, with respect to an available optimal solution basis.\n\nIf the solver does not have a basis statue for the variable because the result_index is beyond the available solutions (whose number is indicated by the ResultCount attribute), getting this attribute must throw a ResultIndexBoundsError. Otherwise, if the result is unavailable for another reason (for instance, only a dual solution is available), the result is undefined. Users should first check PrimalStatus before accessing the VariableBasisStatus attribute.\n\nSee ResultCount for information on how the results are ordered.\n\n\n\n\n\n","category":"type"},{"location":"submodules/Bridges/list_of_bridges/","page":"List of bridges","title":"List of bridges","text":"CurrentModule = MathOptInterface\nDocTestSetup = quote\n import MathOptInterface as MOI\nend\nDocTestFilters = [r\"MathOptInterface|MOI\"]","category":"page"},{"location":"submodules/Bridges/list_of_bridges/#List-of-bridges","page":"List of bridges","title":"List of bridges","text":"","category":"section"},{"location":"submodules/Bridges/list_of_bridges/","page":"List of bridges","title":"List of bridges","text":"This section describes the Bridges.AbstractBridges that are implemented in MathOptInterface.","category":"page"},{"location":"submodules/Bridges/list_of_bridges/#constraint_bridges_ref","page":"List of bridges","title":"Constraint bridges","text":"","category":"section"},{"location":"submodules/Bridges/list_of_bridges/","page":"List of bridges","title":"List of bridges","text":"These bridges are subtypes of Bridges.Constraint.AbstractBridge.","category":"page"},{"location":"submodules/Bridges/list_of_bridges/","page":"List of bridges","title":"List of bridges","text":"Bridges.Constraint.GreaterToIntervalBridge\nBridges.Constraint.LessToIntervalBridge\nBridges.Constraint.GreaterToLessBridge\nBridges.Constraint.LessToGreaterBridge\nBridges.Constraint.NonnegToNonposBridge\nBridges.Constraint.NonposToNonnegBridge\nBridges.Constraint.VectorizeBridge\nBridges.Constraint.ScalarizeBridge\nBridges.Constraint.ScalarSlackBridge\nBridges.Constraint.VectorSlackBridge\nBridges.Constraint.ScalarFunctionizeBridge\nBridges.Constraint.VectorFunctionizeBridge\nBridges.Constraint.ToScalarQuadraticBridge\nBridges.Constraint.ToVectorQuadraticBridge\nBridges.Constraint.ToScalarNonlinearBridge\nBridges.Constraint.FunctionConversionBridge\nBridges.Constraint.SplitComplexEqualToBridge\nBridges.Constraint.SplitComplexZerosBridge\nBridges.Constraint.SplitHyperRectangleBridge\nBridges.Constraint.SplitIntervalBridge\nBridges.Constraint.SOCtoRSOCBridge\nBridges.Constraint.RSOCtoSOCBridge\nBridges.Constraint.SOCtoNonConvexQuadBridge\nBridges.Constraint.RSOCtoNonConvexQuadBridge\nBridges.Constraint.QuadtoSOCBridge\nBridges.Constraint.SOCtoPSDBridge\nBridges.Constraint.RSOCtoPSDBridge\nBridges.Constraint.NormInfinityBridge\nBridges.Constraint.NormOneBridge\nBridges.Constraint.NormToPowerBridge\nBridges.Constraint.NormOneConeToNormConeBridge\nBridges.Constraint.SecondOrderConeToNormConeBridge\nBridges.Constraint.NormInfinityConeToNormConeBridge\nBridges.Constraint.GeoMeantoRelEntrBridge\nBridges.Constraint.GeoMeanToPowerBridge\nBridges.Constraint.GeoMeanBridge\nBridges.Constraint.RelativeEntropyBridge\nBridges.Constraint.NormSpectralBridge\nBridges.Constraint.NormNuclearBridge\nBridges.Constraint.SquareBridge\nBridges.Constraint.HermitianToSymmetricPSDBridge\nBridges.Constraint.SetDotScalingBridge\nBridges.Constraint.SetDotInverseScalingBridge\nBridges.Constraint.RootDetBridge\nBridges.Constraint.LogDetBridge\nBridges.Constraint.IndicatorActiveOnFalseBridge\nBridges.Constraint.IndicatorGreaterToLessThanBridge\nBridges.Constraint.IndicatorLessToGreaterThanBridge\nBridges.Constraint.IndicatorSOS1Bridge\nBridges.Constraint.SemiToBinaryBridge\nBridges.Constraint.ZeroOneBridge\nBridges.Constraint.IntegerToZeroOneBridge\nBridges.Constraint.NumberConversionBridge\nBridges.Constraint.AllDifferentToCountDistinctBridge\nBridges.Constraint.ReifiedAllDifferentToCountDistinctBridge\nBridges.Constraint.BinPackingToMILPBridge\nBridges.Constraint.CircuitToMILPBridge\nBridges.Constraint.CountAtLeastToCountBelongsBridge\nBridges.Constraint.CountBelongsToMILPBridge\nBridges.Constraint.CountDistinctToMILPBridge\nBridges.Constraint.ReifiedCountDistinctToMILPBridge\nBridges.Constraint.CountGreaterThanToMILPBridge\nBridges.Constraint.TableToMILPBridge","category":"page"},{"location":"submodules/Bridges/list_of_bridges/#MathOptInterface.Bridges.Constraint.GreaterToIntervalBridge","page":"List of bridges","title":"MathOptInterface.Bridges.Constraint.GreaterToIntervalBridge","text":"GreaterToIntervalBridge{T,F} <: Bridges.Constraint.AbstractBridge\n\nGreaterToIntervalBridge implements the following reformulations:\n\nf(x) ge l into f(x) in l infty)\n\nSource node\n\nGreaterToIntervalBridge supports:\n\nF in MOI.GreaterThan{T}\n\nTarget nodes\n\nGreaterToIntervalBridge creates:\n\nF in MOI.Interval{T}\n\n\n\n\n\n","category":"type"},{"location":"submodules/Bridges/list_of_bridges/#MathOptInterface.Bridges.Constraint.LessToIntervalBridge","page":"List of bridges","title":"MathOptInterface.Bridges.Constraint.LessToIntervalBridge","text":"LessToIntervalBridge{T,F} <: Bridges.Constraint.AbstractBridge\n\nLessToIntervalBridge implements the following reformulations:\n\nf(x) le u into f(x) in (-infty u\n\nSource node\n\nLessToIntervalBridge supports:\n\nF in MOI.LessThan{T}\n\nTarget nodes\n\nLessToIntervalBridge creates:\n\nF in MOI.Interval{T}\n\n\n\n\n\n","category":"type"},{"location":"submodules/Bridges/list_of_bridges/#MathOptInterface.Bridges.Constraint.GreaterToLessBridge","page":"List of bridges","title":"MathOptInterface.Bridges.Constraint.GreaterToLessBridge","text":"GreaterToLessBridge{T,F,G} <: Bridges.Constraint.AbstractBridge\n\nGreaterToLessBridge implements the following reformulation:\n\nf(x) ge l into -f(x) le -l\n\nSource node\n\nGreaterToLessBridge supports:\n\nG in MOI.GreaterThan{T}\n\nTarget nodes\n\nGreaterToLessBridge creates:\n\nF in MOI.LessThan{T}\n\n\n\n\n\n","category":"type"},{"location":"submodules/Bridges/list_of_bridges/#MathOptInterface.Bridges.Constraint.LessToGreaterBridge","page":"List of bridges","title":"MathOptInterface.Bridges.Constraint.LessToGreaterBridge","text":"LessToGreaterBridge{T,F,G} <: Bridges.Constraint.AbstractBridge\n\nLessToGreaterBridge implements the following reformulation:\n\nf(x) le u into -f(x) ge -u\n\nSource node\n\nLessToGreaterBridge supports:\n\nG in MOI.LessThan{T}\n\nTarget nodes\n\nLessToGreaterBridge creates:\n\nF in MOI.GreaterThan{T}\n\n\n\n\n\n","category":"type"},{"location":"submodules/Bridges/list_of_bridges/#MathOptInterface.Bridges.Constraint.NonnegToNonposBridge","page":"List of bridges","title":"MathOptInterface.Bridges.Constraint.NonnegToNonposBridge","text":"NonnegToNonposBridge{T,F,G} <: Bridges.Constraint.AbstractBridge\n\nNonnegToNonposBridge implements the following reformulation:\n\nf(x) in mathbbR_+ into -f(x) in mathbbR_-\n\nSource node\n\nNonnegToNonposBridge supports:\n\nG in MOI.Nonnegatives\n\nTarget nodes\n\nNonnegToNonposBridge creates:\n\nF in MOI.Nonpositives\n\n\n\n\n\n","category":"type"},{"location":"submodules/Bridges/list_of_bridges/#MathOptInterface.Bridges.Constraint.NonposToNonnegBridge","page":"List of bridges","title":"MathOptInterface.Bridges.Constraint.NonposToNonnegBridge","text":"NonposToNonnegBridge{T,F,G} <: Bridges.Constraint.AbstractBridge\n\nNonposToNonnegBridge implements the following reformulation:\n\nf(x) in mathbbR_- into -f(x) in mathbbR_+\n\nSource node\n\nNonposToNonnegBridge supports:\n\nG in MOI.Nonpositives\n\nTarget nodes\n\nNonposToNonnegBridge creates:\n\nF in MOI.Nonnegatives\n\n\n\n\n\n","category":"type"},{"location":"submodules/Bridges/list_of_bridges/#MathOptInterface.Bridges.Constraint.VectorizeBridge","page":"List of bridges","title":"MathOptInterface.Bridges.Constraint.VectorizeBridge","text":"VectorizeBridge{T,F,S,G} <: Bridges.Constraint.AbstractBridge\n\nVectorizeBridge implements the following reformulations:\n\ng(x) ge a into g(x) - a in mathbbR_+\ng(x) le a into g(x) - a in mathbbR_-\ng(x) == a into g(x) - a in 0\n\nwhere T is the coefficient type of g(x) - a.\n\nSource node\n\nVectorizeBridge supports:\n\nG in MOI.GreaterThan{T}\nG in MOI.LessThan{T}\nG in MOI.EqualTo{T}\n\nTarget nodes\n\nVectorizeBridge creates:\n\nF in S, where S is one of MOI.Nonnegatives, MOI.Nonpositives, MOI.Zeros depending on the type of the input set.\n\n\n\n\n\n","category":"type"},{"location":"submodules/Bridges/list_of_bridges/#MathOptInterface.Bridges.Constraint.ScalarizeBridge","page":"List of bridges","title":"MathOptInterface.Bridges.Constraint.ScalarizeBridge","text":"ScalarizeBridge{T,F,S}\n\nScalarizeBridge implements the following reformulations:\n\nf(x) - a in mathbbR_+ into f_i(x) ge a_i for all i\nf(x) - a in mathbbR_- into f_i(x) le a_i for all i\nf(x) - a in 0 into f_i(x) == a_i for all i\n\nSource node\n\nScalarizeBridge supports:\n\nG in MOI.Nonnegatives{T}\nG in MOI.Nonpositives{T}\nG in MOI.Zeros{T}\n\nTarget nodes\n\nScalarizeBridge creates:\n\nF in S, where S is one of MOI.GreaterThan{T}, MOI.LessThan{T}, and MOI.EqualTo{T}, depending on the type of the input set.\n\n\n\n\n\n","category":"type"},{"location":"submodules/Bridges/list_of_bridges/#MathOptInterface.Bridges.Constraint.ScalarSlackBridge","page":"List of bridges","title":"MathOptInterface.Bridges.Constraint.ScalarSlackBridge","text":"ScalarSlackBridge{T,F,S} <: Bridges.Constraint.AbstractBridge\n\nScalarSlackBridge implements the following reformulation:\n\nf(x) in S into f(x) - y == 0 and y in S\n\nSource node\n\nScalarSlackBridge supports:\n\nG in S, where G is not MOI.VariableIndex and S is not MOI.EqualTo\n\nTarget nodes\n\nScalarSlackBridge creates:\n\nF in MOI.EqualTo{T}\nMOI.VariableIndex in S\n\n\n\n\n\n","category":"type"},{"location":"submodules/Bridges/list_of_bridges/#MathOptInterface.Bridges.Constraint.VectorSlackBridge","page":"List of bridges","title":"MathOptInterface.Bridges.Constraint.VectorSlackBridge","text":"VectorSlackBridge{T,F,S} <: Bridges.Constraint.AbstractBridge\n\nVectorSlackBridge implements the following reformulation:\n\nf(x) in S into f(x) - y in 0 and y in S\n\nSource node\n\nVectorSlackBridge supports:\n\nG in S, where G is not MOI.VectorOfVariables and S is not MOI.Zeros\n\nTarget nodes\n\nVectorSlackBridge creates:\n\nF in MOI.Zeros\nMOI.VectorOfVariables in S\n\n\n\n\n\n","category":"type"},{"location":"submodules/Bridges/list_of_bridges/#MathOptInterface.Bridges.Constraint.ScalarFunctionizeBridge","page":"List of bridges","title":"MathOptInterface.Bridges.Constraint.ScalarFunctionizeBridge","text":"ScalarFunctionizeBridge{T,S} = FunctionConversionBridge{T,MOI.ScalarAffineFunction{T},MOI.VariableIndex,S}\n\nScalarFunctionizeBridge implements the following reformulations:\n\nx in S into 1x + 0 in S\n\nSource node\n\nScalarFunctionizeBridge supports:\n\nMOI.VariableIndex in S\n\nTarget nodes\n\nScalarFunctionizeBridge creates:\n\nMOI.ScalarAffineFunction{T} in S\n\n\n\n\n\n","category":"type"},{"location":"submodules/Bridges/list_of_bridges/#MathOptInterface.Bridges.Constraint.VectorFunctionizeBridge","page":"List of bridges","title":"MathOptInterface.Bridges.Constraint.VectorFunctionizeBridge","text":"VectorFunctionizeBridge{T,S} = FunctionConversionBridge{T,MOI.VectorAffineFunction{T},S}\n\nVectorFunctionizeBridge implements the following reformulations:\n\nx in S into Ix + 0 in S\n\nSource node\n\nVectorFunctionizeBridge supports:\n\nMOI.VectorOfVariables in S\n\nTarget nodes\n\nVectorFunctionizeBridge creates:\n\nMOI.VectorAffineFunction{T} in S\n\n\n\n\n\n","category":"type"},{"location":"submodules/Bridges/list_of_bridges/#MathOptInterface.Bridges.Constraint.ToScalarQuadraticBridge","page":"List of bridges","title":"MathOptInterface.Bridges.Constraint.ToScalarQuadraticBridge","text":"ToScalarQuadraticBridge{T,G,S} <: AbstractFunctionConversionBridge{G,S}\n\nToScalarQuadraticBridge implements the following reformulation:\n\ng(x) in S into f(x) in S\n\nwhere g is an abstract scalar function and f is a MOI.ScalarQuadraticFunction.\n\nSource node\n\nToScalarQuadraticBridge supports:\n\nG<:AbstractScalarFunction in S\n\nTarget nodes\n\nToScalarQuadraticBridge creates:\n\nMOI.ScalarQuadraticFunction in S\n\n\n\n\n\n","category":"type"},{"location":"submodules/Bridges/list_of_bridges/#MathOptInterface.Bridges.Constraint.ToVectorQuadraticBridge","page":"List of bridges","title":"MathOptInterface.Bridges.Constraint.ToVectorQuadraticBridge","text":"ToVectorQuadraticBridge{T,G,S} <: AbstractFunctionConversionBridge{G,S}\n\nToVectorQuadraticBridge implements the following reformulation:\n\ng(x) in S into f(x) in S\n\nwhere g is an abstract vector function and f is a MOI.VectorQuadraticFunction.\n\nSource node\n\nToVectorQuadraticBridge supports:\n\nG<:AbstractVectorFunction in S\n\nTarget nodes\n\nToVectorQuadraticBridge creates:\n\nMOI.VectorQuadraticFunction in S\n\n\n\n\n\n","category":"type"},{"location":"submodules/Bridges/list_of_bridges/#MathOptInterface.Bridges.Constraint.ToScalarNonlinearBridge","page":"List of bridges","title":"MathOptInterface.Bridges.Constraint.ToScalarNonlinearBridge","text":"ToScalarNonlinearBridge{T,G,S} <: AbstractFunctionConversionBridge{G,S}\n\nToScalarNonlinearBridge implements the following reformulation:\n\ng(x) in S into f(x) in S\n\nwhere g is an abstract scalar function and f is a MOI.ScalarNonlinearFunction.\n\nSource node\n\nToScalarNonlinearBridge supports:\n\nG<:AbstractScalarFunction in S\n\nTarget nodes\n\nToScalarNonlinearBridge creates:\n\nMOI.ScalarNonlinearFunction in S\n\n\n\n\n\n","category":"type"},{"location":"submodules/Bridges/list_of_bridges/#MathOptInterface.Bridges.Constraint.FunctionConversionBridge","page":"List of bridges","title":"MathOptInterface.Bridges.Constraint.FunctionConversionBridge","text":"FunctionConversionBridge{T,F,G,S} <: AbstractFunctionConversionBridge{G,S}\n\nFunctionConversionBridge implements the following reformulations:\n\ng(x) in S into f(x) in S\n\nfor these pairs of functions:\n\nMOI.ScalarAffineFunctionto [MOI.ScalarQuadraticFunction`](@ref)\nMOI.ScalarQuadraticFunction to MOI.ScalarNonlinearFunction\nMOI.VectorAffineFunction to MOI.VectorQuadraticFunction\n\nSource node\n\nFunctionConversionBridge supports:\n\nG in S\n\nTarget nodes\n\nFunctionConversionBridge creates:\n\nF in S\n\n\n\n\n\n","category":"type"},{"location":"submodules/Bridges/list_of_bridges/#MathOptInterface.Bridges.Constraint.SplitComplexEqualToBridge","page":"List of bridges","title":"MathOptInterface.Bridges.Constraint.SplitComplexEqualToBridge","text":"SplitComplexEqualToBridge{T,F,G} <: Bridges.Constraint.AbstractBridge\n\nSplitComplexEqualToBridge implements the following reformulation:\n\nf(x) + g(x) * im = a + b * im into f(x) = a and g(x) = b\n\nSource node\n\nSplitComplexEqualToBridge supports:\n\nG in MOI.EqualTo{Complex{T}}\n\nwhere G is a function with Complex coefficients.\n\nTarget nodes\n\nSplitComplexEqualToBridge creates:\n\nF in MOI.EqualTo{T}\n\nwhere F is the type of the real/imaginary part of G.\n\n\n\n\n\n","category":"type"},{"location":"submodules/Bridges/list_of_bridges/#MathOptInterface.Bridges.Constraint.SplitComplexZerosBridge","page":"List of bridges","title":"MathOptInterface.Bridges.Constraint.SplitComplexZerosBridge","text":"SplitComplexZerosBridge{T,F,G} <: Bridges.Constraint.AbstractBridge\n\nSplitComplexZerosBridge implements the following reformulation:\n\nf(x) in 0^n into textRe(f(x)) in 0^n and textIm(f(x)) in 0^n\n\nSource node\n\nSplitComplexZerosBridge supports:\n\nG in MOI.Zeros\n\nwhere G is a function with Complex coefficients.\n\nTarget nodes\n\nSplitComplexZerosBridge creates:\n\nF in MOI.Zeros\n\nwhere F is the type of the real/imaginary part of G.\n\n\n\n\n\n","category":"type"},{"location":"submodules/Bridges/list_of_bridges/#MathOptInterface.Bridges.Constraint.SplitHyperRectangleBridge","page":"List of bridges","title":"MathOptInterface.Bridges.Constraint.SplitHyperRectangleBridge","text":"SplitHyperRectangleBridge{T,G,F} <: Bridges.Constraint.AbstractBridge\n\nSplitHyperRectangleBridge implements the following reformulation:\n\nf(x) in textsfHyperRectangle(l u) to f(x) - l u - f(x) in mathbbR_+.\n\nSource node\n\nSplitHyperRectangleBridge supports:\n\nF in MOI.HyperRectangle\n\nTarget nodes\n\nSplitHyperRectangleBridge creates:\n\nG in MOI.Nonnegatives\n\n\n\n\n\n","category":"type"},{"location":"submodules/Bridges/list_of_bridges/#MathOptInterface.Bridges.Constraint.SplitIntervalBridge","page":"List of bridges","title":"MathOptInterface.Bridges.Constraint.SplitIntervalBridge","text":"SplitIntervalBridge{T,F,S,LS,US} <: Bridges.Constraint.AbstractBridge\n\nSplitIntervalBridge implements the following reformulations:\n\nl le f(x) le u into f(x) ge l and f(x) le u\nf(x) = b into f(x) ge b and f(x) le b\nf(x) in 0 into f(x) in mathbbR_+ and f(x) in mathbbR_-\n\nSource node\n\nSplitIntervalBridge supports:\n\nF in MOI.Interval{T}\nF in MOI.EqualTo{T}\nF in MOI.Zeros\n\nTarget nodes\n\nSplitIntervalBridge creates:\n\nF in MOI.LessThan{T}\nF in MOI.GreaterThan{T}\n\nor\n\nF in MOI.Nonnegatives\nF in MOI.Nonpositives\n\nnote: Note\nIf T<:AbstractFloat and S is MOI.Interval{T} then no lower (resp. upper) bound constraint is created if the lower (resp. upper) bound is typemin(T) (resp. typemax(T)). Similarly, when MOI.ConstraintSet is set, a lower or upper bound constraint may be deleted or created accordingly.\n\n\n\n\n\n","category":"type"},{"location":"submodules/Bridges/list_of_bridges/#MathOptInterface.Bridges.Constraint.SOCtoRSOCBridge","page":"List of bridges","title":"MathOptInterface.Bridges.Constraint.SOCtoRSOCBridge","text":"SOCtoRSOCBridge{T,F,G} <: Bridges.Constraint.AbstractBridge\n\nSOCtoRSOCBridge implements the following reformulation:\n\nx_2 le t into (t+x_1)(t-x_1)ge (x_2ldotsx_N)_2^2\n\nAssumptions\n\nSOCtoRSOCBridge assumes that the length of x is at least one.\n\nSource node\n\nSOCtoRSOCBridge supports:\n\nG in MOI.SecondOrderCone\n\nTarget node\n\nSOCtoRSOCBridge creates:\n\nF in MOI.RotatedSecondOrderCone\n\n\n\n\n\n","category":"type"},{"location":"submodules/Bridges/list_of_bridges/#MathOptInterface.Bridges.Constraint.RSOCtoSOCBridge","page":"List of bridges","title":"MathOptInterface.Bridges.Constraint.RSOCtoSOCBridge","text":"RSOCtoSOCBridge{T,F,G} <: Bridges.Constraint.AbstractBridge\n\nRSOCtoSOCBridge implements the following reformulation:\n\nx_2^2 le 2tu into fract - usqrt 2 x_2 le fract + usqrt 2\n\nSource node\n\nRSOCtoSOCBridge supports:\n\nG in MOI.RotatedSecondOrderCone\n\nTarget node\n\nRSOCtoSOCBridge creates:\n\nF in MOI.SecondOrderCone\n\n\n\n\n\n","category":"type"},{"location":"submodules/Bridges/list_of_bridges/#MathOptInterface.Bridges.Constraint.SOCtoNonConvexQuadBridge","page":"List of bridges","title":"MathOptInterface.Bridges.Constraint.SOCtoNonConvexQuadBridge","text":"SOCtoNonConvexQuadBridge{T} <: Bridges.Constraint.AbstractBridge\n\nSOCtoNonConvexQuadBridge implements the following reformulations:\n\nx_2 le t into sum x^2 - t^2 le 0 and 1t + 0 ge 0\n\nThe MOI.ScalarAffineFunction 1t + 0 is used in case the variable has other bound constraints.\n\nwarning: Warning\nThis transformation starts from a convex constraint and creates a non-convex constraint. Unless the solver has explicit support for detecting second-order cones in quadratic form, this may (wrongly) be interpreted by the solver as being non-convex. Therefore, this bridge is not added automatically by MOI.Bridges.full_bridge_optimizer. Care is recommended when adding this bridge to a optimizer.\n\nSource node\n\nSOCtoNonConvexQuadBridge supports:\n\nMOI.VectorOfVariables in MOI.SecondOrderCone\n\nTarget nodes\n\nSOCtoNonConvexQuadBridge creates:\n\nMOI.ScalarQuadraticFunction{T} in MOI.LessThan{T}\nMOI.ScalarAffineFunction{T} in MOI.GreaterThan{T}\n\n\n\n\n\n","category":"type"},{"location":"submodules/Bridges/list_of_bridges/#MathOptInterface.Bridges.Constraint.RSOCtoNonConvexQuadBridge","page":"List of bridges","title":"MathOptInterface.Bridges.Constraint.RSOCtoNonConvexQuadBridge","text":"RSOCtoNonConvexQuadBridge{T} <: Bridges.Constraint.AbstractBridge\n\nRSOCtoNonConvexQuadBridge implements the following reformulations:\n\nx_2^2 le 2tu into sum x^2 - 2tu le 0, 1t + 0 ge 0, and 1u + 0 ge 0.\n\nThe MOI.ScalarAffineFunctions 1t + 0 and 1u + 0 are used in case the variables have other bound constraints.\n\nwarning: Warning\nThis transformation starts from a convex constraint and creates a non-convex constraint. Unless the solver has explicit support for detecting rotated second-order cones in quadratic form, this may (wrongly) be interpreted by the solver as being non-convex. Therefore, this bridge is not added automatically by MOI.Bridges.full_bridge_optimizer. Care is recommended when adding this bridge to a optimizer.\n\nSource node\n\nRSOCtoNonConvexQuadBridge supports:\n\nMOI.VectorOfVariables in MOI.RotatedSecondOrderCone\n\nTarget nodes\n\nRSOCtoNonConvexQuadBridge creates:\n\nMOI.ScalarQuadraticFunction{T} in MOI.LessThan{T}\nMOI.ScalarAffineFunction{T} in MOI.GreaterThan{T}\n\n\n\n\n\n","category":"type"},{"location":"submodules/Bridges/list_of_bridges/#MathOptInterface.Bridges.Constraint.QuadtoSOCBridge","page":"List of bridges","title":"MathOptInterface.Bridges.Constraint.QuadtoSOCBridge","text":"QuadtoSOCBridge{T} <: Bridges.Constraint.AbstractBridge\n\nQuadtoSOCBridge converts quadratic inequalities\n\nfrac12x^T Q x + a^T x le ub\n\ninto MOI.RotatedSecondOrderCone constraints, but it only applies when Q is positive definite.\n\nThis is because, if Q is positive definite, there exists U such that Q = U^T U, and so the inequality can then be rewritten as;\n\nU x_2^2 le 2 (-a^T x + ub)\n\nTherefore, QuadtoSOCBridge implements the following reformulations:\n\nfrac12x^T Q x + a^T x le ub into (1 -a^T x + ub Ux) in RotatedSecondOrderCone where Q = U^T U\nfrac12x^T Q x + a^T x ge lb into (1 a^T x - lb Ux) in RotatedSecondOrderCone where -Q = U^T U\n\nSource node\n\nQuadtoSOCBridge supports:\n\nMOI.ScalarAffineFunction{T} in MOI.LessThan{T}\nMOI.ScalarAffineFunction{T} in MOI.GreaterThan{T}\n\nTarget nodes\n\nRelativeEntropyBridge creates:\n\nMOI.VectorAffineFunction{T} in MOI.RotatedSecondOrderCone\n\nErrors\n\nThis bridge errors if Q is not positive definite.\n\n\n\n\n\n","category":"type"},{"location":"submodules/Bridges/list_of_bridges/#MathOptInterface.Bridges.Constraint.SOCtoPSDBridge","page":"List of bridges","title":"MathOptInterface.Bridges.Constraint.SOCtoPSDBridge","text":"SOCtoPSDBridge{T,F,G} <: Bridges.Constraint.AbstractBridge\n\nSOCtoPSDBridge implements the following reformulation:\n\nx_2 le t into leftbeginarrayc ct x^top x t mathbfIendarrayrightsucceq 0\n\nwarning: Warning\nThis bridge is not added by default by MOI.Bridges.full_bridge_optimizer because bridging second order cone constraints to semidefinite constraints can be achieved by the SOCtoRSOCBridge followed by the RSOCtoPSDBridge, while creating a smaller semidefinite constraint.\n\nSource node\n\nSOCtoPSDBridge supports:\n\nG in MOI.SecondOrderCone\n\nTarget nodes\n\nSOCtoPSDBridge creates:\n\nF in MOI.PositiveSemidefiniteConeTriangle\n\n\n\n\n\n","category":"type"},{"location":"submodules/Bridges/list_of_bridges/#MathOptInterface.Bridges.Constraint.RSOCtoPSDBridge","page":"List of bridges","title":"MathOptInterface.Bridges.Constraint.RSOCtoPSDBridge","text":"RSOCtoPSDBridge{T,F,G} <: Bridges.Constraint.AbstractBridge\n\nRSOCtoPSDBridge implements the following reformulation:\n\nx_2^2 le 2tcdot u into leftbeginarrayc ct x^top x 2tu mathbfIendarrayrightsucceq 0\n\nSource node\n\nRSOCtoPSDBridge supports:\n\nG in MOI.RotatedSecondOrderCone\n\nTarget nodes\n\nRSOCtoPSDBridge creates:\n\nF in MOI.PositiveSemidefiniteConeTriangle\n\n\n\n\n\n","category":"type"},{"location":"submodules/Bridges/list_of_bridges/#MathOptInterface.Bridges.Constraint.NormInfinityBridge","page":"List of bridges","title":"MathOptInterface.Bridges.Constraint.NormInfinityBridge","text":"NormInfinityBridge{T,F,G} <: Bridges.Constraint.AbstractBridge\n\nNormInfinityBridge implements the following reformulation:\n\nx_infty le t into t - x_i t + x_i in mathbbR_+.\n\nSource node\n\nNormInfinityBridge supports:\n\nG in MOI.NormInfinityCone{T}\n\nTarget nodes\n\nNormInfinityBridge creates:\n\nF in MOI.Nonnegatives\n\n\n\n\n\n","category":"type"},{"location":"submodules/Bridges/list_of_bridges/#MathOptInterface.Bridges.Constraint.NormOneBridge","page":"List of bridges","title":"MathOptInterface.Bridges.Constraint.NormOneBridge","text":"NormOneBridge{T,F,G} <: Bridges.Constraint.AbstractBridge\n\nNormOneBridge implements the following reformulation:\n\nsum x_i le t into t - sum y_i y_i - x_i y_i + x_i in mathbbR_+.\n\nSource node\n\nNormOneBridge supports:\n\nG in MOI.NormOneCone{T}\n\nTarget nodes\n\nNormOneBridge creates:\n\nF in MOI.Nonnegatives\n\n\n\n\n\n","category":"type"},{"location":"submodules/Bridges/list_of_bridges/#MathOptInterface.Bridges.Constraint.NormToPowerBridge","page":"List of bridges","title":"MathOptInterface.Bridges.Constraint.NormToPowerBridge","text":"NormToPowerBridge{T,F} <: Bridges.Constraint.AbstractBridge\n\nNormToPowerBridge implements the following reformulation:\n\n(t x) in NormCone(p 1+d) into (r_i t x_i) in PowerCone(1 p) for all i, and sumlimits_i r_i == t.\n\nFor details, see Alizadeh, F., and Goldfarb, D. (2001). \"Second-order cone programming.\" Mathematical Programming, Series B, 95:3-51.\n\nSource node\n\nNormToPowerBridge supports:\n\nF in MOI.NormCone\n\nTarget nodes\n\nNormToPowerBridge creates:\n\nF in MOI.PowerCone{T}\nMOI.ScalarAffineFunction in MOI.EqualTo\n\n\n\n\n\n","category":"type"},{"location":"submodules/Bridges/list_of_bridges/#MathOptInterface.Bridges.Constraint.NormOneConeToNormConeBridge","page":"List of bridges","title":"MathOptInterface.Bridges.Constraint.NormOneConeToNormConeBridge","text":"NormOneConeToNormConeBridge{T,F} <: Bridges.Constraint.AbstractBridge\n\nNormOneConeToNormConeBridge implements the following reformulations:\n\n(t x) in NormOneCone(d) into (t x) in NormCone(1 d)\n\nSource node\n\nNormOneConeToNormConeBridge supports:\n\nF in MOI.NormOneCone\n\nTarget nodes\n\nNormOneConeToNormConeBridge creates:\n\nF in MOI.NormCone\n\n\n\n\n\n","category":"type"},{"location":"submodules/Bridges/list_of_bridges/#MathOptInterface.Bridges.Constraint.SecondOrderConeToNormConeBridge","page":"List of bridges","title":"MathOptInterface.Bridges.Constraint.SecondOrderConeToNormConeBridge","text":"SecondOrderConeToNormConeBridge{T,F} <: Bridges.Constraint.AbstractBridge\n\nSecondOrderConeToNormConeBridge implements the following reformulations:\n\n(t x) in SecondOrderCone(d) into (t x) in NormCone(2 d)\n\nSource node\n\nSecondOrderConeToNormConeBridge supports:\n\nF in MOI.SecondOrderCone\n\nTarget nodes\n\nSecondOrderConeToNormConeBridge creates:\n\nF in MOI.NormCone\n\n\n\n\n\n","category":"type"},{"location":"submodules/Bridges/list_of_bridges/#MathOptInterface.Bridges.Constraint.NormInfinityConeToNormConeBridge","page":"List of bridges","title":"MathOptInterface.Bridges.Constraint.NormInfinityConeToNormConeBridge","text":"NormInfinityConeToNormConeBridge{T,F} <: Bridges.Constraint.AbstractBridge\n\nNormInfinityConeToNormConeBridge implements the following reformulations:\n\n(t x) in NormInfinityCone(d) into (t x) in NormCone(Inf d)\n\nSource node\n\nNormInfinityConeToNormConeBridge supports:\n\nF in MOI.NormInfinityCone\n\nTarget nodes\n\nNormInfinityConeToNormConeBridge creates:\n\nF in MOI.NormCone\n\n\n\n\n\n","category":"type"},{"location":"submodules/Bridges/list_of_bridges/#MathOptInterface.Bridges.Constraint.GeoMeantoRelEntrBridge","page":"List of bridges","title":"MathOptInterface.Bridges.Constraint.GeoMeantoRelEntrBridge","text":"GeoMeantoRelEntrBridge{T,F,G,H} <: Bridges.Constraint.AbstractBridge\n\nGeoMeantoRelEntrBridge implements the following reformulation:\n\n(u w) in GeometricMeanCone into (0 w (u + y)mathbf1)in RelativeEntropyCone and y ge 0\n\nSource node\n\nGeoMeantoRelEntrBridge supports:\n\nH in MOI.GeometricMeanCone\n\nTarget nodes\n\nGeoMeantoRelEntrBridge creates:\n\nG in MOI.RelativeEntropyCone\nF in MOI.Nonnegatives\n\nDerivation\n\nThe derivation of the bridge is as follows:\n\nbeginaligned\n(u w) in GeometricMeanCone iff u le left(prod_i=1^n w_iright)^1n \niff 0 le u + y le left(prod_i=1^n w_iright)^1n y ge 0 \niff 1 le fracleft(prod_i=1^n w_iright)^1nu + y y ge 0 \niff 1 le left(prod_i=1^n fracw_iu + yright)^1n y ge 0 \niff 0 le sum_i=1^n logleft(fracw_iu + yright) y ge 0 \niff 0 ge sum_i=1^n logleft(fracu + yw_iright) y ge 0 \niff 0 ge sum_i=1^n (u + y) logleft(fracu + yw_iright) y ge 0 \niff (0 w (u + y)mathbf1) in RelativeEntropyCone y ge 0 \nendaligned\n\nThis derivation assumes that u + y 0, which is enforced by the relative entropy cone.\n\n\n\n\n\n","category":"type"},{"location":"submodules/Bridges/list_of_bridges/#MathOptInterface.Bridges.Constraint.GeoMeanToPowerBridge","page":"List of bridges","title":"MathOptInterface.Bridges.Constraint.GeoMeanToPowerBridge","text":"GeoMeanToPowerBridge{T,F} <: Bridges.Constraint.AbstractBridge\n\nGeoMeanToPowerBridge implements the following reformulation:\n\n(y x) in GeometricMeanCone(1+d) into (x_1 t y) in PowerCone(1d) and (t x_2 x_d) in GeometricMeanCone(d), which is then recursively expanded into more PowerCone constraints.\n\nSource node\n\nGeoMeanToPowerBridge supports:\n\nF in MOI.GeometricMeanCone\n\nTarget nodes\n\nGeoMeanToPowerBridge creates:\n\nF in MOI.PowerCone{T}\nMOI.VectorOfVariables in MOI.Nonnegatives\n\n\n\n\n\n","category":"type"},{"location":"submodules/Bridges/list_of_bridges/#MathOptInterface.Bridges.Constraint.GeoMeanBridge","page":"List of bridges","title":"MathOptInterface.Bridges.Constraint.GeoMeanBridge","text":"GeoMeanBridge{T,F,G,H} <: Bridges.Constraint.AbstractBridge\n\nGeoMeanBridge implements a reformulation from MOI.GeometricMeanCone into MOI.RotatedSecondOrderCone.\n\nThe reformulation is best described in an example.\n\nConsider the cone of dimension 4:\n\nt le sqrt3x_1 x_2 x_3\n\nThis can be rewritten as exists y ge 0 such that:\n\nbeginalign*\n t le y\n y^4 le x_1 x_2 x_3 y\nendalign*\n\nNote that we need to create y and not use t^4 directly because t is allowed to be negative.\n\nThis is equivalent to:\n\nbeginalign*\n t le fracy_1sqrt4\n y_1^2 le 2y_2 y_3\n y_2^2 le 2x_1 x_2 \n y_3^2 le 2x_3(y_1sqrt4) \n y ge 0\nendalign*\n\nMore generally, you can show how the geometric mean code is recursively expanded into a set of new variables y in MOI.Nonnegatives, a set of MOI.RotatedSecondOrderCone constraints, and a MOI.LessThan constraint between t and y_1.\n\nSource node\n\nGeoMeanBridge supports:\n\nH in MOI.GeometricMeanCone\n\nTarget nodes\n\nGeoMeanBridge creates:\n\nF in MOI.LessThan{T}\nG in MOI.RotatedSecondOrderCone\nG in MOI.Nonnegatives\n\n\n\n\n\n","category":"type"},{"location":"submodules/Bridges/list_of_bridges/#MathOptInterface.Bridges.Constraint.RelativeEntropyBridge","page":"List of bridges","title":"MathOptInterface.Bridges.Constraint.RelativeEntropyBridge","text":"RelativeEntropyBridge{T,F,G,H} <: Bridges.Constraint.AbstractBridge\n\nRelativeEntropyBridge implements the following reformulation that converts a MOI.RelativeEntropyCone into an MOI.ExponentialCone:\n\nu ge sum_i=1^n w_i log left(fracw_iv_iright) into y_i ge 0, u ge sum_i=1^n y_i, and (-y_i w_i v_i) in ExponentialCone.\n\nSource node\n\nRelativeEntropyBridge supports:\n\nH in MOI.RelativeEntropyCone\n\nTarget nodes\n\nRelativeEntropyBridge creates:\n\nF in MOI.GreaterThan{T}\nG in MOI.ExponentialCone\n\n\n\n\n\n","category":"type"},{"location":"submodules/Bridges/list_of_bridges/#MathOptInterface.Bridges.Constraint.NormSpectralBridge","page":"List of bridges","title":"MathOptInterface.Bridges.Constraint.NormSpectralBridge","text":"NormSpectralBridge{T,F,G} <: Bridges.Constraint.AbstractBridge\n\nNormSpectralBridge implements the following reformulation:\n\nt ge sigma_1(X) into leftbeginarrayc ctmathbfI X^top X t mathbfIendarrayright succeq 0\n\nSource node\n\nNormSpectralBridge supports:\n\nG in MOI.NormSpectralCone\n\nTarget nodes\n\nNormSpectralBridge creates:\n\nF in MOI.PositiveSemidefiniteConeTriangle\n\n\n\n\n\n","category":"type"},{"location":"submodules/Bridges/list_of_bridges/#MathOptInterface.Bridges.Constraint.NormNuclearBridge","page":"List of bridges","title":"MathOptInterface.Bridges.Constraint.NormNuclearBridge","text":"NormNuclearBridge{T,F,G,H} <: Bridges.Constraint.AbstractBridge\n\nNormNuclearBridge implements the following reformulation:\n\nt ge sum_i sigma_i (X) into leftbeginarrayc cU X^top X Vendarrayright succeq 0 and 2t ge tr(U) + tr(V).\n\nSource node\n\nNormNuclearBridge supports:\n\nH in MOI.NormNuclearCone\n\nTarget nodes\n\nNormNuclearBridge creates:\n\nF in MOI.GreaterThan{T}\nG in MOI.PositiveSemidefiniteConeTriangle\n\n\n\n\n\n","category":"type"},{"location":"submodules/Bridges/list_of_bridges/#MathOptInterface.Bridges.Constraint.SquareBridge","page":"List of bridges","title":"MathOptInterface.Bridges.Constraint.SquareBridge","text":"SquareBridge{T,F,G,TT,ST} <: Bridges.Constraint.AbstractBridge\n\nSquareBridge implements the following reformulations:\n\n(t u X) in LogDetConeSquare into (t u Y) in LogDetConeTriangle\n(t X) in RootDetConeSquare into (t Y) in RootDetConeTriangle\nX in AbstractSymmetricMatrixSetSquare into Y in AbstractSymmetricMatrixSetTriangle\n\nwhere Y is the upper triangluar component of X.\n\nIn addition, constraints are added as necessary to constrain the matrix X to be symmetric. For example, the constraint for the matrix:\n\nbeginpmatrix\n 1 1 + x 2 - 3x\n 1 + x 2 + x 3 - x\n 2 - 3x 2 + x 2x\nendpmatrix\n\ncan be broken down to the constraint of the symmetric matrix\n\nbeginpmatrix\n 1 1 + x 2 - 3x\n cdot 2 + x 3 - x\n cdot cdot 2x\nendpmatrix\n\nand the equality constraint between the off-diagonal entries (2, 3) and (3, 2) 3 - x == 2 + x. Note that no symmetrization constraint needs to be added between the off-diagonal entries (1, 2) and (2, 1) or between (1, 3) and (3, 1) because the expressions are the same.\n\nSource node\n\nSquareBridge supports:\n\nF in ST\n\nTarget nodes\n\nSquareBridge creates:\n\nG in TT\n\n\n\n\n\n","category":"type"},{"location":"submodules/Bridges/list_of_bridges/#MathOptInterface.Bridges.Constraint.HermitianToSymmetricPSDBridge","page":"List of bridges","title":"MathOptInterface.Bridges.Constraint.HermitianToSymmetricPSDBridge","text":"HermitianToSymmetricPSDBridge{T,F,G} <: Bridges.Constraint.AbstractBridge\n\nHermitianToSymmetricPSDBridge implements the following reformulation:\n\nHermitian positive semidefinite n x n complex matrix to a symmetric positive semidefinite 2n x 2n real matrix.\n\nSee also MOI.Bridges.Variable.HermitianToSymmetricPSDBridge.\n\nSource node\n\nHermitianToSymmetricPSDBridge supports:\n\nG in MOI.HermitianPositiveSemidefiniteConeTriangle\n\nTarget node\n\nHermitianToSymmetricPSDBridge creates:\n\nF in MOI.PositiveSemidefiniteConeTriangle\n\nReformulation\n\nThe reformulation is best described by example.\n\nThe Hermitian matrix:\n\nbeginbmatrix\n x_11 x_12 + y_12im x_13 + y_13im\n x_12 - y_12im x_22 x_23 + y_23im\n x_13 - y_13im x_23 - y_23im x_33\nendbmatrix\n\nis positive semidefinite if and only if the symmetric matrix:\n\nbeginbmatrix\n x_11 x_12 x_13 0 y_12 y_13 \n x_22 x_23 -y_12 0 y_23 \n x_33 -y_13 -y_23 0 \n x_11 x_12 x_13 \n x_22 x_23 \n x_33\nendbmatrix\n\nis positive semidefinite.\n\nThe bridge achieves this reformulation by constraining the above matrix to belong to the MOI.PositiveSemidefiniteConeTriangle(6).\n\n\n\n\n\n","category":"type"},{"location":"submodules/Bridges/list_of_bridges/#MathOptInterface.Bridges.Constraint.SetDotScalingBridge","page":"List of bridges","title":"MathOptInterface.Bridges.Constraint.SetDotScalingBridge","text":"SetDotScalingBridge{T,S,F,G} <: Bridges.Constraint.AbstractBridge\n\nSetDotScalingBridge implements the reformulation from constraints in S to constraints in MOI.Scaled{S}.\n\nSource node\n\nSetDotScalingBridge supports:\n\nG in S\n\nTarget node\n\nSetDotScalingBridge creates:\n\nF in MOI.Scaled{S}\n\n\n\n\n\n","category":"type"},{"location":"submodules/Bridges/list_of_bridges/#MathOptInterface.Bridges.Constraint.SetDotInverseScalingBridge","page":"List of bridges","title":"MathOptInterface.Bridges.Constraint.SetDotInverseScalingBridge","text":"SetDotInverseScalingBridge{T,S,F,G} <: Bridges.Constraint.AbstractBridge\n\nSetDotInverseScalingBridge implements the reformulation from constraints in the MOI.Scaled{S} to constraints in the S.\n\nSource node\n\nSetDotInverseScalingBridge supports:\n\nG in MOI.Scaled{S}\n\nTarget node\n\nSetDotInverseScalingBridge creates:\n\nF in S\n\n\n\n\n\n","category":"type"},{"location":"submodules/Bridges/list_of_bridges/#MathOptInterface.Bridges.Constraint.RootDetBridge","page":"List of bridges","title":"MathOptInterface.Bridges.Constraint.RootDetBridge","text":"RootDetBridge{T,F,G,H} <: Bridges.Constraint.AbstractBridge\n\nThe MOI.RootDetConeTriangle is representable by MOI.PositiveSemidefiniteConeTriangle and MOI.GeometricMeanCone constraints, see [1, p. 149].\n\nIndeed, t le det(X)^1n if and only if there exists a lower triangular matrix Δ such that:\n\nbeginalign*\n beginpmatrix\n X Δ\n Δ^top mathrmDiag(Δ)\n endpmatrix succeq 0\n (t mathrmDiag(Δ)) in GeometricMeanCone\nendalign*\n\nSource node\n\nRootDetBridge supports:\n\nI in MOI.RootDetConeTriangle\n\nTarget nodes\n\nRootDetBridge creates:\n\nF in MOI.PositiveSemidefiniteConeTriangle\nG in MOI.GeometricMeanCone\n\n[1] Ben-Tal, Aharon, and Arkadi Nemirovski. Lectures on modern convex optimization: analysis, algorithms, and engineering applications. Society for Industrial and Applied Mathematics, 2001.\n\n\n\n\n\n","category":"type"},{"location":"submodules/Bridges/list_of_bridges/#MathOptInterface.Bridges.Constraint.LogDetBridge","page":"List of bridges","title":"MathOptInterface.Bridges.Constraint.LogDetBridge","text":"LogDetBridge{T,F,G,H,I} <: Bridges.Constraint.AbstractBridge\n\nThe MOI.LogDetConeTriangle is representable by MOI.PositiveSemidefiniteConeTriangle and MOI.ExponentialCone constraints.\n\nIndeed, logdet(X) = sumlimits_i=1^n log(delta_i) where delta_i are the eigenvalues of X.\n\nAdapting the method from [1, p. 149], we see that t le u log(det(Xu)) for u 0 if and only if there exists a lower triangular matrix Δ such that\n\nbeginalign*\n beginpmatrix\n X Δ\n Δ^top mathrmDiag(Δ)\n endpmatrix succeq 0\n t - sum_i=1^n u logleft(fracΔ_iiuright) le 0\nendalign*\n\nWhich we reformulate further into\n\nbeginalign*\n beginpmatrix\n X Δ\n Δ^top mathrmDiag(Δ)\n endpmatrix succeq 0\n (l_i u Δ_ii) in ExponentialConequad forall i \n t - sum_i=1^n l_i le 0\nendalign*\n\nSource node\n\nLogDetBridge supports:\n\nI in MOI.LogDetConeTriangle\n\nTarget nodes\n\nLogDetBridge creates:\n\nF in MOI.PositiveSemidefiniteConeTriangle\nG in MOI.ExponentialCone\nH in MOI.LessThan{T}\n\n[1] Ben-Tal, Aharon, and Arkadi Nemirovski. Lectures on modern convex optimization: analysis, algorithms, and engineering applications. Society for Industrial and Applied Mathematics, 2001.\n\n\n\n\n\n","category":"type"},{"location":"submodules/Bridges/list_of_bridges/#MathOptInterface.Bridges.Constraint.IndicatorActiveOnFalseBridge","page":"List of bridges","title":"MathOptInterface.Bridges.Constraint.IndicatorActiveOnFalseBridge","text":"IndicatorActiveOnFalseBridge{T,F,S} <: Bridges.Constraint.AbstractBridge\n\nIndicatorActiveOnFalseBridge implements the following reformulation:\n\nneg z implies f(x) in S into y implies f(x) in S, z + y = 1, and y in 0 1\n\nSource node\n\nIndicatorActiveOnFalseBridge supports:\n\nMOI.VectorAffineFunction{T} in MOI.Indicator{MOI.ACTIVATE_ON_ZERO,S}\n\nTarget nodes\n\nIndicatorActiveOnFalseBridge creates:\n\nMOI.VectorAffineFunction{T} in MOI.Indicator{MOI.ACTIVATE_ON_ONE,S}\nMOI.ScalarAffineFunction{T} in MOI.EqualTo\nMOI.VariableIndex in MOI.ZeroOne\n\n\n\n\n\n","category":"type"},{"location":"submodules/Bridges/list_of_bridges/#MathOptInterface.Bridges.Constraint.IndicatorGreaterToLessThanBridge","page":"List of bridges","title":"MathOptInterface.Bridges.Constraint.IndicatorGreaterToLessThanBridge","text":"IndicatorGreaterToLessThanBridge{T,A} <: Bridges.Constraint.AbstractBridge\n\nIndicatorGreaterToLessThanBridge implements the following reformulation:\n\nz implies f(x) ge l into z implies -f(x) le -l\n\nSource node\n\nIndicatorGreaterToLessThanBridge supports:\n\nMOI.VectorAffineFunction{T} in MOI.Indicator{A,MOI.GreaterThan{T}}\n\nTarget nodes\n\nIndicatorGreaterToLessThanBridge creates:\n\nMOI.VectorAffineFunction{T} in MOI.Indicator{A,MOI.LessThan{T}}\n\n\n\n\n\n","category":"type"},{"location":"submodules/Bridges/list_of_bridges/#MathOptInterface.Bridges.Constraint.IndicatorLessToGreaterThanBridge","page":"List of bridges","title":"MathOptInterface.Bridges.Constraint.IndicatorLessToGreaterThanBridge","text":"IndicatorLessToGreaterThanBridge{T,A} <: Bridges.Constraint.AbstractBridge\n\nIndicatorLessToGreaterThanBridge implements the following reformulations:\n\nz implies f(x) le u into z implies -f(x) ge -u\n\nSource node\n\nIndicatorLessToGreaterThanBridge supports:\n\nMOI.VectorAffineFunction{T} in MOI.Indicator{A,MOI.LessThan{T}}\n\nTarget nodes\n\nIndicatorLessToGreaterThanBridge creates:\n\nMOI.VectorAffineFunction{T} in MOI.Indicator{A,MOI.GreaterThan{T}}\n\n\n\n\n\n","category":"type"},{"location":"submodules/Bridges/list_of_bridges/#MathOptInterface.Bridges.Constraint.IndicatorSOS1Bridge","page":"List of bridges","title":"MathOptInterface.Bridges.Constraint.IndicatorSOS1Bridge","text":"IndicatorSOS1Bridge{T,S} <: Bridges.Constraint.AbstractBridge\n\nIndicatorSOS1Bridge implements the following reformulation:\n\nz implies f(x) in S into f(x) + y in S, SOS1(y z)\n\nwarning: Warning\nThis bridge assumes that the solver supports MOI.SOS1{T} constraints in which one of the variables (y) is continuous.\n\nSource node\n\nIndicatorSOS1Bridge supports:\n\nMOI.VectorAffineFunction{T} in MOI.Indicator{MOI.ACTIVATE_ON_ONE,S}\n\nTarget nodes\n\nIndicatorSOS1Bridge creates:\n\nMOI.ScalarAffineFunction{T} in S\nMOI.VectorOfVariables in MOI.SOS1{T}\n\n\n\n\n\n","category":"type"},{"location":"submodules/Bridges/list_of_bridges/#MathOptInterface.Bridges.Constraint.SemiToBinaryBridge","page":"List of bridges","title":"MathOptInterface.Bridges.Constraint.SemiToBinaryBridge","text":"SemiToBinaryBridge{T,S} <: Bridges.Constraint.AbstractBridge\n\nSemiToBinaryBridge implements the following reformulations:\n\nx in 0 cup l u into\nbeginaligned\nx leq z u \nx geq z l \nz in 0 1\nendaligned\nx in 0 cup l ldots u into\nbeginaligned\nx leq z u \nx geq z l \nz in 0 1 \nx in mathbbZ\nendaligned\n\nSource node\n\nSemiToBinaryBridge supports:\n\nMOI.VariableIndex in MOI.Semicontinuous{T}\nMOI.VariableIndex in MOI.Semiinteger{T}\n\nTarget nodes\n\nSemiToBinaryBridge creates:\n\nMOI.VariableIndex in MOI.ZeroOne\nMOI.ScalarAffineFunction{T} in MOI.LessThan{T}\nMOI.ScalarAffineFunction{T} in MOI.GreaterThan{T}\nMOI.VariableIndex{T} in MOI.Integer (if S is MOI.Semiinteger{T}\n\n\n\n\n\n","category":"type"},{"location":"submodules/Bridges/list_of_bridges/#MathOptInterface.Bridges.Constraint.ZeroOneBridge","page":"List of bridges","title":"MathOptInterface.Bridges.Constraint.ZeroOneBridge","text":"ZeroOneBridge{T} <: Bridges.Constraint.AbstractBridge\n\nZeroOneBridge implements the following reformulation:\n\nx in 0 1 into x in mathbbZ, 1x in 0 1.\n\nnote: Note\nZeroOneBridge adds a linear constraint instead of adding variable bounds to avoid conflicting with bounds set by the user.\n\nSource node\n\nZeroOneBridge supports:\n\nMOI.VariableIndex in MOI.ZeroOne\n\nTarget nodes\n\nZeroOneBridge creates:\n\nMOI.VariableIndex in MOI.Integer\nMOI.ScalarAffineFunction{T} in MOI.Interval{T}\n\n\n\n\n\n","category":"type"},{"location":"submodules/Bridges/list_of_bridges/#MathOptInterface.Bridges.Constraint.IntegerToZeroOneBridge","page":"List of bridges","title":"MathOptInterface.Bridges.Constraint.IntegerToZeroOneBridge","text":"IntegerToZeroOneBridge{T} <: Bridges.Constraint.AbstractBridge\n\nIntegerToZeroOneBridge implements the following reformulation:\n\nx in mathbfZ into y_i in 0 1, x == lb + sum 2^i-1 y_i.\n\nSource node\n\nIntegerToZeroOneBridge supports:\n\nVariableIndex in MOI.Integer\n\nTarget nodes\n\nIntegerToZeroOneBridge creates:\n\nMOI.VariableIndex in MOI.ZeroOne\nMOI.ScalarAffineFunction{T} in MOI.EqualTo{T}\n\nDeveloper note\n\nThis bridge is implemented as a constraint bridge instead of a variable bridge because we don't want to substitute the linear combination of y for every instance of x. Doing so would be expensive and greatly reduce the sparsity of the constraints.\n\n\n\n\n\n","category":"type"},{"location":"submodules/Bridges/list_of_bridges/#MathOptInterface.Bridges.Constraint.NumberConversionBridge","page":"List of bridges","title":"MathOptInterface.Bridges.Constraint.NumberConversionBridge","text":"NumberConversionBridge{T,F1,S1,F2,S2} <: Bridges.Constraint.AbstractBridge\n\nNumberConversionBridge implements the following reformulation:\n\nf1(x) in S1 to f2(x) in S2\n\nwhere f and S are the same functional form, but differ in their coefficient type.\n\nSource node\n\nNumberConversionBridge supports:\n\nF1 in S1\n\nTarget node\n\nNumberConversionBridge creates:\n\nF2 in S2\n\n\n\n\n\n","category":"type"},{"location":"submodules/Bridges/list_of_bridges/#MathOptInterface.Bridges.Constraint.AllDifferentToCountDistinctBridge","page":"List of bridges","title":"MathOptInterface.Bridges.Constraint.AllDifferentToCountDistinctBridge","text":"AllDifferentToCountDistinctBridge{T,F} <: Bridges.Constraint.AbstractBridge\n\nAllDifferentToCountDistinctBridge implements the following reformulations:\n\nx in textsfAllDifferent(d) to (n x) in textsfCountDistinct(1+d) and n = d\nf(x) in textsfAllDifferent(d) to (d f(x)) in textsfCountDistinct(1+d)\n\nSource node\n\nAllDifferentToCountDistinctBridge supports:\n\nF in MOI.AllDifferent\n\nwhere F is MOI.VectorOfVariables or MOI.VectorAffineFunction{T}.\n\nTarget nodes\n\nAllDifferentToCountDistinctBridge creates:\n\nF in MOI.CountDistinct\nMOI.VariableIndex in MOI.EqualTo{T}\n\n\n\n\n\n","category":"type"},{"location":"submodules/Bridges/list_of_bridges/#MathOptInterface.Bridges.Constraint.ReifiedAllDifferentToCountDistinctBridge","page":"List of bridges","title":"MathOptInterface.Bridges.Constraint.ReifiedAllDifferentToCountDistinctBridge","text":"ReifiedAllDifferentToCountDistinctBridge{T,F} <:\nBridges.Constraint.AbstractBridge\n\nReifiedAllDifferentToCountDistinctBridge implements the following reformulations:\n\nr iff x in textsfAllDifferent(d) to r iff (n x) in textsfCountDistinct(1+d) and n = d\nr iff f(x) in textsfAllDifferent(d) to r iff (d f(x)) in textsfCountDistinct(1+d)\n\nSource node\n\nReifiedAllDifferentToCountDistinctBridge supports:\n\nF in MOI.Reified{MOI.AllDifferent}\n\nwhere F is MOI.VectorOfVariables or MOI.VectorAffineFunction{T}.\n\nTarget nodes\n\nReifiedAllDifferentToCountDistinctBridge creates:\n\nF in MOI.Reified{MOI.CountDistinct}\nMOI.VariableIndex in MOI.EqualTo{T}\n\n\n\n\n\n","category":"type"},{"location":"submodules/Bridges/list_of_bridges/#MathOptInterface.Bridges.Constraint.BinPackingToMILPBridge","page":"List of bridges","title":"MathOptInterface.Bridges.Constraint.BinPackingToMILPBridge","text":"BinPackingToMILPBridge{T,F} <: Bridges.Constraint.AbstractBridge\n\nBinPackingToMILPBridge implements the following reformulation:\n\nx in BinPacking(c w) into a mixed-integer linear program.\n\nReformulation\n\nThe reformulation is non-trivial, and it depends on the finite domain of each variable x_i, which we as define S_i = l_ildotsu_i.\n\nFirst, we introduce new binary variables z_ij, which are 1 if variable x_i takes the value j in the optimal solution and 0 otherwise:\n\nbeginaligned\nz_ij in 0 1 forall i in 1ldots d j in S_i \nx_i - sumlimits_jin S_i j cdot z_ij = 0 forall i in 1ldots d \nsumlimits_jin S_i z_ij = 1 forall i in 1ldots d \nendaligned\n\nThen, we add the capacity constraint for all possible bins j:\n\nsumlimits_i w_i z_ij le c forall j in bigcup_i=1ldotsd S_i\n\nSource node\n\nBinPackingToMILPBridge supports:\n\nF in MOI.BinPacking{T}\n\nTarget nodes\n\nBinPackingToMILPBridge creates:\n\nMOI.VariableIndex in MOI.ZeroOne\nMOI.ScalarAffineFunction{T} in MOI.EqualTo{T}\nMOI.ScalarAffineFunction{T} in MOI.LessThan{T}\n\n\n\n\n\n","category":"type"},{"location":"submodules/Bridges/list_of_bridges/#MathOptInterface.Bridges.Constraint.CircuitToMILPBridge","page":"List of bridges","title":"MathOptInterface.Bridges.Constraint.CircuitToMILPBridge","text":"CircuitToMILPBridge{T,F} <: Bridges.Constraint.AbstractBridge\n\nCircuitToMILPBridge implements the following reformulation:\n\nx in textsfCircuit(d) to the Miller-Tucker-Zemlin formulation of the Traveling Salesperson Problem.\n\nSource node\n\nCircuitToMILPBridge supports:\n\nF in MOI.Circuit\n\nwhere F is MOI.VectorOfVariables or MOI.VectorAffineFunction{T}.\n\nTarget nodes\n\nCircuitToMILPBridge creates:\n\nMOI.VariableIndex in MOI.ZeroOne\nMOI.VariableIndex in MOI.Integer\nMOI.VariableIndex in MOI.Interval{T}\nMOI.ScalarAffineFunction{T} in MOI.EqualTo{T}\nMOI.ScalarAffineFunction{T} in MOI.LessThan{T}\n\n\n\n\n\n","category":"type"},{"location":"submodules/Bridges/list_of_bridges/#MathOptInterface.Bridges.Constraint.CountAtLeastToCountBelongsBridge","page":"List of bridges","title":"MathOptInterface.Bridges.Constraint.CountAtLeastToCountBelongsBridge","text":"CountAtLeastToCountBelongsBridge{T,F} <: Bridges.Constraint.AbstractBridge\n\nCountAtLeastToCountBelongsBridge implements the following reformulation:\n\nx in textsfCountAtLeast(n d mathcalS) to (n_i x_d_i) in textsfCountBelongs(1+d mathcalS) and n_i ge n for all i.\n\nSource node\n\nCountAtLeastToCountBelongsBridge supports:\n\nF in MOI.CountAtLeast\n\nwhere F is MOI.VectorOfVariables or MOI.VectorAffineFunction{T}.\n\nTarget nodes\n\nCountAtLeastToCountBelongsBridge creates:\n\nF in MOI.CountBelongs\nMOI.VariableIndex in MOI.GreaterThan{T}\n\n\n\n\n\n","category":"type"},{"location":"submodules/Bridges/list_of_bridges/#MathOptInterface.Bridges.Constraint.CountBelongsToMILPBridge","page":"List of bridges","title":"MathOptInterface.Bridges.Constraint.CountBelongsToMILPBridge","text":"CountBelongsToMILPBridge{T,F} <: Bridges.Constraint.AbstractBridge\n\nCountBelongsToMILPBridge implements the following reformulation:\n\n(n x) in textsfCountBelongs(1+d mathcalS) into a mixed-integer linear program.\n\nReformulation\n\nThe reformulation is non-trivial, and it depends on the finite domain of each variable x_i, which we as define S_i = l_ildotsu_i.\n\nFirst, we introduce new binary variables z_ij, which are 1 if variable x_i takes the value j in the optimal solution and 0 otherwise:\n\nbeginaligned\nz_ij in 0 1 forall i in 1ldots d j in S_i \nx_i - sumlimits_jin S_i j cdot z_ij = 0 forall i in 1ldots d \nsumlimits_jin S_i z_ij = 1 forall i in 1ldots d \nendaligned\n\nFinally, n is constrained to be the number of z_ij elements that are in mathcalS:\n\nn - sumlimits_iin 1ldots d j in mathcalS z_ij = 0\n\nSource node\n\nCountBelongsToMILPBridge supports:\n\nF in MOI.CountBelongs\n\nwhere F is MOI.VectorOfVariables or MOI.VectorAffineFunction{T}.\n\nTarget nodes\n\nCountBelongsToMILPBridge creates:\n\nMOI.VariableIndex in MOI.ZeroOne\nMOI.ScalarAffineFunction{T} in MOI.EqualTo{T}\n\n\n\n\n\n","category":"type"},{"location":"submodules/Bridges/list_of_bridges/#MathOptInterface.Bridges.Constraint.CountDistinctToMILPBridge","page":"List of bridges","title":"MathOptInterface.Bridges.Constraint.CountDistinctToMILPBridge","text":"CountDistinctToMILPBridge{T,F} <: Bridges.Constraint.AbstractBridge\n\nCountDistinctToMILPBridge implements the following reformulation:\n\n(n x) in textsfCountDistinct(1+d) into a mixed-integer linear program.\n\nReformulation\n\nThe reformulation is non-trivial, and it depends on the finite domain of each variable x_i, which we as define S_i = l_ildotsu_i.\n\nFirst, we introduce new binary variables z_ij, which are 1 if variable x_i takes the value j in the optimal solution and 0 otherwise:\n\nbeginaligned\nz_ij in 0 1 forall i in 1ldots d j in S_i \nx_i - sumlimits_jin S_i j cdot z_ij = 0 forall i in 1ldots d \nsumlimits_jin S_i z_ij = 1 forall i in 1ldots d \nendaligned\n\nThen, we introduce new binary variables y_j, which are 1 if a variable takes the value j in the optimal solution and 0 otherwise.\n\nbeginaligned\ny_j in 0 1 forall j in bigcup_i=1ldotsd S_i \ny_j le sumlimits_i in 1ldots d j in S_i z_ij le M y_j forall j in bigcup_i=1ldotsd S_i\nendaligned\n\nFinally, n is constrained to be the number of y_j elements that are non-zero:\n\nn - sumlimits_j in bigcup_i=1ldotsd S_i y_j = 0\n\nSource node\n\nCountDistinctToMILPBridge supports:\n\nF in MOI.CountDistinct\n\nwhere F is MOI.VectorOfVariables or MOI.VectorAffineFunction{T}.\n\nTarget nodes\n\nCountDistinctToMILPBridge creates:\n\nMOI.VariableIndex in MOI.ZeroOne\nMOI.ScalarAffineFunction{T} in MOI.EqualTo{T}\nMOI.ScalarAffineFunction{T} in MOI.LessThan{T}\n\n\n\n\n\n","category":"type"},{"location":"submodules/Bridges/list_of_bridges/#MathOptInterface.Bridges.Constraint.ReifiedCountDistinctToMILPBridge","page":"List of bridges","title":"MathOptInterface.Bridges.Constraint.ReifiedCountDistinctToMILPBridge","text":"ReifiedCountDistinctToMILPBridge{T,F} <: Bridges.Constraint.AbstractBridge\n\nReifiedCountDistinctToMILPBridge implements the following reformulation:\n\nr iff (n x) in textsfCountDistinct(1+d) into a mixed-integer linear program.\n\nReformulation\n\nThe reformulation is non-trivial, and it depends on the finite domain of each variable x_i, which we as define S_i = l_ildotsu_i.\n\nFirst, we introduce new binary variables z_ij, which are 1 if variable x_i takes the value j in the optimal solution and 0 otherwise:\n\nbeginaligned\nz_ij in 0 1 forall i in 1ldots d j in S_i \nx_i - sumlimits_jin S_i j cdot z_ij = 0 forall i in 1ldots d \nsumlimits_jin S_i z_ij = 1 forall i in 1ldots d \nendaligned\n\nThen, we introduce new binary variables y_j, which are 1 if a variable takes the value j in the optimal solution and 0 otherwise.\n\nbeginaligned\ny_j in 0 1 forall j in bigcup_i=1ldotsd S_i \ny_j le sumlimits_i in 1ldots d j in S_i z_ij le M y_j forall j in bigcup_i=1ldotsd S_i\nendaligned\n\nFinally, n is constrained to be the number of y_j elements that are non-zero, with some slack:\n\nn - sumlimits_j in bigcup_i=1ldotsd S_i y_j = delta^+ - delta^-\n\nAnd then the slack is constrained to respect the reif variable r:\n\nbeginaligned\nd_1 le delta^+ le M d_1 \nd_2 le delta^- le M d_s \nd_1 + d_2 + r = 1 \nd_1 d_2 in 0 1\nendaligned\n\nSource node\n\nReifiedCountDistinctToMILPBridge supports:\n\nF in MOI.Reified{MOI.CountDistinct}\n\nwhere F is MOI.VectorOfVariables or MOI.VectorAffineFunction{T}.\n\nTarget nodes\n\nReifiedCountDistinctToMILPBridge creates:\n\nMOI.VariableIndex in MOI.ZeroOne\nMOI.ScalarAffineFunction{T} in MOI.EqualTo{T}\nMOI.ScalarAffineFunction{T} in MOI.LessThan{T}\n\n\n\n\n\n","category":"type"},{"location":"submodules/Bridges/list_of_bridges/#MathOptInterface.Bridges.Constraint.CountGreaterThanToMILPBridge","page":"List of bridges","title":"MathOptInterface.Bridges.Constraint.CountGreaterThanToMILPBridge","text":"CountGreaterThanToMILPBridge{T,F} <: Bridges.Constraint.AbstractBridge\n\nCountGreaterThanToMILPBridge implements the following reformulation:\n\n(c y x) in CountGreaterThan() into a mixed-integer linear program.\n\nSource node\n\nCountGreaterThanToMILPBridge supports:\n\nF in MOI.CountGreaterThan\n\nTarget nodes\n\nCountGreaterThanToMILPBridge creates:\n\nMOI.VariableIndex in MOI.ZeroOne\nMOI.ScalarAffineFunction{T} in MOI.EqualTo{T}\nMOI.ScalarAffineFunction{T} in MOI.GreaterThan{T}\n\n\n\n\n\n","category":"type"},{"location":"submodules/Bridges/list_of_bridges/#MathOptInterface.Bridges.Constraint.TableToMILPBridge","page":"List of bridges","title":"MathOptInterface.Bridges.Constraint.TableToMILPBridge","text":"TableToMILPBridge{T,F} <: Bridges.Constraint.AbstractBridge\n\nTableToMILPBridge implements the following reformulation:\n\nx in Table(t) into\nbeginaligned\nz_j in 0 1 quad forall i j \nsumlimits_j=1^n z_j = 1 \nsumlimits_j=1^n t_ij z_j = x_i quad forall i\nendaligned\n\nSource node\n\nTableToMILPBridge supports:\n\nF in MOI.Table{T}\n\nTarget nodes\n\nTableToMILPBridge creates:\n\nMOI.VariableIndex in MOI.ZeroOne\nMOI.ScalarAffineFunction{T} in MOI.EqualTo{T}\n\n\n\n\n\n","category":"type"},{"location":"submodules/Bridges/list_of_bridges/#objective_bridges_ref","page":"List of bridges","title":"Objective bridges","text":"","category":"section"},{"location":"submodules/Bridges/list_of_bridges/","page":"List of bridges","title":"List of bridges","text":"These bridges are subtypes of Bridges.Objective.AbstractBridge.","category":"page"},{"location":"submodules/Bridges/list_of_bridges/","page":"List of bridges","title":"List of bridges","text":"Bridges.Objective.FunctionizeBridge\nBridges.Objective.QuadratizeBridge\nBridges.Objective.SlackBridge\nBridges.Objective.VectorFunctionizeBridge\nBridges.Objective.VectorSlackBridge","category":"page"},{"location":"submodules/Bridges/list_of_bridges/#MathOptInterface.Bridges.Objective.FunctionizeBridge","page":"List of bridges","title":"MathOptInterface.Bridges.Objective.FunctionizeBridge","text":"FunctionizeBridge{T}\n\nFunctionizeBridge implements the following reformulations:\n\nmin x into min1x + 0\nmax x into max1x + 0\n\nwhere T is the coefficient type of 1 and 0.\n\nSource node\n\nFunctionizeBridge supports:\n\nMOI.ObjectiveFunction{MOI.VariableIndex}\n\nTarget nodes\n\nFunctionizeBridge creates:\n\nOne objective node: MOI.ObjectiveFunction{MOI.ScalarAffineFunction{T}}\n\n\n\n\n\n","category":"type"},{"location":"submodules/Bridges/list_of_bridges/#MathOptInterface.Bridges.Objective.QuadratizeBridge","page":"List of bridges","title":"MathOptInterface.Bridges.Objective.QuadratizeBridge","text":"QuadratizeBridge{T}\n\nQuadratizeBridge implements the following reformulations:\n\nmin a^top x + b into minx^top mathbf0 x + a^top x + b\nmax a^top x + b into maxx^top mathbf0 x + a^top x + b\n\nwhere T is the coefficient type of 0.\n\nSource node\n\nQuadratizeBridge supports:\n\nMOI.ObjectiveFunction{MOI.ScalarAffineFunction{T}}\n\nTarget nodes\n\nQuadratizeBridge creates:\n\nOne objective node: MOI.ObjectiveFunction{MOI.ScalarQuadraticFunction{T}}\n\n\n\n\n\n","category":"type"},{"location":"submodules/Bridges/list_of_bridges/#MathOptInterface.Bridges.Objective.SlackBridge","page":"List of bridges","title":"MathOptInterface.Bridges.Objective.SlackBridge","text":"SlackBridge{T,F,G}\n\nSlackBridge implements the following reformulations:\n\nminf(x) into miny f(x) - y le 0\nmaxf(x) into maxy f(x) - y ge 0\n\nwhere F is the type of f(x) - y, G is the type of f(x), and T is the coefficient type of f(x).\n\nSource node\n\nSlackBridge supports:\n\nMOI.ObjectiveFunction{G}\n\nTarget nodes\n\nSlackBridge creates:\n\nOne variable node: MOI.VariableIndex in MOI.Reals\nOne objective node: MOI.ObjectiveFunction{MOI.VariableIndex}\nOne constraint node, that depends on the MOI.ObjectiveSense:\nF-in-MOI.LessThan if MIN_SENSE\nF-in-MOI.GreaterThan if MAX_SENSE\n\nwarning: Warning\nWhen using this bridge, changing the optimization sense is not supported. Set the sense to MOI.FEASIBILITY_SENSE first to delete the bridge, then set MOI.ObjectiveSense and re-add the objective.\n\n\n\n\n\n","category":"type"},{"location":"submodules/Bridges/list_of_bridges/#MathOptInterface.Bridges.Objective.VectorFunctionizeBridge","page":"List of bridges","title":"MathOptInterface.Bridges.Objective.VectorFunctionizeBridge","text":"VectorFunctionizeBridge{T}\n\nVectorFunctionizeBridge implements the following reformulations:\n\nmin x into min1x + 0\nmax x into max1x + 0\n\nwhere T is the coefficient type of 1 and 0.\n\nSource node\n\nVectorFunctionizeBridge supports:\n\nMOI.ObjectiveFunction{MOI.VectorOfVariables}\n\nTarget nodes\n\nVectorFunctionizeBridge creates:\n\nOne objective node: MOI.ObjectiveFunction{MOI.VectorAffineFunction{T}}\n\n\n\n\n\n","category":"type"},{"location":"submodules/Bridges/list_of_bridges/#MathOptInterface.Bridges.Objective.VectorSlackBridge","page":"List of bridges","title":"MathOptInterface.Bridges.Objective.VectorSlackBridge","text":"VectorSlackBridge{T,F,G}\n\nVectorSlackBridge implements the following reformulations:\n\nminf(x) into miny y - f(x) in mathbbR_+ \nmaxf(x) into maxy f(x) - y in mathbbR_+ \n\nwhere F is the type of f(x) - y, G is the type of f(x), and T is the coefficient type of f(x).\n\nSource node\n\nVectorSlackBridge supports:\n\nMOI.ObjectiveFunction{G}\n\nTarget nodes\n\nVectorSlackBridge creates:\n\nOne variable node: MOI.VectorOfVariables in MOI.Reals\nOne objective node: MOI.ObjectiveFunction{MOI.VectorOfVariables}\nOne constraint node: F-in-MOI.Nonnegatives\n\nwarning: Warning\nWhen using this bridge, changing the optimization sense is not supported. Set the sense to MOI.FEASIBILITY_SENSE first to delete the bridge, then set MOI.ObjectiveSense and re-add the objective.\n\n\n\n\n\n","category":"type"},{"location":"submodules/Bridges/list_of_bridges/#variable_bridges_ref","page":"List of bridges","title":"Variable bridges","text":"","category":"section"},{"location":"submodules/Bridges/list_of_bridges/","page":"List of bridges","title":"List of bridges","text":"These bridges are subtypes of Bridges.Variable.AbstractBridge.","category":"page"},{"location":"submodules/Bridges/list_of_bridges/","page":"List of bridges","title":"List of bridges","text":"Bridges.Variable.FreeBridge\nBridges.Variable.NonposToNonnegBridge\nBridges.Variable.RSOCtoPSDBridge\nBridges.Variable.RSOCtoSOCBridge\nBridges.Variable.SOCtoRSOCBridge\nBridges.Variable.VectorizeBridge\nBridges.Variable.ZerosBridge\nBridges.Variable.HermitianToSymmetricPSDBridge","category":"page"},{"location":"submodules/Bridges/list_of_bridges/#MathOptInterface.Bridges.Variable.FreeBridge","page":"List of bridges","title":"MathOptInterface.Bridges.Variable.FreeBridge","text":"FreeBridge{T} <: Bridges.Variable.AbstractBridge\n\nFreeBridge implements the following reformulation:\n\nx in mathbbR into y z ge 0 with the substitution rule x = y - z,\n\nwhere T is the coefficient type of y - z.\n\nSource node\n\nFreeBridge supports:\n\nMOI.VectorOfVariables in MOI.Reals\n\nTarget nodes\n\nFreeBridge creates:\n\nOne variable node: MOI.VectorOfVariables in MOI.Nonnegatives\n\n\n\n\n\n","category":"type"},{"location":"submodules/Bridges/list_of_bridges/#MathOptInterface.Bridges.Variable.NonposToNonnegBridge","page":"List of bridges","title":"MathOptInterface.Bridges.Variable.NonposToNonnegBridge","text":"NonposToNonnegBridge{T} <: Bridges.Variable.AbstractBridge\n\nNonposToNonnegBridge implements the following reformulation:\n\nx in mathbbR_- into y in mathbbR_+ with the substitution rule x = -y,\n\nwhere T is the coefficient type of -y.\n\nSource node\n\nNonposToNonnegBridge supports:\n\nMOI.VectorOfVariables in MOI.Nonpositives\n\nTarget nodes\n\nNonposToNonnegBridge creates:\n\nOne variable node: MOI.VectorOfVariables in MOI.Nonnegatives,\n\n\n\n\n\n","category":"type"},{"location":"submodules/Bridges/list_of_bridges/#MathOptInterface.Bridges.Variable.RSOCtoPSDBridge","page":"List of bridges","title":"MathOptInterface.Bridges.Variable.RSOCtoPSDBridge","text":"RSOCtoPSDBridge{T} <: Bridges.Variable.AbstractBridge\n\nRSOCtoPSDBridge implements the following reformulation:\n\nx_2^2 le 2tu where t u ge 0 into Y succeq 0, with the substitution rule: Y = leftbeginarrayc ct x^top x 2u mathbfIendarrayright\n\nAdditional bounds are added to ensure the off-diagonals of the 2uI submatrix are 0, and linear constraints are added to ennsure the diagonal of 2uI takes the same values.\n\nAs a special case, if x = 0, then RSOCtoPSDBridge reformulates into (t u) in mathbbR_+.\n\nSource node\n\nRSOCtoPSDBridge supports:\n\nMOI.VectorOfVariables in MOI.RotatedSecondOrderCone\n\nTarget nodes\n\nRSOCtoPSDBridge creates:\n\nOne variable node that depends on the input dimension:\nMOI.VectorOfVariables in MOI.Nonnegatives if dimension is 1 or 2\nMOI.VectorOfVariables in\nMOI.PositiveSemidefiniteConeTriangle otherwise\nThe constraint node MOI.VariableIndex in MOI.EqualTo\nThe constrant node MOI.ScalarAffineFunction in MOI.EqualTo\n\n\n\n\n\n","category":"type"},{"location":"submodules/Bridges/list_of_bridges/#MathOptInterface.Bridges.Variable.RSOCtoSOCBridge","page":"List of bridges","title":"MathOptInterface.Bridges.Variable.RSOCtoSOCBridge","text":"RSOCtoSOCBridge{T} <: Bridges.Variable.AbstractBridge\n\nRSOCtoSOCBridge implements the following reformulation:\n\nx_2^2 le 2tu into v_2 le w, with the substitution rules t = fracwsqrt 2 + fracv_1sqrt 2, u = fracwsqrt 2 - fracv_1sqrt 2, and x = (v_2ldotsv_N).\n\nSource node\n\nRSOCtoSOCBridge supports:\n\nMOI.VectorOfVariables in MOI.RotatedSecondOrderCone\n\nTarget node\n\nRSOCtoSOCBridge creates:\n\nMOI.VectorOfVariables in MOI.SecondOrderCone\n\n\n\n\n\n","category":"type"},{"location":"submodules/Bridges/list_of_bridges/#MathOptInterface.Bridges.Variable.SOCtoRSOCBridge","page":"List of bridges","title":"MathOptInterface.Bridges.Variable.SOCtoRSOCBridge","text":"SOCtoRSOCBridge{T} <: Bridges.Variable.AbstractBridge\n\nSOCtoRSOCBridge implements the following reformulation:\n\nx_2 le t into 2uv ge w_2^2, with the substitution rules t = fracusqrt 2 + fracvsqrt 2, x = (fracusqrt 2 - fracvsqrt 2 w).\n\nAssumptions\n\nSOCtoRSOCBridge assumes that x ge 1.\n\nSource node\n\nSOCtoRSOCBridge supports:\n\nMOI.VectorOfVariables in MOI.SecondOrderCone\n\nTarget node\n\nSOCtoRSOCBridge creates:\n\nMOI.VectorOfVariables in MOI.RotatedSecondOrderCone\n\n\n\n\n\n","category":"type"},{"location":"submodules/Bridges/list_of_bridges/#MathOptInterface.Bridges.Variable.VectorizeBridge","page":"List of bridges","title":"MathOptInterface.Bridges.Variable.VectorizeBridge","text":"VectorizeBridge{T,S} <: Bridges.Variable.AbstractBridge\n\nVectorizeBridge implements the following reformulations:\n\nx ge a into y in mathbbR_+ with the substitution rule x = a + y\nx le a into y in mathbbR_- with the substitution rule x = a + y\nx == a into y in 0 with the substitution rule x = a + y\n\nwhere T is the coefficient type of a + y.\n\nSource node\n\nVectorizeBridge supports:\n\nMOI.VariableIndex in MOI.GreaterThan{T}\nMOI.VariableIndex in MOI.LessThan{T}\nMOI.VariableIndex in MOI.EqualTo{T}\n\nTarget nodes\n\nVectorizeBridge creates:\n\nOne variable node: MOI.VectorOfVariables in S, where S is one of MOI.Nonnegatives, MOI.Nonpositives, MOI.Zeros depending on the type of S.\n\n\n\n\n\n","category":"type"},{"location":"submodules/Bridges/list_of_bridges/#MathOptInterface.Bridges.Variable.ZerosBridge","page":"List of bridges","title":"MathOptInterface.Bridges.Variable.ZerosBridge","text":"ZerosBridge{T} <: Bridges.Variable.AbstractBridge\n\nZerosBridge implements the following reformulation:\n\nx in 0 into the substitution rule x = 0,\n\nwhere T is the coefficient type of 0.\n\nSource node\n\nZerosBridge supports:\n\nMOI.VectorOfVariables in MOI.Zeros\n\nTarget nodes\n\nZerosBridge does not create target nodes. It replaces all instances of x with 0 via substitution. This means that no variables are created in the underlying model.\n\nCaveats\n\nThe bridged variables are similar to parameters with zero values. Parameters with non-zero values can be created with constrained variables in MOI.EqualTo by combining a VectorizeBridge and this bridge.\n\nHowever, functions modified by ZerosBridge cannot be unbridged. That is, for a given function, we cannot determine if the bridged variables were used.\n\nA related implication is that this bridge does not support MOI.ConstraintDual. However, if a MOI.Utilities.CachingOptimizer is used, the dual can be determined by the bridged optimizer using MOI.Utilities.get_fallback because the caching optimizer records the unbridged function.\n\n\n\n\n\n","category":"type"},{"location":"submodules/Bridges/list_of_bridges/#MathOptInterface.Bridges.Variable.HermitianToSymmetricPSDBridge","page":"List of bridges","title":"MathOptInterface.Bridges.Variable.HermitianToSymmetricPSDBridge","text":"HermitianToSymmetricPSDBridge{T} <: Bridges.Variable.AbstractBridge\n\nHermitianToSymmetricPSDBridge implements the following reformulation:\n\nHermitian positive semidefinite n x n complex matrix to a symmetric positive semidefinite 2n x 2n real matrix satisfying equality constraints described below.\n\nSource node\n\nHermitianToSymmetricPSDBridge supports:\n\nMOI.VectorOfVariables in MOI.HermitianPositiveSemidefiniteConeTriangle\n\nTarget node\n\nHermitianToSymmetricPSDBridge creates:\n\nMOI.VectorOfVariables in MOI.PositiveSemidefiniteConeTriangle\nMOI.ScalarAffineFunction{T} in MOI.EqualTo{T}\n\nReformulation\n\nThe reformulation is best described by example.\n\nThe Hermitian matrix:\n\nbeginbmatrix\n x_11 x_12 + y_12im x_13 + y_13im\n x_12 - y_12im x_22 x_23 + y_23im\n x_13 - y_13im x_23 - y_23im x_33\nendbmatrix\n\nis positive semidefinite if and only if the symmetric matrix:\n\nbeginbmatrix\n x_11 x_12 x_13 0 y_12 y_13 \n x_22 x_23 -y_12 0 y_23 \n x_33 -y_13 -y_23 0 \n x_11 x_12 x_13 \n x_22 x_23 \n x_33\nendbmatrix\n\nis positive semidefinite.\n\nThe bridge achieves this reformulation by adding a new set of variables in MOI.PositiveSemidefiniteConeTriangle(6), and then adding three groups of equality constraints to:\n\nconstrain the two x blocks to be equal\nforce the diagonal of the y blocks to be 0\nforce the lower triangular of the y block to be the negative of the upper triangle.\n\n\n\n\n\n","category":"type"},{"location":"submodules/Bridges/overview/","page":"Overview","title":"Overview","text":"CurrentModule = MathOptInterface\nDocTestSetup = quote\n import MathOptInterface as MOI\nend\nDocTestFilters = [r\"MathOptInterface|MOI\"]","category":"page"},{"location":"submodules/Bridges/overview/#The-Bridges-submodule","page":"Overview","title":"The Bridges submodule","text":"","category":"section"},{"location":"submodules/Bridges/overview/","page":"Overview","title":"Overview","text":"The Bridges module simplifies the process of converting models between equivalent formulations.","category":"page"},{"location":"submodules/Bridges/overview/","page":"Overview","title":"Overview","text":"tip: Tip\nRead our paper for more details on how bridges are implemented.","category":"page"},{"location":"submodules/Bridges/overview/#Why-bridges?","page":"Overview","title":"Why bridges?","text":"","category":"section"},{"location":"submodules/Bridges/overview/","page":"Overview","title":"Overview","text":"A constraint can often be written in a number of equivalent formulations. For example, the constraint l le a^top x le u (ScalarAffineFunction-in-Interval) could be re-formulated as two constraints: a^top x ge l (ScalarAffineFunction-in-GreaterThan) and a^top x le u (ScalarAffineFunction-in-LessThan). An alternative re-formulation is to add a dummy variable y with the constraints l le y le u (VariableIndex-in-Interval) and a^top x - y = 0 (ScalarAffineFunction-in-EqualTo).","category":"page"},{"location":"submodules/Bridges/overview/","page":"Overview","title":"Overview","text":"To avoid each solver having to code these transformations manually, MathOptInterface provides bridges.","category":"page"},{"location":"submodules/Bridges/overview/","page":"Overview","title":"Overview","text":"A bridge is a small transformation from one constraint type to another (potentially collection of) constraint type.","category":"page"},{"location":"submodules/Bridges/overview/","page":"Overview","title":"Overview","text":"Because these bridges are included in MathOptInterface, they can be re-used by any optimizer. Some bridges also implement constraint modifications and constraint primal and dual translations.","category":"page"},{"location":"submodules/Bridges/overview/","page":"Overview","title":"Overview","text":"Several bridges can be used in combination to transform a single constraint into a form that the solver may understand. Choosing the bridges to use takes the form of finding a shortest path in the hyper-graph of bridges. The methodology is detailed in the MOI paper.","category":"page"},{"location":"submodules/Bridges/overview/#The-three-types-of-bridges","page":"Overview","title":"The three types of bridges","text":"","category":"section"},{"location":"submodules/Bridges/overview/","page":"Overview","title":"Overview","text":"There are three types of bridges in MathOptInterface:","category":"page"},{"location":"submodules/Bridges/overview/","page":"Overview","title":"Overview","text":"Constraint bridges\nVariable bridges\nObjective bridges","category":"page"},{"location":"submodules/Bridges/overview/#Constraint-bridges","page":"Overview","title":"Constraint bridges","text":"","category":"section"},{"location":"submodules/Bridges/overview/","page":"Overview","title":"Overview","text":"Constraint bridges convert constraints formulated by the user into an equivalent form supported by the solver. Constraint bridges are subtypes of Bridges.Constraint.AbstractBridge.","category":"page"},{"location":"submodules/Bridges/overview/","page":"Overview","title":"Overview","text":"The equivalent formulation may add constraints (and possibly also variables) in the underlying model.","category":"page"},{"location":"submodules/Bridges/overview/","page":"Overview","title":"Overview","text":"In particular, constraint bridges can focus on rewriting the function of a constraint, and do not change the set. Function bridges are subtypes of Bridges.Constraint.AbstractFunctionConversionBridge.","category":"page"},{"location":"submodules/Bridges/overview/","page":"Overview","title":"Overview","text":"Read the list of implemented constraint bridges for more details on the types of transformations that are available. Function bridges are Bridges.Constraint.ScalarFunctionizeBridge and Bridges.Constraint.VectorFunctionizeBridge.","category":"page"},{"location":"submodules/Bridges/overview/#variable_bridges","page":"Overview","title":"Variable bridges","text":"","category":"section"},{"location":"submodules/Bridges/overview/","page":"Overview","title":"Overview","text":"Variable bridges convert variables added by the user, either free with add_variable/add_variables, or constrained with add_constrained_variable/add_constrained_variables, into an equivalent form supported by the solver. Variable bridges are subtypes of Bridges.Variable.AbstractBridge.","category":"page"},{"location":"submodules/Bridges/overview/","page":"Overview","title":"Overview","text":"The equivalent formulation may add constraints (and possibly also variables) in the underlying model.","category":"page"},{"location":"submodules/Bridges/overview/","page":"Overview","title":"Overview","text":"Read the list of implemented variable bridges for more details on the types of transformations that are available.","category":"page"},{"location":"submodules/Bridges/overview/#Objective-bridges","page":"Overview","title":"Objective bridges","text":"","category":"section"},{"location":"submodules/Bridges/overview/","page":"Overview","title":"Overview","text":"Objective bridges convert the ObjectiveFunction set by the user into an equivalent form supported by the solver. Objective bridges are subtypes of Bridges.Objective.AbstractBridge.","category":"page"},{"location":"submodules/Bridges/overview/","page":"Overview","title":"Overview","text":"The equivalent formulation may add constraints (and possibly also variables) in the underlying model.","category":"page"},{"location":"submodules/Bridges/overview/","page":"Overview","title":"Overview","text":"Read the list of implemented objective bridges for more details on the types of transformations that are available.","category":"page"},{"location":"submodules/Bridges/overview/#Bridges.full_bridge_optimizer","page":"Overview","title":"Bridges.full_bridge_optimizer","text":"","category":"section"},{"location":"submodules/Bridges/overview/","page":"Overview","title":"Overview","text":"tip: Tip\nUnless you have an advanced use-case, this is probably the only function you need to care about.","category":"page"},{"location":"submodules/Bridges/overview/","page":"Overview","title":"Overview","text":"To enable the full power of MathOptInterface's bridges, wrap an optimizer in a Bridges.full_bridge_optimizer.","category":"page"},{"location":"submodules/Bridges/overview/","page":"Overview","title":"Overview","text":"julia> inner_optimizer = MOI.Utilities.Model{Float64}()\nMOIU.Model{Float64}\n\njulia> optimizer = MOI.Bridges.full_bridge_optimizer(inner_optimizer, Float64)\nMOIB.LazyBridgeOptimizer{MOIU.Model{Float64}}\nwith 0 variable bridges\nwith 0 constraint bridges\nwith 0 objective bridges\nwith inner model MOIU.Model{Float64}","category":"page"},{"location":"submodules/Bridges/overview/","page":"Overview","title":"Overview","text":"Now, use optimizer as normal, and bridging will happen lazily behind the scenes. By lazily, we mean that bridging will happen if and only if the constraint is not supported by the inner_optimizer.","category":"page"},{"location":"submodules/Bridges/overview/","page":"Overview","title":"Overview","text":"info: Info\nMost bridges are added by default in Bridges.full_bridge_optimizer. However, for technical reasons, some bridges are not added by default. Three examples include Bridges.Constraint.SOCtoPSDBridge, Bridges.Constraint.SOCtoNonConvexQuadBridge and Bridges.Constraint.RSOCtoNonConvexQuadBridge. See the docs of those bridges for more information.","category":"page"},{"location":"submodules/Bridges/overview/#Add-a-single-bridge","page":"Overview","title":"Add a single bridge","text":"","category":"section"},{"location":"submodules/Bridges/overview/","page":"Overview","title":"Overview","text":"If you don't want to use Bridges.full_bridge_optimizer, you can wrap an optimizer in a single bridge.","category":"page"},{"location":"submodules/Bridges/overview/","page":"Overview","title":"Overview","text":"However, this will force the constraint to be bridged, even if the inner_optimizer supports it.","category":"page"},{"location":"submodules/Bridges/overview/","page":"Overview","title":"Overview","text":"julia> inner_optimizer = MOI.Utilities.Model{Float64}()\nMOIU.Model{Float64}\n\njulia> optimizer = MOI.Bridges.Constraint.SplitInterval{Float64}(inner_optimizer)\nMOIB.Constraint.SingleBridgeOptimizer{MOIB.Constraint.SplitIntervalBridge{Float64}, MOIU.Model{Float64}}\nwith 0 constraint bridges\nwith inner model MOIU.Model{Float64}\n\njulia> x = MOI.add_variable(optimizer)\nMOI.VariableIndex(1)\n\njulia> MOI.add_constraint(optimizer, x, MOI.Interval(0.0, 1.0))\nMathOptInterface.ConstraintIndex{MathOptInterface.VariableIndex, MathOptInterface.Interval{Float64}}(1)\n\njulia> MOI.get(optimizer, MOI.ListOfConstraintTypesPresent())\n1-element Vector{Tuple{Type, Type}}:\n (MathOptInterface.VariableIndex, MathOptInterface.Interval{Float64})\n\njulia> MOI.get(inner_optimizer, MOI.ListOfConstraintTypesPresent())\n2-element Vector{Tuple{Type, Type}}:\n (MathOptInterface.VariableIndex, MathOptInterface.GreaterThan{Float64})\n (MathOptInterface.VariableIndex, MathOptInterface.LessThan{Float64})","category":"page"},{"location":"submodules/Bridges/overview/#Bridges.LazyBridgeOptimizer","page":"Overview","title":"Bridges.LazyBridgeOptimizer","text":"","category":"section"},{"location":"submodules/Bridges/overview/","page":"Overview","title":"Overview","text":"If you don't want to use Bridges.full_bridge_optimizer, but you need more than a single bridge (or you want the bridging to happen lazily), you can manually construct a Bridges.LazyBridgeOptimizer.","category":"page"},{"location":"submodules/Bridges/overview/","page":"Overview","title":"Overview","text":"First, wrap an inner optimizer:","category":"page"},{"location":"submodules/Bridges/overview/","page":"Overview","title":"Overview","text":"julia> inner_optimizer = MOI.Utilities.Model{Float64}()\nMOIU.Model{Float64}\n\njulia> optimizer = MOI.Bridges.LazyBridgeOptimizer(inner_optimizer)\nMOIB.LazyBridgeOptimizer{MOIU.Model{Float64}}\nwith 0 variable bridges\nwith 0 constraint bridges\nwith 0 objective bridges\nwith inner model MOIU.Model{Float64}","category":"page"},{"location":"submodules/Bridges/overview/","page":"Overview","title":"Overview","text":"Then use Bridges.add_bridge to add individual bridges:","category":"page"},{"location":"submodules/Bridges/overview/","page":"Overview","title":"Overview","text":"julia> MOI.Bridges.add_bridge(optimizer, MOI.Bridges.Constraint.SplitIntervalBridge{Float64})\n\njulia> MOI.Bridges.add_bridge(optimizer, MOI.Bridges.Objective.FunctionizeBridge{Float64})","category":"page"},{"location":"submodules/Bridges/overview/","page":"Overview","title":"Overview","text":"Now the constraints will be bridged only if needed:","category":"page"},{"location":"submodules/Bridges/overview/","page":"Overview","title":"Overview","text":"julia> x = MOI.add_variable(optimizer)\nMOI.VariableIndex(1)\n\njulia> MOI.add_constraint(optimizer, x, MOI.Interval(0.0, 1.0))\nMathOptInterface.ConstraintIndex{MathOptInterface.VariableIndex, MathOptInterface.Interval{Float64}}(1)\n\njulia> MOI.get(optimizer, MOI.ListOfConstraintTypesPresent())\n1-element Vector{Tuple{Type, Type}}:\n (MathOptInterface.VariableIndex, MathOptInterface.Interval{Float64})\n\njulia> MOI.get(inner_optimizer, MOI.ListOfConstraintTypesPresent())\n1-element Vector{Tuple{Type, Type}}:\n (MathOptInterface.VariableIndex, MathOptInterface.Interval{Float64})","category":"page"},{"location":"developer/checklists/#Checklists","page":"Checklists","title":"Checklists","text":"","category":"section"},{"location":"developer/checklists/","page":"Checklists","title":"Checklists","text":"The purpose of this page is to collate a series of checklists for commonly performed changes to the source code of MathOptInterface.","category":"page"},{"location":"developer/checklists/","page":"Checklists","title":"Checklists","text":"In each case, copy the checklist into the description of the pull request.","category":"page"},{"location":"developer/checklists/#Making-a-release","page":"Checklists","title":"Making a release","text":"","category":"section"},{"location":"developer/checklists/","page":"Checklists","title":"Checklists","text":"Use this checklist when making a release of the MathOptInterface repository.","category":"page"},{"location":"developer/checklists/","page":"Checklists","title":"Checklists","text":"## Basic\n\n - [ ] `version` field of `Project.toml` has been updated\n - If a breaking change, increment the MAJOR field and reset others to 0\n - If adding new features, increment the MINOR field and reset PATCH to 0\n - If adding bug fixes or documentation changes, increment the PATCH field\n\n## Documentation\n\n - [ ] Add a new entry to `docs/src/changelog.md`, following existing style\n\n## Tests\n\n - [ ] The `solver-tests.yml` GitHub action does not have unexpected failures.\n To run the action, go to:\n https://github.com/jump-dev/MathOptInterface.jl/actions/workflows/solver-tests.yml\n and click \"Run workflow\"","category":"page"},{"location":"developer/checklists/#Adding-a-new-set","page":"Checklists","title":"Adding a new set","text":"","category":"section"},{"location":"developer/checklists/","page":"Checklists","title":"Checklists","text":"Use this checklist when adding a new set to the MathOptInterface repository.","category":"page"},{"location":"developer/checklists/","page":"Checklists","title":"Checklists","text":"## Basic\n\n - [ ] Add a new `AbstractScalarSet` or `AbstractVectorSet` to `src/sets.jl`\n - [ ] If `isbitstype(S) == false`, implement `Base.copy(set::S)`\n - [ ] If `isbitstype(S) == false`, implement `Base.:(==)(x::S, y::S)`\n - [ ] If an `AbstractVectorSet`, implement `dimension(set::S)`, unless the\n dimension is given by `set.dimension`.\n\n## Utilities\n\n - [ ] If an `AbstractVectorSet`, implement `Utilities.set_dot`,\n unless the dot product between two vectors in the set is equivalent to\n `LinearAlgebra.dot`\n - [ ] If an `AbstractVectorSet`, implement `Utilities.set_with_dimension` in\n `src/Utilities/matrix_of_constraints.jl`\n - [ ] Add the set to the `@model` macro at the bottom of `src/Utilities.model.jl`\n\n## Documentation\n\n - [ ] Add a docstring, which gives the mathematical definition of the set,\n along with an `## Example` block containing a `jldoctest`\n - [ ] Add the docstring to `docs/src/reference/standard_form.md`\n - [ ] Add the set to the relevant table in `docs/src/manual/standard_form.md`\n\n## Tests\n\n - [ ] Define a new `_set(::Type{S})` method in `src/Test/test_basic_constraint.jl`\n and add the name of the set to the list at the bottom of that files\n - [ ] If the set has any checks in its constructor, add tests to `test/sets.jl`\n\n## MathOptFormat\n\n - [ ] Open an issue at `https://github.com/jump-dev/MathOptFormat` to add\n support for the new set {{ replace with link to the issue }}\n\n## Optional\n\n - [ ] Implement `dual_set(::S)` and `dual_set_type(::Type{S})`\n - [ ] Add new tests to the `Test` submodule exercising your new set\n - [ ] Add new bridges to convert your set into more commonly used sets","category":"page"},{"location":"developer/checklists/#Adding-a-new-bridge","page":"Checklists","title":"Adding a new bridge","text":"","category":"section"},{"location":"developer/checklists/","page":"Checklists","title":"Checklists","text":"Use this checklist when adding a new bridge to the MathOptInterface repository.","category":"page"},{"location":"developer/checklists/","page":"Checklists","title":"Checklists","text":"The steps are mostly the same, but locations depend on whether the bridge is a Constraint, Objective, or Variable bridge. In each case below, replace XXX with the appropriate type of bridge.","category":"page"},{"location":"developer/checklists/","page":"Checklists","title":"Checklists","text":"## Basic\n\n - [ ] Create a new file in `src/Bridges/XXX/bridges`\n - [ ] Define the bridge, following existing examples. The name of the bridge\n struct must end in `Bridge`\n - [ ] Check if your bridge can be a subtype of [`MOI.Bridges.Constraint.SetMapBridge`](@ref)\n - [ ] Define a new `const` that is a `SingleBridgeOptimizer` wrapping the\n new bridge. The name of the const must be the name of the bridge, less\n the `Bridge` suffix\n - [ ] `include` the file in `src/Bridges/XXX/bridges/XXX.jl`\n - [ ] If the bridge should be enabled by default, add the bridge to\n `add_all_bridges` at the bottom of `src/Bridges/XXX/XXX.jl`\n\n## Tests\n\n - [ ] Create a new file in the appropriate subdirectory of `tests/Bridges/XXX`\n - [ ] Use `MOI.Bridges.runtests` to test various inputs and outputs of the\n bridge\n - [ ] If, after opening the pull request to add the bridge, some lines are not\n covered by the tests, add additional bridge-specific tests to cover the\n untested lines.\n\n## Documentation\n\n - [ ] Add a docstring which uses the same template as existing bridges.\n - [ ] Add the docstring to `docs/src/submodules/Bridges/list_of_bridges.md`\n\n## Final touch\n\nIf the bridge depends on run-time values of other variables and constraints in\nthe model:\n\n - [ ] Implement `MOI.Utilities.needs_final_touch(::Bridge)`\n - [ ] Implement `MOI.Utilities.final_touch(::Bridge, ::MOI.ModelLike)`\n - [ ] Ensure that `final_touch` can be called multiple times in a row","category":"page"},{"location":"developer/checklists/#Updating-MathOptFormat","page":"Checklists","title":"Updating MathOptFormat","text":"","category":"section"},{"location":"developer/checklists/","page":"Checklists","title":"Checklists","text":"Use this checklist when updating the version of MathOptFormat.","category":"page"},{"location":"developer/checklists/","page":"Checklists","title":"Checklists","text":"## Basic\n\n - [ ] The file at `src/FileFormats/MOF/mof.X.Y.schema.json` is updated\n - [ ] The constants `SCHEMA_PATH`, `VERSION`, and `SUPPORTED_VERSIONS` are\n updated in `src/FileFormats/MOF/MOF.jl`\n\n## New sets\n\n - [ ] New sets are added to the `@model` in `src/FileFormats/MOF/MOF.jl`\n - [ ] New sets are added to the `@enum` in `src/FileFormats/MOF/read.jl`\n - [ ] `set_to_moi` is defined for each set in `src/FileFormats/MOF/read.jl`\n - [ ] `head_name` is defined for each set in `src/FileFormats/MOF/write.jl`\n - [ ] A new unit test calling `_test_model_equality` is aded to\n `test/FileFormats/MOF/MOF.jl`\n\n## Tests\n\n - [ ] The version field in `test/FileFormats/MOF/nlp.mof.json` is updated\n\n## Documentation\n\n - [ ] The version fields are updated in `docs/src/submodules/FileFormats/overview.md`","category":"page"},{"location":"manual/standard_form/","page":"Standard form problem","title":"Standard form problem","text":"CurrentModule = MathOptInterface\nDocTestSetup = quote\n import MathOptInterface as MOI\nend\nDocTestFilters = [r\"MathOptInterface|MOI\"]","category":"page"},{"location":"manual/standard_form/#Standard-form-problem","page":"Standard form problem","title":"Standard form problem","text":"","category":"section"},{"location":"manual/standard_form/","page":"Standard form problem","title":"Standard form problem","text":"MathOptInterface represents optimization problems in the standard form:","category":"page"},{"location":"manual/standard_form/","page":"Standard form problem","title":"Standard form problem","text":"beginalign\n min_x in mathbbR^n f_0(x)\n \n textst f_i(x) in mathcalS_i i = 1 ldots m\nendalign","category":"page"},{"location":"manual/standard_form/","page":"Standard form problem","title":"Standard form problem","text":"where:","category":"page"},{"location":"manual/standard_form/","page":"Standard form problem","title":"Standard form problem","text":"the functions f_0 f_1 ldots f_m are specified by AbstractFunction objects\nthe sets mathcalS_1 ldots mathcalS_m are specified by AbstractSet objects","category":"page"},{"location":"manual/standard_form/","page":"Standard form problem","title":"Standard form problem","text":"tip: Tip\nFor more information on this standard form, read our paper.","category":"page"},{"location":"manual/standard_form/","page":"Standard form problem","title":"Standard form problem","text":"MOI defines some commonly used functions and sets, but the interface is extensible to other sets recognized by the solver.","category":"page"},{"location":"manual/standard_form/#Functions","page":"Standard form problem","title":"Functions","text":"","category":"section"},{"location":"manual/standard_form/","page":"Standard form problem","title":"Standard form problem","text":"The function types implemented in MathOptInterface.jl are:","category":"page"},{"location":"manual/standard_form/","page":"Standard form problem","title":"Standard form problem","text":"Function Description\nVariableIndex x_j, the projection onto a single coordinate defined by a variable index j.\nVectorOfVariables The projection onto multiple coordinates (that is, extracting a sub-vector).\nScalarAffineFunction a^T x + b, where a is a vector and b scalar.\nScalarNonlinearFunction f(x), where f is a nonlinear function.\nVectorAffineFunction A x + b, where A is a matrix and b is a vector.\nScalarQuadraticFunction frac12 x^T Q x + a^T x + b, where Q is a symmetric matrix, a is a vector, and b is a constant.\nVectorQuadraticFunction A vector of scalar-valued quadratic functions.\nVectorNonlinearFunction f(x), where f is a vector-valued nonlinear function.","category":"page"},{"location":"manual/standard_form/","page":"Standard form problem","title":"Standard form problem","text":"Extensions for nonlinear programming are present but not yet well documented.","category":"page"},{"location":"manual/standard_form/#One-dimensional-sets","page":"Standard form problem","title":"One-dimensional sets","text":"","category":"section"},{"location":"manual/standard_form/","page":"Standard form problem","title":"Standard form problem","text":"The one-dimensional set types implemented in MathOptInterface.jl are:","category":"page"},{"location":"manual/standard_form/","page":"Standard form problem","title":"Standard form problem","text":"Set Description\nLessThan(u) (-infty u\nGreaterThan(l) l infty)\nEqualTo(v) v\nInterval(l, u) l u\nInteger() mathbbZ\nZeroOne() 0 1 \nSemicontinuous(l, u) 0 cup l u\nSemiinteger(l, u) 0 cup ll+1ldotsu-1u","category":"page"},{"location":"manual/standard_form/#Vector-cones","page":"Standard form problem","title":"Vector cones","text":"","category":"section"},{"location":"manual/standard_form/","page":"Standard form problem","title":"Standard form problem","text":"The vector-valued set types implemented in MathOptInterface.jl are:","category":"page"},{"location":"manual/standard_form/","page":"Standard form problem","title":"Standard form problem","text":"Set Description\nReals(d) mathbbR^d\nZeros(d) 0^d\nNonnegatives(d) x in mathbbR^d x ge 0 \nNonpositives(d) x in mathbbR^d x le 0 \nSecondOrderCone(d) (tx) in mathbbR^d t ge lVert x rVert_2 \nRotatedSecondOrderCone(d) (tux) in mathbbR^d 2tu ge lVert x rVert_2^2 t ge 0u ge 0 \nExponentialCone() (xyz) in mathbbR^3 y exp (xy) le z y 0 \nDualExponentialCone() (uvw) in mathbbR^3 -u exp (vu) le exp(1) w u 0 \nGeometricMeanCone(d) (tx) in mathbbR^1+n x ge 0 t le sqrtnx_1 x_2 cdots x_n where n is d - 1\nPowerCone(α) (xyz) in mathbbR^3 x^alpha y^1-alpha ge z x ge 0y ge 0 \nDualPowerCone(α) (uvw) in mathbbR^3 left(fracualpharight(^alphaleft(fracv1-alpharight)^1-alpha ge w uv ge 0 \nNormOneCone(d) (tx) in mathbbR^d t ge sum_i lvert x_i rvert \nNormInfinityCone(d) (tx) in mathbbR^d t ge max_i lvert x_i rvert \nRelativeEntropyCone(d) (u v w) in mathbbR^d u ge sum_i w_i log (fracw_iv_i) v_i ge 0 w_i ge 0 \nHyperRectangle(l, u) x in barmathbbR^d x_i in l_i u_i forall i=1ldotsd\nNormCone(p, d) ``{ (t,x) \\in \\mathbb{R}^{d} : t \\ge \\left(\\sum\\limits_i","category":"page"},{"location":"manual/standard_form/#Matrix-cones","page":"Standard form problem","title":"Matrix cones","text":"","category":"section"},{"location":"manual/standard_form/","page":"Standard form problem","title":"Standard form problem","text":"The matrix-valued set types implemented in MathOptInterface.jl are:","category":"page"},{"location":"manual/standard_form/","page":"Standard form problem","title":"Standard form problem","text":"Set Description\nRootDetConeTriangle(d) (tX) in mathbbR^1+d(1+d)2 t le det(X)^1d X mbox is the upper triangle of a PSD matrix \nRootDetConeSquare(d) (tX) in mathbbR^1+d^2 t le det(X)^1d X mbox is a PSD matrix \nPositiveSemidefiniteConeTriangle(d) X in mathbbR^d(d+1)2 X mbox is the upper triangle of a PSD matrix \nPositiveSemidefiniteConeSquare(d) X in mathbbR^d^2 X mbox is a PSD matrix \nLogDetConeTriangle(d) (tuX) in mathbbR^2+d(1+d)2 t le ulog(det(Xu)) X mbox is the upper triangle of a PSD matrix u 0 \nLogDetConeSquare(d) (tuX) in mathbbR^2+d^2 t le u log(det(Xu)) X mbox is a PSD matrix u 0 \nNormSpectralCone(r, c) (t X) in mathbbR^1 + r times c t ge sigma_1(X) X mbox is a rtimes cmbox matrix \nNormNuclearCone(r, c) (t X) in mathbbR^1 + r times c t ge sum_i sigma_i(X) X mbox is a rtimes cmbox matrix \nHermitianPositiveSemidefiniteConeTriangle(d) The cone of Hermitian positive semidefinite matrices, with\nside_dimension rows and columns. \nScaled(S) The set S scaled so that Utilities.set_dot corresponds to LinearAlgebra.dot","category":"page"},{"location":"manual/standard_form/","page":"Standard form problem","title":"Standard form problem","text":"Some of these cones can take two forms: XXXConeTriangle and XXXConeSquare.","category":"page"},{"location":"manual/standard_form/","page":"Standard form problem","title":"Standard form problem","text":"In XXXConeTriangle sets, the matrix is assumed to be symmetric, and the elements are provided by a vector, in which the entries of the upper-right triangular part of the matrix are given column by column (or equivalently, the entries of the lower-left triangular part are given row by row).","category":"page"},{"location":"manual/standard_form/","page":"Standard form problem","title":"Standard form problem","text":"In XXXConeSquare sets, the entries of the matrix are given column by column (or equivalently, row by row), and the matrix is constrained to be symmetric. As an example, given a 2-by-2 matrix of variables X and a one-dimensional variable t, we can specify a root-det constraint as [t, X11, X12, X22] ∈ RootDetConeTriangle or [t, X11, X12, X21, X22] ∈ RootDetConeSquare.","category":"page"},{"location":"manual/standard_form/","page":"Standard form problem","title":"Standard form problem","text":"We provide both forms to enable flexibility for solvers who may natively support one or the other. Transformations between XXXConeTriangle and XXXConeSquare are handled by bridges, which removes the chance of conversion mistakes by users or solver developers.","category":"page"},{"location":"manual/standard_form/#Multi-dimensional-sets-with-combinatorial-structure","page":"Standard form problem","title":"Multi-dimensional sets with combinatorial structure","text":"","category":"section"},{"location":"manual/standard_form/","page":"Standard form problem","title":"Standard form problem","text":"Other sets are vector-valued, with a particular combinatorial structure. Read their docstrings for more information on how to interpret them.","category":"page"},{"location":"manual/standard_form/","page":"Standard form problem","title":"Standard form problem","text":"Set Description\nSOS1 A Special Ordered Set (SOS) of Type I\nSOS2 A Special Ordered Set (SOS) of Type II\nIndicator A set to specify an indicator constraint\nComplements A set to specify a mixed complementarity constraint\nAllDifferent The all_different global constraint\nBinPacking The bin_packing global constraint\nCircuit The circuit global constraint\nCountAtLeast The at_least global constraint\nCountBelongs The nvalue global constraint\nCountDistinct The distinct global constraint\nCountGreaterThan The count_gt global constraint\nCumulative The cumulative global constraint\nPath The path global constraint\nTable The table global constraint","category":"page"},{"location":"reference/modification/","page":"Modifications","title":"Modifications","text":"CurrentModule = MathOptInterface\nDocTestSetup = quote\n import MathOptInterface as MOI\nend\nDocTestFilters = [r\"MathOptInterface|MOI\"]","category":"page"},{"location":"reference/modification/#Modifications","page":"Modifications","title":"Modifications","text":"","category":"section"},{"location":"reference/modification/","page":"Modifications","title":"Modifications","text":"modify\nAbstractFunctionModification\nScalarConstantChange\nVectorConstantChange\nScalarCoefficientChange\nMultirowChange","category":"page"},{"location":"reference/modification/#MathOptInterface.modify","page":"Modifications","title":"MathOptInterface.modify","text":"Constraint Function\n\nmodify(model::ModelLike, ci::ConstraintIndex, change::AbstractFunctionModification)\n\nApply the modification specified by change to the function of constraint ci.\n\nAn ModifyConstraintNotAllowed error is thrown if modifying constraints is not supported by the model model.\n\nExamples\n\nmodify(model, ci, ScalarConstantChange(10.0))\n\nObjective Function\n\nmodify(model::ModelLike, ::ObjectiveFunction, change::AbstractFunctionModification)\n\nApply the modification specified by change to the objective function of model. To change the function completely, call set instead.\n\nAn ModifyObjectiveNotAllowed error is thrown if modifying objectives is not supported by the model model.\n\nExamples\n\nmodify(model, ObjectiveFunction{ScalarAffineFunction{Float64}}(), ScalarConstantChange(10.0))\n\nMultiple modifications in Constraint Functions\n\nmodify(\n model::ModelLike,\n cis::AbstractVector{<:ConstraintIndex},\n changes::AbstractVector{<:AbstractFunctionModification},\n)\n\nApply multiple modifications specified by changes to the functions of constraints cis.\n\nA ModifyConstraintNotAllowed error is thrown if modifying constraints is not supported by model.\n\nExamples\n\nmodify(\n model,\n [ci, ci],\n [\n ScalarCoefficientChange{Float64}(VariableIndex(1), 1.0),\n ScalarCoefficientChange{Float64}(VariableIndex(2), 0.5),\n ],\n)\n\nMultiple modifications in the Objective Function\n\nmodify(\n model::ModelLike,\n attr::ObjectiveFunction,\n changes::AbstractVector{<:AbstractFunctionModification},\n)\n\nApply multiple modifications specified by changes to the functions of constraints cis.\n\nA ModifyObjectiveNotAllowed error is thrown if modifying objective coefficients is not supported by model.\n\nExamples\n\nmodify(\n model,\n ObjectiveFunction{ScalarAffineFunction{Float64}}(),\n [\n ScalarCoefficientChange{Float64}(VariableIndex(1), 1.0),\n ScalarCoefficientChange{Float64}(VariableIndex(2), 0.5),\n ],\n)\n\n\n\n\n\n","category":"function"},{"location":"reference/modification/#MathOptInterface.AbstractFunctionModification","page":"Modifications","title":"MathOptInterface.AbstractFunctionModification","text":"AbstractFunctionModification\n\nAn abstract supertype for structs which specify partial modifications to functions, to be used for making small modifications instead of replacing the functions entirely.\n\n\n\n\n\n","category":"type"},{"location":"reference/modification/#MathOptInterface.ScalarConstantChange","page":"Modifications","title":"MathOptInterface.ScalarConstantChange","text":"ScalarConstantChange{T}(new_constant::T)\n\nA struct used to request a change in the constant term of a scalar-valued function.\n\nApplicable to ScalarAffineFunction and ScalarQuadraticFunction.\n\n\n\n\n\n","category":"type"},{"location":"reference/modification/#MathOptInterface.VectorConstantChange","page":"Modifications","title":"MathOptInterface.VectorConstantChange","text":"VectorConstantChange{T}(new_constant::Vector{T})\n\nA struct used to request a change in the constant vector of a vector-valued function.\n\nApplicable to VectorAffineFunction and VectorQuadraticFunction.\n\n\n\n\n\n","category":"type"},{"location":"reference/modification/#MathOptInterface.ScalarCoefficientChange","page":"Modifications","title":"MathOptInterface.ScalarCoefficientChange","text":"ScalarCoefficientChange{T}(variable::VariableIndex, new_coefficient::T)\n\nA struct used to request a change in the linear coefficient of a single variable in a scalar-valued function.\n\nApplicable to ScalarAffineFunction and ScalarQuadraticFunction.\n\n\n\n\n\n","category":"type"},{"location":"reference/modification/#MathOptInterface.MultirowChange","page":"Modifications","title":"MathOptInterface.MultirowChange","text":"MultirowChange{T}(\n variable::VariableIndex,\n new_coefficients::Vector{Tuple{Int64,T}},\n) where {T}\n\nA struct used to request a change in the linear coefficients of a single variable in a vector-valued function.\n\nNew coefficients are specified by (output_index, coefficient) tuples.\n\nApplicable to VectorAffineFunction and VectorQuadraticFunction.\n\n\n\n\n\n","category":"type"},{"location":"changelog/","page":"Release notes","title":"Release notes","text":"CurrentModule = MathOptInterface","category":"page"},{"location":"changelog/#Release-notes","page":"Release notes","title":"Release notes","text":"","category":"section"},{"location":"changelog/","page":"Release notes","title":"Release notes","text":"The format is based on Keep a Changelog, and this project adheres to Semantic Versioning.","category":"page"},{"location":"changelog/#v1.20.0-(September-7,-2023)","page":"Release notes","title":"v1.20.0 (September 7, 2023)","text":"","category":"section"},{"location":"changelog/#Added","page":"Release notes","title":"Added","text":"","category":"section"},{"location":"changelog/","page":"Release notes","title":"Release notes","text":"Added Scaled set (#2237) (#2263) (#2264)\nAdded ObjectiveLimit attribute (#2257)","category":"page"},{"location":"changelog/#Other","page":"Release notes","title":"Other","text":"","category":"section"},{"location":"changelog/","page":"Release notes","title":"Release notes","text":"Updated dependencies (#2258)\nImproved performance of ScalarNonlinearFunction utilities (#2259)\nFixed docstrings (#2261)","category":"page"},{"location":"changelog/#v1.19.0-(August-15,-2023)","page":"Release notes","title":"v1.19.0 (August 15, 2023)","text":"","category":"section"},{"location":"changelog/#Added-2","page":"Release notes","title":"Added","text":"","category":"section"},{"location":"changelog/","page":"Release notes","title":"Release notes","text":"Added VectorNonlinearFunction (#2201)\nAdded new bridges\nBridges.Constraint.IntegerToZeroOneBridge (#2205)\nBridges.Constraint.ToScalarQuadraticBridge (#2235)\nBridges.Constraint.ToVectorQuadraticBridge (#2235)\nBridges.Constraint.ToScalarNonlinearBridge (#2233) (#2235)\nBridges.Constraint.FunctionConversionBridge (#2235)\nAdded Bridges.bridging_cost for setting a bridge-specific cost in the bridging graph (#2235)\nAdded Utilities.eval_variables support for ScalarNonlinearFunction (#2218) (#2219)\nAdded support for ScalarNonlinearFunction in FileFormats.NL (#2228) (#2231)\nAdded support for writing non-Float64 functions in FileFormats.MOF\nAdded Utilities.lazy_map (#2254)","category":"page"},{"location":"changelog/#Fixed","page":"Release notes","title":"Fixed","text":"","category":"section"},{"location":"changelog/","page":"Release notes","title":"Release notes","text":"Fixed method ambiguities in operate (#2224)\nFixed reading LP file with a -infinity <= x <= +infinity variable (#2225)\nFixed missing require in Test.test_nonlinear_duals (#2230)\nFixed bug in ConstraintPrimal of Bridges.Constraint.QuadtoSOCBridge (#2240)","category":"page"},{"location":"changelog/#Other-2","page":"Release notes","title":"Other","text":"","category":"section"},{"location":"changelog/","page":"Release notes","title":"Release notes","text":"Added extensions to solver-tests.yml (#2229)\nRefactored test/Benchmarks (#2234)\nFixed warnings in tests (#2241) (#2243)\nSmall refactoring of bridges for upcoming VectorNonlinearFunction (#2244) (#2245)\nFixed various typos (#2251) (#2255)\nPartitioned how we run the tests on GitHub actions (#2252) (#2253)","category":"page"},{"location":"changelog/#v1.18.0-(June-23,-2023)","page":"Release notes","title":"v1.18.0 (June 23, 2023)","text":"","category":"section"},{"location":"changelog/#Added-3","page":"Release notes","title":"Added","text":"","category":"section"},{"location":"changelog/","page":"Release notes","title":"Release notes","text":"Added Bridges.Objective.SlackBridgePrimalDualStart (#2194)\nAdded constraint_gradient_structure and eval_constraint_gradient (#2200)","category":"page"},{"location":"changelog/#Fixed-2","page":"Release notes","title":"Fixed","text":"","category":"section"},{"location":"changelog/","page":"Release notes","title":"Release notes","text":"Fixed a missing @require in MOI.Test (#2195) (#2196)\nFixed incorrect usage of Utilities.operate! in bridges (#2207) (#2216)\nFixed splatting nonlinear expression with univariate operator (#2221)","category":"page"},{"location":"changelog/#Other-3","page":"Release notes","title":"Other","text":"","category":"section"},{"location":"changelog/","page":"Release notes","title":"Release notes","text":"Removed unused argument names (#2199)\nReduced memory requirement for tests (#2204)\nRefactored Utilities.promote_operation (#2206)\nImproved code style in Utilities/mutable_arithmetics.jl (#2209)\nRefactored various methods in Utilities/functions.jl (#2208) (#2212) (#2213) (#2214) (#2215)","category":"page"},{"location":"changelog/#v1.17.1-(June-6,-2023)","page":"Release notes","title":"v1.17.1 (June 6, 2023)","text":"","category":"section"},{"location":"changelog/#Fixed-3","page":"Release notes","title":"Fixed","text":"","category":"section"},{"location":"changelog/","page":"Release notes","title":"Release notes","text":"Fixed comparison of ScalarFunctionConstantNotZero (#2190)","category":"page"},{"location":"changelog/#Other-4","page":"Release notes","title":"Other","text":"","category":"section"},{"location":"changelog/","page":"Release notes","title":"Release notes","text":"Added documentation for enum instances (#2186)\nUpdated chatroom links in documentation (#2188)\nChanged the documentation to build on Julia v1.9 (#2191)","category":"page"},{"location":"changelog/#v1.17.0-(June-1,-2023)","page":"Release notes","title":"v1.17.0 (June 1, 2023)","text":"","category":"section"},{"location":"changelog/#Added-4","page":"Release notes","title":"Added","text":"","category":"section"},{"location":"changelog/","page":"Release notes","title":"Release notes","text":"Added ScalarNonlinearFunction (#2059)\nAdded a variety of tests for NormSpectralCone, NormNuclearCone, and HermitianPositiveSemidefiniteConeTriangle (#2174)\nAdded Utilities.value_type for computing the value type of a function (#2176)","category":"page"},{"location":"changelog/#Fixed-4","page":"Release notes","title":"Fixed","text":"","category":"section"},{"location":"changelog/","page":"Release notes","title":"Release notes","text":"Fixed support for external sets in Utilities.loadfromstring! (#2177)\nFixed promote_operation for ScalarNonlinearFunction (#2179)\nFixed two issues in FileFormats.LP when reading files with quadratic functions (#2182) (#2184)","category":"page"},{"location":"changelog/#v1.16.0-(May-16,-2023)","page":"Release notes","title":"v1.16.0 (May 16, 2023)","text":"","category":"section"},{"location":"changelog/#Added-5","page":"Release notes","title":"Added","text":"","category":"section"},{"location":"changelog/","page":"Release notes","title":"Release notes","text":"Added support for MathOptFormat v1.3 and v1.4 (#2158) (#2169)\nAdded new method to the nonlinear API (#2162) (#2164)\neval_hessian_constraint\neval_hessian_objective\nhessian_constraint_structure\nhessian_objective_structure\nAdded new sets\nNormCone (#2119)\nScaledPositiveSemidefiniteConeTriangle (#2154)","category":"page"},{"location":"changelog/#Fixed-5","page":"Release notes","title":"Fixed","text":"","category":"section"},{"location":"changelog/","page":"Release notes","title":"Release notes","text":"Fixed support for Julia v1.9 to work around a bug in the upstream Julia compiler (#2161) (#2163)\nFixed a correctness bug in Bridges.Constraint.HermitianToSymmetricPSDBridge (#2171)\nFixed convert(::VariableIndex, ::ScalarAffineFunction) when the function has terms with 0coefficients (#2173)","category":"page"},{"location":"changelog/#Other-5","page":"Release notes","title":"Other","text":"","category":"section"},{"location":"changelog/","page":"Release notes","title":"Release notes","text":"Fixed solver-tests.yml (#2157)\nUpdated documentation links to developer chatroom (#2160)\nAdded various tests for bridges (#2156)\nAdded checklists to the developer documentation (#2167) (#2168)","category":"page"},{"location":"changelog/#v1.15.1-(April-25,-2023)","page":"Release notes","title":"v1.15.1 (April 25, 2023)","text":"","category":"section"},{"location":"changelog/#Fixed-6","page":"Release notes","title":"Fixed","text":"","category":"section"},{"location":"changelog/","page":"Release notes","title":"Release notes","text":"Fixed deleting a variable in a bridged objective (#2150)","category":"page"},{"location":"changelog/#v1.15.0-(April-19,-2023)","page":"Release notes","title":"v1.15.0 (April 19, 2023)","text":"","category":"section"},{"location":"changelog/#Added-6","page":"Release notes","title":"Added","text":"","category":"section"},{"location":"changelog/","page":"Release notes","title":"Release notes","text":"Added Bridges.Objective.VectorFunctionizeBridge (#2139)","category":"page"},{"location":"changelog/#Fixed-7","page":"Release notes","title":"Fixed","text":"","category":"section"},{"location":"changelog/","page":"Release notes","title":"Release notes","text":"Fixed support for Rational in Bridges.Constraint.SplitIntervalBridge (#2137)\nFixed printing of LaTeX models (#2141)\nFixed modify in Bridges.Objective.VectorSlackBridge (#2144)\nFixed NAME record with spaces in FileFormats.MPS (#2146)\nFixed deleting a variable in a bridged objective (#2147)","category":"page"},{"location":"changelog/#Other-6","page":"Release notes","title":"Other","text":"","category":"section"},{"location":"changelog/","page":"Release notes","title":"Release notes","text":"Add a test for variables in one-sided open Interval sets (#2133)\nMinor style fixes in the source code (#2148)","category":"page"},{"location":"changelog/#v1.14.1-(April-6,-2023)","page":"Release notes","title":"v1.14.1 (April 6, 2023)","text":"","category":"section"},{"location":"changelog/#Fixed-8","page":"Release notes","title":"Fixed","text":"","category":"section"},{"location":"changelog/","page":"Release notes","title":"Release notes","text":"Fixed a bug in Bridges.print_active_bridges (#2135)","category":"page"},{"location":"changelog/#Other-7","page":"Release notes","title":"Other","text":"","category":"section"},{"location":"changelog/","page":"Release notes","title":"Release notes","text":"Added a warning when an ambiguous string is passed to exclude in Test.runtests (#2136)","category":"page"},{"location":"changelog/#v1.14.0-(April-4,-2023)","page":"Release notes","title":"v1.14.0 (April 4, 2023)","text":"","category":"section"},{"location":"changelog/#Added-7","page":"Release notes","title":"Added","text":"","category":"section"},{"location":"changelog/","page":"Release notes","title":"Release notes","text":"Added support for starting values in Bridges.Constraint.QuadtoSOCBridge (#2115)\nAdded support for Regex in the include and exclude arguments to Test.runtests (#2129)\nAdded Bridges.print_active_bridges methods for individual objectives and constraints (#2128)","category":"page"},{"location":"changelog/#Fixed-9","page":"Release notes","title":"Fixed","text":"","category":"section"},{"location":"changelog/","page":"Release notes","title":"Release notes","text":"Fixed ResultCount when parsing .sol files in FileFormats.NL (#2130)","category":"page"},{"location":"changelog/#v1.13.2-(March-21,-2023)","page":"Release notes","title":"v1.13.2 (March 21, 2023)","text":"","category":"section"},{"location":"changelog/#Fixed-10","page":"Release notes","title":"Fixed","text":"","category":"section"},{"location":"changelog/","page":"Release notes","title":"Release notes","text":"Fixed splatting of containers in MOI.Nonlinear (#2120)\nFixed a bug reading LP files with default bounds (#2121)\nFixed a bug in which Bridges.Constraint.HermitianToSymmetricPSDBridge was not enabled by default (#2123)","category":"page"},{"location":"changelog/#Other-8","page":"Release notes","title":"Other","text":"","category":"section"},{"location":"changelog/","page":"Release notes","title":"Release notes","text":"Fixed typos in the documentation (#2114)\nFunctions now print to the REPL in algebraic form. This is potentially breaking if you have tests which rely on a specific String form of MOI functions. (#2112) (#2126)","category":"page"},{"location":"changelog/#v1.13.1-(March-3,-2023)","page":"Release notes","title":"v1.13.1 (March 3, 2023)","text":"","category":"section"},{"location":"changelog/#Other-9","page":"Release notes","title":"Other","text":"","category":"section"},{"location":"changelog/","page":"Release notes","title":"Release notes","text":"Added the Google style guide to the documentation linter Vale, and fixed the resulting warnings (#2110)\nImproved the docstrings in src/functions.jl (#2108)","category":"page"},{"location":"changelog/#v1.13.0-(February-28,-2023)","page":"Release notes","title":"v1.13.0 (February 28, 2023)","text":"","category":"section"},{"location":"changelog/#Added-8","page":"Release notes","title":"Added","text":"","category":"section"},{"location":"changelog/","page":"Release notes","title":"Release notes","text":"Added Bridges.Constraint.NumberConversionBridge (#2091)\nAdded Parameter set (#2095) (#2105) (#2106) (#2109)\nAdded with_cache_type argument to instantiate (#2097)\nAdded support for HermitianPositiveSemidefiniteConeTriangle in Utilities.Model (#2100)","category":"page"},{"location":"changelog/#Fixed-11","page":"Release notes","title":"Fixed","text":"","category":"section"},{"location":"changelog/","page":"Release notes","title":"Release notes","text":"Fixed bug when Utilities.@product_of_sets is empty (#2101)\nFixed Bridges.print_active_bridges when variable bridge is an AbstractScalarSet (#2107)","category":"page"},{"location":"changelog/#Other-10","page":"Release notes","title":"Other","text":"","category":"section"},{"location":"changelog/","page":"Release notes","title":"Release notes","text":"Added tests for vector-valued objective functions in FileFormats.MOF (#2093)\nUsed and documented preference for import MathOptInterface as MOI (#2096)\nFix and test links in the documentation with linkcheck = true (#2098)\nImproved docstrings of sets in src/sets.jl (#2099)\nSkip checking flakey links in documentation with linkcheck_ignore (#2103)","category":"page"},{"location":"changelog/#v1.12.0-(February-10,-2023)","page":"Release notes","title":"v1.12.0 (February 10, 2023)","text":"","category":"section"},{"location":"changelog/#Added-9","page":"Release notes","title":"Added","text":"","category":"section"},{"location":"changelog/","page":"Release notes","title":"Release notes","text":"Added support for vector-valued objective functions (#2070)\nAdded a Utilities.distance_to_set method for SecondOrderCone (#2060)","category":"page"},{"location":"changelog/#Fixed-12","page":"Release notes","title":"Fixed","text":"","category":"section"},{"location":"changelog/","page":"Release notes","title":"Release notes","text":"Fixed a number of constraint bridges so that Bridges.final_touch can be called multiple times without forcing a rebuild of the reformulation (#2089)","category":"page"},{"location":"changelog/#Other-11","page":"Release notes","title":"Other","text":"","category":"section"},{"location":"changelog/","page":"Release notes","title":"Release notes","text":"Added new tests that a set ObjectiveFunction appears in ListOfModelAttributesSet (#2085)\nImproved the docstrings of a number of constraint-programming related sets (#2087)","category":"page"},{"location":"changelog/#v1.11.5-(January-24,-2023)","page":"Release notes","title":"v1.11.5 (January 24, 2023)","text":"","category":"section"},{"location":"changelog/#Fixed-13","page":"Release notes","title":"Fixed","text":"","category":"section"},{"location":"changelog/","page":"Release notes","title":"Release notes","text":"Fixed a bug writing .lp files with an off-diagonal quadratic objective (#2082)","category":"page"},{"location":"changelog/#Other-12","page":"Release notes","title":"Other","text":"","category":"section"},{"location":"changelog/","page":"Release notes","title":"Release notes","text":"Added SnoopPrecompile directives for reduced time-to-first-X in Julia v1.9 (#2080)","category":"page"},{"location":"changelog/#v1.11.4-(January-12,-2023)","page":"Release notes","title":"v1.11.4 (January 12, 2023)","text":"","category":"section"},{"location":"changelog/#Fixed-14","page":"Release notes","title":"Fixed","text":"","category":"section"},{"location":"changelog/","page":"Release notes","title":"Release notes","text":"Fixed a bug reading .lp files with an Integer section (#2078)","category":"page"},{"location":"changelog/#v1.11.3-(January-12,-2023)","page":"Release notes","title":"v1.11.3 (January 12, 2023)","text":"","category":"section"},{"location":"changelog/#Fixed-15","page":"Release notes","title":"Fixed","text":"","category":"section"},{"location":"changelog/","page":"Release notes","title":"Release notes","text":"Fixed a performance bug when deleting a vector of constraints (#2072)\nFixed a bug reading .lp files with terms like x -1 y (#2076)","category":"page"},{"location":"changelog/#Other-13","page":"Release notes","title":"Other","text":"","category":"section"},{"location":"changelog/","page":"Release notes","title":"Release notes","text":"Documented the two-argument method of optimize! (#2074)","category":"page"},{"location":"changelog/#v1.11.2-(January-2,-2023)","page":"Release notes","title":"v1.11.2 (January 2, 2023)","text":"","category":"section"},{"location":"changelog/#Fixed-16","page":"Release notes","title":"Fixed","text":"","category":"section"},{"location":"changelog/","page":"Release notes","title":"Release notes","text":"Fixed a bug reading .mof.json files with ConstraintName set for VariableIndex constraints (#2066)\nFixed a bug reading .mof.json files with nonlinear objectives and no constraints (#2068)","category":"page"},{"location":"changelog/#v1.11.1-(December-22,-2022)","page":"Release notes","title":"v1.11.1 (December 22, 2022)","text":"","category":"section"},{"location":"changelog/#Fixed-17","page":"Release notes","title":"Fixed","text":"","category":"section"},{"location":"changelog/","page":"Release notes","title":"Release notes","text":"Fixed a bug reading .mof.json files with integer coefficients for affine and quadratic functions (#2063)","category":"page"},{"location":"changelog/#v1.11.0-(December-2,-2022)","page":"Release notes","title":"v1.11.0 (December 2, 2022)","text":"","category":"section"},{"location":"changelog/#Added-10","page":"Release notes","title":"Added","text":"","category":"section"},{"location":"changelog/","page":"Release notes","title":"Release notes","text":"Added Utilities.PenaltyRelaxation and Utilities.ScalarPenaltyRelaxation (#1995)\nAdded Utilities.distance_to_set (#2048)\nAdded support for ConstraintPrimalStart and ConstraintDualStart in FileFormats.MOF (#2056)","category":"page"},{"location":"changelog/#Other-14","page":"Release notes","title":"Other","text":"","category":"section"},{"location":"changelog/","page":"Release notes","title":"Release notes","text":"Tidied these release notes (#2055)","category":"page"},{"location":"changelog/#v1.10.0-(November-22,-2022)","page":"Release notes","title":"v1.10.0 (November 22, 2022)","text":"","category":"section"},{"location":"changelog/#Added-11","page":"Release notes","title":"Added","text":"","category":"section"},{"location":"changelog/","page":"Release notes","title":"Release notes","text":"Added new methods set(::OptimizerWithAttributes, ::RawOptimizerAttribute, value) and get(::OptimizerWithAttributes, ::RawOptimizerAttribute) (#2049)\nAdded new methods Utilities.DoubleDicts.outer_keys and Utilities.DoubleDicts.nonempty_outer_keys (#2052)","category":"page"},{"location":"changelog/#Fixed-18","page":"Release notes","title":"Fixed","text":"","category":"section"},{"location":"changelog/","page":"Release notes","title":"Release notes","text":"Fixed Bridges.Objective.SlackBridge when the objective function is complex-valued (#2036) (#2038)\nFixed docstring of Test.runtests to clarify the warn_unsupported argument (#2037)\nFixed reading of free variables in FileFormats.LP (#2044)\nFixed numerous edge cases reading files from QPLIB using FileFormats.LP (#2042) (#2044)\nFixed situations in which x^y returns a complex value in Nonlinear (#2050)","category":"page"},{"location":"changelog/#Other-15","page":"Release notes","title":"Other","text":"","category":"section"},{"location":"changelog/","page":"Release notes","title":"Release notes","text":"Improved the error message thrown when a user-defined nonlinear function does not accept splatted input (#2032)\nRemoved specialized iterators for keys and values in Utilities.CleverDicts (#2051)","category":"page"},{"location":"changelog/#v1.9.0-(October-29,-2022)","page":"Release notes","title":"v1.9.0 (October 29, 2022)","text":"","category":"section"},{"location":"changelog/#Added-12","page":"Release notes","title":"Added","text":"","category":"section"},{"location":"changelog/","page":"Release notes","title":"Release notes","text":"Added default fallback for getting ListOfConstraintIndices and NumberOfConstraints when the constraint type is unsupported by the model (#2021)\nAdded support for min and max in nonlinear expressions (#2023)\nAdded support for Indicator{EqualTo{T}} constraints in FileFormats.MPS (#2022)\nAdded default fallback for write_to_file and read_from_file (#2029)","category":"page"},{"location":"changelog/#Fixed-19","page":"Release notes","title":"Fixed","text":"","category":"section"},{"location":"changelog/","page":"Release notes","title":"Release notes","text":"Fixed Constraint.ZeroOneBridge by adding new bounds as affine constraints instead of variable bounds (#1879)\nFixed reading free rows in FileFormats.MPS files (#2009)\nFixed parsing of OBJSENSE blocks in FileFormats.MPS files (#2016) (#2019)\nFixed the parsing of deeply nested nonlinear expressions by removing the use of recursion (#2020)\nFixed the requirements check in Test.test_constrainnt_get_ConstraintIndex (#2024)","category":"page"},{"location":"changelog/#v1.8.2-(September-20,-2022)","page":"Release notes","title":"v1.8.2 (September 20, 2022)","text":"","category":"section"},{"location":"changelog/#Documentation","page":"Release notes","title":"Documentation","text":"","category":"section"},{"location":"changelog/","page":"Release notes","title":"Release notes","text":"Added vale as a documentation linter (#2002)\nImproved styling of code blocks in the PDF (#1999) (#2000)\nFixed a number of typos in the documentation (#2001) (#2003)","category":"page"},{"location":"changelog/#v1.8.1-(September-12,-2022)","page":"Release notes","title":"v1.8.1 (September 12, 2022)","text":"","category":"section"},{"location":"changelog/#Fixed-20","page":"Release notes","title":"Fixed","text":"","category":"section"},{"location":"changelog/","page":"Release notes","title":"Release notes","text":"Fixed a bug in supports(::AbstractBridgeOptimizer for constraint attributes (#1991) (#1992)","category":"page"},{"location":"changelog/#v1.8.0-(September-1,-2022)","page":"Release notes","title":"v1.8.0 (September 1, 2022)","text":"","category":"section"},{"location":"changelog/#Added-13","page":"Release notes","title":"Added","text":"","category":"section"},{"location":"changelog/","page":"Release notes","title":"Release notes","text":"Added new sets\nHyperRectangle (#1961)\nReified (#1955)\nAdded new bridges (#1955)\nBridges.Constraint.ReifiedAllDifferentToCountDistinctBridge\nBridges.Constraint.ReifiedCountDistinctToMILPBridge\nBridges.Constraint.SplitHyperRectangleBridge\nAdded support for atan(y, x) in Nonlinear (#1987)","category":"page"},{"location":"changelog/#Fixed-21","page":"Release notes","title":"Fixed","text":"","category":"section"},{"location":"changelog/","page":"Release notes","title":"Release notes","text":"Lazily construct expressions in Nonlinear so that expressions are updated when Nonlinear.Parameter values are updated (#1984)\nAllow NORM_LIMIT as a TerminationStatus for unbounded problems in Test (#1990)","category":"page"},{"location":"changelog/#v1.7.0-(August-16,-2022)","page":"Release notes","title":"v1.7.0 (August 16, 2022)","text":"","category":"section"},{"location":"changelog/#Added-14","page":"Release notes","title":"Added","text":"","category":"section"},{"location":"changelog/","page":"Release notes","title":"Release notes","text":"Added new sets\nHermitianPositiveSemidefiniteConeTriangle\nAdded new optimizer-independent options\nRelativeGapTolerance\nAbsoluteGapTolerance\nAdded new bridges\nBridges.Constraint.GeoMeanToPowerBridge\nBridges.Constraint.HermitianToSymmetricPSDBridge\nBridges.Constraint.IndicatorGreaterToLessThanBridge\nBridges.Constraint.IndicatorLessToGreaterThanBridge\nBridges.Constraint.SplitComplexZerosBridge\nBridges.Constraint.SplitComplexEqualToBridge\nBridges.Objective.QuadratizeBridge\nAdded support for generic number types in Utilities.loadfromstring!\nUpdated FileFormats.MOF to MathOptFormat v1.1, enabling support for constraint programming sets in the MOF file format\nAdded support in various FileFormats for\nindicator constraints in FileFormats.MPS\nquadratic constraints and an objective in FileFormats.LP\nquadratic constraints and an objective in FileFormats.MPS","category":"page"},{"location":"changelog/#Fixed-22","page":"Release notes","title":"Fixed","text":"","category":"section"},{"location":"changelog/","page":"Release notes","title":"Release notes","text":"Fixed some missing promotion rules","category":"page"},{"location":"changelog/#Other-16","page":"Release notes","title":"Other","text":"","category":"section"},{"location":"changelog/","page":"Release notes","title":"Release notes","text":"Improved the performance of Jacobian products in Nonlinear\nRemoved an un-needed copy in Utilities.modify_function\nVarious clean-ups in Bridges/bridge_optimizer.jl","category":"page"},{"location":"changelog/#v1.6.1-(July-23,-2022)","page":"Release notes","title":"v1.6.1 (July 23, 2022)","text":"","category":"section"},{"location":"changelog/#Fixed-23","page":"Release notes","title":"Fixed","text":"","category":"section"},{"location":"changelog/","page":"Release notes","title":"Release notes","text":"Added support for ExponentialCone in MatrixOfConstraints\nFix PSDSquare_3 test to reflect a previously fixed bug getting the ConstraintDual of a PositiveSemidefiniteConeSquare constraint","category":"page"},{"location":"changelog/#v1.6.0-(July-2,-2022)","page":"Release notes","title":"v1.6.0 (July 2, 2022)","text":"","category":"section"},{"location":"changelog/#Added-15","page":"Release notes","title":"Added","text":"","category":"section"},{"location":"changelog/","page":"Release notes","title":"Release notes","text":"Added Bridges.needs_final_touch and Bridges.final_touch\nAdded new bridges from constraint programming sets to mixed-integer linear programs:\nAllDifferentToCountDistinctBridge\nCountAtLeastToCountBelongsBridge\nCountBelongsToMILPBridge\nCountDistinctToMILPBridge\nCountGreaterThanToMILPBridge\nCircuitToMILPBridge","category":"page"},{"location":"changelog/#Fixed-24","page":"Release notes","title":"Fixed","text":"","category":"section"},{"location":"changelog/","page":"Release notes","title":"Release notes","text":"Relax an instance of ::Vector to ::AbstractVector in MOI.Nonlinear\nFix BinPackingToMILPBridge to respect variable bounds\nFix SemiToBinaryBridge to throw error if other bounds are set","category":"page"},{"location":"changelog/#v1.5.0-(June-27,-2022)","page":"Release notes","title":"v1.5.0 (June 27, 2022)","text":"","category":"section"},{"location":"changelog/#Added-16","page":"Release notes","title":"Added","text":"","category":"section"},{"location":"changelog/","page":"Release notes","title":"Release notes","text":"Added GetAttributeNotAllowed for solvers to indicate when getting an attribute encounters an error\nAdded Utilities.get_fallback support for ObjectiveValue and DualObjectiveValue\nAdded new bridges:\nRootDetConeSquare to RootDetConeTriangle\nLogDetConeSquare to LogDetConeTriangle\nBinPacking to a mixed-integer linear program\nTable to a mixed-integer linear program\nAdded Bridges.print_active_bridges to display the current optimal hyper-path in a Bridges.LazyBridgeOptimizer","category":"page"},{"location":"changelog/#Fixed-25","page":"Release notes","title":"Fixed","text":"","category":"section"},{"location":"changelog/","page":"Release notes","title":"Release notes","text":"Fixed ZeroOne tests with lower and upper bounds\nFixed error in FileFormats.LP when reading a malformed file\nFixed reading of nonlinear programs in FileFormats.MOF\nFixed bug in ConstraintDual when using SquareBridge","category":"page"},{"location":"changelog/#Other-17","page":"Release notes","title":"Other","text":"","category":"section"},{"location":"changelog/","page":"Release notes","title":"Release notes","text":"Improved documentation of nonlinear API\nDocumented duality convention for PositiveSemidefiniteConeSquare sets\nFixed typo in Bridges.Constraint.QuadToSOCBridge docstring","category":"page"},{"location":"changelog/#v1.4.0-(June-9,-2022)","page":"Release notes","title":"v1.4.0 (June 9, 2022)","text":"","category":"section"},{"location":"changelog/#Added-17","page":"Release notes","title":"Added","text":"","category":"section"},{"location":"changelog/","page":"Release notes","title":"Release notes","text":"Added a number of sets for constraint programming:\nAllDifferent\nBinPacking\nCircuit\nCountAtLeast\nCountBelongs\nCountDistinct\nCountGreaterThan\nCumulative\nPath\nTable\nAdded support for user-defined hessians in Nonlinear\nAdded Bridges.runtests to simplify the testing of bridge implementations","category":"page"},{"location":"changelog/#Fixed-26","page":"Release notes","title":"Fixed","text":"","category":"section"},{"location":"changelog/","page":"Release notes","title":"Release notes","text":"Fixed a bug in FileFormats.NL when writing univariate *","category":"page"},{"location":"changelog/#Other-18","page":"Release notes","title":"Other","text":"","category":"section"},{"location":"changelog/","page":"Release notes","title":"Release notes","text":"Began a large refactoring of the Bridges submodule, with greatly improved documentation.","category":"page"},{"location":"changelog/#v1.3.0-(May-27,-2022)","page":"Release notes","title":"v1.3.0 (May 27, 2022)","text":"","category":"section"},{"location":"changelog/#Added-18","page":"Release notes","title":"Added","text":"","category":"section"},{"location":"changelog/","page":"Release notes","title":"Release notes","text":"Add MOI.Nonlinear submodule. This is a large new submodule that has been refactored from code that was in JuMP. For now, it should be considered experimental.\nAdd FileFormats.NL.SolFileResults(::IO, ::Model)\nAdd FileFormats.NL.read!(::IO, ::Model)\nAdd MOI.modify that accepts a vector of modifications","category":"page"},{"location":"changelog/#Fixed-27","page":"Release notes","title":"Fixed","text":"","category":"section"},{"location":"changelog/","page":"Release notes","title":"Release notes","text":"Fixed a bug in Test which attempted to include non-.jl files\nFixed a bug in FileFormats for models with open interval constraints","category":"page"},{"location":"changelog/#Other-19","page":"Release notes","title":"Other","text":"","category":"section"},{"location":"changelog/","page":"Release notes","title":"Release notes","text":"Fixed a performance issue in Utilities.DoubleDict\nVarious minor improvements to the documentation","category":"page"},{"location":"changelog/#v1.2.0-(April-25,-2022)","page":"Release notes","title":"v1.2.0 (April 25, 2022)","text":"","category":"section"},{"location":"changelog/#Added-19","page":"Release notes","title":"Added","text":"","category":"section"},{"location":"changelog/","page":"Release notes","title":"Release notes","text":"Add support for the FORMAT_REW/.rew file format in FileFormats.","category":"page"},{"location":"changelog/#Fixed-28","page":"Release notes","title":"Fixed","text":"","category":"section"},{"location":"changelog/","page":"Release notes","title":"Release notes","text":"Fix bug handling of default variable bounds in FileFormats.LP\nFix FileFormats.MPS to not write OBJSENSE by default since this is only supported by some readers.","category":"page"},{"location":"changelog/#v1.1.2-(March-31,-2022)","page":"Release notes","title":"v1.1.2 (March 31, 2022)","text":"","category":"section"},{"location":"changelog/#Fixed-29","page":"Release notes","title":"Fixed","text":"","category":"section"},{"location":"changelog/","page":"Release notes","title":"Release notes","text":"Fix a range of bugs in FileFormats.LP\nFix reading of problem dimensions in FileFormats.SDPA","category":"page"},{"location":"changelog/#v1.1.1-(March-23,-2022)","page":"Release notes","title":"v1.1.1 (March 23, 2022)","text":"","category":"section"},{"location":"changelog/#Fixed-30","page":"Release notes","title":"Fixed","text":"","category":"section"},{"location":"changelog/","page":"Release notes","title":"Release notes","text":"Fix bug in test_model_UpperBoundAlreadySet\nFix bug in test_infeasible_ tests\nFix bug in test_objective_ObjectiveFunction_blank\nRelax restriction of MOI.AbstractOptimizer to MOI.ModelLike in Utilities.CachingOptimizer and instantiate.","category":"page"},{"location":"changelog/#New-tests","page":"Release notes","title":"New tests","text":"","category":"section"},{"location":"changelog/","page":"Release notes","title":"Release notes","text":"Add test_conic_empty_matrix that checks conic solvers support problems with no variables.","category":"page"},{"location":"changelog/#v1.1.0-(March-2,-2022)","page":"Release notes","title":"v1.1.0 (March 2, 2022)","text":"","category":"section"},{"location":"changelog/#Added-20","page":"Release notes","title":"Added","text":"","category":"section"},{"location":"changelog/","page":"Release notes","title":"Release notes","text":"Added MOI.Utilities.throw_unsupported(::UniversalFallback) for simplifying solver wrappers which copy from a UniversalFallback.","category":"page"},{"location":"changelog/#v1.0.2-(March-1,-2022)","page":"Release notes","title":"v1.0.2 (March 1, 2022)","text":"","category":"section"},{"location":"changelog/#Fixed-31","page":"Release notes","title":"Fixed","text":"","category":"section"},{"location":"changelog/","page":"Release notes","title":"Release notes","text":"Fixed a bug in the test_model_ScalarFunctionConstantNotZero test\nFixed the error type when an AbstractFunctionConversionBridge cannot get or set an attribute\nIdentified a correctness bug in RSOCtoPSDBridge. We now thrown an error instead of returning an incorrect result.","category":"page"},{"location":"changelog/#v1.0.1-(February-25,-2022)","page":"Release notes","title":"v1.0.1 (February 25, 2022)","text":"","category":"section"},{"location":"changelog/#Fixed-32","page":"Release notes","title":"Fixed","text":"","category":"section"},{"location":"changelog/","page":"Release notes","title":"Release notes","text":"Fixed a bug in which OptimizerAttributes were not copied in CachingOptimizer\nFixed a bug in which shift_constant did not promote mixed types of coefficients\nFixed a bug in which deleting a constraint of a bridged variable threw ErrorException instead of MOI.DeleteNotAllowed\nFixed a bug in which add_constraint in MatrixOfConstraints did not canonicalize the function\nFixed a bug when modifying scalar constants of a function containing a bridged variable\nFixed a bug in which final_touch was not always called with a CachingOptimizer","category":"page"},{"location":"changelog/#v1.0.0-(February-17,-2022)","page":"Release notes","title":"v1.0.0 (February 17, 2022)","text":"","category":"section"},{"location":"changelog/","page":"Release notes","title":"Release notes","text":"Although tagged as a breaking release, v1.0.0 is v0.10.9 with deprecations removed, similar to how Julia 1.0 was Julia 0.7 with deprecations removed.","category":"page"},{"location":"changelog/#Breaking","page":"Release notes","title":"Breaking","text":"","category":"section"},{"location":"changelog/","page":"Release notes","title":"Release notes","text":"Julia 1.6 is now the minimum supported version\nAll deprecations have been removed","category":"page"},{"location":"changelog/#Troubleshooting-problems-when-updating","page":"Release notes","title":"Troubleshooting problems when updating","text":"","category":"section"},{"location":"changelog/","page":"Release notes","title":"Release notes","text":"If you experience problems when updating, you are likely using previously deprecated features. (By default, Julia does not warn when you use deprecated features.)","category":"page"},{"location":"changelog/","page":"Release notes","title":"Release notes","text":"To find the deprecated features you are using, start Julia with --depwarn=yes:","category":"page"},{"location":"changelog/","page":"Release notes","title":"Release notes","text":"$ julia --depwarn=yes","category":"page"},{"location":"changelog/","page":"Release notes","title":"Release notes","text":"Then install MathOptInterface v0.10.9:","category":"page"},{"location":"changelog/","page":"Release notes","title":"Release notes","text":"julia> using Pkg\njulia> pkg\"add MathOptInterface@0.10\"","category":"page"},{"location":"changelog/","page":"Release notes","title":"Release notes","text":"And then run your code. Apply any suggestions, or search the release notes below for advice on updating a specific deprecated feature.","category":"page"},{"location":"changelog/#v0.10.9-(February-16,-2022)","page":"Release notes","title":"v0.10.9 (February 16, 2022)","text":"","category":"section"},{"location":"changelog/#Added-21","page":"Release notes","title":"Added","text":"","category":"section"},{"location":"changelog/","page":"Release notes","title":"Release notes","text":"Added MOI.Utilities.FreeVariables as a new VariablesConstrainer for conic solvers\nAdded MOI.default_cache for specifying the model used in CachingOptimizer","category":"page"},{"location":"changelog/#Fixed-33","page":"Release notes","title":"Fixed","text":"","category":"section"},{"location":"changelog/","page":"Release notes","title":"Release notes","text":"Fixed LaTeX printing of MOI.Interval sets","category":"page"},{"location":"changelog/#Other-20","page":"Release notes","title":"Other","text":"","category":"section"},{"location":"changelog/","page":"Release notes","title":"Release notes","text":"Added Aqua.jl as a CI check, and fixed suggested issues\nThe constructors of GeoMeanBridge, StructOfConstraints, and CachingOptimizer were changed from outer to inner constructors. This change is technically breaking, but does not impact users who followed the documented API.","category":"page"},{"location":"changelog/#v0.10.8-(February-3,-2022)","page":"Release notes","title":"v0.10.8 (February 3, 2022)","text":"","category":"section"},{"location":"changelog/#Added-22","page":"Release notes","title":"Added","text":"","category":"section"},{"location":"changelog/","page":"Release notes","title":"Release notes","text":"Added a Base.read! for FileFormats.LP.","category":"page"},{"location":"changelog/#Fixed-34","page":"Release notes","title":"Fixed","text":"","category":"section"},{"location":"changelog/","page":"Release notes","title":"Release notes","text":"Fixed a bug in MutableSparseMatrix\nFixed a bug when calling operate!(vcat, ...) with Number arguments\nRemoved unintended export of deprecated symbols\nFixed a bug with PowerCone and DualPowerCone in MatrixOfConstraints.","category":"page"},{"location":"changelog/#v0.10.7-(January-5,-2022)","page":"Release notes","title":"v0.10.7 (January 5, 2022)","text":"","category":"section"},{"location":"changelog/#Added-23","page":"Release notes","title":"Added","text":"","category":"section"},{"location":"changelog/","page":"Release notes","title":"Release notes","text":"Added test for modifying the constant vector in a VectorAffineFunction-in-Zeros constraint.","category":"page"},{"location":"changelog/#Fixed-35","page":"Release notes","title":"Fixed","text":"","category":"section"},{"location":"changelog/","page":"Release notes","title":"Release notes","text":"Fixed the order in which sets are added to a LazyBridgeOptimizer. Compared to v0.10.6, this may result in bridged models being created with a different number (and order) of variables and constraints. However, it was necessary to fix cases which were previously rejected as unsupported, even though there was a valid bridge transformation.\nFixed an error message in FileFormats.CBF\nFixed comparison in test_linear_integration_Interval\nFixed errors for ConstraintPrimal in a CachingOptimizer\nFixed printing of models with non-Float64 coefficients.","category":"page"},{"location":"changelog/#Other-21","page":"Release notes","title":"Other","text":"","category":"section"},{"location":"changelog/","page":"Release notes","title":"Release notes","text":"Various improvements to reduce time-to-first-solve latency\nImproved error message when an optimizer does not support compute_conflict!","category":"page"},{"location":"changelog/#v0.10.6-(November-30,-2021)","page":"Release notes","title":"v0.10.6 (November 30, 2021)","text":"","category":"section"},{"location":"changelog/#Added-24","page":"Release notes","title":"Added","text":"","category":"section"},{"location":"changelog/","page":"Release notes","title":"Release notes","text":"Added new documentation and tests for infeasibility certificates\nAdded a version control system for the tests in MOI.Test.runtests. Pass exclude_tests_after = v\"0.10.5\" to run tests added in v0.10.5 and earlier.\nMOI.Test.runtests now supports generic number types. To specify the number type T, pass MOI.Test.Config(T).\nAdded infeasible_status to MOI.Test.Config for solvers which return LOCALLY_INFEASIBLE\nCachingOptimizers now use a fallback for ConstraintPrimal. This should enable solvers using a CachingOptimizer to pass tests requiring ConstraintPrimal.","category":"page"},{"location":"changelog/#Fixed-36","page":"Release notes","title":"Fixed","text":"","category":"section"},{"location":"changelog/","page":"Release notes","title":"Release notes","text":"Fixed a StackOverflow bug in copy_to\nFixed error thrown when nonconvex quadratic constraints cannot be bridged\nFixed a bug in copy_to for FileFormats.NL.Model\nFixed a bug in FileFormats.NL when printing large integers\nRemove a common test failure for LowerBoundAlreadySet tests\nUtilities.num_rows is now exported\nRemove parts of failing test_model_copy_to_xxx tests due to bridges","category":"page"},{"location":"changelog/#v0.10.5-(November-7,-2021)","page":"Release notes","title":"v0.10.5 (November 7, 2021)","text":"","category":"section"},{"location":"changelog/#Fixed-37","page":"Release notes","title":"Fixed","text":"","category":"section"},{"location":"changelog/","page":"Release notes","title":"Release notes","text":"Fixed getter in UniversalFallback\nFixed test_solve_conflict_zeroone_ii","category":"page"},{"location":"changelog/#Other-22","page":"Release notes","title":"Other","text":"","category":"section"},{"location":"changelog/","page":"Release notes","title":"Release notes","text":"Make normalize_and_add_constraint more flexible\nUpdate paper BibTeX","category":"page"},{"location":"changelog/#v0.10.4-(October-26,-2021)","page":"Release notes","title":"v0.10.4 (October 26, 2021)","text":"","category":"section"},{"location":"changelog/#Added-25","page":"Release notes","title":"Added","text":"","category":"section"},{"location":"changelog/","page":"Release notes","title":"Release notes","text":"Add SolverVersion attribute\nAdd new tests:\ntest_solve_conflict_zeroone_ii\ntest_nonlinear_objective\nUtilities.VariablesContainer now supports ConstraintFunction and ConstraintSet\nThe documentation is now available as a PDF","category":"page"},{"location":"changelog/#Other-23","page":"Release notes","title":"Other","text":"","category":"section"},{"location":"changelog/","page":"Release notes","title":"Release notes","text":"Update to MutableArithmetics 0.3\nVarious improvements to the documentation","category":"page"},{"location":"changelog/#v0.10.3-(September-18,-2021)","page":"Release notes","title":"v0.10.3 (September 18, 2021)","text":"","category":"section"},{"location":"changelog/#Fixed-38","page":"Release notes","title":"Fixed","text":"","category":"section"},{"location":"changelog/","page":"Release notes","title":"Release notes","text":"Fixed bug which prevented callbacks from working through a CachingOptimizer\nFixed bug in Test submodule","category":"page"},{"location":"changelog/#v0.10.2-(September-16,-2021)","page":"Release notes","title":"v0.10.2 (September 16, 2021)","text":"","category":"section"},{"location":"changelog/","page":"Release notes","title":"Release notes","text":"Updated MathOptFormat to v1.0\nUpdated JSONSchema to v1.0\nAdded Utilities.set_with_dimension\nAdded two-argument optimize!(::AbstractOptimizer, ::ModelLike)\nThe experimental feature copy_to_and_optimize! has been removed\nDet bridges now support getting ConstraintFunction and ConstraintSet\nVarious minor bug fixes identified by improved testing","category":"page"},{"location":"changelog/#v0.10.1-(September-8,-2021)","page":"Release notes","title":"v0.10.1 (September 8, 2021)","text":"","category":"section"},{"location":"changelog/","page":"Release notes","title":"Release notes","text":"Various fixes to MOI.Test","category":"page"},{"location":"changelog/#v0.10.0-(September-6,-2021)","page":"Release notes","title":"v0.10.0 (September 6, 2021)","text":"","category":"section"},{"location":"changelog/","page":"Release notes","title":"Release notes","text":"MOI v0.10 is a significant breaking release. There are a large number of user-visible breaking changes and code refactors, as well as a substantial number of new features.","category":"page"},{"location":"changelog/#Breaking-in-MOI","page":"Release notes","title":"Breaking in MOI","text":"","category":"section"},{"location":"changelog/","page":"Release notes","title":"Release notes","text":"SingleVariable has been removed; use VariableIndex instead\nSingleVariableConstraintNameError has been renamed to VariableIndexConstraintNameError\nSettingSingleVariableFunctionNotAllowed has been renamed to SettingVariableIndexFunctionNotAllowed\nVariableIndex constraints should not support ConstraintName\nVariableIndex constraints should not support ConstraintBasisStatus; implement VariableBasisStatus instead\nListOfConstraints has been renamed to ListOfConstraintTypesPresent\nListOfConstraintTypesPresent should now return Tuple{Type,Type} instead of Tuple{DataType,DataType}\nSolveTime has been renamed to SolveTimeSec\nIndicatorSet has been renamed to Indicator\nRawParameter has been renamed to RawOptimizerAttribute and now takes String instead of Any as the only argument\nThe .N field in result attributes has been renamed to .result_index\nThe .variable_index field in ScalarAffineTerm has been renamed to .variable\nThe .variable_index_1 field in ScalarQuadraticTerm has been renamed to .variable_1\nThe .variable_index_2 field in ScalarQuadraticTerm has been renamed to .variable_2\nThe order of affine_terms and quadratic_terms in ScalarQuadraticFunction and VectorQuadraticFunction have been reversed. Both functions now accept quadratic, affine, and constant terms in that order.\nThe index_value function has been removed. Use .value instead.\nisapprox has been removed for SOS1 and SOS2.\nThe dimension argument to Complements(dimension::Int) should now be the length of the corresponding function, instead of half the length. An ArgumentError is thrown if dimension is not even.\ncopy_to no longer takes keyword arguments:\ncopy_names: now copy names if they are supported by the destination solver\nfilter_constraints: use Utilities.ModelFilter instead\nwarn_attributes: never warn about optimizer attributes","category":"page"},{"location":"changelog/#Breaking-in-Bridges","page":"Release notes","title":"Breaking in Bridges","text":"","category":"section"},{"location":"changelog/","page":"Release notes","title":"Release notes","text":"Constraint.RSOCBridge has been renamed to Constraint.RSOCtoSOCBridge\nConstraint.SOCRBridge has been renamed to Constraint.SOCtoRSOCBridge\nBridges now return vectors that can be modified by the user. Previously, some bridges returned views instead of copies.\nBridges.IndexInVector has been unified into a single type. Previously, there was a different type for each submodule within Bridges\nThe signature of indicator bridges has been fixed. Use MOI.Bridges.Constraint.IndicatortoSOS1{Float64}(model).","category":"page"},{"location":"changelog/#Breaking-in-FileFormats","page":"Release notes","title":"Breaking in FileFormats","text":"","category":"section"},{"location":"changelog/","page":"Release notes","title":"Release notes","text":"FileFormats.MOF.Model no longer accepts validate argument. Use the JSONSchema package to validate the MOF file. See the documentation for more information.","category":"page"},{"location":"changelog/#Breaking-in-Utilities","page":"Release notes","title":"Breaking in Utilities","text":"","category":"section"},{"location":"changelog/","page":"Release notes","title":"Release notes","text":"The datastructure of Utilities.Model (and models created with Utilities.@model) has been significantly refactored in a breaking way. This includes the way that objective functions and variable-related information is stored.\nUtilities.supports_default_copy has been renamed to supports_incremental_interface\nUtilities.automatic_copy_to has been renamed to Utilities.default_copy_to\nThe allocate-load API has been removed\nCachingOptimizers are now initialized as EMPTY_OPTIMIZER instead of ATTACHED_OPTIMIZER. If your code relies on the optimizer being attached, call MOIU.attach_optimizer(model) after creation.\nThe field names of Utilities.IndexMap have been renamed to var_map and con_map. Accessing these fields directly is considered a private detail that may change. Use the public getindex and setindex! API instead.\nThe size argument to Utilities.CleverDicts.CleverDict(::Integer) has been removed.\nThe size argument to Utilities.IndexMap(::Integer) has been removed.\nUtilities.DoubleDicts have been significantly refactored. Consult the source code for details.\nUtilities.test_models_equal has been moved to MOI.Test","category":"page"},{"location":"changelog/#Breaking-in-Test","page":"Release notes","title":"Breaking in Test","text":"","category":"section"},{"location":"changelog/","page":"Release notes","title":"Release notes","text":"MOI.Test has been renamed to MOI.DeprecatedTest\nAn entirely new MOI.Test submodule has been written. See the documentation for details. The new MOI.Test submodule may find many bugs in the implementations of existing solvers that were previously untested.","category":"page"},{"location":"changelog/#Other-changes:","page":"Release notes","title":"Other changes:","text":"","category":"section"},{"location":"changelog/","page":"Release notes","title":"Release notes","text":"attribute_value_type has been added\ncopy_to_and_optimize! has been added\nVariableBasisStatus has been added\nprint(model) now prints a human-readable description of the model\nVarious improvements to the FileFormats submodule\nFileFormats.CBF was refactored and received bugfixes\nSupport for MathOptFormat v0.6 was added in FileFormats.MOF\nFileFormats.MPS has had bugfixes and support for more features such as OBJSENSE and objective constants.\nFileFormats.NL has been added to support nonlinear files\nImproved type inference throughout to reduce latency","category":"page"},{"location":"changelog/#Updating","page":"Release notes","title":"Updating","text":"","category":"section"},{"location":"changelog/","page":"Release notes","title":"Release notes","text":"A helpful script when updating is:","category":"page"},{"location":"changelog/","page":"Release notes","title":"Release notes","text":"for (root, dirs, files) in walkdir(\".\")\n for file in files\n if !endswith(file, \".jl\")\n continue\n end\n path = joinpath(root, file)\n s = read(path, String)\n for pair in [\n \".variable_index\" => \".variable\",\n \"RawParameter\" => \"RawOptimizerAttribute\",\n \"ListOfConstraints\" => \"ListOfConstraintTypesPresent\",\n \"TestConfig\" => \"Config\",\n \"attr.N\" => \"attr.result_index\",\n \"SolveTime\" => \"SolveTimeSec\",\n \"DataType\" => \"Type\",\n \"Utilities.supports_default_copy_to\" =>\n \"supports_incremental_interface\",\n \"SingleVariableConstraintNameError\" =>\n \"VariableIndexConstraintNameError\",\n \"SettingSingleVariableFunctionNotAllowed\" =>\n \"SettingVariableIndexFunctionNotAllowed\",\n \"automatic_copy_to\" => \"default_copy_to\",\n ]\n s = replace(s, pair)\n end\n write(path, s)\n end\nend","category":"page"},{"location":"changelog/#v0.9.22-(May-22,-2021)","page":"Release notes","title":"v0.9.22 (May 22, 2021)","text":"","category":"section"},{"location":"changelog/","page":"Release notes","title":"Release notes","text":"This release contains backports from the ongoing development of the v0.10 release.","category":"page"},{"location":"changelog/","page":"Release notes","title":"Release notes","text":"Improved type inference in Utilities, Bridges and FileFormats submodules to reduce latency.\nImproved performance of Utilities.is_canonical.\nFixed Utilities.pass_nonvariable_constraints with bridged variables.\nFixed performance regression of Utilities.Model.\nFixed ordering of objective setting in parser.","category":"page"},{"location":"changelog/#v0.9.21-(April-23,-2021)","page":"Release notes","title":"v0.9.21 (April 23, 2021)","text":"","category":"section"},{"location":"changelog/","page":"Release notes","title":"Release notes","text":"Added supports_shift_constant.\nImprove performance of bridging quadratic constraints.\nAdd precompilation statements.\nLarge improvements to the documentation.\nFix a variety of inference issues, benefiting precompilation and reducing initial latency.\nRawParameters are now ignored when resetting a CachingOptimizer. Previously, changing the underlying optimizer after RawParameters were set would throw an error.\nUtilities.AbstractModel is being refactored. This may break users interacting with private fields of a model generated using @model.","category":"page"},{"location":"changelog/#v0.9.20-(February-20,-2021)","page":"Release notes","title":"v0.9.20 (February 20, 2021)","text":"","category":"section"},{"location":"changelog/","page":"Release notes","title":"Release notes","text":"Improved performance of Utilities.ScalarFunctionIterator\nAdded support for compute_conflict to MOI layers\nAdded test with zero off-diagonal quadratic term in objective\nFixed double deletion of nested bridged SingleVariable/VectorOfVariables constraints\nFixed modification of un-set objective\nFixed function modification with duplicate terms\nMade unit tests abort without failing if the problem class is not supported\nFormatted code with JuliaFormatter\nClarified BasisStatusCode's docstring","category":"page"},{"location":"changelog/#v0.9.19-(December-1,-2020)","page":"Release notes","title":"v0.9.19 (December 1, 2020)","text":"","category":"section"},{"location":"changelog/","page":"Release notes","title":"Release notes","text":"Added CallbackNodeStatus attribute\nAdded bridge from GreaterThan or LessThan to Interval\nAdded tests for infeasibility certificates and double optimize\nFixed support for Julia v1.6\nRe-organized MOI docs and added documentation for adding a test","category":"page"},{"location":"changelog/#v0.9.18-(November-3,-2020)","page":"Release notes","title":"v0.9.18 (November 3, 2020)","text":"","category":"section"},{"location":"changelog/","page":"Release notes","title":"Release notes","text":"Various improvements for working with complex numbers\nAdded GeoMeantoRelEntrBridge to bridge a GeometricMeanCone constraint to a relative entropy constraint","category":"page"},{"location":"changelog/#v0.9.17-(September-21,-2020)","page":"Release notes","title":"v0.9.17 (September 21, 2020)","text":"","category":"section"},{"location":"changelog/","page":"Release notes","title":"Release notes","text":"Fixed CleverDict with variable of negative index value\nImplement supports_add_constrained_variable for MockOptimizer","category":"page"},{"location":"changelog/#v0.9.16-(September-17,-2020)","page":"Release notes","title":"v0.9.16 (September 17, 2020)","text":"","category":"section"},{"location":"changelog/","page":"Release notes","title":"Release notes","text":"Various fixes:\n32-bit support\nCleverDict with abstract value type\nChecks in test suite","category":"page"},{"location":"changelog/#v0.9.15-(September-14,-2020)","page":"Release notes","title":"v0.9.15 (September 14, 2020)","text":"","category":"section"},{"location":"changelog/","page":"Release notes","title":"Release notes","text":"Bridges improvements:\n(R)SOCtoNonConvexQuad bridge\nZeroOne bridge\nUse supports_add_constrained_variable in LazyBridgeOptimizer\nExposed VariableBridgeCost and ConstraintBridgeCost attributes\nPrioritize constraining variables on creation according to these costs\nRefactor bridge debugging\nLarge performance improvements across all submodules\nLots of documentation improvements\nFileFormats improvements:\nUpdate MathOptFormat to v0.5\nFix supported objectives in FileFormats\nTesting improvements:\nAdd name option for basic_constraint_test\nBug fixes and missing methods\nAdd length for iterators\nFix bug with duplicate terms\nFix order of LinearOfConstraintIndices","category":"page"},{"location":"changelog/#v0.9.14-(May-30,-2020)","page":"Release notes","title":"v0.9.14 (May 30, 2020)","text":"","category":"section"},{"location":"changelog/","page":"Release notes","title":"Release notes","text":"Add a solver-independent interface for accessing the set of conflicting constraints an Irreducible Inconsistent Subsystem (#1056).\nBump JSONSchema dependency from v0.2 to v0.3 (#1090).\nDocumentation improvements:\nFix typos (#1054, #1060, #1061, #1064, #1069, #1070).\nRemove the outdated recommendation for a package implementing MOI for a solver XXX to be called MathOptInterfaceXXX (#1087).\nUtilities improvements:\nFix is_canonical for quadratic functions (#1081, #1089).\nImplement add_constrained_variable[s] for CachingOptimizer so that it is added as constrained variables to the underlying optimizer (#1084).\nAdd support for custom objective functions for UniversalFallback (#1086).\nDeterministic ordering of constraints in UniversalFallback (#1088).\nTesting improvements:\nAdd NormOneCone/NormInfinityCone tests (#1045).\nBridges improvements:\nAdd bridges from Semiinteger and Semicontinuous (#1059).\nImplement getting ConstraintSet for Variable.FlipSignBridge (#1066).\nFix setting ConstraintFunction for Constraint.ScalarizeBridge (#1093).\nFix NormOne/NormInf bridges with nonzero constants (#1045).\nFix StackOverflow in debug (#1063).\nFileFormats improvements:\n[SDPA] Implement the extension for integer variables (#1079).\n[SDPA] Ignore comments after m and nblocks and detect dat-s extension (#1077).\n[SDPA] No scaling of off-diagonal coefficient (#1076).\n[SDPA] Add missing negation of constant (#1075).","category":"page"},{"location":"changelog/#v0.9.13-(March-24,-2020)","page":"Release notes","title":"v0.9.13 (March 24, 2020)","text":"","category":"section"},{"location":"changelog/","page":"Release notes","title":"Release notes","text":"Added tests for Semicontinuous and Semiinteger variables (#1033).\nAdded tests for using ExprGraphs from NLP evaluators (#1043).\nUpdate version compatibilities of dependencies (#1034, #1051, #1052).\nFixed typos in documentation (#1044).","category":"page"},{"location":"changelog/#v0.9.12-(February-28,-2020)","page":"Release notes","title":"v0.9.12 (February 28, 2020)","text":"","category":"section"},{"location":"changelog/","page":"Release notes","title":"Release notes","text":"Fixed writing NLPBlock in MathOptFormat (#1037).\nFixed MockOptimizer for result attributes with non-one result index (#1039).\nUpdated test template with instantiate (#1032).","category":"page"},{"location":"changelog/#v0.9.11-(February-21,-2020)","page":"Release notes","title":"v0.9.11 (February 21, 2020)","text":"","category":"section"},{"location":"changelog/","page":"Release notes","title":"Release notes","text":"Add an option for the model created by Utilities.@model to be a subtype of AbstractOptimizer (#1031).\nDescribed dual cone in docstrings of GeoMeanCone and RelativeEntropyCone (#1018, #1028).\nFixed typos in documentation (#1022, #1024).\nFixed warning of unsupported attribute (#1027).\nAdded more rootdet/logdet conic tests (#1026).\nImplemented ConstraintDual for Constraint.GeoMeanBridge, Constraint.RootDetBridge and Constraint.LogDetBridge and test duals in tests with GeoMeanCone and RootDetConeTriangle and LogDetConeTriangle cones (#1025, #1026).","category":"page"},{"location":"changelog/#v0.9.10-(January-31,-2020)","page":"Release notes","title":"v0.9.10 (January 31, 2020)","text":"","category":"section"},{"location":"changelog/","page":"Release notes","title":"Release notes","text":"Added OptimizerWithAttributes grouping an optimizer constructor and a list of optimizer attributes (#1008).\nAdded RelativeEntropyCone with corresponding bridge into exponential cone constraints (#993).\nAdded NormSpectralCone and NormNuclearCone with corresponding bridges into positive semidefinite constraints (#976).\nAdded supports_constrained_variable(s) (#1004).\nAdded dual_set_type (#1002).\nAdded tests for vector specialized version of delete (#989, #1011).\nAdded PSD3 test (#1007).\nClarified dual solution of Tests.pow1v and Tests.pow1f (#1013).\nAdded support for EqualTo and Zero in Bridges.Constraint.SplitIntervalBridge (#1005).\nFixed Utilities.vectorize for empty vector (#1003).\nFixed free variables in LP writer (#1006).","category":"page"},{"location":"changelog/#v0.9.9-(December-29,-2019)","page":"Release notes","title":"v0.9.9 (December 29, 2019)","text":"","category":"section"},{"location":"changelog/","page":"Release notes","title":"Release notes","text":"Incorporated MathOptFormat.jl as the FileFormats submodule. FileFormats provides readers and writers for a number of standard file formats and MOF, a file format specialized for MOI (#969).\nImproved performance of deletion of vector of variables in MOI.Utilities.Model (#983).\nUpdated to MutableArithmetics v0.2 (#981).\nAdded MutableArithmetics.promote_operation allocation tests (#975).\nFixed inference issue on Julia v1.1 (#982).","category":"page"},{"location":"changelog/#v0.9.8-(December-19,-2019)","page":"Release notes","title":"v0.9.8 (December 19, 2019)","text":"","category":"section"},{"location":"changelog/","page":"Release notes","title":"Release notes","text":"Implemented MutableArithmetics API (#924).\nFixed callbacks with CachingOptimizer (#959).\nFixed MOI.dimension for MOI.Complements (#948).\nAdded fallback for add_variables (#972).\nAdded is_diagonal_vectorized_index utility (#965).\nImproved linear constraints display in manual (#963, #964).\nBridges improvements:\nAdded IndicatorSet to SOS1 bridge (#877).\nAdded support for starting values for Variable.VectorizeBridge (#944).\nFixed MOI.add_constraints with non-bridged variable constraint on bridged variable (#951).\nFixed corner cases and docstring of GeoMeanBridge (#961, #962, #966).\nFixed choice between variable or constraint bridges for constrained variables (#973).\nImprove performance of bridge shortest path (#945, #946, #956).\nAdded docstring for test_delete_bridge (#954).\nAdded Variable bridge tests (#952).","category":"page"},{"location":"changelog/#v0.9.7-(October-30,-2019)","page":"Release notes","title":"v0.9.7 (October 30, 2019)","text":"","category":"section"},{"location":"changelog/","page":"Release notes","title":"Release notes","text":"Implemented _result_index_field for NLPBlockDual (#934).\nFixed copy of model with starting values for vector constraints (#941).\nBridges improvements:\nImproved performance of add_bridge and added has_bridge (#935).\nAdded AbstractSetMapBridge for bridges between sets S1, S2 such that there is a linear map A such that A*S1 = S2 (#933).\nAdded support for starting values for FlipSignBridge, VectorizeBridge, ScalarizeBridge, SlackBridge, SplitIntervalBridge, RSOCBridge, SOCRBridge NormInfinityBridge, SOCtoPSDBridge and RSOCtoPSDBridge (#933, #936, #937, #938, #939).","category":"page"},{"location":"changelog/#v0.9.6-(October-25,-2019)","page":"Release notes","title":"v0.9.6 (October 25, 2019)","text":"","category":"section"},{"location":"changelog/","page":"Release notes","title":"Release notes","text":"Added complementarity constraints (#913).\nAllowed ModelLike objects as value of attributes (#928).\nTesting improvements:\nAdded dual_objective_value option to MOI.Test.TestConfig (#922).\nAdded InvalidIndex tests in basic_constraint_tests (#921).\nAdded tests for the constant term in indicator constraint (#929).\nBridges improvements:\nAdded support for starting values for Functionize bridges (#923).\nAdded variable indices context to variable bridges (#920).\nFixed a typo in printing o debug_supports (#927).","category":"page"},{"location":"changelog/#v0.9.5-(October-9,-2019)","page":"Release notes","title":"v0.9.5 (October 9, 2019)","text":"","category":"section"},{"location":"changelog/","page":"Release notes","title":"Release notes","text":"Clarified PrimalStatus/DualStatus to be NO_SOLUTION if result_index is out of bounds (#912).\nAdded tolerance for checks and use ResultCount + 1 for the result_index in MOI.Test.solve_result_status (#910, #917).\nUse 0.5 instead of 2.0 for power in PowerCone in basic_constraint_test (#916).\nBridges improvements:\nAdded debug utilities for unsupported variable/constraint/objective (#861).\nFixed deletion of variables in bridged VectorOfVariables constraints (#909).\nFixed result_index with objective bridges (#911).","category":"page"},{"location":"changelog/#v0.9.4-(October-2,-2019)","page":"Release notes","title":"v0.9.4 (October 2, 2019)","text":"","category":"section"},{"location":"changelog/","page":"Release notes","title":"Release notes","text":"Added solver-independent MIP callbacks (#782).\nImplements submit for Utilities.CachingOptimizer and Bridges.AbstractBridgeOptimizer (#906).\nAdded tests for result count of solution attributes (#901, #904).\nAdded NumberOfThreads attribute (#892).\nAdded Utilities.get_bounds to get the bounds on a variable (#890).\nAdded a note on duplicate coefficients in documentation (#581).\nAdded result index in ConstraintBasisStatus (#898).\nAdded extension dictionary to Utilities.Model (#884, #895).\nFixed deletion of constrained variables for CachingOptimizer (#905).\nImplemented Utilities.shift_constraint for Test.UnknownScalarSet (#896).\nBridges improvements:\nAdded Variable.RSOCtoSOCBridge (#907).\nImplemented MOI.get for ConstraintFunction/ConstraintSet for Bridges.Constraint.SquareBridge (#899).","category":"page"},{"location":"changelog/#v0.9.3-(September-20,-2019)","page":"Release notes","title":"v0.9.3 (September 20, 2019)","text":"","category":"section"},{"location":"changelog/","page":"Release notes","title":"Release notes","text":"Fixed ambiguity detected in Julia v1.3 (#891, #893).\nFixed missing sets from ListOfSupportedConstraints (#880).\nFixed copy of VectorOfVariables constraints with duplicate indices (#886).\nAdded extension dictionary to MOIU.Model (#884).\nImplemented MOI.get for function and set for GeoMeanBridge (#888).\nUpdated documentation for SingleVariable indices and bridges (#885).\nTesting improvements:\nAdded more comprehensive tests for names (#882).\nAdded tests for SingleVariable duals (#883).\nAdded tests for DualExponentialCone and DualPowerCone (#873).\nImprovements for arbitrary coefficient type:\nFixed == for sets with mutable fields (#887).\nRemoved some Float64 assumptions in bridges (#878).\nAutomatic selection of Constraint.[Scalar|Vector]FunctionizeBridge (#889).","category":"page"},{"location":"changelog/#v0.9.2-(September-5,-2019)","page":"Release notes","title":"v0.9.2 (September 5, 2019)","text":"","category":"section"},{"location":"changelog/","page":"Release notes","title":"Release notes","text":"Implemented model printing for MOI.ModelLike and specialized it for models defined in MOI (864).\nGeneralized contlinear tests for arbitrary coefficient type (#855).\nFixed supports_constraint for Semiinteger and Semicontinuous and supports for ObjectiveFunction (#859).\nFixed Allocate-Load copy for single variable constraints (#856).\nBridges improvements:\nAdd objective bridges (#789).\nFixed Variable.RSOCtoPSDBridge for dimension 2 (#869).\nAdded Variable.SOCtoRSOCBridge (#865).\nAdded Constraint.SOCRBridge and disable MOI.Bridges.Constraint.SOCtoPSDBridge (#751).\nFixed added_constraint_types for Contraint.LogDetBridge and Constraint.RootDetBridge (#870).","category":"page"},{"location":"changelog/#v0.9.1-(August-22,-2019)","page":"Release notes","title":"v0.9.1 (August 22, 2019)","text":"","category":"section"},{"location":"changelog/","page":"Release notes","title":"Release notes","text":"Fix support for Julia v1.2 (#834).\nL1 and L∞ norm epigraph cones and corresponding bridges to LP were added (#818).\nAdded tests to MOI.Test.nametest (#833).\nFix MOI.Test.soc3test for solvers not supporting infeasibility certificates (#839).\nImplements operate for operators * and / between vector function and constant (#837).\nImplements show for MOI.Utilities.IndexMap (#847).\nFix corner cases for mapping of variables in MOI.Utilities.CachingOptimizer and substitution of variables in MOI.Bridges.AbstractBridgeOptimizer (#848).\nFix transformation of constant terms for MOI.Bridges.Constraint.SOCtoPSDBridge and MOI.Bridges.Constraint.RSOCtoPSDBridge (#840).","category":"page"},{"location":"changelog/#v0.9.0-(August-13,-2019)","page":"Release notes","title":"v0.9.0 (August 13, 2019)","text":"","category":"section"},{"location":"changelog/","page":"Release notes","title":"Release notes","text":"Support for Julia v0.6 and v0.7 was dropped (#714, #717).\nA MOI.Utilities.Model implementation of ModelLike, this should replace most use cases of MOI.Utilities.@model (#781).\nadd_constrained_variable and add_constrained_variables were added (#759).\nSupport for indicator constraints was added (#709, #712).\nDualObjectiveValue attribute was added (#473).\nRawParameter attribute was added (#733).\nA dual_set function was added (#804).\nA Benchmarks submodule was added to facilitate solver benchmarking (#769).\nA submit function was added, this may for instance allow the user to submit solutions or cuts to the solver from a callback (#775).\nThe field of ObjectiveValue was renamed to result_index (#729).\nThe _constant and Utilities.getconstant function were renamed to constant\nREDUCTION_CERTIFICATE result status was added (#734).\nAbstract matrix sets were added (#731).\nTesting improvements:\nThe testing guideline was updated (#728).\nQuadratic tests were added (#697).\nUnit tests for RawStatusString, SolveTime, Silent and SolverName were added (#726, #741).\nA rotated second-order cone test was added (#759).\nA power cone test was added (#768).\nTests for ZeroOne variables with variable bounds were added (#772).\nAn unbounded test was added (#773).\nExisting tests had a few updates (#702, #703, #763).\nDocumentation improvements:\nAdded a section on CachingOptimizer (#777).\nAdded a section on UniversalFallback, Model and @model (#762).\nTransition the knapsack example to a doctest with MockOptimizer (#786).\nUtilities improvements:\nA CleverDict utility was added for a vector that automatically transform into a dictionary once a first index is removed (#767).\nThe Utilities.constant function was renamed to Utilities.constant_vector (#740).\nImplement optimizer attributes for CachingOptimizer (#745).\nRename Utilities.add_scalar_constraint to Utilities.normalize_and_add_constraint (#801).\noperate with vcat, SingleVariable and VectorOfVariables now returns a VectorOfVariables (#616).\nFix a type piracy of operate (#784).\nThe load_constraint fallback signature was fixed (#760).\nThe set_dot function was extended to work with sparse arrays (#805).\nBridges improvements:\nThe bridges no longer store the constraint function and set before it is bridged, the bridges now have to implement ConstraintFunction and ConstraintSet if the user wants to recover them. As a consequence, the @bridge macro was removed (#722).\nBridge are now instantiated with a bridge_constraint function instead of using a constructor (#730).\nFix constraint attributes for bridges (#699).\nConstraint bridges were moved to the Bridges/Constraint submodule so they should now inherit from MOI.Bridges.Constraint.Abstract and should implement MOI.Bridges.Constraint.concrete_bridge_type instead of MOI.Bridges.concrete_bridge_type (#756).\nVariable bridges were added in (#759).\nVarious improvements (#746, #747).","category":"page"},{"location":"changelog/#v0.8.4-(March-13,-2019)","page":"Release notes","title":"v0.8.4 (March 13, 2019)","text":"","category":"section"},{"location":"changelog/","page":"Release notes","title":"Release notes","text":"Performance improvement in default_copy_to and bridge optimizer (#696).\nAdd Silent and implement setting optimizer attributes in caching and mock optimizers (#695).\nAdd Functionize bridges (SingleVariable and VectorOfVariables) (#659).\nMinor typo fixes (#694).","category":"page"},{"location":"changelog/#v0.8.3-(March-6,-2019)","page":"Release notes","title":"v0.8.3 (March 6, 2019)","text":"","category":"section"},{"location":"changelog/","page":"Release notes","title":"Release notes","text":"Use zero constant in scalar constraint function of MOI.Test.copytest (#691).\nFix variable deletion with SingleVariable objective function (#690).\nFix LazyBridgeOptimizer with bridges that add no constraints (#689).\nError message improvements (#673, #685, #686, #688).\nDocumentation improvements (#682, #683, #687).\nBasis status:\nRemove VariableBasisStatus (#679).\nTest ConstraintBasisStatus and implement it in bridges (#678).\nFix inference of NumberOfVariables and NumberOfConstraints (#677).\nImplement division between a quadratic function and a number (#675).","category":"page"},{"location":"changelog/#v0.8.2-(February-7,-2019)","page":"Release notes","title":"v0.8.2 (February 7, 2019)","text":"","category":"section"},{"location":"changelog/","page":"Release notes","title":"Release notes","text":"Add RawStatusString attribute (#629).\nDo not set names to the optimizer but only to the cache in CachingOptimizer (#638).\nMake scalar MOI functions act as scalars in broadcast (#646).\nAdd function utilities:\nImplement Base.zero (#634), Base.iszero (#643), add missing arithmetic operations (#644, #645) and fix division (#648).\nAdd a vectorize function that turns a vector of ScalarAffineFunction into a VectorAffineFunction (#642).\nImprove support for starting values:\nShow a warning in copy when starting values are not supported instead of throwing an error (#630).\nFix UniversalFallback for getting an variable or constraint attribute set to no indices (#623).\nAdd a test in contlineartest with partially set VariablePrimalStart.\nBridges improvements:\nFix StackOverFlow in LazyBridgeOptimizer when there is a cycle in the graph of bridges.\nAdd Slack bridges (#610, #650).\nAdd FlipSign bridges (#658).\nAdd tests with duplicate coefficients in ScalarAffineFunction and VectorAffineFunction (#639).\nUse tolerance to compare VariablePrimal in rotatedsoc1 test (#632).\nUse a zero constant in ScalarAffineFunction of constraints in psdt2 (#622).","category":"page"},{"location":"changelog/#v0.8.1-(January-7,-2019)","page":"Release notes","title":"v0.8.1 (January 7, 2019)","text":"","category":"section"},{"location":"changelog/","page":"Release notes","title":"Release notes","text":"Adding an NLP objective now overrides any objective set using the ObjectiveFunction attribute (#619).\nRename fullbridgeoptimizer into full_bridge_optimizer (#621).\nAllow custom constraint types with full_bridge_optimizer (#617).\nAdd Vectorize bridge which transforms scalar linear constraints into vector linear constraints (#615).","category":"page"},{"location":"changelog/#v0.8.0-(December-18,-2018)","page":"Release notes","title":"v0.8.0 (December 18, 2018)","text":"","category":"section"},{"location":"changelog/","page":"Release notes","title":"Release notes","text":"Rename all enum values to follow the JuMP naming guidelines for constants, for example, Optimal becomes OPTIMAL, and DualInfeasible becomes DUAL_INFEASIBLE.\nRename CachingOptimizer methods for style compliance.\nAdd an MOI.TerminationStatusCode called ALMOST_DUAL_INFEASIBLE.","category":"page"},{"location":"changelog/#v0.7.0-(December-13,-2018)","page":"Release notes","title":"v0.7.0 (December 13, 2018)","text":"","category":"section"},{"location":"changelog/","page":"Release notes","title":"Release notes","text":"Test that MOI.TerminationStatus is MOI.OptimizeNotCalled before MOI.optimize! is called.\nCheck supports_default_copy_to in tests (#594).\nKey pieces of information like optimality, infeasibility, etc., are now reported through TerminationStatusCode. It is typically no longer necessary to check the result statuses in addition to the termination status.\nAdd perspective dimension to log-det cone (#593).","category":"page"},{"location":"changelog/#v0.6.4-(November-27,-2018)","page":"Release notes","title":"v0.6.4 (November 27, 2018)","text":"","category":"section"},{"location":"changelog/","page":"Release notes","title":"Release notes","text":"Add OptimizeNotCalled termination status (#577) and improve documentation of other statuses (#575).\nAdd a solver naming guideline (#578).\nMake FeasibilitySense the default ObjectiveSense (#579).\nFix Utilities.@model and Bridges.@bridge macros for functions and sets defined outside MOI (#582).\nDocument solver-specific attributes (#580) and implement them in Utilities.CachingOptimizer (#565).","category":"page"},{"location":"changelog/#v0.6.3-(November-16,-2018)","page":"Release notes","title":"v0.6.3 (November 16, 2018)","text":"","category":"section"},{"location":"changelog/","page":"Release notes","title":"Release notes","text":"Variables and constraints are now allowed to have duplicate names. An error is thrown only on lookup. This change breaks some existing tests. (#549)\nAttributes may now be partially set (some values could be nothing). (#563)\nPerformance improvements in Utilities.Model (#549, #567, #568)\nFix bug in QuadtoSOC (#558).\nNew supports_default_copy_to method that optimizers should implement to control caching behavior.\nDocumentation improvements.","category":"page"},{"location":"changelog/#v0.6.2-(October-26,-2018)","page":"Release notes","title":"v0.6.2 (October 26, 2018)","text":"","category":"section"},{"location":"changelog/","page":"Release notes","title":"Release notes","text":"Improve hygiene of @model macro (#544).\nFix bug in copy tests (#543).\nFix bug in UniversalFallback attribute getter (#540).\nAllow all correct solutions for solve_blank_obj unit test (#537).\nAdd errors for Allocate-Load and bad constraints (#534).\n[performance] Add specialized implementation of hash for VariableIndex (#533).\n[performance] Construct the name to object dictionaries lazily in model (#535).\nAdd the QuadtoSOC bridge which transforms ScalarQuadraticFunction constraints into RotatedSecondOrderCone (#483).","category":"page"},{"location":"changelog/#v0.6.1-(September-22,-2018)","page":"Release notes","title":"v0.6.1 (September 22, 2018)","text":"","category":"section"},{"location":"changelog/","page":"Release notes","title":"Release notes","text":"Enable PositiveSemidefiniteConeSquare set and quadratic functions in MOIB.fullbridgeoptimizer (#524).\nAdd warning in the bridge between PositiveSemidefiniteConeSquare and PositiveSemidefiniteConeTriangle when the matrix is almost symmetric (#522).\nModify MOIT.copytest to not add multiples constraints on the same variable (#521).\nAdd missing keyword argument in one of MOIU.add_scalar_constraint methods (#520).","category":"page"},{"location":"changelog/#v0.6.0-(August-30,-2018)","page":"Release notes","title":"v0.6.0 (August 30, 2018)","text":"","category":"section"},{"location":"changelog/","page":"Release notes","title":"Release notes","text":"The MOIU.@model and MOIB.@bridge macros now support functions and sets defined in external modules. As a consequence, function and set names in the macro arguments need to be prefixed by module name.\nRename functions according to the JuMP style guide:\ncopy! with keyword arguments copynames and warnattributes -> copy_to with keyword arguments copy_names and warn_attributes;\nset! -> set;\naddvariable[s]! -> add_variable[s];\nsupportsconstraint -> supports_constraint;\naddconstraint[s]! -> add_constraint[s];\nisvalid -> is_valid;\nisempty -> is_empty;\nBase.delete! -> delete;\nmodify! -> modify;\ntransform! -> transform;\ninitialize! -> initialize;\nwrite -> write_to_file; and\nread! -> read_from_file.\nRemove free! (use Base.finalize instead).\nAdd the SquarePSD bridge which transforms PositiveSemidefiniteConeTriangle constraints into PositiveSemidefiniteConeTriangle.\nAdd result fallback for ConstraintDual of variable-wise constraint, ConstraintPrimal and ObjectiveValue.\nAdd tests for ObjectiveBound.\nAdd test for empty rows in vector linear constraint.\nRework errors: CannotError has been renamed NotAllowedError and the distinction between UnsupportedError and NotAllowedError is now about whether the element is not supported (for example, it cannot be copied a model containing this element) or the operation is not allowed (either because it is not implemented, because it cannot be performed in the current state of the model, or because it cannot be performed for a specific index)\ncanget is removed. NoSolution is added as a result status to indicate that the solver does not have either a primal or dual solution available (See #479).","category":"page"},{"location":"changelog/#v0.5.0-(August-5,-2018)","page":"Release notes","title":"v0.5.0 (August 5, 2018)","text":"","category":"section"},{"location":"changelog/","page":"Release notes","title":"Release notes","text":"Fix names with CachingOptimizer.\nCleanup thanks to @mohamed82008.\nAdded a universal fallback for constraints.\nFast utilities for function canonicalization thanks to @rdeits.\nRenamed dimension field to side_dimension in the context of matrix-like sets.\nNew and improved tests for cases like duplicate terms and ObjectiveBound.\nRemoved cantransform, canaddconstraint, canaddvariable, canset, canmodify, and candelete functions from the API. They are replaced by a new set of errors that are thrown: Subtypes of UnsupportedError indicate unsupported operations, while subtypes of CannotError indicate operations that cannot be performed in the current state.\nThe API for copy! is updated to remove the CopyResult type.\nUpdates for the new JuMP style guide.","category":"page"},{"location":"changelog/#v0.4.1-(June-28,-2018)","page":"Release notes","title":"v0.4.1 (June 28, 2018)","text":"","category":"section"},{"location":"changelog/","page":"Release notes","title":"Release notes","text":"Fixes vector function modification on 32 bits.\nFixes Bellman-Ford algorithm for bridges.\nAdded an NLP test with FeasibilitySense.\nUpdate modification documentation.","category":"page"},{"location":"changelog/#v0.4.0-(June-23,-2018)","page":"Release notes","title":"v0.4.0 (June 23, 2018)","text":"","category":"section"},{"location":"changelog/","page":"Release notes","title":"Release notes","text":"Helper constructors for VectorAffineTerm and VectorQuadraticTerm.\nAdded modify_lhs to TestConfig.\nAdditional unit tests for optimizers.\nAdded a type parameter to CachingOptimizer for the optimizer field.\nNew API for problem modification (#388)\nTests pass without deprecation warnings on Julia 0.7.\nSmall fixes and documentation updates.","category":"page"},{"location":"changelog/#v0.3.0-(May-25,-2018)","page":"Release notes","title":"v0.3.0 (May 25, 2018)","text":"","category":"section"},{"location":"changelog/","page":"Release notes","title":"Release notes","text":"Functions have been redefined to use arrays-of-structs instead of structs-of-arrays.\nImprovements to MockOptimizer.\nSignificant changes to Bridges.\nNew and improved unit tests.\nFixes for Julia 0.7.","category":"page"},{"location":"changelog/#v0.2.0-(April-24,-2018)","page":"Release notes","title":"v0.2.0 (April 24, 2018)","text":"","category":"section"},{"location":"changelog/","page":"Release notes","title":"Release notes","text":"Improvements to and better coverage of Tests.\nDocumentation fixes.\nSolverName attribute.\nChanges to the NLP interface (new definition of variable order and arrays of structs for bound pairs and sparsity patterns).\nAddition of NLP tests.\nIntroduction of UniversalFallback.\ncopynames keyword argument to MOI.copy!.\nAdd Bridges submodule.","category":"page"},{"location":"changelog/#v0.1.0-(February-28,-2018)","page":"Release notes","title":"v0.1.0 (February 28, 2018)","text":"","category":"section"},{"location":"changelog/","page":"Release notes","title":"Release notes","text":"Initial public release.\nThe framework for MOI was developed at the JuMP-dev workshop at MIT in June 2017 as a sorely needed replacement for MathProgBase.","category":"page"},{"location":"background/duality/","page":"Duality","title":"Duality","text":"CurrentModule = MathOptInterface\nDocTestSetup = quote\n import MathOptInterface as MOI\nend\nDocTestFilters = [r\"MathOptInterface|MOI\"]","category":"page"},{"location":"background/duality/#Duality","page":"Duality","title":"Duality","text":"","category":"section"},{"location":"background/duality/","page":"Duality","title":"Duality","text":"Conic duality is the starting point for MOI's duality conventions. When all functions are affine (or coordinate projections), and all constraint sets are closed convex cones, the model may be called a conic optimization problem.","category":"page"},{"location":"background/duality/","page":"Duality","title":"Duality","text":"For a minimization problem in geometric conic form, the primal is:","category":"page"},{"location":"background/duality/","page":"Duality","title":"Duality","text":"beginalign\n min_x in mathbbR^n a_0^T x + b_0\n\n textst A_i x + b_i in mathcalC_i i = 1 ldots m\nendalign","category":"page"},{"location":"background/duality/","page":"Duality","title":"Duality","text":"and the dual is a maximization problem in standard conic form:","category":"page"},{"location":"background/duality/","page":"Duality","title":"Duality","text":"beginalign\n max_y_1 ldots y_m -sum_i=1^m b_i^T y_i + b_0\n\n textst a_0 - sum_i=1^m A_i^T y_i = 0\n\n y_i in mathcalC_i^* i = 1 ldots m\nendalign","category":"page"},{"location":"background/duality/","page":"Duality","title":"Duality","text":"where each mathcalC_i is a closed convex cone and mathcalC_i^* is its dual cone.","category":"page"},{"location":"background/duality/","page":"Duality","title":"Duality","text":"For a maximization problem in geometric conic form, the primal is:","category":"page"},{"location":"background/duality/","page":"Duality","title":"Duality","text":"beginalign\n max_x in mathbbR^n a_0^T x + b_0\n\n textst A_i x + b_i in mathcalC_i i = 1 ldots m\nendalign","category":"page"},{"location":"background/duality/","page":"Duality","title":"Duality","text":"and the dual is a minimization problem in standard conic form:","category":"page"},{"location":"background/duality/","page":"Duality","title":"Duality","text":"beginalign\n min_y_1 ldots y_m sum_i=1^m b_i^T y_i + b_0\n\n textst a_0 + sum_i=1^m A_i^T y_i = 0\n\n y_i in mathcalC_i^* i = 1 ldots m\nendalign","category":"page"},{"location":"background/duality/","page":"Duality","title":"Duality","text":"A linear inequality constraint a^T x + b ge c is equivalent to a^T x + b - c in mathbbR_+, and a^T x + b le c is equivalent to a^T x + b - c in mathbbR_-. Variable-wise constraints are affine constraints with the appropriate identity mapping in place of A_i.","category":"page"},{"location":"background/duality/","page":"Duality","title":"Duality","text":"For the special case of minimization LPs, the MOI primal form can be stated as:","category":"page"},{"location":"background/duality/","page":"Duality","title":"Duality","text":"beginalign\n min_x in mathbbR^n a_0^T x + b_0\n\n textst\nA_1 x ge b_1\n A_2 x le b_2\n A_3 x = b_3\nendalign","category":"page"},{"location":"background/duality/","page":"Duality","title":"Duality","text":"By applying the stated transformations to conic form, taking the dual, and transforming back into linear inequality form, one obtains the following dual:","category":"page"},{"location":"background/duality/","page":"Duality","title":"Duality","text":"beginalign\n max_y_1y_2y_3 b_1^Ty_1 + b_2^Ty_2 + b_3^Ty_3 + b_0\n\n textst\nA_1^Ty_1 + A_2^Ty_2 + A_3^Ty_3 = a_0\n y_1 ge 0\n y_2 le 0\nendalign","category":"page"},{"location":"background/duality/","page":"Duality","title":"Duality","text":"For maximization LPs, the MOI primal form can be stated as:","category":"page"},{"location":"background/duality/","page":"Duality","title":"Duality","text":"beginalign\n max_x in mathbbR^n a_0^T x + b_0\n\n textst\nA_1 x ge b_1\n A_2 x le b_2\n A_3 x = b_3\nendalign","category":"page"},{"location":"background/duality/","page":"Duality","title":"Duality","text":"and similarly, the dual is:","category":"page"},{"location":"background/duality/","page":"Duality","title":"Duality","text":"beginalign\n min_y_1y_2y_3 -b_1^Ty_1 - b_2^Ty_2 - b_3^Ty_3 + b_0\n\n textst\nA_1^Ty_1 + A_2^Ty_2 + A_3^Ty_3 = -a_0\n y_1 ge 0\n y_2 le 0\nendalign","category":"page"},{"location":"background/duality/","page":"Duality","title":"Duality","text":"warning: Warning\nFor the LP case, the signs of the feasible dual variables depend only on the sense of the corresponding primal inequality and not on the objective sense.","category":"page"},{"location":"background/duality/#Duality-and-scalar-product","page":"Duality","title":"Duality and scalar product","text":"","category":"section"},{"location":"background/duality/","page":"Duality","title":"Duality","text":"The scalar product is different from the canonical one for the sets PositiveSemidefiniteConeTriangle, LogDetConeTriangle, RootDetConeTriangle.","category":"page"},{"location":"background/duality/","page":"Duality","title":"Duality","text":"If the set C_i of the section Duality is one of these three cones, then the rows of the matrix A_i corresponding to off-diagonal entries are twice the value of the coefficients field in the VectorAffineFunction for the corresponding rows. See PositiveSemidefiniteConeTriangle for details.","category":"page"},{"location":"background/duality/#Dual-for-problems-with-quadratic-functions","page":"Duality","title":"Dual for problems with quadratic functions","text":"","category":"section"},{"location":"background/duality/#Quadratic-Programs-(QPs)","page":"Duality","title":"Quadratic Programs (QPs)","text":"","category":"section"},{"location":"background/duality/","page":"Duality","title":"Duality","text":"For quadratic programs with only affine conic constraints,","category":"page"},{"location":"background/duality/","page":"Duality","title":"Duality","text":"beginalign*\n min_x in mathbbR^n frac12x^TQ_0x + a_0^T x + b_0\n\n textst A_i x + b_i in mathcalC_i i = 1 ldots m\nendalign*","category":"page"},{"location":"background/duality/","page":"Duality","title":"Duality","text":"with cones mathcalC_i subseteq mathbbR^m_i for i = 1 ldots m, consider the Lagrangian function","category":"page"},{"location":"background/duality/","page":"Duality","title":"Duality","text":"L(x y) = frac12x^TQ_0x + a_0^T x + b_0 - sum_i = 1^m y_i^T (A_i x + b_i)","category":"page"},{"location":"background/duality/","page":"Duality","title":"Duality","text":"Let z(y) denote sum_i = 1^m A_i^T y_i - a_0, the Lagrangian can be rewritten as","category":"page"},{"location":"background/duality/","page":"Duality","title":"Duality","text":"L(x y) = frac12x^TQ_0x - z(y)^T x + b_0 - sum_i = 1^m y_i^T b_i","category":"page"},{"location":"background/duality/","page":"Duality","title":"Duality","text":"The condition nabla_x L(x y) = 0 gives","category":"page"},{"location":"background/duality/","page":"Duality","title":"Duality","text":"0 = nabla_x L(x y) = Q_0x + a_0 - sum_i = 1^m y_i^T b_i","category":"page"},{"location":"background/duality/","page":"Duality","title":"Duality","text":"which gives Q_0x = z(y). This allows to obtain that","category":"page"},{"location":"background/duality/","page":"Duality","title":"Duality","text":"min_x in mathbbR^n L(x y) = -frac12x^TQ_0x + b_0 - sum_i = 1^m y_i^T b_i","category":"page"},{"location":"background/duality/","page":"Duality","title":"Duality","text":"so the dual problem is","category":"page"},{"location":"background/duality/","page":"Duality","title":"Duality","text":"max_y_i in mathcalC_i^* min_x in mathbbR^n -frac12x^TQ_0x + b_0 - sum_i = 1^m y_i^T b_i","category":"page"},{"location":"background/duality/","page":"Duality","title":"Duality","text":"If Q_0 is invertible, we have x = Q_0^-1z(y) hence","category":"page"},{"location":"background/duality/","page":"Duality","title":"Duality","text":"min_x in mathbbR^n L(x y) = -frac12z(y)^TQ_0^-1z(y) + b_0 - sum_i = 1^m y_i^T b_i","category":"page"},{"location":"background/duality/","page":"Duality","title":"Duality","text":"so the dual problem is","category":"page"},{"location":"background/duality/","page":"Duality","title":"Duality","text":"max_y_i in mathcalC_i^* -frac12z(y)^TQ_0^-1z(y) + b_0 - sum_i = 1^m y_i^T b_i","category":"page"},{"location":"background/duality/#Quadratically-Constrained-Quadratic-Programs-(QCQPs)","page":"Duality","title":"Quadratically Constrained Quadratic Programs (QCQPs)","text":"","category":"section"},{"location":"background/duality/","page":"Duality","title":"Duality","text":"Given a problem with both quadratic function and quadratic objectives:","category":"page"},{"location":"background/duality/","page":"Duality","title":"Duality","text":"beginalign*\n min_x in mathbbR^n frac12x^TQ_0x + a_0^T x + b_0\n\n textst frac12x^TQ_ix + a_i^T x + b_i in mathcalC_i i = 1 ldots m\nendalign*","category":"page"},{"location":"background/duality/","page":"Duality","title":"Duality","text":"with cones mathcalC_i subseteq mathbbR for i = 1 ldots m, consider the Lagrangian function","category":"page"},{"location":"background/duality/","page":"Duality","title":"Duality","text":"L(x y) = frac12x^TQ_0x + a_0^T x + b_0 - sum_i = 1^m y_i (frac12x^TQ_ix + a_i^T x + b_i)","category":"page"},{"location":"background/duality/","page":"Duality","title":"Duality","text":"A pair of primal-dual variables (x^star y^star) is optimal if","category":"page"},{"location":"background/duality/","page":"Duality","title":"Duality","text":"x^star is a minimizer of\nmin_x in mathbbR^n L(x y^star)\nThat is,\n0 = nabla_x L(x y^star) = Q_0x + a_0 - sum_i = 1^m y_i^star (Q_ix + a_i)\nand y^star is a maximizer of\nmax_y_i in mathcalC_i^* L(x^star y)\nThat is, for all i = 1 ldots m, frac12x^TQ_ix + a_i^T x + b_i is either zero or in the normal cone of mathcalC_i^* at y^star. For instance, if mathcalC_i is z in mathbbR z le 0 , this means that if frac12x^TQ_ix + a_i^T x + b_i is nonzero at x^star then y_i^star = 0. This is the classical complementary slackness condition.","category":"page"},{"location":"background/duality/","page":"Duality","title":"Duality","text":"If mathcalC_i is a vector set, the discussion remains valid with y_i(frac12x^TQ_ix + a_i^T x + b_i) replaced with the scalar product between y_i and the vector of scalar-valued quadratic functions.","category":"page"},{"location":"background/duality/#Dual-for-square-semidefinite-matrices","page":"Duality","title":"Dual for square semidefinite matrices","text":"","category":"section"},{"location":"background/duality/","page":"Duality","title":"Duality","text":"The set PositiveSemidefiniteConeTriangle is a self-dual. That is, querying ConstraintDual of a PositiveSemidefiniteConeTriangle constraint returns a vector that is itself a member of PositiveSemidefiniteConeTriangle.","category":"page"},{"location":"background/duality/","page":"Duality","title":"Duality","text":"However, the dual of PositiveSemidefiniteConeSquare is not so straight forward. This section explains the duality convention we use, and how it is derived.","category":"page"},{"location":"background/duality/","page":"Duality","title":"Duality","text":"info: Info\nIf you have a PositiveSemidefiniteConeSquare constraint, the result matrix A from ConstraintDual is not positive semidefinite. However, A + A^top is positive semidefinite.","category":"page"},{"location":"background/duality/","page":"Duality","title":"Duality","text":"Let mathcalS_+ be the cone of symmetric semidefinite matrices in the fracn(n+1)2 dimensional space of symmetric mathbbR^n times n matrices. That is, mathcalS_+ is the set PositiveSemidefiniteConeTriangle. It is well known that mathcalS_+ is a self-dual proper cone.","category":"page"},{"location":"background/duality/","page":"Duality","title":"Duality","text":"Let mathcalP_+ be the cone of symmetric semidefinite matrices in the n^2 dimensional space of mathbbR^n times n matrices. That is mathcalP_+ is the set PositiveSemidefiniteConeSquare.","category":"page"},{"location":"background/duality/","page":"Duality","title":"Duality","text":"In addition, let mathcalD_+ be the cone of matrices A such that A+A^top in mathcalP_+.","category":"page"},{"location":"background/duality/","page":"Duality","title":"Duality","text":"mathcalP_+ is not proper because it is not solid (it is not n^2 dimensional), so it is not necessarily true that mathcalP_+^** = mathcalP_+.","category":"page"},{"location":"background/duality/","page":"Duality","title":"Duality","text":"However, this is the case, because we will show that mathcalP_+^* = mathcalD_+ and mathcalD_+^* = mathcalP_+.","category":"page"},{"location":"background/duality/","page":"Duality","title":"Duality","text":"First, let us see why mathcalP_+^* = mathcalD_+.","category":"page"},{"location":"background/duality/","page":"Duality","title":"Duality","text":"If B is symmetric, then","category":"page"},{"location":"background/duality/","page":"Duality","title":"Duality","text":"langle AB rangle = langle A^top B^top rangle = langle A^top Brangle","category":"page"},{"location":"background/duality/","page":"Duality","title":"Duality","text":"so","category":"page"},{"location":"background/duality/","page":"Duality","title":"Duality","text":"2langle A B rangle = langle A B rangle + langle A^top B rangle = langle A + A^top B rangle","category":"page"},{"location":"background/duality/","page":"Duality","title":"Duality","text":"Therefore, langle ABrangle ge 0 for all B in mathcalP_+ if and only if langle A+A^topBrangle ge 0 for all B in mathcalP_+. Since A+A^top is symmetric, and we know that mathcalS_+ is self-dual, we have shown that mathcalP_+^* is the set of matrices A such that A+A^top in mathcalP_+.","category":"page"},{"location":"background/duality/","page":"Duality","title":"Duality","text":"Second, let us see why mathcalD_+^* = mathcalP_+.","category":"page"},{"location":"background/duality/","page":"Duality","title":"Duality","text":"Since A in mathcalD_+ implies that A^top in mathcalD_+, B in mathcalD_+^* means that langle A+A^topBrangle ge 0 for all A in mathcalD_+, and hence B in mathcalP_+.","category":"page"},{"location":"background/duality/","page":"Duality","title":"Duality","text":"To see why it should be symmetric, simply notice that if B_ij B_ji, then langle ABrangle can be made arbitrarily small by setting A_ij = A_ij + s and A_ji = A_ji - s, with s arbitrarily large, and A stays in mathcalD_+ because A+A^top does not change.","category":"page"},{"location":"background/duality/","page":"Duality","title":"Duality","text":"Typically, the primal/dual pair for semidefinite programs is presented as:","category":"page"},{"location":"background/duality/","page":"Duality","title":"Duality","text":"beginalign\n min langle C X rangle \ntextst langle A_k Xrangle = b_k forall k \n X in mathcalS_+\nendalign","category":"page"},{"location":"background/duality/","page":"Duality","title":"Duality","text":"with the dual","category":"page"},{"location":"background/duality/","page":"Duality","title":"Duality","text":"beginalign\n max sum_k b_k y_k \ntextst C - sum A_k y_k in mathcalS_+\nendalign","category":"page"},{"location":"background/duality/","page":"Duality","title":"Duality","text":"If we allow A_k to be non-symmetric, we should instead use:","category":"page"},{"location":"background/duality/","page":"Duality","title":"Duality","text":"beginalign\n min langle C X rangle \ntextst langle A_k Xrangle = b_k forall k \n X in mathcalD_+\nendalign","category":"page"},{"location":"background/duality/","page":"Duality","title":"Duality","text":"with the dual","category":"page"},{"location":"background/duality/","page":"Duality","title":"Duality","text":"beginalign\n max sum b_k y_k \ntextst C - sum A_k y_k in mathcalP_+\nendalign","category":"page"},{"location":"background/duality/","page":"Duality","title":"Duality","text":"This is implemented as:","category":"page"},{"location":"background/duality/","page":"Duality","title":"Duality","text":"beginalign\n min langle C Z rangle + langle C - C^top S rangle \ntextst langle A_k Z rangle + langle A_k - A_k^top S rangle = b_k forall k \n Z in mathcalS_+\nendalign","category":"page"},{"location":"background/duality/","page":"Duality","title":"Duality","text":"with the dual","category":"page"},{"location":"background/duality/","page":"Duality","title":"Duality","text":"beginalign\n max sum b_k y_k \ntextst C+C^top - sum (A_k+A_k^top) y_k in mathcalS_+ \n C-C^top - sum(A_k-A_k^top) y_k = 0\nendalign","category":"page"},{"location":"background/duality/","page":"Duality","title":"Duality","text":"and we recover Z = X + X^top.","category":"page"},{"location":"reference/callbacks/","page":"Callbacks","title":"Callbacks","text":"CurrentModule = MathOptInterface\nDocTestSetup = quote\n import MathOptInterface as MOI\nend\nDocTestFilters = [r\"MathOptInterface|MOI\"]","category":"page"},{"location":"reference/callbacks/#Callbacks","page":"Callbacks","title":"Callbacks","text":"","category":"section"},{"location":"reference/callbacks/","page":"Callbacks","title":"Callbacks","text":"AbstractCallback\nAbstractSubmittable\nsubmit","category":"page"},{"location":"reference/callbacks/#MathOptInterface.AbstractCallback","page":"Callbacks","title":"MathOptInterface.AbstractCallback","text":"abstract type AbstractCallback <: AbstractModelAttribute end\n\nAbstract type for a model attribute representing a callback function. The value set to subtypes of AbstractCallback is a function that may be called during optimize!. As optimize! is in progress, the result attributes (i.e, the attributes attr such that is_set_by_optimize(attr)) may not be accessible from the callback, hence trying to get result attributes might throw a OptimizeInProgress error.\n\nAt most one callback of each type can be registered. If an optimizer already has a function for a callback type, and the user registers a new function, then the old one is replaced.\n\nThe value of the attribute should be a function taking only one argument, commonly called callback_data, that can be used for instance in LazyConstraintCallback, HeuristicCallback and UserCutCallback.\n\n\n\n\n\n","category":"type"},{"location":"reference/callbacks/#MathOptInterface.AbstractSubmittable","page":"Callbacks","title":"MathOptInterface.AbstractSubmittable","text":"AbstractSubmittable\n\nAbstract supertype for objects that can be submitted to the model.\n\n\n\n\n\n","category":"type"},{"location":"reference/callbacks/#MathOptInterface.submit","page":"Callbacks","title":"MathOptInterface.submit","text":"submit(\n optimizer::AbstractOptimizer,\n sub::AbstractSubmittable,\n values...,\n)::Nothing\n\nSubmit values to the submittable sub of the optimizer optimizer.\n\nAn UnsupportedSubmittable error is thrown if model does not support the attribute attr (see supports) and a SubmitNotAllowed error is thrown if it supports the submittable sub but it cannot be submitted.\n\n\n\n\n\n","category":"function"},{"location":"reference/callbacks/#Attributes","page":"Callbacks","title":"Attributes","text":"","category":"section"},{"location":"reference/callbacks/","page":"Callbacks","title":"Callbacks","text":"CallbackNodeStatus\nCallbackVariablePrimal\nCallbackNodeStatusCode\nCALLBACK_NODE_STATUS_INTEGER\nCALLBACK_NODE_STATUS_FRACTIONAL\nCALLBACK_NODE_STATUS_UNKNOWN","category":"page"},{"location":"reference/callbacks/#MathOptInterface.CallbackNodeStatus","page":"Callbacks","title":"MathOptInterface.CallbackNodeStatus","text":"CallbackNodeStatus(callback_data)\n\nAn optimizer attribute describing the (in)feasibility of the primal solution available from CallbackVariablePrimal during a callback identified by callback_data.\n\nReturns a CallbackNodeStatusCode Enum.\n\n\n\n\n\n","category":"type"},{"location":"reference/callbacks/#MathOptInterface.CallbackVariablePrimal","page":"Callbacks","title":"MathOptInterface.CallbackVariablePrimal","text":"CallbackVariablePrimal(callback_data)\n\nA variable attribute for the assignment to some primal variable's value during the callback identified by callback_data.\n\n\n\n\n\n","category":"type"},{"location":"reference/callbacks/#MathOptInterface.CallbackNodeStatusCode","page":"Callbacks","title":"MathOptInterface.CallbackNodeStatusCode","text":"CallbackNodeStatusCode\n\nAn Enum of possible return values from calling get with CallbackNodeStatus.\n\nValues\n\nPossible values are:\n\nCALLBACK_NODE_STATUS_INTEGER: the primal solution available from CallbackVariablePrimal is integer feasible.\nCALLBACK_NODE_STATUS_FRACTIONAL: the primal solution available from CallbackVariablePrimal is integer infeasible.\nCALLBACK_NODE_STATUS_UNKNOWN: the primal solution available from CallbackVariablePrimal might be integer feasible or infeasible.\n\n\n\n\n\n","category":"type"},{"location":"reference/callbacks/#MathOptInterface.CALLBACK_NODE_STATUS_INTEGER","page":"Callbacks","title":"MathOptInterface.CALLBACK_NODE_STATUS_INTEGER","text":"CALLBACK_NODE_STATUS_INTEGER::CallbackNodeStatusCode\n\nAn instance of the CallbackNodeStatusCode enum.\n\nCALLBACK_NODE_STATUS_INTEGER: the primal solution available from CallbackVariablePrimal is integer feasible.\n\n\n\n\n\n","category":"constant"},{"location":"reference/callbacks/#MathOptInterface.CALLBACK_NODE_STATUS_FRACTIONAL","page":"Callbacks","title":"MathOptInterface.CALLBACK_NODE_STATUS_FRACTIONAL","text":"CALLBACK_NODE_STATUS_FRACTIONAL::CallbackNodeStatusCode\n\nAn instance of the CallbackNodeStatusCode enum.\n\nCALLBACK_NODE_STATUS_FRACTIONAL: the primal solution available from CallbackVariablePrimal is integer infeasible.\n\n\n\n\n\n","category":"constant"},{"location":"reference/callbacks/#MathOptInterface.CALLBACK_NODE_STATUS_UNKNOWN","page":"Callbacks","title":"MathOptInterface.CALLBACK_NODE_STATUS_UNKNOWN","text":"CALLBACK_NODE_STATUS_UNKNOWN::CallbackNodeStatusCode\n\nAn instance of the CallbackNodeStatusCode enum.\n\nCALLBACK_NODE_STATUS_UNKNOWN: the primal solution available from CallbackVariablePrimal might be integer feasible or infeasible.\n\n\n\n\n\n","category":"constant"},{"location":"reference/callbacks/#Lazy-constraints","page":"Callbacks","title":"Lazy constraints","text":"","category":"section"},{"location":"reference/callbacks/","page":"Callbacks","title":"Callbacks","text":"LazyConstraintCallback\nLazyConstraint","category":"page"},{"location":"reference/callbacks/#MathOptInterface.LazyConstraintCallback","page":"Callbacks","title":"MathOptInterface.LazyConstraintCallback","text":"LazyConstraintCallback() <: AbstractCallback\n\nThe callback can be used to reduce the feasible set given the current primal solution by submitting a LazyConstraint. For instance, it may be called at an incumbent of a mixed-integer problem. Note that there is no guarantee that the callback is called at every feasible primal solution.\n\nThe current primal solution is accessed through CallbackVariablePrimal. Trying to access other result attributes will throw OptimizeInProgress as discussed in AbstractCallback.\n\nExamples\n\nx = MOI.add_variables(optimizer, 8)\nMOI.set(optimizer, MOI.LazyConstraintCallback(), callback_data -> begin\n sol = MOI.get(optimizer, MOI.CallbackVariablePrimal(callback_data), x)\n if # should add a lazy constraint\n func = # computes function\n set = # computes set\n MOI.submit(optimizer, MOI.LazyConstraint(callback_data), func, set)\n end\nend)\n\n\n\n\n\n","category":"type"},{"location":"reference/callbacks/#MathOptInterface.LazyConstraint","page":"Callbacks","title":"MathOptInterface.LazyConstraint","text":"LazyConstraint(callback_data)\n\nLazy constraint func-in-set submitted as func, set. The optimal solution returned by VariablePrimal will satisfy all lazy constraints that have been submitted.\n\nThis can be submitted only from the LazyConstraintCallback. The field callback_data is a solver-specific callback type that is passed as the argument to the feasible solution callback.\n\nExamples\n\nSuppose x and y are VariableIndexs of optimizer. To add a LazyConstraint for 2x + 3y <= 1, write\n\nfunc = 2.0x + 3.0y\nset = MOI.LessThan(1.0)\nMOI.submit(optimizer, MOI.LazyConstraint(callback_data), func, set)\n\ninside a LazyConstraintCallback of data callback_data.\n\n\n\n\n\n","category":"type"},{"location":"reference/callbacks/#User-cuts","page":"Callbacks","title":"User cuts","text":"","category":"section"},{"location":"reference/callbacks/","page":"Callbacks","title":"Callbacks","text":"UserCutCallback\nUserCut","category":"page"},{"location":"reference/callbacks/#MathOptInterface.UserCutCallback","page":"Callbacks","title":"MathOptInterface.UserCutCallback","text":"UserCutCallback() <: AbstractCallback\n\nThe callback can be used to submit UserCut given the current primal solution. For instance, it may be called at fractional (i.e., non-integer) nodes in the branch and bound tree of a mixed-integer problem. Note that there is not guarantee that the callback is called everytime the solver has an infeasible solution.\n\nThe infeasible solution is accessed through CallbackVariablePrimal. Trying to access other result attributes will throw OptimizeInProgress as discussed in AbstractCallback.\n\nExamples\n\nx = MOI.add_variables(optimizer, 8)\nMOI.set(optimizer, MOI.UserCutCallback(), callback_data -> begin\n sol = MOI.get(optimizer, MOI.CallbackVariablePrimal(callback_data), x)\n if # can find a user cut\n func = # computes function\n set = # computes set\n MOI.submit(optimizer, MOI.UserCut(callback_data), func, set)\n end\nend\n\n\n\n\n\n","category":"type"},{"location":"reference/callbacks/#MathOptInterface.UserCut","page":"Callbacks","title":"MathOptInterface.UserCut","text":"UserCut(callback_data)\n\nConstraint func-to-set suggested to help the solver detect the solution given by CallbackVariablePrimal as infeasible. The cut is submitted as func, set. Typically CallbackVariablePrimal will violate integrality constraints, and a cut would be of the form ScalarAffineFunction-in-LessThan or ScalarAffineFunction-in-GreaterThan. Note that, as opposed to LazyConstraint, the provided constraint cannot modify the feasible set, the constraint should be redundant, e.g., it may be a consequence of affine and integrality constraints.\n\nThis can be submitted only from the UserCutCallback. The field callback_data is a solver-specific callback type that is passed as the argument to the infeasible solution callback.\n\nNote that the solver may silently ignore the provided constraint.\n\n\n\n\n\n","category":"type"},{"location":"reference/callbacks/#Heuristic-solutions","page":"Callbacks","title":"Heuristic solutions","text":"","category":"section"},{"location":"reference/callbacks/","page":"Callbacks","title":"Callbacks","text":"HeuristicCallback\nHeuristicSolution\nHeuristicSolutionStatus\nHEURISTIC_SOLUTION_ACCEPTED\nHEURISTIC_SOLUTION_REJECTED\nHEURISTIC_SOLUTION_UNKNOWN","category":"page"},{"location":"reference/callbacks/#MathOptInterface.HeuristicCallback","page":"Callbacks","title":"MathOptInterface.HeuristicCallback","text":"HeuristicCallback() <: AbstractCallback\n\nThe callback can be used to submit HeuristicSolution given the current primal solution. For example, it may be called at fractional (i.e., non-integer) nodes in the branch and bound tree of a mixed-integer problem. Note that there is no guarantee that the callback is called every time the solver has an infeasible solution.\n\nThe current primal solution is accessed through CallbackVariablePrimal. Trying to access other result attributes will throw OptimizeInProgress as discussed in AbstractCallback.\n\nExamples\n\nx = MOI.add_variables(optimizer, 8)\nMOI.set(optimizer, MOI.HeuristicCallback(), callback_data -> begin\n sol = MOI.get(optimizer, MOI.CallbackVariablePrimal(callback_data), x)\n if # can find a heuristic solution\n values = # computes heuristic solution\n MOI.submit(optimizer, MOI.HeuristicSolution(callback_data), x,\n values)\n end\nend\n\n\n\n\n\n","category":"type"},{"location":"reference/callbacks/#MathOptInterface.HeuristicSolution","page":"Callbacks","title":"MathOptInterface.HeuristicSolution","text":"HeuristicSolution(callback_data)\n\nHeuristically obtained feasible solution. The solution is submitted as variables, values where values[i] gives the value of variables[i], similarly to set. The submit call returns a HeuristicSolutionStatus indicating whether the provided solution was accepted or rejected.\n\nThis can be submitted only from the HeuristicCallback. The field callback_data is a solver-specific callback type that is passed as the argument to the heuristic callback.\n\nSome solvers require a complete solution, others only partial solutions.\n\n\n\n\n\n","category":"type"},{"location":"reference/callbacks/#MathOptInterface.HeuristicSolutionStatus","page":"Callbacks","title":"MathOptInterface.HeuristicSolutionStatus","text":"HeuristicSolutionStatus\n\nAn Enum of possible return values for submit with HeuristicSolution. This informs whether the heuristic solution was accepted or rejected.\n\nValues\n\nPossible values are:\n\nHEURISTIC_SOLUTION_ACCEPTED: The heuristic solution was accepted\nHEURISTIC_SOLUTION_REJECTED: The heuristic solution was rejected\nHEURISTIC_SOLUTION_UNKNOWN: No information available on the acceptance\n\n\n\n\n\n","category":"type"},{"location":"reference/callbacks/#MathOptInterface.HEURISTIC_SOLUTION_ACCEPTED","page":"Callbacks","title":"MathOptInterface.HEURISTIC_SOLUTION_ACCEPTED","text":"HEURISTIC_SOLUTION_ACCEPTED::HeuristicSolutionStatus\n\nAn instance of the HeuristicSolutionStatus enum.\n\nHEURISTIC_SOLUTION_ACCEPTED: The heuristic solution was accepted\n\n\n\n\n\n","category":"constant"},{"location":"reference/callbacks/#MathOptInterface.HEURISTIC_SOLUTION_REJECTED","page":"Callbacks","title":"MathOptInterface.HEURISTIC_SOLUTION_REJECTED","text":"HEURISTIC_SOLUTION_REJECTED::HeuristicSolutionStatus\n\nAn instance of the HeuristicSolutionStatus enum.\n\nHEURISTIC_SOLUTION_REJECTED: The heuristic solution was rejected\n\n\n\n\n\n","category":"constant"},{"location":"reference/callbacks/#MathOptInterface.HEURISTIC_SOLUTION_UNKNOWN","page":"Callbacks","title":"MathOptInterface.HEURISTIC_SOLUTION_UNKNOWN","text":"HEURISTIC_SOLUTION_UNKNOWN::HeuristicSolutionStatus\n\nAn instance of the HeuristicSolutionStatus enum.\n\nHEURISTIC_SOLUTION_UNKNOWN: No information available on the acceptance\n\n\n\n\n\n","category":"constant"},{"location":"reference/models/","page":"Models","title":"Models","text":"CurrentModule = MathOptInterface\nDocTestSetup = quote\n import MathOptInterface as MOI\nend\nDocTestFilters = [r\"MathOptInterface|MOI\"]","category":"page"},{"location":"reference/models/#Models","page":"Models","title":"Models","text":"","category":"section"},{"location":"reference/models/#Attribute-interface","page":"Models","title":"Attribute interface","text":"","category":"section"},{"location":"reference/models/","page":"Models","title":"Models","text":"is_set_by_optimize\nis_copyable\nget\nget!\nset\nsupports\nattribute_value_type","category":"page"},{"location":"reference/models/#MathOptInterface.is_set_by_optimize","page":"Models","title":"MathOptInterface.is_set_by_optimize","text":"is_set_by_optimize(::AnyAttribute)\n\nReturn a Bool indicating whether the value of the attribute is modified during an optimize! call, that is, the attribute is used to query the result of the optimization.\n\nImportant note when defining new attributes\n\nThis function returns false by default so it should be implemented for attributes that are modified by optimize!.\n\n\n\n\n\n","category":"function"},{"location":"reference/models/#MathOptInterface.is_copyable","page":"Models","title":"MathOptInterface.is_copyable","text":"is_copyable(::AnyAttribute)\n\nReturn a Bool indicating whether the value of the attribute may be copied during copy_to using set.\n\nImportant note when defining new attributes\n\nBy default is_copyable(attr) returns !is_set_by_optimize(attr). A specific method should be defined for attributes which are copied indirectly during copy_to. For instance, both is_copyable and is_set_by_optimize return false for the following attributes:\n\nListOfOptimizerAttributesSet, ListOfModelAttributesSet, ListOfConstraintAttributesSet and ListOfVariableAttributesSet.\nSolverName and RawSolver: these attributes cannot be set.\nNumberOfVariables and ListOfVariableIndices: these attributes are set indirectly by add_variable and add_variables.\nObjectiveFunctionType: this attribute is set indirectly when setting the ObjectiveFunction attribute.\nNumberOfConstraints, ListOfConstraintIndices, ListOfConstraintTypesPresent, CanonicalConstraintFunction, ConstraintFunction and ConstraintSet: these attributes are set indirectly by add_constraint and add_constraints.\n\n\n\n\n\n","category":"function"},{"location":"reference/models/#MathOptInterface.get","page":"Models","title":"MathOptInterface.get","text":"get(optimizer::AbstractOptimizer, attr::AbstractOptimizerAttribute)\n\nReturn an attribute attr of the optimizer optimizer.\n\nget(model::ModelLike, attr::AbstractModelAttribute)\n\nReturn an attribute attr of the model model.\n\nget(model::ModelLike, attr::AbstractVariableAttribute, v::VariableIndex)\n\nIf the attribute attr is set for the variable v in the model model, return its value, return nothing otherwise. If the attribute attr is not supported by model then an error should be thrown instead of returning nothing.\n\nget(model::ModelLike, attr::AbstractVariableAttribute, v::Vector{VariableIndex})\n\nReturn a vector of attributes corresponding to each variable in the collection v in the model model.\n\nget(model::ModelLike, attr::AbstractConstraintAttribute, c::ConstraintIndex)\n\nIf the attribute attr is set for the constraint c in the model model, return its value, return nothing otherwise. If the attribute attr is not supported by model then an error should be thrown instead of returning nothing.\n\nget(\n model::ModelLike,\n attr::AbstractConstraintAttribute,\n c::Vector{ConstraintIndex{F,S}},\n) where {F,S}\n\nReturn a vector of attributes corresponding to each constraint in the collection c in the model model.\n\nget(model::ModelLike, ::Type{VariableIndex}, name::String)\n\nIf a variable with name name exists in the model model, return the corresponding index, otherwise return nothing. Errors if two variables have the same name.\n\nget(\n model::ModelLike,\n ::Type{ConstraintIndex{F,S}},\n name::String,\n) where {F,S}\n\nIf an F-in-S constraint with name name exists in the model model, return the corresponding index, otherwise return nothing. Errors if two constraints have the same name.\n\nget(model::ModelLike, ::Type{ConstraintIndex}, name::String)\n\nIf any constraint with name name exists in the model model, return the corresponding index, otherwise return nothing. This version is available for convenience but may incur a performance penalty because it is not type stable. Errors if two constraints have the same name.\n\n\n\n\n\nMOI.get(b::AbstractBridge, ::MOI.NumberOfVariables)::Int64\n\nReturn the number of variables created by the bridge b in the model.\n\nSee also MOI.NumberOfConstraints.\n\nImplementation notes\n\nThere is a default fallback, so you need only implement this if the bridge adds new variables.\n\n\n\n\n\nMOI.get(b::AbstractBridge, ::MOI.ListOfVariableIndices)\n\nReturn the list of variables created by the bridge b.\n\nSee also MOI.ListOfVariableIndices.\n\nImplementation notes\n\nThere is a default fallback, so you need only implement this if the bridge adds new variables.\n\n\n\n\n\nMOI.get(b::AbstractBridge, ::MOI.NumberOfConstraints{F,S})::Int64 where {F,S}\n\nReturn the number of constraints of the type F-in-S created by the bridge b.\n\nSee also MOI.NumberOfConstraints.\n\nImplementation notes\n\nThere is a default fallback, so you need only implement this for the constraint types returned by added_constraint_types.\n\n\n\n\n\nMOI.get(b::AbstractBridge, ::MOI.ListOfConstraintIndices{F,S}) where {F,S}\n\nReturn a Vector{ConstraintIndex{F,S}} with indices of all constraints of type F-in-S created by the bride b.\n\nSee also MOI.ListOfConstraintIndices.\n\nImplementation notes\n\nThere is a default fallback, so you need only implement this for the constraint types returned by added_constraint_types.\n\n\n\n\n\nfunction MOI.get(\n model::MOI.ModelLike,\n attr::MOI.AbstractConstraintAttribute,\n bridge::AbstractBridge,\n)\n\nReturn the value of the attribute attr of the model model for the constraint bridged by bridge.\n\n\n\n\n\n","category":"function"},{"location":"reference/models/#MathOptInterface.get!","page":"Models","title":"MathOptInterface.get!","text":"get!(output, model::ModelLike, args...)\n\nAn in-place version of get.\n\nThe signature matches that of get except that the the result is placed in the vector output.\n\n\n\n\n\n","category":"function"},{"location":"reference/models/#MathOptInterface.set","page":"Models","title":"MathOptInterface.set","text":"set(optimizer::AbstractOptimizer, attr::AbstractOptimizerAttribute, value)\n\nAssign value to the attribute attr of the optimizer optimizer.\n\nset(model::ModelLike, attr::AbstractModelAttribute, value)\n\nAssign value to the attribute attr of the model model.\n\nset(model::ModelLike, attr::AbstractVariableAttribute, v::VariableIndex, value)\n\nAssign value to the attribute attr of variable v in model model.\n\nset(\n model::ModelLike,\n attr::AbstractVariableAttribute,\n v::Vector{VariableIndex},\n vector_of_values,\n)\n\nAssign a value respectively to the attribute attr of each variable in the collection v in model model.\n\nset(\n model::ModelLike,\n attr::AbstractConstraintAttribute,\n c::ConstraintIndex,\n value,\n)\n\nAssign a value to the attribute attr of constraint c in model model.\n\nset(\n model::ModelLike,\n attr::AbstractConstraintAttribute,\n c::Vector{ConstraintIndex{F,S}},\n vector_of_values,\n) where {F,S}\n\nAssign a value respectively to the attribute attr of each constraint in the collection c in model model.\n\nAn UnsupportedAttribute error is thrown if model does not support the attribute attr (see supports) and a SetAttributeNotAllowed error is thrown if it supports the attribute attr but it cannot be set.\n\nset(\n model::ModelLike,\n ::ConstraintSet,\n c::ConstraintIndex{F,S},\n set::S,\n) where {F,S}\n\nChange the set of constraint c to the new set set which should be of the same type as the original set.\n\nset(\n model::ModelLike,\n ::ConstraintFunction,\n c::ConstraintIndex{F,S},\n func::F,\n) where {F,S}\n\nReplace the function in constraint c with func. F must match the original function type used to define the constraint.\n\nnote: Note\nSetting the constraint function is not allowed if F is VariableIndex; a SettingVariableIndexNotAllowed error is thrown instead. This is because, it would require changing the index c since the index of VariableIndex constraints must be the same as the index of the variable.\n\n\n\n\n\nfunction MOI.set(\n model::MOI.ModelLike,\n attr::MOI.AbstractConstraintAttribute,\n bridge::AbstractBridge,\n value,\n)\n\nSet the value of the attribute attr of the model model for the constraint bridged by bridge.\n\n\n\n\n\n","category":"function"},{"location":"reference/models/#MathOptInterface.supports","page":"Models","title":"MathOptInterface.supports","text":"supports(model::ModelLike, sub::AbstractSubmittable)::Bool\n\nReturn a Bool indicating whether model supports the submittable sub.\n\nsupports(model::ModelLike, attr::AbstractOptimizerAttribute)::Bool\n\nReturn a Bool indicating whether model supports the optimizer attribute attr. That is, it returns false if copy_to(model, src) shows a warning in case attr is in the ListOfOptimizerAttributesSet of src; see copy_to for more details on how unsupported optimizer attributes are handled in copy.\n\nsupports(model::ModelLike, attr::AbstractModelAttribute)::Bool\n\nReturn a Bool indicating whether model supports the model attribute attr. That is, it returns false if copy_to(model, src) cannot be performed in case attr is in the ListOfModelAttributesSet of src.\n\nsupports(\n model::ModelLike,\n attr::AbstractVariableAttribute,\n ::Type{VariableIndex},\n)::Bool\n\nReturn a Bool indicating whether model supports the variable attribute attr. That is, it returns false if copy_to(model, src) cannot be performed in case attr is in the ListOfVariableAttributesSet of src.\n\nsupports(\n model::ModelLike,\n attr::AbstractConstraintAttribute,\n ::Type{ConstraintIndex{F,S}},\n)::Bool where {F,S}\n\nReturn a Bool indicating whether model supports the constraint attribute attr applied to an F-in-S constraint. That is, it returns false if copy_to(model, src) cannot be performed in case attr is in the ListOfConstraintAttributesSet of src.\n\nFor all five methods, if the attribute is only not supported in specific circumstances, it should still return true.\n\nNote that supports is only defined for attributes for which is_copyable returns true as other attributes do not appear in the list of attributes set obtained by ListOf...AttributesSet.\n\n\n\n\n\nMOI.supports(\n model::MOI.ModelLike,\n attr::MOI.AbstractConstraintAttribute,\n BT::Type{<:AbstractBridge},\n)\n\nReturn a Bool indicating whether BT supports setting attr to model.\n\n\n\n\n\n","category":"function"},{"location":"reference/models/#MathOptInterface.attribute_value_type","page":"Models","title":"MathOptInterface.attribute_value_type","text":"attribute_value_type(attr::AnyAttribute)\n\nGiven an attribute attr, return the type of value expected by get, or returned by set.\n\nNotes\n\nOnly implement this if it make sense to do so. If un-implemented, the default is Any.\n\n\n\n\n\n","category":"function"},{"location":"reference/models/#Model-interface","page":"Models","title":"Model interface","text":"","category":"section"},{"location":"reference/models/","page":"Models","title":"Models","text":"ModelLike\nis_empty\nempty!\nwrite_to_file\nread_from_file\nsupports_incremental_interface\ncopy_to\nIndexMap","category":"page"},{"location":"reference/models/#MathOptInterface.ModelLike","page":"Models","title":"MathOptInterface.ModelLike","text":"ModelLike\n\nAbstract supertype for objects that implement the \"Model\" interface for defining an optimization problem.\n\n\n\n\n\n","category":"type"},{"location":"reference/models/#MathOptInterface.is_empty","page":"Models","title":"MathOptInterface.is_empty","text":"is_empty(model::ModelLike)\n\nReturns false if the model has any model attribute set or has any variables or constraints.\n\nNote that an empty model can have optimizer attributes set.\n\n\n\n\n\n","category":"function"},{"location":"reference/models/#MathOptInterface.empty!","page":"Models","title":"MathOptInterface.empty!","text":"empty!(model::ModelLike)\n\nEmpty the model, that is, remove all variables, constraints and model attributes but not optimizer attributes.\n\n\n\n\n\n","category":"function"},{"location":"reference/models/#MathOptInterface.write_to_file","page":"Models","title":"MathOptInterface.write_to_file","text":"write_to_file(model::ModelLike, filename::String)\n\nWrite the current model to the file at filename.\n\nSupported file types depend on the model type.\n\n\n\n\n\n","category":"function"},{"location":"reference/models/#MathOptInterface.read_from_file","page":"Models","title":"MathOptInterface.read_from_file","text":"read_from_file(model::ModelLike, filename::String)\n\nRead the file filename into the model model. If model is non-empty, this may throw an error.\n\nSupported file types depend on the model type.\n\nNote\n\nOnce the contents of the file are loaded into the model, users can query the variables via get(model, ListOfVariableIndices()). However, some filetypes, such as LP files, do not maintain an explicit ordering of the variables. Therefore, the returned list may be in an arbitrary order.\n\nTo avoid depending on the order of the indices, look up each variable index by name using get(model, VariableIndex, \"name\").\n\n\n\n\n\n","category":"function"},{"location":"reference/models/#MathOptInterface.supports_incremental_interface","page":"Models","title":"MathOptInterface.supports_incremental_interface","text":"supports_incremental_interface(model::ModelLike)\n\nReturn a Bool indicating whether model supports building incrementally via add_variable and add_constraint.\n\nThe main purpose of this function is to determine whether a model can be loaded into model incrementally or whether it should be cached and copied at once instead.\n\n\n\n\n\n","category":"function"},{"location":"reference/models/#MathOptInterface.copy_to","page":"Models","title":"MathOptInterface.copy_to","text":"copy_to(dest::ModelLike, src::ModelLike)::IndexMap\n\nCopy the model from src into dest.\n\nThe target dest is emptied, and all previous indices to variables and constraints in dest are invalidated.\n\nReturns an IndexMap object that translates variable and constraint indices from the src model to the corresponding indices in the dest model.\n\nNotes\n\nIf a constraint that in src is not supported by dest, then an UnsupportedConstraint error is thrown.\nIf an AbstractModelAttribute, AbstractVariableAttribute, or AbstractConstraintAttribute is set in src but not supported by dest, then an UnsupportedAttribute error is thrown.\n\nAbstractOptimizerAttributes are not copied to the dest model.\n\nIndexMap\n\nImplementations of copy_to must return an IndexMap. For technical reasons, this type is defined in the Utilities submodule as MOI.Utilities.IndexMap. However, since it is an integral part of the MOI API, we provide MOI.IndexMap as an alias.\n\nExample\n\n# Given empty `ModelLike` objects `src` and `dest`.\n\nx = add_variable(src)\n\nis_valid(src, x) # true\nis_valid(dest, x) # false (`dest` has no variables)\n\nindex_map = copy_to(dest, src)\nis_valid(dest, x) # false (unless index_map[x] == x)\nis_valid(dest, index_map[x]) # true\n\n\n\n\n\n","category":"function"},{"location":"reference/models/#MathOptInterface.IndexMap","page":"Models","title":"MathOptInterface.IndexMap","text":"IndexMap()\n\nThe dictionary-like object returned by copy_to.\n\nIndexMap\n\nImplementations of copy_to must return an IndexMap. For technical reasons, the IndexMap type is defined in the Utilities submodule as MOI.Utilities.IndexMap. However, since it is an integral part of the MOI API, we provide this MOI.IndexMap as an alias.\n\n\n\n\n\n","category":"type"},{"location":"reference/models/#Model-attributes","page":"Models","title":"Model attributes","text":"","category":"section"},{"location":"reference/models/","page":"Models","title":"Models","text":"AbstractModelAttribute\nName\nObjectiveFunction\nObjectiveFunctionType\nObjectiveSense\nOptimizationSense\nMIN_SENSE\nMAX_SENSE\nFEASIBILITY_SENSE\nNumberOfVariables\nListOfVariableIndices\nListOfConstraintTypesPresent\nNumberOfConstraints\nListOfConstraintIndices\nListOfOptimizerAttributesSet\nListOfModelAttributesSet\nListOfVariableAttributesSet\nListOfConstraintAttributesSet\nUserDefinedFunction\nListOfSupportedNonlinearOperators","category":"page"},{"location":"reference/models/#MathOptInterface.AbstractModelAttribute","page":"Models","title":"MathOptInterface.AbstractModelAttribute","text":"AbstractModelAttribute\n\nAbstract supertype for attribute objects that can be used to set or get attributes (properties) of the model.\n\n\n\n\n\n","category":"type"},{"location":"reference/models/#MathOptInterface.Name","page":"Models","title":"MathOptInterface.Name","text":"Name()\n\nA model attribute for the string identifying the model. It has a default value of \"\" if not set`.\n\n\n\n\n\n","category":"type"},{"location":"reference/models/#MathOptInterface.ObjectiveFunction","page":"Models","title":"MathOptInterface.ObjectiveFunction","text":"ObjectiveFunction{F<:AbstractScalarFunction}()\n\nA model attribute for the objective function which has a type F<:AbstractScalarFunction.\n\nF should be guaranteed to be equivalent but not necessarily identical to the function type provided by the user.\n\nThrows an InexactError if the objective function cannot be converted to F, e.g., the objective function is quadratic and F is ScalarAffineFunction{Float64} or it has non-integer coefficient and F is ScalarAffineFunction{Int}.\n\n\n\n\n\n","category":"type"},{"location":"reference/models/#MathOptInterface.ObjectiveFunctionType","page":"Models","title":"MathOptInterface.ObjectiveFunctionType","text":"ObjectiveFunctionType()\n\nA model attribute for the type F of the objective function set using the ObjectiveFunction{F} attribute.\n\nExamples\n\nIn the following code, attr should be equal to MOI.VariableIndex:\n\nx = MOI.add_variable(model)\nMOI.set(model, MOI.ObjectiveFunction{MOI.VariableIndex}(), x)\nattr = MOI.get(model, MOI.ObjectiveFunctionType())\n\n\n\n\n\n","category":"type"},{"location":"reference/models/#MathOptInterface.ObjectiveSense","page":"Models","title":"MathOptInterface.ObjectiveSense","text":"ObjectiveSense()\n\nA model attribute for the objective sense of the objective function, which must be an OptimizationSense: MIN_SENSE, MAX_SENSE, or FEASIBILITY_SENSE. The default is FEASIBILITY_SENSE.\n\nInteraction with ObjectiveFunction\n\nSetting the sense to FEASIBILITY_SENSE unsets the ObjectiveFunction attribute. That is, if you first set ObjectiveFunction and then set ObjectiveSense to be FEASIBILITY_SENSE, no objective function will be passed to the solver.\n\nIn addition, some reformulations of ObjectiveFunction via bridges rely on the value of ObjectiveSense. Therefore, you should set ObjectiveSense before setting ObjectiveFunction.\n\n\n\n\n\n","category":"type"},{"location":"reference/models/#MathOptInterface.OptimizationSense","page":"Models","title":"MathOptInterface.OptimizationSense","text":"OptimizationSense\n\nAn enum for the value of the ObjectiveSense attribute.\n\nValues\n\nPossible values are:\n\nMIN_SENSE: the goal is to minimize the objective function\nMAX_SENSE: the goal is to maximize the objective function\nFEASIBILITY_SENSE: the model does not have an objective function\n\n\n\n\n\n","category":"type"},{"location":"reference/models/#MathOptInterface.MIN_SENSE","page":"Models","title":"MathOptInterface.MIN_SENSE","text":"MIN_SENSE::OptimizationSense\n\nAn instance of the OptimizationSense enum.\n\nMIN_SENSE: the goal is to minimize the objective function\n\n\n\n\n\n","category":"constant"},{"location":"reference/models/#MathOptInterface.MAX_SENSE","page":"Models","title":"MathOptInterface.MAX_SENSE","text":"MAX_SENSE::OptimizationSense\n\nAn instance of the OptimizationSense enum.\n\nMAX_SENSE: the goal is to maximize the objective function\n\n\n\n\n\n","category":"constant"},{"location":"reference/models/#MathOptInterface.FEASIBILITY_SENSE","page":"Models","title":"MathOptInterface.FEASIBILITY_SENSE","text":"FEASIBILITY_SENSE::OptimizationSense\n\nAn instance of the OptimizationSense enum.\n\nFEASIBILITY_SENSE: the model does not have an objective function\n\n\n\n\n\n","category":"constant"},{"location":"reference/models/#MathOptInterface.NumberOfVariables","page":"Models","title":"MathOptInterface.NumberOfVariables","text":"NumberOfVariables()\n\nA model attribute for the number of variables in the model.\n\n\n\n\n\n","category":"type"},{"location":"reference/models/#MathOptInterface.ListOfVariableIndices","page":"Models","title":"MathOptInterface.ListOfVariableIndices","text":"ListOfVariableIndices()\n\nA model attribute for the Vector{VariableIndex} of all variable indices present in the model (i.e., of length equal to the value of NumberOfVariables in the order in which they were added.\n\n\n\n\n\n","category":"type"},{"location":"reference/models/#MathOptInterface.ListOfConstraintTypesPresent","page":"Models","title":"MathOptInterface.ListOfConstraintTypesPresent","text":"ListOfConstraintTypesPresent()\n\nA model attribute for the list of tuples of the form (F,S), where F is a function type and S is a set type indicating that the attribute NumberOfConstraints{F,S} has a value greater than zero.\n\n\n\n\n\n","category":"type"},{"location":"reference/models/#MathOptInterface.NumberOfConstraints","page":"Models","title":"MathOptInterface.NumberOfConstraints","text":"NumberOfConstraints{F,S}()\n\nA model attribute for the number of constraints of the type F-in-S present in the model.\n\n\n\n\n\n","category":"type"},{"location":"reference/models/#MathOptInterface.ListOfConstraintIndices","page":"Models","title":"MathOptInterface.ListOfConstraintIndices","text":"ListOfConstraintIndices{F,S}()\n\nA model attribute for the Vector{ConstraintIndex{F,S}} of all constraint indices of type F-in-S in the model (i.e., of length equal to the value of NumberOfConstraints{F,S}) in the order in which they were added.\n\n\n\n\n\n","category":"type"},{"location":"reference/models/#MathOptInterface.ListOfOptimizerAttributesSet","page":"Models","title":"MathOptInterface.ListOfOptimizerAttributesSet","text":"ListOfOptimizerAttributesSet()\n\nAn optimizer attribute for the Vector{AbstractOptimizerAttribute} of all optimizer attributes that were set.\n\n\n\n\n\n","category":"type"},{"location":"reference/models/#MathOptInterface.ListOfModelAttributesSet","page":"Models","title":"MathOptInterface.ListOfModelAttributesSet","text":"ListOfModelAttributesSet()\n\nA model attribute for the Vector{AbstractModelAttribute} of all model attributes attr such that:\n\nis_copyable(attr) returns true, and\nthe attribute was set to the model\n\n\n\n\n\n","category":"type"},{"location":"reference/models/#MathOptInterface.ListOfVariableAttributesSet","page":"Models","title":"MathOptInterface.ListOfVariableAttributesSet","text":"ListOfVariableAttributesSet()\n\nA model attribute for the Vector{AbstractVariableAttribute} of all variable attributes attr such that 1) is_copyable(attr) returns true and 2) the attribute was set to variables.\n\n\n\n\n\n","category":"type"},{"location":"reference/models/#MathOptInterface.ListOfConstraintAttributesSet","page":"Models","title":"MathOptInterface.ListOfConstraintAttributesSet","text":"ListOfConstraintAttributesSet{F, S}()\n\nA model attribute for the Vector{AbstractConstraintAttribute} of all constraint attributes attr such that:\n\nis_copyable(attr) returns true and\nthe attribute was set to F-in-S constraints.\n\nNote\n\nThe attributes ConstraintFunction and ConstraintSet should not be included in the list even if then have been set with set.\n\n\n\n\n\n","category":"type"},{"location":"reference/models/#MathOptInterface.UserDefinedFunction","page":"Models","title":"MathOptInterface.UserDefinedFunction","text":"UserDefinedFunction(name::Symbol, arity::Int) <: AbstractModelAttribute\n\nSet this attribute to register a user-defined function by the name of name with arity arguments.\n\nOnce registered, name will appear in ListOfSupportedNonlinearOperators.\n\nYou cannot register multiple UserDefinedFunctions with the same name but different arity.\n\nValue type\n\nThe value to be set is a tuple containing one, two, or three functions to evaluate the function, the first-order derivative, and the second-order derivative respectively. Both derivatives are optional, but if you pass the second-order derivative you must also pass the first-order derivative.\n\nFor univariate functions with arity == 1, the functions in the tuple must have the form:\n\nf(x::T)::T: returns the value of the function at x\n∇f(x::T)::T: returns the first-order derivative of f with respect to x\n∇²f(x::T)::T: returns the second-order derivative of f with respect to x.\n\nFor multivariate functions with arity > 1, the functions in the tuple must have the form:\n\nf(x::T...)::T: returns the value of the function at x\n∇f(g::AbstractVector{T}, x::T...)::Nothing: fills the components of g, with g[i] being the first-order partial derivative of f with respect to x[i]\n∇²f(H::AbstractMatrix{T}, x::T...)::Nothing: fills the non-zero components of H, with H[i, j] being the second-order partial derivative of f with respect to x[i] and then x[j]. H is initialized to the zero matrix, so you do not need to set any zero elements.\n\nExamples\n\njulia> import MathOptInterface as MOI\n\njulia> f(x, y) = x^2 + y^2\nf (generic function with 1 method)\n\njulia> function ∇f(g, x, y)\n g .= 2 * x, 2 * y\n return\n end\n∇f (generic function with 1 method)\n\njulia> function ∇²f(H, x...)\n H[1, 1] = H[2, 2] = 2.0\n return\n end\n∇²f (generic function with 1 method)\n\njulia> model = MOI.Utilities.UniversalFallback(MOI.Utilities.Model{Float64}())\nMOIU.UniversalFallback{MOIU.Model{Float64}}\nfallback for MOIU.Model{Float64}\n\njulia> MOI.set(model, MOI.UserDefinedFunction(:f, 2), (f,))\n\njulia> MOI.set(model, MOI.UserDefinedFunction(:g, 2), (f, ∇f))\n\njulia> MOI.set(model, MOI.UserDefinedFunction(:h, 2), (f, ∇f, ∇²f))\n\njulia> x = MOI.add_variables(model, 2)\n2-element Vector{MathOptInterface.VariableIndex}:\n MOI.VariableIndex(1)\n MOI.VariableIndex(2)\n\njulia> MOI.set(model, MOI.ObjectiveSense(), MOI.MIN_SENSE)\n\njulia> obj_f = MOI.ScalarNonlinearFunction(:f, Any[x[1], x[2]])\nf(MOI.VariableIndex(1), MOI.VariableIndex(2))\n\njulia> MOI.set(model, MOI.ObjectiveFunction{typeof(obj_f)}(), obj_f)\n\njulia> print(model)\nMinimize ScalarNonlinearFunction:\n f(v[1], v[2])\n\nSubject to:\n\n\n\n\n\n\n","category":"type"},{"location":"reference/models/#MathOptInterface.ListOfSupportedNonlinearOperators","page":"Models","title":"MathOptInterface.ListOfSupportedNonlinearOperators","text":"ListOfSupportedNonlinearOperators() <: AbstractModelAttribute\n\nWhen queried with get, return a Vector{Symbol} listing the operators supported by the model.\n\n\n\n\n\n","category":"type"},{"location":"reference/models/#Optimizer-interface","page":"Models","title":"Optimizer interface","text":"","category":"section"},{"location":"reference/models/","page":"Models","title":"Models","text":"AbstractOptimizer\nOptimizerWithAttributes\noptimize!\noptimize!(::ModelLike, ::ModelLike)\ninstantiate\ndefault_cache","category":"page"},{"location":"reference/models/#MathOptInterface.AbstractOptimizer","page":"Models","title":"MathOptInterface.AbstractOptimizer","text":"AbstractOptimizer <: ModelLike\n\nAbstract supertype for objects representing an instance of an optimization problem tied to a particular solver. This is typically a solver's in-memory representation. In addition to ModelLike, AbstractOptimizer objects let you solve the model and query the solution.\n\n\n\n\n\n","category":"type"},{"location":"reference/models/#MathOptInterface.OptimizerWithAttributes","page":"Models","title":"MathOptInterface.OptimizerWithAttributes","text":"struct OptimizerWithAttributes\n optimizer_constructor\n params::Vector{Pair{AbstractOptimizerAttribute,<:Any}}\nend\n\nObject grouping an optimizer constructor and a list of optimizer attributes. Instances are created with instantiate.\n\n\n\n\n\n","category":"type"},{"location":"reference/models/#MathOptInterface.optimize!","page":"Models","title":"MathOptInterface.optimize!","text":"optimize!(optimizer::AbstractOptimizer)\n\nOptimize the problem contained in optimizer.\n\nBefore calling optimize!, the problem should first be constructed using the incremental interface (see supports_incremental_interface) or copy_to.\n\n\n\n\n\n","category":"function"},{"location":"reference/models/#MathOptInterface.optimize!-Tuple{MathOptInterface.ModelLike, MathOptInterface.ModelLike}","page":"Models","title":"MathOptInterface.optimize!","text":"optimize!(dest::AbstractOptimizer, src::ModelLike)::Tuple{IndexMap,Bool}\n\nA \"one-shot\" call that copies the problem from src into dest and then uses dest to optimize the problem.\n\nReturns a tuple of an IndexMap and a Bool copied.\n\nThe IndexMap object translates variable and constraint indices from the src model to the corresponding indices in the dest optimizer. See copy_to for details.\nIf copied == true, src was copied to dest and then cached, allowing incremental modification if supported by the solver.\nIf copied == false, a cache of the model was not kept in dest. Therefore, only the solution information (attributes for which is_set_by_optimize is true) is available to query.\n\nnote: Note\nThe main purpose of optimize! method with two arguments is for use in Utilities.CachingOptimizer.\n\nRelationship to the single-argument optimize!\n\nThe default fallback of optimize!(dest::AbstractOptimizer, src::ModelLike) is\n\nfunction optimize!(dest::AbstractOptimizer, src::ModelLike)\n index_map = copy_to(dest, src)\n optimize!(dest)\n return index_map, true\nend\n\nTherefore, subtypes of AbstractOptimizer should either implement this two-argument method, or implement both copy_to(::Optimizer, ::ModelLike) and optimize!(::Optimizer).\n\n\n\n\n\n","category":"method"},{"location":"reference/models/#MathOptInterface.instantiate","page":"Models","title":"MathOptInterface.instantiate","text":"instantiate(\n optimizer_constructor,\n with_cache_type::Union{Nothing,Type} = nothing,\n with_bridge_type::Union{Nothing,Type} = nothing,\n)\n\nCreate an instance of an optimizer by either:\n\ncalling optimizer_constructor.optimizer_constructor() and setting the parameters in optimizer_constructor.params if optimizer_constructor is a OptimizerWithAttributes\ncalling optimizer_constructor() if optimizer_constructor is callable.\n\nwithcachetype\n\nIf with_cache_type is not nothing, then the optimizer is wrapped in a Utilities.CachingOptimizer to store a cache of the model. This is most useful if the optimizer you are constructing does not support the incremental interface (see supports_incremental_interface).\n\nwithbridgetype\n\nIf with_bridge_type is not nothing, the optimizer is wrapped in a Bridges.full_bridge_optimizer, enabling all the bridges defined in the MOI.Bridges submodule with coefficient type with_bridge_type.\n\nIn addition, if the optimizer created by optimizer_constructor does not support the incremental interface (see supports_incremental_interface), then, irrespective of with_cache_type, the optimizer is wrapped in a Utilities.CachingOptimizer to store a cache of the bridged model.\n\nIf with_cache_type and with_bridge_type are both not nothing, then they must be the same type.\n\n\n\n\n\n","category":"function"},{"location":"reference/models/#MathOptInterface.default_cache","page":"Models","title":"MathOptInterface.default_cache","text":"default_cache(optimizer::ModelLike, ::Type{T}) where {T}\n\nReturn a new instance of the default model type to be used as cache for optimizer in a Utilities.CachingOptimizer for holding constraints of coefficient type T. By default, this returns Utilities.UniversalFallback(Utilities.Model{T}()). If copying from a instance of a given model type is faster for optimizer then a new method returning an instance of this model type should be defined.\n\n\n\n\n\n","category":"function"},{"location":"reference/models/#Optimizer-attributes","page":"Models","title":"Optimizer attributes","text":"","category":"section"},{"location":"reference/models/","page":"Models","title":"Models","text":"AbstractOptimizerAttribute\nSolverName\nSolverVersion\nSilent\nTimeLimitSec\nObjectiveLimit\nRawOptimizerAttribute\nNumberOfThreads\nRawSolver\nAbsoluteGapTolerance\nRelativeGapTolerance","category":"page"},{"location":"reference/models/#MathOptInterface.AbstractOptimizerAttribute","page":"Models","title":"MathOptInterface.AbstractOptimizerAttribute","text":"AbstractOptimizerAttribute\n\nAbstract supertype for attribute objects that can be used to set or get attributes (properties) of the optimizer.\n\nNotes\n\nThe difference between AbstractOptimizerAttribute and AbstractModelAttribute lies in the behavior of is_empty, empty! and copy_to. Typically optimizer attributes affect only how the model is solved.\n\n\n\n\n\n","category":"type"},{"location":"reference/models/#MathOptInterface.SolverName","page":"Models","title":"MathOptInterface.SolverName","text":"SolverName()\n\nAn optimizer attribute for the string identifying the solver/optimizer.\n\n\n\n\n\n","category":"type"},{"location":"reference/models/#MathOptInterface.SolverVersion","page":"Models","title":"MathOptInterface.SolverVersion","text":"SolverVersion()\n\nAn optimizer attribute for the string identifying the version of the solver.\n\nnote: Note\nFor solvers supporting semantic versioning, the SolverVersion should be a string of the form \"vMAJOR.MINOR.PATCH\", so that it can be converted to a Julia VersionNumber (e.g., `VersionNumber(\"v1.2.3\")).We do not require Semantic Versioning because some solvers use alternate versioning systems. For example, CPLEX uses Calendar Versioning, so SolverVersion will return a string like \"202001\".\n\n\n\n\n\n","category":"type"},{"location":"reference/models/#MathOptInterface.Silent","page":"Models","title":"MathOptInterface.Silent","text":"Silent()\n\nAn optimizer attribute for silencing the output of an optimizer. When set to true, it takes precedence over any other attribute controlling verbosity and requires the solver to produce no output. The default value is false which has no effect. In this case the verbosity is controlled by other attributes.\n\nNote\n\nEvery optimizer should have verbosity on by default. For instance, if a solver has a solver-specific log level attribute, the MOI implementation should set it to 1 by default. If the user sets Silent to true, then the log level should be set to 0, even if the user specifically sets a value of log level. If the value of Silent is false then the log level set to the solver is the value given by the user for this solver-specific parameter or 1 if none is given.\n\n\n\n\n\n","category":"type"},{"location":"reference/models/#MathOptInterface.TimeLimitSec","page":"Models","title":"MathOptInterface.TimeLimitSec","text":"TimeLimitSec()\n\nAn optimizer attribute for setting a time limit (in seconnds) for an optimization. When set to nothing, it deactivates the solver time limit. The default value is nothing.\n\n\n\n\n\n","category":"type"},{"location":"reference/models/#MathOptInterface.ObjectiveLimit","page":"Models","title":"MathOptInterface.ObjectiveLimit","text":"ObjectiveLimit()\n\nAn optimizer attribute for setting a limit on the objective value.\n\nThe provided limit must be a Union{Real,Nothing}.\n\nWhen set to nothing, the limit reverts to the solver's default.\n\nThe default value is nothing.\n\nThe solver may stop when the ObjectiveValue is better (lower for minimization, higher for maximization) than the ObjectiveLimit. If stopped, the TerminationStatus should be OBJECTIVE_LIMIT.\n\n\n\n\n\n","category":"type"},{"location":"reference/models/#MathOptInterface.RawOptimizerAttribute","page":"Models","title":"MathOptInterface.RawOptimizerAttribute","text":"RawOptimizerAttribute(name::String)\n\nAn optimizer attribute for the solver-specific parameter identified by name.\n\n\n\n\n\n","category":"type"},{"location":"reference/models/#MathOptInterface.NumberOfThreads","page":"Models","title":"MathOptInterface.NumberOfThreads","text":"NumberOfThreads()\n\nAn optimizer attribute for setting the number of threads used for an optimization. When set to nothing uses solver default. Values are positive integers. The default value is nothing.\n\n\n\n\n\n","category":"type"},{"location":"reference/models/#MathOptInterface.RawSolver","page":"Models","title":"MathOptInterface.RawSolver","text":"RawSolver()\n\nA model attribute for the object that may be used to access a solver-specific API for this optimizer.\n\n\n\n\n\n","category":"type"},{"location":"reference/models/#MathOptInterface.AbsoluteGapTolerance","page":"Models","title":"MathOptInterface.AbsoluteGapTolerance","text":"AbsoluteGapTolerance()\n\nAn optimizer attribute for setting the absolute gap tolerance for an optimization. This is an optimizer attribute, and should be set before calling optimize!. When set to nothing (if supported), uses solver default.\n\nTo set a relative gap tolerance, see RelativeGapTolerance.\n\nwarning: Warning\nThe mathematical definition of \"absolute gap\", and its treatment during the optimization, are solver-dependent. However, assuming no other limit nor issue is encountered during the optimization, most solvers that implement this attribute will stop once f - b g_abs, where b is the best bound, f is the best feasible objective value, and g_abs is the absolute gap.\n\n\n\n\n\n","category":"type"},{"location":"reference/models/#MathOptInterface.RelativeGapTolerance","page":"Models","title":"MathOptInterface.RelativeGapTolerance","text":"RelativeGapTolerance()\n\nAn optimizer attribute for setting the relative gap tolerance for an optimization. This is an optimizer attribute, and should be set before calling optimize!. When set to nothing (if supported), uses solver default.\n\nIf you are looking for the relative gap of the current best solution, see RelativeGap. If no limit nor issue is encountered during the optimization, the value of RelativeGap should be at most as large as RelativeGapTolerance.\n\n# Before optimizing: set relative gap tolerance\n# set 0.1% relative gap tolerance\nMOI.set(model, MOI.RelativeGapTolerance(), 1e-3)\nMOI.optimize!(model)\n\n# After optimizing (assuming all went well)\n# The relative gap tolerance has not changed...\nMOI.get(model, MOI.RelativeGapTolerance()) # returns 1e-3\n# ... and the relative gap of the obtained solution is smaller or equal to the\n# tolerance\nMOI.get(model, MOI.RelativeGap()) # should return something ≤ 1e-3\n\nwarning: Warning\nThe mathematical definition of \"relative gap\", and its allowed range, are solver-dependent. Typically, solvers expect a value between 0.0 and 1.0.\n\n\n\n\n\n","category":"type"},{"location":"reference/models/","page":"Models","title":"Models","text":"List of attributes useful for optimizers","category":"page"},{"location":"reference/models/","page":"Models","title":"Models","text":"TerminationStatus\nTerminationStatusCode\nOPTIMIZE_NOT_CALLED\nOPTIMAL\nINFEASIBLE\nDUAL_INFEASIBLE\nLOCALLY_SOLVED\nLOCALLY_INFEASIBLE\nINFEASIBLE_OR_UNBOUNDED\nALMOST_OPTIMAL\nALMOST_INFEASIBLE\nALMOST_DUAL_INFEASIBLE\nALMOST_LOCALLY_SOLVED\nITERATION_LIMIT\nTIME_LIMIT\nNODE_LIMIT\nSOLUTION_LIMIT\nMEMORY_LIMIT\nOBJECTIVE_LIMIT\nNORM_LIMIT\nOTHER_LIMIT\nSLOW_PROGRESS\nNUMERICAL_ERROR\nINVALID_MODEL\nINVALID_OPTION\nINTERRUPTED\nOTHER_ERROR\nPrimalStatus\nDualStatus\nRawStatusString\nResultCount\nObjectiveValue\nDualObjectiveValue\nObjectiveBound\nRelativeGap\nSolveTimeSec\nSimplexIterations\nBarrierIterations\nNodeCount","category":"page"},{"location":"reference/models/#MathOptInterface.TerminationStatus","page":"Models","title":"MathOptInterface.TerminationStatus","text":"TerminationStatus()\n\nA model attribute for the TerminationStatusCode explaining why the optimizer stopped.\n\n\n\n\n\n","category":"type"},{"location":"reference/models/#MathOptInterface.TerminationStatusCode","page":"Models","title":"MathOptInterface.TerminationStatusCode","text":"TerminationStatusCode\n\nAn Enum of possible values for the TerminationStatus attribute. This attribute is meant to explain the reason why the optimizer stopped executing in the most recent call to optimize!.\n\nValues\n\nPossible values are:\n\nOPTIMIZE_NOT_CALLED: The algorithm has not started.\nOPTIMAL: The algorithm found a globally optimal solution.\nINFEASIBLE: The algorithm concluded that no feasible solution exists.\nDUAL_INFEASIBLE: The algorithm concluded that no dual bound exists for the problem. If, additionally, a feasible (primal) solution is known to exist, this status typically implies that the problem is unbounded, with some technical exceptions.\nLOCALLY_SOLVED: The algorithm converged to a stationary point, local optimal solution, could not find directions for improvement, or otherwise completed its search without global guarantees.\nLOCALLY_INFEASIBLE: The algorithm converged to an infeasible point or otherwise completed its search without finding a feasible solution, without guarantees that no feasible solution exists.\nINFEASIBLE_OR_UNBOUNDED: The algorithm stopped because it decided that the problem is infeasible or unbounded; this occasionally happens during MIP presolve.\nALMOST_OPTIMAL: The algorithm found a globally optimal solution to relaxed tolerances.\nALMOST_INFEASIBLE: The algorithm concluded that no feasible solution exists within relaxed tolerances.\nALMOST_DUAL_INFEASIBLE: The algorithm concluded that no dual bound exists for the problem within relaxed tolerances.\nALMOST_LOCALLY_SOLVED: The algorithm converged to a stationary point, local optimal solution, or could not find directions for improvement within relaxed tolerances.\nITERATION_LIMIT: An iterative algorithm stopped after conducting the maximum number of iterations.\nTIME_LIMIT: The algorithm stopped after a user-specified computation time.\nNODE_LIMIT: A branch-and-bound algorithm stopped because it explored a maximum number of nodes in the branch-and-bound tree.\nSOLUTION_LIMIT: The algorithm stopped because it found the required number of solutions. This is often used in MIPs to get the solver to return the first feasible solution it encounters.\nMEMORY_LIMIT: The algorithm stopped because it ran out of memory.\nOBJECTIVE_LIMIT: The algorithm stopped because it found a solution better than a minimum limit set by the user.\nNORM_LIMIT: The algorithm stopped because the norm of an iterate became too large.\nOTHER_LIMIT: The algorithm stopped due to a limit not covered by one of the _LIMIT_ statuses above.\nSLOW_PROGRESS: The algorithm stopped because it was unable to continue making progress towards the solution.\nNUMERICAL_ERROR: The algorithm stopped because it encountered unrecoverable numerical error.\nINVALID_MODEL: The algorithm stopped because the model is invalid.\nINVALID_OPTION: The algorithm stopped because it was provided an invalid option.\nINTERRUPTED: The algorithm stopped because of an interrupt signal.\nOTHER_ERROR: The algorithm stopped because of an error not covered by one of the statuses defined above.\n\n\n\n\n\n","category":"type"},{"location":"reference/models/#MathOptInterface.OPTIMIZE_NOT_CALLED","page":"Models","title":"MathOptInterface.OPTIMIZE_NOT_CALLED","text":"OPTIMIZE_NOT_CALLED::TerminationStatusCode\n\nAn instance of the TerminationStatusCode enum.\n\nOPTIMIZE_NOT_CALLED: The algorithm has not started.\n\n\n\n\n\n","category":"constant"},{"location":"reference/models/#MathOptInterface.OPTIMAL","page":"Models","title":"MathOptInterface.OPTIMAL","text":"OPTIMAL::TerminationStatusCode\n\nAn instance of the TerminationStatusCode enum.\n\nOPTIMAL: The algorithm found a globally optimal solution.\n\n\n\n\n\n","category":"constant"},{"location":"reference/models/#MathOptInterface.INFEASIBLE","page":"Models","title":"MathOptInterface.INFEASIBLE","text":"INFEASIBLE::TerminationStatusCode\n\nAn instance of the TerminationStatusCode enum.\n\nINFEASIBLE: The algorithm concluded that no feasible solution exists.\n\n\n\n\n\n","category":"constant"},{"location":"reference/models/#MathOptInterface.DUAL_INFEASIBLE","page":"Models","title":"MathOptInterface.DUAL_INFEASIBLE","text":"DUAL_INFEASIBLE::TerminationStatusCode\n\nAn instance of the TerminationStatusCode enum.\n\nDUAL_INFEASIBLE: The algorithm concluded that no dual bound exists for the problem. If, additionally, a feasible (primal) solution is known to exist, this status typically implies that the problem is unbounded, with some technical exceptions.\n\n\n\n\n\n","category":"constant"},{"location":"reference/models/#MathOptInterface.LOCALLY_SOLVED","page":"Models","title":"MathOptInterface.LOCALLY_SOLVED","text":"LOCALLY_SOLVED::TerminationStatusCode\n\nAn instance of the TerminationStatusCode enum.\n\nLOCALLY_SOLVED: The algorithm converged to a stationary point, local optimal solution, could not find directions for improvement, or otherwise completed its search without global guarantees.\n\n\n\n\n\n","category":"constant"},{"location":"reference/models/#MathOptInterface.LOCALLY_INFEASIBLE","page":"Models","title":"MathOptInterface.LOCALLY_INFEASIBLE","text":"LOCALLY_INFEASIBLE::TerminationStatusCode\n\nAn instance of the TerminationStatusCode enum.\n\nLOCALLY_INFEASIBLE: The algorithm converged to an infeasible point or otherwise completed its search without finding a feasible solution, without guarantees that no feasible solution exists.\n\n\n\n\n\n","category":"constant"},{"location":"reference/models/#MathOptInterface.INFEASIBLE_OR_UNBOUNDED","page":"Models","title":"MathOptInterface.INFEASIBLE_OR_UNBOUNDED","text":"INFEASIBLE_OR_UNBOUNDED::TerminationStatusCode\n\nAn instance of the TerminationStatusCode enum.\n\nINFEASIBLE_OR_UNBOUNDED: The algorithm stopped because it decided that the problem is infeasible or unbounded; this occasionally happens during MIP presolve.\n\n\n\n\n\n","category":"constant"},{"location":"reference/models/#MathOptInterface.ALMOST_OPTIMAL","page":"Models","title":"MathOptInterface.ALMOST_OPTIMAL","text":"ALMOST_OPTIMAL::TerminationStatusCode\n\nAn instance of the TerminationStatusCode enum.\n\nALMOST_OPTIMAL: The algorithm found a globally optimal solution to relaxed tolerances.\n\n\n\n\n\n","category":"constant"},{"location":"reference/models/#MathOptInterface.ALMOST_INFEASIBLE","page":"Models","title":"MathOptInterface.ALMOST_INFEASIBLE","text":"ALMOST_INFEASIBLE::TerminationStatusCode\n\nAn instance of the TerminationStatusCode enum.\n\nALMOST_INFEASIBLE: The algorithm concluded that no feasible solution exists within relaxed tolerances.\n\n\n\n\n\n","category":"constant"},{"location":"reference/models/#MathOptInterface.ALMOST_DUAL_INFEASIBLE","page":"Models","title":"MathOptInterface.ALMOST_DUAL_INFEASIBLE","text":"ALMOST_DUAL_INFEASIBLE::TerminationStatusCode\n\nAn instance of the TerminationStatusCode enum.\n\nALMOST_DUAL_INFEASIBLE: The algorithm concluded that no dual bound exists for the problem within relaxed tolerances.\n\n\n\n\n\n","category":"constant"},{"location":"reference/models/#MathOptInterface.ALMOST_LOCALLY_SOLVED","page":"Models","title":"MathOptInterface.ALMOST_LOCALLY_SOLVED","text":"ALMOST_LOCALLY_SOLVED::TerminationStatusCode\n\nAn instance of the TerminationStatusCode enum.\n\nALMOST_LOCALLY_SOLVED: The algorithm converged to a stationary point, local optimal solution, or could not find directions for improvement within relaxed tolerances.\n\n\n\n\n\n","category":"constant"},{"location":"reference/models/#MathOptInterface.ITERATION_LIMIT","page":"Models","title":"MathOptInterface.ITERATION_LIMIT","text":"ITERATION_LIMIT::TerminationStatusCode\n\nAn instance of the TerminationStatusCode enum.\n\nITERATION_LIMIT: An iterative algorithm stopped after conducting the maximum number of iterations.\n\n\n\n\n\n","category":"constant"},{"location":"reference/models/#MathOptInterface.TIME_LIMIT","page":"Models","title":"MathOptInterface.TIME_LIMIT","text":"TIME_LIMIT::TerminationStatusCode\n\nAn instance of the TerminationStatusCode enum.\n\nTIME_LIMIT: The algorithm stopped after a user-specified computation time.\n\n\n\n\n\n","category":"constant"},{"location":"reference/models/#MathOptInterface.NODE_LIMIT","page":"Models","title":"MathOptInterface.NODE_LIMIT","text":"NODE_LIMIT::TerminationStatusCode\n\nAn instance of the TerminationStatusCode enum.\n\nNODE_LIMIT: A branch-and-bound algorithm stopped because it explored a maximum number of nodes in the branch-and-bound tree.\n\n\n\n\n\n","category":"constant"},{"location":"reference/models/#MathOptInterface.SOLUTION_LIMIT","page":"Models","title":"MathOptInterface.SOLUTION_LIMIT","text":"SOLUTION_LIMIT::TerminationStatusCode\n\nAn instance of the TerminationStatusCode enum.\n\nSOLUTION_LIMIT: The algorithm stopped because it found the required number of solutions. This is often used in MIPs to get the solver to return the first feasible solution it encounters.\n\n\n\n\n\n","category":"constant"},{"location":"reference/models/#MathOptInterface.MEMORY_LIMIT","page":"Models","title":"MathOptInterface.MEMORY_LIMIT","text":"MEMORY_LIMIT::TerminationStatusCode\n\nAn instance of the TerminationStatusCode enum.\n\nMEMORY_LIMIT: The algorithm stopped because it ran out of memory.\n\n\n\n\n\n","category":"constant"},{"location":"reference/models/#MathOptInterface.OBJECTIVE_LIMIT","page":"Models","title":"MathOptInterface.OBJECTIVE_LIMIT","text":"OBJECTIVE_LIMIT::TerminationStatusCode\n\nAn instance of the TerminationStatusCode enum.\n\nOBJECTIVE_LIMIT: The algorithm stopped because it found a solution better than a minimum limit set by the user.\n\n\n\n\n\n","category":"constant"},{"location":"reference/models/#MathOptInterface.NORM_LIMIT","page":"Models","title":"MathOptInterface.NORM_LIMIT","text":"NORM_LIMIT::TerminationStatusCode\n\nAn instance of the TerminationStatusCode enum.\n\nNORM_LIMIT: The algorithm stopped because the norm of an iterate became too large.\n\n\n\n\n\n","category":"constant"},{"location":"reference/models/#MathOptInterface.OTHER_LIMIT","page":"Models","title":"MathOptInterface.OTHER_LIMIT","text":"OTHER_LIMIT::TerminationStatusCode\n\nAn instance of the TerminationStatusCode enum.\n\nOTHER_LIMIT: The algorithm stopped due to a limit not covered by one of the _LIMIT_ statuses above.\n\n\n\n\n\n","category":"constant"},{"location":"reference/models/#MathOptInterface.SLOW_PROGRESS","page":"Models","title":"MathOptInterface.SLOW_PROGRESS","text":"SLOW_PROGRESS::TerminationStatusCode\n\nAn instance of the TerminationStatusCode enum.\n\nSLOW_PROGRESS: The algorithm stopped because it was unable to continue making progress towards the solution.\n\n\n\n\n\n","category":"constant"},{"location":"reference/models/#MathOptInterface.NUMERICAL_ERROR","page":"Models","title":"MathOptInterface.NUMERICAL_ERROR","text":"NUMERICAL_ERROR::TerminationStatusCode\n\nAn instance of the TerminationStatusCode enum.\n\nNUMERICAL_ERROR: The algorithm stopped because it encountered unrecoverable numerical error.\n\n\n\n\n\n","category":"constant"},{"location":"reference/models/#MathOptInterface.INVALID_MODEL","page":"Models","title":"MathOptInterface.INVALID_MODEL","text":"INVALID_MODEL::TerminationStatusCode\n\nAn instance of the TerminationStatusCode enum.\n\nINVALID_MODEL: The algorithm stopped because the model is invalid.\n\n\n\n\n\n","category":"constant"},{"location":"reference/models/#MathOptInterface.INVALID_OPTION","page":"Models","title":"MathOptInterface.INVALID_OPTION","text":"INVALID_OPTION::TerminationStatusCode\n\nAn instance of the TerminationStatusCode enum.\n\nINVALID_OPTION: The algorithm stopped because it was provided an invalid option.\n\n\n\n\n\n","category":"constant"},{"location":"reference/models/#MathOptInterface.INTERRUPTED","page":"Models","title":"MathOptInterface.INTERRUPTED","text":"INTERRUPTED::TerminationStatusCode\n\nAn instance of the TerminationStatusCode enum.\n\nINTERRUPTED: The algorithm stopped because of an interrupt signal.\n\n\n\n\n\n","category":"constant"},{"location":"reference/models/#MathOptInterface.OTHER_ERROR","page":"Models","title":"MathOptInterface.OTHER_ERROR","text":"OTHER_ERROR::TerminationStatusCode\n\nAn instance of the TerminationStatusCode enum.\n\nOTHER_ERROR: The algorithm stopped because of an error not covered by one of the statuses defined above.\n\n\n\n\n\n","category":"constant"},{"location":"reference/models/#MathOptInterface.PrimalStatus","page":"Models","title":"MathOptInterface.PrimalStatus","text":"PrimalStatus(result_index::Int = 1)\n\nA model attribute for the ResultStatusCode of the primal result result_index. If result_index is omitted, it defaults to 1.\n\nSee ResultCount for information on how the results are ordered.\n\nIf result_index is larger than the value of ResultCount then NO_SOLUTION is returned.\n\n\n\n\n\n","category":"type"},{"location":"reference/models/#MathOptInterface.DualStatus","page":"Models","title":"MathOptInterface.DualStatus","text":"DualStatus(result_index::Int = 1)\n\nA model attribute for the ResultStatusCode of the dual result result_index. If result_index is omitted, it defaults to 1.\n\nSee ResultCount for information on how the results are ordered.\n\nIf result_index is larger than the value of ResultCount then NO_SOLUTION is returned.\n\n\n\n\n\n","category":"type"},{"location":"reference/models/#MathOptInterface.RawStatusString","page":"Models","title":"MathOptInterface.RawStatusString","text":"RawStatusString()\n\nA model attribute for a solver specific string explaining why the optimizer stopped.\n\n\n\n\n\n","category":"type"},{"location":"reference/models/#MathOptInterface.ResultCount","page":"Models","title":"MathOptInterface.ResultCount","text":"ResultCount()\n\nA model attribute for the number of results available.\n\nOrder of solutions\n\nA number of attributes contain an index, result_index, which is used to refer to one of the available results. Thus, result_index must be an integer between 1 and the number of available results.\n\nAs a general rule, the first result (result_index=1) is the most important result (e.g., an optimal solution or an infeasibility certificate). Other results will typically be alternate solutions that the solver found during the search for the first result.\n\nIf a (local) optimal solution is available, i.e., TerminationStatus is OPTIMAL or LOCALLY_SOLVED, the first result must correspond to the (locally) optimal solution. Other results may be alternative optimal solutions, or they may be other suboptimal solutions; use ObjectiveValue to distingiush between them.\n\nIf a primal or dual infeasibility certificate is available, i.e., TerminationStatus is INFEASIBLE or DUAL_INFEASIBLE and the corresponding PrimalStatus or DualStatus is INFEASIBILITY_CERTIFICATE, then the first result must be a certificate. Other results may be alternate certificates, or infeasible points.\n\n\n\n\n\n","category":"type"},{"location":"reference/models/#MathOptInterface.ObjectiveValue","page":"Models","title":"MathOptInterface.ObjectiveValue","text":"ObjectiveValue(result_index::Int = 1)\n\nA model attribute for the objective value of the primal solution result_index.\n\nIf the solver does not have a primal value for the objective because the result_index is beyond the available solutions (whose number is indicated by the ResultCount attribute), getting this attribute must throw a ResultIndexBoundsError. Otherwise, if the result is unavailable for another reason (for instance, only a dual solution is available), the result is undefined. Users should first check PrimalStatus before accessing the ObjectiveValue attribute.\n\nSee ResultCount for information on how the results are ordered.\n\n\n\n\n\n","category":"type"},{"location":"reference/models/#MathOptInterface.DualObjectiveValue","page":"Models","title":"MathOptInterface.DualObjectiveValue","text":"DualObjectiveValue(result_index::Int = 1)\n\nA model attribute for the value of the objective function of the dual problem for the result_indexth dual result.\n\nIf the solver does not have a dual value for the objective because the result_index is beyond the available solutions (whose number is indicated by the ResultCount attribute), getting this attribute must throw a ResultIndexBoundsError. Otherwise, if the result is unavailable for another reason (for instance, only a primal solution is available), the result is undefined. Users should first check DualStatus before accessing the DualObjectiveValue attribute.\n\nSee ResultCount for information on how the results are ordered.\n\n\n\n\n\n","category":"type"},{"location":"reference/models/#MathOptInterface.ObjectiveBound","page":"Models","title":"MathOptInterface.ObjectiveBound","text":"ObjectiveBound()\n\nA model attribute for the best known bound on the optimal objective value.\n\n\n\n\n\n","category":"type"},{"location":"reference/models/#MathOptInterface.RelativeGap","page":"Models","title":"MathOptInterface.RelativeGap","text":"RelativeGap()\n\nA model attribute for the final relative optimality gap.\n\nwarning: Warning\nThe definition of this gap is solver-dependent. However, most solvers implementing this attribute define the relative gap as some variation of fracb-ff, where b is the best bound and f is the best feasible objective value.\n\n\n\n\n\n","category":"type"},{"location":"reference/models/#MathOptInterface.SolveTimeSec","page":"Models","title":"MathOptInterface.SolveTimeSec","text":"SolveTimeSec()\n\nA model attribute for the total elapsed solution time (in seconds) as reported by the optimizer.\n\n\n\n\n\n","category":"type"},{"location":"reference/models/#MathOptInterface.SimplexIterations","page":"Models","title":"MathOptInterface.SimplexIterations","text":"SimplexIterations()\n\nA model attribute for the cumulative number of simplex iterations during the optimization process.\n\nFor a mixed-integer program (MIP), the return value is the total simplex iterations for all nodes.\n\n\n\n\n\n","category":"type"},{"location":"reference/models/#MathOptInterface.BarrierIterations","page":"Models","title":"MathOptInterface.BarrierIterations","text":"BarrierIterations()\n\nA model attribute for the cumulative number of barrier iterations while solving a problem.\n\n\n\n\n\n","category":"type"},{"location":"reference/models/#MathOptInterface.NodeCount","page":"Models","title":"MathOptInterface.NodeCount","text":"NodeCount()\n\nA model attribute for the total number of branch-and-bound nodes explored while solving a mixed-integer program (MIP).\n\n\n\n\n\n","category":"type"},{"location":"reference/models/#ResultStatusCode","page":"Models","title":"ResultStatusCode","text":"","category":"section"},{"location":"reference/models/","page":"Models","title":"Models","text":"ResultStatusCode\nNO_SOLUTION\nFEASIBLE_POINT\nNEARLY_FEASIBLE_POINT\nINFEASIBLE_POINT\nINFEASIBILITY_CERTIFICATE\nNEARLY_INFEASIBILITY_CERTIFICATE\nREDUCTION_CERTIFICATE\nNEARLY_REDUCTION_CERTIFICATE\nUNKNOWN_RESULT_STATUS\nOTHER_RESULT_STATUS","category":"page"},{"location":"reference/models/#MathOptInterface.ResultStatusCode","page":"Models","title":"MathOptInterface.ResultStatusCode","text":"ResultStatusCode\n\nAn Enum of possible values for the PrimalStatus and DualStatus attributes.\n\nThe values indicate how to interpret the result vector.\n\nValues\n\nPossible values are:\n\nNO_SOLUTION: the result vector is empty.\nFEASIBLE_POINT: the result vector is a feasible point.\nNEARLY_FEASIBLE_POINT: the result vector is feasible if some constraint tolerances are relaxed.\nINFEASIBLE_POINT: the result vector is an infeasible point.\nINFEASIBILITY_CERTIFICATE: the result vector is an infeasibility certificate. If the PrimalStatus is INFEASIBILITY_CERTIFICATE, then the primal result vector is a certificate of dual infeasibility. If the DualStatus is INFEASIBILITY_CERTIFICATE, then the dual result vector is a proof of primal infeasibility.\nNEARLY_INFEASIBILITY_CERTIFICATE: the result satisfies a relaxed criterion for a certificate of infeasibility.\nREDUCTION_CERTIFICATE: the result vector is an ill-posed certificate; see this article for details. If the PrimalStatus is REDUCTION_CERTIFICATE, then the primal result vector is a proof that the dual problem is ill-posed. If the DualStatus is REDUCTION_CERTIFICATE, then the dual result vector is a proof that the primal is ill-posed.\nNEARLY_REDUCTION_CERTIFICATE: the result satisfies a relaxed criterion for an ill-posed certificate.\nUNKNOWN_RESULT_STATUS: the result vector contains a solution with an unknown interpretation.\nOTHER_RESULT_STATUS: the result vector contains a solution with an interpretation not covered by one of the statuses defined above\n\n\n\n\n\n","category":"type"},{"location":"reference/models/#MathOptInterface.NO_SOLUTION","page":"Models","title":"MathOptInterface.NO_SOLUTION","text":"NO_SOLUTION::ResultStatusCode\n\nAn instance of the ResultStatusCode enum.\n\nNO_SOLUTION: the result vector is empty.\n\n\n\n\n\n","category":"constant"},{"location":"reference/models/#MathOptInterface.FEASIBLE_POINT","page":"Models","title":"MathOptInterface.FEASIBLE_POINT","text":"FEASIBLE_POINT::ResultStatusCode\n\nAn instance of the ResultStatusCode enum.\n\nFEASIBLE_POINT: the result vector is a feasible point.\n\n\n\n\n\n","category":"constant"},{"location":"reference/models/#MathOptInterface.NEARLY_FEASIBLE_POINT","page":"Models","title":"MathOptInterface.NEARLY_FEASIBLE_POINT","text":"NEARLY_FEASIBLE_POINT::ResultStatusCode\n\nAn instance of the ResultStatusCode enum.\n\nNEARLY_FEASIBLE_POINT: the result vector is feasible if some constraint tolerances are relaxed.\n\n\n\n\n\n","category":"constant"},{"location":"reference/models/#MathOptInterface.INFEASIBLE_POINT","page":"Models","title":"MathOptInterface.INFEASIBLE_POINT","text":"INFEASIBLE_POINT::ResultStatusCode\n\nAn instance of the ResultStatusCode enum.\n\nINFEASIBLE_POINT: the result vector is an infeasible point.\n\n\n\n\n\n","category":"constant"},{"location":"reference/models/#MathOptInterface.INFEASIBILITY_CERTIFICATE","page":"Models","title":"MathOptInterface.INFEASIBILITY_CERTIFICATE","text":"INFEASIBILITY_CERTIFICATE::ResultStatusCode\n\nAn instance of the ResultStatusCode enum.\n\nINFEASIBILITY_CERTIFICATE: the result vector is an infeasibility certificate. If the PrimalStatus is INFEASIBILITY_CERTIFICATE, then the primal result vector is a certificate of dual infeasibility. If the DualStatus is INFEASIBILITY_CERTIFICATE, then the dual result vector is a proof of primal infeasibility.\n\n\n\n\n\n","category":"constant"},{"location":"reference/models/#MathOptInterface.NEARLY_INFEASIBILITY_CERTIFICATE","page":"Models","title":"MathOptInterface.NEARLY_INFEASIBILITY_CERTIFICATE","text":"NEARLY_INFEASIBILITY_CERTIFICATE::ResultStatusCode\n\nAn instance of the ResultStatusCode enum.\n\nNEARLY_INFEASIBILITY_CERTIFICATE: the result satisfies a relaxed criterion for a certificate of infeasibility.\n\n\n\n\n\n","category":"constant"},{"location":"reference/models/#MathOptInterface.REDUCTION_CERTIFICATE","page":"Models","title":"MathOptInterface.REDUCTION_CERTIFICATE","text":"REDUCTION_CERTIFICATE::ResultStatusCode\n\nAn instance of the ResultStatusCode enum.\n\nREDUCTION_CERTIFICATE: the result vector is an ill-posed certificate; see this article for details. If the PrimalStatus is REDUCTION_CERTIFICATE, then the primal result vector is a proof that the dual problem is ill-posed. If the DualStatus is REDUCTION_CERTIFICATE, then the dual result vector is a proof that the primal is ill-posed.\n\n\n\n\n\n","category":"constant"},{"location":"reference/models/#MathOptInterface.NEARLY_REDUCTION_CERTIFICATE","page":"Models","title":"MathOptInterface.NEARLY_REDUCTION_CERTIFICATE","text":"NEARLY_REDUCTION_CERTIFICATE::ResultStatusCode\n\nAn instance of the ResultStatusCode enum.\n\nNEARLY_REDUCTION_CERTIFICATE: the result satisfies a relaxed criterion for an ill-posed certificate.\n\n\n\n\n\n","category":"constant"},{"location":"reference/models/#MathOptInterface.UNKNOWN_RESULT_STATUS","page":"Models","title":"MathOptInterface.UNKNOWN_RESULT_STATUS","text":"UNKNOWN_RESULT_STATUS::ResultStatusCode\n\nAn instance of the ResultStatusCode enum.\n\nUNKNOWN_RESULT_STATUS: the result vector contains a solution with an unknown interpretation.\n\n\n\n\n\n","category":"constant"},{"location":"reference/models/#MathOptInterface.OTHER_RESULT_STATUS","page":"Models","title":"MathOptInterface.OTHER_RESULT_STATUS","text":"OTHER_RESULT_STATUS::ResultStatusCode\n\nAn instance of the ResultStatusCode enum.\n\nOTHER_RESULT_STATUS: the result vector contains a solution with an interpretation not covered by one of the statuses defined above\n\n\n\n\n\n","category":"constant"},{"location":"reference/models/#Conflict-Status","page":"Models","title":"Conflict Status","text":"","category":"section"},{"location":"reference/models/","page":"Models","title":"Models","text":"compute_conflict!\nConflictStatus\nConstraintConflictStatus\nConflictStatusCode\nConflictParticipationStatusCode\nNOT_IN_CONFLICT\nIN_CONFLICT\nMAYBE_IN_CONFLICT","category":"page"},{"location":"reference/models/#MathOptInterface.compute_conflict!","page":"Models","title":"MathOptInterface.compute_conflict!","text":"compute_conflict!(optimizer::AbstractOptimizer)\n\nComputes a minimal subset of constraints such that the model with the other constraint removed is still infeasible.\n\nSome solvers call a set of conflicting constraints an Irreducible Inconsistent Subsystem (IIS).\n\nSee also ConflictStatus and ConstraintConflictStatus.\n\nNote\n\nIf the model is modified after a call to compute_conflict!, the implementor is not obliged to purge the conflict. Any calls to the above attributes may return values for the original conflict without a warning. Similarly, when modifying the model, the conflict can be discarded.\n\n\n\n\n\n","category":"function"},{"location":"reference/models/#MathOptInterface.ConflictStatus","page":"Models","title":"MathOptInterface.ConflictStatus","text":"ConflictStatus()\n\nA model attribute for the ConflictStatusCode explaining why the conflict refiner stopped when computing the conflict.\n\n\n\n\n\n","category":"type"},{"location":"reference/models/#MathOptInterface.ConstraintConflictStatus","page":"Models","title":"MathOptInterface.ConstraintConflictStatus","text":"ConstraintConflictStatus()\n\nA constraint attribute indicating whether the constraint participates in the conflict. Its type is ConflictParticipationStatusCode.\n\n\n\n\n\n","category":"type"},{"location":"reference/models/#MathOptInterface.ConflictStatusCode","page":"Models","title":"MathOptInterface.ConflictStatusCode","text":"ConflictStatusCode\n\nAn Enum of possible values for the ConflictStatus attribute. This attribute is meant to explain the reason why the conflict finder stopped executing in the most recent call to compute_conflict!.\n\nPossible values are:\n\nCOMPUTE_CONFLICT_NOT_CALLED: the function compute_conflict! has not yet been called\nNO_CONFLICT_EXISTS: there is no conflict because the problem is feasible\nNO_CONFLICT_FOUND: the solver could not find a conflict\nCONFLICT_FOUND: at least one conflict could be found\n\n\n\n\n\n","category":"type"},{"location":"reference/models/#MathOptInterface.ConflictParticipationStatusCode","page":"Models","title":"MathOptInterface.ConflictParticipationStatusCode","text":"ConflictParticipationStatusCode\n\nAn Enum of possible values for the ConstraintConflictStatus attribute. This attribute is meant to indicate whether a given constraint participates or not in the last computed conflict.\n\nValues\n\nPossible values are:\n\nNOT_IN_CONFLICT: the constraint does not participate in the conflict\nIN_CONFLICT: the constraint participates in the conflict\nMAYBE_IN_CONFLICT: the constraint may participate in the conflict, the solver was not able to prove that the constraint can be excluded from the conflict\n\n\n\n\n\n","category":"type"},{"location":"reference/models/#MathOptInterface.NOT_IN_CONFLICT","page":"Models","title":"MathOptInterface.NOT_IN_CONFLICT","text":"NOT_IN_CONFLICT::ConflictParticipationStatusCode\n\nAn instance of the ConflictParticipationStatusCode enum.\n\nNOT_IN_CONFLICT: the constraint does not participate in the conflict\n\n\n\n\n\n","category":"constant"},{"location":"reference/models/#MathOptInterface.IN_CONFLICT","page":"Models","title":"MathOptInterface.IN_CONFLICT","text":"IN_CONFLICT::ConflictParticipationStatusCode\n\nAn instance of the ConflictParticipationStatusCode enum.\n\nIN_CONFLICT: the constraint participates in the conflict\n\n\n\n\n\n","category":"constant"},{"location":"reference/models/#MathOptInterface.MAYBE_IN_CONFLICT","page":"Models","title":"MathOptInterface.MAYBE_IN_CONFLICT","text":"MAYBE_IN_CONFLICT::ConflictParticipationStatusCode\n\nAn instance of the ConflictParticipationStatusCode enum.\n\nMAYBE_IN_CONFLICT: the constraint may participate in the conflict, the solver was not able to prove that the constraint can be excluded from the conflict\n\n\n\n\n\n","category":"constant"},{"location":"submodules/Utilities/overview/","page":"Overview","title":"Overview","text":"CurrentModule = MathOptInterface\nDocTestSetup = quote\n import MathOptInterface as MOI\nend\nDocTestFilters = [r\"MathOptInterface|MOI\"]","category":"page"},{"location":"submodules/Utilities/overview/#The-Utilities-submodule","page":"Overview","title":"The Utilities submodule","text":"","category":"section"},{"location":"submodules/Utilities/overview/","page":"Overview","title":"Overview","text":"The Utilities submodule provides a variety of functions and datastructures for managing MOI.ModelLike objects.","category":"page"},{"location":"submodules/Utilities/overview/#Utilities.Model","page":"Overview","title":"Utilities.Model","text":"","category":"section"},{"location":"submodules/Utilities/overview/","page":"Overview","title":"Overview","text":"Utilities.Model provides an implementation of a ModelLike that efficiently supports all functions and sets defined within MOI. However, given the extensibility of MOI, this might not cover all use cases.","category":"page"},{"location":"submodules/Utilities/overview/","page":"Overview","title":"Overview","text":"Create a model as follows:","category":"page"},{"location":"submodules/Utilities/overview/","page":"Overview","title":"Overview","text":"julia> model = MOI.Utilities.Model{Float64}()\nMOIU.Model{Float64}","category":"page"},{"location":"submodules/Utilities/overview/#Utilities.UniversalFallback","page":"Overview","title":"Utilities.UniversalFallback","text":"","category":"section"},{"location":"submodules/Utilities/overview/","page":"Overview","title":"Overview","text":"Utilities.UniversalFallback is a layer that sits on top of any ModelLike and provides non-specialized (slower) fallbacks for constraints and attributes that the underlying ModelLike does not support.","category":"page"},{"location":"submodules/Utilities/overview/","page":"Overview","title":"Overview","text":"For example, Utilities.Model doesn't support some variable attributes like VariablePrimalStart, so JuMP uses a combination of Universal fallback and Utilities.Model as a generic problem cache:","category":"page"},{"location":"submodules/Utilities/overview/","page":"Overview","title":"Overview","text":"julia> model = MOI.Utilities.UniversalFallback(MOI.Utilities.Model{Float64}())\nMOIU.UniversalFallback{MOIU.Model{Float64}}\nfallback for MOIU.Model{Float64}","category":"page"},{"location":"submodules/Utilities/overview/","page":"Overview","title":"Overview","text":"warning: Warning\nAdding a UniversalFallback means that your model will now support all constraints, even if the inner-model does not. This can lead to unexpected behavior.","category":"page"},{"location":"submodules/Utilities/overview/#Utilities.@model","page":"Overview","title":"Utilities.@model","text":"","category":"section"},{"location":"submodules/Utilities/overview/","page":"Overview","title":"Overview","text":"For advanced use cases that need efficient support for functions and sets defined outside of MOI (but still known at compile time), we provide the Utilities.@model macro.","category":"page"},{"location":"submodules/Utilities/overview/","page":"Overview","title":"Overview","text":"The @model macro takes a name (for a new type, which must not exist yet), eight tuples specifying the types of constraints that are supported, and then a Bool indicating the type is a subtype of MOI.AbstractOptimizer (if true) or MOI.ModelLike (if false).","category":"page"},{"location":"submodules/Utilities/overview/","page":"Overview","title":"Overview","text":"The eight tuples are in the following order:","category":"page"},{"location":"submodules/Utilities/overview/","page":"Overview","title":"Overview","text":"Un-typed scalar sets, for example, Integer\nTyped scalar sets, for example, LessThan\nUn-typed vector sets, for example, Nonnegatives\nTyped vector sets, for example, PowerCone\nUn-typed scalar functions, for example, VariableIndex\nTyped scalar functions, for example, ScalarAffineFunction\nUn-typed vector functions, for example, VectorOfVariables\nTyped vector functions, for example, VectorAffineFunction","category":"page"},{"location":"submodules/Utilities/overview/","page":"Overview","title":"Overview","text":"The tuples can contain more than one element. Typed-sets must be specified without their type parameter, for example, MOI.LessThan, not MOI.LessThan{Float64}.","category":"page"},{"location":"submodules/Utilities/overview/","page":"Overview","title":"Overview","text":"Here is an example:","category":"page"},{"location":"submodules/Utilities/overview/","page":"Overview","title":"Overview","text":"julia> MOI.Utilities.@model(\n MyNewModel,\n (MOI.Integer,), # Un-typed scalar sets\n (MOI.GreaterThan,), # Typed scalar sets\n (MOI.Nonnegatives,), # Un-typed vector sets\n (MOI.PowerCone,), # Typed vector sets\n (MOI.VariableIndex,), # Un-typed scalar functions\n (MOI.ScalarAffineFunction,), # Typed scalar functions\n (MOI.VectorOfVariables,), # Un-typed vector functions\n (MOI.VectorAffineFunction,), # Typed vector functions\n true, # <:MOI.AbstractOptimizer?\n )\nMathOptInterface.Utilities.GenericOptimizer{T, MathOptInterface.Utilities.ObjectiveContainer{T}, MathOptInterface.Utilities.VariablesContainer{T}, MyNewModelFunctionConstraints{T}} where T\n\njulia> model = MyNewModel{Float64}()\nMOIU.GenericOptimizer{Float64, MOIU.ObjectiveContainer{Float64}, MOIU.VariablesContainer{Float64}, MyNewModelFunctionConstraints{Float64}}","category":"page"},{"location":"submodules/Utilities/overview/","page":"Overview","title":"Overview","text":"warning: Warning\nMyNewModel supports every VariableIndex-in-Set constraint, as well as VariableIndex, ScalarAffineFunction, and ScalarQuadraticFunction objective functions. Implement MOI.supports as needed to forbid constraint and objective function combinations.","category":"page"},{"location":"submodules/Utilities/overview/","page":"Overview","title":"Overview","text":"As another example, PATHSolver, which only supports VectorAffineFunction-in-Complements defines its optimizer as:","category":"page"},{"location":"submodules/Utilities/overview/","page":"Overview","title":"Overview","text":"julia> MOI.Utilities.@model(\n PathOptimizer,\n (), # Scalar sets\n (), # Typed scalar sets\n (MOI.Complements,), # Vector sets\n (), # Typed vector sets\n (), # Scalar functions\n (), # Typed scalar functions\n (), # Vector functions\n (MOI.VectorAffineFunction,), # Typed vector functions\n true, # is_optimizer\n )\nMathOptInterface.Utilities.GenericOptimizer{T, MathOptInterface.Utilities.ObjectiveContainer{T}, MathOptInterface.Utilities.VariablesContainer{T}, MathOptInterface.Utilities.VectorOfConstraints{MathOptInterface.VectorAffineFunction{T}, MathOptInterface.Complements}} where T","category":"page"},{"location":"submodules/Utilities/overview/","page":"Overview","title":"Overview","text":"However, PathOptimizer does not support some VariableIndex-in-Set constraints, so we must explicitly define:","category":"page"},{"location":"submodules/Utilities/overview/","page":"Overview","title":"Overview","text":"julia> function MOI.supports_constraint(\n ::PathOptimizer,\n ::Type{MOI.VariableIndex},\n ::Type{Union{<:MOI.Semiinteger,MOI.Semicontinuous,MOI.ZeroOne,MOI.Integer}}\n )\n return false\n end","category":"page"},{"location":"submodules/Utilities/overview/","page":"Overview","title":"Overview","text":"Finally, PATH doesn't support an objective function, so we need to add:","category":"page"},{"location":"submodules/Utilities/overview/","page":"Overview","title":"Overview","text":"julia> MOI.supports(::PathOptimizer, ::MOI.ObjectiveFunction) = false","category":"page"},{"location":"submodules/Utilities/overview/","page":"Overview","title":"Overview","text":"warning: Warning\nThis macro creates a new type, so it must be called from the top-level of a module, for example, it cannot be called from inside a function.","category":"page"},{"location":"submodules/Utilities/overview/#Utilities.CachingOptimizer","page":"Overview","title":"Utilities.CachingOptimizer","text":"","category":"section"},{"location":"submodules/Utilities/overview/","page":"Overview","title":"Overview","text":"A [Utilities.CachingOptimizer] is an MOI layer that abstracts the difference between solvers that support incremental modification (for example, they support adding variables one-by-one), and solvers that require the entire problem in a single API call (for example, they only accept the A, b and c matrices of a linear program).","category":"page"},{"location":"submodules/Utilities/overview/","page":"Overview","title":"Overview","text":"It has two parts:","category":"page"},{"location":"submodules/Utilities/overview/","page":"Overview","title":"Overview","text":"A cache, where the model can be built and modified incrementally\nAn optimizer, which is used to solve the problem","category":"page"},{"location":"submodules/Utilities/overview/","page":"Overview","title":"Overview","text":"julia> model = MOI.Utilities.CachingOptimizer(\n MOI.Utilities.Model{Float64}(),\n PathOptimizer{Float64}(),\n )\nMOIU.CachingOptimizer{MOIU.GenericOptimizer{Float64, MOIU.ObjectiveContainer{Float64}, MOIU.VariablesContainer{Float64}, MOIU.VectorOfConstraints{MOI.VectorAffineFunction{Float64}, MOI.Complements}}, MOIU.Model{Float64}}\nin state EMPTY_OPTIMIZER\nin mode AUTOMATIC\nwith model cache MOIU.Model{Float64}\nwith optimizer MOIU.GenericOptimizer{Float64, MOIU.ObjectiveContainer{Float64}, MOIU.VariablesContainer{Float64}, MOIU.VectorOfConstraints{MOI.VectorAffineFunction{Float64}, MOI.Complements}}","category":"page"},{"location":"submodules/Utilities/overview/","page":"Overview","title":"Overview","text":"A Utilities.CachingOptimizer may be in one of three possible states:","category":"page"},{"location":"submodules/Utilities/overview/","page":"Overview","title":"Overview","text":"NO_OPTIMIZER: The CachingOptimizer does not have any optimizer.\nEMPTY_OPTIMIZER: The CachingOptimizer has an empty optimizer, and it is not synchronized with the cached model. Modifications are forwarded to the cache, but not to the optimizer.\nATTACHED_OPTIMIZER: The CachingOptimizer has an optimizer, and it is synchronized with the cached model. Modifications are forwarded to the optimizer. If the optimizer does not support modifications, and error will be thrown.","category":"page"},{"location":"submodules/Utilities/overview/","page":"Overview","title":"Overview","text":"Use Utilities.attach_optimizer to go from EMPTY_OPTIMIZER to ATTACHED_OPTIMIZER:","category":"page"},{"location":"submodules/Utilities/overview/","page":"Overview","title":"Overview","text":"julia> MOI.Utilities.attach_optimizer(model)\n\njulia> model\nMOIU.CachingOptimizer{MOIU.GenericOptimizer{Float64, MOIU.ObjectiveContainer{Float64}, MOIU.VariablesContainer{Float64}, MOIU.VectorOfConstraints{MOI.VectorAffineFunction{Float64}, MOI.Complements}}, MOIU.Model{Float64}}\nin state ATTACHED_OPTIMIZER\nin mode AUTOMATIC\nwith model cache MOIU.Model{Float64}\nwith optimizer MOIU.GenericOptimizer{Float64, MOIU.ObjectiveContainer{Float64}, MOIU.VariablesContainer{Float64}, MOIU.VectorOfConstraints{MOI.VectorAffineFunction{Float64}, MOI.Complements}}","category":"page"},{"location":"submodules/Utilities/overview/","page":"Overview","title":"Overview","text":"info: Info\nYou must be in ATTACHED_OPTIMIZER to use optimize!.","category":"page"},{"location":"submodules/Utilities/overview/","page":"Overview","title":"Overview","text":"Use Utilities.reset_optimizer to go from ATTACHED_OPTIMIZER to EMPTY_OPTIMIZER:","category":"page"},{"location":"submodules/Utilities/overview/","page":"Overview","title":"Overview","text":"julia> MOI.Utilities.reset_optimizer(model)\n\njulia> model\nMOIU.CachingOptimizer{MOIU.GenericOptimizer{Float64, MOIU.ObjectiveContainer{Float64}, MOIU.VariablesContainer{Float64}, MOIU.VectorOfConstraints{MOI.VectorAffineFunction{Float64}, MOI.Complements}}, MOIU.Model{Float64}}\nin state EMPTY_OPTIMIZER\nin mode AUTOMATIC\nwith model cache MOIU.Model{Float64}\nwith optimizer MOIU.GenericOptimizer{Float64, MOIU.ObjectiveContainer{Float64}, MOIU.VariablesContainer{Float64}, MOIU.VectorOfConstraints{MOI.VectorAffineFunction{Float64}, MOI.Complements}}","category":"page"},{"location":"submodules/Utilities/overview/","page":"Overview","title":"Overview","text":"info: Info\nCalling MOI.empty!(model) also resets the state to EMPTY_OPTIMIZER. So after emptying a model, the modification will only be applied to the cache.","category":"page"},{"location":"submodules/Utilities/overview/","page":"Overview","title":"Overview","text":"Use Utilities.drop_optimizer to go from any state to NO_OPTIMIZER:","category":"page"},{"location":"submodules/Utilities/overview/","page":"Overview","title":"Overview","text":"julia> MOI.Utilities.drop_optimizer(model)\n\njulia> model\nMOIU.CachingOptimizer{MOIU.GenericOptimizer{Float64, MOIU.ObjectiveContainer{Float64}, MOIU.VariablesContainer{Float64}, MOIU.VectorOfConstraints{MOI.VectorAffineFunction{Float64}, MOI.Complements}}, MOIU.Model{Float64}}\nin state NO_OPTIMIZER\nin mode AUTOMATIC\nwith model cache MOIU.Model{Float64}\nwith optimizer nothing","category":"page"},{"location":"submodules/Utilities/overview/","page":"Overview","title":"Overview","text":"Pass an empty optimizer to Utilities.reset_optimizer to go from NO_OPTIMIZER to EMPTY_OPTIMIZER:","category":"page"},{"location":"submodules/Utilities/overview/","page":"Overview","title":"Overview","text":"julia> MOI.Utilities.reset_optimizer(model, PathOptimizer{Float64}())\n\njulia> model\nMOIU.CachingOptimizer{MOIU.GenericOptimizer{Float64, MOIU.ObjectiveContainer{Float64}, MOIU.VariablesContainer{Float64}, MOIU.VectorOfConstraints{MOI.VectorAffineFunction{Float64}, MOI.Complements}}, MOIU.Model{Float64}}\nin state EMPTY_OPTIMIZER\nin mode AUTOMATIC\nwith model cache MOIU.Model{Float64}\nwith optimizer MOIU.GenericOptimizer{Float64, MOIU.ObjectiveContainer{Float64}, MOIU.VariablesContainer{Float64}, MOIU.VectorOfConstraints{MOI.VectorAffineFunction{Float64}, MOI.Complements}}","category":"page"},{"location":"submodules/Utilities/overview/","page":"Overview","title":"Overview","text":"Deciding when to attach and reset the optimizer is tedious, and you will often write code like this:","category":"page"},{"location":"submodules/Utilities/overview/","page":"Overview","title":"Overview","text":"try\n # modification\ncatch\n MOI.Utilities.reset_optimizer(model)\n # Re-try modification\nend","category":"page"},{"location":"submodules/Utilities/overview/","page":"Overview","title":"Overview","text":"To make this easier, Utilities.CachingOptimizer has two modes of operation:","category":"page"},{"location":"submodules/Utilities/overview/","page":"Overview","title":"Overview","text":"AUTOMATIC: The CachingOptimizer changes its state when necessary. Attempting to add a constraint or perform a modification not supported by the optimizer results in a drop to EMPTY_OPTIMIZER mode.\nMANUAL: The user must change the state of the CachingOptimizer. Attempting to perform an operation in the incorrect state results in an error.","category":"page"},{"location":"submodules/Utilities/overview/","page":"Overview","title":"Overview","text":"By default, AUTOMATIC mode is chosen. However, you can create a CachingOptimizer in MANUAL mode as follows:","category":"page"},{"location":"submodules/Utilities/overview/","page":"Overview","title":"Overview","text":"julia> model = MOI.Utilities.CachingOptimizer(\n MOI.Utilities.Model{Float64}(),\n MOI.Utilities.MANUAL,\n )\nMOIU.CachingOptimizer{MOI.AbstractOptimizer, MOIU.Model{Float64}}\nin state NO_OPTIMIZER\nin mode MANUAL\nwith model cache MOIU.Model{Float64}\nwith optimizer nothing\n\njulia> MOI.Utilities.reset_optimizer(model, PathOptimizer{Float64}())\n\njulia> model\nMOIU.CachingOptimizer{MOI.AbstractOptimizer, MOIU.Model{Float64}}\nin state EMPTY_OPTIMIZER\nin mode MANUAL\nwith model cache MOIU.Model{Float64}\nwith optimizer MOIU.GenericOptimizer{Float64, MOIU.ObjectiveContainer{Float64}, MOIU.VariablesContainer{Float64}, MOIU.VectorOfConstraints{MOI.VectorAffineFunction{Float64}, MOI.Complements}}","category":"page"},{"location":"submodules/Utilities/overview/#Printing","page":"Overview","title":"Printing","text":"","category":"section"},{"location":"submodules/Utilities/overview/","page":"Overview","title":"Overview","text":"Use print to print the formulation of the model.","category":"page"},{"location":"submodules/Utilities/overview/","page":"Overview","title":"Overview","text":"julia> model = MOI.Utilities.Model{Float64}();\n\njulia> x = MOI.add_variable(model)\nMOI.VariableIndex(1)\n\njulia> MOI.set(model, MOI.VariableName(), x, \"x_var\")\n\njulia> MOI.add_constraint(model, x, MOI.ZeroOne())\nMathOptInterface.ConstraintIndex{MathOptInterface.VariableIndex, MathOptInterface.ZeroOne}(1)\n\njulia> MOI.set(model, MOI.ObjectiveFunction{typeof(x)}(), x)\n\njulia> MOI.set(model, MOI.ObjectiveSense(), MOI.MAX_SENSE)\n\njulia> print(model)\nMaximize VariableIndex:\n x_var\n\nSubject to:\n\nVariableIndex-in-ZeroOne\n x_var ∈ {0, 1}","category":"page"},{"location":"submodules/Utilities/overview/","page":"Overview","title":"Overview","text":"Use Utilities.latex_formulation to display the model in LaTeX form:","category":"page"},{"location":"submodules/Utilities/overview/","page":"Overview","title":"Overview","text":"julia> MOI.Utilities.latex_formulation(model)\n$$ \\begin{aligned}\n\\max\\quad & x\\_var \\\\\n\\text{Subject to}\\\\\n & \\text{VariableIndex-in-ZeroOne} \\\\\n & x\\_var \\in \\{0, 1\\} \\\\\n\\end{aligned} $$","category":"page"},{"location":"submodules/Utilities/overview/","page":"Overview","title":"Overview","text":"tip: Tip\nIn IJulia, calling print or ending a cell with Utilities.latex_formulation will render the model in LaTeX.","category":"page"},{"location":"submodules/Utilities/overview/#Utilities.PenaltyRelaxation","page":"Overview","title":"Utilities.PenaltyRelaxation","text":"","category":"section"},{"location":"submodules/Utilities/overview/","page":"Overview","title":"Overview","text":"Pass Utilities.PenaltyRelaxation to modify to relax the problem by adding penalized slack variables to the constraints. This is helpful when debugging sources of infeasible models.","category":"page"},{"location":"submodules/Utilities/overview/","page":"Overview","title":"Overview","text":"julia> model = MOI.Utilities.Model{Float64}();\n\njulia> x = MOI.add_variable(model);\n\njulia> MOI.set(model, MOI.VariableName(), x, \"x\")\n\njulia> c = MOI.add_constraint(model, 1.0 * x, MOI.LessThan(2.0));\n\njulia> map = MOI.modify(model, MOI.Utilities.PenaltyRelaxation(Dict(c => 2.0)));\n\njulia> print(model)\nMinimize ScalarAffineFunction{Float64}:\n 0.0 + 2.0 v[2]\n\nSubject to:\n\nScalarAffineFunction{Float64}-in-LessThan{Float64}\n 0.0 + 1.0 x - 1.0 v[2] <= 2.0\n\nVariableIndex-in-GreaterThan{Float64}\n v[2] >= 0.0\n\njulia> map[c]\n0.0 + 1.0 MOI.VariableIndex(2)","category":"page"},{"location":"submodules/Utilities/overview/","page":"Overview","title":"Overview","text":"You can also modify a single constraint using Utilities.ScalarPenaltyRelaxation:","category":"page"},{"location":"submodules/Utilities/overview/","page":"Overview","title":"Overview","text":"julia> model = MOI.Utilities.Model{Float64}();\n\njulia> x = MOI.add_variable(model);\n\njulia> MOI.set(model, MOI.VariableName(), x, \"x\")\n\njulia> c = MOI.add_constraint(model, 1.0 * x, MOI.LessThan(2.0));\n\njulia> f = MOI.modify(model, c, MOI.Utilities.ScalarPenaltyRelaxation(2.0));\n\njulia> print(model)\nMinimize ScalarAffineFunction{Float64}:\n 0.0 + 2.0 v[2]\n\nSubject to:\n\nScalarAffineFunction{Float64}-in-LessThan{Float64}\n 0.0 + 1.0 x - 1.0 v[2] <= 2.0\n\nVariableIndex-in-GreaterThan{Float64}\n v[2] >= 0.0\n\njulia> f\n0.0 + 1.0 MOI.VariableIndex(2)","category":"page"},{"location":"submodules/Utilities/overview/#Utilities.MatrixOfConstraints","page":"Overview","title":"Utilities.MatrixOfConstraints","text":"","category":"section"},{"location":"submodules/Utilities/overview/","page":"Overview","title":"Overview","text":"The constraints of Utilities.Model are stored as a vector of tuples of function and set in a Utilities.VectorOfConstraints. Other representations can be used by parameterizing the type Utilities.GenericModel (resp. Utilities.GenericOptimizer). For instance, if all non-VariableIndex constraints are affine, the coefficients of all the constraints can be stored in a single sparse matrix using Utilities.MatrixOfConstraints. The constraints storage can even be customized up to a point where it exactly matches the storage of the solver of interest, in which case copy_to can be implemented for the solver by calling copy_to to this custom model.","category":"page"},{"location":"submodules/Utilities/overview/","page":"Overview","title":"Overview","text":"For instance, Clp defines the following model:","category":"page"},{"location":"submodules/Utilities/overview/","page":"Overview","title":"Overview","text":"MOI.Utilities.@product_of_scalar_sets(LP, MOI.EqualTo{T}, MOI.LessThan{T}, MOI.GreaterThan{T})\nconst Model = MOI.Utilities.GenericModel{\n Float64,\n MOI.Utilities.MatrixOfConstraints{\n Float64,\n MOI.Utilities.MutableSparseMatrixCSC{Float64,Cint,MOI.Utilities.ZeroBasedIndexing},\n MOI.Utilities.Hyperrectangle{Float64},\n LP{Float64},\n },\n}","category":"page"},{"location":"submodules/Utilities/overview/","page":"Overview","title":"Overview","text":"The copy_to operation can now be implemented as follows:","category":"page"},{"location":"submodules/Utilities/overview/","page":"Overview","title":"Overview","text":"function _copy_to(dest::Optimizer, src::Model)\n @assert MOI.is_empty(dest)\n A = src.constraints.coefficients\n row_bounds = src.constraints.constants\n Clp_loadProblem(\n dest,\n A.n,\n A.m,\n A.colptr,\n A.rowval,\n A.nzval,\n src.lower_bound,\n src.upper_bound,\n # (...) objective vector (omitted),\n row_bounds.lower,\n row_bounds.upper,\n )\n # Set objective sense and constant (omitted)\n return\nend\n\nfunction MOI.copy_to(dest::Optimizer, src::Model)\n _copy_to(dest, src)\n return MOI.Utilities.identity_index_map(src)\nend\n\nfunction MOI.copy_to(\n dest::Optimizer,\n src::MOI.Utilities.UniversalFallback{Model},\n)\n # Copy attributes from `src` to `dest` and error in case any unsupported\n # constraints or attributes are set in `UniversalFallback`.\n return MOI.copy_to(dest, src.model)\nend\n\nfunction MOI.copy_to(\n dest::Optimizer,\n src::MOI.ModelLike,\n)\n model = Model()\n index_map = MOI.copy_to(model, src)\n _copy_to(dest, model)\n return index_map\nend","category":"page"},{"location":"submodules/Utilities/overview/#ModelFilter","page":"Overview","title":"ModelFilter","text":"","category":"section"},{"location":"submodules/Utilities/overview/","page":"Overview","title":"Overview","text":"Utilities provides Utilities.ModelFilter as a useful tool to copy a subset of a model. For example, given an infeasible model, we can copy the irreducible infeasible subsystem (for models implementing ConstraintConflictStatus) as follows:","category":"page"},{"location":"submodules/Utilities/overview/","page":"Overview","title":"Overview","text":"my_filter(::Any) = true\nfunction my_filter(ci::MOI.ConstraintIndex)\n status = MOI.get(dest, MOI.ConstraintConflictStatus(), ci)\n return status != MOI.NOT_IN_CONFLICT\nend\nfiltered_src = MOI.Utilities.ModelFilter(my_filter, src)\nindex_map = MOI.copy_to(dest, filtered_src)","category":"page"},{"location":"submodules/Utilities/overview/#Fallbacks","page":"Overview","title":"Fallbacks","text":"","category":"section"},{"location":"submodules/Utilities/overview/","page":"Overview","title":"Overview","text":"The value of some attributes can be inferred from the value of other attributes.","category":"page"},{"location":"submodules/Utilities/overview/","page":"Overview","title":"Overview","text":"For example, the value of ObjectiveValue can be computed using ObjectiveFunction and VariablePrimal.","category":"page"},{"location":"submodules/Utilities/overview/","page":"Overview","title":"Overview","text":"When a solver gives direct access to an attribute, it is better to return this value. However, if this is not the case, Utilities.get_fallback can be used instead. For example:","category":"page"},{"location":"submodules/Utilities/overview/","page":"Overview","title":"Overview","text":"function MOI.get(model::Optimizer, attr::MOI.ObjectiveFunction)\n return MOI.Utilities.get_fallback(model, attr)\nend","category":"page"},{"location":"submodules/Utilities/overview/#DoubleDicts","page":"Overview","title":"DoubleDicts","text":"","category":"section"},{"location":"submodules/Utilities/overview/","page":"Overview","title":"Overview","text":"When writing MOI interfaces, we often need to handle situations in which we map ConstraintIndexs to different values. For example, to a string for ConstraintName.","category":"page"},{"location":"submodules/Utilities/overview/","page":"Overview","title":"Overview","text":"One option is to use a dictionary like Dict{MOI.ConstraintIndex,String}. However, this incurs a performance cost because the key is not a concrete type.","category":"page"},{"location":"submodules/Utilities/overview/","page":"Overview","title":"Overview","text":"The DoubleDicts submodule helps this situation by providing two types main types Utilities.DoubleDicts.DoubleDict and Utilities.DoubleDicts.IndexDoubleDict. These types act like normal dictionaries, but internally they use more efficient dictionaries specialized to the type of the function-set pair.","category":"page"},{"location":"submodules/Utilities/overview/","page":"Overview","title":"Overview","text":"The most common usage of a DoubleDict is in the index_map returned by copy_to. Performance can be improved, by using a function barrier. That is, instead of code like:","category":"page"},{"location":"submodules/Utilities/overview/","page":"Overview","title":"Overview","text":"index_map = MOI.copy_to(dest, src)\nfor (F, S) in MOI.get(src, MOI.ListOfConstraintTypesPresent())\n for ci in MOI.get(src, MOI.ListOfConstraintIndices{F,S}())\n dest_ci = index_map[ci]\n # ...\n end\nend","category":"page"},{"location":"submodules/Utilities/overview/","page":"Overview","title":"Overview","text":"use instead:","category":"page"},{"location":"submodules/Utilities/overview/","page":"Overview","title":"Overview","text":"function function_barrier(\n dest,\n src,\n index_map::MOI.Utilities.DoubleDicts.IndexDoubleDictInner{F,S},\n) where {F,S}\n for ci in MOI.get(src, MOI.ListOfConstraintIndices{F,S}())\n dest_ci = index_map[ci]\n # ...\n end\n return\nend\n\nindex_map = MOI.copy_to(dest, src)\nfor (F, S) in MOI.get(src, MOI.ListOfConstraintTypesPresent())\n function_barrier(dest, src, index_map[F, S])\nend","category":"page"},{"location":"submodules/Nonlinear/overview/","page":"Overview","title":"Overview","text":"CurrentModule = MathOptInterface\nDocTestSetup = quote\n import MathOptInterface as MOI\nend\nDocTestFilters = [r\"MathOptInterface|MOI\"]","category":"page"},{"location":"submodules/Nonlinear/overview/#nonlinear_developers","page":"Overview","title":"Nonlinear","text":"","category":"section"},{"location":"submodules/Nonlinear/overview/","page":"Overview","title":"Overview","text":"warning: Warning\nThe Nonlinear submodule is experimental. Until this message is removed, breaking changes may be introduced in any minor or patch release of MathOptInterface.","category":"page"},{"location":"submodules/Nonlinear/overview/","page":"Overview","title":"Overview","text":"The Nonlinear submodule contains data structures and functions for working with a nonlinear optimization problem in the form of an expression graph. This page explains the API and describes the rationale behind its design.","category":"page"},{"location":"submodules/Nonlinear/overview/#Standard-form","page":"Overview","title":"Standard form","text":"","category":"section"},{"location":"submodules/Nonlinear/overview/","page":"Overview","title":"Overview","text":"Nonlinear programs (NLPs) are a class of optimization problems in which some of the constraints or the objective function are nonlinear:","category":"page"},{"location":"submodules/Nonlinear/overview/","page":"Overview","title":"Overview","text":"beginalign\n min_x in mathbbR^n f_0(x) \n textst l_j le f_j(x) le u_j j = 1 ldots m\nendalign","category":"page"},{"location":"submodules/Nonlinear/overview/","page":"Overview","title":"Overview","text":"There may be additional constraints, as well as things like variable bounds and integrality restrictions, but we do not consider them here because they are best dealt with by other components of MathOptInterface.","category":"page"},{"location":"submodules/Nonlinear/overview/#API-overview","page":"Overview","title":"API overview","text":"","category":"section"},{"location":"submodules/Nonlinear/overview/","page":"Overview","title":"Overview","text":"The core element of the Nonlinear submodule is Nonlinear.Model:","category":"page"},{"location":"submodules/Nonlinear/overview/","page":"Overview","title":"Overview","text":"julia> const Nonlinear = MOI.Nonlinear;\n\njulia> model = Nonlinear.Model()\nA Nonlinear.Model with:\n 0 objectives\n 0 parameters\n 0 expressions\n 0 constraints","category":"page"},{"location":"submodules/Nonlinear/overview/","page":"Overview","title":"Overview","text":"Nonlinear.Model is a mutable struct that stores all of the nonlinear information added to the model.","category":"page"},{"location":"submodules/Nonlinear/overview/#Decision-variables","page":"Overview","title":"Decision variables","text":"","category":"section"},{"location":"submodules/Nonlinear/overview/","page":"Overview","title":"Overview","text":"Decision variables are represented by VariableIndexes. The user is responsible for creating these using MOI.VariableIndex(i), where i is the column associated with the variable.","category":"page"},{"location":"submodules/Nonlinear/overview/#Nonlinear_Expressions","page":"Overview","title":"Expressions","text":"","category":"section"},{"location":"submodules/Nonlinear/overview/","page":"Overview","title":"Overview","text":"The input data structure is a Julia Expr. The input expressions can incorporate VariableIndexes, but these must be interpolated into the expression with $:","category":"page"},{"location":"submodules/Nonlinear/overview/","page":"Overview","title":"Overview","text":"julia> x = MOI.VariableIndex(1)\nMOI.VariableIndex(1)\n\njulia> input = :(1 + sin($x)^2)\n:(1 + sin(MathOptInterface.VariableIndex(1)) ^ 2)","category":"page"},{"location":"submodules/Nonlinear/overview/","page":"Overview","title":"Overview","text":"There are a number of restrictions on the input Expr:","category":"page"},{"location":"submodules/Nonlinear/overview/","page":"Overview","title":"Overview","text":"It cannot contain macros\nIt cannot contain broadcasting\nIt cannot contain splatting (except in limited situations)\nIt cannot contain linear algebra, such as matrix-vector products\nIt cannot contain generator expressions, including sum(i for i in S)","category":"page"},{"location":"submodules/Nonlinear/overview/","page":"Overview","title":"Overview","text":"Given an input expression, add an expression using Nonlinear.add_expression:","category":"page"},{"location":"submodules/Nonlinear/overview/","page":"Overview","title":"Overview","text":"julia> expr = Nonlinear.add_expression(model, input)\nMathOptInterface.Nonlinear.ExpressionIndex(1)","category":"page"},{"location":"submodules/Nonlinear/overview/","page":"Overview","title":"Overview","text":"The return value, expr, is a Nonlinear.ExpressionIndex that can then be interpolated into other input expressions.","category":"page"},{"location":"submodules/Nonlinear/overview/","page":"Overview","title":"Overview","text":"Looking again at model, we see:","category":"page"},{"location":"submodules/Nonlinear/overview/","page":"Overview","title":"Overview","text":"julia> model\nA Nonlinear.Model with:\n 0 objectives\n 0 parameters\n 1 expression\n 0 constraints","category":"page"},{"location":"submodules/Nonlinear/overview/#Nonlinear_Parameters","page":"Overview","title":"Parameters","text":"","category":"section"},{"location":"submodules/Nonlinear/overview/","page":"Overview","title":"Overview","text":"In addition to constant literals like 1 or 1.23, you can create parameters. Parameters are placeholders whose values can change before passing the expression to the solver. Create a parameter using Nonlinear.add_parameter, which accepts a default value:","category":"page"},{"location":"submodules/Nonlinear/overview/","page":"Overview","title":"Overview","text":"julia> p = Nonlinear.add_parameter(model, 1.23)\nMathOptInterface.Nonlinear.ParameterIndex(1)","category":"page"},{"location":"submodules/Nonlinear/overview/","page":"Overview","title":"Overview","text":"The return value, p, is a Nonlinear.ParameterIndex that can then be interpolated into other input expressions.","category":"page"},{"location":"submodules/Nonlinear/overview/","page":"Overview","title":"Overview","text":"Looking again at model, we see:","category":"page"},{"location":"submodules/Nonlinear/overview/","page":"Overview","title":"Overview","text":"julia> model\nA Nonlinear.Model with:\n 0 objectives\n 1 parameter\n 1 expression\n 0 constraints","category":"page"},{"location":"submodules/Nonlinear/overview/","page":"Overview","title":"Overview","text":"Update a parameter as follows:","category":"page"},{"location":"submodules/Nonlinear/overview/","page":"Overview","title":"Overview","text":"julia> model[p]\n1.23\n\njulia> model[p] = 4.56\n4.56\n\njulia> model[p]\n4.56","category":"page"},{"location":"submodules/Nonlinear/overview/#Nonlinear_Objectives","page":"Overview","title":"Objectives","text":"","category":"section"},{"location":"submodules/Nonlinear/overview/","page":"Overview","title":"Overview","text":"Set a nonlinear objective using Nonlinear.set_objective:","category":"page"},{"location":"submodules/Nonlinear/overview/","page":"Overview","title":"Overview","text":"julia> Nonlinear.set_objective(model, :($p + $expr + $x))\n\njulia> model\nA Nonlinear.Model with:\n 1 objective\n 1 parameter\n 1 expression\n 0 constraints","category":"page"},{"location":"submodules/Nonlinear/overview/","page":"Overview","title":"Overview","text":"Clear a nonlinear objective by passing nothing:","category":"page"},{"location":"submodules/Nonlinear/overview/","page":"Overview","title":"Overview","text":"julia> Nonlinear.set_objective(model, nothing)\n\njulia> model\nA Nonlinear.Model with:\n 0 objectives\n 1 parameter\n 1 expression\n 0 constraints","category":"page"},{"location":"submodules/Nonlinear/overview/","page":"Overview","title":"Overview","text":"But we'll re-add the objective for later:","category":"page"},{"location":"submodules/Nonlinear/overview/","page":"Overview","title":"Overview","text":"julia> Nonlinear.set_objective(model, :($p + $expr + $x));","category":"page"},{"location":"submodules/Nonlinear/overview/#Nonlinear_Constraints","page":"Overview","title":"Constraints","text":"","category":"section"},{"location":"submodules/Nonlinear/overview/","page":"Overview","title":"Overview","text":"Add a constraint using Nonlinear.add_constraint:","category":"page"},{"location":"submodules/Nonlinear/overview/","page":"Overview","title":"Overview","text":"julia> c = Nonlinear.add_constraint(model, :(1 + sqrt($x)), MOI.LessThan(2.0))\nMathOptInterface.Nonlinear.ConstraintIndex(1)\n\njulia> model\nA Nonlinear.Model with:\n 1 objective\n 1 parameter\n 1 expression\n 1 constraint","category":"page"},{"location":"submodules/Nonlinear/overview/","page":"Overview","title":"Overview","text":"The return value, c, is a Nonlinear.ConstraintIndex that is a unique identifier for the constraint. Interval constraints are also supported:","category":"page"},{"location":"submodules/Nonlinear/overview/","page":"Overview","title":"Overview","text":"julia> c2 = Nonlinear.add_constraint(model, :(1 + sqrt($x)), MOI.Interval(-1.0, 2.0))\nMathOptInterface.Nonlinear.ConstraintIndex(2)\n\njulia> model\nA Nonlinear.Model with:\n 1 objective\n 1 parameter\n 1 expression\n 2 constraints","category":"page"},{"location":"submodules/Nonlinear/overview/","page":"Overview","title":"Overview","text":"Delete a constraint using Nonlinear.delete:","category":"page"},{"location":"submodules/Nonlinear/overview/","page":"Overview","title":"Overview","text":"julia> Nonlinear.delete(model, c2)\n\njulia> model\nA Nonlinear.Model with:\n 1 objective\n 1 parameter\n 1 expression\n 1 constraint","category":"page"},{"location":"submodules/Nonlinear/overview/#User-defined-operators","page":"Overview","title":"User-defined operators","text":"","category":"section"},{"location":"submodules/Nonlinear/overview/","page":"Overview","title":"Overview","text":"By default, Nonlinear supports a wide range of univariate and multivariate operators. However, you can also define your own operators by registering them.","category":"page"},{"location":"submodules/Nonlinear/overview/#Univariate-operators","page":"Overview","title":"Univariate operators","text":"","category":"section"},{"location":"submodules/Nonlinear/overview/","page":"Overview","title":"Overview","text":"Register a univariate user-defined operator using Nonlinear.register_operator:","category":"page"},{"location":"submodules/Nonlinear/overview/","page":"Overview","title":"Overview","text":"julia> f(x) = 1 + sin(x)^2\nf (generic function with 1 method)\n\njulia> Nonlinear.register_operator(model, :my_f, 1, f)","category":"page"},{"location":"submodules/Nonlinear/overview/","page":"Overview","title":"Overview","text":"Now, you can use :my_f in expressions:","category":"page"},{"location":"submodules/Nonlinear/overview/","page":"Overview","title":"Overview","text":"julia> new_expr = Nonlinear.add_expression(model, :(my_f($x + 1)))\nMathOptInterface.Nonlinear.ExpressionIndex(2)","category":"page"},{"location":"submodules/Nonlinear/overview/","page":"Overview","title":"Overview","text":"By default, Nonlinear will compute first- and second-derivatives of the registered operator using ForwardDiff.jl. Override this by passing functions which compute the respective derivative:","category":"page"},{"location":"submodules/Nonlinear/overview/","page":"Overview","title":"Overview","text":"julia> f′(x) = 2 * sin(x) * cos(x)\nf′ (generic function with 1 method)\n\njulia> Nonlinear.register_operator(model, :my_f2, 1, f, f′)","category":"page"},{"location":"submodules/Nonlinear/overview/","page":"Overview","title":"Overview","text":"or","category":"page"},{"location":"submodules/Nonlinear/overview/","page":"Overview","title":"Overview","text":"julia> f′′(x) = 2 * (cos(x)^2 - sin(x)^2)\nf′′ (generic function with 1 method)\n\njulia> Nonlinear.register_operator(model, :my_f3, 1, f, f′, f′′)","category":"page"},{"location":"submodules/Nonlinear/overview/#Multivariate-operators","page":"Overview","title":"Multivariate operators","text":"","category":"section"},{"location":"submodules/Nonlinear/overview/","page":"Overview","title":"Overview","text":"Register a multivariate user-defined operator using Nonlinear.register_operator:","category":"page"},{"location":"submodules/Nonlinear/overview/","page":"Overview","title":"Overview","text":"julia> g(x...) = x[1]^2 + x[1] * x[2] + x[2]^2\ng (generic function with 1 method)\n\njulia> Nonlinear.register_operator(model, :my_g, 2, g)","category":"page"},{"location":"submodules/Nonlinear/overview/","page":"Overview","title":"Overview","text":"Now, you can use :my_g in expressions:","category":"page"},{"location":"submodules/Nonlinear/overview/","page":"Overview","title":"Overview","text":"julia> new_expr = Nonlinear.add_expression(model, :(my_g($x + 1, $x)))\nMathOptInterface.Nonlinear.ExpressionIndex(3)","category":"page"},{"location":"submodules/Nonlinear/overview/","page":"Overview","title":"Overview","text":"By default, Nonlinear will compute the gradient of the registered operator using ForwardDiff.jl. (Hessian information is not supported.) Override this by passing a function to compute the gradient:","category":"page"},{"location":"submodules/Nonlinear/overview/","page":"Overview","title":"Overview","text":"julia> function ∇g(ret, x...)\n ret[1] = 2 * x[1] + x[2]\n ret[2] = x[1] + 2 * x[2]\n return\n end\n∇g (generic function with 1 method)\n\njulia> Nonlinear.register_operator(model, :my_g2, 2, g, ∇g)","category":"page"},{"location":"submodules/Nonlinear/overview/#Nonlinear_MOI_interface","page":"Overview","title":"MathOptInterface","text":"","category":"section"},{"location":"submodules/Nonlinear/overview/","page":"Overview","title":"Overview","text":"MathOptInterface communicates the nonlinear portion of an optimization problem to solvers using concrete subtypes of AbstractNLPEvaluator, which implement the Nonlinear programming API.","category":"page"},{"location":"submodules/Nonlinear/overview/","page":"Overview","title":"Overview","text":"Create an AbstractNLPEvaluator from Nonlinear.Model using Nonlinear.Evaluator.","category":"page"},{"location":"submodules/Nonlinear/overview/","page":"Overview","title":"Overview","text":"Nonlinear.Evaluator requires an Nonlinear.AbstractAutomaticDifferentiation backend and an ordered list of the variables that are included in the model.","category":"page"},{"location":"submodules/Nonlinear/overview/","page":"Overview","title":"Overview","text":"There following backends are available to choose from within MOI, although other packages may add more options by sub-typing Nonlinear.AbstractAutomaticDifferentiation:","category":"page"},{"location":"submodules/Nonlinear/overview/","page":"Overview","title":"Overview","text":"Nonlinear.ExprGraphOnly\nNonlinear.SparseReverseMode.","category":"page"},{"location":"submodules/Nonlinear/overview/","page":"Overview","title":"Overview","text":"julia> evaluator = Nonlinear.Evaluator(model, Nonlinear.ExprGraphOnly(), [x])\nNonlinear.Evaluator with available features:\n * :ExprGraph","category":"page"},{"location":"submodules/Nonlinear/overview/","page":"Overview","title":"Overview","text":"The functions of the Nonlinear programming API implemented by Nonlinear.Evaluator depends upon the chosen Nonlinear.AbstractAutomaticDifferentiation backend.","category":"page"},{"location":"submodules/Nonlinear/overview/","page":"Overview","title":"Overview","text":"The :ExprGraph feature means we can call objective_expr and constraint_expr to retrieve the expression graph of the problem. However, we cannot call gradient terms such as eval_objective_gradient because Nonlinear.ExprGraphOnly does not have the capability to differentiate a nonlinear expression.","category":"page"},{"location":"submodules/Nonlinear/overview/","page":"Overview","title":"Overview","text":"If, instead, we pass Nonlinear.SparseReverseMode, then we get access to :Grad, the gradient of the objective function, :Jac, the Jacobian matrix of the constraints, :JacVec, the ability to compute Jacobian-vector products, and :ExprGraph.","category":"page"},{"location":"submodules/Nonlinear/overview/","page":"Overview","title":"Overview","text":"julia> evaluator = Nonlinear.Evaluator(\n model,\n Nonlinear.SparseReverseMode(),\n [x],\n )\nNonlinear.Evaluator with available features:\n * :Grad\n * :Jac\n * :JacVec\n * :ExprGraph","category":"page"},{"location":"submodules/Nonlinear/overview/","page":"Overview","title":"Overview","text":"However, before using the evaluator, we need to call initialize:","category":"page"},{"location":"submodules/Nonlinear/overview/","page":"Overview","title":"Overview","text":"julia> MOI.initialize(evaluator, [:Grad, :Jac, :JacVec, :ExprGraph])","category":"page"},{"location":"submodules/Nonlinear/overview/","page":"Overview","title":"Overview","text":"Now we can call methods like eval_objective:","category":"page"},{"location":"submodules/Nonlinear/overview/","page":"Overview","title":"Overview","text":"julia> x = [1.0]\n1-element Vector{Float64}:\n 1.0\n\njulia> MOI.eval_objective(evaluator, x)\n7.268073418273571","category":"page"},{"location":"submodules/Nonlinear/overview/","page":"Overview","title":"Overview","text":"and eval_objective_gradient:","category":"page"},{"location":"submodules/Nonlinear/overview/","page":"Overview","title":"Overview","text":"julia> grad = [0.0]\n1-element Vector{Float64}:\n 0.0\n\njulia> MOI.eval_objective_gradient(evaluator, grad, x)\n\njulia> grad\n1-element Vector{Float64}:\n 1.909297426825682","category":"page"},{"location":"submodules/Nonlinear/overview/","page":"Overview","title":"Overview","text":"Instead of passing Nonlinear.Evaluator directly to solvers, solvers query the NLPBlock attribute, which returns an NLPBlockData. This object wraps an Nonlinear.Evaluator and includes other information such as constraint bounds and whether the evaluator has a nonlinear objective. Create and set NLPBlockData as follows:","category":"page"},{"location":"submodules/Nonlinear/overview/","page":"Overview","title":"Overview","text":"julia> block = MOI.NLPBlockData(evaluator);\n\njulia> model = MOI.Utilities.UniversalFallback(MOI.Utilities.Model{Float64}());\n\njulia> MOI.set(model, MOI.NLPBlock(), block);","category":"page"},{"location":"submodules/Nonlinear/overview/","page":"Overview","title":"Overview","text":"warning: Warning\nOnly call NLPBlockData once you have finished modifying the problem in model.","category":"page"},{"location":"submodules/Nonlinear/overview/","page":"Overview","title":"Overview","text":"Putting everything together, you can create a nonlinear optimization problem in MathOptInterface as follows:","category":"page"},{"location":"submodules/Nonlinear/overview/","page":"Overview","title":"Overview","text":"import MathOptInterface as MOI\n\nfunction build_model(\n model::MOI.ModelLike;\n backend::MOI.Nonlinear.AbstractAutomaticDifferentiation,\n)\n x = MOI.add_variable(model)\n y = MOI.add_variable(model)\n MOI.set(model, MOI.ObjectiveSense(), MOI.MIN_SENSE)\n nl_model = MOI.Nonlinear.Model()\n MOI.Nonlinear.set_objective(nl_model, :($x^2 + $y^2))\n evaluator = MOI.Nonlinear.Evaluator(nl_model, backend, [x, y])\n MOI.set(model, MOI.NLPBlock(), MOI.NLPBlockData(evaluator))\n return\nend\n\n# Replace `model` and `backend` with your optimizer and backend of choice.\nmodel = MOI.Utilities.UniversalFallback(MOI.Utilities.Model{Float64}())\nbuild_model(model; backend = MOI.Nonlinear.SparseReverseMode())","category":"page"},{"location":"submodules/Nonlinear/overview/#Expression-graph-representation","page":"Overview","title":"Expression-graph representation","text":"","category":"section"},{"location":"submodules/Nonlinear/overview/","page":"Overview","title":"Overview","text":"Nonlinear.Model stores nonlinear expressions in Nonlinear.Expressions. This section explains the design of the expression graph data structure in Nonlinear.Expression.","category":"page"},{"location":"submodules/Nonlinear/overview/","page":"Overview","title":"Overview","text":"Given a nonlinear function like f(x) = sin(x)^2 + x, a conceptual aid for thinking about the graph representation of the expression is to convert it into Polish prefix notation:","category":"page"},{"location":"submodules/Nonlinear/overview/","page":"Overview","title":"Overview","text":"f(x, y) = (+ (^ (sin x) 2) x)","category":"page"},{"location":"submodules/Nonlinear/overview/","page":"Overview","title":"Overview","text":"This format identifies each operator (function), as well as a list of arguments. Operators can be univariate, like sin, or multivariate, like +.","category":"page"},{"location":"submodules/Nonlinear/overview/","page":"Overview","title":"Overview","text":"A common way of representing Polish prefix notation in code is as follows:","category":"page"},{"location":"submodules/Nonlinear/overview/","page":"Overview","title":"Overview","text":"julia> x = MOI.VariableIndex(1);\n\njulia> struct ExprNode\n op::Symbol\n children::Vector{Union{ExprNode,Float64,MOI.VariableIndex}}\n end\n\njulia> expr = ExprNode(:+, [ExprNode(:^, [ExprNode(:sin, [x]), 2.0]), x]);","category":"page"},{"location":"submodules/Nonlinear/overview/","page":"Overview","title":"Overview","text":"This data structure follows our Polish prefix notation very closely, and we can easily identify the arguments to an operator. However, it has a significant draw-back: each node in the graph requires a Vector, which is heap-allocated and tracked by Julia's garbage collector (GC). For large models, we can expect to have millions of nodes in the expression graph, so this overhead quickly becomes prohibitive for computation.","category":"page"},{"location":"submodules/Nonlinear/overview/","page":"Overview","title":"Overview","text":"An alternative is to record the expression as a linear tape:","category":"page"},{"location":"submodules/Nonlinear/overview/","page":"Overview","title":"Overview","text":"julia> expr = Any[:+, 2, :^, 2, :sin, 1, x, 2.0, x]\n9-element Vector{Any}:\n :+\n 2\n :^\n 2\n :sin\n 1\n MOI.VariableIndex(1)\n 2.0\n MOI.VariableIndex(1)","category":"page"},{"location":"submodules/Nonlinear/overview/","page":"Overview","title":"Overview","text":"The Int after each operator Symbol specifies the number of arguments.","category":"page"},{"location":"submodules/Nonlinear/overview/","page":"Overview","title":"Overview","text":"This data-structure is a single vector, which resolves our problem with the GC, but each element is the abstract type, Any, and so any operations on it will lead to slower dynamic dispatch. It's also hard to identify the children of each operation without reading the entire tape.","category":"page"},{"location":"submodules/Nonlinear/overview/","page":"Overview","title":"Overview","text":"To summarize, representing expression graphs in Julia has the following challenges:","category":"page"},{"location":"submodules/Nonlinear/overview/","page":"Overview","title":"Overview","text":"Nodes in the expression graph should not contain a heap-allocated object\nAll data-structures should be concretely typed\nIt should be easy to identify the children of a node","category":"page"},{"location":"submodules/Nonlinear/overview/#Sketch-of-the-design-in-Nonlinear","page":"Overview","title":"Sketch of the design in Nonlinear","text":"","category":"section"},{"location":"submodules/Nonlinear/overview/","page":"Overview","title":"Overview","text":"Nonlinear overcomes these problems by decomposing the data structure into a number of different concrete-typed vectors.","category":"page"},{"location":"submodules/Nonlinear/overview/","page":"Overview","title":"Overview","text":"First, we create vectors of the supported uni- and multivariate operators.","category":"page"},{"location":"submodules/Nonlinear/overview/","page":"Overview","title":"Overview","text":"julia> const UNIVARIATE_OPERATORS = [:sin];\n\njulia> const MULTIVARIATE_OPERATORS = [:+, :^];","category":"page"},{"location":"submodules/Nonlinear/overview/","page":"Overview","title":"Overview","text":"In practice, there are many more supported operations than the ones listed here.","category":"page"},{"location":"submodules/Nonlinear/overview/","page":"Overview","title":"Overview","text":"Second, we create an enum to represent the different types of nodes present in the expression graph:","category":"page"},{"location":"submodules/Nonlinear/overview/","page":"Overview","title":"Overview","text":"julia> @enum(\n NodeType,\n NODE_CALL_MULTIVARIATE,\n NODE_CALL_UNIVARIATE,\n NODE_VARIABLE,\n NODE_VALUE,\n )","category":"page"},{"location":"submodules/Nonlinear/overview/","page":"Overview","title":"Overview","text":"In practice, there are node types other than the ones listed here.","category":"page"},{"location":"submodules/Nonlinear/overview/","page":"Overview","title":"Overview","text":"Third, we create two concretely typed structs as follows:","category":"page"},{"location":"submodules/Nonlinear/overview/","page":"Overview","title":"Overview","text":"julia> struct Node\n type::NodeType\n parent::Int\n index::Int\n end\n\njulia> struct Expression\n nodes::Vector{Node}\n values::Vector{Float64}\n end","category":"page"},{"location":"submodules/Nonlinear/overview/","page":"Overview","title":"Overview","text":"For each node node in the .nodes field, if node.type is:","category":"page"},{"location":"submodules/Nonlinear/overview/","page":"Overview","title":"Overview","text":"NODE_CALL_MULTIVARIATE, we look up MULTIVARIATE_OPERATORS[node.index] to retrieve the operator\nNODE_CALL_UNIVARIATE, we look up UNIVARIATE_OPERATORS[node.index] to retrieve the operator\nNODE_VARIABLE, we create MOI.VariableIndex(node.index)\nNODE_VALUE, we look up values[node.index]","category":"page"},{"location":"submodules/Nonlinear/overview/","page":"Overview","title":"Overview","text":"The .parent field of each node is the integer index of the parent node in .nodes. For the first node, the parent is -1 by convention.","category":"page"},{"location":"submodules/Nonlinear/overview/","page":"Overview","title":"Overview","text":"Therefore, we can represent our function as:","category":"page"},{"location":"submodules/Nonlinear/overview/","page":"Overview","title":"Overview","text":"julia> expr = Expression(\n [\n Node(NODE_CALL_MULTIVARIATE, -1, 1),\n Node(NODE_CALL_MULTIVARIATE, 1, 2),\n Node(NODE_CALL_UNIVARIATE, 2, 1),\n Node(NODE_VARIABLE, 3, 1),\n Node(NODE_VALUE, 2, 1),\n Node(NODE_VARIABLE, 1, 1),\n ],\n [2.0],\n );","category":"page"},{"location":"submodules/Nonlinear/overview/","page":"Overview","title":"Overview","text":"This is less readable than the other options, but does this data structure meet our design goals?","category":"page"},{"location":"submodules/Nonlinear/overview/","page":"Overview","title":"Overview","text":"Instead of a heap-allocated object for each node, we only have two Vectors for each expression, nodes and values, as well as two constant vectors for the OPERATORS. In addition, all fields are concretely typed, and there are no Union or Any types.","category":"page"},{"location":"submodules/Nonlinear/overview/","page":"Overview","title":"Overview","text":"For our third goal, it is not easy to identify the children of a node, but it is easy to identify the parent of any node. Therefore, we can use Nonlinear.adjacency_matrix to compute a sparse matrix that maps parents to their children.","category":"page"},{"location":"submodules/Nonlinear/overview/","page":"Overview","title":"Overview","text":"The tape is also ordered topologically, so that a reverse pass of the nodes evaluates all children nodes before their parent.","category":"page"},{"location":"submodules/Nonlinear/overview/#The-design-in-practice","page":"Overview","title":"The design in practice","text":"","category":"section"},{"location":"submodules/Nonlinear/overview/","page":"Overview","title":"Overview","text":"In practice, Node and Expression are exactly Nonlinear.Node and Nonlinear.Expression. However, Nonlinear.NodeType has more fields to account for comparison operators such as :>= and :<=, logic operators such as :&& and :||, nonlinear parameters, and nested subexpressions.","category":"page"},{"location":"submodules/Nonlinear/overview/","page":"Overview","title":"Overview","text":"Moreover, instead of storing the operators as global constants, they are stored in Nonlinear.OperatorRegistry, and it also stores a vector of logic operators and a vector of comparison operators. In addition to Nonlinear.DEFAULT_UNIVARIATE_OPERATORS and Nonlinear.DEFAULT_MULTIVARIATE_OPERATORS, you can register user-defined functions using Nonlinear.register_operator.","category":"page"},{"location":"submodules/Nonlinear/overview/","page":"Overview","title":"Overview","text":"Nonlinear.Model is a struct that stores the Nonlinear.OperatorRegistry, as well as a list of parameters and subexpressions in the model.","category":"page"},{"location":"submodules/Nonlinear/overview/#ReverseAD","page":"Overview","title":"ReverseAD","text":"","category":"section"},{"location":"submodules/Nonlinear/overview/","page":"Overview","title":"Overview","text":"Nonlinear.ReverseAD is a submodule for computing derivatives of a nonlinear optimization problem using sparse reverse-mode automatic differentiation (AD).","category":"page"},{"location":"submodules/Nonlinear/overview/","page":"Overview","title":"Overview","text":"This section does not attempt to explain how sparse reverse-mode AD works, but instead explains why MOI contains its own implementation, and highlights notable differences from similar packages.","category":"page"},{"location":"submodules/Nonlinear/overview/","page":"Overview","title":"Overview","text":"warning: Warning\nDon't use the API in ReverseAD to compute derivatives. Instead, create a Nonlinear.Evaluator object with Nonlinear.SparseReverseMode as the backend, and then query the MOI API methods.","category":"page"},{"location":"submodules/Nonlinear/overview/#Design-goals","page":"Overview","title":"Design goals","text":"","category":"section"},{"location":"submodules/Nonlinear/overview/","page":"Overview","title":"Overview","text":"The JuliaDiff organization maintains a list of packages for doing AD in Julia. At last count, there were at least ten packages——not including ReverseAD——for reverse-mode AD in Julia. ReverseAD exists because it has a different set of design goals.","category":"page"},{"location":"submodules/Nonlinear/overview/","page":"Overview","title":"Overview","text":"Goal: handle scale and sparsity. The types of nonlinear optimization problems that MOI represents can be large scale (10^5 or more functions across 10^5 or more variables) with very sparse derivatives. The ability to compute a sparse Hessian matrix is essential. To the best of our knowledge, ReverseAD is the only reverse-mode AD system in Julia that handles sparsity by default.\nGoal: limit the scope to improve robustness. Most other AD packages accept arbitrary Julia functions as input and then trace an expression graph using operator overloading. This means they must deal (or detect and ignore) with control flow, I/O, and other vagaries of Julia. In contrast, ReverseAD only accepts functions in the form of Nonlinear.Expression, which greatly limits the range of syntax that it must deal with. By reducing the scope of what we accept as input to functions relevant for mathematical optimization, we can provide a simpler implementation with various performance optimizations.\nGoal: provide outputs which match what solvers expect. Other AD packages focus on differentiating individual Julia functions. In contrast, ReverseAD has a very specific use-case: to generate outputs needed by the MOI nonlinear API. This means it needs to efficiently compute sparse Hessians, and it needs subexpression handling to avoid recomputing subexpressions that are shared between functions.","category":"page"},{"location":"submodules/Nonlinear/overview/#History","page":"Overview","title":"History","text":"","category":"section"},{"location":"submodules/Nonlinear/overview/","page":"Overview","title":"Overview","text":"ReverseAD started life as ReverseDiffSparse.jl, development of which began in early 2014(!). This was well before the other AD packages started development. Because we had a well-tested, working AD in JuMP, there was less motivation to contribute to and explore other AD packages. The lack of historical interaction also meant that other packages were not optimized for the types of problems that JuMP is built for (that is, large-scale sparse problems). When we first created MathOptInterface, we kept the AD in JuMP to simplify the transition, and post-poned the development of a first-class nonlinear interface in MathOptInterface.","category":"page"},{"location":"submodules/Nonlinear/overview/","page":"Overview","title":"Overview","text":"Prior to the introduction of Nonlinear, JuMP's nonlinear implementation was a confusing mix of functions and types spread across the code base and in the private _Derivatives submodule. This made it hard to swap the AD system for another. The main motivation for refactoring JuMP to create the Nonlinear submodule in MathOptInterface was to abstract the interface between JuMP and the AD system, allowing us to swap-in and test new AD systems in the future.","category":"page"},{"location":"tutorials/bridging_constraint/","page":"Implementing a constraint bridge","title":"Implementing a constraint bridge","text":"CurrentModule = MathOptInterface\nDocTestSetup = quote\n import MathOptInterface as MOI\nend\nDocTestFilters = [r\"MathOptInterface|MOI\"]","category":"page"},{"location":"tutorials/bridging_constraint/#Implementing-a-constraint-bridge","page":"Implementing a constraint bridge","title":"Implementing a constraint bridge","text":"","category":"section"},{"location":"tutorials/bridging_constraint/","page":"Implementing a constraint bridge","title":"Implementing a constraint bridge","text":"This guide outlines the basic steps to create a new bridge from a constraint expressed in the formalism Function-in-Set.","category":"page"},{"location":"tutorials/bridging_constraint/#Preliminaries","page":"Implementing a constraint bridge","title":"Preliminaries","text":"","category":"section"},{"location":"tutorials/bridging_constraint/","page":"Implementing a constraint bridge","title":"Implementing a constraint bridge","text":"First, decide on the set you want to bridge. Then, study its properties: the most important one is whether the set is scalar or vector, which impacts the dimensionality of the functions that can be used with the set.","category":"page"},{"location":"tutorials/bridging_constraint/","page":"Implementing a constraint bridge","title":"Implementing a constraint bridge","text":"A scalar function only has one dimension. MOI defines three types of scalar functions: a variable (VariableIndex), an affine function (ScalarAffineFunction), or a quadratic function (ScalarQuadraticFunction).\nA vector function has several dimensions (at least one). MOI defines three types of vector functions: several variables (VectorOfVariables), an affine function (VectorAffineFunction), or a quadratic function (VectorQuadraticFunction). The main difference with scalar functions is that the order of dimensions can be very important: for instance, in an indicator constraint (Indicator), the first dimension indicates whether the constraint about the second dimension is active.","category":"page"},{"location":"tutorials/bridging_constraint/","page":"Implementing a constraint bridge","title":"Implementing a constraint bridge","text":"To explain how to implement a bridge, we present the example of Bridges.Constraint.FlipSignBridge. This bridge maps <= (LessThan) constraints to >= (GreaterThan) constraints. This corresponds to reversing the sign of the inequality. We focus on scalar affine functions (we disregard the cases of a single variable or of quadratic functions). This example is a simplified version of the code included in MOI.","category":"page"},{"location":"tutorials/bridging_constraint/#Four-mandatory-parts-in-a-constraint-bridge","page":"Implementing a constraint bridge","title":"Four mandatory parts in a constraint bridge","text":"","category":"section"},{"location":"tutorials/bridging_constraint/","page":"Implementing a constraint bridge","title":"Implementing a constraint bridge","text":"The first part of a constraint bridge is a new concrete subtype of Bridges.Constraint.AbstractBridge. This type must have fields to store all the new variables and constraints that the bridge will add. Typically, these types are parametrized by the type of the coefficients in the model.","category":"page"},{"location":"tutorials/bridging_constraint/","page":"Implementing a constraint bridge","title":"Implementing a constraint bridge","text":"Then, three sets of functions must be defined:","category":"page"},{"location":"tutorials/bridging_constraint/","page":"Implementing a constraint bridge","title":"Implementing a constraint bridge","text":"Bridges.Constraint.bridge_constraint: this function implements the bridge and creates the required variables and constraints.\nsupports_constraint: these functions must return true when the combination of function and set is supported by the bridge. By default, the base implementation always returns false and the bridge does not have to provide this implementation.\nBridges.added_constrained_variable_types and Bridges.added_constraint_types: these functions return the types of variables and constraints that this bridge adds. They are used to compute the set of other bridges that are required to use the one you are defining, if need be.","category":"page"},{"location":"tutorials/bridging_constraint/","page":"Implementing a constraint bridge","title":"Implementing a constraint bridge","text":"More functions can be implemented, for instance to retrieve properties from the bridge or deleting a bridged constraint.","category":"page"},{"location":"tutorials/bridging_constraint/#.-Structure-for-the-bridge","page":"Implementing a constraint bridge","title":"1. Structure for the bridge","text":"","category":"section"},{"location":"tutorials/bridging_constraint/","page":"Implementing a constraint bridge","title":"Implementing a constraint bridge","text":"A typical struct behind a bridge depends on the type of the coefficients that are used for the model (typically Float64, but coefficients might also be integers or complex numbers).","category":"page"},{"location":"tutorials/bridging_constraint/","page":"Implementing a constraint bridge","title":"Implementing a constraint bridge","text":"This structure must hold a reference to all the variables and the constraints that are created as part of the bridge.","category":"page"},{"location":"tutorials/bridging_constraint/","page":"Implementing a constraint bridge","title":"Implementing a constraint bridge","text":"The type of this structure is used throughout MOI as an identifier for the bridge. It is passed as argument to most functions related to bridges.","category":"page"},{"location":"tutorials/bridging_constraint/","page":"Implementing a constraint bridge","title":"Implementing a constraint bridge","text":"The best practice is to have the name of this type end with Bridge.","category":"page"},{"location":"tutorials/bridging_constraint/","page":"Implementing a constraint bridge","title":"Implementing a constraint bridge","text":"In our example, the bridge maps any ScalarAffineFunction{T}-in-LessThan{T} constraint to a single ScalarAffineFunction{T}-in-GreaterThan{T} constraint. The affine function has coefficients of type T. The bridge is parametrized with T, so that the constraint that the bridge creates also has coefficients of type T.","category":"page"},{"location":"tutorials/bridging_constraint/","page":"Implementing a constraint bridge","title":"Implementing a constraint bridge","text":"struct SignBridge{T<:Number} <: Bridges.Constraint.AbstractBridge\n constraint::ConstraintIndex{ScalarAffineFunction{T}, GreaterThan{T}}\nend","category":"page"},{"location":"tutorials/bridging_constraint/#.-Bridge-creation","page":"Implementing a constraint bridge","title":"2. Bridge creation","text":"","category":"section"},{"location":"tutorials/bridging_constraint/","page":"Implementing a constraint bridge","title":"Implementing a constraint bridge","text":"The function Bridges.Constraint.bridge_constraint is called whenever the bridge is instantiated for a specific model, with the given function and set. The arguments to bridge_constraint are similar to add_constraint, with the exception of the first argument: it is the Type of the struct defined in the first step (for our example, Type{SignBridge{T}}).","category":"page"},{"location":"tutorials/bridging_constraint/","page":"Implementing a constraint bridge","title":"Implementing a constraint bridge","text":"bridge_constraint returns an instance of the struct defined in the first step. the first step.","category":"page"},{"location":"tutorials/bridging_constraint/","page":"Implementing a constraint bridge","title":"Implementing a constraint bridge","text":"In our example, the bridge constraint could be defined as:","category":"page"},{"location":"tutorials/bridging_constraint/","page":"Implementing a constraint bridge","title":"Implementing a constraint bridge","text":"function Bridges.Constraint.bridge_constraint(\n ::Type{SignBridge{T}}, # Bridge to use.\n model::ModelLike, # Model to which the constraint is being added.\n f::ScalarAffineFunction{T}, # Function to rewrite.\n s::LessThan{T}, # Set to rewrite.\n) where {T}\n # Create the variables and constraints required for the bridge.\n con = add_constraint(model, -f, GreaterThan(-s.upper))\n\n # Return an instance of the bridge type with a reference to all the\n # variables and constraints that were created in this function.\n return SignBridge(con)\nend","category":"page"},{"location":"tutorials/bridging_constraint/#.-Supported-constraint-types","page":"Implementing a constraint bridge","title":"3. Supported constraint types","text":"","category":"section"},{"location":"tutorials/bridging_constraint/","page":"Implementing a constraint bridge","title":"Implementing a constraint bridge","text":"The function supports_constraint determines whether the bridge type supports a given combination of function and set.","category":"page"},{"location":"tutorials/bridging_constraint/","page":"Implementing a constraint bridge","title":"Implementing a constraint bridge","text":"This function must closely match bridge_constraint, because it will not be called if supports_constraint returns false.","category":"page"},{"location":"tutorials/bridging_constraint/","page":"Implementing a constraint bridge","title":"Implementing a constraint bridge","text":"function supports_constraint(\n ::Type{SignBridge{T}}, # Bridge to use.\n ::Type{ScalarAffineFunction{T}}, # Function to rewrite.\n ::Type{LessThan{T}}, # Set to rewrite.\n) where {T}\n # Do some computation to ensure that the constraint is supported.\n # Typically, you can directly return true.\n return true\nend","category":"page"},{"location":"tutorials/bridging_constraint/#.-Metadata-about-the-bridge","page":"Implementing a constraint bridge","title":"4. Metadata about the bridge","text":"","category":"section"},{"location":"tutorials/bridging_constraint/","page":"Implementing a constraint bridge","title":"Implementing a constraint bridge","text":"To determine whether a bridge can be used, MOI uses a shortest-path algorithm that uses the variable types and the constraints that the bridge can create. This information is communicated from the bridge to MOI using the functions Bridges.added_constrained_variable_types and Bridges.added_constraint_types. Both return lists of tuples: either a list of 1-tuples containing the variable types (typically, ZeroOne or Integer) or a list of 2-tuples contained the functions and sets (like ScalarAffineFunction{T}-GreaterThan).","category":"page"},{"location":"tutorials/bridging_constraint/","page":"Implementing a constraint bridge","title":"Implementing a constraint bridge","text":"For our example, the bridge does not create any constrained variables, and only ScalarAffineFunction{T}-in-GreaterThan{T} constraints:","category":"page"},{"location":"tutorials/bridging_constraint/","page":"Implementing a constraint bridge","title":"Implementing a constraint bridge","text":"function Bridges.added_constrained_variable_types(::Type{SignBridge{T}}) where {T}\n # The bridge does not create variables, return an empty list of tuples:\n return Tuple{Type}[]\nend\n\nfunction Bridges.added_constraint_types(::Type{SignBridge{T}}) where {T}\n return Tuple{Type,Type}[\n # One element per F-in-S the bridge creates.\n (ScalarAffineFunction{T}, GreaterThan{T}),\n ]\nend","category":"page"},{"location":"tutorials/bridging_constraint/","page":"Implementing a constraint bridge","title":"Implementing a constraint bridge","text":"A bridge that creates binary variables would rather have this definition of added_constrained_variable_types:","category":"page"},{"location":"tutorials/bridging_constraint/","page":"Implementing a constraint bridge","title":"Implementing a constraint bridge","text":"function Bridges.added_constrained_variable_types(::Type{SomeBridge{T}}) where {T}\n # The bridge only creates binary variables:\n return Tuple{Type}[(ZeroOne,)]\nend","category":"page"},{"location":"tutorials/bridging_constraint/","page":"Implementing a constraint bridge","title":"Implementing a constraint bridge","text":"warning: Warning\nIf you declare the creation of constrained variables in added_constrained_variable_types, the corresponding constraint type VariableIndex must not be indicated in added_constraint_types. This would restrict the use of the bridge to solvers that can add such a constraint after the variable is created.More concretely, if you declare in added_constrained_variable_types that your bridge creates binary variables (ZeroOne), and if you never add such a constraint afterward (you do not call add_constraint(model, var, ZeroOne())), then you must not list (VariableIndex, ZeroOne) in added_constraint_types.","category":"page"},{"location":"tutorials/bridging_constraint/","page":"Implementing a constraint bridge","title":"Implementing a constraint bridge","text":"Typically, the function Bridges.Constraint.concrete_bridge_type does not have to be defined for most bridges.","category":"page"},{"location":"tutorials/bridging_constraint/#Bridge-registration","page":"Implementing a constraint bridge","title":"Bridge registration","text":"","category":"section"},{"location":"tutorials/bridging_constraint/","page":"Implementing a constraint bridge","title":"Implementing a constraint bridge","text":"For a bridge to be used by MOI, it must be known by MOI.","category":"page"},{"location":"tutorials/bridging_constraint/#SingleBridgeOptimizer","page":"Implementing a constraint bridge","title":"SingleBridgeOptimizer","text":"","category":"section"},{"location":"tutorials/bridging_constraint/","page":"Implementing a constraint bridge","title":"Implementing a constraint bridge","text":"The first way to do so is to create a single-bridge optimizer. This type of optimizer wraps another optimizer and adds the possibility to use only one bridge. It is especially useful when unit testing bridges.","category":"page"},{"location":"tutorials/bridging_constraint/","page":"Implementing a constraint bridge","title":"Implementing a constraint bridge","text":"It is common practice to use the same name as the type defined for the bridge (SignBridge, in our example) without the suffix Bridge.","category":"page"},{"location":"tutorials/bridging_constraint/","page":"Implementing a constraint bridge","title":"Implementing a constraint bridge","text":"const Sign{T,OT<: ModelLike} =\n SingleBridgeOptimizer{SignBridge{T}, OT}","category":"page"},{"location":"tutorials/bridging_constraint/","page":"Implementing a constraint bridge","title":"Implementing a constraint bridge","text":"In the context of unit tests, this bridge is used in conjunction with a Utilities.MockOptimizer:","category":"page"},{"location":"tutorials/bridging_constraint/","page":"Implementing a constraint bridge","title":"Implementing a constraint bridge","text":"mock = Utilities.MockOptimizer(\n Utilities.UniversalFallback(Utilities.Model{Float64}()),\n)\nbridged_mock = Sign{Float64}(mock)","category":"page"},{"location":"tutorials/bridging_constraint/#New-bridge-for-a-LazyBridgeOptimizer","page":"Implementing a constraint bridge","title":"New bridge for a LazyBridgeOptimizer","text":"","category":"section"},{"location":"tutorials/bridging_constraint/","page":"Implementing a constraint bridge","title":"Implementing a constraint bridge","text":"Typical user-facing models for MOI are based on Bridges.LazyBridgeOptimizer. For instance, this type of model is returned by Bridges.full_bridge_optimizer. These models can be added more bridges by using Bridges.add_bridge:","category":"page"},{"location":"tutorials/bridging_constraint/","page":"Implementing a constraint bridge","title":"Implementing a constraint bridge","text":"inner_optimizer = Utilities.Model{Float64}()\noptimizer = Bridges.full_bridge_optimizer(inner_optimizer, Float64)\nBridges.add_bridge(optimizer, SignBridge{Float64})","category":"page"},{"location":"tutorials/bridging_constraint/#Bridge-improvements","page":"Implementing a constraint bridge","title":"Bridge improvements","text":"","category":"section"},{"location":"tutorials/bridging_constraint/#Attribute-retrieval","page":"Implementing a constraint bridge","title":"Attribute retrieval","text":"","category":"section"},{"location":"tutorials/bridging_constraint/","page":"Implementing a constraint bridge","title":"Implementing a constraint bridge","text":"Like models, bridges have attributes that can be retrieved using get and set. The most important ones are the number of variables and constraints, but also the lists of variables and constraints.","category":"page"},{"location":"tutorials/bridging_constraint/","page":"Implementing a constraint bridge","title":"Implementing a constraint bridge","text":"In our example, we only have one constraint and only have to implement the NumberOfConstraints and ListOfConstraintIndices attributes:","category":"page"},{"location":"tutorials/bridging_constraint/","page":"Implementing a constraint bridge","title":"Implementing a constraint bridge","text":"function get(\n ::SignBridge{T},\n ::NumberOfConstraints{\n ScalarAffineFunction{T},\n GreaterThan{T},\n },\n) where {T}\n return 1\nend\n\nfunction get(\n bridge::SignBridge{T},\n ::ListOfConstraintIndices{\n ScalarAffineFunction{T},\n GreaterThan{T},\n },\n) where {T}\n return [bridge.constraint]\nend","category":"page"},{"location":"tutorials/bridging_constraint/","page":"Implementing a constraint bridge","title":"Implementing a constraint bridge","text":"You must implement one such pair of functions for each type of constraint the bridge adds to the model.","category":"page"},{"location":"tutorials/bridging_constraint/","page":"Implementing a constraint bridge","title":"Implementing a constraint bridge","text":"warning: Warning\nAvoid returning a list from the bridge object without copying it. Users must be able to change the contents of the returned list without altering the bridge object.","category":"page"},{"location":"tutorials/bridging_constraint/","page":"Implementing a constraint bridge","title":"Implementing a constraint bridge","text":"For variables, the situation is simpler. If your bridge creates new variables, you must implement the NumberOfVariables and ListOfVariableIndices attributes. However, these attributes do not have parameters, unlike their constraint counterparts. Only two functions suffice:","category":"page"},{"location":"tutorials/bridging_constraint/","page":"Implementing a constraint bridge","title":"Implementing a constraint bridge","text":"function get(\n ::SignBridge{T},\n ::NumberOfVariables,\n) where {T}\n return 0\nend\n\nfunction get(\n ::SignBridge{T},\n ::ListOfVariableIndices,\n) where {T}\n return VariableIndex[]\nend","category":"page"},{"location":"tutorials/bridging_constraint/","page":"Implementing a constraint bridge","title":"Implementing a constraint bridge","text":"In order for the user to be able to access the function and set of the original constraint, the bridge needs to implement getters for the ConstraintFunction and ConstraintSet attributes:","category":"page"},{"location":"tutorials/bridging_constraint/","page":"Implementing a constraint bridge","title":"Implementing a constraint bridge","text":"function get(\n model::MOI.ModelLike,\n attr::MOI.ConstraintFunction,\n bridge::SignBridge,\n)\n return -MOI.get(model, attr, bridge.constraint)\nend\n\nfunction get(\n model::MOI.ModelLike,\n attr::MOI.ConstraintSet,\n bridge::SignBridge,\n)\n set = MOI.get(model, attr, bridge.constraint)\n return MOI.LessThan(-set.lower)\nend","category":"page"},{"location":"tutorials/bridging_constraint/","page":"Implementing a constraint bridge","title":"Implementing a constraint bridge","text":"warning: Warning\nAlternatively, one could store the original function and set in SignBridge during Bridges.Constraint.bridge_constraint to make these getters simpler and more efficient. On the other hand, this will increase the memory footprint of the bridges as the garbage collector won't be able to delete that object. The convention is to not store the function in the bridge and not care too much about the efficiency of these getters. If the user needs efficient getters for ConstraintFunction then they should use a Utilities.CachingOptimizer.","category":"page"},{"location":"tutorials/bridging_constraint/#Model-modifications","page":"Implementing a constraint bridge","title":"Model modifications","text":"","category":"section"},{"location":"tutorials/bridging_constraint/","page":"Implementing a constraint bridge","title":"Implementing a constraint bridge","text":"To avoid copying the model when the user request to change a constraint, MOI provides modify. Bridges can also implement this API to allow certain changes, such as coefficient changes.","category":"page"},{"location":"tutorials/bridging_constraint/","page":"Implementing a constraint bridge","title":"Implementing a constraint bridge","text":"In our case, a modification of a coefficient in the original constraint (for example, replacing the value of the coefficient of a variable in the affine function) must be transmitted to the constraint created by the bridge, but with a sign change.","category":"page"},{"location":"tutorials/bridging_constraint/","page":"Implementing a constraint bridge","title":"Implementing a constraint bridge","text":"function modify(\n model::ModelLike,\n bridge::SignBridge,\n change::ScalarCoefficientChange,\n)\n modify(\n model,\n bridge.constraint,\n ScalarCoefficientChange(change.variable, -change.new_coefficient),\n )\n return\nend","category":"page"},{"location":"tutorials/bridging_constraint/#Bridge-deletion","page":"Implementing a constraint bridge","title":"Bridge deletion","text":"","category":"section"},{"location":"tutorials/bridging_constraint/","page":"Implementing a constraint bridge","title":"Implementing a constraint bridge","text":"When a bridge is deleted, the constraints it added must be deleted too.","category":"page"},{"location":"tutorials/bridging_constraint/","page":"Implementing a constraint bridge","title":"Implementing a constraint bridge","text":"function delete(model::ModelLike, bridge::SignBridge)\n delete(model, bridge.constraint)\n return\nend","category":"page"},{"location":"release_notes/","page":"Release notes","title":"Release notes","text":"CurrentModule = MathOptInterface","category":"page"},{"location":"release_notes/#Release-notes","page":"Release notes","title":"Release notes","text":"","category":"section"},{"location":"release_notes/","page":"Release notes","title":"Release notes","text":"The format is based on Keep a Changelog, and this project adheres to Semantic Versioning.","category":"page"},{"location":"release_notes/#[v1.20.0](https://github.com/jump-dev/MathOptInterface.jl/releases/tag/v1.20.0)-(September-7,-2023)","page":"Release notes","title":"v1.20.0 (September 7, 2023)","text":"","category":"section"},{"location":"release_notes/#Added","page":"Release notes","title":"Added","text":"","category":"section"},{"location":"release_notes/","page":"Release notes","title":"Release notes","text":"Added Scaled set (#2237) (#2263) (#2264)\nAdded ObjectiveLimit attribute (#2257)","category":"page"},{"location":"release_notes/#Other","page":"Release notes","title":"Other","text":"","category":"section"},{"location":"release_notes/","page":"Release notes","title":"Release notes","text":"Updated dependencies (#2258)\nImproved performance of ScalarNonlinearFunction utilities (#2259)\nFixed docstrings (#2261)","category":"page"},{"location":"release_notes/#[v1.19.0](https://github.com/jump-dev/MathOptInterface.jl/releases/tag/v1.19.0)-(August-15,-2023)","page":"Release notes","title":"v1.19.0 (August 15, 2023)","text":"","category":"section"},{"location":"release_notes/#Added-2","page":"Release notes","title":"Added","text":"","category":"section"},{"location":"release_notes/","page":"Release notes","title":"Release notes","text":"Added VectorNonlinearFunction (#2201)\nAdded new bridges\nBridges.Constraint.IntegerToZeroOneBridge (#2205)\nBridges.Constraint.ToScalarQuadraticBridge (#2235)\nBridges.Constraint.ToVectorQuadraticBridge (#2235)\nBridges.Constraint.ToScalarNonlinearBridge (#2233) (#2235)\nBridges.Constraint.FunctionConversionBridge (#2235)\nAdded Bridges.bridging_cost for setting a bridge-specific cost in the bridging graph (#2235)\nAdded Utilities.eval_variables support for ScalarNonlinearFunction (#2218) (#2219)\nAdded support for ScalarNonlinearFunction in FileFormats.NL (#2228) (#2231)\nAdded support for writing non-Float64 functions in FileFormats.MOF\nAdded Utilities.lazy_map (#2254)","category":"page"},{"location":"release_notes/#Fixed","page":"Release notes","title":"Fixed","text":"","category":"section"},{"location":"release_notes/","page":"Release notes","title":"Release notes","text":"Fixed method ambiguities in operate (#2224)\nFixed reading LP file with a -infinity <= x <= +infinity variable (#2225)\nFixed missing require in Test.test_nonlinear_duals (#2230)\nFixed bug in ConstraintPrimal of Bridges.Constraint.QuadtoSOCBridge (#2240)","category":"page"},{"location":"release_notes/#Other-2","page":"Release notes","title":"Other","text":"","category":"section"},{"location":"release_notes/","page":"Release notes","title":"Release notes","text":"Added extensions to solver-tests.yml (#2229)\nRefactored test/Benchmarks (#2234)\nFixed warnings in tests (#2241) (#2243)\nSmall refactoring of bridges for upcoming VectorNonlinearFunction (#2244) (#2245)\nFixed various typos (#2251) (#2255)\nPartitioned how we run the tests on GitHub actions (#2252) (#2253)","category":"page"},{"location":"release_notes/#[v1.18.0](https://github.com/jump-dev/MathOptInterface.jl/releases/tag/v1.18.0)-(June-23,-2023)","page":"Release notes","title":"v1.18.0 (June 23, 2023)","text":"","category":"section"},{"location":"release_notes/#Added-3","page":"Release notes","title":"Added","text":"","category":"section"},{"location":"release_notes/","page":"Release notes","title":"Release notes","text":"Added Bridges.Objective.SlackBridgePrimalDualStart (#2194)\nAdded constraint_gradient_structure and eval_constraint_gradient (#2200)","category":"page"},{"location":"release_notes/#Fixed-2","page":"Release notes","title":"Fixed","text":"","category":"section"},{"location":"release_notes/","page":"Release notes","title":"Release notes","text":"Fixed a missing @require in MOI.Test (#2195) (#2196)\nFixed incorrect usage of Utilities.operate! in bridges (#2207) (#2216)\nFixed splatting nonlinear expression with univariate operator (#2221)","category":"page"},{"location":"release_notes/#Other-3","page":"Release notes","title":"Other","text":"","category":"section"},{"location":"release_notes/","page":"Release notes","title":"Release notes","text":"Removed unused argument names (#2199)\nReduced memory requirement for tests (#2204)\nRefactored Utilities.promote_operation (#2206)\nImproved code style in Utilities/mutable_arithmetics.jl (#2209)\nRefactored various methods in Utilities/functions.jl (#2208) (#2212) (#2213) (#2214) (#2215)","category":"page"},{"location":"release_notes/#[v1.17.1](https://github.com/jump-dev/MathOptInterface.jl/releases/tag/v1.17.1)-(June-6,-2023)","page":"Release notes","title":"v1.17.1 (June 6, 2023)","text":"","category":"section"},{"location":"release_notes/#Fixed-3","page":"Release notes","title":"Fixed","text":"","category":"section"},{"location":"release_notes/","page":"Release notes","title":"Release notes","text":"Fixed comparison of ScalarFunctionConstantNotZero (#2190)","category":"page"},{"location":"release_notes/#Other-4","page":"Release notes","title":"Other","text":"","category":"section"},{"location":"release_notes/","page":"Release notes","title":"Release notes","text":"Added documentation for enum instances (#2186)\nUpdated chatroom links in documentation (#2188)\nChanged the documentation to build on Julia v1.9 (#2191)","category":"page"},{"location":"release_notes/#[v1.17.0](https://github.com/jump-dev/MathOptInterface.jl/releases/tag/v1.17.0)-(June-1,-2023)","page":"Release notes","title":"v1.17.0 (June 1, 2023)","text":"","category":"section"},{"location":"release_notes/#Added-4","page":"Release notes","title":"Added","text":"","category":"section"},{"location":"release_notes/","page":"Release notes","title":"Release notes","text":"Added ScalarNonlinearFunction (#2059)\nAdded a variety of tests for NormSpectralCone, NormNuclearCone, and HermitianPositiveSemidefiniteConeTriangle (#2174)\nAdded Utilities.value_type for computing the value type of a function (#2176)","category":"page"},{"location":"release_notes/#Fixed-4","page":"Release notes","title":"Fixed","text":"","category":"section"},{"location":"release_notes/","page":"Release notes","title":"Release notes","text":"Fixed support for external sets in Utilities.loadfromstring! (#2177)\nFixed promote_operation for ScalarNonlinearFunction (#2179)\nFixed two issues in FileFormats.LP when reading files with quadratic functions (#2182) (#2184)","category":"page"},{"location":"release_notes/#[v1.16.0](https://github.com/jump-dev/MathOptInterface.jl/releases/tag/v1.16.0)-(May-16,-2023)","page":"Release notes","title":"v1.16.0 (May 16, 2023)","text":"","category":"section"},{"location":"release_notes/#Added-5","page":"Release notes","title":"Added","text":"","category":"section"},{"location":"release_notes/","page":"Release notes","title":"Release notes","text":"Added support for MathOptFormat v1.3 and v1.4 (#2158) (#2169)\nAdded new method to the nonlinear API (#2162) (#2164)\neval_hessian_constraint\neval_hessian_objective\nhessian_constraint_structure\nhessian_objective_structure\nAdded new sets\nNormCone (#2119)\nScaledPositiveSemidefiniteConeTriangle (#2154)","category":"page"},{"location":"release_notes/#Fixed-5","page":"Release notes","title":"Fixed","text":"","category":"section"},{"location":"release_notes/","page":"Release notes","title":"Release notes","text":"Fixed support for Julia v1.9 to work around a bug in the upstream Julia compiler (#2161) (#2163)\nFixed a correctness bug in Bridges.Constraint.HermitianToSymmetricPSDBridge (#2171)\nFixed convert(::VariableIndex, ::ScalarAffineFunction) when the function has terms with 0coefficients (#2173)","category":"page"},{"location":"release_notes/#Other-5","page":"Release notes","title":"Other","text":"","category":"section"},{"location":"release_notes/","page":"Release notes","title":"Release notes","text":"Fixed solver-tests.yml (#2157)\nUpdated documentation links to developer chatroom (#2160)\nAdded various tests for bridges (#2156)\nAdded checklists to the developer documentation (#2167) (#2168)","category":"page"},{"location":"release_notes/#[v1.15.1](https://github.com/jump-dev/MathOptInterface.jl/releases/tag/v1.15.1)-(April-25,-2023)","page":"Release notes","title":"v1.15.1 (April 25, 2023)","text":"","category":"section"},{"location":"release_notes/#Fixed-6","page":"Release notes","title":"Fixed","text":"","category":"section"},{"location":"release_notes/","page":"Release notes","title":"Release notes","text":"Fixed deleting a variable in a bridged objective (#2150)","category":"page"},{"location":"release_notes/#[v1.15.0](https://github.com/jump-dev/MathOptInterface.jl/releases/tag/v1.15.0)-(April-19,-2023)","page":"Release notes","title":"v1.15.0 (April 19, 2023)","text":"","category":"section"},{"location":"release_notes/#Added-6","page":"Release notes","title":"Added","text":"","category":"section"},{"location":"release_notes/","page":"Release notes","title":"Release notes","text":"Added Bridges.Objective.VectorFunctionizeBridge (#2139)","category":"page"},{"location":"release_notes/#Fixed-7","page":"Release notes","title":"Fixed","text":"","category":"section"},{"location":"release_notes/","page":"Release notes","title":"Release notes","text":"Fixed support for Rational in Bridges.Constraint.SplitIntervalBridge (#2137)\nFixed printing of LaTeX models (#2141)\nFixed modify in Bridges.Objective.VectorSlackBridge (#2144)\nFixed NAME record with spaces in FileFormats.MPS (#2146)\nFixed deleting a variable in a bridged objective (#2147)","category":"page"},{"location":"release_notes/#Other-6","page":"Release notes","title":"Other","text":"","category":"section"},{"location":"release_notes/","page":"Release notes","title":"Release notes","text":"Add a test for variables in one-sided open Interval sets (#2133)\nMinor style fixes in the source code (#2148)","category":"page"},{"location":"release_notes/#[v1.14.1](https://github.com/jump-dev/MathOptInterface.jl/releases/tag/v1.14.1)-(April-6,-2023)","page":"Release notes","title":"v1.14.1 (April 6, 2023)","text":"","category":"section"},{"location":"release_notes/#Fixed-8","page":"Release notes","title":"Fixed","text":"","category":"section"},{"location":"release_notes/","page":"Release notes","title":"Release notes","text":"Fixed a bug in Bridges.print_active_bridges (#2135)","category":"page"},{"location":"release_notes/#Other-7","page":"Release notes","title":"Other","text":"","category":"section"},{"location":"release_notes/","page":"Release notes","title":"Release notes","text":"Added a warning when an ambiguous string is passed to exclude in Test.runtests (#2136)","category":"page"},{"location":"release_notes/#[v1.14.0](https://github.com/jump-dev/MathOptInterface.jl/releases/tag/v1.14.0)-(April-4,-2023)","page":"Release notes","title":"v1.14.0 (April 4, 2023)","text":"","category":"section"},{"location":"release_notes/#Added-7","page":"Release notes","title":"Added","text":"","category":"section"},{"location":"release_notes/","page":"Release notes","title":"Release notes","text":"Added support for starting values in Bridges.Constraint.QuadtoSOCBridge (#2115)\nAdded support for Regex in the include and exclude arguments to Test.runtests (#2129)\nAdded Bridges.print_active_bridges methods for individual objectives and constraints (#2128)","category":"page"},{"location":"release_notes/#Fixed-9","page":"Release notes","title":"Fixed","text":"","category":"section"},{"location":"release_notes/","page":"Release notes","title":"Release notes","text":"Fixed ResultCount when parsing .sol files in FileFormats.NL (#2130)","category":"page"},{"location":"release_notes/#[v1.13.2](https://github.com/jump-dev/MathOptInterface.jl/releases/tag/v1.13.2)-(March-21,-2023)","page":"Release notes","title":"v1.13.2 (March 21, 2023)","text":"","category":"section"},{"location":"release_notes/#Fixed-10","page":"Release notes","title":"Fixed","text":"","category":"section"},{"location":"release_notes/","page":"Release notes","title":"Release notes","text":"Fixed splatting of containers in MOI.Nonlinear (#2120)\nFixed a bug reading LP files with default bounds (#2121)\nFixed a bug in which Bridges.Constraint.HermitianToSymmetricPSDBridge was not enabled by default (#2123)","category":"page"},{"location":"release_notes/#Other-8","page":"Release notes","title":"Other","text":"","category":"section"},{"location":"release_notes/","page":"Release notes","title":"Release notes","text":"Fixed typos in the documentation (#2114)\nFunctions now print to the REPL in algebraic form. This is potentially breaking if you have tests which rely on a specific String form of MOI functions. (#2112) (#2126)","category":"page"},{"location":"release_notes/#[v1.13.1](https://github.com/jump-dev/MathOptInterface.jl/releases/tag/v1.13.1)-(March-3,-2023)","page":"Release notes","title":"v1.13.1 (March 3, 2023)","text":"","category":"section"},{"location":"release_notes/#Other-9","page":"Release notes","title":"Other","text":"","category":"section"},{"location":"release_notes/","page":"Release notes","title":"Release notes","text":"Added the Google style guide to the documentation linter Vale, and fixed the resulting warnings (#2110)\nImproved the docstrings in src/functions.jl (#2108)","category":"page"},{"location":"release_notes/#[v1.13.0](https://github.com/jump-dev/MathOptInterface.jl/releases/tag/v1.13.0)-(February-28,-2023)","page":"Release notes","title":"v1.13.0 (February 28, 2023)","text":"","category":"section"},{"location":"release_notes/#Added-8","page":"Release notes","title":"Added","text":"","category":"section"},{"location":"release_notes/","page":"Release notes","title":"Release notes","text":"Added Bridges.Constraint.NumberConversionBridge (#2091)\nAdded Parameter set (#2095) (#2105) (#2106) (#2109)\nAdded with_cache_type argument to instantiate (#2097)\nAdded support for HermitianPositiveSemidefiniteConeTriangle in Utilities.Model (#2100)","category":"page"},{"location":"release_notes/#Fixed-11","page":"Release notes","title":"Fixed","text":"","category":"section"},{"location":"release_notes/","page":"Release notes","title":"Release notes","text":"Fixed bug when Utilities.@product_of_sets is empty (#2101)\nFixed Bridges.print_active_bridges when variable bridge is an AbstractScalarSet (#2107)","category":"page"},{"location":"release_notes/#Other-10","page":"Release notes","title":"Other","text":"","category":"section"},{"location":"release_notes/","page":"Release notes","title":"Release notes","text":"Added tests for vector-valued objective functions in FileFormats.MOF (#2093)\nUsed and documented preference for import MathOptInterface as MOI (#2096)\nFix and test links in the documentation with linkcheck = true (#2098)\nImproved docstrings of sets in src/sets.jl (#2099)\nSkip checking flakey links in documentation with linkcheck_ignore (#2103)","category":"page"},{"location":"release_notes/#[v1.12.0](https://github.com/jump-dev/MathOptInterface.jl/releases/tag/v1.12.0)-(February-10,-2023)","page":"Release notes","title":"v1.12.0 (February 10, 2023)","text":"","category":"section"},{"location":"release_notes/#Added-9","page":"Release notes","title":"Added","text":"","category":"section"},{"location":"release_notes/","page":"Release notes","title":"Release notes","text":"Added support for vector-valued objective functions (#2070)\nAdded a Utilities.distance_to_set method for SecondOrderCone (#2060)","category":"page"},{"location":"release_notes/#Fixed-12","page":"Release notes","title":"Fixed","text":"","category":"section"},{"location":"release_notes/","page":"Release notes","title":"Release notes","text":"Fixed a number of constraint bridges so that Bridges.final_touch can be called multiple times without forcing a rebuild of the reformulation (#2089)","category":"page"},{"location":"release_notes/#Other-11","page":"Release notes","title":"Other","text":"","category":"section"},{"location":"release_notes/","page":"Release notes","title":"Release notes","text":"Added new tests that a set ObjectiveFunction appears in ListOfModelAttributesSet (#2085)\nImproved the docstrings of a number of constraint-programming related sets (#2087)","category":"page"},{"location":"release_notes/#[v1.11.5](https://github.com/jump-dev/MathOptInterface.jl/releases/tag/v1.11.5)-(January-24,-2023)","page":"Release notes","title":"v1.11.5 (January 24, 2023)","text":"","category":"section"},{"location":"release_notes/#Fixed-13","page":"Release notes","title":"Fixed","text":"","category":"section"},{"location":"release_notes/","page":"Release notes","title":"Release notes","text":"Fixed a bug writing .lp files with an off-diagonal quadratic objective (#2082)","category":"page"},{"location":"release_notes/#Other-12","page":"Release notes","title":"Other","text":"","category":"section"},{"location":"release_notes/","page":"Release notes","title":"Release notes","text":"Added SnoopPrecompile directives for reduced time-to-first-X in Julia v1.9 (#2080)","category":"page"},{"location":"release_notes/#[v1.11.4](https://github.com/jump-dev/MathOptInterface.jl/releases/tag/v1.11.4)-(January-12,-2023)","page":"Release notes","title":"v1.11.4 (January 12, 2023)","text":"","category":"section"},{"location":"release_notes/#Fixed-14","page":"Release notes","title":"Fixed","text":"","category":"section"},{"location":"release_notes/","page":"Release notes","title":"Release notes","text":"Fixed a bug reading .lp files with an Integer section (#2078)","category":"page"},{"location":"release_notes/#[v1.11.3](https://github.com/jump-dev/MathOptInterface.jl/releases/tag/v1.11.3)-(January-12,-2023)","page":"Release notes","title":"v1.11.3 (January 12, 2023)","text":"","category":"section"},{"location":"release_notes/#Fixed-15","page":"Release notes","title":"Fixed","text":"","category":"section"},{"location":"release_notes/","page":"Release notes","title":"Release notes","text":"Fixed a performance bug when deleting a vector of constraints (#2072)\nFixed a bug reading .lp files with terms like x -1 y (#2076)","category":"page"},{"location":"release_notes/#Other-13","page":"Release notes","title":"Other","text":"","category":"section"},{"location":"release_notes/","page":"Release notes","title":"Release notes","text":"Documented the two-argument method of optimize! (#2074)","category":"page"},{"location":"release_notes/#[v1.11.2](https://github.com/jump-dev/MathOptInterface.jl/releases/tag/v1.11.2)-(January-2,-2023)","page":"Release notes","title":"v1.11.2 (January 2, 2023)","text":"","category":"section"},{"location":"release_notes/#Fixed-16","page":"Release notes","title":"Fixed","text":"","category":"section"},{"location":"release_notes/","page":"Release notes","title":"Release notes","text":"Fixed a bug reading .mof.json files with ConstraintName set for VariableIndex constraints (#2066)\nFixed a bug reading .mof.json files with nonlinear objectives and no constraints (#2068)","category":"page"},{"location":"release_notes/#[v1.11.1](https://github.com/jump-dev/MathOptInterface.jl/releases/tag/v1.11.1)-(December-22,-2022)","page":"Release notes","title":"v1.11.1 (December 22, 2022)","text":"","category":"section"},{"location":"release_notes/#Fixed-17","page":"Release notes","title":"Fixed","text":"","category":"section"},{"location":"release_notes/","page":"Release notes","title":"Release notes","text":"Fixed a bug reading .mof.json files with integer coefficients for affine and quadratic functions (#2063)","category":"page"},{"location":"release_notes/#[v1.11.0](https://github.com/jump-dev/MathOptInterface.jl/releases/tag/v1.11.0)-(December-2,-2022)","page":"Release notes","title":"v1.11.0 (December 2, 2022)","text":"","category":"section"},{"location":"release_notes/#Added-10","page":"Release notes","title":"Added","text":"","category":"section"},{"location":"release_notes/","page":"Release notes","title":"Release notes","text":"Added Utilities.PenaltyRelaxation and Utilities.ScalarPenaltyRelaxation (#1995)\nAdded Utilities.distance_to_set (#2048)\nAdded support for ConstraintPrimalStart and ConstraintDualStart in FileFormats.MOF (#2056)","category":"page"},{"location":"release_notes/#Other-14","page":"Release notes","title":"Other","text":"","category":"section"},{"location":"release_notes/","page":"Release notes","title":"Release notes","text":"Tidied these release notes (#2055)","category":"page"},{"location":"release_notes/#[v1.10.0](https://github.com/jump-dev/MathOptInterface.jl/releases/tag/v1.10.0)-(November-22,-2022)","page":"Release notes","title":"v1.10.0 (November 22, 2022)","text":"","category":"section"},{"location":"release_notes/#Added-11","page":"Release notes","title":"Added","text":"","category":"section"},{"location":"release_notes/","page":"Release notes","title":"Release notes","text":"Added new methods set(::OptimizerWithAttributes, ::RawOptimizerAttribute, value) and get(::OptimizerWithAttributes, ::RawOptimizerAttribute) (#2049)\nAdded new methods Utilities.DoubleDicts.outer_keys and Utilities.DoubleDicts.nonempty_outer_keys (#2052)","category":"page"},{"location":"release_notes/#Fixed-18","page":"Release notes","title":"Fixed","text":"","category":"section"},{"location":"release_notes/","page":"Release notes","title":"Release notes","text":"Fixed Bridges.Objective.SlackBridge when the objective function is complex-valued (#2036) (#2038)\nFixed docstring of Test.runtests to clarify the warn_unsupported argument (#2037)\nFixed reading of free variables in FileFormats.LP (#2044)\nFixed numerous edge cases reading files from QPLIB using FileFormats.LP (#2042) (#2044)\nFixed situations in which x^y returns a complex value in Nonlinear (#2050)","category":"page"},{"location":"release_notes/#Other-15","page":"Release notes","title":"Other","text":"","category":"section"},{"location":"release_notes/","page":"Release notes","title":"Release notes","text":"Improved the error message thrown when a user-defined nonlinear function does not accept splatted input (#2032)\nRemoved specialized iterators for keys and values in Utilities.CleverDicts (#2051)","category":"page"},{"location":"release_notes/#[v1.9.0](https://github.com/jump-dev/MathOptInterface.jl/releases/tag/v1.9.0)-(October-29,-2022)","page":"Release notes","title":"v1.9.0 (October 29, 2022)","text":"","category":"section"},{"location":"release_notes/#Added-12","page":"Release notes","title":"Added","text":"","category":"section"},{"location":"release_notes/","page":"Release notes","title":"Release notes","text":"Added default fallback for getting ListOfConstraintIndices and NumberOfConstraints when the constraint type is unsupported by the model (#2021)\nAdded support for min and max in nonlinear expressions (#2023)\nAdded support for Indicator{EqualTo{T}} constraints in FileFormats.MPS (#2022)\nAdded default fallback for write_to_file and read_from_file (#2029)","category":"page"},{"location":"release_notes/#Fixed-19","page":"Release notes","title":"Fixed","text":"","category":"section"},{"location":"release_notes/","page":"Release notes","title":"Release notes","text":"Fixed Constraint.ZeroOneBridge by adding new bounds as affine constraints instead of variable bounds (#1879)\nFixed reading free rows in FileFormats.MPS files (#2009)\nFixed parsing of OBJSENSE blocks in FileFormats.MPS files (#2016) (#2019)\nFixed the parsing of deeply nested nonlinear expressions by removing the use of recursion (#2020)\nFixed the requirements check in Test.test_constrainnt_get_ConstraintIndex (#2024)","category":"page"},{"location":"release_notes/#[v1.8.2](https://github.com/jump-dev/MathOptInterface.jl/releases/tag/v1.8.2)-(September-20,-2022)","page":"Release notes","title":"v1.8.2 (September 20, 2022)","text":"","category":"section"},{"location":"release_notes/#Documentation","page":"Release notes","title":"Documentation","text":"","category":"section"},{"location":"release_notes/","page":"Release notes","title":"Release notes","text":"Added vale as a documentation linter (#2002)\nImproved styling of code blocks in the PDF (#1999) (#2000)\nFixed a number of typos in the documentation (#2001) (#2003)","category":"page"},{"location":"release_notes/#[v1.8.1](https://github.com/jump-dev/MathOptInterface.jl/releases/tag/v1.8.1)-(September-12,-2022)","page":"Release notes","title":"v1.8.1 (September 12, 2022)","text":"","category":"section"},{"location":"release_notes/#Fixed-20","page":"Release notes","title":"Fixed","text":"","category":"section"},{"location":"release_notes/","page":"Release notes","title":"Release notes","text":"Fixed a bug in supports(::AbstractBridgeOptimizer for constraint attributes (#1991) (#1992)","category":"page"},{"location":"release_notes/#[v1.8.0](https://github.com/jump-dev/MathOptInterface.jl/releases/tag/v1.8.0)-(September-1,-2022)","page":"Release notes","title":"v1.8.0 (September 1, 2022)","text":"","category":"section"},{"location":"release_notes/#Added-13","page":"Release notes","title":"Added","text":"","category":"section"},{"location":"release_notes/","page":"Release notes","title":"Release notes","text":"Added new sets\nHyperRectangle (#1961)\nReified (#1955)\nAdded new bridges (#1955)\nBridges.Constraint.ReifiedAllDifferentToCountDistinctBridge\nBridges.Constraint.ReifiedCountDistinctToMILPBridge\nBridges.Constraint.SplitHyperRectangleBridge\nAdded support for atan(y, x) in Nonlinear (#1987)","category":"page"},{"location":"release_notes/#Fixed-21","page":"Release notes","title":"Fixed","text":"","category":"section"},{"location":"release_notes/","page":"Release notes","title":"Release notes","text":"Lazily construct expressions in Nonlinear so that expressions are updated when Nonlinear.Parameter values are updated (#1984)\nAllow NORM_LIMIT as a TerminationStatus for unbounded problems in Test (#1990)","category":"page"},{"location":"release_notes/#[v1.7.0](https://github.com/jump-dev/MathOptInterface.jl/releases/tag/v1.7.0)-(August-16,-2022)","page":"Release notes","title":"v1.7.0 (August 16, 2022)","text":"","category":"section"},{"location":"release_notes/#Added-14","page":"Release notes","title":"Added","text":"","category":"section"},{"location":"release_notes/","page":"Release notes","title":"Release notes","text":"Added new sets\nHermitianPositiveSemidefiniteConeTriangle\nAdded new optimizer-independent options\nRelativeGapTolerance\nAbsoluteGapTolerance\nAdded new bridges\nBridges.Constraint.GeoMeanToPowerBridge\nBridges.Constraint.HermitianToSymmetricPSDBridge\nBridges.Constraint.IndicatorGreaterToLessThanBridge\nBridges.Constraint.IndicatorLessToGreaterThanBridge\nBridges.Constraint.SplitComplexZerosBridge\nBridges.Constraint.SplitComplexEqualToBridge\nBridges.Objective.QuadratizeBridge\nAdded support for generic number types in Utilities.loadfromstring!\nUpdated FileFormats.MOF to MathOptFormat v1.1, enabling support for constraint programming sets in the MOF file format\nAdded support in various FileFormats for\nindicator constraints in FileFormats.MPS\nquadratic constraints and an objective in FileFormats.LP\nquadratic constraints and an objective in FileFormats.MPS","category":"page"},{"location":"release_notes/#Fixed-22","page":"Release notes","title":"Fixed","text":"","category":"section"},{"location":"release_notes/","page":"Release notes","title":"Release notes","text":"Fixed some missing promotion rules","category":"page"},{"location":"release_notes/#Other-16","page":"Release notes","title":"Other","text":"","category":"section"},{"location":"release_notes/","page":"Release notes","title":"Release notes","text":"Improved the performance of Jacobian products in Nonlinear\nRemoved an un-needed copy in Utilities.modify_function\nVarious clean-ups in Bridges/bridge_optimizer.jl","category":"page"},{"location":"release_notes/#[v1.6.1](https://github.com/jump-dev/MathOptInterface.jl/releases/tag/v1.6.1)-(July-23,-2022)","page":"Release notes","title":"v1.6.1 (July 23, 2022)","text":"","category":"section"},{"location":"release_notes/#Fixed-23","page":"Release notes","title":"Fixed","text":"","category":"section"},{"location":"release_notes/","page":"Release notes","title":"Release notes","text":"Added support for ExponentialCone in MatrixOfConstraints\nFix PSDSquare_3 test to reflect a previously fixed bug getting the ConstraintDual of a PositiveSemidefiniteConeSquare constraint","category":"page"},{"location":"release_notes/#[v1.6.0](https://github.com/jump-dev/MathOptInterface.jl/releases/tag/v1.6.0)-(July-2,-2022)","page":"Release notes","title":"v1.6.0 (July 2, 2022)","text":"","category":"section"},{"location":"release_notes/#Added-15","page":"Release notes","title":"Added","text":"","category":"section"},{"location":"release_notes/","page":"Release notes","title":"Release notes","text":"Added Bridges.needs_final_touch and Bridges.final_touch\nAdded new bridges from constraint programming sets to mixed-integer linear programs:\nAllDifferentToCountDistinctBridge\nCountAtLeastToCountBelongsBridge\nCountBelongsToMILPBridge\nCountDistinctToMILPBridge\nCountGreaterThanToMILPBridge\nCircuitToMILPBridge","category":"page"},{"location":"release_notes/#Fixed-24","page":"Release notes","title":"Fixed","text":"","category":"section"},{"location":"release_notes/","page":"Release notes","title":"Release notes","text":"Relax an instance of ::Vector to ::AbstractVector in MOI.Nonlinear\nFix BinPackingToMILPBridge to respect variable bounds\nFix SemiToBinaryBridge to throw error if other bounds are set","category":"page"},{"location":"release_notes/#[v1.5.0](https://github.com/jump-dev/MathOptInterface.jl/releases/tag/v1.5.0)-(June-27,-2022)","page":"Release notes","title":"v1.5.0 (June 27, 2022)","text":"","category":"section"},{"location":"release_notes/#Added-16","page":"Release notes","title":"Added","text":"","category":"section"},{"location":"release_notes/","page":"Release notes","title":"Release notes","text":"Added GetAttributeNotAllowed for solvers to indicate when getting an attribute encounters an error\nAdded Utilities.get_fallback support for ObjectiveValue and DualObjectiveValue\nAdded new bridges:\nRootDetConeSquare to RootDetConeTriangle\nLogDetConeSquare to LogDetConeTriangle\nBinPacking to a mixed-integer linear program\nTable to a mixed-integer linear program\nAdded Bridges.print_active_bridges to display the current optimal hyper-path in a Bridges.LazyBridgeOptimizer","category":"page"},{"location":"release_notes/#Fixed-25","page":"Release notes","title":"Fixed","text":"","category":"section"},{"location":"release_notes/","page":"Release notes","title":"Release notes","text":"Fixed ZeroOne tests with lower and upper bounds\nFixed error in FileFormats.LP when reading a malformed file\nFixed reading of nonlinear programs in FileFormats.MOF\nFixed bug in ConstraintDual when using SquareBridge","category":"page"},{"location":"release_notes/#Other-17","page":"Release notes","title":"Other","text":"","category":"section"},{"location":"release_notes/","page":"Release notes","title":"Release notes","text":"Improved documentation of nonlinear API\nDocumented duality convention for PositiveSemidefiniteConeSquare sets\nFixed typo in Bridges.Constraint.QuadToSOCBridge docstring","category":"page"},{"location":"release_notes/#[v1.4.0](https://github.com/jump-dev/MathOptInterface.jl/releases/tag/v1.4.0)-(June-9,-2022)","page":"Release notes","title":"v1.4.0 (June 9, 2022)","text":"","category":"section"},{"location":"release_notes/#Added-17","page":"Release notes","title":"Added","text":"","category":"section"},{"location":"release_notes/","page":"Release notes","title":"Release notes","text":"Added a number of sets for constraint programming:\nAllDifferent\nBinPacking\nCircuit\nCountAtLeast\nCountBelongs\nCountDistinct\nCountGreaterThan\nCumulative\nPath\nTable\nAdded support for user-defined hessians in Nonlinear\nAdded Bridges.runtests to simplify the testing of bridge implementations","category":"page"},{"location":"release_notes/#Fixed-26","page":"Release notes","title":"Fixed","text":"","category":"section"},{"location":"release_notes/","page":"Release notes","title":"Release notes","text":"Fixed a bug in FileFormats.NL when writing univariate *","category":"page"},{"location":"release_notes/#Other-18","page":"Release notes","title":"Other","text":"","category":"section"},{"location":"release_notes/","page":"Release notes","title":"Release notes","text":"Began a large refactoring of the Bridges submodule, with greatly improved documentation.","category":"page"},{"location":"release_notes/#[v1.3.0](https://github.com/jump-dev/MathOptInterface.jl/releases/tag/v1.3.0)-(May-27,-2022)","page":"Release notes","title":"v1.3.0 (May 27, 2022)","text":"","category":"section"},{"location":"release_notes/#Added-18","page":"Release notes","title":"Added","text":"","category":"section"},{"location":"release_notes/","page":"Release notes","title":"Release notes","text":"Add MOI.Nonlinear submodule. This is a large new submodule that has been refactored from code that was in JuMP. For now, it should be considered experimental.\nAdd FileFormats.NL.SolFileResults(::IO, ::Model)\nAdd FileFormats.NL.read!(::IO, ::Model)\nAdd MOI.modify that accepts a vector of modifications","category":"page"},{"location":"release_notes/#Fixed-27","page":"Release notes","title":"Fixed","text":"","category":"section"},{"location":"release_notes/","page":"Release notes","title":"Release notes","text":"Fixed a bug in Test which attempted to include non-.jl files\nFixed a bug in FileFormats for models with open interval constraints","category":"page"},{"location":"release_notes/#Other-19","page":"Release notes","title":"Other","text":"","category":"section"},{"location":"release_notes/","page":"Release notes","title":"Release notes","text":"Fixed a performance issue in Utilities.DoubleDict\nVarious minor improvements to the documentation","category":"page"},{"location":"release_notes/#[v1.2.0](https://github.com/jump-dev/MathOptInterface.jl/releases/tag/v1.2.0)-(April-25,-2022)","page":"Release notes","title":"v1.2.0 (April 25, 2022)","text":"","category":"section"},{"location":"release_notes/#Added-19","page":"Release notes","title":"Added","text":"","category":"section"},{"location":"release_notes/","page":"Release notes","title":"Release notes","text":"Add support for the FORMAT_REW/.rew file format in FileFormats.","category":"page"},{"location":"release_notes/#Fixed-28","page":"Release notes","title":"Fixed","text":"","category":"section"},{"location":"release_notes/","page":"Release notes","title":"Release notes","text":"Fix bug handling of default variable bounds in FileFormats.LP\nFix FileFormats.MPS to not write OBJSENSE by default since this is only supported by some readers.","category":"page"},{"location":"release_notes/#[v1.1.2](https://github.com/jump-dev/MathOptInterface.jl/releases/tag/v1.1.2)-(March-31,-2022)","page":"Release notes","title":"v1.1.2 (March 31, 2022)","text":"","category":"section"},{"location":"release_notes/#Fixed-29","page":"Release notes","title":"Fixed","text":"","category":"section"},{"location":"release_notes/","page":"Release notes","title":"Release notes","text":"Fix a range of bugs in FileFormats.LP\nFix reading of problem dimensions in FileFormats.SDPA","category":"page"},{"location":"release_notes/#[v1.1.1](https://github.com/jump-dev/MathOptInterface.jl/releases/tag/v1.1.1)-(March-23,-2022)","page":"Release notes","title":"v1.1.1 (March 23, 2022)","text":"","category":"section"},{"location":"release_notes/#Fixed-30","page":"Release notes","title":"Fixed","text":"","category":"section"},{"location":"release_notes/","page":"Release notes","title":"Release notes","text":"Fix bug in test_model_UpperBoundAlreadySet\nFix bug in test_infeasible_ tests\nFix bug in test_objective_ObjectiveFunction_blank\nRelax restriction of MOI.AbstractOptimizer to MOI.ModelLike in Utilities.CachingOptimizer and instantiate.","category":"page"},{"location":"release_notes/#New-tests","page":"Release notes","title":"New tests","text":"","category":"section"},{"location":"release_notes/","page":"Release notes","title":"Release notes","text":"Add test_conic_empty_matrix that checks conic solvers support problems with no variables.","category":"page"},{"location":"release_notes/#[v1.1.0](https://github.com/jump-dev/MathOptInterface.jl/releases/tag/v1.1.0)-(March-2,-2022)","page":"Release notes","title":"v1.1.0 (March 2, 2022)","text":"","category":"section"},{"location":"release_notes/#Added-20","page":"Release notes","title":"Added","text":"","category":"section"},{"location":"release_notes/","page":"Release notes","title":"Release notes","text":"Added MOI.Utilities.throw_unsupported(::UniversalFallback) for simplifying solver wrappers which copy from a UniversalFallback.","category":"page"},{"location":"release_notes/#[v1.0.2](https://github.com/jump-dev/MathOptInterface.jl/releases/tag/v1.0.2)-(March-1,-2022)","page":"Release notes","title":"v1.0.2 (March 1, 2022)","text":"","category":"section"},{"location":"release_notes/#Fixed-31","page":"Release notes","title":"Fixed","text":"","category":"section"},{"location":"release_notes/","page":"Release notes","title":"Release notes","text":"Fixed a bug in the test_model_ScalarFunctionConstantNotZero test\nFixed the error type when an AbstractFunctionConversionBridge cannot get or set an attribute\nIdentified a correctness bug in RSOCtoPSDBridge. We now thrown an error instead of returning an incorrect result.","category":"page"},{"location":"release_notes/#[v1.0.1](https://github.com/jump-dev/MathOptInterface.jl/releases/tag/v1.0.1)-(February-25,-2022)","page":"Release notes","title":"v1.0.1 (February 25, 2022)","text":"","category":"section"},{"location":"release_notes/#Fixed-32","page":"Release notes","title":"Fixed","text":"","category":"section"},{"location":"release_notes/","page":"Release notes","title":"Release notes","text":"Fixed a bug in which OptimizerAttributes were not copied in CachingOptimizer\nFixed a bug in which shift_constant did not promote mixed types of coefficients\nFixed a bug in which deleting a constraint of a bridged variable threw ErrorException instead of MOI.DeleteNotAllowed\nFixed a bug in which add_constraint in MatrixOfConstraints did not canonicalize the function\nFixed a bug when modifying scalar constants of a function containing a bridged variable\nFixed a bug in which final_touch was not always called with a CachingOptimizer","category":"page"},{"location":"release_notes/#[v1.0.0](https://github.com/jump-dev/MathOptInterface.jl/releases/tag/v1.0.0)-(February-17,-2022)","page":"Release notes","title":"v1.0.0 (February 17, 2022)","text":"","category":"section"},{"location":"release_notes/","page":"Release notes","title":"Release notes","text":"Although tagged as a breaking release, v1.0.0 is v0.10.9 with deprecations removed, similar to how Julia 1.0 was Julia 0.7 with deprecations removed.","category":"page"},{"location":"release_notes/#Breaking","page":"Release notes","title":"Breaking","text":"","category":"section"},{"location":"release_notes/","page":"Release notes","title":"Release notes","text":"Julia 1.6 is now the minimum supported version\nAll deprecations have been removed","category":"page"},{"location":"release_notes/#Troubleshooting-problems-when-updating","page":"Release notes","title":"Troubleshooting problems when updating","text":"","category":"section"},{"location":"release_notes/","page":"Release notes","title":"Release notes","text":"If you experience problems when updating, you are likely using previously deprecated features. (By default, Julia does not warn when you use deprecated features.)","category":"page"},{"location":"release_notes/","page":"Release notes","title":"Release notes","text":"To find the deprecated features you are using, start Julia with --depwarn=yes:","category":"page"},{"location":"release_notes/","page":"Release notes","title":"Release notes","text":"$ julia --depwarn=yes","category":"page"},{"location":"release_notes/","page":"Release notes","title":"Release notes","text":"Then install MathOptInterface v0.10.9:","category":"page"},{"location":"release_notes/","page":"Release notes","title":"Release notes","text":"julia> using Pkg\njulia> pkg\"add MathOptInterface@0.10\"","category":"page"},{"location":"release_notes/","page":"Release notes","title":"Release notes","text":"And then run your code. Apply any suggestions, or search the release notes below for advice on updating a specific deprecated feature.","category":"page"},{"location":"release_notes/#[v0.10.9](https://github.com/jump-dev/MathOptInterface.jl/releases/tag/v0.10.9)-(February-16,-2022)","page":"Release notes","title":"v0.10.9 (February 16, 2022)","text":"","category":"section"},{"location":"release_notes/#Added-21","page":"Release notes","title":"Added","text":"","category":"section"},{"location":"release_notes/","page":"Release notes","title":"Release notes","text":"Added MOI.Utilities.FreeVariables as a new VariablesConstrainer for conic solvers\nAdded MOI.default_cache for specifying the model used in CachingOptimizer","category":"page"},{"location":"release_notes/#Fixed-33","page":"Release notes","title":"Fixed","text":"","category":"section"},{"location":"release_notes/","page":"Release notes","title":"Release notes","text":"Fixed LaTeX printing of MOI.Interval sets","category":"page"},{"location":"release_notes/#Other-20","page":"Release notes","title":"Other","text":"","category":"section"},{"location":"release_notes/","page":"Release notes","title":"Release notes","text":"Added Aqua.jl as a CI check, and fixed suggested issues\nThe constructors of GeoMeanBridge, StructOfConstraints, and CachingOptimizer were changed from outer to inner constructors. This change is technically breaking, but does not impact users who followed the documented API.","category":"page"},{"location":"release_notes/#[v0.10.8](https://github.com/jump-dev/MathOptInterface.jl/releases/tag/v0.10.8)-(February-3,-2022)","page":"Release notes","title":"v0.10.8 (February 3, 2022)","text":"","category":"section"},{"location":"release_notes/#Added-22","page":"Release notes","title":"Added","text":"","category":"section"},{"location":"release_notes/","page":"Release notes","title":"Release notes","text":"Added a Base.read! for FileFormats.LP.","category":"page"},{"location":"release_notes/#Fixed-34","page":"Release notes","title":"Fixed","text":"","category":"section"},{"location":"release_notes/","page":"Release notes","title":"Release notes","text":"Fixed a bug in MutableSparseMatrix\nFixed a bug when calling operate!(vcat, ...) with Number arguments\nRemoved unintended export of deprecated symbols\nFixed a bug with PowerCone and DualPowerCone in MatrixOfConstraints.","category":"page"},{"location":"release_notes/#[v0.10.7](https://github.com/jump-dev/MathOptInterface.jl/releases/tag/v0.10.7)-(January-5,-2022)","page":"Release notes","title":"v0.10.7 (January 5, 2022)","text":"","category":"section"},{"location":"release_notes/#Added-23","page":"Release notes","title":"Added","text":"","category":"section"},{"location":"release_notes/","page":"Release notes","title":"Release notes","text":"Added test for modifying the constant vector in a VectorAffineFunction-in-Zeros constraint.","category":"page"},{"location":"release_notes/#Fixed-35","page":"Release notes","title":"Fixed","text":"","category":"section"},{"location":"release_notes/","page":"Release notes","title":"Release notes","text":"Fixed the order in which sets are added to a LazyBridgeOptimizer. Compared to v0.10.6, this may result in bridged models being created with a different number (and order) of variables and constraints. However, it was necessary to fix cases which were previously rejected as unsupported, even though there was a valid bridge transformation.\nFixed an error message in FileFormats.CBF\nFixed comparison in test_linear_integration_Interval\nFixed errors for ConstraintPrimal in a CachingOptimizer\nFixed printing of models with non-Float64 coefficients.","category":"page"},{"location":"release_notes/#Other-21","page":"Release notes","title":"Other","text":"","category":"section"},{"location":"release_notes/","page":"Release notes","title":"Release notes","text":"Various improvements to reduce time-to-first-solve latency\nImproved error message when an optimizer does not support compute_conflict!","category":"page"},{"location":"release_notes/#[v0.10.6](https://github.com/jump-dev/MathOptInterface.jl/releases/tag/v0.10.6)-(November-30,-2021)","page":"Release notes","title":"v0.10.6 (November 30, 2021)","text":"","category":"section"},{"location":"release_notes/#Added-24","page":"Release notes","title":"Added","text":"","category":"section"},{"location":"release_notes/","page":"Release notes","title":"Release notes","text":"Added new documentation and tests for infeasibility certificates\nAdded a version control system for the tests in MOI.Test.runtests. Pass exclude_tests_after = v\"0.10.5\" to run tests added in v0.10.5 and earlier.\nMOI.Test.runtests now supports generic number types. To specify the number type T, pass MOI.Test.Config(T).\nAdded infeasible_status to MOI.Test.Config for solvers which return LOCALLY_INFEASIBLE\nCachingOptimizers now use a fallback for ConstraintPrimal. This should enable solvers using a CachingOptimizer to pass tests requiring ConstraintPrimal.","category":"page"},{"location":"release_notes/#Fixed-36","page":"Release notes","title":"Fixed","text":"","category":"section"},{"location":"release_notes/","page":"Release notes","title":"Release notes","text":"Fixed a StackOverflow bug in copy_to\nFixed error thrown when nonconvex quadratic constraints cannot be bridged\nFixed a bug in copy_to for FileFormats.NL.Model\nFixed a bug in FileFormats.NL when printing large integers\nRemove a common test failure for LowerBoundAlreadySet tests\nUtilities.num_rows is now exported\nRemove parts of failing test_model_copy_to_xxx tests due to bridges","category":"page"},{"location":"release_notes/#[v0.10.5](https://github.com/jump-dev/MathOptInterface.jl/releases/tag/v0.10.5)-(November-7,-2021)","page":"Release notes","title":"v0.10.5 (November 7, 2021)","text":"","category":"section"},{"location":"release_notes/#Fixed-37","page":"Release notes","title":"Fixed","text":"","category":"section"},{"location":"release_notes/","page":"Release notes","title":"Release notes","text":"Fixed getter in UniversalFallback\nFixed test_solve_conflict_zeroone_ii","category":"page"},{"location":"release_notes/#Other-22","page":"Release notes","title":"Other","text":"","category":"section"},{"location":"release_notes/","page":"Release notes","title":"Release notes","text":"Make normalize_and_add_constraint more flexible\nUpdate paper BibTeX","category":"page"},{"location":"release_notes/#[v0.10.4](https://github.com/jump-dev/MathOptInterface.jl/releases/tag/v0.10.4)-(October-26,-2021)","page":"Release notes","title":"v0.10.4 (October 26, 2021)","text":"","category":"section"},{"location":"release_notes/#Added-25","page":"Release notes","title":"Added","text":"","category":"section"},{"location":"release_notes/","page":"Release notes","title":"Release notes","text":"Add SolverVersion attribute\nAdd new tests:\ntest_solve_conflict_zeroone_ii\ntest_nonlinear_objective\nUtilities.VariablesContainer now supports ConstraintFunction and ConstraintSet\nThe documentation is now available as a PDF","category":"page"},{"location":"release_notes/#Other-23","page":"Release notes","title":"Other","text":"","category":"section"},{"location":"release_notes/","page":"Release notes","title":"Release notes","text":"Update to MutableArithmetics 0.3\nVarious improvements to the documentation","category":"page"},{"location":"release_notes/#[v0.10.3](https://github.com/jump-dev/MathOptInterface.jl/releases/tag/v0.10.3)-(September-18,-2021)","page":"Release notes","title":"v0.10.3 (September 18, 2021)","text":"","category":"section"},{"location":"release_notes/#Fixed-38","page":"Release notes","title":"Fixed","text":"","category":"section"},{"location":"release_notes/","page":"Release notes","title":"Release notes","text":"Fixed bug which prevented callbacks from working through a CachingOptimizer\nFixed bug in Test submodule","category":"page"},{"location":"release_notes/#[v0.10.2](https://github.com/jump-dev/MathOptInterface.jl/releases/tag/v0.10.2)-(September-16,-2021)","page":"Release notes","title":"v0.10.2 (September 16, 2021)","text":"","category":"section"},{"location":"release_notes/","page":"Release notes","title":"Release notes","text":"Updated MathOptFormat to v1.0\nUpdated JSONSchema to v1.0\nAdded Utilities.set_with_dimension\nAdded two-argument optimize!(::AbstractOptimizer, ::ModelLike)\nThe experimental feature copy_to_and_optimize! has been removed\nDet bridges now support getting ConstraintFunction and ConstraintSet\nVarious minor bug fixes identified by improved testing","category":"page"},{"location":"release_notes/#[v0.10.1](https://github.com/jump-dev/MathOptInterface.jl/releases/tag/v0.10.1)-(September-8,-2021)","page":"Release notes","title":"v0.10.1 (September 8, 2021)","text":"","category":"section"},{"location":"release_notes/","page":"Release notes","title":"Release notes","text":"Various fixes to MOI.Test","category":"page"},{"location":"release_notes/#[v0.10.0](https://github.com/jump-dev/MathOptInterface.jl/releases/tag/v0.10.0)-(September-6,-2021)","page":"Release notes","title":"v0.10.0 (September 6, 2021)","text":"","category":"section"},{"location":"release_notes/","page":"Release notes","title":"Release notes","text":"MOI v0.10 is a significant breaking release. There are a large number of user-visible breaking changes and code refactors, as well as a substantial number of new features.","category":"page"},{"location":"release_notes/#Breaking-in-MOI","page":"Release notes","title":"Breaking in MOI","text":"","category":"section"},{"location":"release_notes/","page":"Release notes","title":"Release notes","text":"SingleVariable has been removed; use VariableIndex instead\nSingleVariableConstraintNameError has been renamed to VariableIndexConstraintNameError\nSettingSingleVariableFunctionNotAllowed has been renamed to SettingVariableIndexFunctionNotAllowed\nVariableIndex constraints should not support ConstraintName\nVariableIndex constraints should not support ConstraintBasisStatus; implement VariableBasisStatus instead\nListOfConstraints has been renamed to ListOfConstraintTypesPresent\nListOfConstraintTypesPresent should now return Tuple{Type,Type} instead of Tuple{DataType,DataType}\nSolveTime has been renamed to SolveTimeSec\nIndicatorSet has been renamed to Indicator\nRawParameter has been renamed to RawOptimizerAttribute and now takes String instead of Any as the only argument\nThe .N field in result attributes has been renamed to .result_index\nThe .variable_index field in ScalarAffineTerm has been renamed to .variable\nThe .variable_index_1 field in ScalarQuadraticTerm has been renamed to .variable_1\nThe .variable_index_2 field in ScalarQuadraticTerm has been renamed to .variable_2\nThe order of affine_terms and quadratic_terms in ScalarQuadraticFunction and VectorQuadraticFunction have been reversed. Both functions now accept quadratic, affine, and constant terms in that order.\nThe index_value function has been removed. Use .value instead.\nisapprox has been removed for SOS1 and SOS2.\nThe dimension argument to Complements(dimension::Int) should now be the length of the corresponding function, instead of half the length. An ArgumentError is thrown if dimension is not even.\ncopy_to no longer takes keyword arguments:\ncopy_names: now copy names if they are supported by the destination solver\nfilter_constraints: use Utilities.ModelFilter instead\nwarn_attributes: never warn about optimizer attributes","category":"page"},{"location":"release_notes/#Breaking-in-Bridges","page":"Release notes","title":"Breaking in Bridges","text":"","category":"section"},{"location":"release_notes/","page":"Release notes","title":"Release notes","text":"Constraint.RSOCBridge has been renamed to Constraint.RSOCtoSOCBridge\nConstraint.SOCRBridge has been renamed to Constraint.SOCtoRSOCBridge\nBridges now return vectors that can be modified by the user. Previously, some bridges returned views instead of copies.\nBridges.IndexInVector has been unified into a single type. Previously, there was a different type for each submodule within Bridges\nThe signature of indicator bridges has been fixed. Use MOI.Bridges.Constraint.IndicatortoSOS1{Float64}(model).","category":"page"},{"location":"release_notes/#Breaking-in-FileFormats","page":"Release notes","title":"Breaking in FileFormats","text":"","category":"section"},{"location":"release_notes/","page":"Release notes","title":"Release notes","text":"FileFormats.MOF.Model no longer accepts validate argument. Use the JSONSchema package to validate the MOF file. See the documentation for more information.","category":"page"},{"location":"release_notes/#Breaking-in-Utilities","page":"Release notes","title":"Breaking in Utilities","text":"","category":"section"},{"location":"release_notes/","page":"Release notes","title":"Release notes","text":"The datastructure of Utilities.Model (and models created with Utilities.@model) has been significantly refactored in a breaking way. This includes the way that objective functions and variable-related information is stored.\nUtilities.supports_default_copy has been renamed to supports_incremental_interface\nUtilities.automatic_copy_to has been renamed to Utilities.default_copy_to\nThe allocate-load API has been removed\nCachingOptimizers are now initialized as EMPTY_OPTIMIZER instead of ATTACHED_OPTIMIZER. If your code relies on the optimizer being attached, call MOIU.attach_optimizer(model) after creation.\nThe field names of Utilities.IndexMap have been renamed to var_map and con_map. Accessing these fields directly is considered a private detail that may change. Use the public getindex and setindex! API instead.\nThe size argument to Utilities.CleverDicts.CleverDict(::Integer) has been removed.\nThe size argument to Utilities.IndexMap(::Integer) has been removed.\nUtilities.DoubleDicts have been significantly refactored. Consult the source code for details.\nUtilities.test_models_equal has been moved to MOI.Test","category":"page"},{"location":"release_notes/#Breaking-in-Test","page":"Release notes","title":"Breaking in Test","text":"","category":"section"},{"location":"release_notes/","page":"Release notes","title":"Release notes","text":"MOI.Test has been renamed to MOI.DeprecatedTest\nAn entirely new MOI.Test submodule has been written. See the documentation for details. The new MOI.Test submodule may find many bugs in the implementations of existing solvers that were previously untested.","category":"page"},{"location":"release_notes/#Other-changes:","page":"Release notes","title":"Other changes:","text":"","category":"section"},{"location":"release_notes/","page":"Release notes","title":"Release notes","text":"attribute_value_type has been added\ncopy_to_and_optimize! has been added\nVariableBasisStatus has been added\nprint(model) now prints a human-readable description of the model\nVarious improvements to the FileFormats submodule\nFileFormats.CBF was refactored and received bugfixes\nSupport for MathOptFormat v0.6 was added in FileFormats.MOF\nFileFormats.MPS has had bugfixes and support for more features such as OBJSENSE and objective constants.\nFileFormats.NL has been added to support nonlinear files\nImproved type inference throughout to reduce latency","category":"page"},{"location":"release_notes/#Updating","page":"Release notes","title":"Updating","text":"","category":"section"},{"location":"release_notes/","page":"Release notes","title":"Release notes","text":"A helpful script when updating is:","category":"page"},{"location":"release_notes/","page":"Release notes","title":"Release notes","text":"for (root, dirs, files) in walkdir(\".\")\n for file in files\n if !endswith(file, \".jl\")\n continue\n end\n path = joinpath(root, file)\n s = read(path, String)\n for pair in [\n \".variable_index\" => \".variable\",\n \"RawParameter\" => \"RawOptimizerAttribute\",\n \"ListOfConstraints\" => \"ListOfConstraintTypesPresent\",\n \"TestConfig\" => \"Config\",\n \"attr.N\" => \"attr.result_index\",\n \"SolveTime\" => \"SolveTimeSec\",\n \"DataType\" => \"Type\",\n \"Utilities.supports_default_copy_to\" =>\n \"supports_incremental_interface\",\n \"SingleVariableConstraintNameError\" =>\n \"VariableIndexConstraintNameError\",\n \"SettingSingleVariableFunctionNotAllowed\" =>\n \"SettingVariableIndexFunctionNotAllowed\",\n \"automatic_copy_to\" => \"default_copy_to\",\n ]\n s = replace(s, pair)\n end\n write(path, s)\n end\nend","category":"page"},{"location":"release_notes/#[v0.9.22](https://github.com/jump-dev/MathOptInterface.jl/releases/tag/v0.9.22)-(May-22,-2021)","page":"Release notes","title":"v0.9.22 (May 22, 2021)","text":"","category":"section"},{"location":"release_notes/","page":"Release notes","title":"Release notes","text":"This release contains backports from the ongoing development of the v0.10 release.","category":"page"},{"location":"release_notes/","page":"Release notes","title":"Release notes","text":"Improved type inference in Utilities, Bridges and FileFormats submodules to reduce latency.\nImproved performance of Utilities.is_canonical.\nFixed Utilities.pass_nonvariable_constraints with bridged variables.\nFixed performance regression of Utilities.Model.\nFixed ordering of objective setting in parser.","category":"page"},{"location":"release_notes/#[v0.9.21](https://github.com/jump-dev/MathOptInterface.jl/releases/tag/v0.9.21)-(April-23,-2021)","page":"Release notes","title":"v0.9.21 (April 23, 2021)","text":"","category":"section"},{"location":"release_notes/","page":"Release notes","title":"Release notes","text":"Added supports_shift_constant.\nImprove performance of bridging quadratic constraints.\nAdd precompilation statements.\nLarge improvements to the documentation.\nFix a variety of inference issues, benefiting precompilation and reducing initial latency.\nRawParameters are now ignored when resetting a CachingOptimizer. Previously, changing the underlying optimizer after RawParameters were set would throw an error.\nUtilities.AbstractModel is being refactored. This may break users interacting with private fields of a model generated using @model.","category":"page"},{"location":"release_notes/#[v0.9.20](https://github.com/jump-dev/MathOptInterface.jl/releases/tag/v0.9.20)-(February-20,-2021)","page":"Release notes","title":"v0.9.20 (February 20, 2021)","text":"","category":"section"},{"location":"release_notes/","page":"Release notes","title":"Release notes","text":"Improved performance of Utilities.ScalarFunctionIterator\nAdded support for compute_conflict to MOI layers\nAdded test with zero off-diagonal quadratic term in objective\nFixed double deletion of nested bridged SingleVariable/VectorOfVariables constraints\nFixed modification of un-set objective\nFixed function modification with duplicate terms\nMade unit tests abort without failing if the problem class is not supported\nFormatted code with JuliaFormatter\nClarified BasisStatusCode's docstring","category":"page"},{"location":"release_notes/#[v0.9.19](https://github.com/jump-dev/MathOptInterface.jl/releases/tag/v0.9.19)-(December-1,-2020)","page":"Release notes","title":"v0.9.19 (December 1, 2020)","text":"","category":"section"},{"location":"release_notes/","page":"Release notes","title":"Release notes","text":"Added CallbackNodeStatus attribute\nAdded bridge from GreaterThan or LessThan to Interval\nAdded tests for infeasibility certificates and double optimize\nFixed support for Julia v1.6\nRe-organized MOI docs and added documentation for adding a test","category":"page"},{"location":"release_notes/#[v0.9.18](https://github.com/jump-dev/MathOptInterface.jl/releases/tag/v0.9.18)-(November-3,-2020)","page":"Release notes","title":"v0.9.18 (November 3, 2020)","text":"","category":"section"},{"location":"release_notes/","page":"Release notes","title":"Release notes","text":"Various improvements for working with complex numbers\nAdded GeoMeantoRelEntrBridge to bridge a GeometricMeanCone constraint to a relative entropy constraint","category":"page"},{"location":"release_notes/#[v0.9.17](https://github.com/jump-dev/MathOptInterface.jl/releases/tag/v0.9.17)-(September-21,-2020)","page":"Release notes","title":"v0.9.17 (September 21, 2020)","text":"","category":"section"},{"location":"release_notes/","page":"Release notes","title":"Release notes","text":"Fixed CleverDict with variable of negative index value\nImplement supports_add_constrained_variable for MockOptimizer","category":"page"},{"location":"release_notes/#[v0.9.16](https://github.com/jump-dev/MathOptInterface.jl/releases/tag/v0.9.16)-(September-17,-2020)","page":"Release notes","title":"v0.9.16 (September 17, 2020)","text":"","category":"section"},{"location":"release_notes/","page":"Release notes","title":"Release notes","text":"Various fixes:\n32-bit support\nCleverDict with abstract value type\nChecks in test suite","category":"page"},{"location":"release_notes/#[v0.9.15](https://github.com/jump-dev/MathOptInterface.jl/releases/tag/v0.9.15)-(September-14,-2020)","page":"Release notes","title":"v0.9.15 (September 14, 2020)","text":"","category":"section"},{"location":"release_notes/","page":"Release notes","title":"Release notes","text":"Bridges improvements:\n(R)SOCtoNonConvexQuad bridge\nZeroOne bridge\nUse supports_add_constrained_variable in LazyBridgeOptimizer\nExposed VariableBridgeCost and ConstraintBridgeCost attributes\nPrioritize constraining variables on creation according to these costs\nRefactor bridge debugging\nLarge performance improvements across all submodules\nLots of documentation improvements\nFileFormats improvements:\nUpdate MathOptFormat to v0.5\nFix supported objectives in FileFormats\nTesting improvements:\nAdd name option for basic_constraint_test\nBug fixes and missing methods\nAdd length for iterators\nFix bug with duplicate terms\nFix order of LinearOfConstraintIndices","category":"page"},{"location":"release_notes/#[v0.9.14](https://github.com/jump-dev/MathOptInterface.jl/releases/tag/v0.9.14)-(May-30,-2020)","page":"Release notes","title":"v0.9.14 (May 30, 2020)","text":"","category":"section"},{"location":"release_notes/","page":"Release notes","title":"Release notes","text":"Add a solver-independent interface for accessing the set of conflicting constraints an Irreducible Inconsistent Subsystem (#1056).\nBump JSONSchema dependency from v0.2 to v0.3 (#1090).\nDocumentation improvements:\nFix typos (#1054, #1060, #1061, #1064, #1069, #1070).\nRemove the outdated recommendation for a package implementing MOI for a solver XXX to be called MathOptInterfaceXXX (#1087).\nUtilities improvements:\nFix is_canonical for quadratic functions (#1081, #1089).\nImplement add_constrained_variable[s] for CachingOptimizer so that it is added as constrained variables to the underlying optimizer (#1084).\nAdd support for custom objective functions for UniversalFallback (#1086).\nDeterministic ordering of constraints in UniversalFallback (#1088).\nTesting improvements:\nAdd NormOneCone/NormInfinityCone tests (#1045).\nBridges improvements:\nAdd bridges from Semiinteger and Semicontinuous (#1059).\nImplement getting ConstraintSet for Variable.FlipSignBridge (#1066).\nFix setting ConstraintFunction for Constraint.ScalarizeBridge (#1093).\nFix NormOne/NormInf bridges with nonzero constants (#1045).\nFix StackOverflow in debug (#1063).\nFileFormats improvements:\n[SDPA] Implement the extension for integer variables (#1079).\n[SDPA] Ignore comments after m and nblocks and detect dat-s extension (#1077).\n[SDPA] No scaling of off-diagonal coefficient (#1076).\n[SDPA] Add missing negation of constant (#1075).","category":"page"},{"location":"release_notes/#[v0.9.13](https://github.com/jump-dev/MathOptInterface.jl/releases/tag/v0.9.13)-(March-24,-2020)","page":"Release notes","title":"v0.9.13 (March 24, 2020)","text":"","category":"section"},{"location":"release_notes/","page":"Release notes","title":"Release notes","text":"Added tests for Semicontinuous and Semiinteger variables (#1033).\nAdded tests for using ExprGraphs from NLP evaluators (#1043).\nUpdate version compatibilities of dependencies (#1034, #1051, #1052).\nFixed typos in documentation (#1044).","category":"page"},{"location":"release_notes/#[v0.9.12](https://github.com/jump-dev/MathOptInterface.jl/releases/tag/v0.9.12)-(February-28,-2020)","page":"Release notes","title":"v0.9.12 (February 28, 2020)","text":"","category":"section"},{"location":"release_notes/","page":"Release notes","title":"Release notes","text":"Fixed writing NLPBlock in MathOptFormat (#1037).\nFixed MockOptimizer for result attributes with non-one result index (#1039).\nUpdated test template with instantiate (#1032).","category":"page"},{"location":"release_notes/#[v0.9.11](https://github.com/jump-dev/MathOptInterface.jl/releases/tag/v0.9.11)-(February-21,-2020)","page":"Release notes","title":"v0.9.11 (February 21, 2020)","text":"","category":"section"},{"location":"release_notes/","page":"Release notes","title":"Release notes","text":"Add an option for the model created by Utilities.@model to be a subtype of AbstractOptimizer (#1031).\nDescribed dual cone in docstrings of GeoMeanCone and RelativeEntropyCone (#1018, #1028).\nFixed typos in documentation (#1022, #1024).\nFixed warning of unsupported attribute (#1027).\nAdded more rootdet/logdet conic tests (#1026).\nImplemented ConstraintDual for Constraint.GeoMeanBridge, Constraint.RootDetBridge and Constraint.LogDetBridge and test duals in tests with GeoMeanCone and RootDetConeTriangle and LogDetConeTriangle cones (#1025, #1026).","category":"page"},{"location":"release_notes/#[v0.9.10](https://github.com/jump-dev/MathOptInterface.jl/releases/tag/v0.9.10)-(January-31,-2020)","page":"Release notes","title":"v0.9.10 (January 31, 2020)","text":"","category":"section"},{"location":"release_notes/","page":"Release notes","title":"Release notes","text":"Added OptimizerWithAttributes grouping an optimizer constructor and a list of optimizer attributes (#1008).\nAdded RelativeEntropyCone with corresponding bridge into exponential cone constraints (#993).\nAdded NormSpectralCone and NormNuclearCone with corresponding bridges into positive semidefinite constraints (#976).\nAdded supports_constrained_variable(s) (#1004).\nAdded dual_set_type (#1002).\nAdded tests for vector specialized version of delete (#989, #1011).\nAdded PSD3 test (#1007).\nClarified dual solution of Tests.pow1v and Tests.pow1f (#1013).\nAdded support for EqualTo and Zero in Bridges.Constraint.SplitIntervalBridge (#1005).\nFixed Utilities.vectorize for empty vector (#1003).\nFixed free variables in LP writer (#1006).","category":"page"},{"location":"release_notes/#[v0.9.9](https://github.com/jump-dev/MathOptInterface.jl/releases/tag/v0.9.9)-(December-29,-2019)","page":"Release notes","title":"v0.9.9 (December 29, 2019)","text":"","category":"section"},{"location":"release_notes/","page":"Release notes","title":"Release notes","text":"Incorporated MathOptFormat.jl as the FileFormats submodule. FileFormats provides readers and writers for a number of standard file formats and MOF, a file format specialized for MOI (#969).\nImproved performance of deletion of vector of variables in MOI.Utilities.Model (#983).\nUpdated to MutableArithmetics v0.2 (#981).\nAdded MutableArithmetics.promote_operation allocation tests (#975).\nFixed inference issue on Julia v1.1 (#982).","category":"page"},{"location":"release_notes/#[v0.9.8](https://github.com/jump-dev/MathOptInterface.jl/releases/tag/v0.9.8)-(December-19,-2019)","page":"Release notes","title":"v0.9.8 (December 19, 2019)","text":"","category":"section"},{"location":"release_notes/","page":"Release notes","title":"Release notes","text":"Implemented MutableArithmetics API (#924).\nFixed callbacks with CachingOptimizer (#959).\nFixed MOI.dimension for MOI.Complements (#948).\nAdded fallback for add_variables (#972).\nAdded is_diagonal_vectorized_index utility (#965).\nImproved linear constraints display in manual (#963, #964).\nBridges improvements:\nAdded IndicatorSet to SOS1 bridge (#877).\nAdded support for starting values for Variable.VectorizeBridge (#944).\nFixed MOI.add_constraints with non-bridged variable constraint on bridged variable (#951).\nFixed corner cases and docstring of GeoMeanBridge (#961, #962, #966).\nFixed choice between variable or constraint bridges for constrained variables (#973).\nImprove performance of bridge shortest path (#945, #946, #956).\nAdded docstring for test_delete_bridge (#954).\nAdded Variable bridge tests (#952).","category":"page"},{"location":"release_notes/#[v0.9.7](https://github.com/jump-dev/MathOptInterface.jl/releases/tag/v0.9.7)-(October-30,-2019)","page":"Release notes","title":"v0.9.7 (October 30, 2019)","text":"","category":"section"},{"location":"release_notes/","page":"Release notes","title":"Release notes","text":"Implemented _result_index_field for NLPBlockDual (#934).\nFixed copy of model with starting values for vector constraints (#941).\nBridges improvements:\nImproved performance of add_bridge and added has_bridge (#935).\nAdded AbstractSetMapBridge for bridges between sets S1, S2 such that there is a linear map A such that A*S1 = S2 (#933).\nAdded support for starting values for FlipSignBridge, VectorizeBridge, ScalarizeBridge, SlackBridge, SplitIntervalBridge, RSOCBridge, SOCRBridge NormInfinityBridge, SOCtoPSDBridge and RSOCtoPSDBridge (#933, #936, #937, #938, #939).","category":"page"},{"location":"release_notes/#[v0.9.6](https://github.com/jump-dev/MathOptInterface.jl/releases/tag/v0.9.6)-(October-25,-2019)","page":"Release notes","title":"v0.9.6 (October 25, 2019)","text":"","category":"section"},{"location":"release_notes/","page":"Release notes","title":"Release notes","text":"Added complementarity constraints (#913).\nAllowed ModelLike objects as value of attributes (#928).\nTesting improvements:\nAdded dual_objective_value option to MOI.Test.TestConfig (#922).\nAdded InvalidIndex tests in basic_constraint_tests (#921).\nAdded tests for the constant term in indicator constraint (#929).\nBridges improvements:\nAdded support for starting values for Functionize bridges (#923).\nAdded variable indices context to variable bridges (#920).\nFixed a typo in printing o debug_supports (#927).","category":"page"},{"location":"release_notes/#[v0.9.5](https://github.com/jump-dev/MathOptInterface.jl/releases/tag/v0.9.5)-(October-9,-2019)","page":"Release notes","title":"v0.9.5 (October 9, 2019)","text":"","category":"section"},{"location":"release_notes/","page":"Release notes","title":"Release notes","text":"Clarified PrimalStatus/DualStatus to be NO_SOLUTION if result_index is out of bounds (#912).\nAdded tolerance for checks and use ResultCount + 1 for the result_index in MOI.Test.solve_result_status (#910, #917).\nUse 0.5 instead of 2.0 for power in PowerCone in basic_constraint_test (#916).\nBridges improvements:\nAdded debug utilities for unsupported variable/constraint/objective (#861).\nFixed deletion of variables in bridged VectorOfVariables constraints (#909).\nFixed result_index with objective bridges (#911).","category":"page"},{"location":"release_notes/#[v0.9.4](https://github.com/jump-dev/MathOptInterface.jl/releases/tag/v0.9.4)-(October-2,-2019)","page":"Release notes","title":"v0.9.4 (October 2, 2019)","text":"","category":"section"},{"location":"release_notes/","page":"Release notes","title":"Release notes","text":"Added solver-independent MIP callbacks (#782).\nImplements submit for Utilities.CachingOptimizer and Bridges.AbstractBridgeOptimizer (#906).\nAdded tests for result count of solution attributes (#901, #904).\nAdded NumberOfThreads attribute (#892).\nAdded Utilities.get_bounds to get the bounds on a variable (#890).\nAdded a note on duplicate coefficients in documentation (#581).\nAdded result index in ConstraintBasisStatus (#898).\nAdded extension dictionary to Utilities.Model (#884, #895).\nFixed deletion of constrained variables for CachingOptimizer (#905).\nImplemented Utilities.shift_constraint for Test.UnknownScalarSet (#896).\nBridges improvements:\nAdded Variable.RSOCtoSOCBridge (#907).\nImplemented MOI.get for ConstraintFunction/ConstraintSet for Bridges.Constraint.SquareBridge (#899).","category":"page"},{"location":"release_notes/#[v0.9.3](https://github.com/jump-dev/MathOptInterface.jl/releases/tag/v0.9.3)-(September-20,-2019)","page":"Release notes","title":"v0.9.3 (September 20, 2019)","text":"","category":"section"},{"location":"release_notes/","page":"Release notes","title":"Release notes","text":"Fixed ambiguity detected in Julia v1.3 (#891, #893).\nFixed missing sets from ListOfSupportedConstraints (#880).\nFixed copy of VectorOfVariables constraints with duplicate indices (#886).\nAdded extension dictionary to MOIU.Model (#884).\nImplemented MOI.get for function and set for GeoMeanBridge (#888).\nUpdated documentation for SingleVariable indices and bridges (#885).\nTesting improvements:\nAdded more comprehensive tests for names (#882).\nAdded tests for SingleVariable duals (#883).\nAdded tests for DualExponentialCone and DualPowerCone (#873).\nImprovements for arbitrary coefficient type:\nFixed == for sets with mutable fields (#887).\nRemoved some Float64 assumptions in bridges (#878).\nAutomatic selection of Constraint.[Scalar|Vector]FunctionizeBridge (#889).","category":"page"},{"location":"release_notes/#[v0.9.2](https://github.com/jump-dev/MathOptInterface.jl/releases/tag/v0.9.2)-(September-5,-2019)","page":"Release notes","title":"v0.9.2 (September 5, 2019)","text":"","category":"section"},{"location":"release_notes/","page":"Release notes","title":"Release notes","text":"Implemented model printing for MOI.ModelLike and specialized it for models defined in MOI (864).\nGeneralized contlinear tests for arbitrary coefficient type (#855).\nFixed supports_constraint for Semiinteger and Semicontinuous and supports for ObjectiveFunction (#859).\nFixed Allocate-Load copy for single variable constraints (#856).\nBridges improvements:\nAdd objective bridges (#789).\nFixed Variable.RSOCtoPSDBridge for dimension 2 (#869).\nAdded Variable.SOCtoRSOCBridge (#865).\nAdded Constraint.SOCRBridge and disable MOI.Bridges.Constraint.SOCtoPSDBridge (#751).\nFixed added_constraint_types for Contraint.LogDetBridge and Constraint.RootDetBridge (#870).","category":"page"},{"location":"release_notes/#[v0.9.1](https://github.com/jump-dev/MathOptInterface.jl/releases/tag/v0.9.1)-(August-22,-2019)","page":"Release notes","title":"v0.9.1 (August 22, 2019)","text":"","category":"section"},{"location":"release_notes/","page":"Release notes","title":"Release notes","text":"Fix support for Julia v1.2 (#834).\nL1 and L∞ norm epigraph cones and corresponding bridges to LP were added (#818).\nAdded tests to MOI.Test.nametest (#833).\nFix MOI.Test.soc3test for solvers not supporting infeasibility certificates (#839).\nImplements operate for operators * and / between vector function and constant (#837).\nImplements show for MOI.Utilities.IndexMap (#847).\nFix corner cases for mapping of variables in MOI.Utilities.CachingOptimizer and substitution of variables in MOI.Bridges.AbstractBridgeOptimizer (#848).\nFix transformation of constant terms for MOI.Bridges.Constraint.SOCtoPSDBridge and MOI.Bridges.Constraint.RSOCtoPSDBridge (#840).","category":"page"},{"location":"release_notes/#[v0.9.0](https://github.com/jump-dev/MathOptInterface.jl/releases/tag/v0.9.0)-(August-13,-2019)","page":"Release notes","title":"v0.9.0 (August 13, 2019)","text":"","category":"section"},{"location":"release_notes/","page":"Release notes","title":"Release notes","text":"Support for Julia v0.6 and v0.7 was dropped (#714, #717).\nA MOI.Utilities.Model implementation of ModelLike, this should replace most use cases of MOI.Utilities.@model (#781).\nadd_constrained_variable and add_constrained_variables were added (#759).\nSupport for indicator constraints was added (#709, #712).\nDualObjectiveValue attribute was added (#473).\nRawParameter attribute was added (#733).\nA dual_set function was added (#804).\nA Benchmarks submodule was added to facilitate solver benchmarking (#769).\nA submit function was added, this may for instance allow the user to submit solutions or cuts to the solver from a callback (#775).\nThe field of ObjectiveValue was renamed to result_index (#729).\nThe _constant and Utilities.getconstant function were renamed to constant\nREDUCTION_CERTIFICATE result status was added (#734).\nAbstract matrix sets were added (#731).\nTesting improvements:\nThe testing guideline was updated (#728).\nQuadratic tests were added (#697).\nUnit tests for RawStatusString, SolveTime, Silent and SolverName were added (#726, #741).\nA rotated second-order cone test was added (#759).\nA power cone test was added (#768).\nTests for ZeroOne variables with variable bounds were added (#772).\nAn unbounded test was added (#773).\nExisting tests had a few updates (#702, #703, #763).\nDocumentation improvements:\nAdded a section on CachingOptimizer (#777).\nAdded a section on UniversalFallback, Model and @model (#762).\nTransition the knapsack example to a doctest with MockOptimizer (#786).\nUtilities improvements:\nA CleverDict utility was added for a vector that automatically transform into a dictionary once a first index is removed (#767).\nThe Utilities.constant function was renamed to Utilities.constant_vector (#740).\nImplement optimizer attributes for CachingOptimizer (#745).\nRename Utilities.add_scalar_constraint to Utilities.normalize_and_add_constraint (#801).\noperate with vcat, SingleVariable and VectorOfVariables now returns a VectorOfVariables (#616).\nFix a type piracy of operate (#784).\nThe load_constraint fallback signature was fixed (#760).\nThe set_dot function was extended to work with sparse arrays (#805).\nBridges improvements:\nThe bridges no longer store the constraint function and set before it is bridged, the bridges now have to implement ConstraintFunction and ConstraintSet if the user wants to recover them. As a consequence, the @bridge macro was removed (#722).\nBridge are now instantiated with a bridge_constraint function instead of using a constructor (#730).\nFix constraint attributes for bridges (#699).\nConstraint bridges were moved to the Bridges/Constraint submodule so they should now inherit from MOI.Bridges.Constraint.Abstract and should implement MOI.Bridges.Constraint.concrete_bridge_type instead of MOI.Bridges.concrete_bridge_type (#756).\nVariable bridges were added in (#759).\nVarious improvements (#746, #747).","category":"page"},{"location":"release_notes/#[v0.8.4](https://github.com/jump-dev/MathOptInterface.jl/releases/tag/v0.8.4)-(March-13,-2019)","page":"Release notes","title":"v0.8.4 (March 13, 2019)","text":"","category":"section"},{"location":"release_notes/","page":"Release notes","title":"Release notes","text":"Performance improvement in default_copy_to and bridge optimizer (#696).\nAdd Silent and implement setting optimizer attributes in caching and mock optimizers (#695).\nAdd Functionize bridges (SingleVariable and VectorOfVariables) (#659).\nMinor typo fixes (#694).","category":"page"},{"location":"release_notes/#[v0.8.3](https://github.com/jump-dev/MathOptInterface.jl/releases/tag/v0.8.3)-(March-6,-2019)","page":"Release notes","title":"v0.8.3 (March 6, 2019)","text":"","category":"section"},{"location":"release_notes/","page":"Release notes","title":"Release notes","text":"Use zero constant in scalar constraint function of MOI.Test.copytest (#691).\nFix variable deletion with SingleVariable objective function (#690).\nFix LazyBridgeOptimizer with bridges that add no constraints (#689).\nError message improvements (#673, #685, #686, #688).\nDocumentation improvements (#682, #683, #687).\nBasis status:\nRemove VariableBasisStatus (#679).\nTest ConstraintBasisStatus and implement it in bridges (#678).\nFix inference of NumberOfVariables and NumberOfConstraints (#677).\nImplement division between a quadratic function and a number (#675).","category":"page"},{"location":"release_notes/#[v0.8.2](https://github.com/jump-dev/MathOptInterface.jl/releases/tag/v0.8.2)-(February-7,-2019)","page":"Release notes","title":"v0.8.2 (February 7, 2019)","text":"","category":"section"},{"location":"release_notes/","page":"Release notes","title":"Release notes","text":"Add RawStatusString attribute (#629).\nDo not set names to the optimizer but only to the cache in CachingOptimizer (#638).\nMake scalar MOI functions act as scalars in broadcast (#646).\nAdd function utilities:\nImplement Base.zero (#634), Base.iszero (#643), add missing arithmetic operations (#644, #645) and fix division (#648).\nAdd a vectorize function that turns a vector of ScalarAffineFunction into a VectorAffineFunction (#642).\nImprove support for starting values:\nShow a warning in copy when starting values are not supported instead of throwing an error (#630).\nFix UniversalFallback for getting an variable or constraint attribute set to no indices (#623).\nAdd a test in contlineartest with partially set VariablePrimalStart.\nBridges improvements:\nFix StackOverFlow in LazyBridgeOptimizer when there is a cycle in the graph of bridges.\nAdd Slack bridges (#610, #650).\nAdd FlipSign bridges (#658).\nAdd tests with duplicate coefficients in ScalarAffineFunction and VectorAffineFunction (#639).\nUse tolerance to compare VariablePrimal in rotatedsoc1 test (#632).\nUse a zero constant in ScalarAffineFunction of constraints in psdt2 (#622).","category":"page"},{"location":"release_notes/#[v0.8.1](https://github.com/jump-dev/MathOptInterface.jl/releases/tag/v0.8.1)-(January-7,-2019)","page":"Release notes","title":"v0.8.1 (January 7, 2019)","text":"","category":"section"},{"location":"release_notes/","page":"Release notes","title":"Release notes","text":"Adding an NLP objective now overrides any objective set using the ObjectiveFunction attribute (#619).\nRename fullbridgeoptimizer into full_bridge_optimizer (#621).\nAllow custom constraint types with full_bridge_optimizer (#617).\nAdd Vectorize bridge which transforms scalar linear constraints into vector linear constraints (#615).","category":"page"},{"location":"release_notes/#[v0.8.0](https://github.com/jump-dev/MathOptInterface.jl/releases/tag/v0.8.0)-(December-18,-2018)","page":"Release notes","title":"v0.8.0 (December 18, 2018)","text":"","category":"section"},{"location":"release_notes/","page":"Release notes","title":"Release notes","text":"Rename all enum values to follow the JuMP naming guidelines for constants, for example, Optimal becomes OPTIMAL, and DualInfeasible becomes DUAL_INFEASIBLE.\nRename CachingOptimizer methods for style compliance.\nAdd an MOI.TerminationStatusCode called ALMOST_DUAL_INFEASIBLE.","category":"page"},{"location":"release_notes/#[v0.7.0](https://github.com/jump-dev/MathOptInterface.jl/releases/tag/v0.7.0)-(December-13,-2018)","page":"Release notes","title":"v0.7.0 (December 13, 2018)","text":"","category":"section"},{"location":"release_notes/","page":"Release notes","title":"Release notes","text":"Test that MOI.TerminationStatus is MOI.OptimizeNotCalled before MOI.optimize! is called.\nCheck supports_default_copy_to in tests (#594).\nKey pieces of information like optimality, infeasibility, etc., are now reported through TerminationStatusCode. It is typically no longer necessary to check the result statuses in addition to the termination status.\nAdd perspective dimension to log-det cone (#593).","category":"page"},{"location":"release_notes/#[v0.6.4](https://github.com/jump-dev/MathOptInterface.jl/releases/tag/v0.6.4)-(November-27,-2018)","page":"Release notes","title":"v0.6.4 (November 27, 2018)","text":"","category":"section"},{"location":"release_notes/","page":"Release notes","title":"Release notes","text":"Add OptimizeNotCalled termination status (#577) and improve documentation of other statuses (#575).\nAdd a solver naming guideline (#578).\nMake FeasibilitySense the default ObjectiveSense (#579).\nFix Utilities.@model and Bridges.@bridge macros for functions and sets defined outside MOI (#582).\nDocument solver-specific attributes (#580) and implement them in Utilities.CachingOptimizer (#565).","category":"page"},{"location":"release_notes/#[v0.6.3](https://github.com/jump-dev/MathOptInterface.jl/releases/tag/v0.6.3)-(November-16,-2018)","page":"Release notes","title":"v0.6.3 (November 16, 2018)","text":"","category":"section"},{"location":"release_notes/","page":"Release notes","title":"Release notes","text":"Variables and constraints are now allowed to have duplicate names. An error is thrown only on lookup. This change breaks some existing tests. (#549)\nAttributes may now be partially set (some values could be nothing). (#563)\nPerformance improvements in Utilities.Model (#549, #567, #568)\nFix bug in QuadtoSOC (#558).\nNew supports_default_copy_to method that optimizers should implement to control caching behavior.\nDocumentation improvements.","category":"page"},{"location":"release_notes/#[v0.6.2](https://github.com/jump-dev/MathOptInterface.jl/releases/tag/v0.6.2)-(October-26,-2018)","page":"Release notes","title":"v0.6.2 (October 26, 2018)","text":"","category":"section"},{"location":"release_notes/","page":"Release notes","title":"Release notes","text":"Improve hygiene of @model macro (#544).\nFix bug in copy tests (#543).\nFix bug in UniversalFallback attribute getter (#540).\nAllow all correct solutions for solve_blank_obj unit test (#537).\nAdd errors for Allocate-Load and bad constraints (#534).\n[performance] Add specialized implementation of hash for VariableIndex (#533).\n[performance] Construct the name to object dictionaries lazily in model (#535).\nAdd the QuadtoSOC bridge which transforms ScalarQuadraticFunction constraints into RotatedSecondOrderCone (#483).","category":"page"},{"location":"release_notes/#[v0.6.1](https://github.com/jump-dev/MathOptInterface.jl/releases/tag/v0.6.1)-(September-22,-2018)","page":"Release notes","title":"v0.6.1 (September 22, 2018)","text":"","category":"section"},{"location":"release_notes/","page":"Release notes","title":"Release notes","text":"Enable PositiveSemidefiniteConeSquare set and quadratic functions in MOIB.fullbridgeoptimizer (#524).\nAdd warning in the bridge between PositiveSemidefiniteConeSquare and PositiveSemidefiniteConeTriangle when the matrix is almost symmetric (#522).\nModify MOIT.copytest to not add multiples constraints on the same variable (#521).\nAdd missing keyword argument in one of MOIU.add_scalar_constraint methods (#520).","category":"page"},{"location":"release_notes/#[v0.6.0](https://github.com/jump-dev/MathOptInterface.jl/releases/tag/v0.6.0)-(August-30,-2018)","page":"Release notes","title":"v0.6.0 (August 30, 2018)","text":"","category":"section"},{"location":"release_notes/","page":"Release notes","title":"Release notes","text":"The MOIU.@model and MOIB.@bridge macros now support functions and sets defined in external modules. As a consequence, function and set names in the macro arguments need to be prefixed by module name.\nRename functions according to the JuMP style guide:\ncopy! with keyword arguments copynames and warnattributes -> copy_to with keyword arguments copy_names and warn_attributes;\nset! -> set;\naddvariable[s]! -> add_variable[s];\nsupportsconstraint -> supports_constraint;\naddconstraint[s]! -> add_constraint[s];\nisvalid -> is_valid;\nisempty -> is_empty;\nBase.delete! -> delete;\nmodify! -> modify;\ntransform! -> transform;\ninitialize! -> initialize;\nwrite -> write_to_file; and\nread! -> read_from_file.\nRemove free! (use Base.finalize instead).\nAdd the SquarePSD bridge which transforms PositiveSemidefiniteConeTriangle constraints into PositiveSemidefiniteConeTriangle.\nAdd result fallback for ConstraintDual of variable-wise constraint, ConstraintPrimal and ObjectiveValue.\nAdd tests for ObjectiveBound.\nAdd test for empty rows in vector linear constraint.\nRework errors: CannotError has been renamed NotAllowedError and the distinction between UnsupportedError and NotAllowedError is now about whether the element is not supported (for example, it cannot be copied a model containing this element) or the operation is not allowed (either because it is not implemented, because it cannot be performed in the current state of the model, or because it cannot be performed for a specific index)\ncanget is removed. NoSolution is added as a result status to indicate that the solver does not have either a primal or dual solution available (See #479).","category":"page"},{"location":"release_notes/#[v0.5.0](https://github.com/jump-dev/MathOptInterface.jl/releases/tag/v0.5.0)-(August-5,-2018)","page":"Release notes","title":"v0.5.0 (August 5, 2018)","text":"","category":"section"},{"location":"release_notes/","page":"Release notes","title":"Release notes","text":"Fix names with CachingOptimizer.\nCleanup thanks to @mohamed82008.\nAdded a universal fallback for constraints.\nFast utilities for function canonicalization thanks to @rdeits.\nRenamed dimension field to side_dimension in the context of matrix-like sets.\nNew and improved tests for cases like duplicate terms and ObjectiveBound.\nRemoved cantransform, canaddconstraint, canaddvariable, canset, canmodify, and candelete functions from the API. They are replaced by a new set of errors that are thrown: Subtypes of UnsupportedError indicate unsupported operations, while subtypes of CannotError indicate operations that cannot be performed in the current state.\nThe API for copy! is updated to remove the CopyResult type.\nUpdates for the new JuMP style guide.","category":"page"},{"location":"release_notes/#[v0.4.1](https://github.com/jump-dev/MathOptInterface.jl/releases/tag/v0.4.1)-(June-28,-2018)","page":"Release notes","title":"v0.4.1 (June 28, 2018)","text":"","category":"section"},{"location":"release_notes/","page":"Release notes","title":"Release notes","text":"Fixes vector function modification on 32 bits.\nFixes Bellman-Ford algorithm for bridges.\nAdded an NLP test with FeasibilitySense.\nUpdate modification documentation.","category":"page"},{"location":"release_notes/#[v0.4.0](https://github.com/jump-dev/MathOptInterface.jl/releases/tag/v0.4.0)-(June-23,-2018)","page":"Release notes","title":"v0.4.0 (June 23, 2018)","text":"","category":"section"},{"location":"release_notes/","page":"Release notes","title":"Release notes","text":"Helper constructors for VectorAffineTerm and VectorQuadraticTerm.\nAdded modify_lhs to TestConfig.\nAdditional unit tests for optimizers.\nAdded a type parameter to CachingOptimizer for the optimizer field.\nNew API for problem modification (#388)\nTests pass without deprecation warnings on Julia 0.7.\nSmall fixes and documentation updates.","category":"page"},{"location":"release_notes/#[v0.3.0](https://github.com/jump-dev/MathOptInterface.jl/releases/tag/v0.3.0)-(May-25,-2018)","page":"Release notes","title":"v0.3.0 (May 25, 2018)","text":"","category":"section"},{"location":"release_notes/","page":"Release notes","title":"Release notes","text":"Functions have been redefined to use arrays-of-structs instead of structs-of-arrays.\nImprovements to MockOptimizer.\nSignificant changes to Bridges.\nNew and improved unit tests.\nFixes for Julia 0.7.","category":"page"},{"location":"release_notes/#[v0.2.0](https://github.com/jump-dev/MathOptInterface.jl/releases/tag/v0.2.0)-(April-24,-2018)","page":"Release notes","title":"v0.2.0 (April 24, 2018)","text":"","category":"section"},{"location":"release_notes/","page":"Release notes","title":"Release notes","text":"Improvements to and better coverage of Tests.\nDocumentation fixes.\nSolverName attribute.\nChanges to the NLP interface (new definition of variable order and arrays of structs for bound pairs and sparsity patterns).\nAddition of NLP tests.\nIntroduction of UniversalFallback.\ncopynames keyword argument to MOI.copy!.\nAdd Bridges submodule.","category":"page"},{"location":"release_notes/#[v0.1.0](https://github.com/jump-dev/MathOptInterface.jl/releases/tag/v0.1.0)-(February-28,-2018)","page":"Release notes","title":"v0.1.0 (February 28, 2018)","text":"","category":"section"},{"location":"release_notes/","page":"Release notes","title":"Release notes","text":"Initial public release.\nThe framework for MOI was developed at the JuMP-dev workshop at MIT in June 2017 as a sorely needed replacement for MathProgBase.","category":"page"},{"location":"manual/constraints/","page":"Constraints","title":"Constraints","text":"CurrentModule = MathOptInterface\nDocTestSetup = quote\n import MathOptInterface as MOI\nend\nDocTestFilters = [r\"MathOptInterface|MOI\"]","category":"page"},{"location":"manual/constraints/#Constraints","page":"Constraints","title":"Constraints","text":"","category":"section"},{"location":"manual/constraints/#Add-a-constraint","page":"Constraints","title":"Add a constraint","text":"","category":"section"},{"location":"manual/constraints/","page":"Constraints","title":"Constraints","text":"Use add_constraint to add a single constraint.","category":"page"},{"location":"manual/constraints/","page":"Constraints","title":"Constraints","text":"julia> c = MOI.add_constraint(model, MOI.VectorOfVariables(x), MOI.Nonnegatives(2))\nMathOptInterface.ConstraintIndex{MathOptInterface.VectorOfVariables, MathOptInterface.Nonnegatives}(1)","category":"page"},{"location":"manual/constraints/","page":"Constraints","title":"Constraints","text":"add_constraint returns a ConstraintIndex type, which is used to refer to the added constraint in other calls.","category":"page"},{"location":"manual/constraints/","page":"Constraints","title":"Constraints","text":"Check if a ConstraintIndex is valid using is_valid.","category":"page"},{"location":"manual/constraints/","page":"Constraints","title":"Constraints","text":"julia> MOI.is_valid(model, c)\ntrue","category":"page"},{"location":"manual/constraints/","page":"Constraints","title":"Constraints","text":"Use add_constraints to add a number of constraints of the same type.","category":"page"},{"location":"manual/constraints/","page":"Constraints","title":"Constraints","text":"julia> c = MOI.add_constraints(\n model,\n [x[1], x[2]],\n [MOI.GreaterThan(0.0), MOI.GreaterThan(1.0)]\n )\n2-element Vector{MathOptInterface.ConstraintIndex{MathOptInterface.VariableIndex, MathOptInterface.GreaterThan{Float64}}}:\n MathOptInterface.ConstraintIndex{MathOptInterface.VariableIndex, MathOptInterface.GreaterThan{Float64}}(1)\n MathOptInterface.ConstraintIndex{MathOptInterface.VariableIndex, MathOptInterface.GreaterThan{Float64}}(2)","category":"page"},{"location":"manual/constraints/","page":"Constraints","title":"Constraints","text":"This time, a vector of ConstraintIndex are returned.","category":"page"},{"location":"manual/constraints/","page":"Constraints","title":"Constraints","text":"Use supports_constraint to check if the model supports adding a constraint type.","category":"page"},{"location":"manual/constraints/","page":"Constraints","title":"Constraints","text":"julia> MOI.supports_constraint(\n model,\n MOI.VariableIndex,\n MOI.GreaterThan{Float64},\n )\ntrue","category":"page"},{"location":"manual/constraints/#Delete-a-constraint","page":"Constraints","title":"Delete a constraint","text":"","category":"section"},{"location":"manual/constraints/","page":"Constraints","title":"Constraints","text":"Use delete to delete a constraint.","category":"page"},{"location":"manual/constraints/","page":"Constraints","title":"Constraints","text":"julia> MOI.delete(model, c)\n\njulia> MOI.is_valid(model, c)\nfalse","category":"page"},{"location":"manual/constraints/#Constraint-attributes","page":"Constraints","title":"Constraint attributes","text":"","category":"section"},{"location":"manual/constraints/","page":"Constraints","title":"Constraints","text":"The following attributes are available for constraints:","category":"page"},{"location":"manual/constraints/","page":"Constraints","title":"Constraints","text":"ConstraintName\nConstraintPrimalStart\nConstraintDualStart\nConstraintPrimal\nConstraintDual\nConstraintBasisStatus\nConstraintFunction\nCanonicalConstraintFunction\nConstraintSet","category":"page"},{"location":"manual/constraints/","page":"Constraints","title":"Constraints","text":"Get and set these attributes using get and set.","category":"page"},{"location":"manual/constraints/","page":"Constraints","title":"Constraints","text":"julia> MOI.set(model, MOI.ConstraintName(), c, \"con_c\")\n\njulia> MOI.get(model, MOI.ConstraintName(), c)\n\"con_c\"","category":"page"},{"location":"manual/constraints/#Constraints-by-function-set-pairs","page":"Constraints","title":"Constraints by function-set pairs","text":"","category":"section"},{"location":"manual/constraints/","page":"Constraints","title":"Constraints","text":"Below is a list of common constraint types and how they are represented as function-set pairs in MOI. In the notation below, x is a vector of decision variables, x_i is a scalar decision variable, alpha beta are scalar constants, a b are constant vectors, A is a constant matrix and mathbbR_+ (resp. mathbbR_-) is the set of non-negative (resp. non-positive) real numbers.","category":"page"},{"location":"manual/constraints/#Linear-constraints","page":"Constraints","title":"Linear constraints","text":"","category":"section"},{"location":"manual/constraints/","page":"Constraints","title":"Constraints","text":"Mathematical Constraint MOI Function MOI Set\na^Tx le beta ScalarAffineFunction LessThan\na^Tx ge alpha ScalarAffineFunction GreaterThan\na^Tx = beta ScalarAffineFunction EqualTo\nalpha le a^Tx le beta ScalarAffineFunction Interval\nx_i le beta VariableIndex LessThan\nx_i ge alpha VariableIndex GreaterThan\nx_i = beta VariableIndex EqualTo\nalpha le x_i le beta VariableIndex Interval\nAx + b in mathbbR_+^n VectorAffineFunction Nonnegatives\nAx + b in mathbbR_-^n VectorAffineFunction Nonpositives\nAx + b = 0 VectorAffineFunction Zeros","category":"page"},{"location":"manual/constraints/","page":"Constraints","title":"Constraints","text":"By convention, solvers are not expected to support nonzero constant terms in the ScalarAffineFunctions the first four rows of the preceding table because they are redundant with the parameters of the sets. For example, encode 2x + 1 le 2 as 2x le 1.","category":"page"},{"location":"manual/constraints/","page":"Constraints","title":"Constraints","text":"Constraints with VariableIndex in LessThan, GreaterThan, EqualTo, or Interval sets have a natural interpretation as variable bounds. As such, it is typically not natural to impose multiple lower- or upper-bounds on the same variable, and the solver interfaces will throw respectively LowerBoundAlreadySet or UpperBoundAlreadySet.","category":"page"},{"location":"manual/constraints/","page":"Constraints","title":"Constraints","text":"Moreover, adding two VariableIndex constraints on the same variable with the same set is impossible because they share the same index as it is the index of the variable, see ConstraintIndex.","category":"page"},{"location":"manual/constraints/","page":"Constraints","title":"Constraints","text":"It is natural, however, to impose upper- and lower-bounds separately as two different constraints on a single variable. The difference between imposing bounds by using a single Interval constraint and by using separate LessThan and GreaterThan constraints is that the latter will allow the solver to return separate dual multipliers for the two bounds, while the former will allow the solver to return only a single dual for the interval constraint.","category":"page"},{"location":"manual/constraints/#Conic-constraints","page":"Constraints","title":"Conic constraints","text":"","category":"section"},{"location":"manual/constraints/","page":"Constraints","title":"Constraints","text":"Mathematical Constraint MOI Function MOI Set\nlVert Ax + brVert_2 le c^Tx + d VectorAffineFunction SecondOrderCone\ny ge lVert x rVert_2 VectorOfVariables SecondOrderCone\n2yz ge lVert x rVert_2^2 yz ge 0 VectorOfVariables RotatedSecondOrderCone\n(a_1^Tx + b_1a_2^Tx + b_2a_3^Tx + b_3) in mathcalE VectorAffineFunction ExponentialCone\nA(x) in mathcalS_+ VectorAffineFunction PositiveSemidefiniteConeTriangle\nB(x) in mathcalS_+ VectorAffineFunction PositiveSemidefiniteConeSquare\nx in mathcalS_+ VectorOfVariables PositiveSemidefiniteConeTriangle\nx in mathcalS_+ VectorOfVariables PositiveSemidefiniteConeSquare","category":"page"},{"location":"manual/constraints/","page":"Constraints","title":"Constraints","text":"where mathcalE is the exponential cone (see ExponentialCone), mathcalS_+ is the set of positive semidefinite symmetric matrices, A is an affine map that outputs symmetric matrices and B is an affine map that outputs square matrices.","category":"page"},{"location":"manual/constraints/#Quadratic-constraints","page":"Constraints","title":"Quadratic constraints","text":"","category":"section"},{"location":"manual/constraints/","page":"Constraints","title":"Constraints","text":"Mathematical Constraint MOI Function MOI Set\nfrac12x^TQx + a^Tx + b ge 0 ScalarQuadraticFunction GreaterThan\nfrac12x^TQx + a^Tx + b le 0 ScalarQuadraticFunction LessThan\nfrac12x^TQx + a^Tx + b = 0 ScalarQuadraticFunction EqualTo\nBilinear matrix inequality VectorQuadraticFunction PositiveSemidefiniteCone...","category":"page"},{"location":"manual/constraints/","page":"Constraints","title":"Constraints","text":"note: Note\nFor more details on the internal format of the quadratic functions see ScalarQuadraticFunction or VectorQuadraticFunction.","category":"page"},{"location":"manual/constraints/#Discrete-and-logical-constraints","page":"Constraints","title":"Discrete and logical constraints","text":"","category":"section"},{"location":"manual/constraints/","page":"Constraints","title":"Constraints","text":"Mathematical Constraint MOI Function MOI Set\nx_i in mathbbZ VariableIndex Integer\nx_i in 01 VariableIndex ZeroOne\nx_i in 0 cup lu VariableIndex Semicontinuous\nx_i in 0 cup ll+1ldotsu-1u VariableIndex Semiinteger\nAt most one component of x can be nonzero VectorOfVariables SOS1\nAt most two components of x can be nonzero, and if so they must be adjacent components VectorOfVariables SOS2\ny = 1 implies a^T x in S VectorAffineFunction Indicator","category":"page"},{"location":"manual/constraints/#JuMP-mapping","page":"Constraints","title":"JuMP mapping","text":"","category":"section"},{"location":"manual/constraints/","page":"Constraints","title":"Constraints","text":"The following bullet points show examples of how JuMP constraints are translated into MOI function-set pairs:","category":"page"},{"location":"manual/constraints/","page":"Constraints","title":"Constraints","text":"@constraint(m, 2x + y <= 10) becomes ScalarAffineFunction-in-LessThan\n@constraint(m, 2x + y >= 10) becomes ScalarAffineFunction-in-GreaterThan\n@constraint(m, 2x + y == 10) becomes ScalarAffineFunction-in-EqualTo\n@constraint(m, 0 <= 2x + y <= 10) becomes ScalarAffineFunction-in-Interval\n@constraint(m, 2x + y in ArbitrarySet()) becomes ScalarAffineFunction-in-ArbitrarySet.","category":"page"},{"location":"manual/constraints/","page":"Constraints","title":"Constraints","text":"Variable bounds are handled in a similar fashion:","category":"page"},{"location":"manual/constraints/","page":"Constraints","title":"Constraints","text":"@variable(m, x <= 1) becomes VariableIndex-in-LessThan\n@variable(m, x >= 1) becomes VariableIndex-in-GreaterThan","category":"page"},{"location":"manual/constraints/","page":"Constraints","title":"Constraints","text":"One notable difference is that a variable with an upper and lower bound is translated into two constraints, rather than an interval, that is:","category":"page"},{"location":"manual/constraints/","page":"Constraints","title":"Constraints","text":"@variable(m, 0 <= x <= 1) becomes VariableIndex-in-LessThan and VariableIndex-in-GreaterThan.","category":"page"},{"location":"reference/nonlinear/","page":"Nonlinear programming","title":"Nonlinear programming","text":"CurrentModule = MathOptInterface\nDocTestSetup = quote\n import MathOptInterface as MOI\nend\nDocTestFilters = [r\"MathOptInterface|MOI\"]","category":"page"},{"location":"reference/nonlinear/#Nonlinear-programming","page":"Nonlinear programming","title":"Nonlinear programming","text":"","category":"section"},{"location":"reference/nonlinear/#Types","page":"Nonlinear programming","title":"Types","text":"","category":"section"},{"location":"reference/nonlinear/","page":"Nonlinear programming","title":"Nonlinear programming","text":"AbstractNLPEvaluator\nNLPBoundsPair\nNLPBlockData","category":"page"},{"location":"reference/nonlinear/#MathOptInterface.AbstractNLPEvaluator","page":"Nonlinear programming","title":"MathOptInterface.AbstractNLPEvaluator","text":"AbstractNLPEvaluator\n\nAbstract supertype for the callback object that is used to query function values, derivatives, and expression graphs.\n\nIt is used in NLPBlockData.\n\n\n\n\n\n","category":"type"},{"location":"reference/nonlinear/#MathOptInterface.NLPBoundsPair","page":"Nonlinear programming","title":"MathOptInterface.NLPBoundsPair","text":"NLPBoundsPair(lower::Float64, upper::Float64)\n\nA struct holding a pair of lower and upper bounds.\n\n-Inf and Inf can be used to indicate no lower or upper bound, respectively.\n\n\n\n\n\n","category":"type"},{"location":"reference/nonlinear/#MathOptInterface.NLPBlockData","page":"Nonlinear programming","title":"MathOptInterface.NLPBlockData","text":"struct NLPBlockData\n constraint_bounds::Vector{NLPBoundsPair}\n evaluator::AbstractNLPEvaluator\n has_objective::Bool\nend\n\nA struct encoding a set of nonlinear constraints of the form lb le g(x) le ub and, if has_objective == true, a nonlinear objective function f(x).\n\nNonlinear objectives override any objective set by using the ObjectiveFunction attribute.\n\nThe evaluator is a callback object that is used to query function values, derivatives, and expression graphs. If has_objective == false, then it is an error to query properties of the objective function, and in Hessian-of-the-Lagrangian queries, σ must be set to zero.\n\nnote: Note\nThroughout the evaluator, all variables are ordered according to ListOfVariableIndices. Hence, MOI copies of nonlinear problems must not re-order variables.\n\n\n\n\n\n","category":"type"},{"location":"reference/nonlinear/#Attributes","page":"Nonlinear programming","title":"Attributes","text":"","category":"section"},{"location":"reference/nonlinear/","page":"Nonlinear programming","title":"Nonlinear programming","text":"NLPBlock\nNLPBlockDual\nNLPBlockDualStart","category":"page"},{"location":"reference/nonlinear/#MathOptInterface.NLPBlock","page":"Nonlinear programming","title":"MathOptInterface.NLPBlock","text":"NLPBlock()\n\nAn AbstractModelAttribute that stores an NLPBlockData, representing a set of nonlinear constraints, and optionally a nonlinear objective.\n\n\n\n\n\n","category":"type"},{"location":"reference/nonlinear/#MathOptInterface.NLPBlockDual","page":"Nonlinear programming","title":"MathOptInterface.NLPBlockDual","text":"NLPBlockDual(result_index::Int = 1)\n\nAn AbstractModelAttribute for the Lagrange multipliers on the constraints from the NLPBlock in result result_index.\n\nIf result_index is omitted, it is 1 by default.\n\n\n\n\n\n","category":"type"},{"location":"reference/nonlinear/#MathOptInterface.NLPBlockDualStart","page":"Nonlinear programming","title":"MathOptInterface.NLPBlockDualStart","text":"NLPBlockDualStart()\n\nAn AbstractModelAttribute for the initial assignment of the Lagrange multipliers on the constraints from the NLPBlock that the solver may use to warm-start the solve.\n\n\n\n\n\n","category":"type"},{"location":"reference/nonlinear/#Functions","page":"Nonlinear programming","title":"Functions","text":"","category":"section"},{"location":"reference/nonlinear/","page":"Nonlinear programming","title":"Nonlinear programming","text":"initialize\nfeatures_available\neval_objective\neval_constraint\neval_objective_gradient\njacobian_structure\neval_constraint_gradient\nconstraint_gradient_structure\neval_constraint_jacobian\neval_constraint_jacobian_product\neval_constraint_jacobian_transpose_product\nhessian_lagrangian_structure\nhessian_objective_structure\nhessian_constraint_structure\neval_hessian_objective\neval_hessian_constraint\neval_hessian_lagrangian\neval_hessian_lagrangian_product\nobjective_expr\nconstraint_expr","category":"page"},{"location":"reference/nonlinear/#MathOptInterface.initialize","page":"Nonlinear programming","title":"MathOptInterface.initialize","text":"initialize(\n d::AbstractNLPEvaluator,\n requested_features::Vector{Symbol},\n)::Nothing\n\nInitialize d with the set of features in requested_features. Check features_available before calling initialize to see what features are supported by d.\n\nwarning: Warning\nThis method must be called before any other methods.\n\nFeatures\n\nThe following features are defined:\n\n:Grad: enables eval_objective_gradient\n:Jac: enables eval_constraint_jacobian\n:JacVec: enables eval_constraint_jacobian_product and eval_constraint_jacobian_transpose_product\n:Hess: enables eval_hessian_lagrangian\n:HessVec: enables eval_hessian_lagrangian_product\n:ExprGraph: enables objective_expr and constraint_expr.\n\nIn all cases, including when requested_features is empty, eval_objective and eval_constraint are supported.\n\nExamples\n\nMOI.initialize(d, Symbol[])\nMOI.initialize(d, [:ExprGraph])\nMOI.initialize(d, MOI.features_available(d))\n\n\n\n\n\n","category":"function"},{"location":"reference/nonlinear/#MathOptInterface.features_available","page":"Nonlinear programming","title":"MathOptInterface.features_available","text":"features_available(d::AbstractNLPEvaluator)::Vector{Symbol}\n\nReturns the subset of features available for this problem instance.\n\nSee initialize for the list of defined features.\n\n\n\n\n\n","category":"function"},{"location":"reference/nonlinear/#MathOptInterface.eval_objective","page":"Nonlinear programming","title":"MathOptInterface.eval_objective","text":"eval_objective(d::AbstractNLPEvaluator, x::AbstractVector{T})::T where {T}\n\nEvaluate the objective f(x), returning a scalar value.\n\n\n\n\n\n","category":"function"},{"location":"reference/nonlinear/#MathOptInterface.eval_constraint","page":"Nonlinear programming","title":"MathOptInterface.eval_constraint","text":"eval_constraint(d::AbstractNLPEvaluator,\n g::AbstractVector{T},\n x::AbstractVector{T},\n)::Nothing where {T}\n\nGiven a set of vector-valued constraints l le g(x) le u, evaluate the constraint function g(x), storing the result in the vector g.\n\nImplementation notes\n\nWhen implementing this method, you must not assume that g is Vector{Float64}, but you may assume that it supports setindex! and length. For example, it may be the view of a vector.\n\n\n\n\n\n","category":"function"},{"location":"reference/nonlinear/#MathOptInterface.eval_objective_gradient","page":"Nonlinear programming","title":"MathOptInterface.eval_objective_gradient","text":"eval_objective_gradient(\n d::AbstractNLPEvaluator,\n grad::AbstractVector{T},\n x::AbstractVector{T},\n)::Nothing where {T}\n\nEvaluate the gradient of the objective function grad = nabla f(x) as a dense vector, storing the result in the vector grad.\n\nImplementation notes\n\nWhen implementing this method, you must not assume that grad is Vector{Float64}, but you may assume that it supports setindex! and length. For example, it may be the view of a vector.\n\n\n\n\n\n","category":"function"},{"location":"reference/nonlinear/#MathOptInterface.jacobian_structure","page":"Nonlinear programming","title":"MathOptInterface.jacobian_structure","text":"jacobian_structure(d::AbstractNLPEvaluator)::Vector{Tuple{Int64,Int64}}\n\nReturns a vector of tuples, (row, column), where each indicates the position of a structurally nonzero element in the Jacobian matrix: J_g(x) = left beginarrayc nabla g_1(x) nabla g_2(x) vdots nabla g_m(x) endarrayright where g_i is the itextth component of the nonlinear constraints g(x).\n\nThe indices are not required to be sorted and can contain duplicates, in which case the solver should combine the corresponding elements by adding them together.\n\nThe sparsity structure is assumed to be independent of the point x.\n\n\n\n\n\n","category":"function"},{"location":"reference/nonlinear/#MathOptInterface.eval_constraint_gradient","page":"Nonlinear programming","title":"MathOptInterface.eval_constraint_gradient","text":"eval_constraint_gradient(\n d::AbstractNLPEvaluator,\n ∇g::AbstractVector{T},\n x::AbstractVector{T},\n i::Int,\n)::Nothing where {T}\n\nEvaluate the gradient of constraint i, nabla g_i(x), and store the non-zero values in ∇g, corresponding to the structure returned by constraint_gradient_structure.\n\nImplementation notes\n\nWhen implementing this method, you must not assume that ∇g is Vector{Float64}, but you may assume that it supports setindex! and length. For example, it may be the view of a vector.\n\n\n\n\n\n","category":"function"},{"location":"reference/nonlinear/#MathOptInterface.constraint_gradient_structure","page":"Nonlinear programming","title":"MathOptInterface.constraint_gradient_structure","text":"constraint_gradient_structure(d::AbstractNLPEvaluator, i::Int)::Vector{Int64}\n\nReturns a vector of indices, where each element indicates the position of a structurally nonzero element in the gradient of constraint nabla g_i(x).\n\nThe indices are not required to be sorted and can contain duplicates, in which case the solver should combine the corresponding elements by adding them together.\n\nThe sparsity structure is assumed to be independent of the point x.\n\n\n\n\n\n","category":"function"},{"location":"reference/nonlinear/#MathOptInterface.eval_constraint_jacobian","page":"Nonlinear programming","title":"MathOptInterface.eval_constraint_jacobian","text":"eval_constraint_jacobian(d::AbstractNLPEvaluator,\n J::AbstractVector{T},\n x::AbstractVector{T},\n)::Nothing where {T}\n\nEvaluates the sparse Jacobian matrix J_g(x) = left beginarrayc nabla g_1(x) nabla g_2(x) vdots nabla g_m(x) endarrayright.\n\nThe result is stored in the vector J in the same order as the indices returned by jacobian_structure.\n\nImplementation notes\n\nWhen implementing this method, you must not assume that J is Vector{Float64}, but you may assume that it supports setindex! and length. For example, it may be the view of a vector.\n\n\n\n\n\n","category":"function"},{"location":"reference/nonlinear/#MathOptInterface.eval_constraint_jacobian_product","page":"Nonlinear programming","title":"MathOptInterface.eval_constraint_jacobian_product","text":"eval_constraint_jacobian_product(\n d::AbstractNLPEvaluator,\n y::AbstractVector{T},\n x::AbstractVector{T},\n w::AbstractVector{T},\n)::Nothing where {T}\n\nComputes the Jacobian-vector product y = J_g(x)w, storing the result in the vector y.\n\nThe vectors have dimensions such that length(w) == length(x), and length(y) is the number of nonlinear constraints.\n\nImplementation notes\n\nWhen implementing this method, you must not assume that y is Vector{Float64}, but you may assume that it supports setindex! and length. For example, it may be the view of a vector.\n\n\n\n\n\n","category":"function"},{"location":"reference/nonlinear/#MathOptInterface.eval_constraint_jacobian_transpose_product","page":"Nonlinear programming","title":"MathOptInterface.eval_constraint_jacobian_transpose_product","text":"eval_constraint_jacobian_transpose_product(\n d::AbstractNLPEvaluator,\n y::AbstractVector{T},\n x::AbstractVector{T},\n w::AbstractVector{T},\n)::Nothing where {T}\n\nComputes the Jacobian-transpose-vector product y = J_g(x)^Tw, storing the result in the vector y.\n\nThe vectors have dimensions such that length(y) == length(x), and length(w) is the number of nonlinear constraints.\n\nImplementation notes\n\nWhen implementing this method, you must not assume that y is Vector{Float64}, but you may assume that it supports setindex! and length. For example, it may be the view of a vector.\n\n\n\n\n\n","category":"function"},{"location":"reference/nonlinear/#MathOptInterface.hessian_lagrangian_structure","page":"Nonlinear programming","title":"MathOptInterface.hessian_lagrangian_structure","text":"hessian_lagrangian_structure(\n d::AbstractNLPEvaluator,\n)::Vector{Tuple{Int64,Int64}}\n\nReturns a vector of tuples, (row, column), where each indicates the position of a structurally nonzero element in the Hessian-of-the-Lagrangian matrix: nabla^2 f(x) + sum_i=1^m nabla^2 g_i(x).\n\nThe indices are not required to be sorted and can contain duplicates, in which case the solver should combine the corresponding elements by adding them together.\n\nAny mix of lower and upper-triangular indices is valid. Elements (i,j) and (j,i), if both present, should be treated as duplicates.\n\nThe sparsity structure is assumed to be independent of the point x.\n\n\n\n\n\n","category":"function"},{"location":"reference/nonlinear/#MathOptInterface.hessian_objective_structure","page":"Nonlinear programming","title":"MathOptInterface.hessian_objective_structure","text":"hessian_objective_structure(\n d::AbstractNLPEvaluator,\n)::Vector{Tuple{Int64,Int64}}\n\nReturns a vector of tuples, (row, column), where each indicates the position of a structurally nonzero element in the Hessian matrix: nabla^2 f(x).\n\nThe indices are not required to be sorted and can contain duplicates, in which case the solver should combine the corresponding elements by adding them together.\n\nAny mix of lower and upper-triangular indices is valid. Elements (i,j) and (j,i), if both present, should be treated as duplicates.\n\nThe sparsity structure is assumed to be independent of the point x.\n\n\n\n\n\n","category":"function"},{"location":"reference/nonlinear/#MathOptInterface.hessian_constraint_structure","page":"Nonlinear programming","title":"MathOptInterface.hessian_constraint_structure","text":"hessian_constraint_structure(\n d::AbstractNLPEvaluator,\n i::Int64,\n)::Vector{Tuple{Int64,Int64}}\n\nReturns a vector of tuples, (row, column), where each indicates the position of a structurally nonzero element in the Hessian matrix: nabla^2 g_i(x).\n\nThe indices are not required to be sorted and can contain duplicates, in which case the solver should combine the corresponding elements by adding them together.\n\nAny mix of lower and upper-triangular indices is valid. Elements (i,j) and (j,i), if both present, should be treated as duplicates.\n\nThe sparsity structure is assumed to be independent of the point x.\n\n\n\n\n\n","category":"function"},{"location":"reference/nonlinear/#MathOptInterface.eval_hessian_objective","page":"Nonlinear programming","title":"MathOptInterface.eval_hessian_objective","text":"eval_hessian_objective(\n d::AbstractNLPEvaluator,\n H::AbstractVector{T},\n x::AbstractVector{T},\n)::Nothing where {T}\n\nThis function computes the sparse Hessian matrix: nabla^2 f(x), storing the result in the vector H in the same order as the indices returned by hessian_objective_structure.\n\nImplementation notes\n\nWhen implementing this method, you must not assume that H is Vector{Float64}, but you may assume that it supports setindex! and length. For example, it may be the view of a vector.\n\n\n\n\n\n","category":"function"},{"location":"reference/nonlinear/#MathOptInterface.eval_hessian_constraint","page":"Nonlinear programming","title":"MathOptInterface.eval_hessian_constraint","text":"eval_hessian_constraint(\n d::AbstractNLPEvaluator,\n H::AbstractVector{T},\n x::AbstractVector{T},\n i::Int64,\n)::Nothing where {T}\n\nThis function computes the sparse Hessian matrix: nabla^2 g_i(x), storing the result in the vector H in the same order as the indices returned by hessian_constraint_structure.\n\nImplementation notes\n\nWhen implementing this method, you must not assume that H is Vector{Float64}, but you may assume that it supports setindex! and length. For example, it may be the view of a vector.\n\n\n\n\n\n","category":"function"},{"location":"reference/nonlinear/#MathOptInterface.eval_hessian_lagrangian","page":"Nonlinear programming","title":"MathOptInterface.eval_hessian_lagrangian","text":"eval_hessian_lagrangian(\n d::AbstractNLPEvaluator,\n H::AbstractVector{T},\n x::AbstractVector{T},\n σ::T,\n μ::AbstractVector{T},\n)::Nothing where {T}\n\nGiven scalar weight σ and vector of constraint weights μ, this function computes the sparse Hessian-of-the-Lagrangian matrix: sigmanabla^2 f(x) + sum_i=1^m mu_i nabla^2 g_i(x), storing the result in the vector H in the same order as the indices returned by hessian_lagrangian_structure.\n\nImplementation notes\n\nWhen implementing this method, you must not assume that H is Vector{Float64}, but you may assume that it supports setindex! and length. For example, it may be the view of a vector.\n\n\n\n\n\n","category":"function"},{"location":"reference/nonlinear/#MathOptInterface.eval_hessian_lagrangian_product","page":"Nonlinear programming","title":"MathOptInterface.eval_hessian_lagrangian_product","text":"eval_hessian_lagrangian_product(\n d::AbstractNLPEvaluator,\n h::AbstractVector{T},\n x::AbstractVector{T},\n v::AbstractVector{T},\n σ::T,\n μ::AbstractVector{T},\n)::Nothing where {T}\n\nGiven scalar weight σ and vector of constraint weights μ, computes the Hessian-of-the-Lagrangian-vector product h = left(sigmanabla^2 f(x) + sum_i=1^m mu_i nabla^2 g_i(x)right)v, storing the result in the vector h.\n\nThe vectors have dimensions such that length(h) == length(x) == length(v).\n\nImplementation notes\n\nWhen implementing this method, you must not assume that h is Vector{Float64}, but you may assume that it supports setindex! and length. For example, it may be the view of a vector.\n\n\n\n\n\n","category":"function"},{"location":"reference/nonlinear/#MathOptInterface.objective_expr","page":"Nonlinear programming","title":"MathOptInterface.objective_expr","text":"objective_expr(d::AbstractNLPEvaluator)::Expr\n\nReturns a Julia Expr object representing the expression graph of the objective function.\n\nFormat\n\nThe expression has a number of limitations, compared with arbitrary Julia expressions:\n\nAll sums and products are flattened out as simple Expr(:+, ...) and Expr(:*, ...) objects.\nAll decision variables must be of the form Expr(:ref, :x, MOI.VariableIndex(i)), where i is the ith variable in ListOfVariableIndices.\nThere are currently no restrictions on recognized functions; typically these will be built-in Julia functions like ^, exp, log, cos, tan, sqrt, etc., but modeling interfaces may choose to extend these basic functions, or error if they encounter unsupported functions.\n\nExamples\n\nThe expression x_1+sin(x_2exp(x_3)) is represented as\n\n:(x[MOI.VariableIndex(1)] + sin(x[MOI.VariableIndex(2)] / exp(x[MOI.VariableIndex[3]])))\n\nor equivalently\n\nExpr(\n :call,\n :+,\n Expr(:ref, :x, MOI.VariableIndex(1)),\n Expr(\n :call,\n :/,\n Expr(:call, :sin, Expr(:ref, :x, MOI.VariableIndex(2))),\n Expr(:call, :exp, Expr(:ref, :x, MOI.VariableIndex(3))),\n ),\n)\n\n\n\n\n\n","category":"function"},{"location":"reference/nonlinear/#MathOptInterface.constraint_expr","page":"Nonlinear programming","title":"MathOptInterface.constraint_expr","text":"constraint_expr(d::AbstractNLPEvaluator, i::Integer)::Expr\n\nReturns a Julia Expr object representing the expression graph for the itextth nonlinear constraint.\n\nFormat\n\nThe format is the same as objective_expr, with an additional comparison operator indicating the sense of and bounds on the constraint.\n\nFor single-sided comparisons, the body of the constraint must be on the left-hand side, and the right-hand side must be a constant.\n\nFor double-sided comparisons (that is, l le f(x) le u), the body of the constraint must be in the middle, and the left- and right-hand sides must be constants.\n\nThe bounds on the constraints must match the NLPBoundsPairs passed to NLPBlockData.\n\nExamples\n\n:(x[MOI.VariableIndex(1)]^2 <= 1.0)\n:(x[MOI.VariableIndex(1)]^2 >= 2.0)\n:(x[MOI.VariableIndex(1)]^2 == 3.0)\n:(4.0 <= x[MOI.VariableIndex(1)]^2 <= 5.0)\n\n\n\n\n\n","category":"function"},{"location":"reference/standard_form/","page":"Standard form","title":"Standard form","text":"CurrentModule = MathOptInterface\nDocTestSetup = quote\n import MathOptInterface as MOI\nend\nDocTestFilters = [r\"MathOptInterface|MOI\"]","category":"page"},{"location":"reference/standard_form/#Standard-form","page":"Standard form","title":"Standard form","text":"","category":"section"},{"location":"reference/standard_form/#Functions","page":"Standard form","title":"Functions","text":"","category":"section"},{"location":"reference/standard_form/","page":"Standard form","title":"Standard form","text":"AbstractFunction\noutput_dimension\nconstant","category":"page"},{"location":"reference/standard_form/#MathOptInterface.AbstractFunction","page":"Standard form","title":"MathOptInterface.AbstractFunction","text":"AbstractFunction\n\nAbstract supertype for function objects.\n\nRequired methods\n\nAll functions must implement:\n\nBase.copy\nBase.isapprox\nconstant\n\nAbstract subtypes of AbstractFunction may require additional methods to be implemented.\n\n\n\n\n\n","category":"type"},{"location":"reference/standard_form/#MathOptInterface.output_dimension","page":"Standard form","title":"MathOptInterface.output_dimension","text":"output_dimension(f::AbstractFunction)\n\nReturn 1 if f is an AbstractScalarFunction, or the number of output components if f is an AbstractVectorFunction.\n\n\n\n\n\n","category":"function"},{"location":"reference/standard_form/#MathOptInterface.constant","page":"Standard form","title":"MathOptInterface.constant","text":"constant(f::AbstractFunction[, ::Type{T}]) where {T}\n\nReturns the constant term of a scalar-valued function, or the constant vector of a vector-valued function.\n\nIf f is untyped and T is provided, returns zero(T).\n\n\n\n\n\nconstant(set::Union{EqualTo,GreaterThan,LessThan,Parameter})\n\nReturns the constant term of the set set.\n\nExample\n\njulia> import MathOptInterface as MOI\n\njulia> MOI.constant(MOI.GreaterThan(1.0))\n1.0\n\njulia> MOI.constant(MOI.LessThan(2.5))\n2.5\n\njulia> MOI.constant(MOI.EqualTo(3))\n3\n\njulia> MOI.constant(MOI.Parameter(4.5))\n4.5\n\n\n\n\n\n","category":"function"},{"location":"reference/standard_form/#Scalar-functions","page":"Standard form","title":"Scalar functions","text":"","category":"section"},{"location":"reference/standard_form/","page":"Standard form","title":"Standard form","text":"AbstractScalarFunction\nVariableIndex\nScalarAffineTerm\nScalarAffineFunction\nScalarQuadraticTerm\nScalarQuadraticFunction\nScalarNonlinearFunction","category":"page"},{"location":"reference/standard_form/#MathOptInterface.AbstractScalarFunction","page":"Standard form","title":"MathOptInterface.AbstractScalarFunction","text":"abstract type AbstractScalarFunction <: AbstractFunction\n\nAbstract supertype for scalar-valued AbstractFunctions.\n\n\n\n\n\n","category":"type"},{"location":"reference/standard_form/#MathOptInterface.VariableIndex","page":"Standard form","title":"MathOptInterface.VariableIndex","text":"VariableIndex\n\nA type-safe wrapper for Int64 for use in referencing variables in a model. To allow for deletion, indices need not be consecutive.\n\n\n\n\n\n","category":"type"},{"location":"reference/standard_form/#MathOptInterface.ScalarAffineTerm","page":"Standard form","title":"MathOptInterface.ScalarAffineTerm","text":"ScalarAffineTerm{T}(coefficient::T, variable::VariableIndex) where {T}\n\nRepresents the scalar-valued term coefficient * variable.\n\nExample\n\njulia> import MathOptInterface as MOI\n\njulia> x = MOI.VariableIndex(1)\nMOI.VariableIndex(1)\n\njulia> MOI.ScalarAffineTerm(2.0, x)\nMathOptInterface.ScalarAffineTerm{Float64}(2.0, MOI.VariableIndex(1))\n\n\n\n\n\n","category":"type"},{"location":"reference/standard_form/#MathOptInterface.ScalarAffineFunction","page":"Standard form","title":"MathOptInterface.ScalarAffineFunction","text":"ScalarAffineFunction{T}(terms::ScalarAffineTerm{T}, constant::T) where {T}\n\nRepresents the scalar-valued affine function a^top x + b, where:\n\na^top x is represented by the vector of ScalarAffineTerms\nb is a scalar constant::T\n\nDuplicates\n\nDuplicate variable indices in terms are accepted, and the corresponding coefficients are summed together.\n\nExample\n\njulia> import MathOptInterface as MOI\n\njulia> x = MOI.VariableIndex(1)\nMOI.VariableIndex(1)\n\njulia> terms = [MOI.ScalarAffineTerm(2.0, x), MOI.ScalarAffineTerm(3.0, x)]\n2-element Vector{MathOptInterface.ScalarAffineTerm{Float64}}:\n MathOptInterface.ScalarAffineTerm{Float64}(2.0, MOI.VariableIndex(1))\n MathOptInterface.ScalarAffineTerm{Float64}(3.0, MOI.VariableIndex(1))\n\njulia> f = MOI.ScalarAffineFunction(terms, 4.0)\n4.0 + 2.0 MOI.VariableIndex(1) + 3.0 MOI.VariableIndex(1)\n\n\n\n\n\n","category":"type"},{"location":"reference/standard_form/#MathOptInterface.ScalarQuadraticTerm","page":"Standard form","title":"MathOptInterface.ScalarQuadraticTerm","text":"ScalarQuadraticTerm{T}(\n coefficient::T,\n variable_1::VariableIndex,\n variable_2::VariableIndex,\n) where {T}\n\nRepresents the scalar-valued term c x_i x_j where c is coefficient, x_i is variable_1 and x_j is variable_2.\n\nExample\n\njulia> import MathOptInterface as MOI\n\njulia> x = MOI.VariableIndex(1)\nMOI.VariableIndex(1)\n\njulia> MOI.ScalarQuadraticTerm(2.0, x, x)\nMathOptInterface.ScalarQuadraticTerm{Float64}(2.0, MOI.VariableIndex(1), MOI.VariableIndex(1))\n\n\n\n\n\n","category":"type"},{"location":"reference/standard_form/#MathOptInterface.ScalarQuadraticFunction","page":"Standard form","title":"MathOptInterface.ScalarQuadraticFunction","text":"ScalarQuadraticFunction{T}(\n quadratic_terms::Vector{ScalarQuadraticTerm{T}},\n affine_terms::Vector{ScalarAffineTerm{T}},\n constant::T,\n) wher {T}\n\nThe scalar-valued quadratic function frac12x^top Q x + a^top x + b, where:\n\nQ is the symmetric matrix given by the vector of ScalarQuadraticTerms\na^top x is a sparse vector given by the vector of ScalarAffineTerms\nb is the scalar constant::T.\n\nDuplicates\n\nDuplicate indices in quadratic_terms or affine_terms are accepted, and the corresponding coefficients are summed together.\n\nIn quadratic_terms, \"mirrored\" indices, (q, r) and (r, q) where r and q are VariableIndexes, are considered duplicates; only one needs to be specified.\n\nThe 0.5 factor\n\nCoupled with the interpretation of mirrored indices, the 0.5 factor in front of the Q matrix is a common source of bugs.\n\nAs a rule, to represent a * x^2 + b * x * y:\n\nThe coefficient a in front of squared variables (diagonal elements in Q) must be doubled when creating a ScalarQuadraticTerm\nThe coefficient b in front of off-diagonal elements in Q should be left as b, be cause the mirrored index b * y * x will be implicitly added.\n\nExample\n\nTo represent the function f(x y) = 2 * x^2 + 3 * x * y + 4 * x + 5, do:\n\njulia> import MathOptInterface as MOI\n\njulia> x = MOI.VariableIndex(1);\n\njulia> y = MOI.VariableIndex(2);\n\njulia> constant = 5.0;\n\njulia> affine_terms = [MOI.ScalarAffineTerm(4.0, x)];\n\njulia> quadratic_terms = [\n MOI.ScalarQuadraticTerm(4.0, x, x), # Note the changed coefficient\n MOI.ScalarQuadraticTerm(3.0, x, y),\n ]\n2-element Vector{MathOptInterface.ScalarQuadraticTerm{Float64}}:\n MathOptInterface.ScalarQuadraticTerm{Float64}(4.0, MOI.VariableIndex(1), MOI.VariableIndex(1))\n MathOptInterface.ScalarQuadraticTerm{Float64}(3.0, MOI.VariableIndex(1), MOI.VariableIndex(2))\n\njulia> f = MOI.ScalarQuadraticFunction(quadratic_terms, affine_terms, constant)\n5.0 + 4.0 MOI.VariableIndex(1) + 2.0 MOI.VariableIndex(1)² + 3.0 MOI.VariableIndex(1)*MOI.VariableIndex(2)\n\n\n\n\n\n","category":"type"},{"location":"reference/standard_form/#MathOptInterface.ScalarNonlinearFunction","page":"Standard form","title":"MathOptInterface.ScalarNonlinearFunction","text":"ScalarNonlinearFunction(head::Symbol, args::Vector{Any})\n\nThe scalar-valued nonlinear function head(args...), represented as a symbolic expression tree, with the call operator head and ordered arguments in args.\n\nhead\n\nThe head::Symbol must be an operator supported by the model.\n\nThe default list of supported univariate operators is given by:\n\nNonlinear.DEFAULT_UNIVARIATE_OPERATORS\n\nand the default list of supported multivariate operators is given by:\n\nNonlinear.DEFAULT_MULTIVARIATE_OPERATORS\n\nAdditional operators can be registered by setting a UserDefinedFunction attribute.\n\nSee the full list of operators supported by a ModelLike by querying ListOfSupportedNonlinearOperators.\n\nargs\n\nThe vector args contains the arguments to the nonlinear function. If the operator is univariate, it must contain one element. Otherwise, it may contain multiple elements.\n\nEach element must be one of the following:\n\nA constant value of type T<:Real\nA VariableIndex\nA ScalarAffineFunction\nA ScalarQuadraticFunction\nA ScalarNonlinearFunction\n\nUnsupported operators\n\nIf the optimizer does not support head, an UnsupportedNonlinearOperator error will be thrown.\n\nThere is no guarantee about when this error will be thrown; it may be thrown when the function is first added to the model, or it may be thrown when optimize! is called.\n\nExample\n\nTo represent the function f(x) = sin(x)^2, do:\n\njulia> import MathOptInterface as MOI\n\njulia> x = MOI.VariableIndex(1)\nMOI.VariableIndex(1)\n\njulia> MOI.ScalarNonlinearFunction(\n :^,\n Any[MOI.ScalarNonlinearFunction(:sin, Any[x]), 2],\n )\n^(sin(MOI.VariableIndex(1)), (2))\n\n\n\n\n\n","category":"type"},{"location":"reference/standard_form/#Vector-functions","page":"Standard form","title":"Vector functions","text":"","category":"section"},{"location":"reference/standard_form/","page":"Standard form","title":"Standard form","text":"AbstractVectorFunction\nVectorOfVariables\nVectorAffineTerm\nVectorAffineFunction\nVectorQuadraticTerm\nVectorQuadraticFunction\nVectorNonlinearFunction","category":"page"},{"location":"reference/standard_form/#MathOptInterface.AbstractVectorFunction","page":"Standard form","title":"MathOptInterface.AbstractVectorFunction","text":"abstract type AbstractVectorFunction <: AbstractFunction\n\nAbstract supertype for vector-valued AbstractFunctions.\n\nRequired methods\n\nAll subtypes of AbstractVectorFunction must implement:\n\noutput_dimension\n\n\n\n\n\n","category":"type"},{"location":"reference/standard_form/#MathOptInterface.VectorOfVariables","page":"Standard form","title":"MathOptInterface.VectorOfVariables","text":"VectorOfVariables(variables::Vector{VariableIndex}) <: AbstractVectorFunction\n\nThe vector-valued function f(x) = variables, where variables is a subset of VariableIndexes in the model.\n\nThe list of variables may contain duplicates.\n\nExample\n\njulia> import MathOptInterface as MOI\n\njulia> x = MOI.VariableIndex.(1:2)\n2-element Vector{MathOptInterface.VariableIndex}:\n MOI.VariableIndex(1)\n MOI.VariableIndex(2)\n\njulia> f = MOI.VectorOfVariables([x[1], x[2], x[1]])\n┌ ┐\n│MOI.VariableIndex(1)│\n│MOI.VariableIndex(2)│\n│MOI.VariableIndex(1)│\n└ ┘\n\njulia> MOI.output_dimension(f)\n3\n\n\n\n\n\n","category":"type"},{"location":"reference/standard_form/#MathOptInterface.VectorAffineTerm","page":"Standard form","title":"MathOptInterface.VectorAffineTerm","text":"VectorAffineTerm{T}(\n output_index::Int64,\n scalar_term::ScalarAffineTerm{T},\n) where {T}\n\nA VectorAffineTerm is a scalar_term that appears in the output_index row of the vector-valued VectorAffineFunction or VectorQuadraticFunction.\n\nExample\n\njulia> import MathOptInterface as MOI\n\njulia> x = MOI.VariableIndex(1);\n\njulia> MOI.VectorAffineTerm(Int64(2), MOI.ScalarAffineTerm(3.0, x))\nMathOptInterface.VectorAffineTerm{Float64}(2, MathOptInterface.ScalarAffineTerm{Float64}(3.0, MOI.VariableIndex(1)))\n\n\n\n\n\n","category":"type"},{"location":"reference/standard_form/#MathOptInterface.VectorAffineFunction","page":"Standard form","title":"MathOptInterface.VectorAffineFunction","text":"VectorAffineFunction{T}(\n terms::Vector{VectorAffineTerm{T}},\n constants::Vector{T},\n) where {T}\n\nThe vector-valued affine function A x + b, where:\n\nA x is the sparse matrix given by the vector of VectorAffineTerms\nb is the vector constants\n\nDuplicates\n\nDuplicate indices in the A are accepted, and the corresponding coefficients are summed together.\n\nExample\n\njulia> import MathOptInterface as MOI\n\njulia> x = MOI.VariableIndex(1);\n\njulia> terms = [\n MOI.VectorAffineTerm(Int64(1), MOI.ScalarAffineTerm(2.0, x)),\n MOI.VectorAffineTerm(Int64(2), MOI.ScalarAffineTerm(3.0, x)),\n ];\n\njulia> f = MOI.VectorAffineFunction(terms, [4.0, 5.0])\n┌ ┐\n│4.0 + 2.0 MOI.VariableIndex(1)│\n│5.0 + 3.0 MOI.VariableIndex(1)│\n└ ┘\n\njulia> MOI.output_dimension(f)\n2\n\n\n\n\n\n","category":"type"},{"location":"reference/standard_form/#MathOptInterface.VectorQuadraticTerm","page":"Standard form","title":"MathOptInterface.VectorQuadraticTerm","text":"VectorQuadraticTerm{T}(\n output_index::Int64,\n scalar_term::ScalarQuadraticTerm{T},\n) where {T}\n\nA VectorQuadraticTerm is a ScalarQuadraticTerm scalar_term that appears in the output_index row of the vector-valued VectorQuadraticFunction.\n\nExample\n\njulia> import MathOptInterface as MOI\n\njulia> x = MOI.VariableIndex(1);\n\njulia> MOI.VectorQuadraticTerm(Int64(2), MOI.ScalarQuadraticTerm(3.0, x, x))\nMathOptInterface.VectorQuadraticTerm{Float64}(2, MathOptInterface.ScalarQuadraticTerm{Float64}(3.0, MOI.VariableIndex(1), MOI.VariableIndex(1)))\n\n\n\n\n\n","category":"type"},{"location":"reference/standard_form/#MathOptInterface.VectorQuadraticFunction","page":"Standard form","title":"MathOptInterface.VectorQuadraticFunction","text":"VectorQuadraticFunction{T}(\n quadratic_terms::Vector{VectorQuadraticTerm{T}},\n affine_terms::Vector{VectorAffineTerm{T}},\n constants::Vector{T},\n) where {T}\n\nThe vector-valued quadratic function with ith component (\"output index\") defined as frac12x^top Q_i x + a_i^top x + b_i, where:\n\nfrac12x^top Q_i x is the symmetric matrix given by the VectorQuadraticTerm elements in quadratic_terms with output_index == i\na_i^top x is the sparse vector given by the VectorAffineTerm elements in affine_terms with output_index == i\nb_i is a scalar given by constants[i]\n\nDuplicates\n\nDuplicate indices in quadratic_terms and affine_terms with the same output_index are handled in the same manner as duplicates in ScalarQuadraticFunction.\n\nExample\n\njulia> import MathOptInterface as MOI\n\njulia> x = MOI.VariableIndex(1);\n\njulia> y = MOI.VariableIndex(2);\n\njulia> constants = [4.0, 5.0];\n\njulia> affine_terms = [\n MOI.VectorAffineTerm(Int64(1), MOI.ScalarAffineTerm(2.0, x)),\n MOI.VectorAffineTerm(Int64(2), MOI.ScalarAffineTerm(3.0, x)),\n ];\n\njulia> quad_terms = [\n MOI.VectorQuadraticTerm(Int64(1), MOI.ScalarQuadraticTerm(2.0, x, x)),\n MOI.VectorQuadraticTerm(Int64(2), MOI.ScalarQuadraticTerm(3.0, x, y)),\n ];\n\njulia> f = MOI.VectorQuadraticFunction(quad_terms, affine_terms, constants)\n┌ ┐\n│4.0 + 2.0 MOI.VariableIndex(1) + 1.0 MOI.VariableIndex(1)² │\n│5.0 + 3.0 MOI.VariableIndex(1) + 3.0 MOI.VariableIndex(1)*MOI.VariableIndex(2)│\n└ ┘\n\njulia> MOI.output_dimension(f)\n2\n\n\n\n\n\n","category":"type"},{"location":"reference/standard_form/#MathOptInterface.VectorNonlinearFunction","page":"Standard form","title":"MathOptInterface.VectorNonlinearFunction","text":"VectorNonlinearFunction(args::Vector{ScalarNonlinearFunction})\n\nThe vector-valued nonlinear function composed of a vector of ScalarNonlinearFunction.\n\nargs\n\nThe vector args contains the scalar elements of the nonlinear function. Each element must be a ScalarNonlinearFunction, but if you pass a Vector{Any}, the elements can be automatically converted from one of the following:\n\nA constant value of type T<:Real\nA VariableIndex\nA ScalarAffineFunction\nA ScalarQuadraticFunction\nA ScalarNonlinearFunction\n\nExample\n\nTo represent the function f(x) = sin(x)^2 x, do:\n\njulia> import MathOptInterface as MOI\n\njulia> x = MOI.VariableIndex(1)\nMOI.VariableIndex(1)\n\njulia> g = MOI.ScalarNonlinearFunction(\n :^,\n Any[MOI.ScalarNonlinearFunction(:sin, Any[x]), 2.0],\n )\n^(sin(MOI.VariableIndex(1)), 2.0)\n\njulia> MOI.VectorNonlinearFunction([g, x])\n┌ ┐\n│^(sin(MOI.VariableIndex(1)), 2.0)│\n│+(MOI.VariableIndex(1)) │\n└ ┘\n\nNote the automatic conversion from x to +(x).\n\n\n\n\n\n","category":"type"},{"location":"reference/standard_form/#Sets","page":"Standard form","title":"Sets","text":"","category":"section"},{"location":"reference/standard_form/","page":"Standard form","title":"Standard form","text":"AbstractSet\nAbstractScalarSet\nAbstractVectorSet","category":"page"},{"location":"reference/standard_form/#MathOptInterface.AbstractSet","page":"Standard form","title":"MathOptInterface.AbstractSet","text":"AbstractSet\n\nAbstract supertype for set objects used to encode constraints.\n\nRequired methods\n\nFor sets of type S with isbitstype(S) == false, you must implement:\n\nBase.copy(set::S)\nBase.:(==)(x::S, y::S)\n\nSubtypes of AbstractSet such as AbstractScalarSet and AbstractVectorSet may prescribe additional required methods.\n\nOptional methods\n\nYou may optionally implement:\n\ndual_set\ndual_set_type\n\nNote for developers\n\nWhen creating a new set, the set struct must not contain any VariableIndex or ConstraintIndex objects.\n\n\n\n\n\n","category":"type"},{"location":"reference/standard_form/#MathOptInterface.AbstractScalarSet","page":"Standard form","title":"MathOptInterface.AbstractScalarSet","text":"AbstractScalarSet\n\nAbstract supertype for subsets of mathbbR.\n\n\n\n\n\n","category":"type"},{"location":"reference/standard_form/#MathOptInterface.AbstractVectorSet","page":"Standard form","title":"MathOptInterface.AbstractVectorSet","text":"AbstractVectorSet\n\nAbstract supertype for subsets of mathbbR^n for some n.\n\nRequired methods\n\nAll AbstractVectorSets of type S must implement:\n\ndimension, unless the dimension is stored in the set.dimension field\nUtilities.set_dot, unless the dot product between two vectors in the set is equivalent to LinearAlgebra.dot.\n\n\n\n\n\n","category":"type"},{"location":"reference/standard_form/#Utilities","page":"Standard form","title":"Utilities","text":"","category":"section"},{"location":"reference/standard_form/","page":"Standard form","title":"Standard form","text":"dimension\ndual_set\ndual_set_type\nconstant(s::EqualTo)\nsupports_dimension_update\nupdate_dimension","category":"page"},{"location":"reference/standard_form/#MathOptInterface.dimension","page":"Standard form","title":"MathOptInterface.dimension","text":"dimension(set::AbstractSet)\n\nReturn the output_dimension that an AbstractFunction should have to be used with the set set.\n\nExample\n\njulia> import MathOptInterface as MOI\n\njulia> MOI.dimension(MOI.Reals(4))\n4\n\njulia> MOI.dimension(MOI.LessThan(3.0))\n1\n\njulia> MOI.dimension(MOI.PositiveSemidefiniteConeTriangle(2))\n3\n\n\n\n\n\n","category":"function"},{"location":"reference/standard_form/#MathOptInterface.dual_set","page":"Standard form","title":"MathOptInterface.dual_set","text":"dual_set(set::AbstractSet)\n\nReturn the dual set of set, that is the dual cone of the set. This follows the definition of duality discussed in Duality.\n\nSee Dual cone for more information.\n\nIf the dual cone is not defined it returns an error.\n\nExample\n\njulia> import MathOptInterface as MOI\n\njulia> MOI.dual_set(MOI.Reals(4))\nMathOptInterface.Zeros(4)\n\njulia> MOI.dual_set(MOI.SecondOrderCone(5))\nMathOptInterface.SecondOrderCone(5)\n\njulia> MOI.dual_set(MOI.ExponentialCone())\nMathOptInterface.DualExponentialCone()\n\n\n\n\n\n","category":"function"},{"location":"reference/standard_form/#MathOptInterface.dual_set_type","page":"Standard form","title":"MathOptInterface.dual_set_type","text":"dual_set_type(S::Type{<:AbstractSet})\n\nReturn the type of dual set of sets of type S, as returned by dual_set. If the dual cone is not defined it returns an error.\n\nExample\n\njulia> import MathOptInterface as MOI\n\njulia> MOI.dual_set_type(MOI.Reals)\nMathOptInterface.Zeros\n\njulia> MOI.dual_set_type(MOI.SecondOrderCone)\nMathOptInterface.SecondOrderCone\n\njulia> MOI.dual_set_type(MOI.ExponentialCone)\nMathOptInterface.DualExponentialCone\n\n\n\n\n\n","category":"function"},{"location":"reference/standard_form/#MathOptInterface.constant-Tuple{MathOptInterface.EqualTo}","page":"Standard form","title":"MathOptInterface.constant","text":"constant(set::Union{EqualTo,GreaterThan,LessThan,Parameter})\n\nReturns the constant term of the set set.\n\nExample\n\njulia> import MathOptInterface as MOI\n\njulia> MOI.constant(MOI.GreaterThan(1.0))\n1.0\n\njulia> MOI.constant(MOI.LessThan(2.5))\n2.5\n\njulia> MOI.constant(MOI.EqualTo(3))\n3\n\njulia> MOI.constant(MOI.Parameter(4.5))\n4.5\n\n\n\n\n\n","category":"method"},{"location":"reference/standard_form/#MathOptInterface.supports_dimension_update","page":"Standard form","title":"MathOptInterface.supports_dimension_update","text":"supports_dimension_update(S::Type{<:MOI.AbstractVectorSet})\n\nReturn a Bool indicating whether the elimination of any dimension of n-dimensional sets of type S give an n-1-dimensional set S. By default, this function returns false so it should only be implemented for sets that supports dimension update.\n\nFor instance, supports_dimension_update(MOI.Nonnegatives) is true because the elimination of any dimension of the n-dimensional nonnegative orthant gives the n-1-dimensional nonnegative orthant. However supports_dimension_update(MOI.ExponentialCone) is false.\n\n\n\n\n\n","category":"function"},{"location":"reference/standard_form/#MathOptInterface.update_dimension","page":"Standard form","title":"MathOptInterface.update_dimension","text":"update_dimension(s::AbstractVectorSet, new_dim::Int)\n\nReturns a set with the dimension modified to new_dim.\n\n\n\n\n\n","category":"function"},{"location":"reference/standard_form/#Scalar-sets","page":"Standard form","title":"Scalar sets","text":"","category":"section"},{"location":"reference/standard_form/","page":"Standard form","title":"Standard form","text":"List of recognized scalar sets.","category":"page"},{"location":"reference/standard_form/","page":"Standard form","title":"Standard form","text":"GreaterThan\nLessThan\nEqualTo\nInterval\nInteger\nZeroOne\nSemicontinuous\nSemiinteger\nParameter","category":"page"},{"location":"reference/standard_form/#MathOptInterface.GreaterThan","page":"Standard form","title":"MathOptInterface.GreaterThan","text":"GreaterThan{T<:Real}(lower::T)\n\nThe set lower infty) subseteq mathbbR.\n\nExample\n\njulia> import MathOptInterface as MOI\n\njulia> model = MOI.Utilities.Model{Float64}()\nMOIU.Model{Float64}\n\njulia> x = MOI.add_variable(model)\nMOI.VariableIndex(1)\n\njulia> MOI.add_constraint(model, x, MOI.GreaterThan(0.0))\nMathOptInterface.ConstraintIndex{MathOptInterface.VariableIndex, MathOptInterface.GreaterThan{Float64}}(1)\n\n\n\n\n\n","category":"type"},{"location":"reference/standard_form/#MathOptInterface.LessThan","page":"Standard form","title":"MathOptInterface.LessThan","text":"LessThan{T<:Real}(upper::T)\n\nThe set (-infty upper subseteq mathbbR.\n\nExample\n\njulia> import MathOptInterface as MOI\n\njulia> model = MOI.Utilities.Model{Float64}()\nMOIU.Model{Float64}\n\njulia> x = MOI.add_variable(model)\nMOI.VariableIndex(1)\n\njulia> MOI.add_constraint(model, x, MOI.LessThan(2.0))\nMathOptInterface.ConstraintIndex{MathOptInterface.VariableIndex, MathOptInterface.LessThan{Float64}}(1)\n\n\n\n\n\n","category":"type"},{"location":"reference/standard_form/#MathOptInterface.EqualTo","page":"Standard form","title":"MathOptInterface.EqualTo","text":"EqualTo{T<:Number}(value::T)\n\nThe set containing the single point value subseteq mathbbR.\n\nExample\n\njulia> import MathOptInterface as MOI\n\njulia> model = MOI.Utilities.Model{Float64}()\nMOIU.Model{Float64}\n\njulia> x = MOI.add_variable(model)\nMOI.VariableIndex(1)\n\njulia> MOI.add_constraint(model, x, MOI.EqualTo(2.0))\nMathOptInterface.ConstraintIndex{MathOptInterface.VariableIndex, MathOptInterface.EqualTo{Float64}}(1)\n\n\n\n\n\n","category":"type"},{"location":"reference/standard_form/#MathOptInterface.Interval","page":"Standard form","title":"MathOptInterface.Interval","text":"Interval{T<:Real}(lower::T, upper::T)\n\nThe interval lower upper subseteq mathbbR cup -infty +infty.\n\nIf lower or upper is -Inf or Inf, respectively, the set is interpreted as a one-sided interval.\n\nExample\n\njulia> import MathOptInterface as MOI\n\njulia> model = MOI.Utilities.Model{Float64}()\nMOIU.Model{Float64}\n\njulia> x = MOI.add_variable(model)\nMOI.VariableIndex(1)\n\njulia> MOI.add_constraint(model, x, MOI.Interval(1.0, 2.0))\nMathOptInterface.ConstraintIndex{MathOptInterface.VariableIndex, MathOptInterface.Interval{Float64}}(1)\n\n\n\n\n\n","category":"type"},{"location":"reference/standard_form/#MathOptInterface.Integer","page":"Standard form","title":"MathOptInterface.Integer","text":"Integer()\n\nThe set of integers, mathbbZ.\n\nExample\n\njulia> import MathOptInterface as MOI\n\njulia> model = MOI.Utilities.Model{Float64}()\nMOIU.Model{Float64}\n\njulia> x = MOI.add_variable(model)\nMOI.VariableIndex(1)\n\njulia> MOI.add_constraint(model, x, MOI.Integer())\nMathOptInterface.ConstraintIndex{MathOptInterface.VariableIndex, MathOptInterface.Integer}(1)\n\n\n\n\n\n","category":"type"},{"location":"reference/standard_form/#MathOptInterface.ZeroOne","page":"Standard form","title":"MathOptInterface.ZeroOne","text":"ZeroOne()\n\nThe set 0 1.\n\nVariables belonging to the ZeroOne set are also known as \"binary\" variables.\n\nExample\n\njulia> import MathOptInterface as MOI\n\njulia> model = MOI.Utilities.Model{Float64}()\nMOIU.Model{Float64}\n\njulia> x = MOI.add_variable(model)\nMOI.VariableIndex(1)\n\njulia> MOI.add_constraint(model, x, MOI.ZeroOne())\nMathOptInterface.ConstraintIndex{MathOptInterface.VariableIndex, MathOptInterface.ZeroOne}(1)\n\n\n\n\n\n","category":"type"},{"location":"reference/standard_form/#MathOptInterface.Semicontinuous","page":"Standard form","title":"MathOptInterface.Semicontinuous","text":"Semicontinuous{T<:Real}(lower::T, upper::T)\n\nThe set 0 cup lower upper.\n\nExample\n\njulia> import MathOptInterface as MOI\n\njulia> model = MOI.Utilities.Model{Float64}()\nMOIU.Model{Float64}\n\njulia> x = MOI.add_variable(model)\nMOI.VariableIndex(1)\n\njulia> MOI.add_constraint(model, x, MOI.Semicontinuous(2.0, 3.0))\nMathOptInterface.ConstraintIndex{MathOptInterface.VariableIndex, MathOptInterface.Semicontinuous{Float64}}(1)\n\n\n\n\n\n","category":"type"},{"location":"reference/standard_form/#MathOptInterface.Semiinteger","page":"Standard form","title":"MathOptInterface.Semiinteger","text":"Semiinteger{T<:Real}(lower::T, upper::T)\n\nThe set 0 cup lower lower+1 ldots upper-1 upper.\n\nNote that if lower and upper are not equivalent to an integer, then the solver may throw an error, or it may round up lower and round down upper to the nearest integers.\n\nExample\n\njulia> import MathOptInterface as MOI\n\njulia> model = MOI.Utilities.Model{Float64}()\nMOIU.Model{Float64}\n\njulia> x = MOI.add_variable(model)\nMOI.VariableIndex(1)\n\njulia> MOI.add_constraint(model, x, MOI.Semiinteger(2.0, 3.0))\nMathOptInterface.ConstraintIndex{MathOptInterface.VariableIndex, MathOptInterface.Semiinteger{Float64}}(1)\n\n\n\n\n\n","category":"type"},{"location":"reference/standard_form/#MathOptInterface.Parameter","page":"Standard form","title":"MathOptInterface.Parameter","text":"Parameter{T<:Number}(value::T)\n\nThe set containing the single point value subseteq mathbbR.\n\nThe Parameter set is conceptually similar to the EqualTo set, except that a variable constrained to the Parameter set cannot have other constraints added to it, and the Parameter set can never be deleted. Thus, solvers are free to treat the variable as a constant, and they need not add it as a decision variable to the model.\n\nBecause of this behavior, you must add parameters using add_constrained_variable, and solvers should declare supports_add_constrained_variable and not supports_constraint for the Parameter set.\n\nExample\n\njulia> import MathOptInterface as MOI\n\njulia> model = MOI.Utilities.Model{Float64}()\nMOIU.Model{Float64}\n\njulia> p, ci = MOI.add_constrained_variable(model, MOI.Parameter(2.5))\n(MOI.VariableIndex(1), MathOptInterface.ConstraintIndex{MathOptInterface.VariableIndex, MathOptInterface.Parameter{Float64}}(1))\n\njulia> MOI.set(model, MOI.ConstraintSet(), ci, MOI.Parameter(3.0))\n\njulia> MOI.get(model, MOI.ConstraintSet(), ci)\nMathOptInterface.Parameter{Float64}(3.0)\n\n\n\n\n\n","category":"type"},{"location":"reference/standard_form/#Vector-sets","page":"Standard form","title":"Vector sets","text":"","category":"section"},{"location":"reference/standard_form/","page":"Standard form","title":"Standard form","text":"List of recognized vector sets.","category":"page"},{"location":"reference/standard_form/","page":"Standard form","title":"Standard form","text":"Reals\nZeros\nNonnegatives\nNonpositives\nNormInfinityCone\nNormOneCone\nNormCone\nSecondOrderCone\nRotatedSecondOrderCone\nGeometricMeanCone\nExponentialCone\nDualExponentialCone\nPowerCone\nDualPowerCone\nRelativeEntropyCone\nNormSpectralCone\nNormNuclearCone\nSOS1\nSOS2\nIndicator\nComplements\nHyperRectangle\nScaled","category":"page"},{"location":"reference/standard_form/#MathOptInterface.Reals","page":"Standard form","title":"MathOptInterface.Reals","text":"Reals(dimension::Int)\n\nThe set mathbbR^dimension (containing all points) of non-negative dimension dimension.\n\nExample\n\njulia> import MathOptInterface as MOI\n\njulia> model = MOI.Utilities.Model{Float64}()\nMOIU.Model{Float64}\n\njulia> x = MOI.add_variables(model, 3);\n\njulia> MOI.add_constraint(model, MOI.VectorOfVariables(x), MOI.Reals(3))\nMathOptInterface.ConstraintIndex{MathOptInterface.VectorOfVariables, MathOptInterface.Reals}(1)\n\n\n\n\n\n","category":"type"},{"location":"reference/standard_form/#MathOptInterface.Zeros","page":"Standard form","title":"MathOptInterface.Zeros","text":"Zeros(dimension::Int)\n\nThe set 0 ^dimension (containing only the origin) of non-negative dimension dimension.\n\nExample\n\njulia> import MathOptInterface as MOI\n\njulia> model = MOI.Utilities.Model{Float64}()\nMOIU.Model{Float64}\n\njulia> x = MOI.add_variables(model, 3);\n\njulia> MOI.add_constraint(model, MOI.VectorOfVariables(x), MOI.Zeros(3))\nMathOptInterface.ConstraintIndex{MathOptInterface.VectorOfVariables, MathOptInterface.Zeros}(1)\n\n\n\n\n\n","category":"type"},{"location":"reference/standard_form/#MathOptInterface.Nonnegatives","page":"Standard form","title":"MathOptInterface.Nonnegatives","text":"Nonnegatives(dimension::Int)\n\nThe nonnegative orthant x in mathbbR^dimension x ge 0 of non-negative dimension dimension.\n\nExample\n\njulia> import MathOptInterface as MOI\n\njulia> model = MOI.Utilities.Model{Float64}()\nMOIU.Model{Float64}\n\njulia> x = MOI.add_variables(model, 3);\n\njulia> MOI.add_constraint(model, MOI.VectorOfVariables(x), MOI.Nonnegatives(3))\nMathOptInterface.ConstraintIndex{MathOptInterface.VectorOfVariables, MathOptInterface.Nonnegatives}(1)\n\n\n\n\n\n","category":"type"},{"location":"reference/standard_form/#MathOptInterface.Nonpositives","page":"Standard form","title":"MathOptInterface.Nonpositives","text":"Nonpositives(dimension::Int)\n\nThe nonpositive orthant x in mathbbR^dimension x le 0 of non-negative dimension dimension.\n\nExample\n\njulia> import MathOptInterface as MOI\n\njulia> model = MOI.Utilities.Model{Float64}()\nMOIU.Model{Float64}\n\njulia> x = MOI.add_variables(model, 3);\n\njulia> MOI.add_constraint(model, MOI.VectorOfVariables(x), MOI.Nonpositives(3))\nMathOptInterface.ConstraintIndex{MathOptInterface.VectorOfVariables, MathOptInterface.Nonpositives}(1)\n\n\n\n\n\n","category":"type"},{"location":"reference/standard_form/#MathOptInterface.NormInfinityCone","page":"Standard form","title":"MathOptInterface.NormInfinityCone","text":"NormInfinityCone(dimension::Int)\n\nThe ell_infty-norm cone (tx) in mathbbR^dimension t ge lVert x rVert_infty = max_i lvert x_i rvert of dimension dimension.\n\nThe dimension must be at least 1.\n\nExample\n\njulia> import MathOptInterface as MOI\n\njulia> model = MOI.Utilities.Model{Float64}()\nMOIU.Model{Float64}\n\njulia> t = MOI.add_variable(model)\nMOI.VariableIndex(1)\n\njulia> x = MOI.add_variables(model, 3);\n\njulia> MOI.add_constraint(model, MOI.VectorOfVariables([t; x]), MOI.NormInfinityCone(4))\nMathOptInterface.ConstraintIndex{MathOptInterface.VectorOfVariables, MathOptInterface.NormInfinityCone}(1)\n\n\n\n\n\n","category":"type"},{"location":"reference/standard_form/#MathOptInterface.NormOneCone","page":"Standard form","title":"MathOptInterface.NormOneCone","text":"NormOneCone(dimension::Int)\n\nThe ell_1-norm cone (tx) in mathbbR^dimension t ge lVert x rVert_1 = sum_i lvert x_i rvert of dimension dimension.\n\nThe dimension must be at least 1.\n\nExample\n\njulia> import MathOptInterface as MOI\n\njulia> model = MOI.Utilities.Model{Float64}()\nMOIU.Model{Float64}\n\njulia> t = MOI.add_variable(model)\nMOI.VariableIndex(1)\n\njulia> x = MOI.add_variables(model, 3);\n\njulia> MOI.add_constraint(model, MOI.VectorOfVariables([t; x]), MOI.NormOneCone(4))\nMathOptInterface.ConstraintIndex{MathOptInterface.VectorOfVariables, MathOptInterface.NormOneCone}(1)\n\n\n\n\n\n","category":"type"},{"location":"reference/standard_form/#MathOptInterface.NormCone","page":"Standard form","title":"MathOptInterface.NormCone","text":"NormCone(p::Float64, dimension::Int)\n\nThe ell_p-norm cone (tx) in mathbbR^dimension t ge left(sumlimits_i x_i^pright)^frac1p of dimension dimension.\n\nThe dimension must be at least 1.\n\nExample\n\njulia> import MathOptInterface as MOI\n\njulia> model = MOI.Utilities.Model{Float64}()\nMOIU.Model{Float64}\n\njulia> t = MOI.add_variable(model)\nMOI.VariableIndex(1)\n\njulia> x = MOI.add_variables(model, 3);\n\njulia> MOI.add_constraint(model, MOI.VectorOfVariables([t; x]), MOI.NormCone(3, 4))\nMathOptInterface.ConstraintIndex{MathOptInterface.VectorOfVariables, MathOptInterface.NormCone}(1)\n\n\n\n\n\n","category":"type"},{"location":"reference/standard_form/#MathOptInterface.SecondOrderCone","page":"Standard form","title":"MathOptInterface.SecondOrderCone","text":"SecondOrderCone(dimension::Int)\n\nThe second-order cone (or Lorenz cone or ell_2-norm cone) (tx) in mathbbR^dimension t ge lVert x rVert_2 of dimension dimension.\n\nThe dimension must be at least 1.\n\nExample\n\njulia> import MathOptInterface as MOI\n\njulia> model = MOI.Utilities.Model{Float64}()\nMOIU.Model{Float64}\n\njulia> t = MOI.add_variable(model)\nMOI.VariableIndex(1)\n\njulia> x = MOI.add_variables(model, 3);\n\njulia> MOI.add_constraint(model, MOI.VectorOfVariables([t; x]), MOI.SecondOrderCone(4))\nMathOptInterface.ConstraintIndex{MathOptInterface.VectorOfVariables, MathOptInterface.SecondOrderCone}(1)\n\n\n\n\n\n","category":"type"},{"location":"reference/standard_form/#MathOptInterface.RotatedSecondOrderCone","page":"Standard form","title":"MathOptInterface.RotatedSecondOrderCone","text":"RotatedSecondOrderCone(dimension::Int)\n\nThe rotated second-order cone (tux) in mathbbR^dimension 2tu ge lVert x rVert_2^2 tu ge 0 of dimension dimension.\n\nThe dimension must be at least 2.\n\nExample\n\njulia> import MathOptInterface as MOI\n\njulia> model = MOI.Utilities.Model{Float64}()\nMOIU.Model{Float64}\n\njulia> t = MOI.add_variable(model)\nMOI.VariableIndex(1)\n\njulia> u = MOI.add_variable(model)\nMOI.VariableIndex(2)\n\njulia> x = MOI.add_variables(model, 3);\n\njulia> MOI.add_constraint(\n model,\n MOI.VectorOfVariables([t; u; x]),\n MOI.RotatedSecondOrderCone(5),\n )\nMathOptInterface.ConstraintIndex{MathOptInterface.VectorOfVariables, MathOptInterface.RotatedSecondOrderCone}(1)\n\n\n\n\n\n","category":"type"},{"location":"reference/standard_form/#MathOptInterface.GeometricMeanCone","page":"Standard form","title":"MathOptInterface.GeometricMeanCone","text":"GeometricMeanCone(dimension::Int)\n\nThe geometric mean cone (tx) in mathbbR^n+1 x ge 0 t le sqrtnx_1 x_2 cdots x_n , where dimension = n + 1 >= 2.\n\nDuality note\n\nThe dual of the geometric mean cone is (u v) in mathbbR^n+1 u le 0 v ge 0 -u le n sqrtnprod_i v_i , where dimension = n + 1 >= 2.\n\nExample\n\njulia> import MathOptInterface as MOI\n\njulia> model = MOI.Utilities.Model{Float64}()\nMOIU.Model{Float64}\n\njulia> t = MOI.add_variable(model)\nMOI.VariableIndex(1)\n\njulia> x = MOI.add_variables(model, 3);\n\njulia> MOI.add_constraint(\n model,\n MOI.VectorOfVariables([t; x]),\n MOI.GeometricMeanCone(4),\n )\nMathOptInterface.ConstraintIndex{MathOptInterface.VectorOfVariables, MathOptInterface.GeometricMeanCone}(1)\n\n\n\n\n\n","category":"type"},{"location":"reference/standard_form/#MathOptInterface.ExponentialCone","page":"Standard form","title":"MathOptInterface.ExponentialCone","text":"ExponentialCone()\n\nThe 3-dimensional exponential cone (xyz) in mathbbR^3 y exp (xy) le z y 0 .\n\nExample\n\njulia> import MathOptInterface as MOI\n\njulia> model = MOI.Utilities.Model{Float64}()\nMOIU.Model{Float64}\n\njulia> x = MOI.add_variables(model, 3);\n\njulia> MOI.add_constraint(model, MOI.VectorOfVariables(x), MOI.ExponentialCone())\nMathOptInterface.ConstraintIndex{MathOptInterface.VectorOfVariables, MathOptInterface.ExponentialCone}(1)\n\n\n\n\n\n","category":"type"},{"location":"reference/standard_form/#MathOptInterface.DualExponentialCone","page":"Standard form","title":"MathOptInterface.DualExponentialCone","text":"DualExponentialCone()\n\nThe 3-dimensional dual exponential cone (uvw) in mathbbR^3 -u exp (vu) le exp(1) w u 0 .\n\nExample\n\njulia> import MathOptInterface as MOI\n\njulia> model = MOI.Utilities.Model{Float64}()\nMOIU.Model{Float64}\n\njulia> x = MOI.add_variables(model, 3);\n\njulia> MOI.add_constraint(model, MOI.VectorOfVariables(x), MOI.DualExponentialCone())\nMathOptInterface.ConstraintIndex{MathOptInterface.VectorOfVariables, MathOptInterface.DualExponentialCone}(1)\n\n\n\n\n\n","category":"type"},{"location":"reference/standard_form/#MathOptInterface.PowerCone","page":"Standard form","title":"MathOptInterface.PowerCone","text":"PowerCone{T<:Real}(exponent::T)\n\nThe 3-dimensional power cone (xyz) in mathbbR^3 x^exponent y^1-exponent ge z x ge 0 y ge 0 with parameter exponent.\n\nExample\n\njulia> import MathOptInterface as MOI\n\njulia> model = MOI.Utilities.Model{Float64}()\nMOIU.Model{Float64}\n\njulia> x = MOI.add_variables(model, 3);\n\njulia> MOI.add_constraint(model, MOI.VectorOfVariables(x), MOI.PowerCone(0.5))\nMathOptInterface.ConstraintIndex{MathOptInterface.VectorOfVariables, MathOptInterface.PowerCone{Float64}}(1)\n\n\n\n\n\n","category":"type"},{"location":"reference/standard_form/#MathOptInterface.DualPowerCone","page":"Standard form","title":"MathOptInterface.DualPowerCone","text":"DualPowerCone{T<:Real}(exponent::T)\n\nThe 3-dimensional power cone (uvw) in mathbbR^3 (fracuexponent)^exponent (fracv1-exponent)^1-exponent ge w u ge 0 v ge 0 with parameter exponent.\n\nExample\n\njulia> import MathOptInterface as MOI\n\njulia> model = MOI.Utilities.Model{Float64}()\nMOIU.Model{Float64}\n\njulia> x = MOI.add_variables(model, 3);\n\njulia> MOI.add_constraint(model, MOI.VectorOfVariables(x), MOI.DualPowerCone(0.5))\nMathOptInterface.ConstraintIndex{MathOptInterface.VectorOfVariables, MathOptInterface.DualPowerCone{Float64}}(1)\n\n\n\n\n\n","category":"type"},{"location":"reference/standard_form/#MathOptInterface.RelativeEntropyCone","page":"Standard form","title":"MathOptInterface.RelativeEntropyCone","text":"RelativeEntropyCone(dimension::Int)\n\nThe relative entropy cone (u v w) in mathbbR^1+2n u ge sum_i=1^n w_i log(fracw_iv_i) v_i ge 0 w_i ge 0 , where dimension = 2n + 1 >= 1.\n\nDuality note\n\nThe dual of the relative entropy cone is (u v w) in mathbbR^1+2n forall i w_i ge u (log (fracuv_i) - 1) v_i ge 0 u 0 of dimension dimension=2n+1.\n\nExample\n\njulia> import MathOptInterface as MOI\n\njulia> model = MOI.Utilities.Model{Float64}()\nMOIU.Model{Float64}\n\njulia> u = MOI.add_variable(model);\n\njulia> v = MOI.add_variables(model, 3);\n\njulia> w = MOI.add_variables(model, 3);\n\njulia> MOI.add_constraint(\n model,\n MOI.VectorOfVariables([u; v; w]),\n MOI.RelativeEntropyCone(7),\n )\nMathOptInterface.ConstraintIndex{MathOptInterface.VectorOfVariables, MathOptInterface.RelativeEntropyCone}(1)\n\n\n\n\n\n","category":"type"},{"location":"reference/standard_form/#MathOptInterface.NormSpectralCone","page":"Standard form","title":"MathOptInterface.NormSpectralCone","text":"NormSpectralCone(row_dim::Int, column_dim::Int)\n\nThe epigraph of the matrix spectral norm (maximum singular value function) (t X) in mathbbR^1 + row_dim times column_dim t ge sigma_1(X) , where sigma_i is the ith singular value of the matrix X of non-negative row dimension row_dim and column dimension column_dim.\n\nThe matrix X is vectorized by stacking the columns, matching the behavior of Julia's vec function.\n\nExample\n\njulia> import MathOptInterface as MOI\n\njulia> model = MOI.Utilities.Model{Float64}()\nMOIU.Model{Float64}\n\njulia> t = MOI.add_variable(model)\nMOI.VariableIndex(1)\n\njulia> X = reshape(MOI.add_variables(model, 6), 2, 3)\n2×3 Matrix{MathOptInterface.VariableIndex}:\n MOI.VariableIndex(2) MOI.VariableIndex(4) MOI.VariableIndex(6)\n MOI.VariableIndex(3) MOI.VariableIndex(5) MOI.VariableIndex(7)\n\njulia> MOI.add_constraint(\n model,\n MOI.VectorOfVariables([t; vec(X)]),\n MOI.NormSpectralCone(2, 3),\n )\nMathOptInterface.ConstraintIndex{MathOptInterface.VectorOfVariables, MathOptInterface.NormSpectralCone}(1)\n\n\n\n\n\n","category":"type"},{"location":"reference/standard_form/#MathOptInterface.NormNuclearCone","page":"Standard form","title":"MathOptInterface.NormNuclearCone","text":"NormNuclearCone(row_dim::Int, column_dim::Int)\n\nThe epigraph of the matrix nuclear norm (sum of singular values function) (t X) in mathbbR^1 + row_dim times column_dim t ge sum_i sigma_i(X) , where sigma_i is the ith singular value of the matrix X of non-negative row dimension row_dim and column dimension column_dim.\n\nThe matrix X is vectorized by stacking the columns, matching the behavior of Julia's vec function.\n\nExample\n\njulia> import MathOptInterface as MOI\n\njulia> model = MOI.Utilities.Model{Float64}()\nMOIU.Model{Float64}\n\njulia> t = MOI.add_variable(model)\nMOI.VariableIndex(1)\n\njulia> X = reshape(MOI.add_variables(model, 6), 2, 3)\n2×3 Matrix{MathOptInterface.VariableIndex}:\n MOI.VariableIndex(2) MOI.VariableIndex(4) MOI.VariableIndex(6)\n MOI.VariableIndex(3) MOI.VariableIndex(5) MOI.VariableIndex(7)\n\njulia> MOI.add_constraint(\n model,\n MOI.VectorOfVariables([t; vec(X)]),\n MOI.NormNuclearCone(2, 3),\n )\nMathOptInterface.ConstraintIndex{MathOptInterface.VectorOfVariables, MathOptInterface.NormNuclearCone}(1)\n\n\n\n\n\n","category":"type"},{"location":"reference/standard_form/#MathOptInterface.SOS1","page":"Standard form","title":"MathOptInterface.SOS1","text":"SOS1{T<:Real}(weights::Vector{T})\n\nThe set corresponding to the Special Ordered Set (SOS) constraint of Type I.\n\nOf the variables in the set, at most one can be nonzero.\n\nThe weights induce an ordering of the variables such that the kth element in the set corresponds to the kth weight in weights. Solvers may use these weights to improve the efficiency of the solution process, but the ordering does not change the set of feasible solutions.\n\nExample\n\njulia> import MathOptInterface as MOI\n\njulia> model = MOI.Utilities.Model{Float64}()\nMOIU.Model{Float64}\n\njulia> x = MOI.add_variables(model, 3);\n\njulia> MOI.add_constraint(\n model,\n MOI.VectorOfVariables(x),\n MOI.SOS1([1.0, 3.0, 2.5]),\n )\nMathOptInterface.ConstraintIndex{MathOptInterface.VectorOfVariables, MathOptInterface.SOS1{Float64}}(1)\n\n\n\n\n\n","category":"type"},{"location":"reference/standard_form/#MathOptInterface.SOS2","page":"Standard form","title":"MathOptInterface.SOS2","text":"SOS2{T<:Real}(weights::Vector{T})\n\nThe set corresponding to the Special Ordered Set (SOS) constraint of Type II.\n\nThe weights induce an ordering of the variables such that the kth element in the set corresponds to the kth weight in weights. Therefore, the weights must be unique.\n\nOf the variables in the set, at most two can be nonzero, and if two are nonzero, they must be adjacent in the ordering of the set.\n\nExample\n\njulia> import MathOptInterface as MOI\n\njulia> model = MOI.Utilities.Model{Float64}()\nMOIU.Model{Float64}\n\njulia> x = MOI.add_variables(model, 3);\n\njulia> MOI.add_constraint(\n model,\n MOI.VectorOfVariables(x),\n MOI.SOS2([1.0, 3.0, 2.5]),\n )\nMathOptInterface.ConstraintIndex{MathOptInterface.VectorOfVariables, MathOptInterface.SOS2{Float64}}(1)\n\n\n\n\n\n","category":"type"},{"location":"reference/standard_form/#MathOptInterface.Indicator","page":"Standard form","title":"MathOptInterface.Indicator","text":"Indicator{A<:ActivationCondition,S<:AbstractScalarSet}(set::S)\n\nThe set corresponding to an indicator constraint.\n\nWhen A is ACTIVATE_ON_ZERO, this means: (y x) in 0 1 times mathbbR^n y = 0 implies x in set\n\nWhen A is ACTIVATE_ON_ONE, this means: (y x) in 0 1 times mathbbR^n y = 1 implies x in set\n\nNotes\n\nMost solvers expect that the first row of the function is interpretable as a variable index x_i (e.g., 1.0 * x + 0.0). An error will be thrown if this is not the case.\n\nExample\n\nThe constraint (y x) in 0 1 times mathbbR^2 y = 1 implies x_1 + x_2 leq 9 is defined as\n\njulia> import MathOptInterface as MOI\n\njulia> model = MOI.Utilities.Model{Float64}()\nMOIU.Model{Float64}\n\njulia> x = MOI.add_variables(model, 2)\n2-element Vector{MathOptInterface.VariableIndex}:\n MOI.VariableIndex(1)\n MOI.VariableIndex(2)\n\njulia> y, _ = MOI.add_constrained_variable(model, MOI.ZeroOne())\n(MOI.VariableIndex(3), MathOptInterface.ConstraintIndex{MathOptInterface.VariableIndex, MathOptInterface.ZeroOne}(3))\n\njulia> f = MOI.VectorAffineFunction(\n [\n MOI.VectorAffineTerm(1, MOI.ScalarAffineTerm(1.0, y)),\n MOI.VectorAffineTerm(2, MOI.ScalarAffineTerm(1.0, x[1])),\n MOI.VectorAffineTerm(2, MOI.ScalarAffineTerm(1.0, x[2])),\n ],\n [0.0, 0.0],\n )\n┌ ┐\n│0.0 + 1.0 MOI.VariableIndex(3) │\n│0.0 + 1.0 MOI.VariableIndex(1) + 1.0 MOI.VariableIndex(2)│\n└ ┘\n\njulia> s = MOI.Indicator{MOI.ACTIVATE_ON_ONE}(MOI.LessThan(9.0))\nMathOptInterface.Indicator{MathOptInterface.ACTIVATE_ON_ONE, MathOptInterface.LessThan{Float64}}(MathOptInterface.LessThan{Float64}(9.0))\n\njulia> MOI.add_constraint(model, f, s)\nMathOptInterface.ConstraintIndex{MathOptInterface.VectorAffineFunction{Float64}, MathOptInterface.Indicator{MathOptInterface.ACTIVATE_ON_ONE, MathOptInterface.LessThan{Float64}}}(1)\n\n\n\n\n\n","category":"type"},{"location":"reference/standard_form/#MathOptInterface.Complements","page":"Standard form","title":"MathOptInterface.Complements","text":"Complements(dimension::Base.Integer)\n\nThe set corresponding to a mixed complementarity constraint.\n\nComplementarity constraints should be specified with an AbstractVectorFunction-in-Complements(dimension) constraint.\n\nThe dimension of the vector-valued function F must be dimension. This defines a complementarity constraint between the scalar function F[i] and the variable in F[i + dimension/2]. Thus, F[i + dimension/2] must be interpretable as a single variable x_i (e.g., 1.0 * x + 0.0), and dimension must be even.\n\nThe mixed complementarity problem consists of finding x_i in the interval [lb, ub] (i.e., in the set Interval(lb, ub)), such that the following holds:\n\nF_i(x) == 0 if lb_i < x_i < ub_i\nF_i(x) >= 0 if lb_i == x_i\nF_i(x) <= 0 if x_i == ub_i\n\nClassically, the bounding set for x_i is Interval(0, Inf), which recovers: 0 <= F_i(x) ⟂ x_i >= 0, where the ⟂ operator implies F_i(x) * x_i = 0.\n\nExample\n\nThe problem:\n\nx -in- Interval(-1, 1)\n[-4 * x - 3, x] -in- Complements(2)\n\ndefines the mixed complementarity problem where the following holds:\n\n-4 * x - 3 == 0 if -1 < x < 1\n-4 * x - 3 >= 0 if x == -1\n-4 * x - 3 <= 0 if x == 1\n\nThere are three solutions:\n\nx = -3/4 with F(x) = 0\nx = -1 with F(x) = 1\nx = 1 with F(x) = -7\n\njulia> import MathOptInterface as MOI\n\njulia> model = MOI.Utilities.Model{Float64}()\nMOIU.Model{Float64}\n\njulia> x, _ = MOI.add_constrained_variable(model, MOI.Interval(-1.0, 1.0));\n\njulia> MOI.add_constraint(\n model,\n MOI.Utilities.vectorize([-4.0 * x - 3.0, x]),\n MOI.Complements(2),\n )\nMathOptInterface.ConstraintIndex{MathOptInterface.VectorAffineFunction{Float64}, MathOptInterface.Complements}(1)\n\nThe function F can also be defined in terms of single variables. For example, the problem:\n\n[x_3, x_4] -in- Nonnegatives(2)\n[x_1, x_2, x_3, x_4] -in- Complements(4)\n\ndefines the complementarity problem where 0 <= x_1 ⟂ x_3 >= 0 and 0 <= x_2 ⟂ x_4 >= 0.\n\njulia> import MathOptInterface as MOI\n\njulia> model = MOI.Utilities.Model{Float64}()\nMOIU.Model{Float64}\n\njulia> x = MOI.add_variables(model, 4);\n\njulia> MOI.add_constraint(model, MOI.VectorOfVariables(x[3:4]), MOI.Nonnegatives(2))\nMathOptInterface.ConstraintIndex{MathOptInterface.VectorOfVariables, MathOptInterface.Nonnegatives}(1)\n\njulia> MOI.add_constraint(\n model,\n MOI.VectorOfVariables(x),\n MOI.Complements(4),\n )\nMathOptInterface.ConstraintIndex{MathOptInterface.VectorOfVariables, MathOptInterface.Complements}(1)\n\n\n\n\n\n","category":"type"},{"location":"reference/standard_form/#MathOptInterface.HyperRectangle","page":"Standard form","title":"MathOptInterface.HyperRectangle","text":"HyperRectangle(lower::Vector{T}, upper::Vector{T}) where {T}\n\nThe set x in barmathbbR^d x_i in lower_i upper_i forall i=1ldotsd.\n\nExample\n\njulia> import MathOptInterface as MOI\n\njulia> model = MOI.Utilities.Model{Float64}()\nMOIU.Model{Float64}\n\njulia> x = MOI.add_variables(model, 3)\n3-element Vector{MathOptInterface.VariableIndex}:\n MOI.VariableIndex(1)\n MOI.VariableIndex(2)\n MOI.VariableIndex(3)\n\njulia> MOI.add_constraint(\n model,\n MOI.VectorOfVariables(x),\n MOI.HyperRectangle(zeros(3), ones(3)),\n )\nMathOptInterface.ConstraintIndex{MathOptInterface.VectorOfVariables, MathOptInterface.HyperRectangle{Float64}}(1)\n\n\n\n\n\n","category":"type"},{"location":"reference/standard_form/#MathOptInterface.Scaled","page":"Standard form","title":"MathOptInterface.Scaled","text":"struct Scaled{S<:AbstractVectorSet} <: AbstractVectorSet\n set::S\nend\n\nGiven a vector a in mathbbR^d and a set representing the set mathcalS in mathbbR^d such that Utilities.set_dot for x in mathcalS and y in mathcalS^* is\n\nsum_i=1^d a_i x_i y_i\n\nthe set Scaled(set) is defined as\n\n (sqrta_1 x_1 sqrta_2 x_2 ldots sqrta_d x_d) x in S \n\nExample\n\nThis can be used to scale a vector of numbers\n\njulia> import MathOptInterface as MOI\n\njulia> set = MOI.PositiveSemidefiniteConeTriangle(2)\nMathOptInterface.PositiveSemidefiniteConeTriangle(2)\n\njulia> a = MOI.Utilities.SetDotScalingVector{Float64}(set)\n3-element MathOptInterface.Utilities.SetDotScalingVector{Float64, MathOptInterface.PositiveSemidefiniteConeTriangle}:\n 1.0\n 1.4142135623730951\n 1.0\n\njulia> using LinearAlgebra\n\njulia> MOI.Utilities.operate(*, Float64, Diagonal(a), ones(3))\n3-element Vector{Float64}:\n 1.0\n 1.4142135623730951\n 1.0\n\nIt can be also used to scale a vector of function\n\njulia> model = MOI.Utilities.Model{Float64}()\nMOIU.Model{Float64}\n\njulia> x = MOI.add_variables(model, 3);\n\njulia> func = MOI.VectorOfVariables(x)\n┌ ┐\n│MOI.VariableIndex(1)│\n│MOI.VariableIndex(2)│\n│MOI.VariableIndex(3)│\n└ ┘\n\njulia> set = MOI.PositiveSemidefiniteConeTriangle(2)\nMathOptInterface.PositiveSemidefiniteConeTriangle(2)\n\njulia> MOI.Utilities.operate(*, Float64, Diagonal(a), func)\n┌ ┐\n│0.0 + 1.0 MOI.VariableIndex(1) │\n│0.0 + 1.4142135623730951 MOI.VariableIndex(2)│\n│0.0 + 1.0 MOI.VariableIndex(3) │\n└ ┘\n\n\n\n\n\n","category":"type"},{"location":"reference/standard_form/#Constraint-programming-sets","page":"Standard form","title":"Constraint programming sets","text":"","category":"section"},{"location":"reference/standard_form/","page":"Standard form","title":"Standard form","text":"AllDifferent\nBinPacking\nCircuit\nCountAtLeast\nCountBelongs\nCountDistinct\nCountGreaterThan\nCumulative\nPath\nReified\nTable","category":"page"},{"location":"reference/standard_form/#MathOptInterface.AllDifferent","page":"Standard form","title":"MathOptInterface.AllDifferent","text":"AllDifferent(dimension::Int)\n\nThe set x in mathbbZ^d such that no two elements in x take the same value and dimension = d.\n\nAlso known as\n\nThis constraint is called all_different in MiniZinc, and is sometimes also called distinct.\n\nExample\n\nTo enforce x[1] != x[2] AND x[1] != x[3] AND x[2] != x[3]:\n\njulia> import MathOptInterface as MOI\n\njulia> model = MOI.Utilities.Model{Float64}()\nMOIU.Model{Float64}\n\njulia> x = [MOI.add_constrained_variable(model, MOI.Integer())[1] for _ in 1:3]\n3-element Vector{MathOptInterface.VariableIndex}:\n MOI.VariableIndex(1)\n MOI.VariableIndex(2)\n MOI.VariableIndex(3)\n\njulia> MOI.add_constraint(model, MOI.VectorOfVariables(x), MOI.AllDifferent(3))\nMathOptInterface.ConstraintIndex{MathOptInterface.VectorOfVariables, MathOptInterface.AllDifferent}(1)\n\n\n\n\n\n","category":"type"},{"location":"reference/standard_form/#MathOptInterface.BinPacking","page":"Standard form","title":"MathOptInterface.BinPacking","text":"BinPacking(c::T, w::Vector{T}) where {T}\n\nThe set x in mathbbZ^d where d = length(w), such that each item i in 1:d of weight w[i] is put into bin x[i], and the total weight of each bin does not exceed c.\n\nThere are additional assumptions that the capacity, c, and the weights, w, must all be non-negative.\n\nThe bin numbers depend on the bounds of x, so they may be something other than the integers 1:d.\n\nAlso known as\n\nThis constraint is called bin_packing in MiniZinc.\n\nExample\n\njulia> import MathOptInterface as MOI\n\njulia> model = MOI.Utilities.Model{Float64}()\nMOIU.Model{Float64}\n\njulia> bins = MOI.add_variables(model, 5)\n5-element Vector{MathOptInterface.VariableIndex}:\n MOI.VariableIndex(1)\n MOI.VariableIndex(2)\n MOI.VariableIndex(3)\n MOI.VariableIndex(4)\n MOI.VariableIndex(5)\n\njulia> weights = Float64[1, 1, 2, 2, 3]\n5-element Vector{Float64}:\n 1.0\n 1.0\n 2.0\n 2.0\n 3.0\n\njulia> MOI.add_constraint.(model, bins, MOI.Integer())\n5-element Vector{MathOptInterface.ConstraintIndex{MathOptInterface.VariableIndex, MathOptInterface.Integer}}:\n MathOptInterface.ConstraintIndex{MathOptInterface.VariableIndex, MathOptInterface.Integer}(1)\n MathOptInterface.ConstraintIndex{MathOptInterface.VariableIndex, MathOptInterface.Integer}(2)\n MathOptInterface.ConstraintIndex{MathOptInterface.VariableIndex, MathOptInterface.Integer}(3)\n MathOptInterface.ConstraintIndex{MathOptInterface.VariableIndex, MathOptInterface.Integer}(4)\n MathOptInterface.ConstraintIndex{MathOptInterface.VariableIndex, MathOptInterface.Integer}(5)\n\njulia> MOI.add_constraint.(model, bins, MOI.Interval(4.0, 6.0))\n5-element Vector{MathOptInterface.ConstraintIndex{MathOptInterface.VariableIndex, MathOptInterface.Interval{Float64}}}:\n MathOptInterface.ConstraintIndex{MathOptInterface.VariableIndex, MathOptInterface.Interval{Float64}}(1)\n MathOptInterface.ConstraintIndex{MathOptInterface.VariableIndex, MathOptInterface.Interval{Float64}}(2)\n MathOptInterface.ConstraintIndex{MathOptInterface.VariableIndex, MathOptInterface.Interval{Float64}}(3)\n MathOptInterface.ConstraintIndex{MathOptInterface.VariableIndex, MathOptInterface.Interval{Float64}}(4)\n MathOptInterface.ConstraintIndex{MathOptInterface.VariableIndex, MathOptInterface.Interval{Float64}}(5)\n\njulia> MOI.add_constraint(model, MOI.VectorOfVariables(bins), MOI.BinPacking(3.0, weights))\nMathOptInterface.ConstraintIndex{MathOptInterface.VectorOfVariables, MathOptInterface.BinPacking{Float64}}(1)\n\n\n\n\n\n","category":"type"},{"location":"reference/standard_form/#MathOptInterface.Circuit","page":"Standard form","title":"MathOptInterface.Circuit","text":"Circuit(dimension::Int)\n\nThe set x in 1d^d that constraints x to be a circuit, such that x_i = j means that j is the successor of i, and dimension = d.\n\nGraphs with multiple independent circuits, such as [2, 1, 3] and [2, 1, 4, 3], are not valid.\n\nAlso known as\n\nThis constraint is called circuit in MiniZinc, and it is equivalent to forming a (potentially sub-optimal) tour in the travelling salesperson problem.\n\nExample\n\njulia> import MathOptInterface as MOI\n\njulia> model = MOI.Utilities.Model{Float64}()\nMOIU.Model{Float64}\n\njulia> x = [MOI.add_constrained_variable(model, MOI.Integer())[1] for _ in 1:3]\n3-element Vector{MathOptInterface.VariableIndex}:\n MOI.VariableIndex(1)\n MOI.VariableIndex(2)\n MOI.VariableIndex(3)\n\njulia> MOI.add_constraint(model, MOI.VectorOfVariables(x), MOI.Circuit(3))\nMathOptInterface.ConstraintIndex{MathOptInterface.VectorOfVariables, MathOptInterface.Circuit}(1)\n\n\n\n\n\n","category":"type"},{"location":"reference/standard_form/#MathOptInterface.CountAtLeast","page":"Standard form","title":"MathOptInterface.CountAtLeast","text":"CountAtLeast(n::Int, d::Vector{Int}, set::Set{Int})\n\nThe set x in mathbbZ^d_1 + d_2 + ldots d_N, where x is partitioned into N subsets (x_1 ldots x_d_1, x_d_1 + 1 ldots x_d_1 + d_2 and so on), and at least n elements of each subset take one of the values in set.\n\nAlso known as\n\nThis constraint is called at_least in MiniZinc.\n\nExample\n\nTo ensure that 3 appears at least once in each of the subsets {a, b} and {b, c}:\n\njulia> import MathOptInterface as MOI\n\njulia> model = MOI.Utilities.Model{Float64}()\nMOIU.Model{Float64}\n\njulia> a, _ = MOI.add_constrained_variable(model, MOI.Integer())\n(MOI.VariableIndex(1), MathOptInterface.ConstraintIndex{MathOptInterface.VariableIndex, MathOptInterface.Integer}(1))\n\njulia> b, _ = MOI.add_constrained_variable(model, MOI.Integer())\n(MOI.VariableIndex(2), MathOptInterface.ConstraintIndex{MathOptInterface.VariableIndex, MathOptInterface.Integer}(2))\n\njulia> c, _ = MOI.add_constrained_variable(model, MOI.Integer())\n(MOI.VariableIndex(3), MathOptInterface.ConstraintIndex{MathOptInterface.VariableIndex, MathOptInterface.Integer}(3))\n\njulia> x, d, set = [a, b, b, c], [2, 2], [3]\n(MathOptInterface.VariableIndex[MOI.VariableIndex(1), MOI.VariableIndex(2), MOI.VariableIndex(2), MOI.VariableIndex(3)], [2, 2], [3])\n\njulia> MOI.add_constraint(model, MOI.VectorOfVariables(x), MOI.CountAtLeast(1, d, Set(set)))\nMathOptInterface.ConstraintIndex{MathOptInterface.VectorOfVariables, MathOptInterface.CountAtLeast}(1)\n\n\n\n\n\n","category":"type"},{"location":"reference/standard_form/#MathOptInterface.CountBelongs","page":"Standard form","title":"MathOptInterface.CountBelongs","text":"CountBelongs(dimenson::Int, set::Set{Int})\n\nThe set (n x) in mathbbZ^1+d, such that n elements of the vector x take on of the values in set and dimension = 1 + d.\n\nAlso known as\n\nThis constraint is called among by MiniZinc.\n\nExample\n\njulia> import MathOptInterface as MOI\n\njulia> model = MOI.Utilities.Model{Float64}()\nMOIU.Model{Float64}\n\njulia> n, _ = MOI.add_constrained_variable(model, MOI.Integer())\n(MOI.VariableIndex(1), MathOptInterface.ConstraintIndex{MathOptInterface.VariableIndex, MathOptInterface.Integer}(1))\n\njulia> x = [MOI.add_constrained_variable(model, MOI.Integer())[1] for _ in 1:3]\n3-element Vector{MathOptInterface.VariableIndex}:\n MOI.VariableIndex(2)\n MOI.VariableIndex(3)\n MOI.VariableIndex(4)\n\njulia> set = Set([3, 4, 5])\nSet{Int64} with 3 elements:\n 5\n 4\n 3\n\njulia> MOI.add_constraint(model, MOI.VectorOfVariables([n; x]), MOI.CountBelongs(4, set))\nMathOptInterface.ConstraintIndex{MathOptInterface.VectorOfVariables, MathOptInterface.CountBelongs}(1)\n\n\n\n\n\n","category":"type"},{"location":"reference/standard_form/#MathOptInterface.CountDistinct","page":"Standard form","title":"MathOptInterface.CountDistinct","text":"CountDistinct(dimension::Int)\n\nThe set (n x) in mathbbZ^1+d, such that the number of distinct values in x is n and dimension = 1 + d.\n\nAlso known as\n\nThis constraint is called nvalues in MiniZinc.\n\nExample\n\nTo model:\n\nif n == 1`, thenx[1] == x[2] == x[3]`\nif n == 2, then\nx[1] == x[2] != x[3] or\nx[1] != x[2] == x[3] or\nx[1] == x[3] != x[2]\nif n == 3, then x[1] != x[2], x[2] != x[3] and x[3] != x[1]\n\njulia> import MathOptInterface as MOI\n\njulia> model = MOI.Utilities.Model{Float64}()\nMOIU.Model{Float64}\n\njulia> n, _ = MOI.add_constrained_variable(model, MOI.Integer())\n(MOI.VariableIndex(1), MathOptInterface.ConstraintIndex{MathOptInterface.VariableIndex, MathOptInterface.Integer}(1))\n\njulia> x = [MOI.add_constrained_variable(model, MOI.Integer())[1] for _ in 1:3]\n3-element Vector{MathOptInterface.VariableIndex}:\n MOI.VariableIndex(2)\n MOI.VariableIndex(3)\n MOI.VariableIndex(4)\n\njulia> MOI.add_constraint(model, MOI.VectorOfVariables(vcat(n, x)), MOI.CountDistinct(4))\nMathOptInterface.ConstraintIndex{MathOptInterface.VectorOfVariables, MathOptInterface.CountDistinct}(1)\n\nRelationship to AllDifferent\n\nWhen the first element is d, CountDistinct is equivalent to an AllDifferent constraint.\n\n\n\n\n\n","category":"type"},{"location":"reference/standard_form/#MathOptInterface.CountGreaterThan","page":"Standard form","title":"MathOptInterface.CountGreaterThan","text":"CountGreaterThan(dimension::Int)\n\nThe set (c y x) in mathbbZ^1+1+d, such that c is strictly greater than the number of occurances of y in x and dimension = 1 + 1 + d.\n\nAlso known as\n\nThis constraint is called count_gt in MiniZinc.\n\nExample\n\njulia> import MathOptInterface as MOI\n\njulia> model = MOI.Utilities.Model{Float64}()\nMOIU.Model{Float64}\n\njulia> c, _ = MOI.add_constrained_variable(model, MOI.Integer())\n(MOI.VariableIndex(1), MathOptInterface.ConstraintIndex{MathOptInterface.VariableIndex, MathOptInterface.Integer}(1))\n\njulia> y, _ = MOI.add_constrained_variable(model, MOI.Integer())\n(MOI.VariableIndex(2), MathOptInterface.ConstraintIndex{MathOptInterface.VariableIndex, MathOptInterface.Integer}(2))\n\njulia> x = [MOI.add_constrained_variable(model, MOI.Integer())[1] for _ in 1:3]\n3-element Vector{MathOptInterface.VariableIndex}:\n MOI.VariableIndex(3)\n MOI.VariableIndex(4)\n MOI.VariableIndex(5)\n\njulia> MOI.add_constraint(model, MOI.VectorOfVariables([c; y; x]), MOI.CountGreaterThan(5))\nMathOptInterface.ConstraintIndex{MathOptInterface.VectorOfVariables, MathOptInterface.CountGreaterThan}(1)\n\n\n\n\n\n","category":"type"},{"location":"reference/standard_form/#MathOptInterface.Cumulative","page":"Standard form","title":"MathOptInterface.Cumulative","text":"Cumulative(dimension::Int)\n\nThe set (s d r b) in mathbbZ^3n+1, representing the cumulative global constraint, where n == length(s) == length(r) == length(b) and dimension = 3n + 1.\n\nCumulative requires that a set of tasks given by start times s, durations d, and resource requirements r, never requires more than the global resource bound b at any one time.\n\nAlso known as\n\nThis constraint is called cumulative in MiniZinc.\n\nExample\n\njulia> import MathOptInterface as MOI\n\njulia> model = MOI.Utilities.Model{Float64}()\nMOIU.Model{Float64}\n\njulia> s = [MOI.add_constrained_variable(model, MOI.Integer())[1] for _ in 1:3]\n3-element Vector{MathOptInterface.VariableIndex}:\n MOI.VariableIndex(1)\n MOI.VariableIndex(2)\n MOI.VariableIndex(3)\n\njulia> d = [MOI.add_constrained_variable(model, MOI.Integer())[1] for _ in 1:3]\n3-element Vector{MathOptInterface.VariableIndex}:\n MOI.VariableIndex(4)\n MOI.VariableIndex(5)\n MOI.VariableIndex(6)\n\njulia> r = [MOI.add_constrained_variable(model, MOI.Integer())[1] for _ in 1:3]\n3-element Vector{MathOptInterface.VariableIndex}:\n MOI.VariableIndex(7)\n MOI.VariableIndex(8)\n MOI.VariableIndex(9)\n\njulia> b, _ = MOI.add_constrained_variable(model, MOI.Integer())\n(MOI.VariableIndex(10), MathOptInterface.ConstraintIndex{MathOptInterface.VariableIndex, MathOptInterface.Integer}(10))\n\njulia> MOI.add_constraint(model, MOI.VectorOfVariables([s; d; r; b]), MOI.Cumulative(10))\nMathOptInterface.ConstraintIndex{MathOptInterface.VectorOfVariables, MathOptInterface.Cumulative}(1)\n\n\n\n\n\n","category":"type"},{"location":"reference/standard_form/#MathOptInterface.Path","page":"Standard form","title":"MathOptInterface.Path","text":"Path(from::Vector{Int}, to::Vector{Int})\n\nGiven a graph comprised of a set of nodes 1..N and a set of arcs 1..E represented by an edge from node from[i] to node to[i], Path constrains the set (s t ns es) in (1N)times(1E)times01^Ntimes01^E, to form subgraph that is a path from node s to node t, where node n is in the path if ns[n] is 1, and edge e is in the path if es[e] is 1.\n\nThe path must be acyclic, and it must traverse all nodes n for which ns[n] is 1, and all edges e for which es[e] is 1.\n\nAlso known as\n\nThis constraint is called path in MiniZinc.\n\nExample\n\njulia> import MathOptInterface as MOI\n\njulia> model = MOI.Utilities.Model{Float64}()\nMOIU.Model{Float64}\n\njulia> N, E = 4, 5\n(4, 5)\n\njulia> from = [1, 1, 2, 2, 3]\n5-element Vector{Int64}:\n 1\n 1\n 2\n 2\n 3\n\njulia> to = [2, 3, 3, 4, 4]\n5-element Vector{Int64}:\n 2\n 3\n 3\n 4\n 4\n\njulia> s, _ = MOI.add_constrained_variable(model, MOI.Integer())\n(MOI.VariableIndex(1), MathOptInterface.ConstraintIndex{MathOptInterface.VariableIndex, MathOptInterface.Integer}(1))\n\njulia> t, _ = MOI.add_constrained_variable(model, MOI.Integer())\n(MOI.VariableIndex(2), MathOptInterface.ConstraintIndex{MathOptInterface.VariableIndex, MathOptInterface.Integer}(2))\n\njulia> ns = MOI.add_variables(model, N)\n4-element Vector{MathOptInterface.VariableIndex}:\n MOI.VariableIndex(3)\n MOI.VariableIndex(4)\n MOI.VariableIndex(5)\n MOI.VariableIndex(6)\n\njulia> MOI.add_constraint.(model, ns, MOI.ZeroOne())\n4-element Vector{MathOptInterface.ConstraintIndex{MathOptInterface.VariableIndex, MathOptInterface.ZeroOne}}:\n MathOptInterface.ConstraintIndex{MathOptInterface.VariableIndex, MathOptInterface.ZeroOne}(3)\n MathOptInterface.ConstraintIndex{MathOptInterface.VariableIndex, MathOptInterface.ZeroOne}(4)\n MathOptInterface.ConstraintIndex{MathOptInterface.VariableIndex, MathOptInterface.ZeroOne}(5)\n MathOptInterface.ConstraintIndex{MathOptInterface.VariableIndex, MathOptInterface.ZeroOne}(6)\n\njulia> es = MOI.add_variables(model, E)\n5-element Vector{MathOptInterface.VariableIndex}:\n MOI.VariableIndex(7)\n MOI.VariableIndex(8)\n MOI.VariableIndex(9)\n MOI.VariableIndex(10)\n MOI.VariableIndex(11)\n\njulia> MOI.add_constraint.(model, es, MOI.ZeroOne())\n5-element Vector{MathOptInterface.ConstraintIndex{MathOptInterface.VariableIndex, MathOptInterface.ZeroOne}}:\n MathOptInterface.ConstraintIndex{MathOptInterface.VariableIndex, MathOptInterface.ZeroOne}(7)\n MathOptInterface.ConstraintIndex{MathOptInterface.VariableIndex, MathOptInterface.ZeroOne}(8)\n MathOptInterface.ConstraintIndex{MathOptInterface.VariableIndex, MathOptInterface.ZeroOne}(9)\n MathOptInterface.ConstraintIndex{MathOptInterface.VariableIndex, MathOptInterface.ZeroOne}(10)\n MathOptInterface.ConstraintIndex{MathOptInterface.VariableIndex, MathOptInterface.ZeroOne}(11)\n\njulia> MOI.add_constraint(model, MOI.VectorOfVariables([s; t; ns; es]), MOI.Path(from, to))\nMathOptInterface.ConstraintIndex{MathOptInterface.VectorOfVariables, MathOptInterface.Path}(1)\n\n\n\n\n\n","category":"type"},{"location":"reference/standard_form/#MathOptInterface.Reified","page":"Standard form","title":"MathOptInterface.Reified","text":"Reified(set::AbstractSet)\n\nThe constraint z f(x) in Reified(S) ensures that f(x) in S if and only if z == 1, where z in 0 1.\n\njulia> import MathOptInterface as MOI\n\njulia> model = MOI.Utilities.UniversalFallback(MOI.Utilities.Model{Float64}())\nMOIU.UniversalFallback{MOIU.Model{Float64}}\nfallback for MOIU.Model{Float64}\n\njulia> z, _ = MOI.add_constrained_variable(model, MOI.ZeroOne())\n(MOI.VariableIndex(1), MathOptInterface.ConstraintIndex{MathOptInterface.VariableIndex, MathOptInterface.ZeroOne}(1))\n\njulia> x = MOI.add_variable(model)\nMOI.VariableIndex(2)\n\njulia> MOI.add_constraint(\n model,\n MOI.Utilities.vectorize([z, 2.0 * x]),\n MOI.Reified(MOI.GreaterThan(1.0)),\n )\nMathOptInterface.ConstraintIndex{MathOptInterface.VectorAffineFunction{Float64}, MathOptInterface.Reified{MathOptInterface.GreaterThan{Float64}}}(1)\n\n\n\n\n\n","category":"type"},{"location":"reference/standard_form/#MathOptInterface.Table","page":"Standard form","title":"MathOptInterface.Table","text":"Table(table::Matrix{T}) where {T}\n\nThe set x in mathbbR^d where d = size(table, 2), such that x belongs to one row of table. That is, there exists some j in 1:size(table, 1), such that x[i] = table[j, i] for all i=1:size(table, 2).\n\nAlso known as\n\nThis constraint is called table in MiniZinc.\n\nExample\n\njulia> import MathOptInterface as MOI\n\njulia> model = MOI.Utilities.Model{Float64}()\nMOIU.Model{Float64}\n\njulia> x = MOI.add_variables(model, 3)\n3-element Vector{MathOptInterface.VariableIndex}:\n MOI.VariableIndex(1)\n MOI.VariableIndex(2)\n MOI.VariableIndex(3)\n\njulia> table = Float64[1 1 0; 0 1 1; 1 0 1; 1 1 1]\n4×3 Matrix{Float64}:\n 1.0 1.0 0.0\n 0.0 1.0 1.0\n 1.0 0.0 1.0\n 1.0 1.0 1.0\n\njulia> MOI.add_constraint(model, MOI.VectorOfVariables(x), MOI.Table(table))\nMathOptInterface.ConstraintIndex{MathOptInterface.VectorOfVariables, MathOptInterface.Table{Float64}}(1)\n\n\n\n\n\n","category":"type"},{"location":"reference/standard_form/#Matrix-sets","page":"Standard form","title":"Matrix sets","text":"","category":"section"},{"location":"reference/standard_form/","page":"Standard form","title":"Standard form","text":"Matrix sets are vectorized to be subtypes of AbstractVectorSet.","category":"page"},{"location":"reference/standard_form/","page":"Standard form","title":"Standard form","text":"For sets of symmetric matrices, storing both the (i, j) and (j, i) elements is redundant. Use the AbstractSymmetricMatrixSetTriangle set to represent only the vectorization of the upper triangular part of the matrix.","category":"page"},{"location":"reference/standard_form/","page":"Standard form","title":"Standard form","text":"When the matrix of expressions constrained to be in the set is not symmetric, and hence additional constraints are needed to force the equality of the (i, j) and (j, i) elements, use the AbstractSymmetricMatrixSetSquare set.","category":"page"},{"location":"reference/standard_form/","page":"Standard form","title":"Standard form","text":"The Bridges.Constraint.SquareBridge can transform a set from the square form to the triangular_form by adding appropriate constraints if the (i, j) and (j, i) expressions are different.","category":"page"},{"location":"reference/standard_form/","page":"Standard form","title":"Standard form","text":"AbstractSymmetricMatrixSetTriangle\nAbstractSymmetricMatrixSetSquare\nside_dimension\ntriangular_form","category":"page"},{"location":"reference/standard_form/#MathOptInterface.AbstractSymmetricMatrixSetTriangle","page":"Standard form","title":"MathOptInterface.AbstractSymmetricMatrixSetTriangle","text":"abstract type AbstractSymmetricMatrixSetTriangle <: AbstractVectorSet end\n\nAbstract supertype for subsets of the (vectorized) cone of symmetric matrices, with side_dimension rows and columns. The entries of the upper-right triangular part of the matrix are given column by column (or equivalently, the entries of the lower-left triangular part are given row by row). A vectorized cone of dimension n corresponds to a square matrix with side dimension sqrt14 + 2 n - 12. (Because a d times d matrix has d(d + 1) 2 elements in the upper or lower triangle.)\n\nExample\n\nThe matrix\n\nbeginbmatrix\n 1 2 4\n 2 3 5\n 4 5 6\nendbmatrix\n\nhas side_dimension 3 and vectorization (1 2 3 4 5 6).\n\nNote\n\nTwo packed storage formats exist for symmetric matrices, the respective orders of the entries are:\n\nupper triangular column by column (or lower triangular row by row);\nlower triangular column by column (or upper triangular row by row).\n\nThe advantage of the first format is the mapping between the (i, j) matrix indices and the k index of the vectorized form. It is simpler and does not depend on the side dimension of the matrix. Indeed,\n\nthe entry of matrix indices (i, j) has vectorized index k = div((j - 1) * j, 2) + i if i leq j and k = div((i - 1) * i, 2) + j if j leq i;\nand the entry with vectorized index k has matrix indices i = div(1 + isqrt(8k - 7), 2) and j = k - div((i - 1) * i, 2) or j = div(1 + isqrt(8k - 7), 2) and i = k - div((j - 1) * j, 2).\n\nDuality note\n\nThe scalar product for the symmetric matrix in its vectorized form is the sum of the pairwise product of the diagonal entries plus twice the sum of the pairwise product of the upper diagonal entries; see [p. 634, 1]. This has important consequence for duality.\n\nConsider for example the following problem (PositiveSemidefiniteConeTriangle is a subtype of AbstractSymmetricMatrixSetTriangle)\n\nbeginalign*\n max_x in mathbbR x\n \n textst \n (1 -x 1) in textPositiveSemidefiniteConeTriangle(2)\nendalign*\n\nThe dual is the following problem\n\nbeginalign*\n min_x in mathbbR^3 y_1 + y_3\n \n textst 2y_2 = 1\n y in textPositiveSemidefiniteConeTriangle(2)\nendalign*\n\nWhy do we use 2y_2 in the dual constraint instead of y_2 ? The reason is that 2y_2 is the scalar product between y and the symmetric matrix whose vectorized form is (0 1 0). Indeed, with our modified scalar products we have\n\nlangle\n(0 1 0)\n(y_1 y_2 y_3)\nrangle\n=\nmathrmtrace\nbeginpmatrix\n 0 1\n 1 0\nendpmatrix\nbeginpmatrix\n y_1 y_2\n y_2 y_3\nendpmatrix\n= 2y_2\n\nReferences\n\n[1] Boyd, S. and Vandenberghe, L.. Convex optimization. Cambridge university press, 2004.\n\n\n\n\n\n","category":"type"},{"location":"reference/standard_form/#MathOptInterface.AbstractSymmetricMatrixSetSquare","page":"Standard form","title":"MathOptInterface.AbstractSymmetricMatrixSetSquare","text":"abstract type AbstractSymmetricMatrixSetSquare <: AbstractVectorSet end\n\nAbstract supertype for subsets of the (vectorized) cone of symmetric matrices, with side_dimension rows and columns. The entries of the matrix are given column by column (or equivalently, row by row). The matrix is both constrained to be symmetric and to have its triangular_form belong to the corresponding set. That is, if the functions in entries (i j) and (j i) are different, then a constraint will be added to make sure that the entries are equal.\n\nExample\n\nPositiveSemidefiniteConeSquare is a subtype of AbstractSymmetricMatrixSetSquare and constraining the matrix\n\nbeginbmatrix\n 1 -y\n -z 0\nendbmatrix\n\nto be symmetric positive semidefinite can be achieved by constraining the vector (1 -z -y 0) (or (1 -y -z 0)) to belong to the PositiveSemidefiniteConeSquare(2). It both constrains y = z and (1 -y 0) (or (1 -z 0)) to be in PositiveSemidefiniteConeTriangle(2), since triangular_form(PositiveSemidefiniteConeSquare) is PositiveSemidefiniteConeTriangle.\n\n\n\n\n\n","category":"type"},{"location":"reference/standard_form/#MathOptInterface.side_dimension","page":"Standard form","title":"MathOptInterface.side_dimension","text":"side_dimension(\n set::Union{\n AbstractSymmetricMatrixSetTriangle,\n AbstractSymmetricMatrixSetSquare,\n HermitianPositiveSemidefiniteConeTriangle,\n },\n)\n\nSide dimension of the matrices in set.\n\nConvention\n\nBy convention, the side dimension should be stored in the side_dimension field. If this is not the case for a subtype of AbstractSymmetricMatrixSetTriangle, or AbstractSymmetricMatrixSetSquare you must implement this method.\n\n\n\n\n\n","category":"function"},{"location":"reference/standard_form/#MathOptInterface.triangular_form","page":"Standard form","title":"MathOptInterface.triangular_form","text":"triangular_form(S::Type{<:AbstractSymmetricMatrixSetSquare})\ntriangular_form(set::AbstractSymmetricMatrixSetSquare)\n\nReturn the AbstractSymmetricMatrixSetTriangle corresponding to the vectorization of the upper triangular part of matrices in the AbstractSymmetricMatrixSetSquare set.\n\n\n\n\n\n","category":"function"},{"location":"reference/standard_form/","page":"Standard form","title":"Standard form","text":"List of recognized matrix sets.","category":"page"},{"location":"reference/standard_form/","page":"Standard form","title":"Standard form","text":"PositiveSemidefiniteConeTriangle\nPositiveSemidefiniteConeSquare\nHermitianPositiveSemidefiniteConeTriangle\nLogDetConeTriangle\nLogDetConeSquare\nRootDetConeTriangle\nRootDetConeSquare","category":"page"},{"location":"reference/standard_form/#MathOptInterface.PositiveSemidefiniteConeTriangle","page":"Standard form","title":"MathOptInterface.PositiveSemidefiniteConeTriangle","text":"PositiveSemidefiniteConeTriangle(side_dimension::Int) <: AbstractSymmetricMatrixSetTriangle\n\nThe (vectorized) cone of symmetric positive semidefinite matrices, with non-negative side_dimension rows and columns.\n\nSee AbstractSymmetricMatrixSetTriangle for more details on the vectorized form.\n\n\n\n\n\n","category":"type"},{"location":"reference/standard_form/#MathOptInterface.PositiveSemidefiniteConeSquare","page":"Standard form","title":"MathOptInterface.PositiveSemidefiniteConeSquare","text":"PositiveSemidefiniteConeSquare(side_dimension::Int) <: AbstractSymmetricMatrixSetSquare\n\nThe cone of symmetric positive semidefinite matrices, with non-negative side length side_dimension.\n\nSee AbstractSymmetricMatrixSetSquare for more details on the vectorized form.\n\nThe entries of the matrix are given column by column (or equivalently, row by row).\n\nThe matrix is both constrained to be symmetric and to be positive semidefinite. That is, if the functions in entries (i j) and (j i) are different, then a constraint will be added to make sure that the entries are equal.\n\nExample\n\nConstraining the matrix\n\nbeginbmatrix\n 1 -y\n -z 0\nendbmatrix\n\nto be symmetric positive semidefinite can be achieved by constraining the vector (1 -z -y 0) (or (1 -y -z 0)) to belong to the PositiveSemidefiniteConeSquare(2).\n\nIt both constrains y = z and (1 -y 0) (or (1 -z 0)) to be in PositiveSemidefiniteConeTriangle(2).\n\n\n\n\n\n","category":"type"},{"location":"reference/standard_form/#MathOptInterface.HermitianPositiveSemidefiniteConeTriangle","page":"Standard form","title":"MathOptInterface.HermitianPositiveSemidefiniteConeTriangle","text":"HermitianPositiveSemidefiniteConeTriangle(side_dimension::Int) <: AbstractVectorSet\n\nThe (vectorized) cone of Hermitian positive semidefinite matrices, with non-negative side_dimension rows and columns.\n\nBecaue the matrix is Hermitian, the diagonal elements are real, and the complex-valued lower triangular entries are obtained as the conjugate of corresponding upper triangular entries.\n\nVectorization format\n\nThe vectorized form starts with real part of the entries of the upper triangular part of the matrix, given column by column as explained in AbstractSymmetricMatrixSetSquare.\n\nIt is then followed by the imaginary part of the off-diagonal entries of the upper triangular part, also given column by column.\n\nFor example, the matrix\n\nbeginbmatrix\n 1 2 + 7im 4 + 8im\n 2 - 7im 3 5 + 9im\n 4 - 8im 5 - 9im 6\nendbmatrix\n\nhas side_dimension 3 and is represented as the vector 1 2 3 4 5 6 7 8 9.\n\n\n\n\n\n","category":"type"},{"location":"reference/standard_form/#MathOptInterface.LogDetConeTriangle","page":"Standard form","title":"MathOptInterface.LogDetConeTriangle","text":"LogDetConeTriangle(side_dimension::Int)\n\nThe log-determinant cone (t u X) in mathbbR^2 + d(d+1)2 t le u log(det(Xu)) u 0 , where the matrix X is represented in the same symmetric packed format as in the PositiveSemidefiniteConeTriangle.\n\nThe non-negative argument side_dimension is the side dimension of the matrix X, i.e., its number of rows or columns.\n\nExample\n\njulia> import MathOptInterface as MOI\n\njulia> model = MOI.Utilities.Model{Float64}()\nMOIU.Model{Float64}\n\njulia> t = MOI.add_variable(model)\nMOI.VariableIndex(1)\n\njulia> X = MOI.add_variables(model, 3);\n\njulia> MOI.add_constraint(\n model,\n MOI.VectorOfVariables([t; X]),\n MOI.LogDetConeTriangle(2),\n )\nMathOptInterface.ConstraintIndex{MathOptInterface.VectorOfVariables, MathOptInterface.LogDetConeTriangle}(1)\n\n\n\n\n\n","category":"type"},{"location":"reference/standard_form/#MathOptInterface.LogDetConeSquare","page":"Standard form","title":"MathOptInterface.LogDetConeSquare","text":"LogDetConeSquare(side_dimension::Int)\n\nThe log-determinant cone (t u X) in mathbbR^2 + d^2 t le u log(det(Xu)) X text symmetric u 0 , where the matrix X is represented in the same format as in the PositiveSemidefiniteConeSquare.\n\nSimilarly to PositiveSemidefiniteConeSquare, constraints are added to ensure that X is symmetric.\n\nThe non-negative argument side_dimension is the side dimension of the matrix X, i.e., its number of rows or columns.\n\nExample\n\njulia> import MathOptInterface as MOI\n\njulia> model = MOI.Utilities.Model{Float64}()\nMOIU.Model{Float64}\n\njulia> t = MOI.add_variable(model)\nMOI.VariableIndex(1)\n\njulia> X = reshape(MOI.add_variables(model, 4), 2, 2)\n2×2 Matrix{MathOptInterface.VariableIndex}:\n MOI.VariableIndex(2) MOI.VariableIndex(4)\n MOI.VariableIndex(3) MOI.VariableIndex(5)\n\njulia> MOI.add_constraint(\n model,\n MOI.VectorOfVariables([t; vec(X)]),\n MOI.LogDetConeSquare(2),\n )\nMathOptInterface.ConstraintIndex{MathOptInterface.VectorOfVariables, MathOptInterface.LogDetConeSquare}(1)\n\n\n\n\n\n","category":"type"},{"location":"reference/standard_form/#MathOptInterface.RootDetConeTriangle","page":"Standard form","title":"MathOptInterface.RootDetConeTriangle","text":"RootDetConeTriangle(side_dimension::Int)\n\nThe root-determinant cone (t X) in mathbbR^1 + d(d+1)2 t le det(X)^1d , where the matrix X is represented in the same symmetric packed format as in the PositiveSemidefiniteConeTriangle.\n\nThe non-negative argument side_dimension is the side dimension of the matrix X, i.e., its number of rows or columns.\n\nExample\n\njulia> import MathOptInterface as MOI\n\njulia> model = MOI.Utilities.Model{Float64}()\nMOIU.Model{Float64}\n\njulia> t = MOI.add_variable(model)\nMOI.VariableIndex(1)\n\njulia> X = MOI.add_variables(model, 3);\n\njulia> MOI.add_constraint(\n model,\n MOI.VectorOfVariables([t; X]),\n MOI.RootDetConeTriangle(2),\n )\nMathOptInterface.ConstraintIndex{MathOptInterface.VectorOfVariables, MathOptInterface.RootDetConeTriangle}(1)\n\n\n\n\n\n","category":"type"},{"location":"reference/standard_form/#MathOptInterface.RootDetConeSquare","page":"Standard form","title":"MathOptInterface.RootDetConeSquare","text":"RootDetConeSquare(side_dimension::Int)\n\nThe root-determinant cone (t X) in mathbbR^1 + d^2 t le det(X)^1d X text symmetric , where the matrix X is represented in the same format as PositiveSemidefiniteConeSquare.\n\nSimilarly to PositiveSemidefiniteConeSquare, constraints are added to ensure that X is symmetric.\n\nThe non-negative argument side_dimension is the side dimension of the matrix X, i.e., its number of rows or columns.\n\nExample\n\njulia> import MathOptInterface as MOI\n\njulia> model = MOI.Utilities.Model{Float64}()\nMOIU.Model{Float64}\n\njulia> t = MOI.add_variable(model)\nMOI.VariableIndex(1)\n\njulia> X = reshape(MOI.add_variables(model, 4), 2, 2)\n2×2 Matrix{MathOptInterface.VariableIndex}:\n MOI.VariableIndex(2) MOI.VariableIndex(4)\n MOI.VariableIndex(3) MOI.VariableIndex(5)\n\njulia> MOI.add_constraint(\n model,\n MOI.VectorOfVariables([t; vec(X)]),\n MOI.RootDetConeSquare(2),\n )\nMathOptInterface.ConstraintIndex{MathOptInterface.VectorOfVariables, MathOptInterface.RootDetConeSquare}(1)\n\n\n\n\n\n","category":"type"},{"location":"tutorials/latency/","page":"Latency","title":"Latency","text":"CurrentModule = MathOptInterface\nDocTestSetup = quote\n import MathOptInterface as MOI\nend\nDocTestFilters = [r\"MathOptInterface|MOI\"]","category":"page"},{"location":"tutorials/latency/#Latency","page":"Latency","title":"Latency","text":"","category":"section"},{"location":"tutorials/latency/","page":"Latency","title":"Latency","text":"MathOptInterface suffers the \"time-to-first-solve\" problem of start-up latency.","category":"page"},{"location":"tutorials/latency/","page":"Latency","title":"Latency","text":"This hurts both the user- and developer-experience of MathOptInterface. In the first case, because simple models have a multi-second delay before solving, and in the latter, because our tests take so long to run.","category":"page"},{"location":"tutorials/latency/","page":"Latency","title":"Latency","text":"This page contains some advice on profiling and fixing latency-related problems in the MathOptInterface.jl repository.","category":"page"},{"location":"tutorials/latency/#Background","page":"Latency","title":"Background","text":"","category":"section"},{"location":"tutorials/latency/","page":"Latency","title":"Latency","text":"Before reading this part of the documentation, you should familiarize yourself with the reasons for latency in Julia and how to fix them.","category":"page"},{"location":"tutorials/latency/","page":"Latency","title":"Latency","text":"Read the blogposts on julialang.org on precompilation and SnoopCompile\nRead the SnoopCompile documentation.\nWatch Tim Holy's talk at JuliaCon 2021\nWatch the package development workshop at JuliaCon 2021","category":"page"},{"location":"tutorials/latency/#Causes","page":"Latency","title":"Causes","text":"","category":"section"},{"location":"tutorials/latency/","page":"Latency","title":"Latency","text":"There are three main causes of latency in MathOptInterface:","category":"page"},{"location":"tutorials/latency/","page":"Latency","title":"Latency","text":"A large number of types\nLack of method ownership\nType-instability in the bridge layer","category":"page"},{"location":"tutorials/latency/#A-large-number-of-types","page":"Latency","title":"A large number of types","text":"","category":"section"},{"location":"tutorials/latency/","page":"Latency","title":"Latency","text":"Julia is very good at specializing method calls based on the input type. Each specialization has a compilation cost, but the benefit of faster run-time performance.","category":"page"},{"location":"tutorials/latency/","page":"Latency","title":"Latency","text":"The best-case scenario is for a method to be called a large number of times with a single set of argument types. The worst-case scenario is for a method to be called a single time for a large set of argument types.","category":"page"},{"location":"tutorials/latency/","page":"Latency","title":"Latency","text":"Because of MathOptInterface's function-in-set formulation, we fall into the worst-case situation.","category":"page"},{"location":"tutorials/latency/","page":"Latency","title":"Latency","text":"This is a fundamental limitation of Julia, so there isn't much we can do about it. However, if we can precompile MathOptInterface, much of the cost can be shifted from start-up latency to the time it takes to precompile a package on installation.","category":"page"},{"location":"tutorials/latency/","page":"Latency","title":"Latency","text":"However, there are two things which make MathOptInterface hard to precompile.","category":"page"},{"location":"tutorials/latency/#Lack-of-method-ownership","page":"Latency","title":"Lack of method ownership","text":"","category":"section"},{"location":"tutorials/latency/","page":"Latency","title":"Latency","text":"Lack of method ownership happens when a call is made using a mix of structs and methods from different modules. Because of this, no single module \"owns\" the method that is being dispatched, and so it cannot be precompiled.","category":"page"},{"location":"tutorials/latency/","page":"Latency","title":"Latency","text":"tip: Tip\nThis is a slightly simplified explanation. Read the precompilation tutorial for a more in-depth discussion on back-edges.","category":"page"},{"location":"tutorials/latency/","page":"Latency","title":"Latency","text":"Unfortunately, the design of MOI means that this is a frequent occurrence: we have a bunch of types in MOI.Utilities that wrap types defined in external packages (for example, the Optimizers), which implement methods of functions defined in MOI (for example, add_variable, add_constraint).","category":"page"},{"location":"tutorials/latency/","page":"Latency","title":"Latency","text":"Here's a simple example of method-ownership in practice:","category":"page"},{"location":"tutorials/latency/","page":"Latency","title":"Latency","text":"module MyMOI\nstruct Wrapper{T}\n inner::T\nend\noptimize!(x::Wrapper) = optimize!(x.inner)\nend # MyMOI\n\nmodule MyOptimizer\nusing ..MyMOI\nstruct Optimizer end\nMyMOI.optimize!(x::Optimizer) = 1\nend # MyOptimizer\n\nusing SnoopCompile\nmodel = MyMOI.Wrapper(MyOptimizer.Optimizer())\n\njulia> tinf = @snoopi_deep MyMOI.optimize!(model)\nInferenceTimingNode: 0.008256/0.008543 on InferenceFrameInfo for Core.Compiler.Timings.ROOT() with 1 direct children","category":"page"},{"location":"tutorials/latency/","page":"Latency","title":"Latency","text":"The result is that there was one method that required type inference. If we visualize tinf:","category":"page"},{"location":"tutorials/latency/","page":"Latency","title":"Latency","text":"using ProfileView\nProfileView.view(flamegraph(tinf))","category":"page"},{"location":"tutorials/latency/","page":"Latency","title":"Latency","text":"we see a flamegraph with a large red-bar indicating that the method MyMOI.optimize(MyMOI.Wrapper{MyOptimizer.Optimizer}) cannot be precompiled.","category":"page"},{"location":"tutorials/latency/","page":"Latency","title":"Latency","text":"To fix this, we need to designate a module to \"own\" that method (that is, create a back-edge). The easiest way to do this is for MyOptimizer to call MyMOI.optimize(MyMOI.Wrapper{MyOptimizer.Optimizer}) during using MyOptimizer. Let's see that in practice:","category":"page"},{"location":"tutorials/latency/","page":"Latency","title":"Latency","text":"module MyMOI\nstruct Wrapper{T}\n inner::T\nend\noptimize(x::Wrapper) = optimize(x.inner)\nend # MyMOI\n\nmodule MyOptimizer\nusing ..MyMOI\nstruct Optimizer end\nMyMOI.optimize(x::Optimizer) = 1\n# The syntax of this let-while loop is very particular:\n# * `let ... end` keeps everything local to avoid polluting the MyOptimizer\n# namespace\n# * `while true ... break end` runs the code once, and forces Julia to compile\n# the inner loop, rather than interpret it.\nlet\n while true\n model = MyMOI.Wrapper(Optimizer())\n MyMOI.optimize(model)\n break\n end\nend\nend # MyOptimizer\n\nusing SnoopCompile\nmodel = MyMOI.Wrapper(MyOptimizer.Optimizer())\n\njulia> tinf = @snoopi_deep MyMOI.optimize(model)\nInferenceTimingNode: 0.006822/0.006822 on InferenceFrameInfo for Core.Compiler.Timings.ROOT() with 0 direct children","category":"page"},{"location":"tutorials/latency/","page":"Latency","title":"Latency","text":"There are now 0 direct children that required type inference because the method was already stored in MyOptimizer!","category":"page"},{"location":"tutorials/latency/","page":"Latency","title":"Latency","text":"Unfortunately, this trick only works if the call-chain is fully inferrable. If there are breaks (due to type instability), then the benefit of doing this is reduced. And unfortunately for us, the design of MathOptInterface has a lot of type instabilities.","category":"page"},{"location":"tutorials/latency/#Type-instability-in-the-bridge-layer","page":"Latency","title":"Type instability in the bridge layer","text":"","category":"section"},{"location":"tutorials/latency/","page":"Latency","title":"Latency","text":"Most of MathOptInterface is pretty good at ensuring type-stability. However, a key component is not type stable, and that is the bridging layer.","category":"page"},{"location":"tutorials/latency/","page":"Latency","title":"Latency","text":"In particular, the bridging layer defines Bridges.LazyBridgeOptimizer, which has fields like:","category":"page"},{"location":"tutorials/latency/","page":"Latency","title":"Latency","text":"struct LazyBridgeOptimizer\n constraint_bridge_types::Vector{Any}\n constraint_node::Dict{Tuple{Type,Type},ConstraintNode}\n constraint_types::Vector{Tuple{Type,Type}}\nend","category":"page"},{"location":"tutorials/latency/","page":"Latency","title":"Latency","text":"This is because the LazyBridgeOptimizer needs to be able to deal with any function-in-set type passed to it, and we also allow users to pass additional bridges that they defined in external packages.","category":"page"},{"location":"tutorials/latency/","page":"Latency","title":"Latency","text":"So to recap, MathOptInterface suffers package latency because:","category":"page"},{"location":"tutorials/latency/","page":"Latency","title":"Latency","text":"there are a large number of types and functions\nand these are split between multiple modules, including external packages\nand there are type-instabilities like those in the bridging layer.","category":"page"},{"location":"tutorials/latency/#Resolutions","page":"Latency","title":"Resolutions","text":"","category":"section"},{"location":"tutorials/latency/","page":"Latency","title":"Latency","text":"There are no magic solutions to reduce latency. Issue #1313 tracks progress on reducing latency in MathOptInterface.","category":"page"},{"location":"tutorials/latency/","page":"Latency","title":"Latency","text":"A useful script is the following (replace GLPK as needed):","category":"page"},{"location":"tutorials/latency/","page":"Latency","title":"Latency","text":"import GLPK\nimport MathOptInterface as MOI\n\nfunction example_diet(optimizer, bridge)\n category_data = [\n 1800.0 2200.0;\n 91.0 Inf;\n 0.0 65.0;\n 0.0 1779.0\n ]\n cost = [2.49, 2.89, 1.50, 1.89, 2.09, 1.99, 2.49, 0.89, 1.59]\n food_data = [\n 410 24 26 730;\n 420 32 10 1190;\n 560 20 32 1800;\n 380 4 19 270;\n 320 12 10 930;\n 320 15 12 820;\n 320 31 12 1230;\n 100 8 2.5 125;\n 330 8 10 180\n ]\n bridge_model = if bridge\n MOI.instantiate(optimizer; with_bridge_type=Float64)\n else\n MOI.instantiate(optimizer)\n end\n model = MOI.Utilities.CachingOptimizer(\n MOI.Utilities.UniversalFallback(MOI.Utilities.Model{Float64}()),\n MOI.Utilities.AUTOMATIC,\n )\n MOI.Utilities.reset_optimizer(model, bridge_model)\n MOI.set(model, MOI.Silent(), true)\n nutrition = MOI.add_variables(model, size(category_data, 1))\n for (i, v) in enumerate(nutrition)\n MOI.add_constraint(model, v, MOI.GreaterThan(category_data[i, 1]))\n MOI.add_constraint(model, v, MOI.LessThan(category_data[i, 2]))\n end\n buy = MOI.add_variables(model, size(food_data, 1))\n MOI.add_constraint.(model, buy, MOI.GreaterThan(0.0))\n MOI.set(model, MOI.ObjectiveSense(), MOI.MIN_SENSE)\n f = MOI.ScalarAffineFunction(MOI.ScalarAffineTerm.(cost, buy), 0.0)\n MOI.set(model, MOI.ObjectiveFunction{typeof(f)}(), f)\n for (j, n) in enumerate(nutrition)\n f = MOI.ScalarAffineFunction(\n MOI.ScalarAffineTerm.(food_data[:, j], buy),\n 0.0,\n )\n push!(f.terms, MOI.ScalarAffineTerm(-1.0, n))\n MOI.add_constraint(model, f, MOI.EqualTo(0.0))\n end\n MOI.optimize!(model)\n term_status = MOI.get(model, MOI.TerminationStatus())\n @assert term_status == MOI.OPTIMAL\n MOI.add_constraint(\n model,\n MOI.ScalarAffineFunction(\n MOI.ScalarAffineTerm.(1.0, [buy[end-1], buy[end]]),\n 0.0,\n ),\n MOI.LessThan(6.0),\n )\n MOI.optimize!(model)\n @assert MOI.get(model, MOI.TerminationStatus()) == MOI.INFEASIBLE\n return\nend\n\nif length(ARGS) > 0\n bridge = get(ARGS, 2, \"\") != \"--no-bridge\"\n println(\"Running: $(ARGS[1]) $(get(ARGS, 2, \"\"))\")\n @time example_diet(GLPK.Optimizer, bridge)\n @time example_diet(GLPK.Optimizer, bridge)\n exit(0)\nend","category":"page"},{"location":"tutorials/latency/","page":"Latency","title":"Latency","text":"You can create a flame-graph via","category":"page"},{"location":"tutorials/latency/","page":"Latency","title":"Latency","text":"using SnoopComile\ntinf = @snoopi_deep example_diet(GLPK.Optimizer, true)\nusing ProfileView\nProfileView.view(flamegraph(tinf))","category":"page"},{"location":"tutorials/latency/","page":"Latency","title":"Latency","text":"Here's how things looked in mid-August 2021: (Image: flamegraph)","category":"page"},{"location":"tutorials/latency/","page":"Latency","title":"Latency","text":"There are a few opportunities for improvement (non-red flames, particularly on the right). But the main problem is a large red (non-precompilable due to method ownership) flame.","category":"page"},{"location":"tutorials/manipulating_expressions/","page":"Manipulating expressions","title":"Manipulating expressions","text":"CurrentModule = MathOptInterface\nDocTestSetup = quote\n import MathOptInterface as MOI\nend\nDocTestFilters = [r\"MathOptInterface|MOI\"]","category":"page"},{"location":"tutorials/manipulating_expressions/#Manipulating-expressions","page":"Manipulating expressions","title":"Manipulating expressions","text":"","category":"section"},{"location":"tutorials/manipulating_expressions/","page":"Manipulating expressions","title":"Manipulating expressions","text":"This guide highlights a syntactically appealing way to build expressions at the MOI level, but also to look at their contents. It may be especially useful when writing models or bridge code.","category":"page"},{"location":"tutorials/manipulating_expressions/#Creating-functions","page":"Manipulating expressions","title":"Creating functions","text":"","category":"section"},{"location":"tutorials/manipulating_expressions/","page":"Manipulating expressions","title":"Manipulating expressions","text":"This section details the ways to create functions with MathOptInterface.","category":"page"},{"location":"tutorials/manipulating_expressions/#Creating-scalar-affine-functions","page":"Manipulating expressions","title":"Creating scalar affine functions","text":"","category":"section"},{"location":"tutorials/manipulating_expressions/","page":"Manipulating expressions","title":"Manipulating expressions","text":"The simplest scalar function is simply a variable:","category":"page"},{"location":"tutorials/manipulating_expressions/","page":"Manipulating expressions","title":"Manipulating expressions","text":"julia> x = MOI.add_variable(model) # Create the variable x\nMOI.VariableIndex(1)","category":"page"},{"location":"tutorials/manipulating_expressions/","page":"Manipulating expressions","title":"Manipulating expressions","text":"This type of function is extremely simple; to express more complex functions, other types must be used. For instance, a ScalarAffineFunction is a sum of linear terms (a factor times a variable) and a constant. Such an object can be built using the standard constructor:","category":"page"},{"location":"tutorials/manipulating_expressions/","page":"Manipulating expressions","title":"Manipulating expressions","text":"julia> f = MOI.ScalarAffineFunction([MOI.ScalarAffineTerm(1, x)], 2) # x + 2\n(2) + (1) MOI.VariableIndex(1)","category":"page"},{"location":"tutorials/manipulating_expressions/","page":"Manipulating expressions","title":"Manipulating expressions","text":"However, you can also use operators to build the same scalar function:","category":"page"},{"location":"tutorials/manipulating_expressions/","page":"Manipulating expressions","title":"Manipulating expressions","text":"julia> f = x + 2\n(2) + (1) MOI.VariableIndex(1)","category":"page"},{"location":"tutorials/manipulating_expressions/#Creating-scalar-quadratic-functions","page":"Manipulating expressions","title":"Creating scalar quadratic functions","text":"","category":"section"},{"location":"tutorials/manipulating_expressions/","page":"Manipulating expressions","title":"Manipulating expressions","text":"Scalar quadratic functions are stored in ScalarQuadraticFunction objects, in a way that is highly similar to scalar affine functions. You can obtain a quadratic function as a product of affine functions:","category":"page"},{"location":"tutorials/manipulating_expressions/","page":"Manipulating expressions","title":"Manipulating expressions","text":"julia> 1 * x * x\n(0) + 1.0 MOI.VariableIndex(1)²\n\njulia> f * f # (x + 2)²\n(4) + (2) MOI.VariableIndex(1) + (2) MOI.VariableIndex(1) + 1.0 MOI.VariableIndex(1)²\n\njulia> f^2 # (x + 2)² too\n(4) + (2) MOI.VariableIndex(1) + (2) MOI.VariableIndex(1) + 1.0 MOI.VariableIndex(1)²","category":"page"},{"location":"tutorials/manipulating_expressions/#Creating-vector-functions","page":"Manipulating expressions","title":"Creating vector functions","text":"","category":"section"},{"location":"tutorials/manipulating_expressions/","page":"Manipulating expressions","title":"Manipulating expressions","text":"A vector function is a function with several values, irrespective of the number of input variables. Similarly to scalar functions, there are three main types of vector functions: VectorOfVariables, VectorAffineFunction, and VectorQuadraticFunction.","category":"page"},{"location":"tutorials/manipulating_expressions/","page":"Manipulating expressions","title":"Manipulating expressions","text":"The easiest way to create a vector function is to stack several scalar functions using Utilities.vectorize. It takes a vector as input, and the generated vector function (of the most appropriate type) has each dimension corresponding to a dimension of the vector.","category":"page"},{"location":"tutorials/manipulating_expressions/","page":"Manipulating expressions","title":"Manipulating expressions","text":"julia> g = MOI.Utilities.vectorize([f, 2 * f])\n┌ ┐\n│(2) + (1) MOI.VariableIndex(1)│\n│(4) + (2) MOI.VariableIndex(1)│\n└ ┘","category":"page"},{"location":"tutorials/manipulating_expressions/","page":"Manipulating expressions","title":"Manipulating expressions","text":"warning: Warning\nUtilities.vectorize only takes a vector of similar scalar functions: you cannot mix VariableIndex and ScalarAffineFunction, for instance. In practice, it means that Utilities.vectorize([x, f]) does not work; you should rather use Utilities.vectorize([1 * x, f]) instead to only have ScalarAffineFunction objects.","category":"page"},{"location":"tutorials/manipulating_expressions/#Canonicalizing-functions","page":"Manipulating expressions","title":"Canonicalizing functions","text":"","category":"section"},{"location":"tutorials/manipulating_expressions/","page":"Manipulating expressions","title":"Manipulating expressions","text":"In more advanced use cases, you might need to ensure that a function is \"canonical.\" Functions are stored as an array of terms, but there is no check that these terms are redundant: a ScalarAffineFunction object might have two terms with the same variable, like x + x + 1. These terms could be merged without changing the semantics of the function: 2x + 1.","category":"page"},{"location":"tutorials/manipulating_expressions/","page":"Manipulating expressions","title":"Manipulating expressions","text":"Working with these objects might be cumbersome. Canonicalization helps maintain redundancy to zero.","category":"page"},{"location":"tutorials/manipulating_expressions/","page":"Manipulating expressions","title":"Manipulating expressions","text":"Utilities.is_canonical checks whether a function is already in its canonical form:","category":"page"},{"location":"tutorials/manipulating_expressions/","page":"Manipulating expressions","title":"Manipulating expressions","text":"julia> MOI.Utilities.is_canonical(f + f) # (x + 2) + (x + 2) is stored as x + x + 4\nfalse","category":"page"},{"location":"tutorials/manipulating_expressions/","page":"Manipulating expressions","title":"Manipulating expressions","text":"Utilities.canonical returns the equivalent canonical version of the function:","category":"page"},{"location":"tutorials/manipulating_expressions/","page":"Manipulating expressions","title":"Manipulating expressions","text":"julia> MOI.Utilities.canonical(f + f) # Returns 2x + 4\n(4) + (2) MOI.VariableIndex(1)","category":"page"},{"location":"tutorials/manipulating_expressions/#Exploring-functions","page":"Manipulating expressions","title":"Exploring functions","text":"","category":"section"},{"location":"tutorials/manipulating_expressions/","page":"Manipulating expressions","title":"Manipulating expressions","text":"At some point, you might need to dig into a function, for instance to map it into solver constructs.","category":"page"},{"location":"tutorials/manipulating_expressions/#Vector-functions","page":"Manipulating expressions","title":"Vector functions","text":"","category":"section"},{"location":"tutorials/manipulating_expressions/","page":"Manipulating expressions","title":"Manipulating expressions","text":"Utilities.scalarize returns a vector of scalar functions from a vector function:","category":"page"},{"location":"tutorials/manipulating_expressions/","page":"Manipulating expressions","title":"Manipulating expressions","text":"julia> MOI.Utilities.scalarize(g) # Returns a vector [f, 2 * f].\n2-element Vector{MathOptInterface.ScalarAffineFunction{Int64}}:\n (2) + (1) MOI.VariableIndex(1)\n (4) + (2) MOI.VariableIndex(1)","category":"page"},{"location":"tutorials/manipulating_expressions/","page":"Manipulating expressions","title":"Manipulating expressions","text":"note: Note\nUtilities.eachscalar returns an iterator on the dimensions, which serves the same purpose as Utilities.scalarize.","category":"page"},{"location":"tutorials/manipulating_expressions/","page":"Manipulating expressions","title":"Manipulating expressions","text":"output_dimension returns the number of dimensions of the output of a function:","category":"page"},{"location":"tutorials/manipulating_expressions/","page":"Manipulating expressions","title":"Manipulating expressions","text":"julia> MOI.output_dimension(g)\n2","category":"page"},{"location":"manual/solutions/","page":"Solutions","title":"Solutions","text":"CurrentModule = MathOptInterface\nDocTestSetup = quote\n import MathOptInterface as MOI\nend\nDocTestFilters = [r\"MathOptInterface|MOI\"]","category":"page"},{"location":"manual/solutions/#manual_solutions","page":"Solutions","title":"Solutions","text":"","category":"section"},{"location":"manual/solutions/#Solving-and-retrieving-the-results","page":"Solutions","title":"Solving and retrieving the results","text":"","category":"section"},{"location":"manual/solutions/","page":"Solutions","title":"Solutions","text":"Once an optimizer is loaded with the objective function and all of the constraints, we can ask the solver to solve the model by calling optimize!.","category":"page"},{"location":"manual/solutions/","page":"Solutions","title":"Solutions","text":"MOI.optimize!(optimizer)","category":"page"},{"location":"manual/solutions/#Why-did-the-solver-stop?","page":"Solutions","title":"Why did the solver stop?","text":"","category":"section"},{"location":"manual/solutions/","page":"Solutions","title":"Solutions","text":"The optimization procedure may stop for a number of reasons. The TerminationStatus attribute of the optimizer returns a TerminationStatusCode object which explains why the solver stopped.","category":"page"},{"location":"manual/solutions/","page":"Solutions","title":"Solutions","text":"The termination statuses distinguish between proofs of optimality, infeasibility, local convergence, limits, and termination because of something unexpected like invalid problem data or failure to converge.","category":"page"},{"location":"manual/solutions/","page":"Solutions","title":"Solutions","text":"A typical usage of the TerminationStatus attribute is as follows:","category":"page"},{"location":"manual/solutions/","page":"Solutions","title":"Solutions","text":"status = MOI.get(optimizer, TerminationStatus())\nif status == MOI.OPTIMAL\n # Ok, we solved the problem!\nelse\n # Handle other cases.\nend","category":"page"},{"location":"manual/solutions/","page":"Solutions","title":"Solutions","text":"After checking the TerminationStatus, check ResultCount. This attribute returns the number of results that the solver has available to return. A result is defined as a primal-dual pair, but either the primal or the dual may be missing from the result. While the OPTIMAL termination status normally implies that at least one result is available, other statuses do not. For example, in the case of infeasibility, a solver may return no result or a proof of infeasibility. The ResultCount attribute distinguishes between these two cases.","category":"page"},{"location":"manual/solutions/#Primal-solutions","page":"Solutions","title":"Primal solutions","text":"","category":"section"},{"location":"manual/solutions/","page":"Solutions","title":"Solutions","text":"Use the PrimalStatus optimizer attribute to return a ResultStatusCode describing the status of the primal solution.","category":"page"},{"location":"manual/solutions/","page":"Solutions","title":"Solutions","text":"Common returns are described below in the Common status situations section.","category":"page"},{"location":"manual/solutions/","page":"Solutions","title":"Solutions","text":"Query the primal solution using the VariablePrimal and ConstraintPrimal attributes.","category":"page"},{"location":"manual/solutions/","page":"Solutions","title":"Solutions","text":"Query the objective function value using the ObjectiveValue attribute.","category":"page"},{"location":"manual/solutions/#Dual-solutions","page":"Solutions","title":"Dual solutions","text":"","category":"section"},{"location":"manual/solutions/","page":"Solutions","title":"Solutions","text":"warning: Warning\nSee Duality for a discussion of the MOI conventions for primal-dual pairs and certificates.","category":"page"},{"location":"manual/solutions/","page":"Solutions","title":"Solutions","text":"Use the DualStatus optimizer attribute to return a ResultStatusCode describing the status of the dual solution.","category":"page"},{"location":"manual/solutions/","page":"Solutions","title":"Solutions","text":"Query the dual solution using the ConstraintDual attribute.","category":"page"},{"location":"manual/solutions/","page":"Solutions","title":"Solutions","text":"Query the dual objective function value using the DualObjectiveValue attribute.","category":"page"},{"location":"manual/solutions/#Common-status-situations","page":"Solutions","title":"Common status situations","text":"","category":"section"},{"location":"manual/solutions/","page":"Solutions","title":"Solutions","text":"The sections below describe how to interpret typical or interesting status cases for three common classes of solvers. The example cases are illustrative, not comprehensive. Solver wrappers may provide additional information on how the solver's statuses map to MOI statuses.","category":"page"},{"location":"manual/solutions/","page":"Solutions","title":"Solutions","text":"info: Info\n* in the tables indicate that multiple different values are possible.","category":"page"},{"location":"manual/solutions/#Primal-dual-convex-solver","page":"Solutions","title":"Primal-dual convex solver","text":"","category":"section"},{"location":"manual/solutions/","page":"Solutions","title":"Solutions","text":"Linear programming and conic optimization solvers fall into this category.","category":"page"},{"location":"manual/solutions/","page":"Solutions","title":"Solutions","text":"What happened? TerminationStatus ResultCount PrimalStatus DualStatus\nProved optimality OPTIMAL 1 FEASIBLE_POINT FEASIBLE_POINT\nProved infeasible INFEASIBLE 1 NO_SOLUTION INFEASIBILITY_CERTIFICATE\nOptimal within relaxed tolerances ALMOST_OPTIMAL 1 FEASIBLE_POINT FEASIBLE_POINT\nOptimal within relaxed tolerances ALMOST_OPTIMAL 1 ALMOST_FEASIBLE_POINT ALMOST_FEASIBLE_POINT\nDetected an unbounded ray of the primal DUAL_INFEASIBLE 1 INFEASIBILITY_CERTIFICATE NO_SOLUTION\nStall SLOW_PROGRESS 1 * *","category":"page"},{"location":"manual/solutions/#Global-branch-and-bound-solvers","page":"Solutions","title":"Global branch-and-bound solvers","text":"","category":"section"},{"location":"manual/solutions/","page":"Solutions","title":"Solutions","text":"Mixed-integer programming solvers fall into this category.","category":"page"},{"location":"manual/solutions/","page":"Solutions","title":"Solutions","text":"What happened? TerminationStatus ResultCount PrimalStatus DualStatus\nProved optimality OPTIMAL 1 FEASIBLE_POINT NO_SOLUTION\nPresolve detected infeasibility or unboundedness INFEASIBLE_OR_UNBOUNDED 0 NO_SOLUTION NO_SOLUTION\nProved infeasibility INFEASIBLE 0 NO_SOLUTION NO_SOLUTION\nTimed out (no solution) TIME_LIMIT 0 NO_SOLUTION NO_SOLUTION\nTimed out (with a solution) TIME_LIMIT 1 FEASIBLE_POINT NO_SOLUTION\nCPXMIP_OPTIMAL_INFEAS ALMOST_OPTIMAL 1 INFEASIBLE_POINT NO_SOLUTION","category":"page"},{"location":"manual/solutions/","page":"Solutions","title":"Solutions","text":"info: Info\nCPXMIP_OPTIMAL_INFEAS is a CPLEX status that indicates that a preprocessed problem was solved to optimality, but the solver was unable to recover a feasible solution to the original problem. Handling this status was one of the motivating drivers behind the design of MOI.","category":"page"},{"location":"manual/solutions/#Local-search-solvers","page":"Solutions","title":"Local search solvers","text":"","category":"section"},{"location":"manual/solutions/","page":"Solutions","title":"Solutions","text":"Nonlinear programming solvers fall into this category. It also includes non-global tree search solvers like Juniper.","category":"page"},{"location":"manual/solutions/","page":"Solutions","title":"Solutions","text":"What happened? TerminationStatus ResultCount PrimalStatus DualStatus\nConverged to a stationary point LOCALLY_SOLVED 1 FEASIBLE_POINT FEASIBLE_POINT\nCompleted a non-global tree search (with a solution) LOCALLY_SOLVED 1 FEASIBLE_POINT FEASIBLE_POINT\nConverged to an infeasible point LOCALLY_INFEASIBLE 1 INFEASIBLE_POINT *\nCompleted a non-global tree search (no solution found) LOCALLY_INFEASIBLE 0 NO_SOLUTION NO_SOLUTION\nIteration limit ITERATION_LIMIT 1 * *\nDiverging iterates NORM_LIMIT or OBJECTIVE_LIMIT 1 * *","category":"page"},{"location":"manual/solutions/#Querying-solution-attributes","page":"Solutions","title":"Querying solution attributes","text":"","category":"section"},{"location":"manual/solutions/","page":"Solutions","title":"Solutions","text":"Some solvers will not implement every solution attribute. Therefore, a call like MOI.get(model, MOI.SolveTimeSec()) may throw an UnsupportedAttribute error.","category":"page"},{"location":"manual/solutions/","page":"Solutions","title":"Solutions","text":"If you need to write code that is agnostic to the solver (for example, you are writing a library that an end-user passes their choice of solver to), you can work-around this problem using a try-catch:","category":"page"},{"location":"manual/solutions/","page":"Solutions","title":"Solutions","text":"function get_solve_time(model)\n try\n return MOI.get(model, MOI.SolveTimeSec())\n catch err\n if err isa MOI.UnsupportedAttribute\n return NaN # Solver doesn't support. Return a placeholder value.\n end\n rethrow(err) # Something else went wrong. Rethrow the error\n end\nend","category":"page"},{"location":"manual/solutions/","page":"Solutions","title":"Solutions","text":"If, after careful profiling, you find that the try-catch is taking a significant portion of your runtime, you can improve performance by caching the result of the try-catch:","category":"page"},{"location":"manual/solutions/","page":"Solutions","title":"Solutions","text":"mutable struct CachedSolveTime{M}\n model::M\n supports_solve_time::Bool\n CachedSolveTime(model::M) where {M} = new(model, true)\nend\n\nfunction get_solve_time(model::CachedSolveTime)\n if !model.supports_solve_time\n return NaN\n end\n try\n return MOI.get(model, MOI.SolveTimeSec())\n catch err\n if err isa MOI.UnsupportedAttribute\n model.supports_solve_time = false\n return NaN\n end\n rethrow(err) # Something else went wrong. Rethrow the error\n end\nend","category":"page"},{"location":"submodules/Bridges/reference/","page":"API Reference","title":"API Reference","text":"CurrentModule = MathOptInterface\nDocTestSetup = quote\n import MathOptInterface as MOI\nend\nDocTestFilters = [r\"MathOptInterface|MOI\"]","category":"page"},{"location":"submodules/Bridges/reference/#Bridges","page":"API Reference","title":"Bridges","text":"","category":"section"},{"location":"submodules/Bridges/reference/#AbstractBridge-API","page":"API Reference","title":"AbstractBridge API","text":"","category":"section"},{"location":"submodules/Bridges/reference/","page":"API Reference","title":"API Reference","text":"Bridges.AbstractBridge\nBridges.added_constrained_variable_types\nBridges.added_constraint_types\nget(::Bridges.AbstractBridge, ::NumberOfVariables)\nget(::Bridges.AbstractBridge, ::ListOfVariableIndices)\nget(::Bridges.AbstractBridge, ::NumberOfConstraints)\nget(::Bridges.AbstractBridge, ::ListOfConstraintIndices)\nBridges.needs_final_touch\nBridges.final_touch\nBridges.bridging_cost","category":"page"},{"location":"submodules/Bridges/reference/#MathOptInterface.Bridges.AbstractBridge","page":"API Reference","title":"MathOptInterface.Bridges.AbstractBridge","text":"abstract type AbstractBridge end\n\nAn abstract type representing a bridged constraint or variable in a MOI.Bridges.AbstractBridgeOptimizer.\n\nAll bridges must implement:\n\nadded_constrained_variable_types\nadded_constraint_types\nMOI.get(::AbstractBridge, ::MOI.NumberOfVariables)\nMOI.get(::AbstractBridge, ::MOI.ListOfVariableIndices)\nMOI.get(::AbstractBridge, ::MOI.NumberOfConstraints)\nMOI.get(::AbstractBridge, ::MOI.ListOfConstraintIndices)\n\nSubtypes of AbstractBridge may have additional requirements. Consult their docstrings for details.\n\nIn addition, all subtypes may optionally implement the following constraint attributes with the bridge in place of the constraint index:\n\nMOI.ConstraintDual\nMOI.ConstraintPrimal\n\n\n\n\n\n","category":"type"},{"location":"submodules/Bridges/reference/#MathOptInterface.Bridges.added_constrained_variable_types","page":"API Reference","title":"MathOptInterface.Bridges.added_constrained_variable_types","text":"added_constrained_variable_types(\n BT::Type{<:AbstractBridge},\n)::Vector{Tuple{Type}}\n\nReturn a list of the types of constrained variables that bridges of concrete type BT add.\n\nImplementation notes\n\nThis method depends only on the type of the bridge, not the runtime value. If the bridge may add a constrained variable, the type must be included in the return vector.\nIf the bridge adds a free variable via MOI.add_variable or MOI.add_variables, the return vector must include (MOI.Reals,).\n\nExample\n\njulia> MOI.Bridges.added_constrained_variable_types(\n MOI.Bridges.Variable.NonposToNonnegBridge{Float64},\n )\n1-element Vector{Tuple{Type}}:\n (MathOptInterface.Nonnegatives,)\n\n\n\n\n\n","category":"function"},{"location":"submodules/Bridges/reference/#MathOptInterface.Bridges.added_constraint_types","page":"API Reference","title":"MathOptInterface.Bridges.added_constraint_types","text":"added_constraint_types(\n BT::Type{<:AbstractBridge},\n)::Vector{Tuple{Type,Type}}\n\nReturn a list of the types of constraints that bridges of concrete type BT add.\n\nImplementation notes\n\nThis method depends only on the type of the bridge, not the runtime value. If the bridge may add a constraint, the type must be included in the return vector.\n\nExample\n\njulia> MOI.Bridges.added_constraint_types(\n MOI.Bridges.Constraint.ZeroOneBridge{Float64},\n )\n2-element Vector{Tuple{Type, Type}}:\n (MathOptInterface.ScalarAffineFunction{Float64}, MathOptInterface.Interval{Float64})\n (MathOptInterface.VariableIndex, MathOptInterface.Integer)\n\n\n\n\n\n","category":"function"},{"location":"submodules/Bridges/reference/#MathOptInterface.get-Tuple{MathOptInterface.Bridges.AbstractBridge, MathOptInterface.NumberOfVariables}","page":"API Reference","title":"MathOptInterface.get","text":"MOI.get(b::AbstractBridge, ::MOI.NumberOfVariables)::Int64\n\nReturn the number of variables created by the bridge b in the model.\n\nSee also MOI.NumberOfConstraints.\n\nImplementation notes\n\nThere is a default fallback, so you need only implement this if the bridge adds new variables.\n\n\n\n\n\n","category":"method"},{"location":"submodules/Bridges/reference/#MathOptInterface.get-Tuple{MathOptInterface.Bridges.AbstractBridge, MathOptInterface.ListOfVariableIndices}","page":"API Reference","title":"MathOptInterface.get","text":"MOI.get(b::AbstractBridge, ::MOI.ListOfVariableIndices)\n\nReturn the list of variables created by the bridge b.\n\nSee also MOI.ListOfVariableIndices.\n\nImplementation notes\n\nThere is a default fallback, so you need only implement this if the bridge adds new variables.\n\n\n\n\n\n","category":"method"},{"location":"submodules/Bridges/reference/#MathOptInterface.get-Tuple{MathOptInterface.Bridges.AbstractBridge, MathOptInterface.NumberOfConstraints}","page":"API Reference","title":"MathOptInterface.get","text":"MOI.get(b::AbstractBridge, ::MOI.NumberOfConstraints{F,S})::Int64 where {F,S}\n\nReturn the number of constraints of the type F-in-S created by the bridge b.\n\nSee also MOI.NumberOfConstraints.\n\nImplementation notes\n\nThere is a default fallback, so you need only implement this for the constraint types returned by added_constraint_types.\n\n\n\n\n\n","category":"method"},{"location":"submodules/Bridges/reference/#MathOptInterface.get-Tuple{MathOptInterface.Bridges.AbstractBridge, MathOptInterface.ListOfConstraintIndices}","page":"API Reference","title":"MathOptInterface.get","text":"MOI.get(b::AbstractBridge, ::MOI.ListOfConstraintIndices{F,S}) where {F,S}\n\nReturn a Vector{ConstraintIndex{F,S}} with indices of all constraints of type F-in-S created by the bride b.\n\nSee also MOI.ListOfConstraintIndices.\n\nImplementation notes\n\nThere is a default fallback, so you need only implement this for the constraint types returned by added_constraint_types.\n\n\n\n\n\n","category":"method"},{"location":"submodules/Bridges/reference/#MathOptInterface.Bridges.needs_final_touch","page":"API Reference","title":"MathOptInterface.Bridges.needs_final_touch","text":"needs_final_touch(bridge::AbstractBridge)::Bool\n\nReturn whether final_touch is implemented by bridge.\n\n\n\n\n\n","category":"function"},{"location":"submodules/Bridges/reference/#MathOptInterface.Bridges.final_touch","page":"API Reference","title":"MathOptInterface.Bridges.final_touch","text":"final_touch(bridge::AbstractBridge, model::MOI.ModelLike)::Nothing\n\nA function that is called immediately prior to MOI.optimize! to allow bridges to modify their reformulations with repsect to other variables and constraints in model.\n\nFor example, if the correctness of bridge depends on the bounds of a variable or the fact that variables are integer, then the bridge can implement final_touch to check assumptions immediately before a call to MOI.optimize!.\n\nIf you implement this method, you must also implement needs_final_touch.\n\n\n\n\n\n","category":"function"},{"location":"submodules/Bridges/reference/#MathOptInterface.Bridges.bridging_cost","page":"API Reference","title":"MathOptInterface.Bridges.bridging_cost","text":"bridging_cost(b::AbstractBridgeOptimizer, S::Type{<:MOI.AbstractSet}})\n\nReturn the cost of bridging variables constrained in S on creation, is_bridged(b, S) is assumed to be true.\n\nbridging_cost(\n b::AbstractBridgeOptimizer,\n F::Type{<:MOI.AbstractFunction},\n S::Type{<:MOI.AbstractSet},\n)\n\nReturn the cost of bridging F-in-S constraints.\n\nis_bridged(b, S) is assumed to be true.\n\n\n\n\n\n","category":"function"},{"location":"submodules/Bridges/reference/#Constraint-bridge-API","page":"API Reference","title":"Constraint bridge API","text":"","category":"section"},{"location":"submodules/Bridges/reference/","page":"API Reference","title":"API Reference","text":"Bridges.Constraint.AbstractBridge\nsupports_constraint(::Type{<:Bridges.Constraint.AbstractBridge}, ::Type{<:AbstractFunction}, ::Type{<:AbstractSet})\nBridges.Constraint.concrete_bridge_type\nBridges.Constraint.bridge_constraint\nBridges.Constraint.AbstractFunctionConversionBridge\nBridges.Constraint.SingleBridgeOptimizer\nBridges.Constraint.add_all_bridges\nBridges.Constraint.FlipSignBridge\nBridges.Constraint.AbstractToIntervalBridge\nBridges.Constraint.SetMapBridge\nBridges.Constraint.conversion_cost","category":"page"},{"location":"submodules/Bridges/reference/#MathOptInterface.Bridges.Constraint.AbstractBridge","page":"API Reference","title":"MathOptInterface.Bridges.Constraint.AbstractBridge","text":"abstract type AbstractBridge <: MOI.Bridges.AbstractType\n\nSubtype of MOI.Bridges.AbstractBridge for constraint bridges.\n\nIn addition to the required implementation described in MOI.Bridges.AbstractBridge, subtypes of AbstractBridge must additionally implement:\n\nMOI.supports_constraint(::Type{<:AbstractBridge}, ::Type{<:MOI.AbstractFunction}, ::Type{<:MOI.AbstractSet})\nconcrete_bridge_type\nbridge_constraint\n\n\n\n\n\n","category":"type"},{"location":"submodules/Bridges/reference/#MathOptInterface.supports_constraint-Tuple{Type{<:MathOptInterface.Bridges.Constraint.AbstractBridge}, Type{<:MathOptInterface.AbstractFunction}, Type{<:MathOptInterface.AbstractSet}}","page":"API Reference","title":"MathOptInterface.supports_constraint","text":"MOI.supports_constraint(\n BT::Type{<:AbstractBridge},\n F::Type{<:MOI.AbstractFunction},\n S::Type{<:MOI.AbstractSet},\n)::Bool\n\nReturn a Bool indicating whether the bridges of type BT support bridging F-in-S constraints.\n\nImplementation notes\n\nThis method depends only on the type of the inputs, not the runtime values.\nThere is a default fallback, so you need only implement this method for constraint types that the bridge implements.\n\n\n\n\n\n","category":"method"},{"location":"submodules/Bridges/reference/#MathOptInterface.Bridges.Constraint.concrete_bridge_type","page":"API Reference","title":"MathOptInterface.Bridges.Constraint.concrete_bridge_type","text":"concrete_bridge_type(\n BT::Type{<:AbstractBridge},\n F::Type{<:MOI.AbstractFunction},\n S::Type{<:MOI.AbstractSet}\n)::Type\n\nReturn the concrete type of the bridge supporting F-in-S constraints.\n\nThis function can only be called if MOI.supports_constraint(BT, F, S) is true.\n\nExample\n\nThe SplitIntervalBridge bridges a MOI.VariableIndex-in-MOI.Interval constraint into a MOI.VariableIndex-in-MOI.GreaterThan and a MOI.VariableIndex-in-MOI.LessThan constraint.\n\njulia> MOI.Bridges.Constraint.concrete_bridge_type(\n MOI.Bridges.Constraint.SplitIntervalBridge{Float64},\n MOI.VariableIndex,\n MOI.Interval{Float64},\n )\nMathOptInterface.Bridges.Constraint.SplitIntervalBridge{Float64, MathOptInterface.VariableIndex, MathOptInterface.Interval{Float64}, MathOptInterface.GreaterThan{Float64}, MathOptInterface.LessThan{Float64}}\n\n\n\n\n\n","category":"function"},{"location":"submodules/Bridges/reference/#MathOptInterface.Bridges.Constraint.bridge_constraint","page":"API Reference","title":"MathOptInterface.Bridges.Constraint.bridge_constraint","text":"bridge_constraint(\n BT::Type{<:AbstractBridge},\n model::MOI.ModelLike,\n func::AbstractFunction,\n set::MOI.AbstractSet,\n)::BT\n\nBridge the constraint func-in-set using bridge BT to model and returns a bridge object of type BT.\n\nImplementation notes\n\nThe bridge type BT should be a concrete type, that is, all the type parameters of the bridge must be set.\n\n\n\n\n\n","category":"function"},{"location":"submodules/Bridges/reference/#MathOptInterface.Bridges.Constraint.AbstractFunctionConversionBridge","page":"API Reference","title":"MathOptInterface.Bridges.Constraint.AbstractFunctionConversionBridge","text":"abstract type AbstractFunctionConversionBridge{F,S} <: AbstractBridge end\n\nAbstract type to support writing bridges in which the function changes but the set does not.\n\nBy convention, the transformed function is stored in the .constraint field.\n\n\n\n\n\n","category":"type"},{"location":"submodules/Bridges/reference/#MathOptInterface.Bridges.Constraint.SingleBridgeOptimizer","page":"API Reference","title":"MathOptInterface.Bridges.Constraint.SingleBridgeOptimizer","text":"SingleBridgeOptimizer{BT<:AbstractBridge}(model::MOI.ModelLike)\n\nReturn AbstractBridgeOptimizer that always bridges any objective function supported by the bridge BT.\n\nThis is in contrast with the MOI.Bridges.LazyBridgeOptimizer, which only bridges the objective function if it is supported by the bridge BT and unsupported by model.\n\nExample\n\njulia> struct MyNewBridge{T} <: MOI.Bridges.Constraint.AbstractBridge end\n\njulia> bridge = MOI.Bridges.Constraint.SingleBridgeOptimizer{MyNewBridge{Float64}}(\n MOI.Utilities.Model{Float64}(),\n )\nMOIB.Constraint.SingleBridgeOptimizer{MyNewBridge{Float64}, MOIU.Model{Float64}}\nwith 0 constraint bridges\nwith inner model MOIU.Model{Float64}\n\nImplementation notes\n\nAll bridges should simplify the creation of SingleBridgeOptimizers by defining a constant that wraps the bridge in a SingleBridgeOptimizer.\n\njulia> const MyNewBridgeModel{T,OT<:MOI.ModelLike} =\n MOI.Bridges.Constraint.SingleBridgeOptimizer{MyNewBridge{T},OT};\n\nThis enables users to create bridged models as follows:\n\njulia> MyNewBridgeModel{Float64}(MOI.Utilities.Model{Float64}())\nMOIB.Constraint.SingleBridgeOptimizer{MyNewBridge{Float64}, MOIU.Model{Float64}}\nwith 0 constraint bridges\nwith inner model MOIU.Model{Float64}\n\n\n\n\n\n","category":"type"},{"location":"submodules/Bridges/reference/#MathOptInterface.Bridges.Constraint.add_all_bridges","page":"API Reference","title":"MathOptInterface.Bridges.Constraint.add_all_bridges","text":"add_all_bridges(bridged_model, ::Type{T}) where {T}\n\nAdd all bridges defined in the Bridges.Constraint submodule to bridged_model. The coefficient type used is T.\n\n\n\n\n\n","category":"function"},{"location":"submodules/Bridges/reference/#MathOptInterface.Bridges.Constraint.FlipSignBridge","page":"API Reference","title":"MathOptInterface.Bridges.Constraint.FlipSignBridge","text":"FlipSignBridge{T,S1,S2,F,G}\n\nAn abstract type that simplifies the creation of other bridges.\n\n\n\n\n\n","category":"type"},{"location":"submodules/Bridges/reference/#MathOptInterface.Bridges.Constraint.AbstractToIntervalBridge","page":"API Reference","title":"MathOptInterface.Bridges.Constraint.AbstractToIntervalBridge","text":"AbstractToIntervalBridge{T<:AbstractFloat,S,F}\n\nAn abstract type that simplifies the creation of other bridges.\n\nwarning: Warning\nT must be a AbstractFloat type because otherwise typemin and typemax would either be not implemented (e.g. BigInt), or would not give infinite value (e.g. Int). For this reason, this bridge is only added to MOI.Bridges.full_bridge_optimizer when T is a subtype of AbstractFloat.\n\n\n\n\n\n","category":"type"},{"location":"submodules/Bridges/reference/#MathOptInterface.Bridges.Constraint.SetMapBridge","page":"API Reference","title":"MathOptInterface.Bridges.Constraint.SetMapBridge","text":"abstract type SetMapBridge{T,S2,S1,F,G} <: AbstractBridge end\n\nConsider two type of sets, S1 and S2, and a linear mapping A such that the image of a set of type S1 under A is a set of type S2.\n\nA SetMapBridge{T,S2,S1,F,G} is a bridge that maps G-in-S1 constraints into F-in-S2 by mapping the function through A.\n\nThe linear map A is described by;\n\nMOI.Bridges.map_set\nMOI.Bridges.map_function.\n\nImplementing a method for these two functions is sufficient to bridge constraints. However, in order for the getters and setters of attributes such as dual solutions and starting values to work as well, a method for the following functions must be implemented:\n\nMOI.Bridges.inverse_map_set\nMOI.Bridges.inverse_map_function\nMOI.Bridges.adjoint_map_function\nMOI.Bridges.inverse_adjoint_map_function\n\nSee the docstrings of each function to see which feature would be missing if it was not implemented for a given bridge.\n\n\n\n\n\n","category":"type"},{"location":"submodules/Bridges/reference/#MathOptInterface.Bridges.Constraint.conversion_cost","page":"API Reference","title":"MathOptInterface.Bridges.Constraint.conversion_cost","text":"conversion_cost(\n F::Type{<:MOI.AbstractFunction},\n G::Type{<:MOI.AbstractFunction},\n)::Float64\n\nReturn a Float64 returning the cost of converting any function of type G to a function of type F with convert.\n\nThis cost is used to compute MOI.Bridges.bridging_cost.\n\nThe default cost is Inf, which means that MOI.Bridges.Constraint.FunctionConversionBridge should not attempt the conversion.\n\n\n\n\n\n","category":"function"},{"location":"submodules/Bridges/reference/#Objective-bridge-API","page":"API Reference","title":"Objective bridge API","text":"","category":"section"},{"location":"submodules/Bridges/reference/","page":"API Reference","title":"API Reference","text":"Bridges.Objective.AbstractBridge\nBridges.Objective.supports_objective_function\nBridges.set_objective_function_type\nBridges.Objective.concrete_bridge_type\nBridges.Objective.bridge_objective\nBridges.Objective.SingleBridgeOptimizer\nBridges.Objective.add_all_bridges","category":"page"},{"location":"submodules/Bridges/reference/#MathOptInterface.Bridges.Objective.AbstractBridge","page":"API Reference","title":"MathOptInterface.Bridges.Objective.AbstractBridge","text":"abstract type AbstractBridge <: MOI.Bridges.AbstractBridge end\n\nSubtype of MOI.Bridges.AbstractBridge for objective bridges.\n\nIn addition to the required implementation described in MOI.Bridges.AbstractBridge, subtypes of AbstractBridge must additionally implement:\n\nsupports_objective_function\nconcrete_bridge_type\nbridge_objective\nMOI.Bridges.set_objective_function_type\n\n\n\n\n\n","category":"type"},{"location":"submodules/Bridges/reference/#MathOptInterface.Bridges.Objective.supports_objective_function","page":"API Reference","title":"MathOptInterface.Bridges.Objective.supports_objective_function","text":"supports_objective_function(\n BT::Type{<:MOI.Bridges.Objective.AbstractBridge},\n F::Type{<:MOI.AbstractFunction},\n)::Bool\n\nReturn a Bool indicating whether the bridges of type BT support bridging objective functions of type F.\n\nImplementation notes\n\nThis method depends only on the type of the inputs, not the runtime values.\nThere is a default fallback, so you need only implement this method For objective functions that the bridge implements.\n\n\n\n\n\n","category":"function"},{"location":"submodules/Bridges/reference/#MathOptInterface.Bridges.set_objective_function_type","page":"API Reference","title":"MathOptInterface.Bridges.set_objective_function_type","text":"set_objective_function_type(\n BT::Type{<:Objective.AbstractBridge},\n)::Type{<:MOI.AbstractFunction}\n\nReturn the type of objective function that bridges of concrete type BT set.\n\nImplementation notes\n\nThis method depends only on the type of the bridge, not the runtime value.\n\nExample\n\njulia> MOI.Bridges.set_objective_function_type(\n MOI.Bridges.Objective.FunctionizeBridge{Float64},\n )\nMathOptInterface.ScalarAffineFunction{Float64}\n\n\n\n\n\n","category":"function"},{"location":"submodules/Bridges/reference/#MathOptInterface.Bridges.Objective.concrete_bridge_type","page":"API Reference","title":"MathOptInterface.Bridges.Objective.concrete_bridge_type","text":"concrete_bridge_type(\n BT::Type{<:MOI.Bridges.Objective.AbstractBridge},\n F::Type{<:MOI.AbstractFunction},\n)::Type\n\nReturn the concrete type of the bridge supporting objective functions of type F.\n\nThis function can only be called if MOI.supports_objective_function(BT, F) is true.\n\n\n\n\n\n","category":"function"},{"location":"submodules/Bridges/reference/#MathOptInterface.Bridges.Objective.bridge_objective","page":"API Reference","title":"MathOptInterface.Bridges.Objective.bridge_objective","text":"bridge_objective(\n BT::Type{<:MOI.Bridges.Objective.AbstractBridge},\n model::MOI.ModelLike,\n func::MOI.AbstractFunction,\n)::BT\n\nBridge the objective function func using bridge BT to model and returns a bridge object of type BT.\n\nImplementation notes\n\nThe bridge type BT must be a concrete type, that is, all the type parameters of the bridge must be set.\n\n\n\n\n\n","category":"function"},{"location":"submodules/Bridges/reference/#MathOptInterface.Bridges.Objective.SingleBridgeOptimizer","page":"API Reference","title":"MathOptInterface.Bridges.Objective.SingleBridgeOptimizer","text":"SingleBridgeOptimizer{BT<:AbstractBridge}(model::MOI.ModelLike)\n\nReturn AbstractBridgeOptimizer that always bridges any objective function supported by the bridge BT.\n\nThis is in contrast with the MOI.Bridges.LazyBridgeOptimizer, which only bridges the objective function if it is supported by the bridge BT and unsupported by model.\n\nExample\n\njulia> struct MyNewBridge{T} <: MOI.Bridges.Objective.AbstractBridge end\n\njulia> bridge = MOI.Bridges.Objective.SingleBridgeOptimizer{MyNewBridge{Float64}}(\n MOI.Utilities.Model{Float64}(),\n )\nMOIB.Objective.SingleBridgeOptimizer{MyNewBridge{Float64}, MOIU.Model{Float64}}\nwith 0 objective bridges\nwith inner model MOIU.Model{Float64}\n\nImplementation notes\n\nAll bridges should simplify the creation of SingleBridgeOptimizers by defining a constant that wraps the bridge in a SingleBridgeOptimizer.\n\njulia> const MyNewBridgeModel{T,OT<:MOI.ModelLike} =\n MOI.Bridges.Objective.SingleBridgeOptimizer{MyNewBridge{T},OT};\n\nThis enables users to create bridged models as follows:\n\njulia> MyNewBridgeModel{Float64}(MOI.Utilities.Model{Float64}())\nMOIB.Objective.SingleBridgeOptimizer{MyNewBridge{Float64}, MOIU.Model{Float64}}\nwith 0 objective bridges\nwith inner model MOIU.Model{Float64}\n\n\n\n\n\n","category":"type"},{"location":"submodules/Bridges/reference/#MathOptInterface.Bridges.Objective.add_all_bridges","page":"API Reference","title":"MathOptInterface.Bridges.Objective.add_all_bridges","text":"add_all_bridges(model, ::Type{T}) where {T}\n\nAdd all bridges defined in the Bridges.Objective submodule to model.\n\nThe coefficient type used is T.\n\n\n\n\n\n","category":"function"},{"location":"submodules/Bridges/reference/#ref_variable_bridges","page":"API Reference","title":"Variable bridge API","text":"","category":"section"},{"location":"submodules/Bridges/reference/","page":"API Reference","title":"API Reference","text":"Bridges.Variable.AbstractBridge\nBridges.Variable.supports_constrained_variable\nBridges.Variable.concrete_bridge_type\nBridges.Variable.bridge_constrained_variable\nBridges.Variable.SingleBridgeOptimizer\nBridges.Variable.add_all_bridges\nBridges.Variable.FlipSignBridge\nBridges.Variable.SetMapBridge\nBridges.Variable.unbridged_map","category":"page"},{"location":"submodules/Bridges/reference/#MathOptInterface.Bridges.Variable.AbstractBridge","page":"API Reference","title":"MathOptInterface.Bridges.Variable.AbstractBridge","text":"abstract type AbstractBridge <: MOI.Bridges.AbstractBridge end\n\nSubtype of MOI.Bridges.AbstractBridge for variable bridges.\n\nIn addition to the required implementation described in MOI.Bridges.AbstractBridge, subtypes of AbstractBridge must additionally implement:\n\nsupports_constrained_variable\nconcrete_bridge_type\nbridge_constrained_variable\n\n\n\n\n\n","category":"type"},{"location":"submodules/Bridges/reference/#MathOptInterface.Bridges.Variable.supports_constrained_variable","page":"API Reference","title":"MathOptInterface.Bridges.Variable.supports_constrained_variable","text":"supports_constrained_variable(\n BT::Type{<:AbstractBridge},\n S::Type{<:MOI.AbstractSet},\n)::Bool\n\nReturn a Bool indicating whether the bridges of type BT support bridging constrained variables in S. That is, it returns true if the bridge of type BT converts constrained variables of type S into a form supported by the solver.\n\nImplementation notes\n\nThis method depends only on the type of the bridge and set, not the runtime values.\nThere is a default fallback, so you need only implement this method for sets that the bridge implements.\n\nExample\n\njulia> MOI.Bridges.Variable.supports_constrained_variable(\n MOI.Bridges.Variable.NonposToNonnegBridge{Float64},\n MOI.Nonpositives,\n )\ntrue\n\njulia> MOI.Bridges.Variable.supports_constrained_variable(\n MOI.Bridges.Variable.NonposToNonnegBridge{Float64},\n MOI.Nonnegatives,\n )\nfalse\n\n\n\n\n\n","category":"function"},{"location":"submodules/Bridges/reference/#MathOptInterface.Bridges.Variable.concrete_bridge_type","page":"API Reference","title":"MathOptInterface.Bridges.Variable.concrete_bridge_type","text":"concrete_bridge_type(\n BT::Type{<:AbstractBridge},\n S::Type{<:MOI.AbstractSet},\n)::Type\n\nReturn the concrete type of the bridge supporting variables in S constraints.\n\nThis function can only be called if MOI.supports_constrained_variable(BT, S) is true.\n\nExamples\n\nAs a variable in MOI.GreaterThan is bridged into variables in MOI.Nonnegatives by the VectorizeBridge:\n\njulia> MOI.Bridges.Variable.concrete_bridge_type(\n MOI.Bridges.Variable.VectorizeBridge{Float64},\n MOI.GreaterThan{Float64},\n )\nMathOptInterface.Bridges.Variable.VectorizeBridge{Float64, MathOptInterface.Nonnegatives}\n\n\n\n\n\n","category":"function"},{"location":"submodules/Bridges/reference/#MathOptInterface.Bridges.Variable.bridge_constrained_variable","page":"API Reference","title":"MathOptInterface.Bridges.Variable.bridge_constrained_variable","text":"bridge_constrained_variable(\n BT::Type{<:AbstractBridge},\n model::MOI.ModelLike,\n set::MOI.AbstractSet,\n)::BT\n\nBridge the constrained variable in set using bridge BT to model and returns a bridge object of type BT.\n\nImplementation notes\n\nThe bridge type BT must be a concrete type, that is, all the type parameters of the bridge must be set.\n\n\n\n\n\n","category":"function"},{"location":"submodules/Bridges/reference/#MathOptInterface.Bridges.Variable.SingleBridgeOptimizer","page":"API Reference","title":"MathOptInterface.Bridges.Variable.SingleBridgeOptimizer","text":"SingleBridgeOptimizer{BT<:AbstractBridge}(model::MOI.ModelLike)\n\nReturn MOI.Bridges.AbstractBridgeOptimizer that always bridges any variables constrained on creation supported by the bridge BT.\n\nThis is in contrast with the MOI.Bridges.LazyBridgeOptimizer, which only bridges the variables constrained on creation if they are supported by the bridge BT and unsupported by model.\n\nwarning: Warning\nTwo SingleBridgeOptimizers cannot be used together as both of them assume that the underlying model only returns variable indices with nonnegative values. Use MOI.Bridges.LazyBridgeOptimizer instead.\n\nExample\n\njulia> struct MyNewBridge{T} <: MOI.Bridges.Variable.AbstractBridge end\n\njulia> bridge = MOI.Bridges.Variable.SingleBridgeOptimizer{MyNewBridge{Float64}}(\n MOI.Utilities.Model{Float64}(),\n )\nMOIB.Variable.SingleBridgeOptimizer{MyNewBridge{Float64}, MOIU.Model{Float64}}\nwith 0 variable bridges\nwith inner model MOIU.Model{Float64}\n\nImplementation notes\n\nAll bridges should simplify the creation of SingleBridgeOptimizers by defining a constant that wraps the bridge in a SingleBridgeOptimizer.\n\njulia> const MyNewBridgeModel{T,OT<:MOI.ModelLike} =\n MOI.Bridges.Variable.SingleBridgeOptimizer{MyNewBridge{T},OT};\n\nThis enables users to create bridged models as follows:\n\njulia> MyNewBridgeModel{Float64}(MOI.Utilities.Model{Float64}())\nMOIB.Variable.SingleBridgeOptimizer{MyNewBridge{Float64}, MOIU.Model{Float64}}\nwith 0 variable bridges\nwith inner model MOIU.Model{Float64}\n\n\n\n\n\n","category":"type"},{"location":"submodules/Bridges/reference/#MathOptInterface.Bridges.Variable.add_all_bridges","page":"API Reference","title":"MathOptInterface.Bridges.Variable.add_all_bridges","text":"add_all_bridges(model, ::Type{T}) where {T}\n\nAdd all bridges defined in the Bridges.Variable submodule to model.\n\nThe coefficient type used is T.\n\n\n\n\n\n","category":"function"},{"location":"submodules/Bridges/reference/#MathOptInterface.Bridges.Variable.FlipSignBridge","page":"API Reference","title":"MathOptInterface.Bridges.Variable.FlipSignBridge","text":"abstract type FlipSignBridge{T,S1,S2} <: SetMapBridge{T,S2,S1} end\n\nAn abstract type that simplifies the creation of other bridges.\n\n\n\n\n\n","category":"type"},{"location":"submodules/Bridges/reference/#MathOptInterface.Bridges.Variable.SetMapBridge","page":"API Reference","title":"MathOptInterface.Bridges.Variable.SetMapBridge","text":"abstract type SetMapBridge{T,S1,S2} <: AbstractBridge end\n\nConsider two type of sets, S1 and S2, and a linear mapping A such that the image of a set of type S1 under A is a set of type S2.\n\nA SetMapBridge{T,S1,S2} is a bridge that substitutes constrained variables in S2 into the image through A of constrained variables in S1.\n\nThe linear map A is described by:\n\nMOI.Bridges.map_set\nMOI.Bridges.map_function\n\nImplementing a method for these two functions is sufficient to bridge constrained variables. However, in order for the getters and setters of attributes such as dual solutions and starting values to work as well, a method for the following functions must be implemented:\n\nMOI.Bridges.inverse_map_set\nMOI.Bridges.inverse_map_function\nMOI.Bridges.adjoint_map_function\nMOI.Bridges.inverse_adjoint_map_function.\n\nSee the docstrings of each function to see which feature would be missing if it was not implemented for a given bridge.\n\n\n\n\n\n","category":"type"},{"location":"submodules/Bridges/reference/#MathOptInterface.Bridges.Variable.unbridged_map","page":"API Reference","title":"MathOptInterface.Bridges.Variable.unbridged_map","text":"unbridged_map(\n bridge::MOI.Bridges.Variable.AbstractBridge,\n vi::MOI.VariableIndex,\n)\n\nFor a bridged variable in a scalar set, return a tuple of pairs mapping the variables created by the bridge to an affine expression in terms of the bridged variable vi.\n\nunbridged_map(\n bridge::MOI.Bridges.Variable.AbstractBridge,\n vis::Vector{MOI.VariableIndex},\n)\n\nFor a bridged variable in a vector set, return a tuple of pairs mapping the variables created by the bridge to an affine expression in terms of the bridged variable vis. If this method is not implemented, it falls back to calling the following method for every variable of vis.\n\nunbridged_map(\n bridge::MOI.Bridges.Variable.AbstractBridge,\n vi::MOI.VariableIndex,\n i::MOI.Bridges.IndexInVector,\n)\n\nFor a bridged variable in a vector set, return a tuple of pairs mapping the variables created by the bridge to an affine expression in terms of the bridged variable vi corresponding to the ith variable of the vector.\n\nIf there is no way to recover the expression in terms of the bridged variable(s) vi(s), return nothing. See ZerosBridge for an example of bridge returning nothing.\n\n\n\n\n\n","category":"function"},{"location":"submodules/Bridges/reference/#AbstractBridgeOptimizer-API","page":"API Reference","title":"AbstractBridgeOptimizer API","text":"","category":"section"},{"location":"submodules/Bridges/reference/","page":"API Reference","title":"API Reference","text":"Bridges.AbstractBridgeOptimizer\nBridges.bridged_variable_function\nBridges.unbridged_variable_function\nBridges.bridged_function\nBridges.supports_constraint_bridges\nBridges.recursive_model","category":"page"},{"location":"submodules/Bridges/reference/#MathOptInterface.Bridges.AbstractBridgeOptimizer","page":"API Reference","title":"MathOptInterface.Bridges.AbstractBridgeOptimizer","text":"abstract type AbstractBridgeOptimizer <: MOI.AbstractOptimizer end\n\nAn abstract type that implements generic functions for bridges.\n\nImplementation notes\n\nBy convention, the inner optimizer should be stored in a model field. If not, the optimizer must implement MOI.optimize!.\n\n\n\n\n\n","category":"type"},{"location":"submodules/Bridges/reference/#MathOptInterface.Bridges.bridged_variable_function","page":"API Reference","title":"MathOptInterface.Bridges.bridged_variable_function","text":"bridged_variable_function(\n b::AbstractBridgeOptimizer,\n vi::MOI.VariableIndex,\n)\n\nReturn a MOI.AbstractScalarFunction of variables of b.model that equals vi. That is, if the variable vi is bridged, it returns its expression in terms of the variables of b.model. Otherwise, it returns vi.\n\n\n\n\n\n","category":"function"},{"location":"submodules/Bridges/reference/#MathOptInterface.Bridges.unbridged_variable_function","page":"API Reference","title":"MathOptInterface.Bridges.unbridged_variable_function","text":"unbridged_variable_function(\n b::AbstractBridgeOptimizer,\n vi::MOI.VariableIndex,\n)\n\nReturn a MOI.AbstractScalarFunction of variables of b that equals vi. That is, if the variable vi is an internal variable of b.model created by a bridge but not visible to the user, it returns its expression in terms of the variables of bridged variables. Otherwise, it returns vi.\n\n\n\n\n\n","category":"function"},{"location":"submodules/Bridges/reference/#MathOptInterface.Bridges.bridged_function","page":"API Reference","title":"MathOptInterface.Bridges.bridged_function","text":"bridged_function(b::AbstractBridgeOptimizer, value)::typeof(value)\n\nSubstitute any bridged MOI.VariableIndex in value by an equivalent expression in terms of variables of b.model.\n\n\n\n\n\n","category":"function"},{"location":"submodules/Bridges/reference/#MathOptInterface.Bridges.supports_constraint_bridges","page":"API Reference","title":"MathOptInterface.Bridges.supports_constraint_bridges","text":"supports_constraint_bridges(b::AbstractBridgeOptimizer)::Bool\n\nReturn a Bool indicating if b supports MOI.Bridges.Constraint.AbstractBridge.\n\n\n\n\n\n","category":"function"},{"location":"submodules/Bridges/reference/#MathOptInterface.Bridges.recursive_model","page":"API Reference","title":"MathOptInterface.Bridges.recursive_model","text":"recursive_model(b::AbstractBridgeOptimizer)\n\nIf a variable, constraint, or objective is bridged, return the context of the inner variables. For most optimizers, this should be b.model.\n\n\n\n\n\n","category":"function"},{"location":"submodules/Bridges/reference/#LazyBridgeOptimizer-API","page":"API Reference","title":"LazyBridgeOptimizer API","text":"","category":"section"},{"location":"submodules/Bridges/reference/","page":"API Reference","title":"API Reference","text":"Bridges.LazyBridgeOptimizer\nBridges.full_bridge_optimizer\nBridges.ListOfNonstandardBridges\nBridges.add_bridge\nBridges.remove_bridge\nBridges.has_bridge\nBridges.print_active_bridges\nBridges.print_graph\nBridges.debug_supports_constraint\nBridges.debug_supports","category":"page"},{"location":"submodules/Bridges/reference/#MathOptInterface.Bridges.LazyBridgeOptimizer","page":"API Reference","title":"MathOptInterface.Bridges.LazyBridgeOptimizer","text":"LazyBridgeOptimizer(model::MOI.ModelLike)\n\nThe LazyBridgeOptimizer is a bridge optimizer that supports multiple bridges, and only bridges things which are not supported by the internal model.\n\nInternally, the LazyBridgeOptimizer solves a shortest hyper-path problem to determine which bridges to use.\n\nIn general, you should use full_bridge_optimizer instead of this constructor because full_bridge_optimizer automatically adds a large number of supported bridges.\n\nSee also: add_bridge, remove_bridge, has_bridge and full_bridge_optimizer.\n\nExample\n\njulia> model = MOI.Bridges.LazyBridgeOptimizer(MOI.Utilities.Model{Float64}())\nMOIB.LazyBridgeOptimizer{MOIU.Model{Float64}}\nwith 0 variable bridges\nwith 0 constraint bridges\nwith 0 objective bridges\nwith inner model MOIU.Model{Float64}\n\njulia> MOI.Bridges.add_bridge(model, MOI.Bridges.Variable.FreeBridge{Float64})\n\njulia> MOI.Bridges.has_bridge(model, MOI.Bridges.Variable.FreeBridge{Float64})\ntrue\n\n\n\n\n\n","category":"type"},{"location":"submodules/Bridges/reference/#MathOptInterface.Bridges.full_bridge_optimizer","page":"API Reference","title":"MathOptInterface.Bridges.full_bridge_optimizer","text":"full_bridge_optimizer(model::MOI.ModelLike, ::Type{T}) where {T}\n\nReturns a LazyBridgeOptimizer bridging model for every bridge defined in this package (see below for the few exceptions) and for the coefficient type T, as well as the bridges in the list returned by the ListOfNonstandardBridges attribute.\n\nExample\n\njulia> model = MOI.Utilities.Model{Float64}();\n\njulia> bridged_model = MOI.Bridges.full_bridge_optimizer(model, Float64);\n\nExceptions\n\nThe following bridges are not added by full_bridge_optimizer, except if they are in the list returned by the ListOfNonstandardBridges attribute:\n\nConstraint.SOCtoNonConvexQuadBridge\nConstraint.RSOCtoNonConvexQuadBridge](@ref)\nConstraint.SOCtoPSDBridge\nIf T is not a subtype of AbstractFloat, subtypes of Constraint.AbstractToIntervalBridge\nConstraint.GreaterToIntervalBridge\nConstraint.LessToIntervalBridge)\n\nSee the docstring of the each bridge for the reason they are not added.\n\n\n\n\n\n","category":"function"},{"location":"submodules/Bridges/reference/#MathOptInterface.Bridges.ListOfNonstandardBridges","page":"API Reference","title":"MathOptInterface.Bridges.ListOfNonstandardBridges","text":"ListOfNonstandardBridges{T}() <: MOI.AbstractOptimizerAttribute\n\nAny optimizer can be wrapped in a LazyBridgeOptimizer using full_bridge_optimizer. However, by default LazyBridgeOptimizer uses a limited set of bridges that are:\n\nimplemented in MOI.Bridges\ngenerally applicable for all optimizers.\n\nFor some optimizers however, it is useful to add additional bridges, such as those that are implemented in external packages (e.g., within the solver package itself) or only apply in certain circumstances (e.g., Constraint.SOCtoNonConvexQuadBridge).\n\nSuch optimizers should implement the ListOfNonstandardBridges attribute to return a vector of bridge types that are added by full_bridge_optimizer in addition to the list of default bridges.\n\nNote that optimizers implementing ListOfNonstandardBridges may require package-specific functions or sets to be used if the non-standard bridges are not added. Therefore, you are recommended to use model = MOI.instantiate(Package.Optimizer; with_bridge_type = T) instead of model = MOI.instantiate(Package.Optimizer). See MOI.instantiate.\n\nExamples\n\nAn optimizer using a non-default bridge in MOI.Bridges\n\nSolvers supporting MOI.ScalarQuadraticFunction can support MOI.SecondOrderCone and MOI.RotatedSecondOrderCone by defining:\n\nfunction MOI.get(::MyQuadraticOptimizer, ::ListOfNonstandardBridges{Float64})\n return Type[\n MOI.Bridges.Constraint.SOCtoNonConvexQuadBridge{Float64},\n MOI.Bridges.Constraint.RSOCtoNonConvexQuadBridge{Float64},\n ]\nend\n\nAn optimizer defining an internal bridge\n\nSuppose an optimizer can exploit specific structure of a constraint, e.g., it can exploit the structure of the matrix A in the linear system of equations A * x = b.\n\nThe optimizer can define the function:\n\nstruct MatrixAffineFunction{T} <: MOI.AbstractVectorFunction\n A::SomeStructuredMatrixType{T}\n b::Vector{T}\nend\n\nand then a bridge\n\nstruct MatrixAffineFunctionBridge{T} <: MOI.Constraint.AbstractBridge\n # ...\nend\n# ...\n\nfrom VectorAffineFunction{T} to the MatrixAffineFunction. Finally, it defines:\n\nfunction MOI.get(::Optimizer{T}, ::ListOfNonstandardBridges{T}) where {T}\n return Type[MatrixAffineFunctionBridge{T}]\nend\n\n\n\n\n\n","category":"type"},{"location":"submodules/Bridges/reference/#MathOptInterface.Bridges.add_bridge","page":"API Reference","title":"MathOptInterface.Bridges.add_bridge","text":"add_bridge(b::LazyBridgeOptimizer, BT::Type{<:AbstractBridge})\n\nEnable the use of the bridges of type BT by b.\n\n\n\n\n\n","category":"function"},{"location":"submodules/Bridges/reference/#MathOptInterface.Bridges.remove_bridge","page":"API Reference","title":"MathOptInterface.Bridges.remove_bridge","text":"remove_bridge(b::LazyBridgeOptimizer, BT::Type{<:AbstractBridge})\n\nDisable the use of the bridges of type BT by b.\n\n\n\n\n\n","category":"function"},{"location":"submodules/Bridges/reference/#MathOptInterface.Bridges.has_bridge","page":"API Reference","title":"MathOptInterface.Bridges.has_bridge","text":"has_bridge(b::LazyBridgeOptimizer, BT::Type{<:AbstractBridge})\n\nReturn a Bool indicating whether the bridges of type BT are used by b.\n\n\n\n\n\n","category":"function"},{"location":"submodules/Bridges/reference/#MathOptInterface.Bridges.print_active_bridges","page":"API Reference","title":"MathOptInterface.Bridges.print_active_bridges","text":"print_active_bridges([io::IO=stdout,] b::MOI.Bridges.LazyBridgeOptimizer)\n\nPrint the set of bridges that are active in the model b.\n\n\n\n\n\nprint_active_bridges(\n [io::IO=stdout,]\n b::MOI.Bridges.LazyBridgeOptimizer,\n F::Type{<:MOI.AbstractFunction}\n)\n\nPrint the set of bridges required for an objective function of type F.\n\n\n\n\n\nprint_active_bridges(\n [io::IO=stdout,]\n b::MOI.Bridges.LazyBridgeOptimizer,\n F::Type{<:MOI.AbstractFunction},\n S::Type{<:MOI.AbstractSet},\n)\n\nPrint the set of bridges required for a constraint of type F-in-S.\n\n\n\n\n\nprint_active_bridges(\n [io::IO=stdout,]\n b::MOI.Bridges.LazyBridgeOptimizer,\n S::Type{<:MOI.AbstractSet}\n)\n\nPrint the set of bridges required for a variable constrained to set S.\n\n\n\n\n\n","category":"function"},{"location":"submodules/Bridges/reference/#MathOptInterface.Bridges.print_graph","page":"API Reference","title":"MathOptInterface.Bridges.print_graph","text":"print_graph([io::IO = stdout,] b::LazyBridgeOptimizer)\n\nPrint the hyper-graph containing all variable, constraint, and objective types that could be obtained by bridging the variables, constraints, and objectives that are present in the model by all the bridges added to b.\n\nEach node in the hyper-graph corresponds to a variable, constraint, or objective type.\n\nVariable nodes are indicated by [ ]\nConstraint nodes are indicated by ( )\nObjective nodes are indicated by | |\n\nThe number inside each pair of brackets is an index of the node in the hyper-graph.\n\nNote that this hyper-graph is the full list of possible transformations. When the bridged model is created, we select the shortest hyper-path(s) from this graph, so many nodes may be un-used.\n\nTo see which nodes are used, call print_active_bridges.\n\nFor more information, see Legat, B., Dowson, O., Garcia, J., and Lubin, M. (2020). \"MathOptInterface: a data structure for mathematical optimization problems.\" URL: https://arxiv.org/abs/2002.03447\n\n\n\n\n\n","category":"function"},{"location":"submodules/Bridges/reference/#MathOptInterface.Bridges.debug_supports_constraint","page":"API Reference","title":"MathOptInterface.Bridges.debug_supports_constraint","text":"debug_supports_constraint(\n b::LazyBridgeOptimizer,\n F::Type{<:MOI.AbstractFunction},\n S::Type{<:MOI.AbstractSet};\n io::IO = Base.stdout,\n)\n\nPrints to io explanations for the value of MOI.supports_constraint with the same arguments.\n\n\n\n\n\n","category":"function"},{"location":"submodules/Bridges/reference/#MathOptInterface.Bridges.debug_supports","page":"API Reference","title":"MathOptInterface.Bridges.debug_supports","text":"debug_supports(\n b::LazyBridgeOptimizer,\n ::MOI.ObjectiveFunction{F};\n io::IO = Base.stdout,\n) where F\n\nPrints to io explanations for the value of MOI.supports with the same arguments.\n\n\n\n\n\n","category":"function"},{"location":"submodules/Bridges/reference/#constraint_set_map","page":"API Reference","title":"SetMap API","text":"","category":"section"},{"location":"submodules/Bridges/reference/","page":"API Reference","title":"API Reference","text":"Bridges.map_set\nBridges.inverse_map_set\nBridges.map_function\nBridges.inverse_map_function\nBridges.adjoint_map_function\nBridges.inverse_adjoint_map_function","category":"page"},{"location":"submodules/Bridges/reference/#MathOptInterface.Bridges.map_set","page":"API Reference","title":"MathOptInterface.Bridges.map_set","text":"map_set(::Type{BT}, set) where {BT}\n\nReturn the image of set through the linear map A defined in Variable.SetMapBridge and Constraint.SetMapBridge. This is used for bridging the constraint and setting the MOI.ConstraintSet.\n\n\n\n\n\n","category":"function"},{"location":"submodules/Bridges/reference/#MathOptInterface.Bridges.inverse_map_set","page":"API Reference","title":"MathOptInterface.Bridges.inverse_map_set","text":"inverse_map_set(::Type{BT}, set) where {BT}\n\nReturn the preimage of set through the linear map A defined in Variable.SetMapBridge and Constraint.SetMapBridge. This is used for getting the MOI.ConstraintSet.\n\n\n\n\n\n","category":"function"},{"location":"submodules/Bridges/reference/#MathOptInterface.Bridges.map_function","page":"API Reference","title":"MathOptInterface.Bridges.map_function","text":"map_function(::Type{BT}, func) where {BT}\n\nReturn the image of func through the linear map A defined in Variable.SetMapBridge and Constraint.SetMapBridge. This is used for getting the MOI.ConstraintPrimal of variable bridges. For constraint bridges, this is used for bridging the constraint, setting the MOI.ConstraintFunction and MOI.ConstraintPrimalStart and modifying the function with MOI.modify.\n\nmap_function(::Type{BT}, func, i::IndexInVector) where {BT}\n\nReturn the scalar function at the ith index of the vector function that would be returned by map_function(BT, func) except that it may compute the ith element. This is used by bridged_function and for getting the MOI.VariablePrimal and MOI.VariablePrimalStart of variable bridges.\n\n\n\n\n\n","category":"function"},{"location":"submodules/Bridges/reference/#MathOptInterface.Bridges.inverse_map_function","page":"API Reference","title":"MathOptInterface.Bridges.inverse_map_function","text":"inverse_map_function(::Type{BT}, func) where {BT}\n\nReturn the image of func through the inverse of the linear map A defined in Variable.SetMapBridge and Constraint.SetMapBridge. This is used by Variable.unbridged_map and for setting the MOI.VariablePrimalStart of variable bridges and for getting the MOI.ConstraintFunction, the MOI.ConstraintPrimal and the MOI.ConstraintPrimalStart of constraint bridges.\n\n\n\n\n\n","category":"function"},{"location":"submodules/Bridges/reference/#MathOptInterface.Bridges.adjoint_map_function","page":"API Reference","title":"MathOptInterface.Bridges.adjoint_map_function","text":"adjoint_map_function(::Type{BT}, func) where {BT}\n\nReturn the image of func through the adjoint of the linear map A defined in Variable.SetMapBridge and Constraint.SetMapBridge. This is used for getting the MOI.ConstraintDual and MOI.ConstraintDualStart of constraint bridges.\n\n\n\n\n\n","category":"function"},{"location":"submodules/Bridges/reference/#MathOptInterface.Bridges.inverse_adjoint_map_function","page":"API Reference","title":"MathOptInterface.Bridges.inverse_adjoint_map_function","text":"inverse_adjoint_map_function(::Type{BT}, func) where {BT}\n\nReturn the image of func through the inverse of the adjoint of the linear map A defined in Variable.SetMapBridge and Constraint.SetMapBridge. This is used for getting the MOI.ConstraintDual of variable bridges and setting the MOI.ConstraintDualStart of constraint bridges.\n\n\n\n\n\n","category":"function"},{"location":"submodules/Bridges/reference/#Bridging-graph-API","page":"API Reference","title":"Bridging graph API","text":"","category":"section"},{"location":"submodules/Bridges/reference/","page":"API Reference","title":"API Reference","text":"Bridges.Graph\nBridges.VariableNode\nBridges.ConstraintNode\nBridges.ObjectiveNode\nBridges.Edge\nBridges.ObjectiveEdge\nBridges.add_node\nBridges.add_edge\nBridges.set_variable_constraint_node\nBridges.bridge_index\nBridges.is_variable_edge_best","category":"page"},{"location":"submodules/Bridges/reference/#MathOptInterface.Bridges.Graph","page":"API Reference","title":"MathOptInterface.Bridges.Graph","text":"Graph()\n\nA type-stable datastructure for computing the shortest hyperpath problem.\n\nNodes\n\nThere are three types of nodes in the graph:\n\nVariableNode\nConstraintNode\nObjectiveNode\n\nAdd nodes to the graph using add_node.\n\nEdges\n\nThere are two types of edges in the graph:\n\nEdge\nObjectiveEdge\n\nAdd edges to the graph using add_edge.\n\nFor the ability to add a variable constrained on creation as a free variable followed by a constraint, use set_variable_constraint_node.\n\nOptimal hyper-edges\n\nUse bridge_index to compute the minimum-cost bridge leaving a node.\n\nNote that bridge_index lazy runs a Bellman-Ford algorithm to compute the set of minimum cost edges. Thus, the first call to bridge_index after adding new nodes or edges will take longer than subsequent calls.\n\n\n\n\n\n","category":"type"},{"location":"submodules/Bridges/reference/#MathOptInterface.Bridges.VariableNode","page":"API Reference","title":"MathOptInterface.Bridges.VariableNode","text":"VariableNode(index::Int)\n\nA node in Graph representing a variable constrained on creation.\n\n\n\n\n\n","category":"type"},{"location":"submodules/Bridges/reference/#MathOptInterface.Bridges.ConstraintNode","page":"API Reference","title":"MathOptInterface.Bridges.ConstraintNode","text":"ConstraintNode(index::Int)\n\nA node in Graph representing a constraint.\n\n\n\n\n\n","category":"type"},{"location":"submodules/Bridges/reference/#MathOptInterface.Bridges.ObjectiveNode","page":"API Reference","title":"MathOptInterface.Bridges.ObjectiveNode","text":"ObjectiveNode(index::Int)\n\nA node in Graph representing an objective function.\n\n\n\n\n\n","category":"type"},{"location":"submodules/Bridges/reference/#MathOptInterface.Bridges.Edge","page":"API Reference","title":"MathOptInterface.Bridges.Edge","text":"Edge(\n bridge_index::Int,\n added_variables::Vector{VariableNode},\n added_constraints::Vector{ConstraintNode},\n cost::Float64 = 1.0,\n)\n\nReturn a new datastructure representing an edge in Graph that starts at a VariableNode or a ConstraintNode.\n\n\n\n\n\n","category":"type"},{"location":"submodules/Bridges/reference/#MathOptInterface.Bridges.ObjectiveEdge","page":"API Reference","title":"MathOptInterface.Bridges.ObjectiveEdge","text":"ObjectiveEdge(\n bridge_index::Int,\n added_variables::Vector{VariableNode},\n added_constraints::Vector{ConstraintNode},\n)\n\nReturn a new datastructure representing an edge in Graph that starts at an ObjectiveNode.\n\n\n\n\n\n","category":"type"},{"location":"submodules/Bridges/reference/#MathOptInterface.Bridges.add_node","page":"API Reference","title":"MathOptInterface.Bridges.add_node","text":"add_node(graph::Graph, ::Type{VariableNode})::VariableNode\nadd_node(graph::Graph, ::Type{ConstraintNode})::ConstraintNode\nadd_node(graph::Graph, ::Type{ObjectiveNode})::ObjectiveNode\n\nAdd a new node to graph.\n\n\n\n\n\n","category":"function"},{"location":"submodules/Bridges/reference/#MathOptInterface.Bridges.add_edge","page":"API Reference","title":"MathOptInterface.Bridges.add_edge","text":"add_edge(graph::Graph, node::VariableNode, edge::Edge)::Nothing\nadd_edge(graph::Graph, node::ConstraintNode, edge::Edge)::Nothing\nadd_edge(graph::Graph, node::ObjectiveNode, edge::ObjectiveEdge)::Nothing\n\nAdd edge to graph, where edge starts at node and connects to the nodes defined in edge.\n\n\n\n\n\n","category":"function"},{"location":"submodules/Bridges/reference/#MathOptInterface.Bridges.set_variable_constraint_node","page":"API Reference","title":"MathOptInterface.Bridges.set_variable_constraint_node","text":"set_variable_constraint_node(\n graph::Graph,\n variable_node::VariableNode,\n constraint_node::ConstraintNode,\n cost::Int,\n)\n\nAs an alternative to variable_node, add a virtual edge to graph that represents adding a free variable, followed by a constraint of type constraint_node, with bridging cost cost.\n\nWhy is this needed?\n\nVariables can either be added as a variable constrained on creation, or as a free variable which then has a constraint added to it.\n\n\n\n\n\n","category":"function"},{"location":"submodules/Bridges/reference/#MathOptInterface.Bridges.bridge_index","page":"API Reference","title":"MathOptInterface.Bridges.bridge_index","text":"bridge_index(graph::Graph, node::VariableNode)::Int\nbridge_index(graph::Graph, node::ConstraintNode)::Int\nbridge_index(graph::Graph, node::ObjectiveNode)::Int\n\nReturn the optimal index of the bridge to chose from node.\n\n\n\n\n\n","category":"function"},{"location":"submodules/Bridges/reference/#MathOptInterface.Bridges.is_variable_edge_best","page":"API Reference","title":"MathOptInterface.Bridges.is_variable_edge_best","text":"is_variable_edge_best(graph::Graph, node::VariableNode)::Bool\n\nReturn a Bool indicating whether node should be added as a variable constrained on creation, or as a free variable followed by a constraint.\n\n\n\n\n\n","category":"function"},{"location":"#Introduction","page":"Introduction","title":"Introduction","text":"","category":"section"},{"location":"","page":"Introduction","title":"Introduction","text":"Welcome to the documentation for MathOptInterface.","category":"page"},{"location":"","page":"Introduction","title":"Introduction","text":"note: Note\nThis documentation is also available in PDF format: MathOptInterface.pdf.","category":"page"},{"location":"#What-is-MathOptInterface?","page":"Introduction","title":"What is MathOptInterface?","text":"","category":"section"},{"location":"","page":"Introduction","title":"Introduction","text":"MathOptInterface.jl (MOI) is an abstraction layer designed to provide a unified interface to mathematical optimization solvers so that users do not need to understand multiple solver-specific APIs.","category":"page"},{"location":"","page":"Introduction","title":"Introduction","text":"tip: Tip\nThis documentation is aimed at developers writing software interfaces to solvers and modeling languages using the MathOptInterface API. If you are a user interested in solving optimization problems, we encourage you instead to use MOI through a higher-level modeling interface like JuMP or Convex.jl.","category":"page"},{"location":"#How-the-documentation-is-structured","page":"Introduction","title":"How the documentation is structured","text":"","category":"section"},{"location":"","page":"Introduction","title":"Introduction","text":"Having a high-level overview of how this documentation is structured will help you know where to look for certain things.","category":"page"},{"location":"","page":"Introduction","title":"Introduction","text":"The Tutorials section contains articles on how to use and implement the MathOptInteraface API. Look here if you want to write a model in MOI, or write an interface to a new solver.\nThe Manual contains short code-snippets that explain how to use the MOI API. Look here for more details on particular areas of MOI.\nThe Background section contains articles on the theory behind MathOptInterface. Look here if you want to understand why, rather than how.\nThe API Reference contains a complete list of functions and types that comprise the MOI API. Look here is you want to know how to use (or implement) a particular function.\nThe Submodules section contains stand-alone documentation for each of the submodules within MOI. These submodules are not required to interface a solver with MOI, but they make the job much easier.","category":"page"},{"location":"#Citing-MathOptInterface","page":"Introduction","title":"Citing MathOptInterface","text":"","category":"section"},{"location":"","page":"Introduction","title":"Introduction","text":"A paper describing the design and features of MathOptInterface is available on arXiv.","category":"page"},{"location":"","page":"Introduction","title":"Introduction","text":"If you find MathOptInterface useful in your work, we kindly request that you cite the following paper:","category":"page"},{"location":"","page":"Introduction","title":"Introduction","text":"@article{legat2021mathoptinterface,\n title={{MathOptInterface}: a data structure for mathematical optimization problems},\n author={Legat, Beno{\\^\\i}t and Dowson, Oscar and Garcia, Joaquim Dias and Lubin, Miles},\n journal={INFORMS Journal on Computing},\n year={2021},\n doi={10.1287/ijoc.2021.1067},\n publisher={INFORMS}\n}","category":"page"},{"location":"background/naming_conventions/","page":"Naming conventions","title":"Naming conventions","text":"CurrentModule = MathOptInterface\nDocTestSetup = quote\n import MathOptInterface as MOI\nend\nDocTestFilters = [r\"MathOptInterface|MOI\"]","category":"page"},{"location":"background/naming_conventions/#Naming-conventions","page":"Naming conventions","title":"Naming conventions","text":"","category":"section"},{"location":"background/naming_conventions/","page":"Naming conventions","title":"Naming conventions","text":"MOI follows several conventions for naming functions and structures. These should also be followed by packages extending MOI.","category":"page"},{"location":"background/naming_conventions/#Sets","page":"Naming conventions","title":"Sets","text":"","category":"section"},{"location":"background/naming_conventions/","page":"Naming conventions","title":"Naming conventions","text":"Sets encode the structure of constraints. Their names should follow the following conventions:","category":"page"},{"location":"background/naming_conventions/","page":"Naming conventions","title":"Naming conventions","text":"Abstract types in the set hierarchy should begin with Abstract and end in Set, for example, AbstractScalarSet, AbstractVectorSet.\nVector-valued conic sets should end with Cone, for example, NormInfinityCone, SecondOrderCone.\nVector-valued Cartesian products should be plural and not end in Cone, for example, Nonnegatives, not NonnegativeCone.\nMatrix-valued conic sets should provide two representations: ConeSquare and ConeTriangle, for example, RootDetConeTriangle and RootDetConeSquare. See Matrix cones for more details.\nScalar sets should be singular, not plural, for example, Integer, not Integers.\nAs much as possible, the names should follow established conventions in the domain where this set is used: for instance, convex sets should have names close to those of CVX, and constraint-programming sets should follow MiniZinc's constraints.","category":"page"}] +[{"location":"background/motivation/#Motivation","page":"Motivation","title":"Motivation","text":"","category":"section"},{"location":"background/motivation/","page":"Motivation","title":"Motivation","text":"MathOptInterface (MOI) is a replacement for MathProgBase, the first-generation abstraction layer for mathematical optimization previously used by JuMP and Convex.jl.","category":"page"},{"location":"background/motivation/","page":"Motivation","title":"Motivation","text":"To address a number of limitations of MathProgBase, MOI is designed to:","category":"page"},{"location":"background/motivation/","page":"Motivation","title":"Motivation","text":"Be simple and extensible\nunifying linear, quadratic, and conic optimization,\nseamlessly facilitating extensions to essentially arbitrary constraints and functions (for example, indicator constraints, complementarity constraints, and piecewise-linear functions)\nBe fast\nby allowing access to a solver's in-memory representation of a problem without writing intermediate files (when possible)\nby using multiple dispatch and avoiding requiring containers of non-concrete types\nAllow a solver to return multiple results (for example, a pool of solutions)\nAllow a solver to return extra arbitrary information via attributes (for example, variable- and constraint-wise membership in an irreducible inconsistent subset for infeasibility analysis)\nProvide a greatly expanded set of status codes explaining what happened during the optimization procedure\nEnable a solver to more precisely specify which problem classes it supports\nEnable both primal and dual warm starts\nEnable adding and removing both variables and constraints by indices that are not required to be consecutive\nEnable any modification that the solver supports to an existing model\nAvoid requiring the solver wrapper to store an additional copy of the problem data","category":"page"},{"location":"reference/constraints/","page":"Constraints","title":"Constraints","text":"CurrentModule = MathOptInterface\nDocTestSetup = quote\n import MathOptInterface as MOI\nend\nDocTestFilters = [r\"MathOptInterface|MOI\"]","category":"page"},{"location":"reference/constraints/#constraints_ref","page":"Constraints","title":"Constraints","text":"","category":"section"},{"location":"reference/constraints/#Types","page":"Constraints","title":"Types","text":"","category":"section"},{"location":"reference/constraints/","page":"Constraints","title":"Constraints","text":"ConstraintIndex","category":"page"},{"location":"reference/constraints/#MathOptInterface.ConstraintIndex","page":"Constraints","title":"MathOptInterface.ConstraintIndex","text":"ConstraintIndex{F, S}\n\nA type-safe wrapper for Int64 for use in referencing F-in-S constraints in a model. The parameter F is the type of the function in the constraint, and the parameter S is the type of set in the constraint. To allow for deletion, indices need not be consecutive. Indices within a constraint type (i.e. F-in-S) must be unique, but non-unique indices across different constraint types are allowed. If F is VariableIndex then the index is equal to the index of the variable. That is for an index::ConstraintIndex{VariableIndex}, we always have\n\nindex.value == MOI.get(model, MOI.ConstraintFunction(), index).value\n\n\n\n\n\n","category":"type"},{"location":"reference/constraints/#Functions","page":"Constraints","title":"Functions","text":"","category":"section"},{"location":"reference/constraints/","page":"Constraints","title":"Constraints","text":"is_valid(::ModelLike,::ConstraintIndex)\nadd_constraint\nadd_constraints\ntransform\nsupports_constraint","category":"page"},{"location":"reference/constraints/#MathOptInterface.is_valid-Tuple{MathOptInterface.ModelLike, MathOptInterface.ConstraintIndex}","page":"Constraints","title":"MathOptInterface.is_valid","text":"is_valid(model::ModelLike, index::Index)::Bool\n\nReturn a Bool indicating whether this index refers to a valid object in the model model.\n\n\n\n\n\n","category":"method"},{"location":"reference/constraints/#MathOptInterface.add_constraint","page":"Constraints","title":"MathOptInterface.add_constraint","text":"add_constraint(model::ModelLike, func::F, set::S)::ConstraintIndex{F,S} where {F,S}\n\nAdd the constraint f(x) in mathcalS where f is defined by func, and mathcalS is defined by set.\n\nadd_constraint(model::ModelLike, v::VariableIndex, set::S)::ConstraintIndex{VariableIndex,S} where {S}\nadd_constraint(model::ModelLike, vec::Vector{VariableIndex}, set::S)::ConstraintIndex{VectorOfVariables,S} where {S}\n\nAdd the constraint v in mathcalS where v is the variable (or vector of variables) referenced by v and mathcalS is defined by set.\n\nAn UnsupportedConstraint error is thrown if model does not support F-in-S constraints,\na AddConstraintNotAllowed error is thrown if it supports F-in-S constraints but it cannot add the constraint(s) in its current state and\na ScalarFunctionConstantNotZero error may be thrown if func is an AbstractScalarFunction with nonzero constant and set is EqualTo, GreaterThan, LessThan or Interval.\na LowerBoundAlreadySet error is thrown if F is a VariableIndex and a constraint was already added to this variable that sets a lower bound.\na UpperBoundAlreadySet error is thrown if F is a VariableIndex and a constraint was already added to this variable that sets an upper bound.\n\n\n\n\n\n","category":"function"},{"location":"reference/constraints/#MathOptInterface.add_constraints","page":"Constraints","title":"MathOptInterface.add_constraints","text":"add_constraints(model::ModelLike, funcs::Vector{F}, sets::Vector{S})::Vector{ConstraintIndex{F,S}} where {F,S}\n\nAdd the set of constraints specified by each function-set pair in funcs and sets. F and S should be concrete types. This call is equivalent to add_constraint.(model, funcs, sets) but may be more efficient.\n\n\n\n\n\n","category":"function"},{"location":"reference/constraints/#MathOptInterface.transform","page":"Constraints","title":"MathOptInterface.transform","text":"Transform Constraint Set\n\ntransform(model::ModelLike, c::ConstraintIndex{F,S1}, newset::S2)::ConstraintIndex{F,S2}\n\nReplace the set in constraint c with newset. The constraint index c will no longer be valid, and the function returns a new constraint index with the correct type.\n\nSolvers may only support a subset of constraint transforms that they perform efficiently (for example, changing from a LessThan to GreaterThan set). In addition, set modification (where S1 = S2) should be performed via the modify function.\n\nTypically, the user should delete the constraint and add a new one.\n\nExamples\n\nIf c is a ConstraintIndex{ScalarAffineFunction{Float64},LessThan{Float64}},\n\nc2 = transform(model, c, GreaterThan(0.0))\ntransform(model, c, LessThan(0.0)) # errors\n\n\n\n\n\n","category":"function"},{"location":"reference/constraints/#MathOptInterface.supports_constraint","page":"Constraints","title":"MathOptInterface.supports_constraint","text":"MOI.supports_constraint(\n BT::Type{<:AbstractBridge},\n F::Type{<:MOI.AbstractFunction},\n S::Type{<:MOI.AbstractSet},\n)::Bool\n\nReturn a Bool indicating whether the bridges of type BT support bridging F-in-S constraints.\n\nImplementation notes\n\nThis method depends only on the type of the inputs, not the runtime values.\nThere is a default fallback, so you need only implement this method for constraint types that the bridge implements.\n\n\n\n\n\nsupports_constraint(\n model::ModelLike,\n ::Type{F},\n ::Type{S},\n)::Bool where {F<:AbstractFunction,S<:AbstractSet}\n\nReturn a Bool indicating whether model supports F-in-S constraints, that is, copy_to(model, src) does not throw UnsupportedConstraint when src contains F-in-S constraints. If F-in-S constraints are only not supported in specific circumstances, e.g. F-in-S constraints cannot be combined with another type of constraint, it should still return true.\n\n\n\n\n\n","category":"function"},{"location":"reference/constraints/#Attributes","page":"Constraints","title":"Attributes","text":"","category":"section"},{"location":"reference/constraints/","page":"Constraints","title":"Constraints","text":"AbstractConstraintAttribute\nConstraintName\nConstraintPrimalStart\nConstraintDualStart\nConstraintPrimal\nConstraintDual\nConstraintBasisStatus\nConstraintFunction\nCanonicalConstraintFunction\nConstraintSet\nBasisStatusCode\nBASIC\nNONBASIC\nNONBASIC_AT_LOWER\nNONBASIC_AT_UPPER\nSUPER_BASIC","category":"page"},{"location":"reference/constraints/#MathOptInterface.AbstractConstraintAttribute","page":"Constraints","title":"MathOptInterface.AbstractConstraintAttribute","text":"AbstractConstraintAttribute\n\nAbstract supertype for attribute objects that can be used to set or get attributes (properties) of constraints in the model.\n\n\n\n\n\n","category":"type"},{"location":"reference/constraints/#MathOptInterface.ConstraintName","page":"Constraints","title":"MathOptInterface.ConstraintName","text":"ConstraintName()\n\nA constraint attribute for a string identifying the constraint.\n\nIt is valid for constraints variables to have the same name; however, constraints with duplicate names cannot be looked up using get, regardless of whether they have the same F-in-S type.\n\nConstraintName has a default value of \"\" if not set.\n\nNotes\n\nYou should not implement ConstraintName for VariableIndex constraints.\n\n\n\n\n\n","category":"type"},{"location":"reference/constraints/#MathOptInterface.ConstraintPrimalStart","page":"Constraints","title":"MathOptInterface.ConstraintPrimalStart","text":"ConstraintPrimalStart()\n\nA constraint attribute for the initial assignment to some constraint's ConstraintPrimal that the optimizer may use to warm-start the solve.\n\nMay be nothing (unset), a number for AbstractScalarFunction, or a vector for AbstractVectorFunction.\n\n\n\n\n\n","category":"type"},{"location":"reference/constraints/#MathOptInterface.ConstraintDualStart","page":"Constraints","title":"MathOptInterface.ConstraintDualStart","text":"ConstraintDualStart()\n\nA constraint attribute for the initial assignment to some constraint's ConstraintDual that the optimizer may use to warm-start the solve.\n\nMay be nothing (unset), a number for AbstractScalarFunction, or a vector for AbstractVectorFunction.\n\n\n\n\n\n","category":"type"},{"location":"reference/constraints/#MathOptInterface.ConstraintPrimal","page":"Constraints","title":"MathOptInterface.ConstraintPrimal","text":"ConstraintPrimal(result_index::Int = 1)\n\nA constraint attribute for the assignment to some constraint's primal value(s) in result result_index.\n\nIf the constraint is f(x) in S, then in most cases the ConstraintPrimal is the value of f, evaluated at the correspondng VariablePrimal solution.\n\nHowever, some conic solvers reformulate b - Ax in S to s = b - Ax, s in S. These solvers may return the value of s for ConstraintPrimal, rather than b - Ax. (Although these are constrained by an equality constraint, due to numerical tolerances they may not be identical.)\n\nIf the solver does not have a primal value for the constraint because the result_index is beyond the available solutions (whose number is indicated by the ResultCount attribute), getting this attribute must throw a ResultIndexBoundsError. Otherwise, if the result is unavailable for another reason (for instance, only a dual solution is available), the result is undefined. Users should first check PrimalStatus before accessing the ConstraintPrimal attribute.\n\nIf result_index is omitted, it is 1 by default. See ResultCount for information on how the results are ordered.\n\n\n\n\n\n","category":"type"},{"location":"reference/constraints/#MathOptInterface.ConstraintDual","page":"Constraints","title":"MathOptInterface.ConstraintDual","text":"ConstraintDual(result_index::Int = 1)\n\nA constraint attribute for the assignment to some constraint's dual value(s) in result result_index. If result_index is omitted, it is 1 by default.\n\nIf the solver does not have a dual value for the variable because the result_index is beyond the available solutions (whose number is indicated by the ResultCount attribute), getting this attribute must throw a ResultIndexBoundsError. Otherwise, if the result is unavailable for another reason (for instance, only a primal solution is available), the result is undefined. Users should first check DualStatus before accessing the ConstraintDual attribute.\n\nSee ResultCount for information on how the results are ordered.\n\n\n\n\n\n","category":"type"},{"location":"reference/constraints/#MathOptInterface.ConstraintBasisStatus","page":"Constraints","title":"MathOptInterface.ConstraintBasisStatus","text":"ConstraintBasisStatus(result_index::Int = 1)\n\nA constraint attribute for the BasisStatusCode of some constraint in result result_index, with respect to an available optimal solution basis. If result_index is omitted, it is 1 by default.\n\nIf the solver does not have a basis statue for the constraint because the result_index is beyond the available solutions (whose number is indicated by the ResultCount attribute), getting this attribute must throw a ResultIndexBoundsError. Otherwise, if the result is unavailable for another reason (for instance, only a dual solution is available), the result is undefined. Users should first check PrimalStatus before accessing the ConstraintBasisStatus attribute.\n\nSee ResultCount for information on how the results are ordered.\n\nNotes\n\nFor the basis status of a variable, query VariableBasisStatus.\n\nConstraintBasisStatus does not apply to VariableIndex constraints. You can infer the basis status of a VariableIndex constraint by looking at the result of VariableBasisStatus.\n\n\n\n\n\n","category":"type"},{"location":"reference/constraints/#MathOptInterface.ConstraintFunction","page":"Constraints","title":"MathOptInterface.ConstraintFunction","text":"ConstraintFunction()\n\nA constraint attribute for the AbstractFunction object used to define the constraint.\n\nIt is guaranteed to be equivalent but not necessarily identical to the function provided by the user.\n\n\n\n\n\n","category":"type"},{"location":"reference/constraints/#MathOptInterface.CanonicalConstraintFunction","page":"Constraints","title":"MathOptInterface.CanonicalConstraintFunction","text":"CanonicalConstraintFunction()\n\nA constraint attribute for a canonical representation of the AbstractFunction object used to define the constraint.\n\nGetting this attribute is guaranteed to return a function that is equivalent but not necessarily identical to the function provided by the user.\n\nBy default, MOI.get(model, MOI.CanonicalConstraintFunction(), ci) fallbacks to MOI.Utilities.canonical(MOI.get(model, MOI.ConstraintFunction(), ci)). However, if model knows that the constraint function is canonical then it can implement a specialized method that directly return the function without calling Utilities.canonical. Therefore, the value returned cannot be assumed to be a copy of the function stored in model. Moreover, Utilities.Model checks with Utilities.is_canonical whether the function stored internally is already canonical and if it's the case, then it returns the function stored internally instead of a copy.\n\n\n\n\n\n","category":"type"},{"location":"reference/constraints/#MathOptInterface.ConstraintSet","page":"Constraints","title":"MathOptInterface.ConstraintSet","text":"ConstraintSet()\n\nA constraint attribute for the AbstractSet object used to define the constraint.\n\n\n\n\n\n","category":"type"},{"location":"reference/constraints/#MathOptInterface.BasisStatusCode","page":"Constraints","title":"MathOptInterface.BasisStatusCode","text":"BasisStatusCode\n\nAn Enum of possible values for the ConstraintBasisStatus and VariableBasisStatus attributes, explaining the status of a given element with respect to an optimal solution basis.\n\nNotes\n\nNONBASIC_AT_LOWER and NONBASIC_AT_UPPER should be used only for\n\nconstraints with the Interval set. In this case, they are necessary to distinguish which side of the constraint is active. One-sided constraints (e.g., LessThan and GreaterThan) should use NONBASIC instead of the NONBASIC_AT_* values. This restriction does not apply to VariableBasisStatus, which should return NONBASIC_AT_* regardless of whether the alternative bound exists.\n\nIn linear programs, SUPER_BASIC occurs when a variable with no bounds is not\n\nin the basis.\n\nValues\n\nPossible values are:\n\nBASIC: element is in the basis\nNONBASIC: element is not in the basis\nNONBASIC_AT_LOWER: element is not in the basis and is at its lower bound\nNONBASIC_AT_UPPER: element is not in the basis and is at its upper bound\nSUPER_BASIC: element is not in the basis but is also not at one of its bounds\n\n\n\n\n\n","category":"type"},{"location":"reference/constraints/#MathOptInterface.BASIC","page":"Constraints","title":"MathOptInterface.BASIC","text":"BASIC::BasisStatusCode\n\nAn instance of the BasisStatusCode enum.\n\nBASIC: element is in the basis\n\n\n\n\n\n","category":"constant"},{"location":"reference/constraints/#MathOptInterface.NONBASIC","page":"Constraints","title":"MathOptInterface.NONBASIC","text":"NONBASIC::BasisStatusCode\n\nAn instance of the BasisStatusCode enum.\n\nNONBASIC: element is not in the basis\n\n\n\n\n\n","category":"constant"},{"location":"reference/constraints/#MathOptInterface.NONBASIC_AT_LOWER","page":"Constraints","title":"MathOptInterface.NONBASIC_AT_LOWER","text":"NONBASIC_AT_LOWER::BasisStatusCode\n\nAn instance of the BasisStatusCode enum.\n\nNONBASIC_AT_LOWER: element is not in the basis and is at its lower bound\n\n\n\n\n\n","category":"constant"},{"location":"reference/constraints/#MathOptInterface.NONBASIC_AT_UPPER","page":"Constraints","title":"MathOptInterface.NONBASIC_AT_UPPER","text":"NONBASIC_AT_UPPER::BasisStatusCode\n\nAn instance of the BasisStatusCode enum.\n\nNONBASIC_AT_UPPER: element is not in the basis and is at its upper bound\n\n\n\n\n\n","category":"constant"},{"location":"reference/constraints/#MathOptInterface.SUPER_BASIC","page":"Constraints","title":"MathOptInterface.SUPER_BASIC","text":"SUPER_BASIC::BasisStatusCode\n\nAn instance of the BasisStatusCode enum.\n\nSUPER_BASIC: element is not in the basis but is also not at one of its bounds\n\n\n\n\n\n","category":"constant"},{"location":"tutorials/implementing/","page":"Implementing a solver interface","title":"Implementing a solver interface","text":"CurrentModule = MathOptInterface\nDocTestSetup = quote\n import MathOptInterface as MOI\nend\nDocTestFilters = [r\"MathOptInterface|MOI\"]","category":"page"},{"location":"tutorials/implementing/#Implementing-a-solver-interface","page":"Implementing a solver interface","title":"Implementing a solver interface","text":"","category":"section"},{"location":"tutorials/implementing/","page":"Implementing a solver interface","title":"Implementing a solver interface","text":"This guide outlines the basic steps to implement an interface to MathOptInterface for a new solver.","category":"page"},{"location":"tutorials/implementing/","page":"Implementing a solver interface","title":"Implementing a solver interface","text":"danger: Danger\nImplementing an interface to MathOptInterface for a new solver is a lot of work. Before starting, we recommend that you join the Developer chatroom and explain a little bit about the solver you are wrapping. If you have questions that are not answered by this guide, please ask them in the Developer chatroom so we can improve this guide.","category":"page"},{"location":"tutorials/implementing/#A-note-on-the-API","page":"Implementing a solver interface","title":"A note on the API","text":"","category":"section"},{"location":"tutorials/implementing/","page":"Implementing a solver interface","title":"Implementing a solver interface","text":"The API of MathOptInterface is large and varied. In order to support the diversity of solvers and use-cases, we make heavy use of duck-typing. That is, solvers are not expected to implement the full API, nor is there a well-defined minimal subset of what must be implemented. Instead, you should implement the API as necessary to make the solver function as you require.","category":"page"},{"location":"tutorials/implementing/","page":"Implementing a solver interface","title":"Implementing a solver interface","text":"The main reason for using duck-typing is that solvers work in different ways and target different use-cases.","category":"page"},{"location":"tutorials/implementing/","page":"Implementing a solver interface","title":"Implementing a solver interface","text":"For example:","category":"page"},{"location":"tutorials/implementing/","page":"Implementing a solver interface","title":"Implementing a solver interface","text":"Some solvers support incremental problem construction, support modification after a solve, and have native support for things like variable names.\nOther solvers are \"one-shot\" solvers that require all of the problem data to construct and solve the problem in a single function call. They do not support modification or things like variable names.\nOther \"solvers\" are not solvers at all, but things like file readers. These may only support functions like read_from_file, and may not even support the ability to add variables or constraints directly.\nFinally, some \"solvers\" are layers which take a problem as input, transform it according to some rules, and pass the transformed problem to an inner solver.","category":"page"},{"location":"tutorials/implementing/#Preliminaries","page":"Implementing a solver interface","title":"Preliminaries","text":"","category":"section"},{"location":"tutorials/implementing/","page":"Implementing a solver interface","title":"Implementing a solver interface","text":"Before starting on your wrapper, you should do some background research and make the solver accessible via Julia.","category":"page"},{"location":"tutorials/implementing/#Decide-if-MathOptInterface-is-right-for-you","page":"Implementing a solver interface","title":"Decide if MathOptInterface is right for you","text":"","category":"section"},{"location":"tutorials/implementing/","page":"Implementing a solver interface","title":"Implementing a solver interface","text":"The first step in writing a wrapper is to decide whether implementing an interface is the right thing to do.","category":"page"},{"location":"tutorials/implementing/","page":"Implementing a solver interface","title":"Implementing a solver interface","text":"MathOptInterface is an abstraction layer for unifying constrained mathematical optimization solvers. If your solver doesn't fit in the category, for example, it implements a derivative-free algorithm for unconstrained objective functions, MathOptInterface may not be the right tool for the job.","category":"page"},{"location":"tutorials/implementing/","page":"Implementing a solver interface","title":"Implementing a solver interface","text":"tip: Tip\nIf you're not sure whether you should write an interface, ask in the Developer chatroom.","category":"page"},{"location":"tutorials/implementing/#Find-a-similar-solver-already-wrapped","page":"Implementing a solver interface","title":"Find a similar solver already wrapped","text":"","category":"section"},{"location":"tutorials/implementing/","page":"Implementing a solver interface","title":"Implementing a solver interface","text":"The next step is to find (if possible) a similar solver that is already wrapped. Although not strictly necessary, this will be a good place to look for inspiration when implementing your wrapper.","category":"page"},{"location":"tutorials/implementing/","page":"Implementing a solver interface","title":"Implementing a solver interface","text":"The JuMP documentation has a good list of solvers, along with the problem classes they support.","category":"page"},{"location":"tutorials/implementing/","page":"Implementing a solver interface","title":"Implementing a solver interface","text":"tip: Tip\nIf you're not sure which solver is most similar, ask in the Developer chatroom.","category":"page"},{"location":"tutorials/implementing/#Create-a-low-level-interface","page":"Implementing a solver interface","title":"Create a low-level interface","text":"","category":"section"},{"location":"tutorials/implementing/","page":"Implementing a solver interface","title":"Implementing a solver interface","text":"Before writing a MathOptInterface wrapper, you first need to be able to call the solver from Julia.","category":"page"},{"location":"tutorials/implementing/#Wrapping-solvers-written-in-Julia","page":"Implementing a solver interface","title":"Wrapping solvers written in Julia","text":"","category":"section"},{"location":"tutorials/implementing/","page":"Implementing a solver interface","title":"Implementing a solver interface","text":"If your solver is written in Julia, there's nothing to do here. Go to the next section.","category":"page"},{"location":"tutorials/implementing/#Wrapping-solvers-written-in-C","page":"Implementing a solver interface","title":"Wrapping solvers written in C","text":"","category":"section"},{"location":"tutorials/implementing/","page":"Implementing a solver interface","title":"Implementing a solver interface","text":"Julia is well suited to wrapping solvers written in C.","category":"page"},{"location":"tutorials/implementing/","page":"Implementing a solver interface","title":"Implementing a solver interface","text":"info: Info\nThis is not true for C++. If you have a solver written in C++, first write a C interface, then wrap the C interface.","category":"page"},{"location":"tutorials/implementing/","page":"Implementing a solver interface","title":"Implementing a solver interface","text":"Before writing a MathOptInterface wrapper, there are a few extra steps.","category":"page"},{"location":"tutorials/implementing/#Create-a-JLL","page":"Implementing a solver interface","title":"Create a JLL","text":"","category":"section"},{"location":"tutorials/implementing/","page":"Implementing a solver interface","title":"Implementing a solver interface","text":"If the C code is publicly available under an open source license, create a JLL package via Yggdrasil. The easiest way to do this is to copy an existing solver. Good examples to follow are the COIN-OR solvers.","category":"page"},{"location":"tutorials/implementing/","page":"Implementing a solver interface","title":"Implementing a solver interface","text":"warning: Warning\nBuilding the solver via Yggdrasil is non-trivial. Please ask the Developer chatroom for help.","category":"page"},{"location":"tutorials/implementing/","page":"Implementing a solver interface","title":"Implementing a solver interface","text":"If the code is commercial or not publicly available, the user will need to manually install the solver. See Gurobi.jl or CPLEX.jl for examples of how to structure this.","category":"page"},{"location":"tutorials/implementing/#implement_clang","page":"Implementing a solver interface","title":"Use Clang.jl to wrap the C API","text":"","category":"section"},{"location":"tutorials/implementing/","page":"Implementing a solver interface","title":"Implementing a solver interface","text":"The next step is to use Clang.jl to automatically wrap the C API. The easiest way to do this is to follow an example. Good examples to follow are Cbc.jl and HiGHS.jl.","category":"page"},{"location":"tutorials/implementing/","page":"Implementing a solver interface","title":"Implementing a solver interface","text":"Sometimes, you will need to make manual modifications to the resulting files.","category":"page"},{"location":"tutorials/implementing/#Solvers-written-in-other-languages","page":"Implementing a solver interface","title":"Solvers written in other languages","text":"","category":"section"},{"location":"tutorials/implementing/","page":"Implementing a solver interface","title":"Implementing a solver interface","text":"Ask the Developer chatroom for advice. You may be able to use one of the JuliaInterop packages to call out to the solver.","category":"page"},{"location":"tutorials/implementing/","page":"Implementing a solver interface","title":"Implementing a solver interface","text":"For example, SeDuMi.jl uses MATLAB.jl to call the SeDuMi solver written in MATLAB.","category":"page"},{"location":"tutorials/implementing/#Structuring-the-package","page":"Implementing a solver interface","title":"Structuring the package","text":"","category":"section"},{"location":"tutorials/implementing/","page":"Implementing a solver interface","title":"Implementing a solver interface","text":"Structure your wrapper as a Julia package. Consult the Julia documentation if you haven't done this before.","category":"page"},{"location":"tutorials/implementing/","page":"Implementing a solver interface","title":"Implementing a solver interface","text":"MOI solver interfaces may be in the same package as the solver itself (either the C wrapper if the solver is accessible through C, or the Julia code if the solver is written in Julia, for example), or in a separate package which depends on the solver package.","category":"page"},{"location":"tutorials/implementing/","page":"Implementing a solver interface","title":"Implementing a solver interface","text":"note: Note\nThe JuMP core contributors request that you do not use \"JuMP\" in the name of your package without prior consent.","category":"page"},{"location":"tutorials/implementing/","page":"Implementing a solver interface","title":"Implementing a solver interface","text":"Your package should have the following structure:","category":"page"},{"location":"tutorials/implementing/","page":"Implementing a solver interface","title":"Implementing a solver interface","text":"/.github\n /workflows\n ci.yml\n format_check.yml\n TagBot.yml\n/gen\n gen.jl # Code to wrap the C API\n/src\n NewSolver.jl\n /gen\n libnewsolver_api.jl\n libnewsolver_common.jl\n /MOI_wrapper\n MOI_wrapper.jl\n other_files.jl\n/test\n runtests.jl\n /MOI_wrapper\n MOI_wrapper.jl\n.gitignore\n.JuliaFormatter.toml\nREADME.md\nLICENSE.md\nProject.toml","category":"page"},{"location":"tutorials/implementing/","page":"Implementing a solver interface","title":"Implementing a solver interface","text":"The /.github folder contains the scripts for GitHub actions. The easiest way to write these is to copy the ones from an existing solver.\nThe /gen and /src/gen folders are only needed if you are wrapping a solver written in C.\nThe /src/MOI_wrapper folder contains the Julia code for the MOI wrapper.\nThe /test folder contains code for testing your package. See Setup tests for more information.\nThe .JuliaFormatter.toml and .github/workflows/format_check.yml enforce code formatting using JuliaFormatter.jl. Check existing solvers or JuMP.jl for details.","category":"page"},{"location":"tutorials/implementing/#Documentation","page":"Implementing a solver interface","title":"Documentation","text":"","category":"section"},{"location":"tutorials/implementing/","page":"Implementing a solver interface","title":"Implementing a solver interface","text":"Your package must include documentation explaining how to use the package. The easiest approach is to include documentation in your README.md. A more involved option is to use Documenter.jl.","category":"page"},{"location":"tutorials/implementing/","page":"Implementing a solver interface","title":"Implementing a solver interface","text":"Examples of packages with README-based documentation include:","category":"page"},{"location":"tutorials/implementing/","page":"Implementing a solver interface","title":"Implementing a solver interface","text":"Cbc.jl\nHiGHS.jl\nSCS.jl","category":"page"},{"location":"tutorials/implementing/","page":"Implementing a solver interface","title":"Implementing a solver interface","text":"Examples of packages with Documenter-based documentation include:","category":"page"},{"location":"tutorials/implementing/","page":"Implementing a solver interface","title":"Implementing a solver interface","text":"Alpine.jl\nCOSMO.jl\nJuniper.jl","category":"page"},{"location":"tutorials/implementing/#Setup-tests","page":"Implementing a solver interface","title":"Setup tests","text":"","category":"section"},{"location":"tutorials/implementing/","page":"Implementing a solver interface","title":"Implementing a solver interface","text":"The best way to implement an interface to MathOptInterface is via test-driven development.","category":"page"},{"location":"tutorials/implementing/","page":"Implementing a solver interface","title":"Implementing a solver interface","text":"The MOI.Test submodule contains a large test suite to help check that you have implemented things correctly.","category":"page"},{"location":"tutorials/implementing/","page":"Implementing a solver interface","title":"Implementing a solver interface","text":"Follow the guide How to test a solver to set up the tests for your package.","category":"page"},{"location":"tutorials/implementing/","page":"Implementing a solver interface","title":"Implementing a solver interface","text":"tip: Tip\nRun the tests frequently when developing. However, at the start there is going to be a lot of errors. Start by excluding large classes of tests (for example, exclude = [\"test_basic_\", \"test_model_\"], implement any missing methods until the tests pass, then remove an exclusion and repeat.","category":"page"},{"location":"tutorials/implementing/#Initial-code","page":"Implementing a solver interface","title":"Initial code","text":"","category":"section"},{"location":"tutorials/implementing/","page":"Implementing a solver interface","title":"Implementing a solver interface","text":"By this point, you should have a package setup with tests, formatting, and access to the underlying solver. Now it's time to start writing the wrapper.","category":"page"},{"location":"tutorials/implementing/#The-Optimizer-object","page":"Implementing a solver interface","title":"The Optimizer object","text":"","category":"section"},{"location":"tutorials/implementing/","page":"Implementing a solver interface","title":"Implementing a solver interface","text":"The first object to create is a subtype of AbstractOptimizer. This type is going to store everything related to the problem.","category":"page"},{"location":"tutorials/implementing/","page":"Implementing a solver interface","title":"Implementing a solver interface","text":"By convention, these optimizers should not be exported and should be named PackageName.Optimizer.","category":"page"},{"location":"tutorials/implementing/","page":"Implementing a solver interface","title":"Implementing a solver interface","text":"import MathOptInterface as MOI\n\nstruct Optimizer <: MOI.AbstractOptimizer\n # Fields go here\nend","category":"page"},{"location":"tutorials/implementing/#Optimizer-objects-for-C-solvers","page":"Implementing a solver interface","title":"Optimizer objects for C solvers","text":"","category":"section"},{"location":"tutorials/implementing/","page":"Implementing a solver interface","title":"Implementing a solver interface","text":"warning: Warning\nThis section is important if you wrap a solver written in C.","category":"page"},{"location":"tutorials/implementing/","page":"Implementing a solver interface","title":"Implementing a solver interface","text":"Wrapping a solver written in C will require the use of pointers, and for you to manually free the solver's memory when the Optimizer is garbage collected by Julia.","category":"page"},{"location":"tutorials/implementing/","page":"Implementing a solver interface","title":"Implementing a solver interface","text":"Never pass a pointer directly to a Julia ccall function.","category":"page"},{"location":"tutorials/implementing/","page":"Implementing a solver interface","title":"Implementing a solver interface","text":"Instead, store the pointer as a field in your Optimizer, and implement Base.cconvert and Base.unsafe_convert. Then you can pass Optimizer to any ccall function that expects the pointer.","category":"page"},{"location":"tutorials/implementing/","page":"Implementing a solver interface","title":"Implementing a solver interface","text":"In addition, make sure you implement a finalizer for each model you create.","category":"page"},{"location":"tutorials/implementing/","page":"Implementing a solver interface","title":"Implementing a solver interface","text":"If newsolver_createProblem() is the low-level function that creates the problem pointer in C, and newsolver_freeProblem(::Ptr{Cvoid}) is the low-level function that frees memory associated with the pointer, your Optimizer() function should look like this:","category":"page"},{"location":"tutorials/implementing/","page":"Implementing a solver interface","title":"Implementing a solver interface","text":"struct Optimizer <: MOI.AbstractOptimizer\n ptr::Ptr{Cvoid}\n\n function Optimizer()\n ptr = newsolver_createProblem()\n model = Optimizer(ptr)\n finalizer(model) do m\n newsolver_freeProblem(m)\n return\n end\n return model\n end\nend\n\nBase.cconvert(::Type{Ptr{Cvoid}}, model::Optimizer) = model\nBase.unsafe_convert(::Type{Ptr{Cvoid}}, model::Optimizer) = model.ptr","category":"page"},{"location":"tutorials/implementing/#Implement-methods-for-Optimizer","page":"Implementing a solver interface","title":"Implement methods for Optimizer","text":"","category":"section"},{"location":"tutorials/implementing/","page":"Implementing a solver interface","title":"Implementing a solver interface","text":"All Optimizers must implement the following methods:","category":"page"},{"location":"tutorials/implementing/","page":"Implementing a solver interface","title":"Implementing a solver interface","text":"empty!\nis_empty","category":"page"},{"location":"tutorials/implementing/","page":"Implementing a solver interface","title":"Implementing a solver interface","text":"Other methods, detailed below, are optional or depend on how you implement the interface.","category":"page"},{"location":"tutorials/implementing/","page":"Implementing a solver interface","title":"Implementing a solver interface","text":"tip: Tip\nFor this and all future methods, read the docstrings to understand what each method does, what it expects as input, and what it produces as output. If it isn't clear, let us know and we will improve the docstrings. It is also very helpful to look at an existing wrapper for a similar solver.","category":"page"},{"location":"tutorials/implementing/","page":"Implementing a solver interface","title":"Implementing a solver interface","text":"You should also implement Base.show(::IO, ::Optimizer) to print a nice string when someone prints your model. For example","category":"page"},{"location":"tutorials/implementing/","page":"Implementing a solver interface","title":"Implementing a solver interface","text":"function Base.show(io::IO, model::Optimizer)\n return print(io, \"NewSolver with the pointer $(model.ptr)\")\nend","category":"page"},{"location":"tutorials/implementing/#Implement-attributes","page":"Implementing a solver interface","title":"Implement attributes","text":"","category":"section"},{"location":"tutorials/implementing/","page":"Implementing a solver interface","title":"Implementing a solver interface","text":"MathOptInterface uses attributes to manage different aspects of the problem.","category":"page"},{"location":"tutorials/implementing/","page":"Implementing a solver interface","title":"Implementing a solver interface","text":"For each attribute","category":"page"},{"location":"tutorials/implementing/","page":"Implementing a solver interface","title":"Implementing a solver interface","text":"get gets the current value of the attribute\nset sets a new value of the attribute. Not all attributes can be set. For example, the user can't modify the SolverName.\nsupports returns a Bool indicating whether the solver supports the attribute.","category":"page"},{"location":"tutorials/implementing/","page":"Implementing a solver interface","title":"Implementing a solver interface","text":"info: Info\nUse attribute_value_type to check the value expected by a given attribute. You should make sure that your get function correctly infers to this type (or a subtype of it).","category":"page"},{"location":"tutorials/implementing/","page":"Implementing a solver interface","title":"Implementing a solver interface","text":"Each column in the table indicates whether you need to implement the particular method for each attribute.","category":"page"},{"location":"tutorials/implementing/","page":"Implementing a solver interface","title":"Implementing a solver interface","text":"Attribute get set supports\nSolverName Yes No No\nSolverVersion Yes No No\nRawSolver Yes No No\nName Yes Yes Yes\nSilent Yes Yes Yes\nTimeLimitSec Yes Yes Yes\nObjectiveLimit Yes Yes Yes\nRawOptimizerAttribute Yes Yes Yes\nNumberOfThreads Yes Yes Yes\nAbsoluteGapTolerance Yes Yes Yes\nRelativeGapTolerance Yes Yes Yes","category":"page"},{"location":"tutorials/implementing/","page":"Implementing a solver interface","title":"Implementing a solver interface","text":"For example:","category":"page"},{"location":"tutorials/implementing/","page":"Implementing a solver interface","title":"Implementing a solver interface","text":"function MOI.get(model::Optimizer, ::MOI.Silent)\n return # true if MOI.Silent is set\nend\n\nfunction MOI.set(model::Optimizer, ::MOI.Silent, v::Bool)\n if v\n # Set a parameter to turn off printing\n else\n # Restore the default printing\n end\n return\nend\n\nMOI.supports(::Optimizer, ::MOI.Silent) = true","category":"page"},{"location":"tutorials/implementing/#Define-supports_constraint","page":"Implementing a solver interface","title":"Define supports_constraint","text":"","category":"section"},{"location":"tutorials/implementing/","page":"Implementing a solver interface","title":"Implementing a solver interface","text":"The next step is to define which constraints and objective functions you plan to support.","category":"page"},{"location":"tutorials/implementing/","page":"Implementing a solver interface","title":"Implementing a solver interface","text":"For each function-set constraint pair, define supports_constraint:","category":"page"},{"location":"tutorials/implementing/","page":"Implementing a solver interface","title":"Implementing a solver interface","text":"function MOI.supports_constraint(\n ::Optimizer,\n ::Type{MOI.VariableIndex},\n ::Type{MOI.ZeroOne},\n)\n return true\nend","category":"page"},{"location":"tutorials/implementing/","page":"Implementing a solver interface","title":"Implementing a solver interface","text":"To make this easier, you may want to use Unions:","category":"page"},{"location":"tutorials/implementing/","page":"Implementing a solver interface","title":"Implementing a solver interface","text":"function MOI.supports_constraint(\n ::Optimizer,\n ::Type{MOI.VariableIndex},\n ::Type{<:Union{MOI.LessThan,MOI.GreaterThan,MOI.EqualTo}},\n)\n return true\nend","category":"page"},{"location":"tutorials/implementing/","page":"Implementing a solver interface","title":"Implementing a solver interface","text":"tip: Tip\nOnly support a constraint if your solver has native support for it.","category":"page"},{"location":"tutorials/implementing/#The-big-decision:-incremental-modification?","page":"Implementing a solver interface","title":"The big decision: incremental modification?","text":"","category":"section"},{"location":"tutorials/implementing/","page":"Implementing a solver interface","title":"Implementing a solver interface","text":"Now you need to decide whether to support incremental modification or not.","category":"page"},{"location":"tutorials/implementing/","page":"Implementing a solver interface","title":"Implementing a solver interface","text":"Incremental modification means that the user can add variables and constraints one-by-one without needing to rebuild the entire problem, and they can modify the problem data after an optimize! call. Supporting incremental modification means implementing functions like add_variable and add_constraint.","category":"page"},{"location":"tutorials/implementing/","page":"Implementing a solver interface","title":"Implementing a solver interface","text":"The alternative is to accept the problem data in a single optimize! or copy_to function call. Because these functions see all of the data at once, it can typically call a more efficient function to load data into the underlying solver.","category":"page"},{"location":"tutorials/implementing/","page":"Implementing a solver interface","title":"Implementing a solver interface","text":"Good examples of solvers supporting incremental modification are MILP solvers like GLPK.jl and Gurobi.jl. Examples of non-incremental solvers are AmplNLWriter.jl and SCS.jl","category":"page"},{"location":"tutorials/implementing/","page":"Implementing a solver interface","title":"Implementing a solver interface","text":"It is possible for a solver to implement both approaches, but you should probably start with one for simplicity.","category":"page"},{"location":"tutorials/implementing/","page":"Implementing a solver interface","title":"Implementing a solver interface","text":"tip: Tip\nOnly support incremental modification if your solver has native support for it.","category":"page"},{"location":"tutorials/implementing/","page":"Implementing a solver interface","title":"Implementing a solver interface","text":"In general, supporting incremental modification is more work, and it usually requires some extra book-keeping. However, it provides a more efficient interface to the solver if the problem is going to be resolved multiple times with small modifications. Moreover, once you've implemented incremental modification, it's usually not much extra work to add a copy_to interface. The converse is not true.","category":"page"},{"location":"tutorials/implementing/","page":"Implementing a solver interface","title":"Implementing a solver interface","text":"tip: Tip\nIf this is your first time writing an interface, start with the one-shot optimize!.","category":"page"},{"location":"tutorials/implementing/#The-non-incremental-interface","page":"Implementing a solver interface","title":"The non-incremental interface","text":"","category":"section"},{"location":"tutorials/implementing/","page":"Implementing a solver interface","title":"Implementing a solver interface","text":"There are two ways to implement the non-incremental interface. The first uses a two-argument version of optimize!, the second implements copy_to followed by the one-argument version of optimize!.","category":"page"},{"location":"tutorials/implementing/","page":"Implementing a solver interface","title":"Implementing a solver interface","text":"If your solver does not support modification, and requires all data to solve the problem in a single function call, you should implement the \"one-shot\" optimize!.","category":"page"},{"location":"tutorials/implementing/","page":"Implementing a solver interface","title":"Implementing a solver interface","text":"optimize!(::ModelLike, ::ModelLike)","category":"page"},{"location":"tutorials/implementing/","page":"Implementing a solver interface","title":"Implementing a solver interface","text":"If your solver separates data loading and the actual optimization into separate steps, implement the copy_to interface.","category":"page"},{"location":"tutorials/implementing/","page":"Implementing a solver interface","title":"Implementing a solver interface","text":"copy_to(::ModelLike, ::ModelLike)\noptimize!(::ModelLike)","category":"page"},{"location":"tutorials/implementing/#The-incremental-interface","page":"Implementing a solver interface","title":"The incremental interface","text":"","category":"section"},{"location":"tutorials/implementing/","page":"Implementing a solver interface","title":"Implementing a solver interface","text":"warning: Warning\nWriting this interface is a lot of work. The easiest way is to consult the source code of a similar solver.","category":"page"},{"location":"tutorials/implementing/","page":"Implementing a solver interface","title":"Implementing a solver interface","text":"To implement the incremental interface, implement the following functions:","category":"page"},{"location":"tutorials/implementing/","page":"Implementing a solver interface","title":"Implementing a solver interface","text":"add_variable\nadd_variables\nadd_constraint\nadd_constraints\nis_valid\ndelete\noptimize!(::ModelLike)","category":"page"},{"location":"tutorials/implementing/","page":"Implementing a solver interface","title":"Implementing a solver interface","text":"info: Info\nSolvers do not have to support AbstractScalarFunction in GreaterThan, LessThan, EqualTo, or Interval with a nonzero constant in the function. Throw ScalarFunctionConstantNotZero if the function constant is not zero.","category":"page"},{"location":"tutorials/implementing/","page":"Implementing a solver interface","title":"Implementing a solver interface","text":"In addition, you should implement the following model attributes:","category":"page"},{"location":"tutorials/implementing/","page":"Implementing a solver interface","title":"Implementing a solver interface","text":"Attribute get set supports\nListOfModelAttributesSet Yes No No\nObjectiveFunctionType Yes No No\nObjectiveFunction Yes Yes Yes\nObjectiveSense Yes Yes Yes\nName Yes Yes Yes","category":"page"},{"location":"tutorials/implementing/","page":"Implementing a solver interface","title":"Implementing a solver interface","text":"Variable-related attributes:","category":"page"},{"location":"tutorials/implementing/","page":"Implementing a solver interface","title":"Implementing a solver interface","text":"Attribute get set supports\nListOfVariableAttributesSet Yes No No\nNumberOfVariables Yes No No\nListOfVariableIndices Yes No No","category":"page"},{"location":"tutorials/implementing/","page":"Implementing a solver interface","title":"Implementing a solver interface","text":"Constraint-related attributes:","category":"page"},{"location":"tutorials/implementing/","page":"Implementing a solver interface","title":"Implementing a solver interface","text":"Attribute get set supports\nListOfConstraintAttributesSet Yes No No\nNumberOfConstraints Yes No No\nListOfConstraintTypesPresent Yes No No\nConstraintFunction Yes Yes No\nConstraintSet Yes Yes No","category":"page"},{"location":"tutorials/implementing/#Modifications","page":"Implementing a solver interface","title":"Modifications","text":"","category":"section"},{"location":"tutorials/implementing/","page":"Implementing a solver interface","title":"Implementing a solver interface","text":"If your solver supports modifying data in-place, implement modify for the following AbstractModifications:","category":"page"},{"location":"tutorials/implementing/","page":"Implementing a solver interface","title":"Implementing a solver interface","text":"ScalarConstantChange\nScalarCoefficientChange\nVectorConstantChange\nMultirowChange","category":"page"},{"location":"tutorials/implementing/#Variables-constrained-on-creation","page":"Implementing a solver interface","title":"Variables constrained on creation","text":"","category":"section"},{"location":"tutorials/implementing/","page":"Implementing a solver interface","title":"Implementing a solver interface","text":"Some solvers require variables be associated with a set when they are created. This conflicts with the incremental modification approach, since you cannot first add a free variable and then constrain it to the set.","category":"page"},{"location":"tutorials/implementing/","page":"Implementing a solver interface","title":"Implementing a solver interface","text":"If this is the case, implement:","category":"page"},{"location":"tutorials/implementing/","page":"Implementing a solver interface","title":"Implementing a solver interface","text":"add_constrained_variable\nadd_constrained_variables\nsupports_add_constrained_variables","category":"page"},{"location":"tutorials/implementing/","page":"Implementing a solver interface","title":"Implementing a solver interface","text":"By default, MathOptInterface assumes solvers support free variables. If your solver does not support free variables, define:","category":"page"},{"location":"tutorials/implementing/","page":"Implementing a solver interface","title":"Implementing a solver interface","text":"MOI.supports_add_constrained_variables(::Optimizer, ::Type{Reals}) = false","category":"page"},{"location":"tutorials/implementing/#Incremental-and-copy_to","page":"Implementing a solver interface","title":"Incremental and copy_to","text":"","category":"section"},{"location":"tutorials/implementing/","page":"Implementing a solver interface","title":"Implementing a solver interface","text":"If you implement the incremental interface, you have the option of also implementing copy_to.","category":"page"},{"location":"tutorials/implementing/","page":"Implementing a solver interface","title":"Implementing a solver interface","text":"If you don't want to implement copy_to, for example, because the solver has no API for building the problem in a single function call, define the following fallback:","category":"page"},{"location":"tutorials/implementing/","page":"Implementing a solver interface","title":"Implementing a solver interface","text":"MOI.supports_incremental_interface(::Optimizer) = true\n\nfunction MOI.copy_to(dest::Optimizer, src::MOI.ModelLike)\n return MOI.Utilities.default_copy_to(dest, src)\nend","category":"page"},{"location":"tutorials/implementing/#implement_names","page":"Implementing a solver interface","title":"Names","text":"","category":"section"},{"location":"tutorials/implementing/","page":"Implementing a solver interface","title":"Implementing a solver interface","text":"Regardless of which interface you implement, you have the option of implementing the Name attribute for variables and constraints:","category":"page"},{"location":"tutorials/implementing/","page":"Implementing a solver interface","title":"Implementing a solver interface","text":"Attribute get set supports\nVariableName Yes Yes Yes\nConstraintName Yes Yes Yes","category":"page"},{"location":"tutorials/implementing/","page":"Implementing a solver interface","title":"Implementing a solver interface","text":"If you implement names, you must also implement the following three methods:","category":"page"},{"location":"tutorials/implementing/","page":"Implementing a solver interface","title":"Implementing a solver interface","text":"function MOI.get(model::Optimizer, ::Type{MOI.VariableIndex}, name::String)\n return # The variable named `name`.\nend\n\nfunction MOI.get(model::Optimizer, ::Type{MOI.ConstraintIndex}, name::String)\n return # The constraint any type named `name`.\nend\n\nfunction MOI.get(\n model::Optimizer,\n ::Type{MOI.ConstraintIndex{F,S}},\n name::String,\n) where {F,S}\n return # The constraint of type F-in-S named `name`.\nend","category":"page"},{"location":"tutorials/implementing/","page":"Implementing a solver interface","title":"Implementing a solver interface","text":"These methods have the following rules:","category":"page"},{"location":"tutorials/implementing/","page":"Implementing a solver interface","title":"Implementing a solver interface","text":"If there is no variable or constraint with the name, return nothing\nIf there is a single variable or constraint with that name, return the variable or constraint\nIf there are multiple variables or constraints with the name, throw an error.","category":"page"},{"location":"tutorials/implementing/","page":"Implementing a solver interface","title":"Implementing a solver interface","text":"warning: Warning\nYou should not implement ConstraintName for VariableIndex constraints. If you implement ConstraintName for other constraints, you can add the following two methods to disable ConstraintName for VariableIndex constraints.function MOI.supports(\n ::Optimizer,\n ::MOI.ConstraintName,\n ::Type{<:MOI.ConstraintIndex{MOI.VariableIndex,<:MOI.AbstractScalarSet}},\n)\n return throw(MOI.VariableIndexConstraintNameError())\nend\nfunction MOI.set(\n ::Optimizer,\n ::MOI.ConstraintName,\n ::MOI.ConstraintIndex{MOI.VariableIndex,<:MOI.AbstractScalarSet},\n ::String,\n)\n return throw(MOI.VariableIndexConstraintNameError())\nend","category":"page"},{"location":"tutorials/implementing/#Solutions","page":"Implementing a solver interface","title":"Solutions","text":"","category":"section"},{"location":"tutorials/implementing/","page":"Implementing a solver interface","title":"Implementing a solver interface","text":"Implement optimize! to solve the model:","category":"page"},{"location":"tutorials/implementing/","page":"Implementing a solver interface","title":"Implementing a solver interface","text":"optimize!","category":"page"},{"location":"tutorials/implementing/","page":"Implementing a solver interface","title":"Implementing a solver interface","text":"All Optimizers must implement the following attributes:","category":"page"},{"location":"tutorials/implementing/","page":"Implementing a solver interface","title":"Implementing a solver interface","text":"DualStatus\nPrimalStatus\nRawStatusString\nResultCount\nTerminationStatus","category":"page"},{"location":"tutorials/implementing/","page":"Implementing a solver interface","title":"Implementing a solver interface","text":"info: Info\nYou only need to implement get for solution attributes. Don't implement set or supports.","category":"page"},{"location":"tutorials/implementing/","page":"Implementing a solver interface","title":"Implementing a solver interface","text":"note: Note\nSolver wrappers should document how the low-level statuses map to the MOI statuses. Statuses like NEARLY_FEASIBLE_POINT and INFEASIBLE_POINT, are designed to be used when the solver explicitly indicates that relaxed tolerances are satisfied or the returned point is infeasible, respectively.","category":"page"},{"location":"tutorials/implementing/","page":"Implementing a solver interface","title":"Implementing a solver interface","text":"You should also implement the following attributes:","category":"page"},{"location":"tutorials/implementing/","page":"Implementing a solver interface","title":"Implementing a solver interface","text":"ObjectiveValue\nSolveTimeSec\nVariablePrimal","category":"page"},{"location":"tutorials/implementing/","page":"Implementing a solver interface","title":"Implementing a solver interface","text":"tip: Tip\nAttributes like VariablePrimal and ObjectiveValue are indexed by the result count. Use MOI.check_result_index_bounds(model, attr) to throw an error if the attribute is not available.","category":"page"},{"location":"tutorials/implementing/","page":"Implementing a solver interface","title":"Implementing a solver interface","text":"If your solver returns dual solutions, implement:","category":"page"},{"location":"tutorials/implementing/","page":"Implementing a solver interface","title":"Implementing a solver interface","text":"ConstraintDual\nDualObjectiveValue","category":"page"},{"location":"tutorials/implementing/","page":"Implementing a solver interface","title":"Implementing a solver interface","text":"For integer solvers, implement:","category":"page"},{"location":"tutorials/implementing/","page":"Implementing a solver interface","title":"Implementing a solver interface","text":"ObjectiveBound\nRelativeGap","category":"page"},{"location":"tutorials/implementing/","page":"Implementing a solver interface","title":"Implementing a solver interface","text":"If applicable, implement:","category":"page"},{"location":"tutorials/implementing/","page":"Implementing a solver interface","title":"Implementing a solver interface","text":"SimplexIterations\nBarrierIterations\nNodeCount","category":"page"},{"location":"tutorials/implementing/","page":"Implementing a solver interface","title":"Implementing a solver interface","text":"If your solver uses the Simplex method, implement:","category":"page"},{"location":"tutorials/implementing/","page":"Implementing a solver interface","title":"Implementing a solver interface","text":"ConstraintBasisStatus","category":"page"},{"location":"tutorials/implementing/","page":"Implementing a solver interface","title":"Implementing a solver interface","text":"If your solver accepts primal or dual warm-starts, implement:","category":"page"},{"location":"tutorials/implementing/","page":"Implementing a solver interface","title":"Implementing a solver interface","text":"VariablePrimalStart\nConstraintDualStart","category":"page"},{"location":"tutorials/implementing/#Other-tips","page":"Implementing a solver interface","title":"Other tips","text":"","category":"section"},{"location":"tutorials/implementing/","page":"Implementing a solver interface","title":"Implementing a solver interface","text":"Here are some other points to be aware of when writing your wrapper.","category":"page"},{"location":"tutorials/implementing/#Unsupported-constraints-at-runtime","page":"Implementing a solver interface","title":"Unsupported constraints at runtime","text":"","category":"section"},{"location":"tutorials/implementing/","page":"Implementing a solver interface","title":"Implementing a solver interface","text":"In some cases, your solver may support a particular type of constraint (for example, quadratic constraints), but only if the data meets some condition (for example, it is convex).","category":"page"},{"location":"tutorials/implementing/","page":"Implementing a solver interface","title":"Implementing a solver interface","text":"In this case, declare that you support the constraint, and throw AddConstraintNotAllowed.","category":"page"},{"location":"tutorials/implementing/#Dealing-with-multiple-variable-bounds","page":"Implementing a solver interface","title":"Dealing with multiple variable bounds","text":"","category":"section"},{"location":"tutorials/implementing/","page":"Implementing a solver interface","title":"Implementing a solver interface","text":"MathOptInterface uses VariableIndex constraints to represent variable bounds. Defining multiple variable bounds on a single variable is not allowed.","category":"page"},{"location":"tutorials/implementing/","page":"Implementing a solver interface","title":"Implementing a solver interface","text":"Throw LowerBoundAlreadySet or UpperBoundAlreadySet if the user adds a constraint that results in multiple bounds.","category":"page"},{"location":"tutorials/implementing/","page":"Implementing a solver interface","title":"Implementing a solver interface","text":"Only throw if the constraints conflict. It is okay to add VariableIndex-in-GreaterThan and then VariableIndex-in-LessThan, but not VariableIndex-in-Interval and then VariableIndex-in-LessThan,","category":"page"},{"location":"tutorials/implementing/#Expect-duplicate-coefficients","page":"Implementing a solver interface","title":"Expect duplicate coefficients","text":"","category":"section"},{"location":"tutorials/implementing/","page":"Implementing a solver interface","title":"Implementing a solver interface","text":"Solvers must expect that functions such as ScalarAffineFunction and VectorQuadraticFunction may contain duplicate coefficients.","category":"page"},{"location":"tutorials/implementing/","page":"Implementing a solver interface","title":"Implementing a solver interface","text":"For example, ScalarAffineFunction([ScalarAffineTerm(x, 1), ScalarAffineTerm(x, 1)], 0.0).","category":"page"},{"location":"tutorials/implementing/","page":"Implementing a solver interface","title":"Implementing a solver interface","text":"Use Utilities.canonical to return a new function with the duplicate coefficients aggregated together.","category":"page"},{"location":"tutorials/implementing/#Don't-modify-user-data","page":"Implementing a solver interface","title":"Don't modify user-data","text":"","category":"section"},{"location":"tutorials/implementing/","page":"Implementing a solver interface","title":"Implementing a solver interface","text":"All data passed to the solver must be copied immediately to internal data structures. Solvers may not modify any input vectors and must assume that input vectors will not be modified by users in the future.","category":"page"},{"location":"tutorials/implementing/","page":"Implementing a solver interface","title":"Implementing a solver interface","text":"This applies, for example, to the terms vector in ScalarAffineFunction. Vectors returned to the user, for example, via ObjectiveFunction or ConstraintFunction attributes, must not be modified by the solver afterwards. The in-place version of get! can be used by users to avoid extra copies in this case.","category":"page"},{"location":"tutorials/implementing/#Column-Generation","page":"Implementing a solver interface","title":"Column Generation","text":"","category":"section"},{"location":"tutorials/implementing/","page":"Implementing a solver interface","title":"Implementing a solver interface","text":"There is no special interface for column generation. If the solver has a special API for setting coefficients in existing constraints when adding a new variable, it is possible to queue modifications and new variables and then call the solver's API once all of the new coefficients are known.","category":"page"},{"location":"tutorials/implementing/#Solver-specific-attributes","page":"Implementing a solver interface","title":"Solver-specific attributes","text":"","category":"section"},{"location":"tutorials/implementing/","page":"Implementing a solver interface","title":"Implementing a solver interface","text":"You don't need to restrict yourself to the attributes defined in the MathOptInterface.jl package.","category":"page"},{"location":"tutorials/implementing/","page":"Implementing a solver interface","title":"Implementing a solver interface","text":"Solver-specific attributes should be specified by creating an appropriate subtype of AbstractModelAttribute, AbstractOptimizerAttribute, AbstractVariableAttribute, or AbstractConstraintAttribute.","category":"page"},{"location":"tutorials/implementing/","page":"Implementing a solver interface","title":"Implementing a solver interface","text":"For example, Gurobi.jl adds attributes for multiobjective optimization by defining:","category":"page"},{"location":"tutorials/implementing/","page":"Implementing a solver interface","title":"Implementing a solver interface","text":"struct NumberOfObjectives <: MOI.AbstractModelAttribute end\n\nfunction MOI.set(model::Optimizer, ::NumberOfObjectives, n::Integer)\n # Code to set NumberOfObjectives\n return\nend\n\nfunction MOI.get(model::Optimizer, ::NumberOfObjectives)\n n = # Code to get NumberOfObjectives\n return n\nend","category":"page"},{"location":"tutorials/implementing/","page":"Implementing a solver interface","title":"Implementing a solver interface","text":"Then, the user can write:","category":"page"},{"location":"tutorials/implementing/","page":"Implementing a solver interface","title":"Implementing a solver interface","text":"model = Gurobi.Optimizer()\nMOI.set(model, Gurobi.NumberofObjectives(), 3)","category":"page"},{"location":"submodules/Nonlinear/reference/","page":"API Reference","title":"API Reference","text":"CurrentModule = MathOptInterface\nDocTestSetup = quote\n import MathOptInterface as MOI\nend\nDocTestFilters = [r\"MathOptInterface|MOI\"]","category":"page"},{"location":"submodules/Nonlinear/reference/#NonlinearAPI","page":"API Reference","title":"Nonlinear Modeling","text":"","category":"section"},{"location":"submodules/Nonlinear/reference/","page":"API Reference","title":"API Reference","text":"More information can be found in the Nonlinear section of the manual.","category":"page"},{"location":"submodules/Nonlinear/reference/","page":"API Reference","title":"API Reference","text":"Nonlinear\nNonlinear.Model","category":"page"},{"location":"submodules/Nonlinear/reference/#MathOptInterface.Nonlinear","page":"API Reference","title":"MathOptInterface.Nonlinear","text":"Nonlinear\n\nwarning: Warning\nThe Nonlinear submodule is experimental. Until this message is removed, breaking changes may be introduced in any minor or patch release of MathOptInterface.\n\n\n\n\n\n","category":"module"},{"location":"submodules/Nonlinear/reference/#MathOptInterface.Nonlinear.Model","page":"API Reference","title":"MathOptInterface.Nonlinear.Model","text":"Model()\n\nThe core datastructure for representing a nonlinear optimization problem.\n\nIt has the following fields:\n\nobjective::Union{Nothing,Expression} : holds the nonlinear objective function, if one exists, otherwise nothing.\nexpressions::Vector{Expression} : a vector of expressions in the model.\nconstraints::OrderedDict{ConstraintIndex,Constraint} : a map from ConstraintIndex to the corresponding Constraint. An OrderedDict is used instead of a Vector to support constraint deletion.\nparameters::Vector{Float64} : holds the current values of the parameters.\noperators::OperatorRegistry : stores the operators used in the model.\n\n\n\n\n\n","category":"type"},{"location":"submodules/Nonlinear/reference/#nonlinear_api_expressions","page":"API Reference","title":"Expressions","text":"","category":"section"},{"location":"submodules/Nonlinear/reference/","page":"API Reference","title":"API Reference","text":"Nonlinear.ExpressionIndex\nNonlinear.add_expression","category":"page"},{"location":"submodules/Nonlinear/reference/#MathOptInterface.Nonlinear.ExpressionIndex","page":"API Reference","title":"MathOptInterface.Nonlinear.ExpressionIndex","text":"ExpressionIndex\n\nAn index to a nonlinear expression that is returned by add_expression.\n\nGiven data::Model and ex::ExpressionIndex, use data[ex] to retrieve the corresponding Expression.\n\n\n\n\n\n","category":"type"},{"location":"submodules/Nonlinear/reference/#MathOptInterface.Nonlinear.add_expression","page":"API Reference","title":"MathOptInterface.Nonlinear.add_expression","text":"add_expression(model::Model, expr)::ExpressionIndex\n\nParse expr into a Expression and add to model. Returns an ExpressionIndex that can be interpolated into other input expressions.\n\nexpr must be a type that is supported by parse_expression.\n\nExamples\n\nmodel = Model()\nx = MOI.VariableIndex(1)\nex = add_expression(model, :($x^2 + 1))\nset_objective(model, :(sqrt($ex)))\n\n\n\n\n\n","category":"function"},{"location":"submodules/Nonlinear/reference/#nonlinear_api_parameters","page":"API Reference","title":"Parameters","text":"","category":"section"},{"location":"submodules/Nonlinear/reference/","page":"API Reference","title":"API Reference","text":"Nonlinear.ParameterIndex\nNonlinear.add_parameter","category":"page"},{"location":"submodules/Nonlinear/reference/#MathOptInterface.Nonlinear.ParameterIndex","page":"API Reference","title":"MathOptInterface.Nonlinear.ParameterIndex","text":"ParameterIndex\n\nAn index to a nonlinear parameter that is returned by add_parameter. Given data::Model and p::ParameterIndex, use data[p] to retrieve the current value of the parameter and data[p] = value to set a new value.\n\n\n\n\n\n","category":"type"},{"location":"submodules/Nonlinear/reference/#MathOptInterface.Nonlinear.add_parameter","page":"API Reference","title":"MathOptInterface.Nonlinear.add_parameter","text":"add_parameter(model::Model, value::Float64)::ParameterIndex\n\nAdd 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.\n\nExamples\n\nmodel = Model()\nx = MOI.VariableIndex(1)\np = add_parameter(model, 1.2)\nc = add_constraint(model, :($x^2 - $p), MOI.LessThan(0.0))\n\n\n\n\n\n","category":"function"},{"location":"submodules/Nonlinear/reference/#nonlinear_api_objectives","page":"API Reference","title":"Objectives","text":"","category":"section"},{"location":"submodules/Nonlinear/reference/","page":"API Reference","title":"API Reference","text":"Nonlinear.set_objective","category":"page"},{"location":"submodules/Nonlinear/reference/#MathOptInterface.Nonlinear.set_objective","page":"API Reference","title":"MathOptInterface.Nonlinear.set_objective","text":"set_objective(model::Model, obj)::Nothing\n\nParse obj into a Expression and set as the objective function of model.\n\nobj must be a type that is supported by parse_expression.\n\nTo remove the objective, pass nothing.\n\nExamples\n\nmodel = Model()\nx = MOI.VariableIndex(1)\nset_objective(model, :($x^2 + 1))\nset_objective(model, x)\nset_objective(model, nothing)\n\n\n\n\n\n","category":"function"},{"location":"submodules/Nonlinear/reference/#nonlinear_api_constraints","page":"API Reference","title":"Constraints","text":"","category":"section"},{"location":"submodules/Nonlinear/reference/","page":"API Reference","title":"API Reference","text":"Nonlinear.ConstraintIndex\nNonlinear.add_constraint\nNonlinear.delete","category":"page"},{"location":"submodules/Nonlinear/reference/#MathOptInterface.Nonlinear.ConstraintIndex","page":"API Reference","title":"MathOptInterface.Nonlinear.ConstraintIndex","text":"ConstraintIndex\n\nAn index to a nonlinear constraint that is returned by add_constraint.\n\nGiven data::Model and c::ConstraintIndex, use data[c] to retrieve the corresponding Constraint.\n\n\n\n\n\n","category":"type"},{"location":"submodules/Nonlinear/reference/#MathOptInterface.Nonlinear.add_constraint","page":"API Reference","title":"MathOptInterface.Nonlinear.add_constraint","text":"add_constraint(\n model::Model,\n func,\n set::Union{\n MOI.GreaterThan{Float64},\n MOI.LessThan{Float64},\n MOI.Interval{Float64},\n MOI.EqualTo{Float64},\n },\n)\n\nParse 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.\n\nExamples\n\nmodel = Model()\nx = MOI.VariableIndex(1)\nc = add_constraint(model, :($x^2), MOI.LessThan(1.0))\n\n\n\n\n\n","category":"function"},{"location":"submodules/Nonlinear/reference/#MathOptInterface.Nonlinear.delete","page":"API Reference","title":"MathOptInterface.Nonlinear.delete","text":"delete(model::Model, c::ConstraintIndex)::Nothing\n\nDelete the constraint index c from model.\n\nExamples\n\nmodel = Model()\nx = MOI.VariableIndex(1)\nc = add_constraint(model, :($x^2), MOI.LessThan(1.0))\ndelete(model, c)\n\n\n\n\n\n","category":"function"},{"location":"submodules/Nonlinear/reference/#nonlinear_api_operators","page":"API Reference","title":"User-defined operators","text":"","category":"section"},{"location":"submodules/Nonlinear/reference/","page":"API Reference","title":"API Reference","text":"Nonlinear.OperatorRegistry\nNonlinear.DEFAULT_UNIVARIATE_OPERATORS\nNonlinear.DEFAULT_MULTIVARIATE_OPERATORS\nNonlinear.register_operator\nNonlinear.register_operator_if_needed\nNonlinear.assert_registered\nNonlinear.check_return_type\nNonlinear.eval_univariate_function\nNonlinear.eval_univariate_gradient\nNonlinear.eval_univariate_hessian\nNonlinear.eval_multivariate_function\nNonlinear.eval_multivariate_gradient\nNonlinear.eval_multivariate_hessian\nNonlinear.eval_logic_function\nNonlinear.eval_comparison_function","category":"page"},{"location":"submodules/Nonlinear/reference/#MathOptInterface.Nonlinear.OperatorRegistry","page":"API Reference","title":"MathOptInterface.Nonlinear.OperatorRegistry","text":"OperatorRegistry()\n\nCreate a new OperatorRegistry to store and evaluate univariate and multivariate operators.\n\n\n\n\n\n","category":"type"},{"location":"submodules/Nonlinear/reference/#MathOptInterface.Nonlinear.DEFAULT_UNIVARIATE_OPERATORS","page":"API Reference","title":"MathOptInterface.Nonlinear.DEFAULT_UNIVARIATE_OPERATORS","text":"DEFAULT_UNIVARIATE_OPERATORS\n\nThe list of univariate operators that are supported by default.\n\nExample\n\njulia> import MathOptInterface as MOI\n\njulia> MOI.Nonlinear.DEFAULT_UNIVARIATE_OPERATORS\n72-element Vector{Symbol}:\n :+\n :-\n :abs\n :sqrt\n :cbrt\n :abs2\n :inv\n :log\n :log10\n :log2\n ⋮\n :airybi\n :airyaiprime\n :airybiprime\n :besselj0\n :besselj1\n :bessely0\n :bessely1\n :erfcx\n :dawson\n\n\n\n\n\n","category":"constant"},{"location":"submodules/Nonlinear/reference/#MathOptInterface.Nonlinear.DEFAULT_MULTIVARIATE_OPERATORS","page":"API Reference","title":"MathOptInterface.Nonlinear.DEFAULT_MULTIVARIATE_OPERATORS","text":"DEFAULT_MULTIVARIATE_OPERATORS\n\nThe list of multivariate operators that are supported by default.\n\nExample\n\njulia> import MathOptInterface as MOI\n\njulia> MOI.Nonlinear.DEFAULT_MULTIVARIATE_OPERATORS\n9-element Vector{Symbol}:\n :+\n :-\n :*\n :^\n :/\n :ifelse\n :atan\n :min\n :max\n\n\n\n\n\n","category":"constant"},{"location":"submodules/Nonlinear/reference/#MathOptInterface.Nonlinear.register_operator","page":"API Reference","title":"MathOptInterface.Nonlinear.register_operator","text":"register_operator(\n model::Model,\n op::Symbol,\n nargs::Int,\n f::Function,\n [∇f::Function],\n [∇²f::Function],\n)\n\nRegister the user-defined operator op with nargs input arguments in model.\n\nUnivariate functions\n\nf(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.\n∇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.\n∇²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.\n\nMultivariate functions\n\nf(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.\n∇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].\n∇²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.\n\nNotes for multivariate Hessians\n\nH has size(H) == (length(x), length(x)), but you must not access elements H[i, j] for i > j.\nH is dense, but you do not need to fill structural zeros.\n\n\n\n\n\n","category":"function"},{"location":"submodules/Nonlinear/reference/#MathOptInterface.Nonlinear.register_operator_if_needed","page":"API Reference","title":"MathOptInterface.Nonlinear.register_operator_if_needed","text":"register_operator_if_needed(\n registry::OperatorRegistry,\n op::Symbol,\n nargs::Int,\n f::Function;\n)\n\nSimilar to register_operator, but this function warns if the function is not registered, and skips silently if it already is.\n\n\n\n\n\n","category":"function"},{"location":"submodules/Nonlinear/reference/#MathOptInterface.Nonlinear.assert_registered","page":"API Reference","title":"MathOptInterface.Nonlinear.assert_registered","text":"assert_registered(registry::OperatorRegistry, op::Symbol, nargs::Int)\n\nThrow an error if op is not registered in registry with nargs arguments.\n\n\n\n\n\n","category":"function"},{"location":"submodules/Nonlinear/reference/#MathOptInterface.Nonlinear.check_return_type","page":"API Reference","title":"MathOptInterface.Nonlinear.check_return_type","text":"check_return_type(::Type{T}, ret::S) where {T,S}\n\nOverload this method for new types S to throw an informative error if a user-defined function returns the type S instead of T.\n\n\n\n\n\n","category":"function"},{"location":"submodules/Nonlinear/reference/#MathOptInterface.Nonlinear.eval_univariate_function","page":"API Reference","title":"MathOptInterface.Nonlinear.eval_univariate_function","text":"eval_univariate_function(\n registry::OperatorRegistry,\n op::Symbol,\n x::T,\n) where {T}\n\nEvaluate the operator op(x)::T, where op is a univariate function in registry.\n\n\n\n\n\n","category":"function"},{"location":"submodules/Nonlinear/reference/#MathOptInterface.Nonlinear.eval_univariate_gradient","page":"API Reference","title":"MathOptInterface.Nonlinear.eval_univariate_gradient","text":"eval_univariate_gradient(\n registry::OperatorRegistry,\n op::Symbol,\n x::T,\n) where {T}\n\nEvaluate the first-derivative of the operator op(x)::T, where op is a univariate function in registry.\n\n\n\n\n\n","category":"function"},{"location":"submodules/Nonlinear/reference/#MathOptInterface.Nonlinear.eval_univariate_hessian","page":"API Reference","title":"MathOptInterface.Nonlinear.eval_univariate_hessian","text":"eval_univariate_hessian(\n registry::OperatorRegistry,\n op::Symbol,\n x::T,\n) where {T}\n\nEvaluate the second-derivative of the operator op(x)::T, where op is a univariate function in registry.\n\n\n\n\n\n","category":"function"},{"location":"submodules/Nonlinear/reference/#MathOptInterface.Nonlinear.eval_multivariate_function","page":"API Reference","title":"MathOptInterface.Nonlinear.eval_multivariate_function","text":"eval_multivariate_function(\n registry::OperatorRegistry,\n op::Symbol,\n x::AbstractVector{T},\n) where {T}\n\nEvaluate the operator op(x)::T, where op is a multivariate function in registry.\n\n\n\n\n\n","category":"function"},{"location":"submodules/Nonlinear/reference/#MathOptInterface.Nonlinear.eval_multivariate_gradient","page":"API Reference","title":"MathOptInterface.Nonlinear.eval_multivariate_gradient","text":"eval_multivariate_gradient(\n registry::OperatorRegistry,\n op::Symbol,\n g::AbstractVector{T},\n x::AbstractVector{T},\n) where {T}\n\nEvaluate the gradient of operator g .= ∇op(x), where op is a multivariate function in registry.\n\n\n\n\n\n","category":"function"},{"location":"submodules/Nonlinear/reference/#MathOptInterface.Nonlinear.eval_multivariate_hessian","page":"API Reference","title":"MathOptInterface.Nonlinear.eval_multivariate_hessian","text":"eval_multivariate_hessian(\n registry::OperatorRegistry,\n op::Symbol,\n H::AbstractMatrix,\n x::AbstractVector{T},\n) where {T}\n\nEvaluate the Hessian of operator ∇²op(x), where op is a multivariate function in registry.\n\nThe Hessian is stored in the lower-triangular part of the matrix H.\n\nnote: Note\nImplementations of the Hessian operators will not fill structural zeros. Therefore, before calling this function you should pre-populate the matrix H with 0.\n\n\n\n\n\n","category":"function"},{"location":"submodules/Nonlinear/reference/#MathOptInterface.Nonlinear.eval_logic_function","page":"API Reference","title":"MathOptInterface.Nonlinear.eval_logic_function","text":"eval_logic_function(\n registry::OperatorRegistry,\n op::Symbol,\n lhs::T,\n rhs::T,\n)::Bool where {T}\n\nEvaluate (lhs op rhs)::Bool, where op is a logic operator in registry.\n\n\n\n\n\n","category":"function"},{"location":"submodules/Nonlinear/reference/#MathOptInterface.Nonlinear.eval_comparison_function","page":"API Reference","title":"MathOptInterface.Nonlinear.eval_comparison_function","text":"eval_comparison_function(\n registry::OperatorRegistry,\n op::Symbol,\n lhs::T,\n rhs::T,\n)::Bool where {T}\n\nEvaluate (lhs op rhs)::Bool, where op is a comparison operator in registry.\n\n\n\n\n\n","category":"function"},{"location":"submodules/Nonlinear/reference/#Automatic-differentiation-backends","page":"API Reference","title":"Automatic-differentiation backends","text":"","category":"section"},{"location":"submodules/Nonlinear/reference/","page":"API Reference","title":"API Reference","text":"Nonlinear.Evaluator\nNonlinear.AbstractAutomaticDifferentiation\nNonlinear.ExprGraphOnly\nNonlinear.SparseReverseMode","category":"page"},{"location":"submodules/Nonlinear/reference/#MathOptInterface.Nonlinear.Evaluator","page":"API Reference","title":"MathOptInterface.Nonlinear.Evaluator","text":"Evaluator(\n model::Model,\n backend::AbstractAutomaticDifferentiation,\n ordered_variables::Vector{MOI.VariableIndex},\n)\n\nCreate Evaluator, a subtype of MOI.AbstractNLPEvaluator, from Model.\n\n\n\n\n\n","category":"type"},{"location":"submodules/Nonlinear/reference/#MathOptInterface.Nonlinear.AbstractAutomaticDifferentiation","page":"API Reference","title":"MathOptInterface.Nonlinear.AbstractAutomaticDifferentiation","text":"AbstractAutomaticDifferentiation\n\nAn abstract type for extending Evaluator.\n\n\n\n\n\n","category":"type"},{"location":"submodules/Nonlinear/reference/#MathOptInterface.Nonlinear.ExprGraphOnly","page":"API Reference","title":"MathOptInterface.Nonlinear.ExprGraphOnly","text":"ExprGraphOnly() <: AbstractAutomaticDifferentiation\n\nThe default implementation of AbstractAutomaticDifferentiation. The only supported feature is :ExprGraph.\n\n\n\n\n\n","category":"type"},{"location":"submodules/Nonlinear/reference/#MathOptInterface.Nonlinear.SparseReverseMode","page":"API Reference","title":"MathOptInterface.Nonlinear.SparseReverseMode","text":"SparseReverseMode() <: AbstractAutomaticDifferentiation\n\nAn implementation of AbstractAutomaticDifferentiation that uses sparse reverse-mode automatic differentiation to compute derivatives. Supports all features in the MOI nonlinear interface.\n\n\n\n\n\n","category":"type"},{"location":"submodules/Nonlinear/reference/#Data-structure","page":"API Reference","title":"Data-structure","text":"","category":"section"},{"location":"submodules/Nonlinear/reference/","page":"API Reference","title":"API Reference","text":"Nonlinear.Node\nNonlinear.NodeType\nNonlinear.Expression\nNonlinear.Constraint\nNonlinear.adjacency_matrix\nNonlinear.parse_expression\nNonlinear.convert_to_expr\nNonlinear.ordinal_index","category":"page"},{"location":"submodules/Nonlinear/reference/#MathOptInterface.Nonlinear.Node","page":"API Reference","title":"MathOptInterface.Nonlinear.Node","text":"struct Node\n type::NodeType\n index::Int\n parent::Int\nend\n\nA single node in a nonlinear expression tree. Used by Expression.\n\nSee the MathOptInterface documentation for information on how the nodes and values form an expression tree.\n\n\n\n\n\n","category":"type"},{"location":"submodules/Nonlinear/reference/#MathOptInterface.Nonlinear.NodeType","page":"API Reference","title":"MathOptInterface.Nonlinear.NodeType","text":"NodeType\n\nAn enum describing the possible node types. Each Node has a .index field, which should be interpreted as follows:\n\nNODE_CALL_MULTIVARIATE: the index into operators.multivariate_operators\nNODE_CALL_UNIVARIATE: the index into operators.univariate_operators\nNODE_LOGIC: the index into operators.logic_operators\nNODE_COMPARISON: the index into operators.comparison_operators\nNODE_MOI_VARIABLE: the value of MOI.VariableIndex(index) in the user's space of the model.\nNODE_VARIABLE: the 1-based index of the internal vector\nNODE_VALUE: the index into the .values field of Expression\nNODE_PARAMETER: the index into data.parameters\nNODE_SUBEXPRESSION: the index into data.expressions\n\n\n\n\n\n","category":"type"},{"location":"submodules/Nonlinear/reference/#MathOptInterface.Nonlinear.Expression","page":"API Reference","title":"MathOptInterface.Nonlinear.Expression","text":"struct Expression\n nodes::Vector{Node}\n values::Vector{Float64}\nend\n\nThe core type that represents a nonlinear expression. See the MathOptInterface documentation for information on how the nodes and values form an expression tree.\n\n\n\n\n\n","category":"type"},{"location":"submodules/Nonlinear/reference/#MathOptInterface.Nonlinear.Constraint","page":"API Reference","title":"MathOptInterface.Nonlinear.Constraint","text":"struct Constraint\n expression::Expression\n set::Union{\n MOI.LessThan{Float64},\n MOI.GreaterThan{Float64},\n MOI.EqualTo{Float64},\n MOI.Interval{Float64},\n }\nend\n\nA type to hold information relating to the nonlinear constraint f(x) in S, where f(x) is defined by .expression, and S is .set.\n\n\n\n\n\n","category":"type"},{"location":"submodules/Nonlinear/reference/#MathOptInterface.Nonlinear.adjacency_matrix","page":"API Reference","title":"MathOptInterface.Nonlinear.adjacency_matrix","text":"adjacency_matrix(nodes::Vector{Node})\n\nCompute the sparse adjacency matrix describing the parent-child relationships in nodes.\n\nThe 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 (i.e., the children).\n\n\n\n\n\n","category":"function"},{"location":"submodules/Nonlinear/reference/#MathOptInterface.Nonlinear.parse_expression","page":"API Reference","title":"MathOptInterface.Nonlinear.parse_expression","text":"parse_expression(data::Model, input)::Expression\n\nParse input into a Expression.\n\n\n\n\n\nparse_expression(\n data::Model,\n expr::Expression,\n input::Any,\n parent_index::Int,\n)::Expression\n\nParse 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.\n\nYou can extend parsing support to new types of objects by overloading this method with a different type on input::Any.\n\n\n\n\n\n","category":"function"},{"location":"submodules/Nonlinear/reference/#MathOptInterface.Nonlinear.convert_to_expr","page":"API Reference","title":"MathOptInterface.Nonlinear.convert_to_expr","text":"convert_to_expr(data::Model, expr::Expression)\n\nConvert the Expression expr into a Julia Expr.\n\nsubexpressions are represented by a ExpressionIndex object.\nparameters are represented by a ParameterIndex object.\nvariables are represennted by an MOI.VariableIndex object.\n\n\n\n\n\nconvert_to_expr(\n evaluator::Evaluator,\n expr::Expression;\n moi_output_format::Bool,\n)\n\nConvert the Expression expr into a Julia Expr.\n\nIf moi_output_format = true:\n\nsubexpressions will be converted to Julia Expr and substituted into the output expression.\nthe current value of each parameter will be interpolated into the expression\nvariables will be represented in the form x[MOI.VariableIndex(i)]\n\nIf moi_output_format = false:\n\nsubexpressions will be represented by a ExpressionIndex object.\nparameters will be represented by a ParameterIndex object.\nvariables will be represennted by an MOI.VariableIndex object.\n\nwarning: Warning\nTo use moi_output_format = true, you must have first called MOI.initialize with :ExprGraph as a requested feature.\n\n\n\n\n\n","category":"function"},{"location":"submodules/Nonlinear/reference/#MathOptInterface.Nonlinear.ordinal_index","page":"API Reference","title":"MathOptInterface.Nonlinear.ordinal_index","text":"ordinal_index(evaluator::Evaluator, c::ConstraintIndex)::Int\n\nReturn the 1-indexed value of the constraint index c in evaluator.\n\nExamples\n\nmodel = Model()\nx = MOI.VariableIndex(1)\nc1 = add_constraint(model, :($x^2), MOI.LessThan(1.0))\nc2 = add_constraint(model, :($x^2), MOI.LessThan(1.0))\nevaluator = Evaluator(model)\nMOI.initialize(evaluator, Symbol[])\nordinal_index(evaluator, c2) # Returns 2\ndelete(model, c1)\nevaluator = Evaluator(model)\nMOI.initialize(evaluator, Symbol[])\nordinal_index(model, c2) # Returns 1\n\n\n\n\n\n","category":"function"},{"location":"manual/models/","page":"Models","title":"Models","text":"CurrentModule = MathOptInterface\nDocTestSetup = quote\n import MathOptInterface as MOI\nend\nDocTestFilters = [r\"MathOptInterface|MOI\"]","category":"page"},{"location":"manual/models/#Models","page":"Models","title":"Models","text":"","category":"section"},{"location":"manual/models/","page":"Models","title":"Models","text":"The most significant part of MOI is the definition of the model API that is used to specify an instance of an optimization problem (for example, by adding variables and constraints). Objects that implement the model API must inherit from the ModelLike abstract type.","category":"page"},{"location":"manual/models/","page":"Models","title":"Models","text":"Notably missing from the model API is the method to solve an optimization problem. ModelLike objects may store an instance (for example, in memory or backed by a file format) without being linked to a particular solver. In addition to the model API, MOI defines AbstractOptimizer and provides methods to solve the model and interact with solutions. See the Solutions section for more details.","category":"page"},{"location":"manual/models/","page":"Models","title":"Models","text":"info: Info\nThroughout the rest of the manual, model is used as a generic ModelLike, and optimizer is used as a generic AbstractOptimizer.","category":"page"},{"location":"manual/models/","page":"Models","title":"Models","text":"tip: Tip\nMOI does not export functions, but for brevity we often omit qualifying names with the MOI module. Best practice is to haveimport MathOptInterface as MOIand prefix all MOI methods with MOI. in user code. If a name is also available in base Julia, we always explicitly use the module prefix, for example, with MOI.get.","category":"page"},{"location":"manual/models/#Attributes","page":"Models","title":"Attributes","text":"","category":"section"},{"location":"manual/models/","page":"Models","title":"Models","text":"Attributes are properties of the model that can be queried and modified. These include constants such as the number of variables in a model NumberOfVariables), and properties of variables and constraints such as the name of a variable (VariableName).","category":"page"},{"location":"manual/models/","page":"Models","title":"Models","text":"There are four types of attributes:","category":"page"},{"location":"manual/models/","page":"Models","title":"Models","text":"Model attributes (subtypes of AbstractModelAttribute) refer to properties of a model.\nOptimizer attributes (subtypes of AbstractOptimizerAttribute) refer to properties of an optimizer.\nConstraint attributes (subtypes of AbstractConstraintAttribute) refer to properties of an individual constraint.\nVariable attributes (subtypes of AbstractVariableAttribute) refer to properties of an individual variable.","category":"page"},{"location":"manual/models/","page":"Models","title":"Models","text":"Some attributes are values that can be queried by the user but not modified, while other attributes can be modified by the user.","category":"page"},{"location":"manual/models/","page":"Models","title":"Models","text":"All interactions with attributes occur through the get and set functions.","category":"page"},{"location":"manual/models/","page":"Models","title":"Models","text":"Consult the docstrings of each attribute for information on what it represents.","category":"page"},{"location":"manual/models/#ModelLike-API","page":"Models","title":"ModelLike API","text":"","category":"section"},{"location":"manual/models/","page":"Models","title":"Models","text":"The following attributes are available:","category":"page"},{"location":"manual/models/","page":"Models","title":"Models","text":"ListOfConstraintAttributesSet\nListOfConstraintIndices\nListOfConstraintTypesPresent\nListOfModelAttributesSet\nListOfVariableAttributesSet\nListOfVariableIndices\nNumberOfConstraints\nNumberOfVariables\nName\nObjectiveFunction\nObjectiveFunctionType\nObjectiveSense","category":"page"},{"location":"manual/models/#AbstractOptimizer-API","page":"Models","title":"AbstractOptimizer API","text":"","category":"section"},{"location":"manual/models/","page":"Models","title":"Models","text":"The following attributes are available:","category":"page"},{"location":"manual/models/","page":"Models","title":"Models","text":"DualStatus\nPrimalStatus\nRawStatusString\nResultCount\nTerminationStatus\nBarrierIterations\nDualObjectiveValue\nNodeCount\nNumberOfThreads\nObjectiveBound\nObjectiveValue\nRelativeGap\nRawOptimizerAttribute\nRawSolver\nSilent\nSimplexIterations\nSolverName\nSolverVersion\nSolveTimeSec\nTimeLimitSec\nObjectiveLimit","category":"page"},{"location":"tutorials/mathprogbase/#Transitioning-from-MathProgBase","page":"Transitioning from MathProgBase","title":"Transitioning from MathProgBase","text":"","category":"section"},{"location":"tutorials/mathprogbase/","page":"Transitioning from MathProgBase","title":"Transitioning from MathProgBase","text":"MathOptInterface is a replacement for MathProgBase.jl. However, it is not a direct replacement.","category":"page"},{"location":"tutorials/mathprogbase/#Transitioning-a-solver-interface","page":"Transitioning from MathProgBase","title":"Transitioning a solver interface","text":"","category":"section"},{"location":"tutorials/mathprogbase/","page":"Transitioning from MathProgBase","title":"Transitioning from MathProgBase","text":"MathOptInterface is more extensive than MathProgBase which may make its implementation seem daunting at first. There are however numerous utilities in MathOptInterface that the simplify implementation process.","category":"page"},{"location":"tutorials/mathprogbase/","page":"Transitioning from MathProgBase","title":"Transitioning from MathProgBase","text":"For more information, read Implementing a solver interface.","category":"page"},{"location":"tutorials/mathprogbase/#Transitioning-the-high-level-functions","page":"Transitioning from MathProgBase","title":"Transitioning the high-level functions","text":"","category":"section"},{"location":"tutorials/mathprogbase/","page":"Transitioning from MathProgBase","title":"Transitioning from MathProgBase","text":"MathOptInterface doesn't provide replacements for the high-level interfaces in MathProgBase. We recommend you use JuMP as a modeling interface instead.","category":"page"},{"location":"tutorials/mathprogbase/","page":"Transitioning from MathProgBase","title":"Transitioning from MathProgBase","text":"tip: Tip\nIf you haven't used JuMP before, start with the tutorial Getting started with JuMP","category":"page"},{"location":"tutorials/mathprogbase/#linprog","page":"Transitioning from MathProgBase","title":"linprog","text":"","category":"section"},{"location":"tutorials/mathprogbase/","page":"Transitioning from MathProgBase","title":"Transitioning from MathProgBase","text":"Here is one way of transitioning from linprog:","category":"page"},{"location":"tutorials/mathprogbase/","page":"Transitioning from MathProgBase","title":"Transitioning from MathProgBase","text":"using JuMP\n\nfunction linprog(c, A, sense, b, l, u, solver)\n N = length(c)\n model = Model(solver)\n @variable(model, l[i] <= x[i=1:N] <= u[i])\n @objective(model, Min, c' * x)\n eq_rows, ge_rows, le_rows = sense .== '=', sense .== '>', sense .== '<'\n @constraint(model, A[eq_rows, :] * x .== b[eq_rows])\n @constraint(model, A[ge_rows, :] * x .>= b[ge_rows])\n @constraint(model, A[le_rows, :] * x .<= b[le_rows])\n optimize!(model)\n return (\n status = termination_status(model),\n objval = objective_value(model),\n sol = value.(x)\n )\nend","category":"page"},{"location":"tutorials/mathprogbase/#mixintprog","page":"Transitioning from MathProgBase","title":"mixintprog","text":"","category":"section"},{"location":"tutorials/mathprogbase/","page":"Transitioning from MathProgBase","title":"Transitioning from MathProgBase","text":"Here is one way of transitioning from mixintprog:","category":"page"},{"location":"tutorials/mathprogbase/","page":"Transitioning from MathProgBase","title":"Transitioning from MathProgBase","text":"using JuMP\n\nfunction mixintprog(c, A, rowlb, rowub, vartypes, lb, ub, solver)\n N = length(c)\n model = Model(solver)\n @variable(model, lb[i] <= x[i=1:N] <= ub[i])\n for i in 1:N\n if vartypes[i] == :Bin\n set_binary(x[i])\n elseif vartypes[i] == :Int\n set_integer(x[i])\n end\n end\n @objective(model, Min, c' * x)\n @constraint(model, rowlb .<= A * x .<= rowub)\n optimize!(model)\n return (\n status = termination_status(model),\n objval = objective_value(model),\n sol = value.(x)\n )\nend","category":"page"},{"location":"tutorials/mathprogbase/#quadprog","page":"Transitioning from MathProgBase","title":"quadprog","text":"","category":"section"},{"location":"tutorials/mathprogbase/","page":"Transitioning from MathProgBase","title":"Transitioning from MathProgBase","text":"Here is one way of transitioning from quadprog:","category":"page"},{"location":"tutorials/mathprogbase/","page":"Transitioning from MathProgBase","title":"Transitioning from MathProgBase","text":"using JuMP\n\nfunction quadprog(c, Q, A, rowlb, rowub, lb, ub, solver)\n N = length(c)\n model = Model(solver)\n @variable(model, lb[i] <= x[i=1:N] <= ub[i])\n @objective(model, Min, c' * x + 0.5 * x' * Q * x)\n @constraint(model, rowlb .<= A * x .<= rowub)\n optimize!(model)\n return (\n status = termination_status(model),\n objval = objective_value(model),\n sol = value.(x)\n )\nend","category":"page"},{"location":"submodules/Test/reference/","page":"API Reference","title":"API Reference","text":"CurrentModule = MathOptInterface\nDocTestSetup = quote\n import MathOptInterface as MOI\nend\nDocTestFilters = [r\"MathOptInterface|MOI\"]","category":"page"},{"location":"submodules/Test/reference/#test_reference","page":"API Reference","title":"The Test submodule","text":"","category":"section"},{"location":"submodules/Test/reference/","page":"API Reference","title":"API Reference","text":"Functions to help test implementations of MOI. See The Test submodule for more details.","category":"page"},{"location":"submodules/Test/reference/","page":"API Reference","title":"API Reference","text":"Test.Config\nTest.runtests\nTest.setup_test\nTest.version_added\nTest.@requires\nTest.RequirementUnmet","category":"page"},{"location":"submodules/Test/reference/#MathOptInterface.Test.Config","page":"API Reference","title":"MathOptInterface.Test.Config","text":"Config(\n ::Type{T} = Float64;\n atol::Real = Base.rtoldefault(T),\n rtol::Real = Base.rtoldefault(T),\n optimal_status::MOI.TerminationStatusCode = MOI.OPTIMAL,\n infeasible_status::MOI.TerminationStatusCode = MOI.INFEASIBLE,\n exclude::Vector{Any} = Any[],\n) where {T}\n\nReturn an object that is used to configure various tests.\n\nConfiguration arguments\n\natol::Real = Base.rtoldefault(T): Control the absolute tolerance used when comparing solutions.\nrtol::Real = Base.rtoldefault(T): Control the relative tolerance used when comparing solutions.\noptimal_status = MOI.OPTIMAL: Set to MOI.LOCALLY_SOLVED if the solver cannot prove global optimality.\ninfeasible_status = MOI.INFEASIBLE: Set to MOI.LOCALLY_INFEASIBLE if the solver cannot prove global infeasibility.\nexclude = Vector{Any}: Pass attributes or functions to exclude to skip parts of tests that require certain functionality. Common arguments include:\nMOI.delete to skip deletion-related tests\nMOI.optimize! to skip optimize-related tests\nMOI.ConstraintDual to skip dual-related tests\nMOI.VariableName to skip setting variable names\nMOI.ConstraintName to skip setting constraint names\n\nExamples\n\nFor a nonlinear solver that finds local optima and does not support finding dual variables or constraint names:\n\nConfig(\n Float64;\n optimal_status = MOI.LOCALLY_SOLVED,\n exclude = Any[\n MOI.ConstraintDual,\n MOI.VariableName,\n MOI.ConstraintName,\n MOI.delete,\n ],\n)\n\n\n\n\n\n","category":"type"},{"location":"submodules/Test/reference/#MathOptInterface.Test.runtests","page":"API Reference","title":"MathOptInterface.Test.runtests","text":"runtests(\n model::MOI.ModelLike,\n config::Config;\n include::Vector{Union{String,Regex}} = String[],\n exclude::Vector{Union{String,Regex}} = String[],\n warn_unsupported::Bool = false,\n exclude_tests_after::VersionNumber = v\"999.0.0\",\n)\n\nRun all tests in MathOptInterface.Test on model.\n\nConfiguration arguments\n\nconfig is a Test.Config object that can be used to modify the behavior of tests.\nIf include is not empty, only run tests if an element from include occursin the name of the test.\nIf exclude is not empty, skip tests if an element from exclude occursin the name of the test.\nexclude takes priority over include.\nIf warn_unsupported is false, runtests will silently skip tests that fail with a MOI.NotAllowedError, MOI.UnsupportedError, or RequirementUnmet error. (The latter is thrown when an @requires statement returns false.) When warn_unsupported is true, a warning will be printed. For most cases the default behavior, false, is what you want, since these tests likely test functionality that is not supported by model. However, it can be useful to run warn_unsupported = true to check you are not skipping tests due to a missing supports_constraint method or equivalent.\nexclude_tests_after is a version number that excludes any tests to MOI added after that version number. This is useful for solvers who can declare a fixed set of tests, and not cause their tests to break if a new patch of MOI is released with a new test.\n\nSee also: setup_test.\n\nExample\n\nconfig = MathOptInterface.Test.Config()\nMathOptInterface.Test.runtests(\n model,\n config;\n include = [\"test_linear_\", r\"^test_model_Name$\"],\n exclude = [\"VariablePrimalStart\"],\n warn_unsupported = true,\n exclude_tests_after = v\"0.10.5\",\n)\n\n\n\n\n\n","category":"function"},{"location":"submodules/Test/reference/#MathOptInterface.Test.setup_test","page":"API Reference","title":"MathOptInterface.Test.setup_test","text":"setup_test(::typeof(f), model::MOI.ModelLike, config::Config)\n\nOverload this method to modify model before running the test function f on model with config. You can also modify the fields in config (e.g., to loosen the default tolerances).\n\nThis function should either return nothing, or return a function which, when called with zero arguments, undoes the setup to return the model to its previous state. You do not need to undo any modifications to config.\n\nThis function is most useful when writing new tests of the tests for MOI, but it can also be used to set test-specific tolerances, etc.\n\nSee also: runtests\n\nExample\n\nfunction MOI.Test.setup_test(\n ::typeof(MOI.Test.test_linear_VariablePrimalStart_partial),\n mock::MOIU.MockOptimizer,\n ::MOI.Test.Config,\n)\n MOIU.set_mock_optimize!(\n mock,\n (mock::MOIU.MockOptimizer) -> MOIU.mock_optimize!(mock, [1.0, 0.0]),\n )\n mock.eval_variable_constraint_dual = false\n\n function reset_function()\n mock.eval_variable_constraint_dual = true\n return\n end\n return reset_function\nend\n\n\n\n\n\n","category":"function"},{"location":"submodules/Test/reference/#MathOptInterface.Test.version_added","page":"API Reference","title":"MathOptInterface.Test.version_added","text":"version_added(::typeof(function_name))\n\nReturns the version of MOI in which the test function_name was added.\n\nThis method should be implemented for all new tests.\n\nSee the exclude_tests_after keyword of runtests for more details.\n\n\n\n\n\n","category":"function"},{"location":"submodules/Test/reference/#MathOptInterface.Test.@requires","page":"API Reference","title":"MathOptInterface.Test.@requires","text":"@requires(x)\n\nCheck that the condition x is true. Otherwise, throw an RequirementUnmet error to indicate that the model does not support something required by the test function.\n\nExamples\n\n@requires MOI.supports(model, MOI.Silent())\n@test MOI.get(model, MOI.Silent())\n\n\n\n\n\n","category":"macro"},{"location":"submodules/Test/reference/#MathOptInterface.Test.RequirementUnmet","page":"API Reference","title":"MathOptInterface.Test.RequirementUnmet","text":"RequirementUnmet(msg::String) <: Exception\n\nAn error for throwing in tests to indicate that the model does not support some requirement expected by the test function.\n\n\n\n\n\n","category":"type"},{"location":"submodules/Benchmarks/overview/","page":"Overview","title":"Overview","text":"CurrentModule = MathOptInterface\nDocTestSetup = quote\n import MathOptInterface as MOI\nend\nDocTestFilters = [r\"MathOptInterface|MOI\"]","category":"page"},{"location":"submodules/Benchmarks/overview/#The-Benchmarks-submodule","page":"Overview","title":"The Benchmarks submodule","text":"","category":"section"},{"location":"submodules/Benchmarks/overview/","page":"Overview","title":"Overview","text":"To aid the development of efficient solver wrappers, MathOptInterface provides benchmarking capability. Benchmarking a wrapper follows a two-step process.","category":"page"},{"location":"submodules/Benchmarks/overview/","page":"Overview","title":"Overview","text":"First, prior to making changes, create a baseline for the benchmark results on a given benchmark suite as follows:","category":"page"},{"location":"submodules/Benchmarks/overview/","page":"Overview","title":"Overview","text":"using SolverPackage # Replace with your choice of solver.\nimport MathOptInterface as MOI\n\nsuite = MOI.Benchmarks.suite() do\n SolverPackage.Optimizer()\nend\n\nMOI.Benchmarks.create_baseline(\n suite, \"current\"; directory = \"/tmp\", verbose = true\n)","category":"page"},{"location":"submodules/Benchmarks/overview/","page":"Overview","title":"Overview","text":"Use the exclude argument to Benchmarks.suite to exclude benchmarks that the solver doesn't support.","category":"page"},{"location":"submodules/Benchmarks/overview/","page":"Overview","title":"Overview","text":"Second, after making changes to the package, re-run the benchmark suite and compare to the prior saved results:","category":"page"},{"location":"submodules/Benchmarks/overview/","page":"Overview","title":"Overview","text":"using SolverPackage\nimport MathOptInterface as MOI\n\nsuite = MOI.Benchmarks.suite() do\n SolverPackage.Optimizer()\nend\n\nMOI.Benchmarks.compare_against_baseline(\n suite, \"current\"; directory = \"/tmp\", verbose = true\n)","category":"page"},{"location":"submodules/Benchmarks/overview/","page":"Overview","title":"Overview","text":"This comparison will create a report detailing improvements and regressions.","category":"page"},{"location":"submodules/FileFormats/overview/","page":"Overview","title":"Overview","text":"CurrentModule = MathOptInterface\nDocTestSetup = quote\n import MathOptInterface as MOI\nend\nDocTestFilters = [r\"MathOptInterface|MOI\"]","category":"page"},{"location":"submodules/FileFormats/overview/#The-FileFormats-submodule","page":"Overview","title":"The FileFormats submodule","text":"","category":"section"},{"location":"submodules/FileFormats/overview/","page":"Overview","title":"Overview","text":"The FileFormats module provides functions for reading and writing MOI models using write_to_file and read_from_file.","category":"page"},{"location":"submodules/FileFormats/overview/#Supported-file-types","page":"Overview","title":"Supported file types","text":"","category":"section"},{"location":"submodules/FileFormats/overview/","page":"Overview","title":"Overview","text":"You must read and write files to a FileFormats.Model object. Specific the file-type by passing a FileFormats.FileFormat enum. For example:","category":"page"},{"location":"submodules/FileFormats/overview/","page":"Overview","title":"Overview","text":"The Conic Benchmark Format","category":"page"},{"location":"submodules/FileFormats/overview/","page":"Overview","title":"Overview","text":"julia> model = MOI.FileFormats.Model(format = MOI.FileFormats.FORMAT_CBF)\nA Conic Benchmark Format (CBF) model","category":"page"},{"location":"submodules/FileFormats/overview/","page":"Overview","title":"Overview","text":"The LP file format","category":"page"},{"location":"submodules/FileFormats/overview/","page":"Overview","title":"Overview","text":"julia> model = MOI.FileFormats.Model(format = MOI.FileFormats.FORMAT_LP)\nA .LP-file model","category":"page"},{"location":"submodules/FileFormats/overview/","page":"Overview","title":"Overview","text":"The MathOptFormat file format","category":"page"},{"location":"submodules/FileFormats/overview/","page":"Overview","title":"Overview","text":"julia> model = MOI.FileFormats.Model(format = MOI.FileFormats.FORMAT_MOF)\nA MathOptFormat Model","category":"page"},{"location":"submodules/FileFormats/overview/","page":"Overview","title":"Overview","text":"The MPS file format","category":"page"},{"location":"submodules/FileFormats/overview/","page":"Overview","title":"Overview","text":"julia> model = MOI.FileFormats.Model(format = MOI.FileFormats.FORMAT_MPS)\nA Mathematical Programming System (MPS) model","category":"page"},{"location":"submodules/FileFormats/overview/","page":"Overview","title":"Overview","text":"The NL file format","category":"page"},{"location":"submodules/FileFormats/overview/","page":"Overview","title":"Overview","text":"julia> model = MOI.FileFormats.Model(format = MOI.FileFormats.FORMAT_NL)\nAn AMPL (.nl) model","category":"page"},{"location":"submodules/FileFormats/overview/","page":"Overview","title":"Overview","text":"The REW file format","category":"page"},{"location":"submodules/FileFormats/overview/","page":"Overview","title":"Overview","text":"julia> model = MOI.FileFormats.Model(format = MOI.FileFormats.FORMAT_REW)\nA Mathematical Programming System (MPS) model","category":"page"},{"location":"submodules/FileFormats/overview/","page":"Overview","title":"Overview","text":"Note that the REW format is identical to the MPS file format, except that all names are replaced with generic identifiers.","category":"page"},{"location":"submodules/FileFormats/overview/","page":"Overview","title":"Overview","text":"The SDPA file format","category":"page"},{"location":"submodules/FileFormats/overview/","page":"Overview","title":"Overview","text":"julia> model = MOI.FileFormats.Model(format = MOI.FileFormats.FORMAT_SDPA)\nA SemiDefinite Programming Algorithm Format (SDPA) model","category":"page"},{"location":"submodules/FileFormats/overview/#Write-to-file","page":"Overview","title":"Write to file","text":"","category":"section"},{"location":"submodules/FileFormats/overview/","page":"Overview","title":"Overview","text":"To write a model src to a MathOptFormat file, use:","category":"page"},{"location":"submodules/FileFormats/overview/","page":"Overview","title":"Overview","text":"julia> src = MOI.Utilities.Model{Float64}()\nMOIU.Model{Float64}\n\njulia> MOI.add_variable(src)\nMOI.VariableIndex(1)\n\njulia> dest = MOI.FileFormats.Model(format = MOI.FileFormats.FORMAT_MOF)\nA MathOptFormat Model\n\njulia> MOI.copy_to(dest, src)\nMathOptInterface.Utilities.IndexMap with 1 entry:\n MOI.VariableIndex(1) => MOI.VariableIndex(1)\n\njulia> MOI.write_to_file(dest, \"file.mof.json\")\n\njulia> print(read(\"file.mof.json\", String))\n{\n \"name\": \"MathOptFormat Model\",\n \"version\": {\n \"major\": 1,\n \"minor\": 5\n },\n \"variables\": [\n {\n \"name\": \"x1\"\n }\n ],\n \"objective\": {\n \"sense\": \"feasibility\"\n },\n \"constraints\": []\n}","category":"page"},{"location":"submodules/FileFormats/overview/#Read-from-file","page":"Overview","title":"Read from file","text":"","category":"section"},{"location":"submodules/FileFormats/overview/","page":"Overview","title":"Overview","text":"To read a MathOptFormat file, use:","category":"page"},{"location":"submodules/FileFormats/overview/","page":"Overview","title":"Overview","text":"julia> dest = MOI.FileFormats.Model(format = MOI.FileFormats.FORMAT_MOF)\nA MathOptFormat Model\n\njulia> MOI.read_from_file(dest, \"file.mof.json\")\n\njulia> MOI.get(dest, MOI.ListOfVariableIndices())\n1-element Vector{MathOptInterface.VariableIndex}:\n MOI.VariableIndex(1)\n\njulia> rm(\"file.mof.json\") # Clean up after ourselves.","category":"page"},{"location":"submodules/FileFormats/overview/#Detecting-the-file-type-automatically","page":"Overview","title":"Detecting the file-type automatically","text":"","category":"section"},{"location":"submodules/FileFormats/overview/","page":"Overview","title":"Overview","text":"Instead of the format keyword, you can also use the filename keyword argument to FileFormats.Model. This will attempt to automatically guess the format from the file extension. For example:","category":"page"},{"location":"submodules/FileFormats/overview/","page":"Overview","title":"Overview","text":"julia> src = MOI.Utilities.Model{Float64}()\nMOIU.Model{Float64}\n\njulia> dest = MOI.FileFormats.Model(filename = \"file.cbf.gz\")\nA Conic Benchmark Format (CBF) model\n\njulia> MOI.copy_to(dest, src)\nMathOptInterface.Utilities.IndexMap()\n\njulia> MOI.write_to_file(dest, \"file.cbf.gz\")\n\njulia> src_2 = MOI.FileFormats.Model(filename = \"file.cbf.gz\")\nA Conic Benchmark Format (CBF) model\n\njulia> src = MOI.Utilities.Model{Float64}()\nMOIU.Model{Float64}\n\njulia> dest = MOI.FileFormats.Model(filename = \"file.cbf.gz\")\nA Conic Benchmark Format (CBF) model\n\njulia> MOI.copy_to(dest, src)\nMathOptInterface.Utilities.IndexMap()\n\njulia> MOI.write_to_file(dest, \"file.cbf.gz\")\n\njulia> src_2 = MOI.FileFormats.Model(filename = \"file.cbf.gz\")\nA Conic Benchmark Format (CBF) model\n\njulia> MOI.read_from_file(src_2, \"file.cbf.gz\")\n\njulia> rm(\"file.cbf.gz\") # Clean up after ourselves.","category":"page"},{"location":"submodules/FileFormats/overview/","page":"Overview","title":"Overview","text":"Note how the compression format (GZip) is also automatically detected from the filename.","category":"page"},{"location":"submodules/FileFormats/overview/#Unsupported-constraints","page":"Overview","title":"Unsupported constraints","text":"","category":"section"},{"location":"submodules/FileFormats/overview/","page":"Overview","title":"Overview","text":"In some cases src may contain constraints that are not supported by the file format (for example, the CBF format supports integer variables but not binary). If so, copy src to a bridged model using Bridges.full_bridge_optimizer:","category":"page"},{"location":"submodules/FileFormats/overview/","page":"Overview","title":"Overview","text":"src = MOI.Utilities.Model{Float64}()\nx = MOI.add_variable(model)\nMOI.add_constraint(model, x, MOI.ZeroOne())\ndest = MOI.FileFormats.Model(format = MOI.FileFormats.FORMAT_CBF)\nbridged = MOI.Bridges.full_bridge_optimizer(dest, Float64)\nMOI.copy_to(bridged, src)\nMOI.write_to_file(dest, \"my_model.cbf\")","category":"page"},{"location":"submodules/FileFormats/overview/","page":"Overview","title":"Overview","text":"note: Note\nEven after bridging, it may still not be possible to write the model to file because of unsupported constraints (for example, PSD variables in the LP file format).","category":"page"},{"location":"submodules/FileFormats/overview/#Read-and-write-to-io","page":"Overview","title":"Read and write to io","text":"","category":"section"},{"location":"submodules/FileFormats/overview/","page":"Overview","title":"Overview","text":"In addition to write_to_file and read_from_file, you can read and write directly from IO streams using Base.write and Base.read!:","category":"page"},{"location":"submodules/FileFormats/overview/","page":"Overview","title":"Overview","text":"julia> src = MOI.Utilities.Model{Float64}()\nMOIU.Model{Float64}\n\njulia> dest = MOI.FileFormats.Model(format = MOI.FileFormats.FORMAT_MPS)\nA Mathematical Programming System (MPS) model\n\njulia> MOI.copy_to(dest, src)\nMathOptInterface.Utilities.IndexMap()\n\njulia> io = IOBuffer();\n\njulia> write(io, dest)\n\njulia> seekstart(io);\n\njulia> src_2 = MOI.FileFormats.Model(format = MOI.FileFormats.FORMAT_MPS)\nA Mathematical Programming System (MPS) model\n\njulia> read!(io, src_2);","category":"page"},{"location":"submodules/FileFormats/overview/#Validating-MOF-files","page":"Overview","title":"Validating MOF files","text":"","category":"section"},{"location":"submodules/FileFormats/overview/","page":"Overview","title":"Overview","text":"MathOptFormat files are governed by a schema. Use JSONSchema.jl to check if a .mof.json file satisfies the schema.","category":"page"},{"location":"submodules/FileFormats/overview/","page":"Overview","title":"Overview","text":"First, construct the schema object as follows:","category":"page"},{"location":"submodules/FileFormats/overview/","page":"Overview","title":"Overview","text":"julia> import JSON, JSONSchema\n\njulia> schema = JSONSchema.Schema(JSON.parsefile(MOI.FileFormats.MOF.SCHEMA_PATH))\nA JSONSchema","category":"page"},{"location":"submodules/FileFormats/overview/","page":"Overview","title":"Overview","text":"Then, check if a model file is valid using isvalid:","category":"page"},{"location":"submodules/FileFormats/overview/","page":"Overview","title":"Overview","text":"julia> good_model = JSON.parse(\"\"\"\n {\n \"version\": {\n \"major\": 1,\n \"minor\": 5\n },\n \"variables\": [{\"name\": \"x\"}],\n \"objective\": {\"sense\": \"feasibility\"},\n \"constraints\": []\n }\n \"\"\");\n\njulia> isvalid(schema, good_model)\ntrue","category":"page"},{"location":"submodules/FileFormats/overview/","page":"Overview","title":"Overview","text":"If we construct an invalid file, for example by mis-typing name as NaMe, the validation fails:","category":"page"},{"location":"submodules/FileFormats/overview/","page":"Overview","title":"Overview","text":"julia> bad_model = JSON.parse(\"\"\"\n {\n \"version\": {\n \"major\": 1,\n \"minor\": 5\n },\n \"variables\": [{\"NaMe\": \"x\"}],\n \"objective\": {\"sense\": \"feasibility\"},\n \"constraints\": []\n }\n \"\"\");\n\njulia> isvalid(schema, bad_model)\nfalse","category":"page"},{"location":"submodules/FileFormats/overview/","page":"Overview","title":"Overview","text":"Use JSONSchema.validate to obtain more insight into why the validation failed:","category":"page"},{"location":"submodules/FileFormats/overview/","page":"Overview","title":"Overview","text":"julia> JSONSchema.validate(schema, bad_model)\nValidation failed:\npath: [variables][1]\ninstance: Dict{String, Any}(\"NaMe\" => \"x\")\nschema key: required\nschema value: Any[\"name\"]","category":"page"},{"location":"tutorials/example/","page":"Solving a problem using MathOptInterface","title":"Solving a problem using MathOptInterface","text":"CurrentModule = MathOptInterface\nDocTestSetup = quote\n import MathOptInterface as MOI\nend\nDocTestFilters = [r\"MathOptInterface|MOI\"]","category":"page"},{"location":"tutorials/example/#Solving-a-problem-using-MathOptInterface","page":"Solving a problem using MathOptInterface","title":"Solving a problem using MathOptInterface","text":"","category":"section"},{"location":"tutorials/example/","page":"Solving a problem using MathOptInterface","title":"Solving a problem using MathOptInterface","text":"In this tutorial we demonstrate how to use MathOptInterface to solve the binary-constrained knapsack problem:","category":"page"},{"location":"tutorials/example/","page":"Solving a problem using MathOptInterface","title":"Solving a problem using MathOptInterface","text":"beginaligned\nmax c^top x \nst w^top x le C \n x_i in 01quad forall i=1ldotsn\nendaligned","category":"page"},{"location":"tutorials/example/#Required-packages","page":"Solving a problem using MathOptInterface","title":"Required packages","text":"","category":"section"},{"location":"tutorials/example/","page":"Solving a problem using MathOptInterface","title":"Solving a problem using MathOptInterface","text":"Load the MathOptInterface module and define the shorthand MOI:","category":"page"},{"location":"tutorials/example/","page":"Solving a problem using MathOptInterface","title":"Solving a problem using MathOptInterface","text":"import MathOptInterface as MOI","category":"page"},{"location":"tutorials/example/","page":"Solving a problem using MathOptInterface","title":"Solving a problem using MathOptInterface","text":"As an optimizer, we choose GLPK:","category":"page"},{"location":"tutorials/example/","page":"Solving a problem using MathOptInterface","title":"Solving a problem using MathOptInterface","text":"using GLPK\noptimizer = GLPK.Optimizer()","category":"page"},{"location":"tutorials/example/#Define-the-data","page":"Solving a problem using MathOptInterface","title":"Define the data","text":"","category":"section"},{"location":"tutorials/example/","page":"Solving a problem using MathOptInterface","title":"Solving a problem using MathOptInterface","text":"We first define the constants of the problem:","category":"page"},{"location":"tutorials/example/","page":"Solving a problem using MathOptInterface","title":"Solving a problem using MathOptInterface","text":"julia> c = [1.0, 2.0, 3.0]\n3-element Vector{Float64}:\n 1.0\n 2.0\n 3.0\n\njulia> w = [0.3, 0.5, 1.0]\n3-element Vector{Float64}:\n 0.3\n 0.5\n 1.0\n\njulia> C = 3.2\n3.2","category":"page"},{"location":"tutorials/example/#Add-the-variables","page":"Solving a problem using MathOptInterface","title":"Add the variables","text":"","category":"section"},{"location":"tutorials/example/","page":"Solving a problem using MathOptInterface","title":"Solving a problem using MathOptInterface","text":"julia> x = MOI.add_variables(optimizer, length(c));","category":"page"},{"location":"tutorials/example/#set_objective_example","page":"Solving a problem using MathOptInterface","title":"Set the objective","text":"","category":"section"},{"location":"tutorials/example/","page":"Solving a problem using MathOptInterface","title":"Solving a problem using MathOptInterface","text":"julia> MOI.set(\n optimizer,\n MOI.ObjectiveFunction{MOI.ScalarAffineFunction{Float64}}(),\n MOI.ScalarAffineFunction(MOI.ScalarAffineTerm.(c, x), 0.0),\n );\n\njulia> MOI.set(optimizer, MOI.ObjectiveSense(), MOI.MAX_SENSE)","category":"page"},{"location":"tutorials/example/","page":"Solving a problem using MathOptInterface","title":"Solving a problem using MathOptInterface","text":"tip: Tip\nMOI.ScalarAffineTerm.(c, x) is a shortcut for [MOI.ScalarAffineTerm(c[i], x[i]) for i = 1:3]. This is Julia's broadcast syntax in action, and is used quite often throughout MOI.","category":"page"},{"location":"tutorials/example/#Add-the-constraints","page":"Solving a problem using MathOptInterface","title":"Add the constraints","text":"","category":"section"},{"location":"tutorials/example/","page":"Solving a problem using MathOptInterface","title":"Solving a problem using MathOptInterface","text":"We add the knapsack constraint and integrality constraints:","category":"page"},{"location":"tutorials/example/","page":"Solving a problem using MathOptInterface","title":"Solving a problem using MathOptInterface","text":"julia> MOI.add_constraint(\n optimizer,\n MOI.ScalarAffineFunction(MOI.ScalarAffineTerm.(w, x), 0.0),\n MOI.LessThan(C),\n );","category":"page"},{"location":"tutorials/example/","page":"Solving a problem using MathOptInterface","title":"Solving a problem using MathOptInterface","text":"Add integrality constraints:","category":"page"},{"location":"tutorials/example/","page":"Solving a problem using MathOptInterface","title":"Solving a problem using MathOptInterface","text":"julia> for x_i in x\n MOI.add_constraint(optimizer, x_i, MOI.ZeroOne())\n end","category":"page"},{"location":"tutorials/example/#Optimize-the-model","page":"Solving a problem using MathOptInterface","title":"Optimize the model","text":"","category":"section"},{"location":"tutorials/example/","page":"Solving a problem using MathOptInterface","title":"Solving a problem using MathOptInterface","text":"julia> MOI.optimize!(optimizer)","category":"page"},{"location":"tutorials/example/#Understand-why-the-solver-stopped","page":"Solving a problem using MathOptInterface","title":"Understand why the solver stopped","text":"","category":"section"},{"location":"tutorials/example/","page":"Solving a problem using MathOptInterface","title":"Solving a problem using MathOptInterface","text":"The first thing to check after optimization is why the solver stopped, for example, did it stop because of a time limit or did it stop because it found the optimal solution?","category":"page"},{"location":"tutorials/example/","page":"Solving a problem using MathOptInterface","title":"Solving a problem using MathOptInterface","text":"julia> MOI.get(optimizer, MOI.TerminationStatus())\nOPTIMAL::TerminationStatusCode = 1","category":"page"},{"location":"tutorials/example/","page":"Solving a problem using MathOptInterface","title":"Solving a problem using MathOptInterface","text":"Looks like we found an optimal solution.","category":"page"},{"location":"tutorials/example/#Understand-what-solution-was-returned","page":"Solving a problem using MathOptInterface","title":"Understand what solution was returned","text":"","category":"section"},{"location":"tutorials/example/","page":"Solving a problem using MathOptInterface","title":"Solving a problem using MathOptInterface","text":"julia> MOI.get(optimizer, MOI.ResultCount())\n1\n\njulia> MOI.get(optimizer, MOI.PrimalStatus())\nFEASIBLE_POINT::ResultStatusCode = 1\n\njulia> MOI.get(optimizer, MOI.DualStatus())\nNO_SOLUTION::ResultStatusCode = 0","category":"page"},{"location":"tutorials/example/#Query-the-objective","page":"Solving a problem using MathOptInterface","title":"Query the objective","text":"","category":"section"},{"location":"tutorials/example/","page":"Solving a problem using MathOptInterface","title":"Solving a problem using MathOptInterface","text":"What is its objective value?","category":"page"},{"location":"tutorials/example/","page":"Solving a problem using MathOptInterface","title":"Solving a problem using MathOptInterface","text":"julia> MOI.get(optimizer, MOI.ObjectiveValue())\n6.0","category":"page"},{"location":"tutorials/example/#Query-the-primal-solution","page":"Solving a problem using MathOptInterface","title":"Query the primal solution","text":"","category":"section"},{"location":"tutorials/example/","page":"Solving a problem using MathOptInterface","title":"Solving a problem using MathOptInterface","text":"And what is the value of the variables x?","category":"page"},{"location":"tutorials/example/","page":"Solving a problem using MathOptInterface","title":"Solving a problem using MathOptInterface","text":"julia> MOI.get(optimizer, MOI.VariablePrimal(), x)\n3-element Vector{Float64}:\n 1.0\n 1.0\n 1.0","category":"page"},{"location":"submodules/Utilities/reference/","page":"API Reference","title":"API Reference","text":"CurrentModule = MathOptInterface\nDocTestSetup = quote\n import MathOptInterface as MOI\nend\nDocTestFilters = [r\"MathOptInterface|MOI\"]","category":"page"},{"location":"submodules/Utilities/reference/#Utilities.Model","page":"API Reference","title":"Utilities.Model","text":"","category":"section"},{"location":"submodules/Utilities/reference/","page":"API Reference","title":"API Reference","text":"Utilities.Model","category":"page"},{"location":"submodules/Utilities/reference/#MathOptInterface.Utilities.Model","page":"API Reference","title":"MathOptInterface.Utilities.Model","text":"An implementation of ModelLike that supports all functions and sets defined in MOI. It is parameterized by the coefficient type.\n\nExamples\n\nmodel = Model{Float64}()\nx = add_variable(model)\n\n\n\n\n\n","category":"type"},{"location":"submodules/Utilities/reference/#Utilities.UniversalFallback","page":"API Reference","title":"Utilities.UniversalFallback","text":"","category":"section"},{"location":"submodules/Utilities/reference/","page":"API Reference","title":"API Reference","text":"Utilities.UniversalFallback","category":"page"},{"location":"submodules/Utilities/reference/#MathOptInterface.Utilities.UniversalFallback","page":"API Reference","title":"MathOptInterface.Utilities.UniversalFallback","text":"UniversalFallback\n\nThe 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.\n\n\n\n\n\n","category":"type"},{"location":"submodules/Utilities/reference/#Utilities.@model","page":"API Reference","title":"Utilities.@model","text":"","category":"section"},{"location":"submodules/Utilities/reference/","page":"API Reference","title":"API Reference","text":"Utilities.@model\nUtilities.GenericModel\nUtilities.GenericOptimizer","category":"page"},{"location":"submodules/Utilities/reference/#MathOptInterface.Utilities.@model","page":"API Reference","title":"MathOptInterface.Utilities.@model","text":"macro model(\n model_name,\n scalar_sets,\n typed_scalar_sets,\n vector_sets,\n typed_vector_sets,\n scalar_functions,\n typed_scalar_functions,\n vector_functions,\n typed_vector_functions,\n is_optimizer = false\n)\n\nCreates a type model_name implementing the MOI model interface and containing scalar_sets scalar sets typed_scalar_sets typed scalar sets, vector_sets vector sets, typed_vector_sets typed vector sets, scalar_functions scalar functions, typed_scalar_functions typed scalar functions, vector_functions vector functions and typed_vector_functions typed vector functions. To give no set/function, write (), to give one set S, write (S,).\n\nThe function MOI.VariableIndex should not be given in scalar_functions. The model supports MOI.VariableIndex-in-S constraints where S is MOI.EqualTo, MOI.GreaterThan, MOI.LessThan, MOI.Interval, MOI.Integer, MOI.ZeroOne, MOI.Semicontinuous or MOI.Semiinteger. The sets supported with the MOI.VariableIndex cannot be controlled from the macro, use the UniversalFallback to support more sets.\n\nThis macro creates a model specialized for specific types of constraint, by defining specialized structures and methods. To create a model that, in addition to be optimized for specific constraints, also support arbitrary constraints and attributes, use UniversalFallback.\n\nIf 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.\n\nExamples\n\nThe model describing an linear program would be:\n\n@model(LPModel, # Name of model\n (), # untyped scalar sets\n (MOI.EqualTo, MOI.GreaterThan, MOI.LessThan, MOI.Interval), # typed scalar sets\n (MOI.Zeros, MOI.Nonnegatives, MOI.Nonpositives), # untyped vector sets\n (), # typed vector sets\n (), # untyped scalar functions\n (MOI.ScalarAffineFunction,), # typed scalar functions\n (MOI.VectorOfVariables,), # untyped vector functions\n (MOI.VectorAffineFunction,), # typed vector functions\n false\n )\n\nLet MOI denote MathOptInterface, MOIU denote MOI.Utilities. The macro would create the following types with struct_of_constraint_code:\n\nstruct LPModelScalarConstraints{T, C1, C2, C3, C4} <: MOIU.StructOfConstraints\n moi_equalto::C1\n moi_greaterthan::C2\n moi_lessthan::C3\n moi_interval::C4\nend\nstruct LPModelVectorConstraints{T, C1, C2, C3} <: MOIU.StructOfConstraints\n moi_zeros::C1\n moi_nonnegatives::C2\n moi_nonpositives::C3\nend\nstruct LPModelFunctionConstraints{T} <: MOIU.StructOfConstraints\n moi_scalaraffinefunction::LPModelScalarConstraints{\n T,\n MOIU.VectorOfConstraints{MOI.ScalarAffineFunction{T}, MOI.EqualTo{T}},\n MOIU.VectorOfConstraints{MOI.ScalarAffineFunction{T}, MOI.GreaterThan{T}},\n MOIU.VectorOfConstraints{MOI.ScalarAffineFunction{T}, MOI.LessThan{T}},\n MOIU.VectorOfConstraints{MOI.ScalarAffineFunction{T}, MOI.Interval{T}}\n }\n moi_vectorofvariables::LPModelVectorConstraints{\n T,\n MOIU.VectorOfConstraints{MOI.VectorOfVariables, MOI.Zeros},\n MOIU.VectorOfConstraints{MOI.VectorOfVariables, MOI.Nonnegatives},\n MOIU.VectorOfConstraints{MOI.VectorOfVariables, MOI.Nonpositives}\n }\n moi_vectoraffinefunction::LPModelVectorConstraints{\n T,\n MOIU.VectorOfConstraints{MOI.VectorAffineFunction{T}, MOI.Zeros},\n MOIU.VectorOfConstraints{MOI.VectorAffineFunction{T}, MOI.Nonnegatives},\n MOIU.VectorOfConstraints{MOI.VectorAffineFunction{T}, MOI.Nonpositives}\n }\nend\nconst LPModel{T} = MOIU.GenericModel{T,MOIU.ObjectiveContainer{T},MOIU.VariablesContainer{T},LPModelFunctionConstraints{T}}\n\nThe type LPModel implements the MathOptInterface API except methods specific to optimizers like optimize! or get with VariablePrimal.\n\n\n\n\n\n","category":"macro"},{"location":"submodules/Utilities/reference/#MathOptInterface.Utilities.GenericModel","page":"API Reference","title":"MathOptInterface.Utilities.GenericModel","text":"mutable struct GenericModel{T,O,V,C} <: AbstractModelLike{T}\n\nImplements a model supporting coefficients of type T and:\n\nAn objective function stored in .objective::O\nVariables and VariableIndex constraints stored in .variable_bounds::V\nF-in-S constraints (excluding VariableIndex constraints) stored in .constraints::C\n\nAll interactions should take place via the MOI interface, so the types O, V, and C should implement the API as needed for their functionality.\n\n\n\n\n\n","category":"type"},{"location":"submodules/Utilities/reference/#MathOptInterface.Utilities.GenericOptimizer","page":"API Reference","title":"MathOptInterface.Utilities.GenericOptimizer","text":"mutable struct GenericOptimizer{T,O,V,C} <: AbstractOptimizer{T}\n\nImplements a model supporting coefficients of type T and:\n\nAn objective function stored in .objective::O\nVariables and VariableIndex constraints stored in .variable_bounds::V\nF-in-S constraints (excluding VariableIndex constraints) stored in .constraints::C\n\nAll interactions should take place via the MOI interface, so the types O, V, and C should implement the API as needed for their functionality.\n\n\n\n\n\n","category":"type"},{"location":"submodules/Utilities/reference/#.objective","page":"API Reference","title":".objective","text":"","category":"section"},{"location":"submodules/Utilities/reference/","page":"API Reference","title":"API Reference","text":"Utilities.ObjectiveContainer","category":"page"},{"location":"submodules/Utilities/reference/#MathOptInterface.Utilities.ObjectiveContainer","page":"API Reference","title":"MathOptInterface.Utilities.ObjectiveContainer","text":"ObjectiveContainer{T}\n\nA helper struct to simplify the handling of objective functions in Utilities.Model.\n\n\n\n\n\n","category":"type"},{"location":"submodules/Utilities/reference/#.variables","page":"API Reference","title":".variables","text":"","category":"section"},{"location":"submodules/Utilities/reference/","page":"API Reference","title":"API Reference","text":"Utilities.VariablesContainer\nUtilities.FreeVariables","category":"page"},{"location":"submodules/Utilities/reference/#MathOptInterface.Utilities.VariablesContainer","page":"API Reference","title":"MathOptInterface.Utilities.VariablesContainer","text":"struct VariablesContainer{T} <: AbstractVectorBounds\n set_mask::Vector{UInt16}\n lower::Vector{T}\n upper::Vector{T}\nend\n\nA struct for storing variables and VariableIndex-related constraints. Used in MOI.Utilities.Model by default.\n\n\n\n\n\n","category":"type"},{"location":"submodules/Utilities/reference/#MathOptInterface.Utilities.FreeVariables","page":"API Reference","title":"MathOptInterface.Utilities.FreeVariables","text":"mutable struct FreeVariables <: MOI.ModelLike\n n::Int64\n FreeVariables() = new(0)\nend\n\nA 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.\n\nExample\n\nThe 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.\n\njulia> MOI.Utilities.@product_of_sets(\n Cones,\n MOI.Zeros,\n MOI.Nonnegatives,\n MOI.SecondOrderCone,\n MOI.PositiveSemidefiniteConeTriangle,\n);\n\njulia> const ConicModel{T} = MOI.Utilities.GenericOptimizer{\n T,\n MOI.Utilities.ObjectiveContainer{T},\n MOI.Utilities.FreeVariables,\n MOI.Utilities.MatrixOfConstraints{\n T,\n MOI.Utilities.MutableSparseMatrixCSC{\n T,\n Int,\n MOI.Utilities.OneBasedIndexing,\n },\n Vector{T},\n Cones{T},\n },\n};\n\njulia> model = MOI.instantiate(ConicModel{Float64}, with_bridge_type=Float64);\n\njulia> x = MOI.add_variable(model)\nMathOptInterface.VariableIndex(1)\n\njulia> c = MOI.add_constraint(model, x, MOI.GreaterThan(1.0))\nMathOptInterface.ConstraintIndex{MathOptInterface.VariableIndex, MathOptInterface.GreaterThan{Float64}}(1)\n\njulia> MOI.Bridges.is_bridged(model, c)\ntrue\n\njulia> bridge = MOI.Bridges.bridge(model, c)\nMathOptInterface.Bridges.Constraint.VectorizeBridge{Float64, MathOptInterface.VectorAffineFunction{Float64}, MathOptInterface.Nonnegatives, MathOptInterface.VariableIndex}(MathOptInterface.ConstraintIndex{MathOptInterface.VectorAffineFunction{Float64}, MathOptInterface.Nonnegatives}(1), 1.0)\n\njulia> bridge.vector_constraint\nMathOptInterface.ConstraintIndex{MathOptInterface.VectorAffineFunction{Float64}, MathOptInterface.Nonnegatives}(1)\n\njulia> MOI.Bridges.is_bridged(model, bridge.vector_constraint)\nfalse\n\n\n\n\n\n","category":"type"},{"location":"submodules/Utilities/reference/#.constraints","page":"API Reference","title":".constraints","text":"","category":"section"},{"location":"submodules/Utilities/reference/","page":"API Reference","title":"API Reference","text":"Utilities.VectorOfConstraints\nUtilities.StructOfConstraints\nUtilities.@struct_of_constraints_by_function_types\nUtilities.@struct_of_constraints_by_set_types\nUtilities.struct_of_constraint_code","category":"page"},{"location":"submodules/Utilities/reference/#MathOptInterface.Utilities.VectorOfConstraints","page":"API Reference","title":"MathOptInterface.Utilities.VectorOfConstraints","text":"mutable struct VectorOfConstraints{\n F<:MOI.AbstractFunction,\n S<:MOI.AbstractSet,\n} <: MOI.ModelLike\n constraints::CleverDicts.CleverDict{\n MOI.ConstraintIndex{F,S},\n Tuple{F,S},\n typeof(CleverDicts.key_to_index),\n typeof(CleverDicts.index_to_key),\n }\nend\n\nA struct storing F-in-S constraints as a mapping between the constraint indices to the corresponding tuple of function and set.\n\n\n\n\n\n","category":"type"},{"location":"submodules/Utilities/reference/#MathOptInterface.Utilities.StructOfConstraints","page":"API Reference","title":"MathOptInterface.Utilities.StructOfConstraints","text":"abstract type StructOfConstraints <: MOI.ModelLike end\n\nA struct storing a subfields other structs storing constraints of different types.\n\nSee Utilities.@struct_of_constraints_by_function_types and Utilities.@struct_of_constraints_by_set_types.\n\n\n\n\n\n","category":"type"},{"location":"submodules/Utilities/reference/#MathOptInterface.Utilities.@struct_of_constraints_by_function_types","page":"API Reference","title":"MathOptInterface.Utilities.@struct_of_constraints_by_function_types","text":"Utilities.@struct_of_constraints_by_function_types(name, func_types...)\n\nGiven 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 ith field has type Ci and stores the constraints of function type Fi.\n\nThe 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.\n\n\n\n\n\n","category":"macro"},{"location":"submodules/Utilities/reference/#MathOptInterface.Utilities.@struct_of_constraints_by_set_types","page":"API Reference","title":"MathOptInterface.Utilities.@struct_of_constraints_by_set_types","text":"Utilities.@struct_of_constraints_by_set_types(name, func_types...)\n\nGiven 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 ith 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.\n\n\n\n\n\n","category":"macro"},{"location":"submodules/Utilities/reference/#MathOptInterface.Utilities.struct_of_constraint_code","page":"API Reference","title":"MathOptInterface.Utilities.struct_of_constraint_code","text":"struct_of_constraint_code(struct_name, types, field_types = nothing)\n\nGiven 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 ith 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.\n\nThis function is used by the macros @model, @struct_of_constraints_by_function_types and @struct_of_constraints_by_set_types.\n\n\n\n\n\n","category":"function"},{"location":"submodules/Utilities/reference/#Caching-optimizer","page":"API Reference","title":"Caching optimizer","text":"","category":"section"},{"location":"submodules/Utilities/reference/","page":"API Reference","title":"API Reference","text":"Utilities.CachingOptimizer\nUtilities.attach_optimizer\nUtilities.reset_optimizer\nUtilities.drop_optimizer\nUtilities.state\nUtilities.mode","category":"page"},{"location":"submodules/Utilities/reference/#MathOptInterface.Utilities.CachingOptimizer","page":"API Reference","title":"MathOptInterface.Utilities.CachingOptimizer","text":"CachingOptimizer\n\nCachingOptimizer 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.\n\nConstructors\n\n CachingOptimizer(cache::MOI.ModelLike, optimizer::AbstractOptimizer)\n\nCreates a CachingOptimizer in AUTOMATIC mode, with the optimizer optimizer.\n\nThe 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.\n\n CachingOptimizer(cache::MOI.ModelLike, mode::CachingOptimizerMode)\n\nCreates a CachingOptimizer in the NO_OPTIMIZER state and mode mode.\n\nThe 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.\n\nAbout the type\n\nStates\n\nA CachingOptimizer may be in one of three possible states (CachingOptimizerState):\n\nNO_OPTIMIZER: The CachingOptimizer does not have any optimizer.\nEMPTY_OPTIMIZER: The CachingOptimizer has an empty optimizer. The optimizer is not synchronized with the cached model.\nATTACHED_OPTIMIZER: The CachingOptimizer has an optimizer, and it is synchronized with the cached model.\n\nModes\n\nA CachingOptimizer has two modes of operation (CachingOptimizerMode):\n\nMANUAL: The only methods that change the state of the CachingOptimizer are Utilities.reset_optimizer, Utilities.drop_optimizer, and Utilities.attach_optimizer. Attempting to perform an operation in the incorrect state results in an error.\nAUTOMATIC: The CachingOptimizer changes its state when necessary. For example, optimize! will automatically call attach_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 to EMPTY_OPTIMIZER mode.\n\n\n\n\n\n","category":"type"},{"location":"submodules/Utilities/reference/#MathOptInterface.Utilities.attach_optimizer","page":"API Reference","title":"MathOptInterface.Utilities.attach_optimizer","text":"attach_optimizer(model::CachingOptimizer)\n\nAttaches 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.\n\n\n\n\n\n","category":"function"},{"location":"submodules/Utilities/reference/#MathOptInterface.Utilities.reset_optimizer","page":"API Reference","title":"MathOptInterface.Utilities.reset_optimizer","text":"reset_optimizer(m::CachingOptimizer, optimizer::MOI.AbstractOptimizer)\n\nSets or resets m to have the given empty optimizer optimizer.\n\nCan be called from any state. An assertion error will be thrown if optimizer is not empty.\n\nThe CachingOptimizer m will be in state EMPTY_OPTIMIZER after the call.\n\n\n\n\n\nreset_optimizer(m::CachingOptimizer)\n\nDetaches 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.\n\n\n\n\n\n","category":"function"},{"location":"submodules/Utilities/reference/#MathOptInterface.Utilities.drop_optimizer","page":"API Reference","title":"MathOptInterface.Utilities.drop_optimizer","text":"drop_optimizer(m::CachingOptimizer)\n\nDrops the optimizer, if one is present. Can be called from any state. The CachingOptimizer will be in state NO_OPTIMIZER after the call.\n\n\n\n\n\n","category":"function"},{"location":"submodules/Utilities/reference/#MathOptInterface.Utilities.state","page":"API Reference","title":"MathOptInterface.Utilities.state","text":"state(m::CachingOptimizer)::CachingOptimizerState\n\nReturns the state of the CachingOptimizer m. See Utilities.CachingOptimizer.\n\n\n\n\n\n","category":"function"},{"location":"submodules/Utilities/reference/#MathOptInterface.Utilities.mode","page":"API Reference","title":"MathOptInterface.Utilities.mode","text":"mode(m::CachingOptimizer)::CachingOptimizerMode\n\nReturns the operating mode of the CachingOptimizer m. See Utilities.CachingOptimizer.\n\n\n\n\n\n","category":"function"},{"location":"submodules/Utilities/reference/#Mock-optimizer","page":"API Reference","title":"Mock optimizer","text":"","category":"section"},{"location":"submodules/Utilities/reference/","page":"API Reference","title":"API Reference","text":"Utilities.MockOptimizer","category":"page"},{"location":"submodules/Utilities/reference/#MathOptInterface.Utilities.MockOptimizer","page":"API Reference","title":"MathOptInterface.Utilities.MockOptimizer","text":"MockOptimizer\n\nMockOptimizer 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.\n\n\n\n\n\n","category":"type"},{"location":"submodules/Utilities/reference/#Printing","page":"API Reference","title":"Printing","text":"","category":"section"},{"location":"submodules/Utilities/reference/","page":"API Reference","title":"API Reference","text":"Utilities.latex_formulation","category":"page"},{"location":"submodules/Utilities/reference/#MathOptInterface.Utilities.latex_formulation","page":"API Reference","title":"MathOptInterface.Utilities.latex_formulation","text":"latex_formulation(model::MOI.ModelLike; kwargs...)\n\nWrap model in a type so that it can be pretty-printed as text/latex in a notebook like IJulia, or in Documenter.\n\nTo 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.\n\nPossible keyword arguments are:\n\nsimplify_coefficients : Simplify coefficients if possible by omitting them or removing trailing zeros.\ndefault_name : The name given to variables with an empty name.\nprint_types : Print the MOI type of each function and set for clarity.\n\n\n\n\n\n","category":"function"},{"location":"submodules/Utilities/reference/#Copy-utilities","page":"API Reference","title":"Copy utilities","text":"","category":"section"},{"location":"submodules/Utilities/reference/","page":"API Reference","title":"API Reference","text":"Utilities.default_copy_to\nUtilities.IndexMap\nUtilities.identity_index_map\nUtilities.ModelFilter","category":"page"},{"location":"submodules/Utilities/reference/#MathOptInterface.Utilities.default_copy_to","page":"API Reference","title":"MathOptInterface.Utilities.default_copy_to","text":"default_copy_to(dest::MOI.ModelLike, src::MOI.ModelLike)\n\nA default implementation of MOI.copy_to(dest, src) for models that implement the incremental interface, i.e., MOI.supports_incremental_interface returns true.\n\n\n\n\n\n","category":"function"},{"location":"submodules/Utilities/reference/#MathOptInterface.Utilities.IndexMap","page":"API Reference","title":"MathOptInterface.Utilities.IndexMap","text":"IndexMap()\n\nThe dictionary-like object returned by MOI.copy_to.\n\n\n\n\n\n","category":"type"},{"location":"submodules/Utilities/reference/#MathOptInterface.Utilities.identity_index_map","page":"API Reference","title":"MathOptInterface.Utilities.identity_index_map","text":"identity_index_map(model::MOI.ModelLike)\n\nReturn an IndexMap that maps all variable and constraint indices of model to themselves.\n\n\n\n\n\n","category":"function"},{"location":"submodules/Utilities/reference/#MathOptInterface.Utilities.ModelFilter","page":"API Reference","title":"MathOptInterface.Utilities.ModelFilter","text":"ModelFilter(filter::Function, model::MOI.ModelLike)\n\nA layer to filter out various components of model.\n\nThe 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.\n\nThe components that are filtered are:\n\nEntire constraint types via:\nMOI.ListOfConstraintTypesPresent\nIndividual constraints via:\nMOI.ListOfConstraintIndices{F,S}\nSpecific attributes via:\nMOI.ListOfModelAttributesSet\nMOI.ListOfConstraintAttributesSet\nMOI.ListOfVariableAttributesSet\n\nwarning: Warning\nThe 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.\n\nSee below for examples of how this works.\n\nnote: Note\nThis layer has a limited scope. It is intended by be used in conjunction with MOI.copy_to.\n\nExample: copy model excluding integer constraints\n\nUse the do syntax to provide a single function.\n\nfiltered_src = MOI.Utilities.ModelFilter(src) do item\n return item != (MOI.VariableIndex, MOI.Integer)\nend\nMOI.copy_to(dest, filtered_src)\n\nExample: copy model excluding names\n\nUse type dispatch to simplify the implementation:\n\nmy_filter(::Any) = true # Note the generic fallback!\nmy_filter(::MOI.VariableName) = false\nmy_filter(::MOI.ConstraintName) = false\nfiltered_src = MOI.Utilities.ModelFilter(my_filter, src)\nMOI.copy_to(dest, filtered_src)\n\nExample: copy irreducible infeasible subsystem\n\nmy_filter(::Any) = true # Note the generic fallback!\nfunction my_filter(ci::MOI.ConstraintIndex)\n status = MOI.get(dest, MOI.ConstraintConflictStatus(), ci)\n return status != MOI.NOT_IN_CONFLICT\nend\nfiltered_src = MOI.Utilities.ModelFilter(my_filter, src)\nMOI.copy_to(dest, filtered_src)\n\n\n\n\n\n","category":"type"},{"location":"submodules/Utilities/reference/#Penalty-relaxation","page":"API Reference","title":"Penalty relaxation","text":"","category":"section"},{"location":"submodules/Utilities/reference/","page":"API Reference","title":"API Reference","text":"Utilities.PenaltyRelaxation\nUtilities.ScalarPenaltyRelaxation","category":"page"},{"location":"submodules/Utilities/reference/#MathOptInterface.Utilities.PenaltyRelaxation","page":"API Reference","title":"MathOptInterface.Utilities.PenaltyRelaxation","text":"PenaltyRelaxation(\n penalties = Dict{MOI.ConstraintIndex,Float64}();\n default::Union{Nothing,T} = 1.0,\n)\n\nA problem modifier that, when passed to MOI.modify, destructively modifies the model in-place to create a penalized relaxation of the constraints.\n\nwarning: Warning\nThis 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.\n\nReformulation\n\nSee Utilities.ScalarPenaltyRelaxation for details of the reformulation.\n\nFor 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.\n\nReturn value\n\nMOI.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.\n\nRelax a subset of constraints\n\nTo relax a subset of constraints, pass a penalties dictionary and set default = nothing.\n\nSupported constraint types\n\nThe 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.\n\nIt does not include variable bound or integrality constraints, because these cannot be modified in-place.\n\nTo modify variable bounds, rewrite them as linear constraints.\n\nExamples\n\njulia> model = MOI.Utilities.Model{Float64}();\n\njulia> x = MOI.add_variable(model);\n\njulia> c = MOI.add_constraint(model, 1.0 * x, MOI.LessThan(2.0));\n\njulia> map = MOI.modify(model, MOI.Utilities.PenaltyRelaxation(default = 2.0));\n\njulia> print(model)\nMinimize ScalarAffineFunction{Float64}:\n 0.0 + 2.0 v[2]\n\nSubject to:\n\nScalarAffineFunction{Float64}-in-LessThan{Float64}\n 0.0 + 1.0 v[1] - 1.0 v[2] <= 2.0\n\nVariableIndex-in-GreaterThan{Float64}\n v[2] >= 0.0\n\njulia> map[c] isa MOI.ScalarAffineFunction{Float64}\ntrue\n\njulia> model = MOI.Utilities.Model{Float64}();\n\njulia> x = MOI.add_variable(model);\n\njulia> c = MOI.add_constraint(model, 1.0 * x, MOI.LessThan(2.0));\n\njulia> map = MOI.modify(model, MOI.Utilities.PenaltyRelaxation(Dict(c => 3.0)));\n\njulia> print(model)\nMinimize ScalarAffineFunction{Float64}:\n 0.0 + 3.0 v[2]\n\nSubject to:\n\nScalarAffineFunction{Float64}-in-LessThan{Float64}\n 0.0 + 1.0 v[1] - 1.0 v[2] <= 2.0\n\nVariableIndex-in-GreaterThan{Float64}\n v[2] >= 0.0\n\njulia> map[c] isa MOI.ScalarAffineFunction{Float64}\ntrue\n\n\n\n\n\n","category":"type"},{"location":"submodules/Utilities/reference/#MathOptInterface.Utilities.ScalarPenaltyRelaxation","page":"API Reference","title":"MathOptInterface.Utilities.ScalarPenaltyRelaxation","text":"ScalarPenaltyRelaxation(penalty::T) where {T}\n\nA problem modifier that, when passed to MOI.modify, destructively modifies the constraint in-place to create a penalized relaxation of the constraint.\n\nwarning: Warning\nThis 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.\n\nReformulation\n\nThe 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\n\nWhen S is MOI.LessThan or MOI.GreaterThan, we omit y or z respectively as a performance optimization.\n\nReturn value\n\nMOI.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.\n\nExamples\n\njulia> model = MOI.Utilities.Model{Float64}();\n\njulia> x = MOI.add_variable(model);\n\njulia> c = MOI.add_constraint(model, 1.0 * x, MOI.LessThan(2.0));\n\njulia> f = MOI.modify(model, c, MOI.Utilities.ScalarPenaltyRelaxation(2.0));\n\njulia> print(model)\nMinimize ScalarAffineFunction{Float64}:\n 0.0 + 2.0 v[2]\n\nSubject to:\n\nScalarAffineFunction{Float64}-in-LessThan{Float64}\n 0.0 + 1.0 v[1] - 1.0 v[2] <= 2.0\n\nVariableIndex-in-GreaterThan{Float64}\n v[2] >= 0.0\n\njulia> f isa MOI.ScalarAffineFunction{Float64}\ntrue\n\n\n\n\n\n","category":"type"},{"location":"submodules/Utilities/reference/#MatrixOfConstraints","page":"API Reference","title":"MatrixOfConstraints","text":"","category":"section"},{"location":"submodules/Utilities/reference/","page":"API Reference","title":"API Reference","text":"Utilities.MatrixOfConstraints","category":"page"},{"location":"submodules/Utilities/reference/#MathOptInterface.Utilities.MatrixOfConstraints","page":"API Reference","title":"MathOptInterface.Utilities.MatrixOfConstraints","text":"mutable struct MatrixOfConstraints{T,AT,BT,ST} <: MOI.ModelLike\n coefficients::AT\n constants::BT\n sets::ST\n caches::Vector{Any}\n are_indices_mapped::Vector{BitSet}\n final_touch::Bool\nend\n\nRepresent 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.\n\nThis model can only be used as the constraints field of a MOI.Utilities.AbstractModel.\n\nWhen 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.\n\nThe constraints can be added in two different ways:\n\nWith add_constraint, in which case a canonicalized copy of the function is stored in caches.\nWith pass_nonvariable_constraints, in which case the functions and sets are stored themselves in caches without mapping the variable indices. The corresponding index in caches is added in are_indices_mapped. This avoids doing a copy of the function in case the getter of CanonicalConstraintFunction does not make a copy for the source model, e.g., this is the case of VectorOfConstraints.\n\nWe 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.\n\nInterface\n\nThe .coefficients::AT type must implement:\n\nAT()\nMOI.empty(::AT)!\nMOI.Utilities.add_column\nMOI.Utilities.set_number_of_rows\nMOI.Utilities.allocate_terms\nMOI.Utilities.load_terms\nMOI.Utilities.final_touch\n\nThe .constants::BT type must implement:\n\nBT()\nBase.empty!(::BT)\nBase.resize(::BT)\nMOI.Utilities.load_constants\nMOI.Utilities.function_constants\nMOI.Utilities.set_from_constants\n\nThe .sets::ST type must implement:\n\nST()\nMOI.is_empty(::ST)\nMOI.empty(::ST)\nMOI.dimension(::ST)\nMOI.is_valid(::ST, ::MOI.ConstraintIndex)\nMOI.get(::ST, ::MOI.ListOfConstraintTypesPresent)\nMOI.get(::ST, ::MOI.NumberOfConstraints)\nMOI.get(::ST, ::MOI.ListOfConstraintIndices)\nMOI.Utilities.set_types\nMOI.Utilities.set_index\nMOI.Utilities.add_set\nMOI.Utilities.rows\nMOI.Utilities.final_touch\n\n\n\n\n\n","category":"type"},{"location":"submodules/Utilities/reference/#.coefficients","page":"API Reference","title":".coefficients","text":"","category":"section"},{"location":"submodules/Utilities/reference/","page":"API Reference","title":"API Reference","text":"Utilities.add_column\nUtilities.allocate_terms\nUtilities.set_number_of_rows\nUtilities.load_terms\nUtilities.final_touch\nUtilities.extract_function","category":"page"},{"location":"submodules/Utilities/reference/#MathOptInterface.Utilities.add_column","page":"API Reference","title":"MathOptInterface.Utilities.add_column","text":"add_column(coefficients)::Nothing\n\nTell coefficients to pre-allocate datastructures as needed to store one column.\n\n\n\n\n\n","category":"function"},{"location":"submodules/Utilities/reference/#MathOptInterface.Utilities.allocate_terms","page":"API Reference","title":"MathOptInterface.Utilities.allocate_terms","text":"allocate_terms(coefficients, index_map, func)::Nothing\n\nTell coefficients that the terms of the function func where the variable indices are mapped with index_map will be loaded with load_terms.\n\nThe function func must be canonicalized before calling allocate_terms. See is_canonical.\n\n\n\n\n\n","category":"function"},{"location":"submodules/Utilities/reference/#MathOptInterface.Utilities.set_number_of_rows","page":"API Reference","title":"MathOptInterface.Utilities.set_number_of_rows","text":"set_number_of_rows(coefficients, n)::Nothing\n\nTell coefficients to pre-allocate datastructures as needed to store n rows.\n\n\n\n\n\n","category":"function"},{"location":"submodules/Utilities/reference/#MathOptInterface.Utilities.load_terms","page":"API Reference","title":"MathOptInterface.Utilities.load_terms","text":"load_terms(coefficients, index_map, func, offset)::Nothing\n\nLoads the terms of func to coefficients, mapping the variable indices with index_map.\n\nThe ith dimension of func is loaded at the (offset + i)th row of coefficients.\n\nThe function must be allocated first with allocate_terms.\n\nThe function func must be canonicalized, see is_canonical.\n\n\n\n\n\n","category":"function"},{"location":"submodules/Utilities/reference/#MathOptInterface.Utilities.final_touch","page":"API Reference","title":"MathOptInterface.Utilities.final_touch","text":"final_touch(coefficients)::Nothing\n\nInforms the coefficients that all functions have been added with load_terms. No more modification is allowed unless MOI.empty! is called.\n\nfinal_touch(sets)::Nothing\n\nInforms the sets that all functions have been added with add_set. No more modification is allowed unless MOI.empty! is called.\n\n\n\n\n\n","category":"function"},{"location":"submodules/Utilities/reference/#MathOptInterface.Utilities.extract_function","page":"API Reference","title":"MathOptInterface.Utilities.extract_function","text":"extract_function(coefficients, row::Integer, constant::T) where {T}\n\nReturn the MOI.ScalarAffineFunction{T} function corresponding to row row in coefficients.\n\nextract_function(\n coefficients,\n rows::UnitRange,\n constants::Vector{T},\n) where{T}\n\nReturn the MOI.VectorAffineFunction{T} function corresponding to rows rows in coefficients.\n\n\n\n\n\n","category":"function"},{"location":"submodules/Utilities/reference/","page":"API Reference","title":"API Reference","text":"Utilities.MutableSparseMatrixCSC\nUtilities.AbstractIndexing\nUtilities.ZeroBasedIndexing\nUtilities.OneBasedIndexing","category":"page"},{"location":"submodules/Utilities/reference/#MathOptInterface.Utilities.MutableSparseMatrixCSC","page":"API Reference","title":"MathOptInterface.Utilities.MutableSparseMatrixCSC","text":"mutable struct MutableSparseMatrixCSC{Tv,Ti<:Integer,I<:AbstractIndexing}\n indexing::I\n m::Int\n n::Int\n colptr::Vector{Ti}\n rowval::Vector{Ti}\n nzval::Vector{Tv}\n nz_added::Vector{Ti}\nend\n\nMatrix 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.\n\nThe matrix is loaded in 5 steps:\n\nMOI.empty! is called.\nMOI.Utilities.add_column and MOI.Utilities.allocate_terms are called in any order.\nMOI.Utilities.set_number_of_rows is called.\nMOI.Utilities.load_terms is called for each affine function.\nMOI.Utilities.final_touch is called.\n\n\n\n\n\n","category":"type"},{"location":"submodules/Utilities/reference/#MathOptInterface.Utilities.AbstractIndexing","page":"API Reference","title":"MathOptInterface.Utilities.AbstractIndexing","text":"abstract type AbstractIndexing end\n\nIndexing to be used for storing the row and column indices of MutableSparseMatrixCSC. See ZeroBasedIndexing and OneBasedIndexing.\n\n\n\n\n\n","category":"type"},{"location":"submodules/Utilities/reference/#MathOptInterface.Utilities.ZeroBasedIndexing","page":"API Reference","title":"MathOptInterface.Utilities.ZeroBasedIndexing","text":"struct ZeroBasedIndexing <: AbstractIndexing end\n\nZero-based indexing: the ith 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.\n\n\n\n\n\n","category":"type"},{"location":"submodules/Utilities/reference/#MathOptInterface.Utilities.OneBasedIndexing","page":"API Reference","title":"MathOptInterface.Utilities.OneBasedIndexing","text":"struct ZeroBasedIndexing <: AbstractIndexing end\n\nOne-based indexing: the ith row or column has index i. This enables an allocation-free conversion of MutableSparseMatrixCSC to SparseArrays.SparseMatrixCSC.\n\n\n\n\n\n","category":"type"},{"location":"submodules/Utilities/reference/#.constants","page":"API Reference","title":".constants","text":"","category":"section"},{"location":"submodules/Utilities/reference/","page":"API Reference","title":"API Reference","text":"Utilities.load_constants\nUtilities.function_constants\nUtilities.set_from_constants","category":"page"},{"location":"submodules/Utilities/reference/#MathOptInterface.Utilities.load_constants","page":"API Reference","title":"MathOptInterface.Utilities.load_constants","text":"load_constants(constants, offset, func_or_set)::Nothing\n\nThis 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.\n\nThis function should be implemented to be usable as storage of constants for MatrixOfConstraints.\n\nThe constants are loaded in three steps:\n\nBase.empty! is called.\nBase.resize! is called with the sum of the dimensions of all constraints.\nMOI.Utilities.load_constants is called for each function for vector constraint or set for scalar constraint.\n\n\n\n\n\n","category":"function"},{"location":"submodules/Utilities/reference/#MathOptInterface.Utilities.function_constants","page":"API Reference","title":"MathOptInterface.Utilities.function_constants","text":"function_constants(constants, rows)\n\nThis function returns the function constants that were loaded with load_constants at the rows rows.\n\nThis function should be implemented to be usable as storage of constants for MatrixOfConstraints.\n\n\n\n\n\n","category":"function"},{"location":"submodules/Utilities/reference/#MathOptInterface.Utilities.set_from_constants","page":"API Reference","title":"MathOptInterface.Utilities.set_from_constants","text":"set_from_constants(constants, S::Type, rows)::S\n\nThis function returns an instance of the set S for which the constants where loaded with load_constants at the rows rows.\n\nThis function should be implemented to be usable as storage of constants for MatrixOfConstraints.\n\n\n\n\n\n","category":"function"},{"location":"submodules/Utilities/reference/","page":"API Reference","title":"API Reference","text":"Utilities.Hyperrectangle","category":"page"},{"location":"submodules/Utilities/reference/#MathOptInterface.Utilities.Hyperrectangle","page":"API Reference","title":"MathOptInterface.Utilities.Hyperrectangle","text":"struct Hyperrectangle{T} <: AbstractVectorBounds\n lower::Vector{T}\n upper::Vector{T}\nend\n\nA struct for the .constants field in MatrixOfConstraints.\n\n\n\n\n\n","category":"type"},{"location":"submodules/Utilities/reference/#.sets","page":"API Reference","title":".sets","text":"","category":"section"},{"location":"submodules/Utilities/reference/","page":"API Reference","title":"API Reference","text":"Utilities.set_index\nUtilities.set_types\nUtilities.add_set\nUtilities.rows\nUtilities.num_rows\nUtilities.set_with_dimension","category":"page"},{"location":"submodules/Utilities/reference/#MathOptInterface.Utilities.set_index","page":"API Reference","title":"MathOptInterface.Utilities.set_index","text":"set_index(sets, ::Type{S})::Union{Int,Nothing} where {S<:MOI.AbstractSet}\n\nReturn an integer corresponding to the index of the set type in the list given by set_types.\n\nIf S is not part of the list, return nothing.\n\n\n\n\n\n","category":"function"},{"location":"submodules/Utilities/reference/#MathOptInterface.Utilities.set_types","page":"API Reference","title":"MathOptInterface.Utilities.set_types","text":"set_types(sets)::Vector{Type}\n\nReturn the list of the types of the sets allowed in sets.\n\n\n\n\n\n","category":"function"},{"location":"submodules/Utilities/reference/#MathOptInterface.Utilities.add_set","page":"API Reference","title":"MathOptInterface.Utilities.add_set","text":"add_set(sets, i)::Int64\n\nAdd a scalar set of type index i.\n\nadd_set(sets, i, dim)::Int64\n\nAdd a vector set of type index i and dimension dim.\n\nBoth methods return a unique Int64 of the set that can be used to reference this set.\n\n\n\n\n\n","category":"function"},{"location":"submodules/Utilities/reference/#MathOptInterface.Utilities.rows","page":"API Reference","title":"MathOptInterface.Utilities.rows","text":"rows(sets, ci::MOI.ConstraintIndex)::Union{Int,UnitRange{Int}}\n\nReturn the rows in 1:MOI.dimension(sets) corresponding to the set of id ci.value.\n\nFor scalar sets, this returns an Int. For vector sets, this returns an UnitRange{Int}.\n\n\n\n\n\n","category":"function"},{"location":"submodules/Utilities/reference/#MathOptInterface.Utilities.num_rows","page":"API Reference","title":"MathOptInterface.Utilities.num_rows","text":"num_rows(sets::OrderedProductOfSets, ::Type{S}) where {S}\n\nReturn 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.\n\n\n\n\n\n","category":"function"},{"location":"submodules/Utilities/reference/#MathOptInterface.Utilities.set_with_dimension","page":"API Reference","title":"MathOptInterface.Utilities.set_with_dimension","text":"set_with_dimension(::Type{S}, dim) where {S<:MOI.AbstractVectorSet}\n\nReturns the instance of S of MOI.dimension dim. This needs to be implemented for sets of type S to be useable with MatrixOfConstraints.\n\n\n\n\n\n","category":"function"},{"location":"submodules/Utilities/reference/","page":"API Reference","title":"API Reference","text":"Utilities.ProductOfSets\nUtilities.MixOfScalarSets\nUtilities.@mix_of_scalar_sets\nUtilities.OrderedProductOfSets\nUtilities.@product_of_sets","category":"page"},{"location":"submodules/Utilities/reference/#MathOptInterface.Utilities.ProductOfSets","page":"API Reference","title":"MathOptInterface.Utilities.ProductOfSets","text":"abstract type ProductOfSets{T} end\n\nRepresents a cartesian product of sets of given types.\n\n\n\n\n\n","category":"type"},{"location":"submodules/Utilities/reference/#MathOptInterface.Utilities.MixOfScalarSets","page":"API Reference","title":"MathOptInterface.Utilities.MixOfScalarSets","text":"abstract type MixOfScalarSets{T} <: ProductOfSets{T} end\n\nProduct of scalar sets in the order the constraints are added, mixing the constraints of different types.\n\nUse @mix_of_scalar_sets to generate a new subtype.\n\n\n\n\n\n","category":"type"},{"location":"submodules/Utilities/reference/#MathOptInterface.Utilities.@mix_of_scalar_sets","page":"API Reference","title":"MathOptInterface.Utilities.@mix_of_scalar_sets","text":"@mix_of_scalar_sets(name, set_types...)\n\nGenerate a new MixOfScalarSets subtype.\n\nExample\n\n@mix_of_scalar_sets(\n MixedIntegerLinearProgramSets,\n MOI.GreaterThan{T},\n MOI.LessThan{T},\n MOI.EqualTo{T},\n MOI.Integer,\n)\n\n\n\n\n\n","category":"macro"},{"location":"submodules/Utilities/reference/#MathOptInterface.Utilities.OrderedProductOfSets","page":"API Reference","title":"MathOptInterface.Utilities.OrderedProductOfSets","text":"abstract type OrderedProductOfSets{T} <: ProductOfSets{T} end\n\nProduct of sets in the order the constraints are added, grouping the constraints of the same types contiguously.\n\nUse @product_of_sets to generate new subtypes.\n\n\n\n\n\n","category":"type"},{"location":"submodules/Utilities/reference/#MathOptInterface.Utilities.@product_of_sets","page":"API Reference","title":"MathOptInterface.Utilities.@product_of_sets","text":"@product_of_sets(name, set_types...)\n\nGenerate a new OrderedProductOfSets subtype.\n\nExample\n\n@product_of_sets(\n LinearOrthants,\n MOI.Zeros,\n MOI.Nonnegatives,\n MOI.Nonpositives,\n MOI.ZeroOne,\n)\n\n\n\n\n\n","category":"macro"},{"location":"submodules/Utilities/reference/#Fallbacks","page":"API Reference","title":"Fallbacks","text":"","category":"section"},{"location":"submodules/Utilities/reference/","page":"API Reference","title":"API Reference","text":"Utilities.get_fallback","category":"page"},{"location":"submodules/Utilities/reference/#MathOptInterface.Utilities.get_fallback","page":"API Reference","title":"MathOptInterface.Utilities.get_fallback","text":"get_fallback(model::MOI.ModelLike, ::MOI.ObjectiveValue)\n\nCompute the objective function value using the VariablePrimal results and the ObjectiveFunction value.\n\n\n\n\n\nget_fallback(model::MOI.ModelLike, ::MOI.DualObjectiveValue, T::Type)::T\n\nCompute 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.\n\n\n\n\n\nget_fallback(model::MOI.ModelLike, ::MOI.ConstraintPrimal,\n constraint_index::MOI.ConstraintIndex)\n\nCompute the value of the function of the constraint of index constraint_index using the VariablePrimal results and the ConstraintFunction values.\n\n\n\n\n\nget_fallback(model::MOI.ModelLike, attr::MOI.ConstraintDual,\n ci::MOI.ConstraintIndex{Union{MOI.VariableIndex,\n MOI.VectorOfVariables}})\n\nCompute 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.\n\n\n\n\n\n","category":"function"},{"location":"submodules/Utilities/reference/#Function-utilities","page":"API Reference","title":"Function utilities","text":"","category":"section"},{"location":"submodules/Utilities/reference/","page":"API Reference","title":"API Reference","text":"The following utilities are available for functions:","category":"page"},{"location":"submodules/Utilities/reference/","page":"API Reference","title":"API Reference","text":"Utilities.eval_variables\nUtilities.map_indices\nUtilities.substitute_variables\nUtilities.filter_variables\nUtilities.remove_variable\nUtilities.all_coefficients\nUtilities.unsafe_add\nUtilities.isapprox_zero\nUtilities.modify_function\nUtilities.zero_with_output_dimension","category":"page"},{"location":"submodules/Utilities/reference/#MathOptInterface.Utilities.eval_variables","page":"API Reference","title":"MathOptInterface.Utilities.eval_variables","text":"eval_variables(value_fn::Function, f::MOI.AbstractFunction)\n\nReturns the value of function f if each variable index vi is evaluated as value_fn(vi).\n\nNote that value_fn must return a Number. See substitute_variables for a similar function where value_fn returns an MOI.AbstractScalarFunction.\n\nwarning: Warning\nThe 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.\n\n\n\n\n\n","category":"function"},{"location":"submodules/Utilities/reference/#MathOptInterface.Utilities.map_indices","page":"API Reference","title":"MathOptInterface.Utilities.map_indices","text":"map_indices(index_map::Function, attr::MOI.AnyAttribute, x::X)::X where {X}\n\nSubstitute any MOI.VariableIndex (resp. MOI.ConstraintIndex) in x by the MOI.VariableIndex (resp. MOI.ConstraintIndex) of the same type given by index_map(x).\n\nWhen to implement this method for new types X\n\nThis 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.\n\n\n\n\n\nmap_indices(\n variable_map::AbstractDict{T,T},\n x::X,\n)::X where {T<:MOI.Index,X}\n\nShortcut for map_indices(vi -> variable_map[vi], x).\n\n\n\n\n\n","category":"function"},{"location":"submodules/Utilities/reference/#MathOptInterface.Utilities.substitute_variables","page":"API Reference","title":"MathOptInterface.Utilities.substitute_variables","text":"substitute_variables(variable_map::Function, x)\n\nSubstitute 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.\n\nThis 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.\n\nnote: Note\nWhen 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}.\n\n\n\n\n\n","category":"function"},{"location":"submodules/Utilities/reference/#MathOptInterface.Utilities.filter_variables","page":"API Reference","title":"MathOptInterface.Utilities.filter_variables","text":"filter_variables(keep::Function, f::AbstractFunction)\n\nReturn a new function f with the variable vi such that !keep(vi) removed.\n\nWARNING: Don't define filter_variables(::Function, ...) because Julia will not specialize on this. Define instead filter_variables(::F, ...) where {F<:Function}.\n\n\n\n\n\n","category":"function"},{"location":"submodules/Utilities/reference/#MathOptInterface.Utilities.remove_variable","page":"API Reference","title":"MathOptInterface.Utilities.remove_variable","text":"remove_variable(f::AbstractFunction, vi::VariableIndex)\n\nReturn a new function f with the variable vi removed.\n\n\n\n\n\nremove_variable(f::MOI.AbstractFunction, s::MOI.AbstractSet, vi::MOI.VariableIndex)\n\nReturn 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 (e.g. when f is a VectorOfVariables with vi being one of the variables).\n\n\n\n\n\n","category":"function"},{"location":"submodules/Utilities/reference/#MathOptInterface.Utilities.all_coefficients","page":"API Reference","title":"MathOptInterface.Utilities.all_coefficients","text":"all_coefficients(p::Function, f::MOI.AbstractFunction)\n\nDetermine 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.\n\n\n\n\n\n","category":"function"},{"location":"submodules/Utilities/reference/#MathOptInterface.Utilities.unsafe_add","page":"API Reference","title":"MathOptInterface.Utilities.unsafe_add","text":"unsafe_add(t1::MOI.ScalarAffineTerm, t2::MOI.ScalarAffineTerm)\n\nSums 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.\n\n\n\n\n\nunsafe_add(t1::MOI.ScalarQuadraticTerm, t2::MOI.ScalarQuadraticTerm)\n\nSums 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.\n\n\n\n\n\nunsafe_add(t1::MOI.VectorAffineTerm, t2::MOI.VectorAffineTerm)\n\nSums 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.\n\n\n\n\n\n","category":"function"},{"location":"submodules/Utilities/reference/#MathOptInterface.Utilities.isapprox_zero","page":"API Reference","title":"MathOptInterface.Utilities.isapprox_zero","text":"isapprox_zero(f::MOI.AbstractFunction, tol)\n\nReturn a Bool indicating whether the function f is approximately zero using tol as a tolerance.\n\nImportant note\n\nThis function assumes that f does not contain any duplicate terms, you might want to first call canonical if that is not guaranteed. For instance, given\n\nf = MOI.ScalarAffineFunction(MOI.ScalarAffineTerm.([1, -1], [x, x]), 0)\n\nthen isapprox_zero(f) is false but isapprox_zero(MOIU.canonical(f)) is true.\n\n\n\n\n\n","category":"function"},{"location":"submodules/Utilities/reference/#MathOptInterface.Utilities.modify_function","page":"API Reference","title":"MathOptInterface.Utilities.modify_function","text":"modify_function(f::AbstractFunction, change::AbstractFunctionModification)\n\nReturn a copy of the function f, modified according to change.\n\n\n\n\n\n","category":"function"},{"location":"submodules/Utilities/reference/#MathOptInterface.Utilities.zero_with_output_dimension","page":"API Reference","title":"MathOptInterface.Utilities.zero_with_output_dimension","text":"zero_with_output_dimension(::Type{T}, output_dimension::Integer) where {T}\n\nCreate an instance of type T with the output dimension output_dimension.\n\nThis is mostly useful in Bridges, when code needs to be agnostic to the type of vector-valued function that is passed in.\n\n\n\n\n\n","category":"function"},{"location":"submodules/Utilities/reference/","page":"API Reference","title":"API Reference","text":"The following functions can be used to canonicalize a function:","category":"page"},{"location":"submodules/Utilities/reference/","page":"API Reference","title":"API Reference","text":"Utilities.is_canonical\nUtilities.canonical\nUtilities.canonicalize!","category":"page"},{"location":"submodules/Utilities/reference/#MathOptInterface.Utilities.is_canonical","page":"API Reference","title":"MathOptInterface.Utilities.is_canonical","text":"is_canonical(f::Union{ScalarAffineFunction, VectorAffineFunction})\n\nReturns a Bool indicating whether the function is in canonical form. See canonical.\n\n\n\n\n\nis_canonical(f::Union{ScalarQuadraticFunction, VectorQuadraticFunction})\n\nReturns a Bool indicating whether the function is in canonical form. See canonical.\n\n\n\n\n\n","category":"function"},{"location":"submodules/Utilities/reference/#MathOptInterface.Utilities.canonical","page":"API Reference","title":"MathOptInterface.Utilities.canonical","text":"canonical(f::MOI.AbstractFunction)\n\nReturns the function in a canonical form, i.e.\n\nA term appear only once.\nThe coefficients are nonzero.\nThe terms appear in increasing order of variable where there the order of the variables is the order of their value.\nFor a AbstractVectorFunction, the terms are sorted in ascending order of output index.\n\nThe output of canonical can be assumed to be a copy of f, even for VectorOfVariables.\n\nExamples\n\nIf x (resp. y, z) is VariableIndex(1) (resp. 2, 3). The canonical representation of ScalarAffineFunction([y, x, z, x, z], [2, 1, 3, -2, -3], 5) is ScalarAffineFunction([x, y], [-1, 2], 5).\n\n\n\n\n\n","category":"function"},{"location":"submodules/Utilities/reference/#MathOptInterface.Utilities.canonicalize!","page":"API Reference","title":"MathOptInterface.Utilities.canonicalize!","text":"canonicalize!(f::Union{ScalarAffineFunction, VectorAffineFunction})\n\nConvert a function to canonical form in-place, without allocating a copy to hold the result. See canonical.\n\n\n\n\n\ncanonicalize!(f::Union{ScalarQuadraticFunction, VectorQuadraticFunction})\n\nConvert a function to canonical form in-place, without allocating a copy to hold the result. See canonical.\n\n\n\n\n\n","category":"function"},{"location":"submodules/Utilities/reference/","page":"API Reference","title":"API Reference","text":"The following functions can be used to manipulate functions with basic algebra:","category":"page"},{"location":"submodules/Utilities/reference/","page":"API Reference","title":"API Reference","text":"Utilities.scalar_type\nUtilities.scalarize\nUtilities.eachscalar\nUtilities.promote_operation\nUtilities.operate\nUtilities.operate!\nUtilities.operate_output_index!\nUtilities.vectorize","category":"page"},{"location":"submodules/Utilities/reference/#MathOptInterface.Utilities.scalar_type","page":"API Reference","title":"MathOptInterface.Utilities.scalar_type","text":"scalar_type(F::Type{<:MOI.AbstractVectorFunction})\n\nType of functions obtained by indexing objects obtained by calling eachscalar on functions of type F.\n\n\n\n\n\n","category":"function"},{"location":"submodules/Utilities/reference/#MathOptInterface.Utilities.scalarize","page":"API Reference","title":"MathOptInterface.Utilities.scalarize","text":"scalarize(func::MOI.VectorOfVariables, ignore_constants::Bool = false)\n\nReturns a vector of scalar functions making up the vector function in the form of a Vector{MOI.SingleVariable}.\n\nSee also eachscalar.\n\n\n\n\n\nscalarize(func::MOI.VectorAffineFunction{T}, ignore_constants::Bool = false)\n\nReturns a vector of scalar functions making up the vector function in the form of a Vector{MOI.ScalarAffineFunction{T}}.\n\nSee also eachscalar.\n\n\n\n\n\nscalarize(func::MOI.VectorQuadraticFunction{T}, ignore_constants::Bool = false)\n\nReturns a vector of scalar functions making up the vector function in the form of a Vector{MOI.ScalarQuadraticFunction{T}}.\n\nSee also eachscalar.\n\n\n\n\n\n","category":"function"},{"location":"submodules/Utilities/reference/#MathOptInterface.Utilities.eachscalar","page":"API Reference","title":"MathOptInterface.Utilities.eachscalar","text":"eachscalar(f::MOI.AbstractVectorFunction)\n\nReturns an iterator for the scalar components of the vector function.\n\nSee also scalarize.\n\n\n\n\n\neachscalar(f::MOI.AbstractVector)\n\nReturns an iterator for the scalar components of the vector.\n\n\n\n\n\n","category":"function"},{"location":"submodules/Utilities/reference/#MathOptInterface.Utilities.promote_operation","page":"API Reference","title":"MathOptInterface.Utilities.promote_operation","text":"promote_operation(\n op::Function,\n ::Type{T},\n ArgsTypes::Type{<:Union{T,AbstractVector{T},MOI.AbstractFunction}}...,\n) where {T<:Number}\n\nCompute the return type of the call operate(op, T, args...), where the types of the arguments args are ArgsTypes.\n\nOne assumption is that the element type T is invariant under each operation. That is, op(::T, ::T)::T where op is a +, -, *, and /.\n\nThere are six methods for which we implement Utilities.promote_operation:\n\n+ a. promote_operation(::typeof(+), ::Type{T}, ::Type{F1}, ::Type{F2})\n- a. promote_operation(::typeof(-), ::Type{T}, ::Type{F}) b. promote_operation(::typeof(-), ::Type{T}, ::Type{F1}, ::Type{F2})\n* 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}) where F1 and F2 are VariableIndex or ScalarAffineFunction d. promote_operation(::typeof(*), ::Type{T}, ::Type{<:Diagonal{T}}, ::Type{F}\n/ a. promote_operation(::typeof(/), ::Type{T}, ::Type{F}, ::Type{T})\nvcat a. promote_operation(::typeof(vcat), ::Type{T}, ::Type{F}...)\nimag a. promote_operation(::typeof(imag), ::Type{T}, ::Type{F}) where F is VariableIndex or VectorOfVariables\n\nIn 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:\n\n::T\n::VariableIndex\n::ScalarAffineFunction{T}\n::ScalarQuadraticFunction{T}\n::ScalarNonlinearFunction\n::AbstractVector{T}\n::VectorOfVariables\n::VectorAffineFunction{T}\n::VectorQuadraticFunction{T}\n::VectorNonlinearFunction\n\n\n\n\n\n","category":"function"},{"location":"submodules/Utilities/reference/#MathOptInterface.Utilities.operate","page":"API Reference","title":"MathOptInterface.Utilities.operate","text":"operate(\n op::Function,\n ::Type{T},\n args::Union{T,MOI.AbstractFunction}...,\n)::MOI.AbstractFunction where {T<:Number}\n\nReturns an MOI.AbstractFunction representing the function resulting from the operation op(args...) on functions of coefficient type T.\n\nNo argument can be modified.\n\nMethods\n\n+ a. operate(::typeof(+), ::Type{T}, ::F1) b. operate(::typeof(+), ::Type{T}, ::F1, ::F2) c. operate(::typeof(+), ::Type{T}, ::F1...)\n- a. operate(::typeof(-), ::Type{T}, ::F) b. operate(::typeof(-), ::Type{T}, ::F1, ::F2)\n* a. operate(::typeof(*), ::Type{T}, ::T, ::F) b. operate(::typeof(*), ::Type{T}, ::F, ::T) c. operate(::typeof(*), ::Type{T}, ::F1, ::F2) where F1 and F2 are VariableIndex or ScalarAffineFunction d. operate(::typeof(*), ::Type{T}, ::Diagonal{T}, ::F)\n/ a. operate(::typeof(/), ::Type{T}, ::F, ::T)\nvcat a. operate(::typeof(vcat), ::Type{T}, ::F...)\nimag a. operate(::typeof(imag), ::Type{T}, ::F) where F is VariableIndex or VectorOfVariables\n\nOne assumption is that the element type T is invariant under each operation. That is, op(::T, ::T)::T where op is a +, -, *, and /.\n\nIn 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:\n\n::T\n::VariableIndex\n::ScalarAffineFunction{T}\n::ScalarQuadraticFunction{T}\n::ScalarNonlinearFunction\n::AbstractVector{T}\n::VectorOfVariables\n::VectorAffineFunction{T}\n::VectorQuadraticFunction{T}\n::VectorNonlinearFunction\n\n\n\n\n\n","category":"function"},{"location":"submodules/Utilities/reference/#MathOptInterface.Utilities.operate!","page":"API Reference","title":"MathOptInterface.Utilities.operate!","text":"operate!(\n op::Function,\n ::Type{T},\n args::Union{T,MOI.AbstractFunction}...,\n)::MOI.AbstractFunction where {T<:Number}\n\nReturns an MOI.AbstractFunction representing the function resulting from the operation op(args...) on functions of coefficient type T.\n\nThe 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.\n\n\n\n\n\n","category":"function"},{"location":"submodules/Utilities/reference/#MathOptInterface.Utilities.operate_output_index!","page":"API Reference","title":"MathOptInterface.Utilities.operate_output_index!","text":"operate_output_index!(\n op::Union{typeof(+),typeof(-)},\n ::Type{T},\n output_index::Integer,\n f::Union{AbstractVector{T},MOI.AbstractVectorFunction}\n g::Union{T,MOI.AbstractScalarFunction}...\n) where {T<:Number}\n\nReturn an MOI.AbstractVectorFunction in which the scalar function in row output_index is the result of op(f[output_index], g).\n\nThe 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.\n\nMethods\n\n+ a. operate_output_index!(+, ::Type{T}, ::Int, ::VectorF, ::ScalarF)\n- a. operate_output_index!(-, ::Type{T}, ::Int, ::VectorF, ::ScalarF)\n\n\n\n\n\n","category":"function"},{"location":"submodules/Utilities/reference/#MathOptInterface.Utilities.vectorize","page":"API Reference","title":"MathOptInterface.Utilities.vectorize","text":"vectorize(x::AbstractVector{<:Number})\n\nReturns x.\n\n\n\n\n\nvectorize(x::AbstractVector{MOI.VariableIndex})\n\nReturns the vector of scalar affine functions in the form of a MOI.VectorAffineFunction{T}.\n\n\n\n\n\nvectorize(funcs::AbstractVector{MOI.ScalarAffineFunction{T}}) where T\n\nReturns the vector of scalar affine functions in the form of a MOI.VectorAffineFunction{T}.\n\n\n\n\n\nvectorize(funcs::AbstractVector{MOI.ScalarQuadraticFunction{T}}) where T\n\nReturns the vector of scalar quadratic functions in the form of a MOI.VectorQuadraticFunction{T}.\n\n\n\n\n\n","category":"function"},{"location":"submodules/Utilities/reference/#Constraint-utilities","page":"API Reference","title":"Constraint utilities","text":"","category":"section"},{"location":"submodules/Utilities/reference/","page":"API Reference","title":"API Reference","text":"The following utilities are available for moving the function constant to the set for scalar constraints:","category":"page"},{"location":"submodules/Utilities/reference/","page":"API Reference","title":"API Reference","text":"Utilities.shift_constant\nUtilities.supports_shift_constant\nUtilities.normalize_and_add_constraint\nUtilities.normalize_constant","category":"page"},{"location":"submodules/Utilities/reference/#MathOptInterface.Utilities.shift_constant","page":"API Reference","title":"MathOptInterface.Utilities.shift_constant","text":"shift_constant(set::MOI.AbstractScalarSet, offset)\n\nReturns a new scalar set new_set such that func-in-set is equivalent to func + offset-in-new_set.\n\nOnly define this function if it makes sense to!\n\nUse supports_shift_constant to check if the set supports shifting:\n\nif supports_shift_constant(typeof(old_set))\n new_set = shift_constant(old_set, offset)\n f.constant = 0\n add_constraint(model, f, new_set)\nelse\n add_constraint(model, f, old_set)\nend\n\nSee also supports_shift_constant.\n\nExamples\n\nThe call shift_constant(MOI.Interval(-2, 3), 1) is equal to MOI.Interval(-1, 4).\n\n\n\n\n\n","category":"function"},{"location":"submodules/Utilities/reference/#MathOptInterface.Utilities.supports_shift_constant","page":"API Reference","title":"MathOptInterface.Utilities.supports_shift_constant","text":"supports_shift_constant(::Type{S}) where {S<:MOI.AbstractSet}\n\nReturn true if shift_constant is defined for set S.\n\nSee also shift_constant.\n\n\n\n\n\n","category":"function"},{"location":"submodules/Utilities/reference/#MathOptInterface.Utilities.normalize_and_add_constraint","page":"API Reference","title":"MathOptInterface.Utilities.normalize_and_add_constraint","text":"normalize_and_add_constraint(\n model::MOI.ModelLike,\n func::MOI.AbstractScalarFunction,\n set::MOI.AbstractScalarSet;\n allow_modify_function::Bool = false,\n)\n\nAdds 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.\n\n\n\n\n\n","category":"function"},{"location":"submodules/Utilities/reference/#MathOptInterface.Utilities.normalize_constant","page":"API Reference","title":"MathOptInterface.Utilities.normalize_constant","text":"normalize_constant(\n func::MOI.AbstractScalarFunction,\n set::MOI.AbstractScalarSet;\n allow_modify_function::Bool = false,\n)\n\nReturn 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.\n\n\n\n\n\n","category":"function"},{"location":"submodules/Utilities/reference/","page":"API Reference","title":"API Reference","text":"The following utility identifies those constraints imposing bounds on a given variable, and returns those bound values:","category":"page"},{"location":"submodules/Utilities/reference/","page":"API Reference","title":"API Reference","text":"Utilities.get_bounds","category":"page"},{"location":"submodules/Utilities/reference/#MathOptInterface.Utilities.get_bounds","page":"API Reference","title":"MathOptInterface.Utilities.get_bounds","text":"get_bounds(model::MOI.ModelLike, ::Type{T}, x::MOI.VariableIndex)\n\nReturn a tuple (lb, ub) of type Tuple{T, T}, where lb and ub are lower and upper bounds, respectively, imposed on x in model.\n\n\n\n\n\n","category":"function"},{"location":"submodules/Utilities/reference/","page":"API Reference","title":"API Reference","text":"The following utilities are useful when working with symmetric matrix cones.","category":"page"},{"location":"submodules/Utilities/reference/","page":"API Reference","title":"API Reference","text":"Utilities.is_diagonal_vectorized_index\nUtilities.side_dimension_for_vectorized_dimension","category":"page"},{"location":"submodules/Utilities/reference/#MathOptInterface.Utilities.is_diagonal_vectorized_index","page":"API Reference","title":"MathOptInterface.Utilities.is_diagonal_vectorized_index","text":"is_diagonal_vectorized_index(index::Base.Integer)\n\nReturn whether index is the index of a diagonal element in a MOI.AbstractSymmetricMatrixSetTriangle set.\n\n\n\n\n\n","category":"function"},{"location":"submodules/Utilities/reference/#MathOptInterface.Utilities.side_dimension_for_vectorized_dimension","page":"API Reference","title":"MathOptInterface.Utilities.side_dimension_for_vectorized_dimension","text":"side_dimension_for_vectorized_dimension(n::Integer)\n\nReturn the dimension d such that MOI.dimension(MOI.PositiveSemidefiniteConeTriangle(d)) is n.\n\n\n\n\n\n","category":"function"},{"location":"submodules/Utilities/reference/#Set-utilities","page":"API Reference","title":"Set utilities","text":"","category":"section"},{"location":"submodules/Utilities/reference/","page":"API Reference","title":"API Reference","text":"The following utilities are available for sets:","category":"page"},{"location":"submodules/Utilities/reference/","page":"API Reference","title":"API Reference","text":"Utilities.AbstractDistance\nUtilities.ProjectionUpperBoundDistance\nUtilities.distance_to_set\nUtilities.set_dot","category":"page"},{"location":"submodules/Utilities/reference/#MathOptInterface.Utilities.AbstractDistance","page":"API Reference","title":"MathOptInterface.Utilities.AbstractDistance","text":"abstract type AbstractDistance end\n\nAn abstract type used to enabble dispatch of Utilities.distance_to_set.\n\n\n\n\n\n","category":"type"},{"location":"submodules/Utilities/reference/#MathOptInterface.Utilities.ProjectionUpperBoundDistance","page":"API Reference","title":"MathOptInterface.Utilities.ProjectionUpperBoundDistance","text":"ProjectionUpperBoundDistance() <: AbstractDistance\n\nAn upper bound on the minimum distance between point and the closest feasible point in set.\n\nDefinition of distance\n\nThe minimum distance is computed as:\n\nd(x mathcalK) = min_y in mathcalK x - y \n\nwhere x is point and mathcalK is set. The norm is computed as:\n\nx = sqrtf(x x mathcalK)\n\nwhere f is Utilities.set_dot.\n\nIn 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 = sqrtsum x_i^2.\n\nWhy an upper bound?\n\nIn 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.\n\nFor 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.\n\nIf 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.\n\n\n\n\n\n","category":"type"},{"location":"submodules/Utilities/reference/#MathOptInterface.Utilities.distance_to_set","page":"API Reference","title":"MathOptInterface.Utilities.distance_to_set","text":"distance_to_set(\n [d::AbstractDistance = ProjectionUpperBoundDistance()],]\n point::T,\n set::MOI.AbstractScalarSet,\n) where {T}\n\ndistance_to_set(\n [d::AbstractDistance = ProjectionUpperBoundDistance(),]\n point::AbstractVector{T},\n set::MOI.AbstractVectorSet,\n) where {T}\n\nCompute the distance between point and set using the distance metric d. If point is in the set set, this function must return zero(T).\n\nIf d is omitted, the default distance is Utilities.ProjectionUpperBoundDistance.\n\n\n\n\n\n","category":"function"},{"location":"submodules/Utilities/reference/#MathOptInterface.Utilities.set_dot","page":"API Reference","title":"MathOptInterface.Utilities.set_dot","text":"set_dot(x::AbstractVector, y::AbstractVector, set::AbstractVectorSet)\n\nReturn the scalar product between a vector x of the set set and a vector y of the dual of the set s.\n\n\n\n\n\nset_dot(x, y, set::AbstractScalarSet)\n\nReturn the scalar product between a number x of the set set and a number y of the dual of the set s.\n\n\n\n\n\n","category":"function"},{"location":"submodules/Utilities/reference/#DoubleDicts","page":"API Reference","title":"DoubleDicts","text":"","category":"section"},{"location":"submodules/Utilities/reference/","page":"API Reference","title":"API Reference","text":"Utilities.DoubleDicts.DoubleDict\nUtilities.DoubleDicts.DoubleDictInner\nUtilities.DoubleDicts.IndexDoubleDict\nUtilities.DoubleDicts.IndexDoubleDictInner\nUtilities.DoubleDicts.outer_keys\nUtilities.DoubleDicts.nonempty_outer_keys","category":"page"},{"location":"submodules/Utilities/reference/#MathOptInterface.Utilities.DoubleDicts.DoubleDict","page":"API Reference","title":"MathOptInterface.Utilities.DoubleDicts.DoubleDict","text":"DoubleDict{V}\n\nAn optimized dictionary to map MOI.ConstraintIndex to values of type V.\n\nWorks as a AbstractDict{MOI.ConstraintIndex,V} with minimal differences.\n\nIf V is also a MOI.ConstraintIndex, use IndexDoubleDict.\n\nNote that MOI.ConstraintIndex is not a concrete type, opposed to MOI.ConstraintIndex{MOI.VariableIndex, MOI.Integers}, which is a concrete type.\n\nWhen looping through multiple keys of the same Function-in-Set type, use\n\ninner = dict[F, S]\n\nto return a type-stable DoubleDictInner.\n\n\n\n\n\n","category":"type"},{"location":"submodules/Utilities/reference/#MathOptInterface.Utilities.DoubleDicts.DoubleDictInner","page":"API Reference","title":"MathOptInterface.Utilities.DoubleDicts.DoubleDictInner","text":"DoubleDictInner{F,S,V}\n\nA type stable inner dictionary of DoubleDict.\n\n\n\n\n\n","category":"type"},{"location":"submodules/Utilities/reference/#MathOptInterface.Utilities.DoubleDicts.IndexDoubleDict","page":"API Reference","title":"MathOptInterface.Utilities.DoubleDicts.IndexDoubleDict","text":"IndexDoubleDict\n\nA specialized version of [DoubleDict] in which the values are of type MOI.ConstraintIndex\n\nWhen looping through multiple keys of the same Function-in-Set type, use\n\ninner = dict[F, S]\n\nto return a type-stable IndexDoubleDictInner.\n\n\n\n\n\n","category":"type"},{"location":"submodules/Utilities/reference/#MathOptInterface.Utilities.DoubleDicts.IndexDoubleDictInner","page":"API Reference","title":"MathOptInterface.Utilities.DoubleDicts.IndexDoubleDictInner","text":"IndexDoubleDictInner{F,S}\n\nA type stable inner dictionary of IndexDoubleDict.\n\n\n\n\n\n","category":"type"},{"location":"submodules/Utilities/reference/#MathOptInterface.Utilities.DoubleDicts.outer_keys","page":"API Reference","title":"MathOptInterface.Utilities.DoubleDicts.outer_keys","text":"outer_keys(d::AbstractDoubleDict)\n\nReturn 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:\n\nfor (F, S) in DoubleDicts.outer_keys(dict)\n for (k, v) in dict[F, S]\n # ...\n end\nend\n\nFor performance, it is recommended that the inner loop lies in a separate function to gurantee 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.\n\n\n\n\n\n","category":"function"},{"location":"submodules/Utilities/reference/#MathOptInterface.Utilities.DoubleDicts.nonempty_outer_keys","page":"API Reference","title":"MathOptInterface.Utilities.DoubleDicts.nonempty_outer_keys","text":"nonempty_outer_keys(d::AbstractDoubleDict)\n\nReturn a vector of outer keys of the AbstractDoubleDict d.\n\nOnly outer keys that have a nonempty set of inner keys will be returned.\n\nEach outer key is a Tuple{Type,Type} so that a double loop can be easily used\n\nfor (F, S) in DoubleDicts.nonempty_outer_keys(dict)\n for (k, v) in dict[F, S]\n # ...\n end\nend\nFor performance, it is recommended that the inner loop lies in a separate\nfunction to gurantee type-stability.\n\nIf you want an iterator of all current outer keys, use [`outer_keys`](@ref).\n\n\n\n\n\n","category":"function"},{"location":"background/infeasibility_certificates/","page":"Infeasibility certificates","title":"Infeasibility certificates","text":"CurrentModule = MathOptInterface\nDocTestSetup = quote\n import MathOptInterface as MOI\nend\nDocTestFilters = [r\"MathOptInterface|MOI\"]","category":"page"},{"location":"background/infeasibility_certificates/#Infeasibility-certificates","page":"Infeasibility certificates","title":"Infeasibility certificates","text":"","category":"section"},{"location":"background/infeasibility_certificates/","page":"Infeasibility certificates","title":"Infeasibility certificates","text":"When given a conic problem that is infeasible or unbounded, some solvers can produce a certificate of infeasibility. This page explains what a certificate of infeasibility is, and the related conventions that MathOptInterface adopts.","category":"page"},{"location":"background/infeasibility_certificates/#Conic-duality","page":"Infeasibility certificates","title":"Conic duality","text":"","category":"section"},{"location":"background/infeasibility_certificates/","page":"Infeasibility certificates","title":"Infeasibility certificates","text":"MathOptInterface uses conic duality to define infeasibility certificates. A full explanation is given in the section Duality, but here is a brief overview.","category":"page"},{"location":"background/infeasibility_certificates/#Minimization-problems","page":"Infeasibility certificates","title":"Minimization problems","text":"","category":"section"},{"location":"background/infeasibility_certificates/","page":"Infeasibility certificates","title":"Infeasibility certificates","text":"For a minimization problem in geometric conic form, the primal is:","category":"page"},{"location":"background/infeasibility_certificates/","page":"Infeasibility certificates","title":"Infeasibility certificates","text":"beginalign\n min_x in mathbbR^n a_0^top x + b_0\n\n textst A_i x + b_i in mathcalC_i i = 1 ldots m\nendalign","category":"page"},{"location":"background/infeasibility_certificates/","page":"Infeasibility certificates","title":"Infeasibility certificates","text":"and the dual is a maximization problem in standard conic form:","category":"page"},{"location":"background/infeasibility_certificates/","page":"Infeasibility certificates","title":"Infeasibility certificates","text":"beginalign\n max_y_1 ldots y_m -sum_i=1^m b_i^top y_i + b_0\n\n textst a_0 - sum_i=1^m A_i^top y_i = 0\n\n y_i in mathcalC_i^* i = 1 ldots m\nendalign","category":"page"},{"location":"background/infeasibility_certificates/","page":"Infeasibility certificates","title":"Infeasibility certificates","text":"where each mathcalC_i is a closed convex cone and mathcalC_i^* is its dual cone.","category":"page"},{"location":"background/infeasibility_certificates/#Maximization-problems","page":"Infeasibility certificates","title":"Maximization problems","text":"","category":"section"},{"location":"background/infeasibility_certificates/","page":"Infeasibility certificates","title":"Infeasibility certificates","text":"For a maximization problem in geometric conic form, the primal is:","category":"page"},{"location":"background/infeasibility_certificates/","page":"Infeasibility certificates","title":"Infeasibility certificates","text":"beginalign\n max_x in mathbbR^n a_0^top x + b_0\n\n textst A_i x + b_i in mathcalC_i i = 1 ldots m\nendalign","category":"page"},{"location":"background/infeasibility_certificates/","page":"Infeasibility certificates","title":"Infeasibility certificates","text":"and the dual is a minimization problem in standard conic form:","category":"page"},{"location":"background/infeasibility_certificates/","page":"Infeasibility certificates","title":"Infeasibility certificates","text":"beginalign\n min_y_1 ldots y_m sum_i=1^m b_i^top y_i + b_0\n\n textst a_0 + sum_i=1^m A_i^top y_i = 0\n\n y_i in mathcalC_i^* i = 1 ldots m\nendalign","category":"page"},{"location":"background/infeasibility_certificates/#Unbounded-problems","page":"Infeasibility certificates","title":"Unbounded problems","text":"","category":"section"},{"location":"background/infeasibility_certificates/","page":"Infeasibility certificates","title":"Infeasibility certificates","text":"A problem is unbounded if and only if:","category":"page"},{"location":"background/infeasibility_certificates/","page":"Infeasibility certificates","title":"Infeasibility certificates","text":"there exists a feasible primal solution\nthe dual is infeasible.","category":"page"},{"location":"background/infeasibility_certificates/","page":"Infeasibility certificates","title":"Infeasibility certificates","text":"A feasible primal solution—if one exists—can be obtained by setting ObjectiveSense to FEASIBILITY_SENSE before optimizing. Therefore, most solvers stop after they prove the dual is infeasible via a certificate of dual infeasibility, but before they have found a feasible primal solution. This is also the reason that MathOptInterface defines the DUAL_INFEASIBLE status instead of UNBOUNDED.","category":"page"},{"location":"background/infeasibility_certificates/","page":"Infeasibility certificates","title":"Infeasibility certificates","text":"A certificate of dual infeasibility is an improving ray of the primal problem. That is, there exists some vector d such that for all eta 0:","category":"page"},{"location":"background/infeasibility_certificates/","page":"Infeasibility certificates","title":"Infeasibility certificates","text":"A_i (x + eta d) + b_i in mathcalC_i i = 1 ldots m","category":"page"},{"location":"background/infeasibility_certificates/","page":"Infeasibility certificates","title":"Infeasibility certificates","text":"and (for minimization problems):","category":"page"},{"location":"background/infeasibility_certificates/","page":"Infeasibility certificates","title":"Infeasibility certificates","text":"a_0^top (x + eta d) + b_0 a_0^top x + b_0","category":"page"},{"location":"background/infeasibility_certificates/","page":"Infeasibility certificates","title":"Infeasibility certificates","text":"for any feasible point x. The latter simplifies to a_0^top d 0. For maximization problems, the inequality is reversed, so that a_0^top d 0.","category":"page"},{"location":"background/infeasibility_certificates/","page":"Infeasibility certificates","title":"Infeasibility certificates","text":"If the solver has found a certificate of dual infeasibility:","category":"page"},{"location":"background/infeasibility_certificates/","page":"Infeasibility certificates","title":"Infeasibility certificates","text":"TerminationStatus must be DUAL_INFEASIBLE\nPrimalStatus must be INFEASIBILITY_CERTIFICATE\nVariablePrimal must be the corresponding value of d\nConstraintPrimal must be the corresponding value of A_i d\nObjectiveValue must be the value a_0^top d. Note that this is the value of the objective function at d, ignoring the constant b_0.","category":"page"},{"location":"background/infeasibility_certificates/","page":"Infeasibility certificates","title":"Infeasibility certificates","text":"note: Note\nThe choice of whether to scale the ray d to have magnitude 1 is left to the solver.","category":"page"},{"location":"background/infeasibility_certificates/#Infeasible-problems","page":"Infeasibility certificates","title":"Infeasible problems","text":"","category":"section"},{"location":"background/infeasibility_certificates/","page":"Infeasibility certificates","title":"Infeasibility certificates","text":"A certificate of primal infeasibility is an improving ray of the dual problem. However, because infeasibility is independent of the objective function, we first homogenize the primal problem by removing its objective.","category":"page"},{"location":"background/infeasibility_certificates/","page":"Infeasibility certificates","title":"Infeasibility certificates","text":"For a minimization problem, a dual improving ray is some vector d such that for all eta 0:","category":"page"},{"location":"background/infeasibility_certificates/","page":"Infeasibility certificates","title":"Infeasibility certificates","text":"beginalign\n-sum_i=1^m A_i^top (y_i + eta d_i) = 0 \n(y_i + eta d_i) in mathcalC_i^* i = 1 ldots m\nendalign","category":"page"},{"location":"background/infeasibility_certificates/","page":"Infeasibility certificates","title":"Infeasibility certificates","text":"and:","category":"page"},{"location":"background/infeasibility_certificates/","page":"Infeasibility certificates","title":"Infeasibility certificates","text":"-sum_i=1^m b_i^top (y_i + eta d_i) -sum_i=1^m b_i^top y_i","category":"page"},{"location":"background/infeasibility_certificates/","page":"Infeasibility certificates","title":"Infeasibility certificates","text":"for any feasible dual solution y. The latter simplifies to -sum_i=1^m b_i^top d_i 0. For a maximization problem, the inequality is sum_i=1^m b_i^top d_i 0. (Note that these are the same inequality, modulo a - sign.)","category":"page"},{"location":"background/infeasibility_certificates/","page":"Infeasibility certificates","title":"Infeasibility certificates","text":"If the solver has found a certificate of primal infeasibility:","category":"page"},{"location":"background/infeasibility_certificates/","page":"Infeasibility certificates","title":"Infeasibility certificates","text":"TerminationStatus must be INFEASIBLE\nDualStatus must be INFEASIBILITY_CERTIFICATE\nConstraintDual must be the corresponding value of d\nDualObjectiveValue must be the value -sum_i=1^m b_i^top d_i for minimization problems and sum_i=1^m b_i^top d_i for maximization problems.","category":"page"},{"location":"background/infeasibility_certificates/","page":"Infeasibility certificates","title":"Infeasibility certificates","text":"note: Note\nThe choice of whether to scale the ray d to have magnitude 1 is left to the solver.","category":"page"},{"location":"background/infeasibility_certificates/#Infeasibility-certificates-of-variable-bounds","page":"Infeasibility certificates","title":"Infeasibility certificates of variable bounds","text":"","category":"section"},{"location":"background/infeasibility_certificates/","page":"Infeasibility certificates","title":"Infeasibility certificates","text":"Many linear solvers (for example, Gurobi) do not provide explicit access to the primal infeasibility certificate of a variable bound. However, given a set of linear constraints:","category":"page"},{"location":"background/infeasibility_certificates/","page":"Infeasibility certificates","title":"Infeasibility certificates","text":"beginalign\nl_A le A x le u_A \nl_x le x le u_x\nendalign","category":"page"},{"location":"background/infeasibility_certificates/","page":"Infeasibility certificates","title":"Infeasibility certificates","text":"the primal certificate of the variable bounds can be computed using the primal certificate associated with the affine constraints, d. (Note that d will have one element for each row of the A matrix, and that some or all of the elements in the vectors l_A and u_A may be pm infty. If both l_A and u_A are finite for some row, the corresponding element in `d must be 0.)","category":"page"},{"location":"background/infeasibility_certificates/","page":"Infeasibility certificates","title":"Infeasibility certificates","text":"Given d, compute bard = d^top A. If the bound is finite, a certificate for the lower variable bound of x_i is maxbard_i 0, and a certificate for the upper variable bound is minbard_i 0.","category":"page"},{"location":"manual/modification/","page":"Problem modification","title":"Problem modification","text":"CurrentModule = MathOptInterface\nDocTestSetup = quote\n import MathOptInterface as MOI\nend\nDocTestFilters = [r\"MathOptInterface|MOI\"]","category":"page"},{"location":"manual/modification/#Problem-modification","page":"Problem modification","title":"Problem modification","text":"","category":"section"},{"location":"manual/modification/","page":"Problem modification","title":"Problem modification","text":"In addition to adding and deleting constraints and variables, MathOptInterface supports modifying, in-place, coefficients in the constraints and the objective function of a model.","category":"page"},{"location":"manual/modification/","page":"Problem modification","title":"Problem modification","text":"These modifications can be grouped into two categories:","category":"page"},{"location":"manual/modification/","page":"Problem modification","title":"Problem modification","text":"modifications which replace the set of function of a constraint with a new set or function\nmodifications which change, in-place, a component of a function","category":"page"},{"location":"manual/modification/","page":"Problem modification","title":"Problem modification","text":"warning: Warning\nSome ModelLike objects do not support problem modification.","category":"page"},{"location":"manual/modification/#Modify-the-set-of-a-constraint","page":"Problem modification","title":"Modify the set of a constraint","text":"","category":"section"},{"location":"manual/modification/","page":"Problem modification","title":"Problem modification","text":"Use set and ConstraintSet to modify the set of a constraint by replacing it with a new instance of the same type.","category":"page"},{"location":"manual/modification/","page":"Problem modification","title":"Problem modification","text":"julia> c = MOI.add_constraint(\n model,\n MOI.ScalarAffineFunction([MOI.ScalarAffineTerm(1.0, x)], 0.0),\n MOI.EqualTo(1.0),\n )\nMathOptInterface.ConstraintIndex{MathOptInterface.ScalarAffineFunction{Float64}, MathOptInterface.EqualTo{Float64}}(1)\n\njulia> MOI.set(model, MOI.ConstraintSet(), c, MOI.EqualTo(2.0));\n\njulia> MOI.get(model, MOI.ConstraintSet(), c) == MOI.EqualTo(2.0)\ntrue","category":"page"},{"location":"manual/modification/","page":"Problem modification","title":"Problem modification","text":"However, the following will fail as the new set is of a different type to the original set:","category":"page"},{"location":"manual/modification/","page":"Problem modification","title":"Problem modification","text":"julia> MOI.set(model, MOI.ConstraintSet(), c, MOI.GreaterThan(2.0))\nERROR: [...]","category":"page"},{"location":"manual/modification/#Special-cases:-set-transforms","page":"Problem modification","title":"Special cases: set transforms","text":"","category":"section"},{"location":"manual/modification/","page":"Problem modification","title":"Problem modification","text":"If our constraint is an affine inequality, then this corresponds to modifying the right-hand side of a constraint in linear programming.","category":"page"},{"location":"manual/modification/","page":"Problem modification","title":"Problem modification","text":"In some special cases, solvers may support efficiently changing the set of a constraint (for example, from LessThan to GreaterThan). For these cases, MathOptInterface provides the transform method.","category":"page"},{"location":"manual/modification/","page":"Problem modification","title":"Problem modification","text":"The transform function returns a new constraint index, and the old constraint index (that is, c) is no longer valid.","category":"page"},{"location":"manual/modification/","page":"Problem modification","title":"Problem modification","text":"julia> c = MOI.add_constraint(\n model,\n MOI.ScalarAffineFunction([MOI.ScalarAffineTerm(1.0, x)], 0.0),\n MOI.LessThan(1.0),\n )\nMathOptInterface.ConstraintIndex{MathOptInterface.ScalarAffineFunction{Float64}, MathOptInterface.LessThan{Float64}}(1)\n\njulia> new_c = MOI.transform(model, c, MOI.GreaterThan(2.0));\n\njulia> MOI.is_valid(model, c)\nfalse\n\njulia> MOI.is_valid(model, new_c)\ntrue","category":"page"},{"location":"manual/modification/","page":"Problem modification","title":"Problem modification","text":"note: Note\ntransform cannot be called with a set of the same type. Use set instead.","category":"page"},{"location":"manual/modification/#Modify-the-function-of-a-constraint","page":"Problem modification","title":"Modify the function of a constraint","text":"","category":"section"},{"location":"manual/modification/","page":"Problem modification","title":"Problem modification","text":"Use set and ConstraintFunction to modify the function of a constraint by replacing it with a new instance of the same type.","category":"page"},{"location":"manual/modification/","page":"Problem modification","title":"Problem modification","text":"julia> c = MOI.add_constraint(\n model,\n MOI.ScalarAffineFunction([MOI.ScalarAffineTerm(1.0, x)], 0.0),\n MOI.EqualTo(1.0),\n )\nMathOptInterface.ConstraintIndex{MathOptInterface.ScalarAffineFunction{Float64}, MathOptInterface.EqualTo{Float64}}(1)\n\njulia> new_f = MOI.ScalarAffineFunction([MOI.ScalarAffineTerm(2.0, x)], 1.0);\n\njulia> MOI.set(model, MOI.ConstraintFunction(), c, new_f);\n\njulia> MOI.get(model, MOI.ConstraintFunction(), c) ≈ new_f\ntrue","category":"page"},{"location":"manual/modification/","page":"Problem modification","title":"Problem modification","text":"However, the following will fail as the new function is of a different type to the original function:","category":"page"},{"location":"manual/modification/","page":"Problem modification","title":"Problem modification","text":"julia> MOI.set(model, MOI.ConstraintFunction(), c, x)\nERROR: [...]","category":"page"},{"location":"manual/modification/#Modify-constant-term-in-a-scalar-function","page":"Problem modification","title":"Modify constant term in a scalar function","text":"","category":"section"},{"location":"manual/modification/","page":"Problem modification","title":"Problem modification","text":"Use modify and ScalarConstantChange to modify the constant term in a ScalarAffineFunction or ScalarQuadraticFunction.","category":"page"},{"location":"manual/modification/","page":"Problem modification","title":"Problem modification","text":"julia> c = MOI.add_constraint(\n model,\n MOI.ScalarAffineFunction([MOI.ScalarAffineTerm(1.0, x)], 0.0),\n MOI.EqualTo(1.0),\n )\nMathOptInterface.ConstraintIndex{MathOptInterface.ScalarAffineFunction{Float64}, MathOptInterface.EqualTo{Float64}}(1)\n\njulia> MOI.modify(model, c, MOI.ScalarConstantChange(1.0));\n\njulia> new_f = MOI.ScalarAffineFunction([MOI.ScalarAffineTerm(1.0, x)], 1.0);\n\njulia> MOI.get(model, MOI.ConstraintFunction(), c) ≈ new_f\ntrue","category":"page"},{"location":"manual/modification/","page":"Problem modification","title":"Problem modification","text":"ScalarConstantChange can also be used to modify the objective function by passing an instance of ObjectiveFunction:","category":"page"},{"location":"manual/modification/","page":"Problem modification","title":"Problem modification","text":"julia> MOI.set(\n model,\n MOI.ObjectiveFunction{MOI.ScalarAffineFunction{Float64}}(),\n new_f,\n );\n\njulia> MOI.modify(\n model,\n MOI.ObjectiveFunction{MOI.ScalarAffineFunction{Float64}}(),\n MOI.ScalarConstantChange(-1.0)\n );\n\njulia> MOI.get(\n model,\n MOI.ObjectiveFunction{MOI.ScalarAffineFunction{Float64}}(),\n ) ≈ MOI.ScalarAffineFunction([MOI.ScalarAffineTerm(1.0, x)], -1.0)\ntrue","category":"page"},{"location":"manual/modification/#Modify-constant-terms-in-a-vector-function","page":"Problem modification","title":"Modify constant terms in a vector function","text":"","category":"section"},{"location":"manual/modification/","page":"Problem modification","title":"Problem modification","text":"Use modify and VectorConstantChange to modify the constant vector in a VectorAffineFunction or VectorQuadraticFunction.","category":"page"},{"location":"manual/modification/","page":"Problem modification","title":"Problem modification","text":"julia> c = MOI.add_constraint(\n model,\n MOI.VectorAffineFunction([\n MOI.VectorAffineTerm(1, MOI.ScalarAffineTerm(1.0, x)),\n MOI.VectorAffineTerm(2, MOI.ScalarAffineTerm(2.0, x)),\n ],\n [0.0, 0.0],\n ),\n MOI.Nonnegatives(2),\n )\nMathOptInterface.ConstraintIndex{MathOptInterface.VectorAffineFunction{Float64}, MathOptInterface.Nonnegatives}(1)\n\njulia> MOI.modify(model, c, MOI.VectorConstantChange([3.0, 4.0]));\n\njulia> new_f = MOI.VectorAffineFunction(\n [\n MOI.VectorAffineTerm(1, MOI.ScalarAffineTerm(1.0, x)),\n MOI.VectorAffineTerm(2, MOI.ScalarAffineTerm(2.0, x)),\n ],\n [3.0, 4.0],\n );\n\njulia> MOI.get(model, MOI.ConstraintFunction(), c) ≈ new_f\ntrue","category":"page"},{"location":"manual/modification/#Modify-affine-coefficients-in-a-scalar-function","page":"Problem modification","title":"Modify affine coefficients in a scalar function","text":"","category":"section"},{"location":"manual/modification/","page":"Problem modification","title":"Problem modification","text":"Use modify and ScalarCoefficientChange to modify the affine coefficient of a ScalarAffineFunction or ScalarQuadraticFunction.","category":"page"},{"location":"manual/modification/","page":"Problem modification","title":"Problem modification","text":"julia> c = MOI.add_constraint(\n model,\n MOI.ScalarAffineFunction([MOI.ScalarAffineTerm(1.0, x)], 0.0),\n MOI.EqualTo(1.0),\n )\nMathOptInterface.ConstraintIndex{MathOptInterface.ScalarAffineFunction{Float64}, MathOptInterface.EqualTo{Float64}}(1)\n\njulia> MOI.modify(model, c, MOI.ScalarCoefficientChange(x, 2.0));\n\njulia> new_f = MOI.ScalarAffineFunction([MOI.ScalarAffineTerm(2.0, x)], 0.0);\n\njulia> MOI.get(model, MOI.ConstraintFunction(), c) ≈ new_f\ntrue","category":"page"},{"location":"manual/modification/","page":"Problem modification","title":"Problem modification","text":"ScalarCoefficientChange can also be used to modify the objective function by passing an instance of ObjectiveFunction.","category":"page"},{"location":"manual/modification/#Modify-affine-coefficients-in-a-vector-function","page":"Problem modification","title":"Modify affine coefficients in a vector function","text":"","category":"section"},{"location":"manual/modification/","page":"Problem modification","title":"Problem modification","text":"Use modify and MultirowChange to modify a vector of affine coefficients in a VectorAffineFunction or a VectorQuadraticFunction.","category":"page"},{"location":"manual/modification/","page":"Problem modification","title":"Problem modification","text":"julia> c = MOI.add_constraint(\n model,\n MOI.VectorAffineFunction([\n MOI.VectorAffineTerm(1, MOI.ScalarAffineTerm(1.0, x)),\n MOI.VectorAffineTerm(2, MOI.ScalarAffineTerm(2.0, x)),\n ],\n [0.0, 0.0],\n ),\n MOI.Nonnegatives(2),\n )\nMathOptInterface.ConstraintIndex{MathOptInterface.VectorAffineFunction{Float64}, MathOptInterface.Nonnegatives}(1)\n\njulia> MOI.modify(model, c, MOI.MultirowChange(x, [(1, 3.0), (2, 4.0)]));\n\njulia> new_f = MOI.VectorAffineFunction(\n [\n MOI.VectorAffineTerm(1, MOI.ScalarAffineTerm(3.0, x)),\n MOI.VectorAffineTerm(2, MOI.ScalarAffineTerm(4.0, x)),\n ],\n [0.0, 0.0],\n );\n\njulia> MOI.get(model, MOI.ConstraintFunction(), c) ≈ new_f\ntrue","category":"page"},{"location":"manual/variables/","page":"Variables","title":"Variables","text":"CurrentModule = MathOptInterface\nDocTestSetup = quote\n import MathOptInterface as MOI\nend\nDocTestFilters = [r\"MathOptInterface|MOI\"]","category":"page"},{"location":"manual/variables/#Variables","page":"Variables","title":"Variables","text":"","category":"section"},{"location":"manual/variables/#Add-a-variable","page":"Variables","title":"Add a variable","text":"","category":"section"},{"location":"manual/variables/","page":"Variables","title":"Variables","text":"Use add_variable to add a single variable.","category":"page"},{"location":"manual/variables/","page":"Variables","title":"Variables","text":"julia> x = MOI.add_variable(model)\nMOI.VariableIndex(1)","category":"page"},{"location":"manual/variables/","page":"Variables","title":"Variables","text":"add_variable returns a VariableIndex type, which is used to refer to the added variable in other calls.","category":"page"},{"location":"manual/variables/","page":"Variables","title":"Variables","text":"Check if a VariableIndex is valid using is_valid.","category":"page"},{"location":"manual/variables/","page":"Variables","title":"Variables","text":"julia> MOI.is_valid(model, x)\ntrue","category":"page"},{"location":"manual/variables/","page":"Variables","title":"Variables","text":"Use add_variables to add a number of variables.","category":"page"},{"location":"manual/variables/","page":"Variables","title":"Variables","text":"julia> y = MOI.add_variables(model, 2)\n2-element Vector{MathOptInterface.VariableIndex}:\n MOI.VariableIndex(2)\n MOI.VariableIndex(3)","category":"page"},{"location":"manual/variables/","page":"Variables","title":"Variables","text":"warning: Warning\nThe integer does not necessarily correspond to the column inside an optimizer.","category":"page"},{"location":"manual/variables/#Delete-a-variable","page":"Variables","title":"Delete a variable","text":"","category":"section"},{"location":"manual/variables/","page":"Variables","title":"Variables","text":"Delete a variable using delete.","category":"page"},{"location":"manual/variables/","page":"Variables","title":"Variables","text":"julia> MOI.delete(model, x)\n\njulia> MOI.is_valid(model, x)\nfalse","category":"page"},{"location":"manual/variables/","page":"Variables","title":"Variables","text":"warning: Warning\nNot all ModelLike models support deleting variables. A DeleteNotAllowed error is thrown if this is not supported.","category":"page"},{"location":"manual/variables/#Variable-attributes","page":"Variables","title":"Variable attributes","text":"","category":"section"},{"location":"manual/variables/","page":"Variables","title":"Variables","text":"The following attributes are available for variables:","category":"page"},{"location":"manual/variables/","page":"Variables","title":"Variables","text":"VariableName\nVariablePrimalStart\nVariablePrimal","category":"page"},{"location":"manual/variables/","page":"Variables","title":"Variables","text":"Get and set these attributes using get and set.","category":"page"},{"location":"manual/variables/","page":"Variables","title":"Variables","text":"julia> MOI.set(model, MOI.VariableName(), x, \"var_x\")\n\njulia> MOI.get(model, MOI.VariableName(), x)\n\"var_x\"","category":"page"},{"location":"submodules/FileFormats/reference/","page":"API Reference","title":"API Reference","text":"CurrentModule = MathOptInterface\nDocTestSetup = quote\n import MathOptInterface as MOI\nend\nDocTestFilters = [r\"MathOptInterface|MOI\"]","category":"page"},{"location":"submodules/FileFormats/reference/#File-Formats","page":"API Reference","title":"File Formats","text":"","category":"section"},{"location":"submodules/FileFormats/reference/","page":"API Reference","title":"API Reference","text":"Functions to help read and write MOI models to/from various file formats. See The FileFormats submodule for more details.","category":"page"},{"location":"submodules/FileFormats/reference/","page":"API Reference","title":"API Reference","text":"FileFormats.Model\nFileFormats.FileFormat\nFileFormats.CBF.Model\nFileFormats.LP.Model\nFileFormats.MOF.Model\nFileFormats.MPS.Model\nFileFormats.NL.Model\nFileFormats.SDPA.Model","category":"page"},{"location":"submodules/FileFormats/reference/#MathOptInterface.FileFormats.Model","page":"API Reference","title":"MathOptInterface.FileFormats.Model","text":"Model(\n ;\n format::FileFormat = FORMAT_AUTOMATIC,\n filename::Union{Nothing, String} = nothing,\n kwargs...\n)\n\nReturn model corresponding to the FileFormat format, or, if format == FORMAT_AUTOMATIC, guess the format from filename.\n\nThe filename argument is only needed if format == FORMAT_AUTOMATIC.\n\nkwargs are passed to the underlying model constructor.\n\n\n\n\n\n","category":"function"},{"location":"submodules/FileFormats/reference/#MathOptInterface.FileFormats.FileFormat","page":"API Reference","title":"MathOptInterface.FileFormats.FileFormat","text":"FileFormat\n\nList of accepted export formats.\n\nFORMAT_AUTOMATIC: try to detect the file format based on the file name\nFORMAT_CBF: the Conic Benchmark format\nFORMAT_LP: the LP file format\nFORMAT_MOF: the MathOptFormat file format\nFORMAT_MPS: the MPS file format\nFORMAT_NL: the AMPL .nl file format\nFORMAT_REW: the .rew file format, which is MPS with generic names\nFORMAT_SDPA: the SemiDefinite Programming Algorithm format\n\n\n\n\n\n","category":"type"},{"location":"submodules/FileFormats/reference/#MathOptInterface.FileFormats.CBF.Model","page":"API Reference","title":"MathOptInterface.FileFormats.CBF.Model","text":"Model()\n\nCreate an empty instance of FileFormats.CBF.Model.\n\n\n\n\n\n","category":"type"},{"location":"submodules/FileFormats/reference/#MathOptInterface.FileFormats.LP.Model","page":"API Reference","title":"MathOptInterface.FileFormats.LP.Model","text":"Model(; kwargs...)\n\nCreate an empty instance of FileFormats.LP.Model.\n\nKeyword arguments are:\n\nmaximum_length::Int=255: the maximum length for the name of a variable. lp_solve 5.0 allows only 16 characters, while CPLEX 12.5+ allow 255.\nwarn::Bool=false: print a warning when variables or constraints are renamed.\n\n\n\n\n\n","category":"type"},{"location":"submodules/FileFormats/reference/#MathOptInterface.FileFormats.MOF.Model","page":"API Reference","title":"MathOptInterface.FileFormats.MOF.Model","text":"Model(; kwargs...)\n\nCreate an empty instance of FileFormats.MOF.Model.\n\nKeyword arguments are:\n\nprint_compact::Bool=false: print the JSON file in a compact format without spaces or newlines.\nwarn::Bool=false: print a warning when variables or constraints are renamed\ndifferentiation_backend::MOI.Nonlinear.AbstractAutomaticDifferentiation = MOI.Nonlinear.SparseReverseMode(): automatic differentiation backend to use when reading models with nonlinear constraints and objectives.\n\n\n\n\n\n","category":"type"},{"location":"submodules/FileFormats/reference/#MathOptInterface.FileFormats.MPS.Model","page":"API Reference","title":"MathOptInterface.FileFormats.MPS.Model","text":"Model(; kwargs...)\n\nCreate an empty instance of FileFormats.MPS.Model.\n\nKeyword arguments are:\n\nwarn::Bool=false: print a warning when variables or constraints are renamed.\nprint_objsense::Bool=false: print the OBJSENSE section when writing\ngeneric_names::Bool=false: strip all names in the model and replace them with the generic names C$i and R$i for the i'th column and row respectively.\nquadratic_format::QuadraticFormat = kQuadraticFormatGurobi: specify the solver-specific extension used when writing the quadratic components of the model. Options are kQuadraticFormatGurobi, kQuadraticFormatCPLEX, and kQuadraticFormatMosek.\n\n\n\n\n\n","category":"type"},{"location":"submodules/FileFormats/reference/#MathOptInterface.FileFormats.NL.Model","page":"API Reference","title":"MathOptInterface.FileFormats.NL.Model","text":"Model(; use_nlp_block::Bool = true)\n\nCreate a new Optimizer object.\n\n\n\n\n\n","category":"type"},{"location":"submodules/FileFormats/reference/#MathOptInterface.FileFormats.SDPA.Model","page":"API Reference","title":"MathOptInterface.FileFormats.SDPA.Model","text":"Model(; number_type::Type = Float64)\n\nCreate an empty instance of FileFormats.SDPA.Model{number_type}.\n\nIt is important to be aware that the SDPA file format is interpreted in geometric form and not standard conic form. The standard conic form and geometric conic form are two dual standard forms for semidefinite programs (SDPs). The geometric conic form of an SDP is as follows:\n\nbeginalign\n min_y in mathbbR^m b^T y\n\n textst sum_i=1^m A_i y_i - C in mathbbK\nendalign\n\nwhere mathcalK is a cartesian product of nonnegative orthant and positive semidefinite matrices that align with a block diagonal structure shared with the matrices A_i and C.\n\nIn other words, the geometric conic form contains free variables and affine constraints in either the nonnegative orthant or the positive semidefinite cone. That is, in the MathOptInterface's terminology, MOI.VectorAffineFunction-in-MOI.Nonnegatives and MOI.VectorAffineFunction-in-MOI.PositiveSemidefiniteConeTriangle constraints.\n\nThe corresponding standard conic form of the dual SDP is as follows:\n\nbeginalign\n max_X in mathbbK texttr(CX)\n\n textst texttr(A_iX) = b_i i = 1 ldots m\nendalign\n\nIn other words, the standard conic form contains nonnegative and positive semidefinite variables with equality constraints. That is, in the MathOptInterface's terminology, MOI.VectorOfVariables-in-MOI.Nonnegatives, MOI.VectorOfVariables-in-MOI.PositiveSemidefiniteConeTriangle and MOI.ScalarAffineFunction-in-MOI.EqualTo constraints.\n\nIf a model is in standard conic form, use Dualization.jl to transform it into the geometric conic form before writting it. Otherwise, the nonnegative (resp. positive semidefinite) variables will be bridged into free variables with affine constraints constraining them to belong to the nonnegative orthant (resp. positive semidefinite cone) by the MOI.Bridges.Constraint.VectorFunctionizeBridge. Moreover, equality constraints will be bridged into pairs of affine constraints in the nonnegative orthant by the MOI.Bridges.Constraint.SplitIntervalBridge and then the MOI.Bridges.Constraint.VectorizeBridge.\n\nIf a solver is in standard conic form, use Dualization.jl to transform the model read into standard conic form before copying it to the solver. Otherwise, the free variables will be bridged into pairs of variables in the nonnegative orthant by the MOI.Bridges.Variable.FreeBridge and affine constraints will be bridged into equality constraints by creating a slack variable by the MOI.Bridges.Constraint.VectorSlackBridge.\n\n\n\n\n\n","category":"type"},{"location":"submodules/FileFormats/reference/#Other-helpers","page":"API Reference","title":"Other helpers","text":"","category":"section"},{"location":"submodules/FileFormats/reference/","page":"API Reference","title":"API Reference","text":"FileFormats.NL.SolFileResults","category":"page"},{"location":"submodules/FileFormats/reference/#MathOptInterface.FileFormats.NL.SolFileResults","page":"API Reference","title":"MathOptInterface.FileFormats.NL.SolFileResults","text":"SolFileResults(filename::String, model::Model)\n\nParse the .sol file filename created by solving model and return a SolFileResults struct.\n\nThe returned struct supports the MOI.get API for querying result attributes such as MOI.TerminationStatus, MOI.VariablePrimal, and MOI.ConstraintDual.\n\n\n\n\n\nSolFileResults(\n raw_status::String,\n termination_status::MOI.TerminationStatusCode,\n)\n\nReturn a SolFileResults struct with MOI.RawStatusString set to raw_status, MOI.TerminationStatus set to termination_status, and MOI.PrimalStatus and MOI.DualStatus set to NO_SOLUTION.\n\nAll other attributes are un-set.\n\n\n\n\n\n","category":"type"},{"location":"submodules/Benchmarks/reference/","page":"API Reference","title":"API Reference","text":"CurrentModule = MathOptInterface\nDocTestSetup = quote\n import MathOptInterface as MOI\nend\nDocTestFilters = [r\"MathOptInterface|MOI\"]","category":"page"},{"location":"submodules/Benchmarks/reference/#Benchmarks","page":"API Reference","title":"Benchmarks","text":"","category":"section"},{"location":"submodules/Benchmarks/reference/","page":"API Reference","title":"API Reference","text":"Functions to help benchmark the performance of solver wrappers. See The Benchmarks submodule for more details.","category":"page"},{"location":"submodules/Benchmarks/reference/","page":"API Reference","title":"API Reference","text":"Benchmarks.suite\nBenchmarks.create_baseline\nBenchmarks.compare_against_baseline","category":"page"},{"location":"submodules/Benchmarks/reference/#MathOptInterface.Benchmarks.suite","page":"API Reference","title":"MathOptInterface.Benchmarks.suite","text":"suite(\n new_model::Function;\n exclude::Vector{Regex} = Regex[]\n)\n\nCreate a suite of benchmarks. new_model should be a function that takes no arguments, and returns a new instance of the optimizer you wish to benchmark.\n\nUse exclude to exclude a subset of benchmarks.\n\nExamples\n\nsuite() do\n GLPK.Optimizer()\nend\nsuite(exclude = [r\"delete\"]) do\n Gurobi.Optimizer(OutputFlag=0)\nend\n\n\n\n\n\n","category":"function"},{"location":"submodules/Benchmarks/reference/#MathOptInterface.Benchmarks.create_baseline","page":"API Reference","title":"MathOptInterface.Benchmarks.create_baseline","text":"create_baseline(suite, name::String; directory::String = \"\"; kwargs...)\n\nRun all benchmarks in suite and save to files called name in directory.\n\nExtra kwargs are based to BenchmarkTools.run.\n\nExamples\n\nmy_suite = suite(() -> GLPK.Optimizer())\ncreate_baseline(my_suite, \"glpk_master\"; directory = \"/tmp\", verbose = true)\n\n\n\n\n\n","category":"function"},{"location":"submodules/Benchmarks/reference/#MathOptInterface.Benchmarks.compare_against_baseline","page":"API Reference","title":"MathOptInterface.Benchmarks.compare_against_baseline","text":"compare_against_baseline(\n suite, name::String; directory::String = \"\",\n report_filename::String = \"report.txt\"\n)\n\nRun all benchmarks in suite and compare against files called name in directory that were created by a call to create_baseline.\n\nA report summarizing the comparison is written to report_filename in directory.\n\nExtra kwargs are based to BenchmarkTools.run.\n\nExamples\n\nmy_suite = suite(() -> GLPK.Optimizer())\ncompare_against_baseline(\n my_suite, \"glpk_master\"; directory = \"/tmp\", verbose = true\n)\n\n\n\n\n\n","category":"function"},{"location":"submodules/Test/overview/","page":"Overview","title":"Overview","text":"CurrentModule = MathOptInterface\nDocTestSetup = quote\n import MathOptInterface as MOI\nend\nDocTestFilters = [r\"MathOptInterface|MOI\"]","category":"page"},{"location":"submodules/Test/overview/#test_module","page":"Overview","title":"The Test submodule","text":"","category":"section"},{"location":"submodules/Test/overview/","page":"Overview","title":"Overview","text":"The Test submodule provides tools to help solvers implement unit tests in order to ensure they implement the MathOptInterface API correctly, and to check for solver-correctness.","category":"page"},{"location":"submodules/Test/overview/","page":"Overview","title":"Overview","text":"We use a centralized repository of tests, so that if we find a bug in one solver, instead of adding a test to that particular repository, we add it here so that all solvers can benefit.","category":"page"},{"location":"submodules/Test/overview/#How-to-test-a-solver","page":"Overview","title":"How to test a solver","text":"","category":"section"},{"location":"submodules/Test/overview/","page":"Overview","title":"Overview","text":"The skeleton below can be used for the wrapper test file of a solver named FooBar.","category":"page"},{"location":"submodules/Test/overview/","page":"Overview","title":"Overview","text":"# ============================ /test/MOI_wrapper.jl ============================\nmodule TestFooBar\n\nimport FooBar\nusing Test\n\nimport MathOptInterface as MOI\n\nconst OPTIMIZER = MOI.instantiate(\n MOI.OptimizerWithAttributes(FooBar.Optimizer, MOI.Silent() => true),\n)\n\nconst BRIDGED = MOI.instantiate(\n MOI.OptimizerWithAttributes(FooBar.Optimizer, MOI.Silent() => true),\n with_bridge_type = Float64,\n)\n\n# See the docstring of MOI.Test.Config for other arguments.\nconst CONFIG = MOI.Test.Config(\n # Modify tolerances as necessary.\n atol = 1e-6,\n rtol = 1e-6,\n # Use MOI.LOCALLY_SOLVED for local solvers.\n optimal_status = MOI.OPTIMAL,\n # Pass attributes or MOI functions to `exclude` to skip tests that\n # rely on this functionality.\n exclude = Any[MOI.VariableName, MOI.delete],\n)\n\n\"\"\"\n runtests()\n\nThis function runs all functions in the this Module starting with `test_`.\n\"\"\"\nfunction runtests()\n for name in names(@__MODULE__; all = true)\n if startswith(\"$(name)\", \"test_\")\n @testset \"$(name)\" begin\n getfield(@__MODULE__, name)()\n end\n end\n end\nend\n\n\"\"\"\n test_runtests()\n\nThis function runs all the tests in MathOptInterface.Test.\n\nPass arguments to `exclude` to skip tests for functionality that is not\nimplemented or that your solver doesn't support.\n\"\"\"\nfunction test_runtests()\n MOI.Test.runtests(\n BRIDGED,\n CONFIG,\n exclude = [\n \"test_attribute_NumberOfThreads\",\n \"test_quadratic_\",\n ],\n # This argument is useful to prevent tests from failing on future\n # releases of MOI that add new tests. Don't let this number get too far\n # behind the current MOI release though. You should periodically check\n # for new tests to fix bugs and implement new features.\n exclude_tests_after = v\"0.10.5\",\n )\n return\nend\n\n\"\"\"\n test_SolverName()\n\nYou can also write new tests for solver-specific functionality. Write each new\ntest as a function with a name beginning with `test_`.\n\"\"\"\nfunction test_SolverName()\n @test MOI.get(FooBar.Optimizer(), MOI.SolverName()) == \"FooBar\"\n return\nend\n\nend # module TestFooBar\n\n# This line at tne end of the file runs all the tests!\nTestFooBar.runtests()","category":"page"},{"location":"submodules/Test/overview/","page":"Overview","title":"Overview","text":"Then modify your runtests.jl file to include the MOI_wrapper.jl file:","category":"page"},{"location":"submodules/Test/overview/","page":"Overview","title":"Overview","text":"# ============================ /test/runtests.jl ============================\n\nusing Test\n\n@testset \"MOI\" begin\n include(\"test/MOI_wrapper.jl\")\nend","category":"page"},{"location":"submodules/Test/overview/","page":"Overview","title":"Overview","text":"info: Info\nThe optimizer BRIDGED constructed with instantiate automatically bridges constraints that are not supported by OPTIMIZER using the bridges listed in Bridges. It is recommended for an implementation of MOI to only support constraints that are natively supported by the solver and let bridges transform the constraint to the appropriate form. For this reason it is expected that tests may not pass if OPTIMIZER is used instead of BRIDGED.","category":"page"},{"location":"submodules/Test/overview/#How-to-debug-a-failing-test","page":"Overview","title":"How to debug a failing test","text":"","category":"section"},{"location":"submodules/Test/overview/","page":"Overview","title":"Overview","text":"When writing a solver, it's likely that you will initially fail many tests. Some failures will be bugs, but other failures you may choose to exclude.","category":"page"},{"location":"submodules/Test/overview/","page":"Overview","title":"Overview","text":"There are two ways to exclude tests:","category":"page"},{"location":"submodules/Test/overview/","page":"Overview","title":"Overview","text":"Exclude tests whose names contain a string using:\nMOI.Test.runtests(\n model,\n config;\n exclude = String[\"test_to_exclude\", \"test_conic_\"],\n)\nThis will exclude tests whose name contains either of the two strings provided.\nExclude tests which rely on specific functionality using:\nMOI.Test.Config(exclude = Any[MOI.VariableName, MOI.optimize!])\nThis will exclude tests which use the MOI.VariableName attribute, or which call MOI.optimize!.","category":"page"},{"location":"submodules/Test/overview/","page":"Overview","title":"Overview","text":"Each test that fails can be independently called as:","category":"page"},{"location":"submodules/Test/overview/","page":"Overview","title":"Overview","text":"model = FooBar.Optimizer()\nconfig = MOI.Test.Config()\nMOI.empty!(model)\nMOI.Test.test_category_name_that_failed(model, config)","category":"page"},{"location":"submodules/Test/overview/","page":"Overview","title":"Overview","text":"You can look-up the source code of the test that failed by searching for it in the src/Test/test_category.jl file.","category":"page"},{"location":"submodules/Test/overview/","page":"Overview","title":"Overview","text":"tip: Tip\nEach test function also has a docstring that explains what the test is for. Use ? MOI.Test.test_category_name_that_failed from the REPL to read it.","category":"page"},{"location":"submodules/Test/overview/","page":"Overview","title":"Overview","text":"Periodically, you should re-run excluded tests to see if they now pass. The easiest way to do this is to swap the exclude keyword argument of runtests to include. For example:","category":"page"},{"location":"submodules/Test/overview/","page":"Overview","title":"Overview","text":"MOI.Test.runtests(\n model,\n config;\n exclude = String[\"test_to_exclude\", \"test_conic_\"],\n)","category":"page"},{"location":"submodules/Test/overview/","page":"Overview","title":"Overview","text":"becomes","category":"page"},{"location":"submodules/Test/overview/","page":"Overview","title":"Overview","text":"MOI.Test.runtests(\n model,\n config;\n include = String[\"test_to_exclude\", \"test_conic_\"],\n)","category":"page"},{"location":"submodules/Test/overview/#How-to-add-a-test","page":"Overview","title":"How to add a test","text":"","category":"section"},{"location":"submodules/Test/overview/","page":"Overview","title":"Overview","text":"To detect bugs in solvers, we add new tests to MOI.Test.","category":"page"},{"location":"submodules/Test/overview/","page":"Overview","title":"Overview","text":"As an example, ECOS errored calling optimize! twice in a row. (See ECOS.jl PR #72.) We could add a test to ECOS.jl, but that would only stop us from re-introducing the bug to ECOS.jl in the future, but it would not catch other solvers in the ecosystem with the same bug. Instead, if we add a test to MOI.Test, then all solvers will also check that they handle a double optimize call.","category":"page"},{"location":"submodules/Test/overview/","page":"Overview","title":"Overview","text":"For this test, we care about correctness, rather than performance. therefore, we don't expect solvers to efficiently decide that they have already solved the problem, only that calling optimize! twice doesn't throw an error or give the wrong answer.","category":"page"},{"location":"submodules/Test/overview/","page":"Overview","title":"Overview","text":"Step 1","category":"page"},{"location":"submodules/Test/overview/","page":"Overview","title":"Overview","text":"Install the MathOptInterface julia package in dev mode:","category":"page"},{"location":"submodules/Test/overview/","page":"Overview","title":"Overview","text":"julia> ]\n(@v1.6) pkg> dev MathOptInterface","category":"page"},{"location":"submodules/Test/overview/","page":"Overview","title":"Overview","text":"Step 2","category":"page"},{"location":"submodules/Test/overview/","page":"Overview","title":"Overview","text":"From here on, proceed with making the following changes in the ~/.julia/dev/MathOptInterface folder (or equivalent dev path on your machine).","category":"page"},{"location":"submodules/Test/overview/","page":"Overview","title":"Overview","text":"Step 3","category":"page"},{"location":"submodules/Test/overview/","page":"Overview","title":"Overview","text":"Since the double-optimize error involves solving an optimization problem, add a new test to src/Test/test_solve.jl:","category":"page"},{"location":"submodules/Test/overview/","page":"Overview","title":"Overview","text":"\"\"\"\n test_unit_optimize!_twice(model::MOI.ModelLike, config::Config)\n\nTest that calling `MOI.optimize!` twice does not error.\n\nThis problem was first detected in ECOS.jl PR#72:\nhttps://github.com/jump-dev/ECOS.jl/pull/72\n\"\"\"\nfunction test_unit_optimize!_twice(\n model::MOI.ModelLike,\n config::Config{T},\n) where {T}\n # Use the `@requires` macro to check conditions that the test function\n # requires to run. Models failing this `@requires` check will silently skip\n # the test.\n @requires MOI.supports_constraint(\n model,\n MOI.VariableIndex,\n MOI.GreaterThan{Float64},\n )\n @requires _supports(config, MOI.optimize!)\n # If needed, you can test that the model is empty at the start of the test.\n # You can assume that this will be the case for tests run via `runtests`.\n # User's calling tests individually need to call `MOI.empty!` themselves.\n @test MOI.is_empty(model)\n # Create a simple model. Try to make this as simple as possible so that the\n # majority of solvers can run the test.\n x = MOI.add_variable(model)\n MOI.add_constraint(model, x, MOI.GreaterThan(one(T)))\n MOI.set(model, MOI.ObjectiveSense(), MOI.MIN_SENSE)\n MOI.set(\n model,\n MOI.ObjectiveFunction{MOI.VariableIndex}(),\n x,\n )\n # The main component of the test: does calling `optimize!` twice error?\n MOI.optimize!(model)\n MOI.optimize!(model)\n # Check we have a solution.\n @test MOI.get(model, MOI.TerminationStatus()) == MOI.OPTIMAL\n # There is a three-argument version of `Base.isapprox` for checking\n # approximate equality based on the tolerances defined in `config`:\n @test isapprox(MOI.get(model, MOI.VariablePrimal(), x), one(T), config)\n # For code-style, these tests should always `return` `nothing`.\n return\nend","category":"page"},{"location":"submodules/Test/overview/","page":"Overview","title":"Overview","text":"info: Info\nMake sure the function is agnostic to the number type T; don't assume it is a Float64 capable solver.","category":"page"},{"location":"submodules/Test/overview/","page":"Overview","title":"Overview","text":"We also need to write a test for the test. Place this function immediately below the test you just wrote in the same file:","category":"page"},{"location":"submodules/Test/overview/","page":"Overview","title":"Overview","text":"function setup_test(\n ::typeof(test_unit_optimize!_twice),\n model::MOI.Utilities.MockOptimizer,\n ::Config,\n)\n MOI.Utilities.set_mock_optimize!(\n model,\n (mock::MOI.Utilities.MockOptimizer) -> MOIU.mock_optimize!(\n mock,\n MOI.OPTIMAL,\n (MOI.FEASIBLE_POINT, [1.0]),\n ),\n )\n return\nend","category":"page"},{"location":"submodules/Test/overview/","page":"Overview","title":"Overview","text":"Finally, you also need to implement Test.version_added. If we added this test when the latest released version of MOI was v0.10.5, define:","category":"page"},{"location":"submodules/Test/overview/","page":"Overview","title":"Overview","text":"version_added(::typeof(test_unit_optimize!_twice)) = v\"0.10.6\"","category":"page"},{"location":"submodules/Test/overview/","page":"Overview","title":"Overview","text":"Step 6","category":"page"},{"location":"submodules/Test/overview/","page":"Overview","title":"Overview","text":"Commit the changes to git from ~/.julia/dev/MathOptInterface and submit the PR for review.","category":"page"},{"location":"submodules/Test/overview/","page":"Overview","title":"Overview","text":"tip: Tip\nIf you need help writing a test, open an issue on GitHub, or ask the Developer Chatroom.","category":"page"},{"location":"reference/errors/","page":"Errors","title":"Errors","text":"CurrentModule = MathOptInterface\nDocTestSetup = quote\n import MathOptInterface as MOI\nend\nDocTestFilters = [r\"MathOptInterface|MOI\"]","category":"page"},{"location":"reference/errors/#Errors","page":"Errors","title":"Errors","text":"","category":"section"},{"location":"reference/errors/","page":"Errors","title":"Errors","text":"When an MOI call fails on a model, precise errors should be thrown when possible instead of simply calling error with a message. The docstrings for the respective methods describe the errors that the implementation should throw in certain situations. This error-reporting system allows code to distinguish between internal errors (that should be shown to the user) and unsupported operations which may have automatic workarounds.","category":"page"},{"location":"reference/errors/","page":"Errors","title":"Errors","text":"When an invalid index is used in an MOI call, an InvalidIndex is thrown:","category":"page"},{"location":"reference/errors/","page":"Errors","title":"Errors","text":"InvalidIndex","category":"page"},{"location":"reference/errors/#MathOptInterface.InvalidIndex","page":"Errors","title":"MathOptInterface.InvalidIndex","text":"struct InvalidIndex{IndexType<:Index} <: Exception\n index::IndexType\nend\n\nAn error indicating that the index index is invalid.\n\n\n\n\n\n","category":"type"},{"location":"reference/errors/","page":"Errors","title":"Errors","text":"When an invalid result index is used to retrieve an attribute, a ResultIndexBoundsError is thrown:","category":"page"},{"location":"reference/errors/","page":"Errors","title":"Errors","text":"ResultIndexBoundsError\ncheck_result_index_bounds","category":"page"},{"location":"reference/errors/#MathOptInterface.ResultIndexBoundsError","page":"Errors","title":"MathOptInterface.ResultIndexBoundsError","text":"struct ResultIndexBoundsError{AttrType} <: Exception\n attr::AttrType\n result_count::Int\nend\n\nAn error indicating that the requested attribute attr could not be retrieved, because the solver returned too few results compared to what was requested. For instance, the user tries to retrieve VariablePrimal(2) when only one solution is available, or when the model is infeasible and has no solution.\n\nSee also: check_result_index_bounds.\n\n\n\n\n\n","category":"type"},{"location":"reference/errors/#MathOptInterface.check_result_index_bounds","page":"Errors","title":"MathOptInterface.check_result_index_bounds","text":"check_result_index_bounds(model::ModelLike, attr)\n\nThis function checks whether enough results are available in the model for the requested attr, using its result_index field. If the model does not have sufficient results to answer the query, it throws a ResultIndexBoundsError.\n\n\n\n\n\n","category":"function"},{"location":"reference/errors/","page":"Errors","title":"Errors","text":"As discussed in JuMP mapping, for scalar constraint with a nonzero function constant, a ScalarFunctionConstantNotZero exception may be thrown:","category":"page"},{"location":"reference/errors/","page":"Errors","title":"Errors","text":"ScalarFunctionConstantNotZero","category":"page"},{"location":"reference/errors/#MathOptInterface.ScalarFunctionConstantNotZero","page":"Errors","title":"MathOptInterface.ScalarFunctionConstantNotZero","text":"struct ScalarFunctionConstantNotZero{T, F, S} <: Exception\n constant::T\nend\n\nAn error indicating that the constant part of the function in the constraint F-in-S is nonzero.\n\n\n\n\n\n","category":"type"},{"location":"reference/errors/","page":"Errors","title":"Errors","text":"Some VariableIndex constraints cannot be combined on the same variable:","category":"page"},{"location":"reference/errors/","page":"Errors","title":"Errors","text":"LowerBoundAlreadySet\nUpperBoundAlreadySet","category":"page"},{"location":"reference/errors/#MathOptInterface.LowerBoundAlreadySet","page":"Errors","title":"MathOptInterface.LowerBoundAlreadySet","text":"LowerBoundAlreadySet{S1, S2}\n\nError thrown when setting a VariableIndex-in-S2 when a VariableIndex-in-S1 has already been added and the sets S1, S2 both set a lower bound, i.e. they are EqualTo, GreaterThan, Interval, Semicontinuous or Semiinteger.\n\n\n\n\n\n","category":"type"},{"location":"reference/errors/#MathOptInterface.UpperBoundAlreadySet","page":"Errors","title":"MathOptInterface.UpperBoundAlreadySet","text":"UpperBoundAlreadySet{S1, S2}\n\nError thrown when setting a VariableIndex-in-S2 when a VariableIndex-in-S1 has already been added and the sets S1, S2 both set an upper bound, i.e. they are EqualTo, LessThan, Interval, Semicontinuous or Semiinteger.\n\n\n\n\n\n","category":"type"},{"location":"reference/errors/","page":"Errors","title":"Errors","text":"As discussed in AbstractCallback, trying to get attributes inside a callback may throw:","category":"page"},{"location":"reference/errors/","page":"Errors","title":"Errors","text":"OptimizeInProgress","category":"page"},{"location":"reference/errors/#MathOptInterface.OptimizeInProgress","page":"Errors","title":"MathOptInterface.OptimizeInProgress","text":"struct OptimizeInProgress{AttrType<:AnyAttribute} <: Exception\n attr::AttrType\nend\n\nError thrown from optimizer when MOI.get(optimizer, attr) is called inside an AbstractCallback while it is only defined once optimize! has completed. This can only happen when is_set_by_optimize(attr) is true.\n\n\n\n\n\n","category":"type"},{"location":"reference/errors/","page":"Errors","title":"Errors","text":"Trying to submit the wrong type of AbstractSubmittable inside an AbstractCallback (for example, a UserCut inside a LazyConstraintCallback) will throw:","category":"page"},{"location":"reference/errors/","page":"Errors","title":"Errors","text":"InvalidCallbackUsage","category":"page"},{"location":"reference/errors/#MathOptInterface.InvalidCallbackUsage","page":"Errors","title":"MathOptInterface.InvalidCallbackUsage","text":"struct InvalidCallbackUsage{C, S} <: Exception\n callback::C\n submittable::S\nend\n\nAn error indicating that submittable cannot be submitted inside callback.\n\nFor example, UserCut cannot be submitted inside LazyConstraintCallback.\n\n\n\n\n\n","category":"type"},{"location":"reference/errors/","page":"Errors","title":"Errors","text":"The rest of the errors defined in MOI fall in two categories represented by the following two abstract types:","category":"page"},{"location":"reference/errors/","page":"Errors","title":"Errors","text":"UnsupportedError\nNotAllowedError","category":"page"},{"location":"reference/errors/#MathOptInterface.UnsupportedError","page":"Errors","title":"MathOptInterface.UnsupportedError","text":"UnsupportedError <: Exception\n\nAbstract type for error thrown when an element is not supported by the model.\n\n\n\n\n\n","category":"type"},{"location":"reference/errors/#MathOptInterface.NotAllowedError","page":"Errors","title":"MathOptInterface.NotAllowedError","text":"NotAllowedError <: Exception\n\nAbstract type for error thrown when an operation is supported but cannot be applied in the current state of the model.\n\n\n\n\n\n","category":"type"},{"location":"reference/errors/","page":"Errors","title":"Errors","text":"The different UnsupportedError and NotAllowedError are the following errors:","category":"page"},{"location":"reference/errors/","page":"Errors","title":"Errors","text":"UnsupportedAttribute\nSetAttributeNotAllowed\nAddVariableNotAllowed\nUnsupportedConstraint\nAddConstraintNotAllowed\nModifyConstraintNotAllowed\nModifyObjectiveNotAllowed\nDeleteNotAllowed\nUnsupportedSubmittable\nSubmitNotAllowed\nUnsupportedNonlinearOperator","category":"page"},{"location":"reference/errors/#MathOptInterface.UnsupportedAttribute","page":"Errors","title":"MathOptInterface.UnsupportedAttribute","text":"struct UnsupportedAttribute{AttrType} <: UnsupportedError\n attr::AttrType\n message::String\nend\n\nAn error indicating that the attribute attr is not supported by the model, i.e. that supports returns false.\n\n\n\n\n\n","category":"type"},{"location":"reference/errors/#MathOptInterface.SetAttributeNotAllowed","page":"Errors","title":"MathOptInterface.SetAttributeNotAllowed","text":"struct SetAttributeNotAllowed{AttrType} <: NotAllowedError\n attr::AttrType\n message::String\nend\n\nAn error indicating that the attribute attr is supported (see supports) but cannot be set for some reason (see the error string).\n\n\n\n\n\n","category":"type"},{"location":"reference/errors/#MathOptInterface.AddVariableNotAllowed","page":"Errors","title":"MathOptInterface.AddVariableNotAllowed","text":"struct AddVariableNotAllowed <: NotAllowedError\n message::String # Human-friendly explanation why the attribute cannot be set\nend\n\nAn error indicating that variables cannot be added to the model.\n\n\n\n\n\n","category":"type"},{"location":"reference/errors/#MathOptInterface.UnsupportedConstraint","page":"Errors","title":"MathOptInterface.UnsupportedConstraint","text":"struct UnsupportedConstraint{F<:AbstractFunction, S<:AbstractSet} <: UnsupportedError\n message::String # Human-friendly explanation why the attribute cannot be set\nend\n\nAn error indicating that constraints of type F-in-S are not supported by the model, i.e. that supports_constraint returns false.\n\n\n\n\n\n","category":"type"},{"location":"reference/errors/#MathOptInterface.AddConstraintNotAllowed","page":"Errors","title":"MathOptInterface.AddConstraintNotAllowed","text":"struct AddConstraintNotAllowed{F<:AbstractFunction, S<:AbstractSet} <: NotAllowedError\n message::String # Human-friendly explanation why the attribute cannot be set\nend\n\nAn error indicating that constraints of type F-in-S are supported (see supports_constraint) but cannot be added.\n\n\n\n\n\n","category":"type"},{"location":"reference/errors/#MathOptInterface.ModifyConstraintNotAllowed","page":"Errors","title":"MathOptInterface.ModifyConstraintNotAllowed","text":"struct ModifyConstraintNotAllowed{F<:AbstractFunction, S<:AbstractSet,\n C<:AbstractFunctionModification} <: NotAllowedError\n constraint_index::ConstraintIndex{F, S}\n change::C\n message::String\nend\n\nAn error indicating that the constraint modification change cannot be applied to the constraint of index ci.\n\n\n\n\n\n","category":"type"},{"location":"reference/errors/#MathOptInterface.ModifyObjectiveNotAllowed","page":"Errors","title":"MathOptInterface.ModifyObjectiveNotAllowed","text":"struct ModifyObjectiveNotAllowed{C<:AbstractFunctionModification} <: NotAllowedError\n change::C\n message::String\nend\n\nAn error indicating that the objective modification change cannot be applied to the objective.\n\n\n\n\n\n","category":"type"},{"location":"reference/errors/#MathOptInterface.DeleteNotAllowed","page":"Errors","title":"MathOptInterface.DeleteNotAllowed","text":"struct DeleteNotAllowed{IndexType <: Index} <: NotAllowedError\n index::IndexType\n message::String\nend\n\nAn error indicating that the index index cannot be deleted.\n\n\n\n\n\n","category":"type"},{"location":"reference/errors/#MathOptInterface.UnsupportedSubmittable","page":"Errors","title":"MathOptInterface.UnsupportedSubmittable","text":"struct UnsupportedSubmittable{SubmitType} <: UnsupportedError\n sub::SubmitType\n message::String\nend\n\nAn error indicating that the submittable sub is not supported by the model, i.e. that supports returns false.\n\n\n\n\n\n","category":"type"},{"location":"reference/errors/#MathOptInterface.SubmitNotAllowed","page":"Errors","title":"MathOptInterface.SubmitNotAllowed","text":"struct SubmitNotAllowed{SubmitTyp<:AbstractSubmittable} <: NotAllowedError\n sub::SubmitType\n message::String\nend\n\nAn error indicating that the submittable sub is supported (see supports) but cannot be added for some reason (see the error string).\n\n\n\n\n\n","category":"type"},{"location":"reference/errors/#MathOptInterface.UnsupportedNonlinearOperator","page":"Errors","title":"MathOptInterface.UnsupportedNonlinearOperator","text":"UnsupportedNonlinearOperator(head::Symbol[, message::String]) <: UnsupportedError\n\nAn error thrown by optimizers if they do not support the operator head in a ScalarNonlinearFunction.\n\nExample\n\njulia> import MathOptInterface as MOI\n\njulia> throw(MOI.UnsupportedNonlinearOperator(:black_box))\nERROR: MathOptInterface.UnsupportedNonlinearOperator: The nonlinear operator `:black_box` is not supported by the model.\nStacktrace:\n[...]\n\n\n\n\n\n","category":"type"},{"location":"reference/errors/","page":"Errors","title":"Errors","text":"Note that setting the ConstraintFunction of a VariableIndex constraint is not allowed:","category":"page"},{"location":"reference/errors/","page":"Errors","title":"Errors","text":"SettingVariableIndexNotAllowed","category":"page"},{"location":"reference/errors/#MathOptInterface.SettingVariableIndexNotAllowed","page":"Errors","title":"MathOptInterface.SettingVariableIndexNotAllowed","text":"SettingVariableIndexNotAllowed()\n\nError type that should be thrown when the user calls set to change the ConstraintFunction of a VariableIndex constraint.\n\n\n\n\n\n","category":"type"},{"location":"reference/variables/","page":"Variables","title":"Variables","text":"CurrentModule = MathOptInterface\nDocTestSetup = quote\n import MathOptInterface as MOI\nend\nDocTestFilters = [r\"MathOptInterface|MOI\"]","category":"page"},{"location":"reference/variables/#Variables","page":"Variables","title":"Variables","text":"","category":"section"},{"location":"reference/variables/#Functions","page":"Variables","title":"Functions","text":"","category":"section"},{"location":"reference/variables/","page":"Variables","title":"Variables","text":"add_variable\nadd_variables\nadd_constrained_variable\nadd_constrained_variables\nsupports_add_constrained_variable\nsupports_add_constrained_variables\nis_valid(::ModelLike,::VariableIndex)\ndelete(::ModelLike, ::VariableIndex)\ndelete(::ModelLike, ::Vector{VariableIndex})","category":"page"},{"location":"reference/variables/#MathOptInterface.add_variable","page":"Variables","title":"MathOptInterface.add_variable","text":"add_variable(model::ModelLike)::VariableIndex\n\nAdd a scalar variable to the model, returning a variable index.\n\nA AddVariableNotAllowed error is thrown if adding variables cannot be done in the current state of the model model.\n\n\n\n\n\n","category":"function"},{"location":"reference/variables/#MathOptInterface.add_variables","page":"Variables","title":"MathOptInterface.add_variables","text":"add_variables(model::ModelLike, n::Int)::Vector{VariableIndex}\n\nAdd n scalar variables to the model, returning a vector of variable indices.\n\nA AddVariableNotAllowed error is thrown if adding variables cannot be done in the current state of the model model.\n\n\n\n\n\n","category":"function"},{"location":"reference/variables/#MathOptInterface.add_constrained_variable","page":"Variables","title":"MathOptInterface.add_constrained_variable","text":"add_constrained_variable(\n model::ModelLike,\n set::AbstractScalarSet\n)::Tuple{MOI.VariableIndex,\n MOI.ConstraintIndex{MOI.VariableIndex, typeof(set)}}\n\nAdd to model a scalar variable constrained to belong to set, returning the index of the variable created and the index of the constraint constraining the variable to belong to set.\n\nBy default, this function falls back to creating a free variable with add_variable and then constraining it to belong to set with add_constraint.\n\n\n\n\n\n","category":"function"},{"location":"reference/variables/#MathOptInterface.add_constrained_variables","page":"Variables","title":"MathOptInterface.add_constrained_variables","text":"add_constrained_variables(\n model::ModelLike,\n sets::AbstractVector{<:AbstractScalarSet}\n)::Tuple{\n Vector{MOI.VariableIndex},\n Vector{MOI.ConstraintIndex{MOI.VariableIndex,eltype(sets)}},\n}\n\nAdd to model scalar variables constrained to belong to sets, returning the indices of the variables created and the indices of the constraints constraining the variables to belong to each set in sets. That is, if it returns variables and constraints, constraints[i] is the index of the constraint constraining variable[i] to belong to sets[i].\n\nBy default, this function falls back to calling add_constrained_variable on each set.\n\n\n\n\n\nadd_constrained_variables(\n model::ModelLike,\n set::AbstractVectorSet,\n)::Tuple{\n Vector{MOI.VariableIndex},\n MOI.ConstraintIndex{MOI.VectorOfVariables,typeof(set)},\n}\n\nAdd to model a vector of variables constrained to belong to set, returning the indices of the variables created and the index of the constraint constraining the vector of variables to belong to set.\n\nBy default, this function falls back to creating free variables with add_variables and then constraining it to belong to set with add_constraint.\n\n\n\n\n\n","category":"function"},{"location":"reference/variables/#MathOptInterface.supports_add_constrained_variable","page":"Variables","title":"MathOptInterface.supports_add_constrained_variable","text":"supports_add_constrained_variable(\n model::ModelLike,\n S::Type{<:AbstractScalarSet}\n)::Bool\n\nReturn a Bool indicating whether model supports constraining a variable to belong to a set of type S either on creation of the variable with add_constrained_variable or after the variable is created with add_constraint.\n\nBy default, this function falls back to supports_add_constrained_variables(model, Reals) && supports_constraint(model, MOI.VariableIndex, S) which is the correct definition for most models.\n\nExample\n\nSuppose that a solver supports only two kind of variables: binary variables and continuous variables with a lower bound. If the solver decides not to support VariableIndex-in-Binary and VariableIndex-in-GreaterThan constraints, it only has to implement add_constrained_variable for these two sets which prevents the user to add both a binary constraint and a lower bound on the same variable. Moreover, if the user adds a VariableIndex-in-GreaterThan constraint, implementing this interface (i.e., supports_add_constrained_variables) enables the constraint to be transparently bridged into a supported constraint.\n\n\n\n\n\n","category":"function"},{"location":"reference/variables/#MathOptInterface.supports_add_constrained_variables","page":"Variables","title":"MathOptInterface.supports_add_constrained_variables","text":"supports_add_constrained_variables(\n model::ModelLike,\n S::Type{<:AbstractVectorSet}\n)::Bool\n\nReturn a Bool indicating whether model supports constraining a vector of variables to belong to a set of type S either on creation of the vector of variables with add_constrained_variables or after the variable is created with add_constraint.\n\nBy default, if S is Reals then this function returns true and otherwise, it falls back to supports_add_constrained_variables(model, Reals) && supports_constraint(model, MOI.VectorOfVariables, S) which is the correct definition for most models.\n\nExample\n\nIn the standard conic form (see Duality), the variables are grouped into several cones and the constraints are affine equality constraints. If Reals is not one of the cones supported by the solvers then it needs to implement supports_add_constrained_variables(::Optimizer, ::Type{Reals}) = false as free variables are not supported. The solvers should then implement supports_add_constrained_variables(::Optimizer, ::Type{<:SupportedCones}) = true where SupportedCones is the union of all cone types that are supported; it does not have to implement the method supports_constraint(::Type{VectorOfVariables}, Type{<:SupportedCones}) as it should return false and it's the default. This prevents the user to constrain the same variable in two different cones. When a VectorOfVariables-in-S is added, the variables of the vector have already been created so they already belong to given cones. If bridges are enabled, the constraint will therefore be bridged by adding slack variables in S and equality constraints ensuring that the slack variables are equal to the corresponding variables of the given constraint function.\n\nNote that there may also be sets for which !supports_add_constrained_variables(model, S) and supports_constraint(model, MOI.VectorOfVariables, S). For instance, suppose a solver supports positive semidefinite variable constraints and two types of variables: binary variables and nonnegative variables. Then the solver should support adding VectorOfVariables-in-PositiveSemidefiniteConeTriangle constraints, but it should not support creating variables constrained to belong to the PositiveSemidefiniteConeTriangle because the variables in PositiveSemidefiniteConeTriangle should first be created as either binary or non-negative.\n\n\n\n\n\n","category":"function"},{"location":"reference/variables/#MathOptInterface.is_valid-Tuple{MathOptInterface.ModelLike, MathOptInterface.VariableIndex}","page":"Variables","title":"MathOptInterface.is_valid","text":"is_valid(model::ModelLike, index::Index)::Bool\n\nReturn a Bool indicating whether this index refers to a valid object in the model model.\n\n\n\n\n\n","category":"method"},{"location":"reference/variables/#MathOptInterface.delete-Tuple{MathOptInterface.ModelLike, MathOptInterface.VariableIndex}","page":"Variables","title":"MathOptInterface.delete","text":"delete(model::ModelLike, index::Index)\n\nDelete the referenced object from the model. Throw DeleteNotAllowed if if index cannot be deleted.\n\nThe following modifications also take effect if Index is VariableIndex:\n\nIf index used in the objective function, it is removed from the function, i.e., it is substituted for zero.\nFor each func-in-set constraint of the model:\nIf func isa VariableIndex and func == index then the constraint is deleted.\nIf func isa VectorOfVariables and index in func.variables then\nif length(func.variables) == 1 is one, the constraint is deleted;\nif length(func.variables) > 1 and supports_dimension_update(set) then then the variable is removed from func and set is replaced by update_dimension(set, MOI.dimension(set) - 1).\nOtherwise, a DeleteNotAllowed error is thrown.\nOtherwise, the variable is removed from func, i.e., it is substituted for zero.\n\n\n\n\n\n","category":"method"},{"location":"reference/variables/#MathOptInterface.delete-Tuple{MathOptInterface.ModelLike, Vector{MathOptInterface.VariableIndex}}","page":"Variables","title":"MathOptInterface.delete","text":"delete(model::ModelLike, indices::Vector{R<:Index}) where {R}\n\nDelete the referenced objects in the vector indices from the model. It may be assumed that R is a concrete type. The default fallback sequentially deletes the individual items in indices, although specialized implementations may be more efficient.\n\n\n\n\n\n","category":"method"},{"location":"reference/variables/#Attributes","page":"Variables","title":"Attributes","text":"","category":"section"},{"location":"reference/variables/","page":"Variables","title":"Variables","text":"AbstractVariableAttribute\nVariableName\nVariablePrimalStart\nVariablePrimal\nVariableBasisStatus","category":"page"},{"location":"reference/variables/#MathOptInterface.AbstractVariableAttribute","page":"Variables","title":"MathOptInterface.AbstractVariableAttribute","text":"AbstractVariableAttribute\n\nAbstract supertype for attribute objects that can be used to set or get attributes (properties) of variables in the model.\n\n\n\n\n\n","category":"type"},{"location":"reference/variables/#MathOptInterface.VariableName","page":"Variables","title":"MathOptInterface.VariableName","text":"VariableName()\n\nA variable attribute for a string identifying the variable. It is valid for two variables to have the same name; however, variables with duplicate names cannot be looked up using get. It has a default value of \"\" if not set`.\n\n\n\n\n\n","category":"type"},{"location":"reference/variables/#MathOptInterface.VariablePrimalStart","page":"Variables","title":"MathOptInterface.VariablePrimalStart","text":"VariablePrimalStart()\n\nA variable attribute for the initial assignment to some primal variable's value that the optimizer may use to warm-start the solve. May be a number or nothing (unset).\n\n\n\n\n\n","category":"type"},{"location":"reference/variables/#MathOptInterface.VariablePrimal","page":"Variables","title":"MathOptInterface.VariablePrimal","text":"VariablePrimal(result_index::Int = 1)\n\nA variable attribute for the assignment to some primal variable's value in result result_index. If result_index is omitted, it is 1 by default.\n\nIf the solver does not have a primal value for the variable because the result_index is beyond the available solutions (whose number is indicated by the ResultCount attribute), getting this attribute must throw a ResultIndexBoundsError. Otherwise, if the result is unavailable for another reason (for instance, only a dual solution is available), the result is undefined. Users should first check PrimalStatus before accessing the VariablePrimal attribute.\n\nSee ResultCount for information on how the results are ordered.\n\n\n\n\n\n","category":"type"},{"location":"reference/variables/#MathOptInterface.VariableBasisStatus","page":"Variables","title":"MathOptInterface.VariableBasisStatus","text":"VariableBasisStatus(result_index::Int = 1)\n\nA variable attribute for the BasisStatusCode of a variable in result result_index, with respect to an available optimal solution basis.\n\nIf the solver does not have a basis statue for the variable because the result_index is beyond the available solutions (whose number is indicated by the ResultCount attribute), getting this attribute must throw a ResultIndexBoundsError. Otherwise, if the result is unavailable for another reason (for instance, only a dual solution is available), the result is undefined. Users should first check PrimalStatus before accessing the VariableBasisStatus attribute.\n\nSee ResultCount for information on how the results are ordered.\n\n\n\n\n\n","category":"type"},{"location":"submodules/Bridges/list_of_bridges/","page":"List of bridges","title":"List of bridges","text":"CurrentModule = MathOptInterface\nDocTestSetup = quote\n import MathOptInterface as MOI\nend\nDocTestFilters = [r\"MathOptInterface|MOI\"]","category":"page"},{"location":"submodules/Bridges/list_of_bridges/#List-of-bridges","page":"List of bridges","title":"List of bridges","text":"","category":"section"},{"location":"submodules/Bridges/list_of_bridges/","page":"List of bridges","title":"List of bridges","text":"This section describes the Bridges.AbstractBridges that are implemented in MathOptInterface.","category":"page"},{"location":"submodules/Bridges/list_of_bridges/#constraint_bridges_ref","page":"List of bridges","title":"Constraint bridges","text":"","category":"section"},{"location":"submodules/Bridges/list_of_bridges/","page":"List of bridges","title":"List of bridges","text":"These bridges are subtypes of Bridges.Constraint.AbstractBridge.","category":"page"},{"location":"submodules/Bridges/list_of_bridges/","page":"List of bridges","title":"List of bridges","text":"Bridges.Constraint.GreaterToIntervalBridge\nBridges.Constraint.LessToIntervalBridge\nBridges.Constraint.GreaterToLessBridge\nBridges.Constraint.LessToGreaterBridge\nBridges.Constraint.NonnegToNonposBridge\nBridges.Constraint.NonposToNonnegBridge\nBridges.Constraint.VectorizeBridge\nBridges.Constraint.ScalarizeBridge\nBridges.Constraint.ScalarSlackBridge\nBridges.Constraint.VectorSlackBridge\nBridges.Constraint.ScalarFunctionizeBridge\nBridges.Constraint.VectorFunctionizeBridge\nBridges.Constraint.ToScalarQuadraticBridge\nBridges.Constraint.ToVectorQuadraticBridge\nBridges.Constraint.ToScalarNonlinearBridge\nBridges.Constraint.FunctionConversionBridge\nBridges.Constraint.SplitComplexEqualToBridge\nBridges.Constraint.SplitComplexZerosBridge\nBridges.Constraint.SplitHyperRectangleBridge\nBridges.Constraint.SplitIntervalBridge\nBridges.Constraint.SOCtoRSOCBridge\nBridges.Constraint.RSOCtoSOCBridge\nBridges.Constraint.SOCtoNonConvexQuadBridge\nBridges.Constraint.RSOCtoNonConvexQuadBridge\nBridges.Constraint.QuadtoSOCBridge\nBridges.Constraint.SOCtoPSDBridge\nBridges.Constraint.RSOCtoPSDBridge\nBridges.Constraint.NormInfinityBridge\nBridges.Constraint.NormOneBridge\nBridges.Constraint.NormToPowerBridge\nBridges.Constraint.NormOneConeToNormConeBridge\nBridges.Constraint.SecondOrderConeToNormConeBridge\nBridges.Constraint.NormInfinityConeToNormConeBridge\nBridges.Constraint.GeoMeantoRelEntrBridge\nBridges.Constraint.GeoMeanToPowerBridge\nBridges.Constraint.GeoMeanBridge\nBridges.Constraint.RelativeEntropyBridge\nBridges.Constraint.NormSpectralBridge\nBridges.Constraint.NormNuclearBridge\nBridges.Constraint.SquareBridge\nBridges.Constraint.HermitianToSymmetricPSDBridge\nBridges.Constraint.SetDotScalingBridge\nBridges.Constraint.SetDotInverseScalingBridge\nBridges.Constraint.RootDetBridge\nBridges.Constraint.LogDetBridge\nBridges.Constraint.IndicatorActiveOnFalseBridge\nBridges.Constraint.IndicatorGreaterToLessThanBridge\nBridges.Constraint.IndicatorLessToGreaterThanBridge\nBridges.Constraint.IndicatorSOS1Bridge\nBridges.Constraint.SemiToBinaryBridge\nBridges.Constraint.ZeroOneBridge\nBridges.Constraint.IntegerToZeroOneBridge\nBridges.Constraint.NumberConversionBridge\nBridges.Constraint.AllDifferentToCountDistinctBridge\nBridges.Constraint.ReifiedAllDifferentToCountDistinctBridge\nBridges.Constraint.BinPackingToMILPBridge\nBridges.Constraint.CircuitToMILPBridge\nBridges.Constraint.CountAtLeastToCountBelongsBridge\nBridges.Constraint.CountBelongsToMILPBridge\nBridges.Constraint.CountDistinctToMILPBridge\nBridges.Constraint.ReifiedCountDistinctToMILPBridge\nBridges.Constraint.CountGreaterThanToMILPBridge\nBridges.Constraint.TableToMILPBridge","category":"page"},{"location":"submodules/Bridges/list_of_bridges/#MathOptInterface.Bridges.Constraint.GreaterToIntervalBridge","page":"List of bridges","title":"MathOptInterface.Bridges.Constraint.GreaterToIntervalBridge","text":"GreaterToIntervalBridge{T,F} <: Bridges.Constraint.AbstractBridge\n\nGreaterToIntervalBridge implements the following reformulations:\n\nf(x) ge l into f(x) in l infty)\n\nSource node\n\nGreaterToIntervalBridge supports:\n\nF in MOI.GreaterThan{T}\n\nTarget nodes\n\nGreaterToIntervalBridge creates:\n\nF in MOI.Interval{T}\n\n\n\n\n\n","category":"type"},{"location":"submodules/Bridges/list_of_bridges/#MathOptInterface.Bridges.Constraint.LessToIntervalBridge","page":"List of bridges","title":"MathOptInterface.Bridges.Constraint.LessToIntervalBridge","text":"LessToIntervalBridge{T,F} <: Bridges.Constraint.AbstractBridge\n\nLessToIntervalBridge implements the following reformulations:\n\nf(x) le u into f(x) in (-infty u\n\nSource node\n\nLessToIntervalBridge supports:\n\nF in MOI.LessThan{T}\n\nTarget nodes\n\nLessToIntervalBridge creates:\n\nF in MOI.Interval{T}\n\n\n\n\n\n","category":"type"},{"location":"submodules/Bridges/list_of_bridges/#MathOptInterface.Bridges.Constraint.GreaterToLessBridge","page":"List of bridges","title":"MathOptInterface.Bridges.Constraint.GreaterToLessBridge","text":"GreaterToLessBridge{T,F,G} <: Bridges.Constraint.AbstractBridge\n\nGreaterToLessBridge implements the following reformulation:\n\nf(x) ge l into -f(x) le -l\n\nSource node\n\nGreaterToLessBridge supports:\n\nG in MOI.GreaterThan{T}\n\nTarget nodes\n\nGreaterToLessBridge creates:\n\nF in MOI.LessThan{T}\n\n\n\n\n\n","category":"type"},{"location":"submodules/Bridges/list_of_bridges/#MathOptInterface.Bridges.Constraint.LessToGreaterBridge","page":"List of bridges","title":"MathOptInterface.Bridges.Constraint.LessToGreaterBridge","text":"LessToGreaterBridge{T,F,G} <: Bridges.Constraint.AbstractBridge\n\nLessToGreaterBridge implements the following reformulation:\n\nf(x) le u into -f(x) ge -u\n\nSource node\n\nLessToGreaterBridge supports:\n\nG in MOI.LessThan{T}\n\nTarget nodes\n\nLessToGreaterBridge creates:\n\nF in MOI.GreaterThan{T}\n\n\n\n\n\n","category":"type"},{"location":"submodules/Bridges/list_of_bridges/#MathOptInterface.Bridges.Constraint.NonnegToNonposBridge","page":"List of bridges","title":"MathOptInterface.Bridges.Constraint.NonnegToNonposBridge","text":"NonnegToNonposBridge{T,F,G} <: Bridges.Constraint.AbstractBridge\n\nNonnegToNonposBridge implements the following reformulation:\n\nf(x) in mathbbR_+ into -f(x) in mathbbR_-\n\nSource node\n\nNonnegToNonposBridge supports:\n\nG in MOI.Nonnegatives\n\nTarget nodes\n\nNonnegToNonposBridge creates:\n\nF in MOI.Nonpositives\n\n\n\n\n\n","category":"type"},{"location":"submodules/Bridges/list_of_bridges/#MathOptInterface.Bridges.Constraint.NonposToNonnegBridge","page":"List of bridges","title":"MathOptInterface.Bridges.Constraint.NonposToNonnegBridge","text":"NonposToNonnegBridge{T,F,G} <: Bridges.Constraint.AbstractBridge\n\nNonposToNonnegBridge implements the following reformulation:\n\nf(x) in mathbbR_- into -f(x) in mathbbR_+\n\nSource node\n\nNonposToNonnegBridge supports:\n\nG in MOI.Nonpositives\n\nTarget nodes\n\nNonposToNonnegBridge creates:\n\nF in MOI.Nonnegatives\n\n\n\n\n\n","category":"type"},{"location":"submodules/Bridges/list_of_bridges/#MathOptInterface.Bridges.Constraint.VectorizeBridge","page":"List of bridges","title":"MathOptInterface.Bridges.Constraint.VectorizeBridge","text":"VectorizeBridge{T,F,S,G} <: Bridges.Constraint.AbstractBridge\n\nVectorizeBridge implements the following reformulations:\n\ng(x) ge a into g(x) - a in mathbbR_+\ng(x) le a into g(x) - a in mathbbR_-\ng(x) == a into g(x) - a in 0\n\nwhere T is the coefficient type of g(x) - a.\n\nSource node\n\nVectorizeBridge supports:\n\nG in MOI.GreaterThan{T}\nG in MOI.LessThan{T}\nG in MOI.EqualTo{T}\n\nTarget nodes\n\nVectorizeBridge creates:\n\nF in S, where S is one of MOI.Nonnegatives, MOI.Nonpositives, MOI.Zeros depending on the type of the input set.\n\n\n\n\n\n","category":"type"},{"location":"submodules/Bridges/list_of_bridges/#MathOptInterface.Bridges.Constraint.ScalarizeBridge","page":"List of bridges","title":"MathOptInterface.Bridges.Constraint.ScalarizeBridge","text":"ScalarizeBridge{T,F,S}\n\nScalarizeBridge implements the following reformulations:\n\nf(x) - a in mathbbR_+ into f_i(x) ge a_i for all i\nf(x) - a in mathbbR_- into f_i(x) le a_i for all i\nf(x) - a in 0 into f_i(x) == a_i for all i\n\nSource node\n\nScalarizeBridge supports:\n\nG in MOI.Nonnegatives{T}\nG in MOI.Nonpositives{T}\nG in MOI.Zeros{T}\n\nTarget nodes\n\nScalarizeBridge creates:\n\nF in S, where S is one of MOI.GreaterThan{T}, MOI.LessThan{T}, and MOI.EqualTo{T}, depending on the type of the input set.\n\n\n\n\n\n","category":"type"},{"location":"submodules/Bridges/list_of_bridges/#MathOptInterface.Bridges.Constraint.ScalarSlackBridge","page":"List of bridges","title":"MathOptInterface.Bridges.Constraint.ScalarSlackBridge","text":"ScalarSlackBridge{T,F,S} <: Bridges.Constraint.AbstractBridge\n\nScalarSlackBridge implements the following reformulation:\n\nf(x) in S into f(x) - y == 0 and y in S\n\nSource node\n\nScalarSlackBridge supports:\n\nG in S, where G is not MOI.VariableIndex and S is not MOI.EqualTo\n\nTarget nodes\n\nScalarSlackBridge creates:\n\nF in MOI.EqualTo{T}\nMOI.VariableIndex in S\n\n\n\n\n\n","category":"type"},{"location":"submodules/Bridges/list_of_bridges/#MathOptInterface.Bridges.Constraint.VectorSlackBridge","page":"List of bridges","title":"MathOptInterface.Bridges.Constraint.VectorSlackBridge","text":"VectorSlackBridge{T,F,S} <: Bridges.Constraint.AbstractBridge\n\nVectorSlackBridge implements the following reformulation:\n\nf(x) in S into f(x) - y in 0 and y in S\n\nSource node\n\nVectorSlackBridge supports:\n\nG in S, where G is not MOI.VectorOfVariables and S is not MOI.Zeros\n\nTarget nodes\n\nVectorSlackBridge creates:\n\nF in MOI.Zeros\nMOI.VectorOfVariables in S\n\n\n\n\n\n","category":"type"},{"location":"submodules/Bridges/list_of_bridges/#MathOptInterface.Bridges.Constraint.ScalarFunctionizeBridge","page":"List of bridges","title":"MathOptInterface.Bridges.Constraint.ScalarFunctionizeBridge","text":"ScalarFunctionizeBridge{T,S} = FunctionConversionBridge{T,MOI.ScalarAffineFunction{T},MOI.VariableIndex,S}\n\nScalarFunctionizeBridge implements the following reformulations:\n\nx in S into 1x + 0 in S\n\nSource node\n\nScalarFunctionizeBridge supports:\n\nMOI.VariableIndex in S\n\nTarget nodes\n\nScalarFunctionizeBridge creates:\n\nMOI.ScalarAffineFunction{T} in S\n\n\n\n\n\n","category":"type"},{"location":"submodules/Bridges/list_of_bridges/#MathOptInterface.Bridges.Constraint.VectorFunctionizeBridge","page":"List of bridges","title":"MathOptInterface.Bridges.Constraint.VectorFunctionizeBridge","text":"VectorFunctionizeBridge{T,S} = FunctionConversionBridge{T,MOI.VectorAffineFunction{T},S}\n\nVectorFunctionizeBridge implements the following reformulations:\n\nx in S into Ix + 0 in S\n\nSource node\n\nVectorFunctionizeBridge supports:\n\nMOI.VectorOfVariables in S\n\nTarget nodes\n\nVectorFunctionizeBridge creates:\n\nMOI.VectorAffineFunction{T} in S\n\n\n\n\n\n","category":"type"},{"location":"submodules/Bridges/list_of_bridges/#MathOptInterface.Bridges.Constraint.ToScalarQuadraticBridge","page":"List of bridges","title":"MathOptInterface.Bridges.Constraint.ToScalarQuadraticBridge","text":"ToScalarQuadraticBridge{T,G,S} <: AbstractFunctionConversionBridge{G,S}\n\nToScalarQuadraticBridge implements the following reformulation:\n\ng(x) in S into f(x) in S\n\nwhere g is an abstract scalar function and f is a MOI.ScalarQuadraticFunction.\n\nSource node\n\nToScalarQuadraticBridge supports:\n\nG<:AbstractScalarFunction in S\n\nTarget nodes\n\nToScalarQuadraticBridge creates:\n\nMOI.ScalarQuadraticFunction in S\n\n\n\n\n\n","category":"type"},{"location":"submodules/Bridges/list_of_bridges/#MathOptInterface.Bridges.Constraint.ToVectorQuadraticBridge","page":"List of bridges","title":"MathOptInterface.Bridges.Constraint.ToVectorQuadraticBridge","text":"ToVectorQuadraticBridge{T,G,S} <: AbstractFunctionConversionBridge{G,S}\n\nToVectorQuadraticBridge implements the following reformulation:\n\ng(x) in S into f(x) in S\n\nwhere g is an abstract vector function and f is a MOI.VectorQuadraticFunction.\n\nSource node\n\nToVectorQuadraticBridge supports:\n\nG<:AbstractVectorFunction in S\n\nTarget nodes\n\nToVectorQuadraticBridge creates:\n\nMOI.VectorQuadraticFunction in S\n\n\n\n\n\n","category":"type"},{"location":"submodules/Bridges/list_of_bridges/#MathOptInterface.Bridges.Constraint.ToScalarNonlinearBridge","page":"List of bridges","title":"MathOptInterface.Bridges.Constraint.ToScalarNonlinearBridge","text":"ToScalarNonlinearBridge{T,G,S} <: AbstractFunctionConversionBridge{G,S}\n\nToScalarNonlinearBridge implements the following reformulation:\n\ng(x) in S into f(x) in S\n\nwhere g is an abstract scalar function and f is a MOI.ScalarNonlinearFunction.\n\nSource node\n\nToScalarNonlinearBridge supports:\n\nG<:AbstractScalarFunction in S\n\nTarget nodes\n\nToScalarNonlinearBridge creates:\n\nMOI.ScalarNonlinearFunction in S\n\n\n\n\n\n","category":"type"},{"location":"submodules/Bridges/list_of_bridges/#MathOptInterface.Bridges.Constraint.FunctionConversionBridge","page":"List of bridges","title":"MathOptInterface.Bridges.Constraint.FunctionConversionBridge","text":"FunctionConversionBridge{T,F,G,S} <: AbstractFunctionConversionBridge{G,S}\n\nFunctionConversionBridge implements the following reformulations:\n\ng(x) in S into f(x) in S\n\nfor these pairs of functions:\n\nMOI.ScalarAffineFunctionto [MOI.ScalarQuadraticFunction`](@ref)\nMOI.ScalarQuadraticFunction to MOI.ScalarNonlinearFunction\nMOI.VectorAffineFunction to MOI.VectorQuadraticFunction\n\nSource node\n\nFunctionConversionBridge supports:\n\nG in S\n\nTarget nodes\n\nFunctionConversionBridge creates:\n\nF in S\n\n\n\n\n\n","category":"type"},{"location":"submodules/Bridges/list_of_bridges/#MathOptInterface.Bridges.Constraint.SplitComplexEqualToBridge","page":"List of bridges","title":"MathOptInterface.Bridges.Constraint.SplitComplexEqualToBridge","text":"SplitComplexEqualToBridge{T,F,G} <: Bridges.Constraint.AbstractBridge\n\nSplitComplexEqualToBridge implements the following reformulation:\n\nf(x) + g(x) * im = a + b * im into f(x) = a and g(x) = b\n\nSource node\n\nSplitComplexEqualToBridge supports:\n\nG in MOI.EqualTo{Complex{T}}\n\nwhere G is a function with Complex coefficients.\n\nTarget nodes\n\nSplitComplexEqualToBridge creates:\n\nF in MOI.EqualTo{T}\n\nwhere F is the type of the real/imaginary part of G.\n\n\n\n\n\n","category":"type"},{"location":"submodules/Bridges/list_of_bridges/#MathOptInterface.Bridges.Constraint.SplitComplexZerosBridge","page":"List of bridges","title":"MathOptInterface.Bridges.Constraint.SplitComplexZerosBridge","text":"SplitComplexZerosBridge{T,F,G} <: Bridges.Constraint.AbstractBridge\n\nSplitComplexZerosBridge implements the following reformulation:\n\nf(x) in 0^n into textRe(f(x)) in 0^n and textIm(f(x)) in 0^n\n\nSource node\n\nSplitComplexZerosBridge supports:\n\nG in MOI.Zeros\n\nwhere G is a function with Complex coefficients.\n\nTarget nodes\n\nSplitComplexZerosBridge creates:\n\nF in MOI.Zeros\n\nwhere F is the type of the real/imaginary part of G.\n\n\n\n\n\n","category":"type"},{"location":"submodules/Bridges/list_of_bridges/#MathOptInterface.Bridges.Constraint.SplitHyperRectangleBridge","page":"List of bridges","title":"MathOptInterface.Bridges.Constraint.SplitHyperRectangleBridge","text":"SplitHyperRectangleBridge{T,G,F} <: Bridges.Constraint.AbstractBridge\n\nSplitHyperRectangleBridge implements the following reformulation:\n\nf(x) in textsfHyperRectangle(l u) to f(x) - l u - f(x) in mathbbR_+.\n\nSource node\n\nSplitHyperRectangleBridge supports:\n\nF in MOI.HyperRectangle\n\nTarget nodes\n\nSplitHyperRectangleBridge creates:\n\nG in MOI.Nonnegatives\n\n\n\n\n\n","category":"type"},{"location":"submodules/Bridges/list_of_bridges/#MathOptInterface.Bridges.Constraint.SplitIntervalBridge","page":"List of bridges","title":"MathOptInterface.Bridges.Constraint.SplitIntervalBridge","text":"SplitIntervalBridge{T,F,S,LS,US} <: Bridges.Constraint.AbstractBridge\n\nSplitIntervalBridge implements the following reformulations:\n\nl le f(x) le u into f(x) ge l and f(x) le u\nf(x) = b into f(x) ge b and f(x) le b\nf(x) in 0 into f(x) in mathbbR_+ and f(x) in mathbbR_-\n\nSource node\n\nSplitIntervalBridge supports:\n\nF in MOI.Interval{T}\nF in MOI.EqualTo{T}\nF in MOI.Zeros\n\nTarget nodes\n\nSplitIntervalBridge creates:\n\nF in MOI.LessThan{T}\nF in MOI.GreaterThan{T}\n\nor\n\nF in MOI.Nonnegatives\nF in MOI.Nonpositives\n\nnote: Note\nIf T<:AbstractFloat and S is MOI.Interval{T} then no lower (resp. upper) bound constraint is created if the lower (resp. upper) bound is typemin(T) (resp. typemax(T)). Similarly, when MOI.ConstraintSet is set, a lower or upper bound constraint may be deleted or created accordingly.\n\n\n\n\n\n","category":"type"},{"location":"submodules/Bridges/list_of_bridges/#MathOptInterface.Bridges.Constraint.SOCtoRSOCBridge","page":"List of bridges","title":"MathOptInterface.Bridges.Constraint.SOCtoRSOCBridge","text":"SOCtoRSOCBridge{T,F,G} <: Bridges.Constraint.AbstractBridge\n\nSOCtoRSOCBridge implements the following reformulation:\n\nx_2 le t into (t+x_1)(t-x_1)ge (x_2ldotsx_N)_2^2\n\nAssumptions\n\nSOCtoRSOCBridge assumes that the length of x is at least one.\n\nSource node\n\nSOCtoRSOCBridge supports:\n\nG in MOI.SecondOrderCone\n\nTarget node\n\nSOCtoRSOCBridge creates:\n\nF in MOI.RotatedSecondOrderCone\n\n\n\n\n\n","category":"type"},{"location":"submodules/Bridges/list_of_bridges/#MathOptInterface.Bridges.Constraint.RSOCtoSOCBridge","page":"List of bridges","title":"MathOptInterface.Bridges.Constraint.RSOCtoSOCBridge","text":"RSOCtoSOCBridge{T,F,G} <: Bridges.Constraint.AbstractBridge\n\nRSOCtoSOCBridge implements the following reformulation:\n\nx_2^2 le 2tu into fract - usqrt 2 x_2 le fract + usqrt 2\n\nSource node\n\nRSOCtoSOCBridge supports:\n\nG in MOI.RotatedSecondOrderCone\n\nTarget node\n\nRSOCtoSOCBridge creates:\n\nF in MOI.SecondOrderCone\n\n\n\n\n\n","category":"type"},{"location":"submodules/Bridges/list_of_bridges/#MathOptInterface.Bridges.Constraint.SOCtoNonConvexQuadBridge","page":"List of bridges","title":"MathOptInterface.Bridges.Constraint.SOCtoNonConvexQuadBridge","text":"SOCtoNonConvexQuadBridge{T} <: Bridges.Constraint.AbstractBridge\n\nSOCtoNonConvexQuadBridge implements the following reformulations:\n\nx_2 le t into sum x^2 - t^2 le 0 and 1t + 0 ge 0\n\nThe MOI.ScalarAffineFunction 1t + 0 is used in case the variable has other bound constraints.\n\nwarning: Warning\nThis transformation starts from a convex constraint and creates a non-convex constraint. Unless the solver has explicit support for detecting second-order cones in quadratic form, this may (wrongly) be interpreted by the solver as being non-convex. Therefore, this bridge is not added automatically by MOI.Bridges.full_bridge_optimizer. Care is recommended when adding this bridge to a optimizer.\n\nSource node\n\nSOCtoNonConvexQuadBridge supports:\n\nMOI.VectorOfVariables in MOI.SecondOrderCone\n\nTarget nodes\n\nSOCtoNonConvexQuadBridge creates:\n\nMOI.ScalarQuadraticFunction{T} in MOI.LessThan{T}\nMOI.ScalarAffineFunction{T} in MOI.GreaterThan{T}\n\n\n\n\n\n","category":"type"},{"location":"submodules/Bridges/list_of_bridges/#MathOptInterface.Bridges.Constraint.RSOCtoNonConvexQuadBridge","page":"List of bridges","title":"MathOptInterface.Bridges.Constraint.RSOCtoNonConvexQuadBridge","text":"RSOCtoNonConvexQuadBridge{T} <: Bridges.Constraint.AbstractBridge\n\nRSOCtoNonConvexQuadBridge implements the following reformulations:\n\nx_2^2 le 2tu into sum x^2 - 2tu le 0, 1t + 0 ge 0, and 1u + 0 ge 0.\n\nThe MOI.ScalarAffineFunctions 1t + 0 and 1u + 0 are used in case the variables have other bound constraints.\n\nwarning: Warning\nThis transformation starts from a convex constraint and creates a non-convex constraint. Unless the solver has explicit support for detecting rotated second-order cones in quadratic form, this may (wrongly) be interpreted by the solver as being non-convex. Therefore, this bridge is not added automatically by MOI.Bridges.full_bridge_optimizer. Care is recommended when adding this bridge to a optimizer.\n\nSource node\n\nRSOCtoNonConvexQuadBridge supports:\n\nMOI.VectorOfVariables in MOI.RotatedSecondOrderCone\n\nTarget nodes\n\nRSOCtoNonConvexQuadBridge creates:\n\nMOI.ScalarQuadraticFunction{T} in MOI.LessThan{T}\nMOI.ScalarAffineFunction{T} in MOI.GreaterThan{T}\n\n\n\n\n\n","category":"type"},{"location":"submodules/Bridges/list_of_bridges/#MathOptInterface.Bridges.Constraint.QuadtoSOCBridge","page":"List of bridges","title":"MathOptInterface.Bridges.Constraint.QuadtoSOCBridge","text":"QuadtoSOCBridge{T} <: Bridges.Constraint.AbstractBridge\n\nQuadtoSOCBridge converts quadratic inequalities\n\nfrac12x^T Q x + a^T x le ub\n\ninto MOI.RotatedSecondOrderCone constraints, but it only applies when Q is positive definite.\n\nThis is because, if Q is positive definite, there exists U such that Q = U^T U, and so the inequality can then be rewritten as;\n\nU x_2^2 le 2 (-a^T x + ub)\n\nTherefore, QuadtoSOCBridge implements the following reformulations:\n\nfrac12x^T Q x + a^T x le ub into (1 -a^T x + ub Ux) in RotatedSecondOrderCone where Q = U^T U\nfrac12x^T Q x + a^T x ge lb into (1 a^T x - lb Ux) in RotatedSecondOrderCone where -Q = U^T U\n\nSource node\n\nQuadtoSOCBridge supports:\n\nMOI.ScalarAffineFunction{T} in MOI.LessThan{T}\nMOI.ScalarAffineFunction{T} in MOI.GreaterThan{T}\n\nTarget nodes\n\nRelativeEntropyBridge creates:\n\nMOI.VectorAffineFunction{T} in MOI.RotatedSecondOrderCone\n\nErrors\n\nThis bridge errors if Q is not positive definite.\n\n\n\n\n\n","category":"type"},{"location":"submodules/Bridges/list_of_bridges/#MathOptInterface.Bridges.Constraint.SOCtoPSDBridge","page":"List of bridges","title":"MathOptInterface.Bridges.Constraint.SOCtoPSDBridge","text":"SOCtoPSDBridge{T,F,G} <: Bridges.Constraint.AbstractBridge\n\nSOCtoPSDBridge implements the following reformulation:\n\nx_2 le t into leftbeginarrayc ct x^top x t mathbfIendarrayrightsucceq 0\n\nwarning: Warning\nThis bridge is not added by default by MOI.Bridges.full_bridge_optimizer because bridging second order cone constraints to semidefinite constraints can be achieved by the SOCtoRSOCBridge followed by the RSOCtoPSDBridge, while creating a smaller semidefinite constraint.\n\nSource node\n\nSOCtoPSDBridge supports:\n\nG in MOI.SecondOrderCone\n\nTarget nodes\n\nSOCtoPSDBridge creates:\n\nF in MOI.PositiveSemidefiniteConeTriangle\n\n\n\n\n\n","category":"type"},{"location":"submodules/Bridges/list_of_bridges/#MathOptInterface.Bridges.Constraint.RSOCtoPSDBridge","page":"List of bridges","title":"MathOptInterface.Bridges.Constraint.RSOCtoPSDBridge","text":"RSOCtoPSDBridge{T,F,G} <: Bridges.Constraint.AbstractBridge\n\nRSOCtoPSDBridge implements the following reformulation:\n\nx_2^2 le 2tcdot u into leftbeginarrayc ct x^top x 2tu mathbfIendarrayrightsucceq 0\n\nSource node\n\nRSOCtoPSDBridge supports:\n\nG in MOI.RotatedSecondOrderCone\n\nTarget nodes\n\nRSOCtoPSDBridge creates:\n\nF in MOI.PositiveSemidefiniteConeTriangle\n\n\n\n\n\n","category":"type"},{"location":"submodules/Bridges/list_of_bridges/#MathOptInterface.Bridges.Constraint.NormInfinityBridge","page":"List of bridges","title":"MathOptInterface.Bridges.Constraint.NormInfinityBridge","text":"NormInfinityBridge{T,F,G} <: Bridges.Constraint.AbstractBridge\n\nNormInfinityBridge implements the following reformulation:\n\nx_infty le t into t - x_i t + x_i in mathbbR_+.\n\nSource node\n\nNormInfinityBridge supports:\n\nG in MOI.NormInfinityCone{T}\n\nTarget nodes\n\nNormInfinityBridge creates:\n\nF in MOI.Nonnegatives\n\n\n\n\n\n","category":"type"},{"location":"submodules/Bridges/list_of_bridges/#MathOptInterface.Bridges.Constraint.NormOneBridge","page":"List of bridges","title":"MathOptInterface.Bridges.Constraint.NormOneBridge","text":"NormOneBridge{T,F,G} <: Bridges.Constraint.AbstractBridge\n\nNormOneBridge implements the following reformulation:\n\nsum x_i le t into t - sum y_i y_i - x_i y_i + x_i in mathbbR_+.\n\nSource node\n\nNormOneBridge supports:\n\nG in MOI.NormOneCone{T}\n\nTarget nodes\n\nNormOneBridge creates:\n\nF in MOI.Nonnegatives\n\n\n\n\n\n","category":"type"},{"location":"submodules/Bridges/list_of_bridges/#MathOptInterface.Bridges.Constraint.NormToPowerBridge","page":"List of bridges","title":"MathOptInterface.Bridges.Constraint.NormToPowerBridge","text":"NormToPowerBridge{T,F} <: Bridges.Constraint.AbstractBridge\n\nNormToPowerBridge implements the following reformulation:\n\n(t x) in NormCone(p 1+d) into (r_i t x_i) in PowerCone(1 p) for all i, and sumlimits_i r_i == t.\n\nFor details, see Alizadeh, F., and Goldfarb, D. (2001). \"Second-order cone programming.\" Mathematical Programming, Series B, 95:3-51.\n\nSource node\n\nNormToPowerBridge supports:\n\nF in MOI.NormCone\n\nTarget nodes\n\nNormToPowerBridge creates:\n\nF in MOI.PowerCone{T}\nMOI.ScalarAffineFunction in MOI.EqualTo\n\n\n\n\n\n","category":"type"},{"location":"submodules/Bridges/list_of_bridges/#MathOptInterface.Bridges.Constraint.NormOneConeToNormConeBridge","page":"List of bridges","title":"MathOptInterface.Bridges.Constraint.NormOneConeToNormConeBridge","text":"NormOneConeToNormConeBridge{T,F} <: Bridges.Constraint.AbstractBridge\n\nNormOneConeToNormConeBridge implements the following reformulations:\n\n(t x) in NormOneCone(d) into (t x) in NormCone(1 d)\n\nSource node\n\nNormOneConeToNormConeBridge supports:\n\nF in MOI.NormOneCone\n\nTarget nodes\n\nNormOneConeToNormConeBridge creates:\n\nF in MOI.NormCone\n\n\n\n\n\n","category":"type"},{"location":"submodules/Bridges/list_of_bridges/#MathOptInterface.Bridges.Constraint.SecondOrderConeToNormConeBridge","page":"List of bridges","title":"MathOptInterface.Bridges.Constraint.SecondOrderConeToNormConeBridge","text":"SecondOrderConeToNormConeBridge{T,F} <: Bridges.Constraint.AbstractBridge\n\nSecondOrderConeToNormConeBridge implements the following reformulations:\n\n(t x) in SecondOrderCone(d) into (t x) in NormCone(2 d)\n\nSource node\n\nSecondOrderConeToNormConeBridge supports:\n\nF in MOI.SecondOrderCone\n\nTarget nodes\n\nSecondOrderConeToNormConeBridge creates:\n\nF in MOI.NormCone\n\n\n\n\n\n","category":"type"},{"location":"submodules/Bridges/list_of_bridges/#MathOptInterface.Bridges.Constraint.NormInfinityConeToNormConeBridge","page":"List of bridges","title":"MathOptInterface.Bridges.Constraint.NormInfinityConeToNormConeBridge","text":"NormInfinityConeToNormConeBridge{T,F} <: Bridges.Constraint.AbstractBridge\n\nNormInfinityConeToNormConeBridge implements the following reformulations:\n\n(t x) in NormInfinityCone(d) into (t x) in NormCone(Inf d)\n\nSource node\n\nNormInfinityConeToNormConeBridge supports:\n\nF in MOI.NormInfinityCone\n\nTarget nodes\n\nNormInfinityConeToNormConeBridge creates:\n\nF in MOI.NormCone\n\n\n\n\n\n","category":"type"},{"location":"submodules/Bridges/list_of_bridges/#MathOptInterface.Bridges.Constraint.GeoMeantoRelEntrBridge","page":"List of bridges","title":"MathOptInterface.Bridges.Constraint.GeoMeantoRelEntrBridge","text":"GeoMeantoRelEntrBridge{T,F,G,H} <: Bridges.Constraint.AbstractBridge\n\nGeoMeantoRelEntrBridge implements the following reformulation:\n\n(u w) in GeometricMeanCone into (0 w (u + y)mathbf1)in RelativeEntropyCone and y ge 0\n\nSource node\n\nGeoMeantoRelEntrBridge supports:\n\nH in MOI.GeometricMeanCone\n\nTarget nodes\n\nGeoMeantoRelEntrBridge creates:\n\nG in MOI.RelativeEntropyCone\nF in MOI.Nonnegatives\n\nDerivation\n\nThe derivation of the bridge is as follows:\n\nbeginaligned\n(u w) in GeometricMeanCone iff u le left(prod_i=1^n w_iright)^1n \niff 0 le u + y le left(prod_i=1^n w_iright)^1n y ge 0 \niff 1 le fracleft(prod_i=1^n w_iright)^1nu + y y ge 0 \niff 1 le left(prod_i=1^n fracw_iu + yright)^1n y ge 0 \niff 0 le sum_i=1^n logleft(fracw_iu + yright) y ge 0 \niff 0 ge sum_i=1^n logleft(fracu + yw_iright) y ge 0 \niff 0 ge sum_i=1^n (u + y) logleft(fracu + yw_iright) y ge 0 \niff (0 w (u + y)mathbf1) in RelativeEntropyCone y ge 0 \nendaligned\n\nThis derivation assumes that u + y 0, which is enforced by the relative entropy cone.\n\n\n\n\n\n","category":"type"},{"location":"submodules/Bridges/list_of_bridges/#MathOptInterface.Bridges.Constraint.GeoMeanToPowerBridge","page":"List of bridges","title":"MathOptInterface.Bridges.Constraint.GeoMeanToPowerBridge","text":"GeoMeanToPowerBridge{T,F} <: Bridges.Constraint.AbstractBridge\n\nGeoMeanToPowerBridge implements the following reformulation:\n\n(y x) in GeometricMeanCone(1+d) into (x_1 t y) in PowerCone(1d) and (t x_2 x_d) in GeometricMeanCone(d), which is then recursively expanded into more PowerCone constraints.\n\nSource node\n\nGeoMeanToPowerBridge supports:\n\nF in MOI.GeometricMeanCone\n\nTarget nodes\n\nGeoMeanToPowerBridge creates:\n\nF in MOI.PowerCone{T}\nMOI.VectorOfVariables in MOI.Nonnegatives\n\n\n\n\n\n","category":"type"},{"location":"submodules/Bridges/list_of_bridges/#MathOptInterface.Bridges.Constraint.GeoMeanBridge","page":"List of bridges","title":"MathOptInterface.Bridges.Constraint.GeoMeanBridge","text":"GeoMeanBridge{T,F,G,H} <: Bridges.Constraint.AbstractBridge\n\nGeoMeanBridge implements a reformulation from MOI.GeometricMeanCone into MOI.RotatedSecondOrderCone.\n\nThe reformulation is best described in an example.\n\nConsider the cone of dimension 4:\n\nt le sqrt3x_1 x_2 x_3\n\nThis can be rewritten as exists y ge 0 such that:\n\nbeginalign*\n t le y\n y^4 le x_1 x_2 x_3 y\nendalign*\n\nNote that we need to create y and not use t^4 directly because t is allowed to be negative.\n\nThis is equivalent to:\n\nbeginalign*\n t le fracy_1sqrt4\n y_1^2 le 2y_2 y_3\n y_2^2 le 2x_1 x_2 \n y_3^2 le 2x_3(y_1sqrt4) \n y ge 0\nendalign*\n\nMore generally, you can show how the geometric mean code is recursively expanded into a set of new variables y in MOI.Nonnegatives, a set of MOI.RotatedSecondOrderCone constraints, and a MOI.LessThan constraint between t and y_1.\n\nSource node\n\nGeoMeanBridge supports:\n\nH in MOI.GeometricMeanCone\n\nTarget nodes\n\nGeoMeanBridge creates:\n\nF in MOI.LessThan{T}\nG in MOI.RotatedSecondOrderCone\nG in MOI.Nonnegatives\n\n\n\n\n\n","category":"type"},{"location":"submodules/Bridges/list_of_bridges/#MathOptInterface.Bridges.Constraint.RelativeEntropyBridge","page":"List of bridges","title":"MathOptInterface.Bridges.Constraint.RelativeEntropyBridge","text":"RelativeEntropyBridge{T,F,G,H} <: Bridges.Constraint.AbstractBridge\n\nRelativeEntropyBridge implements the following reformulation that converts a MOI.RelativeEntropyCone into an MOI.ExponentialCone:\n\nu ge sum_i=1^n w_i log left(fracw_iv_iright) into y_i ge 0, u ge sum_i=1^n y_i, and (-y_i w_i v_i) in ExponentialCone.\n\nSource node\n\nRelativeEntropyBridge supports:\n\nH in MOI.RelativeEntropyCone\n\nTarget nodes\n\nRelativeEntropyBridge creates:\n\nF in MOI.GreaterThan{T}\nG in MOI.ExponentialCone\n\n\n\n\n\n","category":"type"},{"location":"submodules/Bridges/list_of_bridges/#MathOptInterface.Bridges.Constraint.NormSpectralBridge","page":"List of bridges","title":"MathOptInterface.Bridges.Constraint.NormSpectralBridge","text":"NormSpectralBridge{T,F,G} <: Bridges.Constraint.AbstractBridge\n\nNormSpectralBridge implements the following reformulation:\n\nt ge sigma_1(X) into leftbeginarrayc ctmathbfI X^top X t mathbfIendarrayright succeq 0\n\nSource node\n\nNormSpectralBridge supports:\n\nG in MOI.NormSpectralCone\n\nTarget nodes\n\nNormSpectralBridge creates:\n\nF in MOI.PositiveSemidefiniteConeTriangle\n\n\n\n\n\n","category":"type"},{"location":"submodules/Bridges/list_of_bridges/#MathOptInterface.Bridges.Constraint.NormNuclearBridge","page":"List of bridges","title":"MathOptInterface.Bridges.Constraint.NormNuclearBridge","text":"NormNuclearBridge{T,F,G,H} <: Bridges.Constraint.AbstractBridge\n\nNormNuclearBridge implements the following reformulation:\n\nt ge sum_i sigma_i (X) into leftbeginarrayc cU X^top X Vendarrayright succeq 0 and 2t ge tr(U) + tr(V).\n\nSource node\n\nNormNuclearBridge supports:\n\nH in MOI.NormNuclearCone\n\nTarget nodes\n\nNormNuclearBridge creates:\n\nF in MOI.GreaterThan{T}\nG in MOI.PositiveSemidefiniteConeTriangle\n\n\n\n\n\n","category":"type"},{"location":"submodules/Bridges/list_of_bridges/#MathOptInterface.Bridges.Constraint.SquareBridge","page":"List of bridges","title":"MathOptInterface.Bridges.Constraint.SquareBridge","text":"SquareBridge{T,F,G,TT,ST} <: Bridges.Constraint.AbstractBridge\n\nSquareBridge implements the following reformulations:\n\n(t u X) in LogDetConeSquare into (t u Y) in LogDetConeTriangle\n(t X) in RootDetConeSquare into (t Y) in RootDetConeTriangle\nX in AbstractSymmetricMatrixSetSquare into Y in AbstractSymmetricMatrixSetTriangle\n\nwhere Y is the upper triangluar component of X.\n\nIn addition, constraints are added as necessary to constrain the matrix X to be symmetric. For example, the constraint for the matrix:\n\nbeginpmatrix\n 1 1 + x 2 - 3x\n 1 + x 2 + x 3 - x\n 2 - 3x 2 + x 2x\nendpmatrix\n\ncan be broken down to the constraint of the symmetric matrix\n\nbeginpmatrix\n 1 1 + x 2 - 3x\n cdot 2 + x 3 - x\n cdot cdot 2x\nendpmatrix\n\nand the equality constraint between the off-diagonal entries (2, 3) and (3, 2) 3 - x == 2 + x. Note that no symmetrization constraint needs to be added between the off-diagonal entries (1, 2) and (2, 1) or between (1, 3) and (3, 1) because the expressions are the same.\n\nSource node\n\nSquareBridge supports:\n\nF in ST\n\nTarget nodes\n\nSquareBridge creates:\n\nG in TT\n\n\n\n\n\n","category":"type"},{"location":"submodules/Bridges/list_of_bridges/#MathOptInterface.Bridges.Constraint.HermitianToSymmetricPSDBridge","page":"List of bridges","title":"MathOptInterface.Bridges.Constraint.HermitianToSymmetricPSDBridge","text":"HermitianToSymmetricPSDBridge{T,F,G} <: Bridges.Constraint.AbstractBridge\n\nHermitianToSymmetricPSDBridge implements the following reformulation:\n\nHermitian positive semidefinite n x n complex matrix to a symmetric positive semidefinite 2n x 2n real matrix.\n\nSee also MOI.Bridges.Variable.HermitianToSymmetricPSDBridge.\n\nSource node\n\nHermitianToSymmetricPSDBridge supports:\n\nG in MOI.HermitianPositiveSemidefiniteConeTriangle\n\nTarget node\n\nHermitianToSymmetricPSDBridge creates:\n\nF in MOI.PositiveSemidefiniteConeTriangle\n\nReformulation\n\nThe reformulation is best described by example.\n\nThe Hermitian matrix:\n\nbeginbmatrix\n x_11 x_12 + y_12im x_13 + y_13im\n x_12 - y_12im x_22 x_23 + y_23im\n x_13 - y_13im x_23 - y_23im x_33\nendbmatrix\n\nis positive semidefinite if and only if the symmetric matrix:\n\nbeginbmatrix\n x_11 x_12 x_13 0 y_12 y_13 \n x_22 x_23 -y_12 0 y_23 \n x_33 -y_13 -y_23 0 \n x_11 x_12 x_13 \n x_22 x_23 \n x_33\nendbmatrix\n\nis positive semidefinite.\n\nThe bridge achieves this reformulation by constraining the above matrix to belong to the MOI.PositiveSemidefiniteConeTriangle(6).\n\n\n\n\n\n","category":"type"},{"location":"submodules/Bridges/list_of_bridges/#MathOptInterface.Bridges.Constraint.SetDotScalingBridge","page":"List of bridges","title":"MathOptInterface.Bridges.Constraint.SetDotScalingBridge","text":"SetDotScalingBridge{T,S,F,G} <: Bridges.Constraint.AbstractBridge\n\nSetDotScalingBridge implements the reformulation from constraints in S to constraints in MOI.Scaled{S}.\n\nSource node\n\nSetDotScalingBridge supports:\n\nG in S\n\nTarget node\n\nSetDotScalingBridge creates:\n\nF in MOI.Scaled{S}\n\n\n\n\n\n","category":"type"},{"location":"submodules/Bridges/list_of_bridges/#MathOptInterface.Bridges.Constraint.SetDotInverseScalingBridge","page":"List of bridges","title":"MathOptInterface.Bridges.Constraint.SetDotInverseScalingBridge","text":"SetDotInverseScalingBridge{T,S,F,G} <: Bridges.Constraint.AbstractBridge\n\nSetDotInverseScalingBridge implements the reformulation from constraints in the MOI.Scaled{S} to constraints in the S.\n\nSource node\n\nSetDotInverseScalingBridge supports:\n\nG in MOI.Scaled{S}\n\nTarget node\n\nSetDotInverseScalingBridge creates:\n\nF in S\n\n\n\n\n\n","category":"type"},{"location":"submodules/Bridges/list_of_bridges/#MathOptInterface.Bridges.Constraint.RootDetBridge","page":"List of bridges","title":"MathOptInterface.Bridges.Constraint.RootDetBridge","text":"RootDetBridge{T,F,G,H} <: Bridges.Constraint.AbstractBridge\n\nThe MOI.RootDetConeTriangle is representable by MOI.PositiveSemidefiniteConeTriangle and MOI.GeometricMeanCone constraints, see [1, p. 149].\n\nIndeed, t le det(X)^1n if and only if there exists a lower triangular matrix Δ such that:\n\nbeginalign*\n beginpmatrix\n X Δ\n Δ^top mathrmDiag(Δ)\n endpmatrix succeq 0\n (t mathrmDiag(Δ)) in GeometricMeanCone\nendalign*\n\nSource node\n\nRootDetBridge supports:\n\nI in MOI.RootDetConeTriangle\n\nTarget nodes\n\nRootDetBridge creates:\n\nF in MOI.PositiveSemidefiniteConeTriangle\nG in MOI.GeometricMeanCone\n\n[1] Ben-Tal, Aharon, and Arkadi Nemirovski. Lectures on modern convex optimization: analysis, algorithms, and engineering applications. Society for Industrial and Applied Mathematics, 2001.\n\n\n\n\n\n","category":"type"},{"location":"submodules/Bridges/list_of_bridges/#MathOptInterface.Bridges.Constraint.LogDetBridge","page":"List of bridges","title":"MathOptInterface.Bridges.Constraint.LogDetBridge","text":"LogDetBridge{T,F,G,H,I} <: Bridges.Constraint.AbstractBridge\n\nThe MOI.LogDetConeTriangle is representable by MOI.PositiveSemidefiniteConeTriangle and MOI.ExponentialCone constraints.\n\nIndeed, logdet(X) = sumlimits_i=1^n log(delta_i) where delta_i are the eigenvalues of X.\n\nAdapting the method from [1, p. 149], we see that t le u log(det(Xu)) for u 0 if and only if there exists a lower triangular matrix Δ such that\n\nbeginalign*\n beginpmatrix\n X Δ\n Δ^top mathrmDiag(Δ)\n endpmatrix succeq 0\n t - sum_i=1^n u logleft(fracΔ_iiuright) le 0\nendalign*\n\nWhich we reformulate further into\n\nbeginalign*\n beginpmatrix\n X Δ\n Δ^top mathrmDiag(Δ)\n endpmatrix succeq 0\n (l_i u Δ_ii) in ExponentialConequad forall i \n t - sum_i=1^n l_i le 0\nendalign*\n\nSource node\n\nLogDetBridge supports:\n\nI in MOI.LogDetConeTriangle\n\nTarget nodes\n\nLogDetBridge creates:\n\nF in MOI.PositiveSemidefiniteConeTriangle\nG in MOI.ExponentialCone\nH in MOI.LessThan{T}\n\n[1] Ben-Tal, Aharon, and Arkadi Nemirovski. Lectures on modern convex optimization: analysis, algorithms, and engineering applications. Society for Industrial and Applied Mathematics, 2001.\n\n\n\n\n\n","category":"type"},{"location":"submodules/Bridges/list_of_bridges/#MathOptInterface.Bridges.Constraint.IndicatorActiveOnFalseBridge","page":"List of bridges","title":"MathOptInterface.Bridges.Constraint.IndicatorActiveOnFalseBridge","text":"IndicatorActiveOnFalseBridge{T,F,S} <: Bridges.Constraint.AbstractBridge\n\nIndicatorActiveOnFalseBridge implements the following reformulation:\n\nneg z implies f(x) in S into y implies f(x) in S, z + y = 1, and y in 0 1\n\nSource node\n\nIndicatorActiveOnFalseBridge supports:\n\nMOI.VectorAffineFunction{T} in MOI.Indicator{MOI.ACTIVATE_ON_ZERO,S}\n\nTarget nodes\n\nIndicatorActiveOnFalseBridge creates:\n\nMOI.VectorAffineFunction{T} in MOI.Indicator{MOI.ACTIVATE_ON_ONE,S}\nMOI.ScalarAffineFunction{T} in MOI.EqualTo\nMOI.VariableIndex in MOI.ZeroOne\n\n\n\n\n\n","category":"type"},{"location":"submodules/Bridges/list_of_bridges/#MathOptInterface.Bridges.Constraint.IndicatorGreaterToLessThanBridge","page":"List of bridges","title":"MathOptInterface.Bridges.Constraint.IndicatorGreaterToLessThanBridge","text":"IndicatorGreaterToLessThanBridge{T,A} <: Bridges.Constraint.AbstractBridge\n\nIndicatorGreaterToLessThanBridge implements the following reformulation:\n\nz implies f(x) ge l into z implies -f(x) le -l\n\nSource node\n\nIndicatorGreaterToLessThanBridge supports:\n\nMOI.VectorAffineFunction{T} in MOI.Indicator{A,MOI.GreaterThan{T}}\n\nTarget nodes\n\nIndicatorGreaterToLessThanBridge creates:\n\nMOI.VectorAffineFunction{T} in MOI.Indicator{A,MOI.LessThan{T}}\n\n\n\n\n\n","category":"type"},{"location":"submodules/Bridges/list_of_bridges/#MathOptInterface.Bridges.Constraint.IndicatorLessToGreaterThanBridge","page":"List of bridges","title":"MathOptInterface.Bridges.Constraint.IndicatorLessToGreaterThanBridge","text":"IndicatorLessToGreaterThanBridge{T,A} <: Bridges.Constraint.AbstractBridge\n\nIndicatorLessToGreaterThanBridge implements the following reformulations:\n\nz implies f(x) le u into z implies -f(x) ge -u\n\nSource node\n\nIndicatorLessToGreaterThanBridge supports:\n\nMOI.VectorAffineFunction{T} in MOI.Indicator{A,MOI.LessThan{T}}\n\nTarget nodes\n\nIndicatorLessToGreaterThanBridge creates:\n\nMOI.VectorAffineFunction{T} in MOI.Indicator{A,MOI.GreaterThan{T}}\n\n\n\n\n\n","category":"type"},{"location":"submodules/Bridges/list_of_bridges/#MathOptInterface.Bridges.Constraint.IndicatorSOS1Bridge","page":"List of bridges","title":"MathOptInterface.Bridges.Constraint.IndicatorSOS1Bridge","text":"IndicatorSOS1Bridge{T,S} <: Bridges.Constraint.AbstractBridge\n\nIndicatorSOS1Bridge implements the following reformulation:\n\nz implies f(x) in S into f(x) + y in S, SOS1(y z)\n\nwarning: Warning\nThis bridge assumes that the solver supports MOI.SOS1{T} constraints in which one of the variables (y) is continuous.\n\nSource node\n\nIndicatorSOS1Bridge supports:\n\nMOI.VectorAffineFunction{T} in MOI.Indicator{MOI.ACTIVATE_ON_ONE,S}\n\nTarget nodes\n\nIndicatorSOS1Bridge creates:\n\nMOI.ScalarAffineFunction{T} in S\nMOI.VectorOfVariables in MOI.SOS1{T}\n\n\n\n\n\n","category":"type"},{"location":"submodules/Bridges/list_of_bridges/#MathOptInterface.Bridges.Constraint.SemiToBinaryBridge","page":"List of bridges","title":"MathOptInterface.Bridges.Constraint.SemiToBinaryBridge","text":"SemiToBinaryBridge{T,S} <: Bridges.Constraint.AbstractBridge\n\nSemiToBinaryBridge implements the following reformulations:\n\nx in 0 cup l u into\nbeginaligned\nx leq z u \nx geq z l \nz in 0 1\nendaligned\nx in 0 cup l ldots u into\nbeginaligned\nx leq z u \nx geq z l \nz in 0 1 \nx in mathbbZ\nendaligned\n\nSource node\n\nSemiToBinaryBridge supports:\n\nMOI.VariableIndex in MOI.Semicontinuous{T}\nMOI.VariableIndex in MOI.Semiinteger{T}\n\nTarget nodes\n\nSemiToBinaryBridge creates:\n\nMOI.VariableIndex in MOI.ZeroOne\nMOI.ScalarAffineFunction{T} in MOI.LessThan{T}\nMOI.ScalarAffineFunction{T} in MOI.GreaterThan{T}\nMOI.VariableIndex{T} in MOI.Integer (if S is MOI.Semiinteger{T}\n\n\n\n\n\n","category":"type"},{"location":"submodules/Bridges/list_of_bridges/#MathOptInterface.Bridges.Constraint.ZeroOneBridge","page":"List of bridges","title":"MathOptInterface.Bridges.Constraint.ZeroOneBridge","text":"ZeroOneBridge{T} <: Bridges.Constraint.AbstractBridge\n\nZeroOneBridge implements the following reformulation:\n\nx in 0 1 into x in mathbbZ, 1x in 0 1.\n\nnote: Note\nZeroOneBridge adds a linear constraint instead of adding variable bounds to avoid conflicting with bounds set by the user.\n\nSource node\n\nZeroOneBridge supports:\n\nMOI.VariableIndex in MOI.ZeroOne\n\nTarget nodes\n\nZeroOneBridge creates:\n\nMOI.VariableIndex in MOI.Integer\nMOI.ScalarAffineFunction{T} in MOI.Interval{T}\n\n\n\n\n\n","category":"type"},{"location":"submodules/Bridges/list_of_bridges/#MathOptInterface.Bridges.Constraint.IntegerToZeroOneBridge","page":"List of bridges","title":"MathOptInterface.Bridges.Constraint.IntegerToZeroOneBridge","text":"IntegerToZeroOneBridge{T} <: Bridges.Constraint.AbstractBridge\n\nIntegerToZeroOneBridge implements the following reformulation:\n\nx in mathbfZ into y_i in 0 1, x == lb + sum 2^i-1 y_i.\n\nSource node\n\nIntegerToZeroOneBridge supports:\n\nVariableIndex in MOI.Integer\n\nTarget nodes\n\nIntegerToZeroOneBridge creates:\n\nMOI.VariableIndex in MOI.ZeroOne\nMOI.ScalarAffineFunction{T} in MOI.EqualTo{T}\n\nDeveloper note\n\nThis bridge is implemented as a constraint bridge instead of a variable bridge because we don't want to substitute the linear combination of y for every instance of x. Doing so would be expensive and greatly reduce the sparsity of the constraints.\n\n\n\n\n\n","category":"type"},{"location":"submodules/Bridges/list_of_bridges/#MathOptInterface.Bridges.Constraint.NumberConversionBridge","page":"List of bridges","title":"MathOptInterface.Bridges.Constraint.NumberConversionBridge","text":"NumberConversionBridge{T,F1,S1,F2,S2} <: Bridges.Constraint.AbstractBridge\n\nNumberConversionBridge implements the following reformulation:\n\nf1(x) in S1 to f2(x) in S2\n\nwhere f and S are the same functional form, but differ in their coefficient type.\n\nSource node\n\nNumberConversionBridge supports:\n\nF1 in S1\n\nTarget node\n\nNumberConversionBridge creates:\n\nF2 in S2\n\n\n\n\n\n","category":"type"},{"location":"submodules/Bridges/list_of_bridges/#MathOptInterface.Bridges.Constraint.AllDifferentToCountDistinctBridge","page":"List of bridges","title":"MathOptInterface.Bridges.Constraint.AllDifferentToCountDistinctBridge","text":"AllDifferentToCountDistinctBridge{T,F} <: Bridges.Constraint.AbstractBridge\n\nAllDifferentToCountDistinctBridge implements the following reformulations:\n\nx in textsfAllDifferent(d) to (n x) in textsfCountDistinct(1+d) and n = d\nf(x) in textsfAllDifferent(d) to (d f(x)) in textsfCountDistinct(1+d)\n\nSource node\n\nAllDifferentToCountDistinctBridge supports:\n\nF in MOI.AllDifferent\n\nwhere F is MOI.VectorOfVariables or MOI.VectorAffineFunction{T}.\n\nTarget nodes\n\nAllDifferentToCountDistinctBridge creates:\n\nF in MOI.CountDistinct\nMOI.VariableIndex in MOI.EqualTo{T}\n\n\n\n\n\n","category":"type"},{"location":"submodules/Bridges/list_of_bridges/#MathOptInterface.Bridges.Constraint.ReifiedAllDifferentToCountDistinctBridge","page":"List of bridges","title":"MathOptInterface.Bridges.Constraint.ReifiedAllDifferentToCountDistinctBridge","text":"ReifiedAllDifferentToCountDistinctBridge{T,F} <:\nBridges.Constraint.AbstractBridge\n\nReifiedAllDifferentToCountDistinctBridge implements the following reformulations:\n\nr iff x in textsfAllDifferent(d) to r iff (n x) in textsfCountDistinct(1+d) and n = d\nr iff f(x) in textsfAllDifferent(d) to r iff (d f(x)) in textsfCountDistinct(1+d)\n\nSource node\n\nReifiedAllDifferentToCountDistinctBridge supports:\n\nF in MOI.Reified{MOI.AllDifferent}\n\nwhere F is MOI.VectorOfVariables or MOI.VectorAffineFunction{T}.\n\nTarget nodes\n\nReifiedAllDifferentToCountDistinctBridge creates:\n\nF in MOI.Reified{MOI.CountDistinct}\nMOI.VariableIndex in MOI.EqualTo{T}\n\n\n\n\n\n","category":"type"},{"location":"submodules/Bridges/list_of_bridges/#MathOptInterface.Bridges.Constraint.BinPackingToMILPBridge","page":"List of bridges","title":"MathOptInterface.Bridges.Constraint.BinPackingToMILPBridge","text":"BinPackingToMILPBridge{T,F} <: Bridges.Constraint.AbstractBridge\n\nBinPackingToMILPBridge implements the following reformulation:\n\nx in BinPacking(c w) into a mixed-integer linear program.\n\nReformulation\n\nThe reformulation is non-trivial, and it depends on the finite domain of each variable x_i, which we as define S_i = l_ildotsu_i.\n\nFirst, we introduce new binary variables z_ij, which are 1 if variable x_i takes the value j in the optimal solution and 0 otherwise:\n\nbeginaligned\nz_ij in 0 1 forall i in 1ldots d j in S_i \nx_i - sumlimits_jin S_i j cdot z_ij = 0 forall i in 1ldots d \nsumlimits_jin S_i z_ij = 1 forall i in 1ldots d \nendaligned\n\nThen, we add the capacity constraint for all possible bins j:\n\nsumlimits_i w_i z_ij le c forall j in bigcup_i=1ldotsd S_i\n\nSource node\n\nBinPackingToMILPBridge supports:\n\nF in MOI.BinPacking{T}\n\nTarget nodes\n\nBinPackingToMILPBridge creates:\n\nMOI.VariableIndex in MOI.ZeroOne\nMOI.ScalarAffineFunction{T} in MOI.EqualTo{T}\nMOI.ScalarAffineFunction{T} in MOI.LessThan{T}\n\n\n\n\n\n","category":"type"},{"location":"submodules/Bridges/list_of_bridges/#MathOptInterface.Bridges.Constraint.CircuitToMILPBridge","page":"List of bridges","title":"MathOptInterface.Bridges.Constraint.CircuitToMILPBridge","text":"CircuitToMILPBridge{T,F} <: Bridges.Constraint.AbstractBridge\n\nCircuitToMILPBridge implements the following reformulation:\n\nx in textsfCircuit(d) to the Miller-Tucker-Zemlin formulation of the Traveling Salesperson Problem.\n\nSource node\n\nCircuitToMILPBridge supports:\n\nF in MOI.Circuit\n\nwhere F is MOI.VectorOfVariables or MOI.VectorAffineFunction{T}.\n\nTarget nodes\n\nCircuitToMILPBridge creates:\n\nMOI.VariableIndex in MOI.ZeroOne\nMOI.VariableIndex in MOI.Integer\nMOI.VariableIndex in MOI.Interval{T}\nMOI.ScalarAffineFunction{T} in MOI.EqualTo{T}\nMOI.ScalarAffineFunction{T} in MOI.LessThan{T}\n\n\n\n\n\n","category":"type"},{"location":"submodules/Bridges/list_of_bridges/#MathOptInterface.Bridges.Constraint.CountAtLeastToCountBelongsBridge","page":"List of bridges","title":"MathOptInterface.Bridges.Constraint.CountAtLeastToCountBelongsBridge","text":"CountAtLeastToCountBelongsBridge{T,F} <: Bridges.Constraint.AbstractBridge\n\nCountAtLeastToCountBelongsBridge implements the following reformulation:\n\nx in textsfCountAtLeast(n d mathcalS) to (n_i x_d_i) in textsfCountBelongs(1+d mathcalS) and n_i ge n for all i.\n\nSource node\n\nCountAtLeastToCountBelongsBridge supports:\n\nF in MOI.CountAtLeast\n\nwhere F is MOI.VectorOfVariables or MOI.VectorAffineFunction{T}.\n\nTarget nodes\n\nCountAtLeastToCountBelongsBridge creates:\n\nF in MOI.CountBelongs\nMOI.VariableIndex in MOI.GreaterThan{T}\n\n\n\n\n\n","category":"type"},{"location":"submodules/Bridges/list_of_bridges/#MathOptInterface.Bridges.Constraint.CountBelongsToMILPBridge","page":"List of bridges","title":"MathOptInterface.Bridges.Constraint.CountBelongsToMILPBridge","text":"CountBelongsToMILPBridge{T,F} <: Bridges.Constraint.AbstractBridge\n\nCountBelongsToMILPBridge implements the following reformulation:\n\n(n x) in textsfCountBelongs(1+d mathcalS) into a mixed-integer linear program.\n\nReformulation\n\nThe reformulation is non-trivial, and it depends on the finite domain of each variable x_i, which we as define S_i = l_ildotsu_i.\n\nFirst, we introduce new binary variables z_ij, which are 1 if variable x_i takes the value j in the optimal solution and 0 otherwise:\n\nbeginaligned\nz_ij in 0 1 forall i in 1ldots d j in S_i \nx_i - sumlimits_jin S_i j cdot z_ij = 0 forall i in 1ldots d \nsumlimits_jin S_i z_ij = 1 forall i in 1ldots d \nendaligned\n\nFinally, n is constrained to be the number of z_ij elements that are in mathcalS:\n\nn - sumlimits_iin 1ldots d j in mathcalS z_ij = 0\n\nSource node\n\nCountBelongsToMILPBridge supports:\n\nF in MOI.CountBelongs\n\nwhere F is MOI.VectorOfVariables or MOI.VectorAffineFunction{T}.\n\nTarget nodes\n\nCountBelongsToMILPBridge creates:\n\nMOI.VariableIndex in MOI.ZeroOne\nMOI.ScalarAffineFunction{T} in MOI.EqualTo{T}\n\n\n\n\n\n","category":"type"},{"location":"submodules/Bridges/list_of_bridges/#MathOptInterface.Bridges.Constraint.CountDistinctToMILPBridge","page":"List of bridges","title":"MathOptInterface.Bridges.Constraint.CountDistinctToMILPBridge","text":"CountDistinctToMILPBridge{T,F} <: Bridges.Constraint.AbstractBridge\n\nCountDistinctToMILPBridge implements the following reformulation:\n\n(n x) in textsfCountDistinct(1+d) into a mixed-integer linear program.\n\nReformulation\n\nThe reformulation is non-trivial, and it depends on the finite domain of each variable x_i, which we as define S_i = l_ildotsu_i.\n\nFirst, we introduce new binary variables z_ij, which are 1 if variable x_i takes the value j in the optimal solution and 0 otherwise:\n\nbeginaligned\nz_ij in 0 1 forall i in 1ldots d j in S_i \nx_i - sumlimits_jin S_i j cdot z_ij = 0 forall i in 1ldots d \nsumlimits_jin S_i z_ij = 1 forall i in 1ldots d \nendaligned\n\nThen, we introduce new binary variables y_j, which are 1 if a variable takes the value j in the optimal solution and 0 otherwise.\n\nbeginaligned\ny_j in 0 1 forall j in bigcup_i=1ldotsd S_i \ny_j le sumlimits_i in 1ldots d j in S_i z_ij le M y_j forall j in bigcup_i=1ldotsd S_i\nendaligned\n\nFinally, n is constrained to be the number of y_j elements that are non-zero:\n\nn - sumlimits_j in bigcup_i=1ldotsd S_i y_j = 0\n\nSource node\n\nCountDistinctToMILPBridge supports:\n\nF in MOI.CountDistinct\n\nwhere F is MOI.VectorOfVariables or MOI.VectorAffineFunction{T}.\n\nTarget nodes\n\nCountDistinctToMILPBridge creates:\n\nMOI.VariableIndex in MOI.ZeroOne\nMOI.ScalarAffineFunction{T} in MOI.EqualTo{T}\nMOI.ScalarAffineFunction{T} in MOI.LessThan{T}\n\n\n\n\n\n","category":"type"},{"location":"submodules/Bridges/list_of_bridges/#MathOptInterface.Bridges.Constraint.ReifiedCountDistinctToMILPBridge","page":"List of bridges","title":"MathOptInterface.Bridges.Constraint.ReifiedCountDistinctToMILPBridge","text":"ReifiedCountDistinctToMILPBridge{T,F} <: Bridges.Constraint.AbstractBridge\n\nReifiedCountDistinctToMILPBridge implements the following reformulation:\n\nr iff (n x) in textsfCountDistinct(1+d) into a mixed-integer linear program.\n\nReformulation\n\nThe reformulation is non-trivial, and it depends on the finite domain of each variable x_i, which we as define S_i = l_ildotsu_i.\n\nFirst, we introduce new binary variables z_ij, which are 1 if variable x_i takes the value j in the optimal solution and 0 otherwise:\n\nbeginaligned\nz_ij in 0 1 forall i in 1ldots d j in S_i \nx_i - sumlimits_jin S_i j cdot z_ij = 0 forall i in 1ldots d \nsumlimits_jin S_i z_ij = 1 forall i in 1ldots d \nendaligned\n\nThen, we introduce new binary variables y_j, which are 1 if a variable takes the value j in the optimal solution and 0 otherwise.\n\nbeginaligned\ny_j in 0 1 forall j in bigcup_i=1ldotsd S_i \ny_j le sumlimits_i in 1ldots d j in S_i z_ij le M y_j forall j in bigcup_i=1ldotsd S_i\nendaligned\n\nFinally, n is constrained to be the number of y_j elements that are non-zero, with some slack:\n\nn - sumlimits_j in bigcup_i=1ldotsd S_i y_j = delta^+ - delta^-\n\nAnd then the slack is constrained to respect the reif variable r:\n\nbeginaligned\nd_1 le delta^+ le M d_1 \nd_2 le delta^- le M d_s \nd_1 + d_2 + r = 1 \nd_1 d_2 in 0 1\nendaligned\n\nSource node\n\nReifiedCountDistinctToMILPBridge supports:\n\nF in MOI.Reified{MOI.CountDistinct}\n\nwhere F is MOI.VectorOfVariables or MOI.VectorAffineFunction{T}.\n\nTarget nodes\n\nReifiedCountDistinctToMILPBridge creates:\n\nMOI.VariableIndex in MOI.ZeroOne\nMOI.ScalarAffineFunction{T} in MOI.EqualTo{T}\nMOI.ScalarAffineFunction{T} in MOI.LessThan{T}\n\n\n\n\n\n","category":"type"},{"location":"submodules/Bridges/list_of_bridges/#MathOptInterface.Bridges.Constraint.CountGreaterThanToMILPBridge","page":"List of bridges","title":"MathOptInterface.Bridges.Constraint.CountGreaterThanToMILPBridge","text":"CountGreaterThanToMILPBridge{T,F} <: Bridges.Constraint.AbstractBridge\n\nCountGreaterThanToMILPBridge implements the following reformulation:\n\n(c y x) in CountGreaterThan() into a mixed-integer linear program.\n\nSource node\n\nCountGreaterThanToMILPBridge supports:\n\nF in MOI.CountGreaterThan\n\nTarget nodes\n\nCountGreaterThanToMILPBridge creates:\n\nMOI.VariableIndex in MOI.ZeroOne\nMOI.ScalarAffineFunction{T} in MOI.EqualTo{T}\nMOI.ScalarAffineFunction{T} in MOI.GreaterThan{T}\n\n\n\n\n\n","category":"type"},{"location":"submodules/Bridges/list_of_bridges/#MathOptInterface.Bridges.Constraint.TableToMILPBridge","page":"List of bridges","title":"MathOptInterface.Bridges.Constraint.TableToMILPBridge","text":"TableToMILPBridge{T,F} <: Bridges.Constraint.AbstractBridge\n\nTableToMILPBridge implements the following reformulation:\n\nx in Table(t) into\nbeginaligned\nz_j in 0 1 quad forall i j \nsumlimits_j=1^n z_j = 1 \nsumlimits_j=1^n t_ij z_j = x_i quad forall i\nendaligned\n\nSource node\n\nTableToMILPBridge supports:\n\nF in MOI.Table{T}\n\nTarget nodes\n\nTableToMILPBridge creates:\n\nMOI.VariableIndex in MOI.ZeroOne\nMOI.ScalarAffineFunction{T} in MOI.EqualTo{T}\n\n\n\n\n\n","category":"type"},{"location":"submodules/Bridges/list_of_bridges/#objective_bridges_ref","page":"List of bridges","title":"Objective bridges","text":"","category":"section"},{"location":"submodules/Bridges/list_of_bridges/","page":"List of bridges","title":"List of bridges","text":"These bridges are subtypes of Bridges.Objective.AbstractBridge.","category":"page"},{"location":"submodules/Bridges/list_of_bridges/","page":"List of bridges","title":"List of bridges","text":"Bridges.Objective.FunctionizeBridge\nBridges.Objective.QuadratizeBridge\nBridges.Objective.SlackBridge\nBridges.Objective.VectorFunctionizeBridge\nBridges.Objective.VectorSlackBridge","category":"page"},{"location":"submodules/Bridges/list_of_bridges/#MathOptInterface.Bridges.Objective.FunctionizeBridge","page":"List of bridges","title":"MathOptInterface.Bridges.Objective.FunctionizeBridge","text":"FunctionizeBridge{T}\n\nFunctionizeBridge implements the following reformulations:\n\nmin x into min1x + 0\nmax x into max1x + 0\n\nwhere T is the coefficient type of 1 and 0.\n\nSource node\n\nFunctionizeBridge supports:\n\nMOI.ObjectiveFunction{MOI.VariableIndex}\n\nTarget nodes\n\nFunctionizeBridge creates:\n\nOne objective node: MOI.ObjectiveFunction{MOI.ScalarAffineFunction{T}}\n\n\n\n\n\n","category":"type"},{"location":"submodules/Bridges/list_of_bridges/#MathOptInterface.Bridges.Objective.QuadratizeBridge","page":"List of bridges","title":"MathOptInterface.Bridges.Objective.QuadratizeBridge","text":"QuadratizeBridge{T}\n\nQuadratizeBridge implements the following reformulations:\n\nmin a^top x + b into minx^top mathbf0 x + a^top x + b\nmax a^top x + b into maxx^top mathbf0 x + a^top x + b\n\nwhere T is the coefficient type of 0.\n\nSource node\n\nQuadratizeBridge supports:\n\nMOI.ObjectiveFunction{MOI.ScalarAffineFunction{T}}\n\nTarget nodes\n\nQuadratizeBridge creates:\n\nOne objective node: MOI.ObjectiveFunction{MOI.ScalarQuadraticFunction{T}}\n\n\n\n\n\n","category":"type"},{"location":"submodules/Bridges/list_of_bridges/#MathOptInterface.Bridges.Objective.SlackBridge","page":"List of bridges","title":"MathOptInterface.Bridges.Objective.SlackBridge","text":"SlackBridge{T,F,G}\n\nSlackBridge implements the following reformulations:\n\nminf(x) into miny f(x) - y le 0\nmaxf(x) into maxy f(x) - y ge 0\n\nwhere F is the type of f(x) - y, G is the type of f(x), and T is the coefficient type of f(x).\n\nSource node\n\nSlackBridge supports:\n\nMOI.ObjectiveFunction{G}\n\nTarget nodes\n\nSlackBridge creates:\n\nOne variable node: MOI.VariableIndex in MOI.Reals\nOne objective node: MOI.ObjectiveFunction{MOI.VariableIndex}\nOne constraint node, that depends on the MOI.ObjectiveSense:\nF-in-MOI.LessThan if MIN_SENSE\nF-in-MOI.GreaterThan if MAX_SENSE\n\nwarning: Warning\nWhen using this bridge, changing the optimization sense is not supported. Set the sense to MOI.FEASIBILITY_SENSE first to delete the bridge, then set MOI.ObjectiveSense and re-add the objective.\n\n\n\n\n\n","category":"type"},{"location":"submodules/Bridges/list_of_bridges/#MathOptInterface.Bridges.Objective.VectorFunctionizeBridge","page":"List of bridges","title":"MathOptInterface.Bridges.Objective.VectorFunctionizeBridge","text":"VectorFunctionizeBridge{T}\n\nVectorFunctionizeBridge implements the following reformulations:\n\nmin x into min1x + 0\nmax x into max1x + 0\n\nwhere T is the coefficient type of 1 and 0.\n\nSource node\n\nVectorFunctionizeBridge supports:\n\nMOI.ObjectiveFunction{MOI.VectorOfVariables}\n\nTarget nodes\n\nVectorFunctionizeBridge creates:\n\nOne objective node: MOI.ObjectiveFunction{MOI.VectorAffineFunction{T}}\n\n\n\n\n\n","category":"type"},{"location":"submodules/Bridges/list_of_bridges/#MathOptInterface.Bridges.Objective.VectorSlackBridge","page":"List of bridges","title":"MathOptInterface.Bridges.Objective.VectorSlackBridge","text":"VectorSlackBridge{T,F,G}\n\nVectorSlackBridge implements the following reformulations:\n\nminf(x) into miny y - f(x) in mathbbR_+ \nmaxf(x) into maxy f(x) - y in mathbbR_+ \n\nwhere F is the type of f(x) - y, G is the type of f(x), and T is the coefficient type of f(x).\n\nSource node\n\nVectorSlackBridge supports:\n\nMOI.ObjectiveFunction{G}\n\nTarget nodes\n\nVectorSlackBridge creates:\n\nOne variable node: MOI.VectorOfVariables in MOI.Reals\nOne objective node: MOI.ObjectiveFunction{MOI.VectorOfVariables}\nOne constraint node: F-in-MOI.Nonnegatives\n\nwarning: Warning\nWhen using this bridge, changing the optimization sense is not supported. Set the sense to MOI.FEASIBILITY_SENSE first to delete the bridge, then set MOI.ObjectiveSense and re-add the objective.\n\n\n\n\n\n","category":"type"},{"location":"submodules/Bridges/list_of_bridges/#variable_bridges_ref","page":"List of bridges","title":"Variable bridges","text":"","category":"section"},{"location":"submodules/Bridges/list_of_bridges/","page":"List of bridges","title":"List of bridges","text":"These bridges are subtypes of Bridges.Variable.AbstractBridge.","category":"page"},{"location":"submodules/Bridges/list_of_bridges/","page":"List of bridges","title":"List of bridges","text":"Bridges.Variable.FreeBridge\nBridges.Variable.NonposToNonnegBridge\nBridges.Variable.RSOCtoPSDBridge\nBridges.Variable.RSOCtoSOCBridge\nBridges.Variable.SOCtoRSOCBridge\nBridges.Variable.VectorizeBridge\nBridges.Variable.ZerosBridge\nBridges.Variable.HermitianToSymmetricPSDBridge","category":"page"},{"location":"submodules/Bridges/list_of_bridges/#MathOptInterface.Bridges.Variable.FreeBridge","page":"List of bridges","title":"MathOptInterface.Bridges.Variable.FreeBridge","text":"FreeBridge{T} <: Bridges.Variable.AbstractBridge\n\nFreeBridge implements the following reformulation:\n\nx in mathbbR into y z ge 0 with the substitution rule x = y - z,\n\nwhere T is the coefficient type of y - z.\n\nSource node\n\nFreeBridge supports:\n\nMOI.VectorOfVariables in MOI.Reals\n\nTarget nodes\n\nFreeBridge creates:\n\nOne variable node: MOI.VectorOfVariables in MOI.Nonnegatives\n\n\n\n\n\n","category":"type"},{"location":"submodules/Bridges/list_of_bridges/#MathOptInterface.Bridges.Variable.NonposToNonnegBridge","page":"List of bridges","title":"MathOptInterface.Bridges.Variable.NonposToNonnegBridge","text":"NonposToNonnegBridge{T} <: Bridges.Variable.AbstractBridge\n\nNonposToNonnegBridge implements the following reformulation:\n\nx in mathbbR_- into y in mathbbR_+ with the substitution rule x = -y,\n\nwhere T is the coefficient type of -y.\n\nSource node\n\nNonposToNonnegBridge supports:\n\nMOI.VectorOfVariables in MOI.Nonpositives\n\nTarget nodes\n\nNonposToNonnegBridge creates:\n\nOne variable node: MOI.VectorOfVariables in MOI.Nonnegatives,\n\n\n\n\n\n","category":"type"},{"location":"submodules/Bridges/list_of_bridges/#MathOptInterface.Bridges.Variable.RSOCtoPSDBridge","page":"List of bridges","title":"MathOptInterface.Bridges.Variable.RSOCtoPSDBridge","text":"RSOCtoPSDBridge{T} <: Bridges.Variable.AbstractBridge\n\nRSOCtoPSDBridge implements the following reformulation:\n\nx_2^2 le 2tu where t u ge 0 into Y succeq 0, with the substitution rule: Y = leftbeginarrayc ct x^top x 2u mathbfIendarrayright\n\nAdditional bounds are added to ensure the off-diagonals of the 2uI submatrix are 0, and linear constraints are added to ennsure the diagonal of 2uI takes the same values.\n\nAs a special case, if x = 0, then RSOCtoPSDBridge reformulates into (t u) in mathbbR_+.\n\nSource node\n\nRSOCtoPSDBridge supports:\n\nMOI.VectorOfVariables in MOI.RotatedSecondOrderCone\n\nTarget nodes\n\nRSOCtoPSDBridge creates:\n\nOne variable node that depends on the input dimension:\nMOI.VectorOfVariables in MOI.Nonnegatives if dimension is 1 or 2\nMOI.VectorOfVariables in\nMOI.PositiveSemidefiniteConeTriangle otherwise\nThe constraint node MOI.VariableIndex in MOI.EqualTo\nThe constrant node MOI.ScalarAffineFunction in MOI.EqualTo\n\n\n\n\n\n","category":"type"},{"location":"submodules/Bridges/list_of_bridges/#MathOptInterface.Bridges.Variable.RSOCtoSOCBridge","page":"List of bridges","title":"MathOptInterface.Bridges.Variable.RSOCtoSOCBridge","text":"RSOCtoSOCBridge{T} <: Bridges.Variable.AbstractBridge\n\nRSOCtoSOCBridge implements the following reformulation:\n\nx_2^2 le 2tu into v_2 le w, with the substitution rules t = fracwsqrt 2 + fracv_1sqrt 2, u = fracwsqrt 2 - fracv_1sqrt 2, and x = (v_2ldotsv_N).\n\nSource node\n\nRSOCtoSOCBridge supports:\n\nMOI.VectorOfVariables in MOI.RotatedSecondOrderCone\n\nTarget node\n\nRSOCtoSOCBridge creates:\n\nMOI.VectorOfVariables in MOI.SecondOrderCone\n\n\n\n\n\n","category":"type"},{"location":"submodules/Bridges/list_of_bridges/#MathOptInterface.Bridges.Variable.SOCtoRSOCBridge","page":"List of bridges","title":"MathOptInterface.Bridges.Variable.SOCtoRSOCBridge","text":"SOCtoRSOCBridge{T} <: Bridges.Variable.AbstractBridge\n\nSOCtoRSOCBridge implements the following reformulation:\n\nx_2 le t into 2uv ge w_2^2, with the substitution rules t = fracusqrt 2 + fracvsqrt 2, x = (fracusqrt 2 - fracvsqrt 2 w).\n\nAssumptions\n\nSOCtoRSOCBridge assumes that x ge 1.\n\nSource node\n\nSOCtoRSOCBridge supports:\n\nMOI.VectorOfVariables in MOI.SecondOrderCone\n\nTarget node\n\nSOCtoRSOCBridge creates:\n\nMOI.VectorOfVariables in MOI.RotatedSecondOrderCone\n\n\n\n\n\n","category":"type"},{"location":"submodules/Bridges/list_of_bridges/#MathOptInterface.Bridges.Variable.VectorizeBridge","page":"List of bridges","title":"MathOptInterface.Bridges.Variable.VectorizeBridge","text":"VectorizeBridge{T,S} <: Bridges.Variable.AbstractBridge\n\nVectorizeBridge implements the following reformulations:\n\nx ge a into y in mathbbR_+ with the substitution rule x = a + y\nx le a into y in mathbbR_- with the substitution rule x = a + y\nx == a into y in 0 with the substitution rule x = a + y\n\nwhere T is the coefficient type of a + y.\n\nSource node\n\nVectorizeBridge supports:\n\nMOI.VariableIndex in MOI.GreaterThan{T}\nMOI.VariableIndex in MOI.LessThan{T}\nMOI.VariableIndex in MOI.EqualTo{T}\n\nTarget nodes\n\nVectorizeBridge creates:\n\nOne variable node: MOI.VectorOfVariables in S, where S is one of MOI.Nonnegatives, MOI.Nonpositives, MOI.Zeros depending on the type of S.\n\n\n\n\n\n","category":"type"},{"location":"submodules/Bridges/list_of_bridges/#MathOptInterface.Bridges.Variable.ZerosBridge","page":"List of bridges","title":"MathOptInterface.Bridges.Variable.ZerosBridge","text":"ZerosBridge{T} <: Bridges.Variable.AbstractBridge\n\nZerosBridge implements the following reformulation:\n\nx in 0 into the substitution rule x = 0,\n\nwhere T is the coefficient type of 0.\n\nSource node\n\nZerosBridge supports:\n\nMOI.VectorOfVariables in MOI.Zeros\n\nTarget nodes\n\nZerosBridge does not create target nodes. It replaces all instances of x with 0 via substitution. This means that no variables are created in the underlying model.\n\nCaveats\n\nThe bridged variables are similar to parameters with zero values. Parameters with non-zero values can be created with constrained variables in MOI.EqualTo by combining a VectorizeBridge and this bridge.\n\nHowever, functions modified by ZerosBridge cannot be unbridged. That is, for a given function, we cannot determine if the bridged variables were used.\n\nA related implication is that this bridge does not support MOI.ConstraintDual. However, if a MOI.Utilities.CachingOptimizer is used, the dual can be determined by the bridged optimizer using MOI.Utilities.get_fallback because the caching optimizer records the unbridged function.\n\n\n\n\n\n","category":"type"},{"location":"submodules/Bridges/list_of_bridges/#MathOptInterface.Bridges.Variable.HermitianToSymmetricPSDBridge","page":"List of bridges","title":"MathOptInterface.Bridges.Variable.HermitianToSymmetricPSDBridge","text":"HermitianToSymmetricPSDBridge{T} <: Bridges.Variable.AbstractBridge\n\nHermitianToSymmetricPSDBridge implements the following reformulation:\n\nHermitian positive semidefinite n x n complex matrix to a symmetric positive semidefinite 2n x 2n real matrix satisfying equality constraints described below.\n\nSource node\n\nHermitianToSymmetricPSDBridge supports:\n\nMOI.VectorOfVariables in MOI.HermitianPositiveSemidefiniteConeTriangle\n\nTarget node\n\nHermitianToSymmetricPSDBridge creates:\n\nMOI.VectorOfVariables in MOI.PositiveSemidefiniteConeTriangle\nMOI.ScalarAffineFunction{T} in MOI.EqualTo{T}\n\nReformulation\n\nThe reformulation is best described by example.\n\nThe Hermitian matrix:\n\nbeginbmatrix\n x_11 x_12 + y_12im x_13 + y_13im\n x_12 - y_12im x_22 x_23 + y_23im\n x_13 - y_13im x_23 - y_23im x_33\nendbmatrix\n\nis positive semidefinite if and only if the symmetric matrix:\n\nbeginbmatrix\n x_11 x_12 x_13 0 y_12 y_13 \n x_22 x_23 -y_12 0 y_23 \n x_33 -y_13 -y_23 0 \n x_11 x_12 x_13 \n x_22 x_23 \n x_33\nendbmatrix\n\nis positive semidefinite.\n\nThe bridge achieves this reformulation by adding a new set of variables in MOI.PositiveSemidefiniteConeTriangle(6), and then adding three groups of equality constraints to:\n\nconstrain the two x blocks to be equal\nforce the diagonal of the y blocks to be 0\nforce the lower triangular of the y block to be the negative of the upper triangle.\n\n\n\n\n\n","category":"type"},{"location":"submodules/Bridges/overview/","page":"Overview","title":"Overview","text":"CurrentModule = MathOptInterface\nDocTestSetup = quote\n import MathOptInterface as MOI\nend\nDocTestFilters = [r\"MathOptInterface|MOI\"]","category":"page"},{"location":"submodules/Bridges/overview/#The-Bridges-submodule","page":"Overview","title":"The Bridges submodule","text":"","category":"section"},{"location":"submodules/Bridges/overview/","page":"Overview","title":"Overview","text":"The Bridges module simplifies the process of converting models between equivalent formulations.","category":"page"},{"location":"submodules/Bridges/overview/","page":"Overview","title":"Overview","text":"tip: Tip\nRead our paper for more details on how bridges are implemented.","category":"page"},{"location":"submodules/Bridges/overview/#Why-bridges?","page":"Overview","title":"Why bridges?","text":"","category":"section"},{"location":"submodules/Bridges/overview/","page":"Overview","title":"Overview","text":"A constraint can often be written in a number of equivalent formulations. For example, the constraint l le a^top x le u (ScalarAffineFunction-in-Interval) could be re-formulated as two constraints: a^top x ge l (ScalarAffineFunction-in-GreaterThan) and a^top x le u (ScalarAffineFunction-in-LessThan). An alternative re-formulation is to add a dummy variable y with the constraints l le y le u (VariableIndex-in-Interval) and a^top x - y = 0 (ScalarAffineFunction-in-EqualTo).","category":"page"},{"location":"submodules/Bridges/overview/","page":"Overview","title":"Overview","text":"To avoid each solver having to code these transformations manually, MathOptInterface provides bridges.","category":"page"},{"location":"submodules/Bridges/overview/","page":"Overview","title":"Overview","text":"A bridge is a small transformation from one constraint type to another (potentially collection of) constraint type.","category":"page"},{"location":"submodules/Bridges/overview/","page":"Overview","title":"Overview","text":"Because these bridges are included in MathOptInterface, they can be re-used by any optimizer. Some bridges also implement constraint modifications and constraint primal and dual translations.","category":"page"},{"location":"submodules/Bridges/overview/","page":"Overview","title":"Overview","text":"Several bridges can be used in combination to transform a single constraint into a form that the solver may understand. Choosing the bridges to use takes the form of finding a shortest path in the hyper-graph of bridges. The methodology is detailed in the MOI paper.","category":"page"},{"location":"submodules/Bridges/overview/#The-three-types-of-bridges","page":"Overview","title":"The three types of bridges","text":"","category":"section"},{"location":"submodules/Bridges/overview/","page":"Overview","title":"Overview","text":"There are three types of bridges in MathOptInterface:","category":"page"},{"location":"submodules/Bridges/overview/","page":"Overview","title":"Overview","text":"Constraint bridges\nVariable bridges\nObjective bridges","category":"page"},{"location":"submodules/Bridges/overview/#Constraint-bridges","page":"Overview","title":"Constraint bridges","text":"","category":"section"},{"location":"submodules/Bridges/overview/","page":"Overview","title":"Overview","text":"Constraint bridges convert constraints formulated by the user into an equivalent form supported by the solver. Constraint bridges are subtypes of Bridges.Constraint.AbstractBridge.","category":"page"},{"location":"submodules/Bridges/overview/","page":"Overview","title":"Overview","text":"The equivalent formulation may add constraints (and possibly also variables) in the underlying model.","category":"page"},{"location":"submodules/Bridges/overview/","page":"Overview","title":"Overview","text":"In particular, constraint bridges can focus on rewriting the function of a constraint, and do not change the set. Function bridges are subtypes of Bridges.Constraint.AbstractFunctionConversionBridge.","category":"page"},{"location":"submodules/Bridges/overview/","page":"Overview","title":"Overview","text":"Read the list of implemented constraint bridges for more details on the types of transformations that are available. Function bridges are Bridges.Constraint.ScalarFunctionizeBridge and Bridges.Constraint.VectorFunctionizeBridge.","category":"page"},{"location":"submodules/Bridges/overview/#variable_bridges","page":"Overview","title":"Variable bridges","text":"","category":"section"},{"location":"submodules/Bridges/overview/","page":"Overview","title":"Overview","text":"Variable bridges convert variables added by the user, either free with add_variable/add_variables, or constrained with add_constrained_variable/add_constrained_variables, into an equivalent form supported by the solver. Variable bridges are subtypes of Bridges.Variable.AbstractBridge.","category":"page"},{"location":"submodules/Bridges/overview/","page":"Overview","title":"Overview","text":"The equivalent formulation may add constraints (and possibly also variables) in the underlying model.","category":"page"},{"location":"submodules/Bridges/overview/","page":"Overview","title":"Overview","text":"Read the list of implemented variable bridges for more details on the types of transformations that are available.","category":"page"},{"location":"submodules/Bridges/overview/#Objective-bridges","page":"Overview","title":"Objective bridges","text":"","category":"section"},{"location":"submodules/Bridges/overview/","page":"Overview","title":"Overview","text":"Objective bridges convert the ObjectiveFunction set by the user into an equivalent form supported by the solver. Objective bridges are subtypes of Bridges.Objective.AbstractBridge.","category":"page"},{"location":"submodules/Bridges/overview/","page":"Overview","title":"Overview","text":"The equivalent formulation may add constraints (and possibly also variables) in the underlying model.","category":"page"},{"location":"submodules/Bridges/overview/","page":"Overview","title":"Overview","text":"Read the list of implemented objective bridges for more details on the types of transformations that are available.","category":"page"},{"location":"submodules/Bridges/overview/#Bridges.full_bridge_optimizer","page":"Overview","title":"Bridges.full_bridge_optimizer","text":"","category":"section"},{"location":"submodules/Bridges/overview/","page":"Overview","title":"Overview","text":"tip: Tip\nUnless you have an advanced use-case, this is probably the only function you need to care about.","category":"page"},{"location":"submodules/Bridges/overview/","page":"Overview","title":"Overview","text":"To enable the full power of MathOptInterface's bridges, wrap an optimizer in a Bridges.full_bridge_optimizer.","category":"page"},{"location":"submodules/Bridges/overview/","page":"Overview","title":"Overview","text":"julia> inner_optimizer = MOI.Utilities.Model{Float64}()\nMOIU.Model{Float64}\n\njulia> optimizer = MOI.Bridges.full_bridge_optimizer(inner_optimizer, Float64)\nMOIB.LazyBridgeOptimizer{MOIU.Model{Float64}}\nwith 0 variable bridges\nwith 0 constraint bridges\nwith 0 objective bridges\nwith inner model MOIU.Model{Float64}","category":"page"},{"location":"submodules/Bridges/overview/","page":"Overview","title":"Overview","text":"Now, use optimizer as normal, and bridging will happen lazily behind the scenes. By lazily, we mean that bridging will happen if and only if the constraint is not supported by the inner_optimizer.","category":"page"},{"location":"submodules/Bridges/overview/","page":"Overview","title":"Overview","text":"info: Info\nMost bridges are added by default in Bridges.full_bridge_optimizer. However, for technical reasons, some bridges are not added by default. Three examples include Bridges.Constraint.SOCtoPSDBridge, Bridges.Constraint.SOCtoNonConvexQuadBridge and Bridges.Constraint.RSOCtoNonConvexQuadBridge. See the docs of those bridges for more information.","category":"page"},{"location":"submodules/Bridges/overview/#Add-a-single-bridge","page":"Overview","title":"Add a single bridge","text":"","category":"section"},{"location":"submodules/Bridges/overview/","page":"Overview","title":"Overview","text":"If you don't want to use Bridges.full_bridge_optimizer, you can wrap an optimizer in a single bridge.","category":"page"},{"location":"submodules/Bridges/overview/","page":"Overview","title":"Overview","text":"However, this will force the constraint to be bridged, even if the inner_optimizer supports it.","category":"page"},{"location":"submodules/Bridges/overview/","page":"Overview","title":"Overview","text":"julia> inner_optimizer = MOI.Utilities.Model{Float64}()\nMOIU.Model{Float64}\n\njulia> optimizer = MOI.Bridges.Constraint.SplitInterval{Float64}(inner_optimizer)\nMOIB.Constraint.SingleBridgeOptimizer{MOIB.Constraint.SplitIntervalBridge{Float64}, MOIU.Model{Float64}}\nwith 0 constraint bridges\nwith inner model MOIU.Model{Float64}\n\njulia> x = MOI.add_variable(optimizer)\nMOI.VariableIndex(1)\n\njulia> MOI.add_constraint(optimizer, x, MOI.Interval(0.0, 1.0))\nMathOptInterface.ConstraintIndex{MathOptInterface.VariableIndex, MathOptInterface.Interval{Float64}}(1)\n\njulia> MOI.get(optimizer, MOI.ListOfConstraintTypesPresent())\n1-element Vector{Tuple{Type, Type}}:\n (MathOptInterface.VariableIndex, MathOptInterface.Interval{Float64})\n\njulia> MOI.get(inner_optimizer, MOI.ListOfConstraintTypesPresent())\n2-element Vector{Tuple{Type, Type}}:\n (MathOptInterface.VariableIndex, MathOptInterface.GreaterThan{Float64})\n (MathOptInterface.VariableIndex, MathOptInterface.LessThan{Float64})","category":"page"},{"location":"submodules/Bridges/overview/#Bridges.LazyBridgeOptimizer","page":"Overview","title":"Bridges.LazyBridgeOptimizer","text":"","category":"section"},{"location":"submodules/Bridges/overview/","page":"Overview","title":"Overview","text":"If you don't want to use Bridges.full_bridge_optimizer, but you need more than a single bridge (or you want the bridging to happen lazily), you can manually construct a Bridges.LazyBridgeOptimizer.","category":"page"},{"location":"submodules/Bridges/overview/","page":"Overview","title":"Overview","text":"First, wrap an inner optimizer:","category":"page"},{"location":"submodules/Bridges/overview/","page":"Overview","title":"Overview","text":"julia> inner_optimizer = MOI.Utilities.Model{Float64}()\nMOIU.Model{Float64}\n\njulia> optimizer = MOI.Bridges.LazyBridgeOptimizer(inner_optimizer)\nMOIB.LazyBridgeOptimizer{MOIU.Model{Float64}}\nwith 0 variable bridges\nwith 0 constraint bridges\nwith 0 objective bridges\nwith inner model MOIU.Model{Float64}","category":"page"},{"location":"submodules/Bridges/overview/","page":"Overview","title":"Overview","text":"Then use Bridges.add_bridge to add individual bridges:","category":"page"},{"location":"submodules/Bridges/overview/","page":"Overview","title":"Overview","text":"julia> MOI.Bridges.add_bridge(optimizer, MOI.Bridges.Constraint.SplitIntervalBridge{Float64})\n\njulia> MOI.Bridges.add_bridge(optimizer, MOI.Bridges.Objective.FunctionizeBridge{Float64})","category":"page"},{"location":"submodules/Bridges/overview/","page":"Overview","title":"Overview","text":"Now the constraints will be bridged only if needed:","category":"page"},{"location":"submodules/Bridges/overview/","page":"Overview","title":"Overview","text":"julia> x = MOI.add_variable(optimizer)\nMOI.VariableIndex(1)\n\njulia> MOI.add_constraint(optimizer, x, MOI.Interval(0.0, 1.0))\nMathOptInterface.ConstraintIndex{MathOptInterface.VariableIndex, MathOptInterface.Interval{Float64}}(1)\n\njulia> MOI.get(optimizer, MOI.ListOfConstraintTypesPresent())\n1-element Vector{Tuple{Type, Type}}:\n (MathOptInterface.VariableIndex, MathOptInterface.Interval{Float64})\n\njulia> MOI.get(inner_optimizer, MOI.ListOfConstraintTypesPresent())\n1-element Vector{Tuple{Type, Type}}:\n (MathOptInterface.VariableIndex, MathOptInterface.Interval{Float64})","category":"page"},{"location":"developer/checklists/#Checklists","page":"Checklists","title":"Checklists","text":"","category":"section"},{"location":"developer/checklists/","page":"Checklists","title":"Checklists","text":"The purpose of this page is to collate a series of checklists for commonly performed changes to the source code of MathOptInterface.","category":"page"},{"location":"developer/checklists/","page":"Checklists","title":"Checklists","text":"In each case, copy the checklist into the description of the pull request.","category":"page"},{"location":"developer/checklists/#Making-a-release","page":"Checklists","title":"Making a release","text":"","category":"section"},{"location":"developer/checklists/","page":"Checklists","title":"Checklists","text":"Use this checklist when making a release of the MathOptInterface repository.","category":"page"},{"location":"developer/checklists/","page":"Checklists","title":"Checklists","text":"## Basic\n\n - [ ] `version` field of `Project.toml` has been updated\n - If a breaking change, increment the MAJOR field and reset others to 0\n - If adding new features, increment the MINOR field and reset PATCH to 0\n - If adding bug fixes or documentation changes, increment the PATCH field\n\n## Documentation\n\n - [ ] Add a new entry to `docs/src/changelog.md`, following existing style\n\n## Tests\n\n - [ ] The `solver-tests.yml` GitHub action does not have unexpected failures.\n To run the action, go to:\n https://github.com/jump-dev/MathOptInterface.jl/actions/workflows/solver-tests.yml\n and click \"Run workflow\"","category":"page"},{"location":"developer/checklists/#Adding-a-new-set","page":"Checklists","title":"Adding a new set","text":"","category":"section"},{"location":"developer/checklists/","page":"Checklists","title":"Checklists","text":"Use this checklist when adding a new set to the MathOptInterface repository.","category":"page"},{"location":"developer/checklists/","page":"Checklists","title":"Checklists","text":"## Basic\n\n - [ ] Add a new `AbstractScalarSet` or `AbstractVectorSet` to `src/sets.jl`\n - [ ] If `isbitstype(S) == false`, implement `Base.copy(set::S)`\n - [ ] If `isbitstype(S) == false`, implement `Base.:(==)(x::S, y::S)`\n - [ ] If an `AbstractVectorSet`, implement `dimension(set::S)`, unless the\n dimension is given by `set.dimension`.\n\n## Utilities\n\n - [ ] If an `AbstractVectorSet`, implement `Utilities.set_dot`,\n unless the dot product between two vectors in the set is equivalent to\n `LinearAlgebra.dot`\n - [ ] If an `AbstractVectorSet`, implement `Utilities.set_with_dimension` in\n `src/Utilities/matrix_of_constraints.jl`\n - [ ] Add the set to the `@model` macro at the bottom of `src/Utilities.model.jl`\n\n## Documentation\n\n - [ ] Add a docstring, which gives the mathematical definition of the set,\n along with an `## Example` block containing a `jldoctest`\n - [ ] Add the docstring to `docs/src/reference/standard_form.md`\n - [ ] Add the set to the relevant table in `docs/src/manual/standard_form.md`\n\n## Tests\n\n - [ ] Define a new `_set(::Type{S})` method in `src/Test/test_basic_constraint.jl`\n and add the name of the set to the list at the bottom of that files\n - [ ] If the set has any checks in its constructor, add tests to `test/sets.jl`\n\n## MathOptFormat\n\n - [ ] Open an issue at `https://github.com/jump-dev/MathOptFormat` to add\n support for the new set {{ replace with link to the issue }}\n\n## Optional\n\n - [ ] Implement `dual_set(::S)` and `dual_set_type(::Type{S})`\n - [ ] Add new tests to the `Test` submodule exercising your new set\n - [ ] Add new bridges to convert your set into more commonly used sets","category":"page"},{"location":"developer/checklists/#Adding-a-new-bridge","page":"Checklists","title":"Adding a new bridge","text":"","category":"section"},{"location":"developer/checklists/","page":"Checklists","title":"Checklists","text":"Use this checklist when adding a new bridge to the MathOptInterface repository.","category":"page"},{"location":"developer/checklists/","page":"Checklists","title":"Checklists","text":"The steps are mostly the same, but locations depend on whether the bridge is a Constraint, Objective, or Variable bridge. In each case below, replace XXX with the appropriate type of bridge.","category":"page"},{"location":"developer/checklists/","page":"Checklists","title":"Checklists","text":"## Basic\n\n - [ ] Create a new file in `src/Bridges/XXX/bridges`\n - [ ] Define the bridge, following existing examples. The name of the bridge\n struct must end in `Bridge`\n - [ ] Check if your bridge can be a subtype of [`MOI.Bridges.Constraint.SetMapBridge`](@ref)\n - [ ] Define a new `const` that is a `SingleBridgeOptimizer` wrapping the\n new bridge. The name of the const must be the name of the bridge, less\n the `Bridge` suffix\n - [ ] `include` the file in `src/Bridges/XXX/bridges/XXX.jl`\n - [ ] If the bridge should be enabled by default, add the bridge to\n `add_all_bridges` at the bottom of `src/Bridges/XXX/XXX.jl`\n\n## Tests\n\n - [ ] Create a new file in the appropriate subdirectory of `tests/Bridges/XXX`\n - [ ] Use `MOI.Bridges.runtests` to test various inputs and outputs of the\n bridge\n - [ ] If, after opening the pull request to add the bridge, some lines are not\n covered by the tests, add additional bridge-specific tests to cover the\n untested lines.\n\n## Documentation\n\n - [ ] Add a docstring which uses the same template as existing bridges.\n - [ ] Add the docstring to `docs/src/submodules/Bridges/list_of_bridges.md`\n\n## Final touch\n\nIf the bridge depends on run-time values of other variables and constraints in\nthe model:\n\n - [ ] Implement `MOI.Utilities.needs_final_touch(::Bridge)`\n - [ ] Implement `MOI.Utilities.final_touch(::Bridge, ::MOI.ModelLike)`\n - [ ] Ensure that `final_touch` can be called multiple times in a row","category":"page"},{"location":"developer/checklists/#Updating-MathOptFormat","page":"Checklists","title":"Updating MathOptFormat","text":"","category":"section"},{"location":"developer/checklists/","page":"Checklists","title":"Checklists","text":"Use this checklist when updating the version of MathOptFormat.","category":"page"},{"location":"developer/checklists/","page":"Checklists","title":"Checklists","text":"## Basic\n\n - [ ] The file at `src/FileFormats/MOF/mof.X.Y.schema.json` is updated\n - [ ] The constants `SCHEMA_PATH`, `VERSION`, and `SUPPORTED_VERSIONS` are\n updated in `src/FileFormats/MOF/MOF.jl`\n\n## New sets\n\n - [ ] New sets are added to the `@model` in `src/FileFormats/MOF/MOF.jl`\n - [ ] New sets are added to the `@enum` in `src/FileFormats/MOF/read.jl`\n - [ ] `set_to_moi` is defined for each set in `src/FileFormats/MOF/read.jl`\n - [ ] `head_name` is defined for each set in `src/FileFormats/MOF/write.jl`\n - [ ] A new unit test calling `_test_model_equality` is aded to\n `test/FileFormats/MOF/MOF.jl`\n\n## Tests\n\n - [ ] The version field in `test/FileFormats/MOF/nlp.mof.json` is updated\n\n## Documentation\n\n - [ ] The version fields are updated in `docs/src/submodules/FileFormats/overview.md`","category":"page"},{"location":"manual/standard_form/","page":"Standard form problem","title":"Standard form problem","text":"CurrentModule = MathOptInterface\nDocTestSetup = quote\n import MathOptInterface as MOI\nend\nDocTestFilters = [r\"MathOptInterface|MOI\"]","category":"page"},{"location":"manual/standard_form/#Standard-form-problem","page":"Standard form problem","title":"Standard form problem","text":"","category":"section"},{"location":"manual/standard_form/","page":"Standard form problem","title":"Standard form problem","text":"MathOptInterface represents optimization problems in the standard form:","category":"page"},{"location":"manual/standard_form/","page":"Standard form problem","title":"Standard form problem","text":"beginalign\n min_x in mathbbR^n f_0(x)\n \n textst f_i(x) in mathcalS_i i = 1 ldots m\nendalign","category":"page"},{"location":"manual/standard_form/","page":"Standard form problem","title":"Standard form problem","text":"where:","category":"page"},{"location":"manual/standard_form/","page":"Standard form problem","title":"Standard form problem","text":"the functions f_0 f_1 ldots f_m are specified by AbstractFunction objects\nthe sets mathcalS_1 ldots mathcalS_m are specified by AbstractSet objects","category":"page"},{"location":"manual/standard_form/","page":"Standard form problem","title":"Standard form problem","text":"tip: Tip\nFor more information on this standard form, read our paper.","category":"page"},{"location":"manual/standard_form/","page":"Standard form problem","title":"Standard form problem","text":"MOI defines some commonly used functions and sets, but the interface is extensible to other sets recognized by the solver.","category":"page"},{"location":"manual/standard_form/#Functions","page":"Standard form problem","title":"Functions","text":"","category":"section"},{"location":"manual/standard_form/","page":"Standard form problem","title":"Standard form problem","text":"The function types implemented in MathOptInterface.jl are:","category":"page"},{"location":"manual/standard_form/","page":"Standard form problem","title":"Standard form problem","text":"Function Description\nVariableIndex x_j, the projection onto a single coordinate defined by a variable index j.\nVectorOfVariables The projection onto multiple coordinates (that is, extracting a sub-vector).\nScalarAffineFunction a^T x + b, where a is a vector and b scalar.\nScalarNonlinearFunction f(x), where f is a nonlinear function.\nVectorAffineFunction A x + b, where A is a matrix and b is a vector.\nScalarQuadraticFunction frac12 x^T Q x + a^T x + b, where Q is a symmetric matrix, a is a vector, and b is a constant.\nVectorQuadraticFunction A vector of scalar-valued quadratic functions.\nVectorNonlinearFunction f(x), where f is a vector-valued nonlinear function.","category":"page"},{"location":"manual/standard_form/","page":"Standard form problem","title":"Standard form problem","text":"Extensions for nonlinear programming are present but not yet well documented.","category":"page"},{"location":"manual/standard_form/#One-dimensional-sets","page":"Standard form problem","title":"One-dimensional sets","text":"","category":"section"},{"location":"manual/standard_form/","page":"Standard form problem","title":"Standard form problem","text":"The one-dimensional set types implemented in MathOptInterface.jl are:","category":"page"},{"location":"manual/standard_form/","page":"Standard form problem","title":"Standard form problem","text":"Set Description\nLessThan(u) (-infty u\nGreaterThan(l) l infty)\nEqualTo(v) v\nInterval(l, u) l u\nInteger() mathbbZ\nZeroOne() 0 1 \nSemicontinuous(l, u) 0 cup l u\nSemiinteger(l, u) 0 cup ll+1ldotsu-1u","category":"page"},{"location":"manual/standard_form/#Vector-cones","page":"Standard form problem","title":"Vector cones","text":"","category":"section"},{"location":"manual/standard_form/","page":"Standard form problem","title":"Standard form problem","text":"The vector-valued set types implemented in MathOptInterface.jl are:","category":"page"},{"location":"manual/standard_form/","page":"Standard form problem","title":"Standard form problem","text":"Set Description\nReals(d) mathbbR^d\nZeros(d) 0^d\nNonnegatives(d) x in mathbbR^d x ge 0 \nNonpositives(d) x in mathbbR^d x le 0 \nSecondOrderCone(d) (tx) in mathbbR^d t ge lVert x rVert_2 \nRotatedSecondOrderCone(d) (tux) in mathbbR^d 2tu ge lVert x rVert_2^2 t ge 0u ge 0 \nExponentialCone() (xyz) in mathbbR^3 y exp (xy) le z y 0 \nDualExponentialCone() (uvw) in mathbbR^3 -u exp (vu) le exp(1) w u 0 \nGeometricMeanCone(d) (tx) in mathbbR^1+n x ge 0 t le sqrtnx_1 x_2 cdots x_n where n is d - 1\nPowerCone(α) (xyz) in mathbbR^3 x^alpha y^1-alpha ge z x ge 0y ge 0 \nDualPowerCone(α) (uvw) in mathbbR^3 left(fracualpharight(^alphaleft(fracv1-alpharight)^1-alpha ge w uv ge 0 \nNormOneCone(d) (tx) in mathbbR^d t ge sum_i lvert x_i rvert \nNormInfinityCone(d) (tx) in mathbbR^d t ge max_i lvert x_i rvert \nRelativeEntropyCone(d) (u v w) in mathbbR^d u ge sum_i w_i log (fracw_iv_i) v_i ge 0 w_i ge 0 \nHyperRectangle(l, u) x in barmathbbR^d x_i in l_i u_i forall i=1ldotsd\nNormCone(p, d) ``{ (t,x) \\in \\mathbb{R}^{d} : t \\ge \\left(\\sum\\limits_i","category":"page"},{"location":"manual/standard_form/#Matrix-cones","page":"Standard form problem","title":"Matrix cones","text":"","category":"section"},{"location":"manual/standard_form/","page":"Standard form problem","title":"Standard form problem","text":"The matrix-valued set types implemented in MathOptInterface.jl are:","category":"page"},{"location":"manual/standard_form/","page":"Standard form problem","title":"Standard form problem","text":"Set Description\nRootDetConeTriangle(d) (tX) in mathbbR^1+d(1+d)2 t le det(X)^1d X mbox is the upper triangle of a PSD matrix \nRootDetConeSquare(d) (tX) in mathbbR^1+d^2 t le det(X)^1d X mbox is a PSD matrix \nPositiveSemidefiniteConeTriangle(d) X in mathbbR^d(d+1)2 X mbox is the upper triangle of a PSD matrix \nPositiveSemidefiniteConeSquare(d) X in mathbbR^d^2 X mbox is a PSD matrix \nLogDetConeTriangle(d) (tuX) in mathbbR^2+d(1+d)2 t le ulog(det(Xu)) X mbox is the upper triangle of a PSD matrix u 0 \nLogDetConeSquare(d) (tuX) in mathbbR^2+d^2 t le u log(det(Xu)) X mbox is a PSD matrix u 0 \nNormSpectralCone(r, c) (t X) in mathbbR^1 + r times c t ge sigma_1(X) X mbox is a rtimes cmbox matrix \nNormNuclearCone(r, c) (t X) in mathbbR^1 + r times c t ge sum_i sigma_i(X) X mbox is a rtimes cmbox matrix \nHermitianPositiveSemidefiniteConeTriangle(d) The cone of Hermitian positive semidefinite matrices, with\nside_dimension rows and columns. \nScaled(S) The set S scaled so that Utilities.set_dot corresponds to LinearAlgebra.dot","category":"page"},{"location":"manual/standard_form/","page":"Standard form problem","title":"Standard form problem","text":"Some of these cones can take two forms: XXXConeTriangle and XXXConeSquare.","category":"page"},{"location":"manual/standard_form/","page":"Standard form problem","title":"Standard form problem","text":"In XXXConeTriangle sets, the matrix is assumed to be symmetric, and the elements are provided by a vector, in which the entries of the upper-right triangular part of the matrix are given column by column (or equivalently, the entries of the lower-left triangular part are given row by row).","category":"page"},{"location":"manual/standard_form/","page":"Standard form problem","title":"Standard form problem","text":"In XXXConeSquare sets, the entries of the matrix are given column by column (or equivalently, row by row), and the matrix is constrained to be symmetric. As an example, given a 2-by-2 matrix of variables X and a one-dimensional variable t, we can specify a root-det constraint as [t, X11, X12, X22] ∈ RootDetConeTriangle or [t, X11, X12, X21, X22] ∈ RootDetConeSquare.","category":"page"},{"location":"manual/standard_form/","page":"Standard form problem","title":"Standard form problem","text":"We provide both forms to enable flexibility for solvers who may natively support one or the other. Transformations between XXXConeTriangle and XXXConeSquare are handled by bridges, which removes the chance of conversion mistakes by users or solver developers.","category":"page"},{"location":"manual/standard_form/#Multi-dimensional-sets-with-combinatorial-structure","page":"Standard form problem","title":"Multi-dimensional sets with combinatorial structure","text":"","category":"section"},{"location":"manual/standard_form/","page":"Standard form problem","title":"Standard form problem","text":"Other sets are vector-valued, with a particular combinatorial structure. Read their docstrings for more information on how to interpret them.","category":"page"},{"location":"manual/standard_form/","page":"Standard form problem","title":"Standard form problem","text":"Set Description\nSOS1 A Special Ordered Set (SOS) of Type I\nSOS2 A Special Ordered Set (SOS) of Type II\nIndicator A set to specify an indicator constraint\nComplements A set to specify a mixed complementarity constraint\nAllDifferent The all_different global constraint\nBinPacking The bin_packing global constraint\nCircuit The circuit global constraint\nCountAtLeast The at_least global constraint\nCountBelongs The nvalue global constraint\nCountDistinct The distinct global constraint\nCountGreaterThan The count_gt global constraint\nCumulative The cumulative global constraint\nPath The path global constraint\nTable The table global constraint","category":"page"},{"location":"reference/modification/","page":"Modifications","title":"Modifications","text":"CurrentModule = MathOptInterface\nDocTestSetup = quote\n import MathOptInterface as MOI\nend\nDocTestFilters = [r\"MathOptInterface|MOI\"]","category":"page"},{"location":"reference/modification/#Modifications","page":"Modifications","title":"Modifications","text":"","category":"section"},{"location":"reference/modification/","page":"Modifications","title":"Modifications","text":"modify\nAbstractFunctionModification\nScalarConstantChange\nVectorConstantChange\nScalarCoefficientChange\nMultirowChange","category":"page"},{"location":"reference/modification/#MathOptInterface.modify","page":"Modifications","title":"MathOptInterface.modify","text":"Constraint Function\n\nmodify(model::ModelLike, ci::ConstraintIndex, change::AbstractFunctionModification)\n\nApply the modification specified by change to the function of constraint ci.\n\nAn ModifyConstraintNotAllowed error is thrown if modifying constraints is not supported by the model model.\n\nExamples\n\nmodify(model, ci, ScalarConstantChange(10.0))\n\nObjective Function\n\nmodify(model::ModelLike, ::ObjectiveFunction, change::AbstractFunctionModification)\n\nApply the modification specified by change to the objective function of model. To change the function completely, call set instead.\n\nAn ModifyObjectiveNotAllowed error is thrown if modifying objectives is not supported by the model model.\n\nExamples\n\nmodify(model, ObjectiveFunction{ScalarAffineFunction{Float64}}(), ScalarConstantChange(10.0))\n\nMultiple modifications in Constraint Functions\n\nmodify(\n model::ModelLike,\n cis::AbstractVector{<:ConstraintIndex},\n changes::AbstractVector{<:AbstractFunctionModification},\n)\n\nApply multiple modifications specified by changes to the functions of constraints cis.\n\nA ModifyConstraintNotAllowed error is thrown if modifying constraints is not supported by model.\n\nExamples\n\nmodify(\n model,\n [ci, ci],\n [\n ScalarCoefficientChange{Float64}(VariableIndex(1), 1.0),\n ScalarCoefficientChange{Float64}(VariableIndex(2), 0.5),\n ],\n)\n\nMultiple modifications in the Objective Function\n\nmodify(\n model::ModelLike,\n attr::ObjectiveFunction,\n changes::AbstractVector{<:AbstractFunctionModification},\n)\n\nApply multiple modifications specified by changes to the functions of constraints cis.\n\nA ModifyObjectiveNotAllowed error is thrown if modifying objective coefficients is not supported by model.\n\nExamples\n\nmodify(\n model,\n ObjectiveFunction{ScalarAffineFunction{Float64}}(),\n [\n ScalarCoefficientChange{Float64}(VariableIndex(1), 1.0),\n ScalarCoefficientChange{Float64}(VariableIndex(2), 0.5),\n ],\n)\n\n\n\n\n\n","category":"function"},{"location":"reference/modification/#MathOptInterface.AbstractFunctionModification","page":"Modifications","title":"MathOptInterface.AbstractFunctionModification","text":"AbstractFunctionModification\n\nAn abstract supertype for structs which specify partial modifications to functions, to be used for making small modifications instead of replacing the functions entirely.\n\n\n\n\n\n","category":"type"},{"location":"reference/modification/#MathOptInterface.ScalarConstantChange","page":"Modifications","title":"MathOptInterface.ScalarConstantChange","text":"ScalarConstantChange{T}(new_constant::T)\n\nA struct used to request a change in the constant term of a scalar-valued function.\n\nApplicable to ScalarAffineFunction and ScalarQuadraticFunction.\n\n\n\n\n\n","category":"type"},{"location":"reference/modification/#MathOptInterface.VectorConstantChange","page":"Modifications","title":"MathOptInterface.VectorConstantChange","text":"VectorConstantChange{T}(new_constant::Vector{T})\n\nA struct used to request a change in the constant vector of a vector-valued function.\n\nApplicable to VectorAffineFunction and VectorQuadraticFunction.\n\n\n\n\n\n","category":"type"},{"location":"reference/modification/#MathOptInterface.ScalarCoefficientChange","page":"Modifications","title":"MathOptInterface.ScalarCoefficientChange","text":"ScalarCoefficientChange{T}(variable::VariableIndex, new_coefficient::T)\n\nA struct used to request a change in the linear coefficient of a single variable in a scalar-valued function.\n\nApplicable to ScalarAffineFunction and ScalarQuadraticFunction.\n\n\n\n\n\n","category":"type"},{"location":"reference/modification/#MathOptInterface.MultirowChange","page":"Modifications","title":"MathOptInterface.MultirowChange","text":"MultirowChange{T}(\n variable::VariableIndex,\n new_coefficients::Vector{Tuple{Int64,T}},\n) where {T}\n\nA struct used to request a change in the linear coefficients of a single variable in a vector-valued function.\n\nNew coefficients are specified by (output_index, coefficient) tuples.\n\nApplicable to VectorAffineFunction and VectorQuadraticFunction.\n\n\n\n\n\n","category":"type"},{"location":"changelog/","page":"Release notes","title":"Release notes","text":"CurrentModule = MathOptInterface","category":"page"},{"location":"changelog/#Release-notes","page":"Release notes","title":"Release notes","text":"","category":"section"},{"location":"changelog/","page":"Release notes","title":"Release notes","text":"The format is based on Keep a Changelog, and this project adheres to Semantic Versioning.","category":"page"},{"location":"changelog/#v1.20.0-(September-7,-2023)","page":"Release notes","title":"v1.20.0 (September 7, 2023)","text":"","category":"section"},{"location":"changelog/#Added","page":"Release notes","title":"Added","text":"","category":"section"},{"location":"changelog/","page":"Release notes","title":"Release notes","text":"Added Scaled set (#2237) (#2263) (#2264)\nAdded ObjectiveLimit attribute (#2257)","category":"page"},{"location":"changelog/#Other","page":"Release notes","title":"Other","text":"","category":"section"},{"location":"changelog/","page":"Release notes","title":"Release notes","text":"Updated dependencies (#2258)\nImproved performance of ScalarNonlinearFunction utilities (#2259)\nFixed docstrings (#2261)","category":"page"},{"location":"changelog/#v1.19.0-(August-15,-2023)","page":"Release notes","title":"v1.19.0 (August 15, 2023)","text":"","category":"section"},{"location":"changelog/#Added-2","page":"Release notes","title":"Added","text":"","category":"section"},{"location":"changelog/","page":"Release notes","title":"Release notes","text":"Added VectorNonlinearFunction (#2201)\nAdded new bridges\nBridges.Constraint.IntegerToZeroOneBridge (#2205)\nBridges.Constraint.ToScalarQuadraticBridge (#2235)\nBridges.Constraint.ToVectorQuadraticBridge (#2235)\nBridges.Constraint.ToScalarNonlinearBridge (#2233) (#2235)\nBridges.Constraint.FunctionConversionBridge (#2235)\nAdded Bridges.bridging_cost for setting a bridge-specific cost in the bridging graph (#2235)\nAdded Utilities.eval_variables support for ScalarNonlinearFunction (#2218) (#2219)\nAdded support for ScalarNonlinearFunction in FileFormats.NL (#2228) (#2231)\nAdded support for writing non-Float64 functions in FileFormats.MOF\nAdded Utilities.lazy_map (#2254)","category":"page"},{"location":"changelog/#Fixed","page":"Release notes","title":"Fixed","text":"","category":"section"},{"location":"changelog/","page":"Release notes","title":"Release notes","text":"Fixed method ambiguities in operate (#2224)\nFixed reading LP file with a -infinity <= x <= +infinity variable (#2225)\nFixed missing require in Test.test_nonlinear_duals (#2230)\nFixed bug in ConstraintPrimal of Bridges.Constraint.QuadtoSOCBridge (#2240)","category":"page"},{"location":"changelog/#Other-2","page":"Release notes","title":"Other","text":"","category":"section"},{"location":"changelog/","page":"Release notes","title":"Release notes","text":"Added extensions to solver-tests.yml (#2229)\nRefactored test/Benchmarks (#2234)\nFixed warnings in tests (#2241) (#2243)\nSmall refactoring of bridges for upcoming VectorNonlinearFunction (#2244) (#2245)\nFixed various typos (#2251) (#2255)\nPartitioned how we run the tests on GitHub actions (#2252) (#2253)","category":"page"},{"location":"changelog/#v1.18.0-(June-23,-2023)","page":"Release notes","title":"v1.18.0 (June 23, 2023)","text":"","category":"section"},{"location":"changelog/#Added-3","page":"Release notes","title":"Added","text":"","category":"section"},{"location":"changelog/","page":"Release notes","title":"Release notes","text":"Added Bridges.Objective.SlackBridgePrimalDualStart (#2194)\nAdded constraint_gradient_structure and eval_constraint_gradient (#2200)","category":"page"},{"location":"changelog/#Fixed-2","page":"Release notes","title":"Fixed","text":"","category":"section"},{"location":"changelog/","page":"Release notes","title":"Release notes","text":"Fixed a missing @require in MOI.Test (#2195) (#2196)\nFixed incorrect usage of Utilities.operate! in bridges (#2207) (#2216)\nFixed splatting nonlinear expression with univariate operator (#2221)","category":"page"},{"location":"changelog/#Other-3","page":"Release notes","title":"Other","text":"","category":"section"},{"location":"changelog/","page":"Release notes","title":"Release notes","text":"Removed unused argument names (#2199)\nReduced memory requirement for tests (#2204)\nRefactored Utilities.promote_operation (#2206)\nImproved code style in Utilities/mutable_arithmetics.jl (#2209)\nRefactored various methods in Utilities/functions.jl (#2208) (#2212) (#2213) (#2214) (#2215)","category":"page"},{"location":"changelog/#v1.17.1-(June-6,-2023)","page":"Release notes","title":"v1.17.1 (June 6, 2023)","text":"","category":"section"},{"location":"changelog/#Fixed-3","page":"Release notes","title":"Fixed","text":"","category":"section"},{"location":"changelog/","page":"Release notes","title":"Release notes","text":"Fixed comparison of ScalarFunctionConstantNotZero (#2190)","category":"page"},{"location":"changelog/#Other-4","page":"Release notes","title":"Other","text":"","category":"section"},{"location":"changelog/","page":"Release notes","title":"Release notes","text":"Added documentation for enum instances (#2186)\nUpdated chatroom links in documentation (#2188)\nChanged the documentation to build on Julia v1.9 (#2191)","category":"page"},{"location":"changelog/#v1.17.0-(June-1,-2023)","page":"Release notes","title":"v1.17.0 (June 1, 2023)","text":"","category":"section"},{"location":"changelog/#Added-4","page":"Release notes","title":"Added","text":"","category":"section"},{"location":"changelog/","page":"Release notes","title":"Release notes","text":"Added ScalarNonlinearFunction (#2059)\nAdded a variety of tests for NormSpectralCone, NormNuclearCone, and HermitianPositiveSemidefiniteConeTriangle (#2174)\nAdded Utilities.value_type for computing the value type of a function (#2176)","category":"page"},{"location":"changelog/#Fixed-4","page":"Release notes","title":"Fixed","text":"","category":"section"},{"location":"changelog/","page":"Release notes","title":"Release notes","text":"Fixed support for external sets in Utilities.loadfromstring! (#2177)\nFixed promote_operation for ScalarNonlinearFunction (#2179)\nFixed two issues in FileFormats.LP when reading files with quadratic functions (#2182) (#2184)","category":"page"},{"location":"changelog/#v1.16.0-(May-16,-2023)","page":"Release notes","title":"v1.16.0 (May 16, 2023)","text":"","category":"section"},{"location":"changelog/#Added-5","page":"Release notes","title":"Added","text":"","category":"section"},{"location":"changelog/","page":"Release notes","title":"Release notes","text":"Added support for MathOptFormat v1.3 and v1.4 (#2158) (#2169)\nAdded new method to the nonlinear API (#2162) (#2164)\neval_hessian_constraint\neval_hessian_objective\nhessian_constraint_structure\nhessian_objective_structure\nAdded new sets\nNormCone (#2119)\nScaledPositiveSemidefiniteConeTriangle (#2154)","category":"page"},{"location":"changelog/#Fixed-5","page":"Release notes","title":"Fixed","text":"","category":"section"},{"location":"changelog/","page":"Release notes","title":"Release notes","text":"Fixed support for Julia v1.9 to work around a bug in the upstream Julia compiler (#2161) (#2163)\nFixed a correctness bug in Bridges.Constraint.HermitianToSymmetricPSDBridge (#2171)\nFixed convert(::VariableIndex, ::ScalarAffineFunction) when the function has terms with 0coefficients (#2173)","category":"page"},{"location":"changelog/#Other-5","page":"Release notes","title":"Other","text":"","category":"section"},{"location":"changelog/","page":"Release notes","title":"Release notes","text":"Fixed solver-tests.yml (#2157)\nUpdated documentation links to developer chatroom (#2160)\nAdded various tests for bridges (#2156)\nAdded checklists to the developer documentation (#2167) (#2168)","category":"page"},{"location":"changelog/#v1.15.1-(April-25,-2023)","page":"Release notes","title":"v1.15.1 (April 25, 2023)","text":"","category":"section"},{"location":"changelog/#Fixed-6","page":"Release notes","title":"Fixed","text":"","category":"section"},{"location":"changelog/","page":"Release notes","title":"Release notes","text":"Fixed deleting a variable in a bridged objective (#2150)","category":"page"},{"location":"changelog/#v1.15.0-(April-19,-2023)","page":"Release notes","title":"v1.15.0 (April 19, 2023)","text":"","category":"section"},{"location":"changelog/#Added-6","page":"Release notes","title":"Added","text":"","category":"section"},{"location":"changelog/","page":"Release notes","title":"Release notes","text":"Added Bridges.Objective.VectorFunctionizeBridge (#2139)","category":"page"},{"location":"changelog/#Fixed-7","page":"Release notes","title":"Fixed","text":"","category":"section"},{"location":"changelog/","page":"Release notes","title":"Release notes","text":"Fixed support for Rational in Bridges.Constraint.SplitIntervalBridge (#2137)\nFixed printing of LaTeX models (#2141)\nFixed modify in Bridges.Objective.VectorSlackBridge (#2144)\nFixed NAME record with spaces in FileFormats.MPS (#2146)\nFixed deleting a variable in a bridged objective (#2147)","category":"page"},{"location":"changelog/#Other-6","page":"Release notes","title":"Other","text":"","category":"section"},{"location":"changelog/","page":"Release notes","title":"Release notes","text":"Add a test for variables in one-sided open Interval sets (#2133)\nMinor style fixes in the source code (#2148)","category":"page"},{"location":"changelog/#v1.14.1-(April-6,-2023)","page":"Release notes","title":"v1.14.1 (April 6, 2023)","text":"","category":"section"},{"location":"changelog/#Fixed-8","page":"Release notes","title":"Fixed","text":"","category":"section"},{"location":"changelog/","page":"Release notes","title":"Release notes","text":"Fixed a bug in Bridges.print_active_bridges (#2135)","category":"page"},{"location":"changelog/#Other-7","page":"Release notes","title":"Other","text":"","category":"section"},{"location":"changelog/","page":"Release notes","title":"Release notes","text":"Added a warning when an ambiguous string is passed to exclude in Test.runtests (#2136)","category":"page"},{"location":"changelog/#v1.14.0-(April-4,-2023)","page":"Release notes","title":"v1.14.0 (April 4, 2023)","text":"","category":"section"},{"location":"changelog/#Added-7","page":"Release notes","title":"Added","text":"","category":"section"},{"location":"changelog/","page":"Release notes","title":"Release notes","text":"Added support for starting values in Bridges.Constraint.QuadtoSOCBridge (#2115)\nAdded support for Regex in the include and exclude arguments to Test.runtests (#2129)\nAdded Bridges.print_active_bridges methods for individual objectives and constraints (#2128)","category":"page"},{"location":"changelog/#Fixed-9","page":"Release notes","title":"Fixed","text":"","category":"section"},{"location":"changelog/","page":"Release notes","title":"Release notes","text":"Fixed ResultCount when parsing .sol files in FileFormats.NL (#2130)","category":"page"},{"location":"changelog/#v1.13.2-(March-21,-2023)","page":"Release notes","title":"v1.13.2 (March 21, 2023)","text":"","category":"section"},{"location":"changelog/#Fixed-10","page":"Release notes","title":"Fixed","text":"","category":"section"},{"location":"changelog/","page":"Release notes","title":"Release notes","text":"Fixed splatting of containers in MOI.Nonlinear (#2120)\nFixed a bug reading LP files with default bounds (#2121)\nFixed a bug in which Bridges.Constraint.HermitianToSymmetricPSDBridge was not enabled by default (#2123)","category":"page"},{"location":"changelog/#Other-8","page":"Release notes","title":"Other","text":"","category":"section"},{"location":"changelog/","page":"Release notes","title":"Release notes","text":"Fixed typos in the documentation (#2114)\nFunctions now print to the REPL in algebraic form. This is potentially breaking if you have tests which rely on a specific String form of MOI functions. (#2112) (#2126)","category":"page"},{"location":"changelog/#v1.13.1-(March-3,-2023)","page":"Release notes","title":"v1.13.1 (March 3, 2023)","text":"","category":"section"},{"location":"changelog/#Other-9","page":"Release notes","title":"Other","text":"","category":"section"},{"location":"changelog/","page":"Release notes","title":"Release notes","text":"Added the Google style guide to the documentation linter Vale, and fixed the resulting warnings (#2110)\nImproved the docstrings in src/functions.jl (#2108)","category":"page"},{"location":"changelog/#v1.13.0-(February-28,-2023)","page":"Release notes","title":"v1.13.0 (February 28, 2023)","text":"","category":"section"},{"location":"changelog/#Added-8","page":"Release notes","title":"Added","text":"","category":"section"},{"location":"changelog/","page":"Release notes","title":"Release notes","text":"Added Bridges.Constraint.NumberConversionBridge (#2091)\nAdded Parameter set (#2095) (#2105) (#2106) (#2109)\nAdded with_cache_type argument to instantiate (#2097)\nAdded support for HermitianPositiveSemidefiniteConeTriangle in Utilities.Model (#2100)","category":"page"},{"location":"changelog/#Fixed-11","page":"Release notes","title":"Fixed","text":"","category":"section"},{"location":"changelog/","page":"Release notes","title":"Release notes","text":"Fixed bug when Utilities.@product_of_sets is empty (#2101)\nFixed Bridges.print_active_bridges when variable bridge is an AbstractScalarSet (#2107)","category":"page"},{"location":"changelog/#Other-10","page":"Release notes","title":"Other","text":"","category":"section"},{"location":"changelog/","page":"Release notes","title":"Release notes","text":"Added tests for vector-valued objective functions in FileFormats.MOF (#2093)\nUsed and documented preference for import MathOptInterface as MOI (#2096)\nFix and test links in the documentation with linkcheck = true (#2098)\nImproved docstrings of sets in src/sets.jl (#2099)\nSkip checking flakey links in documentation with linkcheck_ignore (#2103)","category":"page"},{"location":"changelog/#v1.12.0-(February-10,-2023)","page":"Release notes","title":"v1.12.0 (February 10, 2023)","text":"","category":"section"},{"location":"changelog/#Added-9","page":"Release notes","title":"Added","text":"","category":"section"},{"location":"changelog/","page":"Release notes","title":"Release notes","text":"Added support for vector-valued objective functions (#2070)\nAdded a Utilities.distance_to_set method for SecondOrderCone (#2060)","category":"page"},{"location":"changelog/#Fixed-12","page":"Release notes","title":"Fixed","text":"","category":"section"},{"location":"changelog/","page":"Release notes","title":"Release notes","text":"Fixed a number of constraint bridges so that Bridges.final_touch can be called multiple times without forcing a rebuild of the reformulation (#2089)","category":"page"},{"location":"changelog/#Other-11","page":"Release notes","title":"Other","text":"","category":"section"},{"location":"changelog/","page":"Release notes","title":"Release notes","text":"Added new tests that a set ObjectiveFunction appears in ListOfModelAttributesSet (#2085)\nImproved the docstrings of a number of constraint-programming related sets (#2087)","category":"page"},{"location":"changelog/#v1.11.5-(January-24,-2023)","page":"Release notes","title":"v1.11.5 (January 24, 2023)","text":"","category":"section"},{"location":"changelog/#Fixed-13","page":"Release notes","title":"Fixed","text":"","category":"section"},{"location":"changelog/","page":"Release notes","title":"Release notes","text":"Fixed a bug writing .lp files with an off-diagonal quadratic objective (#2082)","category":"page"},{"location":"changelog/#Other-12","page":"Release notes","title":"Other","text":"","category":"section"},{"location":"changelog/","page":"Release notes","title":"Release notes","text":"Added SnoopPrecompile directives for reduced time-to-first-X in Julia v1.9 (#2080)","category":"page"},{"location":"changelog/#v1.11.4-(January-12,-2023)","page":"Release notes","title":"v1.11.4 (January 12, 2023)","text":"","category":"section"},{"location":"changelog/#Fixed-14","page":"Release notes","title":"Fixed","text":"","category":"section"},{"location":"changelog/","page":"Release notes","title":"Release notes","text":"Fixed a bug reading .lp files with an Integer section (#2078)","category":"page"},{"location":"changelog/#v1.11.3-(January-12,-2023)","page":"Release notes","title":"v1.11.3 (January 12, 2023)","text":"","category":"section"},{"location":"changelog/#Fixed-15","page":"Release notes","title":"Fixed","text":"","category":"section"},{"location":"changelog/","page":"Release notes","title":"Release notes","text":"Fixed a performance bug when deleting a vector of constraints (#2072)\nFixed a bug reading .lp files with terms like x -1 y (#2076)","category":"page"},{"location":"changelog/#Other-13","page":"Release notes","title":"Other","text":"","category":"section"},{"location":"changelog/","page":"Release notes","title":"Release notes","text":"Documented the two-argument method of optimize! (#2074)","category":"page"},{"location":"changelog/#v1.11.2-(January-2,-2023)","page":"Release notes","title":"v1.11.2 (January 2, 2023)","text":"","category":"section"},{"location":"changelog/#Fixed-16","page":"Release notes","title":"Fixed","text":"","category":"section"},{"location":"changelog/","page":"Release notes","title":"Release notes","text":"Fixed a bug reading .mof.json files with ConstraintName set for VariableIndex constraints (#2066)\nFixed a bug reading .mof.json files with nonlinear objectives and no constraints (#2068)","category":"page"},{"location":"changelog/#v1.11.1-(December-22,-2022)","page":"Release notes","title":"v1.11.1 (December 22, 2022)","text":"","category":"section"},{"location":"changelog/#Fixed-17","page":"Release notes","title":"Fixed","text":"","category":"section"},{"location":"changelog/","page":"Release notes","title":"Release notes","text":"Fixed a bug reading .mof.json files with integer coefficients for affine and quadratic functions (#2063)","category":"page"},{"location":"changelog/#v1.11.0-(December-2,-2022)","page":"Release notes","title":"v1.11.0 (December 2, 2022)","text":"","category":"section"},{"location":"changelog/#Added-10","page":"Release notes","title":"Added","text":"","category":"section"},{"location":"changelog/","page":"Release notes","title":"Release notes","text":"Added Utilities.PenaltyRelaxation and Utilities.ScalarPenaltyRelaxation (#1995)\nAdded Utilities.distance_to_set (#2048)\nAdded support for ConstraintPrimalStart and ConstraintDualStart in FileFormats.MOF (#2056)","category":"page"},{"location":"changelog/#Other-14","page":"Release notes","title":"Other","text":"","category":"section"},{"location":"changelog/","page":"Release notes","title":"Release notes","text":"Tidied these release notes (#2055)","category":"page"},{"location":"changelog/#v1.10.0-(November-22,-2022)","page":"Release notes","title":"v1.10.0 (November 22, 2022)","text":"","category":"section"},{"location":"changelog/#Added-11","page":"Release notes","title":"Added","text":"","category":"section"},{"location":"changelog/","page":"Release notes","title":"Release notes","text":"Added new methods set(::OptimizerWithAttributes, ::RawOptimizerAttribute, value) and get(::OptimizerWithAttributes, ::RawOptimizerAttribute) (#2049)\nAdded new methods Utilities.DoubleDicts.outer_keys and Utilities.DoubleDicts.nonempty_outer_keys (#2052)","category":"page"},{"location":"changelog/#Fixed-18","page":"Release notes","title":"Fixed","text":"","category":"section"},{"location":"changelog/","page":"Release notes","title":"Release notes","text":"Fixed Bridges.Objective.SlackBridge when the objective function is complex-valued (#2036) (#2038)\nFixed docstring of Test.runtests to clarify the warn_unsupported argument (#2037)\nFixed reading of free variables in FileFormats.LP (#2044)\nFixed numerous edge cases reading files from QPLIB using FileFormats.LP (#2042) (#2044)\nFixed situations in which x^y returns a complex value in Nonlinear (#2050)","category":"page"},{"location":"changelog/#Other-15","page":"Release notes","title":"Other","text":"","category":"section"},{"location":"changelog/","page":"Release notes","title":"Release notes","text":"Improved the error message thrown when a user-defined nonlinear function does not accept splatted input (#2032)\nRemoved specialized iterators for keys and values in Utilities.CleverDicts (#2051)","category":"page"},{"location":"changelog/#v1.9.0-(October-29,-2022)","page":"Release notes","title":"v1.9.0 (October 29, 2022)","text":"","category":"section"},{"location":"changelog/#Added-12","page":"Release notes","title":"Added","text":"","category":"section"},{"location":"changelog/","page":"Release notes","title":"Release notes","text":"Added default fallback for getting ListOfConstraintIndices and NumberOfConstraints when the constraint type is unsupported by the model (#2021)\nAdded support for min and max in nonlinear expressions (#2023)\nAdded support for Indicator{EqualTo{T}} constraints in FileFormats.MPS (#2022)\nAdded default fallback for write_to_file and read_from_file (#2029)","category":"page"},{"location":"changelog/#Fixed-19","page":"Release notes","title":"Fixed","text":"","category":"section"},{"location":"changelog/","page":"Release notes","title":"Release notes","text":"Fixed Constraint.ZeroOneBridge by adding new bounds as affine constraints instead of variable bounds (#1879)\nFixed reading free rows in FileFormats.MPS files (#2009)\nFixed parsing of OBJSENSE blocks in FileFormats.MPS files (#2016) (#2019)\nFixed the parsing of deeply nested nonlinear expressions by removing the use of recursion (#2020)\nFixed the requirements check in Test.test_constrainnt_get_ConstraintIndex (#2024)","category":"page"},{"location":"changelog/#v1.8.2-(September-20,-2022)","page":"Release notes","title":"v1.8.2 (September 20, 2022)","text":"","category":"section"},{"location":"changelog/#Documentation","page":"Release notes","title":"Documentation","text":"","category":"section"},{"location":"changelog/","page":"Release notes","title":"Release notes","text":"Added vale as a documentation linter (#2002)\nImproved styling of code blocks in the PDF (#1999) (#2000)\nFixed a number of typos in the documentation (#2001) (#2003)","category":"page"},{"location":"changelog/#v1.8.1-(September-12,-2022)","page":"Release notes","title":"v1.8.1 (September 12, 2022)","text":"","category":"section"},{"location":"changelog/#Fixed-20","page":"Release notes","title":"Fixed","text":"","category":"section"},{"location":"changelog/","page":"Release notes","title":"Release notes","text":"Fixed a bug in supports(::AbstractBridgeOptimizer for constraint attributes (#1991) (#1992)","category":"page"},{"location":"changelog/#v1.8.0-(September-1,-2022)","page":"Release notes","title":"v1.8.0 (September 1, 2022)","text":"","category":"section"},{"location":"changelog/#Added-13","page":"Release notes","title":"Added","text":"","category":"section"},{"location":"changelog/","page":"Release notes","title":"Release notes","text":"Added new sets\nHyperRectangle (#1961)\nReified (#1955)\nAdded new bridges (#1955)\nBridges.Constraint.ReifiedAllDifferentToCountDistinctBridge\nBridges.Constraint.ReifiedCountDistinctToMILPBridge\nBridges.Constraint.SplitHyperRectangleBridge\nAdded support for atan(y, x) in Nonlinear (#1987)","category":"page"},{"location":"changelog/#Fixed-21","page":"Release notes","title":"Fixed","text":"","category":"section"},{"location":"changelog/","page":"Release notes","title":"Release notes","text":"Lazily construct expressions in Nonlinear so that expressions are updated when Nonlinear.Parameter values are updated (#1984)\nAllow NORM_LIMIT as a TerminationStatus for unbounded problems in Test (#1990)","category":"page"},{"location":"changelog/#v1.7.0-(August-16,-2022)","page":"Release notes","title":"v1.7.0 (August 16, 2022)","text":"","category":"section"},{"location":"changelog/#Added-14","page":"Release notes","title":"Added","text":"","category":"section"},{"location":"changelog/","page":"Release notes","title":"Release notes","text":"Added new sets\nHermitianPositiveSemidefiniteConeTriangle\nAdded new optimizer-independent options\nRelativeGapTolerance\nAbsoluteGapTolerance\nAdded new bridges\nBridges.Constraint.GeoMeanToPowerBridge\nBridges.Constraint.HermitianToSymmetricPSDBridge\nBridges.Constraint.IndicatorGreaterToLessThanBridge\nBridges.Constraint.IndicatorLessToGreaterThanBridge\nBridges.Constraint.SplitComplexZerosBridge\nBridges.Constraint.SplitComplexEqualToBridge\nBridges.Objective.QuadratizeBridge\nAdded support for generic number types in Utilities.loadfromstring!\nUpdated FileFormats.MOF to MathOptFormat v1.1, enabling support for constraint programming sets in the MOF file format\nAdded support in various FileFormats for\nindicator constraints in FileFormats.MPS\nquadratic constraints and an objective in FileFormats.LP\nquadratic constraints and an objective in FileFormats.MPS","category":"page"},{"location":"changelog/#Fixed-22","page":"Release notes","title":"Fixed","text":"","category":"section"},{"location":"changelog/","page":"Release notes","title":"Release notes","text":"Fixed some missing promotion rules","category":"page"},{"location":"changelog/#Other-16","page":"Release notes","title":"Other","text":"","category":"section"},{"location":"changelog/","page":"Release notes","title":"Release notes","text":"Improved the performance of Jacobian products in Nonlinear\nRemoved an un-needed copy in Utilities.modify_function\nVarious clean-ups in Bridges/bridge_optimizer.jl","category":"page"},{"location":"changelog/#v1.6.1-(July-23,-2022)","page":"Release notes","title":"v1.6.1 (July 23, 2022)","text":"","category":"section"},{"location":"changelog/#Fixed-23","page":"Release notes","title":"Fixed","text":"","category":"section"},{"location":"changelog/","page":"Release notes","title":"Release notes","text":"Added support for ExponentialCone in MatrixOfConstraints\nFix PSDSquare_3 test to reflect a previously fixed bug getting the ConstraintDual of a PositiveSemidefiniteConeSquare constraint","category":"page"},{"location":"changelog/#v1.6.0-(July-2,-2022)","page":"Release notes","title":"v1.6.0 (July 2, 2022)","text":"","category":"section"},{"location":"changelog/#Added-15","page":"Release notes","title":"Added","text":"","category":"section"},{"location":"changelog/","page":"Release notes","title":"Release notes","text":"Added Bridges.needs_final_touch and Bridges.final_touch\nAdded new bridges from constraint programming sets to mixed-integer linear programs:\nAllDifferentToCountDistinctBridge\nCountAtLeastToCountBelongsBridge\nCountBelongsToMILPBridge\nCountDistinctToMILPBridge\nCountGreaterThanToMILPBridge\nCircuitToMILPBridge","category":"page"},{"location":"changelog/#Fixed-24","page":"Release notes","title":"Fixed","text":"","category":"section"},{"location":"changelog/","page":"Release notes","title":"Release notes","text":"Relax an instance of ::Vector to ::AbstractVector in MOI.Nonlinear\nFix BinPackingToMILPBridge to respect variable bounds\nFix SemiToBinaryBridge to throw error if other bounds are set","category":"page"},{"location":"changelog/#v1.5.0-(June-27,-2022)","page":"Release notes","title":"v1.5.0 (June 27, 2022)","text":"","category":"section"},{"location":"changelog/#Added-16","page":"Release notes","title":"Added","text":"","category":"section"},{"location":"changelog/","page":"Release notes","title":"Release notes","text":"Added GetAttributeNotAllowed for solvers to indicate when getting an attribute encounters an error\nAdded Utilities.get_fallback support for ObjectiveValue and DualObjectiveValue\nAdded new bridges:\nRootDetConeSquare to RootDetConeTriangle\nLogDetConeSquare to LogDetConeTriangle\nBinPacking to a mixed-integer linear program\nTable to a mixed-integer linear program\nAdded Bridges.print_active_bridges to display the current optimal hyper-path in a Bridges.LazyBridgeOptimizer","category":"page"},{"location":"changelog/#Fixed-25","page":"Release notes","title":"Fixed","text":"","category":"section"},{"location":"changelog/","page":"Release notes","title":"Release notes","text":"Fixed ZeroOne tests with lower and upper bounds\nFixed error in FileFormats.LP when reading a malformed file\nFixed reading of nonlinear programs in FileFormats.MOF\nFixed bug in ConstraintDual when using SquareBridge","category":"page"},{"location":"changelog/#Other-17","page":"Release notes","title":"Other","text":"","category":"section"},{"location":"changelog/","page":"Release notes","title":"Release notes","text":"Improved documentation of nonlinear API\nDocumented duality convention for PositiveSemidefiniteConeSquare sets\nFixed typo in Bridges.Constraint.QuadToSOCBridge docstring","category":"page"},{"location":"changelog/#v1.4.0-(June-9,-2022)","page":"Release notes","title":"v1.4.0 (June 9, 2022)","text":"","category":"section"},{"location":"changelog/#Added-17","page":"Release notes","title":"Added","text":"","category":"section"},{"location":"changelog/","page":"Release notes","title":"Release notes","text":"Added a number of sets for constraint programming:\nAllDifferent\nBinPacking\nCircuit\nCountAtLeast\nCountBelongs\nCountDistinct\nCountGreaterThan\nCumulative\nPath\nTable\nAdded support for user-defined hessians in Nonlinear\nAdded Bridges.runtests to simplify the testing of bridge implementations","category":"page"},{"location":"changelog/#Fixed-26","page":"Release notes","title":"Fixed","text":"","category":"section"},{"location":"changelog/","page":"Release notes","title":"Release notes","text":"Fixed a bug in FileFormats.NL when writing univariate *","category":"page"},{"location":"changelog/#Other-18","page":"Release notes","title":"Other","text":"","category":"section"},{"location":"changelog/","page":"Release notes","title":"Release notes","text":"Began a large refactoring of the Bridges submodule, with greatly improved documentation.","category":"page"},{"location":"changelog/#v1.3.0-(May-27,-2022)","page":"Release notes","title":"v1.3.0 (May 27, 2022)","text":"","category":"section"},{"location":"changelog/#Added-18","page":"Release notes","title":"Added","text":"","category":"section"},{"location":"changelog/","page":"Release notes","title":"Release notes","text":"Add MOI.Nonlinear submodule. This is a large new submodule that has been refactored from code that was in JuMP. For now, it should be considered experimental.\nAdd FileFormats.NL.SolFileResults(::IO, ::Model)\nAdd FileFormats.NL.read!(::IO, ::Model)\nAdd MOI.modify that accepts a vector of modifications","category":"page"},{"location":"changelog/#Fixed-27","page":"Release notes","title":"Fixed","text":"","category":"section"},{"location":"changelog/","page":"Release notes","title":"Release notes","text":"Fixed a bug in Test which attempted to include non-.jl files\nFixed a bug in FileFormats for models with open interval constraints","category":"page"},{"location":"changelog/#Other-19","page":"Release notes","title":"Other","text":"","category":"section"},{"location":"changelog/","page":"Release notes","title":"Release notes","text":"Fixed a performance issue in Utilities.DoubleDict\nVarious minor improvements to the documentation","category":"page"},{"location":"changelog/#v1.2.0-(April-25,-2022)","page":"Release notes","title":"v1.2.0 (April 25, 2022)","text":"","category":"section"},{"location":"changelog/#Added-19","page":"Release notes","title":"Added","text":"","category":"section"},{"location":"changelog/","page":"Release notes","title":"Release notes","text":"Add support for the FORMAT_REW/.rew file format in FileFormats.","category":"page"},{"location":"changelog/#Fixed-28","page":"Release notes","title":"Fixed","text":"","category":"section"},{"location":"changelog/","page":"Release notes","title":"Release notes","text":"Fix bug handling of default variable bounds in FileFormats.LP\nFix FileFormats.MPS to not write OBJSENSE by default since this is only supported by some readers.","category":"page"},{"location":"changelog/#v1.1.2-(March-31,-2022)","page":"Release notes","title":"v1.1.2 (March 31, 2022)","text":"","category":"section"},{"location":"changelog/#Fixed-29","page":"Release notes","title":"Fixed","text":"","category":"section"},{"location":"changelog/","page":"Release notes","title":"Release notes","text":"Fix a range of bugs in FileFormats.LP\nFix reading of problem dimensions in FileFormats.SDPA","category":"page"},{"location":"changelog/#v1.1.1-(March-23,-2022)","page":"Release notes","title":"v1.1.1 (March 23, 2022)","text":"","category":"section"},{"location":"changelog/#Fixed-30","page":"Release notes","title":"Fixed","text":"","category":"section"},{"location":"changelog/","page":"Release notes","title":"Release notes","text":"Fix bug in test_model_UpperBoundAlreadySet\nFix bug in test_infeasible_ tests\nFix bug in test_objective_ObjectiveFunction_blank\nRelax restriction of MOI.AbstractOptimizer to MOI.ModelLike in Utilities.CachingOptimizer and instantiate.","category":"page"},{"location":"changelog/#New-tests","page":"Release notes","title":"New tests","text":"","category":"section"},{"location":"changelog/","page":"Release notes","title":"Release notes","text":"Add test_conic_empty_matrix that checks conic solvers support problems with no variables.","category":"page"},{"location":"changelog/#v1.1.0-(March-2,-2022)","page":"Release notes","title":"v1.1.0 (March 2, 2022)","text":"","category":"section"},{"location":"changelog/#Added-20","page":"Release notes","title":"Added","text":"","category":"section"},{"location":"changelog/","page":"Release notes","title":"Release notes","text":"Added MOI.Utilities.throw_unsupported(::UniversalFallback) for simplifying solver wrappers which copy from a UniversalFallback.","category":"page"},{"location":"changelog/#v1.0.2-(March-1,-2022)","page":"Release notes","title":"v1.0.2 (March 1, 2022)","text":"","category":"section"},{"location":"changelog/#Fixed-31","page":"Release notes","title":"Fixed","text":"","category":"section"},{"location":"changelog/","page":"Release notes","title":"Release notes","text":"Fixed a bug in the test_model_ScalarFunctionConstantNotZero test\nFixed the error type when an AbstractFunctionConversionBridge cannot get or set an attribute\nIdentified a correctness bug in RSOCtoPSDBridge. We now thrown an error instead of returning an incorrect result.","category":"page"},{"location":"changelog/#v1.0.1-(February-25,-2022)","page":"Release notes","title":"v1.0.1 (February 25, 2022)","text":"","category":"section"},{"location":"changelog/#Fixed-32","page":"Release notes","title":"Fixed","text":"","category":"section"},{"location":"changelog/","page":"Release notes","title":"Release notes","text":"Fixed a bug in which OptimizerAttributes were not copied in CachingOptimizer\nFixed a bug in which shift_constant did not promote mixed types of coefficients\nFixed a bug in which deleting a constraint of a bridged variable threw ErrorException instead of MOI.DeleteNotAllowed\nFixed a bug in which add_constraint in MatrixOfConstraints did not canonicalize the function\nFixed a bug when modifying scalar constants of a function containing a bridged variable\nFixed a bug in which final_touch was not always called with a CachingOptimizer","category":"page"},{"location":"changelog/#v1.0.0-(February-17,-2022)","page":"Release notes","title":"v1.0.0 (February 17, 2022)","text":"","category":"section"},{"location":"changelog/","page":"Release notes","title":"Release notes","text":"Although tagged as a breaking release, v1.0.0 is v0.10.9 with deprecations removed, similar to how Julia 1.0 was Julia 0.7 with deprecations removed.","category":"page"},{"location":"changelog/#Breaking","page":"Release notes","title":"Breaking","text":"","category":"section"},{"location":"changelog/","page":"Release notes","title":"Release notes","text":"Julia 1.6 is now the minimum supported version\nAll deprecations have been removed","category":"page"},{"location":"changelog/#Troubleshooting-problems-when-updating","page":"Release notes","title":"Troubleshooting problems when updating","text":"","category":"section"},{"location":"changelog/","page":"Release notes","title":"Release notes","text":"If you experience problems when updating, you are likely using previously deprecated features. (By default, Julia does not warn when you use deprecated features.)","category":"page"},{"location":"changelog/","page":"Release notes","title":"Release notes","text":"To find the deprecated features you are using, start Julia with --depwarn=yes:","category":"page"},{"location":"changelog/","page":"Release notes","title":"Release notes","text":"$ julia --depwarn=yes","category":"page"},{"location":"changelog/","page":"Release notes","title":"Release notes","text":"Then install MathOptInterface v0.10.9:","category":"page"},{"location":"changelog/","page":"Release notes","title":"Release notes","text":"julia> using Pkg\njulia> pkg\"add MathOptInterface@0.10\"","category":"page"},{"location":"changelog/","page":"Release notes","title":"Release notes","text":"And then run your code. Apply any suggestions, or search the release notes below for advice on updating a specific deprecated feature.","category":"page"},{"location":"changelog/#v0.10.9-(February-16,-2022)","page":"Release notes","title":"v0.10.9 (February 16, 2022)","text":"","category":"section"},{"location":"changelog/#Added-21","page":"Release notes","title":"Added","text":"","category":"section"},{"location":"changelog/","page":"Release notes","title":"Release notes","text":"Added MOI.Utilities.FreeVariables as a new VariablesConstrainer for conic solvers\nAdded MOI.default_cache for specifying the model used in CachingOptimizer","category":"page"},{"location":"changelog/#Fixed-33","page":"Release notes","title":"Fixed","text":"","category":"section"},{"location":"changelog/","page":"Release notes","title":"Release notes","text":"Fixed LaTeX printing of MOI.Interval sets","category":"page"},{"location":"changelog/#Other-20","page":"Release notes","title":"Other","text":"","category":"section"},{"location":"changelog/","page":"Release notes","title":"Release notes","text":"Added Aqua.jl as a CI check, and fixed suggested issues\nThe constructors of GeoMeanBridge, StructOfConstraints, and CachingOptimizer were changed from outer to inner constructors. This change is technically breaking, but does not impact users who followed the documented API.","category":"page"},{"location":"changelog/#v0.10.8-(February-3,-2022)","page":"Release notes","title":"v0.10.8 (February 3, 2022)","text":"","category":"section"},{"location":"changelog/#Added-22","page":"Release notes","title":"Added","text":"","category":"section"},{"location":"changelog/","page":"Release notes","title":"Release notes","text":"Added a Base.read! for FileFormats.LP.","category":"page"},{"location":"changelog/#Fixed-34","page":"Release notes","title":"Fixed","text":"","category":"section"},{"location":"changelog/","page":"Release notes","title":"Release notes","text":"Fixed a bug in MutableSparseMatrix\nFixed a bug when calling operate!(vcat, ...) with Number arguments\nRemoved unintended export of deprecated symbols\nFixed a bug with PowerCone and DualPowerCone in MatrixOfConstraints.","category":"page"},{"location":"changelog/#v0.10.7-(January-5,-2022)","page":"Release notes","title":"v0.10.7 (January 5, 2022)","text":"","category":"section"},{"location":"changelog/#Added-23","page":"Release notes","title":"Added","text":"","category":"section"},{"location":"changelog/","page":"Release notes","title":"Release notes","text":"Added test for modifying the constant vector in a VectorAffineFunction-in-Zeros constraint.","category":"page"},{"location":"changelog/#Fixed-35","page":"Release notes","title":"Fixed","text":"","category":"section"},{"location":"changelog/","page":"Release notes","title":"Release notes","text":"Fixed the order in which sets are added to a LazyBridgeOptimizer. Compared to v0.10.6, this may result in bridged models being created with a different number (and order) of variables and constraints. However, it was necessary to fix cases which were previously rejected as unsupported, even though there was a valid bridge transformation.\nFixed an error message in FileFormats.CBF\nFixed comparison in test_linear_integration_Interval\nFixed errors for ConstraintPrimal in a CachingOptimizer\nFixed printing of models with non-Float64 coefficients.","category":"page"},{"location":"changelog/#Other-21","page":"Release notes","title":"Other","text":"","category":"section"},{"location":"changelog/","page":"Release notes","title":"Release notes","text":"Various improvements to reduce time-to-first-solve latency\nImproved error message when an optimizer does not support compute_conflict!","category":"page"},{"location":"changelog/#v0.10.6-(November-30,-2021)","page":"Release notes","title":"v0.10.6 (November 30, 2021)","text":"","category":"section"},{"location":"changelog/#Added-24","page":"Release notes","title":"Added","text":"","category":"section"},{"location":"changelog/","page":"Release notes","title":"Release notes","text":"Added new documentation and tests for infeasibility certificates\nAdded a version control system for the tests in MOI.Test.runtests. Pass exclude_tests_after = v\"0.10.5\" to run tests added in v0.10.5 and earlier.\nMOI.Test.runtests now supports generic number types. To specify the number type T, pass MOI.Test.Config(T).\nAdded infeasible_status to MOI.Test.Config for solvers which return LOCALLY_INFEASIBLE\nCachingOptimizers now use a fallback for ConstraintPrimal. This should enable solvers using a CachingOptimizer to pass tests requiring ConstraintPrimal.","category":"page"},{"location":"changelog/#Fixed-36","page":"Release notes","title":"Fixed","text":"","category":"section"},{"location":"changelog/","page":"Release notes","title":"Release notes","text":"Fixed a StackOverflow bug in copy_to\nFixed error thrown when nonconvex quadratic constraints cannot be bridged\nFixed a bug in copy_to for FileFormats.NL.Model\nFixed a bug in FileFormats.NL when printing large integers\nRemove a common test failure for LowerBoundAlreadySet tests\nUtilities.num_rows is now exported\nRemove parts of failing test_model_copy_to_xxx tests due to bridges","category":"page"},{"location":"changelog/#v0.10.5-(November-7,-2021)","page":"Release notes","title":"v0.10.5 (November 7, 2021)","text":"","category":"section"},{"location":"changelog/#Fixed-37","page":"Release notes","title":"Fixed","text":"","category":"section"},{"location":"changelog/","page":"Release notes","title":"Release notes","text":"Fixed getter in UniversalFallback\nFixed test_solve_conflict_zeroone_ii","category":"page"},{"location":"changelog/#Other-22","page":"Release notes","title":"Other","text":"","category":"section"},{"location":"changelog/","page":"Release notes","title":"Release notes","text":"Make normalize_and_add_constraint more flexible\nUpdate paper BibTeX","category":"page"},{"location":"changelog/#v0.10.4-(October-26,-2021)","page":"Release notes","title":"v0.10.4 (October 26, 2021)","text":"","category":"section"},{"location":"changelog/#Added-25","page":"Release notes","title":"Added","text":"","category":"section"},{"location":"changelog/","page":"Release notes","title":"Release notes","text":"Add SolverVersion attribute\nAdd new tests:\ntest_solve_conflict_zeroone_ii\ntest_nonlinear_objective\nUtilities.VariablesContainer now supports ConstraintFunction and ConstraintSet\nThe documentation is now available as a PDF","category":"page"},{"location":"changelog/#Other-23","page":"Release notes","title":"Other","text":"","category":"section"},{"location":"changelog/","page":"Release notes","title":"Release notes","text":"Update to MutableArithmetics 0.3\nVarious improvements to the documentation","category":"page"},{"location":"changelog/#v0.10.3-(September-18,-2021)","page":"Release notes","title":"v0.10.3 (September 18, 2021)","text":"","category":"section"},{"location":"changelog/#Fixed-38","page":"Release notes","title":"Fixed","text":"","category":"section"},{"location":"changelog/","page":"Release notes","title":"Release notes","text":"Fixed bug which prevented callbacks from working through a CachingOptimizer\nFixed bug in Test submodule","category":"page"},{"location":"changelog/#v0.10.2-(September-16,-2021)","page":"Release notes","title":"v0.10.2 (September 16, 2021)","text":"","category":"section"},{"location":"changelog/","page":"Release notes","title":"Release notes","text":"Updated MathOptFormat to v1.0\nUpdated JSONSchema to v1.0\nAdded Utilities.set_with_dimension\nAdded two-argument optimize!(::AbstractOptimizer, ::ModelLike)\nThe experimental feature copy_to_and_optimize! has been removed\nDet bridges now support getting ConstraintFunction and ConstraintSet\nVarious minor bug fixes identified by improved testing","category":"page"},{"location":"changelog/#v0.10.1-(September-8,-2021)","page":"Release notes","title":"v0.10.1 (September 8, 2021)","text":"","category":"section"},{"location":"changelog/","page":"Release notes","title":"Release notes","text":"Various fixes to MOI.Test","category":"page"},{"location":"changelog/#v0.10.0-(September-6,-2021)","page":"Release notes","title":"v0.10.0 (September 6, 2021)","text":"","category":"section"},{"location":"changelog/","page":"Release notes","title":"Release notes","text":"MOI v0.10 is a significant breaking release. There are a large number of user-visible breaking changes and code refactors, as well as a substantial number of new features.","category":"page"},{"location":"changelog/#Breaking-in-MOI","page":"Release notes","title":"Breaking in MOI","text":"","category":"section"},{"location":"changelog/","page":"Release notes","title":"Release notes","text":"SingleVariable has been removed; use VariableIndex instead\nSingleVariableConstraintNameError has been renamed to VariableIndexConstraintNameError\nSettingSingleVariableFunctionNotAllowed has been renamed to SettingVariableIndexFunctionNotAllowed\nVariableIndex constraints should not support ConstraintName\nVariableIndex constraints should not support ConstraintBasisStatus; implement VariableBasisStatus instead\nListOfConstraints has been renamed to ListOfConstraintTypesPresent\nListOfConstraintTypesPresent should now return Tuple{Type,Type} instead of Tuple{DataType,DataType}\nSolveTime has been renamed to SolveTimeSec\nIndicatorSet has been renamed to Indicator\nRawParameter has been renamed to RawOptimizerAttribute and now takes String instead of Any as the only argument\nThe .N field in result attributes has been renamed to .result_index\nThe .variable_index field in ScalarAffineTerm has been renamed to .variable\nThe .variable_index_1 field in ScalarQuadraticTerm has been renamed to .variable_1\nThe .variable_index_2 field in ScalarQuadraticTerm has been renamed to .variable_2\nThe order of affine_terms and quadratic_terms in ScalarQuadraticFunction and VectorQuadraticFunction have been reversed. Both functions now accept quadratic, affine, and constant terms in that order.\nThe index_value function has been removed. Use .value instead.\nisapprox has been removed for SOS1 and SOS2.\nThe dimension argument to Complements(dimension::Int) should now be the length of the corresponding function, instead of half the length. An ArgumentError is thrown if dimension is not even.\ncopy_to no longer takes keyword arguments:\ncopy_names: now copy names if they are supported by the destination solver\nfilter_constraints: use Utilities.ModelFilter instead\nwarn_attributes: never warn about optimizer attributes","category":"page"},{"location":"changelog/#Breaking-in-Bridges","page":"Release notes","title":"Breaking in Bridges","text":"","category":"section"},{"location":"changelog/","page":"Release notes","title":"Release notes","text":"Constraint.RSOCBridge has been renamed to Constraint.RSOCtoSOCBridge\nConstraint.SOCRBridge has been renamed to Constraint.SOCtoRSOCBridge\nBridges now return vectors that can be modified by the user. Previously, some bridges returned views instead of copies.\nBridges.IndexInVector has been unified into a single type. Previously, there was a different type for each submodule within Bridges\nThe signature of indicator bridges has been fixed. Use MOI.Bridges.Constraint.IndicatortoSOS1{Float64}(model).","category":"page"},{"location":"changelog/#Breaking-in-FileFormats","page":"Release notes","title":"Breaking in FileFormats","text":"","category":"section"},{"location":"changelog/","page":"Release notes","title":"Release notes","text":"FileFormats.MOF.Model no longer accepts validate argument. Use the JSONSchema package to validate the MOF file. See the documentation for more information.","category":"page"},{"location":"changelog/#Breaking-in-Utilities","page":"Release notes","title":"Breaking in Utilities","text":"","category":"section"},{"location":"changelog/","page":"Release notes","title":"Release notes","text":"The datastructure of Utilities.Model (and models created with Utilities.@model) has been significantly refactored in a breaking way. This includes the way that objective functions and variable-related information is stored.\nUtilities.supports_default_copy has been renamed to supports_incremental_interface\nUtilities.automatic_copy_to has been renamed to Utilities.default_copy_to\nThe allocate-load API has been removed\nCachingOptimizers are now initialized as EMPTY_OPTIMIZER instead of ATTACHED_OPTIMIZER. If your code relies on the optimizer being attached, call MOIU.attach_optimizer(model) after creation.\nThe field names of Utilities.IndexMap have been renamed to var_map and con_map. Accessing these fields directly is considered a private detail that may change. Use the public getindex and setindex! API instead.\nThe size argument to Utilities.CleverDicts.CleverDict(::Integer) has been removed.\nThe size argument to Utilities.IndexMap(::Integer) has been removed.\nUtilities.DoubleDicts have been significantly refactored. Consult the source code for details.\nUtilities.test_models_equal has been moved to MOI.Test","category":"page"},{"location":"changelog/#Breaking-in-Test","page":"Release notes","title":"Breaking in Test","text":"","category":"section"},{"location":"changelog/","page":"Release notes","title":"Release notes","text":"MOI.Test has been renamed to MOI.DeprecatedTest\nAn entirely new MOI.Test submodule has been written. See the documentation for details. The new MOI.Test submodule may find many bugs in the implementations of existing solvers that were previously untested.","category":"page"},{"location":"changelog/#Other-changes:","page":"Release notes","title":"Other changes:","text":"","category":"section"},{"location":"changelog/","page":"Release notes","title":"Release notes","text":"attribute_value_type has been added\ncopy_to_and_optimize! has been added\nVariableBasisStatus has been added\nprint(model) now prints a human-readable description of the model\nVarious improvements to the FileFormats submodule\nFileFormats.CBF was refactored and received bugfixes\nSupport for MathOptFormat v0.6 was added in FileFormats.MOF\nFileFormats.MPS has had bugfixes and support for more features such as OBJSENSE and objective constants.\nFileFormats.NL has been added to support nonlinear files\nImproved type inference throughout to reduce latency","category":"page"},{"location":"changelog/#Updating","page":"Release notes","title":"Updating","text":"","category":"section"},{"location":"changelog/","page":"Release notes","title":"Release notes","text":"A helpful script when updating is:","category":"page"},{"location":"changelog/","page":"Release notes","title":"Release notes","text":"for (root, dirs, files) in walkdir(\".\")\n for file in files\n if !endswith(file, \".jl\")\n continue\n end\n path = joinpath(root, file)\n s = read(path, String)\n for pair in [\n \".variable_index\" => \".variable\",\n \"RawParameter\" => \"RawOptimizerAttribute\",\n \"ListOfConstraints\" => \"ListOfConstraintTypesPresent\",\n \"TestConfig\" => \"Config\",\n \"attr.N\" => \"attr.result_index\",\n \"SolveTime\" => \"SolveTimeSec\",\n \"DataType\" => \"Type\",\n \"Utilities.supports_default_copy_to\" =>\n \"supports_incremental_interface\",\n \"SingleVariableConstraintNameError\" =>\n \"VariableIndexConstraintNameError\",\n \"SettingSingleVariableFunctionNotAllowed\" =>\n \"SettingVariableIndexFunctionNotAllowed\",\n \"automatic_copy_to\" => \"default_copy_to\",\n ]\n s = replace(s, pair)\n end\n write(path, s)\n end\nend","category":"page"},{"location":"changelog/#v0.9.22-(May-22,-2021)","page":"Release notes","title":"v0.9.22 (May 22, 2021)","text":"","category":"section"},{"location":"changelog/","page":"Release notes","title":"Release notes","text":"This release contains backports from the ongoing development of the v0.10 release.","category":"page"},{"location":"changelog/","page":"Release notes","title":"Release notes","text":"Improved type inference in Utilities, Bridges and FileFormats submodules to reduce latency.\nImproved performance of Utilities.is_canonical.\nFixed Utilities.pass_nonvariable_constraints with bridged variables.\nFixed performance regression of Utilities.Model.\nFixed ordering of objective setting in parser.","category":"page"},{"location":"changelog/#v0.9.21-(April-23,-2021)","page":"Release notes","title":"v0.9.21 (April 23, 2021)","text":"","category":"section"},{"location":"changelog/","page":"Release notes","title":"Release notes","text":"Added supports_shift_constant.\nImprove performance of bridging quadratic constraints.\nAdd precompilation statements.\nLarge improvements to the documentation.\nFix a variety of inference issues, benefiting precompilation and reducing initial latency.\nRawParameters are now ignored when resetting a CachingOptimizer. Previously, changing the underlying optimizer after RawParameters were set would throw an error.\nUtilities.AbstractModel is being refactored. This may break users interacting with private fields of a model generated using @model.","category":"page"},{"location":"changelog/#v0.9.20-(February-20,-2021)","page":"Release notes","title":"v0.9.20 (February 20, 2021)","text":"","category":"section"},{"location":"changelog/","page":"Release notes","title":"Release notes","text":"Improved performance of Utilities.ScalarFunctionIterator\nAdded support for compute_conflict to MOI layers\nAdded test with zero off-diagonal quadratic term in objective\nFixed double deletion of nested bridged SingleVariable/VectorOfVariables constraints\nFixed modification of un-set objective\nFixed function modification with duplicate terms\nMade unit tests abort without failing if the problem class is not supported\nFormatted code with JuliaFormatter\nClarified BasisStatusCode's docstring","category":"page"},{"location":"changelog/#v0.9.19-(December-1,-2020)","page":"Release notes","title":"v0.9.19 (December 1, 2020)","text":"","category":"section"},{"location":"changelog/","page":"Release notes","title":"Release notes","text":"Added CallbackNodeStatus attribute\nAdded bridge from GreaterThan or LessThan to Interval\nAdded tests for infeasibility certificates and double optimize\nFixed support for Julia v1.6\nRe-organized MOI docs and added documentation for adding a test","category":"page"},{"location":"changelog/#v0.9.18-(November-3,-2020)","page":"Release notes","title":"v0.9.18 (November 3, 2020)","text":"","category":"section"},{"location":"changelog/","page":"Release notes","title":"Release notes","text":"Various improvements for working with complex numbers\nAdded GeoMeantoRelEntrBridge to bridge a GeometricMeanCone constraint to a relative entropy constraint","category":"page"},{"location":"changelog/#v0.9.17-(September-21,-2020)","page":"Release notes","title":"v0.9.17 (September 21, 2020)","text":"","category":"section"},{"location":"changelog/","page":"Release notes","title":"Release notes","text":"Fixed CleverDict with variable of negative index value\nImplement supports_add_constrained_variable for MockOptimizer","category":"page"},{"location":"changelog/#v0.9.16-(September-17,-2020)","page":"Release notes","title":"v0.9.16 (September 17, 2020)","text":"","category":"section"},{"location":"changelog/","page":"Release notes","title":"Release notes","text":"Various fixes:\n32-bit support\nCleverDict with abstract value type\nChecks in test suite","category":"page"},{"location":"changelog/#v0.9.15-(September-14,-2020)","page":"Release notes","title":"v0.9.15 (September 14, 2020)","text":"","category":"section"},{"location":"changelog/","page":"Release notes","title":"Release notes","text":"Bridges improvements:\n(R)SOCtoNonConvexQuad bridge\nZeroOne bridge\nUse supports_add_constrained_variable in LazyBridgeOptimizer\nExposed VariableBridgeCost and ConstraintBridgeCost attributes\nPrioritize constraining variables on creation according to these costs\nRefactor bridge debugging\nLarge performance improvements across all submodules\nLots of documentation improvements\nFileFormats improvements:\nUpdate MathOptFormat to v0.5\nFix supported objectives in FileFormats\nTesting improvements:\nAdd name option for basic_constraint_test\nBug fixes and missing methods\nAdd length for iterators\nFix bug with duplicate terms\nFix order of LinearOfConstraintIndices","category":"page"},{"location":"changelog/#v0.9.14-(May-30,-2020)","page":"Release notes","title":"v0.9.14 (May 30, 2020)","text":"","category":"section"},{"location":"changelog/","page":"Release notes","title":"Release notes","text":"Add a solver-independent interface for accessing the set of conflicting constraints an Irreducible Inconsistent Subsystem (#1056).\nBump JSONSchema dependency from v0.2 to v0.3 (#1090).\nDocumentation improvements:\nFix typos (#1054, #1060, #1061, #1064, #1069, #1070).\nRemove the outdated recommendation for a package implementing MOI for a solver XXX to be called MathOptInterfaceXXX (#1087).\nUtilities improvements:\nFix is_canonical for quadratic functions (#1081, #1089).\nImplement add_constrained_variable[s] for CachingOptimizer so that it is added as constrained variables to the underlying optimizer (#1084).\nAdd support for custom objective functions for UniversalFallback (#1086).\nDeterministic ordering of constraints in UniversalFallback (#1088).\nTesting improvements:\nAdd NormOneCone/NormInfinityCone tests (#1045).\nBridges improvements:\nAdd bridges from Semiinteger and Semicontinuous (#1059).\nImplement getting ConstraintSet for Variable.FlipSignBridge (#1066).\nFix setting ConstraintFunction for Constraint.ScalarizeBridge (#1093).\nFix NormOne/NormInf bridges with nonzero constants (#1045).\nFix StackOverflow in debug (#1063).\nFileFormats improvements:\n[SDPA] Implement the extension for integer variables (#1079).\n[SDPA] Ignore comments after m and nblocks and detect dat-s extension (#1077).\n[SDPA] No scaling of off-diagonal coefficient (#1076).\n[SDPA] Add missing negation of constant (#1075).","category":"page"},{"location":"changelog/#v0.9.13-(March-24,-2020)","page":"Release notes","title":"v0.9.13 (March 24, 2020)","text":"","category":"section"},{"location":"changelog/","page":"Release notes","title":"Release notes","text":"Added tests for Semicontinuous and Semiinteger variables (#1033).\nAdded tests for using ExprGraphs from NLP evaluators (#1043).\nUpdate version compatibilities of dependencies (#1034, #1051, #1052).\nFixed typos in documentation (#1044).","category":"page"},{"location":"changelog/#v0.9.12-(February-28,-2020)","page":"Release notes","title":"v0.9.12 (February 28, 2020)","text":"","category":"section"},{"location":"changelog/","page":"Release notes","title":"Release notes","text":"Fixed writing NLPBlock in MathOptFormat (#1037).\nFixed MockOptimizer for result attributes with non-one result index (#1039).\nUpdated test template with instantiate (#1032).","category":"page"},{"location":"changelog/#v0.9.11-(February-21,-2020)","page":"Release notes","title":"v0.9.11 (February 21, 2020)","text":"","category":"section"},{"location":"changelog/","page":"Release notes","title":"Release notes","text":"Add an option for the model created by Utilities.@model to be a subtype of AbstractOptimizer (#1031).\nDescribed dual cone in docstrings of GeoMeanCone and RelativeEntropyCone (#1018, #1028).\nFixed typos in documentation (#1022, #1024).\nFixed warning of unsupported attribute (#1027).\nAdded more rootdet/logdet conic tests (#1026).\nImplemented ConstraintDual for Constraint.GeoMeanBridge, Constraint.RootDetBridge and Constraint.LogDetBridge and test duals in tests with GeoMeanCone and RootDetConeTriangle and LogDetConeTriangle cones (#1025, #1026).","category":"page"},{"location":"changelog/#v0.9.10-(January-31,-2020)","page":"Release notes","title":"v0.9.10 (January 31, 2020)","text":"","category":"section"},{"location":"changelog/","page":"Release notes","title":"Release notes","text":"Added OptimizerWithAttributes grouping an optimizer constructor and a list of optimizer attributes (#1008).\nAdded RelativeEntropyCone with corresponding bridge into exponential cone constraints (#993).\nAdded NormSpectralCone and NormNuclearCone with corresponding bridges into positive semidefinite constraints (#976).\nAdded supports_constrained_variable(s) (#1004).\nAdded dual_set_type (#1002).\nAdded tests for vector specialized version of delete (#989, #1011).\nAdded PSD3 test (#1007).\nClarified dual solution of Tests.pow1v and Tests.pow1f (#1013).\nAdded support for EqualTo and Zero in Bridges.Constraint.SplitIntervalBridge (#1005).\nFixed Utilities.vectorize for empty vector (#1003).\nFixed free variables in LP writer (#1006).","category":"page"},{"location":"changelog/#v0.9.9-(December-29,-2019)","page":"Release notes","title":"v0.9.9 (December 29, 2019)","text":"","category":"section"},{"location":"changelog/","page":"Release notes","title":"Release notes","text":"Incorporated MathOptFormat.jl as the FileFormats submodule. FileFormats provides readers and writers for a number of standard file formats and MOF, a file format specialized for MOI (#969).\nImproved performance of deletion of vector of variables in MOI.Utilities.Model (#983).\nUpdated to MutableArithmetics v0.2 (#981).\nAdded MutableArithmetics.promote_operation allocation tests (#975).\nFixed inference issue on Julia v1.1 (#982).","category":"page"},{"location":"changelog/#v0.9.8-(December-19,-2019)","page":"Release notes","title":"v0.9.8 (December 19, 2019)","text":"","category":"section"},{"location":"changelog/","page":"Release notes","title":"Release notes","text":"Implemented MutableArithmetics API (#924).\nFixed callbacks with CachingOptimizer (#959).\nFixed MOI.dimension for MOI.Complements (#948).\nAdded fallback for add_variables (#972).\nAdded is_diagonal_vectorized_index utility (#965).\nImproved linear constraints display in manual (#963, #964).\nBridges improvements:\nAdded IndicatorSet to SOS1 bridge (#877).\nAdded support for starting values for Variable.VectorizeBridge (#944).\nFixed MOI.add_constraints with non-bridged variable constraint on bridged variable (#951).\nFixed corner cases and docstring of GeoMeanBridge (#961, #962, #966).\nFixed choice between variable or constraint bridges for constrained variables (#973).\nImprove performance of bridge shortest path (#945, #946, #956).\nAdded docstring for test_delete_bridge (#954).\nAdded Variable bridge tests (#952).","category":"page"},{"location":"changelog/#v0.9.7-(October-30,-2019)","page":"Release notes","title":"v0.9.7 (October 30, 2019)","text":"","category":"section"},{"location":"changelog/","page":"Release notes","title":"Release notes","text":"Implemented _result_index_field for NLPBlockDual (#934).\nFixed copy of model with starting values for vector constraints (#941).\nBridges improvements:\nImproved performance of add_bridge and added has_bridge (#935).\nAdded AbstractSetMapBridge for bridges between sets S1, S2 such that there is a linear map A such that A*S1 = S2 (#933).\nAdded support for starting values for FlipSignBridge, VectorizeBridge, ScalarizeBridge, SlackBridge, SplitIntervalBridge, RSOCBridge, SOCRBridge NormInfinityBridge, SOCtoPSDBridge and RSOCtoPSDBridge (#933, #936, #937, #938, #939).","category":"page"},{"location":"changelog/#v0.9.6-(October-25,-2019)","page":"Release notes","title":"v0.9.6 (October 25, 2019)","text":"","category":"section"},{"location":"changelog/","page":"Release notes","title":"Release notes","text":"Added complementarity constraints (#913).\nAllowed ModelLike objects as value of attributes (#928).\nTesting improvements:\nAdded dual_objective_value option to MOI.Test.TestConfig (#922).\nAdded InvalidIndex tests in basic_constraint_tests (#921).\nAdded tests for the constant term in indicator constraint (#929).\nBridges improvements:\nAdded support for starting values for Functionize bridges (#923).\nAdded variable indices context to variable bridges (#920).\nFixed a typo in printing o debug_supports (#927).","category":"page"},{"location":"changelog/#v0.9.5-(October-9,-2019)","page":"Release notes","title":"v0.9.5 (October 9, 2019)","text":"","category":"section"},{"location":"changelog/","page":"Release notes","title":"Release notes","text":"Clarified PrimalStatus/DualStatus to be NO_SOLUTION if result_index is out of bounds (#912).\nAdded tolerance for checks and use ResultCount + 1 for the result_index in MOI.Test.solve_result_status (#910, #917).\nUse 0.5 instead of 2.0 for power in PowerCone in basic_constraint_test (#916).\nBridges improvements:\nAdded debug utilities for unsupported variable/constraint/objective (#861).\nFixed deletion of variables in bridged VectorOfVariables constraints (#909).\nFixed result_index with objective bridges (#911).","category":"page"},{"location":"changelog/#v0.9.4-(October-2,-2019)","page":"Release notes","title":"v0.9.4 (October 2, 2019)","text":"","category":"section"},{"location":"changelog/","page":"Release notes","title":"Release notes","text":"Added solver-independent MIP callbacks (#782).\nImplements submit for Utilities.CachingOptimizer and Bridges.AbstractBridgeOptimizer (#906).\nAdded tests for result count of solution attributes (#901, #904).\nAdded NumberOfThreads attribute (#892).\nAdded Utilities.get_bounds to get the bounds on a variable (#890).\nAdded a note on duplicate coefficients in documentation (#581).\nAdded result index in ConstraintBasisStatus (#898).\nAdded extension dictionary to Utilities.Model (#884, #895).\nFixed deletion of constrained variables for CachingOptimizer (#905).\nImplemented Utilities.shift_constraint for Test.UnknownScalarSet (#896).\nBridges improvements:\nAdded Variable.RSOCtoSOCBridge (#907).\nImplemented MOI.get for ConstraintFunction/ConstraintSet for Bridges.Constraint.SquareBridge (#899).","category":"page"},{"location":"changelog/#v0.9.3-(September-20,-2019)","page":"Release notes","title":"v0.9.3 (September 20, 2019)","text":"","category":"section"},{"location":"changelog/","page":"Release notes","title":"Release notes","text":"Fixed ambiguity detected in Julia v1.3 (#891, #893).\nFixed missing sets from ListOfSupportedConstraints (#880).\nFixed copy of VectorOfVariables constraints with duplicate indices (#886).\nAdded extension dictionary to MOIU.Model (#884).\nImplemented MOI.get for function and set for GeoMeanBridge (#888).\nUpdated documentation for SingleVariable indices and bridges (#885).\nTesting improvements:\nAdded more comprehensive tests for names (#882).\nAdded tests for SingleVariable duals (#883).\nAdded tests for DualExponentialCone and DualPowerCone (#873).\nImprovements for arbitrary coefficient type:\nFixed == for sets with mutable fields (#887).\nRemoved some Float64 assumptions in bridges (#878).\nAutomatic selection of Constraint.[Scalar|Vector]FunctionizeBridge (#889).","category":"page"},{"location":"changelog/#v0.9.2-(September-5,-2019)","page":"Release notes","title":"v0.9.2 (September 5, 2019)","text":"","category":"section"},{"location":"changelog/","page":"Release notes","title":"Release notes","text":"Implemented model printing for MOI.ModelLike and specialized it for models defined in MOI (864).\nGeneralized contlinear tests for arbitrary coefficient type (#855).\nFixed supports_constraint for Semiinteger and Semicontinuous and supports for ObjectiveFunction (#859).\nFixed Allocate-Load copy for single variable constraints (#856).\nBridges improvements:\nAdd objective bridges (#789).\nFixed Variable.RSOCtoPSDBridge for dimension 2 (#869).\nAdded Variable.SOCtoRSOCBridge (#865).\nAdded Constraint.SOCRBridge and disable MOI.Bridges.Constraint.SOCtoPSDBridge (#751).\nFixed added_constraint_types for Contraint.LogDetBridge and Constraint.RootDetBridge (#870).","category":"page"},{"location":"changelog/#v0.9.1-(August-22,-2019)","page":"Release notes","title":"v0.9.1 (August 22, 2019)","text":"","category":"section"},{"location":"changelog/","page":"Release notes","title":"Release notes","text":"Fix support for Julia v1.2 (#834).\nL1 and L∞ norm epigraph cones and corresponding bridges to LP were added (#818).\nAdded tests to MOI.Test.nametest (#833).\nFix MOI.Test.soc3test for solvers not supporting infeasibility certificates (#839).\nImplements operate for operators * and / between vector function and constant (#837).\nImplements show for MOI.Utilities.IndexMap (#847).\nFix corner cases for mapping of variables in MOI.Utilities.CachingOptimizer and substitution of variables in MOI.Bridges.AbstractBridgeOptimizer (#848).\nFix transformation of constant terms for MOI.Bridges.Constraint.SOCtoPSDBridge and MOI.Bridges.Constraint.RSOCtoPSDBridge (#840).","category":"page"},{"location":"changelog/#v0.9.0-(August-13,-2019)","page":"Release notes","title":"v0.9.0 (August 13, 2019)","text":"","category":"section"},{"location":"changelog/","page":"Release notes","title":"Release notes","text":"Support for Julia v0.6 and v0.7 was dropped (#714, #717).\nA MOI.Utilities.Model implementation of ModelLike, this should replace most use cases of MOI.Utilities.@model (#781).\nadd_constrained_variable and add_constrained_variables were added (#759).\nSupport for indicator constraints was added (#709, #712).\nDualObjectiveValue attribute was added (#473).\nRawParameter attribute was added (#733).\nA dual_set function was added (#804).\nA Benchmarks submodule was added to facilitate solver benchmarking (#769).\nA submit function was added, this may for instance allow the user to submit solutions or cuts to the solver from a callback (#775).\nThe field of ObjectiveValue was renamed to result_index (#729).\nThe _constant and Utilities.getconstant function were renamed to constant\nREDUCTION_CERTIFICATE result status was added (#734).\nAbstract matrix sets were added (#731).\nTesting improvements:\nThe testing guideline was updated (#728).\nQuadratic tests were added (#697).\nUnit tests for RawStatusString, SolveTime, Silent and SolverName were added (#726, #741).\nA rotated second-order cone test was added (#759).\nA power cone test was added (#768).\nTests for ZeroOne variables with variable bounds were added (#772).\nAn unbounded test was added (#773).\nExisting tests had a few updates (#702, #703, #763).\nDocumentation improvements:\nAdded a section on CachingOptimizer (#777).\nAdded a section on UniversalFallback, Model and @model (#762).\nTransition the knapsack example to a doctest with MockOptimizer (#786).\nUtilities improvements:\nA CleverDict utility was added for a vector that automatically transform into a dictionary once a first index is removed (#767).\nThe Utilities.constant function was renamed to Utilities.constant_vector (#740).\nImplement optimizer attributes for CachingOptimizer (#745).\nRename Utilities.add_scalar_constraint to Utilities.normalize_and_add_constraint (#801).\noperate with vcat, SingleVariable and VectorOfVariables now returns a VectorOfVariables (#616).\nFix a type piracy of operate (#784).\nThe load_constraint fallback signature was fixed (#760).\nThe set_dot function was extended to work with sparse arrays (#805).\nBridges improvements:\nThe bridges no longer store the constraint function and set before it is bridged, the bridges now have to implement ConstraintFunction and ConstraintSet if the user wants to recover them. As a consequence, the @bridge macro was removed (#722).\nBridge are now instantiated with a bridge_constraint function instead of using a constructor (#730).\nFix constraint attributes for bridges (#699).\nConstraint bridges were moved to the Bridges/Constraint submodule so they should now inherit from MOI.Bridges.Constraint.Abstract and should implement MOI.Bridges.Constraint.concrete_bridge_type instead of MOI.Bridges.concrete_bridge_type (#756).\nVariable bridges were added in (#759).\nVarious improvements (#746, #747).","category":"page"},{"location":"changelog/#v0.8.4-(March-13,-2019)","page":"Release notes","title":"v0.8.4 (March 13, 2019)","text":"","category":"section"},{"location":"changelog/","page":"Release notes","title":"Release notes","text":"Performance improvement in default_copy_to and bridge optimizer (#696).\nAdd Silent and implement setting optimizer attributes in caching and mock optimizers (#695).\nAdd Functionize bridges (SingleVariable and VectorOfVariables) (#659).\nMinor typo fixes (#694).","category":"page"},{"location":"changelog/#v0.8.3-(March-6,-2019)","page":"Release notes","title":"v0.8.3 (March 6, 2019)","text":"","category":"section"},{"location":"changelog/","page":"Release notes","title":"Release notes","text":"Use zero constant in scalar constraint function of MOI.Test.copytest (#691).\nFix variable deletion with SingleVariable objective function (#690).\nFix LazyBridgeOptimizer with bridges that add no constraints (#689).\nError message improvements (#673, #685, #686, #688).\nDocumentation improvements (#682, #683, #687).\nBasis status:\nRemove VariableBasisStatus (#679).\nTest ConstraintBasisStatus and implement it in bridges (#678).\nFix inference of NumberOfVariables and NumberOfConstraints (#677).\nImplement division between a quadratic function and a number (#675).","category":"page"},{"location":"changelog/#v0.8.2-(February-7,-2019)","page":"Release notes","title":"v0.8.2 (February 7, 2019)","text":"","category":"section"},{"location":"changelog/","page":"Release notes","title":"Release notes","text":"Add RawStatusString attribute (#629).\nDo not set names to the optimizer but only to the cache in CachingOptimizer (#638).\nMake scalar MOI functions act as scalars in broadcast (#646).\nAdd function utilities:\nImplement Base.zero (#634), Base.iszero (#643), add missing arithmetic operations (#644, #645) and fix division (#648).\nAdd a vectorize function that turns a vector of ScalarAffineFunction into a VectorAffineFunction (#642).\nImprove support for starting values:\nShow a warning in copy when starting values are not supported instead of throwing an error (#630).\nFix UniversalFallback for getting an variable or constraint attribute set to no indices (#623).\nAdd a test in contlineartest with partially set VariablePrimalStart.\nBridges improvements:\nFix StackOverFlow in LazyBridgeOptimizer when there is a cycle in the graph of bridges.\nAdd Slack bridges (#610, #650).\nAdd FlipSign bridges (#658).\nAdd tests with duplicate coefficients in ScalarAffineFunction and VectorAffineFunction (#639).\nUse tolerance to compare VariablePrimal in rotatedsoc1 test (#632).\nUse a zero constant in ScalarAffineFunction of constraints in psdt2 (#622).","category":"page"},{"location":"changelog/#v0.8.1-(January-7,-2019)","page":"Release notes","title":"v0.8.1 (January 7, 2019)","text":"","category":"section"},{"location":"changelog/","page":"Release notes","title":"Release notes","text":"Adding an NLP objective now overrides any objective set using the ObjectiveFunction attribute (#619).\nRename fullbridgeoptimizer into full_bridge_optimizer (#621).\nAllow custom constraint types with full_bridge_optimizer (#617).\nAdd Vectorize bridge which transforms scalar linear constraints into vector linear constraints (#615).","category":"page"},{"location":"changelog/#v0.8.0-(December-18,-2018)","page":"Release notes","title":"v0.8.0 (December 18, 2018)","text":"","category":"section"},{"location":"changelog/","page":"Release notes","title":"Release notes","text":"Rename all enum values to follow the JuMP naming guidelines for constants, for example, Optimal becomes OPTIMAL, and DualInfeasible becomes DUAL_INFEASIBLE.\nRename CachingOptimizer methods for style compliance.\nAdd an MOI.TerminationStatusCode called ALMOST_DUAL_INFEASIBLE.","category":"page"},{"location":"changelog/#v0.7.0-(December-13,-2018)","page":"Release notes","title":"v0.7.0 (December 13, 2018)","text":"","category":"section"},{"location":"changelog/","page":"Release notes","title":"Release notes","text":"Test that MOI.TerminationStatus is MOI.OptimizeNotCalled before MOI.optimize! is called.\nCheck supports_default_copy_to in tests (#594).\nKey pieces of information like optimality, infeasibility, etc., are now reported through TerminationStatusCode. It is typically no longer necessary to check the result statuses in addition to the termination status.\nAdd perspective dimension to log-det cone (#593).","category":"page"},{"location":"changelog/#v0.6.4-(November-27,-2018)","page":"Release notes","title":"v0.6.4 (November 27, 2018)","text":"","category":"section"},{"location":"changelog/","page":"Release notes","title":"Release notes","text":"Add OptimizeNotCalled termination status (#577) and improve documentation of other statuses (#575).\nAdd a solver naming guideline (#578).\nMake FeasibilitySense the default ObjectiveSense (#579).\nFix Utilities.@model and Bridges.@bridge macros for functions and sets defined outside MOI (#582).\nDocument solver-specific attributes (#580) and implement them in Utilities.CachingOptimizer (#565).","category":"page"},{"location":"changelog/#v0.6.3-(November-16,-2018)","page":"Release notes","title":"v0.6.3 (November 16, 2018)","text":"","category":"section"},{"location":"changelog/","page":"Release notes","title":"Release notes","text":"Variables and constraints are now allowed to have duplicate names. An error is thrown only on lookup. This change breaks some existing tests. (#549)\nAttributes may now be partially set (some values could be nothing). (#563)\nPerformance improvements in Utilities.Model (#549, #567, #568)\nFix bug in QuadtoSOC (#558).\nNew supports_default_copy_to method that optimizers should implement to control caching behavior.\nDocumentation improvements.","category":"page"},{"location":"changelog/#v0.6.2-(October-26,-2018)","page":"Release notes","title":"v0.6.2 (October 26, 2018)","text":"","category":"section"},{"location":"changelog/","page":"Release notes","title":"Release notes","text":"Improve hygiene of @model macro (#544).\nFix bug in copy tests (#543).\nFix bug in UniversalFallback attribute getter (#540).\nAllow all correct solutions for solve_blank_obj unit test (#537).\nAdd errors for Allocate-Load and bad constraints (#534).\n[performance] Add specialized implementation of hash for VariableIndex (#533).\n[performance] Construct the name to object dictionaries lazily in model (#535).\nAdd the QuadtoSOC bridge which transforms ScalarQuadraticFunction constraints into RotatedSecondOrderCone (#483).","category":"page"},{"location":"changelog/#v0.6.1-(September-22,-2018)","page":"Release notes","title":"v0.6.1 (September 22, 2018)","text":"","category":"section"},{"location":"changelog/","page":"Release notes","title":"Release notes","text":"Enable PositiveSemidefiniteConeSquare set and quadratic functions in MOIB.fullbridgeoptimizer (#524).\nAdd warning in the bridge between PositiveSemidefiniteConeSquare and PositiveSemidefiniteConeTriangle when the matrix is almost symmetric (#522).\nModify MOIT.copytest to not add multiples constraints on the same variable (#521).\nAdd missing keyword argument in one of MOIU.add_scalar_constraint methods (#520).","category":"page"},{"location":"changelog/#v0.6.0-(August-30,-2018)","page":"Release notes","title":"v0.6.0 (August 30, 2018)","text":"","category":"section"},{"location":"changelog/","page":"Release notes","title":"Release notes","text":"The MOIU.@model and MOIB.@bridge macros now support functions and sets defined in external modules. As a consequence, function and set names in the macro arguments need to be prefixed by module name.\nRename functions according to the JuMP style guide:\ncopy! with keyword arguments copynames and warnattributes -> copy_to with keyword arguments copy_names and warn_attributes;\nset! -> set;\naddvariable[s]! -> add_variable[s];\nsupportsconstraint -> supports_constraint;\naddconstraint[s]! -> add_constraint[s];\nisvalid -> is_valid;\nisempty -> is_empty;\nBase.delete! -> delete;\nmodify! -> modify;\ntransform! -> transform;\ninitialize! -> initialize;\nwrite -> write_to_file; and\nread! -> read_from_file.\nRemove free! (use Base.finalize instead).\nAdd the SquarePSD bridge which transforms PositiveSemidefiniteConeTriangle constraints into PositiveSemidefiniteConeTriangle.\nAdd result fallback for ConstraintDual of variable-wise constraint, ConstraintPrimal and ObjectiveValue.\nAdd tests for ObjectiveBound.\nAdd test for empty rows in vector linear constraint.\nRework errors: CannotError has been renamed NotAllowedError and the distinction between UnsupportedError and NotAllowedError is now about whether the element is not supported (for example, it cannot be copied a model containing this element) or the operation is not allowed (either because it is not implemented, because it cannot be performed in the current state of the model, or because it cannot be performed for a specific index)\ncanget is removed. NoSolution is added as a result status to indicate that the solver does not have either a primal or dual solution available (See #479).","category":"page"},{"location":"changelog/#v0.5.0-(August-5,-2018)","page":"Release notes","title":"v0.5.0 (August 5, 2018)","text":"","category":"section"},{"location":"changelog/","page":"Release notes","title":"Release notes","text":"Fix names with CachingOptimizer.\nCleanup thanks to @mohamed82008.\nAdded a universal fallback for constraints.\nFast utilities for function canonicalization thanks to @rdeits.\nRenamed dimension field to side_dimension in the context of matrix-like sets.\nNew and improved tests for cases like duplicate terms and ObjectiveBound.\nRemoved cantransform, canaddconstraint, canaddvariable, canset, canmodify, and candelete functions from the API. They are replaced by a new set of errors that are thrown: Subtypes of UnsupportedError indicate unsupported operations, while subtypes of CannotError indicate operations that cannot be performed in the current state.\nThe API for copy! is updated to remove the CopyResult type.\nUpdates for the new JuMP style guide.","category":"page"},{"location":"changelog/#v0.4.1-(June-28,-2018)","page":"Release notes","title":"v0.4.1 (June 28, 2018)","text":"","category":"section"},{"location":"changelog/","page":"Release notes","title":"Release notes","text":"Fixes vector function modification on 32 bits.\nFixes Bellman-Ford algorithm for bridges.\nAdded an NLP test with FeasibilitySense.\nUpdate modification documentation.","category":"page"},{"location":"changelog/#v0.4.0-(June-23,-2018)","page":"Release notes","title":"v0.4.0 (June 23, 2018)","text":"","category":"section"},{"location":"changelog/","page":"Release notes","title":"Release notes","text":"Helper constructors for VectorAffineTerm and VectorQuadraticTerm.\nAdded modify_lhs to TestConfig.\nAdditional unit tests for optimizers.\nAdded a type parameter to CachingOptimizer for the optimizer field.\nNew API for problem modification (#388)\nTests pass without deprecation warnings on Julia 0.7.\nSmall fixes and documentation updates.","category":"page"},{"location":"changelog/#v0.3.0-(May-25,-2018)","page":"Release notes","title":"v0.3.0 (May 25, 2018)","text":"","category":"section"},{"location":"changelog/","page":"Release notes","title":"Release notes","text":"Functions have been redefined to use arrays-of-structs instead of structs-of-arrays.\nImprovements to MockOptimizer.\nSignificant changes to Bridges.\nNew and improved unit tests.\nFixes for Julia 0.7.","category":"page"},{"location":"changelog/#v0.2.0-(April-24,-2018)","page":"Release notes","title":"v0.2.0 (April 24, 2018)","text":"","category":"section"},{"location":"changelog/","page":"Release notes","title":"Release notes","text":"Improvements to and better coverage of Tests.\nDocumentation fixes.\nSolverName attribute.\nChanges to the NLP interface (new definition of variable order and arrays of structs for bound pairs and sparsity patterns).\nAddition of NLP tests.\nIntroduction of UniversalFallback.\ncopynames keyword argument to MOI.copy!.\nAdd Bridges submodule.","category":"page"},{"location":"changelog/#v0.1.0-(February-28,-2018)","page":"Release notes","title":"v0.1.0 (February 28, 2018)","text":"","category":"section"},{"location":"changelog/","page":"Release notes","title":"Release notes","text":"Initial public release.\nThe framework for MOI was developed at the JuMP-dev workshop at MIT in June 2017 as a sorely needed replacement for MathProgBase.","category":"page"},{"location":"background/duality/","page":"Duality","title":"Duality","text":"CurrentModule = MathOptInterface\nDocTestSetup = quote\n import MathOptInterface as MOI\nend\nDocTestFilters = [r\"MathOptInterface|MOI\"]","category":"page"},{"location":"background/duality/#Duality","page":"Duality","title":"Duality","text":"","category":"section"},{"location":"background/duality/","page":"Duality","title":"Duality","text":"Conic duality is the starting point for MOI's duality conventions. When all functions are affine (or coordinate projections), and all constraint sets are closed convex cones, the model may be called a conic optimization problem.","category":"page"},{"location":"background/duality/","page":"Duality","title":"Duality","text":"For a minimization problem in geometric conic form, the primal is:","category":"page"},{"location":"background/duality/","page":"Duality","title":"Duality","text":"beginalign\n min_x in mathbbR^n a_0^T x + b_0\n\n textst A_i x + b_i in mathcalC_i i = 1 ldots m\nendalign","category":"page"},{"location":"background/duality/","page":"Duality","title":"Duality","text":"and the dual is a maximization problem in standard conic form:","category":"page"},{"location":"background/duality/","page":"Duality","title":"Duality","text":"beginalign\n max_y_1 ldots y_m -sum_i=1^m b_i^T y_i + b_0\n\n textst a_0 - sum_i=1^m A_i^T y_i = 0\n\n y_i in mathcalC_i^* i = 1 ldots m\nendalign","category":"page"},{"location":"background/duality/","page":"Duality","title":"Duality","text":"where each mathcalC_i is a closed convex cone and mathcalC_i^* is its dual cone.","category":"page"},{"location":"background/duality/","page":"Duality","title":"Duality","text":"For a maximization problem in geometric conic form, the primal is:","category":"page"},{"location":"background/duality/","page":"Duality","title":"Duality","text":"beginalign\n max_x in mathbbR^n a_0^T x + b_0\n\n textst A_i x + b_i in mathcalC_i i = 1 ldots m\nendalign","category":"page"},{"location":"background/duality/","page":"Duality","title":"Duality","text":"and the dual is a minimization problem in standard conic form:","category":"page"},{"location":"background/duality/","page":"Duality","title":"Duality","text":"beginalign\n min_y_1 ldots y_m sum_i=1^m b_i^T y_i + b_0\n\n textst a_0 + sum_i=1^m A_i^T y_i = 0\n\n y_i in mathcalC_i^* i = 1 ldots m\nendalign","category":"page"},{"location":"background/duality/","page":"Duality","title":"Duality","text":"A linear inequality constraint a^T x + b ge c is equivalent to a^T x + b - c in mathbbR_+, and a^T x + b le c is equivalent to a^T x + b - c in mathbbR_-. Variable-wise constraints are affine constraints with the appropriate identity mapping in place of A_i.","category":"page"},{"location":"background/duality/","page":"Duality","title":"Duality","text":"For the special case of minimization LPs, the MOI primal form can be stated as:","category":"page"},{"location":"background/duality/","page":"Duality","title":"Duality","text":"beginalign\n min_x in mathbbR^n a_0^T x + b_0\n\n textst\nA_1 x ge b_1\n A_2 x le b_2\n A_3 x = b_3\nendalign","category":"page"},{"location":"background/duality/","page":"Duality","title":"Duality","text":"By applying the stated transformations to conic form, taking the dual, and transforming back into linear inequality form, one obtains the following dual:","category":"page"},{"location":"background/duality/","page":"Duality","title":"Duality","text":"beginalign\n max_y_1y_2y_3 b_1^Ty_1 + b_2^Ty_2 + b_3^Ty_3 + b_0\n\n textst\nA_1^Ty_1 + A_2^Ty_2 + A_3^Ty_3 = a_0\n y_1 ge 0\n y_2 le 0\nendalign","category":"page"},{"location":"background/duality/","page":"Duality","title":"Duality","text":"For maximization LPs, the MOI primal form can be stated as:","category":"page"},{"location":"background/duality/","page":"Duality","title":"Duality","text":"beginalign\n max_x in mathbbR^n a_0^T x + b_0\n\n textst\nA_1 x ge b_1\n A_2 x le b_2\n A_3 x = b_3\nendalign","category":"page"},{"location":"background/duality/","page":"Duality","title":"Duality","text":"and similarly, the dual is:","category":"page"},{"location":"background/duality/","page":"Duality","title":"Duality","text":"beginalign\n min_y_1y_2y_3 -b_1^Ty_1 - b_2^Ty_2 - b_3^Ty_3 + b_0\n\n textst\nA_1^Ty_1 + A_2^Ty_2 + A_3^Ty_3 = -a_0\n y_1 ge 0\n y_2 le 0\nendalign","category":"page"},{"location":"background/duality/","page":"Duality","title":"Duality","text":"warning: Warning\nFor the LP case, the signs of the feasible dual variables depend only on the sense of the corresponding primal inequality and not on the objective sense.","category":"page"},{"location":"background/duality/#Duality-and-scalar-product","page":"Duality","title":"Duality and scalar product","text":"","category":"section"},{"location":"background/duality/","page":"Duality","title":"Duality","text":"The scalar product is different from the canonical one for the sets PositiveSemidefiniteConeTriangle, LogDetConeTriangle, RootDetConeTriangle.","category":"page"},{"location":"background/duality/","page":"Duality","title":"Duality","text":"If the set C_i of the section Duality is one of these three cones, then the rows of the matrix A_i corresponding to off-diagonal entries are twice the value of the coefficients field in the VectorAffineFunction for the corresponding rows. See PositiveSemidefiniteConeTriangle for details.","category":"page"},{"location":"background/duality/#Dual-for-problems-with-quadratic-functions","page":"Duality","title":"Dual for problems with quadratic functions","text":"","category":"section"},{"location":"background/duality/#Quadratic-Programs-(QPs)","page":"Duality","title":"Quadratic Programs (QPs)","text":"","category":"section"},{"location":"background/duality/","page":"Duality","title":"Duality","text":"For quadratic programs with only affine conic constraints,","category":"page"},{"location":"background/duality/","page":"Duality","title":"Duality","text":"beginalign*\n min_x in mathbbR^n frac12x^TQ_0x + a_0^T x + b_0\n\n textst A_i x + b_i in mathcalC_i i = 1 ldots m\nendalign*","category":"page"},{"location":"background/duality/","page":"Duality","title":"Duality","text":"with cones mathcalC_i subseteq mathbbR^m_i for i = 1 ldots m, consider the Lagrangian function","category":"page"},{"location":"background/duality/","page":"Duality","title":"Duality","text":"L(x y) = frac12x^TQ_0x + a_0^T x + b_0 - sum_i = 1^m y_i^T (A_i x + b_i)","category":"page"},{"location":"background/duality/","page":"Duality","title":"Duality","text":"Let z(y) denote sum_i = 1^m A_i^T y_i - a_0, the Lagrangian can be rewritten as","category":"page"},{"location":"background/duality/","page":"Duality","title":"Duality","text":"L(x y) = frac12x^TQ_0x - z(y)^T x + b_0 - sum_i = 1^m y_i^T b_i","category":"page"},{"location":"background/duality/","page":"Duality","title":"Duality","text":"The condition nabla_x L(x y) = 0 gives","category":"page"},{"location":"background/duality/","page":"Duality","title":"Duality","text":"0 = nabla_x L(x y) = Q_0x + a_0 - sum_i = 1^m y_i^T b_i","category":"page"},{"location":"background/duality/","page":"Duality","title":"Duality","text":"which gives Q_0x = z(y). This allows to obtain that","category":"page"},{"location":"background/duality/","page":"Duality","title":"Duality","text":"min_x in mathbbR^n L(x y) = -frac12x^TQ_0x + b_0 - sum_i = 1^m y_i^T b_i","category":"page"},{"location":"background/duality/","page":"Duality","title":"Duality","text":"so the dual problem is","category":"page"},{"location":"background/duality/","page":"Duality","title":"Duality","text":"max_y_i in mathcalC_i^* min_x in mathbbR^n -frac12x^TQ_0x + b_0 - sum_i = 1^m y_i^T b_i","category":"page"},{"location":"background/duality/","page":"Duality","title":"Duality","text":"If Q_0 is invertible, we have x = Q_0^-1z(y) hence","category":"page"},{"location":"background/duality/","page":"Duality","title":"Duality","text":"min_x in mathbbR^n L(x y) = -frac12z(y)^TQ_0^-1z(y) + b_0 - sum_i = 1^m y_i^T b_i","category":"page"},{"location":"background/duality/","page":"Duality","title":"Duality","text":"so the dual problem is","category":"page"},{"location":"background/duality/","page":"Duality","title":"Duality","text":"max_y_i in mathcalC_i^* -frac12z(y)^TQ_0^-1z(y) + b_0 - sum_i = 1^m y_i^T b_i","category":"page"},{"location":"background/duality/#Quadratically-Constrained-Quadratic-Programs-(QCQPs)","page":"Duality","title":"Quadratically Constrained Quadratic Programs (QCQPs)","text":"","category":"section"},{"location":"background/duality/","page":"Duality","title":"Duality","text":"Given a problem with both quadratic function and quadratic objectives:","category":"page"},{"location":"background/duality/","page":"Duality","title":"Duality","text":"beginalign*\n min_x in mathbbR^n frac12x^TQ_0x + a_0^T x + b_0\n\n textst frac12x^TQ_ix + a_i^T x + b_i in mathcalC_i i = 1 ldots m\nendalign*","category":"page"},{"location":"background/duality/","page":"Duality","title":"Duality","text":"with cones mathcalC_i subseteq mathbbR for i = 1 ldots m, consider the Lagrangian function","category":"page"},{"location":"background/duality/","page":"Duality","title":"Duality","text":"L(x y) = frac12x^TQ_0x + a_0^T x + b_0 - sum_i = 1^m y_i (frac12x^TQ_ix + a_i^T x + b_i)","category":"page"},{"location":"background/duality/","page":"Duality","title":"Duality","text":"A pair of primal-dual variables (x^star y^star) is optimal if","category":"page"},{"location":"background/duality/","page":"Duality","title":"Duality","text":"x^star is a minimizer of\nmin_x in mathbbR^n L(x y^star)\nThat is,\n0 = nabla_x L(x y^star) = Q_0x + a_0 - sum_i = 1^m y_i^star (Q_ix + a_i)\nand y^star is a maximizer of\nmax_y_i in mathcalC_i^* L(x^star y)\nThat is, for all i = 1 ldots m, frac12x^TQ_ix + a_i^T x + b_i is either zero or in the normal cone of mathcalC_i^* at y^star. For instance, if mathcalC_i is z in mathbbR z le 0 , this means that if frac12x^TQ_ix + a_i^T x + b_i is nonzero at x^star then y_i^star = 0. This is the classical complementary slackness condition.","category":"page"},{"location":"background/duality/","page":"Duality","title":"Duality","text":"If mathcalC_i is a vector set, the discussion remains valid with y_i(frac12x^TQ_ix + a_i^T x + b_i) replaced with the scalar product between y_i and the vector of scalar-valued quadratic functions.","category":"page"},{"location":"background/duality/#Dual-for-square-semidefinite-matrices","page":"Duality","title":"Dual for square semidefinite matrices","text":"","category":"section"},{"location":"background/duality/","page":"Duality","title":"Duality","text":"The set PositiveSemidefiniteConeTriangle is a self-dual. That is, querying ConstraintDual of a PositiveSemidefiniteConeTriangle constraint returns a vector that is itself a member of PositiveSemidefiniteConeTriangle.","category":"page"},{"location":"background/duality/","page":"Duality","title":"Duality","text":"However, the dual of PositiveSemidefiniteConeSquare is not so straight forward. This section explains the duality convention we use, and how it is derived.","category":"page"},{"location":"background/duality/","page":"Duality","title":"Duality","text":"info: Info\nIf you have a PositiveSemidefiniteConeSquare constraint, the result matrix A from ConstraintDual is not positive semidefinite. However, A + A^top is positive semidefinite.","category":"page"},{"location":"background/duality/","page":"Duality","title":"Duality","text":"Let mathcalS_+ be the cone of symmetric semidefinite matrices in the fracn(n+1)2 dimensional space of symmetric mathbbR^n times n matrices. That is, mathcalS_+ is the set PositiveSemidefiniteConeTriangle. It is well known that mathcalS_+ is a self-dual proper cone.","category":"page"},{"location":"background/duality/","page":"Duality","title":"Duality","text":"Let mathcalP_+ be the cone of symmetric semidefinite matrices in the n^2 dimensional space of mathbbR^n times n matrices. That is mathcalP_+ is the set PositiveSemidefiniteConeSquare.","category":"page"},{"location":"background/duality/","page":"Duality","title":"Duality","text":"In addition, let mathcalD_+ be the cone of matrices A such that A+A^top in mathcalP_+.","category":"page"},{"location":"background/duality/","page":"Duality","title":"Duality","text":"mathcalP_+ is not proper because it is not solid (it is not n^2 dimensional), so it is not necessarily true that mathcalP_+^** = mathcalP_+.","category":"page"},{"location":"background/duality/","page":"Duality","title":"Duality","text":"However, this is the case, because we will show that mathcalP_+^* = mathcalD_+ and mathcalD_+^* = mathcalP_+.","category":"page"},{"location":"background/duality/","page":"Duality","title":"Duality","text":"First, let us see why mathcalP_+^* = mathcalD_+.","category":"page"},{"location":"background/duality/","page":"Duality","title":"Duality","text":"If B is symmetric, then","category":"page"},{"location":"background/duality/","page":"Duality","title":"Duality","text":"langle AB rangle = langle A^top B^top rangle = langle A^top Brangle","category":"page"},{"location":"background/duality/","page":"Duality","title":"Duality","text":"so","category":"page"},{"location":"background/duality/","page":"Duality","title":"Duality","text":"2langle A B rangle = langle A B rangle + langle A^top B rangle = langle A + A^top B rangle","category":"page"},{"location":"background/duality/","page":"Duality","title":"Duality","text":"Therefore, langle ABrangle ge 0 for all B in mathcalP_+ if and only if langle A+A^topBrangle ge 0 for all B in mathcalP_+. Since A+A^top is symmetric, and we know that mathcalS_+ is self-dual, we have shown that mathcalP_+^* is the set of matrices A such that A+A^top in mathcalP_+.","category":"page"},{"location":"background/duality/","page":"Duality","title":"Duality","text":"Second, let us see why mathcalD_+^* = mathcalP_+.","category":"page"},{"location":"background/duality/","page":"Duality","title":"Duality","text":"Since A in mathcalD_+ implies that A^top in mathcalD_+, B in mathcalD_+^* means that langle A+A^topBrangle ge 0 for all A in mathcalD_+, and hence B in mathcalP_+.","category":"page"},{"location":"background/duality/","page":"Duality","title":"Duality","text":"To see why it should be symmetric, simply notice that if B_ij B_ji, then langle ABrangle can be made arbitrarily small by setting A_ij = A_ij + s and A_ji = A_ji - s, with s arbitrarily large, and A stays in mathcalD_+ because A+A^top does not change.","category":"page"},{"location":"background/duality/","page":"Duality","title":"Duality","text":"Typically, the primal/dual pair for semidefinite programs is presented as:","category":"page"},{"location":"background/duality/","page":"Duality","title":"Duality","text":"beginalign\n min langle C X rangle \ntextst langle A_k Xrangle = b_k forall k \n X in mathcalS_+\nendalign","category":"page"},{"location":"background/duality/","page":"Duality","title":"Duality","text":"with the dual","category":"page"},{"location":"background/duality/","page":"Duality","title":"Duality","text":"beginalign\n max sum_k b_k y_k \ntextst C - sum A_k y_k in mathcalS_+\nendalign","category":"page"},{"location":"background/duality/","page":"Duality","title":"Duality","text":"If we allow A_k to be non-symmetric, we should instead use:","category":"page"},{"location":"background/duality/","page":"Duality","title":"Duality","text":"beginalign\n min langle C X rangle \ntextst langle A_k Xrangle = b_k forall k \n X in mathcalD_+\nendalign","category":"page"},{"location":"background/duality/","page":"Duality","title":"Duality","text":"with the dual","category":"page"},{"location":"background/duality/","page":"Duality","title":"Duality","text":"beginalign\n max sum b_k y_k \ntextst C - sum A_k y_k in mathcalP_+\nendalign","category":"page"},{"location":"background/duality/","page":"Duality","title":"Duality","text":"This is implemented as:","category":"page"},{"location":"background/duality/","page":"Duality","title":"Duality","text":"beginalign\n min langle C Z rangle + langle C - C^top S rangle \ntextst langle A_k Z rangle + langle A_k - A_k^top S rangle = b_k forall k \n Z in mathcalS_+\nendalign","category":"page"},{"location":"background/duality/","page":"Duality","title":"Duality","text":"with the dual","category":"page"},{"location":"background/duality/","page":"Duality","title":"Duality","text":"beginalign\n max sum b_k y_k \ntextst C+C^top - sum (A_k+A_k^top) y_k in mathcalS_+ \n C-C^top - sum(A_k-A_k^top) y_k = 0\nendalign","category":"page"},{"location":"background/duality/","page":"Duality","title":"Duality","text":"and we recover Z = X + X^top.","category":"page"},{"location":"reference/callbacks/","page":"Callbacks","title":"Callbacks","text":"CurrentModule = MathOptInterface\nDocTestSetup = quote\n import MathOptInterface as MOI\nend\nDocTestFilters = [r\"MathOptInterface|MOI\"]","category":"page"},{"location":"reference/callbacks/#Callbacks","page":"Callbacks","title":"Callbacks","text":"","category":"section"},{"location":"reference/callbacks/","page":"Callbacks","title":"Callbacks","text":"AbstractCallback\nAbstractSubmittable\nsubmit","category":"page"},{"location":"reference/callbacks/#MathOptInterface.AbstractCallback","page":"Callbacks","title":"MathOptInterface.AbstractCallback","text":"abstract type AbstractCallback <: AbstractModelAttribute end\n\nAbstract type for a model attribute representing a callback function. The value set to subtypes of AbstractCallback is a function that may be called during optimize!. As optimize! is in progress, the result attributes (i.e, the attributes attr such that is_set_by_optimize(attr)) may not be accessible from the callback, hence trying to get result attributes might throw a OptimizeInProgress error.\n\nAt most one callback of each type can be registered. If an optimizer already has a function for a callback type, and the user registers a new function, then the old one is replaced.\n\nThe value of the attribute should be a function taking only one argument, commonly called callback_data, that can be used for instance in LazyConstraintCallback, HeuristicCallback and UserCutCallback.\n\n\n\n\n\n","category":"type"},{"location":"reference/callbacks/#MathOptInterface.AbstractSubmittable","page":"Callbacks","title":"MathOptInterface.AbstractSubmittable","text":"AbstractSubmittable\n\nAbstract supertype for objects that can be submitted to the model.\n\n\n\n\n\n","category":"type"},{"location":"reference/callbacks/#MathOptInterface.submit","page":"Callbacks","title":"MathOptInterface.submit","text":"submit(\n optimizer::AbstractOptimizer,\n sub::AbstractSubmittable,\n values...,\n)::Nothing\n\nSubmit values to the submittable sub of the optimizer optimizer.\n\nAn UnsupportedSubmittable error is thrown if model does not support the attribute attr (see supports) and a SubmitNotAllowed error is thrown if it supports the submittable sub but it cannot be submitted.\n\n\n\n\n\n","category":"function"},{"location":"reference/callbacks/#Attributes","page":"Callbacks","title":"Attributes","text":"","category":"section"},{"location":"reference/callbacks/","page":"Callbacks","title":"Callbacks","text":"CallbackNodeStatus\nCallbackVariablePrimal\nCallbackNodeStatusCode\nCALLBACK_NODE_STATUS_INTEGER\nCALLBACK_NODE_STATUS_FRACTIONAL\nCALLBACK_NODE_STATUS_UNKNOWN","category":"page"},{"location":"reference/callbacks/#MathOptInterface.CallbackNodeStatus","page":"Callbacks","title":"MathOptInterface.CallbackNodeStatus","text":"CallbackNodeStatus(callback_data)\n\nAn optimizer attribute describing the (in)feasibility of the primal solution available from CallbackVariablePrimal during a callback identified by callback_data.\n\nReturns a CallbackNodeStatusCode Enum.\n\n\n\n\n\n","category":"type"},{"location":"reference/callbacks/#MathOptInterface.CallbackVariablePrimal","page":"Callbacks","title":"MathOptInterface.CallbackVariablePrimal","text":"CallbackVariablePrimal(callback_data)\n\nA variable attribute for the assignment to some primal variable's value during the callback identified by callback_data.\n\n\n\n\n\n","category":"type"},{"location":"reference/callbacks/#MathOptInterface.CallbackNodeStatusCode","page":"Callbacks","title":"MathOptInterface.CallbackNodeStatusCode","text":"CallbackNodeStatusCode\n\nAn Enum of possible return values from calling get with CallbackNodeStatus.\n\nValues\n\nPossible values are:\n\nCALLBACK_NODE_STATUS_INTEGER: the primal solution available from CallbackVariablePrimal is integer feasible.\nCALLBACK_NODE_STATUS_FRACTIONAL: the primal solution available from CallbackVariablePrimal is integer infeasible.\nCALLBACK_NODE_STATUS_UNKNOWN: the primal solution available from CallbackVariablePrimal might be integer feasible or infeasible.\n\n\n\n\n\n","category":"type"},{"location":"reference/callbacks/#MathOptInterface.CALLBACK_NODE_STATUS_INTEGER","page":"Callbacks","title":"MathOptInterface.CALLBACK_NODE_STATUS_INTEGER","text":"CALLBACK_NODE_STATUS_INTEGER::CallbackNodeStatusCode\n\nAn instance of the CallbackNodeStatusCode enum.\n\nCALLBACK_NODE_STATUS_INTEGER: the primal solution available from CallbackVariablePrimal is integer feasible.\n\n\n\n\n\n","category":"constant"},{"location":"reference/callbacks/#MathOptInterface.CALLBACK_NODE_STATUS_FRACTIONAL","page":"Callbacks","title":"MathOptInterface.CALLBACK_NODE_STATUS_FRACTIONAL","text":"CALLBACK_NODE_STATUS_FRACTIONAL::CallbackNodeStatusCode\n\nAn instance of the CallbackNodeStatusCode enum.\n\nCALLBACK_NODE_STATUS_FRACTIONAL: the primal solution available from CallbackVariablePrimal is integer infeasible.\n\n\n\n\n\n","category":"constant"},{"location":"reference/callbacks/#MathOptInterface.CALLBACK_NODE_STATUS_UNKNOWN","page":"Callbacks","title":"MathOptInterface.CALLBACK_NODE_STATUS_UNKNOWN","text":"CALLBACK_NODE_STATUS_UNKNOWN::CallbackNodeStatusCode\n\nAn instance of the CallbackNodeStatusCode enum.\n\nCALLBACK_NODE_STATUS_UNKNOWN: the primal solution available from CallbackVariablePrimal might be integer feasible or infeasible.\n\n\n\n\n\n","category":"constant"},{"location":"reference/callbacks/#Lazy-constraints","page":"Callbacks","title":"Lazy constraints","text":"","category":"section"},{"location":"reference/callbacks/","page":"Callbacks","title":"Callbacks","text":"LazyConstraintCallback\nLazyConstraint","category":"page"},{"location":"reference/callbacks/#MathOptInterface.LazyConstraintCallback","page":"Callbacks","title":"MathOptInterface.LazyConstraintCallback","text":"LazyConstraintCallback() <: AbstractCallback\n\nThe callback can be used to reduce the feasible set given the current primal solution by submitting a LazyConstraint. For instance, it may be called at an incumbent of a mixed-integer problem. Note that there is no guarantee that the callback is called at every feasible primal solution.\n\nThe current primal solution is accessed through CallbackVariablePrimal. Trying to access other result attributes will throw OptimizeInProgress as discussed in AbstractCallback.\n\nExamples\n\nx = MOI.add_variables(optimizer, 8)\nMOI.set(optimizer, MOI.LazyConstraintCallback(), callback_data -> begin\n sol = MOI.get(optimizer, MOI.CallbackVariablePrimal(callback_data), x)\n if # should add a lazy constraint\n func = # computes function\n set = # computes set\n MOI.submit(optimizer, MOI.LazyConstraint(callback_data), func, set)\n end\nend)\n\n\n\n\n\n","category":"type"},{"location":"reference/callbacks/#MathOptInterface.LazyConstraint","page":"Callbacks","title":"MathOptInterface.LazyConstraint","text":"LazyConstraint(callback_data)\n\nLazy constraint func-in-set submitted as func, set. The optimal solution returned by VariablePrimal will satisfy all lazy constraints that have been submitted.\n\nThis can be submitted only from the LazyConstraintCallback. The field callback_data is a solver-specific callback type that is passed as the argument to the feasible solution callback.\n\nExamples\n\nSuppose x and y are VariableIndexs of optimizer. To add a LazyConstraint for 2x + 3y <= 1, write\n\nfunc = 2.0x + 3.0y\nset = MOI.LessThan(1.0)\nMOI.submit(optimizer, MOI.LazyConstraint(callback_data), func, set)\n\ninside a LazyConstraintCallback of data callback_data.\n\n\n\n\n\n","category":"type"},{"location":"reference/callbacks/#User-cuts","page":"Callbacks","title":"User cuts","text":"","category":"section"},{"location":"reference/callbacks/","page":"Callbacks","title":"Callbacks","text":"UserCutCallback\nUserCut","category":"page"},{"location":"reference/callbacks/#MathOptInterface.UserCutCallback","page":"Callbacks","title":"MathOptInterface.UserCutCallback","text":"UserCutCallback() <: AbstractCallback\n\nThe callback can be used to submit UserCut given the current primal solution. For instance, it may be called at fractional (i.e., non-integer) nodes in the branch and bound tree of a mixed-integer problem. Note that there is not guarantee that the callback is called everytime the solver has an infeasible solution.\n\nThe infeasible solution is accessed through CallbackVariablePrimal. Trying to access other result attributes will throw OptimizeInProgress as discussed in AbstractCallback.\n\nExamples\n\nx = MOI.add_variables(optimizer, 8)\nMOI.set(optimizer, MOI.UserCutCallback(), callback_data -> begin\n sol = MOI.get(optimizer, MOI.CallbackVariablePrimal(callback_data), x)\n if # can find a user cut\n func = # computes function\n set = # computes set\n MOI.submit(optimizer, MOI.UserCut(callback_data), func, set)\n end\nend\n\n\n\n\n\n","category":"type"},{"location":"reference/callbacks/#MathOptInterface.UserCut","page":"Callbacks","title":"MathOptInterface.UserCut","text":"UserCut(callback_data)\n\nConstraint func-to-set suggested to help the solver detect the solution given by CallbackVariablePrimal as infeasible. The cut is submitted as func, set. Typically CallbackVariablePrimal will violate integrality constraints, and a cut would be of the form ScalarAffineFunction-in-LessThan or ScalarAffineFunction-in-GreaterThan. Note that, as opposed to LazyConstraint, the provided constraint cannot modify the feasible set, the constraint should be redundant, e.g., it may be a consequence of affine and integrality constraints.\n\nThis can be submitted only from the UserCutCallback. The field callback_data is a solver-specific callback type that is passed as the argument to the infeasible solution callback.\n\nNote that the solver may silently ignore the provided constraint.\n\n\n\n\n\n","category":"type"},{"location":"reference/callbacks/#Heuristic-solutions","page":"Callbacks","title":"Heuristic solutions","text":"","category":"section"},{"location":"reference/callbacks/","page":"Callbacks","title":"Callbacks","text":"HeuristicCallback\nHeuristicSolution\nHeuristicSolutionStatus\nHEURISTIC_SOLUTION_ACCEPTED\nHEURISTIC_SOLUTION_REJECTED\nHEURISTIC_SOLUTION_UNKNOWN","category":"page"},{"location":"reference/callbacks/#MathOptInterface.HeuristicCallback","page":"Callbacks","title":"MathOptInterface.HeuristicCallback","text":"HeuristicCallback() <: AbstractCallback\n\nThe callback can be used to submit HeuristicSolution given the current primal solution. For example, it may be called at fractional (i.e., non-integer) nodes in the branch and bound tree of a mixed-integer problem. Note that there is no guarantee that the callback is called every time the solver has an infeasible solution.\n\nThe current primal solution is accessed through CallbackVariablePrimal. Trying to access other result attributes will throw OptimizeInProgress as discussed in AbstractCallback.\n\nExamples\n\nx = MOI.add_variables(optimizer, 8)\nMOI.set(optimizer, MOI.HeuristicCallback(), callback_data -> begin\n sol = MOI.get(optimizer, MOI.CallbackVariablePrimal(callback_data), x)\n if # can find a heuristic solution\n values = # computes heuristic solution\n MOI.submit(optimizer, MOI.HeuristicSolution(callback_data), x,\n values)\n end\nend\n\n\n\n\n\n","category":"type"},{"location":"reference/callbacks/#MathOptInterface.HeuristicSolution","page":"Callbacks","title":"MathOptInterface.HeuristicSolution","text":"HeuristicSolution(callback_data)\n\nHeuristically obtained feasible solution. The solution is submitted as variables, values where values[i] gives the value of variables[i], similarly to set. The submit call returns a HeuristicSolutionStatus indicating whether the provided solution was accepted or rejected.\n\nThis can be submitted only from the HeuristicCallback. The field callback_data is a solver-specific callback type that is passed as the argument to the heuristic callback.\n\nSome solvers require a complete solution, others only partial solutions.\n\n\n\n\n\n","category":"type"},{"location":"reference/callbacks/#MathOptInterface.HeuristicSolutionStatus","page":"Callbacks","title":"MathOptInterface.HeuristicSolutionStatus","text":"HeuristicSolutionStatus\n\nAn Enum of possible return values for submit with HeuristicSolution. This informs whether the heuristic solution was accepted or rejected.\n\nValues\n\nPossible values are:\n\nHEURISTIC_SOLUTION_ACCEPTED: The heuristic solution was accepted\nHEURISTIC_SOLUTION_REJECTED: The heuristic solution was rejected\nHEURISTIC_SOLUTION_UNKNOWN: No information available on the acceptance\n\n\n\n\n\n","category":"type"},{"location":"reference/callbacks/#MathOptInterface.HEURISTIC_SOLUTION_ACCEPTED","page":"Callbacks","title":"MathOptInterface.HEURISTIC_SOLUTION_ACCEPTED","text":"HEURISTIC_SOLUTION_ACCEPTED::HeuristicSolutionStatus\n\nAn instance of the HeuristicSolutionStatus enum.\n\nHEURISTIC_SOLUTION_ACCEPTED: The heuristic solution was accepted\n\n\n\n\n\n","category":"constant"},{"location":"reference/callbacks/#MathOptInterface.HEURISTIC_SOLUTION_REJECTED","page":"Callbacks","title":"MathOptInterface.HEURISTIC_SOLUTION_REJECTED","text":"HEURISTIC_SOLUTION_REJECTED::HeuristicSolutionStatus\n\nAn instance of the HeuristicSolutionStatus enum.\n\nHEURISTIC_SOLUTION_REJECTED: The heuristic solution was rejected\n\n\n\n\n\n","category":"constant"},{"location":"reference/callbacks/#MathOptInterface.HEURISTIC_SOLUTION_UNKNOWN","page":"Callbacks","title":"MathOptInterface.HEURISTIC_SOLUTION_UNKNOWN","text":"HEURISTIC_SOLUTION_UNKNOWN::HeuristicSolutionStatus\n\nAn instance of the HeuristicSolutionStatus enum.\n\nHEURISTIC_SOLUTION_UNKNOWN: No information available on the acceptance\n\n\n\n\n\n","category":"constant"},{"location":"reference/models/","page":"Models","title":"Models","text":"CurrentModule = MathOptInterface\nDocTestSetup = quote\n import MathOptInterface as MOI\nend\nDocTestFilters = [r\"MathOptInterface|MOI\"]","category":"page"},{"location":"reference/models/#Models","page":"Models","title":"Models","text":"","category":"section"},{"location":"reference/models/#Attribute-interface","page":"Models","title":"Attribute interface","text":"","category":"section"},{"location":"reference/models/","page":"Models","title":"Models","text":"is_set_by_optimize\nis_copyable\nget\nget!\nset\nsupports\nattribute_value_type","category":"page"},{"location":"reference/models/#MathOptInterface.is_set_by_optimize","page":"Models","title":"MathOptInterface.is_set_by_optimize","text":"is_set_by_optimize(::AnyAttribute)\n\nReturn a Bool indicating whether the value of the attribute is modified during an optimize! call, that is, the attribute is used to query the result of the optimization.\n\nImportant note when defining new attributes\n\nThis function returns false by default so it should be implemented for attributes that are modified by optimize!.\n\n\n\n\n\n","category":"function"},{"location":"reference/models/#MathOptInterface.is_copyable","page":"Models","title":"MathOptInterface.is_copyable","text":"is_copyable(::AnyAttribute)\n\nReturn a Bool indicating whether the value of the attribute may be copied during copy_to using set.\n\nImportant note when defining new attributes\n\nBy default is_copyable(attr) returns !is_set_by_optimize(attr). A specific method should be defined for attributes which are copied indirectly during copy_to. For instance, both is_copyable and is_set_by_optimize return false for the following attributes:\n\nListOfOptimizerAttributesSet, ListOfModelAttributesSet, ListOfConstraintAttributesSet and ListOfVariableAttributesSet.\nSolverName and RawSolver: these attributes cannot be set.\nNumberOfVariables and ListOfVariableIndices: these attributes are set indirectly by add_variable and add_variables.\nObjectiveFunctionType: this attribute is set indirectly when setting the ObjectiveFunction attribute.\nNumberOfConstraints, ListOfConstraintIndices, ListOfConstraintTypesPresent, CanonicalConstraintFunction, ConstraintFunction and ConstraintSet: these attributes are set indirectly by add_constraint and add_constraints.\n\n\n\n\n\n","category":"function"},{"location":"reference/models/#MathOptInterface.get","page":"Models","title":"MathOptInterface.get","text":"MOI.get(b::AbstractBridge, ::MOI.NumberOfVariables)::Int64\n\nReturn the number of variables created by the bridge b in the model.\n\nSee also MOI.NumberOfConstraints.\n\nImplementation notes\n\nThere is a default fallback, so you need only implement this if the bridge adds new variables.\n\n\n\n\n\nMOI.get(b::AbstractBridge, ::MOI.ListOfVariableIndices)\n\nReturn the list of variables created by the bridge b.\n\nSee also MOI.ListOfVariableIndices.\n\nImplementation notes\n\nThere is a default fallback, so you need only implement this if the bridge adds new variables.\n\n\n\n\n\nMOI.get(b::AbstractBridge, ::MOI.NumberOfConstraints{F,S})::Int64 where {F,S}\n\nReturn the number of constraints of the type F-in-S created by the bridge b.\n\nSee also MOI.NumberOfConstraints.\n\nImplementation notes\n\nThere is a default fallback, so you need only implement this for the constraint types returned by added_constraint_types.\n\n\n\n\n\nMOI.get(b::AbstractBridge, ::MOI.ListOfConstraintIndices{F,S}) where {F,S}\n\nReturn a Vector{ConstraintIndex{F,S}} with indices of all constraints of type F-in-S created by the bride b.\n\nSee also MOI.ListOfConstraintIndices.\n\nImplementation notes\n\nThere is a default fallback, so you need only implement this for the constraint types returned by added_constraint_types.\n\n\n\n\n\nfunction MOI.get(\n model::MOI.ModelLike,\n attr::MOI.AbstractConstraintAttribute,\n bridge::AbstractBridge,\n)\n\nReturn the value of the attribute attr of the model model for the constraint bridged by bridge.\n\n\n\n\n\nget(optimizer::AbstractOptimizer, attr::AbstractOptimizerAttribute)\n\nReturn an attribute attr of the optimizer optimizer.\n\nget(model::ModelLike, attr::AbstractModelAttribute)\n\nReturn an attribute attr of the model model.\n\nget(model::ModelLike, attr::AbstractVariableAttribute, v::VariableIndex)\n\nIf the attribute attr is set for the variable v in the model model, return its value, return nothing otherwise. If the attribute attr is not supported by model then an error should be thrown instead of returning nothing.\n\nget(model::ModelLike, attr::AbstractVariableAttribute, v::Vector{VariableIndex})\n\nReturn a vector of attributes corresponding to each variable in the collection v in the model model.\n\nget(model::ModelLike, attr::AbstractConstraintAttribute, c::ConstraintIndex)\n\nIf the attribute attr is set for the constraint c in the model model, return its value, return nothing otherwise. If the attribute attr is not supported by model then an error should be thrown instead of returning nothing.\n\nget(\n model::ModelLike,\n attr::AbstractConstraintAttribute,\n c::Vector{ConstraintIndex{F,S}},\n) where {F,S}\n\nReturn a vector of attributes corresponding to each constraint in the collection c in the model model.\n\nget(model::ModelLike, ::Type{VariableIndex}, name::String)\n\nIf a variable with name name exists in the model model, return the corresponding index, otherwise return nothing. Errors if two variables have the same name.\n\nget(\n model::ModelLike,\n ::Type{ConstraintIndex{F,S}},\n name::String,\n) where {F,S}\n\nIf an F-in-S constraint with name name exists in the model model, return the corresponding index, otherwise return nothing. Errors if two constraints have the same name.\n\nget(model::ModelLike, ::Type{ConstraintIndex}, name::String)\n\nIf any constraint with name name exists in the model model, return the corresponding index, otherwise return nothing. This version is available for convenience but may incur a performance penalty because it is not type stable. Errors if two constraints have the same name.\n\n\n\n\n\n","category":"function"},{"location":"reference/models/#MathOptInterface.get!","page":"Models","title":"MathOptInterface.get!","text":"get!(output, model::ModelLike, args...)\n\nAn in-place version of get.\n\nThe signature matches that of get except that the the result is placed in the vector output.\n\n\n\n\n\n","category":"function"},{"location":"reference/models/#MathOptInterface.set","page":"Models","title":"MathOptInterface.set","text":"function MOI.set(\n model::MOI.ModelLike,\n attr::MOI.AbstractConstraintAttribute,\n bridge::AbstractBridge,\n value,\n)\n\nSet the value of the attribute attr of the model model for the constraint bridged by bridge.\n\n\n\n\n\nset(optimizer::AbstractOptimizer, attr::AbstractOptimizerAttribute, value)\n\nAssign value to the attribute attr of the optimizer optimizer.\n\nset(model::ModelLike, attr::AbstractModelAttribute, value)\n\nAssign value to the attribute attr of the model model.\n\nset(model::ModelLike, attr::AbstractVariableAttribute, v::VariableIndex, value)\n\nAssign value to the attribute attr of variable v in model model.\n\nset(\n model::ModelLike,\n attr::AbstractVariableAttribute,\n v::Vector{VariableIndex},\n vector_of_values,\n)\n\nAssign a value respectively to the attribute attr of each variable in the collection v in model model.\n\nset(\n model::ModelLike,\n attr::AbstractConstraintAttribute,\n c::ConstraintIndex,\n value,\n)\n\nAssign a value to the attribute attr of constraint c in model model.\n\nset(\n model::ModelLike,\n attr::AbstractConstraintAttribute,\n c::Vector{ConstraintIndex{F,S}},\n vector_of_values,\n) where {F,S}\n\nAssign a value respectively to the attribute attr of each constraint in the collection c in model model.\n\nAn UnsupportedAttribute error is thrown if model does not support the attribute attr (see supports) and a SetAttributeNotAllowed error is thrown if it supports the attribute attr but it cannot be set.\n\nset(\n model::ModelLike,\n ::ConstraintSet,\n c::ConstraintIndex{F,S},\n set::S,\n) where {F,S}\n\nChange the set of constraint c to the new set set which should be of the same type as the original set.\n\nset(\n model::ModelLike,\n ::ConstraintFunction,\n c::ConstraintIndex{F,S},\n func::F,\n) where {F,S}\n\nReplace the function in constraint c with func. F must match the original function type used to define the constraint.\n\nnote: Note\nSetting the constraint function is not allowed if F is VariableIndex; a SettingVariableIndexNotAllowed error is thrown instead. This is because, it would require changing the index c since the index of VariableIndex constraints must be the same as the index of the variable.\n\n\n\n\n\n","category":"function"},{"location":"reference/models/#MathOptInterface.supports","page":"Models","title":"MathOptInterface.supports","text":"MOI.supports(\n model::MOI.ModelLike,\n attr::MOI.AbstractConstraintAttribute,\n BT::Type{<:AbstractBridge},\n)\n\nReturn a Bool indicating whether BT supports setting attr to model.\n\n\n\n\n\nsupports(model::ModelLike, sub::AbstractSubmittable)::Bool\n\nReturn a Bool indicating whether model supports the submittable sub.\n\nsupports(model::ModelLike, attr::AbstractOptimizerAttribute)::Bool\n\nReturn a Bool indicating whether model supports the optimizer attribute attr. That is, it returns false if copy_to(model, src) shows a warning in case attr is in the ListOfOptimizerAttributesSet of src; see copy_to for more details on how unsupported optimizer attributes are handled in copy.\n\nsupports(model::ModelLike, attr::AbstractModelAttribute)::Bool\n\nReturn a Bool indicating whether model supports the model attribute attr. That is, it returns false if copy_to(model, src) cannot be performed in case attr is in the ListOfModelAttributesSet of src.\n\nsupports(\n model::ModelLike,\n attr::AbstractVariableAttribute,\n ::Type{VariableIndex},\n)::Bool\n\nReturn a Bool indicating whether model supports the variable attribute attr. That is, it returns false if copy_to(model, src) cannot be performed in case attr is in the ListOfVariableAttributesSet of src.\n\nsupports(\n model::ModelLike,\n attr::AbstractConstraintAttribute,\n ::Type{ConstraintIndex{F,S}},\n)::Bool where {F,S}\n\nReturn a Bool indicating whether model supports the constraint attribute attr applied to an F-in-S constraint. That is, it returns false if copy_to(model, src) cannot be performed in case attr is in the ListOfConstraintAttributesSet of src.\n\nFor all five methods, if the attribute is only not supported in specific circumstances, it should still return true.\n\nNote that supports is only defined for attributes for which is_copyable returns true as other attributes do not appear in the list of attributes set obtained by ListOf...AttributesSet.\n\n\n\n\n\n","category":"function"},{"location":"reference/models/#MathOptInterface.attribute_value_type","page":"Models","title":"MathOptInterface.attribute_value_type","text":"attribute_value_type(attr::AnyAttribute)\n\nGiven an attribute attr, return the type of value expected by get, or returned by set.\n\nNotes\n\nOnly implement this if it make sense to do so. If un-implemented, the default is Any.\n\n\n\n\n\n","category":"function"},{"location":"reference/models/#Model-interface","page":"Models","title":"Model interface","text":"","category":"section"},{"location":"reference/models/","page":"Models","title":"Models","text":"ModelLike\nis_empty\nempty!\nwrite_to_file\nread_from_file\nsupports_incremental_interface\ncopy_to\nIndexMap","category":"page"},{"location":"reference/models/#MathOptInterface.ModelLike","page":"Models","title":"MathOptInterface.ModelLike","text":"ModelLike\n\nAbstract supertype for objects that implement the \"Model\" interface for defining an optimization problem.\n\n\n\n\n\n","category":"type"},{"location":"reference/models/#MathOptInterface.is_empty","page":"Models","title":"MathOptInterface.is_empty","text":"is_empty(model::ModelLike)\n\nReturns false if the model has any model attribute set or has any variables or constraints.\n\nNote that an empty model can have optimizer attributes set.\n\n\n\n\n\n","category":"function"},{"location":"reference/models/#MathOptInterface.empty!","page":"Models","title":"MathOptInterface.empty!","text":"empty!(model::ModelLike)\n\nEmpty the model, that is, remove all variables, constraints and model attributes but not optimizer attributes.\n\n\n\n\n\n","category":"function"},{"location":"reference/models/#MathOptInterface.write_to_file","page":"Models","title":"MathOptInterface.write_to_file","text":"write_to_file(model::ModelLike, filename::String)\n\nWrite the current model to the file at filename.\n\nSupported file types depend on the model type.\n\n\n\n\n\n","category":"function"},{"location":"reference/models/#MathOptInterface.read_from_file","page":"Models","title":"MathOptInterface.read_from_file","text":"read_from_file(model::ModelLike, filename::String)\n\nRead the file filename into the model model. If model is non-empty, this may throw an error.\n\nSupported file types depend on the model type.\n\nNote\n\nOnce the contents of the file are loaded into the model, users can query the variables via get(model, ListOfVariableIndices()). However, some filetypes, such as LP files, do not maintain an explicit ordering of the variables. Therefore, the returned list may be in an arbitrary order.\n\nTo avoid depending on the order of the indices, look up each variable index by name using get(model, VariableIndex, \"name\").\n\n\n\n\n\n","category":"function"},{"location":"reference/models/#MathOptInterface.supports_incremental_interface","page":"Models","title":"MathOptInterface.supports_incremental_interface","text":"supports_incremental_interface(model::ModelLike)\n\nReturn a Bool indicating whether model supports building incrementally via add_variable and add_constraint.\n\nThe main purpose of this function is to determine whether a model can be loaded into model incrementally or whether it should be cached and copied at once instead.\n\n\n\n\n\n","category":"function"},{"location":"reference/models/#MathOptInterface.copy_to","page":"Models","title":"MathOptInterface.copy_to","text":"copy_to(dest::ModelLike, src::ModelLike)::IndexMap\n\nCopy the model from src into dest.\n\nThe target dest is emptied, and all previous indices to variables and constraints in dest are invalidated.\n\nReturns an IndexMap object that translates variable and constraint indices from the src model to the corresponding indices in the dest model.\n\nNotes\n\nIf a constraint that in src is not supported by dest, then an UnsupportedConstraint error is thrown.\nIf an AbstractModelAttribute, AbstractVariableAttribute, or AbstractConstraintAttribute is set in src but not supported by dest, then an UnsupportedAttribute error is thrown.\n\nAbstractOptimizerAttributes are not copied to the dest model.\n\nIndexMap\n\nImplementations of copy_to must return an IndexMap. For technical reasons, this type is defined in the Utilities submodule as MOI.Utilities.IndexMap. However, since it is an integral part of the MOI API, we provide MOI.IndexMap as an alias.\n\nExample\n\n# Given empty `ModelLike` objects `src` and `dest`.\n\nx = add_variable(src)\n\nis_valid(src, x) # true\nis_valid(dest, x) # false (`dest` has no variables)\n\nindex_map = copy_to(dest, src)\nis_valid(dest, x) # false (unless index_map[x] == x)\nis_valid(dest, index_map[x]) # true\n\n\n\n\n\n","category":"function"},{"location":"reference/models/#MathOptInterface.IndexMap","page":"Models","title":"MathOptInterface.IndexMap","text":"IndexMap()\n\nThe dictionary-like object returned by copy_to.\n\nIndexMap\n\nImplementations of copy_to must return an IndexMap. For technical reasons, the IndexMap type is defined in the Utilities submodule as MOI.Utilities.IndexMap. However, since it is an integral part of the MOI API, we provide this MOI.IndexMap as an alias.\n\n\n\n\n\n","category":"type"},{"location":"reference/models/#Model-attributes","page":"Models","title":"Model attributes","text":"","category":"section"},{"location":"reference/models/","page":"Models","title":"Models","text":"AbstractModelAttribute\nName\nObjectiveFunction\nObjectiveFunctionType\nObjectiveSense\nOptimizationSense\nMIN_SENSE\nMAX_SENSE\nFEASIBILITY_SENSE\nNumberOfVariables\nListOfVariableIndices\nListOfConstraintTypesPresent\nNumberOfConstraints\nListOfConstraintIndices\nListOfOptimizerAttributesSet\nListOfModelAttributesSet\nListOfVariableAttributesSet\nListOfConstraintAttributesSet\nUserDefinedFunction\nListOfSupportedNonlinearOperators","category":"page"},{"location":"reference/models/#MathOptInterface.AbstractModelAttribute","page":"Models","title":"MathOptInterface.AbstractModelAttribute","text":"AbstractModelAttribute\n\nAbstract supertype for attribute objects that can be used to set or get attributes (properties) of the model.\n\n\n\n\n\n","category":"type"},{"location":"reference/models/#MathOptInterface.Name","page":"Models","title":"MathOptInterface.Name","text":"Name()\n\nA model attribute for the string identifying the model. It has a default value of \"\" if not set`.\n\n\n\n\n\n","category":"type"},{"location":"reference/models/#MathOptInterface.ObjectiveFunction","page":"Models","title":"MathOptInterface.ObjectiveFunction","text":"ObjectiveFunction{F<:AbstractScalarFunction}()\n\nA model attribute for the objective function which has a type F<:AbstractScalarFunction.\n\nF should be guaranteed to be equivalent but not necessarily identical to the function type provided by the user.\n\nThrows an InexactError if the objective function cannot be converted to F, e.g., the objective function is quadratic and F is ScalarAffineFunction{Float64} or it has non-integer coefficient and F is ScalarAffineFunction{Int}.\n\n\n\n\n\n","category":"type"},{"location":"reference/models/#MathOptInterface.ObjectiveFunctionType","page":"Models","title":"MathOptInterface.ObjectiveFunctionType","text":"ObjectiveFunctionType()\n\nA model attribute for the type F of the objective function set using the ObjectiveFunction{F} attribute.\n\nExamples\n\nIn the following code, attr should be equal to MOI.VariableIndex:\n\nx = MOI.add_variable(model)\nMOI.set(model, MOI.ObjectiveFunction{MOI.VariableIndex}(), x)\nattr = MOI.get(model, MOI.ObjectiveFunctionType())\n\n\n\n\n\n","category":"type"},{"location":"reference/models/#MathOptInterface.ObjectiveSense","page":"Models","title":"MathOptInterface.ObjectiveSense","text":"ObjectiveSense()\n\nA model attribute for the objective sense of the objective function, which must be an OptimizationSense: MIN_SENSE, MAX_SENSE, or FEASIBILITY_SENSE. The default is FEASIBILITY_SENSE.\n\nInteraction with ObjectiveFunction\n\nSetting the sense to FEASIBILITY_SENSE unsets the ObjectiveFunction attribute. That is, if you first set ObjectiveFunction and then set ObjectiveSense to be FEASIBILITY_SENSE, no objective function will be passed to the solver.\n\nIn addition, some reformulations of ObjectiveFunction via bridges rely on the value of ObjectiveSense. Therefore, you should set ObjectiveSense before setting ObjectiveFunction.\n\n\n\n\n\n","category":"type"},{"location":"reference/models/#MathOptInterface.OptimizationSense","page":"Models","title":"MathOptInterface.OptimizationSense","text":"OptimizationSense\n\nAn enum for the value of the ObjectiveSense attribute.\n\nValues\n\nPossible values are:\n\nMIN_SENSE: the goal is to minimize the objective function\nMAX_SENSE: the goal is to maximize the objective function\nFEASIBILITY_SENSE: the model does not have an objective function\n\n\n\n\n\n","category":"type"},{"location":"reference/models/#MathOptInterface.MIN_SENSE","page":"Models","title":"MathOptInterface.MIN_SENSE","text":"MIN_SENSE::OptimizationSense\n\nAn instance of the OptimizationSense enum.\n\nMIN_SENSE: the goal is to minimize the objective function\n\n\n\n\n\n","category":"constant"},{"location":"reference/models/#MathOptInterface.MAX_SENSE","page":"Models","title":"MathOptInterface.MAX_SENSE","text":"MAX_SENSE::OptimizationSense\n\nAn instance of the OptimizationSense enum.\n\nMAX_SENSE: the goal is to maximize the objective function\n\n\n\n\n\n","category":"constant"},{"location":"reference/models/#MathOptInterface.FEASIBILITY_SENSE","page":"Models","title":"MathOptInterface.FEASIBILITY_SENSE","text":"FEASIBILITY_SENSE::OptimizationSense\n\nAn instance of the OptimizationSense enum.\n\nFEASIBILITY_SENSE: the model does not have an objective function\n\n\n\n\n\n","category":"constant"},{"location":"reference/models/#MathOptInterface.NumberOfVariables","page":"Models","title":"MathOptInterface.NumberOfVariables","text":"NumberOfVariables()\n\nA model attribute for the number of variables in the model.\n\n\n\n\n\n","category":"type"},{"location":"reference/models/#MathOptInterface.ListOfVariableIndices","page":"Models","title":"MathOptInterface.ListOfVariableIndices","text":"ListOfVariableIndices()\n\nA model attribute for the Vector{VariableIndex} of all variable indices present in the model (i.e., of length equal to the value of NumberOfVariables in the order in which they were added.\n\n\n\n\n\n","category":"type"},{"location":"reference/models/#MathOptInterface.ListOfConstraintTypesPresent","page":"Models","title":"MathOptInterface.ListOfConstraintTypesPresent","text":"ListOfConstraintTypesPresent()\n\nA model attribute for the list of tuples of the form (F,S), where F is a function type and S is a set type indicating that the attribute NumberOfConstraints{F,S} has a value greater than zero.\n\n\n\n\n\n","category":"type"},{"location":"reference/models/#MathOptInterface.NumberOfConstraints","page":"Models","title":"MathOptInterface.NumberOfConstraints","text":"NumberOfConstraints{F,S}()\n\nA model attribute for the number of constraints of the type F-in-S present in the model.\n\n\n\n\n\n","category":"type"},{"location":"reference/models/#MathOptInterface.ListOfConstraintIndices","page":"Models","title":"MathOptInterface.ListOfConstraintIndices","text":"ListOfConstraintIndices{F,S}()\n\nA model attribute for the Vector{ConstraintIndex{F,S}} of all constraint indices of type F-in-S in the model (i.e., of length equal to the value of NumberOfConstraints{F,S}) in the order in which they were added.\n\n\n\n\n\n","category":"type"},{"location":"reference/models/#MathOptInterface.ListOfOptimizerAttributesSet","page":"Models","title":"MathOptInterface.ListOfOptimizerAttributesSet","text":"ListOfOptimizerAttributesSet()\n\nAn optimizer attribute for the Vector{AbstractOptimizerAttribute} of all optimizer attributes that were set.\n\n\n\n\n\n","category":"type"},{"location":"reference/models/#MathOptInterface.ListOfModelAttributesSet","page":"Models","title":"MathOptInterface.ListOfModelAttributesSet","text":"ListOfModelAttributesSet()\n\nA model attribute for the Vector{AbstractModelAttribute} of all model attributes attr such that:\n\nis_copyable(attr) returns true, and\nthe attribute was set to the model\n\n\n\n\n\n","category":"type"},{"location":"reference/models/#MathOptInterface.ListOfVariableAttributesSet","page":"Models","title":"MathOptInterface.ListOfVariableAttributesSet","text":"ListOfVariableAttributesSet()\n\nA model attribute for the Vector{AbstractVariableAttribute} of all variable attributes attr such that 1) is_copyable(attr) returns true and 2) the attribute was set to variables.\n\n\n\n\n\n","category":"type"},{"location":"reference/models/#MathOptInterface.ListOfConstraintAttributesSet","page":"Models","title":"MathOptInterface.ListOfConstraintAttributesSet","text":"ListOfConstraintAttributesSet{F, S}()\n\nA model attribute for the Vector{AbstractConstraintAttribute} of all constraint attributes attr such that:\n\nis_copyable(attr) returns true and\nthe attribute was set to F-in-S constraints.\n\nNote\n\nThe attributes ConstraintFunction and ConstraintSet should not be included in the list even if then have been set with set.\n\n\n\n\n\n","category":"type"},{"location":"reference/models/#MathOptInterface.UserDefinedFunction","page":"Models","title":"MathOptInterface.UserDefinedFunction","text":"UserDefinedFunction(name::Symbol, arity::Int) <: AbstractModelAttribute\n\nSet this attribute to register a user-defined function by the name of name with arity arguments.\n\nOnce registered, name will appear in ListOfSupportedNonlinearOperators.\n\nYou cannot register multiple UserDefinedFunctions with the same name but different arity.\n\nValue type\n\nThe value to be set is a tuple containing one, two, or three functions to evaluate the function, the first-order derivative, and the second-order derivative respectively. Both derivatives are optional, but if you pass the second-order derivative you must also pass the first-order derivative.\n\nFor univariate functions with arity == 1, the functions in the tuple must have the form:\n\nf(x::T)::T: returns the value of the function at x\n∇f(x::T)::T: returns the first-order derivative of f with respect to x\n∇²f(x::T)::T: returns the second-order derivative of f with respect to x.\n\nFor multivariate functions with arity > 1, the functions in the tuple must have the form:\n\nf(x::T...)::T: returns the value of the function at x\n∇f(g::AbstractVector{T}, x::T...)::Nothing: fills the components of g, with g[i] being the first-order partial derivative of f with respect to x[i]\n∇²f(H::AbstractMatrix{T}, x::T...)::Nothing: fills the non-zero components of H, with H[i, j] being the second-order partial derivative of f with respect to x[i] and then x[j]. H is initialized to the zero matrix, so you do not need to set any zero elements.\n\nExamples\n\njulia> import MathOptInterface as MOI\n\njulia> f(x, y) = x^2 + y^2\nf (generic function with 1 method)\n\njulia> function ∇f(g, x, y)\n g .= 2 * x, 2 * y\n return\n end\n∇f (generic function with 1 method)\n\njulia> function ∇²f(H, x...)\n H[1, 1] = H[2, 2] = 2.0\n return\n end\n∇²f (generic function with 1 method)\n\njulia> model = MOI.Utilities.UniversalFallback(MOI.Utilities.Model{Float64}())\nMOIU.UniversalFallback{MOIU.Model{Float64}}\nfallback for MOIU.Model{Float64}\n\njulia> MOI.set(model, MOI.UserDefinedFunction(:f, 2), (f,))\n\njulia> MOI.set(model, MOI.UserDefinedFunction(:g, 2), (f, ∇f))\n\njulia> MOI.set(model, MOI.UserDefinedFunction(:h, 2), (f, ∇f, ∇²f))\n\njulia> x = MOI.add_variables(model, 2)\n2-element Vector{MathOptInterface.VariableIndex}:\n MOI.VariableIndex(1)\n MOI.VariableIndex(2)\n\njulia> MOI.set(model, MOI.ObjectiveSense(), MOI.MIN_SENSE)\n\njulia> obj_f = MOI.ScalarNonlinearFunction(:f, Any[x[1], x[2]])\nf(MOI.VariableIndex(1), MOI.VariableIndex(2))\n\njulia> MOI.set(model, MOI.ObjectiveFunction{typeof(obj_f)}(), obj_f)\n\njulia> print(model)\nMinimize ScalarNonlinearFunction:\n f(v[1], v[2])\n\nSubject to:\n\n\n\n\n\n\n","category":"type"},{"location":"reference/models/#MathOptInterface.ListOfSupportedNonlinearOperators","page":"Models","title":"MathOptInterface.ListOfSupportedNonlinearOperators","text":"ListOfSupportedNonlinearOperators() <: AbstractModelAttribute\n\nWhen queried with get, return a Vector{Symbol} listing the operators supported by the model.\n\n\n\n\n\n","category":"type"},{"location":"reference/models/#Optimizer-interface","page":"Models","title":"Optimizer interface","text":"","category":"section"},{"location":"reference/models/","page":"Models","title":"Models","text":"AbstractOptimizer\nOptimizerWithAttributes\noptimize!\noptimize!(::ModelLike, ::ModelLike)\ninstantiate\ndefault_cache","category":"page"},{"location":"reference/models/#MathOptInterface.AbstractOptimizer","page":"Models","title":"MathOptInterface.AbstractOptimizer","text":"AbstractOptimizer <: ModelLike\n\nAbstract supertype for objects representing an instance of an optimization problem tied to a particular solver. This is typically a solver's in-memory representation. In addition to ModelLike, AbstractOptimizer objects let you solve the model and query the solution.\n\n\n\n\n\n","category":"type"},{"location":"reference/models/#MathOptInterface.OptimizerWithAttributes","page":"Models","title":"MathOptInterface.OptimizerWithAttributes","text":"struct OptimizerWithAttributes\n optimizer_constructor\n params::Vector{Pair{AbstractOptimizerAttribute,<:Any}}\nend\n\nObject grouping an optimizer constructor and a list of optimizer attributes. Instances are created with instantiate.\n\n\n\n\n\n","category":"type"},{"location":"reference/models/#MathOptInterface.optimize!","page":"Models","title":"MathOptInterface.optimize!","text":"optimize!(optimizer::AbstractOptimizer)\n\nOptimize the problem contained in optimizer.\n\nBefore calling optimize!, the problem should first be constructed using the incremental interface (see supports_incremental_interface) or copy_to.\n\n\n\n\n\n","category":"function"},{"location":"reference/models/#MathOptInterface.optimize!-Tuple{MathOptInterface.ModelLike, MathOptInterface.ModelLike}","page":"Models","title":"MathOptInterface.optimize!","text":"optimize!(dest::AbstractOptimizer, src::ModelLike)::Tuple{IndexMap,Bool}\n\nA \"one-shot\" call that copies the problem from src into dest and then uses dest to optimize the problem.\n\nReturns a tuple of an IndexMap and a Bool copied.\n\nThe IndexMap object translates variable and constraint indices from the src model to the corresponding indices in the dest optimizer. See copy_to for details.\nIf copied == true, src was copied to dest and then cached, allowing incremental modification if supported by the solver.\nIf copied == false, a cache of the model was not kept in dest. Therefore, only the solution information (attributes for which is_set_by_optimize is true) is available to query.\n\nnote: Note\nThe main purpose of optimize! method with two arguments is for use in Utilities.CachingOptimizer.\n\nRelationship to the single-argument optimize!\n\nThe default fallback of optimize!(dest::AbstractOptimizer, src::ModelLike) is\n\nfunction optimize!(dest::AbstractOptimizer, src::ModelLike)\n index_map = copy_to(dest, src)\n optimize!(dest)\n return index_map, true\nend\n\nTherefore, subtypes of AbstractOptimizer should either implement this two-argument method, or implement both copy_to(::Optimizer, ::ModelLike) and optimize!(::Optimizer).\n\n\n\n\n\n","category":"method"},{"location":"reference/models/#MathOptInterface.instantiate","page":"Models","title":"MathOptInterface.instantiate","text":"instantiate(\n optimizer_constructor,\n with_cache_type::Union{Nothing,Type} = nothing,\n with_bridge_type::Union{Nothing,Type} = nothing,\n)\n\nCreate an instance of an optimizer by either:\n\ncalling optimizer_constructor.optimizer_constructor() and setting the parameters in optimizer_constructor.params if optimizer_constructor is a OptimizerWithAttributes\ncalling optimizer_constructor() if optimizer_constructor is callable.\n\nwithcachetype\n\nIf with_cache_type is not nothing, then the optimizer is wrapped in a Utilities.CachingOptimizer to store a cache of the model. This is most useful if the optimizer you are constructing does not support the incremental interface (see supports_incremental_interface).\n\nwithbridgetype\n\nIf with_bridge_type is not nothing, the optimizer is wrapped in a Bridges.full_bridge_optimizer, enabling all the bridges defined in the MOI.Bridges submodule with coefficient type with_bridge_type.\n\nIn addition, if the optimizer created by optimizer_constructor does not support the incremental interface (see supports_incremental_interface), then, irrespective of with_cache_type, the optimizer is wrapped in a Utilities.CachingOptimizer to store a cache of the bridged model.\n\nIf with_cache_type and with_bridge_type are both not nothing, then they must be the same type.\n\n\n\n\n\n","category":"function"},{"location":"reference/models/#MathOptInterface.default_cache","page":"Models","title":"MathOptInterface.default_cache","text":"default_cache(optimizer::ModelLike, ::Type{T}) where {T}\n\nReturn a new instance of the default model type to be used as cache for optimizer in a Utilities.CachingOptimizer for holding constraints of coefficient type T. By default, this returns Utilities.UniversalFallback(Utilities.Model{T}()). If copying from a instance of a given model type is faster for optimizer then a new method returning an instance of this model type should be defined.\n\n\n\n\n\n","category":"function"},{"location":"reference/models/#Optimizer-attributes","page":"Models","title":"Optimizer attributes","text":"","category":"section"},{"location":"reference/models/","page":"Models","title":"Models","text":"AbstractOptimizerAttribute\nSolverName\nSolverVersion\nSilent\nTimeLimitSec\nObjectiveLimit\nRawOptimizerAttribute\nNumberOfThreads\nRawSolver\nAbsoluteGapTolerance\nRelativeGapTolerance","category":"page"},{"location":"reference/models/#MathOptInterface.AbstractOptimizerAttribute","page":"Models","title":"MathOptInterface.AbstractOptimizerAttribute","text":"AbstractOptimizerAttribute\n\nAbstract supertype for attribute objects that can be used to set or get attributes (properties) of the optimizer.\n\nNotes\n\nThe difference between AbstractOptimizerAttribute and AbstractModelAttribute lies in the behavior of is_empty, empty! and copy_to. Typically optimizer attributes affect only how the model is solved.\n\n\n\n\n\n","category":"type"},{"location":"reference/models/#MathOptInterface.SolverName","page":"Models","title":"MathOptInterface.SolverName","text":"SolverName()\n\nAn optimizer attribute for the string identifying the solver/optimizer.\n\n\n\n\n\n","category":"type"},{"location":"reference/models/#MathOptInterface.SolverVersion","page":"Models","title":"MathOptInterface.SolverVersion","text":"SolverVersion()\n\nAn optimizer attribute for the string identifying the version of the solver.\n\nnote: Note\nFor solvers supporting semantic versioning, the SolverVersion should be a string of the form \"vMAJOR.MINOR.PATCH\", so that it can be converted to a Julia VersionNumber (e.g., `VersionNumber(\"v1.2.3\")).We do not require Semantic Versioning because some solvers use alternate versioning systems. For example, CPLEX uses Calendar Versioning, so SolverVersion will return a string like \"202001\".\n\n\n\n\n\n","category":"type"},{"location":"reference/models/#MathOptInterface.Silent","page":"Models","title":"MathOptInterface.Silent","text":"Silent()\n\nAn optimizer attribute for silencing the output of an optimizer. When set to true, it takes precedence over any other attribute controlling verbosity and requires the solver to produce no output. The default value is false which has no effect. In this case the verbosity is controlled by other attributes.\n\nNote\n\nEvery optimizer should have verbosity on by default. For instance, if a solver has a solver-specific log level attribute, the MOI implementation should set it to 1 by default. If the user sets Silent to true, then the log level should be set to 0, even if the user specifically sets a value of log level. If the value of Silent is false then the log level set to the solver is the value given by the user for this solver-specific parameter or 1 if none is given.\n\n\n\n\n\n","category":"type"},{"location":"reference/models/#MathOptInterface.TimeLimitSec","page":"Models","title":"MathOptInterface.TimeLimitSec","text":"TimeLimitSec()\n\nAn optimizer attribute for setting a time limit (in seconnds) for an optimization. When set to nothing, it deactivates the solver time limit. The default value is nothing.\n\n\n\n\n\n","category":"type"},{"location":"reference/models/#MathOptInterface.ObjectiveLimit","page":"Models","title":"MathOptInterface.ObjectiveLimit","text":"ObjectiveLimit()\n\nAn optimizer attribute for setting a limit on the objective value.\n\nThe provided limit must be a Union{Real,Nothing}.\n\nWhen set to nothing, the limit reverts to the solver's default.\n\nThe default value is nothing.\n\nThe solver may stop when the ObjectiveValue is better (lower for minimization, higher for maximization) than the ObjectiveLimit. If stopped, the TerminationStatus should be OBJECTIVE_LIMIT.\n\n\n\n\n\n","category":"type"},{"location":"reference/models/#MathOptInterface.RawOptimizerAttribute","page":"Models","title":"MathOptInterface.RawOptimizerAttribute","text":"RawOptimizerAttribute(name::String)\n\nAn optimizer attribute for the solver-specific parameter identified by name.\n\n\n\n\n\n","category":"type"},{"location":"reference/models/#MathOptInterface.NumberOfThreads","page":"Models","title":"MathOptInterface.NumberOfThreads","text":"NumberOfThreads()\n\nAn optimizer attribute for setting the number of threads used for an optimization. When set to nothing uses solver default. Values are positive integers. The default value is nothing.\n\n\n\n\n\n","category":"type"},{"location":"reference/models/#MathOptInterface.RawSolver","page":"Models","title":"MathOptInterface.RawSolver","text":"RawSolver()\n\nA model attribute for the object that may be used to access a solver-specific API for this optimizer.\n\n\n\n\n\n","category":"type"},{"location":"reference/models/#MathOptInterface.AbsoluteGapTolerance","page":"Models","title":"MathOptInterface.AbsoluteGapTolerance","text":"AbsoluteGapTolerance()\n\nAn optimizer attribute for setting the absolute gap tolerance for an optimization. This is an optimizer attribute, and should be set before calling optimize!. When set to nothing (if supported), uses solver default.\n\nTo set a relative gap tolerance, see RelativeGapTolerance.\n\nwarning: Warning\nThe mathematical definition of \"absolute gap\", and its treatment during the optimization, are solver-dependent. However, assuming no other limit nor issue is encountered during the optimization, most solvers that implement this attribute will stop once f - b g_abs, where b is the best bound, f is the best feasible objective value, and g_abs is the absolute gap.\n\n\n\n\n\n","category":"type"},{"location":"reference/models/#MathOptInterface.RelativeGapTolerance","page":"Models","title":"MathOptInterface.RelativeGapTolerance","text":"RelativeGapTolerance()\n\nAn optimizer attribute for setting the relative gap tolerance for an optimization. This is an optimizer attribute, and should be set before calling optimize!. When set to nothing (if supported), uses solver default.\n\nIf you are looking for the relative gap of the current best solution, see RelativeGap. If no limit nor issue is encountered during the optimization, the value of RelativeGap should be at most as large as RelativeGapTolerance.\n\n# Before optimizing: set relative gap tolerance\n# set 0.1% relative gap tolerance\nMOI.set(model, MOI.RelativeGapTolerance(), 1e-3)\nMOI.optimize!(model)\n\n# After optimizing (assuming all went well)\n# The relative gap tolerance has not changed...\nMOI.get(model, MOI.RelativeGapTolerance()) # returns 1e-3\n# ... and the relative gap of the obtained solution is smaller or equal to the\n# tolerance\nMOI.get(model, MOI.RelativeGap()) # should return something ≤ 1e-3\n\nwarning: Warning\nThe mathematical definition of \"relative gap\", and its allowed range, are solver-dependent. Typically, solvers expect a value between 0.0 and 1.0.\n\n\n\n\n\n","category":"type"},{"location":"reference/models/","page":"Models","title":"Models","text":"List of attributes useful for optimizers","category":"page"},{"location":"reference/models/","page":"Models","title":"Models","text":"TerminationStatus\nTerminationStatusCode\nOPTIMIZE_NOT_CALLED\nOPTIMAL\nINFEASIBLE\nDUAL_INFEASIBLE\nLOCALLY_SOLVED\nLOCALLY_INFEASIBLE\nINFEASIBLE_OR_UNBOUNDED\nALMOST_OPTIMAL\nALMOST_INFEASIBLE\nALMOST_DUAL_INFEASIBLE\nALMOST_LOCALLY_SOLVED\nITERATION_LIMIT\nTIME_LIMIT\nNODE_LIMIT\nSOLUTION_LIMIT\nMEMORY_LIMIT\nOBJECTIVE_LIMIT\nNORM_LIMIT\nOTHER_LIMIT\nSLOW_PROGRESS\nNUMERICAL_ERROR\nINVALID_MODEL\nINVALID_OPTION\nINTERRUPTED\nOTHER_ERROR\nPrimalStatus\nDualStatus\nRawStatusString\nResultCount\nObjectiveValue\nDualObjectiveValue\nObjectiveBound\nRelativeGap\nSolveTimeSec\nSimplexIterations\nBarrierIterations\nNodeCount","category":"page"},{"location":"reference/models/#MathOptInterface.TerminationStatus","page":"Models","title":"MathOptInterface.TerminationStatus","text":"TerminationStatus()\n\nA model attribute for the TerminationStatusCode explaining why the optimizer stopped.\n\n\n\n\n\n","category":"type"},{"location":"reference/models/#MathOptInterface.TerminationStatusCode","page":"Models","title":"MathOptInterface.TerminationStatusCode","text":"TerminationStatusCode\n\nAn Enum of possible values for the TerminationStatus attribute. This attribute is meant to explain the reason why the optimizer stopped executing in the most recent call to optimize!.\n\nValues\n\nPossible values are:\n\nOPTIMIZE_NOT_CALLED: The algorithm has not started.\nOPTIMAL: The algorithm found a globally optimal solution.\nINFEASIBLE: The algorithm concluded that no feasible solution exists.\nDUAL_INFEASIBLE: The algorithm concluded that no dual bound exists for the problem. If, additionally, a feasible (primal) solution is known to exist, this status typically implies that the problem is unbounded, with some technical exceptions.\nLOCALLY_SOLVED: The algorithm converged to a stationary point, local optimal solution, could not find directions for improvement, or otherwise completed its search without global guarantees.\nLOCALLY_INFEASIBLE: The algorithm converged to an infeasible point or otherwise completed its search without finding a feasible solution, without guarantees that no feasible solution exists.\nINFEASIBLE_OR_UNBOUNDED: The algorithm stopped because it decided that the problem is infeasible or unbounded; this occasionally happens during MIP presolve.\nALMOST_OPTIMAL: The algorithm found a globally optimal solution to relaxed tolerances.\nALMOST_INFEASIBLE: The algorithm concluded that no feasible solution exists within relaxed tolerances.\nALMOST_DUAL_INFEASIBLE: The algorithm concluded that no dual bound exists for the problem within relaxed tolerances.\nALMOST_LOCALLY_SOLVED: The algorithm converged to a stationary point, local optimal solution, or could not find directions for improvement within relaxed tolerances.\nITERATION_LIMIT: An iterative algorithm stopped after conducting the maximum number of iterations.\nTIME_LIMIT: The algorithm stopped after a user-specified computation time.\nNODE_LIMIT: A branch-and-bound algorithm stopped because it explored a maximum number of nodes in the branch-and-bound tree.\nSOLUTION_LIMIT: The algorithm stopped because it found the required number of solutions. This is often used in MIPs to get the solver to return the first feasible solution it encounters.\nMEMORY_LIMIT: The algorithm stopped because it ran out of memory.\nOBJECTIVE_LIMIT: The algorithm stopped because it found a solution better than a minimum limit set by the user.\nNORM_LIMIT: The algorithm stopped because the norm of an iterate became too large.\nOTHER_LIMIT: The algorithm stopped due to a limit not covered by one of the _LIMIT_ statuses above.\nSLOW_PROGRESS: The algorithm stopped because it was unable to continue making progress towards the solution.\nNUMERICAL_ERROR: The algorithm stopped because it encountered unrecoverable numerical error.\nINVALID_MODEL: The algorithm stopped because the model is invalid.\nINVALID_OPTION: The algorithm stopped because it was provided an invalid option.\nINTERRUPTED: The algorithm stopped because of an interrupt signal.\nOTHER_ERROR: The algorithm stopped because of an error not covered by one of the statuses defined above.\n\n\n\n\n\n","category":"type"},{"location":"reference/models/#MathOptInterface.OPTIMIZE_NOT_CALLED","page":"Models","title":"MathOptInterface.OPTIMIZE_NOT_CALLED","text":"OPTIMIZE_NOT_CALLED::TerminationStatusCode\n\nAn instance of the TerminationStatusCode enum.\n\nOPTIMIZE_NOT_CALLED: The algorithm has not started.\n\n\n\n\n\n","category":"constant"},{"location":"reference/models/#MathOptInterface.OPTIMAL","page":"Models","title":"MathOptInterface.OPTIMAL","text":"OPTIMAL::TerminationStatusCode\n\nAn instance of the TerminationStatusCode enum.\n\nOPTIMAL: The algorithm found a globally optimal solution.\n\n\n\n\n\n","category":"constant"},{"location":"reference/models/#MathOptInterface.INFEASIBLE","page":"Models","title":"MathOptInterface.INFEASIBLE","text":"INFEASIBLE::TerminationStatusCode\n\nAn instance of the TerminationStatusCode enum.\n\nINFEASIBLE: The algorithm concluded that no feasible solution exists.\n\n\n\n\n\n","category":"constant"},{"location":"reference/models/#MathOptInterface.DUAL_INFEASIBLE","page":"Models","title":"MathOptInterface.DUAL_INFEASIBLE","text":"DUAL_INFEASIBLE::TerminationStatusCode\n\nAn instance of the TerminationStatusCode enum.\n\nDUAL_INFEASIBLE: The algorithm concluded that no dual bound exists for the problem. If, additionally, a feasible (primal) solution is known to exist, this status typically implies that the problem is unbounded, with some technical exceptions.\n\n\n\n\n\n","category":"constant"},{"location":"reference/models/#MathOptInterface.LOCALLY_SOLVED","page":"Models","title":"MathOptInterface.LOCALLY_SOLVED","text":"LOCALLY_SOLVED::TerminationStatusCode\n\nAn instance of the TerminationStatusCode enum.\n\nLOCALLY_SOLVED: The algorithm converged to a stationary point, local optimal solution, could not find directions for improvement, or otherwise completed its search without global guarantees.\n\n\n\n\n\n","category":"constant"},{"location":"reference/models/#MathOptInterface.LOCALLY_INFEASIBLE","page":"Models","title":"MathOptInterface.LOCALLY_INFEASIBLE","text":"LOCALLY_INFEASIBLE::TerminationStatusCode\n\nAn instance of the TerminationStatusCode enum.\n\nLOCALLY_INFEASIBLE: The algorithm converged to an infeasible point or otherwise completed its search without finding a feasible solution, without guarantees that no feasible solution exists.\n\n\n\n\n\n","category":"constant"},{"location":"reference/models/#MathOptInterface.INFEASIBLE_OR_UNBOUNDED","page":"Models","title":"MathOptInterface.INFEASIBLE_OR_UNBOUNDED","text":"INFEASIBLE_OR_UNBOUNDED::TerminationStatusCode\n\nAn instance of the TerminationStatusCode enum.\n\nINFEASIBLE_OR_UNBOUNDED: The algorithm stopped because it decided that the problem is infeasible or unbounded; this occasionally happens during MIP presolve.\n\n\n\n\n\n","category":"constant"},{"location":"reference/models/#MathOptInterface.ALMOST_OPTIMAL","page":"Models","title":"MathOptInterface.ALMOST_OPTIMAL","text":"ALMOST_OPTIMAL::TerminationStatusCode\n\nAn instance of the TerminationStatusCode enum.\n\nALMOST_OPTIMAL: The algorithm found a globally optimal solution to relaxed tolerances.\n\n\n\n\n\n","category":"constant"},{"location":"reference/models/#MathOptInterface.ALMOST_INFEASIBLE","page":"Models","title":"MathOptInterface.ALMOST_INFEASIBLE","text":"ALMOST_INFEASIBLE::TerminationStatusCode\n\nAn instance of the TerminationStatusCode enum.\n\nALMOST_INFEASIBLE: The algorithm concluded that no feasible solution exists within relaxed tolerances.\n\n\n\n\n\n","category":"constant"},{"location":"reference/models/#MathOptInterface.ALMOST_DUAL_INFEASIBLE","page":"Models","title":"MathOptInterface.ALMOST_DUAL_INFEASIBLE","text":"ALMOST_DUAL_INFEASIBLE::TerminationStatusCode\n\nAn instance of the TerminationStatusCode enum.\n\nALMOST_DUAL_INFEASIBLE: The algorithm concluded that no dual bound exists for the problem within relaxed tolerances.\n\n\n\n\n\n","category":"constant"},{"location":"reference/models/#MathOptInterface.ALMOST_LOCALLY_SOLVED","page":"Models","title":"MathOptInterface.ALMOST_LOCALLY_SOLVED","text":"ALMOST_LOCALLY_SOLVED::TerminationStatusCode\n\nAn instance of the TerminationStatusCode enum.\n\nALMOST_LOCALLY_SOLVED: The algorithm converged to a stationary point, local optimal solution, or could not find directions for improvement within relaxed tolerances.\n\n\n\n\n\n","category":"constant"},{"location":"reference/models/#MathOptInterface.ITERATION_LIMIT","page":"Models","title":"MathOptInterface.ITERATION_LIMIT","text":"ITERATION_LIMIT::TerminationStatusCode\n\nAn instance of the TerminationStatusCode enum.\n\nITERATION_LIMIT: An iterative algorithm stopped after conducting the maximum number of iterations.\n\n\n\n\n\n","category":"constant"},{"location":"reference/models/#MathOptInterface.TIME_LIMIT","page":"Models","title":"MathOptInterface.TIME_LIMIT","text":"TIME_LIMIT::TerminationStatusCode\n\nAn instance of the TerminationStatusCode enum.\n\nTIME_LIMIT: The algorithm stopped after a user-specified computation time.\n\n\n\n\n\n","category":"constant"},{"location":"reference/models/#MathOptInterface.NODE_LIMIT","page":"Models","title":"MathOptInterface.NODE_LIMIT","text":"NODE_LIMIT::TerminationStatusCode\n\nAn instance of the TerminationStatusCode enum.\n\nNODE_LIMIT: A branch-and-bound algorithm stopped because it explored a maximum number of nodes in the branch-and-bound tree.\n\n\n\n\n\n","category":"constant"},{"location":"reference/models/#MathOptInterface.SOLUTION_LIMIT","page":"Models","title":"MathOptInterface.SOLUTION_LIMIT","text":"SOLUTION_LIMIT::TerminationStatusCode\n\nAn instance of the TerminationStatusCode enum.\n\nSOLUTION_LIMIT: The algorithm stopped because it found the required number of solutions. This is often used in MIPs to get the solver to return the first feasible solution it encounters.\n\n\n\n\n\n","category":"constant"},{"location":"reference/models/#MathOptInterface.MEMORY_LIMIT","page":"Models","title":"MathOptInterface.MEMORY_LIMIT","text":"MEMORY_LIMIT::TerminationStatusCode\n\nAn instance of the TerminationStatusCode enum.\n\nMEMORY_LIMIT: The algorithm stopped because it ran out of memory.\n\n\n\n\n\n","category":"constant"},{"location":"reference/models/#MathOptInterface.OBJECTIVE_LIMIT","page":"Models","title":"MathOptInterface.OBJECTIVE_LIMIT","text":"OBJECTIVE_LIMIT::TerminationStatusCode\n\nAn instance of the TerminationStatusCode enum.\n\nOBJECTIVE_LIMIT: The algorithm stopped because it found a solution better than a minimum limit set by the user.\n\n\n\n\n\n","category":"constant"},{"location":"reference/models/#MathOptInterface.NORM_LIMIT","page":"Models","title":"MathOptInterface.NORM_LIMIT","text":"NORM_LIMIT::TerminationStatusCode\n\nAn instance of the TerminationStatusCode enum.\n\nNORM_LIMIT: The algorithm stopped because the norm of an iterate became too large.\n\n\n\n\n\n","category":"constant"},{"location":"reference/models/#MathOptInterface.OTHER_LIMIT","page":"Models","title":"MathOptInterface.OTHER_LIMIT","text":"OTHER_LIMIT::TerminationStatusCode\n\nAn instance of the TerminationStatusCode enum.\n\nOTHER_LIMIT: The algorithm stopped due to a limit not covered by one of the _LIMIT_ statuses above.\n\n\n\n\n\n","category":"constant"},{"location":"reference/models/#MathOptInterface.SLOW_PROGRESS","page":"Models","title":"MathOptInterface.SLOW_PROGRESS","text":"SLOW_PROGRESS::TerminationStatusCode\n\nAn instance of the TerminationStatusCode enum.\n\nSLOW_PROGRESS: The algorithm stopped because it was unable to continue making progress towards the solution.\n\n\n\n\n\n","category":"constant"},{"location":"reference/models/#MathOptInterface.NUMERICAL_ERROR","page":"Models","title":"MathOptInterface.NUMERICAL_ERROR","text":"NUMERICAL_ERROR::TerminationStatusCode\n\nAn instance of the TerminationStatusCode enum.\n\nNUMERICAL_ERROR: The algorithm stopped because it encountered unrecoverable numerical error.\n\n\n\n\n\n","category":"constant"},{"location":"reference/models/#MathOptInterface.INVALID_MODEL","page":"Models","title":"MathOptInterface.INVALID_MODEL","text":"INVALID_MODEL::TerminationStatusCode\n\nAn instance of the TerminationStatusCode enum.\n\nINVALID_MODEL: The algorithm stopped because the model is invalid.\n\n\n\n\n\n","category":"constant"},{"location":"reference/models/#MathOptInterface.INVALID_OPTION","page":"Models","title":"MathOptInterface.INVALID_OPTION","text":"INVALID_OPTION::TerminationStatusCode\n\nAn instance of the TerminationStatusCode enum.\n\nINVALID_OPTION: The algorithm stopped because it was provided an invalid option.\n\n\n\n\n\n","category":"constant"},{"location":"reference/models/#MathOptInterface.INTERRUPTED","page":"Models","title":"MathOptInterface.INTERRUPTED","text":"INTERRUPTED::TerminationStatusCode\n\nAn instance of the TerminationStatusCode enum.\n\nINTERRUPTED: The algorithm stopped because of an interrupt signal.\n\n\n\n\n\n","category":"constant"},{"location":"reference/models/#MathOptInterface.OTHER_ERROR","page":"Models","title":"MathOptInterface.OTHER_ERROR","text":"OTHER_ERROR::TerminationStatusCode\n\nAn instance of the TerminationStatusCode enum.\n\nOTHER_ERROR: The algorithm stopped because of an error not covered by one of the statuses defined above.\n\n\n\n\n\n","category":"constant"},{"location":"reference/models/#MathOptInterface.PrimalStatus","page":"Models","title":"MathOptInterface.PrimalStatus","text":"PrimalStatus(result_index::Int = 1)\n\nA model attribute for the ResultStatusCode of the primal result result_index. If result_index is omitted, it defaults to 1.\n\nSee ResultCount for information on how the results are ordered.\n\nIf result_index is larger than the value of ResultCount then NO_SOLUTION is returned.\n\n\n\n\n\n","category":"type"},{"location":"reference/models/#MathOptInterface.DualStatus","page":"Models","title":"MathOptInterface.DualStatus","text":"DualStatus(result_index::Int = 1)\n\nA model attribute for the ResultStatusCode of the dual result result_index. If result_index is omitted, it defaults to 1.\n\nSee ResultCount for information on how the results are ordered.\n\nIf result_index is larger than the value of ResultCount then NO_SOLUTION is returned.\n\n\n\n\n\n","category":"type"},{"location":"reference/models/#MathOptInterface.RawStatusString","page":"Models","title":"MathOptInterface.RawStatusString","text":"RawStatusString()\n\nA model attribute for a solver specific string explaining why the optimizer stopped.\n\n\n\n\n\n","category":"type"},{"location":"reference/models/#MathOptInterface.ResultCount","page":"Models","title":"MathOptInterface.ResultCount","text":"ResultCount()\n\nA model attribute for the number of results available.\n\nOrder of solutions\n\nA number of attributes contain an index, result_index, which is used to refer to one of the available results. Thus, result_index must be an integer between 1 and the number of available results.\n\nAs a general rule, the first result (result_index=1) is the most important result (e.g., an optimal solution or an infeasibility certificate). Other results will typically be alternate solutions that the solver found during the search for the first result.\n\nIf a (local) optimal solution is available, i.e., TerminationStatus is OPTIMAL or LOCALLY_SOLVED, the first result must correspond to the (locally) optimal solution. Other results may be alternative optimal solutions, or they may be other suboptimal solutions; use ObjectiveValue to distingiush between them.\n\nIf a primal or dual infeasibility certificate is available, i.e., TerminationStatus is INFEASIBLE or DUAL_INFEASIBLE and the corresponding PrimalStatus or DualStatus is INFEASIBILITY_CERTIFICATE, then the first result must be a certificate. Other results may be alternate certificates, or infeasible points.\n\n\n\n\n\n","category":"type"},{"location":"reference/models/#MathOptInterface.ObjectiveValue","page":"Models","title":"MathOptInterface.ObjectiveValue","text":"ObjectiveValue(result_index::Int = 1)\n\nA model attribute for the objective value of the primal solution result_index.\n\nIf the solver does not have a primal value for the objective because the result_index is beyond the available solutions (whose number is indicated by the ResultCount attribute), getting this attribute must throw a ResultIndexBoundsError. Otherwise, if the result is unavailable for another reason (for instance, only a dual solution is available), the result is undefined. Users should first check PrimalStatus before accessing the ObjectiveValue attribute.\n\nSee ResultCount for information on how the results are ordered.\n\n\n\n\n\n","category":"type"},{"location":"reference/models/#MathOptInterface.DualObjectiveValue","page":"Models","title":"MathOptInterface.DualObjectiveValue","text":"DualObjectiveValue(result_index::Int = 1)\n\nA model attribute for the value of the objective function of the dual problem for the result_indexth dual result.\n\nIf the solver does not have a dual value for the objective because the result_index is beyond the available solutions (whose number is indicated by the ResultCount attribute), getting this attribute must throw a ResultIndexBoundsError. Otherwise, if the result is unavailable for another reason (for instance, only a primal solution is available), the result is undefined. Users should first check DualStatus before accessing the DualObjectiveValue attribute.\n\nSee ResultCount for information on how the results are ordered.\n\n\n\n\n\n","category":"type"},{"location":"reference/models/#MathOptInterface.ObjectiveBound","page":"Models","title":"MathOptInterface.ObjectiveBound","text":"ObjectiveBound()\n\nA model attribute for the best known bound on the optimal objective value.\n\n\n\n\n\n","category":"type"},{"location":"reference/models/#MathOptInterface.RelativeGap","page":"Models","title":"MathOptInterface.RelativeGap","text":"RelativeGap()\n\nA model attribute for the final relative optimality gap.\n\nwarning: Warning\nThe definition of this gap is solver-dependent. However, most solvers implementing this attribute define the relative gap as some variation of fracb-ff, where b is the best bound and f is the best feasible objective value.\n\n\n\n\n\n","category":"type"},{"location":"reference/models/#MathOptInterface.SolveTimeSec","page":"Models","title":"MathOptInterface.SolveTimeSec","text":"SolveTimeSec()\n\nA model attribute for the total elapsed solution time (in seconds) as reported by the optimizer.\n\n\n\n\n\n","category":"type"},{"location":"reference/models/#MathOptInterface.SimplexIterations","page":"Models","title":"MathOptInterface.SimplexIterations","text":"SimplexIterations()\n\nA model attribute for the cumulative number of simplex iterations during the optimization process.\n\nFor a mixed-integer program (MIP), the return value is the total simplex iterations for all nodes.\n\n\n\n\n\n","category":"type"},{"location":"reference/models/#MathOptInterface.BarrierIterations","page":"Models","title":"MathOptInterface.BarrierIterations","text":"BarrierIterations()\n\nA model attribute for the cumulative number of barrier iterations while solving a problem.\n\n\n\n\n\n","category":"type"},{"location":"reference/models/#MathOptInterface.NodeCount","page":"Models","title":"MathOptInterface.NodeCount","text":"NodeCount()\n\nA model attribute for the total number of branch-and-bound nodes explored while solving a mixed-integer program (MIP).\n\n\n\n\n\n","category":"type"},{"location":"reference/models/#ResultStatusCode","page":"Models","title":"ResultStatusCode","text":"","category":"section"},{"location":"reference/models/","page":"Models","title":"Models","text":"ResultStatusCode\nNO_SOLUTION\nFEASIBLE_POINT\nNEARLY_FEASIBLE_POINT\nINFEASIBLE_POINT\nINFEASIBILITY_CERTIFICATE\nNEARLY_INFEASIBILITY_CERTIFICATE\nREDUCTION_CERTIFICATE\nNEARLY_REDUCTION_CERTIFICATE\nUNKNOWN_RESULT_STATUS\nOTHER_RESULT_STATUS","category":"page"},{"location":"reference/models/#MathOptInterface.ResultStatusCode","page":"Models","title":"MathOptInterface.ResultStatusCode","text":"ResultStatusCode\n\nAn Enum of possible values for the PrimalStatus and DualStatus attributes.\n\nThe values indicate how to interpret the result vector.\n\nValues\n\nPossible values are:\n\nNO_SOLUTION: the result vector is empty.\nFEASIBLE_POINT: the result vector is a feasible point.\nNEARLY_FEASIBLE_POINT: the result vector is feasible if some constraint tolerances are relaxed.\nINFEASIBLE_POINT: the result vector is an infeasible point.\nINFEASIBILITY_CERTIFICATE: the result vector is an infeasibility certificate. If the PrimalStatus is INFEASIBILITY_CERTIFICATE, then the primal result vector is a certificate of dual infeasibility. If the DualStatus is INFEASIBILITY_CERTIFICATE, then the dual result vector is a proof of primal infeasibility.\nNEARLY_INFEASIBILITY_CERTIFICATE: the result satisfies a relaxed criterion for a certificate of infeasibility.\nREDUCTION_CERTIFICATE: the result vector is an ill-posed certificate; see this article for details. If the PrimalStatus is REDUCTION_CERTIFICATE, then the primal result vector is a proof that the dual problem is ill-posed. If the DualStatus is REDUCTION_CERTIFICATE, then the dual result vector is a proof that the primal is ill-posed.\nNEARLY_REDUCTION_CERTIFICATE: the result satisfies a relaxed criterion for an ill-posed certificate.\nUNKNOWN_RESULT_STATUS: the result vector contains a solution with an unknown interpretation.\nOTHER_RESULT_STATUS: the result vector contains a solution with an interpretation not covered by one of the statuses defined above\n\n\n\n\n\n","category":"type"},{"location":"reference/models/#MathOptInterface.NO_SOLUTION","page":"Models","title":"MathOptInterface.NO_SOLUTION","text":"NO_SOLUTION::ResultStatusCode\n\nAn instance of the ResultStatusCode enum.\n\nNO_SOLUTION: the result vector is empty.\n\n\n\n\n\n","category":"constant"},{"location":"reference/models/#MathOptInterface.FEASIBLE_POINT","page":"Models","title":"MathOptInterface.FEASIBLE_POINT","text":"FEASIBLE_POINT::ResultStatusCode\n\nAn instance of the ResultStatusCode enum.\n\nFEASIBLE_POINT: the result vector is a feasible point.\n\n\n\n\n\n","category":"constant"},{"location":"reference/models/#MathOptInterface.NEARLY_FEASIBLE_POINT","page":"Models","title":"MathOptInterface.NEARLY_FEASIBLE_POINT","text":"NEARLY_FEASIBLE_POINT::ResultStatusCode\n\nAn instance of the ResultStatusCode enum.\n\nNEARLY_FEASIBLE_POINT: the result vector is feasible if some constraint tolerances are relaxed.\n\n\n\n\n\n","category":"constant"},{"location":"reference/models/#MathOptInterface.INFEASIBLE_POINT","page":"Models","title":"MathOptInterface.INFEASIBLE_POINT","text":"INFEASIBLE_POINT::ResultStatusCode\n\nAn instance of the ResultStatusCode enum.\n\nINFEASIBLE_POINT: the result vector is an infeasible point.\n\n\n\n\n\n","category":"constant"},{"location":"reference/models/#MathOptInterface.INFEASIBILITY_CERTIFICATE","page":"Models","title":"MathOptInterface.INFEASIBILITY_CERTIFICATE","text":"INFEASIBILITY_CERTIFICATE::ResultStatusCode\n\nAn instance of the ResultStatusCode enum.\n\nINFEASIBILITY_CERTIFICATE: the result vector is an infeasibility certificate. If the PrimalStatus is INFEASIBILITY_CERTIFICATE, then the primal result vector is a certificate of dual infeasibility. If the DualStatus is INFEASIBILITY_CERTIFICATE, then the dual result vector is a proof of primal infeasibility.\n\n\n\n\n\n","category":"constant"},{"location":"reference/models/#MathOptInterface.NEARLY_INFEASIBILITY_CERTIFICATE","page":"Models","title":"MathOptInterface.NEARLY_INFEASIBILITY_CERTIFICATE","text":"NEARLY_INFEASIBILITY_CERTIFICATE::ResultStatusCode\n\nAn instance of the ResultStatusCode enum.\n\nNEARLY_INFEASIBILITY_CERTIFICATE: the result satisfies a relaxed criterion for a certificate of infeasibility.\n\n\n\n\n\n","category":"constant"},{"location":"reference/models/#MathOptInterface.REDUCTION_CERTIFICATE","page":"Models","title":"MathOptInterface.REDUCTION_CERTIFICATE","text":"REDUCTION_CERTIFICATE::ResultStatusCode\n\nAn instance of the ResultStatusCode enum.\n\nREDUCTION_CERTIFICATE: the result vector is an ill-posed certificate; see this article for details. If the PrimalStatus is REDUCTION_CERTIFICATE, then the primal result vector is a proof that the dual problem is ill-posed. If the DualStatus is REDUCTION_CERTIFICATE, then the dual result vector is a proof that the primal is ill-posed.\n\n\n\n\n\n","category":"constant"},{"location":"reference/models/#MathOptInterface.NEARLY_REDUCTION_CERTIFICATE","page":"Models","title":"MathOptInterface.NEARLY_REDUCTION_CERTIFICATE","text":"NEARLY_REDUCTION_CERTIFICATE::ResultStatusCode\n\nAn instance of the ResultStatusCode enum.\n\nNEARLY_REDUCTION_CERTIFICATE: the result satisfies a relaxed criterion for an ill-posed certificate.\n\n\n\n\n\n","category":"constant"},{"location":"reference/models/#MathOptInterface.UNKNOWN_RESULT_STATUS","page":"Models","title":"MathOptInterface.UNKNOWN_RESULT_STATUS","text":"UNKNOWN_RESULT_STATUS::ResultStatusCode\n\nAn instance of the ResultStatusCode enum.\n\nUNKNOWN_RESULT_STATUS: the result vector contains a solution with an unknown interpretation.\n\n\n\n\n\n","category":"constant"},{"location":"reference/models/#MathOptInterface.OTHER_RESULT_STATUS","page":"Models","title":"MathOptInterface.OTHER_RESULT_STATUS","text":"OTHER_RESULT_STATUS::ResultStatusCode\n\nAn instance of the ResultStatusCode enum.\n\nOTHER_RESULT_STATUS: the result vector contains a solution with an interpretation not covered by one of the statuses defined above\n\n\n\n\n\n","category":"constant"},{"location":"reference/models/#Conflict-Status","page":"Models","title":"Conflict Status","text":"","category":"section"},{"location":"reference/models/","page":"Models","title":"Models","text":"compute_conflict!\nConflictStatus\nConstraintConflictStatus\nConflictStatusCode\nConflictParticipationStatusCode\nNOT_IN_CONFLICT\nIN_CONFLICT\nMAYBE_IN_CONFLICT","category":"page"},{"location":"reference/models/#MathOptInterface.compute_conflict!","page":"Models","title":"MathOptInterface.compute_conflict!","text":"compute_conflict!(optimizer::AbstractOptimizer)\n\nComputes a minimal subset of constraints such that the model with the other constraint removed is still infeasible.\n\nSome solvers call a set of conflicting constraints an Irreducible Inconsistent Subsystem (IIS).\n\nSee also ConflictStatus and ConstraintConflictStatus.\n\nNote\n\nIf the model is modified after a call to compute_conflict!, the implementor is not obliged to purge the conflict. Any calls to the above attributes may return values for the original conflict without a warning. Similarly, when modifying the model, the conflict can be discarded.\n\n\n\n\n\n","category":"function"},{"location":"reference/models/#MathOptInterface.ConflictStatus","page":"Models","title":"MathOptInterface.ConflictStatus","text":"ConflictStatus()\n\nA model attribute for the ConflictStatusCode explaining why the conflict refiner stopped when computing the conflict.\n\n\n\n\n\n","category":"type"},{"location":"reference/models/#MathOptInterface.ConstraintConflictStatus","page":"Models","title":"MathOptInterface.ConstraintConflictStatus","text":"ConstraintConflictStatus()\n\nA constraint attribute indicating whether the constraint participates in the conflict. Its type is ConflictParticipationStatusCode.\n\n\n\n\n\n","category":"type"},{"location":"reference/models/#MathOptInterface.ConflictStatusCode","page":"Models","title":"MathOptInterface.ConflictStatusCode","text":"ConflictStatusCode\n\nAn Enum of possible values for the ConflictStatus attribute. This attribute is meant to explain the reason why the conflict finder stopped executing in the most recent call to compute_conflict!.\n\nPossible values are:\n\nCOMPUTE_CONFLICT_NOT_CALLED: the function compute_conflict! has not yet been called\nNO_CONFLICT_EXISTS: there is no conflict because the problem is feasible\nNO_CONFLICT_FOUND: the solver could not find a conflict\nCONFLICT_FOUND: at least one conflict could be found\n\n\n\n\n\n","category":"type"},{"location":"reference/models/#MathOptInterface.ConflictParticipationStatusCode","page":"Models","title":"MathOptInterface.ConflictParticipationStatusCode","text":"ConflictParticipationStatusCode\n\nAn Enum of possible values for the ConstraintConflictStatus attribute. This attribute is meant to indicate whether a given constraint participates or not in the last computed conflict.\n\nValues\n\nPossible values are:\n\nNOT_IN_CONFLICT: the constraint does not participate in the conflict\nIN_CONFLICT: the constraint participates in the conflict\nMAYBE_IN_CONFLICT: the constraint may participate in the conflict, the solver was not able to prove that the constraint can be excluded from the conflict\n\n\n\n\n\n","category":"type"},{"location":"reference/models/#MathOptInterface.NOT_IN_CONFLICT","page":"Models","title":"MathOptInterface.NOT_IN_CONFLICT","text":"NOT_IN_CONFLICT::ConflictParticipationStatusCode\n\nAn instance of the ConflictParticipationStatusCode enum.\n\nNOT_IN_CONFLICT: the constraint does not participate in the conflict\n\n\n\n\n\n","category":"constant"},{"location":"reference/models/#MathOptInterface.IN_CONFLICT","page":"Models","title":"MathOptInterface.IN_CONFLICT","text":"IN_CONFLICT::ConflictParticipationStatusCode\n\nAn instance of the ConflictParticipationStatusCode enum.\n\nIN_CONFLICT: the constraint participates in the conflict\n\n\n\n\n\n","category":"constant"},{"location":"reference/models/#MathOptInterface.MAYBE_IN_CONFLICT","page":"Models","title":"MathOptInterface.MAYBE_IN_CONFLICT","text":"MAYBE_IN_CONFLICT::ConflictParticipationStatusCode\n\nAn instance of the ConflictParticipationStatusCode enum.\n\nMAYBE_IN_CONFLICT: the constraint may participate in the conflict, the solver was not able to prove that the constraint can be excluded from the conflict\n\n\n\n\n\n","category":"constant"},{"location":"submodules/Utilities/overview/","page":"Overview","title":"Overview","text":"CurrentModule = MathOptInterface\nDocTestSetup = quote\n import MathOptInterface as MOI\nend\nDocTestFilters = [r\"MathOptInterface|MOI\"]","category":"page"},{"location":"submodules/Utilities/overview/#The-Utilities-submodule","page":"Overview","title":"The Utilities submodule","text":"","category":"section"},{"location":"submodules/Utilities/overview/","page":"Overview","title":"Overview","text":"The Utilities submodule provides a variety of functions and datastructures for managing MOI.ModelLike objects.","category":"page"},{"location":"submodules/Utilities/overview/#Utilities.Model","page":"Overview","title":"Utilities.Model","text":"","category":"section"},{"location":"submodules/Utilities/overview/","page":"Overview","title":"Overview","text":"Utilities.Model provides an implementation of a ModelLike that efficiently supports all functions and sets defined within MOI. However, given the extensibility of MOI, this might not cover all use cases.","category":"page"},{"location":"submodules/Utilities/overview/","page":"Overview","title":"Overview","text":"Create a model as follows:","category":"page"},{"location":"submodules/Utilities/overview/","page":"Overview","title":"Overview","text":"julia> model = MOI.Utilities.Model{Float64}()\nMOIU.Model{Float64}","category":"page"},{"location":"submodules/Utilities/overview/#Utilities.UniversalFallback","page":"Overview","title":"Utilities.UniversalFallback","text":"","category":"section"},{"location":"submodules/Utilities/overview/","page":"Overview","title":"Overview","text":"Utilities.UniversalFallback is a layer that sits on top of any ModelLike and provides non-specialized (slower) fallbacks for constraints and attributes that the underlying ModelLike does not support.","category":"page"},{"location":"submodules/Utilities/overview/","page":"Overview","title":"Overview","text":"For example, Utilities.Model doesn't support some variable attributes like VariablePrimalStart, so JuMP uses a combination of Universal fallback and Utilities.Model as a generic problem cache:","category":"page"},{"location":"submodules/Utilities/overview/","page":"Overview","title":"Overview","text":"julia> model = MOI.Utilities.UniversalFallback(MOI.Utilities.Model{Float64}())\nMOIU.UniversalFallback{MOIU.Model{Float64}}\nfallback for MOIU.Model{Float64}","category":"page"},{"location":"submodules/Utilities/overview/","page":"Overview","title":"Overview","text":"warning: Warning\nAdding a UniversalFallback means that your model will now support all constraints, even if the inner-model does not. This can lead to unexpected behavior.","category":"page"},{"location":"submodules/Utilities/overview/#Utilities.@model","page":"Overview","title":"Utilities.@model","text":"","category":"section"},{"location":"submodules/Utilities/overview/","page":"Overview","title":"Overview","text":"For advanced use cases that need efficient support for functions and sets defined outside of MOI (but still known at compile time), we provide the Utilities.@model macro.","category":"page"},{"location":"submodules/Utilities/overview/","page":"Overview","title":"Overview","text":"The @model macro takes a name (for a new type, which must not exist yet), eight tuples specifying the types of constraints that are supported, and then a Bool indicating the type is a subtype of MOI.AbstractOptimizer (if true) or MOI.ModelLike (if false).","category":"page"},{"location":"submodules/Utilities/overview/","page":"Overview","title":"Overview","text":"The eight tuples are in the following order:","category":"page"},{"location":"submodules/Utilities/overview/","page":"Overview","title":"Overview","text":"Un-typed scalar sets, for example, Integer\nTyped scalar sets, for example, LessThan\nUn-typed vector sets, for example, Nonnegatives\nTyped vector sets, for example, PowerCone\nUn-typed scalar functions, for example, VariableIndex\nTyped scalar functions, for example, ScalarAffineFunction\nUn-typed vector functions, for example, VectorOfVariables\nTyped vector functions, for example, VectorAffineFunction","category":"page"},{"location":"submodules/Utilities/overview/","page":"Overview","title":"Overview","text":"The tuples can contain more than one element. Typed-sets must be specified without their type parameter, for example, MOI.LessThan, not MOI.LessThan{Float64}.","category":"page"},{"location":"submodules/Utilities/overview/","page":"Overview","title":"Overview","text":"Here is an example:","category":"page"},{"location":"submodules/Utilities/overview/","page":"Overview","title":"Overview","text":"julia> MOI.Utilities.@model(\n MyNewModel,\n (MOI.Integer,), # Un-typed scalar sets\n (MOI.GreaterThan,), # Typed scalar sets\n (MOI.Nonnegatives,), # Un-typed vector sets\n (MOI.PowerCone,), # Typed vector sets\n (MOI.VariableIndex,), # Un-typed scalar functions\n (MOI.ScalarAffineFunction,), # Typed scalar functions\n (MOI.VectorOfVariables,), # Un-typed vector functions\n (MOI.VectorAffineFunction,), # Typed vector functions\n true, # <:MOI.AbstractOptimizer?\n )\nMathOptInterface.Utilities.GenericOptimizer{T, MathOptInterface.Utilities.ObjectiveContainer{T}, MathOptInterface.Utilities.VariablesContainer{T}, MyNewModelFunctionConstraints{T}} where T\n\njulia> model = MyNewModel{Float64}()\nMOIU.GenericOptimizer{Float64, MOIU.ObjectiveContainer{Float64}, MOIU.VariablesContainer{Float64}, MyNewModelFunctionConstraints{Float64}}","category":"page"},{"location":"submodules/Utilities/overview/","page":"Overview","title":"Overview","text":"warning: Warning\nMyNewModel supports every VariableIndex-in-Set constraint, as well as VariableIndex, ScalarAffineFunction, and ScalarQuadraticFunction objective functions. Implement MOI.supports as needed to forbid constraint and objective function combinations.","category":"page"},{"location":"submodules/Utilities/overview/","page":"Overview","title":"Overview","text":"As another example, PATHSolver, which only supports VectorAffineFunction-in-Complements defines its optimizer as:","category":"page"},{"location":"submodules/Utilities/overview/","page":"Overview","title":"Overview","text":"julia> MOI.Utilities.@model(\n PathOptimizer,\n (), # Scalar sets\n (), # Typed scalar sets\n (MOI.Complements,), # Vector sets\n (), # Typed vector sets\n (), # Scalar functions\n (), # Typed scalar functions\n (), # Vector functions\n (MOI.VectorAffineFunction,), # Typed vector functions\n true, # is_optimizer\n )\nMathOptInterface.Utilities.GenericOptimizer{T, MathOptInterface.Utilities.ObjectiveContainer{T}, MathOptInterface.Utilities.VariablesContainer{T}, MathOptInterface.Utilities.VectorOfConstraints{MathOptInterface.VectorAffineFunction{T}, MathOptInterface.Complements}} where T","category":"page"},{"location":"submodules/Utilities/overview/","page":"Overview","title":"Overview","text":"However, PathOptimizer does not support some VariableIndex-in-Set constraints, so we must explicitly define:","category":"page"},{"location":"submodules/Utilities/overview/","page":"Overview","title":"Overview","text":"julia> function MOI.supports_constraint(\n ::PathOptimizer,\n ::Type{MOI.VariableIndex},\n ::Type{Union{<:MOI.Semiinteger,MOI.Semicontinuous,MOI.ZeroOne,MOI.Integer}}\n )\n return false\n end","category":"page"},{"location":"submodules/Utilities/overview/","page":"Overview","title":"Overview","text":"Finally, PATH doesn't support an objective function, so we need to add:","category":"page"},{"location":"submodules/Utilities/overview/","page":"Overview","title":"Overview","text":"julia> MOI.supports(::PathOptimizer, ::MOI.ObjectiveFunction) = false","category":"page"},{"location":"submodules/Utilities/overview/","page":"Overview","title":"Overview","text":"warning: Warning\nThis macro creates a new type, so it must be called from the top-level of a module, for example, it cannot be called from inside a function.","category":"page"},{"location":"submodules/Utilities/overview/#Utilities.CachingOptimizer","page":"Overview","title":"Utilities.CachingOptimizer","text":"","category":"section"},{"location":"submodules/Utilities/overview/","page":"Overview","title":"Overview","text":"A [Utilities.CachingOptimizer] is an MOI layer that abstracts the difference between solvers that support incremental modification (for example, they support adding variables one-by-one), and solvers that require the entire problem in a single API call (for example, they only accept the A, b and c matrices of a linear program).","category":"page"},{"location":"submodules/Utilities/overview/","page":"Overview","title":"Overview","text":"It has two parts:","category":"page"},{"location":"submodules/Utilities/overview/","page":"Overview","title":"Overview","text":"A cache, where the model can be built and modified incrementally\nAn optimizer, which is used to solve the problem","category":"page"},{"location":"submodules/Utilities/overview/","page":"Overview","title":"Overview","text":"julia> model = MOI.Utilities.CachingOptimizer(\n MOI.Utilities.Model{Float64}(),\n PathOptimizer{Float64}(),\n )\nMOIU.CachingOptimizer{MOIU.GenericOptimizer{Float64, MOIU.ObjectiveContainer{Float64}, MOIU.VariablesContainer{Float64}, MOIU.VectorOfConstraints{MOI.VectorAffineFunction{Float64}, MOI.Complements}}, MOIU.Model{Float64}}\nin state EMPTY_OPTIMIZER\nin mode AUTOMATIC\nwith model cache MOIU.Model{Float64}\nwith optimizer MOIU.GenericOptimizer{Float64, MOIU.ObjectiveContainer{Float64}, MOIU.VariablesContainer{Float64}, MOIU.VectorOfConstraints{MOI.VectorAffineFunction{Float64}, MOI.Complements}}","category":"page"},{"location":"submodules/Utilities/overview/","page":"Overview","title":"Overview","text":"A Utilities.CachingOptimizer may be in one of three possible states:","category":"page"},{"location":"submodules/Utilities/overview/","page":"Overview","title":"Overview","text":"NO_OPTIMIZER: The CachingOptimizer does not have any optimizer.\nEMPTY_OPTIMIZER: The CachingOptimizer has an empty optimizer, and it is not synchronized with the cached model. Modifications are forwarded to the cache, but not to the optimizer.\nATTACHED_OPTIMIZER: The CachingOptimizer has an optimizer, and it is synchronized with the cached model. Modifications are forwarded to the optimizer. If the optimizer does not support modifications, and error will be thrown.","category":"page"},{"location":"submodules/Utilities/overview/","page":"Overview","title":"Overview","text":"Use Utilities.attach_optimizer to go from EMPTY_OPTIMIZER to ATTACHED_OPTIMIZER:","category":"page"},{"location":"submodules/Utilities/overview/","page":"Overview","title":"Overview","text":"julia> MOI.Utilities.attach_optimizer(model)\n\njulia> model\nMOIU.CachingOptimizer{MOIU.GenericOptimizer{Float64, MOIU.ObjectiveContainer{Float64}, MOIU.VariablesContainer{Float64}, MOIU.VectorOfConstraints{MOI.VectorAffineFunction{Float64}, MOI.Complements}}, MOIU.Model{Float64}}\nin state ATTACHED_OPTIMIZER\nin mode AUTOMATIC\nwith model cache MOIU.Model{Float64}\nwith optimizer MOIU.GenericOptimizer{Float64, MOIU.ObjectiveContainer{Float64}, MOIU.VariablesContainer{Float64}, MOIU.VectorOfConstraints{MOI.VectorAffineFunction{Float64}, MOI.Complements}}","category":"page"},{"location":"submodules/Utilities/overview/","page":"Overview","title":"Overview","text":"info: Info\nYou must be in ATTACHED_OPTIMIZER to use optimize!.","category":"page"},{"location":"submodules/Utilities/overview/","page":"Overview","title":"Overview","text":"Use Utilities.reset_optimizer to go from ATTACHED_OPTIMIZER to EMPTY_OPTIMIZER:","category":"page"},{"location":"submodules/Utilities/overview/","page":"Overview","title":"Overview","text":"julia> MOI.Utilities.reset_optimizer(model)\n\njulia> model\nMOIU.CachingOptimizer{MOIU.GenericOptimizer{Float64, MOIU.ObjectiveContainer{Float64}, MOIU.VariablesContainer{Float64}, MOIU.VectorOfConstraints{MOI.VectorAffineFunction{Float64}, MOI.Complements}}, MOIU.Model{Float64}}\nin state EMPTY_OPTIMIZER\nin mode AUTOMATIC\nwith model cache MOIU.Model{Float64}\nwith optimizer MOIU.GenericOptimizer{Float64, MOIU.ObjectiveContainer{Float64}, MOIU.VariablesContainer{Float64}, MOIU.VectorOfConstraints{MOI.VectorAffineFunction{Float64}, MOI.Complements}}","category":"page"},{"location":"submodules/Utilities/overview/","page":"Overview","title":"Overview","text":"info: Info\nCalling MOI.empty!(model) also resets the state to EMPTY_OPTIMIZER. So after emptying a model, the modification will only be applied to the cache.","category":"page"},{"location":"submodules/Utilities/overview/","page":"Overview","title":"Overview","text":"Use Utilities.drop_optimizer to go from any state to NO_OPTIMIZER:","category":"page"},{"location":"submodules/Utilities/overview/","page":"Overview","title":"Overview","text":"julia> MOI.Utilities.drop_optimizer(model)\n\njulia> model\nMOIU.CachingOptimizer{MOIU.GenericOptimizer{Float64, MOIU.ObjectiveContainer{Float64}, MOIU.VariablesContainer{Float64}, MOIU.VectorOfConstraints{MOI.VectorAffineFunction{Float64}, MOI.Complements}}, MOIU.Model{Float64}}\nin state NO_OPTIMIZER\nin mode AUTOMATIC\nwith model cache MOIU.Model{Float64}\nwith optimizer nothing","category":"page"},{"location":"submodules/Utilities/overview/","page":"Overview","title":"Overview","text":"Pass an empty optimizer to Utilities.reset_optimizer to go from NO_OPTIMIZER to EMPTY_OPTIMIZER:","category":"page"},{"location":"submodules/Utilities/overview/","page":"Overview","title":"Overview","text":"julia> MOI.Utilities.reset_optimizer(model, PathOptimizer{Float64}())\n\njulia> model\nMOIU.CachingOptimizer{MOIU.GenericOptimizer{Float64, MOIU.ObjectiveContainer{Float64}, MOIU.VariablesContainer{Float64}, MOIU.VectorOfConstraints{MOI.VectorAffineFunction{Float64}, MOI.Complements}}, MOIU.Model{Float64}}\nin state EMPTY_OPTIMIZER\nin mode AUTOMATIC\nwith model cache MOIU.Model{Float64}\nwith optimizer MOIU.GenericOptimizer{Float64, MOIU.ObjectiveContainer{Float64}, MOIU.VariablesContainer{Float64}, MOIU.VectorOfConstraints{MOI.VectorAffineFunction{Float64}, MOI.Complements}}","category":"page"},{"location":"submodules/Utilities/overview/","page":"Overview","title":"Overview","text":"Deciding when to attach and reset the optimizer is tedious, and you will often write code like this:","category":"page"},{"location":"submodules/Utilities/overview/","page":"Overview","title":"Overview","text":"try\n # modification\ncatch\n MOI.Utilities.reset_optimizer(model)\n # Re-try modification\nend","category":"page"},{"location":"submodules/Utilities/overview/","page":"Overview","title":"Overview","text":"To make this easier, Utilities.CachingOptimizer has two modes of operation:","category":"page"},{"location":"submodules/Utilities/overview/","page":"Overview","title":"Overview","text":"AUTOMATIC: The CachingOptimizer changes its state when necessary. Attempting to add a constraint or perform a modification not supported by the optimizer results in a drop to EMPTY_OPTIMIZER mode.\nMANUAL: The user must change the state of the CachingOptimizer. Attempting to perform an operation in the incorrect state results in an error.","category":"page"},{"location":"submodules/Utilities/overview/","page":"Overview","title":"Overview","text":"By default, AUTOMATIC mode is chosen. However, you can create a CachingOptimizer in MANUAL mode as follows:","category":"page"},{"location":"submodules/Utilities/overview/","page":"Overview","title":"Overview","text":"julia> model = MOI.Utilities.CachingOptimizer(\n MOI.Utilities.Model{Float64}(),\n MOI.Utilities.MANUAL,\n )\nMOIU.CachingOptimizer{MOI.AbstractOptimizer, MOIU.Model{Float64}}\nin state NO_OPTIMIZER\nin mode MANUAL\nwith model cache MOIU.Model{Float64}\nwith optimizer nothing\n\njulia> MOI.Utilities.reset_optimizer(model, PathOptimizer{Float64}())\n\njulia> model\nMOIU.CachingOptimizer{MOI.AbstractOptimizer, MOIU.Model{Float64}}\nin state EMPTY_OPTIMIZER\nin mode MANUAL\nwith model cache MOIU.Model{Float64}\nwith optimizer MOIU.GenericOptimizer{Float64, MOIU.ObjectiveContainer{Float64}, MOIU.VariablesContainer{Float64}, MOIU.VectorOfConstraints{MOI.VectorAffineFunction{Float64}, MOI.Complements}}","category":"page"},{"location":"submodules/Utilities/overview/#Printing","page":"Overview","title":"Printing","text":"","category":"section"},{"location":"submodules/Utilities/overview/","page":"Overview","title":"Overview","text":"Use print to print the formulation of the model.","category":"page"},{"location":"submodules/Utilities/overview/","page":"Overview","title":"Overview","text":"julia> model = MOI.Utilities.Model{Float64}();\n\njulia> x = MOI.add_variable(model)\nMOI.VariableIndex(1)\n\njulia> MOI.set(model, MOI.VariableName(), x, \"x_var\")\n\njulia> MOI.add_constraint(model, x, MOI.ZeroOne())\nMathOptInterface.ConstraintIndex{MathOptInterface.VariableIndex, MathOptInterface.ZeroOne}(1)\n\njulia> MOI.set(model, MOI.ObjectiveFunction{typeof(x)}(), x)\n\njulia> MOI.set(model, MOI.ObjectiveSense(), MOI.MAX_SENSE)\n\njulia> print(model)\nMaximize VariableIndex:\n x_var\n\nSubject to:\n\nVariableIndex-in-ZeroOne\n x_var ∈ {0, 1}","category":"page"},{"location":"submodules/Utilities/overview/","page":"Overview","title":"Overview","text":"Use Utilities.latex_formulation to display the model in LaTeX form:","category":"page"},{"location":"submodules/Utilities/overview/","page":"Overview","title":"Overview","text":"julia> MOI.Utilities.latex_formulation(model)\n$$ \\begin{aligned}\n\\max\\quad & x\\_var \\\\\n\\text{Subject to}\\\\\n & \\text{VariableIndex-in-ZeroOne} \\\\\n & x\\_var \\in \\{0, 1\\} \\\\\n\\end{aligned} $$","category":"page"},{"location":"submodules/Utilities/overview/","page":"Overview","title":"Overview","text":"tip: Tip\nIn IJulia, calling print or ending a cell with Utilities.latex_formulation will render the model in LaTeX.","category":"page"},{"location":"submodules/Utilities/overview/#Utilities.PenaltyRelaxation","page":"Overview","title":"Utilities.PenaltyRelaxation","text":"","category":"section"},{"location":"submodules/Utilities/overview/","page":"Overview","title":"Overview","text":"Pass Utilities.PenaltyRelaxation to modify to relax the problem by adding penalized slack variables to the constraints. This is helpful when debugging sources of infeasible models.","category":"page"},{"location":"submodules/Utilities/overview/","page":"Overview","title":"Overview","text":"julia> model = MOI.Utilities.Model{Float64}();\n\njulia> x = MOI.add_variable(model);\n\njulia> MOI.set(model, MOI.VariableName(), x, \"x\")\n\njulia> c = MOI.add_constraint(model, 1.0 * x, MOI.LessThan(2.0));\n\njulia> map = MOI.modify(model, MOI.Utilities.PenaltyRelaxation(Dict(c => 2.0)));\n\njulia> print(model)\nMinimize ScalarAffineFunction{Float64}:\n 0.0 + 2.0 v[2]\n\nSubject to:\n\nScalarAffineFunction{Float64}-in-LessThan{Float64}\n 0.0 + 1.0 x - 1.0 v[2] <= 2.0\n\nVariableIndex-in-GreaterThan{Float64}\n v[2] >= 0.0\n\njulia> map[c]\n0.0 + 1.0 MOI.VariableIndex(2)","category":"page"},{"location":"submodules/Utilities/overview/","page":"Overview","title":"Overview","text":"You can also modify a single constraint using Utilities.ScalarPenaltyRelaxation:","category":"page"},{"location":"submodules/Utilities/overview/","page":"Overview","title":"Overview","text":"julia> model = MOI.Utilities.Model{Float64}();\n\njulia> x = MOI.add_variable(model);\n\njulia> MOI.set(model, MOI.VariableName(), x, \"x\")\n\njulia> c = MOI.add_constraint(model, 1.0 * x, MOI.LessThan(2.0));\n\njulia> f = MOI.modify(model, c, MOI.Utilities.ScalarPenaltyRelaxation(2.0));\n\njulia> print(model)\nMinimize ScalarAffineFunction{Float64}:\n 0.0 + 2.0 v[2]\n\nSubject to:\n\nScalarAffineFunction{Float64}-in-LessThan{Float64}\n 0.0 + 1.0 x - 1.0 v[2] <= 2.0\n\nVariableIndex-in-GreaterThan{Float64}\n v[2] >= 0.0\n\njulia> f\n0.0 + 1.0 MOI.VariableIndex(2)","category":"page"},{"location":"submodules/Utilities/overview/#Utilities.MatrixOfConstraints","page":"Overview","title":"Utilities.MatrixOfConstraints","text":"","category":"section"},{"location":"submodules/Utilities/overview/","page":"Overview","title":"Overview","text":"The constraints of Utilities.Model are stored as a vector of tuples of function and set in a Utilities.VectorOfConstraints. Other representations can be used by parameterizing the type Utilities.GenericModel (resp. Utilities.GenericOptimizer). For instance, if all non-VariableIndex constraints are affine, the coefficients of all the constraints can be stored in a single sparse matrix using Utilities.MatrixOfConstraints. The constraints storage can even be customized up to a point where it exactly matches the storage of the solver of interest, in which case copy_to can be implemented for the solver by calling copy_to to this custom model.","category":"page"},{"location":"submodules/Utilities/overview/","page":"Overview","title":"Overview","text":"For instance, Clp defines the following model:","category":"page"},{"location":"submodules/Utilities/overview/","page":"Overview","title":"Overview","text":"MOI.Utilities.@product_of_scalar_sets(LP, MOI.EqualTo{T}, MOI.LessThan{T}, MOI.GreaterThan{T})\nconst Model = MOI.Utilities.GenericModel{\n Float64,\n MOI.Utilities.MatrixOfConstraints{\n Float64,\n MOI.Utilities.MutableSparseMatrixCSC{Float64,Cint,MOI.Utilities.ZeroBasedIndexing},\n MOI.Utilities.Hyperrectangle{Float64},\n LP{Float64},\n },\n}","category":"page"},{"location":"submodules/Utilities/overview/","page":"Overview","title":"Overview","text":"The copy_to operation can now be implemented as follows:","category":"page"},{"location":"submodules/Utilities/overview/","page":"Overview","title":"Overview","text":"function _copy_to(dest::Optimizer, src::Model)\n @assert MOI.is_empty(dest)\n A = src.constraints.coefficients\n row_bounds = src.constraints.constants\n Clp_loadProblem(\n dest,\n A.n,\n A.m,\n A.colptr,\n A.rowval,\n A.nzval,\n src.lower_bound,\n src.upper_bound,\n # (...) objective vector (omitted),\n row_bounds.lower,\n row_bounds.upper,\n )\n # Set objective sense and constant (omitted)\n return\nend\n\nfunction MOI.copy_to(dest::Optimizer, src::Model)\n _copy_to(dest, src)\n return MOI.Utilities.identity_index_map(src)\nend\n\nfunction MOI.copy_to(\n dest::Optimizer,\n src::MOI.Utilities.UniversalFallback{Model},\n)\n # Copy attributes from `src` to `dest` and error in case any unsupported\n # constraints or attributes are set in `UniversalFallback`.\n return MOI.copy_to(dest, src.model)\nend\n\nfunction MOI.copy_to(\n dest::Optimizer,\n src::MOI.ModelLike,\n)\n model = Model()\n index_map = MOI.copy_to(model, src)\n _copy_to(dest, model)\n return index_map\nend","category":"page"},{"location":"submodules/Utilities/overview/#ModelFilter","page":"Overview","title":"ModelFilter","text":"","category":"section"},{"location":"submodules/Utilities/overview/","page":"Overview","title":"Overview","text":"Utilities provides Utilities.ModelFilter as a useful tool to copy a subset of a model. For example, given an infeasible model, we can copy the irreducible infeasible subsystem (for models implementing ConstraintConflictStatus) as follows:","category":"page"},{"location":"submodules/Utilities/overview/","page":"Overview","title":"Overview","text":"my_filter(::Any) = true\nfunction my_filter(ci::MOI.ConstraintIndex)\n status = MOI.get(dest, MOI.ConstraintConflictStatus(), ci)\n return status != MOI.NOT_IN_CONFLICT\nend\nfiltered_src = MOI.Utilities.ModelFilter(my_filter, src)\nindex_map = MOI.copy_to(dest, filtered_src)","category":"page"},{"location":"submodules/Utilities/overview/#Fallbacks","page":"Overview","title":"Fallbacks","text":"","category":"section"},{"location":"submodules/Utilities/overview/","page":"Overview","title":"Overview","text":"The value of some attributes can be inferred from the value of other attributes.","category":"page"},{"location":"submodules/Utilities/overview/","page":"Overview","title":"Overview","text":"For example, the value of ObjectiveValue can be computed using ObjectiveFunction and VariablePrimal.","category":"page"},{"location":"submodules/Utilities/overview/","page":"Overview","title":"Overview","text":"When a solver gives direct access to an attribute, it is better to return this value. However, if this is not the case, Utilities.get_fallback can be used instead. For example:","category":"page"},{"location":"submodules/Utilities/overview/","page":"Overview","title":"Overview","text":"function MOI.get(model::Optimizer, attr::MOI.ObjectiveFunction)\n return MOI.Utilities.get_fallback(model, attr)\nend","category":"page"},{"location":"submodules/Utilities/overview/#DoubleDicts","page":"Overview","title":"DoubleDicts","text":"","category":"section"},{"location":"submodules/Utilities/overview/","page":"Overview","title":"Overview","text":"When writing MOI interfaces, we often need to handle situations in which we map ConstraintIndexs to different values. For example, to a string for ConstraintName.","category":"page"},{"location":"submodules/Utilities/overview/","page":"Overview","title":"Overview","text":"One option is to use a dictionary like Dict{MOI.ConstraintIndex,String}. However, this incurs a performance cost because the key is not a concrete type.","category":"page"},{"location":"submodules/Utilities/overview/","page":"Overview","title":"Overview","text":"The DoubleDicts submodule helps this situation by providing two types main types Utilities.DoubleDicts.DoubleDict and Utilities.DoubleDicts.IndexDoubleDict. These types act like normal dictionaries, but internally they use more efficient dictionaries specialized to the type of the function-set pair.","category":"page"},{"location":"submodules/Utilities/overview/","page":"Overview","title":"Overview","text":"The most common usage of a DoubleDict is in the index_map returned by copy_to. Performance can be improved, by using a function barrier. That is, instead of code like:","category":"page"},{"location":"submodules/Utilities/overview/","page":"Overview","title":"Overview","text":"index_map = MOI.copy_to(dest, src)\nfor (F, S) in MOI.get(src, MOI.ListOfConstraintTypesPresent())\n for ci in MOI.get(src, MOI.ListOfConstraintIndices{F,S}())\n dest_ci = index_map[ci]\n # ...\n end\nend","category":"page"},{"location":"submodules/Utilities/overview/","page":"Overview","title":"Overview","text":"use instead:","category":"page"},{"location":"submodules/Utilities/overview/","page":"Overview","title":"Overview","text":"function function_barrier(\n dest,\n src,\n index_map::MOI.Utilities.DoubleDicts.IndexDoubleDictInner{F,S},\n) where {F,S}\n for ci in MOI.get(src, MOI.ListOfConstraintIndices{F,S}())\n dest_ci = index_map[ci]\n # ...\n end\n return\nend\n\nindex_map = MOI.copy_to(dest, src)\nfor (F, S) in MOI.get(src, MOI.ListOfConstraintTypesPresent())\n function_barrier(dest, src, index_map[F, S])\nend","category":"page"},{"location":"submodules/Nonlinear/overview/","page":"Overview","title":"Overview","text":"CurrentModule = MathOptInterface\nDocTestSetup = quote\n import MathOptInterface as MOI\nend\nDocTestFilters = [r\"MathOptInterface|MOI\"]","category":"page"},{"location":"submodules/Nonlinear/overview/#nonlinear_developers","page":"Overview","title":"Nonlinear","text":"","category":"section"},{"location":"submodules/Nonlinear/overview/","page":"Overview","title":"Overview","text":"warning: Warning\nThe Nonlinear submodule is experimental. Until this message is removed, breaking changes may be introduced in any minor or patch release of MathOptInterface.","category":"page"},{"location":"submodules/Nonlinear/overview/","page":"Overview","title":"Overview","text":"The Nonlinear submodule contains data structures and functions for working with a nonlinear optimization problem in the form of an expression graph. This page explains the API and describes the rationale behind its design.","category":"page"},{"location":"submodules/Nonlinear/overview/#Standard-form","page":"Overview","title":"Standard form","text":"","category":"section"},{"location":"submodules/Nonlinear/overview/","page":"Overview","title":"Overview","text":"Nonlinear programs (NLPs) are a class of optimization problems in which some of the constraints or the objective function are nonlinear:","category":"page"},{"location":"submodules/Nonlinear/overview/","page":"Overview","title":"Overview","text":"beginalign\n min_x in mathbbR^n f_0(x) \n textst l_j le f_j(x) le u_j j = 1 ldots m\nendalign","category":"page"},{"location":"submodules/Nonlinear/overview/","page":"Overview","title":"Overview","text":"There may be additional constraints, as well as things like variable bounds and integrality restrictions, but we do not consider them here because they are best dealt with by other components of MathOptInterface.","category":"page"},{"location":"submodules/Nonlinear/overview/#API-overview","page":"Overview","title":"API overview","text":"","category":"section"},{"location":"submodules/Nonlinear/overview/","page":"Overview","title":"Overview","text":"The core element of the Nonlinear submodule is Nonlinear.Model:","category":"page"},{"location":"submodules/Nonlinear/overview/","page":"Overview","title":"Overview","text":"julia> const Nonlinear = MOI.Nonlinear;\n\njulia> model = Nonlinear.Model()\nA Nonlinear.Model with:\n 0 objectives\n 0 parameters\n 0 expressions\n 0 constraints","category":"page"},{"location":"submodules/Nonlinear/overview/","page":"Overview","title":"Overview","text":"Nonlinear.Model is a mutable struct that stores all of the nonlinear information added to the model.","category":"page"},{"location":"submodules/Nonlinear/overview/#Decision-variables","page":"Overview","title":"Decision variables","text":"","category":"section"},{"location":"submodules/Nonlinear/overview/","page":"Overview","title":"Overview","text":"Decision variables are represented by VariableIndexes. The user is responsible for creating these using MOI.VariableIndex(i), where i is the column associated with the variable.","category":"page"},{"location":"submodules/Nonlinear/overview/#Nonlinear_Expressions","page":"Overview","title":"Expressions","text":"","category":"section"},{"location":"submodules/Nonlinear/overview/","page":"Overview","title":"Overview","text":"The input data structure is a Julia Expr. The input expressions can incorporate VariableIndexes, but these must be interpolated into the expression with $:","category":"page"},{"location":"submodules/Nonlinear/overview/","page":"Overview","title":"Overview","text":"julia> x = MOI.VariableIndex(1)\nMOI.VariableIndex(1)\n\njulia> input = :(1 + sin($x)^2)\n:(1 + sin(MathOptInterface.VariableIndex(1)) ^ 2)","category":"page"},{"location":"submodules/Nonlinear/overview/","page":"Overview","title":"Overview","text":"There are a number of restrictions on the input Expr:","category":"page"},{"location":"submodules/Nonlinear/overview/","page":"Overview","title":"Overview","text":"It cannot contain macros\nIt cannot contain broadcasting\nIt cannot contain splatting (except in limited situations)\nIt cannot contain linear algebra, such as matrix-vector products\nIt cannot contain generator expressions, including sum(i for i in S)","category":"page"},{"location":"submodules/Nonlinear/overview/","page":"Overview","title":"Overview","text":"Given an input expression, add an expression using Nonlinear.add_expression:","category":"page"},{"location":"submodules/Nonlinear/overview/","page":"Overview","title":"Overview","text":"julia> expr = Nonlinear.add_expression(model, input)\nMathOptInterface.Nonlinear.ExpressionIndex(1)","category":"page"},{"location":"submodules/Nonlinear/overview/","page":"Overview","title":"Overview","text":"The return value, expr, is a Nonlinear.ExpressionIndex that can then be interpolated into other input expressions.","category":"page"},{"location":"submodules/Nonlinear/overview/","page":"Overview","title":"Overview","text":"Looking again at model, we see:","category":"page"},{"location":"submodules/Nonlinear/overview/","page":"Overview","title":"Overview","text":"julia> model\nA Nonlinear.Model with:\n 0 objectives\n 0 parameters\n 1 expression\n 0 constraints","category":"page"},{"location":"submodules/Nonlinear/overview/#Nonlinear_Parameters","page":"Overview","title":"Parameters","text":"","category":"section"},{"location":"submodules/Nonlinear/overview/","page":"Overview","title":"Overview","text":"In addition to constant literals like 1 or 1.23, you can create parameters. Parameters are placeholders whose values can change before passing the expression to the solver. Create a parameter using Nonlinear.add_parameter, which accepts a default value:","category":"page"},{"location":"submodules/Nonlinear/overview/","page":"Overview","title":"Overview","text":"julia> p = Nonlinear.add_parameter(model, 1.23)\nMathOptInterface.Nonlinear.ParameterIndex(1)","category":"page"},{"location":"submodules/Nonlinear/overview/","page":"Overview","title":"Overview","text":"The return value, p, is a Nonlinear.ParameterIndex that can then be interpolated into other input expressions.","category":"page"},{"location":"submodules/Nonlinear/overview/","page":"Overview","title":"Overview","text":"Looking again at model, we see:","category":"page"},{"location":"submodules/Nonlinear/overview/","page":"Overview","title":"Overview","text":"julia> model\nA Nonlinear.Model with:\n 0 objectives\n 1 parameter\n 1 expression\n 0 constraints","category":"page"},{"location":"submodules/Nonlinear/overview/","page":"Overview","title":"Overview","text":"Update a parameter as follows:","category":"page"},{"location":"submodules/Nonlinear/overview/","page":"Overview","title":"Overview","text":"julia> model[p]\n1.23\n\njulia> model[p] = 4.56\n4.56\n\njulia> model[p]\n4.56","category":"page"},{"location":"submodules/Nonlinear/overview/#Nonlinear_Objectives","page":"Overview","title":"Objectives","text":"","category":"section"},{"location":"submodules/Nonlinear/overview/","page":"Overview","title":"Overview","text":"Set a nonlinear objective using Nonlinear.set_objective:","category":"page"},{"location":"submodules/Nonlinear/overview/","page":"Overview","title":"Overview","text":"julia> Nonlinear.set_objective(model, :($p + $expr + $x))\n\njulia> model\nA Nonlinear.Model with:\n 1 objective\n 1 parameter\n 1 expression\n 0 constraints","category":"page"},{"location":"submodules/Nonlinear/overview/","page":"Overview","title":"Overview","text":"Clear a nonlinear objective by passing nothing:","category":"page"},{"location":"submodules/Nonlinear/overview/","page":"Overview","title":"Overview","text":"julia> Nonlinear.set_objective(model, nothing)\n\njulia> model\nA Nonlinear.Model with:\n 0 objectives\n 1 parameter\n 1 expression\n 0 constraints","category":"page"},{"location":"submodules/Nonlinear/overview/","page":"Overview","title":"Overview","text":"But we'll re-add the objective for later:","category":"page"},{"location":"submodules/Nonlinear/overview/","page":"Overview","title":"Overview","text":"julia> Nonlinear.set_objective(model, :($p + $expr + $x));","category":"page"},{"location":"submodules/Nonlinear/overview/#Nonlinear_Constraints","page":"Overview","title":"Constraints","text":"","category":"section"},{"location":"submodules/Nonlinear/overview/","page":"Overview","title":"Overview","text":"Add a constraint using Nonlinear.add_constraint:","category":"page"},{"location":"submodules/Nonlinear/overview/","page":"Overview","title":"Overview","text":"julia> c = Nonlinear.add_constraint(model, :(1 + sqrt($x)), MOI.LessThan(2.0))\nMathOptInterface.Nonlinear.ConstraintIndex(1)\n\njulia> model\nA Nonlinear.Model with:\n 1 objective\n 1 parameter\n 1 expression\n 1 constraint","category":"page"},{"location":"submodules/Nonlinear/overview/","page":"Overview","title":"Overview","text":"The return value, c, is a Nonlinear.ConstraintIndex that is a unique identifier for the constraint. Interval constraints are also supported:","category":"page"},{"location":"submodules/Nonlinear/overview/","page":"Overview","title":"Overview","text":"julia> c2 = Nonlinear.add_constraint(model, :(1 + sqrt($x)), MOI.Interval(-1.0, 2.0))\nMathOptInterface.Nonlinear.ConstraintIndex(2)\n\njulia> model\nA Nonlinear.Model with:\n 1 objective\n 1 parameter\n 1 expression\n 2 constraints","category":"page"},{"location":"submodules/Nonlinear/overview/","page":"Overview","title":"Overview","text":"Delete a constraint using Nonlinear.delete:","category":"page"},{"location":"submodules/Nonlinear/overview/","page":"Overview","title":"Overview","text":"julia> Nonlinear.delete(model, c2)\n\njulia> model\nA Nonlinear.Model with:\n 1 objective\n 1 parameter\n 1 expression\n 1 constraint","category":"page"},{"location":"submodules/Nonlinear/overview/#User-defined-operators","page":"Overview","title":"User-defined operators","text":"","category":"section"},{"location":"submodules/Nonlinear/overview/","page":"Overview","title":"Overview","text":"By default, Nonlinear supports a wide range of univariate and multivariate operators. However, you can also define your own operators by registering them.","category":"page"},{"location":"submodules/Nonlinear/overview/#Univariate-operators","page":"Overview","title":"Univariate operators","text":"","category":"section"},{"location":"submodules/Nonlinear/overview/","page":"Overview","title":"Overview","text":"Register a univariate user-defined operator using Nonlinear.register_operator:","category":"page"},{"location":"submodules/Nonlinear/overview/","page":"Overview","title":"Overview","text":"julia> f(x) = 1 + sin(x)^2\nf (generic function with 1 method)\n\njulia> Nonlinear.register_operator(model, :my_f, 1, f)","category":"page"},{"location":"submodules/Nonlinear/overview/","page":"Overview","title":"Overview","text":"Now, you can use :my_f in expressions:","category":"page"},{"location":"submodules/Nonlinear/overview/","page":"Overview","title":"Overview","text":"julia> new_expr = Nonlinear.add_expression(model, :(my_f($x + 1)))\nMathOptInterface.Nonlinear.ExpressionIndex(2)","category":"page"},{"location":"submodules/Nonlinear/overview/","page":"Overview","title":"Overview","text":"By default, Nonlinear will compute first- and second-derivatives of the registered operator using ForwardDiff.jl. Override this by passing functions which compute the respective derivative:","category":"page"},{"location":"submodules/Nonlinear/overview/","page":"Overview","title":"Overview","text":"julia> f′(x) = 2 * sin(x) * cos(x)\nf′ (generic function with 1 method)\n\njulia> Nonlinear.register_operator(model, :my_f2, 1, f, f′)","category":"page"},{"location":"submodules/Nonlinear/overview/","page":"Overview","title":"Overview","text":"or","category":"page"},{"location":"submodules/Nonlinear/overview/","page":"Overview","title":"Overview","text":"julia> f′′(x) = 2 * (cos(x)^2 - sin(x)^2)\nf′′ (generic function with 1 method)\n\njulia> Nonlinear.register_operator(model, :my_f3, 1, f, f′, f′′)","category":"page"},{"location":"submodules/Nonlinear/overview/#Multivariate-operators","page":"Overview","title":"Multivariate operators","text":"","category":"section"},{"location":"submodules/Nonlinear/overview/","page":"Overview","title":"Overview","text":"Register a multivariate user-defined operator using Nonlinear.register_operator:","category":"page"},{"location":"submodules/Nonlinear/overview/","page":"Overview","title":"Overview","text":"julia> g(x...) = x[1]^2 + x[1] * x[2] + x[2]^2\ng (generic function with 1 method)\n\njulia> Nonlinear.register_operator(model, :my_g, 2, g)","category":"page"},{"location":"submodules/Nonlinear/overview/","page":"Overview","title":"Overview","text":"Now, you can use :my_g in expressions:","category":"page"},{"location":"submodules/Nonlinear/overview/","page":"Overview","title":"Overview","text":"julia> new_expr = Nonlinear.add_expression(model, :(my_g($x + 1, $x)))\nMathOptInterface.Nonlinear.ExpressionIndex(3)","category":"page"},{"location":"submodules/Nonlinear/overview/","page":"Overview","title":"Overview","text":"By default, Nonlinear will compute the gradient of the registered operator using ForwardDiff.jl. (Hessian information is not supported.) Override this by passing a function to compute the gradient:","category":"page"},{"location":"submodules/Nonlinear/overview/","page":"Overview","title":"Overview","text":"julia> function ∇g(ret, x...)\n ret[1] = 2 * x[1] + x[2]\n ret[2] = x[1] + 2 * x[2]\n return\n end\n∇g (generic function with 1 method)\n\njulia> Nonlinear.register_operator(model, :my_g2, 2, g, ∇g)","category":"page"},{"location":"submodules/Nonlinear/overview/#Nonlinear_MOI_interface","page":"Overview","title":"MathOptInterface","text":"","category":"section"},{"location":"submodules/Nonlinear/overview/","page":"Overview","title":"Overview","text":"MathOptInterface communicates the nonlinear portion of an optimization problem to solvers using concrete subtypes of AbstractNLPEvaluator, which implement the Nonlinear programming API.","category":"page"},{"location":"submodules/Nonlinear/overview/","page":"Overview","title":"Overview","text":"Create an AbstractNLPEvaluator from Nonlinear.Model using Nonlinear.Evaluator.","category":"page"},{"location":"submodules/Nonlinear/overview/","page":"Overview","title":"Overview","text":"Nonlinear.Evaluator requires an Nonlinear.AbstractAutomaticDifferentiation backend and an ordered list of the variables that are included in the model.","category":"page"},{"location":"submodules/Nonlinear/overview/","page":"Overview","title":"Overview","text":"There following backends are available to choose from within MOI, although other packages may add more options by sub-typing Nonlinear.AbstractAutomaticDifferentiation:","category":"page"},{"location":"submodules/Nonlinear/overview/","page":"Overview","title":"Overview","text":"Nonlinear.ExprGraphOnly\nNonlinear.SparseReverseMode.","category":"page"},{"location":"submodules/Nonlinear/overview/","page":"Overview","title":"Overview","text":"julia> evaluator = Nonlinear.Evaluator(model, Nonlinear.ExprGraphOnly(), [x])\nNonlinear.Evaluator with available features:\n * :ExprGraph","category":"page"},{"location":"submodules/Nonlinear/overview/","page":"Overview","title":"Overview","text":"The functions of the Nonlinear programming API implemented by Nonlinear.Evaluator depends upon the chosen Nonlinear.AbstractAutomaticDifferentiation backend.","category":"page"},{"location":"submodules/Nonlinear/overview/","page":"Overview","title":"Overview","text":"The :ExprGraph feature means we can call objective_expr and constraint_expr to retrieve the expression graph of the problem. However, we cannot call gradient terms such as eval_objective_gradient because Nonlinear.ExprGraphOnly does not have the capability to differentiate a nonlinear expression.","category":"page"},{"location":"submodules/Nonlinear/overview/","page":"Overview","title":"Overview","text":"If, instead, we pass Nonlinear.SparseReverseMode, then we get access to :Grad, the gradient of the objective function, :Jac, the Jacobian matrix of the constraints, :JacVec, the ability to compute Jacobian-vector products, and :ExprGraph.","category":"page"},{"location":"submodules/Nonlinear/overview/","page":"Overview","title":"Overview","text":"julia> evaluator = Nonlinear.Evaluator(\n model,\n Nonlinear.SparseReverseMode(),\n [x],\n )\nNonlinear.Evaluator with available features:\n * :Grad\n * :Jac\n * :JacVec\n * :ExprGraph","category":"page"},{"location":"submodules/Nonlinear/overview/","page":"Overview","title":"Overview","text":"However, before using the evaluator, we need to call initialize:","category":"page"},{"location":"submodules/Nonlinear/overview/","page":"Overview","title":"Overview","text":"julia> MOI.initialize(evaluator, [:Grad, :Jac, :JacVec, :ExprGraph])","category":"page"},{"location":"submodules/Nonlinear/overview/","page":"Overview","title":"Overview","text":"Now we can call methods like eval_objective:","category":"page"},{"location":"submodules/Nonlinear/overview/","page":"Overview","title":"Overview","text":"julia> x = [1.0]\n1-element Vector{Float64}:\n 1.0\n\njulia> MOI.eval_objective(evaluator, x)\n7.268073418273571","category":"page"},{"location":"submodules/Nonlinear/overview/","page":"Overview","title":"Overview","text":"and eval_objective_gradient:","category":"page"},{"location":"submodules/Nonlinear/overview/","page":"Overview","title":"Overview","text":"julia> grad = [0.0]\n1-element Vector{Float64}:\n 0.0\n\njulia> MOI.eval_objective_gradient(evaluator, grad, x)\n\njulia> grad\n1-element Vector{Float64}:\n 1.909297426825682","category":"page"},{"location":"submodules/Nonlinear/overview/","page":"Overview","title":"Overview","text":"Instead of passing Nonlinear.Evaluator directly to solvers, solvers query the NLPBlock attribute, which returns an NLPBlockData. This object wraps an Nonlinear.Evaluator and includes other information such as constraint bounds and whether the evaluator has a nonlinear objective. Create and set NLPBlockData as follows:","category":"page"},{"location":"submodules/Nonlinear/overview/","page":"Overview","title":"Overview","text":"julia> block = MOI.NLPBlockData(evaluator);\n\njulia> model = MOI.Utilities.UniversalFallback(MOI.Utilities.Model{Float64}());\n\njulia> MOI.set(model, MOI.NLPBlock(), block);","category":"page"},{"location":"submodules/Nonlinear/overview/","page":"Overview","title":"Overview","text":"warning: Warning\nOnly call NLPBlockData once you have finished modifying the problem in model.","category":"page"},{"location":"submodules/Nonlinear/overview/","page":"Overview","title":"Overview","text":"Putting everything together, you can create a nonlinear optimization problem in MathOptInterface as follows:","category":"page"},{"location":"submodules/Nonlinear/overview/","page":"Overview","title":"Overview","text":"import MathOptInterface as MOI\n\nfunction build_model(\n model::MOI.ModelLike;\n backend::MOI.Nonlinear.AbstractAutomaticDifferentiation,\n)\n x = MOI.add_variable(model)\n y = MOI.add_variable(model)\n MOI.set(model, MOI.ObjectiveSense(), MOI.MIN_SENSE)\n nl_model = MOI.Nonlinear.Model()\n MOI.Nonlinear.set_objective(nl_model, :($x^2 + $y^2))\n evaluator = MOI.Nonlinear.Evaluator(nl_model, backend, [x, y])\n MOI.set(model, MOI.NLPBlock(), MOI.NLPBlockData(evaluator))\n return\nend\n\n# Replace `model` and `backend` with your optimizer and backend of choice.\nmodel = MOI.Utilities.UniversalFallback(MOI.Utilities.Model{Float64}())\nbuild_model(model; backend = MOI.Nonlinear.SparseReverseMode())","category":"page"},{"location":"submodules/Nonlinear/overview/#Expression-graph-representation","page":"Overview","title":"Expression-graph representation","text":"","category":"section"},{"location":"submodules/Nonlinear/overview/","page":"Overview","title":"Overview","text":"Nonlinear.Model stores nonlinear expressions in Nonlinear.Expressions. This section explains the design of the expression graph data structure in Nonlinear.Expression.","category":"page"},{"location":"submodules/Nonlinear/overview/","page":"Overview","title":"Overview","text":"Given a nonlinear function like f(x) = sin(x)^2 + x, a conceptual aid for thinking about the graph representation of the expression is to convert it into Polish prefix notation:","category":"page"},{"location":"submodules/Nonlinear/overview/","page":"Overview","title":"Overview","text":"f(x, y) = (+ (^ (sin x) 2) x)","category":"page"},{"location":"submodules/Nonlinear/overview/","page":"Overview","title":"Overview","text":"This format identifies each operator (function), as well as a list of arguments. Operators can be univariate, like sin, or multivariate, like +.","category":"page"},{"location":"submodules/Nonlinear/overview/","page":"Overview","title":"Overview","text":"A common way of representing Polish prefix notation in code is as follows:","category":"page"},{"location":"submodules/Nonlinear/overview/","page":"Overview","title":"Overview","text":"julia> x = MOI.VariableIndex(1);\n\njulia> struct ExprNode\n op::Symbol\n children::Vector{Union{ExprNode,Float64,MOI.VariableIndex}}\n end\n\njulia> expr = ExprNode(:+, [ExprNode(:^, [ExprNode(:sin, [x]), 2.0]), x]);","category":"page"},{"location":"submodules/Nonlinear/overview/","page":"Overview","title":"Overview","text":"This data structure follows our Polish prefix notation very closely, and we can easily identify the arguments to an operator. However, it has a significant draw-back: each node in the graph requires a Vector, which is heap-allocated and tracked by Julia's garbage collector (GC). For large models, we can expect to have millions of nodes in the expression graph, so this overhead quickly becomes prohibitive for computation.","category":"page"},{"location":"submodules/Nonlinear/overview/","page":"Overview","title":"Overview","text":"An alternative is to record the expression as a linear tape:","category":"page"},{"location":"submodules/Nonlinear/overview/","page":"Overview","title":"Overview","text":"julia> expr = Any[:+, 2, :^, 2, :sin, 1, x, 2.0, x]\n9-element Vector{Any}:\n :+\n 2\n :^\n 2\n :sin\n 1\n MOI.VariableIndex(1)\n 2.0\n MOI.VariableIndex(1)","category":"page"},{"location":"submodules/Nonlinear/overview/","page":"Overview","title":"Overview","text":"The Int after each operator Symbol specifies the number of arguments.","category":"page"},{"location":"submodules/Nonlinear/overview/","page":"Overview","title":"Overview","text":"This data-structure is a single vector, which resolves our problem with the GC, but each element is the abstract type, Any, and so any operations on it will lead to slower dynamic dispatch. It's also hard to identify the children of each operation without reading the entire tape.","category":"page"},{"location":"submodules/Nonlinear/overview/","page":"Overview","title":"Overview","text":"To summarize, representing expression graphs in Julia has the following challenges:","category":"page"},{"location":"submodules/Nonlinear/overview/","page":"Overview","title":"Overview","text":"Nodes in the expression graph should not contain a heap-allocated object\nAll data-structures should be concretely typed\nIt should be easy to identify the children of a node","category":"page"},{"location":"submodules/Nonlinear/overview/#Sketch-of-the-design-in-Nonlinear","page":"Overview","title":"Sketch of the design in Nonlinear","text":"","category":"section"},{"location":"submodules/Nonlinear/overview/","page":"Overview","title":"Overview","text":"Nonlinear overcomes these problems by decomposing the data structure into a number of different concrete-typed vectors.","category":"page"},{"location":"submodules/Nonlinear/overview/","page":"Overview","title":"Overview","text":"First, we create vectors of the supported uni- and multivariate operators.","category":"page"},{"location":"submodules/Nonlinear/overview/","page":"Overview","title":"Overview","text":"julia> const UNIVARIATE_OPERATORS = [:sin];\n\njulia> const MULTIVARIATE_OPERATORS = [:+, :^];","category":"page"},{"location":"submodules/Nonlinear/overview/","page":"Overview","title":"Overview","text":"In practice, there are many more supported operations than the ones listed here.","category":"page"},{"location":"submodules/Nonlinear/overview/","page":"Overview","title":"Overview","text":"Second, we create an enum to represent the different types of nodes present in the expression graph:","category":"page"},{"location":"submodules/Nonlinear/overview/","page":"Overview","title":"Overview","text":"julia> @enum(\n NodeType,\n NODE_CALL_MULTIVARIATE,\n NODE_CALL_UNIVARIATE,\n NODE_VARIABLE,\n NODE_VALUE,\n )","category":"page"},{"location":"submodules/Nonlinear/overview/","page":"Overview","title":"Overview","text":"In practice, there are node types other than the ones listed here.","category":"page"},{"location":"submodules/Nonlinear/overview/","page":"Overview","title":"Overview","text":"Third, we create two concretely typed structs as follows:","category":"page"},{"location":"submodules/Nonlinear/overview/","page":"Overview","title":"Overview","text":"julia> struct Node\n type::NodeType\n parent::Int\n index::Int\n end\n\njulia> struct Expression\n nodes::Vector{Node}\n values::Vector{Float64}\n end","category":"page"},{"location":"submodules/Nonlinear/overview/","page":"Overview","title":"Overview","text":"For each node node in the .nodes field, if node.type is:","category":"page"},{"location":"submodules/Nonlinear/overview/","page":"Overview","title":"Overview","text":"NODE_CALL_MULTIVARIATE, we look up MULTIVARIATE_OPERATORS[node.index] to retrieve the operator\nNODE_CALL_UNIVARIATE, we look up UNIVARIATE_OPERATORS[node.index] to retrieve the operator\nNODE_VARIABLE, we create MOI.VariableIndex(node.index)\nNODE_VALUE, we look up values[node.index]","category":"page"},{"location":"submodules/Nonlinear/overview/","page":"Overview","title":"Overview","text":"The .parent field of each node is the integer index of the parent node in .nodes. For the first node, the parent is -1 by convention.","category":"page"},{"location":"submodules/Nonlinear/overview/","page":"Overview","title":"Overview","text":"Therefore, we can represent our function as:","category":"page"},{"location":"submodules/Nonlinear/overview/","page":"Overview","title":"Overview","text":"julia> expr = Expression(\n [\n Node(NODE_CALL_MULTIVARIATE, -1, 1),\n Node(NODE_CALL_MULTIVARIATE, 1, 2),\n Node(NODE_CALL_UNIVARIATE, 2, 1),\n Node(NODE_VARIABLE, 3, 1),\n Node(NODE_VALUE, 2, 1),\n Node(NODE_VARIABLE, 1, 1),\n ],\n [2.0],\n );","category":"page"},{"location":"submodules/Nonlinear/overview/","page":"Overview","title":"Overview","text":"This is less readable than the other options, but does this data structure meet our design goals?","category":"page"},{"location":"submodules/Nonlinear/overview/","page":"Overview","title":"Overview","text":"Instead of a heap-allocated object for each node, we only have two Vectors for each expression, nodes and values, as well as two constant vectors for the OPERATORS. In addition, all fields are concretely typed, and there are no Union or Any types.","category":"page"},{"location":"submodules/Nonlinear/overview/","page":"Overview","title":"Overview","text":"For our third goal, it is not easy to identify the children of a node, but it is easy to identify the parent of any node. Therefore, we can use Nonlinear.adjacency_matrix to compute a sparse matrix that maps parents to their children.","category":"page"},{"location":"submodules/Nonlinear/overview/","page":"Overview","title":"Overview","text":"The tape is also ordered topologically, so that a reverse pass of the nodes evaluates all children nodes before their parent.","category":"page"},{"location":"submodules/Nonlinear/overview/#The-design-in-practice","page":"Overview","title":"The design in practice","text":"","category":"section"},{"location":"submodules/Nonlinear/overview/","page":"Overview","title":"Overview","text":"In practice, Node and Expression are exactly Nonlinear.Node and Nonlinear.Expression. However, Nonlinear.NodeType has more fields to account for comparison operators such as :>= and :<=, logic operators such as :&& and :||, nonlinear parameters, and nested subexpressions.","category":"page"},{"location":"submodules/Nonlinear/overview/","page":"Overview","title":"Overview","text":"Moreover, instead of storing the operators as global constants, they are stored in Nonlinear.OperatorRegistry, and it also stores a vector of logic operators and a vector of comparison operators. In addition to Nonlinear.DEFAULT_UNIVARIATE_OPERATORS and Nonlinear.DEFAULT_MULTIVARIATE_OPERATORS, you can register user-defined functions using Nonlinear.register_operator.","category":"page"},{"location":"submodules/Nonlinear/overview/","page":"Overview","title":"Overview","text":"Nonlinear.Model is a struct that stores the Nonlinear.OperatorRegistry, as well as a list of parameters and subexpressions in the model.","category":"page"},{"location":"submodules/Nonlinear/overview/#ReverseAD","page":"Overview","title":"ReverseAD","text":"","category":"section"},{"location":"submodules/Nonlinear/overview/","page":"Overview","title":"Overview","text":"Nonlinear.ReverseAD is a submodule for computing derivatives of a nonlinear optimization problem using sparse reverse-mode automatic differentiation (AD).","category":"page"},{"location":"submodules/Nonlinear/overview/","page":"Overview","title":"Overview","text":"This section does not attempt to explain how sparse reverse-mode AD works, but instead explains why MOI contains its own implementation, and highlights notable differences from similar packages.","category":"page"},{"location":"submodules/Nonlinear/overview/","page":"Overview","title":"Overview","text":"warning: Warning\nDon't use the API in ReverseAD to compute derivatives. Instead, create a Nonlinear.Evaluator object with Nonlinear.SparseReverseMode as the backend, and then query the MOI API methods.","category":"page"},{"location":"submodules/Nonlinear/overview/#Design-goals","page":"Overview","title":"Design goals","text":"","category":"section"},{"location":"submodules/Nonlinear/overview/","page":"Overview","title":"Overview","text":"The JuliaDiff organization maintains a list of packages for doing AD in Julia. At last count, there were at least ten packages——not including ReverseAD——for reverse-mode AD in Julia. ReverseAD exists because it has a different set of design goals.","category":"page"},{"location":"submodules/Nonlinear/overview/","page":"Overview","title":"Overview","text":"Goal: handle scale and sparsity. The types of nonlinear optimization problems that MOI represents can be large scale (10^5 or more functions across 10^5 or more variables) with very sparse derivatives. The ability to compute a sparse Hessian matrix is essential. To the best of our knowledge, ReverseAD is the only reverse-mode AD system in Julia that handles sparsity by default.\nGoal: limit the scope to improve robustness. Most other AD packages accept arbitrary Julia functions as input and then trace an expression graph using operator overloading. This means they must deal (or detect and ignore) with control flow, I/O, and other vagaries of Julia. In contrast, ReverseAD only accepts functions in the form of Nonlinear.Expression, which greatly limits the range of syntax that it must deal with. By reducing the scope of what we accept as input to functions relevant for mathematical optimization, we can provide a simpler implementation with various performance optimizations.\nGoal: provide outputs which match what solvers expect. Other AD packages focus on differentiating individual Julia functions. In contrast, ReverseAD has a very specific use-case: to generate outputs needed by the MOI nonlinear API. This means it needs to efficiently compute sparse Hessians, and it needs subexpression handling to avoid recomputing subexpressions that are shared between functions.","category":"page"},{"location":"submodules/Nonlinear/overview/#History","page":"Overview","title":"History","text":"","category":"section"},{"location":"submodules/Nonlinear/overview/","page":"Overview","title":"Overview","text":"ReverseAD started life as ReverseDiffSparse.jl, development of which began in early 2014(!). This was well before the other AD packages started development. Because we had a well-tested, working AD in JuMP, there was less motivation to contribute to and explore other AD packages. The lack of historical interaction also meant that other packages were not optimized for the types of problems that JuMP is built for (that is, large-scale sparse problems). When we first created MathOptInterface, we kept the AD in JuMP to simplify the transition, and post-poned the development of a first-class nonlinear interface in MathOptInterface.","category":"page"},{"location":"submodules/Nonlinear/overview/","page":"Overview","title":"Overview","text":"Prior to the introduction of Nonlinear, JuMP's nonlinear implementation was a confusing mix of functions and types spread across the code base and in the private _Derivatives submodule. This made it hard to swap the AD system for another. The main motivation for refactoring JuMP to create the Nonlinear submodule in MathOptInterface was to abstract the interface between JuMP and the AD system, allowing us to swap-in and test new AD systems in the future.","category":"page"},{"location":"tutorials/bridging_constraint/","page":"Implementing a constraint bridge","title":"Implementing a constraint bridge","text":"CurrentModule = MathOptInterface\nDocTestSetup = quote\n import MathOptInterface as MOI\nend\nDocTestFilters = [r\"MathOptInterface|MOI\"]","category":"page"},{"location":"tutorials/bridging_constraint/#Implementing-a-constraint-bridge","page":"Implementing a constraint bridge","title":"Implementing a constraint bridge","text":"","category":"section"},{"location":"tutorials/bridging_constraint/","page":"Implementing a constraint bridge","title":"Implementing a constraint bridge","text":"This guide outlines the basic steps to create a new bridge from a constraint expressed in the formalism Function-in-Set.","category":"page"},{"location":"tutorials/bridging_constraint/#Preliminaries","page":"Implementing a constraint bridge","title":"Preliminaries","text":"","category":"section"},{"location":"tutorials/bridging_constraint/","page":"Implementing a constraint bridge","title":"Implementing a constraint bridge","text":"First, decide on the set you want to bridge. Then, study its properties: the most important one is whether the set is scalar or vector, which impacts the dimensionality of the functions that can be used with the set.","category":"page"},{"location":"tutorials/bridging_constraint/","page":"Implementing a constraint bridge","title":"Implementing a constraint bridge","text":"A scalar function only has one dimension. MOI defines three types of scalar functions: a variable (VariableIndex), an affine function (ScalarAffineFunction), or a quadratic function (ScalarQuadraticFunction).\nA vector function has several dimensions (at least one). MOI defines three types of vector functions: several variables (VectorOfVariables), an affine function (VectorAffineFunction), or a quadratic function (VectorQuadraticFunction). The main difference with scalar functions is that the order of dimensions can be very important: for instance, in an indicator constraint (Indicator), the first dimension indicates whether the constraint about the second dimension is active.","category":"page"},{"location":"tutorials/bridging_constraint/","page":"Implementing a constraint bridge","title":"Implementing a constraint bridge","text":"To explain how to implement a bridge, we present the example of Bridges.Constraint.FlipSignBridge. This bridge maps <= (LessThan) constraints to >= (GreaterThan) constraints. This corresponds to reversing the sign of the inequality. We focus on scalar affine functions (we disregard the cases of a single variable or of quadratic functions). This example is a simplified version of the code included in MOI.","category":"page"},{"location":"tutorials/bridging_constraint/#Four-mandatory-parts-in-a-constraint-bridge","page":"Implementing a constraint bridge","title":"Four mandatory parts in a constraint bridge","text":"","category":"section"},{"location":"tutorials/bridging_constraint/","page":"Implementing a constraint bridge","title":"Implementing a constraint bridge","text":"The first part of a constraint bridge is a new concrete subtype of Bridges.Constraint.AbstractBridge. This type must have fields to store all the new variables and constraints that the bridge will add. Typically, these types are parametrized by the type of the coefficients in the model.","category":"page"},{"location":"tutorials/bridging_constraint/","page":"Implementing a constraint bridge","title":"Implementing a constraint bridge","text":"Then, three sets of functions must be defined:","category":"page"},{"location":"tutorials/bridging_constraint/","page":"Implementing a constraint bridge","title":"Implementing a constraint bridge","text":"Bridges.Constraint.bridge_constraint: this function implements the bridge and creates the required variables and constraints.\nsupports_constraint: these functions must return true when the combination of function and set is supported by the bridge. By default, the base implementation always returns false and the bridge does not have to provide this implementation.\nBridges.added_constrained_variable_types and Bridges.added_constraint_types: these functions return the types of variables and constraints that this bridge adds. They are used to compute the set of other bridges that are required to use the one you are defining, if need be.","category":"page"},{"location":"tutorials/bridging_constraint/","page":"Implementing a constraint bridge","title":"Implementing a constraint bridge","text":"More functions can be implemented, for instance to retrieve properties from the bridge or deleting a bridged constraint.","category":"page"},{"location":"tutorials/bridging_constraint/#.-Structure-for-the-bridge","page":"Implementing a constraint bridge","title":"1. Structure for the bridge","text":"","category":"section"},{"location":"tutorials/bridging_constraint/","page":"Implementing a constraint bridge","title":"Implementing a constraint bridge","text":"A typical struct behind a bridge depends on the type of the coefficients that are used for the model (typically Float64, but coefficients might also be integers or complex numbers).","category":"page"},{"location":"tutorials/bridging_constraint/","page":"Implementing a constraint bridge","title":"Implementing a constraint bridge","text":"This structure must hold a reference to all the variables and the constraints that are created as part of the bridge.","category":"page"},{"location":"tutorials/bridging_constraint/","page":"Implementing a constraint bridge","title":"Implementing a constraint bridge","text":"The type of this structure is used throughout MOI as an identifier for the bridge. It is passed as argument to most functions related to bridges.","category":"page"},{"location":"tutorials/bridging_constraint/","page":"Implementing a constraint bridge","title":"Implementing a constraint bridge","text":"The best practice is to have the name of this type end with Bridge.","category":"page"},{"location":"tutorials/bridging_constraint/","page":"Implementing a constraint bridge","title":"Implementing a constraint bridge","text":"In our example, the bridge maps any ScalarAffineFunction{T}-in-LessThan{T} constraint to a single ScalarAffineFunction{T}-in-GreaterThan{T} constraint. The affine function has coefficients of type T. The bridge is parametrized with T, so that the constraint that the bridge creates also has coefficients of type T.","category":"page"},{"location":"tutorials/bridging_constraint/","page":"Implementing a constraint bridge","title":"Implementing a constraint bridge","text":"struct SignBridge{T<:Number} <: Bridges.Constraint.AbstractBridge\n constraint::ConstraintIndex{ScalarAffineFunction{T}, GreaterThan{T}}\nend","category":"page"},{"location":"tutorials/bridging_constraint/#.-Bridge-creation","page":"Implementing a constraint bridge","title":"2. Bridge creation","text":"","category":"section"},{"location":"tutorials/bridging_constraint/","page":"Implementing a constraint bridge","title":"Implementing a constraint bridge","text":"The function Bridges.Constraint.bridge_constraint is called whenever the bridge is instantiated for a specific model, with the given function and set. The arguments to bridge_constraint are similar to add_constraint, with the exception of the first argument: it is the Type of the struct defined in the first step (for our example, Type{SignBridge{T}}).","category":"page"},{"location":"tutorials/bridging_constraint/","page":"Implementing a constraint bridge","title":"Implementing a constraint bridge","text":"bridge_constraint returns an instance of the struct defined in the first step. the first step.","category":"page"},{"location":"tutorials/bridging_constraint/","page":"Implementing a constraint bridge","title":"Implementing a constraint bridge","text":"In our example, the bridge constraint could be defined as:","category":"page"},{"location":"tutorials/bridging_constraint/","page":"Implementing a constraint bridge","title":"Implementing a constraint bridge","text":"function Bridges.Constraint.bridge_constraint(\n ::Type{SignBridge{T}}, # Bridge to use.\n model::ModelLike, # Model to which the constraint is being added.\n f::ScalarAffineFunction{T}, # Function to rewrite.\n s::LessThan{T}, # Set to rewrite.\n) where {T}\n # Create the variables and constraints required for the bridge.\n con = add_constraint(model, -f, GreaterThan(-s.upper))\n\n # Return an instance of the bridge type with a reference to all the\n # variables and constraints that were created in this function.\n return SignBridge(con)\nend","category":"page"},{"location":"tutorials/bridging_constraint/#.-Supported-constraint-types","page":"Implementing a constraint bridge","title":"3. Supported constraint types","text":"","category":"section"},{"location":"tutorials/bridging_constraint/","page":"Implementing a constraint bridge","title":"Implementing a constraint bridge","text":"The function supports_constraint determines whether the bridge type supports a given combination of function and set.","category":"page"},{"location":"tutorials/bridging_constraint/","page":"Implementing a constraint bridge","title":"Implementing a constraint bridge","text":"This function must closely match bridge_constraint, because it will not be called if supports_constraint returns false.","category":"page"},{"location":"tutorials/bridging_constraint/","page":"Implementing a constraint bridge","title":"Implementing a constraint bridge","text":"function supports_constraint(\n ::Type{SignBridge{T}}, # Bridge to use.\n ::Type{ScalarAffineFunction{T}}, # Function to rewrite.\n ::Type{LessThan{T}}, # Set to rewrite.\n) where {T}\n # Do some computation to ensure that the constraint is supported.\n # Typically, you can directly return true.\n return true\nend","category":"page"},{"location":"tutorials/bridging_constraint/#.-Metadata-about-the-bridge","page":"Implementing a constraint bridge","title":"4. Metadata about the bridge","text":"","category":"section"},{"location":"tutorials/bridging_constraint/","page":"Implementing a constraint bridge","title":"Implementing a constraint bridge","text":"To determine whether a bridge can be used, MOI uses a shortest-path algorithm that uses the variable types and the constraints that the bridge can create. This information is communicated from the bridge to MOI using the functions Bridges.added_constrained_variable_types and Bridges.added_constraint_types. Both return lists of tuples: either a list of 1-tuples containing the variable types (typically, ZeroOne or Integer) or a list of 2-tuples contained the functions and sets (like ScalarAffineFunction{T}-GreaterThan).","category":"page"},{"location":"tutorials/bridging_constraint/","page":"Implementing a constraint bridge","title":"Implementing a constraint bridge","text":"For our example, the bridge does not create any constrained variables, and only ScalarAffineFunction{T}-in-GreaterThan{T} constraints:","category":"page"},{"location":"tutorials/bridging_constraint/","page":"Implementing a constraint bridge","title":"Implementing a constraint bridge","text":"function Bridges.added_constrained_variable_types(::Type{SignBridge{T}}) where {T}\n # The bridge does not create variables, return an empty list of tuples:\n return Tuple{Type}[]\nend\n\nfunction Bridges.added_constraint_types(::Type{SignBridge{T}}) where {T}\n return Tuple{Type,Type}[\n # One element per F-in-S the bridge creates.\n (ScalarAffineFunction{T}, GreaterThan{T}),\n ]\nend","category":"page"},{"location":"tutorials/bridging_constraint/","page":"Implementing a constraint bridge","title":"Implementing a constraint bridge","text":"A bridge that creates binary variables would rather have this definition of added_constrained_variable_types:","category":"page"},{"location":"tutorials/bridging_constraint/","page":"Implementing a constraint bridge","title":"Implementing a constraint bridge","text":"function Bridges.added_constrained_variable_types(::Type{SomeBridge{T}}) where {T}\n # The bridge only creates binary variables:\n return Tuple{Type}[(ZeroOne,)]\nend","category":"page"},{"location":"tutorials/bridging_constraint/","page":"Implementing a constraint bridge","title":"Implementing a constraint bridge","text":"warning: Warning\nIf you declare the creation of constrained variables in added_constrained_variable_types, the corresponding constraint type VariableIndex must not be indicated in added_constraint_types. This would restrict the use of the bridge to solvers that can add such a constraint after the variable is created.More concretely, if you declare in added_constrained_variable_types that your bridge creates binary variables (ZeroOne), and if you never add such a constraint afterward (you do not call add_constraint(model, var, ZeroOne())), then you must not list (VariableIndex, ZeroOne) in added_constraint_types.","category":"page"},{"location":"tutorials/bridging_constraint/","page":"Implementing a constraint bridge","title":"Implementing a constraint bridge","text":"Typically, the function Bridges.Constraint.concrete_bridge_type does not have to be defined for most bridges.","category":"page"},{"location":"tutorials/bridging_constraint/#Bridge-registration","page":"Implementing a constraint bridge","title":"Bridge registration","text":"","category":"section"},{"location":"tutorials/bridging_constraint/","page":"Implementing a constraint bridge","title":"Implementing a constraint bridge","text":"For a bridge to be used by MOI, it must be known by MOI.","category":"page"},{"location":"tutorials/bridging_constraint/#SingleBridgeOptimizer","page":"Implementing a constraint bridge","title":"SingleBridgeOptimizer","text":"","category":"section"},{"location":"tutorials/bridging_constraint/","page":"Implementing a constraint bridge","title":"Implementing a constraint bridge","text":"The first way to do so is to create a single-bridge optimizer. This type of optimizer wraps another optimizer and adds the possibility to use only one bridge. It is especially useful when unit testing bridges.","category":"page"},{"location":"tutorials/bridging_constraint/","page":"Implementing a constraint bridge","title":"Implementing a constraint bridge","text":"It is common practice to use the same name as the type defined for the bridge (SignBridge, in our example) without the suffix Bridge.","category":"page"},{"location":"tutorials/bridging_constraint/","page":"Implementing a constraint bridge","title":"Implementing a constraint bridge","text":"const Sign{T,OT<: ModelLike} =\n SingleBridgeOptimizer{SignBridge{T}, OT}","category":"page"},{"location":"tutorials/bridging_constraint/","page":"Implementing a constraint bridge","title":"Implementing a constraint bridge","text":"In the context of unit tests, this bridge is used in conjunction with a Utilities.MockOptimizer:","category":"page"},{"location":"tutorials/bridging_constraint/","page":"Implementing a constraint bridge","title":"Implementing a constraint bridge","text":"mock = Utilities.MockOptimizer(\n Utilities.UniversalFallback(Utilities.Model{Float64}()),\n)\nbridged_mock = Sign{Float64}(mock)","category":"page"},{"location":"tutorials/bridging_constraint/#New-bridge-for-a-LazyBridgeOptimizer","page":"Implementing a constraint bridge","title":"New bridge for a LazyBridgeOptimizer","text":"","category":"section"},{"location":"tutorials/bridging_constraint/","page":"Implementing a constraint bridge","title":"Implementing a constraint bridge","text":"Typical user-facing models for MOI are based on Bridges.LazyBridgeOptimizer. For instance, this type of model is returned by Bridges.full_bridge_optimizer. These models can be added more bridges by using Bridges.add_bridge:","category":"page"},{"location":"tutorials/bridging_constraint/","page":"Implementing a constraint bridge","title":"Implementing a constraint bridge","text":"inner_optimizer = Utilities.Model{Float64}()\noptimizer = Bridges.full_bridge_optimizer(inner_optimizer, Float64)\nBridges.add_bridge(optimizer, SignBridge{Float64})","category":"page"},{"location":"tutorials/bridging_constraint/#Bridge-improvements","page":"Implementing a constraint bridge","title":"Bridge improvements","text":"","category":"section"},{"location":"tutorials/bridging_constraint/#Attribute-retrieval","page":"Implementing a constraint bridge","title":"Attribute retrieval","text":"","category":"section"},{"location":"tutorials/bridging_constraint/","page":"Implementing a constraint bridge","title":"Implementing a constraint bridge","text":"Like models, bridges have attributes that can be retrieved using get and set. The most important ones are the number of variables and constraints, but also the lists of variables and constraints.","category":"page"},{"location":"tutorials/bridging_constraint/","page":"Implementing a constraint bridge","title":"Implementing a constraint bridge","text":"In our example, we only have one constraint and only have to implement the NumberOfConstraints and ListOfConstraintIndices attributes:","category":"page"},{"location":"tutorials/bridging_constraint/","page":"Implementing a constraint bridge","title":"Implementing a constraint bridge","text":"function get(\n ::SignBridge{T},\n ::NumberOfConstraints{\n ScalarAffineFunction{T},\n GreaterThan{T},\n },\n) where {T}\n return 1\nend\n\nfunction get(\n bridge::SignBridge{T},\n ::ListOfConstraintIndices{\n ScalarAffineFunction{T},\n GreaterThan{T},\n },\n) where {T}\n return [bridge.constraint]\nend","category":"page"},{"location":"tutorials/bridging_constraint/","page":"Implementing a constraint bridge","title":"Implementing a constraint bridge","text":"You must implement one such pair of functions for each type of constraint the bridge adds to the model.","category":"page"},{"location":"tutorials/bridging_constraint/","page":"Implementing a constraint bridge","title":"Implementing a constraint bridge","text":"warning: Warning\nAvoid returning a list from the bridge object without copying it. Users must be able to change the contents of the returned list without altering the bridge object.","category":"page"},{"location":"tutorials/bridging_constraint/","page":"Implementing a constraint bridge","title":"Implementing a constraint bridge","text":"For variables, the situation is simpler. If your bridge creates new variables, you must implement the NumberOfVariables and ListOfVariableIndices attributes. However, these attributes do not have parameters, unlike their constraint counterparts. Only two functions suffice:","category":"page"},{"location":"tutorials/bridging_constraint/","page":"Implementing a constraint bridge","title":"Implementing a constraint bridge","text":"function get(\n ::SignBridge{T},\n ::NumberOfVariables,\n) where {T}\n return 0\nend\n\nfunction get(\n ::SignBridge{T},\n ::ListOfVariableIndices,\n) where {T}\n return VariableIndex[]\nend","category":"page"},{"location":"tutorials/bridging_constraint/","page":"Implementing a constraint bridge","title":"Implementing a constraint bridge","text":"In order for the user to be able to access the function and set of the original constraint, the bridge needs to implement getters for the ConstraintFunction and ConstraintSet attributes:","category":"page"},{"location":"tutorials/bridging_constraint/","page":"Implementing a constraint bridge","title":"Implementing a constraint bridge","text":"function get(\n model::MOI.ModelLike,\n attr::MOI.ConstraintFunction,\n bridge::SignBridge,\n)\n return -MOI.get(model, attr, bridge.constraint)\nend\n\nfunction get(\n model::MOI.ModelLike,\n attr::MOI.ConstraintSet,\n bridge::SignBridge,\n)\n set = MOI.get(model, attr, bridge.constraint)\n return MOI.LessThan(-set.lower)\nend","category":"page"},{"location":"tutorials/bridging_constraint/","page":"Implementing a constraint bridge","title":"Implementing a constraint bridge","text":"warning: Warning\nAlternatively, one could store the original function and set in SignBridge during Bridges.Constraint.bridge_constraint to make these getters simpler and more efficient. On the other hand, this will increase the memory footprint of the bridges as the garbage collector won't be able to delete that object. The convention is to not store the function in the bridge and not care too much about the efficiency of these getters. If the user needs efficient getters for ConstraintFunction then they should use a Utilities.CachingOptimizer.","category":"page"},{"location":"tutorials/bridging_constraint/#Model-modifications","page":"Implementing a constraint bridge","title":"Model modifications","text":"","category":"section"},{"location":"tutorials/bridging_constraint/","page":"Implementing a constraint bridge","title":"Implementing a constraint bridge","text":"To avoid copying the model when the user request to change a constraint, MOI provides modify. Bridges can also implement this API to allow certain changes, such as coefficient changes.","category":"page"},{"location":"tutorials/bridging_constraint/","page":"Implementing a constraint bridge","title":"Implementing a constraint bridge","text":"In our case, a modification of a coefficient in the original constraint (for example, replacing the value of the coefficient of a variable in the affine function) must be transmitted to the constraint created by the bridge, but with a sign change.","category":"page"},{"location":"tutorials/bridging_constraint/","page":"Implementing a constraint bridge","title":"Implementing a constraint bridge","text":"function modify(\n model::ModelLike,\n bridge::SignBridge,\n change::ScalarCoefficientChange,\n)\n modify(\n model,\n bridge.constraint,\n ScalarCoefficientChange(change.variable, -change.new_coefficient),\n )\n return\nend","category":"page"},{"location":"tutorials/bridging_constraint/#Bridge-deletion","page":"Implementing a constraint bridge","title":"Bridge deletion","text":"","category":"section"},{"location":"tutorials/bridging_constraint/","page":"Implementing a constraint bridge","title":"Implementing a constraint bridge","text":"When a bridge is deleted, the constraints it added must be deleted too.","category":"page"},{"location":"tutorials/bridging_constraint/","page":"Implementing a constraint bridge","title":"Implementing a constraint bridge","text":"function delete(model::ModelLike, bridge::SignBridge)\n delete(model, bridge.constraint)\n return\nend","category":"page"},{"location":"release_notes/","page":"Release notes","title":"Release notes","text":"CurrentModule = MathOptInterface","category":"page"},{"location":"release_notes/#Release-notes","page":"Release notes","title":"Release notes","text":"","category":"section"},{"location":"release_notes/","page":"Release notes","title":"Release notes","text":"The format is based on Keep a Changelog, and this project adheres to Semantic Versioning.","category":"page"},{"location":"release_notes/#[v1.20.0](https://github.com/jump-dev/MathOptInterface.jl/releases/tag/v1.20.0)-(September-7,-2023)","page":"Release notes","title":"v1.20.0 (September 7, 2023)","text":"","category":"section"},{"location":"release_notes/#Added","page":"Release notes","title":"Added","text":"","category":"section"},{"location":"release_notes/","page":"Release notes","title":"Release notes","text":"Added Scaled set (#2237) (#2263) (#2264)\nAdded ObjectiveLimit attribute (#2257)","category":"page"},{"location":"release_notes/#Other","page":"Release notes","title":"Other","text":"","category":"section"},{"location":"release_notes/","page":"Release notes","title":"Release notes","text":"Updated dependencies (#2258)\nImproved performance of ScalarNonlinearFunction utilities (#2259)\nFixed docstrings (#2261)","category":"page"},{"location":"release_notes/#[v1.19.0](https://github.com/jump-dev/MathOptInterface.jl/releases/tag/v1.19.0)-(August-15,-2023)","page":"Release notes","title":"v1.19.0 (August 15, 2023)","text":"","category":"section"},{"location":"release_notes/#Added-2","page":"Release notes","title":"Added","text":"","category":"section"},{"location":"release_notes/","page":"Release notes","title":"Release notes","text":"Added VectorNonlinearFunction (#2201)\nAdded new bridges\nBridges.Constraint.IntegerToZeroOneBridge (#2205)\nBridges.Constraint.ToScalarQuadraticBridge (#2235)\nBridges.Constraint.ToVectorQuadraticBridge (#2235)\nBridges.Constraint.ToScalarNonlinearBridge (#2233) (#2235)\nBridges.Constraint.FunctionConversionBridge (#2235)\nAdded Bridges.bridging_cost for setting a bridge-specific cost in the bridging graph (#2235)\nAdded Utilities.eval_variables support for ScalarNonlinearFunction (#2218) (#2219)\nAdded support for ScalarNonlinearFunction in FileFormats.NL (#2228) (#2231)\nAdded support for writing non-Float64 functions in FileFormats.MOF\nAdded Utilities.lazy_map (#2254)","category":"page"},{"location":"release_notes/#Fixed","page":"Release notes","title":"Fixed","text":"","category":"section"},{"location":"release_notes/","page":"Release notes","title":"Release notes","text":"Fixed method ambiguities in operate (#2224)\nFixed reading LP file with a -infinity <= x <= +infinity variable (#2225)\nFixed missing require in Test.test_nonlinear_duals (#2230)\nFixed bug in ConstraintPrimal of Bridges.Constraint.QuadtoSOCBridge (#2240)","category":"page"},{"location":"release_notes/#Other-2","page":"Release notes","title":"Other","text":"","category":"section"},{"location":"release_notes/","page":"Release notes","title":"Release notes","text":"Added extensions to solver-tests.yml (#2229)\nRefactored test/Benchmarks (#2234)\nFixed warnings in tests (#2241) (#2243)\nSmall refactoring of bridges for upcoming VectorNonlinearFunction (#2244) (#2245)\nFixed various typos (#2251) (#2255)\nPartitioned how we run the tests on GitHub actions (#2252) (#2253)","category":"page"},{"location":"release_notes/#[v1.18.0](https://github.com/jump-dev/MathOptInterface.jl/releases/tag/v1.18.0)-(June-23,-2023)","page":"Release notes","title":"v1.18.0 (June 23, 2023)","text":"","category":"section"},{"location":"release_notes/#Added-3","page":"Release notes","title":"Added","text":"","category":"section"},{"location":"release_notes/","page":"Release notes","title":"Release notes","text":"Added Bridges.Objective.SlackBridgePrimalDualStart (#2194)\nAdded constraint_gradient_structure and eval_constraint_gradient (#2200)","category":"page"},{"location":"release_notes/#Fixed-2","page":"Release notes","title":"Fixed","text":"","category":"section"},{"location":"release_notes/","page":"Release notes","title":"Release notes","text":"Fixed a missing @require in MOI.Test (#2195) (#2196)\nFixed incorrect usage of Utilities.operate! in bridges (#2207) (#2216)\nFixed splatting nonlinear expression with univariate operator (#2221)","category":"page"},{"location":"release_notes/#Other-3","page":"Release notes","title":"Other","text":"","category":"section"},{"location":"release_notes/","page":"Release notes","title":"Release notes","text":"Removed unused argument names (#2199)\nReduced memory requirement for tests (#2204)\nRefactored Utilities.promote_operation (#2206)\nImproved code style in Utilities/mutable_arithmetics.jl (#2209)\nRefactored various methods in Utilities/functions.jl (#2208) (#2212) (#2213) (#2214) (#2215)","category":"page"},{"location":"release_notes/#[v1.17.1](https://github.com/jump-dev/MathOptInterface.jl/releases/tag/v1.17.1)-(June-6,-2023)","page":"Release notes","title":"v1.17.1 (June 6, 2023)","text":"","category":"section"},{"location":"release_notes/#Fixed-3","page":"Release notes","title":"Fixed","text":"","category":"section"},{"location":"release_notes/","page":"Release notes","title":"Release notes","text":"Fixed comparison of ScalarFunctionConstantNotZero (#2190)","category":"page"},{"location":"release_notes/#Other-4","page":"Release notes","title":"Other","text":"","category":"section"},{"location":"release_notes/","page":"Release notes","title":"Release notes","text":"Added documentation for enum instances (#2186)\nUpdated chatroom links in documentation (#2188)\nChanged the documentation to build on Julia v1.9 (#2191)","category":"page"},{"location":"release_notes/#[v1.17.0](https://github.com/jump-dev/MathOptInterface.jl/releases/tag/v1.17.0)-(June-1,-2023)","page":"Release notes","title":"v1.17.0 (June 1, 2023)","text":"","category":"section"},{"location":"release_notes/#Added-4","page":"Release notes","title":"Added","text":"","category":"section"},{"location":"release_notes/","page":"Release notes","title":"Release notes","text":"Added ScalarNonlinearFunction (#2059)\nAdded a variety of tests for NormSpectralCone, NormNuclearCone, and HermitianPositiveSemidefiniteConeTriangle (#2174)\nAdded Utilities.value_type for computing the value type of a function (#2176)","category":"page"},{"location":"release_notes/#Fixed-4","page":"Release notes","title":"Fixed","text":"","category":"section"},{"location":"release_notes/","page":"Release notes","title":"Release notes","text":"Fixed support for external sets in Utilities.loadfromstring! (#2177)\nFixed promote_operation for ScalarNonlinearFunction (#2179)\nFixed two issues in FileFormats.LP when reading files with quadratic functions (#2182) (#2184)","category":"page"},{"location":"release_notes/#[v1.16.0](https://github.com/jump-dev/MathOptInterface.jl/releases/tag/v1.16.0)-(May-16,-2023)","page":"Release notes","title":"v1.16.0 (May 16, 2023)","text":"","category":"section"},{"location":"release_notes/#Added-5","page":"Release notes","title":"Added","text":"","category":"section"},{"location":"release_notes/","page":"Release notes","title":"Release notes","text":"Added support for MathOptFormat v1.3 and v1.4 (#2158) (#2169)\nAdded new method to the nonlinear API (#2162) (#2164)\neval_hessian_constraint\neval_hessian_objective\nhessian_constraint_structure\nhessian_objective_structure\nAdded new sets\nNormCone (#2119)\nScaledPositiveSemidefiniteConeTriangle (#2154)","category":"page"},{"location":"release_notes/#Fixed-5","page":"Release notes","title":"Fixed","text":"","category":"section"},{"location":"release_notes/","page":"Release notes","title":"Release notes","text":"Fixed support for Julia v1.9 to work around a bug in the upstream Julia compiler (#2161) (#2163)\nFixed a correctness bug in Bridges.Constraint.HermitianToSymmetricPSDBridge (#2171)\nFixed convert(::VariableIndex, ::ScalarAffineFunction) when the function has terms with 0coefficients (#2173)","category":"page"},{"location":"release_notes/#Other-5","page":"Release notes","title":"Other","text":"","category":"section"},{"location":"release_notes/","page":"Release notes","title":"Release notes","text":"Fixed solver-tests.yml (#2157)\nUpdated documentation links to developer chatroom (#2160)\nAdded various tests for bridges (#2156)\nAdded checklists to the developer documentation (#2167) (#2168)","category":"page"},{"location":"release_notes/#[v1.15.1](https://github.com/jump-dev/MathOptInterface.jl/releases/tag/v1.15.1)-(April-25,-2023)","page":"Release notes","title":"v1.15.1 (April 25, 2023)","text":"","category":"section"},{"location":"release_notes/#Fixed-6","page":"Release notes","title":"Fixed","text":"","category":"section"},{"location":"release_notes/","page":"Release notes","title":"Release notes","text":"Fixed deleting a variable in a bridged objective (#2150)","category":"page"},{"location":"release_notes/#[v1.15.0](https://github.com/jump-dev/MathOptInterface.jl/releases/tag/v1.15.0)-(April-19,-2023)","page":"Release notes","title":"v1.15.0 (April 19, 2023)","text":"","category":"section"},{"location":"release_notes/#Added-6","page":"Release notes","title":"Added","text":"","category":"section"},{"location":"release_notes/","page":"Release notes","title":"Release notes","text":"Added Bridges.Objective.VectorFunctionizeBridge (#2139)","category":"page"},{"location":"release_notes/#Fixed-7","page":"Release notes","title":"Fixed","text":"","category":"section"},{"location":"release_notes/","page":"Release notes","title":"Release notes","text":"Fixed support for Rational in Bridges.Constraint.SplitIntervalBridge (#2137)\nFixed printing of LaTeX models (#2141)\nFixed modify in Bridges.Objective.VectorSlackBridge (#2144)\nFixed NAME record with spaces in FileFormats.MPS (#2146)\nFixed deleting a variable in a bridged objective (#2147)","category":"page"},{"location":"release_notes/#Other-6","page":"Release notes","title":"Other","text":"","category":"section"},{"location":"release_notes/","page":"Release notes","title":"Release notes","text":"Add a test for variables in one-sided open Interval sets (#2133)\nMinor style fixes in the source code (#2148)","category":"page"},{"location":"release_notes/#[v1.14.1](https://github.com/jump-dev/MathOptInterface.jl/releases/tag/v1.14.1)-(April-6,-2023)","page":"Release notes","title":"v1.14.1 (April 6, 2023)","text":"","category":"section"},{"location":"release_notes/#Fixed-8","page":"Release notes","title":"Fixed","text":"","category":"section"},{"location":"release_notes/","page":"Release notes","title":"Release notes","text":"Fixed a bug in Bridges.print_active_bridges (#2135)","category":"page"},{"location":"release_notes/#Other-7","page":"Release notes","title":"Other","text":"","category":"section"},{"location":"release_notes/","page":"Release notes","title":"Release notes","text":"Added a warning when an ambiguous string is passed to exclude in Test.runtests (#2136)","category":"page"},{"location":"release_notes/#[v1.14.0](https://github.com/jump-dev/MathOptInterface.jl/releases/tag/v1.14.0)-(April-4,-2023)","page":"Release notes","title":"v1.14.0 (April 4, 2023)","text":"","category":"section"},{"location":"release_notes/#Added-7","page":"Release notes","title":"Added","text":"","category":"section"},{"location":"release_notes/","page":"Release notes","title":"Release notes","text":"Added support for starting values in Bridges.Constraint.QuadtoSOCBridge (#2115)\nAdded support for Regex in the include and exclude arguments to Test.runtests (#2129)\nAdded Bridges.print_active_bridges methods for individual objectives and constraints (#2128)","category":"page"},{"location":"release_notes/#Fixed-9","page":"Release notes","title":"Fixed","text":"","category":"section"},{"location":"release_notes/","page":"Release notes","title":"Release notes","text":"Fixed ResultCount when parsing .sol files in FileFormats.NL (#2130)","category":"page"},{"location":"release_notes/#[v1.13.2](https://github.com/jump-dev/MathOptInterface.jl/releases/tag/v1.13.2)-(March-21,-2023)","page":"Release notes","title":"v1.13.2 (March 21, 2023)","text":"","category":"section"},{"location":"release_notes/#Fixed-10","page":"Release notes","title":"Fixed","text":"","category":"section"},{"location":"release_notes/","page":"Release notes","title":"Release notes","text":"Fixed splatting of containers in MOI.Nonlinear (#2120)\nFixed a bug reading LP files with default bounds (#2121)\nFixed a bug in which Bridges.Constraint.HermitianToSymmetricPSDBridge was not enabled by default (#2123)","category":"page"},{"location":"release_notes/#Other-8","page":"Release notes","title":"Other","text":"","category":"section"},{"location":"release_notes/","page":"Release notes","title":"Release notes","text":"Fixed typos in the documentation (#2114)\nFunctions now print to the REPL in algebraic form. This is potentially breaking if you have tests which rely on a specific String form of MOI functions. (#2112) (#2126)","category":"page"},{"location":"release_notes/#[v1.13.1](https://github.com/jump-dev/MathOptInterface.jl/releases/tag/v1.13.1)-(March-3,-2023)","page":"Release notes","title":"v1.13.1 (March 3, 2023)","text":"","category":"section"},{"location":"release_notes/#Other-9","page":"Release notes","title":"Other","text":"","category":"section"},{"location":"release_notes/","page":"Release notes","title":"Release notes","text":"Added the Google style guide to the documentation linter Vale, and fixed the resulting warnings (#2110)\nImproved the docstrings in src/functions.jl (#2108)","category":"page"},{"location":"release_notes/#[v1.13.0](https://github.com/jump-dev/MathOptInterface.jl/releases/tag/v1.13.0)-(February-28,-2023)","page":"Release notes","title":"v1.13.0 (February 28, 2023)","text":"","category":"section"},{"location":"release_notes/#Added-8","page":"Release notes","title":"Added","text":"","category":"section"},{"location":"release_notes/","page":"Release notes","title":"Release notes","text":"Added Bridges.Constraint.NumberConversionBridge (#2091)\nAdded Parameter set (#2095) (#2105) (#2106) (#2109)\nAdded with_cache_type argument to instantiate (#2097)\nAdded support for HermitianPositiveSemidefiniteConeTriangle in Utilities.Model (#2100)","category":"page"},{"location":"release_notes/#Fixed-11","page":"Release notes","title":"Fixed","text":"","category":"section"},{"location":"release_notes/","page":"Release notes","title":"Release notes","text":"Fixed bug when Utilities.@product_of_sets is empty (#2101)\nFixed Bridges.print_active_bridges when variable bridge is an AbstractScalarSet (#2107)","category":"page"},{"location":"release_notes/#Other-10","page":"Release notes","title":"Other","text":"","category":"section"},{"location":"release_notes/","page":"Release notes","title":"Release notes","text":"Added tests for vector-valued objective functions in FileFormats.MOF (#2093)\nUsed and documented preference for import MathOptInterface as MOI (#2096)\nFix and test links in the documentation with linkcheck = true (#2098)\nImproved docstrings of sets in src/sets.jl (#2099)\nSkip checking flakey links in documentation with linkcheck_ignore (#2103)","category":"page"},{"location":"release_notes/#[v1.12.0](https://github.com/jump-dev/MathOptInterface.jl/releases/tag/v1.12.0)-(February-10,-2023)","page":"Release notes","title":"v1.12.0 (February 10, 2023)","text":"","category":"section"},{"location":"release_notes/#Added-9","page":"Release notes","title":"Added","text":"","category":"section"},{"location":"release_notes/","page":"Release notes","title":"Release notes","text":"Added support for vector-valued objective functions (#2070)\nAdded a Utilities.distance_to_set method for SecondOrderCone (#2060)","category":"page"},{"location":"release_notes/#Fixed-12","page":"Release notes","title":"Fixed","text":"","category":"section"},{"location":"release_notes/","page":"Release notes","title":"Release notes","text":"Fixed a number of constraint bridges so that Bridges.final_touch can be called multiple times without forcing a rebuild of the reformulation (#2089)","category":"page"},{"location":"release_notes/#Other-11","page":"Release notes","title":"Other","text":"","category":"section"},{"location":"release_notes/","page":"Release notes","title":"Release notes","text":"Added new tests that a set ObjectiveFunction appears in ListOfModelAttributesSet (#2085)\nImproved the docstrings of a number of constraint-programming related sets (#2087)","category":"page"},{"location":"release_notes/#[v1.11.5](https://github.com/jump-dev/MathOptInterface.jl/releases/tag/v1.11.5)-(January-24,-2023)","page":"Release notes","title":"v1.11.5 (January 24, 2023)","text":"","category":"section"},{"location":"release_notes/#Fixed-13","page":"Release notes","title":"Fixed","text":"","category":"section"},{"location":"release_notes/","page":"Release notes","title":"Release notes","text":"Fixed a bug writing .lp files with an off-diagonal quadratic objective (#2082)","category":"page"},{"location":"release_notes/#Other-12","page":"Release notes","title":"Other","text":"","category":"section"},{"location":"release_notes/","page":"Release notes","title":"Release notes","text":"Added SnoopPrecompile directives for reduced time-to-first-X in Julia v1.9 (#2080)","category":"page"},{"location":"release_notes/#[v1.11.4](https://github.com/jump-dev/MathOptInterface.jl/releases/tag/v1.11.4)-(January-12,-2023)","page":"Release notes","title":"v1.11.4 (January 12, 2023)","text":"","category":"section"},{"location":"release_notes/#Fixed-14","page":"Release notes","title":"Fixed","text":"","category":"section"},{"location":"release_notes/","page":"Release notes","title":"Release notes","text":"Fixed a bug reading .lp files with an Integer section (#2078)","category":"page"},{"location":"release_notes/#[v1.11.3](https://github.com/jump-dev/MathOptInterface.jl/releases/tag/v1.11.3)-(January-12,-2023)","page":"Release notes","title":"v1.11.3 (January 12, 2023)","text":"","category":"section"},{"location":"release_notes/#Fixed-15","page":"Release notes","title":"Fixed","text":"","category":"section"},{"location":"release_notes/","page":"Release notes","title":"Release notes","text":"Fixed a performance bug when deleting a vector of constraints (#2072)\nFixed a bug reading .lp files with terms like x -1 y (#2076)","category":"page"},{"location":"release_notes/#Other-13","page":"Release notes","title":"Other","text":"","category":"section"},{"location":"release_notes/","page":"Release notes","title":"Release notes","text":"Documented the two-argument method of optimize! (#2074)","category":"page"},{"location":"release_notes/#[v1.11.2](https://github.com/jump-dev/MathOptInterface.jl/releases/tag/v1.11.2)-(January-2,-2023)","page":"Release notes","title":"v1.11.2 (January 2, 2023)","text":"","category":"section"},{"location":"release_notes/#Fixed-16","page":"Release notes","title":"Fixed","text":"","category":"section"},{"location":"release_notes/","page":"Release notes","title":"Release notes","text":"Fixed a bug reading .mof.json files with ConstraintName set for VariableIndex constraints (#2066)\nFixed a bug reading .mof.json files with nonlinear objectives and no constraints (#2068)","category":"page"},{"location":"release_notes/#[v1.11.1](https://github.com/jump-dev/MathOptInterface.jl/releases/tag/v1.11.1)-(December-22,-2022)","page":"Release notes","title":"v1.11.1 (December 22, 2022)","text":"","category":"section"},{"location":"release_notes/#Fixed-17","page":"Release notes","title":"Fixed","text":"","category":"section"},{"location":"release_notes/","page":"Release notes","title":"Release notes","text":"Fixed a bug reading .mof.json files with integer coefficients for affine and quadratic functions (#2063)","category":"page"},{"location":"release_notes/#[v1.11.0](https://github.com/jump-dev/MathOptInterface.jl/releases/tag/v1.11.0)-(December-2,-2022)","page":"Release notes","title":"v1.11.0 (December 2, 2022)","text":"","category":"section"},{"location":"release_notes/#Added-10","page":"Release notes","title":"Added","text":"","category":"section"},{"location":"release_notes/","page":"Release notes","title":"Release notes","text":"Added Utilities.PenaltyRelaxation and Utilities.ScalarPenaltyRelaxation (#1995)\nAdded Utilities.distance_to_set (#2048)\nAdded support for ConstraintPrimalStart and ConstraintDualStart in FileFormats.MOF (#2056)","category":"page"},{"location":"release_notes/#Other-14","page":"Release notes","title":"Other","text":"","category":"section"},{"location":"release_notes/","page":"Release notes","title":"Release notes","text":"Tidied these release notes (#2055)","category":"page"},{"location":"release_notes/#[v1.10.0](https://github.com/jump-dev/MathOptInterface.jl/releases/tag/v1.10.0)-(November-22,-2022)","page":"Release notes","title":"v1.10.0 (November 22, 2022)","text":"","category":"section"},{"location":"release_notes/#Added-11","page":"Release notes","title":"Added","text":"","category":"section"},{"location":"release_notes/","page":"Release notes","title":"Release notes","text":"Added new methods set(::OptimizerWithAttributes, ::RawOptimizerAttribute, value) and get(::OptimizerWithAttributes, ::RawOptimizerAttribute) (#2049)\nAdded new methods Utilities.DoubleDicts.outer_keys and Utilities.DoubleDicts.nonempty_outer_keys (#2052)","category":"page"},{"location":"release_notes/#Fixed-18","page":"Release notes","title":"Fixed","text":"","category":"section"},{"location":"release_notes/","page":"Release notes","title":"Release notes","text":"Fixed Bridges.Objective.SlackBridge when the objective function is complex-valued (#2036) (#2038)\nFixed docstring of Test.runtests to clarify the warn_unsupported argument (#2037)\nFixed reading of free variables in FileFormats.LP (#2044)\nFixed numerous edge cases reading files from QPLIB using FileFormats.LP (#2042) (#2044)\nFixed situations in which x^y returns a complex value in Nonlinear (#2050)","category":"page"},{"location":"release_notes/#Other-15","page":"Release notes","title":"Other","text":"","category":"section"},{"location":"release_notes/","page":"Release notes","title":"Release notes","text":"Improved the error message thrown when a user-defined nonlinear function does not accept splatted input (#2032)\nRemoved specialized iterators for keys and values in Utilities.CleverDicts (#2051)","category":"page"},{"location":"release_notes/#[v1.9.0](https://github.com/jump-dev/MathOptInterface.jl/releases/tag/v1.9.0)-(October-29,-2022)","page":"Release notes","title":"v1.9.0 (October 29, 2022)","text":"","category":"section"},{"location":"release_notes/#Added-12","page":"Release notes","title":"Added","text":"","category":"section"},{"location":"release_notes/","page":"Release notes","title":"Release notes","text":"Added default fallback for getting ListOfConstraintIndices and NumberOfConstraints when the constraint type is unsupported by the model (#2021)\nAdded support for min and max in nonlinear expressions (#2023)\nAdded support for Indicator{EqualTo{T}} constraints in FileFormats.MPS (#2022)\nAdded default fallback for write_to_file and read_from_file (#2029)","category":"page"},{"location":"release_notes/#Fixed-19","page":"Release notes","title":"Fixed","text":"","category":"section"},{"location":"release_notes/","page":"Release notes","title":"Release notes","text":"Fixed Constraint.ZeroOneBridge by adding new bounds as affine constraints instead of variable bounds (#1879)\nFixed reading free rows in FileFormats.MPS files (#2009)\nFixed parsing of OBJSENSE blocks in FileFormats.MPS files (#2016) (#2019)\nFixed the parsing of deeply nested nonlinear expressions by removing the use of recursion (#2020)\nFixed the requirements check in Test.test_constrainnt_get_ConstraintIndex (#2024)","category":"page"},{"location":"release_notes/#[v1.8.2](https://github.com/jump-dev/MathOptInterface.jl/releases/tag/v1.8.2)-(September-20,-2022)","page":"Release notes","title":"v1.8.2 (September 20, 2022)","text":"","category":"section"},{"location":"release_notes/#Documentation","page":"Release notes","title":"Documentation","text":"","category":"section"},{"location":"release_notes/","page":"Release notes","title":"Release notes","text":"Added vale as a documentation linter (#2002)\nImproved styling of code blocks in the PDF (#1999) (#2000)\nFixed a number of typos in the documentation (#2001) (#2003)","category":"page"},{"location":"release_notes/#[v1.8.1](https://github.com/jump-dev/MathOptInterface.jl/releases/tag/v1.8.1)-(September-12,-2022)","page":"Release notes","title":"v1.8.1 (September 12, 2022)","text":"","category":"section"},{"location":"release_notes/#Fixed-20","page":"Release notes","title":"Fixed","text":"","category":"section"},{"location":"release_notes/","page":"Release notes","title":"Release notes","text":"Fixed a bug in supports(::AbstractBridgeOptimizer for constraint attributes (#1991) (#1992)","category":"page"},{"location":"release_notes/#[v1.8.0](https://github.com/jump-dev/MathOptInterface.jl/releases/tag/v1.8.0)-(September-1,-2022)","page":"Release notes","title":"v1.8.0 (September 1, 2022)","text":"","category":"section"},{"location":"release_notes/#Added-13","page":"Release notes","title":"Added","text":"","category":"section"},{"location":"release_notes/","page":"Release notes","title":"Release notes","text":"Added new sets\nHyperRectangle (#1961)\nReified (#1955)\nAdded new bridges (#1955)\nBridges.Constraint.ReifiedAllDifferentToCountDistinctBridge\nBridges.Constraint.ReifiedCountDistinctToMILPBridge\nBridges.Constraint.SplitHyperRectangleBridge\nAdded support for atan(y, x) in Nonlinear (#1987)","category":"page"},{"location":"release_notes/#Fixed-21","page":"Release notes","title":"Fixed","text":"","category":"section"},{"location":"release_notes/","page":"Release notes","title":"Release notes","text":"Lazily construct expressions in Nonlinear so that expressions are updated when Nonlinear.Parameter values are updated (#1984)\nAllow NORM_LIMIT as a TerminationStatus for unbounded problems in Test (#1990)","category":"page"},{"location":"release_notes/#[v1.7.0](https://github.com/jump-dev/MathOptInterface.jl/releases/tag/v1.7.0)-(August-16,-2022)","page":"Release notes","title":"v1.7.0 (August 16, 2022)","text":"","category":"section"},{"location":"release_notes/#Added-14","page":"Release notes","title":"Added","text":"","category":"section"},{"location":"release_notes/","page":"Release notes","title":"Release notes","text":"Added new sets\nHermitianPositiveSemidefiniteConeTriangle\nAdded new optimizer-independent options\nRelativeGapTolerance\nAbsoluteGapTolerance\nAdded new bridges\nBridges.Constraint.GeoMeanToPowerBridge\nBridges.Constraint.HermitianToSymmetricPSDBridge\nBridges.Constraint.IndicatorGreaterToLessThanBridge\nBridges.Constraint.IndicatorLessToGreaterThanBridge\nBridges.Constraint.SplitComplexZerosBridge\nBridges.Constraint.SplitComplexEqualToBridge\nBridges.Objective.QuadratizeBridge\nAdded support for generic number types in Utilities.loadfromstring!\nUpdated FileFormats.MOF to MathOptFormat v1.1, enabling support for constraint programming sets in the MOF file format\nAdded support in various FileFormats for\nindicator constraints in FileFormats.MPS\nquadratic constraints and an objective in FileFormats.LP\nquadratic constraints and an objective in FileFormats.MPS","category":"page"},{"location":"release_notes/#Fixed-22","page":"Release notes","title":"Fixed","text":"","category":"section"},{"location":"release_notes/","page":"Release notes","title":"Release notes","text":"Fixed some missing promotion rules","category":"page"},{"location":"release_notes/#Other-16","page":"Release notes","title":"Other","text":"","category":"section"},{"location":"release_notes/","page":"Release notes","title":"Release notes","text":"Improved the performance of Jacobian products in Nonlinear\nRemoved an un-needed copy in Utilities.modify_function\nVarious clean-ups in Bridges/bridge_optimizer.jl","category":"page"},{"location":"release_notes/#[v1.6.1](https://github.com/jump-dev/MathOptInterface.jl/releases/tag/v1.6.1)-(July-23,-2022)","page":"Release notes","title":"v1.6.1 (July 23, 2022)","text":"","category":"section"},{"location":"release_notes/#Fixed-23","page":"Release notes","title":"Fixed","text":"","category":"section"},{"location":"release_notes/","page":"Release notes","title":"Release notes","text":"Added support for ExponentialCone in MatrixOfConstraints\nFix PSDSquare_3 test to reflect a previously fixed bug getting the ConstraintDual of a PositiveSemidefiniteConeSquare constraint","category":"page"},{"location":"release_notes/#[v1.6.0](https://github.com/jump-dev/MathOptInterface.jl/releases/tag/v1.6.0)-(July-2,-2022)","page":"Release notes","title":"v1.6.0 (July 2, 2022)","text":"","category":"section"},{"location":"release_notes/#Added-15","page":"Release notes","title":"Added","text":"","category":"section"},{"location":"release_notes/","page":"Release notes","title":"Release notes","text":"Added Bridges.needs_final_touch and Bridges.final_touch\nAdded new bridges from constraint programming sets to mixed-integer linear programs:\nAllDifferentToCountDistinctBridge\nCountAtLeastToCountBelongsBridge\nCountBelongsToMILPBridge\nCountDistinctToMILPBridge\nCountGreaterThanToMILPBridge\nCircuitToMILPBridge","category":"page"},{"location":"release_notes/#Fixed-24","page":"Release notes","title":"Fixed","text":"","category":"section"},{"location":"release_notes/","page":"Release notes","title":"Release notes","text":"Relax an instance of ::Vector to ::AbstractVector in MOI.Nonlinear\nFix BinPackingToMILPBridge to respect variable bounds\nFix SemiToBinaryBridge to throw error if other bounds are set","category":"page"},{"location":"release_notes/#[v1.5.0](https://github.com/jump-dev/MathOptInterface.jl/releases/tag/v1.5.0)-(June-27,-2022)","page":"Release notes","title":"v1.5.0 (June 27, 2022)","text":"","category":"section"},{"location":"release_notes/#Added-16","page":"Release notes","title":"Added","text":"","category":"section"},{"location":"release_notes/","page":"Release notes","title":"Release notes","text":"Added GetAttributeNotAllowed for solvers to indicate when getting an attribute encounters an error\nAdded Utilities.get_fallback support for ObjectiveValue and DualObjectiveValue\nAdded new bridges:\nRootDetConeSquare to RootDetConeTriangle\nLogDetConeSquare to LogDetConeTriangle\nBinPacking to a mixed-integer linear program\nTable to a mixed-integer linear program\nAdded Bridges.print_active_bridges to display the current optimal hyper-path in a Bridges.LazyBridgeOptimizer","category":"page"},{"location":"release_notes/#Fixed-25","page":"Release notes","title":"Fixed","text":"","category":"section"},{"location":"release_notes/","page":"Release notes","title":"Release notes","text":"Fixed ZeroOne tests with lower and upper bounds\nFixed error in FileFormats.LP when reading a malformed file\nFixed reading of nonlinear programs in FileFormats.MOF\nFixed bug in ConstraintDual when using SquareBridge","category":"page"},{"location":"release_notes/#Other-17","page":"Release notes","title":"Other","text":"","category":"section"},{"location":"release_notes/","page":"Release notes","title":"Release notes","text":"Improved documentation of nonlinear API\nDocumented duality convention for PositiveSemidefiniteConeSquare sets\nFixed typo in Bridges.Constraint.QuadToSOCBridge docstring","category":"page"},{"location":"release_notes/#[v1.4.0](https://github.com/jump-dev/MathOptInterface.jl/releases/tag/v1.4.0)-(June-9,-2022)","page":"Release notes","title":"v1.4.0 (June 9, 2022)","text":"","category":"section"},{"location":"release_notes/#Added-17","page":"Release notes","title":"Added","text":"","category":"section"},{"location":"release_notes/","page":"Release notes","title":"Release notes","text":"Added a number of sets for constraint programming:\nAllDifferent\nBinPacking\nCircuit\nCountAtLeast\nCountBelongs\nCountDistinct\nCountGreaterThan\nCumulative\nPath\nTable\nAdded support for user-defined hessians in Nonlinear\nAdded Bridges.runtests to simplify the testing of bridge implementations","category":"page"},{"location":"release_notes/#Fixed-26","page":"Release notes","title":"Fixed","text":"","category":"section"},{"location":"release_notes/","page":"Release notes","title":"Release notes","text":"Fixed a bug in FileFormats.NL when writing univariate *","category":"page"},{"location":"release_notes/#Other-18","page":"Release notes","title":"Other","text":"","category":"section"},{"location":"release_notes/","page":"Release notes","title":"Release notes","text":"Began a large refactoring of the Bridges submodule, with greatly improved documentation.","category":"page"},{"location":"release_notes/#[v1.3.0](https://github.com/jump-dev/MathOptInterface.jl/releases/tag/v1.3.0)-(May-27,-2022)","page":"Release notes","title":"v1.3.0 (May 27, 2022)","text":"","category":"section"},{"location":"release_notes/#Added-18","page":"Release notes","title":"Added","text":"","category":"section"},{"location":"release_notes/","page":"Release notes","title":"Release notes","text":"Add MOI.Nonlinear submodule. This is a large new submodule that has been refactored from code that was in JuMP. For now, it should be considered experimental.\nAdd FileFormats.NL.SolFileResults(::IO, ::Model)\nAdd FileFormats.NL.read!(::IO, ::Model)\nAdd MOI.modify that accepts a vector of modifications","category":"page"},{"location":"release_notes/#Fixed-27","page":"Release notes","title":"Fixed","text":"","category":"section"},{"location":"release_notes/","page":"Release notes","title":"Release notes","text":"Fixed a bug in Test which attempted to include non-.jl files\nFixed a bug in FileFormats for models with open interval constraints","category":"page"},{"location":"release_notes/#Other-19","page":"Release notes","title":"Other","text":"","category":"section"},{"location":"release_notes/","page":"Release notes","title":"Release notes","text":"Fixed a performance issue in Utilities.DoubleDict\nVarious minor improvements to the documentation","category":"page"},{"location":"release_notes/#[v1.2.0](https://github.com/jump-dev/MathOptInterface.jl/releases/tag/v1.2.0)-(April-25,-2022)","page":"Release notes","title":"v1.2.0 (April 25, 2022)","text":"","category":"section"},{"location":"release_notes/#Added-19","page":"Release notes","title":"Added","text":"","category":"section"},{"location":"release_notes/","page":"Release notes","title":"Release notes","text":"Add support for the FORMAT_REW/.rew file format in FileFormats.","category":"page"},{"location":"release_notes/#Fixed-28","page":"Release notes","title":"Fixed","text":"","category":"section"},{"location":"release_notes/","page":"Release notes","title":"Release notes","text":"Fix bug handling of default variable bounds in FileFormats.LP\nFix FileFormats.MPS to not write OBJSENSE by default since this is only supported by some readers.","category":"page"},{"location":"release_notes/#[v1.1.2](https://github.com/jump-dev/MathOptInterface.jl/releases/tag/v1.1.2)-(March-31,-2022)","page":"Release notes","title":"v1.1.2 (March 31, 2022)","text":"","category":"section"},{"location":"release_notes/#Fixed-29","page":"Release notes","title":"Fixed","text":"","category":"section"},{"location":"release_notes/","page":"Release notes","title":"Release notes","text":"Fix a range of bugs in FileFormats.LP\nFix reading of problem dimensions in FileFormats.SDPA","category":"page"},{"location":"release_notes/#[v1.1.1](https://github.com/jump-dev/MathOptInterface.jl/releases/tag/v1.1.1)-(March-23,-2022)","page":"Release notes","title":"v1.1.1 (March 23, 2022)","text":"","category":"section"},{"location":"release_notes/#Fixed-30","page":"Release notes","title":"Fixed","text":"","category":"section"},{"location":"release_notes/","page":"Release notes","title":"Release notes","text":"Fix bug in test_model_UpperBoundAlreadySet\nFix bug in test_infeasible_ tests\nFix bug in test_objective_ObjectiveFunction_blank\nRelax restriction of MOI.AbstractOptimizer to MOI.ModelLike in Utilities.CachingOptimizer and instantiate.","category":"page"},{"location":"release_notes/#New-tests","page":"Release notes","title":"New tests","text":"","category":"section"},{"location":"release_notes/","page":"Release notes","title":"Release notes","text":"Add test_conic_empty_matrix that checks conic solvers support problems with no variables.","category":"page"},{"location":"release_notes/#[v1.1.0](https://github.com/jump-dev/MathOptInterface.jl/releases/tag/v1.1.0)-(March-2,-2022)","page":"Release notes","title":"v1.1.0 (March 2, 2022)","text":"","category":"section"},{"location":"release_notes/#Added-20","page":"Release notes","title":"Added","text":"","category":"section"},{"location":"release_notes/","page":"Release notes","title":"Release notes","text":"Added MOI.Utilities.throw_unsupported(::UniversalFallback) for simplifying solver wrappers which copy from a UniversalFallback.","category":"page"},{"location":"release_notes/#[v1.0.2](https://github.com/jump-dev/MathOptInterface.jl/releases/tag/v1.0.2)-(March-1,-2022)","page":"Release notes","title":"v1.0.2 (March 1, 2022)","text":"","category":"section"},{"location":"release_notes/#Fixed-31","page":"Release notes","title":"Fixed","text":"","category":"section"},{"location":"release_notes/","page":"Release notes","title":"Release notes","text":"Fixed a bug in the test_model_ScalarFunctionConstantNotZero test\nFixed the error type when an AbstractFunctionConversionBridge cannot get or set an attribute\nIdentified a correctness bug in RSOCtoPSDBridge. We now thrown an error instead of returning an incorrect result.","category":"page"},{"location":"release_notes/#[v1.0.1](https://github.com/jump-dev/MathOptInterface.jl/releases/tag/v1.0.1)-(February-25,-2022)","page":"Release notes","title":"v1.0.1 (February 25, 2022)","text":"","category":"section"},{"location":"release_notes/#Fixed-32","page":"Release notes","title":"Fixed","text":"","category":"section"},{"location":"release_notes/","page":"Release notes","title":"Release notes","text":"Fixed a bug in which OptimizerAttributes were not copied in CachingOptimizer\nFixed a bug in which shift_constant did not promote mixed types of coefficients\nFixed a bug in which deleting a constraint of a bridged variable threw ErrorException instead of MOI.DeleteNotAllowed\nFixed a bug in which add_constraint in MatrixOfConstraints did not canonicalize the function\nFixed a bug when modifying scalar constants of a function containing a bridged variable\nFixed a bug in which final_touch was not always called with a CachingOptimizer","category":"page"},{"location":"release_notes/#[v1.0.0](https://github.com/jump-dev/MathOptInterface.jl/releases/tag/v1.0.0)-(February-17,-2022)","page":"Release notes","title":"v1.0.0 (February 17, 2022)","text":"","category":"section"},{"location":"release_notes/","page":"Release notes","title":"Release notes","text":"Although tagged as a breaking release, v1.0.0 is v0.10.9 with deprecations removed, similar to how Julia 1.0 was Julia 0.7 with deprecations removed.","category":"page"},{"location":"release_notes/#Breaking","page":"Release notes","title":"Breaking","text":"","category":"section"},{"location":"release_notes/","page":"Release notes","title":"Release notes","text":"Julia 1.6 is now the minimum supported version\nAll deprecations have been removed","category":"page"},{"location":"release_notes/#Troubleshooting-problems-when-updating","page":"Release notes","title":"Troubleshooting problems when updating","text":"","category":"section"},{"location":"release_notes/","page":"Release notes","title":"Release notes","text":"If you experience problems when updating, you are likely using previously deprecated features. (By default, Julia does not warn when you use deprecated features.)","category":"page"},{"location":"release_notes/","page":"Release notes","title":"Release notes","text":"To find the deprecated features you are using, start Julia with --depwarn=yes:","category":"page"},{"location":"release_notes/","page":"Release notes","title":"Release notes","text":"$ julia --depwarn=yes","category":"page"},{"location":"release_notes/","page":"Release notes","title":"Release notes","text":"Then install MathOptInterface v0.10.9:","category":"page"},{"location":"release_notes/","page":"Release notes","title":"Release notes","text":"julia> using Pkg\njulia> pkg\"add MathOptInterface@0.10\"","category":"page"},{"location":"release_notes/","page":"Release notes","title":"Release notes","text":"And then run your code. Apply any suggestions, or search the release notes below for advice on updating a specific deprecated feature.","category":"page"},{"location":"release_notes/#[v0.10.9](https://github.com/jump-dev/MathOptInterface.jl/releases/tag/v0.10.9)-(February-16,-2022)","page":"Release notes","title":"v0.10.9 (February 16, 2022)","text":"","category":"section"},{"location":"release_notes/#Added-21","page":"Release notes","title":"Added","text":"","category":"section"},{"location":"release_notes/","page":"Release notes","title":"Release notes","text":"Added MOI.Utilities.FreeVariables as a new VariablesConstrainer for conic solvers\nAdded MOI.default_cache for specifying the model used in CachingOptimizer","category":"page"},{"location":"release_notes/#Fixed-33","page":"Release notes","title":"Fixed","text":"","category":"section"},{"location":"release_notes/","page":"Release notes","title":"Release notes","text":"Fixed LaTeX printing of MOI.Interval sets","category":"page"},{"location":"release_notes/#Other-20","page":"Release notes","title":"Other","text":"","category":"section"},{"location":"release_notes/","page":"Release notes","title":"Release notes","text":"Added Aqua.jl as a CI check, and fixed suggested issues\nThe constructors of GeoMeanBridge, StructOfConstraints, and CachingOptimizer were changed from outer to inner constructors. This change is technically breaking, but does not impact users who followed the documented API.","category":"page"},{"location":"release_notes/#[v0.10.8](https://github.com/jump-dev/MathOptInterface.jl/releases/tag/v0.10.8)-(February-3,-2022)","page":"Release notes","title":"v0.10.8 (February 3, 2022)","text":"","category":"section"},{"location":"release_notes/#Added-22","page":"Release notes","title":"Added","text":"","category":"section"},{"location":"release_notes/","page":"Release notes","title":"Release notes","text":"Added a Base.read! for FileFormats.LP.","category":"page"},{"location":"release_notes/#Fixed-34","page":"Release notes","title":"Fixed","text":"","category":"section"},{"location":"release_notes/","page":"Release notes","title":"Release notes","text":"Fixed a bug in MutableSparseMatrix\nFixed a bug when calling operate!(vcat, ...) with Number arguments\nRemoved unintended export of deprecated symbols\nFixed a bug with PowerCone and DualPowerCone in MatrixOfConstraints.","category":"page"},{"location":"release_notes/#[v0.10.7](https://github.com/jump-dev/MathOptInterface.jl/releases/tag/v0.10.7)-(January-5,-2022)","page":"Release notes","title":"v0.10.7 (January 5, 2022)","text":"","category":"section"},{"location":"release_notes/#Added-23","page":"Release notes","title":"Added","text":"","category":"section"},{"location":"release_notes/","page":"Release notes","title":"Release notes","text":"Added test for modifying the constant vector in a VectorAffineFunction-in-Zeros constraint.","category":"page"},{"location":"release_notes/#Fixed-35","page":"Release notes","title":"Fixed","text":"","category":"section"},{"location":"release_notes/","page":"Release notes","title":"Release notes","text":"Fixed the order in which sets are added to a LazyBridgeOptimizer. Compared to v0.10.6, this may result in bridged models being created with a different number (and order) of variables and constraints. However, it was necessary to fix cases which were previously rejected as unsupported, even though there was a valid bridge transformation.\nFixed an error message in FileFormats.CBF\nFixed comparison in test_linear_integration_Interval\nFixed errors for ConstraintPrimal in a CachingOptimizer\nFixed printing of models with non-Float64 coefficients.","category":"page"},{"location":"release_notes/#Other-21","page":"Release notes","title":"Other","text":"","category":"section"},{"location":"release_notes/","page":"Release notes","title":"Release notes","text":"Various improvements to reduce time-to-first-solve latency\nImproved error message when an optimizer does not support compute_conflict!","category":"page"},{"location":"release_notes/#[v0.10.6](https://github.com/jump-dev/MathOptInterface.jl/releases/tag/v0.10.6)-(November-30,-2021)","page":"Release notes","title":"v0.10.6 (November 30, 2021)","text":"","category":"section"},{"location":"release_notes/#Added-24","page":"Release notes","title":"Added","text":"","category":"section"},{"location":"release_notes/","page":"Release notes","title":"Release notes","text":"Added new documentation and tests for infeasibility certificates\nAdded a version control system for the tests in MOI.Test.runtests. Pass exclude_tests_after = v\"0.10.5\" to run tests added in v0.10.5 and earlier.\nMOI.Test.runtests now supports generic number types. To specify the number type T, pass MOI.Test.Config(T).\nAdded infeasible_status to MOI.Test.Config for solvers which return LOCALLY_INFEASIBLE\nCachingOptimizers now use a fallback for ConstraintPrimal. This should enable solvers using a CachingOptimizer to pass tests requiring ConstraintPrimal.","category":"page"},{"location":"release_notes/#Fixed-36","page":"Release notes","title":"Fixed","text":"","category":"section"},{"location":"release_notes/","page":"Release notes","title":"Release notes","text":"Fixed a StackOverflow bug in copy_to\nFixed error thrown when nonconvex quadratic constraints cannot be bridged\nFixed a bug in copy_to for FileFormats.NL.Model\nFixed a bug in FileFormats.NL when printing large integers\nRemove a common test failure for LowerBoundAlreadySet tests\nUtilities.num_rows is now exported\nRemove parts of failing test_model_copy_to_xxx tests due to bridges","category":"page"},{"location":"release_notes/#[v0.10.5](https://github.com/jump-dev/MathOptInterface.jl/releases/tag/v0.10.5)-(November-7,-2021)","page":"Release notes","title":"v0.10.5 (November 7, 2021)","text":"","category":"section"},{"location":"release_notes/#Fixed-37","page":"Release notes","title":"Fixed","text":"","category":"section"},{"location":"release_notes/","page":"Release notes","title":"Release notes","text":"Fixed getter in UniversalFallback\nFixed test_solve_conflict_zeroone_ii","category":"page"},{"location":"release_notes/#Other-22","page":"Release notes","title":"Other","text":"","category":"section"},{"location":"release_notes/","page":"Release notes","title":"Release notes","text":"Make normalize_and_add_constraint more flexible\nUpdate paper BibTeX","category":"page"},{"location":"release_notes/#[v0.10.4](https://github.com/jump-dev/MathOptInterface.jl/releases/tag/v0.10.4)-(October-26,-2021)","page":"Release notes","title":"v0.10.4 (October 26, 2021)","text":"","category":"section"},{"location":"release_notes/#Added-25","page":"Release notes","title":"Added","text":"","category":"section"},{"location":"release_notes/","page":"Release notes","title":"Release notes","text":"Add SolverVersion attribute\nAdd new tests:\ntest_solve_conflict_zeroone_ii\ntest_nonlinear_objective\nUtilities.VariablesContainer now supports ConstraintFunction and ConstraintSet\nThe documentation is now available as a PDF","category":"page"},{"location":"release_notes/#Other-23","page":"Release notes","title":"Other","text":"","category":"section"},{"location":"release_notes/","page":"Release notes","title":"Release notes","text":"Update to MutableArithmetics 0.3\nVarious improvements to the documentation","category":"page"},{"location":"release_notes/#[v0.10.3](https://github.com/jump-dev/MathOptInterface.jl/releases/tag/v0.10.3)-(September-18,-2021)","page":"Release notes","title":"v0.10.3 (September 18, 2021)","text":"","category":"section"},{"location":"release_notes/#Fixed-38","page":"Release notes","title":"Fixed","text":"","category":"section"},{"location":"release_notes/","page":"Release notes","title":"Release notes","text":"Fixed bug which prevented callbacks from working through a CachingOptimizer\nFixed bug in Test submodule","category":"page"},{"location":"release_notes/#[v0.10.2](https://github.com/jump-dev/MathOptInterface.jl/releases/tag/v0.10.2)-(September-16,-2021)","page":"Release notes","title":"v0.10.2 (September 16, 2021)","text":"","category":"section"},{"location":"release_notes/","page":"Release notes","title":"Release notes","text":"Updated MathOptFormat to v1.0\nUpdated JSONSchema to v1.0\nAdded Utilities.set_with_dimension\nAdded two-argument optimize!(::AbstractOptimizer, ::ModelLike)\nThe experimental feature copy_to_and_optimize! has been removed\nDet bridges now support getting ConstraintFunction and ConstraintSet\nVarious minor bug fixes identified by improved testing","category":"page"},{"location":"release_notes/#[v0.10.1](https://github.com/jump-dev/MathOptInterface.jl/releases/tag/v0.10.1)-(September-8,-2021)","page":"Release notes","title":"v0.10.1 (September 8, 2021)","text":"","category":"section"},{"location":"release_notes/","page":"Release notes","title":"Release notes","text":"Various fixes to MOI.Test","category":"page"},{"location":"release_notes/#[v0.10.0](https://github.com/jump-dev/MathOptInterface.jl/releases/tag/v0.10.0)-(September-6,-2021)","page":"Release notes","title":"v0.10.0 (September 6, 2021)","text":"","category":"section"},{"location":"release_notes/","page":"Release notes","title":"Release notes","text":"MOI v0.10 is a significant breaking release. There are a large number of user-visible breaking changes and code refactors, as well as a substantial number of new features.","category":"page"},{"location":"release_notes/#Breaking-in-MOI","page":"Release notes","title":"Breaking in MOI","text":"","category":"section"},{"location":"release_notes/","page":"Release notes","title":"Release notes","text":"SingleVariable has been removed; use VariableIndex instead\nSingleVariableConstraintNameError has been renamed to VariableIndexConstraintNameError\nSettingSingleVariableFunctionNotAllowed has been renamed to SettingVariableIndexFunctionNotAllowed\nVariableIndex constraints should not support ConstraintName\nVariableIndex constraints should not support ConstraintBasisStatus; implement VariableBasisStatus instead\nListOfConstraints has been renamed to ListOfConstraintTypesPresent\nListOfConstraintTypesPresent should now return Tuple{Type,Type} instead of Tuple{DataType,DataType}\nSolveTime has been renamed to SolveTimeSec\nIndicatorSet has been renamed to Indicator\nRawParameter has been renamed to RawOptimizerAttribute and now takes String instead of Any as the only argument\nThe .N field in result attributes has been renamed to .result_index\nThe .variable_index field in ScalarAffineTerm has been renamed to .variable\nThe .variable_index_1 field in ScalarQuadraticTerm has been renamed to .variable_1\nThe .variable_index_2 field in ScalarQuadraticTerm has been renamed to .variable_2\nThe order of affine_terms and quadratic_terms in ScalarQuadraticFunction and VectorQuadraticFunction have been reversed. Both functions now accept quadratic, affine, and constant terms in that order.\nThe index_value function has been removed. Use .value instead.\nisapprox has been removed for SOS1 and SOS2.\nThe dimension argument to Complements(dimension::Int) should now be the length of the corresponding function, instead of half the length. An ArgumentError is thrown if dimension is not even.\ncopy_to no longer takes keyword arguments:\ncopy_names: now copy names if they are supported by the destination solver\nfilter_constraints: use Utilities.ModelFilter instead\nwarn_attributes: never warn about optimizer attributes","category":"page"},{"location":"release_notes/#Breaking-in-Bridges","page":"Release notes","title":"Breaking in Bridges","text":"","category":"section"},{"location":"release_notes/","page":"Release notes","title":"Release notes","text":"Constraint.RSOCBridge has been renamed to Constraint.RSOCtoSOCBridge\nConstraint.SOCRBridge has been renamed to Constraint.SOCtoRSOCBridge\nBridges now return vectors that can be modified by the user. Previously, some bridges returned views instead of copies.\nBridges.IndexInVector has been unified into a single type. Previously, there was a different type for each submodule within Bridges\nThe signature of indicator bridges has been fixed. Use MOI.Bridges.Constraint.IndicatortoSOS1{Float64}(model).","category":"page"},{"location":"release_notes/#Breaking-in-FileFormats","page":"Release notes","title":"Breaking in FileFormats","text":"","category":"section"},{"location":"release_notes/","page":"Release notes","title":"Release notes","text":"FileFormats.MOF.Model no longer accepts validate argument. Use the JSONSchema package to validate the MOF file. See the documentation for more information.","category":"page"},{"location":"release_notes/#Breaking-in-Utilities","page":"Release notes","title":"Breaking in Utilities","text":"","category":"section"},{"location":"release_notes/","page":"Release notes","title":"Release notes","text":"The datastructure of Utilities.Model (and models created with Utilities.@model) has been significantly refactored in a breaking way. This includes the way that objective functions and variable-related information is stored.\nUtilities.supports_default_copy has been renamed to supports_incremental_interface\nUtilities.automatic_copy_to has been renamed to Utilities.default_copy_to\nThe allocate-load API has been removed\nCachingOptimizers are now initialized as EMPTY_OPTIMIZER instead of ATTACHED_OPTIMIZER. If your code relies on the optimizer being attached, call MOIU.attach_optimizer(model) after creation.\nThe field names of Utilities.IndexMap have been renamed to var_map and con_map. Accessing these fields directly is considered a private detail that may change. Use the public getindex and setindex! API instead.\nThe size argument to Utilities.CleverDicts.CleverDict(::Integer) has been removed.\nThe size argument to Utilities.IndexMap(::Integer) has been removed.\nUtilities.DoubleDicts have been significantly refactored. Consult the source code for details.\nUtilities.test_models_equal has been moved to MOI.Test","category":"page"},{"location":"release_notes/#Breaking-in-Test","page":"Release notes","title":"Breaking in Test","text":"","category":"section"},{"location":"release_notes/","page":"Release notes","title":"Release notes","text":"MOI.Test has been renamed to MOI.DeprecatedTest\nAn entirely new MOI.Test submodule has been written. See the documentation for details. The new MOI.Test submodule may find many bugs in the implementations of existing solvers that were previously untested.","category":"page"},{"location":"release_notes/#Other-changes:","page":"Release notes","title":"Other changes:","text":"","category":"section"},{"location":"release_notes/","page":"Release notes","title":"Release notes","text":"attribute_value_type has been added\ncopy_to_and_optimize! has been added\nVariableBasisStatus has been added\nprint(model) now prints a human-readable description of the model\nVarious improvements to the FileFormats submodule\nFileFormats.CBF was refactored and received bugfixes\nSupport for MathOptFormat v0.6 was added in FileFormats.MOF\nFileFormats.MPS has had bugfixes and support for more features such as OBJSENSE and objective constants.\nFileFormats.NL has been added to support nonlinear files\nImproved type inference throughout to reduce latency","category":"page"},{"location":"release_notes/#Updating","page":"Release notes","title":"Updating","text":"","category":"section"},{"location":"release_notes/","page":"Release notes","title":"Release notes","text":"A helpful script when updating is:","category":"page"},{"location":"release_notes/","page":"Release notes","title":"Release notes","text":"for (root, dirs, files) in walkdir(\".\")\n for file in files\n if !endswith(file, \".jl\")\n continue\n end\n path = joinpath(root, file)\n s = read(path, String)\n for pair in [\n \".variable_index\" => \".variable\",\n \"RawParameter\" => \"RawOptimizerAttribute\",\n \"ListOfConstraints\" => \"ListOfConstraintTypesPresent\",\n \"TestConfig\" => \"Config\",\n \"attr.N\" => \"attr.result_index\",\n \"SolveTime\" => \"SolveTimeSec\",\n \"DataType\" => \"Type\",\n \"Utilities.supports_default_copy_to\" =>\n \"supports_incremental_interface\",\n \"SingleVariableConstraintNameError\" =>\n \"VariableIndexConstraintNameError\",\n \"SettingSingleVariableFunctionNotAllowed\" =>\n \"SettingVariableIndexFunctionNotAllowed\",\n \"automatic_copy_to\" => \"default_copy_to\",\n ]\n s = replace(s, pair)\n end\n write(path, s)\n end\nend","category":"page"},{"location":"release_notes/#[v0.9.22](https://github.com/jump-dev/MathOptInterface.jl/releases/tag/v0.9.22)-(May-22,-2021)","page":"Release notes","title":"v0.9.22 (May 22, 2021)","text":"","category":"section"},{"location":"release_notes/","page":"Release notes","title":"Release notes","text":"This release contains backports from the ongoing development of the v0.10 release.","category":"page"},{"location":"release_notes/","page":"Release notes","title":"Release notes","text":"Improved type inference in Utilities, Bridges and FileFormats submodules to reduce latency.\nImproved performance of Utilities.is_canonical.\nFixed Utilities.pass_nonvariable_constraints with bridged variables.\nFixed performance regression of Utilities.Model.\nFixed ordering of objective setting in parser.","category":"page"},{"location":"release_notes/#[v0.9.21](https://github.com/jump-dev/MathOptInterface.jl/releases/tag/v0.9.21)-(April-23,-2021)","page":"Release notes","title":"v0.9.21 (April 23, 2021)","text":"","category":"section"},{"location":"release_notes/","page":"Release notes","title":"Release notes","text":"Added supports_shift_constant.\nImprove performance of bridging quadratic constraints.\nAdd precompilation statements.\nLarge improvements to the documentation.\nFix a variety of inference issues, benefiting precompilation and reducing initial latency.\nRawParameters are now ignored when resetting a CachingOptimizer. Previously, changing the underlying optimizer after RawParameters were set would throw an error.\nUtilities.AbstractModel is being refactored. This may break users interacting with private fields of a model generated using @model.","category":"page"},{"location":"release_notes/#[v0.9.20](https://github.com/jump-dev/MathOptInterface.jl/releases/tag/v0.9.20)-(February-20,-2021)","page":"Release notes","title":"v0.9.20 (February 20, 2021)","text":"","category":"section"},{"location":"release_notes/","page":"Release notes","title":"Release notes","text":"Improved performance of Utilities.ScalarFunctionIterator\nAdded support for compute_conflict to MOI layers\nAdded test with zero off-diagonal quadratic term in objective\nFixed double deletion of nested bridged SingleVariable/VectorOfVariables constraints\nFixed modification of un-set objective\nFixed function modification with duplicate terms\nMade unit tests abort without failing if the problem class is not supported\nFormatted code with JuliaFormatter\nClarified BasisStatusCode's docstring","category":"page"},{"location":"release_notes/#[v0.9.19](https://github.com/jump-dev/MathOptInterface.jl/releases/tag/v0.9.19)-(December-1,-2020)","page":"Release notes","title":"v0.9.19 (December 1, 2020)","text":"","category":"section"},{"location":"release_notes/","page":"Release notes","title":"Release notes","text":"Added CallbackNodeStatus attribute\nAdded bridge from GreaterThan or LessThan to Interval\nAdded tests for infeasibility certificates and double optimize\nFixed support for Julia v1.6\nRe-organized MOI docs and added documentation for adding a test","category":"page"},{"location":"release_notes/#[v0.9.18](https://github.com/jump-dev/MathOptInterface.jl/releases/tag/v0.9.18)-(November-3,-2020)","page":"Release notes","title":"v0.9.18 (November 3, 2020)","text":"","category":"section"},{"location":"release_notes/","page":"Release notes","title":"Release notes","text":"Various improvements for working with complex numbers\nAdded GeoMeantoRelEntrBridge to bridge a GeometricMeanCone constraint to a relative entropy constraint","category":"page"},{"location":"release_notes/#[v0.9.17](https://github.com/jump-dev/MathOptInterface.jl/releases/tag/v0.9.17)-(September-21,-2020)","page":"Release notes","title":"v0.9.17 (September 21, 2020)","text":"","category":"section"},{"location":"release_notes/","page":"Release notes","title":"Release notes","text":"Fixed CleverDict with variable of negative index value\nImplement supports_add_constrained_variable for MockOptimizer","category":"page"},{"location":"release_notes/#[v0.9.16](https://github.com/jump-dev/MathOptInterface.jl/releases/tag/v0.9.16)-(September-17,-2020)","page":"Release notes","title":"v0.9.16 (September 17, 2020)","text":"","category":"section"},{"location":"release_notes/","page":"Release notes","title":"Release notes","text":"Various fixes:\n32-bit support\nCleverDict with abstract value type\nChecks in test suite","category":"page"},{"location":"release_notes/#[v0.9.15](https://github.com/jump-dev/MathOptInterface.jl/releases/tag/v0.9.15)-(September-14,-2020)","page":"Release notes","title":"v0.9.15 (September 14, 2020)","text":"","category":"section"},{"location":"release_notes/","page":"Release notes","title":"Release notes","text":"Bridges improvements:\n(R)SOCtoNonConvexQuad bridge\nZeroOne bridge\nUse supports_add_constrained_variable in LazyBridgeOptimizer\nExposed VariableBridgeCost and ConstraintBridgeCost attributes\nPrioritize constraining variables on creation according to these costs\nRefactor bridge debugging\nLarge performance improvements across all submodules\nLots of documentation improvements\nFileFormats improvements:\nUpdate MathOptFormat to v0.5\nFix supported objectives in FileFormats\nTesting improvements:\nAdd name option for basic_constraint_test\nBug fixes and missing methods\nAdd length for iterators\nFix bug with duplicate terms\nFix order of LinearOfConstraintIndices","category":"page"},{"location":"release_notes/#[v0.9.14](https://github.com/jump-dev/MathOptInterface.jl/releases/tag/v0.9.14)-(May-30,-2020)","page":"Release notes","title":"v0.9.14 (May 30, 2020)","text":"","category":"section"},{"location":"release_notes/","page":"Release notes","title":"Release notes","text":"Add a solver-independent interface for accessing the set of conflicting constraints an Irreducible Inconsistent Subsystem (#1056).\nBump JSONSchema dependency from v0.2 to v0.3 (#1090).\nDocumentation improvements:\nFix typos (#1054, #1060, #1061, #1064, #1069, #1070).\nRemove the outdated recommendation for a package implementing MOI for a solver XXX to be called MathOptInterfaceXXX (#1087).\nUtilities improvements:\nFix is_canonical for quadratic functions (#1081, #1089).\nImplement add_constrained_variable[s] for CachingOptimizer so that it is added as constrained variables to the underlying optimizer (#1084).\nAdd support for custom objective functions for UniversalFallback (#1086).\nDeterministic ordering of constraints in UniversalFallback (#1088).\nTesting improvements:\nAdd NormOneCone/NormInfinityCone tests (#1045).\nBridges improvements:\nAdd bridges from Semiinteger and Semicontinuous (#1059).\nImplement getting ConstraintSet for Variable.FlipSignBridge (#1066).\nFix setting ConstraintFunction for Constraint.ScalarizeBridge (#1093).\nFix NormOne/NormInf bridges with nonzero constants (#1045).\nFix StackOverflow in debug (#1063).\nFileFormats improvements:\n[SDPA] Implement the extension for integer variables (#1079).\n[SDPA] Ignore comments after m and nblocks and detect dat-s extension (#1077).\n[SDPA] No scaling of off-diagonal coefficient (#1076).\n[SDPA] Add missing negation of constant (#1075).","category":"page"},{"location":"release_notes/#[v0.9.13](https://github.com/jump-dev/MathOptInterface.jl/releases/tag/v0.9.13)-(March-24,-2020)","page":"Release notes","title":"v0.9.13 (March 24, 2020)","text":"","category":"section"},{"location":"release_notes/","page":"Release notes","title":"Release notes","text":"Added tests for Semicontinuous and Semiinteger variables (#1033).\nAdded tests for using ExprGraphs from NLP evaluators (#1043).\nUpdate version compatibilities of dependencies (#1034, #1051, #1052).\nFixed typos in documentation (#1044).","category":"page"},{"location":"release_notes/#[v0.9.12](https://github.com/jump-dev/MathOptInterface.jl/releases/tag/v0.9.12)-(February-28,-2020)","page":"Release notes","title":"v0.9.12 (February 28, 2020)","text":"","category":"section"},{"location":"release_notes/","page":"Release notes","title":"Release notes","text":"Fixed writing NLPBlock in MathOptFormat (#1037).\nFixed MockOptimizer for result attributes with non-one result index (#1039).\nUpdated test template with instantiate (#1032).","category":"page"},{"location":"release_notes/#[v0.9.11](https://github.com/jump-dev/MathOptInterface.jl/releases/tag/v0.9.11)-(February-21,-2020)","page":"Release notes","title":"v0.9.11 (February 21, 2020)","text":"","category":"section"},{"location":"release_notes/","page":"Release notes","title":"Release notes","text":"Add an option for the model created by Utilities.@model to be a subtype of AbstractOptimizer (#1031).\nDescribed dual cone in docstrings of GeoMeanCone and RelativeEntropyCone (#1018, #1028).\nFixed typos in documentation (#1022, #1024).\nFixed warning of unsupported attribute (#1027).\nAdded more rootdet/logdet conic tests (#1026).\nImplemented ConstraintDual for Constraint.GeoMeanBridge, Constraint.RootDetBridge and Constraint.LogDetBridge and test duals in tests with GeoMeanCone and RootDetConeTriangle and LogDetConeTriangle cones (#1025, #1026).","category":"page"},{"location":"release_notes/#[v0.9.10](https://github.com/jump-dev/MathOptInterface.jl/releases/tag/v0.9.10)-(January-31,-2020)","page":"Release notes","title":"v0.9.10 (January 31, 2020)","text":"","category":"section"},{"location":"release_notes/","page":"Release notes","title":"Release notes","text":"Added OptimizerWithAttributes grouping an optimizer constructor and a list of optimizer attributes (#1008).\nAdded RelativeEntropyCone with corresponding bridge into exponential cone constraints (#993).\nAdded NormSpectralCone and NormNuclearCone with corresponding bridges into positive semidefinite constraints (#976).\nAdded supports_constrained_variable(s) (#1004).\nAdded dual_set_type (#1002).\nAdded tests for vector specialized version of delete (#989, #1011).\nAdded PSD3 test (#1007).\nClarified dual solution of Tests.pow1v and Tests.pow1f (#1013).\nAdded support for EqualTo and Zero in Bridges.Constraint.SplitIntervalBridge (#1005).\nFixed Utilities.vectorize for empty vector (#1003).\nFixed free variables in LP writer (#1006).","category":"page"},{"location":"release_notes/#[v0.9.9](https://github.com/jump-dev/MathOptInterface.jl/releases/tag/v0.9.9)-(December-29,-2019)","page":"Release notes","title":"v0.9.9 (December 29, 2019)","text":"","category":"section"},{"location":"release_notes/","page":"Release notes","title":"Release notes","text":"Incorporated MathOptFormat.jl as the FileFormats submodule. FileFormats provides readers and writers for a number of standard file formats and MOF, a file format specialized for MOI (#969).\nImproved performance of deletion of vector of variables in MOI.Utilities.Model (#983).\nUpdated to MutableArithmetics v0.2 (#981).\nAdded MutableArithmetics.promote_operation allocation tests (#975).\nFixed inference issue on Julia v1.1 (#982).","category":"page"},{"location":"release_notes/#[v0.9.8](https://github.com/jump-dev/MathOptInterface.jl/releases/tag/v0.9.8)-(December-19,-2019)","page":"Release notes","title":"v0.9.8 (December 19, 2019)","text":"","category":"section"},{"location":"release_notes/","page":"Release notes","title":"Release notes","text":"Implemented MutableArithmetics API (#924).\nFixed callbacks with CachingOptimizer (#959).\nFixed MOI.dimension for MOI.Complements (#948).\nAdded fallback for add_variables (#972).\nAdded is_diagonal_vectorized_index utility (#965).\nImproved linear constraints display in manual (#963, #964).\nBridges improvements:\nAdded IndicatorSet to SOS1 bridge (#877).\nAdded support for starting values for Variable.VectorizeBridge (#944).\nFixed MOI.add_constraints with non-bridged variable constraint on bridged variable (#951).\nFixed corner cases and docstring of GeoMeanBridge (#961, #962, #966).\nFixed choice between variable or constraint bridges for constrained variables (#973).\nImprove performance of bridge shortest path (#945, #946, #956).\nAdded docstring for test_delete_bridge (#954).\nAdded Variable bridge tests (#952).","category":"page"},{"location":"release_notes/#[v0.9.7](https://github.com/jump-dev/MathOptInterface.jl/releases/tag/v0.9.7)-(October-30,-2019)","page":"Release notes","title":"v0.9.7 (October 30, 2019)","text":"","category":"section"},{"location":"release_notes/","page":"Release notes","title":"Release notes","text":"Implemented _result_index_field for NLPBlockDual (#934).\nFixed copy of model with starting values for vector constraints (#941).\nBridges improvements:\nImproved performance of add_bridge and added has_bridge (#935).\nAdded AbstractSetMapBridge for bridges between sets S1, S2 such that there is a linear map A such that A*S1 = S2 (#933).\nAdded support for starting values for FlipSignBridge, VectorizeBridge, ScalarizeBridge, SlackBridge, SplitIntervalBridge, RSOCBridge, SOCRBridge NormInfinityBridge, SOCtoPSDBridge and RSOCtoPSDBridge (#933, #936, #937, #938, #939).","category":"page"},{"location":"release_notes/#[v0.9.6](https://github.com/jump-dev/MathOptInterface.jl/releases/tag/v0.9.6)-(October-25,-2019)","page":"Release notes","title":"v0.9.6 (October 25, 2019)","text":"","category":"section"},{"location":"release_notes/","page":"Release notes","title":"Release notes","text":"Added complementarity constraints (#913).\nAllowed ModelLike objects as value of attributes (#928).\nTesting improvements:\nAdded dual_objective_value option to MOI.Test.TestConfig (#922).\nAdded InvalidIndex tests in basic_constraint_tests (#921).\nAdded tests for the constant term in indicator constraint (#929).\nBridges improvements:\nAdded support for starting values for Functionize bridges (#923).\nAdded variable indices context to variable bridges (#920).\nFixed a typo in printing o debug_supports (#927).","category":"page"},{"location":"release_notes/#[v0.9.5](https://github.com/jump-dev/MathOptInterface.jl/releases/tag/v0.9.5)-(October-9,-2019)","page":"Release notes","title":"v0.9.5 (October 9, 2019)","text":"","category":"section"},{"location":"release_notes/","page":"Release notes","title":"Release notes","text":"Clarified PrimalStatus/DualStatus to be NO_SOLUTION if result_index is out of bounds (#912).\nAdded tolerance for checks and use ResultCount + 1 for the result_index in MOI.Test.solve_result_status (#910, #917).\nUse 0.5 instead of 2.0 for power in PowerCone in basic_constraint_test (#916).\nBridges improvements:\nAdded debug utilities for unsupported variable/constraint/objective (#861).\nFixed deletion of variables in bridged VectorOfVariables constraints (#909).\nFixed result_index with objective bridges (#911).","category":"page"},{"location":"release_notes/#[v0.9.4](https://github.com/jump-dev/MathOptInterface.jl/releases/tag/v0.9.4)-(October-2,-2019)","page":"Release notes","title":"v0.9.4 (October 2, 2019)","text":"","category":"section"},{"location":"release_notes/","page":"Release notes","title":"Release notes","text":"Added solver-independent MIP callbacks (#782).\nImplements submit for Utilities.CachingOptimizer and Bridges.AbstractBridgeOptimizer (#906).\nAdded tests for result count of solution attributes (#901, #904).\nAdded NumberOfThreads attribute (#892).\nAdded Utilities.get_bounds to get the bounds on a variable (#890).\nAdded a note on duplicate coefficients in documentation (#581).\nAdded result index in ConstraintBasisStatus (#898).\nAdded extension dictionary to Utilities.Model (#884, #895).\nFixed deletion of constrained variables for CachingOptimizer (#905).\nImplemented Utilities.shift_constraint for Test.UnknownScalarSet (#896).\nBridges improvements:\nAdded Variable.RSOCtoSOCBridge (#907).\nImplemented MOI.get for ConstraintFunction/ConstraintSet for Bridges.Constraint.SquareBridge (#899).","category":"page"},{"location":"release_notes/#[v0.9.3](https://github.com/jump-dev/MathOptInterface.jl/releases/tag/v0.9.3)-(September-20,-2019)","page":"Release notes","title":"v0.9.3 (September 20, 2019)","text":"","category":"section"},{"location":"release_notes/","page":"Release notes","title":"Release notes","text":"Fixed ambiguity detected in Julia v1.3 (#891, #893).\nFixed missing sets from ListOfSupportedConstraints (#880).\nFixed copy of VectorOfVariables constraints with duplicate indices (#886).\nAdded extension dictionary to MOIU.Model (#884).\nImplemented MOI.get for function and set for GeoMeanBridge (#888).\nUpdated documentation for SingleVariable indices and bridges (#885).\nTesting improvements:\nAdded more comprehensive tests for names (#882).\nAdded tests for SingleVariable duals (#883).\nAdded tests for DualExponentialCone and DualPowerCone (#873).\nImprovements for arbitrary coefficient type:\nFixed == for sets with mutable fields (#887).\nRemoved some Float64 assumptions in bridges (#878).\nAutomatic selection of Constraint.[Scalar|Vector]FunctionizeBridge (#889).","category":"page"},{"location":"release_notes/#[v0.9.2](https://github.com/jump-dev/MathOptInterface.jl/releases/tag/v0.9.2)-(September-5,-2019)","page":"Release notes","title":"v0.9.2 (September 5, 2019)","text":"","category":"section"},{"location":"release_notes/","page":"Release notes","title":"Release notes","text":"Implemented model printing for MOI.ModelLike and specialized it for models defined in MOI (864).\nGeneralized contlinear tests for arbitrary coefficient type (#855).\nFixed supports_constraint for Semiinteger and Semicontinuous and supports for ObjectiveFunction (#859).\nFixed Allocate-Load copy for single variable constraints (#856).\nBridges improvements:\nAdd objective bridges (#789).\nFixed Variable.RSOCtoPSDBridge for dimension 2 (#869).\nAdded Variable.SOCtoRSOCBridge (#865).\nAdded Constraint.SOCRBridge and disable MOI.Bridges.Constraint.SOCtoPSDBridge (#751).\nFixed added_constraint_types for Contraint.LogDetBridge and Constraint.RootDetBridge (#870).","category":"page"},{"location":"release_notes/#[v0.9.1](https://github.com/jump-dev/MathOptInterface.jl/releases/tag/v0.9.1)-(August-22,-2019)","page":"Release notes","title":"v0.9.1 (August 22, 2019)","text":"","category":"section"},{"location":"release_notes/","page":"Release notes","title":"Release notes","text":"Fix support for Julia v1.2 (#834).\nL1 and L∞ norm epigraph cones and corresponding bridges to LP were added (#818).\nAdded tests to MOI.Test.nametest (#833).\nFix MOI.Test.soc3test for solvers not supporting infeasibility certificates (#839).\nImplements operate for operators * and / between vector function and constant (#837).\nImplements show for MOI.Utilities.IndexMap (#847).\nFix corner cases for mapping of variables in MOI.Utilities.CachingOptimizer and substitution of variables in MOI.Bridges.AbstractBridgeOptimizer (#848).\nFix transformation of constant terms for MOI.Bridges.Constraint.SOCtoPSDBridge and MOI.Bridges.Constraint.RSOCtoPSDBridge (#840).","category":"page"},{"location":"release_notes/#[v0.9.0](https://github.com/jump-dev/MathOptInterface.jl/releases/tag/v0.9.0)-(August-13,-2019)","page":"Release notes","title":"v0.9.0 (August 13, 2019)","text":"","category":"section"},{"location":"release_notes/","page":"Release notes","title":"Release notes","text":"Support for Julia v0.6 and v0.7 was dropped (#714, #717).\nA MOI.Utilities.Model implementation of ModelLike, this should replace most use cases of MOI.Utilities.@model (#781).\nadd_constrained_variable and add_constrained_variables were added (#759).\nSupport for indicator constraints was added (#709, #712).\nDualObjectiveValue attribute was added (#473).\nRawParameter attribute was added (#733).\nA dual_set function was added (#804).\nA Benchmarks submodule was added to facilitate solver benchmarking (#769).\nA submit function was added, this may for instance allow the user to submit solutions or cuts to the solver from a callback (#775).\nThe field of ObjectiveValue was renamed to result_index (#729).\nThe _constant and Utilities.getconstant function were renamed to constant\nREDUCTION_CERTIFICATE result status was added (#734).\nAbstract matrix sets were added (#731).\nTesting improvements:\nThe testing guideline was updated (#728).\nQuadratic tests were added (#697).\nUnit tests for RawStatusString, SolveTime, Silent and SolverName were added (#726, #741).\nA rotated second-order cone test was added (#759).\nA power cone test was added (#768).\nTests for ZeroOne variables with variable bounds were added (#772).\nAn unbounded test was added (#773).\nExisting tests had a few updates (#702, #703, #763).\nDocumentation improvements:\nAdded a section on CachingOptimizer (#777).\nAdded a section on UniversalFallback, Model and @model (#762).\nTransition the knapsack example to a doctest with MockOptimizer (#786).\nUtilities improvements:\nA CleverDict utility was added for a vector that automatically transform into a dictionary once a first index is removed (#767).\nThe Utilities.constant function was renamed to Utilities.constant_vector (#740).\nImplement optimizer attributes for CachingOptimizer (#745).\nRename Utilities.add_scalar_constraint to Utilities.normalize_and_add_constraint (#801).\noperate with vcat, SingleVariable and VectorOfVariables now returns a VectorOfVariables (#616).\nFix a type piracy of operate (#784).\nThe load_constraint fallback signature was fixed (#760).\nThe set_dot function was extended to work with sparse arrays (#805).\nBridges improvements:\nThe bridges no longer store the constraint function and set before it is bridged, the bridges now have to implement ConstraintFunction and ConstraintSet if the user wants to recover them. As a consequence, the @bridge macro was removed (#722).\nBridge are now instantiated with a bridge_constraint function instead of using a constructor (#730).\nFix constraint attributes for bridges (#699).\nConstraint bridges were moved to the Bridges/Constraint submodule so they should now inherit from MOI.Bridges.Constraint.Abstract and should implement MOI.Bridges.Constraint.concrete_bridge_type instead of MOI.Bridges.concrete_bridge_type (#756).\nVariable bridges were added in (#759).\nVarious improvements (#746, #747).","category":"page"},{"location":"release_notes/#[v0.8.4](https://github.com/jump-dev/MathOptInterface.jl/releases/tag/v0.8.4)-(March-13,-2019)","page":"Release notes","title":"v0.8.4 (March 13, 2019)","text":"","category":"section"},{"location":"release_notes/","page":"Release notes","title":"Release notes","text":"Performance improvement in default_copy_to and bridge optimizer (#696).\nAdd Silent and implement setting optimizer attributes in caching and mock optimizers (#695).\nAdd Functionize bridges (SingleVariable and VectorOfVariables) (#659).\nMinor typo fixes (#694).","category":"page"},{"location":"release_notes/#[v0.8.3](https://github.com/jump-dev/MathOptInterface.jl/releases/tag/v0.8.3)-(March-6,-2019)","page":"Release notes","title":"v0.8.3 (March 6, 2019)","text":"","category":"section"},{"location":"release_notes/","page":"Release notes","title":"Release notes","text":"Use zero constant in scalar constraint function of MOI.Test.copytest (#691).\nFix variable deletion with SingleVariable objective function (#690).\nFix LazyBridgeOptimizer with bridges that add no constraints (#689).\nError message improvements (#673, #685, #686, #688).\nDocumentation improvements (#682, #683, #687).\nBasis status:\nRemove VariableBasisStatus (#679).\nTest ConstraintBasisStatus and implement it in bridges (#678).\nFix inference of NumberOfVariables and NumberOfConstraints (#677).\nImplement division between a quadratic function and a number (#675).","category":"page"},{"location":"release_notes/#[v0.8.2](https://github.com/jump-dev/MathOptInterface.jl/releases/tag/v0.8.2)-(February-7,-2019)","page":"Release notes","title":"v0.8.2 (February 7, 2019)","text":"","category":"section"},{"location":"release_notes/","page":"Release notes","title":"Release notes","text":"Add RawStatusString attribute (#629).\nDo not set names to the optimizer but only to the cache in CachingOptimizer (#638).\nMake scalar MOI functions act as scalars in broadcast (#646).\nAdd function utilities:\nImplement Base.zero (#634), Base.iszero (#643), add missing arithmetic operations (#644, #645) and fix division (#648).\nAdd a vectorize function that turns a vector of ScalarAffineFunction into a VectorAffineFunction (#642).\nImprove support for starting values:\nShow a warning in copy when starting values are not supported instead of throwing an error (#630).\nFix UniversalFallback for getting an variable or constraint attribute set to no indices (#623).\nAdd a test in contlineartest with partially set VariablePrimalStart.\nBridges improvements:\nFix StackOverFlow in LazyBridgeOptimizer when there is a cycle in the graph of bridges.\nAdd Slack bridges (#610, #650).\nAdd FlipSign bridges (#658).\nAdd tests with duplicate coefficients in ScalarAffineFunction and VectorAffineFunction (#639).\nUse tolerance to compare VariablePrimal in rotatedsoc1 test (#632).\nUse a zero constant in ScalarAffineFunction of constraints in psdt2 (#622).","category":"page"},{"location":"release_notes/#[v0.8.1](https://github.com/jump-dev/MathOptInterface.jl/releases/tag/v0.8.1)-(January-7,-2019)","page":"Release notes","title":"v0.8.1 (January 7, 2019)","text":"","category":"section"},{"location":"release_notes/","page":"Release notes","title":"Release notes","text":"Adding an NLP objective now overrides any objective set using the ObjectiveFunction attribute (#619).\nRename fullbridgeoptimizer into full_bridge_optimizer (#621).\nAllow custom constraint types with full_bridge_optimizer (#617).\nAdd Vectorize bridge which transforms scalar linear constraints into vector linear constraints (#615).","category":"page"},{"location":"release_notes/#[v0.8.0](https://github.com/jump-dev/MathOptInterface.jl/releases/tag/v0.8.0)-(December-18,-2018)","page":"Release notes","title":"v0.8.0 (December 18, 2018)","text":"","category":"section"},{"location":"release_notes/","page":"Release notes","title":"Release notes","text":"Rename all enum values to follow the JuMP naming guidelines for constants, for example, Optimal becomes OPTIMAL, and DualInfeasible becomes DUAL_INFEASIBLE.\nRename CachingOptimizer methods for style compliance.\nAdd an MOI.TerminationStatusCode called ALMOST_DUAL_INFEASIBLE.","category":"page"},{"location":"release_notes/#[v0.7.0](https://github.com/jump-dev/MathOptInterface.jl/releases/tag/v0.7.0)-(December-13,-2018)","page":"Release notes","title":"v0.7.0 (December 13, 2018)","text":"","category":"section"},{"location":"release_notes/","page":"Release notes","title":"Release notes","text":"Test that MOI.TerminationStatus is MOI.OptimizeNotCalled before MOI.optimize! is called.\nCheck supports_default_copy_to in tests (#594).\nKey pieces of information like optimality, infeasibility, etc., are now reported through TerminationStatusCode. It is typically no longer necessary to check the result statuses in addition to the termination status.\nAdd perspective dimension to log-det cone (#593).","category":"page"},{"location":"release_notes/#[v0.6.4](https://github.com/jump-dev/MathOptInterface.jl/releases/tag/v0.6.4)-(November-27,-2018)","page":"Release notes","title":"v0.6.4 (November 27, 2018)","text":"","category":"section"},{"location":"release_notes/","page":"Release notes","title":"Release notes","text":"Add OptimizeNotCalled termination status (#577) and improve documentation of other statuses (#575).\nAdd a solver naming guideline (#578).\nMake FeasibilitySense the default ObjectiveSense (#579).\nFix Utilities.@model and Bridges.@bridge macros for functions and sets defined outside MOI (#582).\nDocument solver-specific attributes (#580) and implement them in Utilities.CachingOptimizer (#565).","category":"page"},{"location":"release_notes/#[v0.6.3](https://github.com/jump-dev/MathOptInterface.jl/releases/tag/v0.6.3)-(November-16,-2018)","page":"Release notes","title":"v0.6.3 (November 16, 2018)","text":"","category":"section"},{"location":"release_notes/","page":"Release notes","title":"Release notes","text":"Variables and constraints are now allowed to have duplicate names. An error is thrown only on lookup. This change breaks some existing tests. (#549)\nAttributes may now be partially set (some values could be nothing). (#563)\nPerformance improvements in Utilities.Model (#549, #567, #568)\nFix bug in QuadtoSOC (#558).\nNew supports_default_copy_to method that optimizers should implement to control caching behavior.\nDocumentation improvements.","category":"page"},{"location":"release_notes/#[v0.6.2](https://github.com/jump-dev/MathOptInterface.jl/releases/tag/v0.6.2)-(October-26,-2018)","page":"Release notes","title":"v0.6.2 (October 26, 2018)","text":"","category":"section"},{"location":"release_notes/","page":"Release notes","title":"Release notes","text":"Improve hygiene of @model macro (#544).\nFix bug in copy tests (#543).\nFix bug in UniversalFallback attribute getter (#540).\nAllow all correct solutions for solve_blank_obj unit test (#537).\nAdd errors for Allocate-Load and bad constraints (#534).\n[performance] Add specialized implementation of hash for VariableIndex (#533).\n[performance] Construct the name to object dictionaries lazily in model (#535).\nAdd the QuadtoSOC bridge which transforms ScalarQuadraticFunction constraints into RotatedSecondOrderCone (#483).","category":"page"},{"location":"release_notes/#[v0.6.1](https://github.com/jump-dev/MathOptInterface.jl/releases/tag/v0.6.1)-(September-22,-2018)","page":"Release notes","title":"v0.6.1 (September 22, 2018)","text":"","category":"section"},{"location":"release_notes/","page":"Release notes","title":"Release notes","text":"Enable PositiveSemidefiniteConeSquare set and quadratic functions in MOIB.fullbridgeoptimizer (#524).\nAdd warning in the bridge between PositiveSemidefiniteConeSquare and PositiveSemidefiniteConeTriangle when the matrix is almost symmetric (#522).\nModify MOIT.copytest to not add multiples constraints on the same variable (#521).\nAdd missing keyword argument in one of MOIU.add_scalar_constraint methods (#520).","category":"page"},{"location":"release_notes/#[v0.6.0](https://github.com/jump-dev/MathOptInterface.jl/releases/tag/v0.6.0)-(August-30,-2018)","page":"Release notes","title":"v0.6.0 (August 30, 2018)","text":"","category":"section"},{"location":"release_notes/","page":"Release notes","title":"Release notes","text":"The MOIU.@model and MOIB.@bridge macros now support functions and sets defined in external modules. As a consequence, function and set names in the macro arguments need to be prefixed by module name.\nRename functions according to the JuMP style guide:\ncopy! with keyword arguments copynames and warnattributes -> copy_to with keyword arguments copy_names and warn_attributes;\nset! -> set;\naddvariable[s]! -> add_variable[s];\nsupportsconstraint -> supports_constraint;\naddconstraint[s]! -> add_constraint[s];\nisvalid -> is_valid;\nisempty -> is_empty;\nBase.delete! -> delete;\nmodify! -> modify;\ntransform! -> transform;\ninitialize! -> initialize;\nwrite -> write_to_file; and\nread! -> read_from_file.\nRemove free! (use Base.finalize instead).\nAdd the SquarePSD bridge which transforms PositiveSemidefiniteConeTriangle constraints into PositiveSemidefiniteConeTriangle.\nAdd result fallback for ConstraintDual of variable-wise constraint, ConstraintPrimal and ObjectiveValue.\nAdd tests for ObjectiveBound.\nAdd test for empty rows in vector linear constraint.\nRework errors: CannotError has been renamed NotAllowedError and the distinction between UnsupportedError and NotAllowedError is now about whether the element is not supported (for example, it cannot be copied a model containing this element) or the operation is not allowed (either because it is not implemented, because it cannot be performed in the current state of the model, or because it cannot be performed for a specific index)\ncanget is removed. NoSolution is added as a result status to indicate that the solver does not have either a primal or dual solution available (See #479).","category":"page"},{"location":"release_notes/#[v0.5.0](https://github.com/jump-dev/MathOptInterface.jl/releases/tag/v0.5.0)-(August-5,-2018)","page":"Release notes","title":"v0.5.0 (August 5, 2018)","text":"","category":"section"},{"location":"release_notes/","page":"Release notes","title":"Release notes","text":"Fix names with CachingOptimizer.\nCleanup thanks to @mohamed82008.\nAdded a universal fallback for constraints.\nFast utilities for function canonicalization thanks to @rdeits.\nRenamed dimension field to side_dimension in the context of matrix-like sets.\nNew and improved tests for cases like duplicate terms and ObjectiveBound.\nRemoved cantransform, canaddconstraint, canaddvariable, canset, canmodify, and candelete functions from the API. They are replaced by a new set of errors that are thrown: Subtypes of UnsupportedError indicate unsupported operations, while subtypes of CannotError indicate operations that cannot be performed in the current state.\nThe API for copy! is updated to remove the CopyResult type.\nUpdates for the new JuMP style guide.","category":"page"},{"location":"release_notes/#[v0.4.1](https://github.com/jump-dev/MathOptInterface.jl/releases/tag/v0.4.1)-(June-28,-2018)","page":"Release notes","title":"v0.4.1 (June 28, 2018)","text":"","category":"section"},{"location":"release_notes/","page":"Release notes","title":"Release notes","text":"Fixes vector function modification on 32 bits.\nFixes Bellman-Ford algorithm for bridges.\nAdded an NLP test with FeasibilitySense.\nUpdate modification documentation.","category":"page"},{"location":"release_notes/#[v0.4.0](https://github.com/jump-dev/MathOptInterface.jl/releases/tag/v0.4.0)-(June-23,-2018)","page":"Release notes","title":"v0.4.0 (June 23, 2018)","text":"","category":"section"},{"location":"release_notes/","page":"Release notes","title":"Release notes","text":"Helper constructors for VectorAffineTerm and VectorQuadraticTerm.\nAdded modify_lhs to TestConfig.\nAdditional unit tests for optimizers.\nAdded a type parameter to CachingOptimizer for the optimizer field.\nNew API for problem modification (#388)\nTests pass without deprecation warnings on Julia 0.7.\nSmall fixes and documentation updates.","category":"page"},{"location":"release_notes/#[v0.3.0](https://github.com/jump-dev/MathOptInterface.jl/releases/tag/v0.3.0)-(May-25,-2018)","page":"Release notes","title":"v0.3.0 (May 25, 2018)","text":"","category":"section"},{"location":"release_notes/","page":"Release notes","title":"Release notes","text":"Functions have been redefined to use arrays-of-structs instead of structs-of-arrays.\nImprovements to MockOptimizer.\nSignificant changes to Bridges.\nNew and improved unit tests.\nFixes for Julia 0.7.","category":"page"},{"location":"release_notes/#[v0.2.0](https://github.com/jump-dev/MathOptInterface.jl/releases/tag/v0.2.0)-(April-24,-2018)","page":"Release notes","title":"v0.2.0 (April 24, 2018)","text":"","category":"section"},{"location":"release_notes/","page":"Release notes","title":"Release notes","text":"Improvements to and better coverage of Tests.\nDocumentation fixes.\nSolverName attribute.\nChanges to the NLP interface (new definition of variable order and arrays of structs for bound pairs and sparsity patterns).\nAddition of NLP tests.\nIntroduction of UniversalFallback.\ncopynames keyword argument to MOI.copy!.\nAdd Bridges submodule.","category":"page"},{"location":"release_notes/#[v0.1.0](https://github.com/jump-dev/MathOptInterface.jl/releases/tag/v0.1.0)-(February-28,-2018)","page":"Release notes","title":"v0.1.0 (February 28, 2018)","text":"","category":"section"},{"location":"release_notes/","page":"Release notes","title":"Release notes","text":"Initial public release.\nThe framework for MOI was developed at the JuMP-dev workshop at MIT in June 2017 as a sorely needed replacement for MathProgBase.","category":"page"},{"location":"manual/constraints/","page":"Constraints","title":"Constraints","text":"CurrentModule = MathOptInterface\nDocTestSetup = quote\n import MathOptInterface as MOI\nend\nDocTestFilters = [r\"MathOptInterface|MOI\"]","category":"page"},{"location":"manual/constraints/#Constraints","page":"Constraints","title":"Constraints","text":"","category":"section"},{"location":"manual/constraints/#Add-a-constraint","page":"Constraints","title":"Add a constraint","text":"","category":"section"},{"location":"manual/constraints/","page":"Constraints","title":"Constraints","text":"Use add_constraint to add a single constraint.","category":"page"},{"location":"manual/constraints/","page":"Constraints","title":"Constraints","text":"julia> c = MOI.add_constraint(model, MOI.VectorOfVariables(x), MOI.Nonnegatives(2))\nMathOptInterface.ConstraintIndex{MathOptInterface.VectorOfVariables, MathOptInterface.Nonnegatives}(1)","category":"page"},{"location":"manual/constraints/","page":"Constraints","title":"Constraints","text":"add_constraint returns a ConstraintIndex type, which is used to refer to the added constraint in other calls.","category":"page"},{"location":"manual/constraints/","page":"Constraints","title":"Constraints","text":"Check if a ConstraintIndex is valid using is_valid.","category":"page"},{"location":"manual/constraints/","page":"Constraints","title":"Constraints","text":"julia> MOI.is_valid(model, c)\ntrue","category":"page"},{"location":"manual/constraints/","page":"Constraints","title":"Constraints","text":"Use add_constraints to add a number of constraints of the same type.","category":"page"},{"location":"manual/constraints/","page":"Constraints","title":"Constraints","text":"julia> c = MOI.add_constraints(\n model,\n [x[1], x[2]],\n [MOI.GreaterThan(0.0), MOI.GreaterThan(1.0)]\n )\n2-element Vector{MathOptInterface.ConstraintIndex{MathOptInterface.VariableIndex, MathOptInterface.GreaterThan{Float64}}}:\n MathOptInterface.ConstraintIndex{MathOptInterface.VariableIndex, MathOptInterface.GreaterThan{Float64}}(1)\n MathOptInterface.ConstraintIndex{MathOptInterface.VariableIndex, MathOptInterface.GreaterThan{Float64}}(2)","category":"page"},{"location":"manual/constraints/","page":"Constraints","title":"Constraints","text":"This time, a vector of ConstraintIndex are returned.","category":"page"},{"location":"manual/constraints/","page":"Constraints","title":"Constraints","text":"Use supports_constraint to check if the model supports adding a constraint type.","category":"page"},{"location":"manual/constraints/","page":"Constraints","title":"Constraints","text":"julia> MOI.supports_constraint(\n model,\n MOI.VariableIndex,\n MOI.GreaterThan{Float64},\n )\ntrue","category":"page"},{"location":"manual/constraints/#Delete-a-constraint","page":"Constraints","title":"Delete a constraint","text":"","category":"section"},{"location":"manual/constraints/","page":"Constraints","title":"Constraints","text":"Use delete to delete a constraint.","category":"page"},{"location":"manual/constraints/","page":"Constraints","title":"Constraints","text":"julia> MOI.delete(model, c)\n\njulia> MOI.is_valid(model, c)\nfalse","category":"page"},{"location":"manual/constraints/#Constraint-attributes","page":"Constraints","title":"Constraint attributes","text":"","category":"section"},{"location":"manual/constraints/","page":"Constraints","title":"Constraints","text":"The following attributes are available for constraints:","category":"page"},{"location":"manual/constraints/","page":"Constraints","title":"Constraints","text":"ConstraintName\nConstraintPrimalStart\nConstraintDualStart\nConstraintPrimal\nConstraintDual\nConstraintBasisStatus\nConstraintFunction\nCanonicalConstraintFunction\nConstraintSet","category":"page"},{"location":"manual/constraints/","page":"Constraints","title":"Constraints","text":"Get and set these attributes using get and set.","category":"page"},{"location":"manual/constraints/","page":"Constraints","title":"Constraints","text":"julia> MOI.set(model, MOI.ConstraintName(), c, \"con_c\")\n\njulia> MOI.get(model, MOI.ConstraintName(), c)\n\"con_c\"","category":"page"},{"location":"manual/constraints/#Constraints-by-function-set-pairs","page":"Constraints","title":"Constraints by function-set pairs","text":"","category":"section"},{"location":"manual/constraints/","page":"Constraints","title":"Constraints","text":"Below is a list of common constraint types and how they are represented as function-set pairs in MOI. In the notation below, x is a vector of decision variables, x_i is a scalar decision variable, alpha beta are scalar constants, a b are constant vectors, A is a constant matrix and mathbbR_+ (resp. mathbbR_-) is the set of non-negative (resp. non-positive) real numbers.","category":"page"},{"location":"manual/constraints/#Linear-constraints","page":"Constraints","title":"Linear constraints","text":"","category":"section"},{"location":"manual/constraints/","page":"Constraints","title":"Constraints","text":"Mathematical Constraint MOI Function MOI Set\na^Tx le beta ScalarAffineFunction LessThan\na^Tx ge alpha ScalarAffineFunction GreaterThan\na^Tx = beta ScalarAffineFunction EqualTo\nalpha le a^Tx le beta ScalarAffineFunction Interval\nx_i le beta VariableIndex LessThan\nx_i ge alpha VariableIndex GreaterThan\nx_i = beta VariableIndex EqualTo\nalpha le x_i le beta VariableIndex Interval\nAx + b in mathbbR_+^n VectorAffineFunction Nonnegatives\nAx + b in mathbbR_-^n VectorAffineFunction Nonpositives\nAx + b = 0 VectorAffineFunction Zeros","category":"page"},{"location":"manual/constraints/","page":"Constraints","title":"Constraints","text":"By convention, solvers are not expected to support nonzero constant terms in the ScalarAffineFunctions the first four rows of the preceding table because they are redundant with the parameters of the sets. For example, encode 2x + 1 le 2 as 2x le 1.","category":"page"},{"location":"manual/constraints/","page":"Constraints","title":"Constraints","text":"Constraints with VariableIndex in LessThan, GreaterThan, EqualTo, or Interval sets have a natural interpretation as variable bounds. As such, it is typically not natural to impose multiple lower- or upper-bounds on the same variable, and the solver interfaces will throw respectively LowerBoundAlreadySet or UpperBoundAlreadySet.","category":"page"},{"location":"manual/constraints/","page":"Constraints","title":"Constraints","text":"Moreover, adding two VariableIndex constraints on the same variable with the same set is impossible because they share the same index as it is the index of the variable, see ConstraintIndex.","category":"page"},{"location":"manual/constraints/","page":"Constraints","title":"Constraints","text":"It is natural, however, to impose upper- and lower-bounds separately as two different constraints on a single variable. The difference between imposing bounds by using a single Interval constraint and by using separate LessThan and GreaterThan constraints is that the latter will allow the solver to return separate dual multipliers for the two bounds, while the former will allow the solver to return only a single dual for the interval constraint.","category":"page"},{"location":"manual/constraints/#Conic-constraints","page":"Constraints","title":"Conic constraints","text":"","category":"section"},{"location":"manual/constraints/","page":"Constraints","title":"Constraints","text":"Mathematical Constraint MOI Function MOI Set\nlVert Ax + brVert_2 le c^Tx + d VectorAffineFunction SecondOrderCone\ny ge lVert x rVert_2 VectorOfVariables SecondOrderCone\n2yz ge lVert x rVert_2^2 yz ge 0 VectorOfVariables RotatedSecondOrderCone\n(a_1^Tx + b_1a_2^Tx + b_2a_3^Tx + b_3) in mathcalE VectorAffineFunction ExponentialCone\nA(x) in mathcalS_+ VectorAffineFunction PositiveSemidefiniteConeTriangle\nB(x) in mathcalS_+ VectorAffineFunction PositiveSemidefiniteConeSquare\nx in mathcalS_+ VectorOfVariables PositiveSemidefiniteConeTriangle\nx in mathcalS_+ VectorOfVariables PositiveSemidefiniteConeSquare","category":"page"},{"location":"manual/constraints/","page":"Constraints","title":"Constraints","text":"where mathcalE is the exponential cone (see ExponentialCone), mathcalS_+ is the set of positive semidefinite symmetric matrices, A is an affine map that outputs symmetric matrices and B is an affine map that outputs square matrices.","category":"page"},{"location":"manual/constraints/#Quadratic-constraints","page":"Constraints","title":"Quadratic constraints","text":"","category":"section"},{"location":"manual/constraints/","page":"Constraints","title":"Constraints","text":"Mathematical Constraint MOI Function MOI Set\nfrac12x^TQx + a^Tx + b ge 0 ScalarQuadraticFunction GreaterThan\nfrac12x^TQx + a^Tx + b le 0 ScalarQuadraticFunction LessThan\nfrac12x^TQx + a^Tx + b = 0 ScalarQuadraticFunction EqualTo\nBilinear matrix inequality VectorQuadraticFunction PositiveSemidefiniteCone...","category":"page"},{"location":"manual/constraints/","page":"Constraints","title":"Constraints","text":"note: Note\nFor more details on the internal format of the quadratic functions see ScalarQuadraticFunction or VectorQuadraticFunction.","category":"page"},{"location":"manual/constraints/#Discrete-and-logical-constraints","page":"Constraints","title":"Discrete and logical constraints","text":"","category":"section"},{"location":"manual/constraints/","page":"Constraints","title":"Constraints","text":"Mathematical Constraint MOI Function MOI Set\nx_i in mathbbZ VariableIndex Integer\nx_i in 01 VariableIndex ZeroOne\nx_i in 0 cup lu VariableIndex Semicontinuous\nx_i in 0 cup ll+1ldotsu-1u VariableIndex Semiinteger\nAt most one component of x can be nonzero VectorOfVariables SOS1\nAt most two components of x can be nonzero, and if so they must be adjacent components VectorOfVariables SOS2\ny = 1 implies a^T x in S VectorAffineFunction Indicator","category":"page"},{"location":"manual/constraints/#JuMP-mapping","page":"Constraints","title":"JuMP mapping","text":"","category":"section"},{"location":"manual/constraints/","page":"Constraints","title":"Constraints","text":"The following bullet points show examples of how JuMP constraints are translated into MOI function-set pairs:","category":"page"},{"location":"manual/constraints/","page":"Constraints","title":"Constraints","text":"@constraint(m, 2x + y <= 10) becomes ScalarAffineFunction-in-LessThan\n@constraint(m, 2x + y >= 10) becomes ScalarAffineFunction-in-GreaterThan\n@constraint(m, 2x + y == 10) becomes ScalarAffineFunction-in-EqualTo\n@constraint(m, 0 <= 2x + y <= 10) becomes ScalarAffineFunction-in-Interval\n@constraint(m, 2x + y in ArbitrarySet()) becomes ScalarAffineFunction-in-ArbitrarySet.","category":"page"},{"location":"manual/constraints/","page":"Constraints","title":"Constraints","text":"Variable bounds are handled in a similar fashion:","category":"page"},{"location":"manual/constraints/","page":"Constraints","title":"Constraints","text":"@variable(m, x <= 1) becomes VariableIndex-in-LessThan\n@variable(m, x >= 1) becomes VariableIndex-in-GreaterThan","category":"page"},{"location":"manual/constraints/","page":"Constraints","title":"Constraints","text":"One notable difference is that a variable with an upper and lower bound is translated into two constraints, rather than an interval, that is:","category":"page"},{"location":"manual/constraints/","page":"Constraints","title":"Constraints","text":"@variable(m, 0 <= x <= 1) becomes VariableIndex-in-LessThan and VariableIndex-in-GreaterThan.","category":"page"},{"location":"reference/nonlinear/","page":"Nonlinear programming","title":"Nonlinear programming","text":"CurrentModule = MathOptInterface\nDocTestSetup = quote\n import MathOptInterface as MOI\nend\nDocTestFilters = [r\"MathOptInterface|MOI\"]","category":"page"},{"location":"reference/nonlinear/#Nonlinear-programming","page":"Nonlinear programming","title":"Nonlinear programming","text":"","category":"section"},{"location":"reference/nonlinear/#Types","page":"Nonlinear programming","title":"Types","text":"","category":"section"},{"location":"reference/nonlinear/","page":"Nonlinear programming","title":"Nonlinear programming","text":"AbstractNLPEvaluator\nNLPBoundsPair\nNLPBlockData","category":"page"},{"location":"reference/nonlinear/#MathOptInterface.AbstractNLPEvaluator","page":"Nonlinear programming","title":"MathOptInterface.AbstractNLPEvaluator","text":"AbstractNLPEvaluator\n\nAbstract supertype for the callback object that is used to query function values, derivatives, and expression graphs.\n\nIt is used in NLPBlockData.\n\n\n\n\n\n","category":"type"},{"location":"reference/nonlinear/#MathOptInterface.NLPBoundsPair","page":"Nonlinear programming","title":"MathOptInterface.NLPBoundsPair","text":"NLPBoundsPair(lower::Float64, upper::Float64)\n\nA struct holding a pair of lower and upper bounds.\n\n-Inf and Inf can be used to indicate no lower or upper bound, respectively.\n\n\n\n\n\n","category":"type"},{"location":"reference/nonlinear/#MathOptInterface.NLPBlockData","page":"Nonlinear programming","title":"MathOptInterface.NLPBlockData","text":"struct NLPBlockData\n constraint_bounds::Vector{NLPBoundsPair}\n evaluator::AbstractNLPEvaluator\n has_objective::Bool\nend\n\nA struct encoding a set of nonlinear constraints of the form lb le g(x) le ub and, if has_objective == true, a nonlinear objective function f(x).\n\nNonlinear objectives override any objective set by using the ObjectiveFunction attribute.\n\nThe evaluator is a callback object that is used to query function values, derivatives, and expression graphs. If has_objective == false, then it is an error to query properties of the objective function, and in Hessian-of-the-Lagrangian queries, σ must be set to zero.\n\nnote: Note\nThroughout the evaluator, all variables are ordered according to ListOfVariableIndices. Hence, MOI copies of nonlinear problems must not re-order variables.\n\n\n\n\n\n","category":"type"},{"location":"reference/nonlinear/#Attributes","page":"Nonlinear programming","title":"Attributes","text":"","category":"section"},{"location":"reference/nonlinear/","page":"Nonlinear programming","title":"Nonlinear programming","text":"NLPBlock\nNLPBlockDual\nNLPBlockDualStart","category":"page"},{"location":"reference/nonlinear/#MathOptInterface.NLPBlock","page":"Nonlinear programming","title":"MathOptInterface.NLPBlock","text":"NLPBlock()\n\nAn AbstractModelAttribute that stores an NLPBlockData, representing a set of nonlinear constraints, and optionally a nonlinear objective.\n\n\n\n\n\n","category":"type"},{"location":"reference/nonlinear/#MathOptInterface.NLPBlockDual","page":"Nonlinear programming","title":"MathOptInterface.NLPBlockDual","text":"NLPBlockDual(result_index::Int = 1)\n\nAn AbstractModelAttribute for the Lagrange multipliers on the constraints from the NLPBlock in result result_index.\n\nIf result_index is omitted, it is 1 by default.\n\n\n\n\n\n","category":"type"},{"location":"reference/nonlinear/#MathOptInterface.NLPBlockDualStart","page":"Nonlinear programming","title":"MathOptInterface.NLPBlockDualStart","text":"NLPBlockDualStart()\n\nAn AbstractModelAttribute for the initial assignment of the Lagrange multipliers on the constraints from the NLPBlock that the solver may use to warm-start the solve.\n\n\n\n\n\n","category":"type"},{"location":"reference/nonlinear/#Functions","page":"Nonlinear programming","title":"Functions","text":"","category":"section"},{"location":"reference/nonlinear/","page":"Nonlinear programming","title":"Nonlinear programming","text":"initialize\nfeatures_available\neval_objective\neval_constraint\neval_objective_gradient\njacobian_structure\neval_constraint_gradient\nconstraint_gradient_structure\neval_constraint_jacobian\neval_constraint_jacobian_product\neval_constraint_jacobian_transpose_product\nhessian_lagrangian_structure\nhessian_objective_structure\nhessian_constraint_structure\neval_hessian_objective\neval_hessian_constraint\neval_hessian_lagrangian\neval_hessian_lagrangian_product\nobjective_expr\nconstraint_expr","category":"page"},{"location":"reference/nonlinear/#MathOptInterface.initialize","page":"Nonlinear programming","title":"MathOptInterface.initialize","text":"initialize(\n d::AbstractNLPEvaluator,\n requested_features::Vector{Symbol},\n)::Nothing\n\nInitialize d with the set of features in requested_features. Check features_available before calling initialize to see what features are supported by d.\n\nwarning: Warning\nThis method must be called before any other methods.\n\nFeatures\n\nThe following features are defined:\n\n:Grad: enables eval_objective_gradient\n:Jac: enables eval_constraint_jacobian\n:JacVec: enables eval_constraint_jacobian_product and eval_constraint_jacobian_transpose_product\n:Hess: enables eval_hessian_lagrangian\n:HessVec: enables eval_hessian_lagrangian_product\n:ExprGraph: enables objective_expr and constraint_expr.\n\nIn all cases, including when requested_features is empty, eval_objective and eval_constraint are supported.\n\nExamples\n\nMOI.initialize(d, Symbol[])\nMOI.initialize(d, [:ExprGraph])\nMOI.initialize(d, MOI.features_available(d))\n\n\n\n\n\n","category":"function"},{"location":"reference/nonlinear/#MathOptInterface.features_available","page":"Nonlinear programming","title":"MathOptInterface.features_available","text":"features_available(d::AbstractNLPEvaluator)::Vector{Symbol}\n\nReturns the subset of features available for this problem instance.\n\nSee initialize for the list of defined features.\n\n\n\n\n\n","category":"function"},{"location":"reference/nonlinear/#MathOptInterface.eval_objective","page":"Nonlinear programming","title":"MathOptInterface.eval_objective","text":"eval_objective(d::AbstractNLPEvaluator, x::AbstractVector{T})::T where {T}\n\nEvaluate the objective f(x), returning a scalar value.\n\n\n\n\n\n","category":"function"},{"location":"reference/nonlinear/#MathOptInterface.eval_constraint","page":"Nonlinear programming","title":"MathOptInterface.eval_constraint","text":"eval_constraint(d::AbstractNLPEvaluator,\n g::AbstractVector{T},\n x::AbstractVector{T},\n)::Nothing where {T}\n\nGiven a set of vector-valued constraints l le g(x) le u, evaluate the constraint function g(x), storing the result in the vector g.\n\nImplementation notes\n\nWhen implementing this method, you must not assume that g is Vector{Float64}, but you may assume that it supports setindex! and length. For example, it may be the view of a vector.\n\n\n\n\n\n","category":"function"},{"location":"reference/nonlinear/#MathOptInterface.eval_objective_gradient","page":"Nonlinear programming","title":"MathOptInterface.eval_objective_gradient","text":"eval_objective_gradient(\n d::AbstractNLPEvaluator,\n grad::AbstractVector{T},\n x::AbstractVector{T},\n)::Nothing where {T}\n\nEvaluate the gradient of the objective function grad = nabla f(x) as a dense vector, storing the result in the vector grad.\n\nImplementation notes\n\nWhen implementing this method, you must not assume that grad is Vector{Float64}, but you may assume that it supports setindex! and length. For example, it may be the view of a vector.\n\n\n\n\n\n","category":"function"},{"location":"reference/nonlinear/#MathOptInterface.jacobian_structure","page":"Nonlinear programming","title":"MathOptInterface.jacobian_structure","text":"jacobian_structure(d::AbstractNLPEvaluator)::Vector{Tuple{Int64,Int64}}\n\nReturns a vector of tuples, (row, column), where each indicates the position of a structurally nonzero element in the Jacobian matrix: J_g(x) = left beginarrayc nabla g_1(x) nabla g_2(x) vdots nabla g_m(x) endarrayright where g_i is the itextth component of the nonlinear constraints g(x).\n\nThe indices are not required to be sorted and can contain duplicates, in which case the solver should combine the corresponding elements by adding them together.\n\nThe sparsity structure is assumed to be independent of the point x.\n\n\n\n\n\n","category":"function"},{"location":"reference/nonlinear/#MathOptInterface.eval_constraint_gradient","page":"Nonlinear programming","title":"MathOptInterface.eval_constraint_gradient","text":"eval_constraint_gradient(\n d::AbstractNLPEvaluator,\n ∇g::AbstractVector{T},\n x::AbstractVector{T},\n i::Int,\n)::Nothing where {T}\n\nEvaluate the gradient of constraint i, nabla g_i(x), and store the non-zero values in ∇g, corresponding to the structure returned by constraint_gradient_structure.\n\nImplementation notes\n\nWhen implementing this method, you must not assume that ∇g is Vector{Float64}, but you may assume that it supports setindex! and length. For example, it may be the view of a vector.\n\n\n\n\n\n","category":"function"},{"location":"reference/nonlinear/#MathOptInterface.constraint_gradient_structure","page":"Nonlinear programming","title":"MathOptInterface.constraint_gradient_structure","text":"constraint_gradient_structure(d::AbstractNLPEvaluator, i::Int)::Vector{Int64}\n\nReturns a vector of indices, where each element indicates the position of a structurally nonzero element in the gradient of constraint nabla g_i(x).\n\nThe indices are not required to be sorted and can contain duplicates, in which case the solver should combine the corresponding elements by adding them together.\n\nThe sparsity structure is assumed to be independent of the point x.\n\n\n\n\n\n","category":"function"},{"location":"reference/nonlinear/#MathOptInterface.eval_constraint_jacobian","page":"Nonlinear programming","title":"MathOptInterface.eval_constraint_jacobian","text":"eval_constraint_jacobian(d::AbstractNLPEvaluator,\n J::AbstractVector{T},\n x::AbstractVector{T},\n)::Nothing where {T}\n\nEvaluates the sparse Jacobian matrix J_g(x) = left beginarrayc nabla g_1(x) nabla g_2(x) vdots nabla g_m(x) endarrayright.\n\nThe result is stored in the vector J in the same order as the indices returned by jacobian_structure.\n\nImplementation notes\n\nWhen implementing this method, you must not assume that J is Vector{Float64}, but you may assume that it supports setindex! and length. For example, it may be the view of a vector.\n\n\n\n\n\n","category":"function"},{"location":"reference/nonlinear/#MathOptInterface.eval_constraint_jacobian_product","page":"Nonlinear programming","title":"MathOptInterface.eval_constraint_jacobian_product","text":"eval_constraint_jacobian_product(\n d::AbstractNLPEvaluator,\n y::AbstractVector{T},\n x::AbstractVector{T},\n w::AbstractVector{T},\n)::Nothing where {T}\n\nComputes the Jacobian-vector product y = J_g(x)w, storing the result in the vector y.\n\nThe vectors have dimensions such that length(w) == length(x), and length(y) is the number of nonlinear constraints.\n\nImplementation notes\n\nWhen implementing this method, you must not assume that y is Vector{Float64}, but you may assume that it supports setindex! and length. For example, it may be the view of a vector.\n\n\n\n\n\n","category":"function"},{"location":"reference/nonlinear/#MathOptInterface.eval_constraint_jacobian_transpose_product","page":"Nonlinear programming","title":"MathOptInterface.eval_constraint_jacobian_transpose_product","text":"eval_constraint_jacobian_transpose_product(\n d::AbstractNLPEvaluator,\n y::AbstractVector{T},\n x::AbstractVector{T},\n w::AbstractVector{T},\n)::Nothing where {T}\n\nComputes the Jacobian-transpose-vector product y = J_g(x)^Tw, storing the result in the vector y.\n\nThe vectors have dimensions such that length(y) == length(x), and length(w) is the number of nonlinear constraints.\n\nImplementation notes\n\nWhen implementing this method, you must not assume that y is Vector{Float64}, but you may assume that it supports setindex! and length. For example, it may be the view of a vector.\n\n\n\n\n\n","category":"function"},{"location":"reference/nonlinear/#MathOptInterface.hessian_lagrangian_structure","page":"Nonlinear programming","title":"MathOptInterface.hessian_lagrangian_structure","text":"hessian_lagrangian_structure(\n d::AbstractNLPEvaluator,\n)::Vector{Tuple{Int64,Int64}}\n\nReturns a vector of tuples, (row, column), where each indicates the position of a structurally nonzero element in the Hessian-of-the-Lagrangian matrix: nabla^2 f(x) + sum_i=1^m nabla^2 g_i(x).\n\nThe indices are not required to be sorted and can contain duplicates, in which case the solver should combine the corresponding elements by adding them together.\n\nAny mix of lower and upper-triangular indices is valid. Elements (i,j) and (j,i), if both present, should be treated as duplicates.\n\nThe sparsity structure is assumed to be independent of the point x.\n\n\n\n\n\n","category":"function"},{"location":"reference/nonlinear/#MathOptInterface.hessian_objective_structure","page":"Nonlinear programming","title":"MathOptInterface.hessian_objective_structure","text":"hessian_objective_structure(\n d::AbstractNLPEvaluator,\n)::Vector{Tuple{Int64,Int64}}\n\nReturns a vector of tuples, (row, column), where each indicates the position of a structurally nonzero element in the Hessian matrix: nabla^2 f(x).\n\nThe indices are not required to be sorted and can contain duplicates, in which case the solver should combine the corresponding elements by adding them together.\n\nAny mix of lower and upper-triangular indices is valid. Elements (i,j) and (j,i), if both present, should be treated as duplicates.\n\nThe sparsity structure is assumed to be independent of the point x.\n\n\n\n\n\n","category":"function"},{"location":"reference/nonlinear/#MathOptInterface.hessian_constraint_structure","page":"Nonlinear programming","title":"MathOptInterface.hessian_constraint_structure","text":"hessian_constraint_structure(\n d::AbstractNLPEvaluator,\n i::Int64,\n)::Vector{Tuple{Int64,Int64}}\n\nReturns a vector of tuples, (row, column), where each indicates the position of a structurally nonzero element in the Hessian matrix: nabla^2 g_i(x).\n\nThe indices are not required to be sorted and can contain duplicates, in which case the solver should combine the corresponding elements by adding them together.\n\nAny mix of lower and upper-triangular indices is valid. Elements (i,j) and (j,i), if both present, should be treated as duplicates.\n\nThe sparsity structure is assumed to be independent of the point x.\n\n\n\n\n\n","category":"function"},{"location":"reference/nonlinear/#MathOptInterface.eval_hessian_objective","page":"Nonlinear programming","title":"MathOptInterface.eval_hessian_objective","text":"eval_hessian_objective(\n d::AbstractNLPEvaluator,\n H::AbstractVector{T},\n x::AbstractVector{T},\n)::Nothing where {T}\n\nThis function computes the sparse Hessian matrix: nabla^2 f(x), storing the result in the vector H in the same order as the indices returned by hessian_objective_structure.\n\nImplementation notes\n\nWhen implementing this method, you must not assume that H is Vector{Float64}, but you may assume that it supports setindex! and length. For example, it may be the view of a vector.\n\n\n\n\n\n","category":"function"},{"location":"reference/nonlinear/#MathOptInterface.eval_hessian_constraint","page":"Nonlinear programming","title":"MathOptInterface.eval_hessian_constraint","text":"eval_hessian_constraint(\n d::AbstractNLPEvaluator,\n H::AbstractVector{T},\n x::AbstractVector{T},\n i::Int64,\n)::Nothing where {T}\n\nThis function computes the sparse Hessian matrix: nabla^2 g_i(x), storing the result in the vector H in the same order as the indices returned by hessian_constraint_structure.\n\nImplementation notes\n\nWhen implementing this method, you must not assume that H is Vector{Float64}, but you may assume that it supports setindex! and length. For example, it may be the view of a vector.\n\n\n\n\n\n","category":"function"},{"location":"reference/nonlinear/#MathOptInterface.eval_hessian_lagrangian","page":"Nonlinear programming","title":"MathOptInterface.eval_hessian_lagrangian","text":"eval_hessian_lagrangian(\n d::AbstractNLPEvaluator,\n H::AbstractVector{T},\n x::AbstractVector{T},\n σ::T,\n μ::AbstractVector{T},\n)::Nothing where {T}\n\nGiven scalar weight σ and vector of constraint weights μ, this function computes the sparse Hessian-of-the-Lagrangian matrix: sigmanabla^2 f(x) + sum_i=1^m mu_i nabla^2 g_i(x), storing the result in the vector H in the same order as the indices returned by hessian_lagrangian_structure.\n\nImplementation notes\n\nWhen implementing this method, you must not assume that H is Vector{Float64}, but you may assume that it supports setindex! and length. For example, it may be the view of a vector.\n\n\n\n\n\n","category":"function"},{"location":"reference/nonlinear/#MathOptInterface.eval_hessian_lagrangian_product","page":"Nonlinear programming","title":"MathOptInterface.eval_hessian_lagrangian_product","text":"eval_hessian_lagrangian_product(\n d::AbstractNLPEvaluator,\n h::AbstractVector{T},\n x::AbstractVector{T},\n v::AbstractVector{T},\n σ::T,\n μ::AbstractVector{T},\n)::Nothing where {T}\n\nGiven scalar weight σ and vector of constraint weights μ, computes the Hessian-of-the-Lagrangian-vector product h = left(sigmanabla^2 f(x) + sum_i=1^m mu_i nabla^2 g_i(x)right)v, storing the result in the vector h.\n\nThe vectors have dimensions such that length(h) == length(x) == length(v).\n\nImplementation notes\n\nWhen implementing this method, you must not assume that h is Vector{Float64}, but you may assume that it supports setindex! and length. For example, it may be the view of a vector.\n\n\n\n\n\n","category":"function"},{"location":"reference/nonlinear/#MathOptInterface.objective_expr","page":"Nonlinear programming","title":"MathOptInterface.objective_expr","text":"objective_expr(d::AbstractNLPEvaluator)::Expr\n\nReturns a Julia Expr object representing the expression graph of the objective function.\n\nFormat\n\nThe expression has a number of limitations, compared with arbitrary Julia expressions:\n\nAll sums and products are flattened out as simple Expr(:+, ...) and Expr(:*, ...) objects.\nAll decision variables must be of the form Expr(:ref, :x, MOI.VariableIndex(i)), where i is the ith variable in ListOfVariableIndices.\nThere are currently no restrictions on recognized functions; typically these will be built-in Julia functions like ^, exp, log, cos, tan, sqrt, etc., but modeling interfaces may choose to extend these basic functions, or error if they encounter unsupported functions.\n\nExamples\n\nThe expression x_1+sin(x_2exp(x_3)) is represented as\n\n:(x[MOI.VariableIndex(1)] + sin(x[MOI.VariableIndex(2)] / exp(x[MOI.VariableIndex[3]])))\n\nor equivalently\n\nExpr(\n :call,\n :+,\n Expr(:ref, :x, MOI.VariableIndex(1)),\n Expr(\n :call,\n :/,\n Expr(:call, :sin, Expr(:ref, :x, MOI.VariableIndex(2))),\n Expr(:call, :exp, Expr(:ref, :x, MOI.VariableIndex(3))),\n ),\n)\n\n\n\n\n\n","category":"function"},{"location":"reference/nonlinear/#MathOptInterface.constraint_expr","page":"Nonlinear programming","title":"MathOptInterface.constraint_expr","text":"constraint_expr(d::AbstractNLPEvaluator, i::Integer)::Expr\n\nReturns a Julia Expr object representing the expression graph for the itextth nonlinear constraint.\n\nFormat\n\nThe format is the same as objective_expr, with an additional comparison operator indicating the sense of and bounds on the constraint.\n\nFor single-sided comparisons, the body of the constraint must be on the left-hand side, and the right-hand side must be a constant.\n\nFor double-sided comparisons (that is, l le f(x) le u), the body of the constraint must be in the middle, and the left- and right-hand sides must be constants.\n\nThe bounds on the constraints must match the NLPBoundsPairs passed to NLPBlockData.\n\nExamples\n\n:(x[MOI.VariableIndex(1)]^2 <= 1.0)\n:(x[MOI.VariableIndex(1)]^2 >= 2.0)\n:(x[MOI.VariableIndex(1)]^2 == 3.0)\n:(4.0 <= x[MOI.VariableIndex(1)]^2 <= 5.0)\n\n\n\n\n\n","category":"function"},{"location":"reference/standard_form/","page":"Standard form","title":"Standard form","text":"CurrentModule = MathOptInterface\nDocTestSetup = quote\n import MathOptInterface as MOI\nend\nDocTestFilters = [r\"MathOptInterface|MOI\"]","category":"page"},{"location":"reference/standard_form/#Standard-form","page":"Standard form","title":"Standard form","text":"","category":"section"},{"location":"reference/standard_form/#Functions","page":"Standard form","title":"Functions","text":"","category":"section"},{"location":"reference/standard_form/","page":"Standard form","title":"Standard form","text":"AbstractFunction\noutput_dimension\nconstant","category":"page"},{"location":"reference/standard_form/#MathOptInterface.AbstractFunction","page":"Standard form","title":"MathOptInterface.AbstractFunction","text":"AbstractFunction\n\nAbstract supertype for function objects.\n\nRequired methods\n\nAll functions must implement:\n\nBase.copy\nBase.isapprox\nconstant\n\nAbstract subtypes of AbstractFunction may require additional methods to be implemented.\n\n\n\n\n\n","category":"type"},{"location":"reference/standard_form/#MathOptInterface.output_dimension","page":"Standard form","title":"MathOptInterface.output_dimension","text":"output_dimension(f::AbstractFunction)\n\nReturn 1 if f is an AbstractScalarFunction, or the number of output components if f is an AbstractVectorFunction.\n\n\n\n\n\n","category":"function"},{"location":"reference/standard_form/#MathOptInterface.constant","page":"Standard form","title":"MathOptInterface.constant","text":"constant(f::AbstractFunction[, ::Type{T}]) where {T}\n\nReturns the constant term of a scalar-valued function, or the constant vector of a vector-valued function.\n\nIf f is untyped and T is provided, returns zero(T).\n\n\n\n\n\nconstant(set::Union{EqualTo,GreaterThan,LessThan,Parameter})\n\nReturns the constant term of the set set.\n\nExample\n\njulia> import MathOptInterface as MOI\n\njulia> MOI.constant(MOI.GreaterThan(1.0))\n1.0\n\njulia> MOI.constant(MOI.LessThan(2.5))\n2.5\n\njulia> MOI.constant(MOI.EqualTo(3))\n3\n\njulia> MOI.constant(MOI.Parameter(4.5))\n4.5\n\n\n\n\n\n","category":"function"},{"location":"reference/standard_form/#Scalar-functions","page":"Standard form","title":"Scalar functions","text":"","category":"section"},{"location":"reference/standard_form/","page":"Standard form","title":"Standard form","text":"AbstractScalarFunction\nVariableIndex\nScalarAffineTerm\nScalarAffineFunction\nScalarQuadraticTerm\nScalarQuadraticFunction\nScalarNonlinearFunction","category":"page"},{"location":"reference/standard_form/#MathOptInterface.AbstractScalarFunction","page":"Standard form","title":"MathOptInterface.AbstractScalarFunction","text":"abstract type AbstractScalarFunction <: AbstractFunction\n\nAbstract supertype for scalar-valued AbstractFunctions.\n\n\n\n\n\n","category":"type"},{"location":"reference/standard_form/#MathOptInterface.VariableIndex","page":"Standard form","title":"MathOptInterface.VariableIndex","text":"VariableIndex\n\nA type-safe wrapper for Int64 for use in referencing variables in a model. To allow for deletion, indices need not be consecutive.\n\n\n\n\n\n","category":"type"},{"location":"reference/standard_form/#MathOptInterface.ScalarAffineTerm","page":"Standard form","title":"MathOptInterface.ScalarAffineTerm","text":"ScalarAffineTerm{T}(coefficient::T, variable::VariableIndex) where {T}\n\nRepresents the scalar-valued term coefficient * variable.\n\nExample\n\njulia> import MathOptInterface as MOI\n\njulia> x = MOI.VariableIndex(1)\nMOI.VariableIndex(1)\n\njulia> MOI.ScalarAffineTerm(2.0, x)\nMathOptInterface.ScalarAffineTerm{Float64}(2.0, MOI.VariableIndex(1))\n\n\n\n\n\n","category":"type"},{"location":"reference/standard_form/#MathOptInterface.ScalarAffineFunction","page":"Standard form","title":"MathOptInterface.ScalarAffineFunction","text":"ScalarAffineFunction{T}(terms::ScalarAffineTerm{T}, constant::T) where {T}\n\nRepresents the scalar-valued affine function a^top x + b, where:\n\na^top x is represented by the vector of ScalarAffineTerms\nb is a scalar constant::T\n\nDuplicates\n\nDuplicate variable indices in terms are accepted, and the corresponding coefficients are summed together.\n\nExample\n\njulia> import MathOptInterface as MOI\n\njulia> x = MOI.VariableIndex(1)\nMOI.VariableIndex(1)\n\njulia> terms = [MOI.ScalarAffineTerm(2.0, x), MOI.ScalarAffineTerm(3.0, x)]\n2-element Vector{MathOptInterface.ScalarAffineTerm{Float64}}:\n MathOptInterface.ScalarAffineTerm{Float64}(2.0, MOI.VariableIndex(1))\n MathOptInterface.ScalarAffineTerm{Float64}(3.0, MOI.VariableIndex(1))\n\njulia> f = MOI.ScalarAffineFunction(terms, 4.0)\n4.0 + 2.0 MOI.VariableIndex(1) + 3.0 MOI.VariableIndex(1)\n\n\n\n\n\n","category":"type"},{"location":"reference/standard_form/#MathOptInterface.ScalarQuadraticTerm","page":"Standard form","title":"MathOptInterface.ScalarQuadraticTerm","text":"ScalarQuadraticTerm{T}(\n coefficient::T,\n variable_1::VariableIndex,\n variable_2::VariableIndex,\n) where {T}\n\nRepresents the scalar-valued term c x_i x_j where c is coefficient, x_i is variable_1 and x_j is variable_2.\n\nExample\n\njulia> import MathOptInterface as MOI\n\njulia> x = MOI.VariableIndex(1)\nMOI.VariableIndex(1)\n\njulia> MOI.ScalarQuadraticTerm(2.0, x, x)\nMathOptInterface.ScalarQuadraticTerm{Float64}(2.0, MOI.VariableIndex(1), MOI.VariableIndex(1))\n\n\n\n\n\n","category":"type"},{"location":"reference/standard_form/#MathOptInterface.ScalarQuadraticFunction","page":"Standard form","title":"MathOptInterface.ScalarQuadraticFunction","text":"ScalarQuadraticFunction{T}(\n quadratic_terms::Vector{ScalarQuadraticTerm{T}},\n affine_terms::Vector{ScalarAffineTerm{T}},\n constant::T,\n) wher {T}\n\nThe scalar-valued quadratic function frac12x^top Q x + a^top x + b, where:\n\nQ is the symmetric matrix given by the vector of ScalarQuadraticTerms\na^top x is a sparse vector given by the vector of ScalarAffineTerms\nb is the scalar constant::T.\n\nDuplicates\n\nDuplicate indices in quadratic_terms or affine_terms are accepted, and the corresponding coefficients are summed together.\n\nIn quadratic_terms, \"mirrored\" indices, (q, r) and (r, q) where r and q are VariableIndexes, are considered duplicates; only one needs to be specified.\n\nThe 0.5 factor\n\nCoupled with the interpretation of mirrored indices, the 0.5 factor in front of the Q matrix is a common source of bugs.\n\nAs a rule, to represent a * x^2 + b * x * y:\n\nThe coefficient a in front of squared variables (diagonal elements in Q) must be doubled when creating a ScalarQuadraticTerm\nThe coefficient b in front of off-diagonal elements in Q should be left as b, be cause the mirrored index b * y * x will be implicitly added.\n\nExample\n\nTo represent the function f(x y) = 2 * x^2 + 3 * x * y + 4 * x + 5, do:\n\njulia> import MathOptInterface as MOI\n\njulia> x = MOI.VariableIndex(1);\n\njulia> y = MOI.VariableIndex(2);\n\njulia> constant = 5.0;\n\njulia> affine_terms = [MOI.ScalarAffineTerm(4.0, x)];\n\njulia> quadratic_terms = [\n MOI.ScalarQuadraticTerm(4.0, x, x), # Note the changed coefficient\n MOI.ScalarQuadraticTerm(3.0, x, y),\n ]\n2-element Vector{MathOptInterface.ScalarQuadraticTerm{Float64}}:\n MathOptInterface.ScalarQuadraticTerm{Float64}(4.0, MOI.VariableIndex(1), MOI.VariableIndex(1))\n MathOptInterface.ScalarQuadraticTerm{Float64}(3.0, MOI.VariableIndex(1), MOI.VariableIndex(2))\n\njulia> f = MOI.ScalarQuadraticFunction(quadratic_terms, affine_terms, constant)\n5.0 + 4.0 MOI.VariableIndex(1) + 2.0 MOI.VariableIndex(1)² + 3.0 MOI.VariableIndex(1)*MOI.VariableIndex(2)\n\n\n\n\n\n","category":"type"},{"location":"reference/standard_form/#MathOptInterface.ScalarNonlinearFunction","page":"Standard form","title":"MathOptInterface.ScalarNonlinearFunction","text":"ScalarNonlinearFunction(head::Symbol, args::Vector{Any})\n\nThe scalar-valued nonlinear function head(args...), represented as a symbolic expression tree, with the call operator head and ordered arguments in args.\n\nhead\n\nThe head::Symbol must be an operator supported by the model.\n\nThe default list of supported univariate operators is given by:\n\nNonlinear.DEFAULT_UNIVARIATE_OPERATORS\n\nand the default list of supported multivariate operators is given by:\n\nNonlinear.DEFAULT_MULTIVARIATE_OPERATORS\n\nAdditional operators can be registered by setting a UserDefinedFunction attribute.\n\nSee the full list of operators supported by a ModelLike by querying ListOfSupportedNonlinearOperators.\n\nargs\n\nThe vector args contains the arguments to the nonlinear function. If the operator is univariate, it must contain one element. Otherwise, it may contain multiple elements.\n\nEach element must be one of the following:\n\nA constant value of type T<:Real\nA VariableIndex\nA ScalarAffineFunction\nA ScalarQuadraticFunction\nA ScalarNonlinearFunction\n\nUnsupported operators\n\nIf the optimizer does not support head, an UnsupportedNonlinearOperator error will be thrown.\n\nThere is no guarantee about when this error will be thrown; it may be thrown when the function is first added to the model, or it may be thrown when optimize! is called.\n\nExample\n\nTo represent the function f(x) = sin(x)^2, do:\n\njulia> import MathOptInterface as MOI\n\njulia> x = MOI.VariableIndex(1)\nMOI.VariableIndex(1)\n\njulia> MOI.ScalarNonlinearFunction(\n :^,\n Any[MOI.ScalarNonlinearFunction(:sin, Any[x]), 2],\n )\n^(sin(MOI.VariableIndex(1)), (2))\n\n\n\n\n\n","category":"type"},{"location":"reference/standard_form/#Vector-functions","page":"Standard form","title":"Vector functions","text":"","category":"section"},{"location":"reference/standard_form/","page":"Standard form","title":"Standard form","text":"AbstractVectorFunction\nVectorOfVariables\nVectorAffineTerm\nVectorAffineFunction\nVectorQuadraticTerm\nVectorQuadraticFunction\nVectorNonlinearFunction","category":"page"},{"location":"reference/standard_form/#MathOptInterface.AbstractVectorFunction","page":"Standard form","title":"MathOptInterface.AbstractVectorFunction","text":"abstract type AbstractVectorFunction <: AbstractFunction\n\nAbstract supertype for vector-valued AbstractFunctions.\n\nRequired methods\n\nAll subtypes of AbstractVectorFunction must implement:\n\noutput_dimension\n\n\n\n\n\n","category":"type"},{"location":"reference/standard_form/#MathOptInterface.VectorOfVariables","page":"Standard form","title":"MathOptInterface.VectorOfVariables","text":"VectorOfVariables(variables::Vector{VariableIndex}) <: AbstractVectorFunction\n\nThe vector-valued function f(x) = variables, where variables is a subset of VariableIndexes in the model.\n\nThe list of variables may contain duplicates.\n\nExample\n\njulia> import MathOptInterface as MOI\n\njulia> x = MOI.VariableIndex.(1:2)\n2-element Vector{MathOptInterface.VariableIndex}:\n MOI.VariableIndex(1)\n MOI.VariableIndex(2)\n\njulia> f = MOI.VectorOfVariables([x[1], x[2], x[1]])\n┌ ┐\n│MOI.VariableIndex(1)│\n│MOI.VariableIndex(2)│\n│MOI.VariableIndex(1)│\n└ ┘\n\njulia> MOI.output_dimension(f)\n3\n\n\n\n\n\n","category":"type"},{"location":"reference/standard_form/#MathOptInterface.VectorAffineTerm","page":"Standard form","title":"MathOptInterface.VectorAffineTerm","text":"VectorAffineTerm{T}(\n output_index::Int64,\n scalar_term::ScalarAffineTerm{T},\n) where {T}\n\nA VectorAffineTerm is a scalar_term that appears in the output_index row of the vector-valued VectorAffineFunction or VectorQuadraticFunction.\n\nExample\n\njulia> import MathOptInterface as MOI\n\njulia> x = MOI.VariableIndex(1);\n\njulia> MOI.VectorAffineTerm(Int64(2), MOI.ScalarAffineTerm(3.0, x))\nMathOptInterface.VectorAffineTerm{Float64}(2, MathOptInterface.ScalarAffineTerm{Float64}(3.0, MOI.VariableIndex(1)))\n\n\n\n\n\n","category":"type"},{"location":"reference/standard_form/#MathOptInterface.VectorAffineFunction","page":"Standard form","title":"MathOptInterface.VectorAffineFunction","text":"VectorAffineFunction{T}(\n terms::Vector{VectorAffineTerm{T}},\n constants::Vector{T},\n) where {T}\n\nThe vector-valued affine function A x + b, where:\n\nA x is the sparse matrix given by the vector of VectorAffineTerms\nb is the vector constants\n\nDuplicates\n\nDuplicate indices in the A are accepted, and the corresponding coefficients are summed together.\n\nExample\n\njulia> import MathOptInterface as MOI\n\njulia> x = MOI.VariableIndex(1);\n\njulia> terms = [\n MOI.VectorAffineTerm(Int64(1), MOI.ScalarAffineTerm(2.0, x)),\n MOI.VectorAffineTerm(Int64(2), MOI.ScalarAffineTerm(3.0, x)),\n ];\n\njulia> f = MOI.VectorAffineFunction(terms, [4.0, 5.0])\n┌ ┐\n│4.0 + 2.0 MOI.VariableIndex(1)│\n│5.0 + 3.0 MOI.VariableIndex(1)│\n└ ┘\n\njulia> MOI.output_dimension(f)\n2\n\n\n\n\n\n","category":"type"},{"location":"reference/standard_form/#MathOptInterface.VectorQuadraticTerm","page":"Standard form","title":"MathOptInterface.VectorQuadraticTerm","text":"VectorQuadraticTerm{T}(\n output_index::Int64,\n scalar_term::ScalarQuadraticTerm{T},\n) where {T}\n\nA VectorQuadraticTerm is a ScalarQuadraticTerm scalar_term that appears in the output_index row of the vector-valued VectorQuadraticFunction.\n\nExample\n\njulia> import MathOptInterface as MOI\n\njulia> x = MOI.VariableIndex(1);\n\njulia> MOI.VectorQuadraticTerm(Int64(2), MOI.ScalarQuadraticTerm(3.0, x, x))\nMathOptInterface.VectorQuadraticTerm{Float64}(2, MathOptInterface.ScalarQuadraticTerm{Float64}(3.0, MOI.VariableIndex(1), MOI.VariableIndex(1)))\n\n\n\n\n\n","category":"type"},{"location":"reference/standard_form/#MathOptInterface.VectorQuadraticFunction","page":"Standard form","title":"MathOptInterface.VectorQuadraticFunction","text":"VectorQuadraticFunction{T}(\n quadratic_terms::Vector{VectorQuadraticTerm{T}},\n affine_terms::Vector{VectorAffineTerm{T}},\n constants::Vector{T},\n) where {T}\n\nThe vector-valued quadratic function with ith component (\"output index\") defined as frac12x^top Q_i x + a_i^top x + b_i, where:\n\nfrac12x^top Q_i x is the symmetric matrix given by the VectorQuadraticTerm elements in quadratic_terms with output_index == i\na_i^top x is the sparse vector given by the VectorAffineTerm elements in affine_terms with output_index == i\nb_i is a scalar given by constants[i]\n\nDuplicates\n\nDuplicate indices in quadratic_terms and affine_terms with the same output_index are handled in the same manner as duplicates in ScalarQuadraticFunction.\n\nExample\n\njulia> import MathOptInterface as MOI\n\njulia> x = MOI.VariableIndex(1);\n\njulia> y = MOI.VariableIndex(2);\n\njulia> constants = [4.0, 5.0];\n\njulia> affine_terms = [\n MOI.VectorAffineTerm(Int64(1), MOI.ScalarAffineTerm(2.0, x)),\n MOI.VectorAffineTerm(Int64(2), MOI.ScalarAffineTerm(3.0, x)),\n ];\n\njulia> quad_terms = [\n MOI.VectorQuadraticTerm(Int64(1), MOI.ScalarQuadraticTerm(2.0, x, x)),\n MOI.VectorQuadraticTerm(Int64(2), MOI.ScalarQuadraticTerm(3.0, x, y)),\n ];\n\njulia> f = MOI.VectorQuadraticFunction(quad_terms, affine_terms, constants)\n┌ ┐\n│4.0 + 2.0 MOI.VariableIndex(1) + 1.0 MOI.VariableIndex(1)² │\n│5.0 + 3.0 MOI.VariableIndex(1) + 3.0 MOI.VariableIndex(1)*MOI.VariableIndex(2)│\n└ ┘\n\njulia> MOI.output_dimension(f)\n2\n\n\n\n\n\n","category":"type"},{"location":"reference/standard_form/#MathOptInterface.VectorNonlinearFunction","page":"Standard form","title":"MathOptInterface.VectorNonlinearFunction","text":"VectorNonlinearFunction(args::Vector{ScalarNonlinearFunction})\n\nThe vector-valued nonlinear function composed of a vector of ScalarNonlinearFunction.\n\nargs\n\nThe vector args contains the scalar elements of the nonlinear function. Each element must be a ScalarNonlinearFunction, but if you pass a Vector{Any}, the elements can be automatically converted from one of the following:\n\nA constant value of type T<:Real\nA VariableIndex\nA ScalarAffineFunction\nA ScalarQuadraticFunction\nA ScalarNonlinearFunction\n\nExample\n\nTo represent the function f(x) = sin(x)^2 x, do:\n\njulia> import MathOptInterface as MOI\n\njulia> x = MOI.VariableIndex(1)\nMOI.VariableIndex(1)\n\njulia> g = MOI.ScalarNonlinearFunction(\n :^,\n Any[MOI.ScalarNonlinearFunction(:sin, Any[x]), 2.0],\n )\n^(sin(MOI.VariableIndex(1)), 2.0)\n\njulia> MOI.VectorNonlinearFunction([g, x])\n┌ ┐\n│^(sin(MOI.VariableIndex(1)), 2.0)│\n│+(MOI.VariableIndex(1)) │\n└ ┘\n\nNote the automatic conversion from x to +(x).\n\n\n\n\n\n","category":"type"},{"location":"reference/standard_form/#Sets","page":"Standard form","title":"Sets","text":"","category":"section"},{"location":"reference/standard_form/","page":"Standard form","title":"Standard form","text":"AbstractSet\nAbstractScalarSet\nAbstractVectorSet","category":"page"},{"location":"reference/standard_form/#MathOptInterface.AbstractSet","page":"Standard form","title":"MathOptInterface.AbstractSet","text":"AbstractSet\n\nAbstract supertype for set objects used to encode constraints.\n\nRequired methods\n\nFor sets of type S with isbitstype(S) == false, you must implement:\n\nBase.copy(set::S)\nBase.:(==)(x::S, y::S)\n\nSubtypes of AbstractSet such as AbstractScalarSet and AbstractVectorSet may prescribe additional required methods.\n\nOptional methods\n\nYou may optionally implement:\n\ndual_set\ndual_set_type\n\nNote for developers\n\nWhen creating a new set, the set struct must not contain any VariableIndex or ConstraintIndex objects.\n\n\n\n\n\n","category":"type"},{"location":"reference/standard_form/#MathOptInterface.AbstractScalarSet","page":"Standard form","title":"MathOptInterface.AbstractScalarSet","text":"AbstractScalarSet\n\nAbstract supertype for subsets of mathbbR.\n\n\n\n\n\n","category":"type"},{"location":"reference/standard_form/#MathOptInterface.AbstractVectorSet","page":"Standard form","title":"MathOptInterface.AbstractVectorSet","text":"AbstractVectorSet\n\nAbstract supertype for subsets of mathbbR^n for some n.\n\nRequired methods\n\nAll AbstractVectorSets of type S must implement:\n\ndimension, unless the dimension is stored in the set.dimension field\nUtilities.set_dot, unless the dot product between two vectors in the set is equivalent to LinearAlgebra.dot.\n\n\n\n\n\n","category":"type"},{"location":"reference/standard_form/#Utilities","page":"Standard form","title":"Utilities","text":"","category":"section"},{"location":"reference/standard_form/","page":"Standard form","title":"Standard form","text":"dimension\ndual_set\ndual_set_type\nconstant(s::EqualTo)\nsupports_dimension_update\nupdate_dimension","category":"page"},{"location":"reference/standard_form/#MathOptInterface.dimension","page":"Standard form","title":"MathOptInterface.dimension","text":"dimension(set::AbstractSet)\n\nReturn the output_dimension that an AbstractFunction should have to be used with the set set.\n\nExample\n\njulia> import MathOptInterface as MOI\n\njulia> MOI.dimension(MOI.Reals(4))\n4\n\njulia> MOI.dimension(MOI.LessThan(3.0))\n1\n\njulia> MOI.dimension(MOI.PositiveSemidefiniteConeTriangle(2))\n3\n\n\n\n\n\n","category":"function"},{"location":"reference/standard_form/#MathOptInterface.dual_set","page":"Standard form","title":"MathOptInterface.dual_set","text":"dual_set(set::AbstractSet)\n\nReturn the dual set of set, that is the dual cone of the set. This follows the definition of duality discussed in Duality.\n\nSee Dual cone for more information.\n\nIf the dual cone is not defined it returns an error.\n\nExample\n\njulia> import MathOptInterface as MOI\n\njulia> MOI.dual_set(MOI.Reals(4))\nMathOptInterface.Zeros(4)\n\njulia> MOI.dual_set(MOI.SecondOrderCone(5))\nMathOptInterface.SecondOrderCone(5)\n\njulia> MOI.dual_set(MOI.ExponentialCone())\nMathOptInterface.DualExponentialCone()\n\n\n\n\n\n","category":"function"},{"location":"reference/standard_form/#MathOptInterface.dual_set_type","page":"Standard form","title":"MathOptInterface.dual_set_type","text":"dual_set_type(S::Type{<:AbstractSet})\n\nReturn the type of dual set of sets of type S, as returned by dual_set. If the dual cone is not defined it returns an error.\n\nExample\n\njulia> import MathOptInterface as MOI\n\njulia> MOI.dual_set_type(MOI.Reals)\nMathOptInterface.Zeros\n\njulia> MOI.dual_set_type(MOI.SecondOrderCone)\nMathOptInterface.SecondOrderCone\n\njulia> MOI.dual_set_type(MOI.ExponentialCone)\nMathOptInterface.DualExponentialCone\n\n\n\n\n\n","category":"function"},{"location":"reference/standard_form/#MathOptInterface.constant-Tuple{MathOptInterface.EqualTo}","page":"Standard form","title":"MathOptInterface.constant","text":"constant(set::Union{EqualTo,GreaterThan,LessThan,Parameter})\n\nReturns the constant term of the set set.\n\nExample\n\njulia> import MathOptInterface as MOI\n\njulia> MOI.constant(MOI.GreaterThan(1.0))\n1.0\n\njulia> MOI.constant(MOI.LessThan(2.5))\n2.5\n\njulia> MOI.constant(MOI.EqualTo(3))\n3\n\njulia> MOI.constant(MOI.Parameter(4.5))\n4.5\n\n\n\n\n\n","category":"method"},{"location":"reference/standard_form/#MathOptInterface.supports_dimension_update","page":"Standard form","title":"MathOptInterface.supports_dimension_update","text":"supports_dimension_update(S::Type{<:MOI.AbstractVectorSet})\n\nReturn a Bool indicating whether the elimination of any dimension of n-dimensional sets of type S give an n-1-dimensional set S. By default, this function returns false so it should only be implemented for sets that supports dimension update.\n\nFor instance, supports_dimension_update(MOI.Nonnegatives) is true because the elimination of any dimension of the n-dimensional nonnegative orthant gives the n-1-dimensional nonnegative orthant. However supports_dimension_update(MOI.ExponentialCone) is false.\n\n\n\n\n\n","category":"function"},{"location":"reference/standard_form/#MathOptInterface.update_dimension","page":"Standard form","title":"MathOptInterface.update_dimension","text":"update_dimension(s::AbstractVectorSet, new_dim::Int)\n\nReturns a set with the dimension modified to new_dim.\n\n\n\n\n\n","category":"function"},{"location":"reference/standard_form/#Scalar-sets","page":"Standard form","title":"Scalar sets","text":"","category":"section"},{"location":"reference/standard_form/","page":"Standard form","title":"Standard form","text":"List of recognized scalar sets.","category":"page"},{"location":"reference/standard_form/","page":"Standard form","title":"Standard form","text":"GreaterThan\nLessThan\nEqualTo\nInterval\nInteger\nZeroOne\nSemicontinuous\nSemiinteger\nParameter","category":"page"},{"location":"reference/standard_form/#MathOptInterface.GreaterThan","page":"Standard form","title":"MathOptInterface.GreaterThan","text":"GreaterThan{T<:Real}(lower::T)\n\nThe set lower infty) subseteq mathbbR.\n\nExample\n\njulia> import MathOptInterface as MOI\n\njulia> model = MOI.Utilities.Model{Float64}()\nMOIU.Model{Float64}\n\njulia> x = MOI.add_variable(model)\nMOI.VariableIndex(1)\n\njulia> MOI.add_constraint(model, x, MOI.GreaterThan(0.0))\nMathOptInterface.ConstraintIndex{MathOptInterface.VariableIndex, MathOptInterface.GreaterThan{Float64}}(1)\n\n\n\n\n\n","category":"type"},{"location":"reference/standard_form/#MathOptInterface.LessThan","page":"Standard form","title":"MathOptInterface.LessThan","text":"LessThan{T<:Real}(upper::T)\n\nThe set (-infty upper subseteq mathbbR.\n\nExample\n\njulia> import MathOptInterface as MOI\n\njulia> model = MOI.Utilities.Model{Float64}()\nMOIU.Model{Float64}\n\njulia> x = MOI.add_variable(model)\nMOI.VariableIndex(1)\n\njulia> MOI.add_constraint(model, x, MOI.LessThan(2.0))\nMathOptInterface.ConstraintIndex{MathOptInterface.VariableIndex, MathOptInterface.LessThan{Float64}}(1)\n\n\n\n\n\n","category":"type"},{"location":"reference/standard_form/#MathOptInterface.EqualTo","page":"Standard form","title":"MathOptInterface.EqualTo","text":"EqualTo{T<:Number}(value::T)\n\nThe set containing the single point value subseteq mathbbR.\n\nExample\n\njulia> import MathOptInterface as MOI\n\njulia> model = MOI.Utilities.Model{Float64}()\nMOIU.Model{Float64}\n\njulia> x = MOI.add_variable(model)\nMOI.VariableIndex(1)\n\njulia> MOI.add_constraint(model, x, MOI.EqualTo(2.0))\nMathOptInterface.ConstraintIndex{MathOptInterface.VariableIndex, MathOptInterface.EqualTo{Float64}}(1)\n\n\n\n\n\n","category":"type"},{"location":"reference/standard_form/#MathOptInterface.Interval","page":"Standard form","title":"MathOptInterface.Interval","text":"Interval{T<:Real}(lower::T, upper::T)\n\nThe interval lower upper subseteq mathbbR cup -infty +infty.\n\nIf lower or upper is -Inf or Inf, respectively, the set is interpreted as a one-sided interval.\n\nExample\n\njulia> import MathOptInterface as MOI\n\njulia> model = MOI.Utilities.Model{Float64}()\nMOIU.Model{Float64}\n\njulia> x = MOI.add_variable(model)\nMOI.VariableIndex(1)\n\njulia> MOI.add_constraint(model, x, MOI.Interval(1.0, 2.0))\nMathOptInterface.ConstraintIndex{MathOptInterface.VariableIndex, MathOptInterface.Interval{Float64}}(1)\n\n\n\n\n\n","category":"type"},{"location":"reference/standard_form/#MathOptInterface.Integer","page":"Standard form","title":"MathOptInterface.Integer","text":"Integer()\n\nThe set of integers, mathbbZ.\n\nExample\n\njulia> import MathOptInterface as MOI\n\njulia> model = MOI.Utilities.Model{Float64}()\nMOIU.Model{Float64}\n\njulia> x = MOI.add_variable(model)\nMOI.VariableIndex(1)\n\njulia> MOI.add_constraint(model, x, MOI.Integer())\nMathOptInterface.ConstraintIndex{MathOptInterface.VariableIndex, MathOptInterface.Integer}(1)\n\n\n\n\n\n","category":"type"},{"location":"reference/standard_form/#MathOptInterface.ZeroOne","page":"Standard form","title":"MathOptInterface.ZeroOne","text":"ZeroOne()\n\nThe set 0 1.\n\nVariables belonging to the ZeroOne set are also known as \"binary\" variables.\n\nExample\n\njulia> import MathOptInterface as MOI\n\njulia> model = MOI.Utilities.Model{Float64}()\nMOIU.Model{Float64}\n\njulia> x = MOI.add_variable(model)\nMOI.VariableIndex(1)\n\njulia> MOI.add_constraint(model, x, MOI.ZeroOne())\nMathOptInterface.ConstraintIndex{MathOptInterface.VariableIndex, MathOptInterface.ZeroOne}(1)\n\n\n\n\n\n","category":"type"},{"location":"reference/standard_form/#MathOptInterface.Semicontinuous","page":"Standard form","title":"MathOptInterface.Semicontinuous","text":"Semicontinuous{T<:Real}(lower::T, upper::T)\n\nThe set 0 cup lower upper.\n\nExample\n\njulia> import MathOptInterface as MOI\n\njulia> model = MOI.Utilities.Model{Float64}()\nMOIU.Model{Float64}\n\njulia> x = MOI.add_variable(model)\nMOI.VariableIndex(1)\n\njulia> MOI.add_constraint(model, x, MOI.Semicontinuous(2.0, 3.0))\nMathOptInterface.ConstraintIndex{MathOptInterface.VariableIndex, MathOptInterface.Semicontinuous{Float64}}(1)\n\n\n\n\n\n","category":"type"},{"location":"reference/standard_form/#MathOptInterface.Semiinteger","page":"Standard form","title":"MathOptInterface.Semiinteger","text":"Semiinteger{T<:Real}(lower::T, upper::T)\n\nThe set 0 cup lower lower+1 ldots upper-1 upper.\n\nNote that if lower and upper are not equivalent to an integer, then the solver may throw an error, or it may round up lower and round down upper to the nearest integers.\n\nExample\n\njulia> import MathOptInterface as MOI\n\njulia> model = MOI.Utilities.Model{Float64}()\nMOIU.Model{Float64}\n\njulia> x = MOI.add_variable(model)\nMOI.VariableIndex(1)\n\njulia> MOI.add_constraint(model, x, MOI.Semiinteger(2.0, 3.0))\nMathOptInterface.ConstraintIndex{MathOptInterface.VariableIndex, MathOptInterface.Semiinteger{Float64}}(1)\n\n\n\n\n\n","category":"type"},{"location":"reference/standard_form/#MathOptInterface.Parameter","page":"Standard form","title":"MathOptInterface.Parameter","text":"Parameter{T<:Number}(value::T)\n\nThe set containing the single point value subseteq mathbbR.\n\nThe Parameter set is conceptually similar to the EqualTo set, except that a variable constrained to the Parameter set cannot have other constraints added to it, and the Parameter set can never be deleted. Thus, solvers are free to treat the variable as a constant, and they need not add it as a decision variable to the model.\n\nBecause of this behavior, you must add parameters using add_constrained_variable, and solvers should declare supports_add_constrained_variable and not supports_constraint for the Parameter set.\n\nExample\n\njulia> import MathOptInterface as MOI\n\njulia> model = MOI.Utilities.Model{Float64}()\nMOIU.Model{Float64}\n\njulia> p, ci = MOI.add_constrained_variable(model, MOI.Parameter(2.5))\n(MOI.VariableIndex(1), MathOptInterface.ConstraintIndex{MathOptInterface.VariableIndex, MathOptInterface.Parameter{Float64}}(1))\n\njulia> MOI.set(model, MOI.ConstraintSet(), ci, MOI.Parameter(3.0))\n\njulia> MOI.get(model, MOI.ConstraintSet(), ci)\nMathOptInterface.Parameter{Float64}(3.0)\n\n\n\n\n\n","category":"type"},{"location":"reference/standard_form/#Vector-sets","page":"Standard form","title":"Vector sets","text":"","category":"section"},{"location":"reference/standard_form/","page":"Standard form","title":"Standard form","text":"List of recognized vector sets.","category":"page"},{"location":"reference/standard_form/","page":"Standard form","title":"Standard form","text":"Reals\nZeros\nNonnegatives\nNonpositives\nNormInfinityCone\nNormOneCone\nNormCone\nSecondOrderCone\nRotatedSecondOrderCone\nGeometricMeanCone\nExponentialCone\nDualExponentialCone\nPowerCone\nDualPowerCone\nRelativeEntropyCone\nNormSpectralCone\nNormNuclearCone\nSOS1\nSOS2\nIndicator\nComplements\nHyperRectangle\nScaled","category":"page"},{"location":"reference/standard_form/#MathOptInterface.Reals","page":"Standard form","title":"MathOptInterface.Reals","text":"Reals(dimension::Int)\n\nThe set mathbbR^dimension (containing all points) of non-negative dimension dimension.\n\nExample\n\njulia> import MathOptInterface as MOI\n\njulia> model = MOI.Utilities.Model{Float64}()\nMOIU.Model{Float64}\n\njulia> x = MOI.add_variables(model, 3);\n\njulia> MOI.add_constraint(model, MOI.VectorOfVariables(x), MOI.Reals(3))\nMathOptInterface.ConstraintIndex{MathOptInterface.VectorOfVariables, MathOptInterface.Reals}(1)\n\n\n\n\n\n","category":"type"},{"location":"reference/standard_form/#MathOptInterface.Zeros","page":"Standard form","title":"MathOptInterface.Zeros","text":"Zeros(dimension::Int)\n\nThe set 0 ^dimension (containing only the origin) of non-negative dimension dimension.\n\nExample\n\njulia> import MathOptInterface as MOI\n\njulia> model = MOI.Utilities.Model{Float64}()\nMOIU.Model{Float64}\n\njulia> x = MOI.add_variables(model, 3);\n\njulia> MOI.add_constraint(model, MOI.VectorOfVariables(x), MOI.Zeros(3))\nMathOptInterface.ConstraintIndex{MathOptInterface.VectorOfVariables, MathOptInterface.Zeros}(1)\n\n\n\n\n\n","category":"type"},{"location":"reference/standard_form/#MathOptInterface.Nonnegatives","page":"Standard form","title":"MathOptInterface.Nonnegatives","text":"Nonnegatives(dimension::Int)\n\nThe nonnegative orthant x in mathbbR^dimension x ge 0 of non-negative dimension dimension.\n\nExample\n\njulia> import MathOptInterface as MOI\n\njulia> model = MOI.Utilities.Model{Float64}()\nMOIU.Model{Float64}\n\njulia> x = MOI.add_variables(model, 3);\n\njulia> MOI.add_constraint(model, MOI.VectorOfVariables(x), MOI.Nonnegatives(3))\nMathOptInterface.ConstraintIndex{MathOptInterface.VectorOfVariables, MathOptInterface.Nonnegatives}(1)\n\n\n\n\n\n","category":"type"},{"location":"reference/standard_form/#MathOptInterface.Nonpositives","page":"Standard form","title":"MathOptInterface.Nonpositives","text":"Nonpositives(dimension::Int)\n\nThe nonpositive orthant x in mathbbR^dimension x le 0 of non-negative dimension dimension.\n\nExample\n\njulia> import MathOptInterface as MOI\n\njulia> model = MOI.Utilities.Model{Float64}()\nMOIU.Model{Float64}\n\njulia> x = MOI.add_variables(model, 3);\n\njulia> MOI.add_constraint(model, MOI.VectorOfVariables(x), MOI.Nonpositives(3))\nMathOptInterface.ConstraintIndex{MathOptInterface.VectorOfVariables, MathOptInterface.Nonpositives}(1)\n\n\n\n\n\n","category":"type"},{"location":"reference/standard_form/#MathOptInterface.NormInfinityCone","page":"Standard form","title":"MathOptInterface.NormInfinityCone","text":"NormInfinityCone(dimension::Int)\n\nThe ell_infty-norm cone (tx) in mathbbR^dimension t ge lVert x rVert_infty = max_i lvert x_i rvert of dimension dimension.\n\nThe dimension must be at least 1.\n\nExample\n\njulia> import MathOptInterface as MOI\n\njulia> model = MOI.Utilities.Model{Float64}()\nMOIU.Model{Float64}\n\njulia> t = MOI.add_variable(model)\nMOI.VariableIndex(1)\n\njulia> x = MOI.add_variables(model, 3);\n\njulia> MOI.add_constraint(model, MOI.VectorOfVariables([t; x]), MOI.NormInfinityCone(4))\nMathOptInterface.ConstraintIndex{MathOptInterface.VectorOfVariables, MathOptInterface.NormInfinityCone}(1)\n\n\n\n\n\n","category":"type"},{"location":"reference/standard_form/#MathOptInterface.NormOneCone","page":"Standard form","title":"MathOptInterface.NormOneCone","text":"NormOneCone(dimension::Int)\n\nThe ell_1-norm cone (tx) in mathbbR^dimension t ge lVert x rVert_1 = sum_i lvert x_i rvert of dimension dimension.\n\nThe dimension must be at least 1.\n\nExample\n\njulia> import MathOptInterface as MOI\n\njulia> model = MOI.Utilities.Model{Float64}()\nMOIU.Model{Float64}\n\njulia> t = MOI.add_variable(model)\nMOI.VariableIndex(1)\n\njulia> x = MOI.add_variables(model, 3);\n\njulia> MOI.add_constraint(model, MOI.VectorOfVariables([t; x]), MOI.NormOneCone(4))\nMathOptInterface.ConstraintIndex{MathOptInterface.VectorOfVariables, MathOptInterface.NormOneCone}(1)\n\n\n\n\n\n","category":"type"},{"location":"reference/standard_form/#MathOptInterface.NormCone","page":"Standard form","title":"MathOptInterface.NormCone","text":"NormCone(p::Float64, dimension::Int)\n\nThe ell_p-norm cone (tx) in mathbbR^dimension t ge left(sumlimits_i x_i^pright)^frac1p of dimension dimension.\n\nThe dimension must be at least 1.\n\nExample\n\njulia> import MathOptInterface as MOI\n\njulia> model = MOI.Utilities.Model{Float64}()\nMOIU.Model{Float64}\n\njulia> t = MOI.add_variable(model)\nMOI.VariableIndex(1)\n\njulia> x = MOI.add_variables(model, 3);\n\njulia> MOI.add_constraint(model, MOI.VectorOfVariables([t; x]), MOI.NormCone(3, 4))\nMathOptInterface.ConstraintIndex{MathOptInterface.VectorOfVariables, MathOptInterface.NormCone}(1)\n\n\n\n\n\n","category":"type"},{"location":"reference/standard_form/#MathOptInterface.SecondOrderCone","page":"Standard form","title":"MathOptInterface.SecondOrderCone","text":"SecondOrderCone(dimension::Int)\n\nThe second-order cone (or Lorenz cone or ell_2-norm cone) (tx) in mathbbR^dimension t ge lVert x rVert_2 of dimension dimension.\n\nThe dimension must be at least 1.\n\nExample\n\njulia> import MathOptInterface as MOI\n\njulia> model = MOI.Utilities.Model{Float64}()\nMOIU.Model{Float64}\n\njulia> t = MOI.add_variable(model)\nMOI.VariableIndex(1)\n\njulia> x = MOI.add_variables(model, 3);\n\njulia> MOI.add_constraint(model, MOI.VectorOfVariables([t; x]), MOI.SecondOrderCone(4))\nMathOptInterface.ConstraintIndex{MathOptInterface.VectorOfVariables, MathOptInterface.SecondOrderCone}(1)\n\n\n\n\n\n","category":"type"},{"location":"reference/standard_form/#MathOptInterface.RotatedSecondOrderCone","page":"Standard form","title":"MathOptInterface.RotatedSecondOrderCone","text":"RotatedSecondOrderCone(dimension::Int)\n\nThe rotated second-order cone (tux) in mathbbR^dimension 2tu ge lVert x rVert_2^2 tu ge 0 of dimension dimension.\n\nThe dimension must be at least 2.\n\nExample\n\njulia> import MathOptInterface as MOI\n\njulia> model = MOI.Utilities.Model{Float64}()\nMOIU.Model{Float64}\n\njulia> t = MOI.add_variable(model)\nMOI.VariableIndex(1)\n\njulia> u = MOI.add_variable(model)\nMOI.VariableIndex(2)\n\njulia> x = MOI.add_variables(model, 3);\n\njulia> MOI.add_constraint(\n model,\n MOI.VectorOfVariables([t; u; x]),\n MOI.RotatedSecondOrderCone(5),\n )\nMathOptInterface.ConstraintIndex{MathOptInterface.VectorOfVariables, MathOptInterface.RotatedSecondOrderCone}(1)\n\n\n\n\n\n","category":"type"},{"location":"reference/standard_form/#MathOptInterface.GeometricMeanCone","page":"Standard form","title":"MathOptInterface.GeometricMeanCone","text":"GeometricMeanCone(dimension::Int)\n\nThe geometric mean cone (tx) in mathbbR^n+1 x ge 0 t le sqrtnx_1 x_2 cdots x_n , where dimension = n + 1 >= 2.\n\nDuality note\n\nThe dual of the geometric mean cone is (u v) in mathbbR^n+1 u le 0 v ge 0 -u le n sqrtnprod_i v_i , where dimension = n + 1 >= 2.\n\nExample\n\njulia> import MathOptInterface as MOI\n\njulia> model = MOI.Utilities.Model{Float64}()\nMOIU.Model{Float64}\n\njulia> t = MOI.add_variable(model)\nMOI.VariableIndex(1)\n\njulia> x = MOI.add_variables(model, 3);\n\njulia> MOI.add_constraint(\n model,\n MOI.VectorOfVariables([t; x]),\n MOI.GeometricMeanCone(4),\n )\nMathOptInterface.ConstraintIndex{MathOptInterface.VectorOfVariables, MathOptInterface.GeometricMeanCone}(1)\n\n\n\n\n\n","category":"type"},{"location":"reference/standard_form/#MathOptInterface.ExponentialCone","page":"Standard form","title":"MathOptInterface.ExponentialCone","text":"ExponentialCone()\n\nThe 3-dimensional exponential cone (xyz) in mathbbR^3 y exp (xy) le z y 0 .\n\nExample\n\njulia> import MathOptInterface as MOI\n\njulia> model = MOI.Utilities.Model{Float64}()\nMOIU.Model{Float64}\n\njulia> x = MOI.add_variables(model, 3);\n\njulia> MOI.add_constraint(model, MOI.VectorOfVariables(x), MOI.ExponentialCone())\nMathOptInterface.ConstraintIndex{MathOptInterface.VectorOfVariables, MathOptInterface.ExponentialCone}(1)\n\n\n\n\n\n","category":"type"},{"location":"reference/standard_form/#MathOptInterface.DualExponentialCone","page":"Standard form","title":"MathOptInterface.DualExponentialCone","text":"DualExponentialCone()\n\nThe 3-dimensional dual exponential cone (uvw) in mathbbR^3 -u exp (vu) le exp(1) w u 0 .\n\nExample\n\njulia> import MathOptInterface as MOI\n\njulia> model = MOI.Utilities.Model{Float64}()\nMOIU.Model{Float64}\n\njulia> x = MOI.add_variables(model, 3);\n\njulia> MOI.add_constraint(model, MOI.VectorOfVariables(x), MOI.DualExponentialCone())\nMathOptInterface.ConstraintIndex{MathOptInterface.VectorOfVariables, MathOptInterface.DualExponentialCone}(1)\n\n\n\n\n\n","category":"type"},{"location":"reference/standard_form/#MathOptInterface.PowerCone","page":"Standard form","title":"MathOptInterface.PowerCone","text":"PowerCone{T<:Real}(exponent::T)\n\nThe 3-dimensional power cone (xyz) in mathbbR^3 x^exponent y^1-exponent ge z x ge 0 y ge 0 with parameter exponent.\n\nExample\n\njulia> import MathOptInterface as MOI\n\njulia> model = MOI.Utilities.Model{Float64}()\nMOIU.Model{Float64}\n\njulia> x = MOI.add_variables(model, 3);\n\njulia> MOI.add_constraint(model, MOI.VectorOfVariables(x), MOI.PowerCone(0.5))\nMathOptInterface.ConstraintIndex{MathOptInterface.VectorOfVariables, MathOptInterface.PowerCone{Float64}}(1)\n\n\n\n\n\n","category":"type"},{"location":"reference/standard_form/#MathOptInterface.DualPowerCone","page":"Standard form","title":"MathOptInterface.DualPowerCone","text":"DualPowerCone{T<:Real}(exponent::T)\n\nThe 3-dimensional power cone (uvw) in mathbbR^3 (fracuexponent)^exponent (fracv1-exponent)^1-exponent ge w u ge 0 v ge 0 with parameter exponent.\n\nExample\n\njulia> import MathOptInterface as MOI\n\njulia> model = MOI.Utilities.Model{Float64}()\nMOIU.Model{Float64}\n\njulia> x = MOI.add_variables(model, 3);\n\njulia> MOI.add_constraint(model, MOI.VectorOfVariables(x), MOI.DualPowerCone(0.5))\nMathOptInterface.ConstraintIndex{MathOptInterface.VectorOfVariables, MathOptInterface.DualPowerCone{Float64}}(1)\n\n\n\n\n\n","category":"type"},{"location":"reference/standard_form/#MathOptInterface.RelativeEntropyCone","page":"Standard form","title":"MathOptInterface.RelativeEntropyCone","text":"RelativeEntropyCone(dimension::Int)\n\nThe relative entropy cone (u v w) in mathbbR^1+2n u ge sum_i=1^n w_i log(fracw_iv_i) v_i ge 0 w_i ge 0 , where dimension = 2n + 1 >= 1.\n\nDuality note\n\nThe dual of the relative entropy cone is (u v w) in mathbbR^1+2n forall i w_i ge u (log (fracuv_i) - 1) v_i ge 0 u 0 of dimension dimension=2n+1.\n\nExample\n\njulia> import MathOptInterface as MOI\n\njulia> model = MOI.Utilities.Model{Float64}()\nMOIU.Model{Float64}\n\njulia> u = MOI.add_variable(model);\n\njulia> v = MOI.add_variables(model, 3);\n\njulia> w = MOI.add_variables(model, 3);\n\njulia> MOI.add_constraint(\n model,\n MOI.VectorOfVariables([u; v; w]),\n MOI.RelativeEntropyCone(7),\n )\nMathOptInterface.ConstraintIndex{MathOptInterface.VectorOfVariables, MathOptInterface.RelativeEntropyCone}(1)\n\n\n\n\n\n","category":"type"},{"location":"reference/standard_form/#MathOptInterface.NormSpectralCone","page":"Standard form","title":"MathOptInterface.NormSpectralCone","text":"NormSpectralCone(row_dim::Int, column_dim::Int)\n\nThe epigraph of the matrix spectral norm (maximum singular value function) (t X) in mathbbR^1 + row_dim times column_dim t ge sigma_1(X) , where sigma_i is the ith singular value of the matrix X of non-negative row dimension row_dim and column dimension column_dim.\n\nThe matrix X is vectorized by stacking the columns, matching the behavior of Julia's vec function.\n\nExample\n\njulia> import MathOptInterface as MOI\n\njulia> model = MOI.Utilities.Model{Float64}()\nMOIU.Model{Float64}\n\njulia> t = MOI.add_variable(model)\nMOI.VariableIndex(1)\n\njulia> X = reshape(MOI.add_variables(model, 6), 2, 3)\n2×3 Matrix{MathOptInterface.VariableIndex}:\n MOI.VariableIndex(2) MOI.VariableIndex(4) MOI.VariableIndex(6)\n MOI.VariableIndex(3) MOI.VariableIndex(5) MOI.VariableIndex(7)\n\njulia> MOI.add_constraint(\n model,\n MOI.VectorOfVariables([t; vec(X)]),\n MOI.NormSpectralCone(2, 3),\n )\nMathOptInterface.ConstraintIndex{MathOptInterface.VectorOfVariables, MathOptInterface.NormSpectralCone}(1)\n\n\n\n\n\n","category":"type"},{"location":"reference/standard_form/#MathOptInterface.NormNuclearCone","page":"Standard form","title":"MathOptInterface.NormNuclearCone","text":"NormNuclearCone(row_dim::Int, column_dim::Int)\n\nThe epigraph of the matrix nuclear norm (sum of singular values function) (t X) in mathbbR^1 + row_dim times column_dim t ge sum_i sigma_i(X) , where sigma_i is the ith singular value of the matrix X of non-negative row dimension row_dim and column dimension column_dim.\n\nThe matrix X is vectorized by stacking the columns, matching the behavior of Julia's vec function.\n\nExample\n\njulia> import MathOptInterface as MOI\n\njulia> model = MOI.Utilities.Model{Float64}()\nMOIU.Model{Float64}\n\njulia> t = MOI.add_variable(model)\nMOI.VariableIndex(1)\n\njulia> X = reshape(MOI.add_variables(model, 6), 2, 3)\n2×3 Matrix{MathOptInterface.VariableIndex}:\n MOI.VariableIndex(2) MOI.VariableIndex(4) MOI.VariableIndex(6)\n MOI.VariableIndex(3) MOI.VariableIndex(5) MOI.VariableIndex(7)\n\njulia> MOI.add_constraint(\n model,\n MOI.VectorOfVariables([t; vec(X)]),\n MOI.NormNuclearCone(2, 3),\n )\nMathOptInterface.ConstraintIndex{MathOptInterface.VectorOfVariables, MathOptInterface.NormNuclearCone}(1)\n\n\n\n\n\n","category":"type"},{"location":"reference/standard_form/#MathOptInterface.SOS1","page":"Standard form","title":"MathOptInterface.SOS1","text":"SOS1{T<:Real}(weights::Vector{T})\n\nThe set corresponding to the Special Ordered Set (SOS) constraint of Type I.\n\nOf the variables in the set, at most one can be nonzero.\n\nThe weights induce an ordering of the variables such that the kth element in the set corresponds to the kth weight in weights. Solvers may use these weights to improve the efficiency of the solution process, but the ordering does not change the set of feasible solutions.\n\nExample\n\njulia> import MathOptInterface as MOI\n\njulia> model = MOI.Utilities.Model{Float64}()\nMOIU.Model{Float64}\n\njulia> x = MOI.add_variables(model, 3);\n\njulia> MOI.add_constraint(\n model,\n MOI.VectorOfVariables(x),\n MOI.SOS1([1.0, 3.0, 2.5]),\n )\nMathOptInterface.ConstraintIndex{MathOptInterface.VectorOfVariables, MathOptInterface.SOS1{Float64}}(1)\n\n\n\n\n\n","category":"type"},{"location":"reference/standard_form/#MathOptInterface.SOS2","page":"Standard form","title":"MathOptInterface.SOS2","text":"SOS2{T<:Real}(weights::Vector{T})\n\nThe set corresponding to the Special Ordered Set (SOS) constraint of Type II.\n\nThe weights induce an ordering of the variables such that the kth element in the set corresponds to the kth weight in weights. Therefore, the weights must be unique.\n\nOf the variables in the set, at most two can be nonzero, and if two are nonzero, they must be adjacent in the ordering of the set.\n\nExample\n\njulia> import MathOptInterface as MOI\n\njulia> model = MOI.Utilities.Model{Float64}()\nMOIU.Model{Float64}\n\njulia> x = MOI.add_variables(model, 3);\n\njulia> MOI.add_constraint(\n model,\n MOI.VectorOfVariables(x),\n MOI.SOS2([1.0, 3.0, 2.5]),\n )\nMathOptInterface.ConstraintIndex{MathOptInterface.VectorOfVariables, MathOptInterface.SOS2{Float64}}(1)\n\n\n\n\n\n","category":"type"},{"location":"reference/standard_form/#MathOptInterface.Indicator","page":"Standard form","title":"MathOptInterface.Indicator","text":"Indicator{A<:ActivationCondition,S<:AbstractScalarSet}(set::S)\n\nThe set corresponding to an indicator constraint.\n\nWhen A is ACTIVATE_ON_ZERO, this means: (y x) in 0 1 times mathbbR^n y = 0 implies x in set\n\nWhen A is ACTIVATE_ON_ONE, this means: (y x) in 0 1 times mathbbR^n y = 1 implies x in set\n\nNotes\n\nMost solvers expect that the first row of the function is interpretable as a variable index x_i (e.g., 1.0 * x + 0.0). An error will be thrown if this is not the case.\n\nExample\n\nThe constraint (y x) in 0 1 times mathbbR^2 y = 1 implies x_1 + x_2 leq 9 is defined as\n\njulia> import MathOptInterface as MOI\n\njulia> model = MOI.Utilities.Model{Float64}()\nMOIU.Model{Float64}\n\njulia> x = MOI.add_variables(model, 2)\n2-element Vector{MathOptInterface.VariableIndex}:\n MOI.VariableIndex(1)\n MOI.VariableIndex(2)\n\njulia> y, _ = MOI.add_constrained_variable(model, MOI.ZeroOne())\n(MOI.VariableIndex(3), MathOptInterface.ConstraintIndex{MathOptInterface.VariableIndex, MathOptInterface.ZeroOne}(3))\n\njulia> f = MOI.VectorAffineFunction(\n [\n MOI.VectorAffineTerm(1, MOI.ScalarAffineTerm(1.0, y)),\n MOI.VectorAffineTerm(2, MOI.ScalarAffineTerm(1.0, x[1])),\n MOI.VectorAffineTerm(2, MOI.ScalarAffineTerm(1.0, x[2])),\n ],\n [0.0, 0.0],\n )\n┌ ┐\n│0.0 + 1.0 MOI.VariableIndex(3) │\n│0.0 + 1.0 MOI.VariableIndex(1) + 1.0 MOI.VariableIndex(2)│\n└ ┘\n\njulia> s = MOI.Indicator{MOI.ACTIVATE_ON_ONE}(MOI.LessThan(9.0))\nMathOptInterface.Indicator{MathOptInterface.ACTIVATE_ON_ONE, MathOptInterface.LessThan{Float64}}(MathOptInterface.LessThan{Float64}(9.0))\n\njulia> MOI.add_constraint(model, f, s)\nMathOptInterface.ConstraintIndex{MathOptInterface.VectorAffineFunction{Float64}, MathOptInterface.Indicator{MathOptInterface.ACTIVATE_ON_ONE, MathOptInterface.LessThan{Float64}}}(1)\n\n\n\n\n\n","category":"type"},{"location":"reference/standard_form/#MathOptInterface.Complements","page":"Standard form","title":"MathOptInterface.Complements","text":"Complements(dimension::Base.Integer)\n\nThe set corresponding to a mixed complementarity constraint.\n\nComplementarity constraints should be specified with an AbstractVectorFunction-in-Complements(dimension) constraint.\n\nThe dimension of the vector-valued function F must be dimension. This defines a complementarity constraint between the scalar function F[i] and the variable in F[i + dimension/2]. Thus, F[i + dimension/2] must be interpretable as a single variable x_i (e.g., 1.0 * x + 0.0), and dimension must be even.\n\nThe mixed complementarity problem consists of finding x_i in the interval [lb, ub] (i.e., in the set Interval(lb, ub)), such that the following holds:\n\nF_i(x) == 0 if lb_i < x_i < ub_i\nF_i(x) >= 0 if lb_i == x_i\nF_i(x) <= 0 if x_i == ub_i\n\nClassically, the bounding set for x_i is Interval(0, Inf), which recovers: 0 <= F_i(x) ⟂ x_i >= 0, where the ⟂ operator implies F_i(x) * x_i = 0.\n\nExample\n\nThe problem:\n\nx -in- Interval(-1, 1)\n[-4 * x - 3, x] -in- Complements(2)\n\ndefines the mixed complementarity problem where the following holds:\n\n-4 * x - 3 == 0 if -1 < x < 1\n-4 * x - 3 >= 0 if x == -1\n-4 * x - 3 <= 0 if x == 1\n\nThere are three solutions:\n\nx = -3/4 with F(x) = 0\nx = -1 with F(x) = 1\nx = 1 with F(x) = -7\n\njulia> import MathOptInterface as MOI\n\njulia> model = MOI.Utilities.Model{Float64}()\nMOIU.Model{Float64}\n\njulia> x, _ = MOI.add_constrained_variable(model, MOI.Interval(-1.0, 1.0));\n\njulia> MOI.add_constraint(\n model,\n MOI.Utilities.vectorize([-4.0 * x - 3.0, x]),\n MOI.Complements(2),\n )\nMathOptInterface.ConstraintIndex{MathOptInterface.VectorAffineFunction{Float64}, MathOptInterface.Complements}(1)\n\nThe function F can also be defined in terms of single variables. For example, the problem:\n\n[x_3, x_4] -in- Nonnegatives(2)\n[x_1, x_2, x_3, x_4] -in- Complements(4)\n\ndefines the complementarity problem where 0 <= x_1 ⟂ x_3 >= 0 and 0 <= x_2 ⟂ x_4 >= 0.\n\njulia> import MathOptInterface as MOI\n\njulia> model = MOI.Utilities.Model{Float64}()\nMOIU.Model{Float64}\n\njulia> x = MOI.add_variables(model, 4);\n\njulia> MOI.add_constraint(model, MOI.VectorOfVariables(x[3:4]), MOI.Nonnegatives(2))\nMathOptInterface.ConstraintIndex{MathOptInterface.VectorOfVariables, MathOptInterface.Nonnegatives}(1)\n\njulia> MOI.add_constraint(\n model,\n MOI.VectorOfVariables(x),\n MOI.Complements(4),\n )\nMathOptInterface.ConstraintIndex{MathOptInterface.VectorOfVariables, MathOptInterface.Complements}(1)\n\n\n\n\n\n","category":"type"},{"location":"reference/standard_form/#MathOptInterface.HyperRectangle","page":"Standard form","title":"MathOptInterface.HyperRectangle","text":"HyperRectangle(lower::Vector{T}, upper::Vector{T}) where {T}\n\nThe set x in barmathbbR^d x_i in lower_i upper_i forall i=1ldotsd.\n\nExample\n\njulia> import MathOptInterface as MOI\n\njulia> model = MOI.Utilities.Model{Float64}()\nMOIU.Model{Float64}\n\njulia> x = MOI.add_variables(model, 3)\n3-element Vector{MathOptInterface.VariableIndex}:\n MOI.VariableIndex(1)\n MOI.VariableIndex(2)\n MOI.VariableIndex(3)\n\njulia> MOI.add_constraint(\n model,\n MOI.VectorOfVariables(x),\n MOI.HyperRectangle(zeros(3), ones(3)),\n )\nMathOptInterface.ConstraintIndex{MathOptInterface.VectorOfVariables, MathOptInterface.HyperRectangle{Float64}}(1)\n\n\n\n\n\n","category":"type"},{"location":"reference/standard_form/#MathOptInterface.Scaled","page":"Standard form","title":"MathOptInterface.Scaled","text":"struct Scaled{S<:AbstractVectorSet} <: AbstractVectorSet\n set::S\nend\n\nGiven a vector a in mathbbR^d and a set representing the set mathcalS in mathbbR^d such that Utilities.set_dot for x in mathcalS and y in mathcalS^* is\n\nsum_i=1^d a_i x_i y_i\n\nthe set Scaled(set) is defined as\n\n (sqrta_1 x_1 sqrta_2 x_2 ldots sqrta_d x_d) x in S \n\nExample\n\nThis can be used to scale a vector of numbers\n\njulia> import MathOptInterface as MOI\n\njulia> set = MOI.PositiveSemidefiniteConeTriangle(2)\nMathOptInterface.PositiveSemidefiniteConeTriangle(2)\n\njulia> a = MOI.Utilities.SetDotScalingVector{Float64}(set)\n3-element MathOptInterface.Utilities.SetDotScalingVector{Float64, MathOptInterface.PositiveSemidefiniteConeTriangle}:\n 1.0\n 1.4142135623730951\n 1.0\n\njulia> using LinearAlgebra\n\njulia> MOI.Utilities.operate(*, Float64, Diagonal(a), ones(3))\n3-element Vector{Float64}:\n 1.0\n 1.4142135623730951\n 1.0\n\nIt can be also used to scale a vector of function\n\njulia> model = MOI.Utilities.Model{Float64}()\nMOIU.Model{Float64}\n\njulia> x = MOI.add_variables(model, 3);\n\njulia> func = MOI.VectorOfVariables(x)\n┌ ┐\n│MOI.VariableIndex(1)│\n│MOI.VariableIndex(2)│\n│MOI.VariableIndex(3)│\n└ ┘\n\njulia> set = MOI.PositiveSemidefiniteConeTriangle(2)\nMathOptInterface.PositiveSemidefiniteConeTriangle(2)\n\njulia> MOI.Utilities.operate(*, Float64, Diagonal(a), func)\n┌ ┐\n│0.0 + 1.0 MOI.VariableIndex(1) │\n│0.0 + 1.4142135623730951 MOI.VariableIndex(2)│\n│0.0 + 1.0 MOI.VariableIndex(3) │\n└ ┘\n\n\n\n\n\n","category":"type"},{"location":"reference/standard_form/#Constraint-programming-sets","page":"Standard form","title":"Constraint programming sets","text":"","category":"section"},{"location":"reference/standard_form/","page":"Standard form","title":"Standard form","text":"AllDifferent\nBinPacking\nCircuit\nCountAtLeast\nCountBelongs\nCountDistinct\nCountGreaterThan\nCumulative\nPath\nReified\nTable","category":"page"},{"location":"reference/standard_form/#MathOptInterface.AllDifferent","page":"Standard form","title":"MathOptInterface.AllDifferent","text":"AllDifferent(dimension::Int)\n\nThe set x in mathbbZ^d such that no two elements in x take the same value and dimension = d.\n\nAlso known as\n\nThis constraint is called all_different in MiniZinc, and is sometimes also called distinct.\n\nExample\n\nTo enforce x[1] != x[2] AND x[1] != x[3] AND x[2] != x[3]:\n\njulia> import MathOptInterface as MOI\n\njulia> model = MOI.Utilities.Model{Float64}()\nMOIU.Model{Float64}\n\njulia> x = [MOI.add_constrained_variable(model, MOI.Integer())[1] for _ in 1:3]\n3-element Vector{MathOptInterface.VariableIndex}:\n MOI.VariableIndex(1)\n MOI.VariableIndex(2)\n MOI.VariableIndex(3)\n\njulia> MOI.add_constraint(model, MOI.VectorOfVariables(x), MOI.AllDifferent(3))\nMathOptInterface.ConstraintIndex{MathOptInterface.VectorOfVariables, MathOptInterface.AllDifferent}(1)\n\n\n\n\n\n","category":"type"},{"location":"reference/standard_form/#MathOptInterface.BinPacking","page":"Standard form","title":"MathOptInterface.BinPacking","text":"BinPacking(c::T, w::Vector{T}) where {T}\n\nThe set x in mathbbZ^d where d = length(w), such that each item i in 1:d of weight w[i] is put into bin x[i], and the total weight of each bin does not exceed c.\n\nThere are additional assumptions that the capacity, c, and the weights, w, must all be non-negative.\n\nThe bin numbers depend on the bounds of x, so they may be something other than the integers 1:d.\n\nAlso known as\n\nThis constraint is called bin_packing in MiniZinc.\n\nExample\n\njulia> import MathOptInterface as MOI\n\njulia> model = MOI.Utilities.Model{Float64}()\nMOIU.Model{Float64}\n\njulia> bins = MOI.add_variables(model, 5)\n5-element Vector{MathOptInterface.VariableIndex}:\n MOI.VariableIndex(1)\n MOI.VariableIndex(2)\n MOI.VariableIndex(3)\n MOI.VariableIndex(4)\n MOI.VariableIndex(5)\n\njulia> weights = Float64[1, 1, 2, 2, 3]\n5-element Vector{Float64}:\n 1.0\n 1.0\n 2.0\n 2.0\n 3.0\n\njulia> MOI.add_constraint.(model, bins, MOI.Integer())\n5-element Vector{MathOptInterface.ConstraintIndex{MathOptInterface.VariableIndex, MathOptInterface.Integer}}:\n MathOptInterface.ConstraintIndex{MathOptInterface.VariableIndex, MathOptInterface.Integer}(1)\n MathOptInterface.ConstraintIndex{MathOptInterface.VariableIndex, MathOptInterface.Integer}(2)\n MathOptInterface.ConstraintIndex{MathOptInterface.VariableIndex, MathOptInterface.Integer}(3)\n MathOptInterface.ConstraintIndex{MathOptInterface.VariableIndex, MathOptInterface.Integer}(4)\n MathOptInterface.ConstraintIndex{MathOptInterface.VariableIndex, MathOptInterface.Integer}(5)\n\njulia> MOI.add_constraint.(model, bins, MOI.Interval(4.0, 6.0))\n5-element Vector{MathOptInterface.ConstraintIndex{MathOptInterface.VariableIndex, MathOptInterface.Interval{Float64}}}:\n MathOptInterface.ConstraintIndex{MathOptInterface.VariableIndex, MathOptInterface.Interval{Float64}}(1)\n MathOptInterface.ConstraintIndex{MathOptInterface.VariableIndex, MathOptInterface.Interval{Float64}}(2)\n MathOptInterface.ConstraintIndex{MathOptInterface.VariableIndex, MathOptInterface.Interval{Float64}}(3)\n MathOptInterface.ConstraintIndex{MathOptInterface.VariableIndex, MathOptInterface.Interval{Float64}}(4)\n MathOptInterface.ConstraintIndex{MathOptInterface.VariableIndex, MathOptInterface.Interval{Float64}}(5)\n\njulia> MOI.add_constraint(model, MOI.VectorOfVariables(bins), MOI.BinPacking(3.0, weights))\nMathOptInterface.ConstraintIndex{MathOptInterface.VectorOfVariables, MathOptInterface.BinPacking{Float64}}(1)\n\n\n\n\n\n","category":"type"},{"location":"reference/standard_form/#MathOptInterface.Circuit","page":"Standard form","title":"MathOptInterface.Circuit","text":"Circuit(dimension::Int)\n\nThe set x in 1d^d that constraints x to be a circuit, such that x_i = j means that j is the successor of i, and dimension = d.\n\nGraphs with multiple independent circuits, such as [2, 1, 3] and [2, 1, 4, 3], are not valid.\n\nAlso known as\n\nThis constraint is called circuit in MiniZinc, and it is equivalent to forming a (potentially sub-optimal) tour in the travelling salesperson problem.\n\nExample\n\njulia> import MathOptInterface as MOI\n\njulia> model = MOI.Utilities.Model{Float64}()\nMOIU.Model{Float64}\n\njulia> x = [MOI.add_constrained_variable(model, MOI.Integer())[1] for _ in 1:3]\n3-element Vector{MathOptInterface.VariableIndex}:\n MOI.VariableIndex(1)\n MOI.VariableIndex(2)\n MOI.VariableIndex(3)\n\njulia> MOI.add_constraint(model, MOI.VectorOfVariables(x), MOI.Circuit(3))\nMathOptInterface.ConstraintIndex{MathOptInterface.VectorOfVariables, MathOptInterface.Circuit}(1)\n\n\n\n\n\n","category":"type"},{"location":"reference/standard_form/#MathOptInterface.CountAtLeast","page":"Standard form","title":"MathOptInterface.CountAtLeast","text":"CountAtLeast(n::Int, d::Vector{Int}, set::Set{Int})\n\nThe set x in mathbbZ^d_1 + d_2 + ldots d_N, where x is partitioned into N subsets (x_1 ldots x_d_1, x_d_1 + 1 ldots x_d_1 + d_2 and so on), and at least n elements of each subset take one of the values in set.\n\nAlso known as\n\nThis constraint is called at_least in MiniZinc.\n\nExample\n\nTo ensure that 3 appears at least once in each of the subsets {a, b} and {b, c}:\n\njulia> import MathOptInterface as MOI\n\njulia> model = MOI.Utilities.Model{Float64}()\nMOIU.Model{Float64}\n\njulia> a, _ = MOI.add_constrained_variable(model, MOI.Integer())\n(MOI.VariableIndex(1), MathOptInterface.ConstraintIndex{MathOptInterface.VariableIndex, MathOptInterface.Integer}(1))\n\njulia> b, _ = MOI.add_constrained_variable(model, MOI.Integer())\n(MOI.VariableIndex(2), MathOptInterface.ConstraintIndex{MathOptInterface.VariableIndex, MathOptInterface.Integer}(2))\n\njulia> c, _ = MOI.add_constrained_variable(model, MOI.Integer())\n(MOI.VariableIndex(3), MathOptInterface.ConstraintIndex{MathOptInterface.VariableIndex, MathOptInterface.Integer}(3))\n\njulia> x, d, set = [a, b, b, c], [2, 2], [3]\n(MathOptInterface.VariableIndex[MOI.VariableIndex(1), MOI.VariableIndex(2), MOI.VariableIndex(2), MOI.VariableIndex(3)], [2, 2], [3])\n\njulia> MOI.add_constraint(model, MOI.VectorOfVariables(x), MOI.CountAtLeast(1, d, Set(set)))\nMathOptInterface.ConstraintIndex{MathOptInterface.VectorOfVariables, MathOptInterface.CountAtLeast}(1)\n\n\n\n\n\n","category":"type"},{"location":"reference/standard_form/#MathOptInterface.CountBelongs","page":"Standard form","title":"MathOptInterface.CountBelongs","text":"CountBelongs(dimenson::Int, set::Set{Int})\n\nThe set (n x) in mathbbZ^1+d, such that n elements of the vector x take on of the values in set and dimension = 1 + d.\n\nAlso known as\n\nThis constraint is called among by MiniZinc.\n\nExample\n\njulia> import MathOptInterface as MOI\n\njulia> model = MOI.Utilities.Model{Float64}()\nMOIU.Model{Float64}\n\njulia> n, _ = MOI.add_constrained_variable(model, MOI.Integer())\n(MOI.VariableIndex(1), MathOptInterface.ConstraintIndex{MathOptInterface.VariableIndex, MathOptInterface.Integer}(1))\n\njulia> x = [MOI.add_constrained_variable(model, MOI.Integer())[1] for _ in 1:3]\n3-element Vector{MathOptInterface.VariableIndex}:\n MOI.VariableIndex(2)\n MOI.VariableIndex(3)\n MOI.VariableIndex(4)\n\njulia> set = Set([3, 4, 5])\nSet{Int64} with 3 elements:\n 5\n 4\n 3\n\njulia> MOI.add_constraint(model, MOI.VectorOfVariables([n; x]), MOI.CountBelongs(4, set))\nMathOptInterface.ConstraintIndex{MathOptInterface.VectorOfVariables, MathOptInterface.CountBelongs}(1)\n\n\n\n\n\n","category":"type"},{"location":"reference/standard_form/#MathOptInterface.CountDistinct","page":"Standard form","title":"MathOptInterface.CountDistinct","text":"CountDistinct(dimension::Int)\n\nThe set (n x) in mathbbZ^1+d, such that the number of distinct values in x is n and dimension = 1 + d.\n\nAlso known as\n\nThis constraint is called nvalues in MiniZinc.\n\nExample\n\nTo model:\n\nif n == 1`, thenx[1] == x[2] == x[3]`\nif n == 2, then\nx[1] == x[2] != x[3] or\nx[1] != x[2] == x[3] or\nx[1] == x[3] != x[2]\nif n == 3, then x[1] != x[2], x[2] != x[3] and x[3] != x[1]\n\njulia> import MathOptInterface as MOI\n\njulia> model = MOI.Utilities.Model{Float64}()\nMOIU.Model{Float64}\n\njulia> n, _ = MOI.add_constrained_variable(model, MOI.Integer())\n(MOI.VariableIndex(1), MathOptInterface.ConstraintIndex{MathOptInterface.VariableIndex, MathOptInterface.Integer}(1))\n\njulia> x = [MOI.add_constrained_variable(model, MOI.Integer())[1] for _ in 1:3]\n3-element Vector{MathOptInterface.VariableIndex}:\n MOI.VariableIndex(2)\n MOI.VariableIndex(3)\n MOI.VariableIndex(4)\n\njulia> MOI.add_constraint(model, MOI.VectorOfVariables(vcat(n, x)), MOI.CountDistinct(4))\nMathOptInterface.ConstraintIndex{MathOptInterface.VectorOfVariables, MathOptInterface.CountDistinct}(1)\n\nRelationship to AllDifferent\n\nWhen the first element is d, CountDistinct is equivalent to an AllDifferent constraint.\n\n\n\n\n\n","category":"type"},{"location":"reference/standard_form/#MathOptInterface.CountGreaterThan","page":"Standard form","title":"MathOptInterface.CountGreaterThan","text":"CountGreaterThan(dimension::Int)\n\nThe set (c y x) in mathbbZ^1+1+d, such that c is strictly greater than the number of occurances of y in x and dimension = 1 + 1 + d.\n\nAlso known as\n\nThis constraint is called count_gt in MiniZinc.\n\nExample\n\njulia> import MathOptInterface as MOI\n\njulia> model = MOI.Utilities.Model{Float64}()\nMOIU.Model{Float64}\n\njulia> c, _ = MOI.add_constrained_variable(model, MOI.Integer())\n(MOI.VariableIndex(1), MathOptInterface.ConstraintIndex{MathOptInterface.VariableIndex, MathOptInterface.Integer}(1))\n\njulia> y, _ = MOI.add_constrained_variable(model, MOI.Integer())\n(MOI.VariableIndex(2), MathOptInterface.ConstraintIndex{MathOptInterface.VariableIndex, MathOptInterface.Integer}(2))\n\njulia> x = [MOI.add_constrained_variable(model, MOI.Integer())[1] for _ in 1:3]\n3-element Vector{MathOptInterface.VariableIndex}:\n MOI.VariableIndex(3)\n MOI.VariableIndex(4)\n MOI.VariableIndex(5)\n\njulia> MOI.add_constraint(model, MOI.VectorOfVariables([c; y; x]), MOI.CountGreaterThan(5))\nMathOptInterface.ConstraintIndex{MathOptInterface.VectorOfVariables, MathOptInterface.CountGreaterThan}(1)\n\n\n\n\n\n","category":"type"},{"location":"reference/standard_form/#MathOptInterface.Cumulative","page":"Standard form","title":"MathOptInterface.Cumulative","text":"Cumulative(dimension::Int)\n\nThe set (s d r b) in mathbbZ^3n+1, representing the cumulative global constraint, where n == length(s) == length(r) == length(b) and dimension = 3n + 1.\n\nCumulative requires that a set of tasks given by start times s, durations d, and resource requirements r, never requires more than the global resource bound b at any one time.\n\nAlso known as\n\nThis constraint is called cumulative in MiniZinc.\n\nExample\n\njulia> import MathOptInterface as MOI\n\njulia> model = MOI.Utilities.Model{Float64}()\nMOIU.Model{Float64}\n\njulia> s = [MOI.add_constrained_variable(model, MOI.Integer())[1] for _ in 1:3]\n3-element Vector{MathOptInterface.VariableIndex}:\n MOI.VariableIndex(1)\n MOI.VariableIndex(2)\n MOI.VariableIndex(3)\n\njulia> d = [MOI.add_constrained_variable(model, MOI.Integer())[1] for _ in 1:3]\n3-element Vector{MathOptInterface.VariableIndex}:\n MOI.VariableIndex(4)\n MOI.VariableIndex(5)\n MOI.VariableIndex(6)\n\njulia> r = [MOI.add_constrained_variable(model, MOI.Integer())[1] for _ in 1:3]\n3-element Vector{MathOptInterface.VariableIndex}:\n MOI.VariableIndex(7)\n MOI.VariableIndex(8)\n MOI.VariableIndex(9)\n\njulia> b, _ = MOI.add_constrained_variable(model, MOI.Integer())\n(MOI.VariableIndex(10), MathOptInterface.ConstraintIndex{MathOptInterface.VariableIndex, MathOptInterface.Integer}(10))\n\njulia> MOI.add_constraint(model, MOI.VectorOfVariables([s; d; r; b]), MOI.Cumulative(10))\nMathOptInterface.ConstraintIndex{MathOptInterface.VectorOfVariables, MathOptInterface.Cumulative}(1)\n\n\n\n\n\n","category":"type"},{"location":"reference/standard_form/#MathOptInterface.Path","page":"Standard form","title":"MathOptInterface.Path","text":"Path(from::Vector{Int}, to::Vector{Int})\n\nGiven a graph comprised of a set of nodes 1..N and a set of arcs 1..E represented by an edge from node from[i] to node to[i], Path constrains the set (s t ns es) in (1N)times(1E)times01^Ntimes01^E, to form subgraph that is a path from node s to node t, where node n is in the path if ns[n] is 1, and edge e is in the path if es[e] is 1.\n\nThe path must be acyclic, and it must traverse all nodes n for which ns[n] is 1, and all edges e for which es[e] is 1.\n\nAlso known as\n\nThis constraint is called path in MiniZinc.\n\nExample\n\njulia> import MathOptInterface as MOI\n\njulia> model = MOI.Utilities.Model{Float64}()\nMOIU.Model{Float64}\n\njulia> N, E = 4, 5\n(4, 5)\n\njulia> from = [1, 1, 2, 2, 3]\n5-element Vector{Int64}:\n 1\n 1\n 2\n 2\n 3\n\njulia> to = [2, 3, 3, 4, 4]\n5-element Vector{Int64}:\n 2\n 3\n 3\n 4\n 4\n\njulia> s, _ = MOI.add_constrained_variable(model, MOI.Integer())\n(MOI.VariableIndex(1), MathOptInterface.ConstraintIndex{MathOptInterface.VariableIndex, MathOptInterface.Integer}(1))\n\njulia> t, _ = MOI.add_constrained_variable(model, MOI.Integer())\n(MOI.VariableIndex(2), MathOptInterface.ConstraintIndex{MathOptInterface.VariableIndex, MathOptInterface.Integer}(2))\n\njulia> ns = MOI.add_variables(model, N)\n4-element Vector{MathOptInterface.VariableIndex}:\n MOI.VariableIndex(3)\n MOI.VariableIndex(4)\n MOI.VariableIndex(5)\n MOI.VariableIndex(6)\n\njulia> MOI.add_constraint.(model, ns, MOI.ZeroOne())\n4-element Vector{MathOptInterface.ConstraintIndex{MathOptInterface.VariableIndex, MathOptInterface.ZeroOne}}:\n MathOptInterface.ConstraintIndex{MathOptInterface.VariableIndex, MathOptInterface.ZeroOne}(3)\n MathOptInterface.ConstraintIndex{MathOptInterface.VariableIndex, MathOptInterface.ZeroOne}(4)\n MathOptInterface.ConstraintIndex{MathOptInterface.VariableIndex, MathOptInterface.ZeroOne}(5)\n MathOptInterface.ConstraintIndex{MathOptInterface.VariableIndex, MathOptInterface.ZeroOne}(6)\n\njulia> es = MOI.add_variables(model, E)\n5-element Vector{MathOptInterface.VariableIndex}:\n MOI.VariableIndex(7)\n MOI.VariableIndex(8)\n MOI.VariableIndex(9)\n MOI.VariableIndex(10)\n MOI.VariableIndex(11)\n\njulia> MOI.add_constraint.(model, es, MOI.ZeroOne())\n5-element Vector{MathOptInterface.ConstraintIndex{MathOptInterface.VariableIndex, MathOptInterface.ZeroOne}}:\n MathOptInterface.ConstraintIndex{MathOptInterface.VariableIndex, MathOptInterface.ZeroOne}(7)\n MathOptInterface.ConstraintIndex{MathOptInterface.VariableIndex, MathOptInterface.ZeroOne}(8)\n MathOptInterface.ConstraintIndex{MathOptInterface.VariableIndex, MathOptInterface.ZeroOne}(9)\n MathOptInterface.ConstraintIndex{MathOptInterface.VariableIndex, MathOptInterface.ZeroOne}(10)\n MathOptInterface.ConstraintIndex{MathOptInterface.VariableIndex, MathOptInterface.ZeroOne}(11)\n\njulia> MOI.add_constraint(model, MOI.VectorOfVariables([s; t; ns; es]), MOI.Path(from, to))\nMathOptInterface.ConstraintIndex{MathOptInterface.VectorOfVariables, MathOptInterface.Path}(1)\n\n\n\n\n\n","category":"type"},{"location":"reference/standard_form/#MathOptInterface.Reified","page":"Standard form","title":"MathOptInterface.Reified","text":"Reified(set::AbstractSet)\n\nThe constraint z f(x) in Reified(S) ensures that f(x) in S if and only if z == 1, where z in 0 1.\n\njulia> import MathOptInterface as MOI\n\njulia> model = MOI.Utilities.UniversalFallback(MOI.Utilities.Model{Float64}())\nMOIU.UniversalFallback{MOIU.Model{Float64}}\nfallback for MOIU.Model{Float64}\n\njulia> z, _ = MOI.add_constrained_variable(model, MOI.ZeroOne())\n(MOI.VariableIndex(1), MathOptInterface.ConstraintIndex{MathOptInterface.VariableIndex, MathOptInterface.ZeroOne}(1))\n\njulia> x = MOI.add_variable(model)\nMOI.VariableIndex(2)\n\njulia> MOI.add_constraint(\n model,\n MOI.Utilities.vectorize([z, 2.0 * x]),\n MOI.Reified(MOI.GreaterThan(1.0)),\n )\nMathOptInterface.ConstraintIndex{MathOptInterface.VectorAffineFunction{Float64}, MathOptInterface.Reified{MathOptInterface.GreaterThan{Float64}}}(1)\n\n\n\n\n\n","category":"type"},{"location":"reference/standard_form/#MathOptInterface.Table","page":"Standard form","title":"MathOptInterface.Table","text":"Table(table::Matrix{T}) where {T}\n\nThe set x in mathbbR^d where d = size(table, 2), such that x belongs to one row of table. That is, there exists some j in 1:size(table, 1), such that x[i] = table[j, i] for all i=1:size(table, 2).\n\nAlso known as\n\nThis constraint is called table in MiniZinc.\n\nExample\n\njulia> import MathOptInterface as MOI\n\njulia> model = MOI.Utilities.Model{Float64}()\nMOIU.Model{Float64}\n\njulia> x = MOI.add_variables(model, 3)\n3-element Vector{MathOptInterface.VariableIndex}:\n MOI.VariableIndex(1)\n MOI.VariableIndex(2)\n MOI.VariableIndex(3)\n\njulia> table = Float64[1 1 0; 0 1 1; 1 0 1; 1 1 1]\n4×3 Matrix{Float64}:\n 1.0 1.0 0.0\n 0.0 1.0 1.0\n 1.0 0.0 1.0\n 1.0 1.0 1.0\n\njulia> MOI.add_constraint(model, MOI.VectorOfVariables(x), MOI.Table(table))\nMathOptInterface.ConstraintIndex{MathOptInterface.VectorOfVariables, MathOptInterface.Table{Float64}}(1)\n\n\n\n\n\n","category":"type"},{"location":"reference/standard_form/#Matrix-sets","page":"Standard form","title":"Matrix sets","text":"","category":"section"},{"location":"reference/standard_form/","page":"Standard form","title":"Standard form","text":"Matrix sets are vectorized to be subtypes of AbstractVectorSet.","category":"page"},{"location":"reference/standard_form/","page":"Standard form","title":"Standard form","text":"For sets of symmetric matrices, storing both the (i, j) and (j, i) elements is redundant. Use the AbstractSymmetricMatrixSetTriangle set to represent only the vectorization of the upper triangular part of the matrix.","category":"page"},{"location":"reference/standard_form/","page":"Standard form","title":"Standard form","text":"When the matrix of expressions constrained to be in the set is not symmetric, and hence additional constraints are needed to force the equality of the (i, j) and (j, i) elements, use the AbstractSymmetricMatrixSetSquare set.","category":"page"},{"location":"reference/standard_form/","page":"Standard form","title":"Standard form","text":"The Bridges.Constraint.SquareBridge can transform a set from the square form to the triangular_form by adding appropriate constraints if the (i, j) and (j, i) expressions are different.","category":"page"},{"location":"reference/standard_form/","page":"Standard form","title":"Standard form","text":"AbstractSymmetricMatrixSetTriangle\nAbstractSymmetricMatrixSetSquare\nside_dimension\ntriangular_form","category":"page"},{"location":"reference/standard_form/#MathOptInterface.AbstractSymmetricMatrixSetTriangle","page":"Standard form","title":"MathOptInterface.AbstractSymmetricMatrixSetTriangle","text":"abstract type AbstractSymmetricMatrixSetTriangle <: AbstractVectorSet end\n\nAbstract supertype for subsets of the (vectorized) cone of symmetric matrices, with side_dimension rows and columns. The entries of the upper-right triangular part of the matrix are given column by column (or equivalently, the entries of the lower-left triangular part are given row by row). A vectorized cone of dimension n corresponds to a square matrix with side dimension sqrt14 + 2 n - 12. (Because a d times d matrix has d(d + 1) 2 elements in the upper or lower triangle.)\n\nExample\n\nThe matrix\n\nbeginbmatrix\n 1 2 4\n 2 3 5\n 4 5 6\nendbmatrix\n\nhas side_dimension 3 and vectorization (1 2 3 4 5 6).\n\nNote\n\nTwo packed storage formats exist for symmetric matrices, the respective orders of the entries are:\n\nupper triangular column by column (or lower triangular row by row);\nlower triangular column by column (or upper triangular row by row).\n\nThe advantage of the first format is the mapping between the (i, j) matrix indices and the k index of the vectorized form. It is simpler and does not depend on the side dimension of the matrix. Indeed,\n\nthe entry of matrix indices (i, j) has vectorized index k = div((j - 1) * j, 2) + i if i leq j and k = div((i - 1) * i, 2) + j if j leq i;\nand the entry with vectorized index k has matrix indices i = div(1 + isqrt(8k - 7), 2) and j = k - div((i - 1) * i, 2) or j = div(1 + isqrt(8k - 7), 2) and i = k - div((j - 1) * j, 2).\n\nDuality note\n\nThe scalar product for the symmetric matrix in its vectorized form is the sum of the pairwise product of the diagonal entries plus twice the sum of the pairwise product of the upper diagonal entries; see [p. 634, 1]. This has important consequence for duality.\n\nConsider for example the following problem (PositiveSemidefiniteConeTriangle is a subtype of AbstractSymmetricMatrixSetTriangle)\n\nbeginalign*\n max_x in mathbbR x\n \n textst \n (1 -x 1) in textPositiveSemidefiniteConeTriangle(2)\nendalign*\n\nThe dual is the following problem\n\nbeginalign*\n min_x in mathbbR^3 y_1 + y_3\n \n textst 2y_2 = 1\n y in textPositiveSemidefiniteConeTriangle(2)\nendalign*\n\nWhy do we use 2y_2 in the dual constraint instead of y_2 ? The reason is that 2y_2 is the scalar product between y and the symmetric matrix whose vectorized form is (0 1 0). Indeed, with our modified scalar products we have\n\nlangle\n(0 1 0)\n(y_1 y_2 y_3)\nrangle\n=\nmathrmtrace\nbeginpmatrix\n 0 1\n 1 0\nendpmatrix\nbeginpmatrix\n y_1 y_2\n y_2 y_3\nendpmatrix\n= 2y_2\n\nReferences\n\n[1] Boyd, S. and Vandenberghe, L.. Convex optimization. Cambridge university press, 2004.\n\n\n\n\n\n","category":"type"},{"location":"reference/standard_form/#MathOptInterface.AbstractSymmetricMatrixSetSquare","page":"Standard form","title":"MathOptInterface.AbstractSymmetricMatrixSetSquare","text":"abstract type AbstractSymmetricMatrixSetSquare <: AbstractVectorSet end\n\nAbstract supertype for subsets of the (vectorized) cone of symmetric matrices, with side_dimension rows and columns. The entries of the matrix are given column by column (or equivalently, row by row). The matrix is both constrained to be symmetric and to have its triangular_form belong to the corresponding set. That is, if the functions in entries (i j) and (j i) are different, then a constraint will be added to make sure that the entries are equal.\n\nExample\n\nPositiveSemidefiniteConeSquare is a subtype of AbstractSymmetricMatrixSetSquare and constraining the matrix\n\nbeginbmatrix\n 1 -y\n -z 0\nendbmatrix\n\nto be symmetric positive semidefinite can be achieved by constraining the vector (1 -z -y 0) (or (1 -y -z 0)) to belong to the PositiveSemidefiniteConeSquare(2). It both constrains y = z and (1 -y 0) (or (1 -z 0)) to be in PositiveSemidefiniteConeTriangle(2), since triangular_form(PositiveSemidefiniteConeSquare) is PositiveSemidefiniteConeTriangle.\n\n\n\n\n\n","category":"type"},{"location":"reference/standard_form/#MathOptInterface.side_dimension","page":"Standard form","title":"MathOptInterface.side_dimension","text":"side_dimension(\n set::Union{\n AbstractSymmetricMatrixSetTriangle,\n AbstractSymmetricMatrixSetSquare,\n HermitianPositiveSemidefiniteConeTriangle,\n },\n)\n\nSide dimension of the matrices in set.\n\nConvention\n\nBy convention, the side dimension should be stored in the side_dimension field. If this is not the case for a subtype of AbstractSymmetricMatrixSetTriangle, or AbstractSymmetricMatrixSetSquare you must implement this method.\n\n\n\n\n\n","category":"function"},{"location":"reference/standard_form/#MathOptInterface.triangular_form","page":"Standard form","title":"MathOptInterface.triangular_form","text":"triangular_form(S::Type{<:AbstractSymmetricMatrixSetSquare})\ntriangular_form(set::AbstractSymmetricMatrixSetSquare)\n\nReturn the AbstractSymmetricMatrixSetTriangle corresponding to the vectorization of the upper triangular part of matrices in the AbstractSymmetricMatrixSetSquare set.\n\n\n\n\n\n","category":"function"},{"location":"reference/standard_form/","page":"Standard form","title":"Standard form","text":"List of recognized matrix sets.","category":"page"},{"location":"reference/standard_form/","page":"Standard form","title":"Standard form","text":"PositiveSemidefiniteConeTriangle\nPositiveSemidefiniteConeSquare\nHermitianPositiveSemidefiniteConeTriangle\nLogDetConeTriangle\nLogDetConeSquare\nRootDetConeTriangle\nRootDetConeSquare","category":"page"},{"location":"reference/standard_form/#MathOptInterface.PositiveSemidefiniteConeTriangle","page":"Standard form","title":"MathOptInterface.PositiveSemidefiniteConeTriangle","text":"PositiveSemidefiniteConeTriangle(side_dimension::Int) <: AbstractSymmetricMatrixSetTriangle\n\nThe (vectorized) cone of symmetric positive semidefinite matrices, with non-negative side_dimension rows and columns.\n\nSee AbstractSymmetricMatrixSetTriangle for more details on the vectorized form.\n\n\n\n\n\n","category":"type"},{"location":"reference/standard_form/#MathOptInterface.PositiveSemidefiniteConeSquare","page":"Standard form","title":"MathOptInterface.PositiveSemidefiniteConeSquare","text":"PositiveSemidefiniteConeSquare(side_dimension::Int) <: AbstractSymmetricMatrixSetSquare\n\nThe cone of symmetric positive semidefinite matrices, with non-negative side length side_dimension.\n\nSee AbstractSymmetricMatrixSetSquare for more details on the vectorized form.\n\nThe entries of the matrix are given column by column (or equivalently, row by row).\n\nThe matrix is both constrained to be symmetric and to be positive semidefinite. That is, if the functions in entries (i j) and (j i) are different, then a constraint will be added to make sure that the entries are equal.\n\nExample\n\nConstraining the matrix\n\nbeginbmatrix\n 1 -y\n -z 0\nendbmatrix\n\nto be symmetric positive semidefinite can be achieved by constraining the vector (1 -z -y 0) (or (1 -y -z 0)) to belong to the PositiveSemidefiniteConeSquare(2).\n\nIt both constrains y = z and (1 -y 0) (or (1 -z 0)) to be in PositiveSemidefiniteConeTriangle(2).\n\n\n\n\n\n","category":"type"},{"location":"reference/standard_form/#MathOptInterface.HermitianPositiveSemidefiniteConeTriangle","page":"Standard form","title":"MathOptInterface.HermitianPositiveSemidefiniteConeTriangle","text":"HermitianPositiveSemidefiniteConeTriangle(side_dimension::Int) <: AbstractVectorSet\n\nThe (vectorized) cone of Hermitian positive semidefinite matrices, with non-negative side_dimension rows and columns.\n\nBecaue the matrix is Hermitian, the diagonal elements are real, and the complex-valued lower triangular entries are obtained as the conjugate of corresponding upper triangular entries.\n\nVectorization format\n\nThe vectorized form starts with real part of the entries of the upper triangular part of the matrix, given column by column as explained in AbstractSymmetricMatrixSetSquare.\n\nIt is then followed by the imaginary part of the off-diagonal entries of the upper triangular part, also given column by column.\n\nFor example, the matrix\n\nbeginbmatrix\n 1 2 + 7im 4 + 8im\n 2 - 7im 3 5 + 9im\n 4 - 8im 5 - 9im 6\nendbmatrix\n\nhas side_dimension 3 and is represented as the vector 1 2 3 4 5 6 7 8 9.\n\n\n\n\n\n","category":"type"},{"location":"reference/standard_form/#MathOptInterface.LogDetConeTriangle","page":"Standard form","title":"MathOptInterface.LogDetConeTriangle","text":"LogDetConeTriangle(side_dimension::Int)\n\nThe log-determinant cone (t u X) in mathbbR^2 + d(d+1)2 t le u log(det(Xu)) u 0 , where the matrix X is represented in the same symmetric packed format as in the PositiveSemidefiniteConeTriangle.\n\nThe non-negative argument side_dimension is the side dimension of the matrix X, i.e., its number of rows or columns.\n\nExample\n\njulia> import MathOptInterface as MOI\n\njulia> model = MOI.Utilities.Model{Float64}()\nMOIU.Model{Float64}\n\njulia> t = MOI.add_variable(model)\nMOI.VariableIndex(1)\n\njulia> X = MOI.add_variables(model, 3);\n\njulia> MOI.add_constraint(\n model,\n MOI.VectorOfVariables([t; X]),\n MOI.LogDetConeTriangle(2),\n )\nMathOptInterface.ConstraintIndex{MathOptInterface.VectorOfVariables, MathOptInterface.LogDetConeTriangle}(1)\n\n\n\n\n\n","category":"type"},{"location":"reference/standard_form/#MathOptInterface.LogDetConeSquare","page":"Standard form","title":"MathOptInterface.LogDetConeSquare","text":"LogDetConeSquare(side_dimension::Int)\n\nThe log-determinant cone (t u X) in mathbbR^2 + d^2 t le u log(det(Xu)) X text symmetric u 0 , where the matrix X is represented in the same format as in the PositiveSemidefiniteConeSquare.\n\nSimilarly to PositiveSemidefiniteConeSquare, constraints are added to ensure that X is symmetric.\n\nThe non-negative argument side_dimension is the side dimension of the matrix X, i.e., its number of rows or columns.\n\nExample\n\njulia> import MathOptInterface as MOI\n\njulia> model = MOI.Utilities.Model{Float64}()\nMOIU.Model{Float64}\n\njulia> t = MOI.add_variable(model)\nMOI.VariableIndex(1)\n\njulia> X = reshape(MOI.add_variables(model, 4), 2, 2)\n2×2 Matrix{MathOptInterface.VariableIndex}:\n MOI.VariableIndex(2) MOI.VariableIndex(4)\n MOI.VariableIndex(3) MOI.VariableIndex(5)\n\njulia> MOI.add_constraint(\n model,\n MOI.VectorOfVariables([t; vec(X)]),\n MOI.LogDetConeSquare(2),\n )\nMathOptInterface.ConstraintIndex{MathOptInterface.VectorOfVariables, MathOptInterface.LogDetConeSquare}(1)\n\n\n\n\n\n","category":"type"},{"location":"reference/standard_form/#MathOptInterface.RootDetConeTriangle","page":"Standard form","title":"MathOptInterface.RootDetConeTriangle","text":"RootDetConeTriangle(side_dimension::Int)\n\nThe root-determinant cone (t X) in mathbbR^1 + d(d+1)2 t le det(X)^1d , where the matrix X is represented in the same symmetric packed format as in the PositiveSemidefiniteConeTriangle.\n\nThe non-negative argument side_dimension is the side dimension of the matrix X, i.e., its number of rows or columns.\n\nExample\n\njulia> import MathOptInterface as MOI\n\njulia> model = MOI.Utilities.Model{Float64}()\nMOIU.Model{Float64}\n\njulia> t = MOI.add_variable(model)\nMOI.VariableIndex(1)\n\njulia> X = MOI.add_variables(model, 3);\n\njulia> MOI.add_constraint(\n model,\n MOI.VectorOfVariables([t; X]),\n MOI.RootDetConeTriangle(2),\n )\nMathOptInterface.ConstraintIndex{MathOptInterface.VectorOfVariables, MathOptInterface.RootDetConeTriangle}(1)\n\n\n\n\n\n","category":"type"},{"location":"reference/standard_form/#MathOptInterface.RootDetConeSquare","page":"Standard form","title":"MathOptInterface.RootDetConeSquare","text":"RootDetConeSquare(side_dimension::Int)\n\nThe root-determinant cone (t X) in mathbbR^1 + d^2 t le det(X)^1d X text symmetric , where the matrix X is represented in the same format as PositiveSemidefiniteConeSquare.\n\nSimilarly to PositiveSemidefiniteConeSquare, constraints are added to ensure that X is symmetric.\n\nThe non-negative argument side_dimension is the side dimension of the matrix X, i.e., its number of rows or columns.\n\nExample\n\njulia> import MathOptInterface as MOI\n\njulia> model = MOI.Utilities.Model{Float64}()\nMOIU.Model{Float64}\n\njulia> t = MOI.add_variable(model)\nMOI.VariableIndex(1)\n\njulia> X = reshape(MOI.add_variables(model, 4), 2, 2)\n2×2 Matrix{MathOptInterface.VariableIndex}:\n MOI.VariableIndex(2) MOI.VariableIndex(4)\n MOI.VariableIndex(3) MOI.VariableIndex(5)\n\njulia> MOI.add_constraint(\n model,\n MOI.VectorOfVariables([t; vec(X)]),\n MOI.RootDetConeSquare(2),\n )\nMathOptInterface.ConstraintIndex{MathOptInterface.VectorOfVariables, MathOptInterface.RootDetConeSquare}(1)\n\n\n\n\n\n","category":"type"},{"location":"tutorials/latency/","page":"Latency","title":"Latency","text":"CurrentModule = MathOptInterface\nDocTestSetup = quote\n import MathOptInterface as MOI\nend\nDocTestFilters = [r\"MathOptInterface|MOI\"]","category":"page"},{"location":"tutorials/latency/#Latency","page":"Latency","title":"Latency","text":"","category":"section"},{"location":"tutorials/latency/","page":"Latency","title":"Latency","text":"MathOptInterface suffers the \"time-to-first-solve\" problem of start-up latency.","category":"page"},{"location":"tutorials/latency/","page":"Latency","title":"Latency","text":"This hurts both the user- and developer-experience of MathOptInterface. In the first case, because simple models have a multi-second delay before solving, and in the latter, because our tests take so long to run.","category":"page"},{"location":"tutorials/latency/","page":"Latency","title":"Latency","text":"This page contains some advice on profiling and fixing latency-related problems in the MathOptInterface.jl repository.","category":"page"},{"location":"tutorials/latency/#Background","page":"Latency","title":"Background","text":"","category":"section"},{"location":"tutorials/latency/","page":"Latency","title":"Latency","text":"Before reading this part of the documentation, you should familiarize yourself with the reasons for latency in Julia and how to fix them.","category":"page"},{"location":"tutorials/latency/","page":"Latency","title":"Latency","text":"Read the blogposts on julialang.org on precompilation and SnoopCompile\nRead the SnoopCompile documentation.\nWatch Tim Holy's talk at JuliaCon 2021\nWatch the package development workshop at JuliaCon 2021","category":"page"},{"location":"tutorials/latency/#Causes","page":"Latency","title":"Causes","text":"","category":"section"},{"location":"tutorials/latency/","page":"Latency","title":"Latency","text":"There are three main causes of latency in MathOptInterface:","category":"page"},{"location":"tutorials/latency/","page":"Latency","title":"Latency","text":"A large number of types\nLack of method ownership\nType-instability in the bridge layer","category":"page"},{"location":"tutorials/latency/#A-large-number-of-types","page":"Latency","title":"A large number of types","text":"","category":"section"},{"location":"tutorials/latency/","page":"Latency","title":"Latency","text":"Julia is very good at specializing method calls based on the input type. Each specialization has a compilation cost, but the benefit of faster run-time performance.","category":"page"},{"location":"tutorials/latency/","page":"Latency","title":"Latency","text":"The best-case scenario is for a method to be called a large number of times with a single set of argument types. The worst-case scenario is for a method to be called a single time for a large set of argument types.","category":"page"},{"location":"tutorials/latency/","page":"Latency","title":"Latency","text":"Because of MathOptInterface's function-in-set formulation, we fall into the worst-case situation.","category":"page"},{"location":"tutorials/latency/","page":"Latency","title":"Latency","text":"This is a fundamental limitation of Julia, so there isn't much we can do about it. However, if we can precompile MathOptInterface, much of the cost can be shifted from start-up latency to the time it takes to precompile a package on installation.","category":"page"},{"location":"tutorials/latency/","page":"Latency","title":"Latency","text":"However, there are two things which make MathOptInterface hard to precompile.","category":"page"},{"location":"tutorials/latency/#Lack-of-method-ownership","page":"Latency","title":"Lack of method ownership","text":"","category":"section"},{"location":"tutorials/latency/","page":"Latency","title":"Latency","text":"Lack of method ownership happens when a call is made using a mix of structs and methods from different modules. Because of this, no single module \"owns\" the method that is being dispatched, and so it cannot be precompiled.","category":"page"},{"location":"tutorials/latency/","page":"Latency","title":"Latency","text":"tip: Tip\nThis is a slightly simplified explanation. Read the precompilation tutorial for a more in-depth discussion on back-edges.","category":"page"},{"location":"tutorials/latency/","page":"Latency","title":"Latency","text":"Unfortunately, the design of MOI means that this is a frequent occurrence: we have a bunch of types in MOI.Utilities that wrap types defined in external packages (for example, the Optimizers), which implement methods of functions defined in MOI (for example, add_variable, add_constraint).","category":"page"},{"location":"tutorials/latency/","page":"Latency","title":"Latency","text":"Here's a simple example of method-ownership in practice:","category":"page"},{"location":"tutorials/latency/","page":"Latency","title":"Latency","text":"module MyMOI\nstruct Wrapper{T}\n inner::T\nend\noptimize!(x::Wrapper) = optimize!(x.inner)\nend # MyMOI\n\nmodule MyOptimizer\nusing ..MyMOI\nstruct Optimizer end\nMyMOI.optimize!(x::Optimizer) = 1\nend # MyOptimizer\n\nusing SnoopCompile\nmodel = MyMOI.Wrapper(MyOptimizer.Optimizer())\n\njulia> tinf = @snoopi_deep MyMOI.optimize!(model)\nInferenceTimingNode: 0.008256/0.008543 on InferenceFrameInfo for Core.Compiler.Timings.ROOT() with 1 direct children","category":"page"},{"location":"tutorials/latency/","page":"Latency","title":"Latency","text":"The result is that there was one method that required type inference. If we visualize tinf:","category":"page"},{"location":"tutorials/latency/","page":"Latency","title":"Latency","text":"using ProfileView\nProfileView.view(flamegraph(tinf))","category":"page"},{"location":"tutorials/latency/","page":"Latency","title":"Latency","text":"we see a flamegraph with a large red-bar indicating that the method MyMOI.optimize(MyMOI.Wrapper{MyOptimizer.Optimizer}) cannot be precompiled.","category":"page"},{"location":"tutorials/latency/","page":"Latency","title":"Latency","text":"To fix this, we need to designate a module to \"own\" that method (that is, create a back-edge). The easiest way to do this is for MyOptimizer to call MyMOI.optimize(MyMOI.Wrapper{MyOptimizer.Optimizer}) during using MyOptimizer. Let's see that in practice:","category":"page"},{"location":"tutorials/latency/","page":"Latency","title":"Latency","text":"module MyMOI\nstruct Wrapper{T}\n inner::T\nend\noptimize(x::Wrapper) = optimize(x.inner)\nend # MyMOI\n\nmodule MyOptimizer\nusing ..MyMOI\nstruct Optimizer end\nMyMOI.optimize(x::Optimizer) = 1\n# The syntax of this let-while loop is very particular:\n# * `let ... end` keeps everything local to avoid polluting the MyOptimizer\n# namespace\n# * `while true ... break end` runs the code once, and forces Julia to compile\n# the inner loop, rather than interpret it.\nlet\n while true\n model = MyMOI.Wrapper(Optimizer())\n MyMOI.optimize(model)\n break\n end\nend\nend # MyOptimizer\n\nusing SnoopCompile\nmodel = MyMOI.Wrapper(MyOptimizer.Optimizer())\n\njulia> tinf = @snoopi_deep MyMOI.optimize(model)\nInferenceTimingNode: 0.006822/0.006822 on InferenceFrameInfo for Core.Compiler.Timings.ROOT() with 0 direct children","category":"page"},{"location":"tutorials/latency/","page":"Latency","title":"Latency","text":"There are now 0 direct children that required type inference because the method was already stored in MyOptimizer!","category":"page"},{"location":"tutorials/latency/","page":"Latency","title":"Latency","text":"Unfortunately, this trick only works if the call-chain is fully inferrable. If there are breaks (due to type instability), then the benefit of doing this is reduced. And unfortunately for us, the design of MathOptInterface has a lot of type instabilities.","category":"page"},{"location":"tutorials/latency/#Type-instability-in-the-bridge-layer","page":"Latency","title":"Type instability in the bridge layer","text":"","category":"section"},{"location":"tutorials/latency/","page":"Latency","title":"Latency","text":"Most of MathOptInterface is pretty good at ensuring type-stability. However, a key component is not type stable, and that is the bridging layer.","category":"page"},{"location":"tutorials/latency/","page":"Latency","title":"Latency","text":"In particular, the bridging layer defines Bridges.LazyBridgeOptimizer, which has fields like:","category":"page"},{"location":"tutorials/latency/","page":"Latency","title":"Latency","text":"struct LazyBridgeOptimizer\n constraint_bridge_types::Vector{Any}\n constraint_node::Dict{Tuple{Type,Type},ConstraintNode}\n constraint_types::Vector{Tuple{Type,Type}}\nend","category":"page"},{"location":"tutorials/latency/","page":"Latency","title":"Latency","text":"This is because the LazyBridgeOptimizer needs to be able to deal with any function-in-set type passed to it, and we also allow users to pass additional bridges that they defined in external packages.","category":"page"},{"location":"tutorials/latency/","page":"Latency","title":"Latency","text":"So to recap, MathOptInterface suffers package latency because:","category":"page"},{"location":"tutorials/latency/","page":"Latency","title":"Latency","text":"there are a large number of types and functions\nand these are split between multiple modules, including external packages\nand there are type-instabilities like those in the bridging layer.","category":"page"},{"location":"tutorials/latency/#Resolutions","page":"Latency","title":"Resolutions","text":"","category":"section"},{"location":"tutorials/latency/","page":"Latency","title":"Latency","text":"There are no magic solutions to reduce latency. Issue #1313 tracks progress on reducing latency in MathOptInterface.","category":"page"},{"location":"tutorials/latency/","page":"Latency","title":"Latency","text":"A useful script is the following (replace GLPK as needed):","category":"page"},{"location":"tutorials/latency/","page":"Latency","title":"Latency","text":"import GLPK\nimport MathOptInterface as MOI\n\nfunction example_diet(optimizer, bridge)\n category_data = [\n 1800.0 2200.0;\n 91.0 Inf;\n 0.0 65.0;\n 0.0 1779.0\n ]\n cost = [2.49, 2.89, 1.50, 1.89, 2.09, 1.99, 2.49, 0.89, 1.59]\n food_data = [\n 410 24 26 730;\n 420 32 10 1190;\n 560 20 32 1800;\n 380 4 19 270;\n 320 12 10 930;\n 320 15 12 820;\n 320 31 12 1230;\n 100 8 2.5 125;\n 330 8 10 180\n ]\n bridge_model = if bridge\n MOI.instantiate(optimizer; with_bridge_type=Float64)\n else\n MOI.instantiate(optimizer)\n end\n model = MOI.Utilities.CachingOptimizer(\n MOI.Utilities.UniversalFallback(MOI.Utilities.Model{Float64}()),\n MOI.Utilities.AUTOMATIC,\n )\n MOI.Utilities.reset_optimizer(model, bridge_model)\n MOI.set(model, MOI.Silent(), true)\n nutrition = MOI.add_variables(model, size(category_data, 1))\n for (i, v) in enumerate(nutrition)\n MOI.add_constraint(model, v, MOI.GreaterThan(category_data[i, 1]))\n MOI.add_constraint(model, v, MOI.LessThan(category_data[i, 2]))\n end\n buy = MOI.add_variables(model, size(food_data, 1))\n MOI.add_constraint.(model, buy, MOI.GreaterThan(0.0))\n MOI.set(model, MOI.ObjectiveSense(), MOI.MIN_SENSE)\n f = MOI.ScalarAffineFunction(MOI.ScalarAffineTerm.(cost, buy), 0.0)\n MOI.set(model, MOI.ObjectiveFunction{typeof(f)}(), f)\n for (j, n) in enumerate(nutrition)\n f = MOI.ScalarAffineFunction(\n MOI.ScalarAffineTerm.(food_data[:, j], buy),\n 0.0,\n )\n push!(f.terms, MOI.ScalarAffineTerm(-1.0, n))\n MOI.add_constraint(model, f, MOI.EqualTo(0.0))\n end\n MOI.optimize!(model)\n term_status = MOI.get(model, MOI.TerminationStatus())\n @assert term_status == MOI.OPTIMAL\n MOI.add_constraint(\n model,\n MOI.ScalarAffineFunction(\n MOI.ScalarAffineTerm.(1.0, [buy[end-1], buy[end]]),\n 0.0,\n ),\n MOI.LessThan(6.0),\n )\n MOI.optimize!(model)\n @assert MOI.get(model, MOI.TerminationStatus()) == MOI.INFEASIBLE\n return\nend\n\nif length(ARGS) > 0\n bridge = get(ARGS, 2, \"\") != \"--no-bridge\"\n println(\"Running: $(ARGS[1]) $(get(ARGS, 2, \"\"))\")\n @time example_diet(GLPK.Optimizer, bridge)\n @time example_diet(GLPK.Optimizer, bridge)\n exit(0)\nend","category":"page"},{"location":"tutorials/latency/","page":"Latency","title":"Latency","text":"You can create a flame-graph via","category":"page"},{"location":"tutorials/latency/","page":"Latency","title":"Latency","text":"using SnoopComile\ntinf = @snoopi_deep example_diet(GLPK.Optimizer, true)\nusing ProfileView\nProfileView.view(flamegraph(tinf))","category":"page"},{"location":"tutorials/latency/","page":"Latency","title":"Latency","text":"Here's how things looked in mid-August 2021: (Image: flamegraph)","category":"page"},{"location":"tutorials/latency/","page":"Latency","title":"Latency","text":"There are a few opportunities for improvement (non-red flames, particularly on the right). But the main problem is a large red (non-precompilable due to method ownership) flame.","category":"page"},{"location":"tutorials/manipulating_expressions/","page":"Manipulating expressions","title":"Manipulating expressions","text":"CurrentModule = MathOptInterface\nDocTestSetup = quote\n import MathOptInterface as MOI\nend\nDocTestFilters = [r\"MathOptInterface|MOI\"]","category":"page"},{"location":"tutorials/manipulating_expressions/#Manipulating-expressions","page":"Manipulating expressions","title":"Manipulating expressions","text":"","category":"section"},{"location":"tutorials/manipulating_expressions/","page":"Manipulating expressions","title":"Manipulating expressions","text":"This guide highlights a syntactically appealing way to build expressions at the MOI level, but also to look at their contents. It may be especially useful when writing models or bridge code.","category":"page"},{"location":"tutorials/manipulating_expressions/#Creating-functions","page":"Manipulating expressions","title":"Creating functions","text":"","category":"section"},{"location":"tutorials/manipulating_expressions/","page":"Manipulating expressions","title":"Manipulating expressions","text":"This section details the ways to create functions with MathOptInterface.","category":"page"},{"location":"tutorials/manipulating_expressions/#Creating-scalar-affine-functions","page":"Manipulating expressions","title":"Creating scalar affine functions","text":"","category":"section"},{"location":"tutorials/manipulating_expressions/","page":"Manipulating expressions","title":"Manipulating expressions","text":"The simplest scalar function is simply a variable:","category":"page"},{"location":"tutorials/manipulating_expressions/","page":"Manipulating expressions","title":"Manipulating expressions","text":"julia> x = MOI.add_variable(model) # Create the variable x\nMOI.VariableIndex(1)","category":"page"},{"location":"tutorials/manipulating_expressions/","page":"Manipulating expressions","title":"Manipulating expressions","text":"This type of function is extremely simple; to express more complex functions, other types must be used. For instance, a ScalarAffineFunction is a sum of linear terms (a factor times a variable) and a constant. Such an object can be built using the standard constructor:","category":"page"},{"location":"tutorials/manipulating_expressions/","page":"Manipulating expressions","title":"Manipulating expressions","text":"julia> f = MOI.ScalarAffineFunction([MOI.ScalarAffineTerm(1, x)], 2) # x + 2\n(2) + (1) MOI.VariableIndex(1)","category":"page"},{"location":"tutorials/manipulating_expressions/","page":"Manipulating expressions","title":"Manipulating expressions","text":"However, you can also use operators to build the same scalar function:","category":"page"},{"location":"tutorials/manipulating_expressions/","page":"Manipulating expressions","title":"Manipulating expressions","text":"julia> f = x + 2\n(2) + (1) MOI.VariableIndex(1)","category":"page"},{"location":"tutorials/manipulating_expressions/#Creating-scalar-quadratic-functions","page":"Manipulating expressions","title":"Creating scalar quadratic functions","text":"","category":"section"},{"location":"tutorials/manipulating_expressions/","page":"Manipulating expressions","title":"Manipulating expressions","text":"Scalar quadratic functions are stored in ScalarQuadraticFunction objects, in a way that is highly similar to scalar affine functions. You can obtain a quadratic function as a product of affine functions:","category":"page"},{"location":"tutorials/manipulating_expressions/","page":"Manipulating expressions","title":"Manipulating expressions","text":"julia> 1 * x * x\n(0) + 1.0 MOI.VariableIndex(1)²\n\njulia> f * f # (x + 2)²\n(4) + (2) MOI.VariableIndex(1) + (2) MOI.VariableIndex(1) + 1.0 MOI.VariableIndex(1)²\n\njulia> f^2 # (x + 2)² too\n(4) + (2) MOI.VariableIndex(1) + (2) MOI.VariableIndex(1) + 1.0 MOI.VariableIndex(1)²","category":"page"},{"location":"tutorials/manipulating_expressions/#Creating-vector-functions","page":"Manipulating expressions","title":"Creating vector functions","text":"","category":"section"},{"location":"tutorials/manipulating_expressions/","page":"Manipulating expressions","title":"Manipulating expressions","text":"A vector function is a function with several values, irrespective of the number of input variables. Similarly to scalar functions, there are three main types of vector functions: VectorOfVariables, VectorAffineFunction, and VectorQuadraticFunction.","category":"page"},{"location":"tutorials/manipulating_expressions/","page":"Manipulating expressions","title":"Manipulating expressions","text":"The easiest way to create a vector function is to stack several scalar functions using Utilities.vectorize. It takes a vector as input, and the generated vector function (of the most appropriate type) has each dimension corresponding to a dimension of the vector.","category":"page"},{"location":"tutorials/manipulating_expressions/","page":"Manipulating expressions","title":"Manipulating expressions","text":"julia> g = MOI.Utilities.vectorize([f, 2 * f])\n┌ ┐\n│(2) + (1) MOI.VariableIndex(1)│\n│(4) + (2) MOI.VariableIndex(1)│\n└ ┘","category":"page"},{"location":"tutorials/manipulating_expressions/","page":"Manipulating expressions","title":"Manipulating expressions","text":"warning: Warning\nUtilities.vectorize only takes a vector of similar scalar functions: you cannot mix VariableIndex and ScalarAffineFunction, for instance. In practice, it means that Utilities.vectorize([x, f]) does not work; you should rather use Utilities.vectorize([1 * x, f]) instead to only have ScalarAffineFunction objects.","category":"page"},{"location":"tutorials/manipulating_expressions/#Canonicalizing-functions","page":"Manipulating expressions","title":"Canonicalizing functions","text":"","category":"section"},{"location":"tutorials/manipulating_expressions/","page":"Manipulating expressions","title":"Manipulating expressions","text":"In more advanced use cases, you might need to ensure that a function is \"canonical.\" Functions are stored as an array of terms, but there is no check that these terms are redundant: a ScalarAffineFunction object might have two terms with the same variable, like x + x + 1. These terms could be merged without changing the semantics of the function: 2x + 1.","category":"page"},{"location":"tutorials/manipulating_expressions/","page":"Manipulating expressions","title":"Manipulating expressions","text":"Working with these objects might be cumbersome. Canonicalization helps maintain redundancy to zero.","category":"page"},{"location":"tutorials/manipulating_expressions/","page":"Manipulating expressions","title":"Manipulating expressions","text":"Utilities.is_canonical checks whether a function is already in its canonical form:","category":"page"},{"location":"tutorials/manipulating_expressions/","page":"Manipulating expressions","title":"Manipulating expressions","text":"julia> MOI.Utilities.is_canonical(f + f) # (x + 2) + (x + 2) is stored as x + x + 4\nfalse","category":"page"},{"location":"tutorials/manipulating_expressions/","page":"Manipulating expressions","title":"Manipulating expressions","text":"Utilities.canonical returns the equivalent canonical version of the function:","category":"page"},{"location":"tutorials/manipulating_expressions/","page":"Manipulating expressions","title":"Manipulating expressions","text":"julia> MOI.Utilities.canonical(f + f) # Returns 2x + 4\n(4) + (2) MOI.VariableIndex(1)","category":"page"},{"location":"tutorials/manipulating_expressions/#Exploring-functions","page":"Manipulating expressions","title":"Exploring functions","text":"","category":"section"},{"location":"tutorials/manipulating_expressions/","page":"Manipulating expressions","title":"Manipulating expressions","text":"At some point, you might need to dig into a function, for instance to map it into solver constructs.","category":"page"},{"location":"tutorials/manipulating_expressions/#Vector-functions","page":"Manipulating expressions","title":"Vector functions","text":"","category":"section"},{"location":"tutorials/manipulating_expressions/","page":"Manipulating expressions","title":"Manipulating expressions","text":"Utilities.scalarize returns a vector of scalar functions from a vector function:","category":"page"},{"location":"tutorials/manipulating_expressions/","page":"Manipulating expressions","title":"Manipulating expressions","text":"julia> MOI.Utilities.scalarize(g) # Returns a vector [f, 2 * f].\n2-element Vector{MathOptInterface.ScalarAffineFunction{Int64}}:\n (2) + (1) MOI.VariableIndex(1)\n (4) + (2) MOI.VariableIndex(1)","category":"page"},{"location":"tutorials/manipulating_expressions/","page":"Manipulating expressions","title":"Manipulating expressions","text":"note: Note\nUtilities.eachscalar returns an iterator on the dimensions, which serves the same purpose as Utilities.scalarize.","category":"page"},{"location":"tutorials/manipulating_expressions/","page":"Manipulating expressions","title":"Manipulating expressions","text":"output_dimension returns the number of dimensions of the output of a function:","category":"page"},{"location":"tutorials/manipulating_expressions/","page":"Manipulating expressions","title":"Manipulating expressions","text":"julia> MOI.output_dimension(g)\n2","category":"page"},{"location":"manual/solutions/","page":"Solutions","title":"Solutions","text":"CurrentModule = MathOptInterface\nDocTestSetup = quote\n import MathOptInterface as MOI\nend\nDocTestFilters = [r\"MathOptInterface|MOI\"]","category":"page"},{"location":"manual/solutions/#manual_solutions","page":"Solutions","title":"Solutions","text":"","category":"section"},{"location":"manual/solutions/#Solving-and-retrieving-the-results","page":"Solutions","title":"Solving and retrieving the results","text":"","category":"section"},{"location":"manual/solutions/","page":"Solutions","title":"Solutions","text":"Once an optimizer is loaded with the objective function and all of the constraints, we can ask the solver to solve the model by calling optimize!.","category":"page"},{"location":"manual/solutions/","page":"Solutions","title":"Solutions","text":"MOI.optimize!(optimizer)","category":"page"},{"location":"manual/solutions/#Why-did-the-solver-stop?","page":"Solutions","title":"Why did the solver stop?","text":"","category":"section"},{"location":"manual/solutions/","page":"Solutions","title":"Solutions","text":"The optimization procedure may stop for a number of reasons. The TerminationStatus attribute of the optimizer returns a TerminationStatusCode object which explains why the solver stopped.","category":"page"},{"location":"manual/solutions/","page":"Solutions","title":"Solutions","text":"The termination statuses distinguish between proofs of optimality, infeasibility, local convergence, limits, and termination because of something unexpected like invalid problem data or failure to converge.","category":"page"},{"location":"manual/solutions/","page":"Solutions","title":"Solutions","text":"A typical usage of the TerminationStatus attribute is as follows:","category":"page"},{"location":"manual/solutions/","page":"Solutions","title":"Solutions","text":"status = MOI.get(optimizer, TerminationStatus())\nif status == MOI.OPTIMAL\n # Ok, we solved the problem!\nelse\n # Handle other cases.\nend","category":"page"},{"location":"manual/solutions/","page":"Solutions","title":"Solutions","text":"After checking the TerminationStatus, check ResultCount. This attribute returns the number of results that the solver has available to return. A result is defined as a primal-dual pair, but either the primal or the dual may be missing from the result. While the OPTIMAL termination status normally implies that at least one result is available, other statuses do not. For example, in the case of infeasibility, a solver may return no result or a proof of infeasibility. The ResultCount attribute distinguishes between these two cases.","category":"page"},{"location":"manual/solutions/#Primal-solutions","page":"Solutions","title":"Primal solutions","text":"","category":"section"},{"location":"manual/solutions/","page":"Solutions","title":"Solutions","text":"Use the PrimalStatus optimizer attribute to return a ResultStatusCode describing the status of the primal solution.","category":"page"},{"location":"manual/solutions/","page":"Solutions","title":"Solutions","text":"Common returns are described below in the Common status situations section.","category":"page"},{"location":"manual/solutions/","page":"Solutions","title":"Solutions","text":"Query the primal solution using the VariablePrimal and ConstraintPrimal attributes.","category":"page"},{"location":"manual/solutions/","page":"Solutions","title":"Solutions","text":"Query the objective function value using the ObjectiveValue attribute.","category":"page"},{"location":"manual/solutions/#Dual-solutions","page":"Solutions","title":"Dual solutions","text":"","category":"section"},{"location":"manual/solutions/","page":"Solutions","title":"Solutions","text":"warning: Warning\nSee Duality for a discussion of the MOI conventions for primal-dual pairs and certificates.","category":"page"},{"location":"manual/solutions/","page":"Solutions","title":"Solutions","text":"Use the DualStatus optimizer attribute to return a ResultStatusCode describing the status of the dual solution.","category":"page"},{"location":"manual/solutions/","page":"Solutions","title":"Solutions","text":"Query the dual solution using the ConstraintDual attribute.","category":"page"},{"location":"manual/solutions/","page":"Solutions","title":"Solutions","text":"Query the dual objective function value using the DualObjectiveValue attribute.","category":"page"},{"location":"manual/solutions/#Common-status-situations","page":"Solutions","title":"Common status situations","text":"","category":"section"},{"location":"manual/solutions/","page":"Solutions","title":"Solutions","text":"The sections below describe how to interpret typical or interesting status cases for three common classes of solvers. The example cases are illustrative, not comprehensive. Solver wrappers may provide additional information on how the solver's statuses map to MOI statuses.","category":"page"},{"location":"manual/solutions/","page":"Solutions","title":"Solutions","text":"info: Info\n* in the tables indicate that multiple different values are possible.","category":"page"},{"location":"manual/solutions/#Primal-dual-convex-solver","page":"Solutions","title":"Primal-dual convex solver","text":"","category":"section"},{"location":"manual/solutions/","page":"Solutions","title":"Solutions","text":"Linear programming and conic optimization solvers fall into this category.","category":"page"},{"location":"manual/solutions/","page":"Solutions","title":"Solutions","text":"What happened? TerminationStatus ResultCount PrimalStatus DualStatus\nProved optimality OPTIMAL 1 FEASIBLE_POINT FEASIBLE_POINT\nProved infeasible INFEASIBLE 1 NO_SOLUTION INFEASIBILITY_CERTIFICATE\nOptimal within relaxed tolerances ALMOST_OPTIMAL 1 FEASIBLE_POINT FEASIBLE_POINT\nOptimal within relaxed tolerances ALMOST_OPTIMAL 1 ALMOST_FEASIBLE_POINT ALMOST_FEASIBLE_POINT\nDetected an unbounded ray of the primal DUAL_INFEASIBLE 1 INFEASIBILITY_CERTIFICATE NO_SOLUTION\nStall SLOW_PROGRESS 1 * *","category":"page"},{"location":"manual/solutions/#Global-branch-and-bound-solvers","page":"Solutions","title":"Global branch-and-bound solvers","text":"","category":"section"},{"location":"manual/solutions/","page":"Solutions","title":"Solutions","text":"Mixed-integer programming solvers fall into this category.","category":"page"},{"location":"manual/solutions/","page":"Solutions","title":"Solutions","text":"What happened? TerminationStatus ResultCount PrimalStatus DualStatus\nProved optimality OPTIMAL 1 FEASIBLE_POINT NO_SOLUTION\nPresolve detected infeasibility or unboundedness INFEASIBLE_OR_UNBOUNDED 0 NO_SOLUTION NO_SOLUTION\nProved infeasibility INFEASIBLE 0 NO_SOLUTION NO_SOLUTION\nTimed out (no solution) TIME_LIMIT 0 NO_SOLUTION NO_SOLUTION\nTimed out (with a solution) TIME_LIMIT 1 FEASIBLE_POINT NO_SOLUTION\nCPXMIP_OPTIMAL_INFEAS ALMOST_OPTIMAL 1 INFEASIBLE_POINT NO_SOLUTION","category":"page"},{"location":"manual/solutions/","page":"Solutions","title":"Solutions","text":"info: Info\nCPXMIP_OPTIMAL_INFEAS is a CPLEX status that indicates that a preprocessed problem was solved to optimality, but the solver was unable to recover a feasible solution to the original problem. Handling this status was one of the motivating drivers behind the design of MOI.","category":"page"},{"location":"manual/solutions/#Local-search-solvers","page":"Solutions","title":"Local search solvers","text":"","category":"section"},{"location":"manual/solutions/","page":"Solutions","title":"Solutions","text":"Nonlinear programming solvers fall into this category. It also includes non-global tree search solvers like Juniper.","category":"page"},{"location":"manual/solutions/","page":"Solutions","title":"Solutions","text":"What happened? TerminationStatus ResultCount PrimalStatus DualStatus\nConverged to a stationary point LOCALLY_SOLVED 1 FEASIBLE_POINT FEASIBLE_POINT\nCompleted a non-global tree search (with a solution) LOCALLY_SOLVED 1 FEASIBLE_POINT FEASIBLE_POINT\nConverged to an infeasible point LOCALLY_INFEASIBLE 1 INFEASIBLE_POINT *\nCompleted a non-global tree search (no solution found) LOCALLY_INFEASIBLE 0 NO_SOLUTION NO_SOLUTION\nIteration limit ITERATION_LIMIT 1 * *\nDiverging iterates NORM_LIMIT or OBJECTIVE_LIMIT 1 * *","category":"page"},{"location":"manual/solutions/#Querying-solution-attributes","page":"Solutions","title":"Querying solution attributes","text":"","category":"section"},{"location":"manual/solutions/","page":"Solutions","title":"Solutions","text":"Some solvers will not implement every solution attribute. Therefore, a call like MOI.get(model, MOI.SolveTimeSec()) may throw an UnsupportedAttribute error.","category":"page"},{"location":"manual/solutions/","page":"Solutions","title":"Solutions","text":"If you need to write code that is agnostic to the solver (for example, you are writing a library that an end-user passes their choice of solver to), you can work-around this problem using a try-catch:","category":"page"},{"location":"manual/solutions/","page":"Solutions","title":"Solutions","text":"function get_solve_time(model)\n try\n return MOI.get(model, MOI.SolveTimeSec())\n catch err\n if err isa MOI.UnsupportedAttribute\n return NaN # Solver doesn't support. Return a placeholder value.\n end\n rethrow(err) # Something else went wrong. Rethrow the error\n end\nend","category":"page"},{"location":"manual/solutions/","page":"Solutions","title":"Solutions","text":"If, after careful profiling, you find that the try-catch is taking a significant portion of your runtime, you can improve performance by caching the result of the try-catch:","category":"page"},{"location":"manual/solutions/","page":"Solutions","title":"Solutions","text":"mutable struct CachedSolveTime{M}\n model::M\n supports_solve_time::Bool\n CachedSolveTime(model::M) where {M} = new(model, true)\nend\n\nfunction get_solve_time(model::CachedSolveTime)\n if !model.supports_solve_time\n return NaN\n end\n try\n return MOI.get(model, MOI.SolveTimeSec())\n catch err\n if err isa MOI.UnsupportedAttribute\n model.supports_solve_time = false\n return NaN\n end\n rethrow(err) # Something else went wrong. Rethrow the error\n end\nend","category":"page"},{"location":"submodules/Bridges/reference/","page":"API Reference","title":"API Reference","text":"CurrentModule = MathOptInterface\nDocTestSetup = quote\n import MathOptInterface as MOI\nend\nDocTestFilters = [r\"MathOptInterface|MOI\"]","category":"page"},{"location":"submodules/Bridges/reference/#Bridges","page":"API Reference","title":"Bridges","text":"","category":"section"},{"location":"submodules/Bridges/reference/#AbstractBridge-API","page":"API Reference","title":"AbstractBridge API","text":"","category":"section"},{"location":"submodules/Bridges/reference/","page":"API Reference","title":"API Reference","text":"Bridges.AbstractBridge\nBridges.added_constrained_variable_types\nBridges.added_constraint_types\nget(::Bridges.AbstractBridge, ::NumberOfVariables)\nget(::Bridges.AbstractBridge, ::ListOfVariableIndices)\nget(::Bridges.AbstractBridge, ::NumberOfConstraints)\nget(::Bridges.AbstractBridge, ::ListOfConstraintIndices)\nBridges.needs_final_touch\nBridges.final_touch\nBridges.bridging_cost","category":"page"},{"location":"submodules/Bridges/reference/#MathOptInterface.Bridges.AbstractBridge","page":"API Reference","title":"MathOptInterface.Bridges.AbstractBridge","text":"abstract type AbstractBridge end\n\nAn abstract type representing a bridged constraint or variable in a MOI.Bridges.AbstractBridgeOptimizer.\n\nAll bridges must implement:\n\nadded_constrained_variable_types\nadded_constraint_types\nMOI.get(::AbstractBridge, ::MOI.NumberOfVariables)\nMOI.get(::AbstractBridge, ::MOI.ListOfVariableIndices)\nMOI.get(::AbstractBridge, ::MOI.NumberOfConstraints)\nMOI.get(::AbstractBridge, ::MOI.ListOfConstraintIndices)\n\nSubtypes of AbstractBridge may have additional requirements. Consult their docstrings for details.\n\nIn addition, all subtypes may optionally implement the following constraint attributes with the bridge in place of the constraint index:\n\nMOI.ConstraintDual\nMOI.ConstraintPrimal\n\n\n\n\n\n","category":"type"},{"location":"submodules/Bridges/reference/#MathOptInterface.Bridges.added_constrained_variable_types","page":"API Reference","title":"MathOptInterface.Bridges.added_constrained_variable_types","text":"added_constrained_variable_types(\n BT::Type{<:AbstractBridge},\n)::Vector{Tuple{Type}}\n\nReturn a list of the types of constrained variables that bridges of concrete type BT add.\n\nImplementation notes\n\nThis method depends only on the type of the bridge, not the runtime value. If the bridge may add a constrained variable, the type must be included in the return vector.\nIf the bridge adds a free variable via MOI.add_variable or MOI.add_variables, the return vector must include (MOI.Reals,).\n\nExample\n\njulia> MOI.Bridges.added_constrained_variable_types(\n MOI.Bridges.Variable.NonposToNonnegBridge{Float64},\n )\n1-element Vector{Tuple{Type}}:\n (MathOptInterface.Nonnegatives,)\n\n\n\n\n\n","category":"function"},{"location":"submodules/Bridges/reference/#MathOptInterface.Bridges.added_constraint_types","page":"API Reference","title":"MathOptInterface.Bridges.added_constraint_types","text":"added_constraint_types(\n BT::Type{<:AbstractBridge},\n)::Vector{Tuple{Type,Type}}\n\nReturn a list of the types of constraints that bridges of concrete type BT add.\n\nImplementation notes\n\nThis method depends only on the type of the bridge, not the runtime value. If the bridge may add a constraint, the type must be included in the return vector.\n\nExample\n\njulia> MOI.Bridges.added_constraint_types(\n MOI.Bridges.Constraint.ZeroOneBridge{Float64},\n )\n2-element Vector{Tuple{Type, Type}}:\n (MathOptInterface.ScalarAffineFunction{Float64}, MathOptInterface.Interval{Float64})\n (MathOptInterface.VariableIndex, MathOptInterface.Integer)\n\n\n\n\n\n","category":"function"},{"location":"submodules/Bridges/reference/#MathOptInterface.get-Tuple{MathOptInterface.Bridges.AbstractBridge, MathOptInterface.NumberOfVariables}","page":"API Reference","title":"MathOptInterface.get","text":"MOI.get(b::AbstractBridge, ::MOI.NumberOfVariables)::Int64\n\nReturn the number of variables created by the bridge b in the model.\n\nSee also MOI.NumberOfConstraints.\n\nImplementation notes\n\nThere is a default fallback, so you need only implement this if the bridge adds new variables.\n\n\n\n\n\n","category":"method"},{"location":"submodules/Bridges/reference/#MathOptInterface.get-Tuple{MathOptInterface.Bridges.AbstractBridge, MathOptInterface.ListOfVariableIndices}","page":"API Reference","title":"MathOptInterface.get","text":"MOI.get(b::AbstractBridge, ::MOI.ListOfVariableIndices)\n\nReturn the list of variables created by the bridge b.\n\nSee also MOI.ListOfVariableIndices.\n\nImplementation notes\n\nThere is a default fallback, so you need only implement this if the bridge adds new variables.\n\n\n\n\n\n","category":"method"},{"location":"submodules/Bridges/reference/#MathOptInterface.get-Tuple{MathOptInterface.Bridges.AbstractBridge, MathOptInterface.NumberOfConstraints}","page":"API Reference","title":"MathOptInterface.get","text":"MOI.get(b::AbstractBridge, ::MOI.NumberOfConstraints{F,S})::Int64 where {F,S}\n\nReturn the number of constraints of the type F-in-S created by the bridge b.\n\nSee also MOI.NumberOfConstraints.\n\nImplementation notes\n\nThere is a default fallback, so you need only implement this for the constraint types returned by added_constraint_types.\n\n\n\n\n\n","category":"method"},{"location":"submodules/Bridges/reference/#MathOptInterface.get-Tuple{MathOptInterface.Bridges.AbstractBridge, MathOptInterface.ListOfConstraintIndices}","page":"API Reference","title":"MathOptInterface.get","text":"MOI.get(b::AbstractBridge, ::MOI.ListOfConstraintIndices{F,S}) where {F,S}\n\nReturn a Vector{ConstraintIndex{F,S}} with indices of all constraints of type F-in-S created by the bride b.\n\nSee also MOI.ListOfConstraintIndices.\n\nImplementation notes\n\nThere is a default fallback, so you need only implement this for the constraint types returned by added_constraint_types.\n\n\n\n\n\n","category":"method"},{"location":"submodules/Bridges/reference/#MathOptInterface.Bridges.needs_final_touch","page":"API Reference","title":"MathOptInterface.Bridges.needs_final_touch","text":"needs_final_touch(bridge::AbstractBridge)::Bool\n\nReturn whether final_touch is implemented by bridge.\n\n\n\n\n\n","category":"function"},{"location":"submodules/Bridges/reference/#MathOptInterface.Bridges.final_touch","page":"API Reference","title":"MathOptInterface.Bridges.final_touch","text":"final_touch(bridge::AbstractBridge, model::MOI.ModelLike)::Nothing\n\nA function that is called immediately prior to MOI.optimize! to allow bridges to modify their reformulations with repsect to other variables and constraints in model.\n\nFor example, if the correctness of bridge depends on the bounds of a variable or the fact that variables are integer, then the bridge can implement final_touch to check assumptions immediately before a call to MOI.optimize!.\n\nIf you implement this method, you must also implement needs_final_touch.\n\n\n\n\n\n","category":"function"},{"location":"submodules/Bridges/reference/#MathOptInterface.Bridges.bridging_cost","page":"API Reference","title":"MathOptInterface.Bridges.bridging_cost","text":"bridging_cost(b::AbstractBridgeOptimizer, S::Type{<:MOI.AbstractSet}})\n\nReturn the cost of bridging variables constrained in S on creation, is_bridged(b, S) is assumed to be true.\n\nbridging_cost(\n b::AbstractBridgeOptimizer,\n F::Type{<:MOI.AbstractFunction},\n S::Type{<:MOI.AbstractSet},\n)\n\nReturn the cost of bridging F-in-S constraints.\n\nis_bridged(b, S) is assumed to be true.\n\n\n\n\n\n","category":"function"},{"location":"submodules/Bridges/reference/#Constraint-bridge-API","page":"API Reference","title":"Constraint bridge API","text":"","category":"section"},{"location":"submodules/Bridges/reference/","page":"API Reference","title":"API Reference","text":"Bridges.Constraint.AbstractBridge\nsupports_constraint(::Type{<:Bridges.Constraint.AbstractBridge}, ::Type{<:AbstractFunction}, ::Type{<:AbstractSet})\nBridges.Constraint.concrete_bridge_type\nBridges.Constraint.bridge_constraint\nBridges.Constraint.AbstractFunctionConversionBridge\nBridges.Constraint.SingleBridgeOptimizer\nBridges.Constraint.add_all_bridges\nBridges.Constraint.FlipSignBridge\nBridges.Constraint.AbstractToIntervalBridge\nBridges.Constraint.SetMapBridge\nBridges.Constraint.conversion_cost","category":"page"},{"location":"submodules/Bridges/reference/#MathOptInterface.Bridges.Constraint.AbstractBridge","page":"API Reference","title":"MathOptInterface.Bridges.Constraint.AbstractBridge","text":"abstract type AbstractBridge <: MOI.Bridges.AbstractType\n\nSubtype of MOI.Bridges.AbstractBridge for constraint bridges.\n\nIn addition to the required implementation described in MOI.Bridges.AbstractBridge, subtypes of AbstractBridge must additionally implement:\n\nMOI.supports_constraint(::Type{<:AbstractBridge}, ::Type{<:MOI.AbstractFunction}, ::Type{<:MOI.AbstractSet})\nconcrete_bridge_type\nbridge_constraint\n\n\n\n\n\n","category":"type"},{"location":"submodules/Bridges/reference/#MathOptInterface.supports_constraint-Tuple{Type{<:MathOptInterface.Bridges.Constraint.AbstractBridge}, Type{<:MathOptInterface.AbstractFunction}, Type{<:MathOptInterface.AbstractSet}}","page":"API Reference","title":"MathOptInterface.supports_constraint","text":"MOI.supports_constraint(\n BT::Type{<:AbstractBridge},\n F::Type{<:MOI.AbstractFunction},\n S::Type{<:MOI.AbstractSet},\n)::Bool\n\nReturn a Bool indicating whether the bridges of type BT support bridging F-in-S constraints.\n\nImplementation notes\n\nThis method depends only on the type of the inputs, not the runtime values.\nThere is a default fallback, so you need only implement this method for constraint types that the bridge implements.\n\n\n\n\n\n","category":"method"},{"location":"submodules/Bridges/reference/#MathOptInterface.Bridges.Constraint.concrete_bridge_type","page":"API Reference","title":"MathOptInterface.Bridges.Constraint.concrete_bridge_type","text":"concrete_bridge_type(\n BT::Type{<:AbstractBridge},\n F::Type{<:MOI.AbstractFunction},\n S::Type{<:MOI.AbstractSet}\n)::Type\n\nReturn the concrete type of the bridge supporting F-in-S constraints.\n\nThis function can only be called if MOI.supports_constraint(BT, F, S) is true.\n\nExample\n\nThe SplitIntervalBridge bridges a MOI.VariableIndex-in-MOI.Interval constraint into a MOI.VariableIndex-in-MOI.GreaterThan and a MOI.VariableIndex-in-MOI.LessThan constraint.\n\njulia> MOI.Bridges.Constraint.concrete_bridge_type(\n MOI.Bridges.Constraint.SplitIntervalBridge{Float64},\n MOI.VariableIndex,\n MOI.Interval{Float64},\n )\nMathOptInterface.Bridges.Constraint.SplitIntervalBridge{Float64, MathOptInterface.VariableIndex, MathOptInterface.Interval{Float64}, MathOptInterface.GreaterThan{Float64}, MathOptInterface.LessThan{Float64}}\n\n\n\n\n\n","category":"function"},{"location":"submodules/Bridges/reference/#MathOptInterface.Bridges.Constraint.bridge_constraint","page":"API Reference","title":"MathOptInterface.Bridges.Constraint.bridge_constraint","text":"bridge_constraint(\n BT::Type{<:AbstractBridge},\n model::MOI.ModelLike,\n func::AbstractFunction,\n set::MOI.AbstractSet,\n)::BT\n\nBridge the constraint func-in-set using bridge BT to model and returns a bridge object of type BT.\n\nImplementation notes\n\nThe bridge type BT should be a concrete type, that is, all the type parameters of the bridge must be set.\n\n\n\n\n\n","category":"function"},{"location":"submodules/Bridges/reference/#MathOptInterface.Bridges.Constraint.AbstractFunctionConversionBridge","page":"API Reference","title":"MathOptInterface.Bridges.Constraint.AbstractFunctionConversionBridge","text":"abstract type AbstractFunctionConversionBridge{F,S} <: AbstractBridge end\n\nAbstract type to support writing bridges in which the function changes but the set does not.\n\nBy convention, the transformed function is stored in the .constraint field.\n\n\n\n\n\n","category":"type"},{"location":"submodules/Bridges/reference/#MathOptInterface.Bridges.Constraint.SingleBridgeOptimizer","page":"API Reference","title":"MathOptInterface.Bridges.Constraint.SingleBridgeOptimizer","text":"SingleBridgeOptimizer{BT<:AbstractBridge}(model::MOI.ModelLike)\n\nReturn AbstractBridgeOptimizer that always bridges any objective function supported by the bridge BT.\n\nThis is in contrast with the MOI.Bridges.LazyBridgeOptimizer, which only bridges the objective function if it is supported by the bridge BT and unsupported by model.\n\nExample\n\njulia> struct MyNewBridge{T} <: MOI.Bridges.Constraint.AbstractBridge end\n\njulia> bridge = MOI.Bridges.Constraint.SingleBridgeOptimizer{MyNewBridge{Float64}}(\n MOI.Utilities.Model{Float64}(),\n )\nMOIB.Constraint.SingleBridgeOptimizer{MyNewBridge{Float64}, MOIU.Model{Float64}}\nwith 0 constraint bridges\nwith inner model MOIU.Model{Float64}\n\nImplementation notes\n\nAll bridges should simplify the creation of SingleBridgeOptimizers by defining a constant that wraps the bridge in a SingleBridgeOptimizer.\n\njulia> const MyNewBridgeModel{T,OT<:MOI.ModelLike} =\n MOI.Bridges.Constraint.SingleBridgeOptimizer{MyNewBridge{T},OT};\n\nThis enables users to create bridged models as follows:\n\njulia> MyNewBridgeModel{Float64}(MOI.Utilities.Model{Float64}())\nMOIB.Constraint.SingleBridgeOptimizer{MyNewBridge{Float64}, MOIU.Model{Float64}}\nwith 0 constraint bridges\nwith inner model MOIU.Model{Float64}\n\n\n\n\n\n","category":"type"},{"location":"submodules/Bridges/reference/#MathOptInterface.Bridges.Constraint.add_all_bridges","page":"API Reference","title":"MathOptInterface.Bridges.Constraint.add_all_bridges","text":"add_all_bridges(bridged_model, ::Type{T}) where {T}\n\nAdd all bridges defined in the Bridges.Constraint submodule to bridged_model. The coefficient type used is T.\n\n\n\n\n\n","category":"function"},{"location":"submodules/Bridges/reference/#MathOptInterface.Bridges.Constraint.FlipSignBridge","page":"API Reference","title":"MathOptInterface.Bridges.Constraint.FlipSignBridge","text":"FlipSignBridge{T,S1,S2,F,G}\n\nAn abstract type that simplifies the creation of other bridges.\n\n\n\n\n\n","category":"type"},{"location":"submodules/Bridges/reference/#MathOptInterface.Bridges.Constraint.AbstractToIntervalBridge","page":"API Reference","title":"MathOptInterface.Bridges.Constraint.AbstractToIntervalBridge","text":"AbstractToIntervalBridge{T<:AbstractFloat,S,F}\n\nAn abstract type that simplifies the creation of other bridges.\n\nwarning: Warning\nT must be a AbstractFloat type because otherwise typemin and typemax would either be not implemented (e.g. BigInt), or would not give infinite value (e.g. Int). For this reason, this bridge is only added to MOI.Bridges.full_bridge_optimizer when T is a subtype of AbstractFloat.\n\n\n\n\n\n","category":"type"},{"location":"submodules/Bridges/reference/#MathOptInterface.Bridges.Constraint.SetMapBridge","page":"API Reference","title":"MathOptInterface.Bridges.Constraint.SetMapBridge","text":"abstract type SetMapBridge{T,S2,S1,F,G} <: AbstractBridge end\n\nConsider two type of sets, S1 and S2, and a linear mapping A such that the image of a set of type S1 under A is a set of type S2.\n\nA SetMapBridge{T,S2,S1,F,G} is a bridge that maps G-in-S1 constraints into F-in-S2 by mapping the function through A.\n\nThe linear map A is described by;\n\nMOI.Bridges.map_set\nMOI.Bridges.map_function.\n\nImplementing a method for these two functions is sufficient to bridge constraints. However, in order for the getters and setters of attributes such as dual solutions and starting values to work as well, a method for the following functions must be implemented:\n\nMOI.Bridges.inverse_map_set\nMOI.Bridges.inverse_map_function\nMOI.Bridges.adjoint_map_function\nMOI.Bridges.inverse_adjoint_map_function\n\nSee the docstrings of each function to see which feature would be missing if it was not implemented for a given bridge.\n\n\n\n\n\n","category":"type"},{"location":"submodules/Bridges/reference/#MathOptInterface.Bridges.Constraint.conversion_cost","page":"API Reference","title":"MathOptInterface.Bridges.Constraint.conversion_cost","text":"conversion_cost(\n F::Type{<:MOI.AbstractFunction},\n G::Type{<:MOI.AbstractFunction},\n)::Float64\n\nReturn a Float64 returning the cost of converting any function of type G to a function of type F with convert.\n\nThis cost is used to compute MOI.Bridges.bridging_cost.\n\nThe default cost is Inf, which means that MOI.Bridges.Constraint.FunctionConversionBridge should not attempt the conversion.\n\n\n\n\n\n","category":"function"},{"location":"submodules/Bridges/reference/#Objective-bridge-API","page":"API Reference","title":"Objective bridge API","text":"","category":"section"},{"location":"submodules/Bridges/reference/","page":"API Reference","title":"API Reference","text":"Bridges.Objective.AbstractBridge\nBridges.Objective.supports_objective_function\nBridges.set_objective_function_type\nBridges.Objective.concrete_bridge_type\nBridges.Objective.bridge_objective\nBridges.Objective.SingleBridgeOptimizer\nBridges.Objective.add_all_bridges","category":"page"},{"location":"submodules/Bridges/reference/#MathOptInterface.Bridges.Objective.AbstractBridge","page":"API Reference","title":"MathOptInterface.Bridges.Objective.AbstractBridge","text":"abstract type AbstractBridge <: MOI.Bridges.AbstractBridge end\n\nSubtype of MOI.Bridges.AbstractBridge for objective bridges.\n\nIn addition to the required implementation described in MOI.Bridges.AbstractBridge, subtypes of AbstractBridge must additionally implement:\n\nsupports_objective_function\nconcrete_bridge_type\nbridge_objective\nMOI.Bridges.set_objective_function_type\n\n\n\n\n\n","category":"type"},{"location":"submodules/Bridges/reference/#MathOptInterface.Bridges.Objective.supports_objective_function","page":"API Reference","title":"MathOptInterface.Bridges.Objective.supports_objective_function","text":"supports_objective_function(\n BT::Type{<:MOI.Bridges.Objective.AbstractBridge},\n F::Type{<:MOI.AbstractFunction},\n)::Bool\n\nReturn a Bool indicating whether the bridges of type BT support bridging objective functions of type F.\n\nImplementation notes\n\nThis method depends only on the type of the inputs, not the runtime values.\nThere is a default fallback, so you need only implement this method For objective functions that the bridge implements.\n\n\n\n\n\n","category":"function"},{"location":"submodules/Bridges/reference/#MathOptInterface.Bridges.set_objective_function_type","page":"API Reference","title":"MathOptInterface.Bridges.set_objective_function_type","text":"set_objective_function_type(\n BT::Type{<:Objective.AbstractBridge},\n)::Type{<:MOI.AbstractFunction}\n\nReturn the type of objective function that bridges of concrete type BT set.\n\nImplementation notes\n\nThis method depends only on the type of the bridge, not the runtime value.\n\nExample\n\njulia> MOI.Bridges.set_objective_function_type(\n MOI.Bridges.Objective.FunctionizeBridge{Float64},\n )\nMathOptInterface.ScalarAffineFunction{Float64}\n\n\n\n\n\n","category":"function"},{"location":"submodules/Bridges/reference/#MathOptInterface.Bridges.Objective.concrete_bridge_type","page":"API Reference","title":"MathOptInterface.Bridges.Objective.concrete_bridge_type","text":"concrete_bridge_type(\n BT::Type{<:MOI.Bridges.Objective.AbstractBridge},\n F::Type{<:MOI.AbstractFunction},\n)::Type\n\nReturn the concrete type of the bridge supporting objective functions of type F.\n\nThis function can only be called if MOI.supports_objective_function(BT, F) is true.\n\n\n\n\n\n","category":"function"},{"location":"submodules/Bridges/reference/#MathOptInterface.Bridges.Objective.bridge_objective","page":"API Reference","title":"MathOptInterface.Bridges.Objective.bridge_objective","text":"bridge_objective(\n BT::Type{<:MOI.Bridges.Objective.AbstractBridge},\n model::MOI.ModelLike,\n func::MOI.AbstractFunction,\n)::BT\n\nBridge the objective function func using bridge BT to model and returns a bridge object of type BT.\n\nImplementation notes\n\nThe bridge type BT must be a concrete type, that is, all the type parameters of the bridge must be set.\n\n\n\n\n\n","category":"function"},{"location":"submodules/Bridges/reference/#MathOptInterface.Bridges.Objective.SingleBridgeOptimizer","page":"API Reference","title":"MathOptInterface.Bridges.Objective.SingleBridgeOptimizer","text":"SingleBridgeOptimizer{BT<:AbstractBridge}(model::MOI.ModelLike)\n\nReturn AbstractBridgeOptimizer that always bridges any objective function supported by the bridge BT.\n\nThis is in contrast with the MOI.Bridges.LazyBridgeOptimizer, which only bridges the objective function if it is supported by the bridge BT and unsupported by model.\n\nExample\n\njulia> struct MyNewBridge{T} <: MOI.Bridges.Objective.AbstractBridge end\n\njulia> bridge = MOI.Bridges.Objective.SingleBridgeOptimizer{MyNewBridge{Float64}}(\n MOI.Utilities.Model{Float64}(),\n )\nMOIB.Objective.SingleBridgeOptimizer{MyNewBridge{Float64}, MOIU.Model{Float64}}\nwith 0 objective bridges\nwith inner model MOIU.Model{Float64}\n\nImplementation notes\n\nAll bridges should simplify the creation of SingleBridgeOptimizers by defining a constant that wraps the bridge in a SingleBridgeOptimizer.\n\njulia> const MyNewBridgeModel{T,OT<:MOI.ModelLike} =\n MOI.Bridges.Objective.SingleBridgeOptimizer{MyNewBridge{T},OT};\n\nThis enables users to create bridged models as follows:\n\njulia> MyNewBridgeModel{Float64}(MOI.Utilities.Model{Float64}())\nMOIB.Objective.SingleBridgeOptimizer{MyNewBridge{Float64}, MOIU.Model{Float64}}\nwith 0 objective bridges\nwith inner model MOIU.Model{Float64}\n\n\n\n\n\n","category":"type"},{"location":"submodules/Bridges/reference/#MathOptInterface.Bridges.Objective.add_all_bridges","page":"API Reference","title":"MathOptInterface.Bridges.Objective.add_all_bridges","text":"add_all_bridges(model, ::Type{T}) where {T}\n\nAdd all bridges defined in the Bridges.Objective submodule to model.\n\nThe coefficient type used is T.\n\n\n\n\n\n","category":"function"},{"location":"submodules/Bridges/reference/#ref_variable_bridges","page":"API Reference","title":"Variable bridge API","text":"","category":"section"},{"location":"submodules/Bridges/reference/","page":"API Reference","title":"API Reference","text":"Bridges.Variable.AbstractBridge\nBridges.Variable.supports_constrained_variable\nBridges.Variable.concrete_bridge_type\nBridges.Variable.bridge_constrained_variable\nBridges.Variable.SingleBridgeOptimizer\nBridges.Variable.add_all_bridges\nBridges.Variable.FlipSignBridge\nBridges.Variable.SetMapBridge\nBridges.Variable.unbridged_map","category":"page"},{"location":"submodules/Bridges/reference/#MathOptInterface.Bridges.Variable.AbstractBridge","page":"API Reference","title":"MathOptInterface.Bridges.Variable.AbstractBridge","text":"abstract type AbstractBridge <: MOI.Bridges.AbstractBridge end\n\nSubtype of MOI.Bridges.AbstractBridge for variable bridges.\n\nIn addition to the required implementation described in MOI.Bridges.AbstractBridge, subtypes of AbstractBridge must additionally implement:\n\nsupports_constrained_variable\nconcrete_bridge_type\nbridge_constrained_variable\n\n\n\n\n\n","category":"type"},{"location":"submodules/Bridges/reference/#MathOptInterface.Bridges.Variable.supports_constrained_variable","page":"API Reference","title":"MathOptInterface.Bridges.Variable.supports_constrained_variable","text":"supports_constrained_variable(\n BT::Type{<:AbstractBridge},\n S::Type{<:MOI.AbstractSet},\n)::Bool\n\nReturn a Bool indicating whether the bridges of type BT support bridging constrained variables in S. That is, it returns true if the bridge of type BT converts constrained variables of type S into a form supported by the solver.\n\nImplementation notes\n\nThis method depends only on the type of the bridge and set, not the runtime values.\nThere is a default fallback, so you need only implement this method for sets that the bridge implements.\n\nExample\n\njulia> MOI.Bridges.Variable.supports_constrained_variable(\n MOI.Bridges.Variable.NonposToNonnegBridge{Float64},\n MOI.Nonpositives,\n )\ntrue\n\njulia> MOI.Bridges.Variable.supports_constrained_variable(\n MOI.Bridges.Variable.NonposToNonnegBridge{Float64},\n MOI.Nonnegatives,\n )\nfalse\n\n\n\n\n\n","category":"function"},{"location":"submodules/Bridges/reference/#MathOptInterface.Bridges.Variable.concrete_bridge_type","page":"API Reference","title":"MathOptInterface.Bridges.Variable.concrete_bridge_type","text":"concrete_bridge_type(\n BT::Type{<:AbstractBridge},\n S::Type{<:MOI.AbstractSet},\n)::Type\n\nReturn the concrete type of the bridge supporting variables in S constraints.\n\nThis function can only be called if MOI.supports_constrained_variable(BT, S) is true.\n\nExamples\n\nAs a variable in MOI.GreaterThan is bridged into variables in MOI.Nonnegatives by the VectorizeBridge:\n\njulia> MOI.Bridges.Variable.concrete_bridge_type(\n MOI.Bridges.Variable.VectorizeBridge{Float64},\n MOI.GreaterThan{Float64},\n )\nMathOptInterface.Bridges.Variable.VectorizeBridge{Float64, MathOptInterface.Nonnegatives}\n\n\n\n\n\n","category":"function"},{"location":"submodules/Bridges/reference/#MathOptInterface.Bridges.Variable.bridge_constrained_variable","page":"API Reference","title":"MathOptInterface.Bridges.Variable.bridge_constrained_variable","text":"bridge_constrained_variable(\n BT::Type{<:AbstractBridge},\n model::MOI.ModelLike,\n set::MOI.AbstractSet,\n)::BT\n\nBridge the constrained variable in set using bridge BT to model and returns a bridge object of type BT.\n\nImplementation notes\n\nThe bridge type BT must be a concrete type, that is, all the type parameters of the bridge must be set.\n\n\n\n\n\n","category":"function"},{"location":"submodules/Bridges/reference/#MathOptInterface.Bridges.Variable.SingleBridgeOptimizer","page":"API Reference","title":"MathOptInterface.Bridges.Variable.SingleBridgeOptimizer","text":"SingleBridgeOptimizer{BT<:AbstractBridge}(model::MOI.ModelLike)\n\nReturn MOI.Bridges.AbstractBridgeOptimizer that always bridges any variables constrained on creation supported by the bridge BT.\n\nThis is in contrast with the MOI.Bridges.LazyBridgeOptimizer, which only bridges the variables constrained on creation if they are supported by the bridge BT and unsupported by model.\n\nwarning: Warning\nTwo SingleBridgeOptimizers cannot be used together as both of them assume that the underlying model only returns variable indices with nonnegative values. Use MOI.Bridges.LazyBridgeOptimizer instead.\n\nExample\n\njulia> struct MyNewBridge{T} <: MOI.Bridges.Variable.AbstractBridge end\n\njulia> bridge = MOI.Bridges.Variable.SingleBridgeOptimizer{MyNewBridge{Float64}}(\n MOI.Utilities.Model{Float64}(),\n )\nMOIB.Variable.SingleBridgeOptimizer{MyNewBridge{Float64}, MOIU.Model{Float64}}\nwith 0 variable bridges\nwith inner model MOIU.Model{Float64}\n\nImplementation notes\n\nAll bridges should simplify the creation of SingleBridgeOptimizers by defining a constant that wraps the bridge in a SingleBridgeOptimizer.\n\njulia> const MyNewBridgeModel{T,OT<:MOI.ModelLike} =\n MOI.Bridges.Variable.SingleBridgeOptimizer{MyNewBridge{T},OT};\n\nThis enables users to create bridged models as follows:\n\njulia> MyNewBridgeModel{Float64}(MOI.Utilities.Model{Float64}())\nMOIB.Variable.SingleBridgeOptimizer{MyNewBridge{Float64}, MOIU.Model{Float64}}\nwith 0 variable bridges\nwith inner model MOIU.Model{Float64}\n\n\n\n\n\n","category":"type"},{"location":"submodules/Bridges/reference/#MathOptInterface.Bridges.Variable.add_all_bridges","page":"API Reference","title":"MathOptInterface.Bridges.Variable.add_all_bridges","text":"add_all_bridges(model, ::Type{T}) where {T}\n\nAdd all bridges defined in the Bridges.Variable submodule to model.\n\nThe coefficient type used is T.\n\n\n\n\n\n","category":"function"},{"location":"submodules/Bridges/reference/#MathOptInterface.Bridges.Variable.FlipSignBridge","page":"API Reference","title":"MathOptInterface.Bridges.Variable.FlipSignBridge","text":"abstract type FlipSignBridge{T,S1,S2} <: SetMapBridge{T,S2,S1} end\n\nAn abstract type that simplifies the creation of other bridges.\n\n\n\n\n\n","category":"type"},{"location":"submodules/Bridges/reference/#MathOptInterface.Bridges.Variable.SetMapBridge","page":"API Reference","title":"MathOptInterface.Bridges.Variable.SetMapBridge","text":"abstract type SetMapBridge{T,S1,S2} <: AbstractBridge end\n\nConsider two type of sets, S1 and S2, and a linear mapping A such that the image of a set of type S1 under A is a set of type S2.\n\nA SetMapBridge{T,S1,S2} is a bridge that substitutes constrained variables in S2 into the image through A of constrained variables in S1.\n\nThe linear map A is described by:\n\nMOI.Bridges.map_set\nMOI.Bridges.map_function\n\nImplementing a method for these two functions is sufficient to bridge constrained variables. However, in order for the getters and setters of attributes such as dual solutions and starting values to work as well, a method for the following functions must be implemented:\n\nMOI.Bridges.inverse_map_set\nMOI.Bridges.inverse_map_function\nMOI.Bridges.adjoint_map_function\nMOI.Bridges.inverse_adjoint_map_function.\n\nSee the docstrings of each function to see which feature would be missing if it was not implemented for a given bridge.\n\n\n\n\n\n","category":"type"},{"location":"submodules/Bridges/reference/#MathOptInterface.Bridges.Variable.unbridged_map","page":"API Reference","title":"MathOptInterface.Bridges.Variable.unbridged_map","text":"unbridged_map(\n bridge::MOI.Bridges.Variable.AbstractBridge,\n vi::MOI.VariableIndex,\n)\n\nFor a bridged variable in a scalar set, return a tuple of pairs mapping the variables created by the bridge to an affine expression in terms of the bridged variable vi.\n\nunbridged_map(\n bridge::MOI.Bridges.Variable.AbstractBridge,\n vis::Vector{MOI.VariableIndex},\n)\n\nFor a bridged variable in a vector set, return a tuple of pairs mapping the variables created by the bridge to an affine expression in terms of the bridged variable vis. If this method is not implemented, it falls back to calling the following method for every variable of vis.\n\nunbridged_map(\n bridge::MOI.Bridges.Variable.AbstractBridge,\n vi::MOI.VariableIndex,\n i::MOI.Bridges.IndexInVector,\n)\n\nFor a bridged variable in a vector set, return a tuple of pairs mapping the variables created by the bridge to an affine expression in terms of the bridged variable vi corresponding to the ith variable of the vector.\n\nIf there is no way to recover the expression in terms of the bridged variable(s) vi(s), return nothing. See ZerosBridge for an example of bridge returning nothing.\n\n\n\n\n\n","category":"function"},{"location":"submodules/Bridges/reference/#AbstractBridgeOptimizer-API","page":"API Reference","title":"AbstractBridgeOptimizer API","text":"","category":"section"},{"location":"submodules/Bridges/reference/","page":"API Reference","title":"API Reference","text":"Bridges.AbstractBridgeOptimizer\nBridges.bridged_variable_function\nBridges.unbridged_variable_function\nBridges.bridged_function\nBridges.supports_constraint_bridges\nBridges.recursive_model","category":"page"},{"location":"submodules/Bridges/reference/#MathOptInterface.Bridges.AbstractBridgeOptimizer","page":"API Reference","title":"MathOptInterface.Bridges.AbstractBridgeOptimizer","text":"abstract type AbstractBridgeOptimizer <: MOI.AbstractOptimizer end\n\nAn abstract type that implements generic functions for bridges.\n\nImplementation notes\n\nBy convention, the inner optimizer should be stored in a model field. If not, the optimizer must implement MOI.optimize!.\n\n\n\n\n\n","category":"type"},{"location":"submodules/Bridges/reference/#MathOptInterface.Bridges.bridged_variable_function","page":"API Reference","title":"MathOptInterface.Bridges.bridged_variable_function","text":"bridged_variable_function(\n b::AbstractBridgeOptimizer,\n vi::MOI.VariableIndex,\n)\n\nReturn a MOI.AbstractScalarFunction of variables of b.model that equals vi. That is, if the variable vi is bridged, it returns its expression in terms of the variables of b.model. Otherwise, it returns vi.\n\n\n\n\n\n","category":"function"},{"location":"submodules/Bridges/reference/#MathOptInterface.Bridges.unbridged_variable_function","page":"API Reference","title":"MathOptInterface.Bridges.unbridged_variable_function","text":"unbridged_variable_function(\n b::AbstractBridgeOptimizer,\n vi::MOI.VariableIndex,\n)\n\nReturn a MOI.AbstractScalarFunction of variables of b that equals vi. That is, if the variable vi is an internal variable of b.model created by a bridge but not visible to the user, it returns its expression in terms of the variables of bridged variables. Otherwise, it returns vi.\n\n\n\n\n\n","category":"function"},{"location":"submodules/Bridges/reference/#MathOptInterface.Bridges.bridged_function","page":"API Reference","title":"MathOptInterface.Bridges.bridged_function","text":"bridged_function(b::AbstractBridgeOptimizer, value)::typeof(value)\n\nSubstitute any bridged MOI.VariableIndex in value by an equivalent expression in terms of variables of b.model.\n\n\n\n\n\n","category":"function"},{"location":"submodules/Bridges/reference/#MathOptInterface.Bridges.supports_constraint_bridges","page":"API Reference","title":"MathOptInterface.Bridges.supports_constraint_bridges","text":"supports_constraint_bridges(b::AbstractBridgeOptimizer)::Bool\n\nReturn a Bool indicating if b supports MOI.Bridges.Constraint.AbstractBridge.\n\n\n\n\n\n","category":"function"},{"location":"submodules/Bridges/reference/#MathOptInterface.Bridges.recursive_model","page":"API Reference","title":"MathOptInterface.Bridges.recursive_model","text":"recursive_model(b::AbstractBridgeOptimizer)\n\nIf a variable, constraint, or objective is bridged, return the context of the inner variables. For most optimizers, this should be b.model.\n\n\n\n\n\n","category":"function"},{"location":"submodules/Bridges/reference/#LazyBridgeOptimizer-API","page":"API Reference","title":"LazyBridgeOptimizer API","text":"","category":"section"},{"location":"submodules/Bridges/reference/","page":"API Reference","title":"API Reference","text":"Bridges.LazyBridgeOptimizer\nBridges.full_bridge_optimizer\nBridges.ListOfNonstandardBridges\nBridges.add_bridge\nBridges.remove_bridge\nBridges.has_bridge\nBridges.print_active_bridges\nBridges.print_graph\nBridges.debug_supports_constraint\nBridges.debug_supports","category":"page"},{"location":"submodules/Bridges/reference/#MathOptInterface.Bridges.LazyBridgeOptimizer","page":"API Reference","title":"MathOptInterface.Bridges.LazyBridgeOptimizer","text":"LazyBridgeOptimizer(model::MOI.ModelLike)\n\nThe LazyBridgeOptimizer is a bridge optimizer that supports multiple bridges, and only bridges things which are not supported by the internal model.\n\nInternally, the LazyBridgeOptimizer solves a shortest hyper-path problem to determine which bridges to use.\n\nIn general, you should use full_bridge_optimizer instead of this constructor because full_bridge_optimizer automatically adds a large number of supported bridges.\n\nSee also: add_bridge, remove_bridge, has_bridge and full_bridge_optimizer.\n\nExample\n\njulia> model = MOI.Bridges.LazyBridgeOptimizer(MOI.Utilities.Model{Float64}())\nMOIB.LazyBridgeOptimizer{MOIU.Model{Float64}}\nwith 0 variable bridges\nwith 0 constraint bridges\nwith 0 objective bridges\nwith inner model MOIU.Model{Float64}\n\njulia> MOI.Bridges.add_bridge(model, MOI.Bridges.Variable.FreeBridge{Float64})\n\njulia> MOI.Bridges.has_bridge(model, MOI.Bridges.Variable.FreeBridge{Float64})\ntrue\n\n\n\n\n\n","category":"type"},{"location":"submodules/Bridges/reference/#MathOptInterface.Bridges.full_bridge_optimizer","page":"API Reference","title":"MathOptInterface.Bridges.full_bridge_optimizer","text":"full_bridge_optimizer(model::MOI.ModelLike, ::Type{T}) where {T}\n\nReturns a LazyBridgeOptimizer bridging model for every bridge defined in this package (see below for the few exceptions) and for the coefficient type T, as well as the bridges in the list returned by the ListOfNonstandardBridges attribute.\n\nExample\n\njulia> model = MOI.Utilities.Model{Float64}();\n\njulia> bridged_model = MOI.Bridges.full_bridge_optimizer(model, Float64);\n\nExceptions\n\nThe following bridges are not added by full_bridge_optimizer, except if they are in the list returned by the ListOfNonstandardBridges attribute:\n\nConstraint.SOCtoNonConvexQuadBridge\nConstraint.RSOCtoNonConvexQuadBridge](@ref)\nConstraint.SOCtoPSDBridge\nIf T is not a subtype of AbstractFloat, subtypes of Constraint.AbstractToIntervalBridge\nConstraint.GreaterToIntervalBridge\nConstraint.LessToIntervalBridge)\n\nSee the docstring of the each bridge for the reason they are not added.\n\n\n\n\n\n","category":"function"},{"location":"submodules/Bridges/reference/#MathOptInterface.Bridges.ListOfNonstandardBridges","page":"API Reference","title":"MathOptInterface.Bridges.ListOfNonstandardBridges","text":"ListOfNonstandardBridges{T}() <: MOI.AbstractOptimizerAttribute\n\nAny optimizer can be wrapped in a LazyBridgeOptimizer using full_bridge_optimizer. However, by default LazyBridgeOptimizer uses a limited set of bridges that are:\n\nimplemented in MOI.Bridges\ngenerally applicable for all optimizers.\n\nFor some optimizers however, it is useful to add additional bridges, such as those that are implemented in external packages (e.g., within the solver package itself) or only apply in certain circumstances (e.g., Constraint.SOCtoNonConvexQuadBridge).\n\nSuch optimizers should implement the ListOfNonstandardBridges attribute to return a vector of bridge types that are added by full_bridge_optimizer in addition to the list of default bridges.\n\nNote that optimizers implementing ListOfNonstandardBridges may require package-specific functions or sets to be used if the non-standard bridges are not added. Therefore, you are recommended to use model = MOI.instantiate(Package.Optimizer; with_bridge_type = T) instead of model = MOI.instantiate(Package.Optimizer). See MOI.instantiate.\n\nExamples\n\nAn optimizer using a non-default bridge in MOI.Bridges\n\nSolvers supporting MOI.ScalarQuadraticFunction can support MOI.SecondOrderCone and MOI.RotatedSecondOrderCone by defining:\n\nfunction MOI.get(::MyQuadraticOptimizer, ::ListOfNonstandardBridges{Float64})\n return Type[\n MOI.Bridges.Constraint.SOCtoNonConvexQuadBridge{Float64},\n MOI.Bridges.Constraint.RSOCtoNonConvexQuadBridge{Float64},\n ]\nend\n\nAn optimizer defining an internal bridge\n\nSuppose an optimizer can exploit specific structure of a constraint, e.g., it can exploit the structure of the matrix A in the linear system of equations A * x = b.\n\nThe optimizer can define the function:\n\nstruct MatrixAffineFunction{T} <: MOI.AbstractVectorFunction\n A::SomeStructuredMatrixType{T}\n b::Vector{T}\nend\n\nand then a bridge\n\nstruct MatrixAffineFunctionBridge{T} <: MOI.Constraint.AbstractBridge\n # ...\nend\n# ...\n\nfrom VectorAffineFunction{T} to the MatrixAffineFunction. Finally, it defines:\n\nfunction MOI.get(::Optimizer{T}, ::ListOfNonstandardBridges{T}) where {T}\n return Type[MatrixAffineFunctionBridge{T}]\nend\n\n\n\n\n\n","category":"type"},{"location":"submodules/Bridges/reference/#MathOptInterface.Bridges.add_bridge","page":"API Reference","title":"MathOptInterface.Bridges.add_bridge","text":"add_bridge(b::LazyBridgeOptimizer, BT::Type{<:AbstractBridge})\n\nEnable the use of the bridges of type BT by b.\n\n\n\n\n\n","category":"function"},{"location":"submodules/Bridges/reference/#MathOptInterface.Bridges.remove_bridge","page":"API Reference","title":"MathOptInterface.Bridges.remove_bridge","text":"remove_bridge(b::LazyBridgeOptimizer, BT::Type{<:AbstractBridge})\n\nDisable the use of the bridges of type BT by b.\n\n\n\n\n\n","category":"function"},{"location":"submodules/Bridges/reference/#MathOptInterface.Bridges.has_bridge","page":"API Reference","title":"MathOptInterface.Bridges.has_bridge","text":"has_bridge(b::LazyBridgeOptimizer, BT::Type{<:AbstractBridge})\n\nReturn a Bool indicating whether the bridges of type BT are used by b.\n\n\n\n\n\n","category":"function"},{"location":"submodules/Bridges/reference/#MathOptInterface.Bridges.print_active_bridges","page":"API Reference","title":"MathOptInterface.Bridges.print_active_bridges","text":"print_active_bridges([io::IO=stdout,] b::MOI.Bridges.LazyBridgeOptimizer)\n\nPrint the set of bridges that are active in the model b.\n\n\n\n\n\nprint_active_bridges(\n [io::IO=stdout,]\n b::MOI.Bridges.LazyBridgeOptimizer,\n F::Type{<:MOI.AbstractFunction}\n)\n\nPrint the set of bridges required for an objective function of type F.\n\n\n\n\n\nprint_active_bridges(\n [io::IO=stdout,]\n b::MOI.Bridges.LazyBridgeOptimizer,\n F::Type{<:MOI.AbstractFunction},\n S::Type{<:MOI.AbstractSet},\n)\n\nPrint the set of bridges required for a constraint of type F-in-S.\n\n\n\n\n\nprint_active_bridges(\n [io::IO=stdout,]\n b::MOI.Bridges.LazyBridgeOptimizer,\n S::Type{<:MOI.AbstractSet}\n)\n\nPrint the set of bridges required for a variable constrained to set S.\n\n\n\n\n\n","category":"function"},{"location":"submodules/Bridges/reference/#MathOptInterface.Bridges.print_graph","page":"API Reference","title":"MathOptInterface.Bridges.print_graph","text":"print_graph([io::IO = stdout,] b::LazyBridgeOptimizer)\n\nPrint the hyper-graph containing all variable, constraint, and objective types that could be obtained by bridging the variables, constraints, and objectives that are present in the model by all the bridges added to b.\n\nEach node in the hyper-graph corresponds to a variable, constraint, or objective type.\n\nVariable nodes are indicated by [ ]\nConstraint nodes are indicated by ( )\nObjective nodes are indicated by | |\n\nThe number inside each pair of brackets is an index of the node in the hyper-graph.\n\nNote that this hyper-graph is the full list of possible transformations. When the bridged model is created, we select the shortest hyper-path(s) from this graph, so many nodes may be un-used.\n\nTo see which nodes are used, call print_active_bridges.\n\nFor more information, see Legat, B., Dowson, O., Garcia, J., and Lubin, M. (2020). \"MathOptInterface: a data structure for mathematical optimization problems.\" URL: https://arxiv.org/abs/2002.03447\n\n\n\n\n\n","category":"function"},{"location":"submodules/Bridges/reference/#MathOptInterface.Bridges.debug_supports_constraint","page":"API Reference","title":"MathOptInterface.Bridges.debug_supports_constraint","text":"debug_supports_constraint(\n b::LazyBridgeOptimizer,\n F::Type{<:MOI.AbstractFunction},\n S::Type{<:MOI.AbstractSet};\n io::IO = Base.stdout,\n)\n\nPrints to io explanations for the value of MOI.supports_constraint with the same arguments.\n\n\n\n\n\n","category":"function"},{"location":"submodules/Bridges/reference/#MathOptInterface.Bridges.debug_supports","page":"API Reference","title":"MathOptInterface.Bridges.debug_supports","text":"debug_supports(\n b::LazyBridgeOptimizer,\n ::MOI.ObjectiveFunction{F};\n io::IO = Base.stdout,\n) where F\n\nPrints to io explanations for the value of MOI.supports with the same arguments.\n\n\n\n\n\n","category":"function"},{"location":"submodules/Bridges/reference/#constraint_set_map","page":"API Reference","title":"SetMap API","text":"","category":"section"},{"location":"submodules/Bridges/reference/","page":"API Reference","title":"API Reference","text":"Bridges.map_set\nBridges.inverse_map_set\nBridges.map_function\nBridges.inverse_map_function\nBridges.adjoint_map_function\nBridges.inverse_adjoint_map_function","category":"page"},{"location":"submodules/Bridges/reference/#MathOptInterface.Bridges.map_set","page":"API Reference","title":"MathOptInterface.Bridges.map_set","text":"map_set(::Type{BT}, set) where {BT}\n\nReturn the image of set through the linear map A defined in Variable.SetMapBridge and Constraint.SetMapBridge. This is used for bridging the constraint and setting the MOI.ConstraintSet.\n\n\n\n\n\n","category":"function"},{"location":"submodules/Bridges/reference/#MathOptInterface.Bridges.inverse_map_set","page":"API Reference","title":"MathOptInterface.Bridges.inverse_map_set","text":"inverse_map_set(::Type{BT}, set) where {BT}\n\nReturn the preimage of set through the linear map A defined in Variable.SetMapBridge and Constraint.SetMapBridge. This is used for getting the MOI.ConstraintSet.\n\n\n\n\n\n","category":"function"},{"location":"submodules/Bridges/reference/#MathOptInterface.Bridges.map_function","page":"API Reference","title":"MathOptInterface.Bridges.map_function","text":"map_function(::Type{BT}, func) where {BT}\n\nReturn the image of func through the linear map A defined in Variable.SetMapBridge and Constraint.SetMapBridge. This is used for getting the MOI.ConstraintPrimal of variable bridges. For constraint bridges, this is used for bridging the constraint, setting the MOI.ConstraintFunction and MOI.ConstraintPrimalStart and modifying the function with MOI.modify.\n\nmap_function(::Type{BT}, func, i::IndexInVector) where {BT}\n\nReturn the scalar function at the ith index of the vector function that would be returned by map_function(BT, func) except that it may compute the ith element. This is used by bridged_function and for getting the MOI.VariablePrimal and MOI.VariablePrimalStart of variable bridges.\n\n\n\n\n\n","category":"function"},{"location":"submodules/Bridges/reference/#MathOptInterface.Bridges.inverse_map_function","page":"API Reference","title":"MathOptInterface.Bridges.inverse_map_function","text":"inverse_map_function(::Type{BT}, func) where {BT}\n\nReturn the image of func through the inverse of the linear map A defined in Variable.SetMapBridge and Constraint.SetMapBridge. This is used by Variable.unbridged_map and for setting the MOI.VariablePrimalStart of variable bridges and for getting the MOI.ConstraintFunction, the MOI.ConstraintPrimal and the MOI.ConstraintPrimalStart of constraint bridges.\n\n\n\n\n\n","category":"function"},{"location":"submodules/Bridges/reference/#MathOptInterface.Bridges.adjoint_map_function","page":"API Reference","title":"MathOptInterface.Bridges.adjoint_map_function","text":"adjoint_map_function(::Type{BT}, func) where {BT}\n\nReturn the image of func through the adjoint of the linear map A defined in Variable.SetMapBridge and Constraint.SetMapBridge. This is used for getting the MOI.ConstraintDual and MOI.ConstraintDualStart of constraint bridges.\n\n\n\n\n\n","category":"function"},{"location":"submodules/Bridges/reference/#MathOptInterface.Bridges.inverse_adjoint_map_function","page":"API Reference","title":"MathOptInterface.Bridges.inverse_adjoint_map_function","text":"inverse_adjoint_map_function(::Type{BT}, func) where {BT}\n\nReturn the image of func through the inverse of the adjoint of the linear map A defined in Variable.SetMapBridge and Constraint.SetMapBridge. This is used for getting the MOI.ConstraintDual of variable bridges and setting the MOI.ConstraintDualStart of constraint bridges.\n\n\n\n\n\n","category":"function"},{"location":"submodules/Bridges/reference/#Bridging-graph-API","page":"API Reference","title":"Bridging graph API","text":"","category":"section"},{"location":"submodules/Bridges/reference/","page":"API Reference","title":"API Reference","text":"Bridges.Graph\nBridges.VariableNode\nBridges.ConstraintNode\nBridges.ObjectiveNode\nBridges.Edge\nBridges.ObjectiveEdge\nBridges.add_node\nBridges.add_edge\nBridges.set_variable_constraint_node\nBridges.bridge_index\nBridges.is_variable_edge_best","category":"page"},{"location":"submodules/Bridges/reference/#MathOptInterface.Bridges.Graph","page":"API Reference","title":"MathOptInterface.Bridges.Graph","text":"Graph()\n\nA type-stable datastructure for computing the shortest hyperpath problem.\n\nNodes\n\nThere are three types of nodes in the graph:\n\nVariableNode\nConstraintNode\nObjectiveNode\n\nAdd nodes to the graph using add_node.\n\nEdges\n\nThere are two types of edges in the graph:\n\nEdge\nObjectiveEdge\n\nAdd edges to the graph using add_edge.\n\nFor the ability to add a variable constrained on creation as a free variable followed by a constraint, use set_variable_constraint_node.\n\nOptimal hyper-edges\n\nUse bridge_index to compute the minimum-cost bridge leaving a node.\n\nNote that bridge_index lazy runs a Bellman-Ford algorithm to compute the set of minimum cost edges. Thus, the first call to bridge_index after adding new nodes or edges will take longer than subsequent calls.\n\n\n\n\n\n","category":"type"},{"location":"submodules/Bridges/reference/#MathOptInterface.Bridges.VariableNode","page":"API Reference","title":"MathOptInterface.Bridges.VariableNode","text":"VariableNode(index::Int)\n\nA node in Graph representing a variable constrained on creation.\n\n\n\n\n\n","category":"type"},{"location":"submodules/Bridges/reference/#MathOptInterface.Bridges.ConstraintNode","page":"API Reference","title":"MathOptInterface.Bridges.ConstraintNode","text":"ConstraintNode(index::Int)\n\nA node in Graph representing a constraint.\n\n\n\n\n\n","category":"type"},{"location":"submodules/Bridges/reference/#MathOptInterface.Bridges.ObjectiveNode","page":"API Reference","title":"MathOptInterface.Bridges.ObjectiveNode","text":"ObjectiveNode(index::Int)\n\nA node in Graph representing an objective function.\n\n\n\n\n\n","category":"type"},{"location":"submodules/Bridges/reference/#MathOptInterface.Bridges.Edge","page":"API Reference","title":"MathOptInterface.Bridges.Edge","text":"Edge(\n bridge_index::Int,\n added_variables::Vector{VariableNode},\n added_constraints::Vector{ConstraintNode},\n cost::Float64 = 1.0,\n)\n\nReturn a new datastructure representing an edge in Graph that starts at a VariableNode or a ConstraintNode.\n\n\n\n\n\n","category":"type"},{"location":"submodules/Bridges/reference/#MathOptInterface.Bridges.ObjectiveEdge","page":"API Reference","title":"MathOptInterface.Bridges.ObjectiveEdge","text":"ObjectiveEdge(\n bridge_index::Int,\n added_variables::Vector{VariableNode},\n added_constraints::Vector{ConstraintNode},\n)\n\nReturn a new datastructure representing an edge in Graph that starts at an ObjectiveNode.\n\n\n\n\n\n","category":"type"},{"location":"submodules/Bridges/reference/#MathOptInterface.Bridges.add_node","page":"API Reference","title":"MathOptInterface.Bridges.add_node","text":"add_node(graph::Graph, ::Type{VariableNode})::VariableNode\nadd_node(graph::Graph, ::Type{ConstraintNode})::ConstraintNode\nadd_node(graph::Graph, ::Type{ObjectiveNode})::ObjectiveNode\n\nAdd a new node to graph.\n\n\n\n\n\n","category":"function"},{"location":"submodules/Bridges/reference/#MathOptInterface.Bridges.add_edge","page":"API Reference","title":"MathOptInterface.Bridges.add_edge","text":"add_edge(graph::Graph, node::VariableNode, edge::Edge)::Nothing\nadd_edge(graph::Graph, node::ConstraintNode, edge::Edge)::Nothing\nadd_edge(graph::Graph, node::ObjectiveNode, edge::ObjectiveEdge)::Nothing\n\nAdd edge to graph, where edge starts at node and connects to the nodes defined in edge.\n\n\n\n\n\n","category":"function"},{"location":"submodules/Bridges/reference/#MathOptInterface.Bridges.set_variable_constraint_node","page":"API Reference","title":"MathOptInterface.Bridges.set_variable_constraint_node","text":"set_variable_constraint_node(\n graph::Graph,\n variable_node::VariableNode,\n constraint_node::ConstraintNode,\n cost::Int,\n)\n\nAs an alternative to variable_node, add a virtual edge to graph that represents adding a free variable, followed by a constraint of type constraint_node, with bridging cost cost.\n\nWhy is this needed?\n\nVariables can either be added as a variable constrained on creation, or as a free variable which then has a constraint added to it.\n\n\n\n\n\n","category":"function"},{"location":"submodules/Bridges/reference/#MathOptInterface.Bridges.bridge_index","page":"API Reference","title":"MathOptInterface.Bridges.bridge_index","text":"bridge_index(graph::Graph, node::VariableNode)::Int\nbridge_index(graph::Graph, node::ConstraintNode)::Int\nbridge_index(graph::Graph, node::ObjectiveNode)::Int\n\nReturn the optimal index of the bridge to chose from node.\n\n\n\n\n\n","category":"function"},{"location":"submodules/Bridges/reference/#MathOptInterface.Bridges.is_variable_edge_best","page":"API Reference","title":"MathOptInterface.Bridges.is_variable_edge_best","text":"is_variable_edge_best(graph::Graph, node::VariableNode)::Bool\n\nReturn a Bool indicating whether node should be added as a variable constrained on creation, or as a free variable followed by a constraint.\n\n\n\n\n\n","category":"function"},{"location":"#Introduction","page":"Introduction","title":"Introduction","text":"","category":"section"},{"location":"","page":"Introduction","title":"Introduction","text":"Welcome to the documentation for MathOptInterface.","category":"page"},{"location":"","page":"Introduction","title":"Introduction","text":"note: Note\nThis documentation is also available in PDF format: MathOptInterface.pdf.","category":"page"},{"location":"#What-is-MathOptInterface?","page":"Introduction","title":"What is MathOptInterface?","text":"","category":"section"},{"location":"","page":"Introduction","title":"Introduction","text":"MathOptInterface.jl (MOI) is an abstraction layer designed to provide a unified interface to mathematical optimization solvers so that users do not need to understand multiple solver-specific APIs.","category":"page"},{"location":"","page":"Introduction","title":"Introduction","text":"tip: Tip\nThis documentation is aimed at developers writing software interfaces to solvers and modeling languages using the MathOptInterface API. If you are a user interested in solving optimization problems, we encourage you instead to use MOI through a higher-level modeling interface like JuMP or Convex.jl.","category":"page"},{"location":"#How-the-documentation-is-structured","page":"Introduction","title":"How the documentation is structured","text":"","category":"section"},{"location":"","page":"Introduction","title":"Introduction","text":"Having a high-level overview of how this documentation is structured will help you know where to look for certain things.","category":"page"},{"location":"","page":"Introduction","title":"Introduction","text":"The Tutorials section contains articles on how to use and implement the MathOptInteraface API. Look here if you want to write a model in MOI, or write an interface to a new solver.\nThe Manual contains short code-snippets that explain how to use the MOI API. Look here for more details on particular areas of MOI.\nThe Background section contains articles on the theory behind MathOptInterface. Look here if you want to understand why, rather than how.\nThe API Reference contains a complete list of functions and types that comprise the MOI API. Look here is you want to know how to use (or implement) a particular function.\nThe Submodules section contains stand-alone documentation for each of the submodules within MOI. These submodules are not required to interface a solver with MOI, but they make the job much easier.","category":"page"},{"location":"#Citing-MathOptInterface","page":"Introduction","title":"Citing MathOptInterface","text":"","category":"section"},{"location":"","page":"Introduction","title":"Introduction","text":"A paper describing the design and features of MathOptInterface is available on arXiv.","category":"page"},{"location":"","page":"Introduction","title":"Introduction","text":"If you find MathOptInterface useful in your work, we kindly request that you cite the following paper:","category":"page"},{"location":"","page":"Introduction","title":"Introduction","text":"@article{legat2021mathoptinterface,\n title={{MathOptInterface}: a data structure for mathematical optimization problems},\n author={Legat, Beno{\\^\\i}t and Dowson, Oscar and Garcia, Joaquim Dias and Lubin, Miles},\n journal={INFORMS Journal on Computing},\n year={2021},\n doi={10.1287/ijoc.2021.1067},\n publisher={INFORMS}\n}","category":"page"},{"location":"background/naming_conventions/","page":"Naming conventions","title":"Naming conventions","text":"CurrentModule = MathOptInterface\nDocTestSetup = quote\n import MathOptInterface as MOI\nend\nDocTestFilters = [r\"MathOptInterface|MOI\"]","category":"page"},{"location":"background/naming_conventions/#Naming-conventions","page":"Naming conventions","title":"Naming conventions","text":"","category":"section"},{"location":"background/naming_conventions/","page":"Naming conventions","title":"Naming conventions","text":"MOI follows several conventions for naming functions and structures. These should also be followed by packages extending MOI.","category":"page"},{"location":"background/naming_conventions/#Sets","page":"Naming conventions","title":"Sets","text":"","category":"section"},{"location":"background/naming_conventions/","page":"Naming conventions","title":"Naming conventions","text":"Sets encode the structure of constraints. Their names should follow the following conventions:","category":"page"},{"location":"background/naming_conventions/","page":"Naming conventions","title":"Naming conventions","text":"Abstract types in the set hierarchy should begin with Abstract and end in Set, for example, AbstractScalarSet, AbstractVectorSet.\nVector-valued conic sets should end with Cone, for example, NormInfinityCone, SecondOrderCone.\nVector-valued Cartesian products should be plural and not end in Cone, for example, Nonnegatives, not NonnegativeCone.\nMatrix-valued conic sets should provide two representations: ConeSquare and ConeTriangle, for example, RootDetConeTriangle and RootDetConeSquare. See Matrix cones for more details.\nScalar sets should be singular, not plural, for example, Integer, not Integers.\nAs much as possible, the names should follow established conventions in the domain where this set is used: for instance, convex sets should have names close to those of CVX, and constraint-programming sets should follow MiniZinc's constraints.","category":"page"}] } diff --git a/dev/submodules/Benchmarks/overview/index.html b/dev/submodules/Benchmarks/overview/index.html index af187b41c6..bb5a6554e8 100644 --- a/dev/submodules/Benchmarks/overview/index.html +++ b/dev/submodules/Benchmarks/overview/index.html @@ -17,4 +17,4 @@ MOI.Benchmarks.compare_against_baseline( suite, "current"; directory = "/tmp", verbose = true -)

This comparison will create a report detailing improvements and regressions.

+)

This comparison will create a report detailing improvements and regressions.

diff --git a/dev/submodules/Benchmarks/reference/index.html b/dev/submodules/Benchmarks/reference/index.html index ecbf49fe29..842e745f69 100644 --- a/dev/submodules/Benchmarks/reference/index.html +++ b/dev/submodules/Benchmarks/reference/index.html @@ -7,11 +7,11 @@ end suite(exclude = [r"delete"]) do Gurobi.Optimizer(OutputFlag=0) -endsource
MathOptInterface.Benchmarks.create_baselineFunction
create_baseline(suite, name::String; directory::String = ""; kwargs...)

Run all benchmarks in suite and save to files called name in directory.

Extra kwargs are based to BenchmarkTools.run.

Examples

my_suite = suite(() -> GLPK.Optimizer())
-create_baseline(my_suite, "glpk_master"; directory = "/tmp", verbose = true)
source
MathOptInterface.Benchmarks.create_baselineFunction
create_baseline(suite, name::String; directory::String = ""; kwargs...)

Run all benchmarks in suite and save to files called name in directory.

Extra kwargs are based to BenchmarkTools.run.

Examples

my_suite = suite(() -> GLPK.Optimizer())
+create_baseline(my_suite, "glpk_master"; directory = "/tmp", verbose = true)
source
MathOptInterface.Benchmarks.compare_against_baselineFunction
compare_against_baseline(
     suite, name::String; directory::String = "",
     report_filename::String = "report.txt"
 )

Run all benchmarks in suite and compare against files called name in directory that were created by a call to create_baseline.

A report summarizing the comparison is written to report_filename in directory.

Extra kwargs are based to BenchmarkTools.run.

Examples

my_suite = suite(() -> GLPK.Optimizer())
 compare_against_baseline(
     my_suite, "glpk_master"; directory = "/tmp", verbose = true
-)
source
+)source diff --git a/dev/submodules/Bridges/list_of_bridges/index.html b/dev/submodules/Bridges/list_of_bridges/index.html index c14d35b9a2..9e66c1104b 100644 --- a/dev/submodules/Bridges/list_of_bridges/index.html +++ b/dev/submodules/Bridges/list_of_bridges/index.html @@ -1,5 +1,5 @@ -List of bridges · MathOptInterface

List of bridges

This section describes the Bridges.AbstractBridges that are implemented in MathOptInterface.

Constraint bridges

These bridges are subtypes of Bridges.Constraint.AbstractBridge.

MathOptInterface.Bridges.Constraint.VectorizeBridgeType
VectorizeBridge{T,F,S,G} <: Bridges.Constraint.AbstractBridge

VectorizeBridge implements the following reformulations:

  • $g(x) \ge a$ into $[g(x) - a] \in \mathbb{R}_+$
  • $g(x) \le a$ into $[g(x) - a] \in \mathbb{R}_-$
  • $g(x) == a$ into $[g(x) - a] \in \{0\}$

where T is the coefficient type of g(x) - a.

Source node

VectorizeBridge supports:

Target nodes

VectorizeBridge creates:

source
MathOptInterface.Bridges.Constraint.ScalarizeBridgeType
ScalarizeBridge{T,F,S}

ScalarizeBridge implements the following reformulations:

  • $f(x) - a \in \mathbb{R}_+$ into $f_i(x) \ge a_i$ for all $i$
  • $f(x) - a \in \mathbb{R}_-$ into $f_i(x) \le a_i$ for all $i$
  • $f(x) - a \in \{0\}$ into $f_i(x) == a_i$ for all $i$

Source node

ScalarizeBridge supports:

Target nodes

ScalarizeBridge creates:

source
MathOptInterface.Bridges.Constraint.FunctionConversionBridgeType
FunctionConversionBridge{T,F,G,S} <: AbstractFunctionConversionBridge{G,S}

FunctionConversionBridge implements the following reformulations:

  • $g(x) \in S$ into $f(x) \in S$

for these pairs of functions:

Source node

FunctionConversionBridge supports:

  • G in S

Target nodes

FunctionConversionBridge creates:

  • F in S
source
MathOptInterface.Bridges.Constraint.SplitComplexEqualToBridgeType
SplitComplexEqualToBridge{T,F,G} <: Bridges.Constraint.AbstractBridge

SplitComplexEqualToBridge implements the following reformulation:

  • $f(x) + g(x) * im = a + b * im$ into $f(x) = a$ and $g(x) = b$

Source node

SplitComplexEqualToBridge supports:

where G is a function with Complex coefficients.

Target nodes

SplitComplexEqualToBridge creates:

where F is the type of the real/imaginary part of G.

source
MathOptInterface.Bridges.Constraint.SplitComplexZerosBridgeType
SplitComplexZerosBridge{T,F,G} <: Bridges.Constraint.AbstractBridge

SplitComplexZerosBridge implements the following reformulation:

  • $f(x) \in \{0\}^n$ into $\text{Re}(f(x)) \in \{0\}^n$ and $\text{Im}(f(x)) \in \{0\}^n$

Source node

SplitComplexZerosBridge supports:

where G is a function with Complex coefficients.

Target nodes

SplitComplexZerosBridge creates:

where F is the type of the real/imaginary part of G.

source
MathOptInterface.Bridges.Constraint.SplitIntervalBridgeType
SplitIntervalBridge{T,F,S,LS,US} <: Bridges.Constraint.AbstractBridge

SplitIntervalBridge implements the following reformulations:

  • $l \le f(x) \le u$ into $f(x) \ge l$ and $f(x) \le u$
  • $f(x) = b$ into $f(x) \ge b$ and $f(x) \le b$
  • $f(x) \in \{0\}$ into $f(x) \in \mathbb{R}_+$ and $f(x) \in \mathbb{R}_-$

Source node

SplitIntervalBridge supports:

Target nodes

SplitIntervalBridge creates:

or

Note

If T<:AbstractFloat and S is MOI.Interval{T} then no lower (resp. upper) bound constraint is created if the lower (resp. upper) bound is typemin(T) (resp. typemax(T)). Similarly, when MOI.ConstraintSet is set, a lower or upper bound constraint may be deleted or created accordingly.

source
MathOptInterface.Bridges.Constraint.SOCtoNonConvexQuadBridgeType
SOCtoNonConvexQuadBridge{T} <: Bridges.Constraint.AbstractBridge

SOCtoNonConvexQuadBridge implements the following reformulations:

  • $||x||_2 \le t$ into $\sum x^2 - t^2 \le 0$ and $1t + 0 \ge 0$

The MOI.ScalarAffineFunction $1t + 0$ is used in case the variable has other bound constraints.

Warning

This transformation starts from a convex constraint and creates a non-convex constraint. Unless the solver has explicit support for detecting second-order cones in quadratic form, this may (wrongly) be interpreted by the solver as being non-convex. Therefore, this bridge is not added automatically by MOI.Bridges.full_bridge_optimizer. Care is recommended when adding this bridge to a optimizer.

Source node

SOCtoNonConvexQuadBridge supports:

Target nodes

SOCtoNonConvexQuadBridge creates:

source
MathOptInterface.Bridges.Constraint.RSOCtoNonConvexQuadBridgeType
RSOCtoNonConvexQuadBridge{T} <: Bridges.Constraint.AbstractBridge

RSOCtoNonConvexQuadBridge implements the following reformulations:

  • $||x||_2^2 \le 2tu$ into $\sum x^2 - 2tu \le 0$, $1t + 0 \ge 0$, and $1u + 0 \ge 0$.

The MOI.ScalarAffineFunctions $1t + 0$ and $1u + 0$ are used in case the variables have other bound constraints.

Warning

This transformation starts from a convex constraint and creates a non-convex constraint. Unless the solver has explicit support for detecting rotated second-order cones in quadratic form, this may (wrongly) be interpreted by the solver as being non-convex. Therefore, this bridge is not added automatically by MOI.Bridges.full_bridge_optimizer. Care is recommended when adding this bridge to a optimizer.

Source node

RSOCtoNonConvexQuadBridge supports:

Target nodes

RSOCtoNonConvexQuadBridge creates:

source
MathOptInterface.Bridges.Constraint.QuadtoSOCBridgeType
QuadtoSOCBridge{T} <: Bridges.Constraint.AbstractBridge

QuadtoSOCBridge converts quadratic inequalities

\[\frac{1}{2}x^T Q x + a^T x \le ub\]

into MOI.RotatedSecondOrderCone constraints, but it only applies when $Q$ is positive definite.

This is because, if Q is positive definite, there exists U such that $Q = U^T U$, and so the inequality can then be rewritten as;

\[\|U x\|_2^2 \le 2 (-a^T x + ub)\]

Therefore, QuadtoSOCBridge implements the following reformulations:

  • $\frac{1}{2}x^T Q x + a^T x \le ub$ into $(1, -a^T x + ub, Ux) \in RotatedSecondOrderCone$ where $Q = U^T U$
  • $\frac{1}{2}x^T Q x + a^T x \ge lb$ into $(1, a^T x - lb, Ux) \in RotatedSecondOrderCone$ where $-Q = U^T U$

Source node

QuadtoSOCBridge supports:

Target nodes

RelativeEntropyBridge creates:

Errors

This bridge errors if Q is not positive definite.

source
MathOptInterface.Bridges.Constraint.SOCtoPSDBridgeType
SOCtoPSDBridge{T,F,G} <: Bridges.Constraint.AbstractBridge

SOCtoPSDBridge implements the following reformulation:

  • $||x||_2 \le t$ into $\left[\begin{array}{c c}t & x^\top \\ x & t \mathbf{I}\end{array}\right]\succeq 0$
Warning

This bridge is not added by default by MOI.Bridges.full_bridge_optimizer because bridging second order cone constraints to semidefinite constraints can be achieved by the SOCtoRSOCBridge followed by the RSOCtoPSDBridge, while creating a smaller semidefinite constraint.

Source node

SOCtoPSDBridge supports:

Target nodes

SOCtoPSDBridge creates:

source
MathOptInterface.Bridges.Constraint.NormToPowerBridgeType
NormToPowerBridge{T,F} <: Bridges.Constraint.AbstractBridge

NormToPowerBridge implements the following reformulation:

  • $(t, x) \in NormCone(p, 1+d)$ into $(r_i, t, x_i) \in PowerCone(1 / p)$ for all $i$, and $\sum\limits_i r_i == t$.

For details, see Alizadeh, F., and Goldfarb, D. (2001). "Second-order cone programming." Mathematical Programming, Series B, 95:3-51.

Source node

NormToPowerBridge supports:

Target nodes

NormToPowerBridge creates:

source
MathOptInterface.Bridges.Constraint.GeoMeantoRelEntrBridgeType
GeoMeantoRelEntrBridge{T,F,G,H} <: Bridges.Constraint.AbstractBridge

GeoMeantoRelEntrBridge implements the following reformulation:

  • $(u, w) \in GeometricMeanCone$ into $(0, w, (u + y)\mathbf{1})\in RelativeEntropyCone$ and $y \ge 0$

Source node

GeoMeantoRelEntrBridge supports:

Target nodes

GeoMeantoRelEntrBridge creates:

Derivation

The derivation of the bridge is as follows:

\[\begin{aligned} +List of bridges · MathOptInterface

List of bridges

This section describes the Bridges.AbstractBridges that are implemented in MathOptInterface.

Constraint bridges

These bridges are subtypes of Bridges.Constraint.AbstractBridge.

MathOptInterface.Bridges.Constraint.VectorizeBridgeType
VectorizeBridge{T,F,S,G} <: Bridges.Constraint.AbstractBridge

VectorizeBridge implements the following reformulations:

  • $g(x) \ge a$ into $[g(x) - a] \in \mathbb{R}_+$
  • $g(x) \le a$ into $[g(x) - a] \in \mathbb{R}_-$
  • $g(x) == a$ into $[g(x) - a] \in \{0\}$

where T is the coefficient type of g(x) - a.

Source node

VectorizeBridge supports:

Target nodes

VectorizeBridge creates:

source
MathOptInterface.Bridges.Constraint.ScalarizeBridgeType
ScalarizeBridge{T,F,S}

ScalarizeBridge implements the following reformulations:

  • $f(x) - a \in \mathbb{R}_+$ into $f_i(x) \ge a_i$ for all $i$
  • $f(x) - a \in \mathbb{R}_-$ into $f_i(x) \le a_i$ for all $i$
  • $f(x) - a \in \{0\}$ into $f_i(x) == a_i$ for all $i$

Source node

ScalarizeBridge supports:

Target nodes

ScalarizeBridge creates:

source
MathOptInterface.Bridges.Constraint.FunctionConversionBridgeType
FunctionConversionBridge{T,F,G,S} <: AbstractFunctionConversionBridge{G,S}

FunctionConversionBridge implements the following reformulations:

  • $g(x) \in S$ into $f(x) \in S$

for these pairs of functions:

Source node

FunctionConversionBridge supports:

  • G in S

Target nodes

FunctionConversionBridge creates:

  • F in S
source
MathOptInterface.Bridges.Constraint.SplitComplexEqualToBridgeType
SplitComplexEqualToBridge{T,F,G} <: Bridges.Constraint.AbstractBridge

SplitComplexEqualToBridge implements the following reformulation:

  • $f(x) + g(x) * im = a + b * im$ into $f(x) = a$ and $g(x) = b$

Source node

SplitComplexEqualToBridge supports:

where G is a function with Complex coefficients.

Target nodes

SplitComplexEqualToBridge creates:

where F is the type of the real/imaginary part of G.

source
MathOptInterface.Bridges.Constraint.SplitComplexZerosBridgeType
SplitComplexZerosBridge{T,F,G} <: Bridges.Constraint.AbstractBridge

SplitComplexZerosBridge implements the following reformulation:

  • $f(x) \in \{0\}^n$ into $\text{Re}(f(x)) \in \{0\}^n$ and $\text{Im}(f(x)) \in \{0\}^n$

Source node

SplitComplexZerosBridge supports:

where G is a function with Complex coefficients.

Target nodes

SplitComplexZerosBridge creates:

where F is the type of the real/imaginary part of G.

source
MathOptInterface.Bridges.Constraint.SplitIntervalBridgeType
SplitIntervalBridge{T,F,S,LS,US} <: Bridges.Constraint.AbstractBridge

SplitIntervalBridge implements the following reformulations:

  • $l \le f(x) \le u$ into $f(x) \ge l$ and $f(x) \le u$
  • $f(x) = b$ into $f(x) \ge b$ and $f(x) \le b$
  • $f(x) \in \{0\}$ into $f(x) \in \mathbb{R}_+$ and $f(x) \in \mathbb{R}_-$

Source node

SplitIntervalBridge supports:

Target nodes

SplitIntervalBridge creates:

or

Note

If T<:AbstractFloat and S is MOI.Interval{T} then no lower (resp. upper) bound constraint is created if the lower (resp. upper) bound is typemin(T) (resp. typemax(T)). Similarly, when MOI.ConstraintSet is set, a lower or upper bound constraint may be deleted or created accordingly.

source
MathOptInterface.Bridges.Constraint.SOCtoNonConvexQuadBridgeType
SOCtoNonConvexQuadBridge{T} <: Bridges.Constraint.AbstractBridge

SOCtoNonConvexQuadBridge implements the following reformulations:

  • $||x||_2 \le t$ into $\sum x^2 - t^2 \le 0$ and $1t + 0 \ge 0$

The MOI.ScalarAffineFunction $1t + 0$ is used in case the variable has other bound constraints.

Warning

This transformation starts from a convex constraint and creates a non-convex constraint. Unless the solver has explicit support for detecting second-order cones in quadratic form, this may (wrongly) be interpreted by the solver as being non-convex. Therefore, this bridge is not added automatically by MOI.Bridges.full_bridge_optimizer. Care is recommended when adding this bridge to a optimizer.

Source node

SOCtoNonConvexQuadBridge supports:

Target nodes

SOCtoNonConvexQuadBridge creates:

source
MathOptInterface.Bridges.Constraint.RSOCtoNonConvexQuadBridgeType
RSOCtoNonConvexQuadBridge{T} <: Bridges.Constraint.AbstractBridge

RSOCtoNonConvexQuadBridge implements the following reformulations:

  • $||x||_2^2 \le 2tu$ into $\sum x^2 - 2tu \le 0$, $1t + 0 \ge 0$, and $1u + 0 \ge 0$.

The MOI.ScalarAffineFunctions $1t + 0$ and $1u + 0$ are used in case the variables have other bound constraints.

Warning

This transformation starts from a convex constraint and creates a non-convex constraint. Unless the solver has explicit support for detecting rotated second-order cones in quadratic form, this may (wrongly) be interpreted by the solver as being non-convex. Therefore, this bridge is not added automatically by MOI.Bridges.full_bridge_optimizer. Care is recommended when adding this bridge to a optimizer.

Source node

RSOCtoNonConvexQuadBridge supports:

Target nodes

RSOCtoNonConvexQuadBridge creates:

source
MathOptInterface.Bridges.Constraint.QuadtoSOCBridgeType
QuadtoSOCBridge{T} <: Bridges.Constraint.AbstractBridge

QuadtoSOCBridge converts quadratic inequalities

\[\frac{1}{2}x^T Q x + a^T x \le ub\]

into MOI.RotatedSecondOrderCone constraints, but it only applies when $Q$ is positive definite.

This is because, if Q is positive definite, there exists U such that $Q = U^T U$, and so the inequality can then be rewritten as;

\[\|U x\|_2^2 \le 2 (-a^T x + ub)\]

Therefore, QuadtoSOCBridge implements the following reformulations:

  • $\frac{1}{2}x^T Q x + a^T x \le ub$ into $(1, -a^T x + ub, Ux) \in RotatedSecondOrderCone$ where $Q = U^T U$
  • $\frac{1}{2}x^T Q x + a^T x \ge lb$ into $(1, a^T x - lb, Ux) \in RotatedSecondOrderCone$ where $-Q = U^T U$

Source node

QuadtoSOCBridge supports:

Target nodes

RelativeEntropyBridge creates:

Errors

This bridge errors if Q is not positive definite.

source
MathOptInterface.Bridges.Constraint.SOCtoPSDBridgeType
SOCtoPSDBridge{T,F,G} <: Bridges.Constraint.AbstractBridge

SOCtoPSDBridge implements the following reformulation:

  • $||x||_2 \le t$ into $\left[\begin{array}{c c}t & x^\top \\ x & t \mathbf{I}\end{array}\right]\succeq 0$
Warning

This bridge is not added by default by MOI.Bridges.full_bridge_optimizer because bridging second order cone constraints to semidefinite constraints can be achieved by the SOCtoRSOCBridge followed by the RSOCtoPSDBridge, while creating a smaller semidefinite constraint.

Source node

SOCtoPSDBridge supports:

Target nodes

SOCtoPSDBridge creates:

source
MathOptInterface.Bridges.Constraint.NormToPowerBridgeType
NormToPowerBridge{T,F} <: Bridges.Constraint.AbstractBridge

NormToPowerBridge implements the following reformulation:

  • $(t, x) \in NormCone(p, 1+d)$ into $(r_i, t, x_i) \in PowerCone(1 / p)$ for all $i$, and $\sum\limits_i r_i == t$.

For details, see Alizadeh, F., and Goldfarb, D. (2001). "Second-order cone programming." Mathematical Programming, Series B, 95:3-51.

Source node

NormToPowerBridge supports:

Target nodes

NormToPowerBridge creates:

source
MathOptInterface.Bridges.Constraint.GeoMeantoRelEntrBridgeType
GeoMeantoRelEntrBridge{T,F,G,H} <: Bridges.Constraint.AbstractBridge

GeoMeantoRelEntrBridge implements the following reformulation:

  • $(u, w) \in GeometricMeanCone$ into $(0, w, (u + y)\mathbf{1})\in RelativeEntropyCone$ and $y \ge 0$

Source node

GeoMeantoRelEntrBridge supports:

Target nodes

GeoMeantoRelEntrBridge creates:

Derivation

The derivation of the bridge is as follows:

\[\begin{aligned} (u, w) \in GeometricMeanCone \iff & u \le \left(\prod_{i=1}^n w_i\right)^{1/n} \\ \iff & 0 \le u + y \le \left(\prod_{i=1}^n w_i\right)^{1/n}, y \ge 0 \\ \iff & 1 \le \frac{\left(\prod_{i=1}^n w_i\right)^{1/n}}{u + y}, y \ge 0 \\ @@ -8,7 +8,7 @@ \iff & 0 \ge \sum_{i=1}^n \log\left(\frac{u + y}{w_i}\right), y \ge 0 \\ \iff & 0 \ge \sum_{i=1}^n (u + y) \log\left(\frac{u + y}{w_i}\right), y \ge 0 \\ \iff & (0, w, (u + y)\mathbf{1}) \in RelativeEntropyCone, y \ge 0 \\ -\end{aligned}\]

This derivation assumes that $u + y > 0$, which is enforced by the relative entropy cone.

source
MathOptInterface.Bridges.Constraint.GeoMeanToPowerBridgeType
GeoMeanToPowerBridge{T,F} <: Bridges.Constraint.AbstractBridge

GeoMeanToPowerBridge implements the following reformulation:

  • $(y, x...) \in GeometricMeanCone(1+d)$ into $(x_1, t, y) \in PowerCone(1/d)$ and $(t, x_2, ..., x_d) in GeometricMeanCone(d)$, which is then recursively expanded into more PowerCone constraints.

Source node

GeoMeanToPowerBridge supports:

Target nodes

GeoMeanToPowerBridge creates:

source
MathOptInterface.Bridges.Constraint.GeoMeanBridgeType
GeoMeanBridge{T,F,G,H} <: Bridges.Constraint.AbstractBridge

GeoMeanBridge implements a reformulation from MOI.GeometricMeanCone into MOI.RotatedSecondOrderCone.

The reformulation is best described in an example.

Consider the cone of dimension 4:

\[t \le \sqrt[3]{x_1 x_2 x_3}\]

This can be rewritten as $\exists y \ge 0$ such that:

\[\begin{align*} +\end{aligned}\]

This derivation assumes that $u + y > 0$, which is enforced by the relative entropy cone.

source
MathOptInterface.Bridges.Constraint.GeoMeanToPowerBridgeType
GeoMeanToPowerBridge{T,F} <: Bridges.Constraint.AbstractBridge

GeoMeanToPowerBridge implements the following reformulation:

  • $(y, x...) \in GeometricMeanCone(1+d)$ into $(x_1, t, y) \in PowerCone(1/d)$ and $(t, x_2, ..., x_d) in GeometricMeanCone(d)$, which is then recursively expanded into more PowerCone constraints.

Source node

GeoMeanToPowerBridge supports:

Target nodes

GeoMeanToPowerBridge creates:

source
MathOptInterface.Bridges.Constraint.GeoMeanBridgeType
GeoMeanBridge{T,F,G,H} <: Bridges.Constraint.AbstractBridge

GeoMeanBridge implements a reformulation from MOI.GeometricMeanCone into MOI.RotatedSecondOrderCone.

The reformulation is best described in an example.

Consider the cone of dimension 4:

\[t \le \sqrt[3]{x_1 x_2 x_3}\]

This can be rewritten as $\exists y \ge 0$ such that:

\[\begin{align*} t & \le y,\\ y^4 & \le x_1 x_2 x_3 y. \end{align*}\]

Note that we need to create $y$ and not use $t^4$ directly because $t$ is allowed to be negative.

This is equivalent to:

\[\begin{align*} @@ -17,7 +17,7 @@ y_2^2 & \le 2x_1 x_2, \\ y_3^2 & \le 2x_3(y_1/\sqrt{4}) \\ y & \ge 0. -\end{align*}\]

More generally, you can show how the geometric mean code is recursively expanded into a set of new variables $y$ in MOI.Nonnegatives, a set of MOI.RotatedSecondOrderCone constraints, and a MOI.LessThan constraint between $t$ and $y_1$.

Source node

GeoMeanBridge supports:

Target nodes

GeoMeanBridge creates:

source
MathOptInterface.Bridges.Constraint.RelativeEntropyBridgeType
RelativeEntropyBridge{T,F,G,H} <: Bridges.Constraint.AbstractBridge

RelativeEntropyBridge implements the following reformulation that converts a MOI.RelativeEntropyCone into an MOI.ExponentialCone:

  • $u \ge \sum_{i=1}^n w_i \log \left(\frac{w_i}{v_i}\right)$ into $y_i \ge 0$, $u \ge \sum_{i=1}^n y_i$, and $(-y_i, w_i, v_i) \in ExponentialCone$.

Source node

RelativeEntropyBridge supports:

Target nodes

RelativeEntropyBridge creates:

source
MathOptInterface.Bridges.Constraint.SquareBridgeType
SquareBridge{T,F,G,TT,ST} <: Bridges.Constraint.AbstractBridge

SquareBridge implements the following reformulations:

  • $(t, u, X) \in LogDetConeSquare$ into $(t, u, Y) in LogDetConeTriangle$
  • $(t, X) \in RootDetConeSquare$ into $(t, Y) in RootDetConeTriangle$
  • $X \in AbstractSymmetricMatrixSetSquare$ into $Y in AbstractSymmetricMatrixSetTriangle$

where $Y$ is the upper triangluar component of $X$.

In addition, constraints are added as necessary to constrain the matrix $X$ to be symmetric. For example, the constraint for the matrix:

\[\begin{pmatrix} +\end{align*}\]

More generally, you can show how the geometric mean code is recursively expanded into a set of new variables $y$ in MOI.Nonnegatives, a set of MOI.RotatedSecondOrderCone constraints, and a MOI.LessThan constraint between $t$ and $y_1$.

Source node

GeoMeanBridge supports:

Target nodes

GeoMeanBridge creates:

source
MathOptInterface.Bridges.Constraint.RelativeEntropyBridgeType
RelativeEntropyBridge{T,F,G,H} <: Bridges.Constraint.AbstractBridge

RelativeEntropyBridge implements the following reformulation that converts a MOI.RelativeEntropyCone into an MOI.ExponentialCone:

  • $u \ge \sum_{i=1}^n w_i \log \left(\frac{w_i}{v_i}\right)$ into $y_i \ge 0$, $u \ge \sum_{i=1}^n y_i$, and $(-y_i, w_i, v_i) \in ExponentialCone$.

Source node

RelativeEntropyBridge supports:

Target nodes

RelativeEntropyBridge creates:

source
MathOptInterface.Bridges.Constraint.SquareBridgeType
SquareBridge{T,F,G,TT,ST} <: Bridges.Constraint.AbstractBridge

SquareBridge implements the following reformulations:

  • $(t, u, X) \in LogDetConeSquare$ into $(t, u, Y) in LogDetConeTriangle$
  • $(t, X) \in RootDetConeSquare$ into $(t, Y) in RootDetConeTriangle$
  • $X \in AbstractSymmetricMatrixSetSquare$ into $Y in AbstractSymmetricMatrixSetTriangle$

where $Y$ is the upper triangluar component of $X$.

In addition, constraints are added as necessary to constrain the matrix $X$ to be symmetric. For example, the constraint for the matrix:

\[\begin{pmatrix} 1 & 1 + x & 2 - 3x\\ 1 + x & 2 + x & 3 - x\\ 2 - 3x & 2 + x & 2x @@ -25,7 +25,7 @@ 1 & 1 + x & 2 - 3x\\ \cdot & 2 + x & 3 - x\\ \cdot & \cdot & 2x -\end{pmatrix}\]

and the equality constraint between the off-diagonal entries (2, 3) and (3, 2) $3 - x == 2 + x$. Note that no symmetrization constraint needs to be added between the off-diagonal entries (1, 2) and (2, 1) or between (1, 3) and (3, 1) because the expressions are the same.

Source node

SquareBridge supports:

  • F in ST

Target nodes

SquareBridge creates:

  • G in TT
source
MathOptInterface.Bridges.Constraint.HermitianToSymmetricPSDBridgeType
HermitianToSymmetricPSDBridge{T,F,G} <: Bridges.Constraint.AbstractBridge

HermitianToSymmetricPSDBridge implements the following reformulation:

  • Hermitian positive semidefinite n x n complex matrix to a symmetric positive semidefinite 2n x 2n real matrix.

See also MOI.Bridges.Variable.HermitianToSymmetricPSDBridge.

Source node

HermitianToSymmetricPSDBridge supports:

Target node

HermitianToSymmetricPSDBridge creates:

Reformulation

The reformulation is best described by example.

The Hermitian matrix:

\[\begin{bmatrix} +\end{pmatrix}\]

and the equality constraint between the off-diagonal entries (2, 3) and (3, 2) $3 - x == 2 + x$. Note that no symmetrization constraint needs to be added between the off-diagonal entries (1, 2) and (2, 1) or between (1, 3) and (3, 1) because the expressions are the same.

Source node

SquareBridge supports:

  • F in ST

Target nodes

SquareBridge creates:

  • G in TT
source
MathOptInterface.Bridges.Constraint.HermitianToSymmetricPSDBridgeType
HermitianToSymmetricPSDBridge{T,F,G} <: Bridges.Constraint.AbstractBridge

HermitianToSymmetricPSDBridge implements the following reformulation:

  • Hermitian positive semidefinite n x n complex matrix to a symmetric positive semidefinite 2n x 2n real matrix.

See also MOI.Bridges.Variable.HermitianToSymmetricPSDBridge.

Source node

HermitianToSymmetricPSDBridge supports:

Target node

HermitianToSymmetricPSDBridge creates:

Reformulation

The reformulation is best described by example.

The Hermitian matrix:

\[\begin{bmatrix} x_{11} & x_{12} + y_{12}im & x_{13} + y_{13}im\\ x_{12} - y_{12}im & x_{22} & x_{23} + y_{23}im\\ x_{13} - y_{13}im & x_{23} - y_{23}im & x_{33} @@ -36,13 +36,13 @@ & & & x_{11} & x_{12} & x_{13} \\ & & & & x_{22} & x_{23} \\ & & & & & x_{33} -\end{bmatrix}\]

is positive semidefinite.

The bridge achieves this reformulation by constraining the above matrix to belong to the MOI.PositiveSemidefiniteConeTriangle(6).

source
MathOptInterface.Bridges.Constraint.RootDetBridgeType
RootDetBridge{T,F,G,H} <: Bridges.Constraint.AbstractBridge

The MOI.RootDetConeTriangle is representable by MOI.PositiveSemidefiniteConeTriangle and MOI.GeometricMeanCone constraints, see [1, p. 149].

Indeed, $t \le \det(X)^{1/n}$ if and only if there exists a lower triangular matrix $Δ$ such that:

\[\begin{align*} +\end{bmatrix}\]

is positive semidefinite.

The bridge achieves this reformulation by constraining the above matrix to belong to the MOI.PositiveSemidefiniteConeTriangle(6).

source
MathOptInterface.Bridges.Constraint.RootDetBridgeType
RootDetBridge{T,F,G,H} <: Bridges.Constraint.AbstractBridge

The MOI.RootDetConeTriangle is representable by MOI.PositiveSemidefiniteConeTriangle and MOI.GeometricMeanCone constraints, see [1, p. 149].

Indeed, $t \le \det(X)^{1/n}$ if and only if there exists a lower triangular matrix $Δ$ such that:

\[\begin{align*} \begin{pmatrix} X & Δ\\ Δ^\top & \mathrm{Diag}(Δ) \end{pmatrix} & \succeq 0\\ (t, \mathrm{Diag}(Δ)) & \in GeometricMeanCone -\end{align*}\]

Source node

RootDetBridge supports:

Target nodes

RootDetBridge creates:

[1] Ben-Tal, Aharon, and Arkadi Nemirovski. Lectures on modern convex optimization: analysis, algorithms, and engineering applications. Society for Industrial and Applied Mathematics, 2001.

source
MathOptInterface.Bridges.Constraint.LogDetBridgeType
LogDetBridge{T,F,G,H,I} <: Bridges.Constraint.AbstractBridge

The MOI.LogDetConeTriangle is representable by MOI.PositiveSemidefiniteConeTriangle and MOI.ExponentialCone constraints.

Indeed, $\log\det(X) = \sum\limits_{i=1}^n \log(\delta_i)$ where $\delta_i$ are the eigenvalues of $X$.

Adapting the method from [1, p. 149], we see that $t \le u \log(\det(X/u))$ for $u > 0$ if and only if there exists a lower triangular matrix $Δ$ such that

\[\begin{align*} +\end{align*}\]

Source node

RootDetBridge supports:

Target nodes

RootDetBridge creates:

[1] Ben-Tal, Aharon, and Arkadi Nemirovski. Lectures on modern convex optimization: analysis, algorithms, and engineering applications. Society for Industrial and Applied Mathematics, 2001.

source
MathOptInterface.Bridges.Constraint.LogDetBridgeType
LogDetBridge{T,F,G,H,I} <: Bridges.Constraint.AbstractBridge

The MOI.LogDetConeTriangle is representable by MOI.PositiveSemidefiniteConeTriangle and MOI.ExponentialCone constraints.

Indeed, $\log\det(X) = \sum\limits_{i=1}^n \log(\delta_i)$ where $\delta_i$ are the eigenvalues of $X$.

Adapting the method from [1, p. 149], we see that $t \le u \log(\det(X/u))$ for $u > 0$ if and only if there exists a lower triangular matrix $Δ$ such that

\[\begin{align*} \begin{pmatrix} X & Δ\\ Δ^\top & \mathrm{Diag}(Δ) @@ -55,7 +55,7 @@ \end{pmatrix} & \succeq 0\\ (l_i, u , Δ_{ii}) & \in ExponentialCone\quad \forall i \\ t - \sum_{i=1}^n l_i & \le 0 -\end{align*}\]

Source node

LogDetBridge supports:

Target nodes

LogDetBridge creates:

[1] Ben-Tal, Aharon, and Arkadi Nemirovski. Lectures on modern convex optimization: analysis, algorithms, and engineering applications. Society for Industrial and Applied Mathematics, 2001.

source
MathOptInterface.Bridges.Constraint.IndicatorActiveOnFalseBridgeType
IndicatorActiveOnFalseBridge{T,F,S} <: Bridges.Constraint.AbstractBridge

IndicatorActiveOnFalseBridge implements the following reformulation:

  • $\neg z \implies {f(x) \in S}$ into $y \implies {f(x) \in S}$, $z + y = 1$, and $y \in \{0, 1\}$

Source node

IndicatorActiveOnFalseBridge supports:

Target nodes

IndicatorActiveOnFalseBridge creates:

source
MathOptInterface.Bridges.Constraint.IndicatorGreaterToLessThanBridgeType
IndicatorGreaterToLessThanBridge{T,A} <: Bridges.Constraint.AbstractBridge

IndicatorGreaterToLessThanBridge implements the following reformulation:

  • $z \implies {f(x) \ge l}$ into $z \implies {-f(x) \le -l}$

Source node

IndicatorGreaterToLessThanBridge supports:

Target nodes

IndicatorGreaterToLessThanBridge creates:

source
MathOptInterface.Bridges.Constraint.IndicatorLessToGreaterThanBridgeType
IndicatorLessToGreaterThanBridge{T,A} <: Bridges.Constraint.AbstractBridge

IndicatorLessToGreaterThanBridge implements the following reformulations:

  • $z \implies {f(x) \le u}$ into $z \implies {-f(x) \ge -u}$

Source node

IndicatorLessToGreaterThanBridge supports:

Target nodes

IndicatorLessToGreaterThanBridge creates:

source
MathOptInterface.Bridges.Constraint.IndicatorSOS1BridgeType
IndicatorSOS1Bridge{T,S} <: Bridges.Constraint.AbstractBridge

IndicatorSOS1Bridge implements the following reformulation:

  • $z \implies {f(x) \in S}$ into $f(x) + y \in S$, $SOS1(y, z)$
Warning

This bridge assumes that the solver supports MOI.SOS1{T} constraints in which one of the variables ($y$) is continuous.

Source node

IndicatorSOS1Bridge supports:

Target nodes

IndicatorSOS1Bridge creates:

source
MathOptInterface.Bridges.Constraint.SemiToBinaryBridgeType
SemiToBinaryBridge{T,S} <: Bridges.Constraint.AbstractBridge

SemiToBinaryBridge implements the following reformulations:

source
MathOptInterface.Bridges.Constraint.IndicatorActiveOnFalseBridgeType
IndicatorActiveOnFalseBridge{T,F,S} <: Bridges.Constraint.AbstractBridge

IndicatorActiveOnFalseBridge implements the following reformulation:

  • $\neg z \implies {f(x) \in S}$ into $y \implies {f(x) \in S}$, $z + y = 1$, and $y \in \{0, 1\}$

Source node

IndicatorActiveOnFalseBridge supports:

Target nodes

IndicatorActiveOnFalseBridge creates:

source
MathOptInterface.Bridges.Constraint.IndicatorGreaterToLessThanBridgeType
IndicatorGreaterToLessThanBridge{T,A} <: Bridges.Constraint.AbstractBridge

IndicatorGreaterToLessThanBridge implements the following reformulation:

  • $z \implies {f(x) \ge l}$ into $z \implies {-f(x) \le -l}$

Source node

IndicatorGreaterToLessThanBridge supports:

Target nodes

IndicatorGreaterToLessThanBridge creates:

source
MathOptInterface.Bridges.Constraint.IndicatorLessToGreaterThanBridgeType
IndicatorLessToGreaterThanBridge{T,A} <: Bridges.Constraint.AbstractBridge

IndicatorLessToGreaterThanBridge implements the following reformulations:

  • $z \implies {f(x) \le u}$ into $z \implies {-f(x) \ge -u}$

Source node

IndicatorLessToGreaterThanBridge supports:

Target nodes

IndicatorLessToGreaterThanBridge creates:

source
MathOptInterface.Bridges.Constraint.IndicatorSOS1BridgeType
IndicatorSOS1Bridge{T,S} <: Bridges.Constraint.AbstractBridge

IndicatorSOS1Bridge implements the following reformulation:

  • $z \implies {f(x) \in S}$ into $f(x) + y \in S$, $SOS1(y, z)$
Warning

This bridge assumes that the solver supports MOI.SOS1{T} constraints in which one of the variables ($y$) is continuous.

Source node

IndicatorSOS1Bridge supports:

Target nodes

IndicatorSOS1Bridge creates:

source
MathOptInterface.Bridges.Constraint.SemiToBinaryBridgeType
SemiToBinaryBridge{T,S} <: Bridges.Constraint.AbstractBridge

SemiToBinaryBridge implements the following reformulations:

  • $x \in \{0\} \cup [l, u]$ into

    \[\begin{aligned} x \leq z u \\ x \geq z l \\ z \in \{0, 1\} @@ -64,23 +64,23 @@ x \geq z l \\ z \in \{0, 1\} \\ x \in \mathbb{Z} -\end{aligned}\]

Source node

SemiToBinaryBridge supports:

Target nodes

SemiToBinaryBridge creates:

source
MathOptInterface.Bridges.Constraint.ZeroOneBridgeType
ZeroOneBridge{T} <: Bridges.Constraint.AbstractBridge

ZeroOneBridge implements the following reformulation:

  • $x \in \{0, 1\}$ into $x \in \mathbb{Z}$, $1x \in [0, 1]$.
Note

ZeroOneBridge adds a linear constraint instead of adding variable bounds to avoid conflicting with bounds set by the user.

Source node

ZeroOneBridge supports:

Target nodes

ZeroOneBridge creates:

source
MathOptInterface.Bridges.Constraint.IntegerToZeroOneBridgeType
IntegerToZeroOneBridge{T} <: Bridges.Constraint.AbstractBridge

IntegerToZeroOneBridge implements the following reformulation:

  • $x \in \mathbf{Z}$ into $y_i \in \{0, 1\}$, $x == lb + \sum 2^{i-1} y_i$.

Source node

IntegerToZeroOneBridge supports:

Target nodes

IntegerToZeroOneBridge creates:

Developer note

This bridge is implemented as a constraint bridge instead of a variable bridge because we don't want to substitute the linear combination of y for every instance of x. Doing so would be expensive and greatly reduce the sparsity of the constraints.

source
MathOptInterface.Bridges.Constraint.NumberConversionBridgeType
NumberConversionBridge{T,F1,S1,F2,S2} <: Bridges.Constraint.AbstractBridge

NumberConversionBridge implements the following reformulation:

  • $f1(x) \in S1$ to $f2(x) \in S2$

where f and S are the same functional form, but differ in their coefficient type.

Source node

NumberConversionBridge supports:

  • F1 in S1

Target node

NumberConversionBridge creates:

  • F2 in S2
source
MathOptInterface.Bridges.Constraint.AllDifferentToCountDistinctBridgeType
AllDifferentToCountDistinctBridge{T,F} <: Bridges.Constraint.AbstractBridge

AllDifferentToCountDistinctBridge implements the following reformulations:

  • $x \in \textsf{AllDifferent}(d)$ to $(n, x) \in \textsf{CountDistinct}(1+d)$ and $n = d$
  • $f(x) \in \textsf{AllDifferent}(d)$ to $(d, f(x)) \in \textsf{CountDistinct}(1+d)$

Source node

AllDifferentToCountDistinctBridge supports:

where F is MOI.VectorOfVariables or MOI.VectorAffineFunction{T}.

Target nodes

AllDifferentToCountDistinctBridge creates:

source
MathOptInterface.Bridges.Constraint.ReifiedAllDifferentToCountDistinctBridgeType
ReifiedAllDifferentToCountDistinctBridge{T,F} <:
-Bridges.Constraint.AbstractBridge

ReifiedAllDifferentToCountDistinctBridge implements the following reformulations:

  • $r \iff x \in \textsf{AllDifferent}(d)$ to $r \iff (n, x) \in \textsf{CountDistinct}(1+d)$ and $n = d$
  • $r \iff f(x) \in \textsf{AllDifferent}(d)$ to $r \iff (d, f(x)) \in \textsf{CountDistinct}(1+d)$

Source node

ReifiedAllDifferentToCountDistinctBridge supports:

where F is MOI.VectorOfVariables or MOI.VectorAffineFunction{T}.

Target nodes

ReifiedAllDifferentToCountDistinctBridge creates:

source
MathOptInterface.Bridges.Constraint.BinPackingToMILPBridgeType
BinPackingToMILPBridge{T,F} <: Bridges.Constraint.AbstractBridge

BinPackingToMILPBridge implements the following reformulation:

  • $x \in BinPacking(c, w)$ into a mixed-integer linear program.

Reformulation

The reformulation is non-trivial, and it depends on the finite domain of each variable $x_i$, which we as define $S_i = \{l_i,\ldots,u_i\}$.

First, we introduce new binary variables $z_{ij}$, which are $1$ if variable $x_i$ takes the value $j$ in the optimal solution and $0$ otherwise:

\[\begin{aligned} +\end{aligned}\]

Source node

SemiToBinaryBridge supports:

Target nodes

SemiToBinaryBridge creates:

source
MathOptInterface.Bridges.Constraint.ZeroOneBridgeType
ZeroOneBridge{T} <: Bridges.Constraint.AbstractBridge

ZeroOneBridge implements the following reformulation:

  • $x \in \{0, 1\}$ into $x \in \mathbb{Z}$, $1x \in [0, 1]$.
Note

ZeroOneBridge adds a linear constraint instead of adding variable bounds to avoid conflicting with bounds set by the user.

Source node

ZeroOneBridge supports:

Target nodes

ZeroOneBridge creates:

source
MathOptInterface.Bridges.Constraint.IntegerToZeroOneBridgeType
IntegerToZeroOneBridge{T} <: Bridges.Constraint.AbstractBridge

IntegerToZeroOneBridge implements the following reformulation:

  • $x \in \mathbf{Z}$ into $y_i \in \{0, 1\}$, $x == lb + \sum 2^{i-1} y_i$.

Source node

IntegerToZeroOneBridge supports:

Target nodes

IntegerToZeroOneBridge creates:

Developer note

This bridge is implemented as a constraint bridge instead of a variable bridge because we don't want to substitute the linear combination of y for every instance of x. Doing so would be expensive and greatly reduce the sparsity of the constraints.

source
MathOptInterface.Bridges.Constraint.NumberConversionBridgeType
NumberConversionBridge{T,F1,S1,F2,S2} <: Bridges.Constraint.AbstractBridge

NumberConversionBridge implements the following reformulation:

  • $f1(x) \in S1$ to $f2(x) \in S2$

where f and S are the same functional form, but differ in their coefficient type.

Source node

NumberConversionBridge supports:

  • F1 in S1

Target node

NumberConversionBridge creates:

  • F2 in S2
source
MathOptInterface.Bridges.Constraint.AllDifferentToCountDistinctBridgeType
AllDifferentToCountDistinctBridge{T,F} <: Bridges.Constraint.AbstractBridge

AllDifferentToCountDistinctBridge implements the following reformulations:

  • $x \in \textsf{AllDifferent}(d)$ to $(n, x) \in \textsf{CountDistinct}(1+d)$ and $n = d$
  • $f(x) \in \textsf{AllDifferent}(d)$ to $(d, f(x)) \in \textsf{CountDistinct}(1+d)$

Source node

AllDifferentToCountDistinctBridge supports:

where F is MOI.VectorOfVariables or MOI.VectorAffineFunction{T}.

Target nodes

AllDifferentToCountDistinctBridge creates:

source
MathOptInterface.Bridges.Constraint.ReifiedAllDifferentToCountDistinctBridgeType
ReifiedAllDifferentToCountDistinctBridge{T,F} <:
+Bridges.Constraint.AbstractBridge

ReifiedAllDifferentToCountDistinctBridge implements the following reformulations:

  • $r \iff x \in \textsf{AllDifferent}(d)$ to $r \iff (n, x) \in \textsf{CountDistinct}(1+d)$ and $n = d$
  • $r \iff f(x) \in \textsf{AllDifferent}(d)$ to $r \iff (d, f(x)) \in \textsf{CountDistinct}(1+d)$

Source node

ReifiedAllDifferentToCountDistinctBridge supports:

where F is MOI.VectorOfVariables or MOI.VectorAffineFunction{T}.

Target nodes

ReifiedAllDifferentToCountDistinctBridge creates:

source
MathOptInterface.Bridges.Constraint.BinPackingToMILPBridgeType
BinPackingToMILPBridge{T,F} <: Bridges.Constraint.AbstractBridge

BinPackingToMILPBridge implements the following reformulation:

  • $x \in BinPacking(c, w)$ into a mixed-integer linear program.

Reformulation

The reformulation is non-trivial, and it depends on the finite domain of each variable $x_i$, which we as define $S_i = \{l_i,\ldots,u_i\}$.

First, we introduce new binary variables $z_{ij}$, which are $1$ if variable $x_i$ takes the value $j$ in the optimal solution and $0$ otherwise:

\[\begin{aligned} z_{ij} \in \{0, 1\} & \;\; \forall i \in 1\ldots d, j \in S_i \\ x_i - \sum\limits_{j\in S_i} j \cdot z_{ij} = 0 & \;\; \forall i \in 1\ldots d \\ \sum\limits_{j\in S_i} z_{ij} = 1 & \;\; \forall i \in 1\ldots d \\ -\end{aligned}\]

Then, we add the capacity constraint for all possible bins $j$:

\[\sum\limits_{i} w_i z_{ij} \le c \forall j \in \bigcup_{i=1,\ldots,d} S_i\]

Source node

BinPackingToMILPBridge supports:

Target nodes

BinPackingToMILPBridge creates:

source
MathOptInterface.Bridges.Constraint.CircuitToMILPBridgeType
CircuitToMILPBridge{T,F} <: Bridges.Constraint.AbstractBridge

CircuitToMILPBridge implements the following reformulation:

  • $x \in \textsf{Circuit}(d)$ to the Miller-Tucker-Zemlin formulation of the Traveling Salesperson Problem.

Source node

CircuitToMILPBridge supports:

where F is MOI.VectorOfVariables or MOI.VectorAffineFunction{T}.

Target nodes

CircuitToMILPBridge creates:

source
MathOptInterface.Bridges.Constraint.CountAtLeastToCountBelongsBridgeType
CountAtLeastToCountBelongsBridge{T,F} <: Bridges.Constraint.AbstractBridge

CountAtLeastToCountBelongsBridge implements the following reformulation:

  • $x \in \textsf{CountAtLeast}(n, d, \mathcal{S})$ to $(n_i, x_{d_i}) \in \textsf{CountBelongs}(1+d, \mathcal{S})$ and $n_i \ge n$ for all $i$.

Source node

CountAtLeastToCountBelongsBridge supports:

where F is MOI.VectorOfVariables or MOI.VectorAffineFunction{T}.

Target nodes

CountAtLeastToCountBelongsBridge creates:

source
MathOptInterface.Bridges.Constraint.CountBelongsToMILPBridgeType
CountBelongsToMILPBridge{T,F} <: Bridges.Constraint.AbstractBridge

CountBelongsToMILPBridge implements the following reformulation:

  • $(n, x) \in \textsf{CountBelongs}(1+d, \mathcal{S})$ into a mixed-integer linear program.

Reformulation

The reformulation is non-trivial, and it depends on the finite domain of each variable $x_i$, which we as define $S_i = \{l_i,\ldots,u_i\}$.

First, we introduce new binary variables $z_{ij}$, which are $1$ if variable $x_i$ takes the value $j$ in the optimal solution and $0$ otherwise:

\[\begin{aligned} +\end{aligned}\]

Then, we add the capacity constraint for all possible bins $j$:

\[\sum\limits_{i} w_i z_{ij} \le c \forall j \in \bigcup_{i=1,\ldots,d} S_i\]

Source node

BinPackingToMILPBridge supports:

Target nodes

BinPackingToMILPBridge creates:

source
MathOptInterface.Bridges.Constraint.CircuitToMILPBridgeType
CircuitToMILPBridge{T,F} <: Bridges.Constraint.AbstractBridge

CircuitToMILPBridge implements the following reformulation:

  • $x \in \textsf{Circuit}(d)$ to the Miller-Tucker-Zemlin formulation of the Traveling Salesperson Problem.

Source node

CircuitToMILPBridge supports:

where F is MOI.VectorOfVariables or MOI.VectorAffineFunction{T}.

Target nodes

CircuitToMILPBridge creates:

source
MathOptInterface.Bridges.Constraint.CountAtLeastToCountBelongsBridgeType
CountAtLeastToCountBelongsBridge{T,F} <: Bridges.Constraint.AbstractBridge

CountAtLeastToCountBelongsBridge implements the following reformulation:

  • $x \in \textsf{CountAtLeast}(n, d, \mathcal{S})$ to $(n_i, x_{d_i}) \in \textsf{CountBelongs}(1+d, \mathcal{S})$ and $n_i \ge n$ for all $i$.

Source node

CountAtLeastToCountBelongsBridge supports:

where F is MOI.VectorOfVariables or MOI.VectorAffineFunction{T}.

Target nodes

CountAtLeastToCountBelongsBridge creates:

source
MathOptInterface.Bridges.Constraint.CountBelongsToMILPBridgeType
CountBelongsToMILPBridge{T,F} <: Bridges.Constraint.AbstractBridge

CountBelongsToMILPBridge implements the following reformulation:

  • $(n, x) \in \textsf{CountBelongs}(1+d, \mathcal{S})$ into a mixed-integer linear program.

Reformulation

The reformulation is non-trivial, and it depends on the finite domain of each variable $x_i$, which we as define $S_i = \{l_i,\ldots,u_i\}$.

First, we introduce new binary variables $z_{ij}$, which are $1$ if variable $x_i$ takes the value $j$ in the optimal solution and $0$ otherwise:

\[\begin{aligned} z_{ij} \in \{0, 1\} & \;\; \forall i \in 1\ldots d, j \in S_i \\ x_i - \sum\limits_{j\in S_i} j \cdot z_{ij} = 0 & \;\; \forall i \in 1\ldots d \\ \sum\limits_{j\in S_i} z_{ij} = 1 & \;\; \forall i \in 1\ldots d \\ -\end{aligned}\]

Finally, $n$ is constrained to be the number of $z_{ij}$ elements that are in $\mathcal{S}$:

\[n - \sum\limits_{i\in 1\ldots d, j \in \mathcal{S}} z_{ij} = 0\]

Source node

CountBelongsToMILPBridge supports:

where F is MOI.VectorOfVariables or MOI.VectorAffineFunction{T}.

Target nodes

CountBelongsToMILPBridge creates:

source
MathOptInterface.Bridges.Constraint.CountDistinctToMILPBridgeType
CountDistinctToMILPBridge{T,F} <: Bridges.Constraint.AbstractBridge

CountDistinctToMILPBridge implements the following reformulation:

  • $(n, x) \in \textsf{CountDistinct}(1+d)$ into a mixed-integer linear program.

Reformulation

The reformulation is non-trivial, and it depends on the finite domain of each variable $x_i$, which we as define $S_i = \{l_i,\ldots,u_i\}$.

First, we introduce new binary variables $z_{ij}$, which are $1$ if variable $x_i$ takes the value $j$ in the optimal solution and $0$ otherwise:

\[\begin{aligned} +\end{aligned}\]

Finally, $n$ is constrained to be the number of $z_{ij}$ elements that are in $\mathcal{S}$:

\[n - \sum\limits_{i\in 1\ldots d, j \in \mathcal{S}} z_{ij} = 0\]

Source node

CountBelongsToMILPBridge supports:

where F is MOI.VectorOfVariables or MOI.VectorAffineFunction{T}.

Target nodes

CountBelongsToMILPBridge creates:

source
MathOptInterface.Bridges.Constraint.CountDistinctToMILPBridgeType
CountDistinctToMILPBridge{T,F} <: Bridges.Constraint.AbstractBridge

CountDistinctToMILPBridge implements the following reformulation:

  • $(n, x) \in \textsf{CountDistinct}(1+d)$ into a mixed-integer linear program.

Reformulation

The reformulation is non-trivial, and it depends on the finite domain of each variable $x_i$, which we as define $S_i = \{l_i,\ldots,u_i\}$.

First, we introduce new binary variables $z_{ij}$, which are $1$ if variable $x_i$ takes the value $j$ in the optimal solution and $0$ otherwise:

\[\begin{aligned} z_{ij} \in \{0, 1\} & \;\; \forall i \in 1\ldots d, j \in S_i \\ x_i - \sum\limits_{j\in S_i} j \cdot z_{ij} = 0 & \;\; \forall i \in 1\ldots d \\ \sum\limits_{j\in S_i} z_{ij} = 1 & \;\; \forall i \in 1\ldots d \\ \end{aligned}\]

Then, we introduce new binary variables $y_j$, which are $1$ if a variable takes the value $j$ in the optimal solution and $0$ otherwise.

\[\begin{aligned} y_{j} \in \{0, 1\} & \;\; \forall j \in \bigcup_{i=1,\ldots,d} S_i \\ y_j \le \sum\limits_{i \in 1\ldots d: j \in S_i} z_{ij} \le M y_j & \;\; \forall j \in \bigcup_{i=1,\ldots,d} S_i\\ -\end{aligned}\]

Finally, $n$ is constrained to be the number of $y_j$ elements that are non-zero:

\[n - \sum\limits_{j \in \bigcup_{i=1,\ldots,d} S_i} y_{j} = 0\]

Source node

CountDistinctToMILPBridge supports:

where F is MOI.VectorOfVariables or MOI.VectorAffineFunction{T}.

Target nodes

CountDistinctToMILPBridge creates:

source
MathOptInterface.Bridges.Constraint.ReifiedCountDistinctToMILPBridgeType
ReifiedCountDistinctToMILPBridge{T,F} <: Bridges.Constraint.AbstractBridge

ReifiedCountDistinctToMILPBridge implements the following reformulation:

  • $r \iff (n, x) \in \textsf{CountDistinct}(1+d)$ into a mixed-integer linear program.

Reformulation

The reformulation is non-trivial, and it depends on the finite domain of each variable $x_i$, which we as define $S_i = \{l_i,\ldots,u_i\}$.

First, we introduce new binary variables $z_{ij}$, which are $1$ if variable $x_i$ takes the value $j$ in the optimal solution and $0$ otherwise:

\[\begin{aligned} +\end{aligned}\]

Finally, $n$ is constrained to be the number of $y_j$ elements that are non-zero:

\[n - \sum\limits_{j \in \bigcup_{i=1,\ldots,d} S_i} y_{j} = 0\]

Source node

CountDistinctToMILPBridge supports:

where F is MOI.VectorOfVariables or MOI.VectorAffineFunction{T}.

Target nodes

CountDistinctToMILPBridge creates:

source
MathOptInterface.Bridges.Constraint.ReifiedCountDistinctToMILPBridgeType
ReifiedCountDistinctToMILPBridge{T,F} <: Bridges.Constraint.AbstractBridge

ReifiedCountDistinctToMILPBridge implements the following reformulation:

  • $r \iff (n, x) \in \textsf{CountDistinct}(1+d)$ into a mixed-integer linear program.

Reformulation

The reformulation is non-trivial, and it depends on the finite domain of each variable $x_i$, which we as define $S_i = \{l_i,\ldots,u_i\}$.

First, we introduce new binary variables $z_{ij}$, which are $1$ if variable $x_i$ takes the value $j$ in the optimal solution and $0$ otherwise:

\[\begin{aligned} z_{ij} \in \{0, 1\} & \;\; \forall i \in 1\ldots d, j \in S_i \\ x_i - \sum\limits_{j\in S_i} j \cdot z_{ij} = 0 & \;\; \forall i \in 1\ldots d \\ \sum\limits_{j\in S_i} z_{ij} = 1 & \;\; \forall i \in 1\ldots d \\ @@ -92,11 +92,11 @@ d_2 \le \delta^- \le M d_s \\ d_1 + d_2 + r = 1 \\ d_1, d_2 \in \{0, 1\} -\end{aligned}\]

Source node

ReifiedCountDistinctToMILPBridge supports:

where F is MOI.VectorOfVariables or MOI.VectorAffineFunction{T}.

Target nodes

ReifiedCountDistinctToMILPBridge creates:

source
MathOptInterface.Bridges.Constraint.CountGreaterThanToMILPBridgeType
CountGreaterThanToMILPBridge{T,F} <: Bridges.Constraint.AbstractBridge

CountGreaterThanToMILPBridge implements the following reformulation:

  • $(c, y, x) \in CountGreaterThan()$ into a mixed-integer linear program.

Source node

CountGreaterThanToMILPBridge supports:

Target nodes

CountGreaterThanToMILPBridge creates:

source
MathOptInterface.Bridges.Constraint.TableToMILPBridgeType
TableToMILPBridge{T,F} <: Bridges.Constraint.AbstractBridge

TableToMILPBridge implements the following reformulation:

source
MathOptInterface.Bridges.Constraint.CountGreaterThanToMILPBridgeType
CountGreaterThanToMILPBridge{T,F} <: Bridges.Constraint.AbstractBridge

CountGreaterThanToMILPBridge implements the following reformulation:

  • $(c, y, x) \in CountGreaterThan()$ into a mixed-integer linear program.

Source node

CountGreaterThanToMILPBridge supports:

Target nodes

CountGreaterThanToMILPBridge creates:

source
MathOptInterface.Bridges.Constraint.TableToMILPBridgeType
TableToMILPBridge{T,F} <: Bridges.Constraint.AbstractBridge

TableToMILPBridge implements the following reformulation:

  • $x \in Table(t)$ into

    \[\begin{aligned} z_{j} \in \{0, 1\} & \quad \forall i, j \\ \sum\limits_{j=1}^n z_{j} = 1 \\ \sum\limits_{j=1}^n t_{ij} z_{j} = x_i & \quad \forall i -\end{aligned}\]

Source node

TableToMILPBridge supports:

Target nodes

TableToMILPBridge creates:

source

Objective bridges

These bridges are subtypes of Bridges.Objective.AbstractBridge.

MathOptInterface.Bridges.Objective.QuadratizeBridgeType
QuadratizeBridge{T}

QuadratizeBridge implements the following reformulations:

  • $\min \{a^\top x + b\}$ into $\min\{x^\top \mathbf{0} x + a^\top x + b\}$
  • $\max \{a^\top x + b\}$ into $\max\{x^\top \mathbf{0} x + a^\top x + b\}$

where T is the coefficient type of 0.

Source node

QuadratizeBridge supports:

Target nodes

QuadratizeBridge creates:

source
MathOptInterface.Bridges.Objective.SlackBridgeType
SlackBridge{T,F,G}

SlackBridge implements the following reformulations:

  • $\min\{f(x)\}$ into $\min\{y\;|\; f(x) - y \le 0\}$
  • $\max\{f(x)\}$ into $\max\{y\;|\; f(x) - y \ge 0\}$

where F is the type of f(x) - y, G is the type of f(x), and T is the coefficient type of f(x).

Source node

SlackBridge supports:

Target nodes

SlackBridge creates:

Warning

When using this bridge, changing the optimization sense is not supported. Set the sense to MOI.FEASIBILITY_SENSE first to delete the bridge, then set MOI.ObjectiveSense and re-add the objective.

source
MathOptInterface.Bridges.Objective.VectorSlackBridgeType
VectorSlackBridge{T,F,G}

VectorSlackBridge implements the following reformulations:

  • $\min\{f(x)\}$ into $\min\{y\;|\; y - f(x) \in \mathbb{R}_+ \}$
  • $\max\{f(x)\}$ into $\max\{y\;|\; f(x) - y \in \mathbb{R}_+ \}$

where F is the type of f(x) - y, G is the type of f(x), and T is the coefficient type of f(x).

Source node

VectorSlackBridge supports:

Target nodes

VectorSlackBridge creates:

Warning

When using this bridge, changing the optimization sense is not supported. Set the sense to MOI.FEASIBILITY_SENSE first to delete the bridge, then set MOI.ObjectiveSense and re-add the objective.

source

Variable bridges

These bridges are subtypes of Bridges.Variable.AbstractBridge.

MathOptInterface.Bridges.Variable.RSOCtoPSDBridgeType
RSOCtoPSDBridge{T} <: Bridges.Variable.AbstractBridge

RSOCtoPSDBridge implements the following reformulation:

  • $||x||_2^2 \le 2tu$ where $t, u \ge 0$ into $Y \succeq 0$, with the substitution rule: $Y = \left[\begin{array}{c c}t & x^\top \\ x & 2u \mathbf{I}\end{array}\right].$

Additional bounds are added to ensure the off-diagonals of the $2uI$ submatrix are 0, and linear constraints are added to ennsure the diagonal of $2uI$ takes the same values.

As a special case, if $|x|| = 0$, then RSOCtoPSDBridge reformulates into $(t, u) \in \mathbb{R}_+$.

Source node

RSOCtoPSDBridge supports:

Target nodes

RSOCtoPSDBridge creates:

source
MathOptInterface.Bridges.Variable.RSOCtoSOCBridgeType
RSOCtoSOCBridge{T} <: Bridges.Variable.AbstractBridge

RSOCtoSOCBridge implements the following reformulation:

  • $||x||_2^2 \le 2tu$ into $||v||_2 \le w$, with the substitution rules $t = \frac{w}{\sqrt 2} + \frac{v_1}{\sqrt 2}$, $u = \frac{w}{\sqrt 2} - \frac{v_1}{\sqrt 2}$, and $x = (v_2,\ldots,v_N)$.

Source node

RSOCtoSOCBridge supports:

Target node

RSOCtoSOCBridge creates:

source
MathOptInterface.Bridges.Variable.SOCtoRSOCBridgeType
SOCtoRSOCBridge{T} <: Bridges.Variable.AbstractBridge

SOCtoRSOCBridge implements the following reformulation:

  • $||x||_2 \le t$ into $2uv \ge ||w||_2^2$, with the substitution rules $t = \frac{u}{\sqrt 2} + \frac{v}{\sqrt 2}$, $x = (\frac{u}{\sqrt 2} - \frac{v}{\sqrt 2}, w)$.

Assumptions

  • SOCtoRSOCBridge assumes that $|x| \ge 1$.

Source node

SOCtoRSOCBridge supports:

Target node

SOCtoRSOCBridge creates:

source
MathOptInterface.Bridges.Variable.VectorizeBridgeType
VectorizeBridge{T,S} <: Bridges.Variable.AbstractBridge

VectorizeBridge implements the following reformulations:

  • $x \ge a$ into $[y] \in \mathbb{R}_+$ with the substitution rule $x = a + y$
  • $x \le a$ into $[y] \in \mathbb{R}_-$ with the substitution rule $x = a + y$
  • $x == a$ into $[y] \in \{0\}$ with the substitution rule $x = a + y$

where T is the coefficient type of a + y.

Source node

VectorizeBridge supports:

Target nodes

VectorizeBridge creates:

source
MathOptInterface.Bridges.Variable.ZerosBridgeType
ZerosBridge{T} <: Bridges.Variable.AbstractBridge

ZerosBridge implements the following reformulation:

  • $x \in \{0\}$ into the substitution rule $x = 0$,

where T is the coefficient type of 0.

Source node

ZerosBridge supports:

Target nodes

ZerosBridge does not create target nodes. It replaces all instances of x with 0 via substitution. This means that no variables are created in the underlying model.

Caveats

The bridged variables are similar to parameters with zero values. Parameters with non-zero values can be created with constrained variables in MOI.EqualTo by combining a VectorizeBridge and this bridge.

However, functions modified by ZerosBridge cannot be unbridged. That is, for a given function, we cannot determine if the bridged variables were used.

A related implication is that this bridge does not support MOI.ConstraintDual. However, if a MOI.Utilities.CachingOptimizer is used, the dual can be determined by the bridged optimizer using MOI.Utilities.get_fallback because the caching optimizer records the unbridged function.

source
MathOptInterface.Bridges.Variable.HermitianToSymmetricPSDBridgeType
HermitianToSymmetricPSDBridge{T} <: Bridges.Variable.AbstractBridge

HermitianToSymmetricPSDBridge implements the following reformulation:

  • Hermitian positive semidefinite n x n complex matrix to a symmetric positive semidefinite 2n x 2n real matrix satisfying equality constraints described below.

Source node

HermitianToSymmetricPSDBridge supports:

Target node

HermitianToSymmetricPSDBridge creates:

Reformulation

The reformulation is best described by example.

The Hermitian matrix:

\[\begin{bmatrix} +\end{aligned}\]

Source node

TableToMILPBridge supports:

Target nodes

TableToMILPBridge creates:

source

Objective bridges

These bridges are subtypes of Bridges.Objective.AbstractBridge.

MathOptInterface.Bridges.Objective.QuadratizeBridgeType
QuadratizeBridge{T}

QuadratizeBridge implements the following reformulations:

  • $\min \{a^\top x + b\}$ into $\min\{x^\top \mathbf{0} x + a^\top x + b\}$
  • $\max \{a^\top x + b\}$ into $\max\{x^\top \mathbf{0} x + a^\top x + b\}$

where T is the coefficient type of 0.

Source node

QuadratizeBridge supports:

Target nodes

QuadratizeBridge creates:

source
MathOptInterface.Bridges.Objective.SlackBridgeType
SlackBridge{T,F,G}

SlackBridge implements the following reformulations:

  • $\min\{f(x)\}$ into $\min\{y\;|\; f(x) - y \le 0\}$
  • $\max\{f(x)\}$ into $\max\{y\;|\; f(x) - y \ge 0\}$

where F is the type of f(x) - y, G is the type of f(x), and T is the coefficient type of f(x).

Source node

SlackBridge supports:

Target nodes

SlackBridge creates:

Warning

When using this bridge, changing the optimization sense is not supported. Set the sense to MOI.FEASIBILITY_SENSE first to delete the bridge, then set MOI.ObjectiveSense and re-add the objective.

source
MathOptInterface.Bridges.Objective.VectorSlackBridgeType
VectorSlackBridge{T,F,G}

VectorSlackBridge implements the following reformulations:

  • $\min\{f(x)\}$ into $\min\{y\;|\; y - f(x) \in \mathbb{R}_+ \}$
  • $\max\{f(x)\}$ into $\max\{y\;|\; f(x) - y \in \mathbb{R}_+ \}$

where F is the type of f(x) - y, G is the type of f(x), and T is the coefficient type of f(x).

Source node

VectorSlackBridge supports:

Target nodes

VectorSlackBridge creates:

Warning

When using this bridge, changing the optimization sense is not supported. Set the sense to MOI.FEASIBILITY_SENSE first to delete the bridge, then set MOI.ObjectiveSense and re-add the objective.

source

Variable bridges

These bridges are subtypes of Bridges.Variable.AbstractBridge.

MathOptInterface.Bridges.Variable.RSOCtoPSDBridgeType
RSOCtoPSDBridge{T} <: Bridges.Variable.AbstractBridge

RSOCtoPSDBridge implements the following reformulation:

  • $||x||_2^2 \le 2tu$ where $t, u \ge 0$ into $Y \succeq 0$, with the substitution rule: $Y = \left[\begin{array}{c c}t & x^\top \\ x & 2u \mathbf{I}\end{array}\right].$

Additional bounds are added to ensure the off-diagonals of the $2uI$ submatrix are 0, and linear constraints are added to ennsure the diagonal of $2uI$ takes the same values.

As a special case, if $|x|| = 0$, then RSOCtoPSDBridge reformulates into $(t, u) \in \mathbb{R}_+$.

Source node

RSOCtoPSDBridge supports:

Target nodes

RSOCtoPSDBridge creates:

source
MathOptInterface.Bridges.Variable.RSOCtoSOCBridgeType
RSOCtoSOCBridge{T} <: Bridges.Variable.AbstractBridge

RSOCtoSOCBridge implements the following reformulation:

  • $||x||_2^2 \le 2tu$ into $||v||_2 \le w$, with the substitution rules $t = \frac{w}{\sqrt 2} + \frac{v_1}{\sqrt 2}$, $u = \frac{w}{\sqrt 2} - \frac{v_1}{\sqrt 2}$, and $x = (v_2,\ldots,v_N)$.

Source node

RSOCtoSOCBridge supports:

Target node

RSOCtoSOCBridge creates:

source
MathOptInterface.Bridges.Variable.SOCtoRSOCBridgeType
SOCtoRSOCBridge{T} <: Bridges.Variable.AbstractBridge

SOCtoRSOCBridge implements the following reformulation:

  • $||x||_2 \le t$ into $2uv \ge ||w||_2^2$, with the substitution rules $t = \frac{u}{\sqrt 2} + \frac{v}{\sqrt 2}$, $x = (\frac{u}{\sqrt 2} - \frac{v}{\sqrt 2}, w)$.

Assumptions

  • SOCtoRSOCBridge assumes that $|x| \ge 1$.

Source node

SOCtoRSOCBridge supports:

Target node

SOCtoRSOCBridge creates:

source
MathOptInterface.Bridges.Variable.VectorizeBridgeType
VectorizeBridge{T,S} <: Bridges.Variable.AbstractBridge

VectorizeBridge implements the following reformulations:

  • $x \ge a$ into $[y] \in \mathbb{R}_+$ with the substitution rule $x = a + y$
  • $x \le a$ into $[y] \in \mathbb{R}_-$ with the substitution rule $x = a + y$
  • $x == a$ into $[y] \in \{0\}$ with the substitution rule $x = a + y$

where T is the coefficient type of a + y.

Source node

VectorizeBridge supports:

Target nodes

VectorizeBridge creates:

source
MathOptInterface.Bridges.Variable.ZerosBridgeType
ZerosBridge{T} <: Bridges.Variable.AbstractBridge

ZerosBridge implements the following reformulation:

  • $x \in \{0\}$ into the substitution rule $x = 0$,

where T is the coefficient type of 0.

Source node

ZerosBridge supports:

Target nodes

ZerosBridge does not create target nodes. It replaces all instances of x with 0 via substitution. This means that no variables are created in the underlying model.

Caveats

The bridged variables are similar to parameters with zero values. Parameters with non-zero values can be created with constrained variables in MOI.EqualTo by combining a VectorizeBridge and this bridge.

However, functions modified by ZerosBridge cannot be unbridged. That is, for a given function, we cannot determine if the bridged variables were used.

A related implication is that this bridge does not support MOI.ConstraintDual. However, if a MOI.Utilities.CachingOptimizer is used, the dual can be determined by the bridged optimizer using MOI.Utilities.get_fallback because the caching optimizer records the unbridged function.

source
MathOptInterface.Bridges.Variable.HermitianToSymmetricPSDBridgeType
HermitianToSymmetricPSDBridge{T} <: Bridges.Variable.AbstractBridge

HermitianToSymmetricPSDBridge implements the following reformulation:

  • Hermitian positive semidefinite n x n complex matrix to a symmetric positive semidefinite 2n x 2n real matrix satisfying equality constraints described below.

Source node

HermitianToSymmetricPSDBridge supports:

Target node

HermitianToSymmetricPSDBridge creates:

Reformulation

The reformulation is best described by example.

The Hermitian matrix:

\[\begin{bmatrix} x_{11} & x_{12} + y_{12}im & x_{13} + y_{13}im\\ x_{12} - y_{12}im & x_{22} & x_{23} + y_{23}im\\ x_{13} - y_{13}im & x_{23} - y_{23}im & x_{33} @@ -107,4 +107,4 @@ & & & x_{11} & x_{12} & x_{13} \\ & & & & x_{22} & x_{23} \\ & & & & & x_{33} -\end{bmatrix}\]

is positive semidefinite.

The bridge achieves this reformulation by adding a new set of variables in MOI.PositiveSemidefiniteConeTriangle(6), and then adding three groups of equality constraints to:

  • constrain the two x blocks to be equal
  • force the diagonal of the y blocks to be 0
  • force the lower triangular of the y block to be the negative of the upper triangle.
source
+\end{bmatrix}\]

is positive semidefinite.

The bridge achieves this reformulation by adding a new set of variables in MOI.PositiveSemidefiniteConeTriangle(6), and then adding three groups of equality constraints to:

  • constrain the two x blocks to be equal
  • force the diagonal of the y blocks to be 0
  • force the lower triangular of the y block to be the negative of the upper triangle.
source
diff --git a/dev/submodules/Bridges/overview/index.html b/dev/submodules/Bridges/overview/index.html index 378fa93013..2079c89d7a 100644 --- a/dev/submodules/Bridges/overview/index.html +++ b/dev/submodules/Bridges/overview/index.html @@ -50,4 +50,4 @@ julia> MOI.get(inner_optimizer, MOI.ListOfConstraintTypesPresent()) 1-element Vector{Tuple{Type, Type}}: - (MathOptInterface.VariableIndex, MathOptInterface.Interval{Float64}) + (MathOptInterface.VariableIndex, MathOptInterface.Interval{Float64}) diff --git a/dev/submodules/Bridges/reference/index.html b/dev/submodules/Bridges/reference/index.html index 951e938b86..c756258ded 100644 --- a/dev/submodules/Bridges/reference/index.html +++ b/dev/submodules/Bridges/reference/index.html @@ -1,26 +1,26 @@ -API Reference · MathOptInterface

Bridges

AbstractBridge API

MathOptInterface.Bridges.AbstractBridgeType
abstract type AbstractBridge end

An abstract type representing a bridged constraint or variable in a MOI.Bridges.AbstractBridgeOptimizer.

All bridges must implement:

Subtypes of AbstractBridge may have additional requirements. Consult their docstrings for details.

In addition, all subtypes may optionally implement the following constraint attributes with the bridge in place of the constraint index:

source
MathOptInterface.Bridges.added_constrained_variable_typesFunction
added_constrained_variable_types(
+API Reference · MathOptInterface

Bridges

AbstractBridge API

MathOptInterface.Bridges.AbstractBridgeType
abstract type AbstractBridge end

An abstract type representing a bridged constraint or variable in a MOI.Bridges.AbstractBridgeOptimizer.

All bridges must implement:

Subtypes of AbstractBridge may have additional requirements. Consult their docstrings for details.

In addition, all subtypes may optionally implement the following constraint attributes with the bridge in place of the constraint index:

source
MathOptInterface.Bridges.added_constrained_variable_typesFunction
added_constrained_variable_types(
     BT::Type{<:AbstractBridge},
 )::Vector{Tuple{Type}}

Return a list of the types of constrained variables that bridges of concrete type BT add.

Implementation notes

  • This method depends only on the type of the bridge, not the runtime value. If the bridge may add a constrained variable, the type must be included in the return vector.
  • If the bridge adds a free variable via MOI.add_variable or MOI.add_variables, the return vector must include (MOI.Reals,).

Example

julia> MOI.Bridges.added_constrained_variable_types(
            MOI.Bridges.Variable.NonposToNonnegBridge{Float64},
        )
 1-element Vector{Tuple{Type}}:
- (MathOptInterface.Nonnegatives,)
source
MathOptInterface.Bridges.added_constraint_typesFunction
added_constraint_types(
     BT::Type{<:AbstractBridge},
 )::Vector{Tuple{Type,Type}}

Return a list of the types of constraints that bridges of concrete type BT add.

Implementation notes

  • This method depends only on the type of the bridge, not the runtime value. If the bridge may add a constraint, the type must be included in the return vector.

Example

julia> MOI.Bridges.added_constraint_types(
            MOI.Bridges.Constraint.ZeroOneBridge{Float64},
        )
 2-element Vector{Tuple{Type, Type}}:
  (MathOptInterface.ScalarAffineFunction{Float64}, MathOptInterface.Interval{Float64})
- (MathOptInterface.VariableIndex, MathOptInterface.Integer)
source
MathOptInterface.getMethod
MOI.get(b::AbstractBridge, ::MOI.NumberOfVariables)::Int64

Return the number of variables created by the bridge b in the model.

See also MOI.NumberOfConstraints.

Implementation notes

  • There is a default fallback, so you need only implement this if the bridge adds new variables.
source
MathOptInterface.getMethod
MOI.get(b::AbstractBridge, ::MOI.ListOfVariableIndices)

Return the list of variables created by the bridge b.

See also MOI.ListOfVariableIndices.

Implementation notes

  • There is a default fallback, so you need only implement this if the bridge adds new variables.
source
MathOptInterface.getMethod
MOI.get(b::AbstractBridge, ::MOI.NumberOfConstraints{F,S})::Int64 where {F,S}

Return the number of constraints of the type F-in-S created by the bridge b.

See also MOI.NumberOfConstraints.

Implementation notes

  • There is a default fallback, so you need only implement this for the constraint types returned by added_constraint_types.
source
MathOptInterface.getMethod
MOI.get(b::AbstractBridge, ::MOI.ListOfConstraintIndices{F,S}) where {F,S}

Return a Vector{ConstraintIndex{F,S}} with indices of all constraints of type F-in-S created by the bride b.

See also MOI.ListOfConstraintIndices.

Implementation notes

  • There is a default fallback, so you need only implement this for the constraint types returned by added_constraint_types.
source
MathOptInterface.Bridges.final_touchFunction
final_touch(bridge::AbstractBridge, model::MOI.ModelLike)::Nothing

A function that is called immediately prior to MOI.optimize! to allow bridges to modify their reformulations with repsect to other variables and constraints in model.

For example, if the correctness of bridge depends on the bounds of a variable or the fact that variables are integer, then the bridge can implement final_touch to check assumptions immediately before a call to MOI.optimize!.

If you implement this method, you must also implement needs_final_touch.

source
MathOptInterface.Bridges.bridging_costFunction
bridging_cost(b::AbstractBridgeOptimizer, S::Type{<:MOI.AbstractSet}})

Return the cost of bridging variables constrained in S on creation, is_bridged(b, S) is assumed to be true.

bridging_cost(
+ (MathOptInterface.VariableIndex, MathOptInterface.Integer)
source
MathOptInterface.getMethod
MOI.get(b::AbstractBridge, ::MOI.NumberOfVariables)::Int64

Return the number of variables created by the bridge b in the model.

See also MOI.NumberOfConstraints.

Implementation notes

  • There is a default fallback, so you need only implement this if the bridge adds new variables.
source
MathOptInterface.getMethod
MOI.get(b::AbstractBridge, ::MOI.ListOfVariableIndices)

Return the list of variables created by the bridge b.

See also MOI.ListOfVariableIndices.

Implementation notes

  • There is a default fallback, so you need only implement this if the bridge adds new variables.
source
MathOptInterface.getMethod
MOI.get(b::AbstractBridge, ::MOI.NumberOfConstraints{F,S})::Int64 where {F,S}

Return the number of constraints of the type F-in-S created by the bridge b.

See also MOI.NumberOfConstraints.

Implementation notes

  • There is a default fallback, so you need only implement this for the constraint types returned by added_constraint_types.
source
MathOptInterface.getMethod
MOI.get(b::AbstractBridge, ::MOI.ListOfConstraintIndices{F,S}) where {F,S}

Return a Vector{ConstraintIndex{F,S}} with indices of all constraints of type F-in-S created by the bride b.

See also MOI.ListOfConstraintIndices.

Implementation notes

  • There is a default fallback, so you need only implement this for the constraint types returned by added_constraint_types.
source
MathOptInterface.Bridges.final_touchFunction
final_touch(bridge::AbstractBridge, model::MOI.ModelLike)::Nothing

A function that is called immediately prior to MOI.optimize! to allow bridges to modify their reformulations with repsect to other variables and constraints in model.

For example, if the correctness of bridge depends on the bounds of a variable or the fact that variables are integer, then the bridge can implement final_touch to check assumptions immediately before a call to MOI.optimize!.

If you implement this method, you must also implement needs_final_touch.

source
MathOptInterface.Bridges.bridging_costFunction
bridging_cost(b::AbstractBridgeOptimizer, S::Type{<:MOI.AbstractSet}})

Return the cost of bridging variables constrained in S on creation, is_bridged(b, S) is assumed to be true.

bridging_cost(
     b::AbstractBridgeOptimizer,
     F::Type{<:MOI.AbstractFunction},
     S::Type{<:MOI.AbstractSet},
-)

Return the cost of bridging F-in-S constraints.

is_bridged(b, S) is assumed to be true.

source

Constraint bridge API

Constraint bridge API

MathOptInterface.supports_constraintMethod
MOI.supports_constraint(
     BT::Type{<:AbstractBridge},
     F::Type{<:MOI.AbstractFunction},
     S::Type{<:MOI.AbstractSet},
-)::Bool

Return a Bool indicating whether the bridges of type BT support bridging F-in-S constraints.

Implementation notes

  • This method depends only on the type of the inputs, not the runtime values.
  • There is a default fallback, so you need only implement this method for constraint types that the bridge implements.
source
MathOptInterface.Bridges.Constraint.concrete_bridge_typeFunction
concrete_bridge_type(
+)::Bool

Return a Bool indicating whether the bridges of type BT support bridging F-in-S constraints.

Implementation notes

  • This method depends only on the type of the inputs, not the runtime values.
  • There is a default fallback, so you need only implement this method for constraint types that the bridge implements.
source
MathOptInterface.Bridges.Constraint.concrete_bridge_typeFunction
concrete_bridge_type(
     BT::Type{<:AbstractBridge},
     F::Type{<:MOI.AbstractFunction},
     S::Type{<:MOI.AbstractSet}
@@ -29,12 +29,12 @@
            MOI.VariableIndex,
            MOI.Interval{Float64},
        )
-MathOptInterface.Bridges.Constraint.SplitIntervalBridge{Float64, MathOptInterface.VariableIndex, MathOptInterface.Interval{Float64}, MathOptInterface.GreaterThan{Float64}, MathOptInterface.LessThan{Float64}}
source
MathOptInterface.Bridges.Constraint.bridge_constraintFunction
bridge_constraint(
+MathOptInterface.Bridges.Constraint.SplitIntervalBridge{Float64, MathOptInterface.VariableIndex, MathOptInterface.Interval{Float64}, MathOptInterface.GreaterThan{Float64}, MathOptInterface.LessThan{Float64}}
source
MathOptInterface.Bridges.Constraint.bridge_constraintFunction
bridge_constraint(
     BT::Type{<:AbstractBridge},
     model::MOI.ModelLike,
     func::AbstractFunction,
     set::MOI.AbstractSet,
-)::BT

Bridge the constraint func-in-set using bridge BT to model and returns a bridge object of type BT.

Implementation notes

  • The bridge type BT should be a concrete type, that is, all the type parameters of the bridge must be set.
source
MathOptInterface.Bridges.Constraint.SingleBridgeOptimizerType
SingleBridgeOptimizer{BT<:AbstractBridge}(model::MOI.ModelLike)

Return AbstractBridgeOptimizer that always bridges any objective function supported by the bridge BT.

This is in contrast with the MOI.Bridges.LazyBridgeOptimizer, which only bridges the objective function if it is supported by the bridge BT and unsupported by model.

Example

julia> struct MyNewBridge{T} <: MOI.Bridges.Constraint.AbstractBridge end
+)::BT

Bridge the constraint func-in-set using bridge BT to model and returns a bridge object of type BT.

Implementation notes

  • The bridge type BT should be a concrete type, that is, all the type parameters of the bridge must be set.
source
MathOptInterface.Bridges.Constraint.SingleBridgeOptimizerType
SingleBridgeOptimizer{BT<:AbstractBridge}(model::MOI.ModelLike)

Return AbstractBridgeOptimizer that always bridges any objective function supported by the bridge BT.

This is in contrast with the MOI.Bridges.LazyBridgeOptimizer, which only bridges the objective function if it is supported by the bridge BT and unsupported by model.

Example

julia> struct MyNewBridge{T} <: MOI.Bridges.Constraint.AbstractBridge end
 
 julia> bridge = MOI.Bridges.Constraint.SingleBridgeOptimizer{MyNewBridge{Float64}}(
            MOI.Utilities.Model{Float64}(),
@@ -45,25 +45,25 @@
            MOI.Bridges.Constraint.SingleBridgeOptimizer{MyNewBridge{T},OT};

This enables users to create bridged models as follows:

julia> MyNewBridgeModel{Float64}(MOI.Utilities.Model{Float64}())
 MOIB.Constraint.SingleBridgeOptimizer{MyNewBridge{Float64}, MOIU.Model{Float64}}
 with 0 constraint bridges
-with inner model MOIU.Model{Float64}
source
MathOptInterface.Bridges.Constraint.SetMapBridgeType
abstract type SetMapBridge{T,S2,S1,F,G} <: AbstractBridge end

Consider two type of sets, S1 and S2, and a linear mapping A such that the image of a set of type S1 under A is a set of type S2.

A SetMapBridge{T,S2,S1,F,G} is a bridge that maps G-in-S1 constraints into F-in-S2 by mapping the function through A.

The linear map A is described by;

Implementing a method for these two functions is sufficient to bridge constraints. However, in order for the getters and setters of attributes such as dual solutions and starting values to work as well, a method for the following functions must be implemented:

See the docstrings of each function to see which feature would be missing if it was not implemented for a given bridge.

source
MathOptInterface.Bridges.Constraint.SetMapBridgeType
abstract type SetMapBridge{T,S2,S1,F,G} <: AbstractBridge end

Consider two type of sets, S1 and S2, and a linear mapping A such that the image of a set of type S1 under A is a set of type S2.

A SetMapBridge{T,S2,S1,F,G} is a bridge that maps G-in-S1 constraints into F-in-S2 by mapping the function through A.

The linear map A is described by;

Implementing a method for these two functions is sufficient to bridge constraints. However, in order for the getters and setters of attributes such as dual solutions and starting values to work as well, a method for the following functions must be implemented:

See the docstrings of each function to see which feature would be missing if it was not implemented for a given bridge.

source

Objective bridge API

Objective bridge API

MathOptInterface.Bridges.Objective.supports_objective_functionFunction
supports_objective_function(
     BT::Type{<:MOI.Bridges.Objective.AbstractBridge},
     F::Type{<:MOI.AbstractFunction},
-)::Bool

Return a Bool indicating whether the bridges of type BT support bridging objective functions of type F.

Implementation notes

  • This method depends only on the type of the inputs, not the runtime values.
  • There is a default fallback, so you need only implement this method For objective functions that the bridge implements.
source
MathOptInterface.Bridges.set_objective_function_typeFunction
set_objective_function_type(
+)::Bool

Return a Bool indicating whether the bridges of type BT support bridging objective functions of type F.

Implementation notes

  • This method depends only on the type of the inputs, not the runtime values.
  • There is a default fallback, so you need only implement this method For objective functions that the bridge implements.
source
MathOptInterface.Bridges.set_objective_function_typeFunction
set_objective_function_type(
     BT::Type{<:Objective.AbstractBridge},
 )::Type{<:MOI.AbstractFunction}

Return the type of objective function that bridges of concrete type BT set.

Implementation notes

  • This method depends only on the type of the bridge, not the runtime value.

Example

julia> MOI.Bridges.set_objective_function_type(
            MOI.Bridges.Objective.FunctionizeBridge{Float64},
        )
-MathOptInterface.ScalarAffineFunction{Float64}
source
MathOptInterface.Bridges.Objective.concrete_bridge_typeFunction
concrete_bridge_type(
     BT::Type{<:MOI.Bridges.Objective.AbstractBridge},
     F::Type{<:MOI.AbstractFunction},
-)::Type

Return the concrete type of the bridge supporting objective functions of type F.

This function can only be called if MOI.supports_objective_function(BT, F) is true.

source
MathOptInterface.Bridges.Objective.bridge_objectiveFunction
bridge_objective(
     BT::Type{<:MOI.Bridges.Objective.AbstractBridge},
     model::MOI.ModelLike,
     func::MOI.AbstractFunction,
-)::BT

Bridge the objective function func using bridge BT to model and returns a bridge object of type BT.

Implementation notes

  • The bridge type BT must be a concrete type, that is, all the type parameters of the bridge must be set.
source
MathOptInterface.Bridges.Objective.SingleBridgeOptimizerType
SingleBridgeOptimizer{BT<:AbstractBridge}(model::MOI.ModelLike)

Return AbstractBridgeOptimizer that always bridges any objective function supported by the bridge BT.

This is in contrast with the MOI.Bridges.LazyBridgeOptimizer, which only bridges the objective function if it is supported by the bridge BT and unsupported by model.

Example

julia> struct MyNewBridge{T} <: MOI.Bridges.Objective.AbstractBridge end
+)::BT

Bridge the objective function func using bridge BT to model and returns a bridge object of type BT.

Implementation notes

  • The bridge type BT must be a concrete type, that is, all the type parameters of the bridge must be set.
source
MathOptInterface.Bridges.Objective.SingleBridgeOptimizerType
SingleBridgeOptimizer{BT<:AbstractBridge}(model::MOI.ModelLike)

Return AbstractBridgeOptimizer that always bridges any objective function supported by the bridge BT.

This is in contrast with the MOI.Bridges.LazyBridgeOptimizer, which only bridges the objective function if it is supported by the bridge BT and unsupported by model.

Example

julia> struct MyNewBridge{T} <: MOI.Bridges.Objective.AbstractBridge end
 
 julia> bridge = MOI.Bridges.Objective.SingleBridgeOptimizer{MyNewBridge{Float64}}(
            MOI.Utilities.Model{Float64}(),
@@ -74,7 +74,7 @@
            MOI.Bridges.Objective.SingleBridgeOptimizer{MyNewBridge{T},OT};

This enables users to create bridged models as follows:

julia> MyNewBridgeModel{Float64}(MOI.Utilities.Model{Float64}())
 MOIB.Objective.SingleBridgeOptimizer{MyNewBridge{Float64}, MOIU.Model{Float64}}
 with 0 objective bridges
-with inner model MOIU.Model{Float64}
source

Variable bridge API

Variable bridge API

MathOptInterface.Bridges.Variable.supports_constrained_variableFunction
supports_constrained_variable(
     BT::Type{<:AbstractBridge},
     S::Type{<:MOI.AbstractSet},
 )::Bool

Return a Bool indicating whether the bridges of type BT support bridging constrained variables in S. That is, it returns true if the bridge of type BT converts constrained variables of type S into a form supported by the solver.

Implementation notes

  • This method depends only on the type of the bridge and set, not the runtime values.
  • There is a default fallback, so you need only implement this method for sets that the bridge implements.

Example

julia> MOI.Bridges.Variable.supports_constrained_variable(
@@ -87,18 +87,18 @@
            MOI.Bridges.Variable.NonposToNonnegBridge{Float64},
            MOI.Nonnegatives,
        )
-false
source
MathOptInterface.Bridges.Variable.concrete_bridge_typeFunction
concrete_bridge_type(
     BT::Type{<:AbstractBridge},
     S::Type{<:MOI.AbstractSet},
 )::Type

Return the concrete type of the bridge supporting variables in S constraints.

This function can only be called if MOI.supports_constrained_variable(BT, S) is true.

Examples

As a variable in MOI.GreaterThan is bridged into variables in MOI.Nonnegatives by the VectorizeBridge:

julia> MOI.Bridges.Variable.concrete_bridge_type(
            MOI.Bridges.Variable.VectorizeBridge{Float64},
            MOI.GreaterThan{Float64},
        )
-MathOptInterface.Bridges.Variable.VectorizeBridge{Float64, MathOptInterface.Nonnegatives}
source
MathOptInterface.Bridges.Variable.bridge_constrained_variableFunction
bridge_constrained_variable(
     BT::Type{<:AbstractBridge},
     model::MOI.ModelLike,
     set::MOI.AbstractSet,
-)::BT

Bridge the constrained variable in set using bridge BT to model and returns a bridge object of type BT.

Implementation notes

  • The bridge type BT must be a concrete type, that is, all the type parameters of the bridge must be set.
source
MathOptInterface.Bridges.Variable.SingleBridgeOptimizerType
SingleBridgeOptimizer{BT<:AbstractBridge}(model::MOI.ModelLike)

Return MOI.Bridges.AbstractBridgeOptimizer that always bridges any variables constrained on creation supported by the bridge BT.

This is in contrast with the MOI.Bridges.LazyBridgeOptimizer, which only bridges the variables constrained on creation if they are supported by the bridge BT and unsupported by model.

Warning

Two SingleBridgeOptimizers cannot be used together as both of them assume that the underlying model only returns variable indices with nonnegative values. Use MOI.Bridges.LazyBridgeOptimizer instead.

Example

julia> struct MyNewBridge{T} <: MOI.Bridges.Variable.AbstractBridge end
+)::BT

Bridge the constrained variable in set using bridge BT to model and returns a bridge object of type BT.

Implementation notes

  • The bridge type BT must be a concrete type, that is, all the type parameters of the bridge must be set.
source
MathOptInterface.Bridges.Variable.SingleBridgeOptimizerType
SingleBridgeOptimizer{BT<:AbstractBridge}(model::MOI.ModelLike)

Return MOI.Bridges.AbstractBridgeOptimizer that always bridges any variables constrained on creation supported by the bridge BT.

This is in contrast with the MOI.Bridges.LazyBridgeOptimizer, which only bridges the variables constrained on creation if they are supported by the bridge BT and unsupported by model.

Warning

Two SingleBridgeOptimizers cannot be used together as both of them assume that the underlying model only returns variable indices with nonnegative values. Use MOI.Bridges.LazyBridgeOptimizer instead.

Example

julia> struct MyNewBridge{T} <: MOI.Bridges.Variable.AbstractBridge end
 
 julia> bridge = MOI.Bridges.Variable.SingleBridgeOptimizer{MyNewBridge{Float64}}(
            MOI.Utilities.Model{Float64}(),
@@ -109,7 +109,7 @@
            MOI.Bridges.Variable.SingleBridgeOptimizer{MyNewBridge{T},OT};

This enables users to create bridged models as follows:

julia> MyNewBridgeModel{Float64}(MOI.Utilities.Model{Float64}())
 MOIB.Variable.SingleBridgeOptimizer{MyNewBridge{Float64}, MOIU.Model{Float64}}
 with 0 variable bridges
-with inner model MOIU.Model{Float64}
source
MathOptInterface.Bridges.Variable.SetMapBridgeType
abstract type SetMapBridge{T,S1,S2} <: AbstractBridge end

Consider two type of sets, S1 and S2, and a linear mapping A such that the image of a set of type S1 under A is a set of type S2.

A SetMapBridge{T,S1,S2} is a bridge that substitutes constrained variables in S2 into the image through A of constrained variables in S1.

The linear map A is described by:

Implementing a method for these two functions is sufficient to bridge constrained variables. However, in order for the getters and setters of attributes such as dual solutions and starting values to work as well, a method for the following functions must be implemented:

See the docstrings of each function to see which feature would be missing if it was not implemented for a given bridge.

source
MathOptInterface.Bridges.Variable.SetMapBridgeType
abstract type SetMapBridge{T,S1,S2} <: AbstractBridge end

Consider two type of sets, S1 and S2, and a linear mapping A such that the image of a set of type S1 under A is a set of type S2.

A SetMapBridge{T,S1,S2} is a bridge that substitutes constrained variables in S2 into the image through A of constrained variables in S1.

The linear map A is described by:

Implementing a method for these two functions is sufficient to bridge constrained variables. However, in order for the getters and setters of attributes such as dual solutions and starting values to work as well, a method for the following functions must be implemented:

See the docstrings of each function to see which feature would be missing if it was not implemented for a given bridge.

source
MathOptInterface.Bridges.Variable.unbridged_mapFunction
unbridged_map(
    bridge::MOI.Bridges.Variable.AbstractBridge,
     vi::MOI.VariableIndex,
 )

For a bridged variable in a scalar set, return a tuple of pairs mapping the variables created by the bridge to an affine expression in terms of the bridged variable vi.

unbridged_map(
@@ -119,13 +119,13 @@
     bridge::MOI.Bridges.Variable.AbstractBridge,
     vi::MOI.VariableIndex,
     i::MOI.Bridges.IndexInVector,
-)

For a bridged variable in a vector set, return a tuple of pairs mapping the variables created by the bridge to an affine expression in terms of the bridged variable vi corresponding to the ith variable of the vector.

If there is no way to recover the expression in terms of the bridged variable(s) vi(s), return nothing. See ZerosBridge for an example of bridge returning nothing.

source

AbstractBridgeOptimizer API

MathOptInterface.Bridges.bridged_variable_functionFunction
bridged_variable_function(
+)

For a bridged variable in a vector set, return a tuple of pairs mapping the variables created by the bridge to an affine expression in terms of the bridged variable vi corresponding to the ith variable of the vector.

If there is no way to recover the expression in terms of the bridged variable(s) vi(s), return nothing. See ZerosBridge for an example of bridge returning nothing.

source

AbstractBridgeOptimizer API

MathOptInterface.Bridges.bridged_variable_functionFunction
bridged_variable_function(
     b::AbstractBridgeOptimizer,
     vi::MOI.VariableIndex,
-)

Return a MOI.AbstractScalarFunction of variables of b.model that equals vi. That is, if the variable vi is bridged, it returns its expression in terms of the variables of b.model. Otherwise, it returns vi.

source
MathOptInterface.Bridges.unbridged_variable_functionFunction
unbridged_variable_function(
+)

Return a MOI.AbstractScalarFunction of variables of b.model that equals vi. That is, if the variable vi is bridged, it returns its expression in terms of the variables of b.model. Otherwise, it returns vi.

source
MathOptInterface.Bridges.unbridged_variable_functionFunction
unbridged_variable_function(
     b::AbstractBridgeOptimizer,
     vi::MOI.VariableIndex,
-)

Return a MOI.AbstractScalarFunction of variables of b that equals vi. That is, if the variable vi is an internal variable of b.model created by a bridge but not visible to the user, it returns its expression in terms of the variables of bridged variables. Otherwise, it returns vi.

source
MathOptInterface.Bridges.recursive_modelFunction
recursive_model(b::AbstractBridgeOptimizer)

If a variable, constraint, or objective is bridged, return the context of the inner variables. For most optimizers, this should be b.model.

source

LazyBridgeOptimizer API

MathOptInterface.Bridges.LazyBridgeOptimizerType
LazyBridgeOptimizer(model::MOI.ModelLike)

The LazyBridgeOptimizer is a bridge optimizer that supports multiple bridges, and only bridges things which are not supported by the internal model.

Internally, the LazyBridgeOptimizer solves a shortest hyper-path problem to determine which bridges to use.

In general, you should use full_bridge_optimizer instead of this constructor because full_bridge_optimizer automatically adds a large number of supported bridges.

See also: add_bridge, remove_bridge, has_bridge and full_bridge_optimizer.

Example

julia> model = MOI.Bridges.LazyBridgeOptimizer(MOI.Utilities.Model{Float64}())
+)

Return a MOI.AbstractScalarFunction of variables of b that equals vi. That is, if the variable vi is an internal variable of b.model created by a bridge but not visible to the user, it returns its expression in terms of the variables of bridged variables. Otherwise, it returns vi.

source
MathOptInterface.Bridges.recursive_modelFunction
recursive_model(b::AbstractBridgeOptimizer)

If a variable, constraint, or objective is bridged, return the context of the inner variables. For most optimizers, this should be b.model.

source

LazyBridgeOptimizer API

MathOptInterface.Bridges.LazyBridgeOptimizerType
LazyBridgeOptimizer(model::MOI.ModelLike)

The LazyBridgeOptimizer is a bridge optimizer that supports multiple bridges, and only bridges things which are not supported by the internal model.

Internally, the LazyBridgeOptimizer solves a shortest hyper-path problem to determine which bridges to use.

In general, you should use full_bridge_optimizer instead of this constructor because full_bridge_optimizer automatically adds a large number of supported bridges.

See also: add_bridge, remove_bridge, has_bridge and full_bridge_optimizer.

Example

julia> model = MOI.Bridges.LazyBridgeOptimizer(MOI.Utilities.Model{Float64}())
 MOIB.LazyBridgeOptimizer{MOIU.Model{Float64}}
 with 0 variable bridges
 with 0 constraint bridges
@@ -135,9 +135,9 @@
 julia> MOI.Bridges.add_bridge(model, MOI.Bridges.Variable.FreeBridge{Float64})
 
 julia> MOI.Bridges.has_bridge(model, MOI.Bridges.Variable.FreeBridge{Float64})
-true
source
MathOptInterface.Bridges.full_bridge_optimizerFunction
full_bridge_optimizer(model::MOI.ModelLike, ::Type{T}) where {T}

Returns a LazyBridgeOptimizer bridging model for every bridge defined in this package (see below for the few exceptions) and for the coefficient type T, as well as the bridges in the list returned by the ListOfNonstandardBridges attribute.

Example

julia> model = MOI.Utilities.Model{Float64}();
 
-julia> bridged_model = MOI.Bridges.full_bridge_optimizer(model, Float64);

Exceptions

The following bridges are not added by full_bridge_optimizer, except if they are in the list returned by the ListOfNonstandardBridges attribute:

See the docstring of the each bridge for the reason they are not added.

source
MathOptInterface.Bridges.ListOfNonstandardBridgesType
ListOfNonstandardBridges{T}() <: MOI.AbstractOptimizerAttribute

Any optimizer can be wrapped in a LazyBridgeOptimizer using full_bridge_optimizer. However, by default LazyBridgeOptimizer uses a limited set of bridges that are:

  1. implemented in MOI.Bridges
  2. generally applicable for all optimizers.

For some optimizers however, it is useful to add additional bridges, such as those that are implemented in external packages (e.g., within the solver package itself) or only apply in certain circumstances (e.g., Constraint.SOCtoNonConvexQuadBridge).

Such optimizers should implement the ListOfNonstandardBridges attribute to return a vector of bridge types that are added by full_bridge_optimizer in addition to the list of default bridges.

Note that optimizers implementing ListOfNonstandardBridges may require package-specific functions or sets to be used if the non-standard bridges are not added. Therefore, you are recommended to use model = MOI.instantiate(Package.Optimizer; with_bridge_type = T) instead of model = MOI.instantiate(Package.Optimizer). See MOI.instantiate.

Examples

An optimizer using a non-default bridge in MOI.Bridges

Solvers supporting MOI.ScalarQuadraticFunction can support MOI.SecondOrderCone and MOI.RotatedSecondOrderCone by defining:

function MOI.get(::MyQuadraticOptimizer, ::ListOfNonstandardBridges{Float64})
+julia> bridged_model = MOI.Bridges.full_bridge_optimizer(model, Float64);

Exceptions

The following bridges are not added by full_bridge_optimizer, except if they are in the list returned by the ListOfNonstandardBridges attribute:

See the docstring of the each bridge for the reason they are not added.

source
MathOptInterface.Bridges.ListOfNonstandardBridgesType
ListOfNonstandardBridges{T}() <: MOI.AbstractOptimizerAttribute

Any optimizer can be wrapped in a LazyBridgeOptimizer using full_bridge_optimizer. However, by default LazyBridgeOptimizer uses a limited set of bridges that are:

  1. implemented in MOI.Bridges
  2. generally applicable for all optimizers.

For some optimizers however, it is useful to add additional bridges, such as those that are implemented in external packages (e.g., within the solver package itself) or only apply in certain circumstances (e.g., Constraint.SOCtoNonConvexQuadBridge).

Such optimizers should implement the ListOfNonstandardBridges attribute to return a vector of bridge types that are added by full_bridge_optimizer in addition to the list of default bridges.

Note that optimizers implementing ListOfNonstandardBridges may require package-specific functions or sets to be used if the non-standard bridges are not added. Therefore, you are recommended to use model = MOI.instantiate(Package.Optimizer; with_bridge_type = T) instead of model = MOI.instantiate(Package.Optimizer). See MOI.instantiate.

Examples

An optimizer using a non-default bridge in MOI.Bridges

Solvers supporting MOI.ScalarQuadraticFunction can support MOI.SecondOrderCone and MOI.RotatedSecondOrderCone by defining:

function MOI.get(::MyQuadraticOptimizer, ::ListOfNonstandardBridges{Float64})
     return Type[
         MOI.Bridges.Constraint.SOCtoNonConvexQuadBridge{Float64},
         MOI.Bridges.Constraint.RSOCtoNonConvexQuadBridge{Float64},
@@ -150,46 +150,46 @@
 end
 # ...

from VectorAffineFunction{T} to the MatrixAffineFunction. Finally, it defines:

function MOI.get(::Optimizer{T}, ::ListOfNonstandardBridges{T}) where {T}
     return Type[MatrixAffineFunctionBridge{T}]
-end
source
MathOptInterface.Bridges.print_active_bridgesFunction
print_active_bridges([io::IO=stdout,] b::MOI.Bridges.LazyBridgeOptimizer)

Print the set of bridges that are active in the model b.

source
print_active_bridges(
     [io::IO=stdout,]
     b::MOI.Bridges.LazyBridgeOptimizer,
     F::Type{<:MOI.AbstractFunction}
-)

Print the set of bridges required for an objective function of type F.

source
print_active_bridges(
+)

Print the set of bridges required for an objective function of type F.

source
print_active_bridges(
     [io::IO=stdout,]
     b::MOI.Bridges.LazyBridgeOptimizer,
     F::Type{<:MOI.AbstractFunction},
     S::Type{<:MOI.AbstractSet},
-)

Print the set of bridges required for a constraint of type F-in-S.

source
print_active_bridges(
+)

Print the set of bridges required for a constraint of type F-in-S.

source
print_active_bridges(
     [io::IO=stdout,]
     b::MOI.Bridges.LazyBridgeOptimizer,
     S::Type{<:MOI.AbstractSet}
-)

Print the set of bridges required for a variable constrained to set S.

source
MathOptInterface.Bridges.print_graphFunction
print_graph([io::IO = stdout,] b::LazyBridgeOptimizer)

Print the hyper-graph containing all variable, constraint, and objective types that could be obtained by bridging the variables, constraints, and objectives that are present in the model by all the bridges added to b.

Each node in the hyper-graph corresponds to a variable, constraint, or objective type.

  • Variable nodes are indicated by [ ]
  • Constraint nodes are indicated by ( )
  • Objective nodes are indicated by | |

The number inside each pair of brackets is an index of the node in the hyper-graph.

Note that this hyper-graph is the full list of possible transformations. When the bridged model is created, we select the shortest hyper-path(s) from this graph, so many nodes may be un-used.

To see which nodes are used, call print_active_bridges.

For more information, see Legat, B., Dowson, O., Garcia, J., and Lubin, M. (2020). "MathOptInterface: a data structure for mathematical optimization problems." URL: https://arxiv.org/abs/2002.03447

source
MathOptInterface.Bridges.print_graphFunction
print_graph([io::IO = stdout,] b::LazyBridgeOptimizer)

Print the hyper-graph containing all variable, constraint, and objective types that could be obtained by bridging the variables, constraints, and objectives that are present in the model by all the bridges added to b.

Each node in the hyper-graph corresponds to a variable, constraint, or objective type.

  • Variable nodes are indicated by [ ]
  • Constraint nodes are indicated by ( )
  • Objective nodes are indicated by | |

The number inside each pair of brackets is an index of the node in the hyper-graph.

Note that this hyper-graph is the full list of possible transformations. When the bridged model is created, we select the shortest hyper-path(s) from this graph, so many nodes may be un-used.

To see which nodes are used, call print_active_bridges.

For more information, see Legat, B., Dowson, O., Garcia, J., and Lubin, M. (2020). "MathOptInterface: a data structure for mathematical optimization problems." URL: https://arxiv.org/abs/2002.03447

source

SetMap API

MathOptInterface.Bridges.map_functionFunction
map_function(::Type{BT}, func) where {BT}

Return the image of func through the linear map A defined in Variable.SetMapBridge and Constraint.SetMapBridge. This is used for getting the MOI.ConstraintPrimal of variable bridges. For constraint bridges, this is used for bridging the constraint, setting the MOI.ConstraintFunction and MOI.ConstraintPrimalStart and modifying the function with MOI.modify.

map_function(::Type{BT}, func, i::IndexInVector) where {BT}

Return the scalar function at the ith index of the vector function that would be returned by map_function(BT, func) except that it may compute the ith element. This is used by bridged_function and for getting the MOI.VariablePrimal and MOI.VariablePrimalStart of variable bridges.

source

Bridging graph API

MathOptInterface.Bridges.GraphType
Graph()

A type-stable datastructure for computing the shortest hyperpath problem.

Nodes

There are three types of nodes in the graph:

Add nodes to the graph using add_node.

Edges

There are two types of edges in the graph:

Add edges to the graph using add_edge.

For the ability to add a variable constrained on creation as a free variable followed by a constraint, use set_variable_constraint_node.

Optimal hyper-edges

Use bridge_index to compute the minimum-cost bridge leaving a node.

Note that bridge_index lazy runs a Bellman-Ford algorithm to compute the set of minimum cost edges. Thus, the first call to bridge_index after adding new nodes or edges will take longer than subsequent calls.

source

SetMap API

MathOptInterface.Bridges.map_functionFunction
map_function(::Type{BT}, func) where {BT}

Return the image of func through the linear map A defined in Variable.SetMapBridge and Constraint.SetMapBridge. This is used for getting the MOI.ConstraintPrimal of variable bridges. For constraint bridges, this is used for bridging the constraint, setting the MOI.ConstraintFunction and MOI.ConstraintPrimalStart and modifying the function with MOI.modify.

map_function(::Type{BT}, func, i::IndexInVector) where {BT}

Return the scalar function at the ith index of the vector function that would be returned by map_function(BT, func) except that it may compute the ith element. This is used by bridged_function and for getting the MOI.VariablePrimal and MOI.VariablePrimalStart of variable bridges.

source

Bridging graph API

MathOptInterface.Bridges.GraphType
Graph()

A type-stable datastructure for computing the shortest hyperpath problem.

Nodes

There are three types of nodes in the graph:

Add nodes to the graph using add_node.

Edges

There are two types of edges in the graph:

Add edges to the graph using add_edge.

For the ability to add a variable constrained on creation as a free variable followed by a constraint, use set_variable_constraint_node.

Optimal hyper-edges

Use bridge_index to compute the minimum-cost bridge leaving a node.

Note that bridge_index lazy runs a Bellman-Ford algorithm to compute the set of minimum cost edges. Thus, the first call to bridge_index after adding new nodes or edges will take longer than subsequent calls.

source
MathOptInterface.Bridges.add_nodeFunction
add_node(graph::Graph, ::Type{VariableNode})::VariableNode
 add_node(graph::Graph, ::Type{ConstraintNode})::ConstraintNode
-add_node(graph::Graph, ::Type{ObjectiveNode})::ObjectiveNode

Add a new node to graph.

source
MathOptInterface.Bridges.add_edgeFunction
add_edge(graph::Graph, node::VariableNode, edge::Edge)::Nothing
+add_node(graph::Graph, ::Type{ObjectiveNode})::ObjectiveNode

Add a new node to graph.

source
MathOptInterface.Bridges.add_edgeFunction
add_edge(graph::Graph, node::VariableNode, edge::Edge)::Nothing
 add_edge(graph::Graph, node::ConstraintNode, edge::Edge)::Nothing
-add_edge(graph::Graph, node::ObjectiveNode, edge::ObjectiveEdge)::Nothing

Add edge to graph, where edge starts at node and connects to the nodes defined in edge.

source
MathOptInterface.Bridges.set_variable_constraint_nodeFunction
set_variable_constraint_node(
     graph::Graph,
     variable_node::VariableNode,
     constraint_node::ConstraintNode,
     cost::Int,
-)

As an alternative to variable_node, add a virtual edge to graph that represents adding a free variable, followed by a constraint of type constraint_node, with bridging cost cost.

Why is this needed?

Variables can either be added as a variable constrained on creation, or as a free variable which then has a constraint added to it.

source
MathOptInterface.Bridges.bridge_indexFunction
bridge_index(graph::Graph, node::VariableNode)::Int
+)

As an alternative to variable_node, add a virtual edge to graph that represents adding a free variable, followed by a constraint of type constraint_node, with bridging cost cost.

Why is this needed?

Variables can either be added as a variable constrained on creation, or as a free variable which then has a constraint added to it.

source
MathOptInterface.Bridges.bridge_indexFunction
bridge_index(graph::Graph, node::VariableNode)::Int
 bridge_index(graph::Graph, node::ConstraintNode)::Int
-bridge_index(graph::Graph, node::ObjectiveNode)::Int

Return the optimal index of the bridge to chose from node.

source
MathOptInterface.Bridges.is_variable_edge_bestFunction
is_variable_edge_best(graph::Graph, node::VariableNode)::Bool

Return a Bool indicating whether node should be added as a variable constrained on creation, or as a free variable followed by a constraint.

source
+bridge_index(graph::Graph, node::ObjectiveNode)::Int

Return the optimal index of the bridge to chose from node.

source
MathOptInterface.Bridges.is_variable_edge_bestFunction
is_variable_edge_best(graph::Graph, node::VariableNode)::Bool

Return a Bool indicating whether node should be added as a variable constrained on creation, or as a free variable followed by a constraint.

source
diff --git a/dev/submodules/FileFormats/overview/index.html b/dev/submodules/FileFormats/overview/index.html index a298e35f52..244e47ac83 100644 --- a/dev/submodules/FileFormats/overview/index.html +++ b/dev/submodules/FileFormats/overview/index.html @@ -134,4 +134,4 @@ path: [variables][1] instance: Dict{String, Any}("NaMe" => "x") schema key: required -schema value: Any["name"] +schema value: Any["name"] diff --git a/dev/submodules/FileFormats/reference/index.html b/dev/submodules/FileFormats/reference/index.html index 72a59981cd..8f22c313c4 100644 --- a/dev/submodules/FileFormats/reference/index.html +++ b/dev/submodules/FileFormats/reference/index.html @@ -4,7 +4,7 @@ format::FileFormat = FORMAT_AUTOMATIC, filename::Union{Nothing, String} = nothing, kwargs... -)

Return model corresponding to the FileFormat format, or, if format == FORMAT_AUTOMATIC, guess the format from filename.

The filename argument is only needed if format == FORMAT_AUTOMATIC.

kwargs are passed to the underlying model constructor.

source
MathOptInterface.FileFormats.FileFormatType
FileFormat

List of accepted export formats.

  • FORMAT_AUTOMATIC: try to detect the file format based on the file name
  • FORMAT_CBF: the Conic Benchmark format
  • FORMAT_LP: the LP file format
  • FORMAT_MOF: the MathOptFormat file format
  • FORMAT_MPS: the MPS file format
  • FORMAT_NL: the AMPL .nl file format
  • FORMAT_REW: the .rew file format, which is MPS with generic names
  • FORMAT_SDPA: the SemiDefinite Programming Algorithm format
source
MathOptInterface.FileFormats.LP.ModelType
Model(; kwargs...)

Create an empty instance of FileFormats.LP.Model.

Keyword arguments are:

  • maximum_length::Int=255: the maximum length for the name of a variable. lp_solve 5.0 allows only 16 characters, while CPLEX 12.5+ allow 255.

  • warn::Bool=false: print a warning when variables or constraints are renamed.

source
MathOptInterface.FileFormats.MOF.ModelType
Model(; kwargs...)

Create an empty instance of FileFormats.MOF.Model.

Keyword arguments are:

  • print_compact::Bool=false: print the JSON file in a compact format without spaces or newlines.
  • warn::Bool=false: print a warning when variables or constraints are renamed
  • differentiation_backend::MOI.Nonlinear.AbstractAutomaticDifferentiation = MOI.Nonlinear.SparseReverseMode(): automatic differentiation backend to use when reading models with nonlinear constraints and objectives.
source
MathOptInterface.FileFormats.MPS.ModelType
Model(; kwargs...)

Create an empty instance of FileFormats.MPS.Model.

Keyword arguments are:

  • warn::Bool=false: print a warning when variables or constraints are renamed.
  • print_objsense::Bool=false: print the OBJSENSE section when writing
  • generic_names::Bool=false: strip all names in the model and replace them with the generic names C$i and R$i for the i'th column and row respectively.
  • quadratic_format::QuadraticFormat = kQuadraticFormatGurobi: specify the solver-specific extension used when writing the quadratic components of the model. Options are kQuadraticFormatGurobi, kQuadraticFormatCPLEX, and kQuadraticFormatMosek.
source
MathOptInterface.FileFormats.SDPA.ModelType
Model(; number_type::Type = Float64)

Create an empty instance of FileFormats.SDPA.Model{number_type}.

It is important to be aware that the SDPA file format is interpreted in geometric form and not standard conic form. The standard conic form and geometric conic form are two dual standard forms for semidefinite programs (SDPs). The geometric conic form of an SDP is as follows:

\[\begin{align} +)

Return model corresponding to the FileFormat format, or, if format == FORMAT_AUTOMATIC, guess the format from filename.

The filename argument is only needed if format == FORMAT_AUTOMATIC.

kwargs are passed to the underlying model constructor.

source
MathOptInterface.FileFormats.FileFormatType
FileFormat

List of accepted export formats.

  • FORMAT_AUTOMATIC: try to detect the file format based on the file name
  • FORMAT_CBF: the Conic Benchmark format
  • FORMAT_LP: the LP file format
  • FORMAT_MOF: the MathOptFormat file format
  • FORMAT_MPS: the MPS file format
  • FORMAT_NL: the AMPL .nl file format
  • FORMAT_REW: the .rew file format, which is MPS with generic names
  • FORMAT_SDPA: the SemiDefinite Programming Algorithm format
source
MathOptInterface.FileFormats.LP.ModelType
Model(; kwargs...)

Create an empty instance of FileFormats.LP.Model.

Keyword arguments are:

  • maximum_length::Int=255: the maximum length for the name of a variable. lp_solve 5.0 allows only 16 characters, while CPLEX 12.5+ allow 255.

  • warn::Bool=false: print a warning when variables or constraints are renamed.

source
MathOptInterface.FileFormats.MOF.ModelType
Model(; kwargs...)

Create an empty instance of FileFormats.MOF.Model.

Keyword arguments are:

  • print_compact::Bool=false: print the JSON file in a compact format without spaces or newlines.
  • warn::Bool=false: print a warning when variables or constraints are renamed
  • differentiation_backend::MOI.Nonlinear.AbstractAutomaticDifferentiation = MOI.Nonlinear.SparseReverseMode(): automatic differentiation backend to use when reading models with nonlinear constraints and objectives.
source
MathOptInterface.FileFormats.MPS.ModelType
Model(; kwargs...)

Create an empty instance of FileFormats.MPS.Model.

Keyword arguments are:

  • warn::Bool=false: print a warning when variables or constraints are renamed.
  • print_objsense::Bool=false: print the OBJSENSE section when writing
  • generic_names::Bool=false: strip all names in the model and replace them with the generic names C$i and R$i for the i'th column and row respectively.
  • quadratic_format::QuadraticFormat = kQuadraticFormatGurobi: specify the solver-specific extension used when writing the quadratic components of the model. Options are kQuadraticFormatGurobi, kQuadraticFormatCPLEX, and kQuadraticFormatMosek.
source
MathOptInterface.FileFormats.SDPA.ModelType
Model(; number_type::Type = Float64)

Create an empty instance of FileFormats.SDPA.Model{number_type}.

It is important to be aware that the SDPA file format is interpreted in geometric form and not standard conic form. The standard conic form and geometric conic form are two dual standard forms for semidefinite programs (SDPs). The geometric conic form of an SDP is as follows:

\[\begin{align} & \min_{y \in \mathbb{R}^m} & b^T y \\ & \;\;\text{s.t.} & \sum_{i=1}^m A_i y_i - C & \in \mathbb{K} @@ -12,7 +12,7 @@ & \max_{X \in \mathbb{K}} & \text{tr}(CX) \\ & \;\;\text{s.t.} & \text{tr}(A_iX) & = b_i & i = 1, \ldots, m. -\end{align}\]

In other words, the standard conic form contains nonnegative and positive semidefinite variables with equality constraints. That is, in the MathOptInterface's terminology, MOI.VectorOfVariables-in-MOI.Nonnegatives, MOI.VectorOfVariables-in-MOI.PositiveSemidefiniteConeTriangle and MOI.ScalarAffineFunction-in-MOI.EqualTo constraints.

If a model is in standard conic form, use Dualization.jl to transform it into the geometric conic form before writting it. Otherwise, the nonnegative (resp. positive semidefinite) variables will be bridged into free variables with affine constraints constraining them to belong to the nonnegative orthant (resp. positive semidefinite cone) by the MOI.Bridges.Constraint.VectorFunctionizeBridge. Moreover, equality constraints will be bridged into pairs of affine constraints in the nonnegative orthant by the MOI.Bridges.Constraint.SplitIntervalBridge and then the MOI.Bridges.Constraint.VectorizeBridge.

If a solver is in standard conic form, use Dualization.jl to transform the model read into standard conic form before copying it to the solver. Otherwise, the free variables will be bridged into pairs of variables in the nonnegative orthant by the MOI.Bridges.Variable.FreeBridge and affine constraints will be bridged into equality constraints by creating a slack variable by the MOI.Bridges.Constraint.VectorSlackBridge.

source

Other helpers

MathOptInterface.FileFormats.NL.SolFileResultsType
SolFileResults(filename::String, model::Model)

Parse the .sol file filename created by solving model and return a SolFileResults struct.

The returned struct supports the MOI.get API for querying result attributes such as MOI.TerminationStatus, MOI.VariablePrimal, and MOI.ConstraintDual.

source
SolFileResults(
+\end{align}\]

In other words, the standard conic form contains nonnegative and positive semidefinite variables with equality constraints. That is, in the MathOptInterface's terminology, MOI.VectorOfVariables-in-MOI.Nonnegatives, MOI.VectorOfVariables-in-MOI.PositiveSemidefiniteConeTriangle and MOI.ScalarAffineFunction-in-MOI.EqualTo constraints.

If a model is in standard conic form, use Dualization.jl to transform it into the geometric conic form before writting it. Otherwise, the nonnegative (resp. positive semidefinite) variables will be bridged into free variables with affine constraints constraining them to belong to the nonnegative orthant (resp. positive semidefinite cone) by the MOI.Bridges.Constraint.VectorFunctionizeBridge. Moreover, equality constraints will be bridged into pairs of affine constraints in the nonnegative orthant by the MOI.Bridges.Constraint.SplitIntervalBridge and then the MOI.Bridges.Constraint.VectorizeBridge.

If a solver is in standard conic form, use Dualization.jl to transform the model read into standard conic form before copying it to the solver. Otherwise, the free variables will be bridged into pairs of variables in the nonnegative orthant by the MOI.Bridges.Variable.FreeBridge and affine constraints will be bridged into equality constraints by creating a slack variable by the MOI.Bridges.Constraint.VectorSlackBridge.

source

Other helpers

MathOptInterface.FileFormats.NL.SolFileResultsType
SolFileResults(filename::String, model::Model)

Parse the .sol file filename created by solving model and return a SolFileResults struct.

The returned struct supports the MOI.get API for querying result attributes such as MOI.TerminationStatus, MOI.VariablePrimal, and MOI.ConstraintDual.

source
SolFileResults(
     raw_status::String,
     termination_status::MOI.TerminationStatusCode,
-)

Return a SolFileResults struct with MOI.RawStatusString set to raw_status, MOI.TerminationStatus set to termination_status, and MOI.PrimalStatus and MOI.DualStatus set to NO_SOLUTION.

All other attributes are un-set.

source
+)

Return a SolFileResults struct with MOI.RawStatusString set to raw_status, MOI.TerminationStatus set to termination_status, and MOI.PrimalStatus and MOI.DualStatus set to NO_SOLUTION.

All other attributes are un-set.

source diff --git a/dev/submodules/Nonlinear/overview/index.html b/dev/submodules/Nonlinear/overview/index.html index 0b3f17aa31..78b90419e9 100644 --- a/dev/submodules/Nonlinear/overview/index.html +++ b/dev/submodules/Nonlinear/overview/index.html @@ -180,4 +180,4 @@ Node(NODE_VARIABLE, 1, 1), ], [2.0], - );

This is less readable than the other options, but does this data structure meet our design goals?

Instead of a heap-allocated object for each node, we only have two Vectors for each expression, nodes and values, as well as two constant vectors for the OPERATORS. In addition, all fields are concretely typed, and there are no Union or Any types.

For our third goal, it is not easy to identify the children of a node, but it is easy to identify the parent of any node. Therefore, we can use Nonlinear.adjacency_matrix to compute a sparse matrix that maps parents to their children.

The tape is also ordered topologically, so that a reverse pass of the nodes evaluates all children nodes before their parent.

The design in practice

In practice, Node and Expression are exactly Nonlinear.Node and Nonlinear.Expression. However, Nonlinear.NodeType has more fields to account for comparison operators such as :>= and :<=, logic operators such as :&& and :||, nonlinear parameters, and nested subexpressions.

Moreover, instead of storing the operators as global constants, they are stored in Nonlinear.OperatorRegistry, and it also stores a vector of logic operators and a vector of comparison operators. In addition to Nonlinear.DEFAULT_UNIVARIATE_OPERATORS and Nonlinear.DEFAULT_MULTIVARIATE_OPERATORS, you can register user-defined functions using Nonlinear.register_operator.

Nonlinear.Model is a struct that stores the Nonlinear.OperatorRegistry, as well as a list of parameters and subexpressions in the model.

ReverseAD

Nonlinear.ReverseAD is a submodule for computing derivatives of a nonlinear optimization problem using sparse reverse-mode automatic differentiation (AD).

This section does not attempt to explain how sparse reverse-mode AD works, but instead explains why MOI contains its own implementation, and highlights notable differences from similar packages.

Warning

Don't use the API in ReverseAD to compute derivatives. Instead, create a Nonlinear.Evaluator object with Nonlinear.SparseReverseMode as the backend, and then query the MOI API methods.

Design goals

The JuliaDiff organization maintains a list of packages for doing AD in Julia. At last count, there were at least ten packages——not including ReverseAD——for reverse-mode AD in Julia. ReverseAD exists because it has a different set of design goals.

  • Goal: handle scale and sparsity. The types of nonlinear optimization problems that MOI represents can be large scale (10^5 or more functions across 10^5 or more variables) with very sparse derivatives. The ability to compute a sparse Hessian matrix is essential. To the best of our knowledge, ReverseAD is the only reverse-mode AD system in Julia that handles sparsity by default.
  • Goal: limit the scope to improve robustness. Most other AD packages accept arbitrary Julia functions as input and then trace an expression graph using operator overloading. This means they must deal (or detect and ignore) with control flow, I/O, and other vagaries of Julia. In contrast, ReverseAD only accepts functions in the form of Nonlinear.Expression, which greatly limits the range of syntax that it must deal with. By reducing the scope of what we accept as input to functions relevant for mathematical optimization, we can provide a simpler implementation with various performance optimizations.
  • Goal: provide outputs which match what solvers expect. Other AD packages focus on differentiating individual Julia functions. In contrast, ReverseAD has a very specific use-case: to generate outputs needed by the MOI nonlinear API. This means it needs to efficiently compute sparse Hessians, and it needs subexpression handling to avoid recomputing subexpressions that are shared between functions.

History

ReverseAD started life as ReverseDiffSparse.jl, development of which began in early 2014(!). This was well before the other AD packages started development. Because we had a well-tested, working AD in JuMP, there was less motivation to contribute to and explore other AD packages. The lack of historical interaction also meant that other packages were not optimized for the types of problems that JuMP is built for (that is, large-scale sparse problems). When we first created MathOptInterface, we kept the AD in JuMP to simplify the transition, and post-poned the development of a first-class nonlinear interface in MathOptInterface.

Prior to the introduction of Nonlinear, JuMP's nonlinear implementation was a confusing mix of functions and types spread across the code base and in the private _Derivatives submodule. This made it hard to swap the AD system for another. The main motivation for refactoring JuMP to create the Nonlinear submodule in MathOptInterface was to abstract the interface between JuMP and the AD system, allowing us to swap-in and test new AD systems in the future.

+ );

This is less readable than the other options, but does this data structure meet our design goals?

Instead of a heap-allocated object for each node, we only have two Vectors for each expression, nodes and values, as well as two constant vectors for the OPERATORS. In addition, all fields are concretely typed, and there are no Union or Any types.

For our third goal, it is not easy to identify the children of a node, but it is easy to identify the parent of any node. Therefore, we can use Nonlinear.adjacency_matrix to compute a sparse matrix that maps parents to their children.

The tape is also ordered topologically, so that a reverse pass of the nodes evaluates all children nodes before their parent.

The design in practice

In practice, Node and Expression are exactly Nonlinear.Node and Nonlinear.Expression. However, Nonlinear.NodeType has more fields to account for comparison operators such as :>= and :<=, logic operators such as :&& and :||, nonlinear parameters, and nested subexpressions.

Moreover, instead of storing the operators as global constants, they are stored in Nonlinear.OperatorRegistry, and it also stores a vector of logic operators and a vector of comparison operators. In addition to Nonlinear.DEFAULT_UNIVARIATE_OPERATORS and Nonlinear.DEFAULT_MULTIVARIATE_OPERATORS, you can register user-defined functions using Nonlinear.register_operator.

Nonlinear.Model is a struct that stores the Nonlinear.OperatorRegistry, as well as a list of parameters and subexpressions in the model.

ReverseAD

Nonlinear.ReverseAD is a submodule for computing derivatives of a nonlinear optimization problem using sparse reverse-mode automatic differentiation (AD).

This section does not attempt to explain how sparse reverse-mode AD works, but instead explains why MOI contains its own implementation, and highlights notable differences from similar packages.

Warning

Don't use the API in ReverseAD to compute derivatives. Instead, create a Nonlinear.Evaluator object with Nonlinear.SparseReverseMode as the backend, and then query the MOI API methods.

Design goals

The JuliaDiff organization maintains a list of packages for doing AD in Julia. At last count, there were at least ten packages——not including ReverseAD——for reverse-mode AD in Julia. ReverseAD exists because it has a different set of design goals.

  • Goal: handle scale and sparsity. The types of nonlinear optimization problems that MOI represents can be large scale (10^5 or more functions across 10^5 or more variables) with very sparse derivatives. The ability to compute a sparse Hessian matrix is essential. To the best of our knowledge, ReverseAD is the only reverse-mode AD system in Julia that handles sparsity by default.
  • Goal: limit the scope to improve robustness. Most other AD packages accept arbitrary Julia functions as input and then trace an expression graph using operator overloading. This means they must deal (or detect and ignore) with control flow, I/O, and other vagaries of Julia. In contrast, ReverseAD only accepts functions in the form of Nonlinear.Expression, which greatly limits the range of syntax that it must deal with. By reducing the scope of what we accept as input to functions relevant for mathematical optimization, we can provide a simpler implementation with various performance optimizations.
  • Goal: provide outputs which match what solvers expect. Other AD packages focus on differentiating individual Julia functions. In contrast, ReverseAD has a very specific use-case: to generate outputs needed by the MOI nonlinear API. This means it needs to efficiently compute sparse Hessians, and it needs subexpression handling to avoid recomputing subexpressions that are shared between functions.

History

ReverseAD started life as ReverseDiffSparse.jl, development of which began in early 2014(!). This was well before the other AD packages started development. Because we had a well-tested, working AD in JuMP, there was less motivation to contribute to and explore other AD packages. The lack of historical interaction also meant that other packages were not optimized for the types of problems that JuMP is built for (that is, large-scale sparse problems). When we first created MathOptInterface, we kept the AD in JuMP to simplify the transition, and post-poned the development of a first-class nonlinear interface in MathOptInterface.

Prior to the introduction of Nonlinear, JuMP's nonlinear implementation was a confusing mix of functions and types spread across the code base and in the private _Derivatives submodule. This made it hard to swap the AD system for another. The main motivation for refactoring JuMP to create the Nonlinear submodule in MathOptInterface was to abstract the interface between JuMP and the AD system, allowing us to swap-in and test new AD systems in the future.

diff --git a/dev/submodules/Nonlinear/reference/index.html b/dev/submodules/Nonlinear/reference/index.html index cc174451a2..c0982a83b9 100644 --- a/dev/submodules/Nonlinear/reference/index.html +++ b/dev/submodules/Nonlinear/reference/index.html @@ -1,15 +1,15 @@ -API Reference · MathOptInterface

Nonlinear Modeling

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

MathOptInterface.NonlinearModule
Nonlinear
Warning

The Nonlinear submodule is experimental. Until this message is removed, breaking changes may be introduced in any minor or patch release of MathOptInterface.

source
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.

Examples

model = Model()
+API Reference · MathOptInterface

Nonlinear Modeling

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

MathOptInterface.NonlinearModule
Nonlinear
Warning

The Nonlinear submodule is experimental. Until this message is removed, breaking changes may be introduced in any minor or patch release of MathOptInterface.

source
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

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.

Examples

model = Model()
+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.

Examples

model = Model()
 x = MOI.VariableIndex(1)
 p = add_parameter(model, 1.2)
-c = add_constraint(model, :($x^2 - $p), MOI.LessThan(0.0))
source

Objectives

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.

Examples

model = Model()
 x = MOI.VariableIndex(1)
 set_objective(model, :($x^2 + 1))
 set_objective(model, x)
-set_objective(model, nothing)
source

Constraints

Constraints

MathOptInterface.Nonlinear.add_constraintFunction
add_constraint(
     model::Model,
     func,
     set::Union{
@@ -20,10 +20,10 @@
     },
 )

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.

Examples

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

Delete the constraint index c from model.

Examples

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

Delete the constraint index c from model.

Examples

model = Model()
 x = MOI.VariableIndex(1)
 c = add_constraint(model, :($x^2), MOI.LessThan(1.0))
-delete(model, c)
source

User-defined operators

User-defined operators

MathOptInterface.Nonlinear.DEFAULT_UNIVARIATE_OPERATORSConstant
DEFAULT_UNIVARIATE_OPERATORS

The list of univariate operators that are supported by default.

Example

julia> import MathOptInterface as MOI
 
 julia> MOI.Nonlinear.DEFAULT_UNIVARIATE_OPERATORS
 72-element Vector{Symbol}:
@@ -46,7 +46,7 @@
  :bessely0
  :bessely1
  :erfcx
- :dawson
source
MathOptInterface.Nonlinear.DEFAULT_MULTIVARIATE_OPERATORSConstant
DEFAULT_MULTIVARIATE_OPERATORS

The list of multivariate operators that are supported by default.

Example

julia> import MathOptInterface as MOI
 
 julia> MOI.Nonlinear.DEFAULT_MULTIVARIATE_OPERATORS
 9-element Vector{Symbol}:
@@ -58,66 +58,66 @@
  :ifelse
  :atan
  :min
- :max
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.register_operator_if_neededFunction
register_operator_if_needed(
+)

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_multivariate_hessianFunction
eval_multivariate_hessian(
     registry::OperatorRegistry,
     op::Symbol,
     H::AbstractMatrix,
     x::AbstractVector{T},
-) 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.

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
MathOptInterface.Nonlinear.eval_logic_functionFunction
eval_logic_function(
+) 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.

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

Automatic-differentiation backends

MathOptInterface.Nonlinear.EvaluatorType
Evaluator(
     model::Model,
     backend::AbstractAutomaticDifferentiation,
     ordered_variables::Vector{MOI.VariableIndex},
-)

Create Evaluator, a subtype of MOI.AbstractNLPEvaluator, from Model.

source
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

Data-structure

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

Data-structure

MathOptInterface.Nonlinear.NodeType
struct Node
     type::NodeType
     index::Int
     parent::Int
-end

A single node in a nonlinear expression tree. Used by Expression.

See the MathOptInterface documentation for information on how the nodes and values form an expression tree.

source
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.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.ConstraintType
struct Constraint
+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.ConstraintType
struct Constraint
     expression::Expression
     set::Union{
         MOI.LessThan{Float64},
@@ -125,16 +125,16 @@
         MOI.EqualTo{Float64},
         MOI.Interval{Float64},
     }
-end

A type to hold information relating to the nonlinear constraint f(x) in S, where f(x) is defined by .expression, and S is .set.

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 (i.e., the children).

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 (i.e., 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(
+)::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.

Examples

model = Model()
+)

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.

Examples

model = Model()
 x = MOI.VariableIndex(1)
 c1 = add_constraint(model, :($x^2), MOI.LessThan(1.0))
 c2 = add_constraint(model, :($x^2), MOI.LessThan(1.0))
@@ -144,4 +144,4 @@
 delete(model, c1)
 evaluator = Evaluator(model)
 MOI.initialize(evaluator, Symbol[])
-ordinal_index(model, c2)  # Returns 1
source
+ordinal_index(model, c2) # Returns 1
source
diff --git a/dev/submodules/Test/overview/index.html b/dev/submodules/Test/overview/index.html index db1a040a83..68c4620adb 100644 --- a/dev/submodules/Test/overview/index.html +++ b/dev/submodules/Test/overview/index.html @@ -163,4 +163,4 @@ ), ) return -end

Finally, you also need to implement Test.version_added. If we added this test when the latest released version of MOI was v0.10.5, define:

version_added(::typeof(test_unit_optimize!_twice)) = v"0.10.6"

Step 6

Commit the changes to git from ~/.julia/dev/MathOptInterface and submit the PR for review.

Tip

If you need help writing a test, open an issue on GitHub, or ask the Developer Chatroom.

+end

Finally, you also need to implement Test.version_added. If we added this test when the latest released version of MOI was v0.10.5, define:

version_added(::typeof(test_unit_optimize!_twice)) = v"0.10.6"

Step 6

Commit the changes to git from ~/.julia/dev/MathOptInterface and submit the PR for review.

Tip

If you need help writing a test, open an issue on GitHub, or ask the Developer Chatroom.

diff --git a/dev/submodules/Test/reference/index.html b/dev/submodules/Test/reference/index.html index c9260973d4..9b4e6023cf 100644 --- a/dev/submodules/Test/reference/index.html +++ b/dev/submodules/Test/reference/index.html @@ -15,7 +15,7 @@ MOI.ConstraintName, MOI.delete, ], -)source
MathOptInterface.Test.runtestsFunction
runtests(
     model::MOI.ModelLike,
     config::Config;
     include::Vector{Union{String,Regex}} = String[],
@@ -30,7 +30,7 @@
     exclude = ["VariablePrimalStart"],
     warn_unsupported = true,
     exclude_tests_after = v"0.10.5",
-)
source
MathOptInterface.Test.setup_testFunction
setup_test(::typeof(f), model::MOI.ModelLike, config::Config)

Overload this method to modify model before running the test function f on model with config. You can also modify the fields in config (e.g., to loosen the default tolerances).

This function should either return nothing, or return a function which, when called with zero arguments, undoes the setup to return the model to its previous state. You do not need to undo any modifications to config.

This function is most useful when writing new tests of the tests for MOI, but it can also be used to set test-specific tolerances, etc.

See also: runtests

Example

function MOI.Test.setup_test(
+)
source
MathOptInterface.Test.setup_testFunction
setup_test(::typeof(f), model::MOI.ModelLike, config::Config)

Overload this method to modify model before running the test function f on model with config. You can also modify the fields in config (e.g., to loosen the default tolerances).

This function should either return nothing, or return a function which, when called with zero arguments, undoes the setup to return the model to its previous state. You do not need to undo any modifications to config.

This function is most useful when writing new tests of the tests for MOI, but it can also be used to set test-specific tolerances, etc.

See also: runtests

Example

function MOI.Test.setup_test(
     ::typeof(MOI.Test.test_linear_VariablePrimalStart_partial),
     mock::MOIU.MockOptimizer,
     ::MOI.Test.Config,
@@ -46,5 +46,5 @@
         return
     end
     return reset_function
-end
source
MathOptInterface.Test.version_addedFunction
version_added(::typeof(function_name))

Returns the version of MOI in which the test function_name was added.

This method should be implemented for all new tests.

See the exclude_tests_after keyword of runtests for more details.

source
MathOptInterface.Test.@requiresMacro
@requires(x)

Check that the condition x is true. Otherwise, throw an RequirementUnmet error to indicate that the model does not support something required by the test function.

Examples

@requires MOI.supports(model, MOI.Silent())
-@test MOI.get(model, MOI.Silent())
source
+endsource
MathOptInterface.Test.version_addedFunction
version_added(::typeof(function_name))

Returns the version of MOI in which the test function_name was added.

This method should be implemented for all new tests.

See the exclude_tests_after keyword of runtests for more details.

source
MathOptInterface.Test.@requiresMacro
@requires(x)

Check that the condition x is true. Otherwise, throw an RequirementUnmet error to indicate that the model does not support something required by the test function.

Examples

@requires MOI.supports(model, MOI.Silent())
+@test MOI.get(model, MOI.Silent())
source
diff --git a/dev/submodules/Utilities/overview/index.html b/dev/submodules/Utilities/overview/index.html index 18b621c1f4..dbad80a6ec 100644 --- a/dev/submodules/Utilities/overview/index.html +++ b/dev/submodules/Utilities/overview/index.html @@ -247,4 +247,4 @@ index_map = MOI.copy_to(dest, src) for (F, S) in MOI.get(src, MOI.ListOfConstraintTypesPresent()) function_barrier(dest, src, index_map[F, S]) -end +end diff --git a/dev/submodules/Utilities/reference/index.html b/dev/submodules/Utilities/reference/index.html index 601a8218b3..e11b8412aa 100644 --- a/dev/submodules/Utilities/reference/index.html +++ b/dev/submodules/Utilities/reference/index.html @@ -1,6 +1,6 @@ API Reference · MathOptInterface

Utilities.Model

MathOptInterface.Utilities.ModelType

An implementation of ModelLike that supports all functions and sets defined in MOI. It is parameterized by the coefficient type.

Examples

model = Model{Float64}()
-x = add_variable(model)
source

Utilities.UniversalFallback

MathOptInterface.Utilities.UniversalFallbackType
UniversalFallback

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.

source

Utilities.@model

Utilities.UniversalFallback

MathOptInterface.Utilities.UniversalFallbackType
UniversalFallback

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.

source

Utilities.@model

MathOptInterface.Utilities.@modelMacro
macro model(
     model_name,
     scalar_sets,
     typed_scalar_sets,
@@ -53,11 +53,11 @@
         MOIU.VectorOfConstraints{MOI.VectorAffineFunction{T}, MOI.Nonpositives}
     }
 end
-const LPModel{T} = MOIU.GenericModel{T,MOIU.ObjectiveContainer{T},MOIU.VariablesContainer{T},LPModelFunctionConstraints{T}}

The type LPModel implements the MathOptInterface API except methods specific to optimizers like optimize! or get with VariablePrimal.

source
MathOptInterface.Utilities.GenericModelType
mutable 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 (excluding VariableIndex constraints) stored in .constraints::C

All interactions should take place via the MOI interface, so the types O, V, and C should implement the API as needed for their functionality.

source
MathOptInterface.Utilities.GenericOptimizerType
mutable 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 (excluding VariableIndex constraints) stored in .constraints::C

All interactions should take place via the MOI interface, so the types O, V, and C should implement the API as needed for their functionality.

source

.objective

.variables

MathOptInterface.Utilities.VariablesContainerType
struct VariablesContainer{T} <: AbstractVectorBounds
+const LPModel{T} = MOIU.GenericModel{T,MOIU.ObjectiveContainer{T},MOIU.VariablesContainer{T},LPModelFunctionConstraints{T}}

The type LPModel implements the MathOptInterface API except methods specific to optimizers like optimize! or get with VariablePrimal.

source
MathOptInterface.Utilities.GenericModelType
mutable 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 (excluding VariableIndex constraints) stored in .constraints::C

All interactions should take place via the MOI interface, so the types O, V, and C should implement the API as needed for their functionality.

source
MathOptInterface.Utilities.GenericOptimizerType
mutable 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 (excluding VariableIndex constraints) stored in .constraints::C

All interactions should take place via the MOI interface, so the types O, V, and C should implement the API as needed for their functionality.

source

.objective

.variables

MathOptInterface.Utilities.VariablesContainerType
struct 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.

source
MathOptInterface.Utilities.FreeVariablesType
mutable 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(
@@ -102,7 +102,7 @@
 MathOptInterface.ConstraintIndex{MathOptInterface.VectorAffineFunction{Float64}, MathOptInterface.Nonnegatives}(1)
 
 julia> MOI.Bridges.is_bridged(model, bridge.vector_constraint)
-false
source

.constraints

.constraints

MathOptInterface.Utilities.VectorOfConstraintsType
mutable struct VectorOfConstraints{
     F<:MOI.AbstractFunction,
     S<:MOI.AbstractSet,
 } <: MOI.ModelLike
@@ -112,7 +112,7 @@
         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.

source
MathOptInterface.Utilities.@struct_of_constraints_by_function_typesMacro
Utilities.@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 ith 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.

source
MathOptInterface.Utilities.@struct_of_constraints_by_set_typesMacro
Utilities.@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 ith 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.

source
MathOptInterface.Utilities.struct_of_constraint_codeFunction
struct_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 ith 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.

source

Caching optimizer

MathOptInterface.Utilities.CachingOptimizerType
CachingOptimizer

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 the CachingOptimizer are Utilities.reset_optimizer, Utilities.drop_optimizer, and Utilities.attach_optimizer. Attempting to perform an operation in the incorrect state results in an error.
  • AUTOMATIC: The CachingOptimizer changes its state when necessary. For example, optimize! will automatically call attach_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 to EMPTY_OPTIMIZER mode.
source
MathOptInterface.Utilities.attach_optimizerFunction
attach_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.

source
MathOptInterface.Utilities.reset_optimizerFunction
reset_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.

source
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.

source

Mock optimizer

Printing

MathOptInterface.Utilities.latex_formulationFunction
latex_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.
source

Copy utilities

MathOptInterface.Utilities.ModelFilterType
ModelFilter(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
Warning

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.

Note

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
+end

A struct storing F-in-S constraints as a mapping between the constraint indices to the corresponding tuple of function and set.

source
MathOptInterface.Utilities.@struct_of_constraints_by_function_typesMacro
Utilities.@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 ith 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.

source
MathOptInterface.Utilities.@struct_of_constraints_by_set_typesMacro
Utilities.@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 ith 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.

source
MathOptInterface.Utilities.struct_of_constraint_codeFunction
struct_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 ith 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.

source

Caching optimizer

MathOptInterface.Utilities.CachingOptimizerType
CachingOptimizer

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 the CachingOptimizer are Utilities.reset_optimizer, Utilities.drop_optimizer, and Utilities.attach_optimizer. Attempting to perform an operation in the incorrect state results in an error.
  • AUTOMATIC: The CachingOptimizer changes its state when necessary. For example, optimize! will automatically call attach_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 to EMPTY_OPTIMIZER mode.
source
MathOptInterface.Utilities.attach_optimizerFunction
attach_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.

source
MathOptInterface.Utilities.reset_optimizerFunction
reset_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.

source
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.

source

Mock optimizer

Printing

MathOptInterface.Utilities.latex_formulationFunction
latex_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.
source

Copy utilities

MathOptInterface.Utilities.ModelFilterType
ModelFilter(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
Warning

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.

Note

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!
@@ -125,7 +125,7 @@
     return status != MOI.NOT_IN_CONFLICT
 end
 filtered_src = MOI.Utilities.ModelFilter(my_filter, src)
-MOI.copy_to(dest, filtered_src)
source

Penalty relaxation

Penalty relaxation

MathOptInterface.Utilities.PenaltyRelaxationType
PenaltyRelaxation(
     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.

Warning

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.

Examples

julia> model = MOI.Utilities.Model{Float64}();
@@ -170,7 +170,7 @@
  v[2] >= 0.0
 
 julia> map[c] isa MOI.ScalarAffineFunction{Float64}
-true
source
MathOptInterface.Utilities.ScalarPenaltyRelaxationType
ScalarPenaltyRelaxation(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.

Warning

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.

Examples

julia> model = MOI.Utilities.Model{Float64}();
+true
source
MathOptInterface.Utilities.ScalarPenaltyRelaxationType
ScalarPenaltyRelaxation(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.

Warning

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.

Examples

julia> model = MOI.Utilities.Model{Float64}();
 
 julia> x = MOI.add_variable(model);
 
@@ -191,18 +191,18 @@
  v[2] >= 0.0
 
 julia> f isa MOI.ScalarAffineFunction{Float64}
-true
source

MatrixOfConstraints

MatrixOfConstraints

MathOptInterface.Utilities.MatrixOfConstraintsType
mutable 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:

  1. With add_constraint, in which case a canonicalized copy of the function is stored in caches.
  2. With pass_nonvariable_constraints, in which case the functions and sets are stored themselves in caches without mapping the variable indices. The corresponding index in caches is added in are_indices_mapped. This avoids doing a copy of the function in case the getter of CanonicalConstraintFunction does not make a copy for the source model, e.g., this is the case of VectorOfConstraints.

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:

The .constants::BT type must implement:

The .sets::ST type must implement:

source

.coefficients

MathOptInterface.Utilities.load_termsFunction
load_terms(coefficients, index_map, func, offset)::Nothing

Loads the terms of func to coefficients, mapping the variable indices with index_map.

The ith 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.

source
MathOptInterface.Utilities.final_touchFunction
final_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.

source
MathOptInterface.Utilities.extract_functionFunction
extract_function(coefficients, row::Integer, constant::T) where {T}

Return the MOI.ScalarAffineFunction{T} function corresponding to row row in coefficients.

extract_function(
+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:

  1. With add_constraint, in which case a canonicalized copy of the function is stored in caches.
  2. With pass_nonvariable_constraints, in which case the functions and sets are stored themselves in caches without mapping the variable indices. The corresponding index in caches is added in are_indices_mapped. This avoids doing a copy of the function in case the getter of CanonicalConstraintFunction does not make a copy for the source model, e.g., this is the case of VectorOfConstraints.

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:

The .constants::BT type must implement:

The .sets::ST type must implement:

source

.coefficients

MathOptInterface.Utilities.load_termsFunction
load_terms(coefficients, index_map, func, offset)::Nothing

Loads the terms of func to coefficients, mapping the variable indices with index_map.

The ith 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.

source
MathOptInterface.Utilities.final_touchFunction
final_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.

source
MathOptInterface.Utilities.extract_functionFunction
extract_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.

source
MathOptInterface.Utilities.MutableSparseMatrixCSCType
mutable struct MutableSparseMatrixCSC{Tv,Ti<:Integer,I<:AbstractIndexing}
     indexing::I
     m::Int
     n::Int
@@ -210,61 +210,61 @@
     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:

  1. MOI.empty! is called.
  2. MOI.Utilities.add_column and MOI.Utilities.allocate_terms are called in any order.
  3. MOI.Utilities.set_number_of_rows is called.
  4. MOI.Utilities.load_terms is called for each affine function.
  5. MOI.Utilities.final_touch is called.
source
MathOptInterface.Utilities.ZeroBasedIndexingType
struct ZeroBasedIndexing <: AbstractIndexing end

Zero-based indexing: the ith 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.

source

.constants

MathOptInterface.Utilities.load_constantsFunction
load_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:

  1. Base.empty! is called.
  2. Base.resize! is called with the sum of the dimensions of all constraints.
  3. MOI.Utilities.load_constants is called for each function for vector constraint or set for scalar constraint.
source
MathOptInterface.Utilities.HyperrectangleType
struct Hyperrectangle{T} <: AbstractVectorBounds
+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:

  1. MOI.empty! is called.
  2. MOI.Utilities.add_column and MOI.Utilities.allocate_terms are called in any order.
  3. MOI.Utilities.set_number_of_rows is called.
  4. MOI.Utilities.load_terms is called for each affine function.
  5. MOI.Utilities.final_touch is called.
source
MathOptInterface.Utilities.ZeroBasedIndexingType
struct ZeroBasedIndexing <: AbstractIndexing end

Zero-based indexing: the ith 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.

source

.constants

MathOptInterface.Utilities.load_constantsFunction
load_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:

  1. Base.empty! is called.
  2. Base.resize! is called with the sum of the dimensions of all constraints.
  3. MOI.Utilities.load_constants is called for each function for vector constraint or set for scalar constraint.
source

.sets

MathOptInterface.Utilities.set_indexFunction
set_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.

source
MathOptInterface.Utilities.add_setFunction
add_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.

source
MathOptInterface.Utilities.rowsFunction
rows(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}.

source
MathOptInterface.Utilities.num_rowsFunction
num_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.

source

.sets

MathOptInterface.Utilities.set_indexFunction
set_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.

source
MathOptInterface.Utilities.add_setFunction
add_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.

source
MathOptInterface.Utilities.rowsFunction
rows(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}.

source
MathOptInterface.Utilities.num_rowsFunction
num_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.

source

Fallbacks

MathOptInterface.Utilities.get_fallbackFunction
get_fallback(model::MOI.ModelLike, ::MOI.ObjectiveValue)

Compute the objective function value using the VariablePrimal results and the ObjectiveFunction value.

source
get_fallback(model::MOI.ModelLike, ::MOI.DualObjectiveValue, T::Type)::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.

source
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.

source
get_fallback(model::MOI.ModelLike, attr::MOI.ConstraintDual,
+)
source

Fallbacks

MathOptInterface.Utilities.get_fallbackFunction
get_fallback(model::MOI.ModelLike, ::MOI.ObjectiveValue)

Compute the objective function value using the VariablePrimal results and the ObjectiveFunction value.

source
get_fallback(model::MOI.ModelLike, ::MOI.DualObjectiveValue, T::Type)::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.

source
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.

source
get_fallback(model::MOI.ModelLike, attr::MOI.ConstraintDual,
              ci::MOI.ConstraintIndex{Union{MOI.VariableIndex,
-                                           MOI.VectorOfVariables}})

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.

source

Function utilities

The following utilities are available for functions:

MathOptInterface.Utilities.eval_variablesFunction
eval_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.

Warning

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.

source
MathOptInterface.Utilities.map_indicesFunction
map_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.

source
map_indices(
+                                           MOI.VectorOfVariables}})

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.

source

Function utilities

The following utilities are available for functions:

MathOptInterface.Utilities.eval_variablesFunction
eval_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.

Warning

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.

source
MathOptInterface.Utilities.map_indicesFunction
map_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.

source
map_indices(
     variable_map::AbstractDict{T,T},
     x::X,
-)::X where {T<:MOI.Index,X}

Shortcut for map_indices(vi -> variable_map[vi], x).

source
MathOptInterface.Utilities.substitute_variablesFunction
substitute_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.

Note

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}.

source
MathOptInterface.Utilities.filter_variablesFunction
filter_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}.

source
MathOptInterface.Utilities.remove_variableFunction
remove_variable(f::AbstractFunction, vi::VariableIndex)

Return a new function f with the variable vi removed.

source
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 (e.g. when f is a VectorOfVariables with vi being one of the variables).

source
MathOptInterface.Utilities.all_coefficientsFunction
all_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.

source
MathOptInterface.Utilities.unsafe_addFunction
unsafe_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.

source
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.

source
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.

source
MathOptInterface.Utilities.isapprox_zeroFunction
isapprox_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. For instance, given

f = MOI.ScalarAffineFunction(MOI.ScalarAffineTerm.([1, -1], [x, x]), 0)

then isapprox_zero(f) is false but isapprox_zero(MOIU.canonical(f)) is true.

source
MathOptInterface.Utilities.zero_with_output_dimensionFunction
zero_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.

source

The following functions can be used to canonicalize a function:

MathOptInterface.Utilities.is_canonicalFunction
is_canonical(f::Union{ScalarAffineFunction, VectorAffineFunction})

Returns a Bool indicating whether the function is in canonical form. See canonical.

source
is_canonical(f::Union{ScalarQuadraticFunction, VectorQuadraticFunction})

Returns a Bool indicating whether the function is in canonical form. See canonical.

source
MathOptInterface.Utilities.canonicalFunction
canonical(f::MOI.AbstractFunction)

Returns the function in a canonical form, i.e.

  • 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.

Examples

If x (resp. y, z) is VariableIndex(1) (resp. 2, 3). The canonical representation of ScalarAffineFunction([y, x, z, x, z], [2, 1, 3, -2, -3], 5) is ScalarAffineFunction([x, y], [-1, 2], 5).

source
MathOptInterface.Utilities.canonicalize!Function
canonicalize!(f::Union{ScalarAffineFunction, VectorAffineFunction})

Convert a function to canonical form in-place, without allocating a copy to hold the result. See canonical.

source
canonicalize!(f::Union{ScalarQuadraticFunction, VectorQuadraticFunction})

Convert a function to canonical form in-place, without allocating a copy to hold the result. See canonical.

source

The following functions can be used to manipulate functions with basic algebra:

MathOptInterface.Utilities.scalarizeFunction
scalarize(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.

source
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.

source
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.

source
MathOptInterface.Utilities.substitute_variablesFunction
substitute_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.

Note

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}.

source
MathOptInterface.Utilities.filter_variablesFunction
filter_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}.

source
MathOptInterface.Utilities.remove_variableFunction
remove_variable(f::AbstractFunction, vi::VariableIndex)

Return a new function f with the variable vi removed.

source
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 (e.g. when f is a VectorOfVariables with vi being one of the variables).

source
MathOptInterface.Utilities.all_coefficientsFunction
all_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.

source
MathOptInterface.Utilities.unsafe_addFunction
unsafe_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.

source
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.

source
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.

source
MathOptInterface.Utilities.isapprox_zeroFunction
isapprox_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. For instance, given

f = MOI.ScalarAffineFunction(MOI.ScalarAffineTerm.([1, -1], [x, x]), 0)

then isapprox_zero(f) is false but isapprox_zero(MOIU.canonical(f)) is true.

source
MathOptInterface.Utilities.zero_with_output_dimensionFunction
zero_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.

source

The following functions can be used to canonicalize a function:

MathOptInterface.Utilities.is_canonicalFunction
is_canonical(f::Union{ScalarAffineFunction, VectorAffineFunction})

Returns a Bool indicating whether the function is in canonical form. See canonical.

source
is_canonical(f::Union{ScalarQuadraticFunction, VectorQuadraticFunction})

Returns a Bool indicating whether the function is in canonical form. See canonical.

source
MathOptInterface.Utilities.canonicalFunction
canonical(f::MOI.AbstractFunction)

Returns the function in a canonical form, i.e.

  • 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.

Examples

If x (resp. y, z) is VariableIndex(1) (resp. 2, 3). The canonical representation of ScalarAffineFunction([y, x, z, x, z], [2, 1, 3, -2, -3], 5) is ScalarAffineFunction([x, y], [-1, 2], 5).

source
MathOptInterface.Utilities.canonicalize!Function
canonicalize!(f::Union{ScalarAffineFunction, VectorAffineFunction})

Convert a function to canonical form in-place, without allocating a copy to hold the result. See canonical.

source
canonicalize!(f::Union{ScalarQuadraticFunction, VectorQuadraticFunction})

Convert a function to canonical form in-place, without allocating a copy to hold the result. See canonical.

source

The following functions can be used to manipulate functions with basic algebra:

MathOptInterface.Utilities.scalarizeFunction
scalarize(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.

source
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.

source
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.

source
MathOptInterface.Utilities.promote_operationFunction
promote_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:

  1. + a. promote_operation(::typeof(+), ::Type{T}, ::Type{F1}, ::Type{F2})
  2. - a. promote_operation(::typeof(-), ::Type{T}, ::Type{F}) b. promote_operation(::typeof(-), ::Type{T}, ::Type{F1}, ::Type{F2})
  3. * 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}) where F1 and F2 are VariableIndex or ScalarAffineFunction d. promote_operation(::typeof(*), ::Type{T}, ::Type{<:Diagonal{T}}, ::Type{F}
  4. / a. promote_operation(::typeof(/), ::Type{T}, ::Type{F}, ::Type{T})
  5. vcat a. promote_operation(::typeof(vcat), ::Type{T}, ::Type{F}...)
  6. imag a. promote_operation(::typeof(imag), ::Type{T}, ::Type{F}) where F is VariableIndex or VectorOfVariables

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:

  1. ::T
  2. ::VariableIndex
  3. ::ScalarAffineFunction{T}
  4. ::ScalarQuadraticFunction{T}
  5. ::ScalarNonlinearFunction
  6. ::AbstractVector{T}
  7. ::VectorOfVariables
  8. ::VectorAffineFunction{T}
  9. ::VectorQuadraticFunction{T}
  10. ::VectorNonlinearFunction
source
MathOptInterface.Utilities.operateFunction
operate(
+) 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:

  1. + a. promote_operation(::typeof(+), ::Type{T}, ::Type{F1}, ::Type{F2})
  2. - a. promote_operation(::typeof(-), ::Type{T}, ::Type{F}) b. promote_operation(::typeof(-), ::Type{T}, ::Type{F1}, ::Type{F2})
  3. * 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}) where F1 and F2 are VariableIndex or ScalarAffineFunction d. promote_operation(::typeof(*), ::Type{T}, ::Type{<:Diagonal{T}}, ::Type{F}
  4. / a. promote_operation(::typeof(/), ::Type{T}, ::Type{F}, ::Type{T})
  5. vcat a. promote_operation(::typeof(vcat), ::Type{T}, ::Type{F}...)
  6. imag a. promote_operation(::typeof(imag), ::Type{T}, ::Type{F}) where F is VariableIndex or VectorOfVariables

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:

  1. ::T
  2. ::VariableIndex
  3. ::ScalarAffineFunction{T}
  4. ::ScalarQuadraticFunction{T}
  5. ::ScalarNonlinearFunction
  6. ::AbstractVector{T}
  7. ::VectorOfVariables
  8. ::VectorAffineFunction{T}
  9. ::VectorQuadraticFunction{T}
  10. ::VectorNonlinearFunction
source
MathOptInterface.Utilities.operateFunction
operate(
     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

  1. + a. operate(::typeof(+), ::Type{T}, ::F1) b. operate(::typeof(+), ::Type{T}, ::F1, ::F2) c. operate(::typeof(+), ::Type{T}, ::F1...)
  2. - a. operate(::typeof(-), ::Type{T}, ::F) b. operate(::typeof(-), ::Type{T}, ::F1, ::F2)
  3. * a. operate(::typeof(*), ::Type{T}, ::T, ::F) b. operate(::typeof(*), ::Type{T}, ::F, ::T) c. operate(::typeof(*), ::Type{T}, ::F1, ::F2) where F1 and F2 are VariableIndex or ScalarAffineFunction d. operate(::typeof(*), ::Type{T}, ::Diagonal{T}, ::F)
  4. / a. operate(::typeof(/), ::Type{T}, ::F, ::T)
  5. vcat a. operate(::typeof(vcat), ::Type{T}, ::F...)
  6. imag a. operate(::typeof(imag), ::Type{T}, ::F) where F is VariableIndex or VectorOfVariables

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:

  1. ::T
  2. ::VariableIndex
  3. ::ScalarAffineFunction{T}
  4. ::ScalarQuadraticFunction{T}
  5. ::ScalarNonlinearFunction
  6. ::AbstractVector{T}
  7. ::VectorOfVariables
  8. ::VectorAffineFunction{T}
  9. ::VectorQuadraticFunction{T}
  10. ::VectorNonlinearFunction
source
MathOptInterface.Utilities.operate!Function
operate!(
+)::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

  1. + a. operate(::typeof(+), ::Type{T}, ::F1) b. operate(::typeof(+), ::Type{T}, ::F1, ::F2) c. operate(::typeof(+), ::Type{T}, ::F1...)
  2. - a. operate(::typeof(-), ::Type{T}, ::F) b. operate(::typeof(-), ::Type{T}, ::F1, ::F2)
  3. * a. operate(::typeof(*), ::Type{T}, ::T, ::F) b. operate(::typeof(*), ::Type{T}, ::F, ::T) c. operate(::typeof(*), ::Type{T}, ::F1, ::F2) where F1 and F2 are VariableIndex or ScalarAffineFunction d. operate(::typeof(*), ::Type{T}, ::Diagonal{T}, ::F)
  4. / a. operate(::typeof(/), ::Type{T}, ::F, ::T)
  5. vcat a. operate(::typeof(vcat), ::Type{T}, ::F...)
  6. imag a. operate(::typeof(imag), ::Type{T}, ::F) where F is VariableIndex or VectorOfVariables

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:

  1. ::T
  2. ::VariableIndex
  3. ::ScalarAffineFunction{T}
  4. ::ScalarQuadraticFunction{T}
  5. ::ScalarNonlinearFunction
  6. ::AbstractVector{T}
  7. ::VectorOfVariables
  8. ::VectorAffineFunction{T}
  9. ::VectorQuadraticFunction{T}
  10. ::VectorNonlinearFunction
source
MathOptInterface.Utilities.operate!Function
operate!(
     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.

source
MathOptInterface.Utilities.operate_output_index!Function
operate_output_index!(
+)::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.

source
MathOptInterface.Utilities.operate_output_index!Function
operate_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

  1. + a. operate_output_index!(+, ::Type{T}, ::Int, ::VectorF, ::ScalarF)
  2. - a. operate_output_index!(-, ::Type{T}, ::Int, ::VectorF, ::ScalarF)
source
MathOptInterface.Utilities.vectorizeFunction
vectorize(x::AbstractVector{<:Number})

Returns x.

source
vectorize(x::AbstractVector{MOI.VariableIndex})

Returns the vector of scalar affine functions in the form of a MOI.VectorAffineFunction{T}.

source
vectorize(funcs::AbstractVector{MOI.ScalarAffineFunction{T}}) where T

Returns the vector of scalar affine functions in the form of a MOI.VectorAffineFunction{T}.

source
vectorize(funcs::AbstractVector{MOI.ScalarQuadraticFunction{T}}) where T

Returns the vector of scalar quadratic functions in the form of a MOI.VectorQuadraticFunction{T}.

source

Constraint utilities

The following utilities are available for moving the function constant to the set for scalar constraints:

MathOptInterface.Utilities.shift_constantFunction
shift_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.

Only define this function if it makes sense to!

Use supports_shift_constant to check if the set supports shifting:

if supports_shift_constant(typeof(old_set))
+) 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

  1. + a. operate_output_index!(+, ::Type{T}, ::Int, ::VectorF, ::ScalarF)
  2. - a. operate_output_index!(-, ::Type{T}, ::Int, ::VectorF, ::ScalarF)
source
MathOptInterface.Utilities.vectorizeFunction
vectorize(x::AbstractVector{<:Number})

Returns x.

source
vectorize(x::AbstractVector{MOI.VariableIndex})

Returns the vector of scalar affine functions in the form of a MOI.VectorAffineFunction{T}.

source
vectorize(funcs::AbstractVector{MOI.ScalarAffineFunction{T}}) where T

Returns the vector of scalar affine functions in the form of a MOI.VectorAffineFunction{T}.

source
vectorize(funcs::AbstractVector{MOI.ScalarQuadraticFunction{T}}) where T

Returns the vector of scalar quadratic functions in the form of a MOI.VectorQuadraticFunction{T}.

source

Constraint utilities

The following utilities are available for moving the function constant to the set for scalar constraints:

MathOptInterface.Utilities.shift_constantFunction
shift_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.

Only define this function if it makes sense to!

Use supports_shift_constant to check if the set supports shifting:

if supports_shift_constant(typeof(old_set))
     new_set = shift_constant(old_set, offset)
     f.constant = 0
     add_constraint(model, f, new_set)
 else
     add_constraint(model, f, old_set)
-end

See also supports_shift_constant.

Examples

The call shift_constant(MOI.Interval(-2, 3), 1) is equal to MOI.Interval(-1, 4).

source
MathOptInterface.Utilities.normalize_and_add_constraintFunction
normalize_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.

source

The following utility identifies those constraints imposing bounds on a given variable, and returns those bound values:

MathOptInterface.Utilities.get_boundsFunction
get_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.

source

The following utilities are useful when working with symmetric matrix cones.

Set utilities

The following utilities are available for sets:

MathOptInterface.Utilities.ProjectionUpperBoundDistanceType
ProjectionUpperBoundDistance() <: 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.

source

The following utility identifies those constraints imposing bounds on a given variable, and returns those bound values:

MathOptInterface.Utilities.get_boundsFunction
get_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.

source

The following utilities are useful when working with symmetric matrix cones.

Set utilities

The following utilities are available for sets:

MathOptInterface.Utilities.ProjectionUpperBoundDistanceType
ProjectionUpperBoundDistance() <: 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.

source
MathOptInterface.Utilities.distance_to_setFunction
distance_to_set(
     [d::AbstractDistance = ProjectionUpperBoundDistance()],]
     point::T,
     set::MOI.AbstractScalarSet,
@@ -274,11 +274,11 @@
     [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.

source
MathOptInterface.Utilities.set_dotFunction
set_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.

source
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.

source

DoubleDicts

MathOptInterface.Utilities.DoubleDicts.DoubleDictType
DoubleDict{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.

source
MathOptInterface.Utilities.DoubleDicts.outer_keysFunction
outer_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)
+) 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.

source
MathOptInterface.Utilities.set_dotFunction
set_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.

source
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.

source

DoubleDicts

MathOptInterface.Utilities.DoubleDicts.DoubleDictType
DoubleDict{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.

source
MathOptInterface.Utilities.DoubleDicts.outer_keysFunction
outer_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 gurantee 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.

source
MathOptInterface.Utilities.DoubleDicts.nonempty_outer_keysFunction
nonempty_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)
+end

For performance, it is recommended that the inner loop lies in a separate function to gurantee 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.

source
MathOptInterface.Utilities.DoubleDicts.nonempty_outer_keysFunction
nonempty_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
@@ -286,4 +286,4 @@
 For performance, it is recommended that the inner loop lies in a separate
 function to gurantee type-stability.
 
-If you want an iterator of all current outer keys, use [`outer_keys`](@ref).
source
+If you want an iterator of all current outer keys, use [`outer_keys`](@ref).source diff --git a/dev/tutorials/bridging_constraint/index.html b/dev/tutorials/bridging_constraint/index.html index e302538d98..0fad50f795 100644 --- a/dev/tutorials/bridging_constraint/index.html +++ b/dev/tutorials/bridging_constraint/index.html @@ -99,4 +99,4 @@ end

Bridge deletion

When a bridge is deleted, the constraints it added must be deleted too.

function delete(model::ModelLike, bridge::SignBridge)
     delete(model, bridge.constraint)
     return
-end
+end diff --git a/dev/tutorials/example/index.html b/dev/tutorials/example/index.html index e852568e27..fdfc945c1e 100644 --- a/dev/tutorials/example/index.html +++ b/dev/tutorials/example/index.html @@ -42,4 +42,4 @@ 3-element Vector{Float64}: 1.0 1.0 - 1.0 + 1.0 diff --git a/dev/tutorials/implementing/index.html b/dev/tutorials/implementing/index.html index b4d50ed6e2..fe857a1dab 100644 --- a/dev/tutorials/implementing/index.html +++ b/dev/tutorials/implementing/index.html @@ -111,4 +111,4 @@ n = # Code to get NumberOfObjectives return n end

Then, the user can write:

model = Gurobi.Optimizer()
-MOI.set(model, Gurobi.NumberofObjectives(), 3)
+MOI.set(model, Gurobi.NumberofObjectives(), 3) diff --git a/dev/tutorials/latency/index.html b/dev/tutorials/latency/index.html index 8081a44adf..8eb5bd78e1 100644 --- a/dev/tutorials/latency/index.html +++ b/dev/tutorials/latency/index.html @@ -126,4 +126,4 @@ end

You can create a flame-graph via

using SnoopComile
 tinf = @snoopi_deep example_diet(GLPK.Optimizer, true)
 using ProfileView
-ProfileView.view(flamegraph(tinf))

Here's how things looked in mid-August 2021: flamegraph

There are a few opportunities for improvement (non-red flames, particularly on the right). But the main problem is a large red (non-precompilable due to method ownership) flame.

+ProfileView.view(flamegraph(tinf))

Here's how things looked in mid-August 2021: flamegraph

There are a few opportunities for improvement (non-red flames, particularly on the right). But the main problem is a large red (non-precompilable due to method ownership) flame.

diff --git a/dev/tutorials/manipulating_expressions/index.html b/dev/tutorials/manipulating_expressions/index.html index 311b06164e..3f8b648ee9 100644 --- a/dev/tutorials/manipulating_expressions/index.html +++ b/dev/tutorials/manipulating_expressions/index.html @@ -19,4 +19,4 @@ 2-element Vector{MathOptInterface.ScalarAffineFunction{Int64}}: (2) + (1) MOI.VariableIndex(1) (4) + (2) MOI.VariableIndex(1)
Note

Utilities.eachscalar returns an iterator on the dimensions, which serves the same purpose as Utilities.scalarize.

output_dimension returns the number of dimensions of the output of a function:

julia> MOI.output_dimension(g)
-2
+2 diff --git a/dev/tutorials/mathprogbase/index.html b/dev/tutorials/mathprogbase/index.html index 982af3f76c..45e3346e4b 100644 --- a/dev/tutorials/mathprogbase/index.html +++ b/dev/tutorials/mathprogbase/index.html @@ -51,4 +51,4 @@ objval = objective_value(model), sol = value.(x) ) -end +end