-
Notifications
You must be signed in to change notification settings - Fork 220
Java bindings for LP, MIP and QP #1524
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
base: main
Are you sure you want to change the base?
Changes from 2 commits
9e8fba9
9e76c16
c61bb62
e8f178d
85e5440
fa275f6
54bfe2d
1f5a5fb
275f657
233a9c1
7063df8
93c907a
9decf1e
d2ceef7
f0a264f
57aaeb6
d87382c
4db2d2b
bbe4b5b
99c3964
5972293
4eb70d8
d981aec
6a04604
8d854d3
dc8b4b0
39cbff3
8b178d9
ce50c37
d1ebd46
8a06bf2
acd9be0
d757259
84a9af6
44302d9
785faec
d4660f3
86cd996
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,188 @@ | ||
| =================================== | ||
| Convex Optimization API Reference | ||
| =================================== | ||
|
|
||
| The Java LP/QP bindings are in the package | ||
| ``com.nvidia.cuopt.linearprogramming``. The public API is documented below by | ||
| role. Method names are Java names and therefore use fluent methods instead of | ||
| Python operator overloads. | ||
|
|
||
| High-level model | ||
| ---------------- | ||
|
|
||
| ``Problem`` is the recommended entry point for models built in Java. | ||
|
nvidiacbrissette marked this conversation as resolved.
Outdated
|
||
|
|
||
| .. list-table:: ``Problem`` | ||
| :header-rows: 1 | ||
| :widths: 28 72 | ||
|
|
||
| * - API | ||
| - Description | ||
| * - ``new Problem()`` / ``new Problem(String name)`` | ||
| - Create an empty model, optionally with a problem name. | ||
| * - ``addVariable(...)`` | ||
| - Add a variable with lower/upper bounds, objective coefficient, variable type, and name. | ||
| * - ``addConstraint(Constraint, String name)`` | ||
| - Add a linear or quadratic constraint. | ||
| * - ``setObjective(LinearExpression, ObjectiveSense)`` | ||
| - Set a linear objective. | ||
| * - ``setObjective(QuadraticExpression, ObjectiveSense)`` | ||
| - Set a quadratic objective with optional linear and constant terms. | ||
| * - ``solve()`` / ``solve(SolverSettings)`` | ||
| - Convert the model to a native ``DataModel`` and return a ``Solution``. | ||
| * - ``toDataModel()`` | ||
|
nvidiacbrissette marked this conversation as resolved.
Outdated
|
||
| - Materialize the high-level model as the lower-level native data model. | ||
| * - ``getCSR()`` / ``getQCSR()`` | ||
| - Inspect the linear or quadratic objective matrix in CSR form. | ||
|
Contributor
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. What is a linear objective matrix? Does this return the constraint matrix? Or the objective? I'd suggest renaming these functions to make what they do more clear. |
||
| * - ``writeMPS(String)`` / ``read(String)`` / ``readMPS(String)`` | ||
|
Contributor
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more.
|
||
| - Write or load MPS/QPS-backed models. The fixed-format overloads accept a boolean flag. | ||
| * - ``update()`` / ``updateConstraint(...)`` / ``updateObjective(...)`` | ||
| - Update model state and reset solved values where appropriate. | ||
| * - ``relax()`` | ||
| - Return a copy with variables converted to continuous type. | ||
|
|
||
| The model also exposes ``getVariables``, ``getVariable``, ``getConstraints``, | ||
| ``getConstraint``, ``getNumVariables``, ``getNumConstraints``, | ||
| ``getNumNonZeros``, ``isMip``, ``isSolved``, ``getStatus``, | ||
|
nvidiacbrissette marked this conversation as resolved.
Outdated
|
||
| ``getObjectiveValue``, and ``getSolveTime``. | ||
|
|
||
| Low-level data model | ||
| -------------------- | ||
|
|
||
| ``DataModel`` is useful when the problem is already available as arrays or | ||
| when direct access to native CSR and quadratic data is required. | ||
|
|
||
| Create a model with one of the following factories: | ||
|
|
||
| .. code-block:: java | ||
|
|
||
| DataModel.createProblem( | ||
| numConstraints, numVariables, objectiveSense, objectiveOffset, | ||
| objectiveCoefficients, constraintMatrix, constraintSense, rhs, | ||
| variableLowerBounds, variableUpperBounds, variableTypes); | ||
|
|
||
| DataModel.createRangedProblem( | ||
| numConstraints, numVariables, objectiveSense, objectiveOffset, | ||
| objectiveCoefficients, constraintMatrix, constraintLowerBounds, | ||
| constraintUpperBounds, variableLowerBounds, variableUpperBounds, | ||
| variableTypes); | ||
|
|
||
| ``CsrMatrix`` stores ``rowOffsets``, ``columnIndices``, and ``values``. The | ||
| arrays are available through ``getRowOffsets``, ``getColumnIndices``, and | ||
| ``getValues``. | ||
|
|
||
| The mutable ``DataModel`` setters cover: | ||
|
|
||
| * objective sense, coefficients, offset, and scaling factor; | ||
| * linear constraint CSR arrays, row types, RHS, and ranged bounds; | ||
| * variable bounds, types, names, and row names; | ||
| * objective and problem names; | ||
| * initial primal and dual solutions; and | ||
| * quadratic objective matrices and quadratic constraints. | ||
|
|
||
| The corresponding getters include ``getConstraintMatrix``, | ||
| ``getConstraintMatrixValues``, ``getConstraintMatrixIndices``, | ||
| ``getConstraintMatrixOffsets``, ``getConstraintRhs``, | ||
| ``getConstraintLowerBounds``, ``getConstraintUpperBounds``, | ||
| ``getQuadraticObjectiveValues``, ``getQuadraticObjectiveIndices``, | ||
| ``getQuadraticObjectiveOffsets``, ``getQuadraticConstraints``, | ||
| ``getVariableNames``, ``getRowNames``, ``getObjectiveName``, | ||
| ``getProblemName``, ``getProblemCategory``, and ``toDict``. | ||
|
|
||
| Use ``clearQuadraticConstraints`` to remove all quadratic constraints from a | ||
| mutable data model. ``DataModel`` implements ``AutoCloseable``. | ||
|
|
||
| Variables, expressions, and constraints | ||
| ---------------------------------------- | ||
|
|
||
| ``Variable`` stores the model index, bounds, objective coefficient, type, | ||
| name, solved value, reduced cost, and optional MIP start. Its mutable methods | ||
| return the variable so calls can be chained: | ||
|
|
||
| .. code-block:: java | ||
|
|
||
| Variable x = problem.addVariable( | ||
| 0.0, Double.POSITIVE_INFINITY, 1.0, | ||
| VariableType.CONTINUOUS, "x"); | ||
| x.setUpperBound(100.0).setObjectiveCoefficient(2.0); | ||
|
|
||
| ``LinearExpression`` supports ``of``, ``ofConstant``, ``plus``, ``minus``, | ||
| ``times``, ``dividedBy``, ``constant``, and the comparison methods ``le``, | ||
| ``ge``, and ``eq``. Comparisons return a ``Constraint``. | ||
|
|
||
| ``QuadraticExpression`` supports quadratic terms through | ||
| ``QuadraticExpression.of(first, second, coefficient)`` and the same fluent | ||
|
Contributor
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Nit: what does "fluent" mean in this context? Maybe reword for clarity?
Contributor
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. FWIW fluent is a standard term for describing APIs: https://en.wikipedia.org/wiki/Fluent_interface |
||
| arithmetic pattern. It can also contain linear and constant terms. Its | ||
| ``le`` and ``ge`` methods return quadratic constraints; ``eq`` throws because | ||
| equality quadratic constraints are not supported. | ||
|
|
||
| The enums used in model construction are: | ||
|
|
||
| * ``ObjectiveSense.MINIMIZE`` and ``ObjectiveSense.MAXIMIZE``; | ||
| * ``ConstraintSense.LE``, ``ConstraintSense.GE``, and ``ConstraintSense.EQ``; | ||
| * ``VariableType.CONTINUOUS``, ``VariableType.INTEGER``, and | ||
| ``VariableType.SEMI_CONTINUOUS``; and | ||
| * ``ProblemCategory`` for the native problem classification. | ||
|
Contributor
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. What is ProblemCategory used for? Could we get away with just isMIP()? |
||
|
|
||
| ``Constraint`` provides ``getSense``, ``getRHS``, ``getCoefficient``, | ||
| ``getLinearExpression``, ``getQuadraticExpression``, ``isQuadratic``, | ||
| ``computeSlack``, ``getSlack``, and ``getDualValue``. | ||
|
Contributor
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Is |
||
|
|
||
| Solver settings | ||
| --------------- | ||
|
|
||
| ``SolverSettings`` owns native solver configuration and implements | ||
| ``AutoCloseable``. Parameters can be set with the overloaded | ||
| ``setParameter`` methods for ``String``, ``int``, ``double``, and ``boolean`` | ||
|
nvidiacbrissette marked this conversation as resolved.
Outdated
|
||
| values. Use ``getParameter`` or ``getParameterAsString`` for the native string | ||
| representation, and ``getTypedParameter`` when a Java ``Boolean``, | ||
| ``Integer``, ``Double``, or ``String`` value is preferred. | ||
|
|
||
| The settings API also includes: | ||
|
|
||
| * ``getSolverParameterNames`` and the static setting accessors; | ||
| * ``setMethod`` and ``setPdlpSolverMode``; | ||
| * ``setOptimalityTolerance``; | ||
| * primal and dual initial solutions; | ||
| * ``dumpParametersToFile`` and ``loadParametersFromFile``; | ||
| * ``toDict``; | ||
| * ``setPdlpWarmStartData``; and | ||
|
nvidiacbrissette marked this conversation as resolved.
Outdated
|
||
| * MIP callback registration through ``setMipCallback``. | ||
|
|
||
| ``SolverMethod`` includes ``PDLP``, ``DUAL_SIMPLEX``, ``BARRIER``, | ||
| ``CONCURRENT``, and ``UNSET``. ``PDLPSolverMode`` exposes the supported PDLP | ||
| solver modes. | ||
|
|
||
| Solutions and statistics | ||
| ------------------------ | ||
|
|
||
| ``Solution`` implements ``AutoCloseable`` and exposes: | ||
|
|
||
| * ``getPrimalSolution``, ``getDualSolution``, and ``getReducedCost``; | ||
|
Contributor
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. I'm not sure we want |
||
| * ``getPrimalObjective`` and ``getDualObjective``; | ||
| * ``getTerminationStatus`` and ``getTerminationReason``; | ||
| * ``getErrorStatus`` and ``getErrorMessage``; | ||
| * ``getSolveTime`` and ``getProblemCategory``; and | ||
| * ``getVars`` when variable names are available. | ||
|
|
||
| LP solutions additionally expose ``getLpStats`` and PDLP warm-start data. | ||
|
nvidiacbrissette marked this conversation as resolved.
Outdated
|
||
| ``LPStats`` contains primal residual, dual residual, gap, iteration count, and | ||
| the ``SolverMethod`` used. MIP-only solution fields are documented in | ||
| :doc:`../mip/mip-api`. | ||
|
|
||
| MPS, batching, and errors | ||
| ------------------------- | ||
|
|
||
| ``DataModel.read``, ``DataModel.parseMps``, ``Problem.read``, and | ||
|
nvidiacbrissette marked this conversation as resolved.
Outdated
|
||
| ``Problem.readMPS`` support MPS/QPS parsing, including a fixed-format boolean | ||
| overload. ``writeMPS`` writes a model for round trips or use by another cuOpt | ||
| interface. | ||
|
|
||
| ``BatchSolve.solve(List<DataModel>, SolverSettings)`` is a sequential Java | ||
| compatibility entry point. It returns ``BatchSolveResult``, containing the | ||
| solutions and elapsed solve time. | ||
|
|
||
| Native failures are reported as ``CuOptException`` with a cuOpt status code | ||
| available through ``getStatusCode``. Accessing an LP-only field on a MIP | ||
| solution, or a MIP-only field on an LP solution, raises | ||
| ``IllegalStateException``. | ||
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,182 @@ | ||
| ============================ | ||
| Convex Optimization Examples | ||
| ============================ | ||
|
|
||
| These examples show the Java modeling patterns corresponding to the Python | ||
| LP/QP examples. They assume the Java module has been compiled as described in | ||
| :doc:`../quick-start` and that the application can load ``libcuopt_jni``. | ||
|
|
||
| Simple linear programming | ||
| -------------------------- | ||
|
|
||
| The high-level API uses fluent expressions and explicit comparison methods. | ||
|
|
||
| .. code-block:: java | ||
|
|
||
| import com.nvidia.cuopt.linearprogramming.*; | ||
|
|
||
| try (Problem problem = new Problem("simple-lp")) { | ||
| Variable x = problem.addVariable( | ||
| 0.0, Double.POSITIVE_INFINITY, 1.0, | ||
| VariableType.CONTINUOUS, "x"); | ||
| Variable y = problem.addVariable( | ||
| 0.0, Double.POSITIVE_INFINITY, 1.0, | ||
| VariableType.CONTINUOUS, "y"); | ||
|
|
||
| problem.addConstraint( | ||
| LinearExpression.of(x).plus(y).ge(10.0), "demand"); | ||
| problem.setObjective( | ||
| LinearExpression.of(x).plus(y), ObjectiveSense.MINIMIZE); | ||
|
|
||
| try (SolverSettings settings = new SolverSettings() | ||
| .setMethod(SolverMethod.PDLP); | ||
| Solution solution = problem.solve(settings)) { | ||
| System.out.println("Status: " + solution.getTerminationStatus()); | ||
| System.out.println("x = " + x.getValue()); | ||
| System.out.println("y = " + y.getValue()); | ||
| System.out.println("Objective = " + solution.getPrimalObjective()); | ||
| } | ||
| } | ||
|
|
||
| ``Problem.solve`` copies the model to a native ``DataModel`` and populates | ||
| the ``Variable`` and ``Constraint`` objects after the solve. The solution | ||
| object remains available for detailed native results and statistics. | ||
|
|
||
| Low-level CSR linear program | ||
| ----------------------------- | ||
|
|
||
| Use ``DataModel`` when the input is already in CSR form: | ||
|
|
||
| .. code-block:: java | ||
|
|
||
| CsrMatrix matrix = new CsrMatrix( | ||
| new int[] {0, 2}, // row offsets | ||
| new int[] {0, 1}, // column indices | ||
| new double[] {1.0, 1.0}); | ||
|
|
||
| try (DataModel model = DataModel.createProblem( | ||
| 1, 2, | ||
| ObjectiveSense.MINIMIZE, | ||
| 0.0, | ||
| new double[] {1.0, 1.0}, | ||
| matrix, | ||
| new byte[] {(byte) 'G'}, | ||
|
nvidiacbrissette marked this conversation as resolved.
Outdated
|
||
| new double[] {10.0}, | ||
| new double[] {0.0, 0.0}, | ||
| new double[] {Double.POSITIVE_INFINITY, Double.POSITIVE_INFINITY}, | ||
| new byte[] {(byte) 'C', (byte) 'C'}); | ||
| SolverSettings settings = new SolverSettings().setMethod(SolverMethod.PDLP); | ||
| Solution solution = model.solve(settings)) { | ||
| System.out.println(solution.getPrimalObjective()); | ||
| System.out.println(model.getConstraintMatrix().getRowOffsets().length); | ||
| } | ||
|
|
||
| For ranged rows, use ``createRangedProblem`` with | ||
| ``constraintLowerBounds`` and ``constraintUpperBounds`` instead of row sense | ||
| and RHS arrays. The mutable setters provide the same representation after an | ||
| empty ``new DataModel()``. | ||
|
|
||
| Simple quadratic programming | ||
| ----------------------------- | ||
|
|
||
| Quadratic objectives combine quadratic, linear, and constant terms: | ||
|
|
||
| .. code-block:: java | ||
|
|
||
| try (Problem problem = new Problem("simple-qp")) { | ||
| Variable x = problem.addVariable(0.0, 10.0, 0.0, VariableType.CONTINUOUS, "x"); | ||
| Variable y = problem.addVariable(0.0, 10.0, 0.0, VariableType.CONTINUOUS, "y"); | ||
|
|
||
| QuadraticExpression objective = QuadraticExpression | ||
| .of(x, x, 1.0) | ||
| .plus(y, y, 1.0) | ||
| .plus(LinearExpression.of(x).times(-1.0)) | ||
| .plus(LinearExpression.of(y).times(-1.0)); | ||
|
|
||
| problem.addConstraint( | ||
| LinearExpression.of(x).plus(y).eq(1.0), "sum"); | ||
| problem.setObjective(objective, ObjectiveSense.MINIMIZE); | ||
|
|
||
| try (Solution solution = problem.solve()) { | ||
| System.out.println("x = " + x.getValue()); | ||
| System.out.println("y = " + y.getValue()); | ||
| System.out.println("Objective = " + solution.getPrimalObjective()); | ||
| System.out.println("LP stats gap = " + solution.getLpStats().getGap()); | ||
| } | ||
| } | ||
|
|
||
| The lower-level equivalent is ``DataModel.setQuadraticObjective`` with a | ||
| ``QuadraticExpression`` or ``setQuadraticObjectiveMatrix`` with quadratic CSR | ||
| arrays. For QP solutions, ``getPrimalSolution``, ``getDualSolution``, | ||
| ``getReducedCost``, ``getDualObjective``, and ``getLpStats`` are available when | ||
| the solver returns the corresponding values. | ||
|
|
||
| Quadratic constraints | ||
| --------------------- | ||
|
|
||
| Quadratic constraints can be added to a high-level ``Problem`` or directly to | ||
| a ``DataModel``: | ||
|
|
||
| .. code-block:: java | ||
|
|
||
| try (Problem problem = new Problem("quadratic-constraint")) { | ||
| Variable x = problem.addVariable(0.0, 10.0, 1.0, VariableType.CONTINUOUS, "x"); | ||
| Variable y = problem.addVariable(0.0, 10.0, 1.0, VariableType.CONTINUOUS, "y"); | ||
|
|
||
| QuadraticExpression radius = QuadraticExpression | ||
| .of(x, x, 1.0) | ||
| .plus(y, y, 1.0); | ||
| problem.addConstraint(radius.le(4.0), "radius"); | ||
| problem.setObjective( | ||
| LinearExpression.of(x).plus(y), ObjectiveSense.MAXIMIZE); | ||
|
|
||
| try (Solution solution = problem.solve()) { | ||
| System.out.println(solution.getTerminationStatus()); | ||
| } | ||
| } | ||
|
|
||
| Only ``LE`` and ``GE`` quadratic constraints are supported. Calling | ||
| ``QuadraticExpression.eq`` or adding an equality quadratic constraint raises | ||
|
nvidiacbrissette marked this conversation as resolved.
Outdated
|
||
| ``IllegalArgumentException``. | ||
|
|
||
| Reading and writing MPS/QPS | ||
| --------------------------- | ||
|
|
||
| ``DataModel`` and ``Problem`` expose both extension-dispatch and direct MPS | ||
| entry points: | ||
|
|
||
| .. code-block:: java | ||
|
|
||
| try (DataModel model = DataModel.read("model.mps")) { | ||
| System.out.println("Variables: " + model.getNumVariables()); | ||
| System.out.println("QP terms: " + model.getQuadraticObjectiveValues().length); | ||
| model.writeMPS("roundtrip.mps"); | ||
| } | ||
|
|
||
| try (DataModel fixed = DataModel.parseMps("fixed-format.mps", true)) { | ||
| // Use fixed-format parsing explicitly. | ||
| } | ||
|
|
||
| ``Problem.read`` and ``Problem.readMPS`` build the high-level Java model from | ||
| the parsed data. Parsing failures are reported as ``CuOptException`` with the | ||
| cuOpt status code available from ``getStatusCode``. | ||
|
|
||
| Inspecting solutions and PDLP warm starts | ||
| ------------------------------------------ | ||
|
|
||
| LP solutions expose residuals and solver metadata through ``LPStats``. When | ||
| PDLP warm-start data is available, retrieve a defensive-copy representation: | ||
|
|
||
| .. code-block:: java | ||
|
|
||
| try (SolverSettings settings = new SolverSettings().setMethod(SolverMethod.PDLP); | ||
| Solution solution = problem.solve(settings)) { | ||
| if (solution.hasPdlpWarmStartData()) { | ||
| PDLPWarmStartData warmStart = solution.getPdlpWarmStartData(); | ||
| System.out.println(warmStart.getCurrentPrimalSolution().length); | ||
| System.out.println(warmStart.getTotalPdlpIterations()); | ||
| } | ||
| } | ||
|
|
||
| The same ``PDLPWarmStartData`` can be supplied to | ||
| ``SolverSettings.setPdlpWarmStartData`` for a subsequent compatible LP solve. | ||
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,26 @@ | ||
| ===================================== | ||
| Convex Optimization (LP/QP) | ||
| ===================================== | ||
|
|
||
| This section documents the Java bindings for continuous linear and quadratic | ||
| optimization. The Java API includes both: | ||
|
|
||
| * a high-level modeling API based on ``Problem``, ``Variable``, expressions, | ||
| and constraints; and | ||
| * a lower-level ``DataModel`` API that exposes CSR data, ranged bounds, | ||
| quadratic matrices, MPS I/O, and solver results. | ||
|
|
||
| Quadratic constraints are supported for ``LE`` and ``GE`` constraints. Equality | ||
| quadratic constraints are rejected by the Java API. Dedicated SOCP modeling | ||
|
nvidiacbrissette marked this conversation as resolved.
Outdated
|
||
| helpers are not currently exposed; cone models can be represented through the | ||
| supported quadratic-expression API when they satisfy cuOpt's quadratic | ||
| constraint requirements. | ||
|
|
||
| .. toctree:: | ||
| :maxdepth: 3 | ||
| :caption: LP/QP Java API | ||
| :name: LP/QP Java API Reference | ||
| :titlesonly: | ||
|
|
||
| convex-api.rst | ||
| convex-examples.rst | ||
Uh oh!
There was an error while loading. Please reload this page.