MIP Examples#

These examples show mixed-integer modeling, MIP starts, semi-continuous variables, and incumbent callbacks in Java.

Simple MIP#

SimpleMip.java

 1/*
 2 * SPDX-FileCopyrightText: Copyright (c) 2026, NVIDIA CORPORATION & AFFILIATES. All rights reserved.
 3 * SPDX-License-Identifier: Apache-2.0
 4 */
 5import com.nvidia.cuopt.mathematicaloptimization.*;
 6
 7public class SimpleMip {
 8  public static void main(String[] args) throws Exception {
 9    try (Problem problem = new Problem("simple-milp")) {
10      Variable x = problem.addVariable(
11          0.0, 100.0, 3.0, VariableType.INTEGER, "x");
12      Variable y = problem.addVariable(
13          0.0, 100.0, 5.0, VariableType.INTEGER, "y");
14
15      problem.addConstraint(
16          LinearExpression.of(x).times(2.0).plus(y).le(8.0), "capacity");
17      problem.setObjective(
18          LinearExpression.of(x).times(3.0).plus(y, 5.0),
19          ObjectiveSense.MAXIMIZE);
20
21      try (SolverSettings settings = new SolverSettings()
22               .setSetting(CuOptConstants.CUOPT_TIME_LIMIT, 10.0);
23           Solution solution = problem.solve(settings)) {
24        System.out.println("Status: " + solution.getTerminationStatus());
25        System.out.println("x = " + x.getValue());
26        System.out.println("y = " + y.getValue());
27        System.out.println("Objective = " + solution.getPrimalObjective());
28        System.out.println("MIP gap = " + solution.getMIPGap());
29        System.out.println("Bound = " + solution.getSolutionBound());
30      }
31    }
32  }
33}

Example Response:

Status: OPTIMAL
x = 0.0
y = 8.0
Objective = 40.0
MIP gap = 0.0
Bound = 40.0

The MIP solver can return a feasible solution before proving optimality. Use the termination status, MIP gap, and solution bound together when interpreting the result.

Semi-Continuous Variables#

SEMI_CONTINUOUS variables are zero or lie within their declared bounds.

SemiContinuous.java

 1/*
 2 * SPDX-FileCopyrightText: Copyright (c) 2026, NVIDIA CORPORATION & AFFILIATES. All rights reserved.
 3 * SPDX-License-Identifier: Apache-2.0
 4 */
 5import com.nvidia.cuopt.mathematicaloptimization.*;
 6
 7public class SemiContinuous {
 8  public static void main(String[] args) throws Exception {
 9    try (Problem problem = new Problem("semi-continuous")) {
10      Variable production = problem.addVariable(
11          10.0, 100.0, 1.0,
12          VariableType.SEMI_CONTINUOUS, "production");
13
14      // cuOptCreateProblem currently requires at least one linear constraint row.
15      problem.addConstraint(LinearExpression.of(production).le(1000.0), "capacity");
16
17      problem.setObjective(production, ObjectiveSense.MINIMIZE);
18
19      try (Solution solution = problem.solve()) {
20        System.out.println("production = " + production.getValue());
21      }
22    }
23  }
24}

MIP Starts#

Set starts on variables when using the high-level Problem API:

MipStarts.java

x.setMIPStart(3.0);
y.setMIPStart(2.0);

try (SolverSettings settings = new SolverSettings();
     Solution solution = problem.solve(settings)) {
  System.out.println(solution.getPrimalObjective());
}

Setting a start per variable avoids handling the ordering at all, and is the form to prefer.

SolverSettings.addMIPStart takes a complete array instead, indexed by Variable.getIndex(). It is the way to supply more than one starting point, since it can be called repeatedly while each Variable holds a single value. Build it from getVariables so the ordering comes from the problem rather than from you:

try (SolverSettings settings = new SolverSettings()) {
  double[] values = new double[problem.getNumVariables()];
  for (Variable variable : problem.getVariables()) {
    values[variable.getIndex()] = variable.getMIPStart();
  }
  settings.addMIPStart(values);

  try (Solution solution = problem.solve(settings)) {
    System.out.println(solution.getPrimalObjective());
  }
}

MIP starts are currently unsupported with presolve on.

Incumbent Callback#

Register an incumbent callback before solving:

IncumbentCallback.java

try (SolverSettings settings = new SolverSettings()) {
  settings.setMIPCallback(
      (incumbent, objective, bound, userData) -> {
        System.out.println(
            "incumbent objective=" + objective + ", bound=" + bound);
      },
      null,
      problem.getNumVariables());

  try (Solution solution = problem.solve(settings)) {
    System.out.println("Final status: " + solution.getTerminationStatus());
  }
}

The callback receives a defensive copy of the incumbent vector, the incumbent objective, the current solution bound, and the user data object.

The vector is in variable-index order. To read specific variables out of it without depending on that order, pass them to Problem.fromIncumbent, which returns their values in the order you ask for:

try (SolverSettings settings = new SolverSettings()) {
  settings.setMIPCallback(
      (incumbent, objective, bound, userData) -> {
        double[] picked = Problem.fromIncumbent(incumbent, y, x);
        System.out.println("y=" + picked[0] + " x=" + picked[1]);
      },
      null,
      problem.getNumVariables());

  try (Solution solution = problem.solve(settings)) {
    System.out.println("Final status: " + solution.getTerminationStatus());
  }
}

LP Relaxation#

Relax the integer variables before solving:

LpRelaxation.java

for (Variable variable : problem.getVariables()) {
  variable.setVariableType(VariableType.CONTINUOUS);
}
try (Solution solution = problem.solve()) {
  System.out.println("LP relaxation objective = " + solution.getPrimalObjective());
}