ortools.math_opt.python.ipc.remote_http_solve
Solve MathOpt models via HTTP request to the OR API.
1# Copyright 2010-2025 Google LLC 2# Licensed under the Apache License, Version 2.0 (the "License"); 3# you may not use this file except in compliance with the License. 4# You may obtain a copy of the License at 5# 6# http://www.apache.org/licenses/LICENSE-2.0 7# 8# Unless required by applicable law or agreed to in writing, software 9# distributed under the License is distributed on an "AS IS" BASIS, 10# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 11# See the License for the specific language governing permissions and 12# limitations under the License. 13 14"""Solve MathOpt models via HTTP request to the OR API.""" 15 16import json 17from typing import List, Optional, Tuple 18from google.protobuf import json_format 19import requests 20from ortools.service.v1 import optimization_pb2 21from ortools.math_opt import rpc_pb2 22from ortools.math_opt.python import mathopt 23from ortools.math_opt.python.ipc import proto_converter 24 25_DEFAULT_DEADLINE_SEC = 10 26_DEFAULT_ENDPOINT = "https://optimization.googleapis.com/v1/mathopt:solveMathOptModel" 27_RELATIVE_TIME_BUFFER = 0.05 28 29 30class OptimizationServiceError(Exception): 31 """Error produced when solving a MathOpt model via HTTP request.""" 32 33 34def remote_http_solve( 35 model: mathopt.Model, 36 solver_type: mathopt.SolverType, 37 params: Optional[mathopt.SolveParameters] = None, 38 model_params: Optional[mathopt.ModelSolveParameters] = None, 39 endpoint: Optional[str] = _DEFAULT_ENDPOINT, 40 api_key: Optional[str] = None, 41 deadline_sec: Optional[float] = _DEFAULT_DEADLINE_SEC, 42 resources: Optional[mathopt.SolverResources] = None, 43) -> Tuple[mathopt.SolveResult, List[str]]: 44 """Solves a MathOpt model via HTTP request to the OR API. 45 46 Args: 47 model: The optimization model. 48 solver_type: The underlying solver to use. 49 params: Optional configuration of the underlying solver. 50 model_params: Optional configuration of the solver that is model specific. 51 endpoint: An URI identifying the service for remote solves. 52 api_key: Key to the OR API. 53 deadline_sec: The number of seconds before the request times out. 54 resources: Hints on resources requested for the solve. 55 56 Returns: 57 A SolveResult containing the termination reason, solution(s) and stats. 58 A list of messages with the logs (if specified in the `params`). 59 60 Raises: 61 OptimizationServiceError: if an HTTP error is returned while solving a 62 model. 63 """ 64 if api_key is None: 65 # TODO(b/306709279): Relax this when unauthenticated solves are allowed. 66 raise ValueError("api_key can't be None when solving remotely") 67 68 payload = _build_json_payload(model, solver_type, params, model_params, resources) 69 70 session = create_optimization_service_session(api_key, deadline_sec) 71 response = session.post( 72 url=endpoint, 73 json=payload, 74 timeout=deadline_sec, 75 ) 76 77 if not response.ok: 78 http_error = json.loads(response.content)["error"] 79 raise OptimizationServiceError( 80 f'status code {http_error["code"]}: {http_error["message"]}' 81 ) from None 82 83 return _build_solve_result(response.content, model) 84 85 86def create_optimization_service_session( 87 api_key: str, 88 deadline_sec: float, 89) -> requests.Session: 90 """Creates a session with the appropriate headers. 91 92 This function sets headers for authentication via an API key, and it sets 93 deadlines set for the server and the connection. 94 95 Args: 96 api_key: Key to the OR API. 97 deadline_sec: The number of seconds before the request times out. 98 99 Returns: 100 requests.Session a session with the necessary headers to call the 101 optimization service. 102 """ 103 session = requests.Session() 104 server_timeout = deadline_sec * (1 - _RELATIVE_TIME_BUFFER) 105 session.headers = { 106 "Content-Type": "application/json", 107 "Connection": "keep-alive", 108 "Keep-Alive": f"timeout={deadline_sec}, max=1", 109 "X-Server-Timeout": f"{server_timeout}", 110 "X-Goog-Api-Key": api_key, 111 } 112 return session 113 114 115def _build_json_payload( 116 model: mathopt.Model, 117 solver_type: mathopt.SolverType, 118 params: Optional[mathopt.SolveParameters], 119 model_params: Optional[mathopt.ModelSolveParameters], 120 resources: Optional[mathopt.SolverResources], 121): 122 """Builds a JSON payload. 123 124 Args: 125 model: The optimization model. 126 solver_type: The underlying solver to use. 127 params: Optional configuration of the underlying solver. 128 model_params: Optional configuration of the solver that is model specific. 129 resources: Hints on resources requested for the solve. 130 131 Returns: 132 A JSON object with a MathOpt model and corresponding parameters. 133 134 Raises: 135 SerializationError: If building the OR API proto is not successful or 136 deserializing to JSON fails. 137 """ 138 params = params or mathopt.SolveParameters() 139 model_params = model_params or mathopt.ModelSolveParameters() 140 resources = resources or mathopt.SolverResources() 141 try: 142 request = rpc_pb2.SolveRequest( 143 model=model.export_model(), 144 solver_type=solver_type.value, 145 resources=resources.to_proto(), 146 parameters=params.to_proto(), 147 model_parameters=model_params.to_proto(), 148 ) 149 api_request = proto_converter.convert_request(request) 150 except ValueError as err: 151 raise ValueError from err 152 153 return json.loads(json_format.MessageToJson(api_request)) 154 155 156def _build_solve_result( 157 json_response: bytes, model: mathopt.Model 158) -> Tuple[mathopt.SolveResult, List[str]]: 159 """Parses a JSON representation of a response to a SolveResult object. 160 161 Args: 162 json_response: bytes representing the `SolveMathOptModelResponse` in JSON 163 format 164 model: The optimization model that was solved 165 166 Returns: 167 A SolveResult of the model. 168 A list of messages with the logs. 169 170 Raises: 171 SerializationError: If parsing the json response fails or if converting the 172 OR API response to the internal MathOpt response fails. 173 """ 174 try: 175 api_response = json_format.Parse( 176 json_response, optimization_pb2.SolveMathOptModelResponse() 177 ) 178 except json_format.ParseError as json_err: 179 raise ValueError( 180 "API response is not a valid SolveMathOptModelResponse JSON" 181 ) from json_err 182 183 response = proto_converter.convert_response(api_response) 184 return mathopt.parse_solve_result(response.result, model), list(response.messages)
class
OptimizationServiceError(builtins.Exception):
31class OptimizationServiceError(Exception): 32 """Error produced when solving a MathOpt model via HTTP request."""
Error produced when solving a MathOpt model via HTTP request.
def
remote_http_solve( model: ortools.math_opt.python.model.Model, solver_type: ortools.math_opt.python.parameters.SolverType, params: Optional[ortools.math_opt.python.parameters.SolveParameters] = None, model_params: Optional[ortools.math_opt.python.model_parameters.ModelSolveParameters] = None, endpoint: Optional[str] = 'https://optimization.googleapis.com/v1/mathopt:solveMathOptModel', api_key: Optional[str] = None, deadline_sec: Optional[float] = 10, resources: Optional[ortools.math_opt.python.solver_resources.SolverResources] = None) -> Tuple[ortools.math_opt.python.result.SolveResult, List[str]]:
35def remote_http_solve( 36 model: mathopt.Model, 37 solver_type: mathopt.SolverType, 38 params: Optional[mathopt.SolveParameters] = None, 39 model_params: Optional[mathopt.ModelSolveParameters] = None, 40 endpoint: Optional[str] = _DEFAULT_ENDPOINT, 41 api_key: Optional[str] = None, 42 deadline_sec: Optional[float] = _DEFAULT_DEADLINE_SEC, 43 resources: Optional[mathopt.SolverResources] = None, 44) -> Tuple[mathopt.SolveResult, List[str]]: 45 """Solves a MathOpt model via HTTP request to the OR API. 46 47 Args: 48 model: The optimization model. 49 solver_type: The underlying solver to use. 50 params: Optional configuration of the underlying solver. 51 model_params: Optional configuration of the solver that is model specific. 52 endpoint: An URI identifying the service for remote solves. 53 api_key: Key to the OR API. 54 deadline_sec: The number of seconds before the request times out. 55 resources: Hints on resources requested for the solve. 56 57 Returns: 58 A SolveResult containing the termination reason, solution(s) and stats. 59 A list of messages with the logs (if specified in the `params`). 60 61 Raises: 62 OptimizationServiceError: if an HTTP error is returned while solving a 63 model. 64 """ 65 if api_key is None: 66 # TODO(b/306709279): Relax this when unauthenticated solves are allowed. 67 raise ValueError("api_key can't be None when solving remotely") 68 69 payload = _build_json_payload(model, solver_type, params, model_params, resources) 70 71 session = create_optimization_service_session(api_key, deadline_sec) 72 response = session.post( 73 url=endpoint, 74 json=payload, 75 timeout=deadline_sec, 76 ) 77 78 if not response.ok: 79 http_error = json.loads(response.content)["error"] 80 raise OptimizationServiceError( 81 f'status code {http_error["code"]}: {http_error["message"]}' 82 ) from None 83 84 return _build_solve_result(response.content, model)
Solves a MathOpt model via HTTP request to the OR API.
Arguments:
- model: The optimization model.
- solver_type: The underlying solver to use.
- params: Optional configuration of the underlying solver.
- model_params: Optional configuration of the solver that is model specific.
- endpoint: An URI identifying the service for remote solves.
- api_key: Key to the OR API.
- deadline_sec: The number of seconds before the request times out.
- resources: Hints on resources requested for the solve.
Returns:
A SolveResult containing the termination reason, solution(s) and stats. A list of messages with the logs (if specified in the
params
).
Raises:
- OptimizationServiceError: if an HTTP error is returned while solving a model.
def
create_optimization_service_session(api_key: str, deadline_sec: float) -> requests.sessions.Session:
87def create_optimization_service_session( 88 api_key: str, 89 deadline_sec: float, 90) -> requests.Session: 91 """Creates a session with the appropriate headers. 92 93 This function sets headers for authentication via an API key, and it sets 94 deadlines set for the server and the connection. 95 96 Args: 97 api_key: Key to the OR API. 98 deadline_sec: The number of seconds before the request times out. 99 100 Returns: 101 requests.Session a session with the necessary headers to call the 102 optimization service. 103 """ 104 session = requests.Session() 105 server_timeout = deadline_sec * (1 - _RELATIVE_TIME_BUFFER) 106 session.headers = { 107 "Content-Type": "application/json", 108 "Connection": "keep-alive", 109 "Keep-Alive": f"timeout={deadline_sec}, max=1", 110 "X-Server-Timeout": f"{server_timeout}", 111 "X-Goog-Api-Key": api_key, 112 } 113 return session
Creates a session with the appropriate headers.
This function sets headers for authentication via an API key, and it sets deadlines set for the server and the connection.
Arguments:
- api_key: Key to the OR API.
- deadline_sec: The number of seconds before the request times out.
Returns:
requests.Session a session with the necessary headers to call the optimization service.