Google OR-Tools v9.15
a fast and portable software suite for combinatorial optimization
Loading...
Searching...
No Matches
result.proto
Go to the documentation of this file.
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// The result of solving a MathOpt model, both the Solution and metadata.
15
16syntax = "proto3";
17
18package operations_research.service.v1.mathopt;
19
20import "google/protobuf/duration.proto";
21import "ortools/service/v1/mathopt/solution.proto";
22
23option java_multiple_files = true;
24option java_package = "com.google.ortools.service.v1.mathopt";
25
26option csharp_namespace = "Google.OrTools.Service";
27
28// Problem feasibility status as claimed by the solver (solver is not required
29// to return a certificate for the claim).
30enum FeasibilityStatusProto {
31 // Guard value representing no status.
32 FEASIBILITY_STATUS_UNSPECIFIED = 0;
33
34 // Solver does not claim a status.
35 FEASIBILITY_STATUS_UNDETERMINED = 1;
36
37 // Solver claims the problem is feasible.
38 FEASIBILITY_STATUS_FEASIBLE = 2;
39
40 // Solver claims the problem is infeasible.
41 FEASIBILITY_STATUS_INFEASIBLE = 3;
42}
43
44// Feasibility status of the primal problem and its dual (or the dual of a
45// continuous relaxation) as claimed by the solver. The solver is not required
46// to return a certificate for the claim (e.g. the solver may claim primal
47// feasibility without returning a primal feasible solutuion). This combined
48// status gives a comprehensive description of a solver's claims about
49// feasibility and unboundedness of the solved problem. For instance,
50//
51// * a feasible status for primal and dual problems indicates the primal is
52// feasible and bounded and likely has an optimal solution (guaranteed for
53// problems without non-linear constraints).
54// * a primal feasible and a dual infeasible status indicates the primal
55// problem is unbounded (i.e. has arbitrarily good solutions).
56//
57// Note that a dual infeasible status by itself (i.e. accompanied by an
58// undetermined primal status) does not imply the primal problem is unbounded as
59// we could have both problems be infeasible. Also, while a primal and dual
60// feasible status may imply the existence of an optimal solution, it does not
61// guarantee the solver has actually found such optimal solution.
62message ProblemStatusProto {
63 // Status for the primal problem.
64 FeasibilityStatusProto primal_status = 1;
65
66 // Status for the dual problem (or for the dual of a continuous relaxation).
67 FeasibilityStatusProto dual_status = 2;
68
69 // If true, the solver claims the primal or dual problem is infeasible, but
70 // it does not know which (or if both are infeasible). Can be true only when
71 // primal_problem_status = dual_problem_status = kUndetermined. This extra
72 // information is often needed when preprocessing determines there is no
73 // optimal solution to the problem (but can't determine if it is due to
74 // infeasibility, unboundedness, or both).
75 bool primal_or_dual_infeasible = 3;
76}
77
78message SolveStatsProto {
79 // Elapsed wall clock time as measured by math_opt, roughly the time inside
80 // Solver::Solve(). Note: this does not include work done building the model.
81 google.protobuf.Duration solve_time = 1;
82
83 // Fields previously used for `best_primal_bound` and `best_dual_bound`.
84 reserved 2, 3;
85
86 // Feasibility statuses for primal and dual problems.
87 ProblemStatusProto problem_status = 4;
88
89 int64 simplex_iterations = 5;
90
91 int64 barrier_iterations = 6;
92
93 int64 first_order_iterations = 8;
94
95 int64 node_count = 7;
96
97 // Next id: 9
98}
99
100// The reason a call to Solve() terminates.
101enum TerminationReasonProto {
102 TERMINATION_REASON_UNSPECIFIED = 0;
103
104 // A provably optimal solution (up to numerical tolerances) has been found.
105 TERMINATION_REASON_OPTIMAL = 1;
106
107 // The primal problem has no feasible solutions.
108 TERMINATION_REASON_INFEASIBLE = 2;
109
110 // The primal problem is feasible and arbitrarily good solutions can be
111 // found along a primal ray.
112 TERMINATION_REASON_UNBOUNDED = 3;
113
114 // The primal problem is either infeasible or unbounded. More details on the
115 // problem status may be available in solve_stats.problem_status. Note that
116 // Gurobi's unbounded status may be mapped here.
117 TERMINATION_REASON_INFEASIBLE_OR_UNBOUNDED = 4;
118
119 // The problem was solved to one of the criteria above (Optimal, Infeasible,
120 // Unbounded, or InfeasibleOrUnbounded), but one or more tolerances was not
121 // met. Some primal/dual solutions/rays be present, but either they will be
122 // slightly infeasible, or (if the problem was nearly optimal) their may be
123 // a gap between the best solution objective and best objective bound.
124 //
125 // Users can still query primal/dual solutions/rays and solution stats, but
126 // they are responsible for dealing with the numerical imprecision.
127 TERMINATION_REASON_IMPRECISE = 5;
128
129 // The optimizer reached some kind of limit and a primal feasible solution
130 // is returned. See SolveResultProto.limit_detail for detailed description of
131 // the kind of limit that was reached.
132 TERMINATION_REASON_FEASIBLE = 9;
133
134 // The optimizer reached some kind of limit and it did not find a primal
135 // feasible solution. See SolveResultProto.limit_detail for detailed
136 // description of the kind of limit that was reached.
137 TERMINATION_REASON_NO_SOLUTION_FOUND = 6;
138
139 // The algorithm stopped because it encountered unrecoverable numerical
140 // error. No solution information is available.
141 TERMINATION_REASON_NUMERICAL_ERROR = 7;
142
143 // The algorithm stopped because of an error not covered by one of the
144 // statuses defined above. No solution information is available.
145 TERMINATION_REASON_OTHER_ERROR = 8;
146}
147
148// When a Solve() stops early with TerminationReasonProto FEASIBLE or
149// NO_SOLUTION_FOUND, the specific limit that was hit.
150enum LimitProto {
151 // Used as a null value when we terminated not from a limit (e.g.
152 // TERMINATION_REASON_OPTIMAL).
153 LIMIT_UNSPECIFIED = 0;
154
155 // The underlying solver does not expose which limit was reached.
156 LIMIT_UNDETERMINED = 1;
157
158 // An iterative algorithm stopped after conducting the maximum number of
159 // iterations (e.g. simplex or barrier iterations).
160 LIMIT_ITERATION = 2;
161
162 // The algorithm stopped after a user-specified computation time.
163 LIMIT_TIME = 3;
164
165 // A branch-and-bound algorithm stopped because it explored a maximum number
166 // of nodes in the branch-and-bound tree.
167 LIMIT_NODE = 4;
168
169 // The algorithm stopped because it found the required number of solutions.
170 // This is often used in MIPs to get the solver to return the first feasible
171 // solution it encounters.
172 LIMIT_SOLUTION = 5;
173
174 // The algorithm stopped because it ran out of memory.
175 LIMIT_MEMORY = 6;
176
177 // The solver was run with a cutoff (e.g. SolveParameters.cutoff_limit was
178 // set) on the objective, indicating that the user did not want any solution
179 // worse than the cutoff, and the solver concluded there were no solutions at
180 // least as good as the cutoff. Typically no further solution information is
181 // provided.
182 LIMIT_CUTOFF = 12;
183
184 // The algorithm stopped because it either found a solution or a bound better
185 // than a limit set by the user (see SolveParameters.objective_limit and
186 // SolveParameters.best_bound_limit).
187 LIMIT_OBJECTIVE = 7;
188
189 // The algorithm stopped because the norm of an iterate became too large.
190 LIMIT_NORM = 8;
191
192 // The algorithm stopped because of an interrupt signal or a user interrupt
193 // request.
194 LIMIT_INTERRUPTED = 9;
195
196 // The algorithm stopped because it was unable to continue making progress
197 // towards the solution.
198 LIMIT_SLOW_PROGRESS = 10;
199
200 // The algorithm stopped due to a limit not covered by one of the above. Note
201 // that LIMIT_UNDETERMINED is used when the reason cannot be determined, and
202 // LIMIT_OTHER is used when the reason is known but does not fit into any of
203 // the above alternatives.
204 //
205 // TerminationProto.detail may contain additional information about the limit.
206 LIMIT_OTHER = 11;
207}
208
209// Bounds on the optimal objective value.
210message ObjectiveBoundsProto {
211 // Solver claims the optimal value is equal or better (smaller for
212 // minimization and larger for maximization) than primal_bound up to the
213 // solvers primal feasibility tolerance (see warning below):
214 // * primal_bound is trivial (+inf for minimization and -inf
215 // maximization) when the solver does not claim to have such bound.
216 // * primal_bound can be closer to the optimal value than the objective
217 // of the best primal feasible solution. In particular, primal_bound
218 // may be non-trivial even when no primal feasible solutions are returned.
219 // Warning: The precise claim is that there exists a primal solution that:
220 // * is numerically feasible (i.e. feasible up to the solvers tolerance), and
221 // * has an objective value primal_bound.
222 // This numerically feasible solution could be slightly infeasible, in which
223 // case primal_bound could be strictly better than the optimal value.
224 // Translating a primal feasibility tolerance to a tolerance on
225 // primal_bound is non-trivial, specially when the feasibility tolerance
226 // is relatively large (e.g. when solving with PDLP).
227 double primal_bound = 2;
228
229 // Solver claims the optimal value is equal or worse (larger for
230 // minimization and smaller for maximization) than dual_bound up to the
231 // solvers dual feasibility tolerance (see warning below):
232 // * dual_bound is trivial (-inf for minimization and +inf
233 // maximization) when the solver does not claim to have such bound.
234 // Similarly to primal_bound, this may happen for some solvers even
235 // when returning optimal. MIP solvers will typically report a bound even
236 // if it is imprecise.
237 // * for continuous problems dual_bound can be closer to the optimal
238 // value than the objective of the best dual feasible solution. For MIP
239 // one of the first non-trivial values for dual_bound is often the
240 // optimal value of the LP relaxation of the MIP.
241 // * dual_bound should be better (smaller for minimization and larger
242 // for maximization) than primal_bound up to the solvers tolerances
243 // (see warning below).
244 // Warning:
245 // * For continuous problems, the precise claim is that there exists a
246 // dual solution that:
247 // * is numerically feasible (i.e. feasible up to the solvers tolerance),
248 // and
249 // * has an objective value dual_bound.
250 // This numerically feasible solution could be slightly infeasible, in
251 // which case dual_bound could be strictly worse than the optimal
252 // value and primal_bound. Similar to the primal case, translating a
253 // dual feasibility tolerance to a tolerance on dual_bound is
254 // non-trivial, specially when the feasibility tolerance is relatively
255 // large. However, some solvers provide a corrected version of
256 // dual_bound that can be numerically safer. This corrected version
257 // can be accessed through the solver's specific output (e.g. for PDLP,
258 // pdlp_output.convergence_information.corrected_dual_objective).
259 // * For MIP solvers, dual_bound may be associated to a dual solution
260 // for some continuous relaxation (e.g. LP relaxation), but it is often a
261 // complex consequence of the solvers execution and is typically more
262 // imprecise than the bounds reported by LP solvers.
263 double dual_bound = 3;
264}
265
266// All information regarding why a call to Solve() terminated.
267message TerminationProto {
268 // Additional information in `limit` when value is TERMINATION_REASON_FEASIBLE
269 // or TERMINATION_REASON_NO_SOLUTION_FOUND, see `limit` for details.
270 TerminationReasonProto reason = 1;
271
272 // Is LIMIT_UNSPECIFIED unless reason is TERMINATION_REASON_FEASIBLE or
273 // TERMINATION_REASON_NO_SOLUTION_FOUND. Not all solvers can always determine
274 // the limit which caused termination, LIMIT_UNDETERMINED is used when the
275 // cause cannot be determined.
276 LimitProto limit = 2;
277
278 // Additional typically solver specific information about termination.
279 string detail = 3;
280
281 // Feasibility statuses for primal and dual problems.
282 // As of July 18, 2023 this message may be missing. If missing, problem_status
283 // can be found in SolveResultProto.solve_stats.
284 ProblemStatusProto problem_status = 4;
285
286 // Bounds on the optimal objective value.
287 // As of July 18, 2023 this message may be missing. If missing,
288 // objective_bounds.primal_bound can be found in
289 // SolveResultProto.solve.stats.best_primal_bound and
290 // objective_bounds.dual_bound can be found in
291 // SolveResultProto.solve.stats.best_dual_bound
292 ObjectiveBoundsProto objective_bounds = 5;
293}
294
295// The contract of when primal/dual solutions/rays is complex, see
296// termination_reasons.md for a complete description.
297//
298// Until an exact contract is finalized, it is safest to simply check if a
299// solution/ray is present rather than relying on the termination reason.
300message SolveResultProto {
301 // The reason the solver stopped.
302 TerminationProto termination = 2;
303
304 // Basic solutions use, as of Nov 2021:
305 // * All convex optimization solvers (LP, convex QP) return only one
306 // solution as a primal dual pair.
307 // * Only MI(Q)P solvers return more than one solution. MIP solvers do not
308 // return any dual information, or primal infeasible solutions. Solutions
309 // are returned in order of best primal objective first. Gurobi solves
310 // nonconvex QP (integer or continuous) as MIQP.
311
312 // The general contract for the order of solutions that future solvers should
313 // implement is to order by:
314 // 1. The solutions with a primal feasible solution, ordered by best primal
315 // objective first.
316 // 2. The solutions with a dual feasible solution, ordered by best dual
317 // objective (unknown dual objective is worst)
318 // 3. All remaining solutions can be returned in any order.
319 repeated SolutionProto solutions = 3;
320
321 // Directions of unbounded primal improvement, or equivalently, dual
322 // infeasibility certificates. Typically provided for TerminationReasonProtos
323 // UNBOUNDED and DUAL_INFEASIBLE
324 repeated PrimalRayProto primal_rays = 4;
325
326 // Directions of unbounded dual improvement, or equivalently, primal
327 // infeasibility certificates. Typically provided for TerminationReasonProto
328 // INFEASIBLE.
329 repeated DualRayProto dual_rays = 5;
330
331 // Statistics on the solve process, e.g. running time, iterations.
332 SolveStatsProto solve_stats = 6;
333
334 reserved 7, 8, 9;
335
336 reserved 1; // Deleted fields.
337}