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
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"
29
30namespace operations_research {
31namespace 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.
37struct 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.
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;
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 {
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.
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.
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.
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;
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
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:167
LinearConstraintMap< BasisStatus > constraint_status
Definition: result.h:166
LinearConstraintMap< double > dual_values
Definition: result.h:132
LinearConstraintMap< double > dual_values
Definition: result.h:103
const VariableMap< double > & ray_variable_values() const
Definition: result.h:204
const LinearConstraintMap< double > & dual_values() const
Definition: result.h:217
std::vector< PrimalSolution > primal_solutions
Definition: result.h:276
const VariableMap< BasisStatus > & variable_status() const
Definition: result.h:264
absl::Duration solve_time() const
Definition: result.h:179
std::vector< std::string > warnings
Definition: result.h:269
const LinearConstraintMap< double > & ray_dual_values() const
Definition: result.h:242
std::vector< PrimalRay > primal_rays
Definition: result.h:277
SolveResultProto::TerminationReason termination_reason
Definition: result.h:270
const VariableMap< double > & ray_reduced_costs() const
Definition: result.h:249
const LinearConstraintMap< BasisStatus > & constraint_status() const
Definition: result.h:258
const VariableMap< double > & variable_values() const
Definition: result.h:191
Result(IndexedModel *model, const SolveResultProto &solve_result)
Definition: result.cc:49
const VariableMap< double > & reduced_costs() const
Definition: result.h:227
std::vector< DualSolution > dual_solutions
Definition: result.h:280
std::vector< DualRay > dual_rays
Definition: result.h:281
std::vector< Basis > basis
Definition: result.h:287