OR-Tools  9.0
result.h
Go to the documentation of this file.
1 // Copyright 2010-2021 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 #ifndef OR_TOOLS_MATH_OPT_CPP_RESULT_H_
15 #define OR_TOOLS_MATH_OPT_CPP_RESULT_H_
16 
17 #include <string>
18 #include <vector>
19 
20 #include "ortools/base/logging.h"
21 #include "absl/status/statusor.h"
22 #include "absl/time/time.h"
26 #include "ortools/math_opt/result.pb.h"
27 #include "ortools/math_opt/solution.pb.h"
28 #include "ortools/base/protoutil.h"
29 
30 namespace operations_research {
31 namespace math_opt {
32 
33 // The result of solving an optimization problem with MathOpt::Solve.
34 //
35 // TODO(b/172211596): there is already a parallel proto named solve result, the
36 // naming convention should be more consistent.
37 struct Result {
38  // A solution to an optimization problem.
39  //
40  // E.g. consider a simple linear program:
41  //    min c * x
42  //    s.t. A * x >= b
43  //    x >= 0
44  // where c, x in R^m, b, y in R^n, and A in R^{m*n}.
45  //
46  // A primal solution is assignment values to x. It is feasible if it satisfies
47  // A * x >= b and x >= 0 from above. In the class PrimalSolution below,
48  // variable_values is x and objective_value is c * x.
49  //
50  // For the general case of a MathOpt optimization model, see
51  // go/mathopt-solutions for details.
52  struct PrimalSolution {
53  PrimalSolution() = default;
55 
57  double objective_value = 0.0;
58  };
59 
60  // A direction of unbounded improvement to an optimization problem;
61  // equivalently, a certificate of infeasibility for the dual of the
62  // optimization problem.
63  //
64  // E.g. consider a simple linear program:
65  //    min c * x
66  //    s.t. A * x >= b
67  //    x >= 0
68  // where c, x in R^m, b, y in R^n, and A in R^{m*n}.
69  //
70  // A primal ray is an x that satisfies:
71  // c * x < 0
72  // A * x >= 0
73  // x >= 0
74  // Observe that given a feasible solution, any positive multiple of the primal
75  // ray plus that solution is still feasible, and gives a better objective
76  // value. A primal ray also proves the dual optimization problem infeasible.
77  //
78  // In the class PrimalRay below, variable_values is this x.
79  //
80  // For the general case of a MathOpt optimization model, see
81  // go/mathopt-solutions for details.
82  struct PrimalRay {
83  PrimalRay() = default;
85 
87  };
88 
89  // A solution to the dual of an optimization problem.
90  //
91  // E.g. consider the primal dual pair linear program pair:
92  //    (Primal)            (Dual)
93  //    min c * x             max b * y
94  //    s.t. A * x >= b       s.t. y * A + r = c
95  //    x >= 0              y, r >= 0
96  // where c, x, r are in R^m, b, y in R^n and A in R^{m*n}.
97  //
98  // The dual solution is the pair (y, r). It is feasible if it satisfies the
99  // constraints from (Dual) above.
100  //
101  // Below, y is dual_values, r is reduced_costs, and b * y is objective value.
102  //
103  // For the general case, see go/mathopt-solutions and go/mathopt-dual (and
104  // note that the dual objective depends on r in the general case).
105  struct DualSolution {
106  DualSolution() = default;
108 
111  double objective_value = 0.0;
112  };
113 
114  // A direction of unbounded improvement to the dual of an optimization,
115  // problem; equivalently, a certificate of primal infeasibility.
116  //
117  // E.g. consider the primal dual pair linear program pair:
118  //    (Primal)           (Dual)
119  //    min c * x             max b * y
120  //    s.t. A * x >= b       s.t. y * A + r = c
121  //    x >= 0              y, r >= 0
122  // where c, x, r are in R^m, b, y in R^n and A in R^{m*n}.
123  //
124  // The dual ray is the pair (y, r) satisfying:
125  // b * y > 0
126  // y * A + r = 0
127  // y, r >= 0
128  // Observe that adding a positive multiple of (y, r) to dual feasible solution
129  // maintains dual feasibility and improves the objective (proving the dual is
130  // unbounded). The dual ray also proves the primal problem is infeasible.
131  //
132  // In the class DualRay below, y is dual_values and r is reduced_costs.
133  //
134  // For the general case, see go/mathopt-solutions and go/mathopt-dual (and
135  // note that the dual objective depends on r in the general case).
136  struct DualRay {
137  DualRay() = default;
138  DualRay(IndexedModel* model, IndexedDualRay indexed_ray);
139 
142  };
143  struct Basis {
144  Basis() = default;
145  Basis(IndexedModel* model, IndexedBasis indexed_basis);
146 
149  };
150 
151  Result(IndexedModel* model, const SolveResultProto& solve_result);
152 
153  // The objective value of the best primal solution. Will CHECK fail if there
154  // are no primal solutions.
155  double objective_value() const {
156  CHECK(has_solution());
157  return primal_solutions[0].objective_value;
158  }
159 
160  absl::Duration solve_time() const {
161  return util_time::DecodeGoogleApiProto(solve_stats.solve_time()).value();
162  }
163 
164  // Indicates if at least one primal feasible solution is available.
165  //
166  // When termination_reason is TERMINATION_REASON_OPTIMAL, this is guaranteed
167  // to be true and need not be checked.
168  bool has_solution() const { return !primal_solutions.empty(); }
169 
170  // The variable values from the best primal solution. Will CHECK fail if there
171  // are no primal solutions.
173  CHECK(has_solution());
174  return primal_solutions[0].variable_values;
175  }
176 
177  // Indicates if at least one primal ray is available.
178  //
179  // This is NOT guaranteed to be true when termination_reason is
180  // UNBOUNDED or DUAL_INFEASIBLE.
181  bool has_ray() const { return !primal_rays.empty(); }
182 
183  // The variable values from the first primal ray. Will CHECK fail if there
184  // are no primal rays.
186  CHECK(has_ray());
187  return primal_rays[0].variable_values;
188  }
189 
190  // Indicates if at least one dual solution is available.
191  //
192  // This is NOT guaranteed to be true when termination_reason is
193  // TERMINATION_REASON_OPTIMAL.
194  bool has_dual_solution() const { return !dual_solutions.empty(); }
195 
196  // The dual values from the best dual solution. Will CHECK fail if there
197  // are no dual solutions.
200  return dual_solutions[0].dual_values;
201  }
202 
203  // The reduced from the best dual solution. Will CHECK fail if there
204  // are no dual solutions.
205  // TODO(b/174564572): if reduced_costs in DualSolution was something like
206  // dual_reduced cost it would help prevent people forgetting to call
207  // has_dual_solution().
210  return dual_solutions[0].reduced_costs;
211  }
212 
213  // Indicates if at least one dual ray is available.
214  //
215  // This is NOT guaranteed to be true when termination_reason is
216  // INFEASIBLE.
217  bool has_dual_ray() const { return !dual_rays.empty(); }
218 
219  // The dual values from the first dual ray. Will CHECK fail if there
220  // are no dual rays.
221  // TODO(b/174564572): note the redunancy of the "double" dual and the
222  // inconsistency with `dual_values` in the proto.
224  CHECK(has_dual_ray());
225  return dual_rays[0].dual_values;
226  }
227 
228  // The reduced from the first dual ray. Will CHECK fail if there
229  // are no dual rays.
231  CHECK(has_dual_ray());
232  return dual_rays[0].reduced_costs;
233  }
234 
235  // Indicates if at least one basis is available.
236  bool has_basis() const { return !basis.empty(); }
237 
238  // The constraint basis status for the first primal/dual pair.
240  CHECK(has_basis());
241  return basis[0].constraint_status;
242  }
243 
244  // The variable basis status for the first primal/dual pair.
246  CHECK(has_basis());
247  return basis[0].variable_status;
248  }
249 
250  std::vector<std::string> warnings;
251  SolveResultProto::TerminationReason termination_reason =
252  SolveResultProto::TERMINATION_REASON_UNSPECIFIED;
253  std::string termination_detail;
254  SolveStatsProto solve_stats;
255 
256  // Primal solutions should be ordered best objective value first.
257  std::vector<PrimalSolution> primal_solutions;
258  std::vector<PrimalRay> primal_rays;
259 
260  // Dual solutions should be ordered best objective value first.
261  std::vector<DualSolution> dual_solutions;
262  std::vector<DualRay> dual_rays;
263 
264  // basis[i] corresponds to the primal dual pair:
265  // {primal_solutions[i], dual_solutions[i]}. These fields must have at least
266  // as many elements as basis. Basis will only be populated for LPs, and may
267  // not be populated.
268  std::vector<Basis> basis;
269 
270  // Set to true if MathOpt::Solve() has attempted an incremental solve instead
271  // of starting from scratch.
272  //
273  // We have three components involve in Solve(): MathOpt, the solver wrapper
274  // (solver.h) and the actual solver (SCIP, ...). For some model modifications,
275  // the wrapper can support modifying the actual solver's in-memory model
276  // instead of recreating it from scratch. This member is set to true when this
277  // happens.
279 };
280 
281 } // namespace math_opt
282 } // namespace operations_research
283 
284 #endif // OR_TOOLS_MATH_OPT_CPP_RESULT_H_
#define CHECK(condition)
Definition: base/logging.h:498
GRBmodel * model
Collection of objects used to extend the Constraint Solver library.
inline ::absl::StatusOr< absl::Duration > DecodeGoogleApiProto(const google::protobuf::Duration &proto)
Definition: protoutil.h:42
VariableMap< BasisStatus > variable_status
Definition: result.h:148
LinearConstraintMap< BasisStatus > constraint_status
Definition: result.h:147
LinearConstraintMap< double > dual_values
Definition: result.h:140
LinearConstraintMap< double > dual_values
Definition: result.h:109
const VariableMap< double > & ray_variable_values() const
Definition: result.h:185
const VariableMap< double > & ray_reduced_costs() const
Definition: result.h:230
const LinearConstraintMap< BasisStatus > & constraint_status() const
Definition: result.h:239
std::vector< PrimalSolution > primal_solutions
Definition: result.h:257
absl::Duration solve_time() const
Definition: result.h:160
std::vector< std::string > warnings
Definition: result.h:250
const VariableMap< double > & reduced_costs() const
Definition: result.h:208
std::vector< PrimalRay > primal_rays
Definition: result.h:258
const LinearConstraintMap< double > & dual_values() const
Definition: result.h:198
const VariableMap< BasisStatus > & variable_status() const
Definition: result.h:245
const VariableMap< double > & variable_values() const
Definition: result.h:172
const LinearConstraintMap< double > & ray_dual_values() const
Definition: result.h:223
SolveResultProto::TerminationReason termination_reason
Definition: result.h:251
Result(IndexedModel *model, const SolveResultProto &solve_result)
Definition: result.cc:49
std::vector< DualSolution > dual_solutions
Definition: result.h:261
std::vector< DualRay > dual_rays
Definition: result.h:262
std::vector< Basis > basis
Definition: result.h:268