Routing Python Examples#

The following example showcases how to use the CuOptServiceSelfHostClient to solve a simple routing problem.

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 OptimizeRoutingData under schema section.

Generic Example#

 1from cuopt_sh_client import CuOptServiceSelfHostClient
 2import json
 3import time
 4
 5# Example data for routing problem
 6# The data is structured as per the OpenAPI specification for the server, please refer /cuopt/request -> schema -> OptimizeRoutingData
 7data = {"cost_matrix_data": {"data": {"0": [[0,1],[1,0]]}},
 8        "task_data": {"task_locations": [0,1]},
 9        "fleet_data": {"vehicle_locations": [[0,0],[0,0]]}}
10
11# If cuOpt is not running on localhost:5000, edit ip and port parameters
12cuopt_service_client = CuOptServiceSelfHostClient(
13    ip="localhost",
14    port=5000,
15    polling_timeout=25,
16    timeout_exception=False
17)
18
19def repoll(solution, repoll_tries):
20    # If solver is still busy solving, the job will be assigned a request id and response is sent back in the
21    # following format {"reqId": <REQUEST-ID>}.
22    # Solver needs to be re-polled for response using this <REQUEST-ID>.
23
24    if "reqId" in solution and "response" not in solution:
25        req_id = solution["reqId"]
26        for i in range(repoll_tries):
27            solution = cuopt_service_client.repoll(req_id, response_type="dict")
28            if "reqId" in solution and "response" in solution:
29                break;
30
31            # Sleep for a second before requesting
32            time.sleep(1)
33
34    return solution
35
36solution = cuopt_service_client.get_optimized_routes(data)
37
38# Number of repoll requests to be carried out for a successful response
39repoll_tries = 500
40
41solution = repoll(solution, repoll_tries)
42
43print(json.dumps(solution, indent=4))

The response would be as follows:

 1{
 2"response": {
 3    "solver_response": {
 4        "status": 0,
 5        "num_vehicles": 1,
 6        "solution_cost": 2.0,
 7        "objective_values": {
 8            "cost": 2.0
 9        },
10        "vehicle_data": {
11            "0": {
12                "task_id": [
13                    "Depot",
14                    "0",
15                    "1",
16                    "Depot"
17                ],
18                "arrival_stamp": [
19                    0.0,
20                    0.0,
21                    0.0,
22                    0.0
23                ],
24                "type": [
25                    "Depot",
26                    "Delivery",
27                    "Delivery",
28                    "Depot"
29                ],
30                "route": [
31                    0,
32                    0,
33                    1,
34                    0
35                ]
36            }
37        },
38        "initial_solutions": [],
39        "dropped_tasks": {
40            "task_id": [],
41            "task_index": []
42        }
43    },
44    "total_solve_time": 0.1120915412902832
45},
46"reqId": "ebd378a3-c02a-47f3-b0a1-adec81be7cdd"
47}

Initial Solution#

Previously run solutions or uploaded solutions can be used as the initial solution for new requests using previously run reqIds as follows:

 1from cuopt_sh_client import CuOptServiceSelfHostClient
 2import json
 3import time
 4
 5data = {"cost_matrix_data": {"data": {"0": [[0,1],[1,0]]}},
 6        "task_data": {"task_locations": [0,1]},
 7        "fleet_data": {"vehicle_locations": [[0,0],[0,0]]}}
 8
 9# If cuOpt is not running on localhost:5000, edit ip and port parameters
10cuopt_service_client = CuOptServiceSelfHostClient(
11    ip="localhost",
12    port=5000,
13    timeout_exception=False
14)
15
16# Get initial solution
17# Set delete_solution to false so it can be used in next request
18initial_solution = cuopt_service_client.get_optimized_routes(
19    data, delete_solution=False
20)
21
22
23# Upload a solution returned/saved from previous request as initial solution
24initial_solution_3 = cuopt_service_client.upload_solution(initial_solution)
25
26# Use previous solution saved in server as initial solution to this request.
27# That solution is referenced with previous request id.
28solution = cuopt_service_client.get_optimized_routes(
29    data,
30    initial_ids=[
31        initial_solution["reqId"],
32        initial_solution_3["reqId"]
33    ]
34)
35
36print(json.dumps(solution, indent=4))
37
38# Delete saved solution if not required to save space
39cuopt_service_client.delete(initial_solution["reqId"])
40cuopt_service_client.delete(initial_solution_3["reqId"])
41
42# Another option is to add a solution that was generated
43# to data model option as follows
44initial_solution_2 = [
45    {
46        "0": {
47            "task_id": ["Depot", "0", "1", "Depot"],
48            "type": ["Depot", "Delivery", "Delivery", "Depot"]
49        }
50    }
51]
52
53data["initial_solution"] = initial_solution_2
54solution = cuopt_service_client.get_optimized_routes(data)
55
56print(json.dumps(solution, indent=4))

The initial solution in the response is not accepted, because the problem is too small, and the optimal solution is found even before cuOpt could use an initial solution.

The response would be as follows:

 1{
 2"response": {
 3    "solver_response": {
 4        "status": 0,
 5        "num_vehicles": 1,
 6        "solution_cost": 2.0,
 7        "objective_values": {
 8            "cost": 2.0
 9        },
10        "vehicle_data": {
11            "0": {
12                "task_id": [
13                    "Depot",
14                    "0",
15                    "1",
16                    "Depot"
17                ],
18                "arrival_stamp": [
19                    0.0,
20                    0.0,
21                    0.0,
22                    0.0
23                ],
24                "type": [
25                    "Depot",
26                    "Delivery",
27                    "Delivery",
28                    "Depot"
29                ],
30                "route": [
31                    0,
32                    0,
33                    1,
34                    0
35                ]
36            }
37        },
38        "initial_solutions": [
39            "not accepted",
40        ],
41        "dropped_tasks": {
42            "task_id": [],
43            "task_index": []
44        }
45    },
46    "total_solve_time": 0.06160402297973633
47},
48"reqId": "ebd378a3-c02a-47f3-b0a1-adec81be7cdd"
49}

The data argument to get_optimized_routes may be a dictionary of the format shown in Get Routes Open-API spec. It may also be the path of a file containing such a dictionary as JSON or written using the Python msgpack module. A JSON file may optionally be compressed with zlib. More details on the responses can be found under the responses schema under request and solution API spec.

To enable HTTPS:

  • In the case of the server using public certificates, simply enable https.

     1from cuopt_sh_client import CuOptServiceSelfHostClient
     2
     3data = {"cost_matrix_data": {"data": {"0": [[0,1],[1,0]]}},
     4        "task_data": {"task_locations": [0,1]},
     5        "fleet_data": {"vehicle_locations": [[0,0],[0,0]]}}
     6
     7# If cuOpt is not running on localhost:5000, edit ip and port parameters
     8cuopt_service_client = CuOptServiceSelfHostClient(
     9    ip="localhost",
    10    port=5000,
    11    use_https=True
    12)
    
  • In the case of a self-signed certificate, provide the complete path to the certificate.

     1from cuopt_sh_client import CuOptServiceSelfHostClient
     2
     3data = {"cost_matrix_data": {"data": {"0": [[0,1],[1,0]]}},
     4        "task_data": {"task_locations": [0,1]},
     5        "fleet_data": {"vehicle_locations": [[0,0],[0,0]]}}
     6
     7# If cuOpt is not running on localhost:5000, edit ip and port parameters
     8cuopt_service_client = CuOptServiceSelfHostClient(
     9    ip="localhost",
    10    port=5000,
    11    use_https=True,
    12    self_signed_cert=/complete/path/to/certificate
    13)
    

    You can generate a self-signed certificate easily as follows:

    openssl genrsa -out ca.key 2048
    openssl req -new -x509 -days 365 -key ca.key -subj "/C=CN/ST=GD/L=SZ/O=Acme, Inc./CN=Acme Root CA" -out ca.crt
    
    openssl req -newkey rsa:2048 -nodes -keyout server.key -subj "/C=CN/ST=GD/L=SZ/O=Acme, Inc./CN=*.example.com" -out server.csr
    openssl x509 -req -extfile <(printf "subjectAltName=DNS:example.com,DNS:www.example.com") -days 365 -in server.csr -CA ca.crt -CAkey ca.key -CAcreateserial -out server.crt
    

    server.crt and server.key are meant for server, ca.crt is meant for client.

More examples are available in the Examples Notebooks Repository.

Aborting a Running Job in Thin Client#

Please refer to the MILP Example on Aborting a Running Job in Thin Client for more details.

Routing CLI Examples#

Create a data.json file containing this sample data:

Routing Example#

echo '{"cost_matrix_data": {"data": {"0": [[0, 1], [1, 0]]}},
 "task_data": {"task_locations": [0, 1]},
 "fleet_data": {"vehicle_locations": [[0, 0], [0, 0]]}}' > data.json

Invoke the CLI.

# client's default ip address for cuOpt is localhost:5000 if ip/port are not specified
export ip="localhost"
export port=5000
cuopt_sh data.json -i $ip -p $port

Initial Solution in CLI#

To use a previous solution as an initial solution for a new request ID, you are required to save the previous solution, which can be accomplished use option -k. Use the previous reqId in the next request 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
reqId=$(cuopt_sh data.json -i $ip -p $port -k | sed "s/'/\"/g" | jq -r '.reqId')

cuopt_sh data.json -i $ip -p $port -id $reqId

# delete previous saved solutions using follwing command
cuopt_sh -i $ip -p $port -d $reqId

Uploading a Solution#

Users can also upload a solution which might have been saved for later runs.

# Please update ip and port if the server is running on a different IP address or port
export ip="localhost"
export port=5000

# Save solution to a file
cuopt_sh data.json -i $ip -p $port | sed "s/'/\"/g" > solution.json

# Upload the solution and get request-id generated for that
reqId=$(cuopt_sh solution.json -us -i $ip -p $port | sed "s/'/\"/g" | jq -r '.reqId')

# Use this request id for initial solution
cuopt_sh data.json -i $ip -p $port -id $reqId

# delete previous saved solutions using follwing command
cuopt_sh -i $ip -p $port -ds $reqId

Aborting a Running Job In CLI#

Please refer to the MILP Example for more details.

Note

Please use solver settings while using .mps files.

To enable HTTPS#

  • In the case of the server using public certificates, simply enable https.

    cuopt_sh data.json -s -i $ip -p $port
    
  • In the case of a self-signed certificate, provide the complete path to the certificate.

    cuopt_sh data.json -s -c /complete/path/to/certificate -i $ip -p $port