14#ifndef OR_TOOLS_SAT_PRESOLVE_UTIL_H_
15#define OR_TOOLS_SAT_PRESOLVE_UTIL_H_
23#include "absl/container/flat_hash_map.h"
24#include "absl/container/flat_hash_set.h"
25#include "absl/random/bit_gen_ref.h"
26#include "absl/types/span.h"
29#include "ortools/sat/cp_model.pb.h"
48 : name_(
std::move(name)), logger_(logger), time_limit_(
time_limit) {
61 if (count == 0)
return;
62 counters_.emplace_back(std::move(name), count);
66 void AddMessage(std::string name) { extra_infos_.push_back(std::move(name)); }
72 const std::string name_;
79 std::vector<std::pair<std::string, int64_t>> counters_;
80 std::vector<std::string> extra_infos_;
116 absl::Span<const int> clause);
121 something_changed_.ClearAndResize(something_changed_.size());
129 Index IndexFromLiteral(
int ref)
const {
130 return Index(ref >= 0 ? 2 * ref : -2 * ref - 1);
133 std::vector<int> tmp_num_occurrences_;
137 absl::flat_hash_map<std::pair<Index, int>,
Domain> deductions_;
145 ConstraintProto* to_modify);
153 const ConstraintProto& definition, ConstraintProto* ct);
168 : index_to_position_(
i),
169 position_to_index_(pi),
170 position_to_value_(pv) {}
173 const int p = index_to_position_[index];
174 if (p < size_ && index == position_to_index_[p]) {
176 return position_to_value_[p];
180 index_to_position_[index] = size_;
181 position_to_index_[size_] = index;
182 position_to_value_[size_] = 0;
183 return position_to_value_[size_++];
188 int*
const index_to_position_;
189 int*
const position_to_index_;
190 T*
const position_to_value_;
195 index_to_position_.resize(size);
196 position_to_index_.resize(size);
197 position_to_value_.resize(size);
198 return View(index_to_position_.data(), position_to_index_.data(),
199 position_to_value_.data());
205 std::vector<int> index_to_position_;
208 std::vector<int> position_to_index_;
209 std::vector<T> position_to_value_;
252 absl::Span<
const std::pair<int, int64_t>> terms,
253 std::vector<std::array<int64_t, 2>>* conditional =
nullptr) {
254 return ComputeActivity(
false, terms, conditional);
257 absl::Span<
const std::pair<int, int64_t>> terms,
258 std::vector<std::array<int64_t, 2>>* conditional =
nullptr) {
259 return ComputeActivity(
true, terms, conditional);
271 absl::flat_hash_set<int>* literals_at_true);
279 absl::Span<
const std::pair<int, int64_t>> boolean_terms,
280 const Domain& other_terms,
const Domain& rhs, ConstraintProto* ct);
285 absl::Span<const int> literals);
288 bool IsAmo(absl::Span<const int> literals);
292 const Index
i = IndexFromLiteral(var);
293 const Index j = IndexFromLiteral(
NegatedRef(var));
294 return (
i < amo_indices_.size() ? amo_indices_[
i].size() : 0) +
295 (j < amo_indices_.size() ? amo_indices_[j].size() : 0);
300 Index IndexFromLiteral(
int ref)
const {
301 return Index(ref >= 0 ? 2 * ref : -2 * ref - 1);
304 bool AppearInTriggeredAmo(
int literal);
306 int64_t ComputeActivity(
307 bool compute_min, absl::Span<
const std::pair<int, int64_t>> terms,
308 std::vector<std::array<int64_t, 2>>* conditional =
nullptr);
310 void PartitionIntoAmo(absl::Span<
const std::pair<int, int64_t>> terms);
314 int64_t ComputeMaxActivityInternal(
315 absl::Span<
const std::pair<int, int64_t>> terms,
316 std::vector<std::array<int64_t, 2>>* conditional =
nullptr);
320 int num_at_most_ones_ = 0;
323 std::vector<std::pair<int, int64_t>> tmp_terms_for_compute_activity_;
325 struct TermWithIndex {
330 std::vector<TermWithIndex> to_sort_;
333 VectorWithSparseUsage<int64_t> amo_sums_;
334 std::vector<int> partition_;
335 std::vector<int64_t> max_by_partition_;
336 std::vector<int64_t> second_max_by_partition_;
339 CompactVectorVector<int, int> part_to_literals_;
341 absl::flat_hash_set<int> triggered_amo_;
342 absl::flat_hash_set<int> tmp_set_;
357 return clause_to_hash_[c] ^ literal_to_hash_[IndexFromLiteral(ref)];
365 Index IndexFromLiteral(
int ref)
const {
366 return Index(ref >= 0 ? 2 * ref : -2 * ref - 1);
369 absl::BitGenRef random_;
371 std::vector<uint64_t> clause_to_hash_;
384 absl::Span<const int> enforcement,
386 if (clause.size() != enforcement.size() + 1)
return false;
388 for (
int i = 0;
i < clause.size(); ++
i) {
389 if (clause[
i] == literal)
continue;
390 if (clause[
i] !=
NegatedRef(enforcement[j]))
return false;
398 const LinearConstraintProto& lin2,
int* var1,
399 int64_t* coeff1,
int* var2, int64_t* coeff2);
405 const LinearConstraintProto& lin2) {
407 int64_t coeff1, coeff2;
void AddAllAtMostOnes(const CpModelProto &proto)
int64_t ComputeMaxActivity(absl::Span< const std::pair< int, int64_t > > terms, std::vector< std::array< int64_t, 2 > > *conditional=nullptr)
void AddAtMostOne(absl::Span< const int > amo)
int RemoveEnforcementThatMakesConstraintTrivial(absl::Span< const std::pair< int, int64_t > > boolean_terms, const Domain &other_terms, const Domain &rhs, ConstraintProto *ct)
int64_t ComputeMinActivity(absl::Span< const std::pair< int, int64_t > > terms, std::vector< std::array< int64_t, 2 > > *conditional=nullptr)
ActivityBoundHelper()=default
std::vector< absl::Span< const int > > PartitionLiteralsIntoAmo(absl::Span< const int > literals)
Similar algo as above for this simpler case.
bool PresolveEnforcement(absl::Span< const int > refs, ConstraintProto *ct, absl::flat_hash_set< int > *literals_at_true)
bool IsAmo(absl::Span< const int > literals)
Returns true iff the given literal are in at most one relationship.
int NumAmoForVariable(int var) const
Returns in how many amo var or Not(var) are part of.
uint64_t HashWithout(int c, int ref) const
void RegisterClause(int c, absl::Span< const int > clause)
We use the proto encoding of literals here.
ClauseWithOneMissingHasher(absl::BitGenRef random)
uint64_t HashOfNegatedLiterals(absl::Span< const int > literals)
Returns a hash of the negation of all the given literals.
int NumDeductions() const
Returns the total number of "deductions" stored by this class.
void MarkProcessingAsDoneForNow()
std::vector< std::pair< int, Domain > > ProcessClause(absl::Span< const int > clause)
void AddDeduction(int literal_ref, int var, Domain domain)
Domain ImpliedDomain(int literal_ref, int var) const
void AddToWork(double dtime)
void TrackSimpleLoop(int size)
void AddMessage(std::string name)
Extra info at the end of the log line.
bool WorkLimitIsReached() const
PresolveTimer(std::string name, SolverLogger *logger, TimeLimit *time_limit)
~PresolveTimer()
Update dtime and log operation summary.
void AddCounter(std::string name, int64_t count)
Taking a view allow to cache the never changing addresses.
T & operator[](int index)
View(int *i, int *pi, T *pv)
View ClearedView(int size)
This reserve the size for using indices in [0, size).
bool FindSingleLinearDifference(const LinearConstraintProto &lin1, const LinearConstraintProto &lin2, int *var1, int64_t *coeff1, int *var2, int64_t *coeff2)
Same as LinearsDifferAtOneTerm() below but also fills the differing terms.
bool ClauseIsEnforcementImpliesLiteral(absl::Span< const int > clause, absl::Span< const int > enforcement, int literal)
bool SubstituteVariable(int var, int64_t var_coeff_in_definition, const ConstraintProto &definition, ConstraintProto *ct)
bool AddLinearConstraintMultiple(int64_t factor, const ConstraintProto &to_add, ConstraintProto *to_modify)
bool LinearsDifferAtOneTerm(const LinearConstraintProto &lin1, const LinearConstraintProto &lin2)
int NegatedRef(int ref)
Small utility functions to deal with negative variable/literal references.
In SWIG mode, we don't want anything besides these top-level includes.
#define DEFINE_STRONG_INDEX_TYPE(index_type_name)