OR-Tools  9.0
presolve_util.cc
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 
15 
16 #include <cstdint>
17 
18 #include "ortools/base/map_util.h"
20 
21 namespace operations_research {
22 namespace sat {
23 
24 void DomainDeductions::AddDeduction(int literal_ref, int var, Domain domain) {
25  CHECK_GE(var, 0);
26  const Index index = IndexFromLiteral(literal_ref);
27  if (index >= something_changed_.size()) {
28  something_changed_.Resize(index + 1);
29  enforcement_to_vars_.resize(index.value() + 1);
30  }
31  if (var >= tmp_num_occurrences_.size()) {
32  tmp_num_occurrences_.resize(var + 1, 0);
33  }
34  const auto insert = deductions_.insert({{index, var}, domain});
35  if (insert.second) {
36  // New element.
37  something_changed_.Set(index);
38  enforcement_to_vars_[index].push_back(var);
39  } else {
40  // Existing element.
41  const Domain& old_domain = insert.first->second;
42  if (!old_domain.IsIncludedIn(domain)) {
43  insert.first->second = domain.IntersectionWith(old_domain);
44  something_changed_.Set(index);
45  }
46  }
47 }
48 
49 std::vector<std::pair<int, Domain>> DomainDeductions::ProcessClause(
50  absl::Span<const int> clause) {
51  std::vector<std::pair<int, Domain>> result;
52 
53  // We only need to process this clause if something changed since last time.
54  bool abort = true;
55  for (const int ref : clause) {
56  const Index index = IndexFromLiteral(ref);
57  if (index >= something_changed_.size()) return result;
58  if (something_changed_[index]) {
59  abort = false;
60  }
61  }
62  if (abort) return result;
63 
64  // Count for each variable, how many times it appears in the deductions lists.
65  std::vector<int> to_process;
66  std::vector<int> to_clean;
67  for (const int ref : clause) {
68  const Index index = IndexFromLiteral(ref);
69  for (const int var : enforcement_to_vars_[index]) {
70  if (tmp_num_occurrences_[var] == 0) {
71  to_clean.push_back(var);
72  }
73  tmp_num_occurrences_[var]++;
74  if (tmp_num_occurrences_[var] == clause.size()) {
75  to_process.push_back(var);
76  }
77  }
78  }
79 
80  // Clear the counts.
81  for (const int var : to_clean) {
82  tmp_num_occurrences_[var] = 0;
83  }
84 
85  // Compute the domain unions.
86  std::vector<Domain> domains(to_process.size());
87  for (const int ref : clause) {
88  const Index index = IndexFromLiteral(ref);
89  for (int i = 0; i < to_process.size(); ++i) {
90  domains[i] = domains[i].UnionWith(
91  gtl::FindOrDieNoPrint(deductions_, {index, to_process[i]}));
92  }
93  }
94 
95  for (int i = 0; i < to_process.size(); ++i) {
96  result.push_back({to_process[i], std::move(domains[i])});
97  }
98  return result;
99 }
100 
101 namespace {
102 // Helper method for variable substitution. Returns the coefficient of 'var' in
103 // 'proto' and copies other terms in 'terms'.
104 template <typename ProtoWithVarsAndCoeffs>
105 int64_t GetVarCoeffAndCopyOtherTerms(
106  const int var, const ProtoWithVarsAndCoeffs& proto,
107  std::vector<std::pair<int, int64_t>>* terms) {
108  bool found = false;
109  int64_t var_coeff = 0;
110  const int size = proto.vars().size();
111  for (int i = 0; i < size; ++i) {
112  int ref = proto.vars(i);
113  int64_t coeff = proto.coeffs(i);
114  if (!RefIsPositive(ref)) {
115  ref = NegatedRef(ref);
116  coeff = -coeff;
117  }
118 
119  if (ref == var) {
120  CHECK(!found);
121  found = true;
122  var_coeff = coeff;
123  continue;
124  } else {
125  terms->push_back({ref, coeff});
126  }
127  }
128  CHECK(found);
129  return var_coeff;
130 }
131 
132 // Helper method for variable substituion. Sorts and merges the terms in 'terms'
133 // and adds them to 'proto'.
134 template <typename ProtoWithVarsAndCoeffs>
135 void SortAndMergeTerms(std::vector<std::pair<int, int64_t>>* terms,
136  ProtoWithVarsAndCoeffs* proto) {
137  proto->clear_vars();
138  proto->clear_coeffs();
139  std::sort(terms->begin(), terms->end());
140  int current_var = 0;
141  int64_t current_coeff = 0;
142  for (const auto entry : *terms) {
143  CHECK(RefIsPositive(entry.first));
144  if (entry.first == current_var) {
145  current_coeff += entry.second;
146  } else {
147  if (current_coeff != 0) {
148  proto->add_vars(current_var);
149  proto->add_coeffs(current_coeff);
150  }
151  current_var = entry.first;
152  current_coeff = entry.second;
153  }
154  }
155  if (current_coeff != 0) {
156  proto->add_vars(current_var);
157  proto->add_coeffs(current_coeff);
158  }
159 }
160 
161 // Adds all the terms from the var definition constraint with given var
162 // coefficient.
163 void AddTermsFromVarDefinition(const int var, const int64_t var_coeff,
164  const ConstraintProto& definition,
165  std::vector<std::pair<int, int64_t>>* terms) {
166  const int definition_size = definition.linear().vars().size();
167  for (int i = 0; i < definition_size; ++i) {
168  int ref = definition.linear().vars(i);
169  int64_t coeff = definition.linear().coeffs(i);
170  if (!RefIsPositive(ref)) {
171  ref = NegatedRef(ref);
172  coeff = -coeff;
173  }
174 
175  if (ref == var) {
176  continue;
177  } else {
178  terms->push_back({ref, -coeff * var_coeff});
179  }
180  }
181 }
182 } // namespace
183 
184 void SubstituteVariable(int var, int64_t var_coeff_in_definition,
185  const ConstraintProto& definition,
186  ConstraintProto* ct) {
188  CHECK_EQ(std::abs(var_coeff_in_definition), 1);
189 
190  // Copy all the terms (except the one refering to var).
191  std::vector<std::pair<int, int64_t>> terms;
192  int64_t var_coeff = GetVarCoeffAndCopyOtherTerms(var, ct->linear(), &terms);
193 
194  if (var_coeff_in_definition < 0) var_coeff *= -1;
195 
196  AddTermsFromVarDefinition(var, var_coeff, definition, &terms);
197 
198  // The substitution is correct only if we don't loose information here.
199  // But for a constant definition rhs that is always the case.
200  bool exact = false;
201  Domain offset = ReadDomainFromProto(definition.linear());
202  offset = offset.MultiplicationBy(-var_coeff, &exact);
203  CHECK(exact);
204 
205  const Domain rhs = ReadDomainFromProto(ct->linear());
206  FillDomainInProto(rhs.AdditionWith(offset), ct->mutable_linear());
207 
208  SortAndMergeTerms(&terms, ct->mutable_linear());
209 }
210 
211 } // namespace sat
212 } // namespace operations_research
#define CHECK(condition)
Definition: base/logging.h:498
#define CHECK_EQ(val1, val2)
Definition: base/logging.h:705
#define CHECK_GE(val1, val2)
Definition: base/logging.h:709
void resize(size_type new_size)
void push_back(const value_type &x)
We call domain any subset of Int64 = [kint64min, kint64max].
bool IsIncludedIn(const Domain &domain) const
Returns true iff D is included in the given domain.
Domain AdditionWith(const Domain &domain) const
Returns {x ∈ Int64, ∃ a ∈ D, ∃ b ∈ domain, x = a + b}.
Domain MultiplicationBy(int64_t coeff, bool *exact=nullptr) const
Returns {x ∈ Int64, ∃ e ∈ D, x = e * coeff}.
Domain IntersectionWith(const Domain &domain) const
Returns the intersection of D and domain.
IntegerType size() const
Definition: bitset.h:770
void Set(IntegerType index)
Definition: bitset.h:804
void Resize(IntegerType size)
Definition: bitset.h:790
std::vector< std::pair< int, Domain > > ProcessClause(absl::Span< const int > clause)
void AddDeduction(int literal_ref, int var, Domain domain)
CpModelProto proto
const Constraint * ct
IntVar * var
Definition: expr_array.cc:1874
const Collection::value_type::second_type & FindOrDieNoPrint(const Collection &collection, const typename Collection::value_type::first_type &key)
Definition: map_util.h:216
bool RefIsPositive(int ref)
void SubstituteVariable(int var, int64_t var_coeff_in_definition, const ConstraintProto &definition, ConstraintProto *ct)
void FillDomainInProto(const Domain &domain, ProtoWithDomain *proto)
Domain ReadDomainFromProto(const ProtoWithDomain &proto)
Collection of objects used to extend the Constraint Solver library.
int index
Definition: pack.cc:509