14#ifndef ORTOOLS_SAT_INTEGER_EXPR_H_
15#define ORTOOLS_SAT_INTEGER_EXPR_H_
26#include "absl/base/attributes.h"
27#include "absl/log/check.h"
28#include "absl/log/log.h"
29#include "absl/types/span.h"
71template <
bool use_
int128 = false>
80 absl::Span<const IntegerVariable> vars,
81 absl::Span<const IntegerValue> coeffs,
82 IntegerValue upper_bound,
Model* model);
90 return use_int128 ?
"IntegerSumLE128" :
"IntegerSumLE";
110 IntegerLiteral integer_literal, IntegerVariable target_var) const;
120 void FillIntegerReason();
122 const IntegerValue upper_bound_;
129 explicit Shared(
Model* model)
134 rev_integer_value_repository(
144 std::vector<IntegerLiteral> integer_reason;
145 std::vector<IntegerValue> reason_coeffs;
150 bool is_registered_ =
false;
151 IntegerValue rev_lb_fixed_vars_;
154 int rev_num_fixed_vars_;
160 const std::unique_ptr<IntegerVariable[]> vars_;
161 const std::unique_ptr<IntegerValue[]> coeffs_;
162 const std::unique_ptr<IntegerValue[]> max_variations_;
165 std::vector<Literal> literal_reason_;
186 const std::vector<IntegerVariable>& vars,
187 const std::vector<IntegerValue>& coeffs,
Model* model);
192 const IntegerVariable target_;
193 const std::vector<IntegerVariable> vars_;
194 const std::vector<IntegerValue> coeffs_;
196 IntegerValue gcd_ = IntegerValue(1);
253 absl::Span<const Literal> enforcement_literals,
254 std::vector<LinearExpression> exprs, IntegerVariable min_var,
262 return "GreaterThanMinOfExprsPropagator";
265 bool Propagate() final;
276 bool PropagateLinearUpperBound(
int id,
absl::Span<const IntegerVariable> vars,
277 absl::Span<const IntegerValue> coeffs,
278 IntegerValue upper_bound);
281 const IntegerVariable min_var_;
282 std::vector<IntegerValue> expr_lbs_;
286 EnforcementId enforcement_id_;
287 std::vector<IntegerValue> max_variations_;
288 std::vector<IntegerValue> reason_coeffs_;
291 int rev_unique_candidate_ = 0;
293 std::vector<IntegerVariable> tmp_vars_;
294 std::vector<IntegerValue> tmp_coeffs_;
317 bool CanonicalizeCases();
321 bool PropagateWhenAllNonNegative();
325 IntegerValue min_p, IntegerValue max_p);
334 EnforcementId enforcement_id_;
378 EnforcementId enforcement_id_;
399 const IntegerValue b_;
403 EnforcementId enforcement_id_;
425 bool PropagateWhenFalseAndTargetDomainContainsZero();
426 bool PropagateSignsAndTargetRange();
429 bool PropagateOuterBounds();
432 const IntegerValue mod_;
438 EnforcementId enforcement_id_;
461 EnforcementId enforcement_id_;
471 absl::Span<const IntegerVariable> vars,
472 absl::Span<const IntegerValue> coefficients, int64_t upper_bound,
475 DCHECK_GE(vars.size(), 1);
476 if (vars.size() == 1) {
477 DCHECK_NE(coefficients[0], 0);
478 IntegerVariable var = vars[0];
479 IntegerValue coeff(coefficients[0]);
484 const IntegerValue rhs =
FloorRatio(IntegerValue(upper_bound), coeff);
485 if (enforcement_literals.empty()) {
497 if (vars.size() == 2 && (coefficients[0] == 1 || coefficients[0] == -1) &&
498 (coefficients[1] == 1 || coefficients[1] == -1)) {
500 enforcement_literals,
501 coefficients[0] == 1 ? vars[0] :
NegationOf(vars[0]),
502 coefficients[1] == 1 ? vars[1] :
NegationOf(vars[1]), upper_bound,
506 if (vars.size() == 3 && (coefficients[0] == 1 || coefficients[0] == -1) &&
507 (coefficients[1] == 1 || coefficients[1] == -1) &&
508 (coefficients[2] == 1 || coefficients[2] == -1)) {
510 enforcement_literals,
511 coefficients[0] == 1 ? vars[0] :
NegationOf(vars[0]),
512 coefficients[1] == 1 ? vars[1] :
NegationOf(vars[1]),
513 coefficients[2] == 1 ? vars[2] :
NegationOf(vars[2]), upper_bound,
523 if (!enforcement_literals.empty()) {
524 IntegerValue expression_min(0);
525 auto* integer_trail = model->GetOrCreate<
IntegerTrail>();
526 for (
int i = 0;
i < vars.size(); ++
i) {
528 coefficients[
i] * (coefficients[
i] >= 0
532 if (expression_min == upper_bound) {
536 IntegerValue non_cached_min;
537 for (
int i = 0;
i < vars.size(); ++
i) {
538 if (coefficients[
i] > 0) {
540 non_cached_min += coefficients[
i] * lb;
543 }
else if (coefficients[
i] < 0) {
545 non_cached_min += coefficients[
i] * ub;
550 if (non_cached_min > expression_min) {
551 std::vector<Literal> clause;
552 for (
const Literal l : enforcement_literals) {
553 clause.push_back(l.Negated());
563 enforcement_literals, vars, coefficients, IntegerValue(upper_bound));
565 auto* sat_solver = model->GetOrCreate<
SatSolver>();
566 if (sat_solver->CurrentDecisionLevel() == 0) {
567 sat_solver->NotifyThatModelIsUnsat();
569 LOG(FATAL) <<
"We currently do not support adding conflicting "
570 "constraint at positive level.";
575 new IntegerSumLE(enforcement_literals, vars, coefficients,
576 IntegerValue(upper_bound), model);
578 model->TakeOwnership(constraint);
584 absl::Span<const Literal> enforcement_literals,
585 absl::Span<const IntegerVariable> vars,
586 absl::Span<const IntegerValue> coefficients, int64_t lower_bound,
589 std::vector<IntegerValue> negated_coeffs(coefficients.begin(),
591 for (IntegerValue& ref : negated_coeffs) ref = -ref;
593 -lower_bound, model);
597template <
typename VectorInt>
599 absl::Span<const IntegerVariable> vars,
const VectorInt& coefficients,
600 int64_t upper_bound) {
601 return [=, vars = std::vector<IntegerVariable>(vars.begin(), vars.end()),
602 coeffs = std::vector<IntegerValue>(
603 coefficients.begin(), coefficients.end())](
Model* model) {
609template <
typename VectorInt>
611 absl::Span<const IntegerVariable> vars,
const VectorInt& coefficients,
612 int64_t lower_bound) {
614 std::vector<IntegerValue> negated_coeffs(coefficients.begin(),
616 for (IntegerValue& ref : negated_coeffs) ref = -ref;
621template <
typename VectorInt>
623 absl::Span<const IntegerVariable> vars,
const VectorInt& coefficients,
625 return [=, vars = std::vector<IntegerVariable>(vars.begin(), vars.end())](
634 absl::Span<const Literal> enforcement_literals,
635 absl::Span<const IntegerVariable> vars,
636 absl::Span<const int64_t> coefficients, int64_t upper_bound) {
637 return [=, vars = std::vector<IntegerVariable>(vars.begin(), vars.end()),
638 coeffs = std::vector<IntegerValue>(coefficients.begin(),
640 enforcement_literals =
641 std::vector<Literal>(enforcement_literals.begin(),
642 enforcement_literals.end())](
Model* model) {
648 absl::Span<const Literal> enforcement_literals,
649 absl::Span<const IntegerVariable> vars,
650 absl::Span<const int64_t> coefficients, int64_t upper_bound) {
652 coeffs = std::vector<IntegerValue>(coefficients.begin(),
654 vars = std::vector<IntegerVariable>(vars.begin(), vars.end()),
655 enforcement_literals =
656 std::vector<Literal>(enforcement_literals.begin(),
657 enforcement_literals.end())](
Model* model) {
665 const absl::Span<const Literal> enforcement_literals,
668 if (cst.
lb <= 0 && cst.
ub >= 0)
return;
671 std::vector<Literal> clause;
672 for (
const Literal lit : enforcement_literals) {
673 clause.push_back(lit.Negated());
693 const absl::Span<const Literal> enforcement_literals, AffineExpression left,
708template <
typename VectorInt>
710 const VectorInt& coefficients,
const std::vector<IntegerVariable>& vars) {
712 std::vector<IntegerVariable> new_vars = vars;
719 for (
int i = 0;
i < new_vars.size(); ++
i) {
720 if (coefficients[
i] > 0) {
721 sum_lb += coefficients[
i] * model->Get(
LowerBound(new_vars[
i]));
722 sum_ub += coefficients[
i] * model->Get(
UpperBound(new_vars[
i]));
724 sum_lb += coefficients[
i] * model->Get(
UpperBound(new_vars[
i]));
725 sum_ub += coefficients[
i] * model->Get(
LowerBound(new_vars[
i]));
730 new_vars.push_back(sum);
731 std::vector<int64_t> new_coeffs(coefficients.begin(), coefficients.end());
732 new_coeffs.push_back(-1);
742 const absl::Span<const Literal> enforcement_literals,
747 IntegerVariable min_var;
748 if (min_expr.
vars.size() == 1 && std::abs(min_expr.
coeffs[0].value()) == 1 &&
750 if (min_expr.
coeffs[0].value() == 1) {
751 min_var = min_expr.
vars[0];
757 IntegerValue min_lb = min_expr.
Min(*integer_trail);
758 IntegerValue min_ub = min_expr.
Max(*integer_trail);
779 std::move(exprs), min_var, model);
783ABSL_DEPRECATED(
"Use AddIsEqualToMinOf() instead.")
785 const LinearExpression& min_expr,
787 return [&](
Model* model) {
794 absl::Span<const Literal> enforcement_literals, AffineExpression a,
796 return [=](
Model* model) {
801 model->TakeOwnership(
806 model->TakeOwnership(
811 model->TakeOwnership(
818 absl::Span<const Literal> enforcement_literals, AffineExpression num,
820 return [=](
Model* model) {
831 model->TakeOwnership(constraint);
837 absl::Span<const Literal> enforcement_literals, AffineExpression a,
839 return [=](
Model* model) {
846 model->TakeOwnership(constraint);
852 absl::Span<const Literal> enforcement_literals, AffineExpression a,
854 return [=](
Model* model) {
855 model->TakeOwnership(
DivisionPropagator(absl::Span< const Literal > enforcement_literals, AffineExpression num, AffineExpression denom, AffineExpression div, Model *model)
DivisionPropagator(const DivisionPropagator &)=delete
DivisionPropagator & operator=(const DivisionPropagator &)=delete
FixedDivisionPropagator(const FixedDivisionPropagator &)=delete
FixedDivisionPropagator(absl::Span< const Literal > enforcement_literals, AffineExpression a, IntegerValue b, AffineExpression c, Model *model)
FixedDivisionPropagator & operator=(const FixedDivisionPropagator &)=delete
FixedModuloPropagator & operator=(const FixedModuloPropagator &)=delete
FixedModuloPropagator(absl::Span< const Literal > enforcement_literals, AffineExpression expr, IntegerValue mod, AffineExpression target, Model *model)
FixedModuloPropagator(const FixedModuloPropagator &)=delete
GreaterThanMinOfExprsPropagator(absl::Span< const Literal > enforcement_literals, std::vector< LinearExpression > exprs, IntegerVariable min_var, Model *model)
GreaterThanMinOfExprsPropagator & operator=(const GreaterThanMinOfExprsPropagator &)=delete
std::string LazyReasonName() const override
GreaterThanMinOfExprsPropagator(const GreaterThanMinOfExprsPropagator &)=delete
IntegerValue LowerBound(IntegerVariable i) const
IntegerValue UpperBound(IntegerVariable i) const
IntegerValue LevelZeroUpperBound(IntegerVariable var) const
IntegerValue LevelZeroLowerBound(IntegerVariable var) const
IntegerVariable AddIntegerVariable(IntegerValue lower_bound, IntegerValue upper_bound)
LazyReasonInterface()=default
LevelZeroEquality(IntegerVariable target, const std::vector< IntegerVariable > &vars, const std::vector< IntegerValue > &coeffs, Model *model)
void AddTerm(IntegerVariable var, IntegerValue coeff)
void AddLinearExpression(const LinearExpression &expr)
std::string LazyReasonName() const override
void Explain(int id, IntegerLiteral to_explain, IntegerReason *reason) final
std::pair< IntegerValue, IntegerValue > ConditionalLb(IntegerLiteral integer_literal, IntegerVariable target_var) const
LinearConstraintPropagator(LinearConstraint ct, Model *model)
void RegisterWith(GenericLiteralWatcher *watcher)
LinearConstraintPropagator(absl::Span< const Literal > enforcement_literals, absl::Span< const IntegerVariable > vars, absl::Span< const IntegerValue > coeffs, IntegerValue upper_bound, Model *model)
bool PropagateAtLevelZero()
MinPropagator(const MinPropagator &)=delete
void RegisterWith(GenericLiteralWatcher *watcher)
MinPropagator(std::vector< AffineExpression > vars, AffineExpression min_var, IntegerTrail *integer_trail)
MinPropagator & operator=(const MinPropagator &)=delete
T Add(std::function< T(Model *)> f)
ProductPropagator(const ProductPropagator &)=delete
ProductPropagator(absl::Span< const Literal > enforcement_literals, AffineExpression a, AffineExpression b, AffineExpression p, Model *model)
ProductPropagator & operator=(const ProductPropagator &)=delete
PropagatorInterface()=default
bool new_linear_propagation() const
SquarePropagator(const SquarePropagator &)=delete
SquarePropagator & operator=(const SquarePropagator &)=delete
SquarePropagator(absl::Span< const Literal > enforcement_literals, AffineExpression x, AffineExpression s, Model *model)
const VariablesAssignment & Assignment() const
IntegerValue FloorRatio(IntegerValue dividend, IntegerValue positive_divisor)
void AddIsEqualToMinOf(const absl::Span< const Literal > enforcement_literals, const LinearExpression &min_expr, std::vector< LinearExpression > exprs, Model *model)
constexpr IntegerValue kMaxIntegerValue(std::numeric_limits< IntegerValue::ValueType >::max() - 1)
std::function< void(Model *)> WeightedSumGreaterOrEqual(absl::Span< const IntegerVariable > vars, const VectorInt &coefficients, int64_t lower_bound)
void AddWeightedSumLowerOrEqual(absl::Span< const Literal > enforcement_literals, absl::Span< const IntegerVariable > vars, absl::Span< const IntegerValue > coefficients, int64_t upper_bound, Model *model)
std::function< void(Model *)> ClauseConstraint(absl::Span< const Literal > literals)
void AddWeightedSumGreaterOrEqual(absl::Span< const Literal > enforcement_literals, absl::Span< const IntegerVariable > vars, absl::Span< const IntegerValue > coefficients, int64_t lower_bound, Model *model)
std::function< int64_t(const Model &)> LowerBound(IntegerVariable v)
std::function< void(Model *)> LowerOrEqual(IntegerVariable v, int64_t ub)
std::function< void(Model *)> FixedDivisionConstraint(absl::Span< const Literal > enforcement_literals, AffineExpression a, IntegerValue b, AffineExpression c)
std::vector< IntegerVariable > NegationOf(absl::Span< const IntegerVariable > vars)
std::function< void(Model *)> FixedWeightedSum(absl::Span< const IntegerVariable > vars, const VectorInt &coefficients, int64_t value)
void LoadConditionalLinearConstraint(const absl::Span< const Literal > enforcement_literals, const LinearConstraint &cst, Model *model)
std::function< void(Model *)> IsEqualToMinOf(const LinearExpression &min_expr, const std::vector< LinearExpression > &exprs)
constexpr IntegerValue kMinIntegerValue(-kMaxIntegerValue.value())
std::function< void(Model *)> Implication(absl::Span< const Literal > enforcement_literals, IntegerLiteral i)
std::function< void(Model *)> ProductConstraint(absl::Span< const Literal > enforcement_literals, AffineExpression a, AffineExpression b, AffineExpression p)
std::function< void(Model *)> ConditionalWeightedSumLowerOrEqual(absl::Span< const Literal > enforcement_literals, absl::Span< const IntegerVariable > vars, absl::Span< const int64_t > coefficients, int64_t upper_bound)
void AddConditionalAffinePrecedence(const absl::Span< const Literal > enforcement_literals, AffineExpression left, AffineExpression right, Model *model)
std::function< void(Model *)> DivisionConstraint(absl::Span< const Literal > enforcement_literals, AffineExpression num, AffineExpression denom, AffineExpression div)
std::function< void(Model *)> ConditionalWeightedSumGreaterOrEqual(absl::Span< const Literal > enforcement_literals, absl::Span< const IntegerVariable > vars, absl::Span< const int64_t > coefficients, int64_t upper_bound)
std::function< void(Model *)> FixedModuloConstraint(absl::Span< const Literal > enforcement_literals, AffineExpression a, IntegerValue b, AffineExpression c)
std::function< int64_t(const Model &)> UpperBound(IntegerVariable v)
std::function< IntegerVariable(Model *)> NewIntegerVariable(int64_t lb, int64_t ub)
void AddConditionalSum3LowerOrEqual(absl::Span< const Literal > enforcement_literals, IntegerVariable a, IntegerVariable b, IntegerVariable c, int64_t ub, Model *model)
std::function< IntegerVariable(Model *)> NewWeightedSum(const VectorInt &coefficients, const std::vector< IntegerVariable > &vars)
void LoadLinearConstraint(const ConstraintProto &ct, Model *m)
LinearConstraintPropagator< true > IntegerSumLE128
LinearConstraintPropagator< false > IntegerSumLE
void AddConditionalSum2LowerOrEqual(absl::Span< const Literal > enforcement_literals, IntegerVariable a, IntegerVariable b, int64_t ub, Model *model)
std::function< void(Model *)> WeightedSumLowerOrEqual(absl::Span< const IntegerVariable > vars, const VectorInt &coefficients, int64_t upper_bound)
AffineExpression Negated() const
static IntegerLiteral GreaterOrEqual(IntegerVariable i, IntegerValue bound)
static IntegerLiteral LowerOrEqual(IntegerVariable i, IntegerValue bound)
absl::Span< const IntegerValue > CoeffsAsSpan() const
absl::Span< const IntegerVariable > VarsAsSpan() const
IntegerValue Min(const IntegerTrail &integer_trail) const
std::vector< IntegerVariable > vars
std::vector< IntegerValue > coeffs
IntegerValue Max(const IntegerTrail &integer_trail) const