From 7fd556bb99e5723c20e6d05bff774dc21a008ce1 Mon Sep 17 00:00:00 2001 From: "Documenter.jl" Date: Fri, 22 Sep 2023 11:19:12 +0000 Subject: [PATCH] build based on e6b6932 --- previews/PR2288/.documenter-siteinfo.json | 2 +- previews/PR2288/MathOptInterface.pdf | Bin 1248289 -> 1247160 bytes previews/PR2288/background/duality/index.html | 2 +- .../infeasibility_certificates/index.html | 2 +- .../PR2288/background/motivation/index.html | 2 +- .../background/naming_conventions/index.html | 2 +- previews/PR2288/changelog/index.html | 4 +- .../PR2288/developer/checklists/index.html | 2 +- previews/PR2288/index.html | 2 +- previews/PR2288/manual/constraints/index.html | 2 +- previews/PR2288/manual/models/index.html | 2 +- .../PR2288/manual/modification/index.html | 2 +- previews/PR2288/manual/solutions/index.html | 2 +- .../PR2288/manual/standard_form/index.html | 2 +- previews/PR2288/manual/variables/index.html | 2 +- .../PR2288/reference/callbacks/index.html | 12 +- .../PR2288/reference/constraints/index.html | 10 +- previews/PR2288/reference/errors/index.html | 32 ++-- previews/PR2288/reference/models/index.html | 38 ++--- .../PR2288/reference/modification/index.html | 4 +- .../PR2288/reference/nonlinear/index.html | 36 ++--- .../PR2288/reference/standard_form/index.html | 140 +++++++++--------- .../PR2288/reference/variables/index.html | 12 +- previews/PR2288/release_notes/index.html | 4 +- previews/PR2288/search_index.js | 2 +- .../submodules/Benchmarks/overview/index.html | 2 +- .../Benchmarks/reference/index.html | 6 +- .../Bridges/list_of_bridges/index.html | 30 ++-- .../submodules/Bridges/overview/index.html | 2 +- .../submodules/Bridges/reference/index.html | 70 ++++----- .../FileFormats/overview/index.html | 2 +- .../FileFormats/reference/index.html | 6 +- .../submodules/Nonlinear/overview/index.html | 2 +- .../submodules/Nonlinear/reference/index.html | 50 +++---- .../submodules/Test/overview/index.html | 2 +- .../submodules/Test/reference/index.html | 8 +- .../submodules/Utilities/overview/index.html | 2 +- .../submodules/Utilities/reference/index.html | 115 ++++++-------- .../tutorials/bridging_constraint/index.html | 2 +- previews/PR2288/tutorials/example/index.html | 2 +- .../PR2288/tutorials/implementing/index.html | 2 +- previews/PR2288/tutorials/latency/index.html | 2 +- .../manipulating_expressions/index.html | 2 +- .../PR2288/tutorials/mathprogbase/index.html | 2 +- 44 files changed, 302 insertions(+), 327 deletions(-) diff --git a/previews/PR2288/.documenter-siteinfo.json b/previews/PR2288/.documenter-siteinfo.json index 75dec32cea..35d318c58a 100644 --- a/previews/PR2288/.documenter-siteinfo.json +++ b/previews/PR2288/.documenter-siteinfo.json @@ -1 +1 @@ -{"documenter":{"julia_version":"1.9.3","generation_timestamp":"2023-09-22T04:53:36","documenter_version":"1.0.1"}} \ No newline at end of file +{"documenter":{"julia_version":"1.9.3","generation_timestamp":"2023-09-22T11:13:12","documenter_version":"1.0.1"}} \ No newline at end of file diff --git a/previews/PR2288/MathOptInterface.pdf b/previews/PR2288/MathOptInterface.pdf index fbead48efab83e9be826e2c940f31ba07b53e39a..1b4db17cea08ea3403728ba76b8d4a5b4328a552 100644 GIT binary patch delta 216292 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
(5>Bl=)_BMf<&jTOa`4!EynA#hts}i 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 z

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

w;``AXN?Mr1f1~ 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

*VI3MtL?EA_p6(r&?!XJw>6aUqCS!4}H# zdyiL01p&0$uyT}ef8C*)U_@s%a!T=y=;M;rlbDAK+Wo|%R1f}*g5`tFRJ&hHElBpO zCYP5v;OQtjg4fRwMbo1I*7^VHw1HDj*z;=lD`@Y0ELWMcg3g?9{wJay-lcPkt>^~a z4EpP0;DQsB|K=vPx_ey4kuU#eY{ z`wbWh7-Ha3_fS;(XCn3kb zYbqS5WoX$gm_U*1PYqHZAY>oScXp1A^wF;(m=W!Fi-tybMngv^?xE93OD=5liK~3P z{omO~zc@=qahhgfZ{QFVcX|%XDg-#AM5!6;pKJ)KUHm965Wb08P}tZc+U{y<8c-@c z07}PtU)2$8ckyZTvptjRFB0`a6Q(wCcyi333LBp?Mo z%zm%e|MH)Ov=Q&f4zY|iHPDTkGR?x-o*gCie$x1Ih*vr(RUW`1*2*sD2k z!o9+b?cr8N1>BS|b?9a0R_h)8QK04hh4vE~{aobDO0c0b) zD+#{rZ^sX`Iec(htE#}yhm%Kqw^Ygp>kY)k&~k>`#QlvqFm|z0?9N0Tsdwd_gu}!0 zy_4*u`(Ky?L=Q}RCsa+SW2*>4GT^t*a3+;8f;;#whUS>>JcjuA$4Ly@vF0<4<*%^29kz;d9Sh|9DCeZS%g!65-HPk*!Q9sr_vZDTPV*>?rCtTd`-^&83X20i3d{T&vxcUn4OQDc6 z&m^Vj6)!=uHu>nFYtM5=Zq_?{A@A&r5678jwA_aec0%5n8ST)H{%v^~-P4XoLm8VJ zC=hNctMF29L&e(WW}R+BMMrn?>e^F1C*|O7&{I7=MSqSwmcv@+a?4XaJ>_odk(;cq zWAggATOPQBlR@LT*83?x%;Un!a-E}uYjlY;EcvaKYTzdT delta 217551 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%0DbeDVRuhB>we@Bry)``u?^JHX; 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

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/previews/PR2288/background/motivation/index.html b/previews/PR2288/background/motivation/index.html index c13f33615b..0c49836e44 100644 --- a/previews/PR2288/background/motivation/index.html +++ b/previews/PR2288/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/previews/PR2288/background/naming_conventions/index.html b/previews/PR2288/background/naming_conventions/index.html index f72e708d52..6071e5daeb 100644 --- a/previews/PR2288/background/naming_conventions/index.html +++ b/previews/PR2288/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/previews/PR2288/changelog/index.html b/previews/PR2288/changelog/index.html index 708762888c..79da0ddbee 100644 --- a/previews/PR2288/changelog/index.html +++ b/previews/PR2288/changelog/index.html @@ -1,5 +1,5 @@ -Release notes · MathOptInterface

Release notes

The format is based on Keep a Changelog, and this project adheres to Semantic Versioning.

v1.20.1 (September 22, 2023)

Fixed

Other

  • Added MathOptSetDistances to solver-tests.yml (#2265)
  • Updated Documenter (#2266)
  • Fixed various JET errors (#2267) (#2269) (#2270) (#2271) (#2276) (#2277) (#2289)
  • Various style improvements
    • Replaced using Package with import Package where possible (#2274)
    • Removed Utilities.EMPTYSTRING (#2283)
    • Removed unnecessary const acronyms in Utilities (#2280) (#2281)
    • Removed invalid and unused method (#2286)

v1.20.0 (September 7, 2023)

Added

Other

  • Updated dependencies (#2258)
  • Improved performance of ScalarNonlinearFunction utilities (#2259)
  • Fixed docstrings (#2261)

v1.19.0 (August 15, 2023)

Added

Fixed

Other

  • Added extensions to solver-tests.yml (#2229)
  • Refactored test/Benchmarks (#2234)
  • Fixed warnings in tests (#2241) (#2243)
  • Small refactoring of bridges for upcoming VectorNonlinearFunction (#2244) (#2245)
  • Fixed various typos (#2251) (#2255)
  • Partitioned how we run the tests on GitHub actions (#2252) (#2253)

v1.18.0 (June 23, 2023)

Added

Fixed

  • Fixed a missing @require in MOI.Test (#2195) (#2196)
  • Fixed incorrect usage of Utilities.operate! in bridges (#2207) (#2216)
  • Fixed splatting nonlinear expression with univariate operator (#2221)

Other

  • Removed unused argument names (#2199)
  • Reduced memory requirement for tests (#2204)
  • Refactored Utilities.promote_operation (#2206)
  • Improved code style in Utilities/mutable_arithmetics.jl (#2209)
  • Refactored various methods in Utilities/functions.jl (#2208) (#2212) (#2213) (#2214) (#2215)

v1.17.1 (June 6, 2023)

Fixed

Other

  • Added documentation for enum instances (#2186)
  • Updated chatroom links in documentation (#2188)
  • Changed the documentation to build on Julia v1.9 (#2191)

v1.17.0 (June 1, 2023)

Added

Fixed

  • Fixed support for external sets in Utilities.loadfromstring! (#2177)
  • Fixed promote_operation for ScalarNonlinearFunction (#2179)
  • Fixed two issues in FileFormats.LP when reading files with quadratic functions (#2182) (#2184)

v1.16.0 (May 16, 2023)

Added

Fixed

  • Fixed support for Julia v1.9 to work around a bug in the upstream Julia compiler (#2161) (#2163)
  • Fixed a correctness bug in Bridges.Constraint.HermitianToSymmetricPSDBridge (#2171)
  • Fixed convert(::VariableIndex, ::ScalarAffineFunction) when the function has terms with 0coefficients (#2173)

Other

  • Fixed solver-tests.yml (#2157)
  • Updated documentation links to developer chatroom (#2160)
  • Added various tests for bridges (#2156)
  • Added checklists to the developer documentation (#2167) (#2168)

v1.15.1 (April 25, 2023)

Fixed

  • Fixed deleting a variable in a bridged objective (#2150)

v1.15.0 (April 19, 2023)

Added

Fixed

Other

  • Add a test for variables in one-sided open Interval sets (#2133)
  • Minor style fixes in the source code (#2148)

v1.14.1 (April 6, 2023)

Fixed

Other

  • Added a warning when an ambiguous string is passed to exclude in Test.runtests (#2136)

v1.14.0 (April 4, 2023)

Added

Fixed

  • Fixed ResultCount when parsing .sol files in FileFormats.NL (#2130)

v1.13.2 (March 21, 2023)

Fixed

Other

  • Fixed typos in the documentation (#2114)
  • Functions 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)

v1.13.1 (March 3, 2023)

Other

  • Added the Google style guide to the documentation linter Vale, and fixed the resulting warnings (#2110)
  • Improved the docstrings in src/functions.jl (#2108)

v1.13.0 (February 28, 2023)

Added

Fixed

Other

  • Added tests for vector-valued objective functions in FileFormats.MOF (#2093)
  • Used and documented preference for import MathOptInterface as MOI (#2096)
  • Fix and test links in the documentation with linkcheck = true (#2098)
  • Improved docstrings of sets in src/sets.jl (#2099)
  • Skip checking flakey links in documentation with linkcheck_ignore (#2103)

v1.12.0 (February 10, 2023)

Added

Fixed

  • Fixed a number of constraint bridges so that Bridges.final_touch can be called multiple times without forcing a rebuild of the reformulation (#2089)

Other

v1.11.5 (January 24, 2023)

Fixed

  • Fixed a bug writing .lp files with an off-diagonal quadratic objective (#2082)

Other

  • Added SnoopPrecompile directives for reduced time-to-first-X in Julia v1.9 (#2080)

v1.11.4 (January 12, 2023)

Fixed

  • Fixed a bug reading .lp files with an Integer section (#2078)

v1.11.3 (January 12, 2023)

Fixed

  • Fixed a performance bug when deleting a vector of constraints (#2072)
  • Fixed a bug reading .lp files with terms like x -1 y (#2076)

Other

  • Documented the two-argument method of optimize! (#2074)

v1.11.2 (January 2, 2023)

Fixed

  • Fixed a bug reading .mof.json files with ConstraintName set for VariableIndex constraints (#2066)
  • Fixed a bug reading .mof.json files with nonlinear objectives and no constraints (#2068)

v1.11.1 (December 22, 2022)

Fixed

  • Fixed a bug reading .mof.json files with integer coefficients for affine and quadratic functions (#2063)

v1.11.0 (December 2, 2022)

Added

Other

  • Tidied these release notes (#2055)

v1.10.0 (November 22, 2022)

Added

Fixed

  • Fixed Bridges.Objective.SlackBridge when the objective function is complex-valued (#2036) (#2038)
  • Fixed docstring of Test.runtests to clarify the warn_unsupported argument (#2037)
  • Fixed reading of free variables in FileFormats.LP (#2044)
  • Fixed numerous edge cases reading files from QPLIB using FileFormats.LP (#2042) (#2044)
  • Fixed situations in which x^y returns a complex value in Nonlinear (#2050)

Other

  • Improved the error message thrown when a user-defined nonlinear function does not accept splatted input (#2032)
  • Removed specialized iterators for keys and values in Utilities.CleverDicts (#2051)

v1.9.0 (October 29, 2022)

Added

  • Added default fallback for getting ListOfConstraintIndices and NumberOfConstraints when the constraint type is unsupported by the model (#2021)
  • Added support for min and max in nonlinear expressions (#2023)
  • Added support for Indicator{EqualTo{T}} constraints in FileFormats.MPS (#2022)
  • Added default fallback for write_to_file and read_from_file (#2029)

Fixed

  • Fixed Constraint.ZeroOneBridge by adding new bounds as affine constraints instead of variable bounds (#1879)
  • Fixed reading free rows in FileFormats.MPS files (#2009)
  • Fixed parsing of OBJSENSE blocks in FileFormats.MPS files (#2016) (#2019)
  • Fixed the parsing of deeply nested nonlinear expressions by removing the use of recursion (#2020)
  • Fixed the requirements check in Test.test_constrainnt_get_ConstraintIndex (#2024)

v1.8.2 (September 20, 2022)

Documentation

  • Added vale as a documentation linter (#2002)
  • Improved styling of code blocks in the PDF (#1999) (#2000)
  • Fixed a number of typos in the documentation (#2001) (#2003)

v1.8.1 (September 12, 2022)

Fixed

  • Fixed a bug in supports(::AbstractBridgeOptimizer for constraint attributes (#1991) (#1992)

v1.8.0 (September 1, 2022)

Added

Fixed

  • Lazily construct expressions in Nonlinear so that expressions are updated when Nonlinear.Parameter values are updated (#1984)
  • Allow NORM_LIMIT as a TerminationStatus for unbounded problems in Test (#1990)

v1.7.0 (August 16, 2022)

Added

Fixed

  • Fixed some missing promotion rules

Other

  • Improved the performance of Jacobian products in Nonlinear
  • Removed an un-needed copy in Utilities.modify_function
  • Various clean-ups in Bridges/bridge_optimizer.jl

v1.6.1 (July 23, 2022)

Fixed

  • Added support for ExponentialCone in MatrixOfConstraints
  • Fix PSDSquare_3 test to reflect a previously fixed bug getting the ConstraintDual of a PositiveSemidefiniteConeSquare constraint

v1.6.0 (July 2, 2022)

Added

  • Added Bridges.needs_final_touch and Bridges.final_touch
  • Added new bridges from constraint programming sets to mixed-integer linear programs:
    • AllDifferentToCountDistinctBridge
    • CountAtLeastToCountBelongsBridge
    • CountBelongsToMILPBridge
    • CountDistinctToMILPBridge
    • CountGreaterThanToMILPBridge
    • CircuitToMILPBridge

Fixed

  • Relax an instance of ::Vector to ::AbstractVector in MOI.Nonlinear
  • Fix BinPackingToMILPBridge to respect variable bounds
  • Fix SemiToBinaryBridge to throw error if other bounds are set

v1.5.0 (June 27, 2022)

Added

  • Added GetAttributeNotAllowed for solvers to indicate when getting an attribute encounters an error
  • Added Utilities.get_fallback support for ObjectiveValue and DualObjectiveValue
  • Added new bridges:
    • RootDetConeSquare to RootDetConeTriangle
    • LogDetConeSquare to LogDetConeTriangle
    • BinPacking to a mixed-integer linear program
    • Table to a mixed-integer linear program
  • Added Bridges.print_active_bridges to display the current optimal hyper-path in a Bridges.LazyBridgeOptimizer

Fixed

  • Fixed ZeroOne tests with lower and upper bounds
  • Fixed error in FileFormats.LP when reading a malformed file
  • Fixed reading of nonlinear programs in FileFormats.MOF
  • Fixed bug in ConstraintDual when using SquareBridge

Other

  • Improved documentation of nonlinear API
  • Documented duality convention for PositiveSemidefiniteConeSquare sets
  • Fixed typo in Bridges.Constraint.QuadToSOCBridge docstring

v1.4.0 (June 9, 2022)

Added

  • Added a number of sets for constraint programming:
    • AllDifferent
    • BinPacking
    • Circuit
    • CountAtLeast
    • CountBelongs
    • CountDistinct
    • CountGreaterThan
    • Cumulative
    • Path
    • Table
  • Added support for user-defined hessians in Nonlinear
  • Added Bridges.runtests to simplify the testing of bridge implementations

Fixed

  • Fixed a bug in FileFormats.NL when writing univariate *

Other

  • Began a large refactoring of the Bridges submodule, with greatly improved documentation.

v1.3.0 (May 27, 2022)

Added

  • 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.
  • Add FileFormats.NL.SolFileResults(::IO, ::Model)
  • Add FileFormats.NL.read!(::IO, ::Model)
  • Add MOI.modify that accepts a vector of modifications

Fixed

  • Fixed a bug in Test which attempted to include non-.jl files
  • Fixed a bug in FileFormats for models with open interval constraints

Other

  • Fixed a performance issue in Utilities.DoubleDict
  • Various minor improvements to the documentation

v1.2.0 (April 25, 2022)

Added

  • Add support for the FORMAT_REW/.rew file format in FileFormats.

Fixed

  • Fix bug handling of default variable bounds in FileFormats.LP
  • Fix FileFormats.MPS to not write OBJSENSE by default since this is only supported by some readers.

v1.1.2 (March 31, 2022)

Fixed

  • Fix a range of bugs in FileFormats.LP
  • Fix reading of problem dimensions in FileFormats.SDPA

v1.1.1 (March 23, 2022)

Fixed

  • Fix bug in test_model_UpperBoundAlreadySet
  • Fix bug in test_infeasible_ tests
  • Fix bug in test_objective_ObjectiveFunction_blank
  • Relax restriction of MOI.AbstractOptimizer to MOI.ModelLike in Utilities.CachingOptimizer and instantiate.

New tests

  • Add test_conic_empty_matrix that checks conic solvers support problems with no variables.

v1.1.0 (March 2, 2022)

Added

  • Added MOI.Utilities.throw_unsupported(::UniversalFallback) for simplifying solver wrappers which copy from a UniversalFallback.

v1.0.2 (March 1, 2022)

Fixed

  • Fixed a bug in the test_model_ScalarFunctionConstantNotZero test
  • Fixed the error type when an AbstractFunctionConversionBridge cannot get or set an attribute
  • Identified a correctness bug in RSOCtoPSDBridge. We now thrown an error instead of returning an incorrect result.

v1.0.1 (February 25, 2022)

Fixed

  • Fixed a bug in which OptimizerAttributes were not copied in CachingOptimizer
  • Fixed a bug in which shift_constant did not promote mixed types of coefficients
  • Fixed a bug in which deleting a constraint of a bridged variable threw ErrorException instead of MOI.DeleteNotAllowed
  • Fixed a bug in which add_constraint in MatrixOfConstraints did not canonicalize the function
  • Fixed a bug when modifying scalar constants of a function containing a bridged variable
  • Fixed a bug in which final_touch was not always called with a CachingOptimizer

v1.0.0 (February 17, 2022)

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.

Breaking

  • Julia 1.6 is now the minimum supported version
  • All deprecations have been removed

Troubleshooting problems when updating

If you experience problems when updating, you are likely using previously deprecated features. (By default, Julia does not warn when you use deprecated features.)

To find the deprecated features you are using, start Julia with --depwarn=yes:

$ julia --depwarn=yes

Then install MathOptInterface v0.10.9:

julia> using Pkg
+Release notes · MathOptInterface

Release notes

The format is based on Keep a Changelog, and this project adheres to Semantic Versioning.

v1.20.1 (September 22, 2023)

Fixed

Other

  • Added MathOptSetDistances to solver-tests.yml (#2265)
  • Updated Documenter (#2266)
  • Fixed various JET errors (#2267) (#2269) (#2270) (#2271) (#2276) (#2277) (#2289)
  • Various style improvements
    • Replaced using Package with import Package where possible (#2274)
    • Removed Utilities.EMPTYSTRING (#2283)
    • Removed unnecessary const acronyms in Utilities (#2280) (#2281)
    • Removed invalid and unused method (#2286)
  • Refactored src/Utilities/model.jl (#2287)

v1.20.0 (September 7, 2023)

Added

Other

  • Updated dependencies (#2258)
  • Improved performance of ScalarNonlinearFunction utilities (#2259)
  • Fixed docstrings (#2261)

v1.19.0 (August 15, 2023)

Added

Fixed

Other

  • Added extensions to solver-tests.yml (#2229)
  • Refactored test/Benchmarks (#2234)
  • Fixed warnings in tests (#2241) (#2243)
  • Small refactoring of bridges for upcoming VectorNonlinearFunction (#2244) (#2245)
  • Fixed various typos (#2251) (#2255)
  • Partitioned how we run the tests on GitHub actions (#2252) (#2253)

v1.18.0 (June 23, 2023)

Added

Fixed

  • Fixed a missing @require in MOI.Test (#2195) (#2196)
  • Fixed incorrect usage of Utilities.operate! in bridges (#2207) (#2216)
  • Fixed splatting nonlinear expression with univariate operator (#2221)

Other

  • Removed unused argument names (#2199)
  • Reduced memory requirement for tests (#2204)
  • Refactored Utilities.promote_operation (#2206)
  • Improved code style in Utilities/mutable_arithmetics.jl (#2209)
  • Refactored various methods in Utilities/functions.jl (#2208) (#2212) (#2213) (#2214) (#2215)

v1.17.1 (June 6, 2023)

Fixed

Other

  • Added documentation for enum instances (#2186)
  • Updated chatroom links in documentation (#2188)
  • Changed the documentation to build on Julia v1.9 (#2191)

v1.17.0 (June 1, 2023)

Added

Fixed

  • Fixed support for external sets in Utilities.loadfromstring! (#2177)
  • Fixed promote_operation for ScalarNonlinearFunction (#2179)
  • Fixed two issues in FileFormats.LP when reading files with quadratic functions (#2182) (#2184)

v1.16.0 (May 16, 2023)

Added

Fixed

  • Fixed support for Julia v1.9 to work around a bug in the upstream Julia compiler (#2161) (#2163)
  • Fixed a correctness bug in Bridges.Constraint.HermitianToSymmetricPSDBridge (#2171)
  • Fixed convert(::VariableIndex, ::ScalarAffineFunction) when the function has terms with 0coefficients (#2173)

Other

  • Fixed solver-tests.yml (#2157)
  • Updated documentation links to developer chatroom (#2160)
  • Added various tests for bridges (#2156)
  • Added checklists to the developer documentation (#2167) (#2168)

v1.15.1 (April 25, 2023)

Fixed

  • Fixed deleting a variable in a bridged objective (#2150)

v1.15.0 (April 19, 2023)

Added

Fixed

Other

  • Add a test for variables in one-sided open Interval sets (#2133)
  • Minor style fixes in the source code (#2148)

v1.14.1 (April 6, 2023)

Fixed

Other

  • Added a warning when an ambiguous string is passed to exclude in Test.runtests (#2136)

v1.14.0 (April 4, 2023)

Added

Fixed

  • Fixed ResultCount when parsing .sol files in FileFormats.NL (#2130)

v1.13.2 (March 21, 2023)

Fixed

Other

  • Fixed typos in the documentation (#2114)
  • Functions 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)

v1.13.1 (March 3, 2023)

Other

  • Added the Google style guide to the documentation linter Vale, and fixed the resulting warnings (#2110)
  • Improved the docstrings in src/functions.jl (#2108)

v1.13.0 (February 28, 2023)

Added

Fixed

Other

  • Added tests for vector-valued objective functions in FileFormats.MOF (#2093)
  • Used and documented preference for import MathOptInterface as MOI (#2096)
  • Fix and test links in the documentation with linkcheck = true (#2098)
  • Improved docstrings of sets in src/sets.jl (#2099)
  • Skip checking flakey links in documentation with linkcheck_ignore (#2103)

v1.12.0 (February 10, 2023)

Added

Fixed

  • Fixed a number of constraint bridges so that Bridges.final_touch can be called multiple times without forcing a rebuild of the reformulation (#2089)

Other

v1.11.5 (January 24, 2023)

Fixed

  • Fixed a bug writing .lp files with an off-diagonal quadratic objective (#2082)

Other

  • Added SnoopPrecompile directives for reduced time-to-first-X in Julia v1.9 (#2080)

v1.11.4 (January 12, 2023)

Fixed

  • Fixed a bug reading .lp files with an Integer section (#2078)

v1.11.3 (January 12, 2023)

Fixed

  • Fixed a performance bug when deleting a vector of constraints (#2072)
  • Fixed a bug reading .lp files with terms like x -1 y (#2076)

Other

  • Documented the two-argument method of optimize! (#2074)

v1.11.2 (January 2, 2023)

Fixed

  • Fixed a bug reading .mof.json files with ConstraintName set for VariableIndex constraints (#2066)
  • Fixed a bug reading .mof.json files with nonlinear objectives and no constraints (#2068)

v1.11.1 (December 22, 2022)

Fixed

  • Fixed a bug reading .mof.json files with integer coefficients for affine and quadratic functions (#2063)

v1.11.0 (December 2, 2022)

Added

Other

  • Tidied these release notes (#2055)

v1.10.0 (November 22, 2022)

Added

Fixed

  • Fixed Bridges.Objective.SlackBridge when the objective function is complex-valued (#2036) (#2038)
  • Fixed docstring of Test.runtests to clarify the warn_unsupported argument (#2037)
  • Fixed reading of free variables in FileFormats.LP (#2044)
  • Fixed numerous edge cases reading files from QPLIB using FileFormats.LP (#2042) (#2044)
  • Fixed situations in which x^y returns a complex value in Nonlinear (#2050)

Other

  • Improved the error message thrown when a user-defined nonlinear function does not accept splatted input (#2032)
  • Removed specialized iterators for keys and values in Utilities.CleverDicts (#2051)

v1.9.0 (October 29, 2022)

Added

  • Added default fallback for getting ListOfConstraintIndices and NumberOfConstraints when the constraint type is unsupported by the model (#2021)
  • Added support for min and max in nonlinear expressions (#2023)
  • Added support for Indicator{EqualTo{T}} constraints in FileFormats.MPS (#2022)
  • Added default fallback for write_to_file and read_from_file (#2029)

Fixed

  • Fixed Constraint.ZeroOneBridge by adding new bounds as affine constraints instead of variable bounds (#1879)
  • Fixed reading free rows in FileFormats.MPS files (#2009)
  • Fixed parsing of OBJSENSE blocks in FileFormats.MPS files (#2016) (#2019)
  • Fixed the parsing of deeply nested nonlinear expressions by removing the use of recursion (#2020)
  • Fixed the requirements check in Test.test_constrainnt_get_ConstraintIndex (#2024)

v1.8.2 (September 20, 2022)

Documentation

  • Added vale as a documentation linter (#2002)
  • Improved styling of code blocks in the PDF (#1999) (#2000)
  • Fixed a number of typos in the documentation (#2001) (#2003)

v1.8.1 (September 12, 2022)

Fixed

  • Fixed a bug in supports(::AbstractBridgeOptimizer for constraint attributes (#1991) (#1992)

v1.8.0 (September 1, 2022)

Added

Fixed

  • Lazily construct expressions in Nonlinear so that expressions are updated when Nonlinear.Parameter values are updated (#1984)
  • Allow NORM_LIMIT as a TerminationStatus for unbounded problems in Test (#1990)

v1.7.0 (August 16, 2022)

Added

Fixed

  • Fixed some missing promotion rules

Other

  • Improved the performance of Jacobian products in Nonlinear
  • Removed an un-needed copy in Utilities.modify_function
  • Various clean-ups in Bridges/bridge_optimizer.jl

v1.6.1 (July 23, 2022)

Fixed

  • Added support for ExponentialCone in MatrixOfConstraints
  • Fix PSDSquare_3 test to reflect a previously fixed bug getting the ConstraintDual of a PositiveSemidefiniteConeSquare constraint

v1.6.0 (July 2, 2022)

Added

  • Added Bridges.needs_final_touch and Bridges.final_touch
  • Added new bridges from constraint programming sets to mixed-integer linear programs:
    • AllDifferentToCountDistinctBridge
    • CountAtLeastToCountBelongsBridge
    • CountBelongsToMILPBridge
    • CountDistinctToMILPBridge
    • CountGreaterThanToMILPBridge
    • CircuitToMILPBridge

Fixed

  • Relax an instance of ::Vector to ::AbstractVector in MOI.Nonlinear
  • Fix BinPackingToMILPBridge to respect variable bounds
  • Fix SemiToBinaryBridge to throw error if other bounds are set

v1.5.0 (June 27, 2022)

Added

  • Added GetAttributeNotAllowed for solvers to indicate when getting an attribute encounters an error
  • Added Utilities.get_fallback support for ObjectiveValue and DualObjectiveValue
  • Added new bridges:
    • RootDetConeSquare to RootDetConeTriangle
    • LogDetConeSquare to LogDetConeTriangle
    • BinPacking to a mixed-integer linear program
    • Table to a mixed-integer linear program
  • Added Bridges.print_active_bridges to display the current optimal hyper-path in a Bridges.LazyBridgeOptimizer

Fixed

  • Fixed ZeroOne tests with lower and upper bounds
  • Fixed error in FileFormats.LP when reading a malformed file
  • Fixed reading of nonlinear programs in FileFormats.MOF
  • Fixed bug in ConstraintDual when using SquareBridge

Other

  • Improved documentation of nonlinear API
  • Documented duality convention for PositiveSemidefiniteConeSquare sets
  • Fixed typo in Bridges.Constraint.QuadToSOCBridge docstring

v1.4.0 (June 9, 2022)

Added

  • Added a number of sets for constraint programming:
    • AllDifferent
    • BinPacking
    • Circuit
    • CountAtLeast
    • CountBelongs
    • CountDistinct
    • CountGreaterThan
    • Cumulative
    • Path
    • Table
  • Added support for user-defined hessians in Nonlinear
  • Added Bridges.runtests to simplify the testing of bridge implementations

Fixed

  • Fixed a bug in FileFormats.NL when writing univariate *

Other

  • Began a large refactoring of the Bridges submodule, with greatly improved documentation.

v1.3.0 (May 27, 2022)

Added

  • 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.
  • Add FileFormats.NL.SolFileResults(::IO, ::Model)
  • Add FileFormats.NL.read!(::IO, ::Model)
  • Add MOI.modify that accepts a vector of modifications

Fixed

  • Fixed a bug in Test which attempted to include non-.jl files
  • Fixed a bug in FileFormats for models with open interval constraints

Other

  • Fixed a performance issue in Utilities.DoubleDict
  • Various minor improvements to the documentation

v1.2.0 (April 25, 2022)

Added

  • Add support for the FORMAT_REW/.rew file format in FileFormats.

Fixed

  • Fix bug handling of default variable bounds in FileFormats.LP
  • Fix FileFormats.MPS to not write OBJSENSE by default since this is only supported by some readers.

v1.1.2 (March 31, 2022)

Fixed

  • Fix a range of bugs in FileFormats.LP
  • Fix reading of problem dimensions in FileFormats.SDPA

v1.1.1 (March 23, 2022)

Fixed

  • Fix bug in test_model_UpperBoundAlreadySet
  • Fix bug in test_infeasible_ tests
  • Fix bug in test_objective_ObjectiveFunction_blank
  • Relax restriction of MOI.AbstractOptimizer to MOI.ModelLike in Utilities.CachingOptimizer and instantiate.

New tests

  • Add test_conic_empty_matrix that checks conic solvers support problems with no variables.

v1.1.0 (March 2, 2022)

Added

  • Added MOI.Utilities.throw_unsupported(::UniversalFallback) for simplifying solver wrappers which copy from a UniversalFallback.

v1.0.2 (March 1, 2022)

Fixed

  • Fixed a bug in the test_model_ScalarFunctionConstantNotZero test
  • Fixed the error type when an AbstractFunctionConversionBridge cannot get or set an attribute
  • Identified a correctness bug in RSOCtoPSDBridge. We now thrown an error instead of returning an incorrect result.

v1.0.1 (February 25, 2022)

Fixed

  • Fixed a bug in which OptimizerAttributes were not copied in CachingOptimizer
  • Fixed a bug in which shift_constant did not promote mixed types of coefficients
  • Fixed a bug in which deleting a constraint of a bridged variable threw ErrorException instead of MOI.DeleteNotAllowed
  • Fixed a bug in which add_constraint in MatrixOfConstraints did not canonicalize the function
  • Fixed a bug when modifying scalar constants of a function containing a bridged variable
  • Fixed a bug in which final_touch was not always called with a CachingOptimizer

v1.0.0 (February 17, 2022)

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.

Breaking

  • Julia 1.6 is now the minimum supported version
  • All deprecations have been removed

Troubleshooting problems when updating

If you experience problems when updating, you are likely using previously deprecated features. (By default, Julia does not warn when you use deprecated features.)

To find the deprecated features you are using, start Julia with --depwarn=yes:

$ julia --depwarn=yes

Then install MathOptInterface v0.10.9:

julia> using Pkg
 julia> pkg"add MathOptInterface@0.10"

And then run your code. Apply any suggestions, or search the release notes below for advice on updating a specific deprecated feature.

v0.10.9 (February 16, 2022)

Added

  • Added MOI.Utilities.FreeVariables as a new VariablesConstrainer for conic solvers
  • Added MOI.default_cache for specifying the model used in CachingOptimizer

Fixed

  • Fixed LaTeX printing of MOI.Interval sets

Other

  • Added Aqua.jl as a CI check, and fixed suggested issues
  • The 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.

v0.10.8 (February 3, 2022)

Added

  • Added a Base.read! for FileFormats.LP.

Fixed

  • Fixed a bug in MutableSparseMatrix
  • Fixed a bug when calling operate!(vcat, ...) with Number arguments
  • Removed unintended export of deprecated symbols
  • Fixed a bug with PowerCone and DualPowerCone in MatrixOfConstraints.

v0.10.7 (January 5, 2022)

Added

  • Added test for modifying the constant vector in a VectorAffineFunction-in-Zeros constraint.

Fixed

  • 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.
  • Fixed an error message in FileFormats.CBF
  • Fixed comparison in test_linear_integration_Interval
  • Fixed errors for ConstraintPrimal in a CachingOptimizer
  • Fixed printing of models with non-Float64 coefficients.

Other

  • Various improvements to reduce time-to-first-solve latency
  • Improved error message when an optimizer does not support compute_conflict!

v0.10.6 (November 30, 2021)

Added

  • Added new documentation and tests for infeasibility certificates
  • Added 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.
  • MOI.Test.runtests now supports generic number types. To specify the number type T, pass MOI.Test.Config(T).
  • Added infeasible_status to MOI.Test.Config for solvers which return LOCALLY_INFEASIBLE
  • CachingOptimizers now use a fallback for ConstraintPrimal. This should enable solvers using a CachingOptimizer to pass tests requiring ConstraintPrimal.

Fixed

  • Fixed a StackOverflow bug in copy_to
  • Fixed error thrown when nonconvex quadratic constraints cannot be bridged
  • Fixed a bug in copy_to for FileFormats.NL.Model
  • Fixed a bug in FileFormats.NL when printing large integers
  • Remove a common test failure for LowerBoundAlreadySet tests
  • Utilities.num_rows is now exported
  • Remove parts of failing test_model_copy_to_xxx tests due to bridges

v0.10.5 (November 7, 2021)

Fixed

  • Fixed getter in UniversalFallback
  • Fixed test_solve_conflict_zeroone_ii

Other

  • Make normalize_and_add_constraint more flexible
  • Update paper BibTeX

v0.10.4 (October 26, 2021)

Added

  • Add SolverVersion attribute
  • Add new tests:
    • test_solve_conflict_zeroone_ii
    • test_nonlinear_objective
  • Utilities.VariablesContainer now supports ConstraintFunction and ConstraintSet
  • The documentation is now available as a PDF

Other

  • Update to MutableArithmetics 0.3
  • Various improvements to the documentation

v0.10.3 (September 18, 2021)

Fixed

  • Fixed bug which prevented callbacks from working through a CachingOptimizer
  • Fixed bug in Test submodule

v0.10.2 (September 16, 2021)

  • Updated MathOptFormat to v1.0
  • Updated JSONSchema to v1.0
  • Added Utilities.set_with_dimension
  • Added two-argument optimize!(::AbstractOptimizer, ::ModelLike)
  • The experimental feature copy_to_and_optimize! has been removed
  • Det bridges now support getting ConstraintFunction and ConstraintSet
  • Various minor bug fixes identified by improved testing

v0.10.1 (September 8, 2021)

  • Various fixes to MOI.Test

v0.10.0 (September 6, 2021)

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.

Breaking in MOI

  • SingleVariable has been removed; use VariableIndex instead
  • SingleVariableConstraintNameError has been renamed to VariableIndexConstraintNameError
  • SettingSingleVariableFunctionNotAllowed has been renamed to SettingVariableIndexFunctionNotAllowed
  • VariableIndex constraints should not support ConstraintName
  • VariableIndex constraints should not support ConstraintBasisStatus; implement VariableBasisStatus instead
  • ListOfConstraints has been renamed to ListOfConstraintTypesPresent
  • ListOfConstraintTypesPresent should now return Tuple{Type,Type} instead of Tuple{DataType,DataType}
  • SolveTime has been renamed to SolveTimeSec
  • IndicatorSet has been renamed to Indicator
  • RawParameter has been renamed to RawOptimizerAttribute and now takes String instead of Any as the only argument
  • The .N field in result attributes has been renamed to .result_index
  • The .variable_index field in ScalarAffineTerm has been renamed to .variable
  • The .variable_index_1 field in ScalarQuadraticTerm has been renamed to .variable_1
  • The .variable_index_2 field in ScalarQuadraticTerm has been renamed to .variable_2
  • The 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.
  • The index_value function has been removed. Use .value instead.
  • isapprox has been removed for SOS1 and SOS2.
  • The 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.
  • copy_to no longer takes keyword arguments:
    • copy_names: now copy names if they are supported by the destination solver
    • filter_constraints: use Utilities.ModelFilter instead
    • warn_attributes: never warn about optimizer attributes

Breaking in Bridges

  • Constraint.RSOCBridge has been renamed to Constraint.RSOCtoSOCBridge
  • Constraint.SOCRBridge has been renamed to Constraint.SOCtoRSOCBridge
  • Bridges now return vectors that can be modified by the user. Previously, some bridges returned views instead of copies.
  • Bridges.IndexInVector has been unified into a single type. Previously, there was a different type for each submodule within Bridges
  • The signature of indicator bridges has been fixed. Use MOI.Bridges.Constraint.IndicatortoSOS1{Float64}(model).

Breaking in FileFormats

  • FileFormats.MOF.Model no longer accepts validate argument. Use the JSONSchema package to validate the MOF file. See the documentation for more information.

Breaking in Utilities

  • 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.
  • Utilities.supports_default_copy has been renamed to supports_incremental_interface
  • Utilities.automatic_copy_to has been renamed to Utilities.default_copy_to
  • The allocate-load API has been removed
  • CachingOptimizers 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.
  • The 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.
  • The size argument to Utilities.CleverDicts.CleverDict(::Integer) has been removed.
  • The size argument to Utilities.IndexMap(::Integer) has been removed.
  • Utilities.DoubleDicts have been significantly refactored. Consult the source code for details.
  • Utilities.test_models_equal has been moved to MOI.Test

Breaking in Test

  • MOI.Test has been renamed to MOI.DeprecatedTest
  • An 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.

Other changes:

  • attribute_value_type has been added
  • copy_to_and_optimize! has been added
  • VariableBasisStatus has been added
  • print(model) now prints a human-readable description of the model
  • Various improvements to the FileFormats submodule
    • FileFormats.CBF was refactored and received bugfixes
    • Support for MathOptFormat v0.6 was added in FileFormats.MOF
    • FileFormats.MPS has had bugfixes and support for more features such as OBJSENSE and objective constants.
    • FileFormats.NL has been added to support nonlinear files
  • Improved type inference throughout to reduce latency

Updating

A helpful script when updating is:

for (root, dirs, files) in walkdir(".")
     for file in files
         if !endswith(file, ".jl")
@@ -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/previews/PR2288/developer/checklists/index.html b/previews/PR2288/developer/checklists/index.html index efa6d81fba..3ba60ed06c 100644 --- a/previews/PR2288/developer/checklists/index.html +++ b/previews/PR2288/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/previews/PR2288/index.html b/previews/PR2288/index.html index e029c532b5..10923bbe67 100644 --- a/previews/PR2288/index.html +++ b/previews/PR2288/index.html @@ -6,4 +6,4 @@ year={2021}, doi={10.1287/ijoc.2021.1067}, publisher={INFORMS} -} +} diff --git a/previews/PR2288/manual/constraints/index.html b/previews/PR2288/manual/constraints/index.html index b0ca823623..e16617d988 100644 --- a/previews/PR2288/manual/constraints/index.html +++ b/previews/PR2288/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/previews/PR2288/manual/models/index.html b/previews/PR2288/manual/models/index.html index 97b8697357..cf6c6d5425 100644 --- a/previews/PR2288/manual/models/index.html +++ b/previews/PR2288/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/previews/PR2288/manual/modification/index.html b/previews/PR2288/manual/modification/index.html index f255864dd0..f99786e236 100644 --- a/previews/PR2288/manual/modification/index.html +++ b/previews/PR2288/manual/modification/index.html @@ -122,4 +122,4 @@ ); julia> MOI.get(model, MOI.ConstraintFunction(), c) ≈ new_f -true +true diff --git a/previews/PR2288/manual/solutions/index.html b/previews/PR2288/manual/solutions/index.html index 4a335c3c68..a89ad62954 100644 --- a/previews/PR2288/manual/solutions/index.html +++ b/previews/PR2288/manual/solutions/index.html @@ -32,4 +32,4 @@ end rethrow(err) # Something else went wrong. Rethrow the error end -end +end diff --git a/previews/PR2288/manual/standard_form/index.html b/previews/PR2288/manual/standard_form/index.html index 7fb39ec10a..88d58be528 100644 --- a/previews/PR2288/manual/standard_form/index.html +++ b/previews/PR2288/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/previews/PR2288/manual/variables/index.html b/previews/PR2288/manual/variables/index.html index ddd6d48ee6..b6854cbfb4 100644 --- a/previews/PR2288/manual/variables/index.html +++ b/previews/PR2288/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/previews/PR2288/reference/callbacks/index.html b/previews/PR2288/reference/callbacks/index.html index c4943a1539..9f3c238f41 100644 --- a/previews/PR2288/reference/callbacks/index.html +++ b/previews/PR2288/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/previews/PR2288/reference/constraints/index.html b/previews/PR2288/reference/constraints/index.html index 2e08ba3793..a7c8fc67db 100644 --- a/previews/PR2288/reference/constraints/index.html +++ b/previews/PR2288/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
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
supports_constraint(
+)::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
+)::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/previews/PR2288/reference/errors/index.html b/previews/PR2288/reference/errors/index.html index a3c21a315f..5ec2214902 100644 --- a/previews/PR2288/reference/errors/index.html +++ b/previews/PR2288/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/previews/PR2288/reference/models/index.html b/previews/PR2288/reference/models/index.html index 4a5bc74f9f..f0ec4152e0 100644 --- a/previews/PR2288/reference/models/index.html +++ b/previews/PR2288/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/previews/PR2288/reference/modification/index.html b/previews/PR2288/reference/modification/index.html index fc55296ea6..28ea8840d0 100644 --- a/previews/PR2288/reference/modification/index.html +++ b/previews/PR2288/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/previews/PR2288/reference/nonlinear/index.html b/previews/PR2288/reference/nonlinear/index.html index c1283cf4f7..25c5931c19 100644 --- a/previews/PR2288/reference/nonlinear/index.html +++ b/previews/PR2288/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/previews/PR2288/reference/standard_form/index.html b/previews/PR2288/reference/standard_form/index.html index 43308d829c..769fc0884b 100644 --- a/previews/PR2288/reference/standard_form/index.html +++ b/previews/PR2288/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/previews/PR2288/reference/variables/index.html b/previews/PR2288/reference/variables/index.html index 274c00a843..99be2a79dc 100644 --- a/previews/PR2288/reference/variables/index.html +++ b/previews/PR2288/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/previews/PR2288/release_notes/index.html b/previews/PR2288/release_notes/index.html index 929c009d19..6e5a93ef8c 100644 --- a/previews/PR2288/release_notes/index.html +++ b/previews/PR2288/release_notes/index.html @@ -1,5 +1,5 @@ -Release notes · MathOptInterface

Release notes

The format is based on Keep a Changelog, and this project adheres to Semantic Versioning.

v1.20.1 (September 22, 2023)

Fixed

Other

  • Added MathOptSetDistances to solver-tests.yml (#2265)
  • Updated Documenter (#2266)
  • Fixed various JET errors (#2267) (#2269) (#2270) (#2271) (#2276) (#2277) (#2289)
  • Various style improvements
    • Replaced using Package with import Package where possible (#2274)
    • Removed Utilities.EMPTYSTRING (#2283)
    • Removed unnecessary const acronyms in Utilities (#2280) (#2281)
    • Removed invalid and unused method (#2286)

v1.20.0 (September 7, 2023)

Added

Other

v1.19.0 (August 15, 2023)

Added

Fixed

Other

  • Added extensions to solver-tests.yml (#2229)
  • Refactored test/Benchmarks (#2234)
  • Fixed warnings in tests (#2241) (#2243)
  • Small refactoring of bridges for upcoming VectorNonlinearFunction (#2244) (#2245)
  • Fixed various typos (#2251) (#2255)
  • Partitioned how we run the tests on GitHub actions (#2252) (#2253)

v1.18.0 (June 23, 2023)

Added

Fixed

  • Fixed a missing @require in MOI.Test (#2195) (#2196)
  • Fixed incorrect usage of Utilities.operate! in bridges (#2207) (#2216)
  • Fixed splatting nonlinear expression with univariate operator (#2221)

Other

  • Removed unused argument names (#2199)
  • Reduced memory requirement for tests (#2204)
  • Refactored Utilities.promote_operation (#2206)
  • Improved code style in Utilities/mutable_arithmetics.jl (#2209)
  • Refactored various methods in Utilities/functions.jl (#2208) (#2212) (#2213) (#2214) (#2215)

v1.17.1 (June 6, 2023)

Fixed

Other

  • Added documentation for enum instances (#2186)
  • Updated chatroom links in documentation (#2188)
  • Changed the documentation to build on Julia v1.9 (#2191)

v1.17.0 (June 1, 2023)

Added

Fixed

  • Fixed support for external sets in Utilities.loadfromstring! (#2177)
  • Fixed promote_operation for ScalarNonlinearFunction (#2179)
  • Fixed two issues in FileFormats.LP when reading files with quadratic functions (#2182) (#2184)

v1.16.0 (May 16, 2023)

Added

Fixed

Other

  • Fixed solver-tests.yml (#2157)
  • Updated documentation links to developer chatroom (#2160)
  • Added various tests for bridges (#2156)
  • Added checklists to the developer documentation (#2167) (#2168)

v1.15.1 (April 25, 2023)

Fixed

  • Fixed deleting a variable in a bridged objective (#2150)

v1.15.0 (April 19, 2023)

Added

Fixed

Other

  • Add a test for variables in one-sided open Interval sets (#2133)
  • Minor style fixes in the source code (#2148)

v1.14.1 (April 6, 2023)

Fixed

Other

v1.14.0 (April 4, 2023)

Added

Fixed

v1.13.2 (March 21, 2023)

Fixed

Other

  • Fixed typos in the documentation (#2114)
  • Functions 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)

v1.13.1 (March 3, 2023)

Other

  • Added the Google style guide to the documentation linter Vale, and fixed the resulting warnings (#2110)
  • Improved the docstrings in src/functions.jl (#2108)

v1.13.0 (February 28, 2023)

Added

Fixed

Other

  • Added tests for vector-valued objective functions in FileFormats.MOF (#2093)
  • Used and documented preference for import MathOptInterface as MOI (#2096)
  • Fix and test links in the documentation with linkcheck = true (#2098)
  • Improved docstrings of sets in src/sets.jl (#2099)
  • Skip checking flakey links in documentation with linkcheck_ignore (#2103)

v1.12.0 (February 10, 2023)

Added

Fixed

  • Fixed a number of constraint bridges so that Bridges.final_touch can be called multiple times without forcing a rebuild of the reformulation (#2089)

Other

v1.11.5 (January 24, 2023)

Fixed

  • Fixed a bug writing .lp files with an off-diagonal quadratic objective (#2082)

Other

  • Added SnoopPrecompile directives for reduced time-to-first-X in Julia v1.9 (#2080)

v1.11.4 (January 12, 2023)

Fixed

  • Fixed a bug reading .lp files with an Integer section (#2078)

v1.11.3 (January 12, 2023)

Fixed

  • Fixed a performance bug when deleting a vector of constraints (#2072)
  • Fixed a bug reading .lp files with terms like x -1 y (#2076)

Other

v1.11.2 (January 2, 2023)

Fixed

  • Fixed a bug reading .mof.json files with ConstraintName set for VariableIndex constraints (#2066)
  • Fixed a bug reading .mof.json files with nonlinear objectives and no constraints (#2068)

v1.11.1 (December 22, 2022)

Fixed

  • Fixed a bug reading .mof.json files with integer coefficients for affine and quadratic functions (#2063)

v1.11.0 (December 2, 2022)

Added

Other

  • Tidied these release notes (#2055)

v1.10.0 (November 22, 2022)

Added

Fixed

  • Fixed Bridges.Objective.SlackBridge when the objective function is complex-valued (#2036) (#2038)
  • Fixed docstring of Test.runtests to clarify the warn_unsupported argument (#2037)
  • Fixed reading of free variables in FileFormats.LP (#2044)
  • Fixed numerous edge cases reading files from QPLIB using FileFormats.LP (#2042) (#2044)
  • Fixed situations in which x^y returns a complex value in Nonlinear (#2050)

Other

  • Improved the error message thrown when a user-defined nonlinear function does not accept splatted input (#2032)
  • Removed specialized iterators for keys and values in Utilities.CleverDicts (#2051)

v1.9.0 (October 29, 2022)

Added

Fixed

  • Fixed Constraint.ZeroOneBridge by adding new bounds as affine constraints instead of variable bounds (#1879)
  • Fixed reading free rows in FileFormats.MPS files (#2009)
  • Fixed parsing of OBJSENSE blocks in FileFormats.MPS files (#2016) (#2019)
  • Fixed the parsing of deeply nested nonlinear expressions by removing the use of recursion (#2020)
  • Fixed the requirements check in Test.test_constrainnt_get_ConstraintIndex (#2024)

v1.8.2 (September 20, 2022)

Documentation

  • Added vale as a documentation linter (#2002)
  • Improved styling of code blocks in the PDF (#1999) (#2000)
  • Fixed a number of typos in the documentation (#2001) (#2003)

v1.8.1 (September 12, 2022)

Fixed

  • Fixed a bug in supports(::AbstractBridgeOptimizer for constraint attributes (#1991) (#1992)

v1.8.0 (September 1, 2022)

Added

Fixed

  • Lazily construct expressions in Nonlinear so that expressions are updated when Nonlinear.Parameter values are updated (#1984)
  • Allow NORM_LIMIT as a TerminationStatus for unbounded problems in Test (#1990)

v1.7.0 (August 16, 2022)

Added

Fixed

  • Fixed some missing promotion rules

Other

  • Improved the performance of Jacobian products in Nonlinear
  • Removed an un-needed copy in Utilities.modify_function
  • Various clean-ups in Bridges/bridge_optimizer.jl

v1.6.1 (July 23, 2022)

Fixed

  • Added support for ExponentialCone in MatrixOfConstraints
  • Fix PSDSquare_3 test to reflect a previously fixed bug getting the ConstraintDual of a PositiveSemidefiniteConeSquare constraint

v1.6.0 (July 2, 2022)

Added

  • Added Bridges.needs_final_touch and Bridges.final_touch
  • Added new bridges from constraint programming sets to mixed-integer linear programs:
    • AllDifferentToCountDistinctBridge
    • CountAtLeastToCountBelongsBridge
    • CountBelongsToMILPBridge
    • CountDistinctToMILPBridge
    • CountGreaterThanToMILPBridge
    • CircuitToMILPBridge

Fixed

  • Relax an instance of ::Vector to ::AbstractVector in MOI.Nonlinear
  • Fix BinPackingToMILPBridge to respect variable bounds
  • Fix SemiToBinaryBridge to throw error if other bounds are set

v1.5.0 (June 27, 2022)

Added

  • Added GetAttributeNotAllowed for solvers to indicate when getting an attribute encounters an error
  • Added Utilities.get_fallback support for ObjectiveValue and DualObjectiveValue
  • Added new bridges:
    • RootDetConeSquare to RootDetConeTriangle
    • LogDetConeSquare to LogDetConeTriangle
    • BinPacking to a mixed-integer linear program
    • Table to a mixed-integer linear program
  • Added Bridges.print_active_bridges to display the current optimal hyper-path in a Bridges.LazyBridgeOptimizer

Fixed

  • Fixed ZeroOne tests with lower and upper bounds
  • Fixed error in FileFormats.LP when reading a malformed file
  • Fixed reading of nonlinear programs in FileFormats.MOF
  • Fixed bug in ConstraintDual when using SquareBridge

Other

  • Improved documentation of nonlinear API
  • Documented duality convention for PositiveSemidefiniteConeSquare sets
  • Fixed typo in Bridges.Constraint.QuadToSOCBridge docstring

v1.4.0 (June 9, 2022)

Added

  • Added a number of sets for constraint programming:
    • AllDifferent
    • BinPacking
    • Circuit
    • CountAtLeast
    • CountBelongs
    • CountDistinct
    • CountGreaterThan
    • Cumulative
    • Path
    • Table
  • Added support for user-defined hessians in Nonlinear
  • Added Bridges.runtests to simplify the testing of bridge implementations

Fixed

  • Fixed a bug in FileFormats.NL when writing univariate *

Other

  • Began a large refactoring of the Bridges submodule, with greatly improved documentation.

v1.3.0 (May 27, 2022)

Added

  • 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.
  • Add FileFormats.NL.SolFileResults(::IO, ::Model)
  • Add FileFormats.NL.read!(::IO, ::Model)
  • Add MOI.modify that accepts a vector of modifications

Fixed

  • Fixed a bug in Test which attempted to include non-.jl files
  • Fixed a bug in FileFormats for models with open interval constraints

Other

  • Fixed a performance issue in Utilities.DoubleDict
  • Various minor improvements to the documentation

v1.2.0 (April 25, 2022)

Added

  • Add support for the FORMAT_REW/.rew file format in FileFormats.

Fixed

  • Fix bug handling of default variable bounds in FileFormats.LP
  • Fix FileFormats.MPS to not write OBJSENSE by default since this is only supported by some readers.

v1.1.2 (March 31, 2022)

Fixed

  • Fix a range of bugs in FileFormats.LP
  • Fix reading of problem dimensions in FileFormats.SDPA

v1.1.1 (March 23, 2022)

Fixed

  • Fix bug in test_model_UpperBoundAlreadySet
  • Fix bug in test_infeasible_ tests
  • Fix bug in test_objective_ObjectiveFunction_blank
  • Relax restriction of MOI.AbstractOptimizer to MOI.ModelLike in Utilities.CachingOptimizer and instantiate.

New tests

  • Add test_conic_empty_matrix that checks conic solvers support problems with no variables.

v1.1.0 (March 2, 2022)

Added

  • Added MOI.Utilities.throw_unsupported(::UniversalFallback) for simplifying solver wrappers which copy from a UniversalFallback.

v1.0.2 (March 1, 2022)

Fixed

  • Fixed a bug in the test_model_ScalarFunctionConstantNotZero test
  • Fixed the error type when an AbstractFunctionConversionBridge cannot get or set an attribute
  • Identified a correctness bug in RSOCtoPSDBridge. We now thrown an error instead of returning an incorrect result.

v1.0.1 (February 25, 2022)

Fixed

  • Fixed a bug in which OptimizerAttributes were not copied in CachingOptimizer
  • Fixed a bug in which shift_constant did not promote mixed types of coefficients
  • Fixed a bug in which deleting a constraint of a bridged variable threw ErrorException instead of MOI.DeleteNotAllowed
  • Fixed a bug in which add_constraint in MatrixOfConstraints did not canonicalize the function
  • Fixed a bug when modifying scalar constants of a function containing a bridged variable
  • Fixed a bug in which final_touch was not always called with a CachingOptimizer

v1.0.0 (February 17, 2022)

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.

Breaking

  • Julia 1.6 is now the minimum supported version
  • All deprecations have been removed

Troubleshooting problems when updating

If you experience problems when updating, you are likely using previously deprecated features. (By default, Julia does not warn when you use deprecated features.)

To find the deprecated features you are using, start Julia with --depwarn=yes:

$ julia --depwarn=yes

Then install MathOptInterface v0.10.9:

julia> using Pkg
+Release notes · MathOptInterface

Release notes

The format is based on Keep a Changelog, and this project adheres to Semantic Versioning.

v1.20.1 (September 22, 2023)

Fixed

Other

  • Added MathOptSetDistances to solver-tests.yml (#2265)
  • Updated Documenter (#2266)
  • Fixed various JET errors (#2267) (#2269) (#2270) (#2271) (#2276) (#2277) (#2289)
  • Various style improvements
    • Replaced using Package with import Package where possible (#2274)
    • Removed Utilities.EMPTYSTRING (#2283)
    • Removed unnecessary const acronyms in Utilities (#2280) (#2281)
    • Removed invalid and unused method (#2286)
  • Refactored src/Utilities/model.jl (#2287)

v1.20.0 (September 7, 2023)

Added

Other

v1.19.0 (August 15, 2023)

Added

Fixed

Other

  • Added extensions to solver-tests.yml (#2229)
  • Refactored test/Benchmarks (#2234)
  • Fixed warnings in tests (#2241) (#2243)
  • Small refactoring of bridges for upcoming VectorNonlinearFunction (#2244) (#2245)
  • Fixed various typos (#2251) (#2255)
  • Partitioned how we run the tests on GitHub actions (#2252) (#2253)

v1.18.0 (June 23, 2023)

Added

Fixed

  • Fixed a missing @require in MOI.Test (#2195) (#2196)
  • Fixed incorrect usage of Utilities.operate! in bridges (#2207) (#2216)
  • Fixed splatting nonlinear expression with univariate operator (#2221)

Other

  • Removed unused argument names (#2199)
  • Reduced memory requirement for tests (#2204)
  • Refactored Utilities.promote_operation (#2206)
  • Improved code style in Utilities/mutable_arithmetics.jl (#2209)
  • Refactored various methods in Utilities/functions.jl (#2208) (#2212) (#2213) (#2214) (#2215)

v1.17.1 (June 6, 2023)

Fixed

Other

  • Added documentation for enum instances (#2186)
  • Updated chatroom links in documentation (#2188)
  • Changed the documentation to build on Julia v1.9 (#2191)

v1.17.0 (June 1, 2023)

Added

Fixed

  • Fixed support for external sets in Utilities.loadfromstring! (#2177)
  • Fixed promote_operation for ScalarNonlinearFunction (#2179)
  • Fixed two issues in FileFormats.LP when reading files with quadratic functions (#2182) (#2184)

v1.16.0 (May 16, 2023)

Added

Fixed

Other

  • Fixed solver-tests.yml (#2157)
  • Updated documentation links to developer chatroom (#2160)
  • Added various tests for bridges (#2156)
  • Added checklists to the developer documentation (#2167) (#2168)

v1.15.1 (April 25, 2023)

Fixed

  • Fixed deleting a variable in a bridged objective (#2150)

v1.15.0 (April 19, 2023)

Added

Fixed

Other

  • Add a test for variables in one-sided open Interval sets (#2133)
  • Minor style fixes in the source code (#2148)

v1.14.1 (April 6, 2023)

Fixed

Other

v1.14.0 (April 4, 2023)

Added

Fixed

v1.13.2 (March 21, 2023)

Fixed

Other

  • Fixed typos in the documentation (#2114)
  • Functions 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)

v1.13.1 (March 3, 2023)

Other

  • Added the Google style guide to the documentation linter Vale, and fixed the resulting warnings (#2110)
  • Improved the docstrings in src/functions.jl (#2108)

v1.13.0 (February 28, 2023)

Added

Fixed

Other

  • Added tests for vector-valued objective functions in FileFormats.MOF (#2093)
  • Used and documented preference for import MathOptInterface as MOI (#2096)
  • Fix and test links in the documentation with linkcheck = true (#2098)
  • Improved docstrings of sets in src/sets.jl (#2099)
  • Skip checking flakey links in documentation with linkcheck_ignore (#2103)

v1.12.0 (February 10, 2023)

Added

Fixed

  • Fixed a number of constraint bridges so that Bridges.final_touch can be called multiple times without forcing a rebuild of the reformulation (#2089)

Other

v1.11.5 (January 24, 2023)

Fixed

  • Fixed a bug writing .lp files with an off-diagonal quadratic objective (#2082)

Other

  • Added SnoopPrecompile directives for reduced time-to-first-X in Julia v1.9 (#2080)

v1.11.4 (January 12, 2023)

Fixed

  • Fixed a bug reading .lp files with an Integer section (#2078)

v1.11.3 (January 12, 2023)

Fixed

  • Fixed a performance bug when deleting a vector of constraints (#2072)
  • Fixed a bug reading .lp files with terms like x -1 y (#2076)

Other

v1.11.2 (January 2, 2023)

Fixed

  • Fixed a bug reading .mof.json files with ConstraintName set for VariableIndex constraints (#2066)
  • Fixed a bug reading .mof.json files with nonlinear objectives and no constraints (#2068)

v1.11.1 (December 22, 2022)

Fixed

  • Fixed a bug reading .mof.json files with integer coefficients for affine and quadratic functions (#2063)

v1.11.0 (December 2, 2022)

Added

Other

  • Tidied these release notes (#2055)

v1.10.0 (November 22, 2022)

Added

Fixed

  • Fixed Bridges.Objective.SlackBridge when the objective function is complex-valued (#2036) (#2038)
  • Fixed docstring of Test.runtests to clarify the warn_unsupported argument (#2037)
  • Fixed reading of free variables in FileFormats.LP (#2044)
  • Fixed numerous edge cases reading files from QPLIB using FileFormats.LP (#2042) (#2044)
  • Fixed situations in which x^y returns a complex value in Nonlinear (#2050)

Other

  • Improved the error message thrown when a user-defined nonlinear function does not accept splatted input (#2032)
  • Removed specialized iterators for keys and values in Utilities.CleverDicts (#2051)

v1.9.0 (October 29, 2022)

Added

Fixed

  • Fixed Constraint.ZeroOneBridge by adding new bounds as affine constraints instead of variable bounds (#1879)
  • Fixed reading free rows in FileFormats.MPS files (#2009)
  • Fixed parsing of OBJSENSE blocks in FileFormats.MPS files (#2016) (#2019)
  • Fixed the parsing of deeply nested nonlinear expressions by removing the use of recursion (#2020)
  • Fixed the requirements check in Test.test_constrainnt_get_ConstraintIndex (#2024)

v1.8.2 (September 20, 2022)

Documentation

  • Added vale as a documentation linter (#2002)
  • Improved styling of code blocks in the PDF (#1999) (#2000)
  • Fixed a number of typos in the documentation (#2001) (#2003)

v1.8.1 (September 12, 2022)

Fixed

  • Fixed a bug in supports(::AbstractBridgeOptimizer for constraint attributes (#1991) (#1992)

v1.8.0 (September 1, 2022)

Added

Fixed

  • Lazily construct expressions in Nonlinear so that expressions are updated when Nonlinear.Parameter values are updated (#1984)
  • Allow NORM_LIMIT as a TerminationStatus for unbounded problems in Test (#1990)

v1.7.0 (August 16, 2022)

Added

Fixed

  • Fixed some missing promotion rules

Other

  • Improved the performance of Jacobian products in Nonlinear
  • Removed an un-needed copy in Utilities.modify_function
  • Various clean-ups in Bridges/bridge_optimizer.jl

v1.6.1 (July 23, 2022)

Fixed

  • Added support for ExponentialCone in MatrixOfConstraints
  • Fix PSDSquare_3 test to reflect a previously fixed bug getting the ConstraintDual of a PositiveSemidefiniteConeSquare constraint

v1.6.0 (July 2, 2022)

Added

  • Added Bridges.needs_final_touch and Bridges.final_touch
  • Added new bridges from constraint programming sets to mixed-integer linear programs:
    • AllDifferentToCountDistinctBridge
    • CountAtLeastToCountBelongsBridge
    • CountBelongsToMILPBridge
    • CountDistinctToMILPBridge
    • CountGreaterThanToMILPBridge
    • CircuitToMILPBridge

Fixed

  • Relax an instance of ::Vector to ::AbstractVector in MOI.Nonlinear
  • Fix BinPackingToMILPBridge to respect variable bounds
  • Fix SemiToBinaryBridge to throw error if other bounds are set

v1.5.0 (June 27, 2022)

Added

  • Added GetAttributeNotAllowed for solvers to indicate when getting an attribute encounters an error
  • Added Utilities.get_fallback support for ObjectiveValue and DualObjectiveValue
  • Added new bridges:
    • RootDetConeSquare to RootDetConeTriangle
    • LogDetConeSquare to LogDetConeTriangle
    • BinPacking to a mixed-integer linear program
    • Table to a mixed-integer linear program
  • Added Bridges.print_active_bridges to display the current optimal hyper-path in a Bridges.LazyBridgeOptimizer

Fixed

  • Fixed ZeroOne tests with lower and upper bounds
  • Fixed error in FileFormats.LP when reading a malformed file
  • Fixed reading of nonlinear programs in FileFormats.MOF
  • Fixed bug in ConstraintDual when using SquareBridge

Other

  • Improved documentation of nonlinear API
  • Documented duality convention for PositiveSemidefiniteConeSquare sets
  • Fixed typo in Bridges.Constraint.QuadToSOCBridge docstring

v1.4.0 (June 9, 2022)

Added

  • Added a number of sets for constraint programming:
    • AllDifferent
    • BinPacking
    • Circuit
    • CountAtLeast
    • CountBelongs
    • CountDistinct
    • CountGreaterThan
    • Cumulative
    • Path
    • Table
  • Added support for user-defined hessians in Nonlinear
  • Added Bridges.runtests to simplify the testing of bridge implementations

Fixed

  • Fixed a bug in FileFormats.NL when writing univariate *

Other

  • Began a large refactoring of the Bridges submodule, with greatly improved documentation.

v1.3.0 (May 27, 2022)

Added

  • 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.
  • Add FileFormats.NL.SolFileResults(::IO, ::Model)
  • Add FileFormats.NL.read!(::IO, ::Model)
  • Add MOI.modify that accepts a vector of modifications

Fixed

  • Fixed a bug in Test which attempted to include non-.jl files
  • Fixed a bug in FileFormats for models with open interval constraints

Other

  • Fixed a performance issue in Utilities.DoubleDict
  • Various minor improvements to the documentation

v1.2.0 (April 25, 2022)

Added

  • Add support for the FORMAT_REW/.rew file format in FileFormats.

Fixed

  • Fix bug handling of default variable bounds in FileFormats.LP
  • Fix FileFormats.MPS to not write OBJSENSE by default since this is only supported by some readers.

v1.1.2 (March 31, 2022)

Fixed

  • Fix a range of bugs in FileFormats.LP
  • Fix reading of problem dimensions in FileFormats.SDPA

v1.1.1 (March 23, 2022)

Fixed

  • Fix bug in test_model_UpperBoundAlreadySet
  • Fix bug in test_infeasible_ tests
  • Fix bug in test_objective_ObjectiveFunction_blank
  • Relax restriction of MOI.AbstractOptimizer to MOI.ModelLike in Utilities.CachingOptimizer and instantiate.

New tests

  • Add test_conic_empty_matrix that checks conic solvers support problems with no variables.

v1.1.0 (March 2, 2022)

Added

  • Added MOI.Utilities.throw_unsupported(::UniversalFallback) for simplifying solver wrappers which copy from a UniversalFallback.

v1.0.2 (March 1, 2022)

Fixed

  • Fixed a bug in the test_model_ScalarFunctionConstantNotZero test
  • Fixed the error type when an AbstractFunctionConversionBridge cannot get or set an attribute
  • Identified a correctness bug in RSOCtoPSDBridge. We now thrown an error instead of returning an incorrect result.

v1.0.1 (February 25, 2022)

Fixed

  • Fixed a bug in which OptimizerAttributes were not copied in CachingOptimizer
  • Fixed a bug in which shift_constant did not promote mixed types of coefficients
  • Fixed a bug in which deleting a constraint of a bridged variable threw ErrorException instead of MOI.DeleteNotAllowed
  • Fixed a bug in which add_constraint in MatrixOfConstraints did not canonicalize the function
  • Fixed a bug when modifying scalar constants of a function containing a bridged variable
  • Fixed a bug in which final_touch was not always called with a CachingOptimizer

v1.0.0 (February 17, 2022)

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.

Breaking

  • Julia 1.6 is now the minimum supported version
  • All deprecations have been removed

Troubleshooting problems when updating

If you experience problems when updating, you are likely using previously deprecated features. (By default, Julia does not warn when you use deprecated features.)

To find the deprecated features you are using, start Julia with --depwarn=yes:

$ julia --depwarn=yes

Then install MathOptInterface v0.10.9:

julia> using Pkg
 julia> pkg"add MathOptInterface@0.10"

And then run your code. Apply any suggestions, or search the release notes below for advice on updating a specific deprecated feature.

v0.10.9 (February 16, 2022)

Added

  • Added MOI.Utilities.FreeVariables as a new VariablesConstrainer for conic solvers
  • Added MOI.default_cache for specifying the model used in CachingOptimizer

Fixed

  • Fixed LaTeX printing of MOI.Interval sets

Other

  • Added Aqua.jl as a CI check, and fixed suggested issues
  • The 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.

v0.10.8 (February 3, 2022)

Added

  • Added a Base.read! for FileFormats.LP.

Fixed

  • Fixed a bug in MutableSparseMatrix
  • Fixed a bug when calling operate!(vcat, ...) with Number arguments
  • Removed unintended export of deprecated symbols
  • Fixed a bug with PowerCone and DualPowerCone in MatrixOfConstraints.

v0.10.7 (January 5, 2022)

Added

  • Added test for modifying the constant vector in a VectorAffineFunction-in-Zeros constraint.

Fixed

  • 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.
  • Fixed an error message in FileFormats.CBF
  • Fixed comparison in test_linear_integration_Interval
  • Fixed errors for ConstraintPrimal in a CachingOptimizer
  • Fixed printing of models with non-Float64 coefficients.

Other

  • Various improvements to reduce time-to-first-solve latency
  • Improved error message when an optimizer does not support compute_conflict!

v0.10.6 (November 30, 2021)

Added

  • Added new documentation and tests for infeasibility certificates
  • Added 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.
  • MOI.Test.runtests now supports generic number types. To specify the number type T, pass MOI.Test.Config(T).
  • Added infeasible_status to MOI.Test.Config for solvers which return LOCALLY_INFEASIBLE
  • CachingOptimizers now use a fallback for ConstraintPrimal. This should enable solvers using a CachingOptimizer to pass tests requiring ConstraintPrimal.

Fixed

  • Fixed a StackOverflow bug in copy_to
  • Fixed error thrown when nonconvex quadratic constraints cannot be bridged
  • Fixed a bug in copy_to for FileFormats.NL.Model
  • Fixed a bug in FileFormats.NL when printing large integers
  • Remove a common test failure for LowerBoundAlreadySet tests
  • Utilities.num_rows is now exported
  • Remove parts of failing test_model_copy_to_xxx tests due to bridges

v0.10.5 (November 7, 2021)

Fixed

  • Fixed getter in UniversalFallback
  • Fixed test_solve_conflict_zeroone_ii

Other

  • Make normalize_and_add_constraint more flexible
  • Update paper BibTeX

v0.10.4 (October 26, 2021)

Added

  • Add SolverVersion attribute
  • Add new tests:
    • test_solve_conflict_zeroone_ii
    • test_nonlinear_objective
  • Utilities.VariablesContainer now supports ConstraintFunction and ConstraintSet
  • The documentation is now available as a PDF

Other

  • Update to MutableArithmetics 0.3
  • Various improvements to the documentation

v0.10.3 (September 18, 2021)

Fixed

  • Fixed bug which prevented callbacks from working through a CachingOptimizer
  • Fixed bug in Test submodule

v0.10.2 (September 16, 2021)

  • Updated MathOptFormat to v1.0
  • Updated JSONSchema to v1.0
  • Added Utilities.set_with_dimension
  • Added two-argument optimize!(::AbstractOptimizer, ::ModelLike)
  • The experimental feature copy_to_and_optimize! has been removed
  • Det bridges now support getting ConstraintFunction and ConstraintSet
  • Various minor bug fixes identified by improved testing

v0.10.1 (September 8, 2021)

  • Various fixes to MOI.Test

v0.10.0 (September 6, 2021)

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.

Breaking in MOI

  • SingleVariable has been removed; use VariableIndex instead
  • SingleVariableConstraintNameError has been renamed to VariableIndexConstraintNameError
  • SettingSingleVariableFunctionNotAllowed has been renamed to SettingVariableIndexFunctionNotAllowed
  • VariableIndex constraints should not support ConstraintName
  • VariableIndex constraints should not support ConstraintBasisStatus; implement VariableBasisStatus instead
  • ListOfConstraints has been renamed to ListOfConstraintTypesPresent
  • ListOfConstraintTypesPresent should now return Tuple{Type,Type} instead of Tuple{DataType,DataType}
  • SolveTime has been renamed to SolveTimeSec
  • IndicatorSet has been renamed to Indicator
  • RawParameter has been renamed to RawOptimizerAttribute and now takes String instead of Any as the only argument
  • The .N field in result attributes has been renamed to .result_index
  • The .variable_index field in ScalarAffineTerm has been renamed to .variable
  • The .variable_index_1 field in ScalarQuadraticTerm has been renamed to .variable_1
  • The .variable_index_2 field in ScalarQuadraticTerm has been renamed to .variable_2
  • The 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.
  • The index_value function has been removed. Use .value instead.
  • isapprox has been removed for SOS1 and SOS2.
  • The 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.
  • copy_to no longer takes keyword arguments:
    • copy_names: now copy names if they are supported by the destination solver
    • filter_constraints: use Utilities.ModelFilter instead
    • warn_attributes: never warn about optimizer attributes

Breaking in Bridges

  • Constraint.RSOCBridge has been renamed to Constraint.RSOCtoSOCBridge
  • Constraint.SOCRBridge has been renamed to Constraint.SOCtoRSOCBridge
  • Bridges now return vectors that can be modified by the user. Previously, some bridges returned views instead of copies.
  • Bridges.IndexInVector has been unified into a single type. Previously, there was a different type for each submodule within Bridges
  • The signature of indicator bridges has been fixed. Use MOI.Bridges.Constraint.IndicatortoSOS1{Float64}(model).

Breaking in FileFormats

  • FileFormats.MOF.Model no longer accepts validate argument. Use the JSONSchema package to validate the MOF file. See the documentation for more information.

Breaking in Utilities

  • 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.
  • Utilities.supports_default_copy has been renamed to supports_incremental_interface
  • Utilities.automatic_copy_to has been renamed to Utilities.default_copy_to
  • The allocate-load API has been removed
  • CachingOptimizers 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.
  • The 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.
  • The size argument to Utilities.CleverDicts.CleverDict(::Integer) has been removed.
  • The size argument to Utilities.IndexMap(::Integer) has been removed.
  • Utilities.DoubleDicts have been significantly refactored. Consult the source code for details.
  • Utilities.test_models_equal has been moved to MOI.Test

Breaking in Test

  • MOI.Test has been renamed to MOI.DeprecatedTest
  • An 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.

Other changes:

  • attribute_value_type has been added
  • copy_to_and_optimize! has been added
  • VariableBasisStatus has been added
  • print(model) now prints a human-readable description of the model
  • Various improvements to the FileFormats submodule
    • FileFormats.CBF was refactored and received bugfixes
    • Support for MathOptFormat v0.6 was added in FileFormats.MOF
    • FileFormats.MPS has had bugfixes and support for more features such as OBJSENSE and objective constants.
    • FileFormats.NL has been added to support nonlinear files
  • Improved type inference throughout to reduce latency

Updating

A helpful script when updating is:

for (root, dirs, files) in walkdir(".")
     for file in files
         if !endswith(file, ".jl")
@@ -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/previews/PR2288/search_index.js b/previews/PR2288/search_index.js index 7a861b8e69..af17d654a5 100644 --- a/previews/PR2288/search_index.js +++ b/previews/PR2288/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":"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.1-(September-22,-2023)","page":"Release notes","title":"v1.20.1 (September 22, 2023)","text":"","category":"section"},{"location":"changelog/#Fixed","page":"Release notes","title":"Fixed","text":"","category":"section"},{"location":"changelog/","page":"Release notes","title":"Release notes","text":"Removed incorrect kwargs in some copy_to methods (#2272)\nFixed ConstraintDualStart for Bridges.Constraint.SplitIntervalBridge (#2275)\nFixed MethodError when trying to modify a variable objective (#2278)\nFixed stack-overflow in Utilities.operate(+,...) with many arguments (#2285)","category":"page"},{"location":"changelog/#Other","page":"Release notes","title":"Other","text":"","category":"section"},{"location":"changelog/","page":"Release notes","title":"Release notes","text":"Added MathOptSetDistances to solver-tests.yml (#2265)\nUpdated Documenter (#2266)\nFixed various JET errors (#2267) (#2269) (#2270) (#2271) (#2276) (#2277) (#2289)\nVarious style improvements\nReplaced using Package with import Package where possible (#2274)\nRemoved Utilities.EMPTYSTRING (#2283)\nRemoved unnecessary const acronyms in Utilities (#2280) (#2281)\nRemoved invalid and unused method (#2286)","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-2","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-2","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-3","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-3","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-4","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-4","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-5","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-5","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-6","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-6","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-7","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-8","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-7","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-9","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-8","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-10","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-11","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-9","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-10","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-12","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-11","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-13","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-12","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-14","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-13","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-15","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-16","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-14","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-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 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-18","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-15","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-19","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-16","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-20","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-21","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-22","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-23","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-17","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-24","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-25","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-26","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-18","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-27","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-19","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-28","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-20","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-29","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-30","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-31","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-32","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-33","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-34","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-21","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-35","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-36","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-22","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-37","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-38","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-23","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-24","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-39","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.1](https://github.com/jump-dev/MathOptInterface.jl/releases/tag/v1.20.1)-(September-22,-2023)","page":"Release notes","title":"v1.20.1 (September 22, 2023)","text":"","category":"section"},{"location":"release_notes/#Fixed","page":"Release notes","title":"Fixed","text":"","category":"section"},{"location":"release_notes/","page":"Release notes","title":"Release notes","text":"Removed incorrect kwargs in some copy_to methods (#2272)\nFixed ConstraintDualStart for Bridges.Constraint.SplitIntervalBridge (#2275)\nFixed MethodError when trying to modify a variable objective (#2278)\nFixed stack-overflow in Utilities.operate(+,...) with many arguments (#2285)","category":"page"},{"location":"release_notes/#Other","page":"Release notes","title":"Other","text":"","category":"section"},{"location":"release_notes/","page":"Release notes","title":"Release notes","text":"Added MathOptSetDistances to solver-tests.yml (#2265)\nUpdated Documenter (#2266)\nFixed various JET errors (#2267) (#2269) (#2270) (#2271) (#2276) (#2277) (#2289)\nVarious style improvements\nReplaced using Package with import Package where possible (#2274)\nRemoved Utilities.EMPTYSTRING (#2283)\nRemoved unnecessary const acronyms in Utilities (#2280) (#2281)\nRemoved invalid and unused method (#2286)","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-2","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-2","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-3","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-3","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-4","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-4","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-5","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-5","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-6","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-6","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-7","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-8","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-7","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-9","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-8","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-10","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-11","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-9","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-10","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-12","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-11","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-13","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-12","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-14","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-13","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-15","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-16","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-14","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-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 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-18","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-15","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-19","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-16","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-20","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-21","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-22","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-23","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-17","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-24","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-25","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-26","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-18","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-27","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-19","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-28","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-20","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-29","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-30","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-31","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-32","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-33","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-34","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-21","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-35","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-36","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-22","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-37","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-38","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-23","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-24","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-39","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":"MOI.Utilities.Model{T}() where {T}\n\nAn implementation of ModelLike that supports all functions and sets defined in MOI. It is parameterized by the coefficient type.\n\nExamples\n\njulia> import MathOptInterface as MOI\n\njulia> model = MOI.Utilities.Model{Float64}()\nMOIU.Model{Float64}\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 supporting all combinations of the provided functions and sets.\n\nEach typed_ scalar/vector sets/functions argument is a tuple of types. A type is \"typed\" if it has a coefficient {T} as the first type parameter.\n\nTuple syntax\n\nTo give no set/function, write (). To give one set or function X, write (X,).\n\nis_optimizer\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\nVariableIndex\n\nThe function MOI.VariableIndex must not be given in scalar_functions.\nThe 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.\nThe sets supported with MOI.VariableIndex cannot be controlled from the macro; use UniversalFallback to support more sets.\n\nExamples\n\nThe model describing a linear program would be:\n\n@model(\n LPModel, # model_name\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, # is_optimizer\n)\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 take place via the MOI interface, so the types O, V, and C must 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 take place via the MOI interface, so the types O, V, and C must 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(\n f::MOI.AbstractFunction,\n s::MOI.AbstractSet,\n vi::MOI.VariableIndex,\n)\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.1-(September-22,-2023)","page":"Release notes","title":"v1.20.1 (September 22, 2023)","text":"","category":"section"},{"location":"changelog/#Fixed","page":"Release notes","title":"Fixed","text":"","category":"section"},{"location":"changelog/","page":"Release notes","title":"Release notes","text":"Removed incorrect kwargs in some copy_to methods (#2272)\nFixed ConstraintDualStart for Bridges.Constraint.SplitIntervalBridge (#2275)\nFixed MethodError when trying to modify a variable objective (#2278)\nFixed stack-overflow in Utilities.operate(+,...) with many arguments (#2285)","category":"page"},{"location":"changelog/#Other","page":"Release notes","title":"Other","text":"","category":"section"},{"location":"changelog/","page":"Release notes","title":"Release notes","text":"Added MathOptSetDistances to solver-tests.yml (#2265)\nUpdated Documenter (#2266)\nFixed various JET errors (#2267) (#2269) (#2270) (#2271) (#2276) (#2277) (#2289)\nVarious style improvements\nReplaced using Package with import Package where possible (#2274)\nRemoved Utilities.EMPTYSTRING (#2283)\nRemoved unnecessary const acronyms in Utilities (#2280) (#2281)\nRemoved invalid and unused method (#2286)\nRefactored src/Utilities/model.jl (#2287)","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-2","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-2","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-3","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-3","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-4","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-4","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-5","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-5","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-6","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-6","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-7","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-8","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-7","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-9","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-8","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-10","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-11","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-9","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-10","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-12","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-11","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-13","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-12","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-14","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-13","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-15","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-16","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-14","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-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 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-18","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-15","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-19","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-16","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-20","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-21","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-22","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-23","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-17","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-24","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-25","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-26","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-18","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-27","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-19","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-28","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-20","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-29","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-30","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-31","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-32","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-33","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-34","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-21","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-35","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-36","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-22","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-37","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-38","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-23","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-24","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-39","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.1](https://github.com/jump-dev/MathOptInterface.jl/releases/tag/v1.20.1)-(September-22,-2023)","page":"Release notes","title":"v1.20.1 (September 22, 2023)","text":"","category":"section"},{"location":"release_notes/#Fixed","page":"Release notes","title":"Fixed","text":"","category":"section"},{"location":"release_notes/","page":"Release notes","title":"Release notes","text":"Removed incorrect kwargs in some copy_to methods (#2272)\nFixed ConstraintDualStart for Bridges.Constraint.SplitIntervalBridge (#2275)\nFixed MethodError when trying to modify a variable objective (#2278)\nFixed stack-overflow in Utilities.operate(+,...) with many arguments (#2285)","category":"page"},{"location":"release_notes/#Other","page":"Release notes","title":"Other","text":"","category":"section"},{"location":"release_notes/","page":"Release notes","title":"Release notes","text":"Added MathOptSetDistances to solver-tests.yml (#2265)\nUpdated Documenter (#2266)\nFixed various JET errors (#2267) (#2269) (#2270) (#2271) (#2276) (#2277) (#2289)\nVarious style improvements\nReplaced using Package with import Package where possible (#2274)\nRemoved Utilities.EMPTYSTRING (#2283)\nRemoved unnecessary const acronyms in Utilities (#2280) (#2281)\nRemoved invalid and unused method (#2286)\nRefactored src/Utilities/model.jl (#2287)","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-2","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-2","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-3","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-3","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-4","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-4","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-5","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-5","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-6","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-6","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-7","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-8","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-7","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-9","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-8","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-10","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-11","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-9","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-10","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-12","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-11","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-13","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-12","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-14","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-13","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-15","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-16","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-14","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-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 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-18","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-15","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-19","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-16","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-20","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-21","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-22","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-23","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-17","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-24","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-25","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-26","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-18","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-27","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-19","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-28","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-20","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-29","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-30","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-31","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-32","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-33","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-34","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-21","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-35","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-36","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-22","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-37","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-38","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-23","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-24","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-39","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/previews/PR2288/submodules/Benchmarks/overview/index.html b/previews/PR2288/submodules/Benchmarks/overview/index.html index f3011bb6df..838dcbf816 100644 --- a/previews/PR2288/submodules/Benchmarks/overview/index.html +++ b/previews/PR2288/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/previews/PR2288/submodules/Benchmarks/reference/index.html b/previews/PR2288/submodules/Benchmarks/reference/index.html index 24dc945766..a217d52c56 100644 --- a/previews/PR2288/submodules/Benchmarks/reference/index.html +++ b/previews/PR2288/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/previews/PR2288/submodules/Bridges/list_of_bridges/index.html b/previews/PR2288/submodules/Bridges/list_of_bridges/index.html index 6672178455..077021c187 100644 --- a/previews/PR2288/submodules/Bridges/list_of_bridges/index.html +++ b/previews/PR2288/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/previews/PR2288/submodules/Bridges/overview/index.html b/previews/PR2288/submodules/Bridges/overview/index.html index adea7dcb88..3c8391384f 100644 --- a/previews/PR2288/submodules/Bridges/overview/index.html +++ b/previews/PR2288/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/previews/PR2288/submodules/Bridges/reference/index.html b/previews/PR2288/submodules/Bridges/reference/index.html index 9d64f66fca..ffc61ccb08 100644 --- a/previews/PR2288/submodules/Bridges/reference/index.html +++ b/previews/PR2288/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/previews/PR2288/submodules/FileFormats/overview/index.html b/previews/PR2288/submodules/FileFormats/overview/index.html index 5b5ec403d7..7a7f1c2973 100644 --- a/previews/PR2288/submodules/FileFormats/overview/index.html +++ b/previews/PR2288/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/previews/PR2288/submodules/FileFormats/reference/index.html b/previews/PR2288/submodules/FileFormats/reference/index.html index 48ac95a4fa..c8e4c44597 100644 --- a/previews/PR2288/submodules/FileFormats/reference/index.html +++ b/previews/PR2288/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/previews/PR2288/submodules/Nonlinear/overview/index.html b/previews/PR2288/submodules/Nonlinear/overview/index.html index fdce5472ef..f8068eb478 100644 --- a/previews/PR2288/submodules/Nonlinear/overview/index.html +++ b/previews/PR2288/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/previews/PR2288/submodules/Nonlinear/reference/index.html b/previews/PR2288/submodules/Nonlinear/reference/index.html index c41694622a..9f864a6db1 100644 --- a/previews/PR2288/submodules/Nonlinear/reference/index.html +++ b/previews/PR2288/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/previews/PR2288/submodules/Test/overview/index.html b/previews/PR2288/submodules/Test/overview/index.html index 395da2e18e..e3a278e740 100644 --- a/previews/PR2288/submodules/Test/overview/index.html +++ b/previews/PR2288/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/previews/PR2288/submodules/Test/reference/index.html b/previews/PR2288/submodules/Test/reference/index.html index 8a8f0444c1..3e6ad82aba 100644 --- a/previews/PR2288/submodules/Test/reference/index.html +++ b/previews/PR2288/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/previews/PR2288/submodules/Utilities/overview/index.html b/previews/PR2288/submodules/Utilities/overview/index.html index e285a3eda0..b40b42bab6 100644 --- a/previews/PR2288/submodules/Utilities/overview/index.html +++ b/previews/PR2288/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/previews/PR2288/submodules/Utilities/reference/index.html b/previews/PR2288/submodules/Utilities/reference/index.html index 53aad948d3..4870b2dd2a 100644 --- a/previews/PR2288/submodules/Utilities/reference/index.html +++ b/previews/PR2288/submodules/Utilities/reference/index.html @@ -1,6 +1,8 @@ -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

MathOptInterface.Utilities.@modelMacro
macro model(
+API Reference · MathOptInterface

Utilities.Model

MathOptInterface.Utilities.ModelType
MOI.Utilities.Model{T}() where {T}

An implementation of ModelLike that supports all functions and sets defined in MOI. It is parameterized by the coefficient type.

Examples

julia> import MathOptInterface as MOI
+
+julia> model = MOI.Utilities.Model{Float64}()
+MOIU.Model{Float64}
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

MathOptInterface.Utilities.@modelMacro
macro model(
     model_name,
     scalar_sets,
     typed_scalar_sets,
@@ -11,53 +13,22 @@
     vector_functions,
     typed_vector_functions,
     is_optimizer = false
-)

Creates 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,).

The 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.

This 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.

If is_optimizer = true, the resulting struct is a of GenericOptimizer, which is a subtype of MOI.AbstractOptimizer, otherwise, it is a GenericModel, which is a subtype of MOI.ModelLike.

Examples

The model describing an linear program would be:

@model(LPModel,                                                   # Name of model
-      (),                                                         # untyped scalar sets
-      (MOI.EqualTo, MOI.GreaterThan, MOI.LessThan, MOI.Interval), #   typed scalar sets
-      (MOI.Zeros, MOI.Nonnegatives, MOI.Nonpositives),            # untyped vector sets
-      (),                                                         #   typed vector sets
-      (),                                                         # untyped scalar functions
-      (MOI.ScalarAffineFunction,),                                #   typed scalar functions
-      (MOI.VectorOfVariables,),                                   # untyped vector functions
-      (MOI.VectorAffineFunction,),                                #   typed vector functions
-      false
-    )

Let MOI denote MathOptInterface, MOIU denote MOI.Utilities. The macro would create the following types with struct_of_constraint_code:

struct LPModelScalarConstraints{T, C1, C2, C3, C4} <: MOIU.StructOfConstraints
-    moi_equalto::C1
-    moi_greaterthan::C2
-    moi_lessthan::C3
-    moi_interval::C4
-end
-struct LPModelVectorConstraints{T, C1, C2, C3} <: MOIU.StructOfConstraints
-    moi_zeros::C1
-    moi_nonnegatives::C2
-    moi_nonpositives::C3
-end
-struct LPModelFunctionConstraints{T} <: MOIU.StructOfConstraints
-    moi_scalaraffinefunction::LPModelScalarConstraints{
-        T,
-        MOIU.VectorOfConstraints{MOI.ScalarAffineFunction{T}, MOI.EqualTo{T}},
-        MOIU.VectorOfConstraints{MOI.ScalarAffineFunction{T}, MOI.GreaterThan{T}},
-        MOIU.VectorOfConstraints{MOI.ScalarAffineFunction{T}, MOI.LessThan{T}},
-        MOIU.VectorOfConstraints{MOI.ScalarAffineFunction{T}, MOI.Interval{T}}
-    }
-    moi_vectorofvariables::LPModelVectorConstraints{
-        T,
-        MOIU.VectorOfConstraints{MOI.VectorOfVariables, MOI.Zeros},
-        MOIU.VectorOfConstraints{MOI.VectorOfVariables, MOI.Nonnegatives},
-        MOIU.VectorOfConstraints{MOI.VectorOfVariables, MOI.Nonpositives}
-    }
-    moi_vectoraffinefunction::LPModelVectorConstraints{
-        T,
-        MOIU.VectorOfConstraints{MOI.VectorAffineFunction{T}, MOI.Zeros},
-        MOIU.VectorOfConstraints{MOI.VectorAffineFunction{T}, MOI.Nonnegatives},
-        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
+)

Creates a type model_name implementing the MOI model interface and supporting all combinations of the provided functions and sets.

Each typed_ scalar/vector sets/functions argument is a tuple of types. A type is "typed" if it has a coefficient {T} as the first type parameter.

Tuple syntax

To give no set/function, write (). To give one set or function X, write (X,).

is_optimizer

If is_optimizer = true, the resulting struct is a of GenericOptimizer, which is a subtype of MOI.AbstractOptimizer, otherwise, it is a GenericModel, which is a subtype of MOI.ModelLike.

VariableIndex

Examples

The model describing a linear program would be:

@model(
+    LPModel,                                          # model_name
+    (),                                               # untyped scalar sets
+    (MOI.EqualTo, MOI.GreaterThan, MOI.LessThan, MOI.Interval), #   typed scalar sets
+    (MOI.Zeros, MOI.Nonnegatives, MOI.Nonpositives),  # untyped vector sets
+    (),                                               #   typed vector sets
+    (),                                               # untyped scalar functions
+    (MOI.ScalarAffineFunction,),                      #   typed scalar functions
+    (MOI.VectorOfVariables,),                         # untyped vector functions
+    (MOI.VectorAffineFunction,),                      #   typed vector functions
+    false,                                            # is_optimizer
+)
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 take place via the MOI interface, so the types O, V, and C must 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 take place via the MOI interface, so the types O, V, and C must 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 +73,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 +83,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 +96,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 +141,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 +162,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 +181,65 @@
     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 +249,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 +261,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/previews/PR2288/tutorials/bridging_constraint/index.html b/previews/PR2288/tutorials/bridging_constraint/index.html index 1a70d83d84..023b65c96d 100644 --- a/previews/PR2288/tutorials/bridging_constraint/index.html +++ b/previews/PR2288/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/previews/PR2288/tutorials/example/index.html b/previews/PR2288/tutorials/example/index.html index 186a08dfcc..6faa6efd66 100644 --- a/previews/PR2288/tutorials/example/index.html +++ b/previews/PR2288/tutorials/example/index.html @@ -42,4 +42,4 @@ 3-element Vector{Float64}: 1.0 1.0 - 1.0 + 1.0 diff --git a/previews/PR2288/tutorials/implementing/index.html b/previews/PR2288/tutorials/implementing/index.html index 3ae153a058..0e36fbd84d 100644 --- a/previews/PR2288/tutorials/implementing/index.html +++ b/previews/PR2288/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/previews/PR2288/tutorials/latency/index.html b/previews/PR2288/tutorials/latency/index.html index 85d51b3048..ae3939023f 100644 --- a/previews/PR2288/tutorials/latency/index.html +++ b/previews/PR2288/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/previews/PR2288/tutorials/manipulating_expressions/index.html b/previews/PR2288/tutorials/manipulating_expressions/index.html index fdfa0ea550..37ed3851b5 100644 --- a/previews/PR2288/tutorials/manipulating_expressions/index.html +++ b/previews/PR2288/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/previews/PR2288/tutorials/mathprogbase/index.html b/previews/PR2288/tutorials/mathprogbase/index.html index 7b5739a0c0..cd974fe61b 100644 --- a/previews/PR2288/tutorials/mathprogbase/index.html +++ b/previews/PR2288/tutorials/mathprogbase/index.html @@ -51,4 +51,4 @@ objval = objective_value(model), sol = value.(x) ) -end +end
7GGT4i1(&91iE2)2f`i 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 FMhb*r4sZYf diff --git a/previews/PR2288/background/duality/index.html b/previews/PR2288/background/duality/index.html index 98d679d63d..469ebca8f4 100644 --- a/previews/PR2288/background/duality/index.html +++ b/previews/PR2288/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/previews/PR2288/background/infeasibility_certificates/index.html b/previews/PR2288/background/infeasibility_certificates/index.html index b95fd687a0..e0631a175d 100644 --- a/previews/PR2288/background/infeasibility_certificates/index.html +++ b/previews/PR2288/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.