MILP Python Examples#

The major difference between this example and the LP example is that some of the variables are integers, so variable_types need to be shared. The OpenAPI specification for the server is available in open-api spec. The example data is structured as per the OpenAPI specification for the server, please refer LPData data under “POST /cuopt/request” under schema section. LP and MILP share same spec.

Generic Example#

basic_milp_example.py

  1# SPDX-FileCopyrightText: Copyright (c) 2025 NVIDIA CORPORATION & AFFILIATES. All rights reserved.
  2# SPDX-License-Identifier: Apache-2.0
  3"""
  4Basic MILP Server Example
  5
  6This example demonstrates how to use the cuOpt Self-Hosted Service Client
  7to solve MILP (Mixed Integer Linear Programming) problems via the cuOpt server.
  8
  9The major difference between this example and the LP example is that some of
 10the variables are integers, so 'variable_types' need to be specified.
 11
 12Requirements:
 13    - cuOpt server running (default: localhost:5000)
 14    - cuopt_sh_client package installed
 15
 16Problem:
 17    Maximize: 1.2*x + 1.7*y
 18    Subject to:
 19        x + y <= 5000
 20        x, y are integers
 21        0 <= x <= 3000
 22        0 <= y <= 5000
 23
 24Expected Response:
 25    {
 26        "response": {
 27            "solver_response": {
 28                "status": "Optimal",
 29                "solution": {
 30                    "primal_objective": 8500.0,
 31                    "vars": {
 32                        "x": 0.0,
 33                        "y": 5000.0
 34                    }
 35                }
 36            }
 37        }
 38    }
 39"""
 40
 41from cuopt_sh_client import CuOptServiceSelfHostClient
 42import json
 43import time
 44
 45
 46def repoll(cuopt_service_client, solution, repoll_tries):
 47    """
 48    Repoll the server for solution if it's still processing.
 49
 50    If solver is still busy solving, the job will be assigned a request id
 51    and response is sent back in the format {"reqId": <REQUEST-ID>}.
 52    """
 53    if "reqId" in solution and "response" not in solution:
 54        req_id = solution["reqId"]
 55        for i in range(repoll_tries):
 56            solution = cuopt_service_client.repoll(
 57                req_id, response_type="dict"
 58            )
 59            if "reqId" in solution and "response" in solution:
 60                break
 61
 62            # Sleep for a second before requesting
 63            time.sleep(1)
 64
 65    return solution
 66
 67
 68def main():
 69    """Run the basic MILP example."""
 70    # Example data for MILP problem
 71    # The data is structured as per the OpenAPI specification for the server
 72    data = {
 73        "csr_constraint_matrix": {
 74            "offsets": [0, 2],
 75            "indices": [0, 1],
 76            "values": [1.0, 1.0],
 77        },
 78        "constraint_bounds": {"upper_bounds": [5000.0], "lower_bounds": [0.0]},
 79        "objective_data": {
 80            "coefficients": [1.2, 1.7],
 81            "scalability_factor": 1.0,
 82            "offset": 0.0,
 83        },
 84        "variable_bounds": {
 85            "upper_bounds": [3000.0, 5000.0],
 86            "lower_bounds": [0.0, 0.0],
 87        },
 88        "maximize": True,
 89        "variable_names": ["x", "y"],
 90        "variable_types": ["I", "I"],  # Both variables are integers
 91        "solver_config": {"time_limit": 30},
 92    }
 93
 94    # If cuOpt is not running on localhost:5000, edit ip and port parameters
 95    cuopt_service_client = CuOptServiceSelfHostClient(
 96        ip="localhost", port=5000, polling_timeout=25, timeout_exception=False
 97    )
 98
 99    print("=== Solving MILP Problem ===")
100    solution = cuopt_service_client.get_LP_solve(data, response_type="dict")
101
102    # Number of repoll requests to be carried out for a successful response
103    repoll_tries = 500
104
105    solution = repoll(cuopt_service_client, solution, repoll_tries)
106
107    print(json.dumps(solution, indent=4))
108
109
110if __name__ == "__main__":
111    main()

The response would be as follows:

 1{
 2    "response": {
 3        "solver_response": {
 4            "status": "Optimal",
 5            "solution": {
 6                "problem_category": "MIP",
 7                "primal_solution": [
 8                    0.0,
 9                    5000.0
10                ],
11                "dual_solution": null,
12                "primal_objective": 8500.0,
13                "dual_objective": null,
14                "solver_time": 0.0,
15                "vars": {
16                    "x": 0.0,
17                    "y": 5000.0
18                },
19                "lp_statistics": {},
20                "reduced_cost": null,
21                "milp_statistics": {
22                    "mip_gap": 0.0,
23                    "solution_bound": 8500.0,
24                    "presolve_time": 0.007354775,
25                    "max_constraint_violation": 0.0,
26                    "max_int_violation": 0.0,
27                    "max_variable_bound_violation": 0.0,
28                    "num_nodes": 1999468624,
29                    "num_simplex_iterations": 21951
30                }
31            }
32        },
33        "total_solve_time": 0.08600544929504395
34    },
35    "reqId": "524e2e37-3494-4c16-bd06-2a9bfd768f76"
36}

Incumbent and Logging Callback#

The incumbent solution can be retrieved using a callback function as follows:

Note

Incumbent solution callback is only applicable to MILP.

incumbent_callback_example.py

 1# SPDX-FileCopyrightText: Copyright (c) 2025 NVIDIA CORPORATION & AFFILIATES. All rights reserved.
 2# SPDX-License-Identifier: Apache-2.0
 3"""
 4MILP Incumbent and Logging Callback Example
 5
 6This example demonstrates how to use callbacks with the cuOpt server:
 7- Incumbent solution callback: Receives intermediate solutions as they're found
 8- Logging callback: Receives solver log messages in real-time
 9
10Note:
11    Incumbent solution callback is only applicable to MILP, not for LP.
12
13Requirements:
14    - cuOpt server running (default: localhost:5000)
15    - cuopt_sh_client package installed
16
17Problem:
18    Maximize: 1.2*x + 1.7*y
19    Subject to:
20        x + y <= 5000
21        x, y are integers
22        0 <= x <= 3000
23        0 <= y <= 5000
24
25Expected Output:
26    server-log: Solving a problem with 1 constraints 2 variables (2 integers) and 2 nonzeros
27    ...
28    Solution : [0.0, 5000.0] cost : 8500.0
29"""
30
31from cuopt_sh_client import CuOptServiceSelfHostClient
32import json
33
34
35def main():
36    """Run the incumbent and logging callback example."""
37    data = {
38        "csr_constraint_matrix": {
39            "offsets": [0, 2],
40            "indices": [0, 1],
41            "values": [1.0, 1.0],
42        },
43        "constraint_bounds": {"upper_bounds": [5000.0], "lower_bounds": [0.0]},
44        "objective_data": {
45            "coefficients": [1.2, 1.7],
46            "scalability_factor": 1.0,
47            "offset": 0.0,
48        },
49        "variable_bounds": {
50            "upper_bounds": [3000.0, 5000.0],
51            "lower_bounds": [0.0, 0.0],
52        },
53        "maximize": True,
54        "variable_names": ["x", "y"],
55        "variable_types": ["I", "I"],
56        "solver_config": {"time_limit": 30},
57    }
58
59    # If cuOpt is not running on localhost:5000, edit ip and port parameters
60    cuopt_service_client = CuOptServiceSelfHostClient(
61        ip="localhost", port=5000, timeout_exception=False
62    )
63
64    # Incumbent callback - receives intermediate solutions
65    def callback(solution, solution_cost):
66        """Called when solver finds a new incumbent solution."""
67        print(f"Solution : {solution} cost : {solution_cost}\n")
68
69    # Logging callback - receives server log messages
70    def log_callback(log):
71        """Called when server sends log messages."""
72        for i in log:
73            print("server-log: ", i)
74
75    print("=== Solving MILP with Callbacks ===")
76    print("\n--- Logging Output ---")
77
78    solution = cuopt_service_client.get_LP_solve(
79        data,
80        incumbent_callback=callback,
81        response_type="dict",
82        logging_callback=log_callback,
83    )
84
85    print("\n--- Final Solution ---")
86    print(json.dumps(solution, indent=4))
87
88
89if __name__ == "__main__":
90    main()

Log the callback response:

1server-log:  Solving a problem with 1 constraints 2 variables (2 integers) and 2 nonzeros
2server-log:  Objective offset 0.000000 scaling_factor -1.000000
3server-log:  After trivial presolve updated 1 constraints 2 variables
4server-log:  Running presolve!
5server-log:  Solving LP root relaxation
6.....

Incumbent callback response:

1 Solution : [0.0, 5000.0] cost : 8500.0
 1{
 2    "response": {
 3        "solver_response": {
 4            "status": "Optimal",
 5            "solution": {
 6                "problem_category": "MIP",
 7                "primal_solution": [
 8                    0.0,
 9                    5000.0
10                ],
11                "dual_solution": null,
12                "primal_objective": 8500.0,
13                "dual_objective": null,
14                "solver_time": 0.0,
15                "vars": {
16                    "x": 0.0,
17                    "y": 5000.0
18                },
19                "lp_statistics": {},
20                "reduced_cost": null,
21                "milp_statistics": {
22                    "mip_gap": 0.0,
23                    "solution_bound": 8500.0,
24                    "presolve_time": 0.001391178,
25                    "max_constraint_violation": 0.0,
26                    "max_int_violation": 0.0,
27                    "max_variable_bound_violation": 0.0,
28                    "num_nodes": 1999468624,
29                    "num_simplex_iterations": 21951
30                }
31            }
32        },
33        "total_solve_time": 0.025009632110595703
34    },
35    "reqId": "eb753ac0-c6a2-4fda-9ad4-ee595cddf0ec"
36}

An example with DataModel is available in the Examples Notebooks Repository.

The data argument to get_LP_solve may be a dictionary of the format shown in MILP Open-API spec. More details on the response can be found under responses schema in “/cuopt/request” and “/cuopt/solution” API spec. They can be of different format as well, please check the documentation.

Aborting a Running Job in Thin Client#

abort_job_example.py

 1# SPDX-FileCopyrightText: Copyright (c) 2025 NVIDIA CORPORATION & AFFILIATES. All rights reserved.
 2# SPDX-License-Identifier: Apache-2.0
 3"""
 4Aborting a Running MILP Job Example
 5
 6This example demonstrates how to abort a running or queued job on the cuOpt server.
 7This is useful when:
 8- A solve is taking too long
 9- You want to cancel a queued job
10- You need to free up server resources
11
12Requirements:
13    - cuOpt server running (default: localhost:5000)
14    - cuopt_sh_client package installed
15
16Usage:
17    Replace <UUID_THAT_WE_GOT> with the actual UUID returned by the solver
18    when you submitted a job.
19"""
20
21from cuopt_sh_client import CuOptServiceSelfHostClient
22
23
24def main():
25    """Run the abort job example."""
26    # This is a UUID that is returned by the solver while the solver is trying
27    # to find solution so users can come back and check the status or query for results.
28    job_uuid = "<UUID_THAT_WE_GOT>"
29
30    print(f"Attempting to abort job: {job_uuid}")
31
32    # If cuOpt is not running on localhost:5000, edit ip and port parameters
33    cuopt_service_client = CuOptServiceSelfHostClient(
34        ip="localhost", port=5000
35    )
36
37    # Delete the job if it is still queued or running
38    # Parameters:
39    #   - job_uuid: The UUID of the job to abort
40    #   - running=True: Abort if the job is currently running
41    #   - queued=True: Abort if the job is in the queue
42    #   - cached=False: Don't delete from cache (only abort active/queued jobs)
43    response = cuopt_service_client.delete(
44        job_uuid, running=True, queued=True, cached=False
45    )
46
47    print(f"Response: {response}")
48
49
50if __name__ == "__main__":
51    # Example usage - in practice, you would get the UUID from a previous job submission
52    print("This is a template example.")
53    print("To use this:")
54    print("1. Submit a MILP job and get its UUID")
55    print("2. Replace '<UUID_THAT_WE_GOT>' in this file with that UUID")
56    print("3. Run this script to abort the job")
57
58    # Uncomment the line below and add your actual UUID to run
59    # main()

MILP CLI Examples#

Generic MILP Example#

The only difference between this example and the prior LP example would be the variable types provided in data.

echo '{
   "csr_constraint_matrix": {
       "offsets": [0, 2, 4],
       "indices": [0, 1, 0, 1],
       "values": [3.0, 4.0, 2.7, 10.1]
   },
   "constraint_bounds": {
       "upper_bounds": [5.4, 4.9],
       "lower_bounds": ["ninf", "ninf"]
   },
   "objective_data": {
       "coefficients": [0.2, 0.1],
       "scalability_factor": 1.0,
       "offset": 0.0
   },
   "variable_bounds": {
       "upper_bounds": ["inf", "inf"],
       "lower_bounds": [0.0, 0.0]
   },
   "variable_names": ["x", "y"],
   "variable_types": ["I", "I"],
   "maximize": "False",
   "solver_config": {
       "time_limit": 30
   }
}' > data.json

Invoke the CLI:

# Please update ip and port if the server is running on a different IP address or port
export ip="localhost"
export port=5000
cuopt_sh data.json -t LP -i $ip -p $port -sl -il

In case the user needs to update solver settings through CLI, the option -ss can be used as follows:

# Please update ip and port if the server is running on a different IP address or port
export ip="localhost"
export port=5000
cuopt_sh data.json -t LP -i $ip -p $port -ss '{"time_limit": 5}'

Note

Batch mode is not supported for MILP.

Aborting a Running Job In CLI#

UUID that is returned by the solver while the solver is trying to find a solution so users can come back and check the status or query for results.

This aborts a job with UUID if it’s in running state.

# Please update ip and port if the server is running on a different IP address or port
export ip="localhost"
export port=5000
cuopt_sh -d -r -q <UUID> -i $ip -p $port