OR-Tools  9.1
sat/linear_constraint.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_LINEAR_CONSTRAINT_H_
15#define OR_TOOLS_SAT_LINEAR_CONSTRAINT_H_
16
17#include <vector>
18
20#include "ortools/sat/integer.h"
21#include "ortools/sat/model.h"
22
23namespace operations_research {
24namespace sat {
25
26// One linear constraint on a set of Integer variables.
27// Important: there should be no duplicate variables.
28//
29// We also assume that we never have integer overflow when evaluating such
30// constraint at the ROOT node. This should be enforced by the checker for user
31// given constraints, and we must enforce it ourselves for the newly created
32// constraint. See ValidateLinearConstraintForOverflow().
34 IntegerValue lb;
35 IntegerValue ub;
36 std::vector<IntegerVariable> vars;
37 std::vector<IntegerValue> coeffs;
38
40 LinearConstraint(IntegerValue _lb, IntegerValue _ub) : lb(_lb), ub(_ub) {}
41
42 void AddTerm(IntegerVariable var, IntegerValue coeff) {
43 vars.push_back(var);
44 coeffs.push_back(coeff);
45 }
46
47 void Clear() {
48 lb = ub = IntegerValue(0);
49 ClearTerms();
50 }
51
52 void ClearTerms() {
53 vars.clear();
54 coeffs.clear();
55 }
56
57 std::string DebugString() const {
58 std::string result;
59 if (lb.value() > kMinIntegerValue) {
60 absl::StrAppend(&result, lb.value(), " <= ");
61 }
62 for (int i = 0; i < vars.size(); ++i) {
63 absl::StrAppend(&result, i > 0 ? " " : "",
65 }
66 if (ub.value() < kMaxIntegerValue) {
67 absl::StrAppend(&result, " <= ", ub.value());
68 }
69 return result;
70 }
71
72 bool operator==(const LinearConstraint other) const {
73 if (this->lb != other.lb) return false;
74 if (this->ub != other.ub) return false;
75 if (this->vars != other.vars) return false;
76 if (this->coeffs != other.coeffs) return false;
77 return true;
78 }
79};
80
81inline std::ostream& operator<<(std::ostream& os, const LinearConstraint& ct) {
82 os << ct.DebugString();
83 return os;
84}
85
86// Helper struct to model linear expression for lin_min/lin_max constraints. The
87// canonical expression should only contain positive coefficients.
89 std::vector<IntegerVariable> vars;
90 std::vector<IntegerValue> coeffs;
91 IntegerValue offset = IntegerValue(0);
92
93 // Return the evaluation of the linear expression using the values from
94 // lp_values.
95 double LpValue(
96 const absl::StrongVector<IntegerVariable, double>& lp_values) const;
97
98 std::string DebugString() const;
99};
100
101// Returns the same expression in the canonical form (all positive
102// coefficients).
104
105// Returns lower bound of linear expression using variable bounds of the
106// variables in expression. Assumes Canonical expression (all positive
107// coefficients).
108IntegerValue LinExprLowerBound(const LinearExpression& expr,
109 const IntegerTrail& integer_trail);
110
111// Returns upper bound of linear expression using variable bounds of the
112// variables in expression. Assumes Canonical expression (all positive
113// coefficients).
114IntegerValue LinExprUpperBound(const LinearExpression& expr,
115 const IntegerTrail& integer_trail);
116
117// Makes sure that any of our future computation on this constraint will not
118// cause overflow. We use the level zero bounds and use the same definition as
119// in PossibleIntegerOverflow() in the cp_model.proto checker.
120//
121// Namely, the sum of positive terms, the sum of negative terms and their
122// difference shouldn't overflow. Note that we don't validate the rhs, but if
123// the bounds are properly relaxed, then this shouldn't cause any issues.
124//
125// Note(user): We should avoid doing this test too often as it can be slow. At
126// least do not do it more than once on each constraint.
128 const IntegerTrail& integer_trail);
129
130// Preserves canonicality.
132
133// Returns the same expression with positive variables.
135
136// Returns the coefficient of the variable in the expression. Works in linear
137// time.
138// Note: GetCoefficient(NegationOf(var, expr)) == -GetCoefficient(var, expr).
139IntegerValue GetCoefficient(const IntegerVariable var,
140 const LinearExpression& expr);
141IntegerValue GetCoefficientOfPositiveVar(const IntegerVariable var,
142 const LinearExpression& expr);
143
144// Allow to build a LinearConstraint while making sure there is no duplicate
145// variables. Note that we do not simplify literal/variable that are currently
146// fixed here.
148 public:
149 // We support "sticky" kMinIntegerValue for lb and kMaxIntegerValue for ub
150 // for one-sided constraints.
151 //
152 // Assumes that the 'model' has IntegerEncoder.
153 LinearConstraintBuilder(const Model* model, IntegerValue lb, IntegerValue ub)
154 : encoder_(*model->Get<IntegerEncoder>()), lb_(lb), ub_(ub) {}
155
156 // Adds var * coeff to the constraint.
157 void AddTerm(IntegerVariable var, IntegerValue coeff);
158 void AddTerm(AffineExpression expr, IntegerValue coeff);
159 void AddLinearExpression(const LinearExpression& expr);
160 void AddLinearExpression(const LinearExpression& expr, IntegerValue coeff);
161
162 // Add an under linearization of the product of two affine expressions.
163 // If at least one of them is fixed, then we add the exact product (which is
164 // linear). Otherwise, we use McCormick relaxation:
165 // left * right = (left_min + delta_left) * (right_min + delta_right) =
166 // left_min * right_min + delta_left * right_min +
167 // delta_right * left_min + delta_left * delta_right
168 // which is >= (by ignoring the quatratic term)
169 // right_min * left + left_min * right - right_min * left_min
170 //
171 // TODO(user): We could use (max - delta) instead of (min + delta) for each
172 // expression instead. This would depend on the LP value of the left and
173 // right.
175 IntegerTrail* integer_trail);
176
177 // Add value as a constant term to the linear equation.
178 void AddConstant(IntegerValue value);
179
180 // Add literal * coeff to the constaint. Returns false and do nothing if the
181 // given literal didn't have an integer view.
182 ABSL_MUST_USE_RESULT bool AddLiteralTerm(Literal lit, IntegerValue coeff);
183
184 // Builds and return the corresponding constraint in a canonical form.
185 // All the IntegerVariable will be positive and appear in increasing index
186 // order.
187 //
188 // TODO(user): this doesn't invalidate the builder object, but if one wants
189 // to do a lot of dynamic editing to the constraint, then then underlying
190 // algorithm needs to be optimized of that.
192
193 private:
194 const IntegerEncoder& encoder_;
195 IntegerValue lb_;
196 IntegerValue ub_;
197
198 // Initially we push all AddTerm() here, and during Build() we merge terms
199 // on the same variable.
200 std::vector<std::pair<IntegerVariable, IntegerValue>> terms_;
201};
202
203// Returns the activity of the given constraint. That is the current value of
204// the linear terms.
205double ComputeActivity(
206 const LinearConstraint& constraint,
208
209// Returns sqrt(sum square(coeff)).
210double ComputeL2Norm(const LinearConstraint& constraint);
211
212// Returns the maximum absolute value of the coefficients.
213IntegerValue ComputeInfinityNorm(const LinearConstraint& constraint);
214
215// Returns the scalar product of given constraint coefficients. This method
216// assumes that the constraint variables are in sorted order.
217double ScalarProduct(const LinearConstraint& constraint1,
218 const LinearConstraint& constraint2);
219
220// Computes the GCD of the constraint coefficient, and divide them by it. This
221// also tighten the constraint bounds assumming all the variables are integer.
222void DivideByGCD(LinearConstraint* constraint);
223
224// Removes the entries with a coefficient of zero.
225void RemoveZeroTerms(LinearConstraint* constraint);
226
227// Makes all coefficients positive by transforming a variable to its negation.
228void MakeAllCoefficientsPositive(LinearConstraint* constraint);
229
230// Makes all variables "positive" by transforming a variable to its negation.
231void MakeAllVariablesPositive(LinearConstraint* constraint);
232
233// Sorts and merges duplicate IntegerVariable in the given "terms".
234// Fills the given LinearConstraint with the result.
236 std::vector<std::pair<IntegerVariable, IntegerValue>>* terms,
237 LinearConstraint* constraint);
238
239// Sorts the terms and makes all IntegerVariable positive. This assumes that a
240// variable or its negation only appear once.
241//
242// Note that currently this allocates some temporary memory.
243void CanonicalizeConstraint(LinearConstraint* ct);
244
245// Returns false if duplicate variables are found in ct.
246bool NoDuplicateVariable(const LinearConstraint& ct);
247
248} // namespace sat
249} // namespace operations_research
250
251#endif // OR_TOOLS_SAT_LINEAR_CONSTRAINT_H_
ABSL_MUST_USE_RESULT bool AddLiteralTerm(Literal lit, IntegerValue coeff)
void AddLinearExpression(const LinearExpression &expr)
void AddQuadraticLowerBound(AffineExpression left, AffineExpression right, IntegerTrail *integer_trail)
LinearConstraintBuilder(const Model *model, IntegerValue lb, IntegerValue ub)
void AddTerm(IntegerVariable var, IntegerValue coeff)
Class that owns everything related to a particular optimization model.
Definition: sat/model.h:38
const Constraint * ct
int64_t value
IntVar * var
Definition: expr_array.cc:1874
GRBmodel * model
bool ValidateLinearConstraintForOverflow(const LinearConstraint &constraint, const IntegerTrail &integer_trail)
void CleanTermsAndFillConstraint(std::vector< std::pair< IntegerVariable, IntegerValue > > *terms, LinearConstraint *constraint)
constexpr IntegerValue kMaxIntegerValue(std::numeric_limits< IntegerValue::ValueType >::max() - 1)
IntegerValue LinExprLowerBound(const LinearExpression &expr, const IntegerTrail &integer_trail)
std::ostream & operator<<(std::ostream &os, const BoolVar &var)
Definition: cp_model.cc:68
constexpr IntegerValue kMinIntegerValue(-kMaxIntegerValue)
std::string IntegerTermDebugString(IntegerVariable var, IntegerValue coeff)
Definition: integer.h:152
void RemoveZeroTerms(LinearConstraint *constraint)
LinearExpression PositiveVarExpr(const LinearExpression &expr)
double ScalarProduct(const LinearConstraint &constraint1, const LinearConstraint &constraint2)
void MakeAllCoefficientsPositive(LinearConstraint *constraint)
LinearExpression CanonicalizeExpr(const LinearExpression &expr)
void CanonicalizeConstraint(LinearConstraint *ct)
bool NoDuplicateVariable(const LinearConstraint &ct)
double ComputeL2Norm(const LinearConstraint &constraint)
IntegerValue GetCoefficient(const IntegerVariable var, const LinearExpression &expr)
void MakeAllVariablesPositive(LinearConstraint *constraint)
std::vector< IntegerVariable > NegationOf(const std::vector< IntegerVariable > &vars)
Definition: integer.cc:29
IntegerValue GetCoefficientOfPositiveVar(const IntegerVariable var, const LinearExpression &expr)
IntegerValue ComputeInfinityNorm(const LinearConstraint &constraint)
IntegerValue LinExprUpperBound(const LinearExpression &expr, const IntegerTrail &integer_trail)
void DivideByGCD(LinearConstraint *constraint)
double ComputeActivity(const LinearConstraint &constraint, const absl::StrongVector< IntegerVariable, double > &values)
Collection of objects used to extend the Constraint Solver library.
bool operator==(const LinearConstraint other) const
LinearConstraint(IntegerValue _lb, IntegerValue _ub)
void AddTerm(IntegerVariable var, IntegerValue coeff)
double LpValue(const absl::StrongVector< IntegerVariable, double > &lp_values) const