OR-Tools  9.6
feasibility_pump.h
Go to the documentation of this file.
1 // Copyright 2010-2022 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_SAT_FEASIBILITY_PUMP_H_
15 #define OR_TOOLS_SAT_FEASIBILITY_PUMP_H_
16 
17 #include <algorithm>
18 #include <cstdint>
19 #include <utility>
20 #include <vector>
21 
22 #include "absl/container/flat_hash_map.h"
29 #include "ortools/sat/integer.h"
31 #include "ortools/sat/model.h"
32 #include "ortools/sat/sat_base.h"
33 #include "ortools/sat/sat_parameters.pb.h"
34 #include "ortools/sat/sat_solver.h"
36 #include "ortools/sat/util.h"
38 
39 namespace operations_research {
40 namespace sat {
41 
43  public:
44  explicit FeasibilityPump(Model* model);
46 
47  typedef glop::RowIndex ConstraintIndex;
48 
49  void SetMaxFPIterations(int max_iter) {
50  max_fp_iterations_ = std::max(1, max_iter);
51  }
52 
53  // Add a new linear constraint to this LP.
55 
56  // Set the coefficient of the variable in the objective. Calling it twice will
57  // overwrite the previous value. Note that this doesn't set the objective
58  // coefficient if the variable doesn't appear in any constraints. So this has
59  // to be called after all the constraints are added.
60  void SetObjectiveCoefficient(IntegerVariable ivar, IntegerValue coeff);
61 
62  // Returns the LP value of a variable in the current
63  // solution. These functions should only be called when HasSolution() is true.
64  bool HasLPSolution() const { return lp_solution_is_set_; }
65  double LPSolutionObjectiveValue() const { return lp_objective_; }
66  double GetLPSolutionValue(IntegerVariable variable) const;
67  bool LPSolutionIsInteger() const { return lp_solution_is_integer_; }
68  double LPSolutionFractionality() const { return lp_solution_fractionality_; }
69 
70  // Returns the Integer solution value of a variable in the current rounded
71  // solution. These functions should only be called when HasIntegerSolution()
72  // is true.
73  bool HasIntegerSolution() const { return integer_solution_is_set_; }
75  return integer_solution_objective_;
76  }
78  return integer_solution_is_feasible_;
79  }
80  int64_t GetIntegerSolutionValue(IntegerVariable variable) const;
81 
82  // Returns false if the model is proven to be infeasible.
83  bool Solve();
84 
85  private:
86  // Solve the LP, returns false if something went wrong in the LP solver.
87  bool SolveLp();
88 
89  // Calls the specified rounding method in the parameters. Returns false if the
90  // rounding couldn't be finished.
91  bool Round();
92 
93  // Round the fractional LP solution values to nearest integer values. This
94  // rounding always finishes so always returns true.
95  bool NearestIntegerRounding();
96 
97  // Counts the number of up and down locks as defined below.
98  // #up_locks = #upper bounded constraints with positive coeff for var
99  // + #lower bounded constraints with negative coeff for var.
100  // #down_locks = #lower bounded constraints with positive coeff for var
101  // + #upper bounded constraints with negative coeff for var.
102  // Rounds the variable in the direction of lesser locks. When the
103  // fractionality is low (less than 0.1), this reverts to nearest integer
104  // rounding to avoid rounding almost integer values in wrong direction.
105  // This rounding always finishes so always returns true.
106  bool LockBasedRounding();
107 
108  // Similar to LockBasedRounding except this only considers locks of active
109  // constraints.
110  bool ActiveLockBasedRounding();
111 
112  // This is expensive rounding algorithm. We round variables one by one and
113  // propagate the bounds in between. If none of the rounded values fall in
114  // the continuous domain specified by lower and upper bound, we use the
115  // current lower/upper bound (whichever one is closest) instead of rounding
116  // the fractional lp solution value. If both the rounded values are in the
117  // domain, we round to nearest integer. This idea was presented in the paper
118  // "Feasibility pump 2.0" (2009) by Matteo Fischetti, Domenico Salvagnin.
119  //
120  // This rounding might not finish either because the time limit is reached or
121  // the model is detected to be unsat. Returns false in those cases.
122  bool PropagationRounding();
123 
124  void FillIntegerSolutionStats();
125 
126  // Loads the lp_data_.
127  void InitializeWorkingLP();
128 
129  // Changes the LP objective and bounds of the norm constraints so the new
130  // objective also tries to minimize the distance to the rounded solution.
131  void L1DistanceMinimize();
132 
133  // Stores the solutions in the shared repository. Stores LP solution if it is
134  // integer and stores the integer solution if it is feasible.
135  void MaybePushToRepo();
136 
137  void PrintStats();
138 
139  // Returns the variable value on the same scale as the CP variable value.
140  double GetVariableValueAtCpScale(glop::ColIndex var);
141 
142  // Shortcut for an integer linear expression type.
143  using LinearExpression = std::vector<std::pair<glop::ColIndex, IntegerValue>>;
144 
145  // Gets or creates an LP variable that mirrors a model variable.
146  // The variable should be a positive reference.
147  glop::ColIndex GetOrCreateMirrorVariable(IntegerVariable positive_variable);
148 
149  // Updates the bounds of the LP variables from the CP bounds.
150  void UpdateBoundsOfLpVariables();
151 
152  // This epsilon is related to the precision of the value returned by the LP
153  // once they have been scaled back into the CP domain. So for large domain or
154  // cost coefficient, we may have some issues.
155  static const double kCpEpsilon;
156 
157  // Initial problem in integer form.
158  // We always sort the inner vectors by increasing glop::ColIndex.
159  struct LinearConstraintInternal {
160  IntegerValue lb;
161  IntegerValue ub;
162  LinearExpression terms;
163  };
164  LinearExpression integer_objective_;
165  IntegerValue objective_infinity_norm_ = IntegerValue(0);
166  double objective_normalization_factor_ = 0.0;
167  double mixing_factor_ = 1.0;
168 
170  int model_vars_size_ = 0;
171 
172  // Underlying LP solver API.
173  glop::LinearProgram lp_data_;
174  glop::RevisedSimplex simplex_;
175 
176  glop::ColMapping norm_variables_;
177  glop::ColToRowMapping norm_lhs_constraints_;
178  glop::ColToRowMapping norm_rhs_constraints_;
179 
180  // For the scaling.
181  glop::LpScalingHelper scaler_;
182 
183  // Structures used for mirroring IntegerVariables inside the underlying LP
184  // solver: an integer variable var is mirrored by mirror_lp_variable_[var].
185  // Note that these indices are dense in [0, mirror_lp_variable_.size()] so
186  // they can be used as vector indices.
187  std::vector<IntegerVariable> integer_variables_;
188  absl::flat_hash_map<IntegerVariable, glop::ColIndex> mirror_lp_variable_;
189 
190  // True if the variable was binary before we apply scaling.
191  std::vector<bool> var_is_binary_;
192 
193  // The following lock information is computed only once.
194  // Number of constraints restricting variable to take higher (resp. lower)
195  // values.
196  std::vector<int> var_up_locks_;
197  std::vector<int> var_down_locks_;
198 
199  // We need to remember what to optimize if an objective is given, because
200  // then we will switch the objective between feasibility and optimization.
201  bool objective_is_defined_ = false;
202 
203  // Singletons from Model.
204  const SatParameters& sat_parameters_;
205  TimeLimit* time_limit_;
206  IntegerTrail* integer_trail_;
207  Trail* trail_;
208  IntegerEncoder* integer_encoder_;
209  SharedIncompleteSolutionManager* incomplete_solutions_;
210  SatSolver* sat_solver_;
211  IntegerDomains* domains_;
212  const CpModelMapping* mapping_;
213 
214  // Last OPTIMAL/Feasible solution found by a call to the underlying LP solver.
215  bool lp_solution_is_set_ = false;
216  bool lp_solution_is_integer_ = false;
217  double lp_objective_;
218  std::vector<double> lp_solution_;
219  std::vector<double> best_lp_solution_;
220  // We use max fractionality of all variables.
221  double lp_solution_fractionality_;
222 
223  // Rounded Integer solution. This might not be feasible.
224  bool integer_solution_is_set_ = false;
225  bool integer_solution_is_feasible_ = false;
226  int64_t integer_solution_objective_;
227  std::vector<int64_t> integer_solution_;
228  std::vector<int64_t> best_integer_solution_;
229  int num_infeasible_constraints_;
230  // We use max infeasibility of all constraints.
231  int64_t integer_solution_infeasibility_;
232 
233  // Sum of all simplex iterations performed by this class. This is useful to
234  // test the incrementality and compare to other solvers.
235  int64_t total_num_simplex_iterations_ = 0;
236 
237  // TODO(user): Tune default value. Expose as parameter.
238  int max_fp_iterations_ = 20;
239 
240  bool model_is_unsat_ = false;
241 };
242 
243 } // namespace sat
244 } // namespace operations_research
245 
246 #endif // OR_TOOLS_SAT_FEASIBILITY_PUMP_H_
int64_t max
Definition: alldiff_cst.cc:140
A simple class to enforce both an elapsed time limit and a deterministic time limit in the same threa...
Definition: time_limit.h:106
double GetLPSolutionValue(IntegerVariable variable) const
int64_t GetIntegerSolutionValue(IntegerVariable variable) const
void AddLinearConstraint(const LinearConstraint &ct)
void SetObjectiveCoefficient(IntegerVariable ivar, IntegerValue coeff)
Class that owns everything related to a particular optimization model.
Definition: sat/model.h:42
const Constraint * ct
IntVar * var
Definition: expr_array.cc:1874
GRBmodel * model
Collection of objects used to extend the Constraint Solver library.