MIP Examples#

This section contains examples of how to use the cuOpt MIP Python API.

Note

The examples in this section are not exhaustive. They are provided to help you get started with the cuOpt mixed integer linear programming Python API. For more examples, please refer to the cuopt-examples GitHub repository.

Mixed Integer Linear Programming Example#

simple_milp_example.py

 1# SPDX-FileCopyrightText: Copyright (c) 2025-2026, NVIDIA CORPORATION & AFFILIATES. All rights reserved.
 2# SPDX-License-Identifier: Apache-2.0
 3
 4"""
 5Mixed Integer Linear Programming Example
 6
 7This example demonstrates how to:
 8- Create a mixed integer programming problem
 9- Add integer variables with bounds
10- Add constraints with integer variables
11- Solve a MIP problem
12
13Problem:
14    Maximize: 5*x + 3*y
15    Subject to:
16        2*x + 4*y >= 230
17        3*x + 2*y <= 190
18        10 <= y <= 50
19        x, y are integers
20
21Expected Output:
22    Optimal solution found in 0.00 seconds
23    x = 36.0
24    y = 41.0
25    Objective value = 303.0
26"""
27
28from cuopt.linear_programming.problem import Problem, INTEGER, MAXIMIZE
29from cuopt.linear_programming.solver_settings import SolverSettings
30
31
32def main():
33    """Run the simple MIP example."""
34    # Create a new MIP problem
35    problem = Problem("Simple MIP")
36
37    # Add integer variables with bounds
38    x = problem.addVariable(vtype=INTEGER, name="V_x")
39    y = problem.addVariable(lb=10, ub=50, vtype=INTEGER, name="V_y")
40
41    # Add constraints
42    problem.addConstraint(2 * x + 4 * y >= 230, name="C1")
43    problem.addConstraint(3 * x + 2 * y <= 190, name="C2")
44
45    # Set objective function
46    problem.setObjective(5 * x + 3 * y, sense=MAXIMIZE)
47
48    # Configure solver settings
49    settings = SolverSettings()
50    settings.set_parameter("time_limit", 60)
51
52    # Solve the problem
53    problem.solve(settings)
54
55    # Check solution status and results
56    if problem.Status.name == "Optimal":
57        print(f"Optimal solution found in {problem.SolveTime:.2f} seconds")
58        print(f"x = {x.getValue()}")
59        print(f"y = {y.getValue()}")
60        print(f"Objective value = {problem.ObjValue}")
61    else:
62        print(f"Problem status: {problem.Status.name}")
63
64
65if __name__ == "__main__":
66    main()

The response is as follows:

Optimal solution found in 0.00 seconds
x = 36.0
y = 41.0
Objective value = 303.0

Semi-continuous Variable Example#

semi_continuous_example.py

 1# SPDX-FileCopyrightText: Copyright (c) 2026, NVIDIA CORPORATION & AFFILIATES. All rights reserved.
 2# SPDX-License-Identifier: Apache-2.0
 3
 4"""
 5Semi-continuous Variable Example
 6
 7This example demonstrates how to:
 8- Add a semi-continuous variable
 9- Solve a small MIP that uses the semi-continuous domain
10
11Problem:
12    Minimize: x
13    Subject to:
14        x + y = 1
15        x is either 0 or in [5, 10]
16        0 <= y <= 1
17
18Expected Output:
19    Optimal solution found in 0.00 seconds
20    x = 0.0
21    y = 1.0
22    Objective value = 0.0
23"""
24
25from cuopt.linear_programming.problem import (
26    CONTINUOUS,
27    MINIMIZE,
28    SEMI_CONTINUOUS,
29    Problem,
30)
31from cuopt.linear_programming.solver_settings import SolverSettings
32
33
34def main():
35    """Run the semi-continuous variable example."""
36    problem = Problem("Semi-continuous")
37
38    x = problem.addVariable(lb=5.0, ub=10.0, vtype=SEMI_CONTINUOUS, name="x")
39    y = problem.addVariable(lb=0.0, ub=1.0, vtype=CONTINUOUS, name="y")
40
41    problem.addConstraint(x + y == 1.0)
42    problem.setObjective(x, sense=MINIMIZE)
43
44    settings = SolverSettings()
45    settings.set_parameter("time_limit", 10)
46
47    problem.solve(settings)
48
49    if problem.Status.name == "Optimal":
50        print(f"Optimal solution found in {problem.SolveTime:.2f} seconds")
51        print(f"x = {x.getValue()}")
52        print(f"y = {y.getValue()}")
53        print(f"Objective value = {problem.ObjValue}")
54    else:
55        print(f"Problem status: {problem.Status.name}")
56
57
58if __name__ == "__main__":
59    main()

The response is as follows:

Optimal solution found in 0.00 seconds
x = 0.0
y = 1.0
Objective value = 0.0

Working with Incumbent Solutions#

Incumbent solutions are intermediate feasible solutions found during the MIP solving process. They represent the best integer-feasible solution discovered so far and can be accessed through callback functions.

Note

Incumbent solutions are only available for Mixed Integer Programming (MIP) problems, not for pure Linear Programming (LP) problems.

incumbent_solutions_example.py

  1# SPDX-FileCopyrightText: Copyright (c) 2025-2026, NVIDIA CORPORATION & AFFILIATES. All rights reserved.
  2# SPDX-License-Identifier: Apache-2.0
  3
  4"""
  5Working with Incumbent Solutions Example
  6
  7This example demonstrates:
  8- Using callbacks to receive intermediate solutions during MIP solving
  9- Using Problem.getIncumbentValues() to extract variable values from
 10  incumbent solutions
 11- Tracking solution progress as the solver improves the solution
 12- Accessing incumbent (best so far) solutions before final optimum
 13- Custom callback class implementation
 14
 15Incumbent solutions are intermediate feasible solutions found during the MIP
 16solving process. They represent the best integer-feasible solution discovered
 17so far.
 18
 19Note:
 20    Incumbent solutions are only available for Mixed Integer Programming (MIP)
 21    problems, not for pure Linear Programming (LP) problems.
 22
 23Problem:
 24    Maximize: 5*x + 3*y
 25    Subject to:
 26        2*x + 4*y >= 230
 27        3*x + 2*y <= 190
 28        x, y are integers
 29
 30Expected Output:
 31    Incumbent 1: x=36.0, y=41.0, cost: 303.00
 32
 33    === Final Results ===
 34    Problem status: Optimal
 35    Solve time: 0.27 seconds
 36    Final solution: x=36.0, y=41.0
 37    Final objective value: 303.00
 38"""
 39
 40from cuopt.linear_programming.problem import Problem, INTEGER, MAXIMIZE
 41from cuopt.linear_programming.solver_settings import SolverSettings
 42from cuopt.linear_programming.solver.solver_parameters import CUOPT_TIME_LIMIT
 43from cuopt.linear_programming.internals import GetSolutionCallback
 44
 45
 46class IncumbentCallback(GetSolutionCallback):
 47    """Callback to receive and track incumbent solutions during solving.
 48
 49    Uses Problem.getIncumbentValues() to extract variable values from the
 50    raw incumbent solution array.
 51    """
 52
 53    def __init__(self, problem, variables, user_data):
 54        super().__init__()
 55        self.problem = problem
 56        self.variables = variables
 57        self.solutions = []
 58        self.n_callbacks = 0
 59        self.user_data = user_data
 60
 61    def get_solution(self, solution, solution_cost, solution_bound, user_data):
 62        """Called whenever the solver finds a new incumbent solution."""
 63        assert user_data is self.user_data
 64        self.n_callbacks += 1
 65
 66        # Use getIncumbentValues to extract values for specific variables
 67        values = self.problem.getIncumbentValues(solution, self.variables)
 68
 69        incumbent = {
 70            "values": values,
 71            "cost": float(solution_cost[0]),
 72            "bound": float(solution_bound[0]),
 73            "iteration": self.n_callbacks,
 74        }
 75        self.solutions.append(incumbent)
 76
 77        print(f"Incumbent {self.n_callbacks}:", end=" ")
 78        for i, var in enumerate(self.variables):
 79            print(f"{var.VariableName}={values[i]}", end=" ")
 80        print(f"cost: {incumbent['cost']:.2f}")
 81
 82
 83def main():
 84    """Run the incumbent solutions example."""
 85    problem = Problem("Incumbent Example")
 86
 87    # Add integer variables
 88    x = problem.addVariable(vtype=INTEGER, name="x")
 89    y = problem.addVariable(vtype=INTEGER, name="y")
 90
 91    # Add constraints
 92    problem.addConstraint(2 * x + 4 * y >= 230)
 93    problem.addConstraint(3 * x + 2 * y <= 190)
 94
 95    # Set objective to maximize
 96    problem.setObjective(5 * x + 3 * y, sense=MAXIMIZE)
 97
 98    # Configure solver settings with callback
 99    settings = SolverSettings()
100    user_data = {"source": "incumbent_solutions_example"}
101    incumbent_callback = IncumbentCallback(problem, [x, y], user_data)
102    settings.set_mip_callback(incumbent_callback, user_data)
103    settings.set_parameter(CUOPT_TIME_LIMIT, 30)
104
105    # Solve the problem
106    problem.solve(settings)
107
108    # Display final results
109    print("\n=== Final Results ===")
110    print(f"Problem status: {problem.Status.name}")
111    print(f"Solve time: {problem.SolveTime:.2f} seconds")
112    print("Final solution: ", end=" ")
113    for i, var in enumerate(problem.getVariables()):
114        print(f"{var.VariableName}={var.getValue()} ", end=" ")
115    print(f"\nFinal objective value: {problem.ObjValue:.2f}")
116
117    print(
118        f"\nTotal incumbent solutions found: "
119        f"{len(incumbent_callback.solutions)}"
120    )
121
122
123if __name__ == "__main__":
124    main()

The response is as follows:

Optimal solution found.
Incumbent 1: x=36.0 y=41.0 cost: 303.00
Solution objective: 303.000000 , relative_mip_gap 0.000000 solution_bound 303.000000 presolve_time 0.103659 total_solve_time 0.173678 max constraint violation 0.000000 max int violation 0.000000 max var bounds violation 0.000000 nodes 0 simplex_iterations 2

=== Final Results ===
Problem status: Optimal
Solve time: 0.17 seconds
Final solution:  x=36.0  y=41.0
Final objective value: 303.00

Total incumbent solutions found: 1