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 under schema section. LP and MILP share same spec.
Generic Example#
1from cuopt_sh_client import CuOptServiceSelfHostClient
2import json
3import time
4
5# Example data for MILP problem
6# The data is structured as per the OpenAPI specification for the server, please refer /cuopt/request -> schema -> LPData
7data = {
8 "csr_constraint_matrix": {
9 "offsets": [0, 2],
10 "indices": [0, 1],
11 "values": [1.0, 1.0]
12 },
13 "constraint_bounds": {
14 "upper_bounds": [5000.0],
15 "lower_bounds": [0.0]
16 },
17 "objective_data": {
18 "coefficients": [1.2, 1.7],
19 "scalability_factor": 1.0,
20 "offset": 0.0
21 },
22 "variable_bounds": {
23 "upper_bounds": [3000.0, 5000.0],
24 "lower_bounds": [0.0, 0.0]
25 },
26 "maximize": True,
27 "variable_names": ["x", "y"],
28 "variable_types": ["I", "I"],
29 "solver_config":{
30 "time_limit": 30
31 }
32}
33
34# If cuOpt is not running on localhost:5000, edit ip and port parameters
35cuopt_service_client = CuOptServiceSelfHostClient(
36 ip="localhost",
37 port=5000,
38 polling_timeout=25,
39 timeout_exception=False
40)
41
42def repoll(solution, repoll_tries):
43 # If solver is still busy solving, the job will be assigned a request id and response is sent back in the
44 # following format {"reqId": <REQUEST-ID>}.
45 # Solver needs to be re-polled for response using this <REQUEST-ID>.
46
47 if "reqId" in solution and "response" not in solution:
48 req_id = solution["reqId"]
49 for i in range(repoll_tries):
50 solution = cuopt_service_client.repoll(req_id, response_type="dict")
51 if "reqId" in solution and "response" in solution:
52 break;
53
54 # Sleep for a second before requesting
55 time.sleep(1)
56
57 return solution
58
59solution = cuopt_service_client.get_LP_solve(data, response_type="dict")
60
61# Number of repoll requests to be carried out for a successful response
62repoll_tries = 500
63
64solution = repoll(solution, repoll_tries)
65
66print(json.dumps(solution, indent=4))
The response would be as follows:
1{
2 "response": {
3 "solver_response": {
4 "status": 1,
5 "solution": {
6 "problem_category": 1,
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 Solution#
The incumbent solution can be retrieved using a callback function as follows:
Note
Incumbent solution callback is only applicable to MILP.
1from cuopt_sh_client import CuOptServiceSelfHostClient
2import json
3import time
4
5data = {
6 "csr_constraint_matrix": {
7 "offsets": [0, 2],
8 "indices": [0, 1],
9 "values": [1.0, 1.0]
10 },
11 "constraint_bounds": {
12 "upper_bounds": [5000.0],
13 "lower_bounds": [0.0]
14 },
15 "objective_data": {
16 "coefficients": [1.2, 1.7],
17 "scalability_factor": 1.0,
18 "offset": 0.0
19 },
20 "variable_bounds": {
21 "upper_bounds": [3000.0, 5000.0],
22 "lower_bounds": [0.0, 0.0]
23 },
24 "maximize": True,
25 "variable_names": ["x", "y"],
26 "variable_types": ["I", "I"],
27 "solver_config":{
28 "time_limit": 30
29 }
30}
31
32# If cuOpt is not running on localhost:5000, edit ip and port parameters
33cuopt_service_client = CuOptServiceSelfHostClient(
34 ip="localhost",
35 port=5000,
36 timeout_exception=False
37)
38
39# callback should accept 2 values, one is solution and another is cost
40def callback(solution, solution_cost):
41 print(f"Solution : {solution} cost : {solution_cost}\n")
42
43# Logging callback
44def log_callback(log):
45 for i in log:
46 print("server-log: ", i)
47
48solution = cuopt_service_client.get_LP_solve(
49 data, incumbent_callback=callback, response_type="dict", logging_callback=log_callback
50)
51
52print(json.dumps(solution, indent=4))
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": 1,
5 "solution": {
6 "problem_category": 1,
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 request and solution API spec.
They can be of different format as well, please check the documentation.
Aborting a Running Job in Thin Client#
1from cuopt_sh_client import CuOptServiceSelfHostClient
2
3# This is an UUID that is returned by the solver while the solver is trying to find solution so users can come back and check the status or query for results.
4job_uuid = "<UUID_THAT_WE_GOT>"
5
6# If cuOpt is not running on localhost:5000, edit ip and port parameters
7cuopt_service_client = CuOptServiceSelfHostClient(
8 ip="localhost",
9 port=5000
10)
11
12# Delete the job if it is still queued or running
13response = cuopt_service_client.delete(job_uuid, running=True, queued=True, cached=False)
14
15print(response)
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