OR-Tools  9.2
lp_solver.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_GLOP_LP_SOLVER_H_
15 #define OR_TOOLS_GLOP_LP_SOLVER_H_
16 
17 #include <memory>
18 
23 #include "ortools/util/logging.h"
25 
26 namespace operations_research {
27 namespace glop {
28 
29 // A full-fledged linear programming solver.
30 class LPSolver {
31  public:
32  LPSolver();
33 
34  // Sets and gets the solver parameters.
35  // See the proto for an extensive documentation.
37  const GlopParameters& GetParameters() const;
39 
40  // Solves the given linear program and returns the solve status. See the
41  // ProblemStatus documentation for a description of the different values.
42  //
43  // The solution can be retrieved afterwards using the getter functions below.
44  // Note that depending on the returned ProblemStatus the solution values may
45  // not mean much, so it is important to check the returned status.
46  //
47  // Incrementality: From one Solve() call to the next, the internal state is
48  // not cleared and the solver may take advantage of its current state if the
49  // given lp is only slightly modified. If the modification is too important,
50  // or if the solver does not see how to reuse the previous state efficiently,
51  // it will just solve the problem from scratch. On the other hand, if the lp
52  // is the same, calling Solve() again should basically resume the solve from
53  // the last position. To disable this behavior, simply call Clear() before.
54  ABSL_MUST_USE_RESULT ProblemStatus Solve(const LinearProgram& lp);
55 
56  // Same as Solve() but use the given time limit rather than constructing a new
57  // one from the current GlopParameters.
58  ABSL_MUST_USE_RESULT ProblemStatus SolveWithTimeLimit(const LinearProgram& lp,
60 
61  // Puts the solver in a clean state.
62  //
63  // Calling Solve() for the first time, or calling Clear() then Solve() on the
64  // same problem is guaranted to be deterministic and to always give the same
65  // result, assuming that no time limit was specified.
66  void Clear();
67 
68  // Advanced usage. This should be called before calling Solve(). It will
69  // configure the solver to try to start from the given point for the next
70  // Solve() only. Note that calling Clear() will invalidate this information.
71  //
72  // If the set of variables/constraints with a BASIC status does not form a
73  // basis a warning will be logged and the code will ignore it. Otherwise, the
74  // non-basic variables will be initialized to their given status and solving
75  // will start from there (even if the solution is not primal/dual feasible).
76  //
77  // Important: There is no facility to transform this information in sync with
78  // presolve. So you should probably disable presolve when using this since
79  // otherwise there is a good chance that the matrix will change and that the
80  // given basis will make no sense. Even worse if it happens to be factorizable
81  // but doesn't correspond to what was intended.
84 
85  // This loads a given solution and computes related quantities so that the
86  // getters below will refer to it.
87  //
88  // Depending on the given solution status, this also checks the solution
89  // feasibility or optimality. The exact behavior and tolerances are controlled
90  // by the solver parameters. Because of this, the returned ProblemStatus may
91  // be changed from the one passed in the ProblemSolution to ABNORMAL or
92  // IMPRECISE. Note that this is the same logic as the one used by Solve() to
93  // verify the solver solution.
95  const ProblemSolution& solution);
96 
97  // Returns the objective value of the solution with its offset and scaling.
99 
100  // Accessors to information related to variables.
101  const DenseRow& variable_values() const { return primal_values_; }
102  const DenseRow& reduced_costs() const { return reduced_costs_; }
104  return variable_statuses_;
105  }
106 
107  // Accessors to information related to constraints. The activity of a
108  // constraint is the sum of its linear terms evaluated with variables taking
109  // their values at the current solution.
110  //
111  // Note that the dual_values() do not take into account an eventual objective
112  // scaling of the solved LinearProgram.
113  const DenseColumn& dual_values() const { return dual_values_; }
115  return constraint_activities_;
116  }
118  return constraint_statuses_;
119  }
120 
121  // Accessors to information related to unboundedness. A primal ray is returned
122  // for primal unbounded problems and a dual ray is returned for dual unbounded
123  // problems. constraints_dual_ray corresponds to dual multiplier for
124  // constraints and variable_bounds_dual_ray corresponds to dual multipliers
125  // for variable bounds (cf. reduced_costs).
126  const DenseRow& primal_ray() const { return primal_ray_; }
128  return constraints_dual_ray_;
129  }
131  return variable_bounds_dual_ray_;
132  }
133 
134  // Returns the primal maximum infeasibility of the solution.
135  // This indicates by how much the variable and constraint bounds are violated.
137 
138  // Returns the dual maximum infeasibility of the solution.
139  // This indicates by how much the variable costs (i.e. objective) should be
140  // modified for the solution to be an exact optimal solution.
142 
143  // Returns true if the solution status was OPTIMAL and it seems that there is
144  // more than one basic optimal solution. Note that this solver always returns
145  // an optimal BASIC solution and that there is only a finite number of them.
146  // Moreover, given one basic solution, since the basis is always refactorized
147  // at optimality before reporting the numerical result, then all the
148  // quantities (even the floating point ones) should be always the same.
149  //
150  // TODO(user): Test this behavior extensively if a client relies on it.
151  bool MayHaveMultipleOptimalSolutions() const;
152 
153  // Returns the number of simplex iterations used by the last Solve().
154  int GetNumberOfSimplexIterations() const;
155 
156  // Returns the "deterministic time" since the creation of the solver. Note
157  // That this time is only increased when some operations take place in this
158  // class.
159  //
160  // TODO(user): Currently, this is only modified when the simplex code is
161  // executed.
162  //
163  // TODO(user): Improve the correlation with the running time.
164  double DeterministicTime() const;
165 
166  // Returns the SolverLogger used during solves.
167  //
168  // Please note that EnableLogging() and SetLogToStdOut() are reset at the
169  // beginning of each solve based on parameters so setting them will have no
170  // effect.
172 
173  private:
174  // Resizes all the solution vectors to the given sizes.
175  // This is used in case of error to make sure all the getter functions will
176  // not crash when given row/col inside the initial linear program dimension.
177  void ResizeSolution(RowIndex num_rows, ColIndex num_cols);
178 
179  // Make sure the primal and dual values are within their bounds in order to
180  // have a strong guarantee on the optimal solution. See
181  // provide_strong_optimal_guarantee in the GlopParameters proto.
182  void MovePrimalValuesWithinBounds(const LinearProgram& lp);
183  void MoveDualValuesWithinBounds(const LinearProgram& lp);
184 
185  // Runs the revised simplex algorithm if needed (i.e. if the program was not
186  // already solved by the preprocessors).
187  void RunRevisedSimplexIfNeeded(ProblemSolution* solution,
189 
190  // Checks that the returned solution values and statuses are consistent.
191  // Returns true if this is the case. See the code for the exact check
192  // performed.
193  bool IsProblemSolutionConsistent(const LinearProgram& lp,
194  const ProblemSolution& solution) const;
195 
196  // Returns true if there may be multiple optimal solutions.
197  // The return value is true if:
198  // - a non-fixed variable, at one of its boumds, has its reduced
199  // cost close to zero.
200  // or if:
201  // - a non-equality constraint (i.e. l <= a.x <= r, with l != r), is at one of
202  // its bounds (a.x = r or a.x = l) and has its dual value close to zero.
203  bool IsOptimalSolutionOnFacet(const LinearProgram& lp);
204 
205  // Computes derived quantities from the solution.
206  void ComputeReducedCosts(const LinearProgram& lp);
207  void ComputeConstraintActivities(const LinearProgram& lp);
208 
209  // Computes the primal/dual objectives (without the offset). Note that the
210  // dual objective needs the reduced costs in addition to the dual values.
211  double ComputeObjective(const LinearProgram& lp);
212  double ComputeDualObjective(const LinearProgram& lp);
213 
214  // Given a relative precision on the primal values of up to
215  // solution_feasibility_tolerance(), this returns an upper bound on the
216  // expected precision of the objective.
217  double ComputeMaxExpectedObjectiveError(const LinearProgram& lp);
218 
219  // Returns the max absolute cost pertubation (resp. rhs perturbation) so that
220  // the pair (primal values, dual values) is an EXACT optimal solution to the
221  // perturbed problem. Note that this assumes that
222  // MovePrimalValuesWithinBounds() and MoveDualValuesWithinBounds() have
223  // already been called. The Boolean is_too_large is set to true if any of the
224  // perturbation exceed the tolerance (which depends of the coordinate).
225  //
226  // These bounds are computed using the variable and constraint statuses by
227  // enforcing the complementary slackness optimal conditions. Note that they
228  // are almost the same as ComputeActivityInfeasibility() and
229  // ComputeReducedCostInfeasibility() but looks for optimality rather than just
230  // feasibility.
231  //
232  // Note(user): We could get EXACT bounds on these perturbations by changing
233  // the rounding mode appropriately during these computations. But this is
234  // probably not needed.
235  Fractional ComputeMaxCostPerturbationToEnforceOptimality(
236  const LinearProgram& lp, bool* is_too_large);
237  Fractional ComputeMaxRhsPerturbationToEnforceOptimality(
238  const LinearProgram& lp, bool* is_too_large);
239 
240  // Computes the maximum of the infeasibilities associated with each values.
241  // The returned infeasibilities are the maximum of the "absolute" errors of
242  // each vector coefficients.
243  //
244  // These function also set is_too_large to true if any infeasibility is
245  // greater than the tolerance (which depends of the coordinate).
246  double ComputePrimalValueInfeasibility(const LinearProgram& lp,
247  bool* is_too_large);
248  double ComputeActivityInfeasibility(const LinearProgram& lp,
249  bool* is_too_large);
250  double ComputeDualValueInfeasibility(const LinearProgram& lp,
251  bool* is_too_large);
252  double ComputeReducedCostInfeasibility(const LinearProgram& lp,
253  bool* is_too_large);
254 
255  // On a call to Solve(), this is initialized to an exact copy of the given
256  // linear program. It is later modified by the preprocessors and then solved
257  // by the revised simplex.
258  //
259  // This is not efficient memory-wise but allows to check optimality with
260  // respect to the given LinearProgram that is guaranteed to not have been
261  // modified. It also allows for a nicer Solve() API with a const
262  // LinearProgram& input.
263  LinearProgram current_linear_program_;
264 
265  SolverLogger logger_;
266 
267  // The revised simplex solver.
268  std::unique_ptr<RevisedSimplex> revised_simplex_;
269 
270  // The number of revised simplex iterations used by the last Solve().
271  int num_revised_simplex_iterations_;
272 
273  // The current ProblemSolution.
274  // TODO(user): use a ProblemSolution directly?
275  DenseRow primal_values_;
276  DenseColumn dual_values_;
277  VariableStatusRow variable_statuses_;
278  ConstraintStatusColumn constraint_statuses_;
279  DenseRow primal_ray_;
280  DenseColumn constraints_dual_ray_;
281  DenseRow variable_bounds_dual_ray_;
282 
283  // Quantities computed from the solution and the linear program.
284  DenseRow reduced_costs_;
285  DenseColumn constraint_activities_;
286  Fractional problem_objective_value_;
287  bool may_have_multiple_solutions_;
288  Fractional max_absolute_primal_infeasibility_;
289  Fractional max_absolute_dual_infeasibility_;
290 
291  // Proto holding all the parameters of the algorithm.
292  GlopParameters parameters_;
293 
294  // The number of times Solve() was called. Used to number dump files.
295  int num_solves_;
296 
297  DISALLOW_COPY_AND_ASSIGN(LPSolver);
298 };
299 
300 } // namespace glop
301 } // namespace operations_research
302 
303 #endif // OR_TOOLS_GLOP_LP_SOLVER_H_
A simple class to enforce both an elapsed time limit and a deterministic time limit in the same threa...
Definition: time_limit.h:106
Fractional GetMaximumPrimalInfeasibility() const
Definition: lp_solver.cc:489
const GlopParameters & GetParameters() const
Definition: lp_solver.cc:124
void SetInitialBasis(const VariableStatusRow &variable_statuses, const ConstraintStatusColumn &constraint_statuses)
Definition: lp_solver.cc:238
const DenseRow & variable_bounds_dual_ray() const
Definition: lp_solver.h:130
ModelSharedTimeLimit * time_limit
const DenseColumn & constraints_dual_ray() const
Definition: lp_solver.h:127
Fractional GetObjectiveValue() const
Definition: lp_solver.cc:485
ABSL_MUST_USE_RESULT ProblemStatus SolveWithTimeLimit(const LinearProgram &lp, TimeLimit *time_limit)
Definition: lp_solver.cc:136
const DenseRow & variable_values() const
Definition: lp_solver.h:101
void SetParameters(const GlopParameters &parameters)
Definition: lp_solver.cc:112
ProblemStatus LoadAndVerifySolution(const LinearProgram &lp, const ProblemSolution &solution)
Definition: lp_solver.cc:293
GlopParameters * GetMutableParameters()
Definition: lp_solver.cc:126
bool MayHaveMultipleOptimalSolutions() const
Definition: lp_solver.cc:497
const VariableStatusRow & variable_statuses() const
Definition: lp_solver.h:103
const DenseColumn & constraint_activities() const
Definition: lp_solver.h:114
const ConstraintStatusColumn & constraint_statuses() const
Definition: lp_solver.h:117
Collection of objects used to extend the Constraint Solver library.
SatParameters parameters
const DenseRow & primal_ray() const
Definition: lp_solver.h:126
const DenseColumn & dual_values() const
Definition: lp_solver.h:113
ABSL_MUST_USE_RESULT ProblemStatus Solve(const LinearProgram &lp)
Definition: lp_solver.cc:130
const DenseRow & reduced_costs() const
Definition: lp_solver.h:102
Fractional GetMaximumDualInfeasibility() const
Definition: lp_solver.cc:493