24#include "absl/container/flat_hash_map.h"
25#include "absl/meta/type_traits.h"
26#include "absl/strings/str_cat.h"
33#include "ortools/sat/sat_parameters.pb.h"
44 VLOG(1) << num_deductions_ <<
" enqueued deductions.";
45 VLOG(1) << bounds_.size() <<
" implied bounds stored.";
46 VLOG(1) << num_enqueued_in_var_to_bounds_
47 <<
" implied bounds with view stored.";
51 if (!parameters_.use_implied_bounds())
return;
52 const IntegerVariable
var = integer_literal.
var;
55 if (
var >= level_zero_lower_bounds_.
size()) {
64 if (integer_literal.
bound <= level_zero_lower_bounds_[
var]) {
78 const auto key = std::make_pair(
literal.Index(),
var);
79 auto insert_result = bounds_.insert({key, integer_literal.
bound});
80 if (!insert_result.second) {
81 if (insert_result.first->second < integer_literal.
bound) {
82 insert_result.first->second = integer_literal.
bound;
95 if (it != bounds_.end() && it->second == -integer_literal.
bound) {
107 const auto it = bounds_.find(std::make_pair(
literal.NegatedIndex(),
var));
108 if (it != bounds_.end()) {
109 if (it->second <= level_zero_lower_bounds_[
var]) {
114 const IntegerValue deduction =
124 level_zero_lower_bounds_[
var] = deduction;
125 new_level_zero_bounds_.
Set(
var);
127 VLOG(1) <<
"Deduction old: "
134 if (it->second == deduction) {
137 if (integer_literal.
bound == deduction) {
138 bounds_.erase(std::make_pair(
literal.Index(),
var));
160 if (var_to_bounds_.size() <=
var) {
161 var_to_bounds_.resize(
var.value() + 1);
164 ++num_enqueued_in_var_to_bounds_;
165 has_implied_bounds_.
Set(
var);
167 integer_literal.
bound,
true});
170 if (var_to_bounds_.size() <=
var) {
171 var_to_bounds_.resize(
var.value() + 1);
174 ++num_enqueued_in_var_to_bounds_;
175 has_implied_bounds_.
Set(
var);
176 var_to_bounds_[
var].push_back(
178 integer_literal.
bound,
false});
183 IntegerVariable
var) {
184 if (
var >= var_to_bounds_.size())
return empty_implied_bounds_;
191 std::vector<ImpliedBoundEntry>& ref = var_to_bounds_[
var];
192 const IntegerValue level_zero_lb =
std::max(
194 level_zero_lower_bounds_[
var] = level_zero_lb;
196 if (entry.lower_bound <= level_zero_lb)
continue;
197 ref[new_size++] = entry;
206 IntegerValue
value) {
215 if (!parameters_.use_implied_bounds())
return;
218 tmp_integer_literals_.clear();
221 Add(first_decision, lit);
226 IntegerVariable
var,
const std::vector<ValueLiteralPair>& encoding,
227 int exactly_one_index) {
228 var_to_index_to_element_encodings_[
var][exactly_one_index] = encoding;
231const absl::flat_hash_map<int, std::vector<ValueLiteralPair>>&
233 const auto& it = var_to_index_to_element_encodings_.find(
var);
234 if (it == var_to_index_to_element_encodings_.end()) {
235 return empty_element_encoding_;
243 return element_encoded_variables_;
248 for (
const IntegerVariable
var :
260std::string
EncodingStr(
const std::vector<ValueLiteralPair>& enc) {
263 absl::StrAppend(&result, term.literal.DebugString(),
":",
264 term.value.value(),
" ");
286 const std::vector<ValueLiteralPair>& affine_var_encoding,
Model*
model,
289 IntegerVariable binary = size2_affine.
var;
291 const std::vector<ValueLiteralPair>& size2_enc =
294 Literal lit0 = size2_enc[0].literal;
295 IntegerValue value0 =
296 size2_enc[0].value * size2_affine.
coeff + size2_affine.
constant;
297 Literal lit1 = size2_enc[1].literal;
298 IntegerValue value1 =
299 size2_enc[1].value * size2_affine.
coeff + size2_affine.
constant;
300 for (
const auto& [unused, candidate_literal] : affine_var_encoding) {
301 if (candidate_literal == lit1) {
305 if (candidate_literal != lit0)
continue;
309 for (
const auto& [
value,
literal] : affine_var_encoding) {
319 for (
const auto& [
value,
literal] : affine_var_encoding) {
323 if (
energy > min_energy) {
340 CHECK(builder !=
nullptr);
346 if (integer_trail->
IsFixed(left)) {
352 if (integer_trail->
IsFixed(right)) {
363 const IntegerValue left_coeff =
365 const IntegerValue right_coeff =
368 left_coeff * right_coeff + left.
constant * right_coeff +
375 const absl::flat_hash_map<int, std::vector<ValueLiteralPair>>&
376 left_encodings = implied_bounds->GetElementEncodings(left.
var);
379 const absl::flat_hash_map<int, std::vector<ValueLiteralPair>>&
380 right_encodings = implied_bounds->GetElementEncodings(right.
var);
382 std::vector<int> compatible_keys;
383 for (
const auto& [
index, encoding] : left_encodings) {
384 if (right_encodings.contains(
index)) {
385 compatible_keys.push_back(
index);
389 if (compatible_keys.empty()) {
391 for (
const auto& [
index, right_encoding] : right_encodings) {
399 for (
const auto& [
index, left_encoding] : left_encodings) {
409 if (compatible_keys.size() > 1) {
410 VLOG(1) <<
"More than one exactly_one involved in the encoding of the two "
415 const int min_index =
416 *std::min_element(compatible_keys.begin(), compatible_keys.end());
419 const std::vector<ValueLiteralPair>& left_encoding =
420 left_encodings.at(min_index);
421 const std::vector<ValueLiteralPair>& right_encoding =
422 right_encodings.at(min_index);
423 DCHECK_EQ(left_encoding.size(), right_encoding.size());
427 for (
int i = 0; i < left_encoding.size(); ++i) {
434 for (
int i = 0; i < left_encoding.size(); ++i) {
437 if (
energy == min_energy)
continue;
439 const Literal lit = left_encoding[i].literal;
457 return !expr.
vars.empty() ||
462 const std::vector<AffineExpression>& right,
464 std::vector<LinearExpression>* energies) {
466 for (
int i = 0; i < left.size(); ++i) {
469 VLOG(3) <<
"linearized energy: "
473 VLOG(2) <<
"Product is not linearizable: demands "
474 << left[i].DebugString() <<
" with var domain "
475 << integer_trail->InitialVariableDomain(left[i].
var)
476 <<
", size = " << right[i].DebugString() <<
" with var domain "
477 << integer_trail->InitialVariableDomain(right[i].
var);
#define CHECK_EQ(val1, val2)
#define DCHECK_GT(val1, val2)
#define DCHECK_EQ(val1, val2)
#define VLOG(verboselevel)
void resize(size_type new_size)
int64_t Size() const
Returns the number of elements in the domain.
void Set(IntegerType index)
const std::vector< IntegerType > & PositionsSetAtLeastOnce() const
void Resize(IntegerType size)
bool EnqueueNewDeductions()
const std::vector< ImpliedBoundEntry > & GetImpliedBounds(IntegerVariable var)
void AddLiteralImpliesVarEqValue(Literal literal, IntegerVariable var, IntegerValue value)
const absl::flat_hash_map< int, std::vector< ValueLiteralPair > > & GetElementEncodings(IntegerVariable var)
void Add(Literal literal, IntegerLiteral integer_literal)
void AddElementEncoding(IntegerVariable var, const std::vector< ValueLiteralPair > &encoding, int exactly_one_index)
const std::vector< IntegerVariable > & GetElementEncodedVariables() const
void ProcessIntegerTrail(Literal first_decision)
const IntegerVariable GetLiteralView(Literal lit) const
std::vector< ValueLiteralPair > FullDomainEncoding(IntegerVariable var) const
bool VariableIsFullyEncoded(IntegerVariable var) const
ABSL_MUST_USE_RESULT bool Enqueue(IntegerLiteral i_lit, absl::Span< const Literal > literal_reason, absl::Span< const IntegerLiteral > integer_reason)
bool IsFixed(IntegerVariable i) const
IntegerValue UpperBound(IntegerVariable i) const
IntegerValue LevelZeroUpperBound(IntegerVariable var) const
IntegerValue FixedValue(IntegerVariable i) const
IntegerValue LevelZeroLowerBound(IntegerVariable var) const
void AppendNewBounds(std::vector< IntegerLiteral > *output) const
IntegerValue LowerBound(IntegerVariable i) const
bool IsOptional(IntegerVariable i) const
const Domain & InitialVariableDomain(IntegerVariable var) const
ABSL_MUST_USE_RESULT bool AddLiteralTerm(Literal lit, IntegerValue coeff)
void AddConstant(IntegerValue value)
LinearExpression BuildExpression()
void AddTerm(IntegerVariable var, IntegerValue coeff)
Class that owns everything related to a particular optimization model.
int CurrentDecisionLevel() const
void swap(IdMap< K, V > &a, IdMap< K, V > &b)
constexpr IntegerValue kMaxIntegerValue(std::numeric_limits< IntegerValue::ValueType >::max() - 1)
void LinearizeInnerProduct(const std::vector< AffineExpression > &left, const std::vector< AffineExpression > &right, Model *model, std::vector< LinearExpression > *energies)
std::string EncodingStr(const std::vector< ValueLiteralPair > &enc)
constexpr IntegerValue kMinIntegerValue(-kMaxIntegerValue.value())
const IntegerVariable kNoIntegerVariable(-1)
LinearExpression NotLinearizedEnergy()
IntegerVariable PositiveVariable(IntegerVariable i)
bool ProductIsLinearized(const LinearExpression &expr)
bool DetectLinearEncodingOfProducts(const AffineExpression &left, const AffineExpression &right, Model *model, LinearConstraintBuilder *builder)
std::vector< IntegerVariable > NegationOf(const std::vector< IntegerVariable > &vars)
bool TryToReconcileEncodings(const AffineExpression &size2_affine, const AffineExpression &affine, const std::vector< ValueLiteralPair > &affine_var_encoding, Model *model, LinearConstraintBuilder *builder)
bool VariableIsPositive(IntegerVariable i)
Collection of objects used to extend the Constraint Solver library.
IntegerValue ValueAt(IntegerValue var_value) const
static IntegerLiteral GreaterOrEqual(IntegerVariable i, IntegerValue bound)
std::vector< IntegerVariable > vars
std::string DebugString() const