Google OR-Tools v9.11
a fast and portable software suite for combinatorial optimization
Loading...
Searching...
No Matches
feasibility_pump.h
Go to the documentation of this file.
1// Copyright 2010-2024 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"
33#include "ortools/sat/sat_parameters.pb.h"
36#include "ortools/sat/util.h"
38
39namespace operations_research {
40namespace 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 integer_lp_;
171 int model_vars_size_ = 0;
172
173 // Underlying LP solver API.
174 glop::LinearProgram lp_data_;
175 glop::RevisedSimplex simplex_;
176
177 glop::ColMapping norm_variables_;
178 glop::ColToRowMapping norm_lhs_constraints_;
179 glop::ColToRowMapping norm_rhs_constraints_;
180
181 // For the scaling.
182 glop::LpScalingHelper scaler_;
183
184 // Structures used for mirroring IntegerVariables inside the underlying LP
185 // solver: an integer variable var is mirrored by mirror_lp_variable_[var].
186 // Note that these indices are dense in [0, mirror_lp_variable_.size()] so
187 // they can be used as vector indices.
188 std::vector<IntegerVariable> integer_variables_;
189 absl::flat_hash_map<IntegerVariable, glop::ColIndex> mirror_lp_variable_;
190
191 // True if the variable was binary before we apply scaling.
192 std::vector<bool> var_is_binary_;
193
194 // The following lock information is computed only once.
195 // Number of constraints restricting variable to take higher (resp. lower)
196 // values.
197 std::vector<int> var_up_locks_;
198 std::vector<int> var_down_locks_;
199
200 // We need to remember what to optimize if an objective is given, because
201 // then we will switch the objective between feasibility and optimization.
202 bool objective_is_defined_ = false;
203
204 // Singletons from Model.
205 const SatParameters& sat_parameters_;
206 TimeLimit* time_limit_;
207 IntegerTrail* integer_trail_;
208 Trail* trail_;
209 IntegerEncoder* integer_encoder_;
210 SharedIncompleteSolutionManager* incomplete_solutions_;
211 SatSolver* sat_solver_;
212 IntegerDomains* domains_;
213 const CpModelMapping* mapping_;
214
215 // Last OPTIMAL/Feasible solution found by a call to the underlying LP solver.
216 bool lp_solution_is_set_ = false;
217 bool lp_solution_is_integer_ = false;
218 double lp_objective_;
219 std::vector<double> lp_solution_;
220 std::vector<double> best_lp_solution_;
221 // We use max fractionality of all variables.
222 double lp_solution_fractionality_;
223
224 // Rounded Integer solution. This might not be feasible.
225 bool integer_solution_is_set_ = false;
226 bool integer_solution_is_feasible_ = false;
227 int64_t integer_solution_objective_;
228 std::vector<int64_t> integer_solution_;
229 std::vector<int64_t> best_integer_solution_;
230 int num_infeasible_constraints_;
231 // We use max infeasibility of all constraints.
232 int64_t integer_solution_infeasibility_;
233
234 // Sum of all simplex iterations performed by this class. This is useful to
235 // test the incrementality and compare to other solvers.
236 int64_t total_num_simplex_iterations_ = 0;
237
238 // TODO(user): Tune default value. Expose as parameter.
239 int max_fp_iterations_ = 20;
240};
241
242} // namespace sat
243} // namespace operations_research
244
245#endif // OR_TOOLS_SAT_FEASIBILITY_PUMP_H_
Entry point of the revised simplex algorithm implementation.
void SetObjectiveCoefficient(IntegerVariable ivar, IntegerValue coeff)
int64_t GetIntegerSolutionValue(IntegerVariable variable) const
bool Solve()
Returns false if the model is proven to be infeasible.
void AddLinearConstraint(const LinearConstraint &ct)
Add a new linear constraint to this LP.
double GetLPSolutionValue(IntegerVariable variable) const
const Constraint * ct
IntVar * var
GRBmodel * model
In SWIG mode, we don't want anything besides these top-level includes.