OR-Tools  9.1
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  // A primal solution is assignment values to x. It is feasible if it satisfies
45  // A * x >= b and x >= 0 from above. In the class PrimalSolution below,
46  // variable_values is x and objective_value is c * x.
47  //
48  // For the general case of a MathOpt optimization model, see
49  // go/mathopt-solutions for details.
50  struct PrimalSolution {
51  PrimalSolution() = default;
53 
55  double objective_value = 0.0;
56  };
57 
58  // A direction of unbounded improvement to an optimization problem;
59  // equivalently, a certificate of infeasibility for the dual of the
60  // optimization problem.
61  //
62  // E.g. consider a simple linear program:
63  // min c * x
64  // s.t. A * x >= b
65  // x >= 0
66  // A primal ray is an x that satisfies:
67  // c * x < 0
68  // A * x >= 0
69  // x >= 0
70  // Observe that given a feasible solution, any positive multiple of the primal
71  // ray plus that solution is still feasible, and gives a better objective
72  // value. A primal ray also proves the dual optimization problem infeasible.
73  //
74  // In the class PrimalRay below, variable_values is this x.
75  //
76  // For the general case of a MathOpt optimization model, see
77  // go/mathopt-solutions for details.
78  struct PrimalRay {
79  PrimalRay() = default;
81 
83  };
84 
85  // A solution to the dual of an optimization problem.
86  //
87  // E.g. consider the primal dual pair linear program pair:
88  // (Primal) (Dual)
89  // min c * x max b * y
90  // s.t. A * x >= b s.t. y * A + r = c
91  // x >= 0 y, r >= 0.
92  // The dual solution is the pair (y, r). It is feasible if it satisfies the
93  // constraints from (Dual) above.
94  //
95  // Below, y is dual_values, r is reduced_costs, and b * y is objective value.
96  //
97  // For the general case, see go/mathopt-solutions and go/mathopt-dual (and
98  // note that the dual objective depends on r in the general case).
99  struct DualSolution {
100  DualSolution() = default;
102 
105  double objective_value = 0.0;
106  };
107 
108  // A direction of unbounded improvement to the dual of an optimization,
109  // problem; equivalently, a certificate of primal infeasibility.
110  //
111  // E.g. consider the primal dual pair linear program pair:
112  // (Primal) (Dual)
113  // min c * x max b * y
114  // s.t. A * x >= b s.t. y * A + r = c
115  // x >= 0 y, r >= 0.
116  // The dual ray is the pair (y, r) satisfying:
117  // b * y > 0
118  // y * A + r = 0
119  // y, r >= 0
120  // Observe that adding a positive multiple of (y, r) to dual feasible solution
121  // maintains dual feasibility and improves the objective (proving the dual is
122  // unbounded). The dual ray also proves the primal problem is infeasible.
123  //
124  // In the class DualRay below, y is dual_values and r is reduced_costs.
125  //
126  // For the general case, see go/mathopt-solutions and go/mathopt-dual (and
127  // note that the dual objective depends on r in the general case).
128  struct DualRay {
129  DualRay() = default;
130  DualRay(IndexedModel* model, IndexedDualRay indexed_ray);
131 
134  };
135 
136  // A combinatorial characterization for a solution to a linear program.
137  //
138  // The simplex method for solving linear programs always returns a "basic
139  // feasible solution" which can be described combinatorially as a Basis. A
140  // basis assigns a BasisStatus for every variable and linear constraint.
141  //
142  // E.g. consider a standard form LP:
143  // min c * x
144  // s.t. A * x = b
145  // x >= 0
146  // that has more variables than constraints and with full row rank A.
147  //
148  // Let n be the number of variables and m the number of linear constraints. A
149  // valid basis for this problem can be constructed as follows:
150  // * All constraints will have basis status FIXED.
151  // * Pick m variables such that the columns of A are linearly independent and
152  // assign the status BASIC.
153  // * Assign the status AT_LOWER for the remaining n - m variables.
154  //
155  // The basic solution for this basis is the unique solution of A * x = b that
156  // has all variables with status AT_LOWER fixed to their lower bounds (all
157  // zero). The resulting solution is called a basic feasible solution if it
158  // also satisfies x >= 0.
159  //
160  // See go/mathopt-basis for treatment of the general case and an explanation
161  // of how a dual solution is determined for a basis.
162  struct Basis {
163  Basis() = default;
164  Basis(IndexedModel* model, IndexedBasis indexed_basis);
165 
168  };
169 
170  Result(IndexedModel* model, const SolveResultProto& solve_result);
171 
172  // The objective value of the best primal solution. Will CHECK fail if there
173  // are no primal solutions.
174  double objective_value() const {
175  CHECK(has_solution());
176  return primal_solutions[0].objective_value;
177  }
178 
179  absl::Duration solve_time() const {
180  return util_time::DecodeGoogleApiProto(solve_stats.solve_time()).value();
181  }
182 
183  // Indicates if at least one primal feasible solution is available.
184  //
185  // When termination_reason is TERMINATION_REASON_OPTIMAL, this is guaranteed
186  // to be true and need not be checked.
187  bool has_solution() const { return !primal_solutions.empty(); }
188 
189  // The variable values from the best primal solution. Will CHECK fail if there
190  // are no primal solutions.
192  CHECK(has_solution());
193  return primal_solutions[0].variable_values;
194  }
195 
196  // Indicates if at least one primal ray is available.
197  //
198  // This is NOT guaranteed to be true when termination_reason is
199  // UNBOUNDED or DUAL_INFEASIBLE.
200  bool has_ray() const { return !primal_rays.empty(); }
201 
202  // The variable values from the first primal ray. Will CHECK fail if there
203  // are no primal rays.
205  CHECK(has_ray());
206  return primal_rays[0].variable_values;
207  }
208 
209  // Indicates if at least one dual solution is available.
210  //
211  // This is NOT guaranteed to be true when termination_reason is
212  // TERMINATION_REASON_OPTIMAL.
213  bool has_dual_solution() const { return !dual_solutions.empty(); }
214 
215  // The dual values from the best dual solution. Will CHECK fail if there
216  // are no dual solutions.
219  return dual_solutions[0].dual_values;
220  }
221 
222  // The reduced from the best dual solution. Will CHECK fail if there
223  // are no dual solutions.
224  // TODO(b/174564572): if reduced_costs in DualSolution was something like
225  // dual_reduced cost it would help prevent people forgetting to call
226  // has_dual_solution().
229  return dual_solutions[0].reduced_costs;
230  }
231 
232  // Indicates if at least one dual ray is available.
233  //
234  // This is NOT guaranteed to be true when termination_reason is
235  // INFEASIBLE.
236  bool has_dual_ray() const { return !dual_rays.empty(); }
237 
238  // The dual values from the first dual ray. Will CHECK fail if there
239  // are no dual rays.
240  // TODO(b/174564572): note the redunancy of the "double" dual and the
241  // inconsistency with `dual_values` in the proto.
243  CHECK(has_dual_ray());
244  return dual_rays[0].dual_values;
245  }
246 
247  // The reduced from the first dual ray. Will CHECK fail if there
248  // are no dual rays.
250  CHECK(has_dual_ray());
251  return dual_rays[0].reduced_costs;
252  }
253 
254  // Indicates if at least one basis is available.
255  bool has_basis() const { return !basis.empty(); }
256 
257  // The constraint basis status for the first primal/dual pair.
259  CHECK(has_basis());
260  return basis[0].constraint_status;
261  }
262 
263  // The variable basis status for the first primal/dual pair.
265  CHECK(has_basis());
266  return basis[0].variable_status;
267  }
268 
269  std::vector<std::string> warnings;
270  SolveResultProto::TerminationReason termination_reason =
271  SolveResultProto::TERMINATION_REASON_UNSPECIFIED;
272  std::string termination_detail;
273  SolveStatsProto solve_stats;
274 
275  // Primal solutions should be ordered best objective value first.
276  std::vector<PrimalSolution> primal_solutions;
277  std::vector<PrimalRay> primal_rays;
278 
279  // Dual solutions should be ordered best objective value first.
280  std::vector<DualSolution> dual_solutions;
281  std::vector<DualRay> dual_rays;
282 
283  // basis[i] corresponds to the primal dual pair:
284  // {primal_solutions[i], dual_solutions[i]}. These fields must have at least
285  // as many elements as basis. Basis will only be populated for LPs, and may
286  // not be populated.
287  std::vector<Basis> basis;
288 
289  // Set to true if MathOpt::Solve() has attempted an incremental solve instead
290  // of starting from scratch.
291  //
292  // We have three components involve in Solve(): MathOpt, the solver wrapper
293  // (solver.h) and the actual solver (SCIP, ...). For some model modifications,
294  // the wrapper can support modifying the actual solver's in-memory model
295  // instead of recreating it from scratch. This member is set to true when this
296  // happens.
298 };
299 
300 } // namespace math_opt
301 } // namespace operations_research
302 
303 #endif // OR_TOOLS_MATH_OPT_CPP_RESULT_H_
#define CHECK(condition)
Definition: base/logging.h:491
SolveResultProto::TerminationReason termination_reason
Definition: result.h:270
const VariableMap< double > & reduced_costs() const
Definition: result.h:227
GRBmodel * model
std::vector< std::string > warnings
Definition: result.h:269
const LinearConstraintMap< double > & ray_dual_values() const
Definition: result.h:242
const VariableMap< BasisStatus > & variable_status() const
Definition: result.h:264
std::vector< DualSolution > dual_solutions
Definition: result.h:280
inline ::absl::StatusOr< absl::Duration > DecodeGoogleApiProto(const google::protobuf::Duration &proto)
Definition: protoutil.h:42
const VariableMap< double > & ray_reduced_costs() const
Definition: result.h:249
std::vector< Basis > basis
Definition: result.h:287
LinearConstraintMap< double > dual_values
Definition: result.h:103
std::vector< PrimalSolution > primal_solutions
Definition: result.h:276
const LinearConstraintMap< BasisStatus > & constraint_status() const
Definition: result.h:258
VariableMap< BasisStatus > variable_status
Definition: result.h:167
const VariableMap< double > & ray_variable_values() const
Definition: result.h:204
LinearConstraintMap< BasisStatus > constraint_status
Definition: result.h:166
Result(IndexedModel *model, const SolveResultProto &solve_result)
Definition: result.cc:49
LinearConstraintMap< double > dual_values
Definition: result.h:132
std::vector< PrimalRay > primal_rays
Definition: result.h:277
const LinearConstraintMap< double > & dual_values() const
Definition: result.h:217
Collection of objects used to extend the Constraint Solver library.
std::vector< DualRay > dual_rays
Definition: result.h:281
const VariableMap< double > & variable_values() const
Definition: result.h:191
absl::Duration solve_time() const
Definition: result.h:179
int64_t value