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