14#ifndef ORTOOLS_SAT_CUTS_H_
15#define ORTOOLS_SAT_CUTS_H_
28#include "absl/container/btree_map.h"
29#include "absl/container/btree_set.h"
30#include "absl/container/flat_hash_map.h"
31#include "absl/container/flat_hash_set.h"
32#include "absl/functional/any_invocable.h"
33#include "absl/numeric/int128.h"
34#include "absl/strings/str_cat.h"
35#include "absl/types/span.h"
59 std::vector<IntegerVariable>
vars;
97 IntegerValue
coeff = IntegerValue(0);
126 absl::Span<const IntegerVariable> vars,
127 absl::Span<const IntegerValue> coeffs,
128 absl::Span<const double> lp_values,
129 absl::Span<const IntegerValue> lower_bounds,
130 absl::Span<const IntegerValue> upper_bounds);
132 bool AppendOneTerm(IntegerVariable var, IntegerValue coeff,
double lp_value,
133 IntegerValue lb, IntegerValue ub);
176 bool MergeIfPossible(IntegerValue t,
CutTerm& to_add,
CutTerm& target);
178 absl::flat_hash_map<IntegerVariable, int> bool_index_;
179 absl::flat_hash_map<IntegerVariable, int> secondary_bool_index_;
180 absl::btree_map<IntegerVariable, IntegerValue> tmp_map_;
196 : lp_vars_(lp_vars_.
begin(), lp_vars_.
end()),
197 integer_trail_(integer_trail),
198 implied_bounds_(implied_bounds) {}
214 IntegerValue factor_t,
CutTerm& bool_term,
224 IntegerValue factor_t,
CutTerm& bool_term,
233 const std::function<IntegerValue(IntegerValue)>& f, IntegerValue factor_t,
242 CutTerm* term, absl::int128* rhs,
243 std::vector<CutTerm>* new_bool_terms);
274 const double bool_term =
276 return var_lp_value -
static_cast<double>(lb.value()) - bool_term;
291 BestImpliedBoundInfo ComputeBestImpliedBound(
295 absl::flat_hash_set<IntegerVariable> lp_vars_;
296 mutable absl::flat_hash_map<IntegerVariable, BestImpliedBoundInfo> cache_;
299 std::vector<CutTerm> tmp_terms_;
301 std::vector<BestImpliedBoundInfo> cached_data_;
339IntegerValue
GetFactorT(IntegerValue rhs_remainder, IntegerValue divisor,
340 IntegerValue max_magnitude);
342 IntegerValue rhs_remainder, IntegerValue divisor, IntegerValue t,
343 IntegerValue max_scaling);
365 IntegerValue positive_rhs, IntegerValue min_magnitude);
369std::function<IntegerValue(IntegerValue)>
371 IntegerValue scaling);
377 std::function<IntegerValue(IntegerValue)> base_f, IntegerValue period) {
378 const IntegerValue m = -base_f(-period);
379 return [m, period, base_f](IntegerValue v) {
381 const IntegerValue output_r = m + base_f(r - period);
399 const std::function<IntegerValue(IntegerValue)>& f, IntegerValue divisor,
413 struct LiteralInCut {
416 IntegerValue original_coeff;
426 std::vector<IntegerValue> initial_coeffs_;
427 std::vector<LiteralInCut> literals_;
428 absl::flat_hash_set<Literal> already_seen_;
429 absl::flat_hash_map<int, int> amo_count_;
432 int64_t num_improvements_ = 0;
433 int64_t num_todo_both_complements_ = 0;
473 : gub_helper_(model),
486 std::string
Info()
const {
return absl::StrCat(
"ib_lift=", num_ib_used_); }
489 double GetScaledViolation(IntegerValue divisor, IntegerValue max_scaling,
490 IntegerValue remainder_threshold,
497 std::vector<IntegerValue> divisors_;
498 std::vector<IntegerValue> remainders_;
499 std::vector<IntegerValue> rs_;
500 std::vector<IntegerValue> best_rs_;
502 int64_t num_ib_used_ = 0;
505 std::vector<std::pair<int, IntegerValue>> adjusted_coeffs_;
506 std::vector<std::pair<int, IntegerValue>> best_adjusted_coeffs_;
509 int64_t total_num_dominating_f_ = 0;
510 int64_t total_num_pos_lifts_ = 0;
511 int64_t total_num_neg_lifts_ = 0;
512 int64_t total_num_post_complements_ = 0;
513 int64_t total_num_overflow_abort_ = 0;
514 int64_t total_num_coeff_adjust_ = 0;
515 int64_t total_num_merges_ = 0;
516 int64_t total_num_bumps_ = 0;
517 int64_t total_num_final_complements_ = 0;
519 int64_t total_num_initial_ibs_ = 0;
520 int64_t total_num_initial_merges_ = 0;
527 : gub_helper_(model),
581 std::string
Info()
const {
return absl::StrCat(
"lift=", num_lifting_); }
586 void InitializeCut(
const CutData& input_ct);
590 template <
class CompareAdd,
class CompareRemove>
591 int GetCoverSize(
int relevant_size);
595 int GetCoverSizeForBooleans();
597 template <
class Compare>
598 int MinimizeCover(
int cover_size, absl::int128 slack);
608 bool has_bool_base_ct_ =
false;
610 int bool_cover_size_ = 0;
613 int64_t num_lifting_ = 0;
617 int64_t num_cuts = 0;
618 int64_t num_initial_ibs = 0;
619 int64_t num_lb_ibs = 0;
620 int64_t num_ub_ibs = 0;
621 int64_t num_merges = 0;
622 int64_t num_bumps = 0;
623 int64_t num_lifting = 0;
624 int64_t num_gubs = 0;
625 int64_t num_overflow_aborts = 0;
627 CutStats flow_stats_;
628 CutStats cover_stats_;
647 void Initialize(absl::Span<const IntegerVariable> lp_vars);
656 std::string
Info()
const {
return ""; }
661 double GetLiteralLpValue(IntegerVariable var)
const;
665 bool TryProduct(IntegerVariable factor,
const CutData&
input);
667 bool enabled_ =
false;
675 int64_t num_tried_ = 0;
676 int64_t num_tried_factors_ = 0;
683 int linearization_level,
692 AffineExpression square,
694 IntegerValue x_ub,
Model* model);
702 AffineExpression square,
703 IntegerValue x_value,
709 int linearization_level,
Model* model);
718 absl::Span<const AffineExpression> exprs,
Model* model);
758 absl::Span<const LinearExpression> exprs,
759 absl::Span<const IntegerVariable> z_vars,
766 const LinearExpression& target, IntegerVariable var,
767 absl::Span<
const std::pair<IntegerValue, IntegerValue>> affines,
768 Model* model, LinearConstraintBuilder* builder);
775 LinearExpression target, IntegerVariable var,
776 std::vector<std::pair<IntegerValue, IntegerValue>> affines,
777 std::string cut_name,
Model* model);
783 absl::Span<const IntegerVariable> base_variables,
Model* model);
797 int size()
const {
return expr_mins_.size(); }
800 absl::btree_set<IntegerValue> min_values_;
801 std::vector<IntegerValue> expr_mins_;
bool TrySimpleSeparation(const CutData &input_ct)
BoolRLTCutHelper(Model *model)
void Initialize(absl::Span< const IntegerVariable > lp_vars)
const CutData & cut() const
const CutData & cut() const
bool TrySimpleKnapsack(const CutData &input_ct, ImpliedBoundsProcessor *ib_processor=nullptr)
CoverCutHelper(Model *model)
bool TryWithLetchfordSouliLifting(const CutData &input_ct, ImpliedBoundsProcessor *ib_processor=nullptr)
bool TrySingleNodeFlow(const CutData &input_ct, ImpliedBoundsProcessor *ib_processor=nullptr)
bool ConvertToLinearConstraint(const CutData &cut, LinearConstraint *output)
int AddOrMergeBooleanTerms(absl::Span< CutTerm > terms, IntegerValue t, CutData *cut)
int last_num_lifts() const
int last_num_gubs() const
void ApplyWithPotentialBumpAndGUB(const std::function< IntegerValue(IntegerValue)> &f, IntegerValue divisor, CutData *cut)
int last_num_bumps() const
std::vector< CutTerm > * ClearedMutableTempTerms()
void RecomputeCacheAndSeparateSomeImpliedBoundCuts(const util_intops::StrongVector< IntegerVariable, double > &lp_values)
bool CacheDataForCut(IntegerVariable first_slack, CutData *cut)
bool TryToExpandWithLowerImpliedbound(IntegerValue factor_t, bool complement, CutTerm *term, absl::int128 *rhs, std::vector< CutTerm > *new_bool_terms)
ImpliedBoundsProcessor(absl::Span< const IntegerVariable > lp_vars_, IntegerTrail *integer_trail, ImpliedBounds *implied_bounds)
void AddLpVariable(IntegerVariable var)
BestImpliedBoundInfo GetCachedImpliedBoundInfo(IntegerVariable var) const
CutDataBuilder * MutableCutBuilder()
bool DecomposeWithImpliedLowerBound(const CutTerm &term, IntegerValue factor_t, CutTerm &bool_term, CutTerm &slack_term)
std::tuple< int, int, int > PostprocessWithImpliedBound(const std::function< IntegerValue(IntegerValue)> &f, IntegerValue factor_t, CutData *cut)
bool DecomposeWithImpliedUpperBound(const CutTerm &term, IntegerValue factor_t, CutTerm &bool_term, CutTerm &slack_term)
~IntegerRoundingCutHelper()
bool ComputeCut(RoundingOptions options, const CutData &base_ct, ImpliedBoundsProcessor *ib_processor=nullptr)
const CutData & cut() const
IntegerRoundingCutHelper(Model *model)
IntegerValue GetBestLowerBound(std::string &suffix)
void Add(const AffineExpression &expr, int num_expr, const IntegerTrail &integer_trail)
IntegerValue SumOfDifferentMins()
IntegerValue SumOfMinDomainValues()
IntegerValue FloorRatio(IntegerValue dividend, IntegerValue positive_divisor)
bool BuildMaxAffineUpConstraint(const LinearExpression &target, IntegerVariable var, absl::Span< const std::pair< IntegerValue, IntegerValue > > affines, Model *model, LinearConstraintBuilder *builder)
IntegerValue GetFactorT(IntegerValue rhs_remainder, IntegerValue divisor, IntegerValue max_magnitude)
CutGenerator CreatePositiveMultiplicationCutGenerator(AffineExpression z, AffineExpression x, AffineExpression y, int linearization_level, Model *model)
LinearConstraint ComputeHyperplanBelowSquare(AffineExpression x, AffineExpression square, IntegerValue x_value, Model *model)
const IntegerVariable kNoIntegerVariable(-1)
CutGenerator CreateLinMaxCutGenerator(const IntegerVariable target, absl::Span< const LinearExpression > exprs, absl::Span< const IntegerVariable > z_vars, Model *model)
std::function< IntegerValue(IntegerValue)> GetSuperAdditiveStrengtheningFunction(IntegerValue positive_rhs, IntegerValue min_magnitude)
CutGenerator CreateAllDifferentCutGenerator(absl::Span< const AffineExpression > exprs, Model *model)
CutGenerator CreateSquareCutGenerator(AffineExpression y, AffineExpression x, int linearization_level, Model *model)
CutGenerator CreateCliqueCutGenerator(absl::Span< const IntegerVariable > base_variables, Model *model)
IntegerValue PositiveRemainder(IntegerValue dividend, IntegerValue positive_divisor)
CutGenerator CreateMaxAffineCutGenerator(LinearExpression target, IntegerVariable var, std::vector< std::pair< IntegerValue, IntegerValue > > affines, const std::string cut_name, Model *model)
LinearConstraint ComputeHyperplanAboveSquare(AffineExpression x, AffineExpression square, IntegerValue x_lb, IntegerValue x_ub, Model *model)
std::function< IntegerValue(IntegerValue)> ExtendNegativeFunction(std::function< IntegerValue(IntegerValue)> base_f, IntegerValue period)
std::function< IntegerValue(IntegerValue)> GetSuperAdditiveStrengtheningMirFunction(IntegerValue positive_rhs, IntegerValue scaling)
std::function< IntegerValue(IntegerValue)> GetSuperAdditiveRoundingFunction(IntegerValue rhs_remainder, IntegerValue divisor, IntegerValue t, IntegerValue max_scaling)
ClosedInterval::Iterator end(ClosedInterval interval)
ClosedInterval::Iterator begin(ClosedInterval interval)
static int input(yyscan_t yyscanner)
bool FillFromLinearConstraint(const LinearConstraint &base_ct, const util_intops::StrongVector< IntegerVariable, double > &lp_values, IntegerTrail *integer_trail)
bool AllCoefficientsArePositive() const
std::vector< CutTerm > terms
bool FillFromParallelVectors(IntegerValue ub, absl::Span< const IntegerVariable > vars, absl::Span< const IntegerValue > coeffs, absl::Span< const double > lp_values, absl::Span< const IntegerValue > lower_bounds, absl::Span< const IntegerValue > upper_bounds)
double ComputeEfficacy() const
void ComplementForPositiveCoefficients()
std::string DebugString() const
double ComputeViolation() const
IntegerValue max_magnitude
bool AppendOneTerm(IntegerVariable var, IntegerValue coeff, double lp_value, IntegerValue lb, IntegerValue ub)
void SortRelevantEntries()
void ComplementForSmallerLpValues()
absl::AnyInvocable< bool(LinearConstraintManager *manager)> generate_cuts
std::vector< IntegerVariable > vars
bool only_run_at_level_zero
IntegerVariable GetUnderlyingLiteralOrNone() const
std::string DebugString() const
double LpDistToMaxValue() const
void ReplaceExpressionByLiteral(IntegerVariable var)
void Complement(absl::int128 *rhs)
std::array< IntegerVariable, 2 > expr_vars
std::array< IntegerValue, 2 > expr_coeffs
bool HasRelevantLpValue() const
bool IsFractional() const
std::string DebugString() const
double SlackLpValue(IntegerValue lb) const
IntegerValue implied_bound
bool use_ib_before_heuristic