Google OR-Tools v9.15
a fast and portable software suite for combinatorial optimization
Loading...
Searching...
No Matches
preprocessor.h
Go to the documentation of this file.
1// Copyright 2010-2025 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 ORTOOLS_LINEAR_SOLVER_PROTO_SOLVER_PREPROCESSOR_H_
15#define ORTOOLS_LINEAR_SOLVER_PROTO_SOLVER_PREPROCESSOR_H_
16
20
21namespace operations_research {
22
23// --------------------------------------------------------
24// IntegerBoundsPreprocessor
25// --------------------------------------------------------
26
27// Makes the bounds of integer variables integer. Makes the bounds of
28// constraints involving only integer variables with integer coefficients
29// integer.
31 public:
33 glop::Fractional integer_solution_tolerance)
34 : glop::Preprocessor(parameters),
35 integer_solution_tolerance_(integer_solution_tolerance) {}
36
39 delete;
40 ~IntegerBoundsPreprocessor() override = default;
41
42 bool Run(glop::LinearProgram* linear_program) override;
43 void RecoverSolution(glop::ProblemSolution* /*solution*/) const override {}
44
45 private:
46 const glop::Fractional integer_solution_tolerance_;
47};
48
49// --------------------------------------------------------
50// BoundPropagationPreprocessor
51// --------------------------------------------------------
52
53// It is possible to compute "implied" bounds on a variable from the bounds of
54// all the other variables and the constraints in which this variable take
55// place. These "implied" bounds can be used to restrict the variable bounds.
56// This preprocessor just does that until no more bounds can be propagated or
57// a given limit on the number of propagations is reached.
58//
59// Note(user): In particular, this preprocessor will remove any singleton row.
60//
61// Note(user): This seems like a general LP preprocessor but it is really
62// difficult to postsolve it correctly in the LP context when one wants to have
63// a basic optimal solution at the end. By contrast, in Mip context one is happy
64// with any form of an optimal solution at the end, thus restoring the full
65// solution is trivial. Consequently, bound propagation is implemented as a mip
66// preprocessor.
68 public:
70 glop::Fractional integer_solution_tolerance)
71 : glop::Preprocessor(parameters),
72 integer_solution_tolerance_(integer_solution_tolerance) {}
77 ~BoundPropagationPreprocessor() override = default;
79 bool Run(glop::LinearProgram* linear_program) override;
80 void RecoverSolution(glop::ProblemSolution* /*solution*/) const override {}
82 private:
83 const glop::Fractional integer_solution_tolerance_;
84};
85
86// --------------------------------------------------------
87// ImpliedIntegerPreprocessor
88// --------------------------------------------------------
89
90// In this preprocessor, we find continuous variables which can only take
91// integer values and mark them as integer variables.
92//
93// There are two methods for detecting implied integer variables: 1) primal
94// and 2) dual detection. If the variable appears in at least one equality
95// constraint then we use primal detection otherwise we use dual detection.
97 public:
99 const glop::GlopParameters* parameters,
100 glop::Fractional integer_solution_tolerance)
101 : glop::Preprocessor(parameters),
102 integer_solution_tolerance_(integer_solution_tolerance) {}
103
109 // TODO(user): When some variable are detected to be implied integer, other
110 // can in turn be detected as such. Change the code to reach a fixed point.
111 // Calling this multiple time has a similar effect, but is a lot less
112 // efficient and can require O(num_variables) calls to reach the fix point.
113 bool Run(glop::LinearProgram* linear_program) override;
114 void RecoverSolution(glop::ProblemSolution* /*solution*/) const override {}
115
116 private:
117 // Returns true if the given variable is implied integer. This method is used
118 // for continuous variables appearing in at least one equality constraint.
119 // This is sometimes called "primal" detection in the literature.
120 //
121 // For each equality constraint s in which the given continuous variable x_j
122 // appears, this method checks the primal detection criteria by using
123 // ConstraintSupportsImpliedIntegrality() method.
124 bool AnyEqualityConstraintImpliesIntegrality(
125 const glop::LinearProgram& linear_program, glop::ColIndex variable);
126
127 // Returns true if given variable is implied integer variable. This method is
128 // used for continuous variables for which primal detection is not applicable
129 // i.e. all constraints containing the given variable are inequalities. This
130 // is sometimes called "dual" detection in the literature.
131 //
132 // This method checks the following for the givan continuous variable x_j.
133 // a) The lower and upper bound of x_j are integers or the variable has no
134 // cost and its domain contains an integer point.
135 // b) For all constraint containing x_j, when treated as equality under primal
136 // detection, implies x_j as integer variable.
137 // If both conditions are satisfied then the variable x_j is implied integer
138 // variable.
139 bool AllInequalityConstraintsImplyIntegrality(
140 const glop::LinearProgram& linear_program, glop::ColIndex variable);
141
142 // Returns true if the following conditions are satisfied.
143 //
144 // Let the constraint be lb_s <= \sum_{i=1..n}(a_si*x_i) + a_sj*x_j <= ub_s
145 // a) lb_s / a_sj and ub_s / a_sj are integers.
146 // b) a_si / a_sj is integer for all i.
147 // c) x_i are all integer variables.
148 bool ConstraintSupportsImpliedIntegrality(
149 const glop::LinearProgram& linear_program, glop::ColIndex variable,
150 glop::RowIndex row);
151
152 // Returns true if the variable occurs in at least one equality constraint.
153 bool VariableOccursInAtLeastOneEqualityConstraint(
154 const glop::LinearProgram& linear_program, glop::ColIndex variable);
155
156 private:
157 const glop::Fractional integer_solution_tolerance_;
158};
159
160// --------------------------------------------------------
161// ReduceCostOverExclusiveOrConstraintPreprocessor
162// --------------------------------------------------------
163
164// For an "exclusive or" constraint (sum Boolean = 1), if all the costs of the
165// Boolean variables are positive, then we can subtract the cost of the one
166// with minimum cost from the cost of all the others. We can do that for all
167// such constraints one by one.
168//
169// ex: if x,y,z are Boolean variables with respective cost 1,2,1 and x+y+z=1,
170// then we can change their costs to 0,1,0 and add 1 to the objective offset
171// without changing the cost of any feasible solution.
172//
173// This seems pretty trivial, but can have a big impact depending on the
174// technique we use to solve the MIP. It also makes the objective sparser which
175// can only be a good thing.
176//
177// TODO(user): In more generality, in presence of an exclusive or constraint we
178// can shift the cost by any value (even negative), so it may be good to
179// maximize the number of coefficients at zero. To investigate.
181 : public glop::Preprocessor {
182 public:
184 const glop::GlopParameters* mip_parameters)
185 : glop::Preprocessor(mip_parameters) {}
192 bool Run(glop::LinearProgram* linear_program) override;
193 void RecoverSolution(glop::ProblemSolution* /*solution*/) const override {}
195
196} // namespace operations_research
197
198#endif // ORTOOLS_LINEAR_SOLVER_PROTO_SOLVER_PREPROCESSOR_H_
void RecoverSolution(glop::ProblemSolution *) const override
BoundPropagationPreprocessor & operator=(const BoundPropagationPreprocessor &)=delete
BoundPropagationPreprocessor(const glop::GlopParameters *parameters, glop::Fractional integer_solution_tolerance)
ImpliedIntegerPreprocessor & operator=(const ImpliedIntegerPreprocessor &)=delete
ImpliedIntegerPreprocessor(const glop::GlopParameters *parameters, glop::Fractional integer_solution_tolerance)
void RecoverSolution(glop::ProblemSolution *) const override
void RecoverSolution(glop::ProblemSolution *) const override
IntegerBoundsPreprocessor(const glop::GlopParameters *parameters, glop::Fractional integer_solution_tolerance)
IntegerBoundsPreprocessor & operator=(const IntegerBoundsPreprocessor &)=delete
void RecoverSolution(glop::ProblemSolution *) const override
ReduceCostOverExclusiveOrConstraintPreprocessor(const glop::GlopParameters *mip_parameters)
ReduceCostOverExclusiveOrConstraintPreprocessor & operator=(const ReduceCostOverExclusiveOrConstraintPreprocessor &)=delete
Preprocessor(const GlopParameters *parameters)
OR-Tools root namespace.