Google OR-Tools v9.11
a fast and portable software suite for combinatorial optimization
Loading...
Searching...
No Matches
solve_result.h
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// IWYU pragma: private, include "ortools/math_opt/cpp/math_opt.h"
15// IWYU pragma: friend "ortools/math_opt/cpp/.*"
16
17#ifndef OR_TOOLS_MATH_OPT_CPP_SOLVE_RESULT_H_
18#define OR_TOOLS_MATH_OPT_CPP_SOLVE_RESULT_H_
19
20#include <initializer_list>
21#include <optional>
22#include <ostream>
23#include <string>
24#include <utility>
25#include <vector>
26
27#include "absl/status/status.h"
28#include "absl/status/statusor.h"
29#include "absl/time/time.h"
30#include "ortools/gscip/gscip.pb.h"
31#include "ortools/math_opt/cpp/enums.h" // IWYU pragma: export
33#include "ortools/math_opt/cpp/solution.h" // IWYU pragma: export
35#include "ortools/math_opt/result.pb.h" // IWYU pragma: export
37
38namespace operations_research {
39namespace math_opt {
40
41// Problem feasibility status as claimed by the solver (solver is not required
42// to return a certificate for the claim).
44 // Solver does not claim a status.
45 kUndetermined = FEASIBILITY_STATUS_UNDETERMINED,
46
47 // Solver claims the problem is feasible.
48 kFeasible = FEASIBILITY_STATUS_FEASIBLE,
49
50 // Solver claims the problem is infeasible.
51 kInfeasible = FEASIBILITY_STATUS_INFEASIBLE,
52};
53
54MATH_OPT_DEFINE_ENUM(FeasibilityStatus, FEASIBILITY_STATUS_UNSPECIFIED);
55
56// Feasibility status of the primal problem and its dual (or the dual of a
57// continuous relaxation) as claimed by the solver. The solver is not required
58// to return a certificate for the claim (e.g. the solver may claim primal
59// feasibility without returning a primal feasible solution). This combined
60// status gives a comprehensive description of a solver's claims about
61// feasibility and unboundedness of the solved problem. For instance,
62//
63// * a feasible status for primal and dual problems indicates the primal is
64// feasible and bounded and likely has an optimal solution (guaranteed for
65// problems without non-linear constraints).
66// * a primal feasible and a dual infeasible status indicates the primal
67// problem is unbounded (i.e. has arbitrarily good solutions).
68//
69// Note that a dual infeasible status by itself (i.e. accompanied by an
70// undetermined primal status) does not imply the primal problem is unbounded as
71// we could have both problems be infeasible. Also, while a primal and dual
72// feasible status may imply the existence of an optimal solution, it does not
73// guarantee the solver has actually found such optimal solution.
75 // Status for the primal problem.
77
78 // Status for the dual problem (or for the dual of a continuous relaxation).
80
81 // If true, the solver claims the primal or dual problem is infeasible, but
82 // it does not know which (or if both are infeasible). Can be true only when
83 // primal_problem_status = dual_problem_status = kUndetermined. This extra
84 // information is often needed when preprocessing determines there is no
85 // optimal solution to the problem (but can't determine if it is due to
86 // infeasibility, unboundedness, or both).
88
89 // Returns an error if the primal_status or dual_status is unspecified.
90 static absl::StatusOr<ProblemStatus> FromProto(
91 const ProblemStatusProto& problem_status_proto);
92
93 ProblemStatusProto Proto() const;
94 std::string ToString() const;
95};
96
97std::ostream& operator<<(std::ostream& ostr, const ProblemStatus& status);
98
99struct SolveStats {
100 // Elapsed wall clock time as measured by math_opt, roughly the time inside
101 // Solver::Solve(). Note: this does not include work done building the model.
102 absl::Duration solve_time = absl::ZeroDuration();
103
105
107
109
110 int node_count = 0;
111
112 // Returns an error if converting the problem_status or solve_time fails.
113 static absl::StatusOr<SolveStats> FromProto(
114 const SolveStatsProto& solve_stats_proto);
115
116 // Will return an error if solve_time is not finite.
117 absl::StatusOr<SolveStatsProto> Proto() const;
118 std::string ToString() const;
119};
120
121std::ostream& operator<<(std::ostream& ostr, const SolveStats& stats);
122
123// The reason a call to Solve() terminates.
125 // A provably optimal solution (up to numerical tolerances) has been found.
126 kOptimal = TERMINATION_REASON_OPTIMAL,
127
128 // The primal problem has no feasible solutions.
129 kInfeasible = TERMINATION_REASON_INFEASIBLE,
130
131 // The primal problem is feasible and arbitrarily good solutions can be
132 // found along a primal ray.
133 kUnbounded = TERMINATION_REASON_UNBOUNDED,
134
135 // The primal problem is either infeasible or unbounded. More details on the
136 // problem status may be available in termination.problem_status. Note that
137 // Gurobi's unbounded status may be mapped here.
138 kInfeasibleOrUnbounded = TERMINATION_REASON_INFEASIBLE_OR_UNBOUNDED,
139
140 // The problem was solved to one of the criteria above (Optimal, Infeasible,
141 // Unbounded, or InfeasibleOrUnbounded), but one or more tolerances was not
142 // met. Some primal/dual solutions/rays may be present, but either they will
143 // be slightly infeasible, or (if the problem was nearly optimal) their may be
144 // a gap between the best solution objective and best objective bound.
145 //
146 // Users can still query primal/dual solutions/rays and solution stats, but
147 // they are responsible for dealing with the numerical imprecision.
148 kImprecise = TERMINATION_REASON_IMPRECISE,
149
150 // The optimizer reached some kind of limit and a primal feasible solution
151 // is returned. See SolveResultProto.limit_detail for detailed description of
152 // the kind of limit that was reached.
153 kFeasible = TERMINATION_REASON_FEASIBLE,
154
155 // The optimizer reached some kind of limit and it did not find a primal
156 // feasible solution. See SolveResultProto.limit_detail for detailed
157 // description of the kind of limit that was reached.
158 kNoSolutionFound = TERMINATION_REASON_NO_SOLUTION_FOUND,
159
160 // The algorithm stopped because it encountered unrecoverable numerical
161 // error. No solution information is available.
162 kNumericalError = TERMINATION_REASON_NUMERICAL_ERROR,
163
164 // The algorithm stopped because of an error not covered by one of the
165 // statuses defined above. No solution information is available.
166 kOtherError = TERMINATION_REASON_OTHER_ERROR
167};
168
169MATH_OPT_DEFINE_ENUM(TerminationReason, TERMINATION_REASON_UNSPECIFIED);
170
171// When a Solve() stops early with TerminationReason kFeasible or
172// kNoSolutionFound, the specific limit that was hit.
173enum class Limit {
174 // Used if the underlying solver cannot determine which limit was reached, or
175 // as a null value when we terminated not from a limit (e.g. kOptimal).
176 kUndetermined = LIMIT_UNDETERMINED,
177
178 // An iterative algorithm stopped after conducting the maximum number of
179 // iterations (e.g. simplex or barrier iterations).
180 kIteration = LIMIT_ITERATION,
181
182 // The algorithm stopped after a user-specified computation time.
183 kTime = LIMIT_TIME,
184
185 // A branch-and-bound algorithm stopped because it explored a maximum number
186 // of nodes in the branch-and-bound tree.
187 kNode = LIMIT_NODE,
188
189 // The algorithm stopped because it found the required number of solutions.
190 // This is often used in MIPs to get the solver to return the first feasible
191 // solution it encounters.
192 kSolution = LIMIT_SOLUTION,
193
194 // The algorithm stopped because it ran out of memory.
195 kMemory = LIMIT_MEMORY,
196
197 // The solver was run with a cutoff (e.g. SolveParameters.cutoff_limit was
198 // set) on the objective, indicating that the user did not want any solution
199 // worse than the cutoff, and the solver concluded there were no solutions at
200 // least as good as the cutoff. Typically no further solution information is
201 // provided.
202 kCutoff = LIMIT_CUTOFF,
203
204 // The algorithm stopped because it found a solution better than a minimum
205 // limit set by the user.
206 kObjective = LIMIT_OBJECTIVE,
207
208 // The algorithm stopped because the norm of an iterate became too large.
209 kNorm = LIMIT_NORM,
210
211 // The algorithm stopped because of an interrupt signal or a user interrupt
212 // request.
213 kInterrupted = LIMIT_INTERRUPTED,
214
215 // The algorithm stopped because it was unable to continue making progress
216 // towards the solution.
217 kSlowProgress = LIMIT_SLOW_PROGRESS,
218
219 // The algorithm stopped due to a limit not covered by one of the above. Note
220 // that kUndetermined is used when the reason cannot be determined, and kOther
221 // is used when the reason is known but does not fit into any of the above
222 // alternatives.
223 kOther = LIMIT_OTHER
224};
225
226MATH_OPT_DEFINE_ENUM(Limit, LIMIT_UNSPECIFIED);
227
228// Bounds on the optimal objective value.
230 // Solver claims there exists a primal solution that is numerically feasible
231 // (i.e. feasible up to the solvers tolerance), and whose objective value is
232 // primal_bound.
233 //
234 // The optimal value is equal or better (smaller for min objectives and larger
235 // for max objectives) than primal_bound, but only up to solver-tolerances.
236 double primal_bound = 0.0;
237
238 // Solver claims there exists a dual solution that is numerically feasible
239 // (i.e. feasible up to the solvers tolerance), and whose objective value is
240 // dual_bound.
241 //
242 // For MIP solvers, the associated dual problem may be some continuous
243 // relaxation (e.g. LP relaxation), but it is often an implicitly defined
244 // problem that is a complex consequence of the solvers execution. For both
245 // continuous and MIP solvers, the optimal value is equal or worse (larger for
246 // min objective and smaller for max objectives) than dual_bound, but only up
247 // to solver-tolerances. Some continuous solvers provide a numerically safer
248 // dual bound through solver's specific output (e.g. for PDLP,
249 // pdlp_output.convergence_information.corrected_dual_objective).
250 double dual_bound = 0.0;
251
252 // Returns trivial bounds.
253 //
254 // Trivial bounds are:
255 // * for a maximization:
256 // - primal_bound = -inf
257 // - dual_bound = +inf
258 // * for a minimization:
259 // - primal_bound = +inf
260 // - dual_bound = -inf
261 static ObjectiveBounds MakeTrivial(bool is_maximize);
264
265 // Returns unbounded bounds.
266 //
267 // Unbounded bounds are:
268 // * for a maximization:
269 // - primal_bound = dual_bound = +inf
270 // * for a minimization:
271 // - primal_bound = dual_bound = -inf
272 static ObjectiveBounds MakeUnbounded(bool is_maximize);
275
276 // Sets both bounds to objective_value.
278
280 const ObjectiveBoundsProto& objective_bounds_proto);
281 ObjectiveBoundsProto Proto() const;
282 std::string ToString() const;
283};
284
285std::ostream& operator<<(std::ostream& ostr,
286 const ObjectiveBounds& objective_bounds);
287
288// All information regarding why a call to Solve() terminated.
290 // Returns a Termination with the provided reason and details along with
291 // trivial bounds and kUndetermined statuses.
292 // A variety of static factory functions are provided below for common
293 // Termination conditions, generally prefer these if applicable.
294 Termination(bool is_maximize, TerminationReason reason,
295 std::string detail = {});
296
297 // Additional information in `limit` when value is kFeasible or
298 // kNoSolutionFound, see `limit` for details.
300
301 // A Termination within a SolveResult returned by math_opt::Solve() satisfies
302 // some additional invariants:
303 // * limit is set iff reason is kFeasible or kNoSolutionFound.
304 // * if the limit is kCutoff, the termination reason will be
305 // kNoSolutionFound.
306 std::optional<Limit> limit;
307
308 // Additional typically solver specific information about termination.
309 // Not all solvers can always determine the limit which caused termination,
310 // Limit::kUndetermined is used when the cause cannot be determined.
311 std::string detail;
312
313 // Feasibility statuses for primal and dual problems.
315
316 // Bounds on the optimal objective value.
318
319 // Returns true if a limit was reached (i.e. if reason is kFeasible or
320 // kNoSolutionFound, and limit is not empty).
321 bool limit_reached() const;
322
323 // Returns an OkStatus if the reason of this `Termination` is
324 // `TerminationReason::kOptimal` or `TerminationReason::kFeasible`, or an
325 // `InternalError` otherwise.
326 absl::Status EnsureIsOptimalOrFeasible() const;
327
328 // Returns true if the reason of this Termination` is
329 // `TerminationReason::kOptimal` or `TerminationReason::kFeasible`, or false
330 // otherwise.
331 bool IsOptimalOrFeasible() const;
332
333 // Returns an OkStatus if the reason of this `Termination` is
334 // `TerminationReason::kOptimal`, or an `InternalError` otherwise.
335 //
336 // In most use cases, at least for MIPs, `EnsureIsOptimalOrFeasible` should be
337 // used instead.
338 absl::Status EnsureIsOptimal() const;
339
340 // Returns true if the reason of this `Termination` is
341 // `TerminationReason::kOptimal`, or false otherwise.
342 //
343 // In most use cases, at least for MIPs, `IsOptimalOrFeasible` should be
344 // used instead.
345 bool IsOptimal() const;
346
347 // Returns an OkStatus if the reason of this `Termination` is `reason`, or an
348 // `InternalError` otherwise.
349 absl::Status EnsureReasonIs(TerminationReason reason) const;
350
351 // Returns an OkStatus if the reason of this `Termination` is in `reasons`, or
352 // an `InternalError` otherwise.
353 absl::Status EnsureReasonIsAnyOf(
354 std::initializer_list<TerminationReason> reasons) const;
355
356 // Returns termination with reason kOptimal, the provided objective for both
357 // primal and dual bounds, and kFeasible primal and dual statuses.
358 static Termination Optimal(double objective_value, std::string detail = {});
359
360 // Returns termination with reason kOptimal, the provided objective bounds and
361 // kFeasible primal and dual statuses.
362 static Termination Optimal(double primal_objective_value,
363 double dual_objective_value,
364 std::string detail = {});
365
366 // Returns a termination with reason kInfeasible, primal status kInfeasible
367 // and the provided dual status.
368 //
369 // It sets a trivial primal bound and a dual bound based on the provided dual
370 // status, which should be kFeasible or kUndetermined. If the dual status is
371 // kUndetermined, then the dual bound will be trivial and if the dual status
372 // is kFeasible, then the dual bound will be equal to the primal bound.
373 //
374 // The convention for infeasible MIPs is that dual_feasibility_status is
375 // feasible (There always exist a dual feasible convex relaxation of an
376 // infeasible MIP).
377 static Termination Infeasible(bool is_maximize,
378 FeasibilityStatus dual_feasibility_status =
380 std::string detail = {});
381
382 // Returns a termination with reason kInfeasibleOrUnbounded, primal status
383 // kUndetermined, the provided dual status (which should be kUndetermined or
384 // kInfeasible) and trivial bounds.
385 //
386 // primal_or_dual_infeasible is set if dual_feasibility_status is
387 // kUndetermined.
388 static Termination InfeasibleOrUnbounded(
389 bool is_maximize,
390 FeasibilityStatus dual_feasibility_status =
392 std::string detail = {});
393
394 // Returns a termination with reason kUnbounded, primal status kFeasible,
395 // dual status kInfeasible and unbounded bounds.
396 static Termination Unbounded(bool is_maximize, std::string detail = {});
397
398 // Returns a termination with reason kNoSolutionFound and primal status
399 // kUndetermined.
400 //
401 // Assumes dual solution exists iff optional_dual_objective is set even if
402 // infinite (some solvers return feasible dual solutions without an objective
403 // value). optional_dual_objective should not be set when limit is
404 // kCutoff for a valid TerminationProto to be returned (use LimitCutoff()
405 // below instead).
406 //
407 // It sets a trivial primal bound. The dual bound is either set to the
408 // optional_dual_objective if set, else to a trivial value.
409 //
410 // TODO(b/290359402): Consider improving to require a finite dual bound when
411 // dual feasible solutions are returned.
412 static Termination NoSolutionFound(
413 bool is_maximize, Limit limit,
414 std::optional<double> optional_dual_objective = std::nullopt,
415 std::string detail = {});
416
417 // Returns a termination with reason kFeasible and primal status kFeasible.
418 // The dual status depends on optional_dual_objective.
419 //
420 // finite_primal_objective should be finite and limit should not be
421 // kCutoff for a valid TerminationProto to be returned (use LimitCutoff()
422 // below instead).
423 //
424 // Assumes dual solution exists iff optional_dual_objective is set even if
425 // infinite (some solvers return feasible dual solutions without an objective
426 // value). If set the dual status is set to kFeasible, else
427 // it is kUndetermined.
428 //
429 // It sets the primal bound based on the primal objective. The dual bound is
430 // either set to the optional_dual_objective if set, else to a trivial value.
431 //
432 // TODO(b/290359402): Consider improving to require a finite dual bound when
433 // dual feasible solutions are returned.
434 static Termination Feasible(
435 bool is_maximize, Limit limit, double finite_primal_objective,
436 std::optional<double> optional_dual_objective = std::nullopt,
437 std::string detail = {});
438
439 // Calls NoSolutionFound() with LIMIT_CUTOFF LIMIT.
440 static Termination Cutoff(bool is_maximize, std::string detail = {});
441
442 // Will return an error if termination_proto.reason is UNSPECIFIED.
443 static absl::StatusOr<Termination> FromProto(
444 const TerminationProto& termination_proto);
445 TerminationProto Proto() const;
446
447 std::string ToString() const;
448};
449
450std::ostream& operator<<(std::ostream& ostr, const Termination& termination);
451
452template <typename Sink>
453void AbslStringify(Sink& sink, const Termination& termination) {
454 sink.Append(termination.ToString());
455}
456
457// The result of solving an optimization problem with Solve().
458struct SolveResult {
459 explicit SolveResult(Termination termination)
460 : termination(std::move(termination)) {}
461
462 // The reason the solver stopped.
463 Termination termination;
464
465 // Statistics on the solve process, e.g. running time, iterations.
466 SolveStats solve_stats;
467
468 // Basic solutions use, as of Nov 2021:
469 // * All convex optimization solvers (LP, convex QP) return only one
470 // solution as a primal dual pair.
471 // * Only MI(Q)P solvers return more than one solution. MIP solvers do not
472 // return any dual information, or primal infeasible solutions. Solutions
473 // are returned in order of best primal objective first. Gurobi solves
474 // nonconvex QP (integer or continuous) as MIQP.
475
476 // The general contract for the order of solutions that future solvers should
477 // implement is to order by:
478 // 1. The solutions with a primal feasible solution, ordered by best primal
479 // objective first.
480 // 2. The solutions with a dual feasible solution, ordered by best dual
481 // objective (unknown dual objective is worst)
482 // 3. All remaining solutions can be returned in any order.
483 std::vector<Solution> solutions;
484
485 // Directions of unbounded primal improvement, or equivalently, dual
486 // infeasibility certificates. Typically provided for TerminationReasons
487 // kUnbounded and kInfeasibleOrUnbounded.
488 std::vector<PrimalRay> primal_rays;
489
490 // Directions of unbounded dual improvement, or equivalently, primal
491 // infeasibility certificates. Typically provided for TerminationReason
492 // kInfeasible.
493 std::vector<DualRay> dual_rays;
494
495 // Solver specific output from Gscip. Only populated if Gscip is used.
496 GScipOutput gscip_solver_specific_output;
497 // Solver specific output from Pdlp. Only populated if Pdlp is used.
498 SolveResultProto::PdlpOutput pdlp_solver_specific_output;
499
500 // Returns the SolveResult equivalent of solve_result_proto.
501 //
502 // Returns an error if:
503 // * Any solution or ray cannot be read from proto (e.g. on a subfield,
504 // ids.size != values.size).
505 // * termination or solve_stats cannot be read from proto.
506 // See the FromProto() functions for these types for details.
507 //
508 // Note: this is (intentionally) a much weaker test than ValidateResult(). The
509 // guarantees are just strong enough to ensure that a SolveResult and
510 // SolveResultProto can round trip cleanly, e.g. we do not check that a
511 // termination reason optimal implies that there is at least one primal
512 // feasible solution.
513 //
514 // While ValidateResult() is called automatically when you are solving
515 // locally, users who are reading a solution from disk, solving remotely, or
516 // getting their SolveResultProto (or SolveResult) by any other means are
517 // encouraged to either call ValidateResult() themselves, do their own
518 // validation, or not rely on the strong guarantees of ValidateResult()
519 // and just treat SolveResult as a simple struct.
520 static absl::StatusOr<SolveResult> FromProto(
521 const ModelStorage* model, const SolveResultProto& solve_result_proto);
522
523 // Returns the proto equivalent of this.
524 //
525 // Note that the proto uses a oneof for solver specific output. This method
526 // will fail if multiple solver specific outputs are set.
527 //
528 // TODO(b/231134639): investigate removing the oneof from the proto.
529 absl::StatusOr<SolveResultProto> Proto() const;
530
531 absl::Duration solve_time() const { return solve_stats.solve_time; }
532
533 // A primal bound on the optimal objective value as described in
534 // ObjectiveBounds. Will return a valid (possibly infinite) bound even if
535 // no primal feasible solutions are available.
536 double primal_bound() const;
537
538 // A dual bound on the optimal objective value as described in
539 // ObjectiveBounds. Will return a valid (possibly infinite) bound even if
540 // no dual feasible solutions are available.
541 double dual_bound() const;
542
543 // Indicates if at least one primal feasible solution is available.
544 //
545 // For SolveResults generated by calling Solver::Solve(), when
546 // termination.reason is TerminationReason::kOptimal or
547 // TerminationReason::kFeasible, this is guaranteed to be true and need not be
548 // checked. SolveResult objects generated directed from a proto need not have
549 // this property.
550 bool has_primal_feasible_solution() const;
551
552 // Returns the best primal feasible solution. CHECK fails if no such solution
553 // is available; check this using `has_primal_feasible_solution()`.
555
556 // The objective value of the best primal feasible solution. Will CHECK fail
557 // if there are no primal feasible solutions.
558 //
559 // primal_bound() above is guaranteed to be at least as good (larger or equal
560 // for max problems and smaller or equal for min problems) as
561 // objective_value() and will never CHECK fail, so it may be preferable in
562 // some cases. Note that primal_bound() could be better than objective_value()
563 // even for optimal terminations, but on such optimal termination, both should
564 // satisfy the optimality tolerances.
565 double objective_value() const;
566 double objective_value(Objective objective) const;
567
568 // A bound on the best possible objective value.
569 //
570 // best_objective_bound() is always equal to dual_bound(), so they can be
571 // used interchangeably.
572 double best_objective_bound() const;
573
574 // The variable values from the best primal feasible solution. Will CHECK fail
575 // if there are no primal feasible solutions.
577
578 // Returns true only if the problem has been shown to be feasible and bounded.
579 bool bounded() const;
580
581 // Indicates if at least one primal ray is available.
582 //
583 // This is NOT guaranteed to be true when termination.reason is
584 // TerminationReason::kUnbounded or TerminationReason::kInfeasibleOrUnbounded.
585 bool has_ray() const { return !primal_rays.empty(); }
586
587 // The variable values from the first primal ray. Will CHECK fail if there
588 // are no primal rays.
590
591 // Indicates if the best solution has an associated dual feasible solution.
592 //
593 // This is NOT guaranteed to be true when termination.reason is
594 // TerminationReason::kOptimal. It also may be true even when the best
595 // solution does not have an associated primal feasible solution.
597
598 // The dual values associated to the best solution.
599 //
600 // If there is at least one primal feasible solution, this corresponds to the
601 // dual values associated to the best primal feasible solution. Will CHECK
602 // fail if the best solution does not have an associated dual feasible
603 // solution.
605
606 // The reduced costs associated to the best solution.
607 //
608 // If there is at least one primal feasible solution, this corresponds to the
609 // reduced costs associated to the best primal feasible solution. Will CHECK
610 // fail if the best solution does not have an associated dual feasible
611 // solution.
613
614 // Indicates if at least one dual ray is available.
615 //
616 // This is NOT guaranteed to be true when termination.reason is
617 // TerminationReason::kInfeasible.
618 bool has_dual_ray() const { return !dual_rays.empty(); }
619
620 // The dual values from the first dual ray. Will CHECK fail if there
621 // are no dual rays.
623
624 // The reduced from the first dual ray. Will CHECK fail if there
625 // are no dual rays.
627
628 // Indicates if the best solution has an associated basis.
629 bool has_basis() const;
630
631 // The constraint basis status for the best solution. Will CHECK fail if the
632 // best solution does not have an associated basis.
634
635 // The variable basis status for the best solution. Will CHECK fail if the
636 // best solution does not have an associated basis.
638};
639
640// Prints a summary of the solve result on a single line.
641//
642// This prints the number of available solutions and rays instead of their
643// values.
644//
645// Printing the whole solution could be problematic for huge models.
646std::ostream& operator<<(std::ostream& out, const SolveResult& result);
647
648} // namespace math_opt
649} // namespace operations_research
650
651#endif // OR_TOOLS_MATH_OPT_CPP_SOLVE_RESULT_H_
#define MATH_OPT_DEFINE_ENUM(CppEnum, proto_unspecified_value)
Definition enums.h:325
absl::Status status
Definition g_gurobi.cc:44
GRBmodel * model
TerminationReason termination
absl::flat_hash_map< Variable, V > VariableMap
TerminationReason
The reason a call to Solve() terminates.
@ kOptimal
A provably optimal solution (up to numerical tolerances) has been found.
absl::flat_hash_map< LinearConstraint, V > LinearConstraintMap
std::string ToString(QpSupportType qp_support)
Definition qp_tests.cc:64
std::ostream & operator<<(std::ostream &ostr, const IndicatorConstraint &constraint)
@ kUndetermined
Solver does not claim a feasibility status.
@ kFeasible
Solver claims the solution is feasible.
@ kInfeasible
Solver claims the solution is infeasible.
@ kMemory
The algorithm stopped because it ran out of memory.
@ kTime
The algorithm stopped after a user-specified computation time.
@ kNorm
The algorithm stopped because the norm of an iterate became too large.
Matcher< SolveResult > IsOptimal(const std::optional< double > expected_primal_objective, const double tolerance)
Definition matchers.cc:762
@ kUndetermined
Solver does not claim a status.
In SWIG mode, we don't want anything besides these top-level includes.
void AbslStringify(Sink &sink, StrongIndex< T... > arg)
STL namespace.
Bounds on the optimal objective value.
static ObjectiveBounds MakeTrivial(bool is_maximize)
static ObjectiveBounds MakeUnbounded(bool is_maximize)
static ObjectiveBounds MakeOptimal(double objective_value)
Sets both bounds to objective_value.
static ObjectiveBounds FromProto(const ObjectiveBoundsProto &objective_bounds_proto)
FeasibilityStatus primal_status
Status for the primal problem.
static absl::StatusOr< ProblemStatus > FromProto(const ProblemStatusProto &problem_status_proto)
Returns an error if the primal_status or dual_status is unspecified.
FeasibilityStatus dual_status
Status for the dual problem (or for the dual of a continuous relaxation).
absl::StatusOr< SolveStatsProto > Proto() const
Will return an error if solve_time is not finite.
static absl::StatusOr< SolveStats > FromProto(const SolveStatsProto &solve_stats_proto)
Returns an error if converting the problem_status or solve_time fails.
All information regarding why a call to Solve() terminated.
const PrimalSolution & best_primal_solution() const
Termination(bool is_maximize, TerminationReason reason, std::string detail={})
const LinearConstraintMap< double > & dual_values() const
const VariableMap< BasisStatus > & variable_status() const
const VariableMap< double > & ray_reduced_costs() const
const VariableMap< double > & reduced_costs() const
bool bounded() const
Returns true only if the problem has been shown to be feasible and bounded.
const LinearConstraintMap< double > & ray_dual_values() const
double objective_value(Objective objective) const
const VariableMap< double > & variable_values() const
const VariableMap< double > & ray_variable_values() const
bool has_basis() const
Indicates if the best solution has an associated basis.
ProblemStatus problem_status
Feasibility statuses for primal and dual problems.
const LinearConstraintMap< BasisStatus > & constraint_status() const
ObjectiveBounds objective_bounds
Bounds on the optimal objective value.
double objective_value
The value objective_vector^T * (solution - center_point).