Google OR-Tools v9.11
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-2024 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.
15syntax = "proto3";
16
17package operations_research.math_opt;
18
19import "google/protobuf/duration.proto";
20import "ortools/pdlp/solve_log.proto";
21import "ortools/gscip/gscip.proto";
22import "ortools/math_opt/solution.proto";
23import "ortools/math_opt/solvers/osqp.proto";
24
25option java_package = "com.google.ortools.mathopt";
26option java_multiple_files = true;
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 // Deprecated in favor of ObjectiveBoundsProto.primal_bound found in
84 // TerminationProto.
85 double best_primal_bound = 2 [deprecated = true];
86
87 // Deprecated in favor of ObjectiveBoundsProto.dual_bound found in
88 // TerminationProto.
89 double best_dual_bound = 3 [deprecated = true];
90
91 // The presence of problem_status in SolverStatsProto is deprecated in favor
92 // of the same ProblemStatusProto message found in TerminationProto.
93 ProblemStatusProto problem_status = 4 [deprecated = true];
94
95 int64 simplex_iterations = 5;
96
97 int64 barrier_iterations = 6;
98
99 int64 first_order_iterations = 8;
100
101 int64 node_count = 7;
102
103 // Next id: 9
104}
105
106// The reason a call to Solve() terminates.
107enum TerminationReasonProto {
108 TERMINATION_REASON_UNSPECIFIED = 0;
109
110 // A provably optimal solution (up to numerical tolerances) has been found.
111 TERMINATION_REASON_OPTIMAL = 1;
112
113 // The primal problem has no feasible solutions.
114 TERMINATION_REASON_INFEASIBLE = 2;
115
116 // The primal problem is feasible and arbitrarily good solutions can be
117 // found along a primal ray.
118 TERMINATION_REASON_UNBOUNDED = 3;
119
120 // The primal problem is either infeasible or unbounded. More details on the
121 // problem status may be available in solve_stats.problem_status. Note that
122 // Gurobi's unbounded status may be mapped here.
123 TERMINATION_REASON_INFEASIBLE_OR_UNBOUNDED = 4;
124
125 // The problem was solved to one of the criteria above (Optimal, Infeasible,
126 // Unbounded, or InfeasibleOrUnbounded), but one or more tolerances was not
127 // met. Some primal/dual solutions/rays be present, but either they will be
128 // slightly infeasible, or (if the problem was nearly optimal) their may be
129 // a gap between the best solution objective and best objective bound.
130 //
131 // Users can still query primal/dual solutions/rays and solution stats, but
132 // they are responsible for dealing with the numerical imprecision.
133 TERMINATION_REASON_IMPRECISE = 5;
134
135 // The optimizer reached some kind of limit and a primal feasible solution
136 // is returned. See SolveResultProto.limit_detail for detailed description of
137 // the kind of limit that was reached.
138 TERMINATION_REASON_FEASIBLE = 9;
139
140 // The optimizer reached some kind of limit and it did not find a primal
141 // feasible solution. See SolveResultProto.limit_detail for detailed
142 // description of the kind of limit that was reached.
143 TERMINATION_REASON_NO_SOLUTION_FOUND = 6;
144
145 // The algorithm stopped because it encountered unrecoverable numerical
146 // error. No solution information is available.
147 TERMINATION_REASON_NUMERICAL_ERROR = 7;
148
149 // The algorithm stopped because of an error not covered by one of the
150 // statuses defined above. No solution information is available.
151 TERMINATION_REASON_OTHER_ERROR = 8;
152}
153
154// When a Solve() stops early with TerminationReasonProto FEASIBLE or
155// NO_SOLUTION_FOUND, the specific limit that was hit.
156enum LimitProto {
157 // Used as a null value when we terminated not from a limit (e.g.
158 // TERMINATION_REASON_OPTIMAL).
159 LIMIT_UNSPECIFIED = 0;
160
161 // The underlying solver does not expose which limit was reached.
162 LIMIT_UNDETERMINED = 1;
163
164 // An iterative algorithm stopped after conducting the maximum number of
165 // iterations (e.g. simplex or barrier iterations).
166 LIMIT_ITERATION = 2;
167
168 // The algorithm stopped after a user-specified computation time.
169 LIMIT_TIME = 3;
170
171 // A branch-and-bound algorithm stopped because it explored a maximum number
172 // of nodes in the branch-and-bound tree.
173 LIMIT_NODE = 4;
174
175 // The algorithm stopped because it found the required number of solutions.
176 // This is often used in MIPs to get the solver to return the first feasible
177 // solution it encounters.
178 LIMIT_SOLUTION = 5;
179
180 // The algorithm stopped because it ran out of memory.
181 LIMIT_MEMORY = 6;
182
183 // The solver was run with a cutoff (e.g. SolveParameters.cutoff_limit was
184 // set) on the objective, indicating that the user did not want any solution
185 // worse than the cutoff, and the solver concluded there were no solutions at
186 // least as good as the cutoff. Typically no further solution information is
187 // provided.
188 LIMIT_CUTOFF = 12;
189
190 // The algorithm stopped because it either found a solution or a bound better
191 // than a limit set by the user (see SolveParameters.objective_limit and
192 // SolveParameters.best_bound_limit).
193 LIMIT_OBJECTIVE = 7;
194
195 // The algorithm stopped because the norm of an iterate became too large.
196 LIMIT_NORM = 8;
197
198 // The algorithm stopped because of an interrupt signal or a user interrupt
199 // request.
200 LIMIT_INTERRUPTED = 9;
201
202 // The algorithm stopped because it was unable to continue making progress
203 // towards the solution.
204 LIMIT_SLOW_PROGRESS = 10;
205
206 // The algorithm stopped due to a limit not covered by one of the above. Note
207 // that LIMIT_UNDETERMINED is used when the reason cannot be determined, and
208 // LIMIT_OTHER is used when the reason is known but does not fit into any of
209 // the above alternatives.
210 //
211 // TerminationProto.detail may contain additional information about the limit.
212 LIMIT_OTHER = 11;
213}
214
215// Bounds on the optimal objective value.
216message ObjectiveBoundsProto {
217 // Solver claims there exists a primal solution that is numerically feasible
218 // (i.e. feasible up to the solvers tolerance), and whose objective value is
219 // primal_bound.
220 //
221 // The optimal value is equal or better (smaller for min objectives and larger
222 // for max objectives) than primal_bound, but only up to solver-tolerances.
223 double primal_bound = 2;
224
225 // Solver claims there exists a dual solution that is numerically feasible
226 // (i.e. feasible up to the solvers tolerance), and whose objective value is
227 // dual_bound.
228 //
229 // For MIP solvers, the associated dual problem may be some continuous
230 // relaxation (e.g. LP relaxation), but it is often an implicitly defined
231 // problem that is a complex consequence of the solvers execution. For both
232 // continuous and MIP solvers, the optimal value is equal or worse (larger for
233 // min objective and smaller for max objectives) than dual_bound, but only up
234 // to solver-tolerances. Some continuous solvers provide a numerically safer
235 // dual bound through solver's specific output (e.g. for PDLP,
236 // pdlp_output.convergence_information.corrected_dual_objective).
237 double dual_bound = 3;
238}
239
240// All information regarding why a call to Solve() terminated.
241message TerminationProto {
242 // Additional information in `limit` when value is TERMINATION_REASON_FEASIBLE
243 // or TERMINATION_REASON_NO_SOLUTION_FOUND, see `limit` for details.
244 TerminationReasonProto reason = 1;
245
246 // Is LIMIT_UNSPECIFIED unless reason is TERMINATION_REASON_FEASIBLE or
247 // TERMINATION_REASON_NO_SOLUTION_FOUND. Not all solvers can always determine
248 // the limit which caused termination, LIMIT_UNDETERMINED is used when the
249 // cause cannot be determined.
250 LimitProto limit = 2;
251
252 // Additional typically solver specific information about termination.
253 string detail = 3;
254
255 // Feasibility statuses for primal and dual problems.
256 // As of July 18, 2023 this message may be missing. If missing, problem_status
257 // can be found in SolveResultProto.solve_stats.
258 ProblemStatusProto problem_status = 4;
259
260 // Bounds on the optimal objective value.
261 // As of July 18, 2023 this message may be missing. If missing,
262 // objective_bounds.primal_bound can be found in
263 // SolveResultProto.solve.stats.best_primal_bound and
264 // objective_bounds.dual_bound can be found in
265 // SolveResultProto.solve.stats.best_dual_bound
266 ObjectiveBoundsProto objective_bounds = 5;
267}
268
269// The contract of when primal/dual solutions/rays is complex, see
270// termination_reasons.md for a complete description.
271//
272// Until an exact contract is finalized, it is safest to simply check if a
273// solution/ray is present rather than relying on the termination reason.
274message SolveResultProto {
275 // The reason the solver stopped.
276 TerminationProto termination = 2;
277
278 // Basic solutions use, as of Nov 2021:
279 // * All convex optimization solvers (LP, convex QP) return only one
280 // solution as a primal dual pair.
281 // * Only MI(Q)P solvers return more than one solution. MIP solvers do not
282 // return any dual information, or primal infeasible solutions. Solutions
283 // are returned in order of best primal objective first. Gurobi solves
284 // nonconvex QP (integer or continuous) as MIQP.
285
286 // The general contract for the order of solutions that future solvers should
287 // implement is to order by:
288 // 1. The solutions with a primal feasible solution, ordered by best primal
289 // objective first.
290 // 2. The solutions with a dual feasible solution, ordered by best dual
291 // objective (unknown dual objective is worst)
292 // 3. All remaining solutions can be returned in any order.
293 repeated SolutionProto solutions = 3;
294
295 // Directions of unbounded primal improvement, or equivalently, dual
296 // infeasibility certificates. Typically provided for TerminationReasonProtos
297 // UNBOUNDED and DUAL_INFEASIBLE
298 repeated PrimalRayProto primal_rays = 4;
299
300 // Directions of unbounded dual improvement, or equivalently, primal
301 // infeasibility certificates. Typically provided for TerminationReasonProto
302 // INFEASIBLE.
303 repeated DualRayProto dual_rays = 5;
304
305 // Statistics on the solve process, e.g. running time, iterations.
306 SolveStatsProto solve_stats = 6;
307
308 message PdlpOutput {
309 pdlp.ConvergenceInformation convergence_information = 1;
310 }
311
312 oneof solver_specific_output {
313 GScipOutput gscip_output = 7;
314 OsqpOutput osqp_output = 8;
315 PdlpOutput pdlp_output = 9;
316 }
317
318 reserved 1; // Deleted fields.
319}