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.