14#ifndef OR_TOOLS_SAT_INTEGER_EXPR_H_
15#define OR_TOOLS_SAT_INTEGER_EXPR_H_
25#include "absl/log/check.h"
26#include "absl/types/span.h"
35#include "ortools/sat/sat_parameters.pb.h"
67template <
bool use_
int128 = false>
76 absl::Span<const IntegerVariable> vars,
77 absl::Span<const IntegerValue> coeffs,
78 IntegerValue upper_bound,
Model* model);
102 IntegerLiteral integer_literal, IntegerVariable target_var) const;
105 void Explain(
int id, IntegerValue propagation_slack,
106 IntegerVariable var_to_explain,
int trail_index,
108 std::vector<
int>* trail_indices_reason) final;
115 void FillIntegerReason();
117 const IntegerValue upper_bound_;
124 explicit Shared(
Model* model)
129 rev_integer_value_repository(
139 std::vector<IntegerLiteral> integer_reason;
140 std::vector<IntegerValue> reason_coeffs;
145 bool is_registered_ =
false;
146 IntegerValue rev_lb_fixed_vars_;
149 int rev_num_fixed_vars_;
155 const std::unique_ptr<IntegerVariable[]> vars_;
156 const std::unique_ptr<IntegerValue[]> coeffs_;
157 const std::unique_ptr<IntegerValue[]> max_variations_;
160 std::vector<Literal> literal_reason_;
181 const std::vector<IntegerVariable>& vars,
182 const std::vector<IntegerValue>& coeffs,
Model* model);
187 const IntegerVariable target_;
188 const std::vector<IntegerVariable> vars_;
189 const std::vector<IntegerValue> coeffs_;
191 IntegerValue gcd_ = IntegerValue(1);
246 LinMinPropagator(std::vector<LinearExpression> exprs, IntegerVariable min_var,
255 void Explain(
int id, IntegerValue propagation_slack,
256 IntegerVariable var_to_explain,
int trail_index,
258 std::vector<
int>* trail_indices_reason) final;
264 bool PropagateLinearUpperBound(
int id,
absl::Span<const IntegerVariable> vars,
265 absl::Span<const IntegerValue> coeffs,
266 IntegerValue upper_bound);
269 const IntegerVariable min_var_;
270 std::vector<IntegerValue> expr_lbs_;
273 std::vector<IntegerValue> max_variations_;
274 std::vector<IntegerValue> reason_coeffs_;
277 int rev_unique_candidate_ = 0;
298 bool CanonicalizeCases();
302 bool PropagateWhenAllNonNegative();
306 IntegerValue min_p, IntegerValue max_p);
375 const IntegerValue b_;
396 bool PropagateSignsAndTargetRange();
399 bool PropagateOuterBounds();
402 const IntegerValue mod_;
434template <typename VectorInt>
436 absl::Span<const IntegerVariable> vars, const VectorInt& coefficients,
437 int64_t upper_bound) {
438 return [=, vars = std::vector<IntegerVariable>(vars.begin(), vars.end())](
446template <
typename VectorInt>
448 absl::Span<const IntegerVariable> vars,
const VectorInt& coefficients,
449 int64_t lower_bound) {
451 std::vector<int64_t> negated_coeffs(coefficients.begin(), coefficients.end());
452 for (int64_t& ref : negated_coeffs) ref = -ref;
457template <
typename VectorInt>
459 absl::Span<const IntegerVariable> vars,
const VectorInt& coefficients,
461 return [=, vars = std::vector<IntegerVariable>(vars.begin(), vars.end())](
470 absl::Span<const Literal> enforcement_literals,
471 absl::Span<const IntegerVariable> vars,
472 absl::Span<const int64_t> coefficients, int64_t upper_bound,
Model* model) {
474 DCHECK_GE(vars.size(), 1);
475 if (vars.size() == 1) {
476 DCHECK_NE(coefficients[0], 0);
477 IntegerVariable var = vars[0];
478 IntegerValue coeff(coefficients[0]);
483 const IntegerValue rhs =
FloorRatio(IntegerValue(upper_bound), coeff);
484 if (enforcement_literals.empty()) {
494 const SatParameters& params = *model->
GetOrCreate<SatParameters>();
495 if (!params.new_linear_propagation()) {
496 if (vars.size() == 2 && (coefficients[0] == 1 || coefficients[0] == -1) &&
497 (coefficients[1] == 1 || coefficients[1] == -1)) {
499 enforcement_literals,
500 coefficients[0] == 1 ? vars[0] :
NegationOf(vars[0]),
501 coefficients[1] == 1 ? vars[1] :
NegationOf(vars[1]), upper_bound,
505 if (vars.size() == 3 && (coefficients[0] == 1 || coefficients[0] == -1) &&
506 (coefficients[1] == 1 || coefficients[1] == -1) &&
507 (coefficients[2] == 1 || coefficients[2] == -1)) {
509 enforcement_literals,
510 coefficients[0] == 1 ? vars[0] :
NegationOf(vars[0]),
511 coefficients[1] == 1 ? vars[1] :
NegationOf(vars[1]),
512 coefficients[2] == 1 ? vars[2] :
NegationOf(vars[2]), upper_bound,
522 if (!enforcement_literals.empty()) {
523 IntegerValue expression_min(0);
525 for (
int i = 0;
i < vars.size(); ++
i) {
527 coefficients[
i] * (coefficients[
i] >= 0
531 if (expression_min == upper_bound) {
535 IntegerValue non_cached_min;
536 for (
int i = 0;
i < vars.size(); ++
i) {
537 if (coefficients[
i] > 0) {
539 non_cached_min += coefficients[
i] * lb;
542 }
else if (coefficients[
i] < 0) {
544 non_cached_min += coefficients[
i] * ub;
549 if (non_cached_min > expression_min) {
550 std::vector<Literal> clause;
551 for (
const Literal l : enforcement_literals) {
552 clause.push_back(l.Negated());
560 if (params.new_linear_propagation()) {
562 enforcement_literals, vars,
563 std::vector<IntegerValue>(coefficients.begin(), coefficients.end()),
564 IntegerValue(upper_bound));
567 if (sat_solver->CurrentDecisionLevel() == 0) {
568 sat_solver->NotifyThatModelIsUnsat();
570 LOG(FATAL) <<
"We currently do not support adding conflicting "
571 "constraint at positive level.";
576 enforcement_literals, vars,
577 std::vector<IntegerValue>(coefficients.begin(), coefficients.end()),
578 IntegerValue(upper_bound), model);
586 absl::Span<const Literal> enforcement_literals,
587 absl::Span<const IntegerVariable> vars,
588 absl::Span<const int64_t> coefficients, int64_t lower_bound,
Model* model) {
590 std::vector<int64_t> negated_coeffs(coefficients.begin(), coefficients.end());
591 for (int64_t& ref : negated_coeffs) ref = -ref;
593 -lower_bound, model);
598 absl::Span<const Literal> enforcement_literals,
599 absl::Span<const IntegerVariable> vars,
600 absl::Span<const int64_t> coefficients, int64_t upper_bound) {
601 return [=, vars = std::vector<IntegerVariable>(vars.begin(), vars.end()),
603 std::vector<int64_t>(coefficients.begin(), coefficients.end()),
604 enforcement_literals =
605 std::vector<Literal>(enforcement_literals.begin(),
606 enforcement_literals.end())](
Model* model) {
612 absl::Span<const Literal> enforcement_literals,
613 absl::Span<const IntegerVariable> vars,
614 absl::Span<const int64_t> coefficients, int64_t upper_bound) {
617 std::vector<int64_t>(coefficients.begin(), coefficients.end()),
618 vars = std::vector<IntegerVariable>(vars.begin(), vars.end()),
619 enforcement_literals =
620 std::vector<Literal>(enforcement_literals.begin(),
621 enforcement_literals.end())](
Model* model) {
629 const absl::Span<const Literal> enforcement_literals,
632 if (cst.
lb <= 0 && cst.
ub >= 0)
return;
635 std::vector<Literal> clause;
636 for (
const Literal lit : enforcement_literals) {
637 clause.push_back(lit.Negated());
643 std::vector<IntegerVariable> vars(cst.
num_terms);
644 std::vector<int64_t> coeffs(cst.
num_terms);
652 cst.
ub.value(), model);
656 cst.
lb.value(), model);
665 const absl::Span<const Literal> enforcement_literals, AffineExpression left,
680template <
typename VectorInt>
682 const VectorInt& coefficients,
const std::vector<IntegerVariable>& vars) {
684 std::vector<IntegerVariable> new_vars = vars;
691 for (
int i = 0;
i < new_vars.size(); ++
i) {
692 if (coefficients[
i] > 0) {
693 sum_lb += coefficients[
i] * model->Get(
LowerBound(new_vars[
i]));
694 sum_ub += coefficients[
i] * model->Get(
UpperBound(new_vars[
i]));
696 sum_lb += coefficients[
i] * model->Get(
UpperBound(new_vars[
i]));
697 sum_ub += coefficients[
i] * model->Get(
LowerBound(new_vars[
i]));
702 new_vars.push_back(sum);
703 std::vector<int64_t> new_coeffs(coefficients.begin(), coefficients.end());
704 new_coeffs.push_back(-1);
714 std::vector<LinearExpression> exprs,
718 IntegerVariable min_var;
719 if (min_expr.vars.size() == 1 && std::abs(min_expr.coeffs[0].value()) == 1 &&
720 min_expr.offset == 0) {
721 if (min_expr.coeffs[0].value() == 1) {
722 min_var = min_expr.vars[0];
728 IntegerValue min_lb = min_expr.Min(*integer_trail);
729 IntegerValue min_ub = min_expr.Max(*integer_trail);
753ABSL_DEPRECATED(
"Use AddIsEqualToMinOf() instead.")
755 const LinearExpression& min_expr,
762 ct->RegisterWith(model->GetOrCreate<GenericLiteralWatcher>());
763 model->TakeOwnership(ct);
769 return [=](
Model* model) {
790 AffineExpression denom,
792 return [=](
Model* model) {
803 model->TakeOwnership(constraint);
811 return [=](
Model* model) {
817 model->TakeOwnership(constraint);
825 return [=](
Model* model) {
830 model->TakeOwnership(constraint);
void RegisterWith(GenericLiteralWatcher *watcher)
DivisionPropagator(AffineExpression num, AffineExpression denom, AffineExpression div, IntegerTrail *integer_trail)
DivisionPropagator(const DivisionPropagator &)=delete
This type is neither copyable nor movable.
DivisionPropagator & operator=(const DivisionPropagator &)=delete
void RegisterWith(GenericLiteralWatcher *watcher)
FixedDivisionPropagator(const FixedDivisionPropagator &)=delete
This type is neither copyable nor movable.
FixedDivisionPropagator(AffineExpression a, IntegerValue b, AffineExpression c, IntegerTrail *integer_trail)
FixedDivisionPropagator & operator=(const FixedDivisionPropagator &)=delete
FixedModuloPropagator & operator=(const FixedModuloPropagator &)=delete
FixedModuloPropagator(AffineExpression expr, IntegerValue mod, AffineExpression target, IntegerTrail *integer_trail)
FixedModuloPropagator(const FixedModuloPropagator &)=delete
This type is neither copyable nor movable.
void RegisterWith(GenericLiteralWatcher *watcher)
IntegerValue LowerBound(IntegerVariable i) const
Returns the current lower/upper bound of the given integer variable.
IntegerValue UpperBound(IntegerVariable i) const
IntegerValue LevelZeroUpperBound(IntegerVariable var) const
IntegerValue LevelZeroLowerBound(IntegerVariable var) const
Returns globally valid lower/upper bound on the given integer variable.
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)
LinMinPropagator & operator=(const LinMinPropagator &)=delete
void RegisterWith(GenericLiteralWatcher *watcher)
LinMinPropagator(const LinMinPropagator &)=delete
void Explain(int id, IntegerValue propagation_slack, IntegerVariable var_to_explain, int trail_index, std::vector< Literal > *literals_reason, std::vector< int > *trail_indices_reason) final
For LazyReasonInterface.
LinMinPropagator(std::vector< LinearExpression > exprs, IntegerVariable min_var, Model *model)
void AddTerm(IntegerVariable var, IntegerValue coeff)
void AddLinearExpression(const LinearExpression &expr)
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)
void Explain(int id, IntegerValue propagation_slack, IntegerVariable var_to_explain, int trail_index, std::vector< Literal > *literals_reason, std::vector< int > *trail_indices_reason) final
bool PropagateAtLevelZero()
MinPropagator(const MinPropagator &)=delete
This type is neither copyable nor movable.
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
This type is neither copyable nor movable.
ProductPropagator(AffineExpression a, AffineExpression b, AffineExpression p, IntegerTrail *integer_trail)
ProductPropagator & operator=(const ProductPropagator &)=delete
void RegisterWith(GenericLiteralWatcher *watcher)
PropagatorInterface()=default
SquarePropagator(const SquarePropagator &)=delete
This type is neither copyable nor movable.
SquarePropagator(AffineExpression x, AffineExpression s, IntegerTrail *integer_trail)
SquarePropagator & operator=(const SquarePropagator &)=delete
void RegisterWith(GenericLiteralWatcher *watcher)
const VariablesAssignment & Assignment() const
IntegerValue FloorRatio(IntegerValue dividend, IntegerValue positive_divisor)
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)
Weighted sum >= constant.
std::function< void(Model *)> ProductConstraint(AffineExpression a, AffineExpression b, AffineExpression p)
Adds the constraint: a * b = p.
std::function< void(Model *)> ClauseConstraint(absl::Span< const Literal > literals)
std::function< int64_t(const Model &)> LowerBound(IntegerVariable v)
std::function< void(Model *)> LowerOrEqual(IntegerVariable v, int64_t ub)
std::function< void(Model *)> FixedDivisionConstraint(AffineExpression a, IntegerValue b, AffineExpression c)
Adds the constraint: a / b = c where b is a constant.
std::vector< IntegerVariable > NegationOf(absl::Span< const IntegerVariable > vars)
Returns the vector of the negated variables.
std::function< void(Model *)> FixedWeightedSum(absl::Span< const IntegerVariable > vars, const VectorInt &coefficients, int64_t value)
Weighted sum == constant.
void LoadConditionalLinearConstraint(const absl::Span< const Literal > enforcement_literals, const LinearConstraint &cst, Model *model)
LinearConstraint version.
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 *)> ConditionalWeightedSumLowerOrEqual(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 *)> DivisionConstraint(AffineExpression num, AffineExpression denom, AffineExpression div)
Adds the constraint: num / denom = div. (denom > 0).
void AddConditionalAffinePrecedence(const absl::Span< const Literal > enforcement_literals, AffineExpression left, AffineExpression right, Model *model)
void RegisterAndTransferOwnership(Model *model, T *ct)
void AddWeightedSumLowerOrEqual(absl::Span< const Literal > enforcement_literals, absl::Span< const IntegerVariable > vars, absl::Span< const int64_t > coefficients, int64_t upper_bound, Model *model)
enforcement_literals => sum <= upper_bound
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< 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)
std::function< void(Model *)> FixedModuloConstraint(AffineExpression a, IntegerValue b, AffineExpression c)
Adds the constraint: a % b = c where b is a constant.
void LoadLinearConstraint(const ConstraintProto &ct, Model *m)
void AddWeightedSumGreaterOrEqual(absl::Span< const Literal > enforcement_literals, absl::Span< const IntegerVariable > vars, absl::Span< const int64_t > coefficients, int64_t lower_bound, Model *model)
enforcement_literals => sum >= lower_bound
LinearConstraintPropagator< true > IntegerSumLE128
void AddIsEqualToMinOf(const LinearExpression &min_expr, std::vector< LinearExpression > exprs, Model *model)
LinearConstraintPropagator< false > IntegerSumLE
void AddConditionalSum2LowerOrEqual(absl::Span< const Literal > enforcement_literals, IntegerVariable a, IntegerVariable b, int64_t ub, Model *model)
l => (a + b <= ub).
std::function< void(Model *)> WeightedSumLowerOrEqual(absl::Span< const IntegerVariable > vars, const VectorInt &coefficients, int64_t upper_bound)
Weighted sum <= constant.
In SWIG mode, we don't want anything besides these top-level includes.
static IntegerLiteral GreaterOrEqual(IntegerVariable i, IntegerValue bound)
static IntegerLiteral LowerOrEqual(IntegerVariable i, IntegerValue bound)
std::unique_ptr< IntegerValue[]> coeffs
std::unique_ptr< IntegerVariable[]> vars