27#include "absl/container/btree_map.h"
28#include "absl/container/flat_hash_map.h"
29#include "absl/log/check.h"
30#include "absl/meta/type_traits.h"
31#include "absl/strings/str_cat.h"
32#include "absl/strings/string_view.h"
33#include "absl/types/span.h"
43#include "ortools/sat/sat_parameters.pb.h"
54 if (!VLOG_IS_ON(1))
return;
55 std::vector<std::pair<std::string, int64_t>> stats;
56 stats.push_back({
"symmetrizer/overflows", num_overflows_});
57 shared_stats_->AddStats(stats);
61 IntegerVariable sum_var, absl::Span<const IntegerVariable> orbit) {
62 CHECK_GT(orbit.size(), 1);
65 const int orbit_index = orbits_.size();
67 orbit_sum_vars_.push_back(sum_var);
71 const int new_size = integer_trail_->NumIntegerVariables().value() / 2;
72 if (var_to_orbit_index_.size() < new_size) {
73 var_to_orbit_index_.resize(new_size, -1);
78 for (
const IntegerVariable var : orbit) {
107 if (!has_symmetry_)
return true;
111 int64_t scaling_factor = 1;
113 const IntegerVariable var = ct->
vars[
i];
117 if (orbit_index == -1 || orbit_sum_vars_[orbit_index] == var) {
124 const int orbit_size = orbits_[orbit_index].size();
127 VLOG(2) <<
"SYMMETRY skip constraint due to overflow";
130 scaling_factor = std::lcm(scaling_factor, orbit_size);
133 if (scaling_factor == 1) {
138 if (folded !=
nullptr) *folded =
true;
146 const IntegerVariable var = ct->
vars[
i];
147 const IntegerValue coeff = ct->
coeffs[
i];
150 if (orbit_index == -1 || orbit_sum_vars_[orbit_index] == var) {
151 const int64_t scaled_coeff =
CapProd(coeff.value(), scaling_factor);
154 VLOG(2) <<
"SYMMETRY skip constraint due to overflow";
157 builder_.AddTerm(var, scaled_coeff);
159 const int64_t orbit_size = orbits_[orbit_index].size();
160 const int64_t factor = scaling_factor / orbit_size;
161 const int64_t scaled_coeff =
CapProd(coeff.value(), factor);
164 VLOG(2) <<
"SYMMETRY skip constraint due to overflow";
167 builder_.AddTerm(orbit_sum_vars_[orbit_index], scaled_coeff);
174 VLOG(2) <<
"SYMMETRY skip constraint due to lb/ub overflow";
177 if (!builder_.BuildIntoConstraintAndCheckOverflow(
178 ct->
lb * scaling_factor, ct->
ub * scaling_factor, ct)) {
180 VLOG(2) <<
"SYMMETRY skip constraint due to overflow";
188 VLOG(2) <<
"SYMMETRY skip constraint due to overflow factor = "
200 if (!has_symmetry_)
return -1;
205 if (!has_symmetry_)
return false;
207 return orbit_index >= 0 && orbit_sum_vars_[orbit_index] == var;
211 IntegerVariable var)
const {
212 if (!has_symmetry_)
return true;
214 return orbit_index == -1 || orbit_sum_vars_[orbit_index] == var;
219const LinearConstraintManager::ConstraintIndex kInvalidConstraintIndex(-1);
225 for (
int i = 0;
i < num_terms; ++
i) {
235 if (!VLOG_IS_ON(1))
return;
238 std::vector<std::pair<std::string, int64_t>> cut_stats;
239 for (
const auto& entry : type_to_num_cuts_) {
240 cut_stats.push_back({absl::StrCat(
"cut/", entry.first), entry.second});
245void LinearConstraintManager::RescaleActiveCounts(
const double scaling_factor) {
246 for (ConstraintIndex
i(0);
i < constraint_infos_.size(); ++
i) {
247 constraint_infos_[
i].active_count *= scaling_factor;
249 constraint_active_count_increase_ *= scaling_factor;
250 VLOG(3) <<
"Rescaled active counts by " << scaling_factor;
253bool LinearConstraintManager::MaybeRemoveSomeInactiveConstraints(
254 glop::BasisState* solution_state) {
255 if (solution_state->IsEmpty())
return false;
256 const glop::RowIndex num_rows(lp_constraints_.size());
257 const glop::ColIndex num_cols =
258 solution_state->statuses.size() - RowToColIndex(num_rows);
260 for (
int i = 0;
i < num_rows; ++
i) {
261 const ConstraintIndex constraint_index = lp_constraints_[
i];
262 if (constraint_infos_[constraint_index].constraint.num_terms == 0) {
268 constraint_infos_[constraint_index].is_in_lp =
false;
279 solution_state->statuses[num_cols + glop::ColIndex(
i)];
281 constraint_infos_[constraint_index].inactive_count++;
282 if (constraint_infos_[constraint_index].inactive_count >
283 sat_parameters_.max_consecutive_inactive_count()) {
284 constraint_infos_[constraint_index].is_in_lp =
false;
289 constraint_infos_[constraint_index].inactive_count = 0;
292 lp_constraints_[new_size] = constraint_index;
293 solution_state->statuses[num_cols + glop::ColIndex(new_size)] = row_status;
296 const int num_removed_constraints = lp_constraints_.size() - new_size;
297 lp_constraints_.resize(new_size);
298 solution_state->statuses.resize(num_cols + glop::ColIndex(new_size));
299 if (num_removed_constraints > 0) {
300 VLOG(3) <<
"Removed " << num_removed_constraints <<
" constraints";
302 return num_removed_constraints > 0;
313 SimplifyConstraint(&ct);
320 if (symmetrizer_->HasSymmetry() &&
321 !symmetrizer_->FoldLinearConstraint(&ct, folded)) {
322 return kInvalidConstraintIndex;
327 const size_t key = ComputeHashOfTerms(ct);
328 if (equiv_constraints_.contains(key)) {
329 const ConstraintIndex ct_index = equiv_constraints_[key];
330 if (constraint_infos_[ct_index].constraint.IsEqualIgnoringBounds(ct)) {
331 bool tightened =
false;
332 if (ct.
lb > constraint_infos_[ct_index].constraint.lb) {
334 if (constraint_infos_[ct_index].is_in_lp) current_lp_is_changed_ =
true;
335 constraint_infos_[ct_index].constraint.lb = ct.
lb;
337 if (ct.
ub < constraint_infos_[ct_index].constraint.ub) {
339 if (constraint_infos_[ct_index].is_in_lp) current_lp_is_changed_ =
true;
340 constraint_infos_[ct_index].constraint.ub = ct.
ub;
342 if (added !=
nullptr) *added = tightened;
344 ++num_merged_constraints_;
345 FillDerivedFields(&constraint_infos_[ct_index]);
351 if (added !=
nullptr) *added =
true;
352 const ConstraintIndex ct_index(constraint_infos_.size());
356 FillDerivedFields(&ct_info);
358 equiv_constraints_[key] = ct_index;
359 ct_info.
active_count = constraint_active_count_increase_;
360 constraint_infos_.push_back(std::move(ct_info));
365 IntegerValue new_lb) {
366 const ConstraintIndex index = lp_constraints_[index_in_lp.value()];
369 ++num_constraint_updates_;
370 current_lp_is_changed_ =
true;
376 IntegerValue new_ub) {
377 const ConstraintIndex index = lp_constraints_[index_in_lp.value()];
380 ++num_constraint_updates_;
381 current_lp_is_changed_ =
true;
386void LinearConstraintManager::ComputeObjectiveParallelism(
387 const ConstraintIndex ct_index) {
388 CHECK(objective_is_defined_);
390 if (!objective_norm_computed_) {
391 objective_l2_norm_ = std::sqrt(sum_of_squared_objective_coeffs_);
392 objective_norm_computed_ =
true;
394 CHECK_GT(objective_l2_norm_, 0.0);
396 constraint_infos_[ct_index].objective_parallelism_computed =
true;
397 if (constraint_infos_[ct_index].l2_norm == 0.0) {
398 constraint_infos_[ct_index].objective_parallelism = 0.0;
402 const LinearConstraint& lc = constraint_infos_[ct_index].constraint;
403 double unscaled_objective_parallelism = 0.0;
404 for (
int i = 0;
i < lc.num_terms; ++
i) {
405 const IntegerVariable var = lc.vars[
i];
406 const auto it = objective_map_.find(var);
407 if (it == objective_map_.end())
continue;
408 unscaled_objective_parallelism += it->second *
ToDouble(lc.coeffs[
i]);
410 const double objective_parallelism =
411 unscaled_objective_parallelism /
412 (constraint_infos_[ct_index].l2_norm * objective_l2_norm_);
413 constraint_infos_[ct_index].objective_parallelism =
414 std::abs(objective_parallelism);
420 std::string extra_info) {
421 ++num_add_cut_calls_;
425 const double violation =
430 if (violation / l2_norm < 1e-4) {
431 VLOG(3) <<
"BAD Cut '" << type_name <<
"'"
434 <<
" norm=" << l2_norm <<
" violation=" << violation
435 <<
" eff=" << violation / l2_norm <<
" " << extra_info;
446 const ConstraintIndex ct_index =
Add(std::move(ct), &added);
450 if (!added)
return false;
454 constraint_infos_[ct_index].is_deletable =
true;
456 VLOG(2) <<
"Cut '" << type_name <<
"'"
457 <<
" size=" << constraint_infos_[ct_index].constraint.num_terms
460 <<
" norm=" << l2_norm <<
" violation=" << violation
461 <<
" eff=" << violation / l2_norm <<
" " << extra_info;
464 num_deletable_constraints_++;
465 type_to_num_cuts_[type_name]++;
469void LinearConstraintManager::PermanentlyRemoveSomeConstraints() {
470 std::vector<double> deletable_constraint_counts;
471 for (ConstraintIndex
i(0);
i < constraint_infos_.size(); ++
i) {
472 if (constraint_infos_[
i].is_deletable && !constraint_infos_[
i].is_in_lp) {
473 deletable_constraint_counts.push_back(constraint_infos_[
i].active_count);
476 if (deletable_constraint_counts.empty())
return;
477 std::sort(deletable_constraint_counts.begin(),
478 deletable_constraint_counts.end());
482 double active_count_threshold = std::numeric_limits<double>::infinity();
483 if (sat_parameters_.cut_cleanup_target() <
484 deletable_constraint_counts.size()) {
485 active_count_threshold =
486 deletable_constraint_counts[sat_parameters_.cut_cleanup_target()];
489 ConstraintIndex new_size(0);
490 equiv_constraints_.clear();
491 util_intops::StrongVector<ConstraintIndex, ConstraintIndex> index_mapping(
492 constraint_infos_.size());
493 int num_deleted_constraints = 0;
494 for (ConstraintIndex
i(0);
i < constraint_infos_.size(); ++
i) {
495 if (constraint_infos_[
i].is_deletable && !constraint_infos_[
i].is_in_lp &&
496 constraint_infos_[
i].active_count <= active_count_threshold &&
497 num_deleted_constraints < sat_parameters_.cut_cleanup_target()) {
498 ++num_deleted_constraints;
503 constraint_infos_[new_size] = std::move(constraint_infos_[
i]);
505 index_mapping[
i] = new_size;
508 equiv_constraints_[constraint_infos_[new_size].hash] = new_size;
511 constraint_infos_.resize(new_size.value());
514 for (
int i = 0;
i < lp_constraints_.size(); ++
i) {
515 lp_constraints_[
i] = index_mapping[lp_constraints_[
i]];
518 if (num_deleted_constraints > 0) {
519 VLOG(3) <<
"Constraint manager cleanup: #deleted:"
520 << num_deleted_constraints;
522 num_deletable_constraints_ -= num_deleted_constraints;
526 IntegerValue coeff) {
527 if (coeff == IntegerValue(0))
return;
528 objective_is_defined_ =
true;
533 const double coeff_as_double =
ToDouble(coeff);
534 const auto insert = objective_map_.insert({var, coeff_as_double});
536 <<
"SetObjectiveCoefficient() called twice with same variable";
537 sum_of_squared_objective_coeffs_ += coeff_as_double * coeff_as_double;
542 bool term_changed =
false;
544 IntegerValue min_sum(0);
545 IntegerValue max_sum(0);
546 IntegerValue max_magnitude(0);
550 for (
int i = 0;
i < num_terms; ++
i) {
551 const IntegerVariable var = ct->
vars[
i];
552 const IntegerValue coeff = ct->
coeffs[
i];
558 if (lb == ub)
continue;
561 const IntegerValue magnitude =
IntTypeAbs(coeff);
562 max_magnitude = std::max(max_magnitude, magnitude);
563 min_magnitude = std::min(min_magnitude, magnitude);
565 min_sum += coeff * lb;
566 max_sum += coeff * ub;
568 min_sum += coeff * ub;
569 max_sum += coeff * lb;
574 IntegerValue fixed_part = 0;
575 if (new_size < num_terms) {
577 ++num_shortened_constraints_;
579 for (
int i = 0;
i < num_terms; ++
i) {
580 const IntegerVariable var = ct->
vars[
i];
581 const IntegerValue coeff = ct->
coeffs[
i];
582 const IntegerValue lb = integer_trail_.LevelZeroLowerBound(var);
583 const IntegerValue ub = integer_trail_.LevelZeroUpperBound(var);
585 fixed_part += coeff * lb;
588 ct->
vars[new_size] = var;
589 ct->
coeffs[new_size] = coeff;
597 if (min_sum + fixed_part >= ct->
lb && max_sum + fixed_part <= ct->ub) {
605 ct->
lb = std::max(ct->
lb, min_sum + fixed_part);
606 ct->
ub = std::min(ct->
ub, max_sum + fixed_part);
607 ct->
lb -= fixed_part;
608 ct->
ub -= fixed_part;
616 const IntegerValue threshold_ub = max_sum - ct->
ub;
617 const IntegerValue threshold_lb = ct->
lb - min_sum;
618 const IntegerValue threshold = std::max(threshold_lb, threshold_ub);
619 CHECK_GT(threshold, 0);
623 if (threshold_ub > 0 && threshold_lb > 0 && threshold_lb != threshold_ub) {
624 if (max_magnitude > std::min(threshold_lb, threshold_ub)) {
625 ++num_split_constraints_;
631 const IntegerValue second_threshold = std::max(
632 {
CeilRatio(threshold, IntegerValue(2)), threshold - min_magnitude,
633 std::min(threshold_lb, threshold_ub)});
634 if (max_magnitude > second_threshold) {
636 for (
int i = 0;
i < num_terms; ++
i) {
641 const IntegerValue coeff = ct->
coeffs[
i];
642 const IntegerVariable var = ct->
vars[
i];
643 const IntegerValue lb = integer_trail_.LevelZeroLowerBound(var);
644 const IntegerValue ub = integer_trail_.LevelZeroUpperBound(var);
645 if (coeff > threshold) {
647 ++num_coeff_strenghtening_;
649 ct->
ub -= (coeff - threshold) * ub;
650 ct->
lb -= (coeff - threshold) * lb;
651 }
else if (coeff > second_threshold && coeff < threshold) {
653 ++num_coeff_strenghtening_;
654 ct->
coeffs[
i] = second_threshold;
655 ct->
ub -= (coeff - second_threshold) * ub;
656 ct->
lb -= (coeff - second_threshold) * lb;
657 }
else if (coeff < -threshold) {
659 ++num_coeff_strenghtening_;
661 ct->
ub -= (coeff + threshold) * lb;
662 ct->
lb -= (coeff + threshold) * ub;
663 }
else if (coeff < -second_threshold && coeff > -threshold) {
665 ++num_coeff_strenghtening_;
666 ct->
coeffs[
i] = -second_threshold;
667 ct->
ub -= (coeff + second_threshold) * lb;
668 ct->
lb -= (coeff + second_threshold) * ub;
676void LinearConstraintManager::FillDerivedFields(ConstraintInfo* info) {
677 IntegerValue min_sum(0);
678 IntegerValue max_sum(0);
679 const int num_terms = info->constraint.num_terms;
680 for (
int i = 0;
i < num_terms; ++
i) {
681 const IntegerVariable var = info->constraint.vars[
i];
682 const IntegerValue coeff = info->constraint.coeffs[
i];
683 const IntegerValue lb = integer_trail_.LevelZeroLowerBound(var);
684 const IntegerValue ub = integer_trail_.LevelZeroUpperBound(var);
686 min_sum += coeff * lb;
687 max_sum += coeff * ub;
689 min_sum += coeff * ub;
690 max_sum += coeff * lb;
693 info->constraint.lb = std::max(min_sum, info->constraint.lb);
694 info->constraint.ub = std::min(max_sum, info->constraint.ub);
695 CHECK_NE(
CapSub(info->constraint.ub.value(), info->constraint.lb.value()),
696 std::numeric_limits<int64_t>::max());
697 info->lb_is_trivial = min_sum >= info->constraint.lb;
698 info->ub_is_trivial = max_sum <= info->constraint.ub;
702 int* num_new_constraints) {
703 VLOG(3) <<
"Enter ChangeLP, scan " << constraint_infos_.size()
705 const double saved_dtime = dtime_;
706 std::vector<std::pair<ConstraintIndex, double>> new_constraints_by_score;
707 std::vector<double> new_constraints_efficacies;
708 std::vector<double> new_constraints_orthogonalities;
710 const bool simplify_constraints =
711 integer_trail_.num_level_zero_enqueues() > last_simplification_timestamp_;
712 last_simplification_timestamp_ = integer_trail_.num_level_zero_enqueues();
717 bool rescale_active_count =
false;
718 const double tolerance = 1e-6;
719 for (ConstraintIndex
i(0);
i < constraint_infos_.size(); ++
i) {
721 if (simplify_constraints &&
722 SimplifyConstraint(&constraint_infos_[
i].constraint)) {
723 ++num_simplifications_;
731 constraint_infos_[
i].objective_parallelism_computed =
false;
732 constraint_infos_[
i].l2_norm =
734 FillDerivedFields(&constraint_infos_[
i]);
736 if (constraint_infos_[
i].is_in_lp) current_lp_is_changed_ =
true;
737 equiv_constraints_.erase(constraint_infos_[
i].hash);
738 constraint_infos_[
i].hash =
739 ComputeHashOfTerms(constraint_infos_[
i].constraint);
743 equiv_constraints_[constraint_infos_[
i].hash] =
i;
746 if (constraint_infos_[
i].is_in_lp)
continue;
751 1.7e-9 *
static_cast<double>(constraint_infos_[
i].constraint.num_terms);
752 const double activity =
754 const double lb_violation =
755 ToDouble(constraint_infos_[
i].constraint.lb) - activity;
756 const double ub_violation =
757 activity -
ToDouble(constraint_infos_[
i].constraint.ub);
758 const double violation = std::max(lb_violation, ub_violation);
759 if (violation >= tolerance) {
760 constraint_infos_[
i].inactive_count = 0;
761 if (objective_is_defined_ &&
762 !constraint_infos_[
i].objective_parallelism_computed) {
763 ComputeObjectiveParallelism(
i);
764 }
else if (!objective_is_defined_) {
765 constraint_infos_[
i].objective_parallelism = 0.0;
768 const double score = violation / constraint_infos_[
i].l2_norm +
769 constraint_infos_[
i].objective_parallelism;
770 new_constraints_by_score.push_back({
i, score});
772 if (constraint_infos_[
i].is_deletable) {
773 constraint_infos_[
i].active_count += constraint_active_count_increase_;
774 if (constraint_infos_[
i].active_count >
775 sat_parameters_.cut_max_active_count_value()) {
776 rescale_active_count =
true;
783 if (solution_state !=
nullptr) {
784 const glop::RowIndex num_rows(lp_constraints_.size());
785 const glop::ColIndex num_cols =
786 solution_state->
statuses.
size() - RowToColIndex(num_rows);
788 for (
int i = 0;
i < num_rows; ++
i) {
789 const ConstraintIndex constraint_index = lp_constraints_[
i];
791 solution_state->
statuses[num_cols + glop::ColIndex(
i)];
793 constraint_infos_[constraint_index].is_deletable) {
794 constraint_infos_[constraint_index].active_count +=
795 constraint_active_count_increase_;
796 if (constraint_infos_[constraint_index].active_count >
797 sat_parameters_.cut_max_active_count_value()) {
798 rescale_active_count =
true;
804 if (rescale_active_count) {
805 CHECK_GT(sat_parameters_.cut_max_active_count_value(), 0.0);
806 RescaleActiveCounts(1.0 / sat_parameters_.cut_max_active_count_value());
810 constraint_active_count_increase_ *=
811 1.0 / sat_parameters_.cut_active_count_decay();
816 if (MaybeRemoveSomeInactiveConstraints(solution_state)) {
817 current_lp_is_changed_ =
true;
830 const int kBlowupFactor = 4;
831 const int current_size =
static_cast<int>(new_constraints_by_score.size());
832 int constraint_limit =
833 std::min(sat_parameters_.new_constraints_batch_size(), current_size);
834 if (lp_constraints_.empty()) {
835 constraint_limit = std::min(1000, current_size);
837 VLOG(3) <<
" - size = " << current_size <<
", limit = " << constraint_limit;
839 std::stable_sort(new_constraints_by_score.begin(),
840 new_constraints_by_score.end(),
841 [&](std::pair<ConstraintIndex, double> a,
842 std::pair<ConstraintIndex, double>
b) {
843 return a.second > b.second;
845 if (new_constraints_by_score.size() > kBlowupFactor * constraint_limit) {
846 VLOG(3) <<
"Resize candidate constraints from "
847 << new_constraints_by_score.size() <<
" down to "
848 << kBlowupFactor * constraint_limit;
849 new_constraints_by_score.resize(kBlowupFactor * constraint_limit);
853 int num_skipped_checks = 0;
854 const int kCheckFrequency = 100;
855 ConstraintIndex last_added_candidate = kInvalidConstraintIndex;
856 std::vector<double> orthogonality_score(new_constraints_by_score.size(), 1.0);
857 for (
int i = 0;
i < constraint_limit; ++
i) {
862 double best_score = 0.0;
863 ConstraintIndex best_candidate = kInvalidConstraintIndex;
864 for (
int j = 0; j < new_constraints_by_score.size(); ++j) {
866 if (++num_skipped_checks >= kCheckFrequency) {
867 if (time_limit_->LimitReached())
return current_lp_is_changed_;
868 num_skipped_checks = 0;
871 const ConstraintIndex new_index = new_constraints_by_score[j].first;
872 if (constraint_infos_[new_index].is_in_lp)
continue;
874 if (last_added_candidate != kInvalidConstraintIndex) {
875 const double current_orthogonality =
877 constraint_infos_[last_added_candidate].constraint,
878 constraint_infos_[new_index].constraint)) /
879 (constraint_infos_[last_added_candidate].l2_norm *
880 constraint_infos_[new_index].l2_norm));
881 orthogonality_score[j] =
882 std::min(orthogonality_score[j], current_orthogonality);
890 if (orthogonality_score[j] <
891 sat_parameters_.min_orthogonality_for_lp_constraints()) {
898 orthogonality_score[j] + new_constraints_by_score[j].second;
899 CHECK_GE(score, 0.0);
900 if (score > best_score || best_candidate == kInvalidConstraintIndex) {
902 best_candidate = new_index;
906 if (best_candidate != kInvalidConstraintIndex) {
908 constraint_infos_[best_candidate].is_in_lp =
true;
913 current_lp_is_changed_ =
true;
914 lp_constraints_.push_back(best_candidate);
915 last_added_candidate = best_candidate;
922 if (num_new_constraints !=
nullptr) {
923 *num_new_constraints = num_added;
927 VLOG(3) <<
"Added " << num_added <<
" constraints.";
934 if (num_deletable_constraints_ > sat_parameters_.max_num_cuts()) {
935 PermanentlyRemoveSomeConstraints();
938 time_limit_->AdvanceDeterministicTime(dtime_ - saved_dtime);
942 if (current_lp_is_changed_) {
943 current_lp_is_changed_ =
false;
950 for (ConstraintIndex
i(0);
i < constraint_infos_.size(); ++
i) {
951 if (constraint_infos_[
i].is_in_lp)
continue;
952 if (constraint_infos_[
i].constraint.num_terms == 0)
continue;
954 constraint_infos_[
i].is_in_lp =
true;
955 lp_constraints_.push_back(
i);
962 const auto& debug_solution = *(model_->Get<
DebugSolution>());
964 IntegerValue activity(0);
966 const IntegerVariable var = cut.
vars[
i];
967 const IntegerValue coeff = cut.
coeffs[
i];
968 CHECK(debug_solution.ivar_has_value[var]);
969 activity += coeff * debug_solution.ivar_values[var];
971 if (activity > cut.
ub || activity < cut.
lb) {
973 LOG(INFO) <<
"activity " << activity <<
" not in [" << cut.
lb <<
","
985 const double violation =
988 cuts_.Add({std::string(name), std::move(ct)}, violation / l2_norm);
992 for (CutCandidate& candidate : *cuts_.MutableUnorderedElements()) {
993 manager->
AddCut(std::move(candidate.cut), candidate.name);
void resize(IntType size)
IntegerValue LevelZeroUpperBound(IntegerVariable var) const
IntegerValue LevelZeroLowerBound(IntegerVariable var) const
Returns globally valid lower/upper bound on the given integer variable.
~LinearConstraintManager()
ConstraintIndex Add(LinearConstraint ct, bool *added=nullptr, bool *folded=nullptr)
bool ChangeLp(glop::BasisState *solution_state, int *num_new_constraints=nullptr)
bool AddCut(LinearConstraint ct, std::string type_name, std::string extra_info="")
bool UpdateConstraintUb(glop::RowIndex index_in_lp, IntegerValue new_ub)
bool DebugCheckConstraint(const LinearConstraint &cut)
bool UpdateConstraintLb(glop::RowIndex index_in_lp, IntegerValue new_lb)
These must be level zero bounds.
void AddAllConstraintsToLp()
void SetObjectiveCoefficient(IntegerVariable var, IntegerValue coeff)
bool FoldLinearConstraint(LinearConstraint *ct, bool *folded=nullptr)
int OrbitIndex(IntegerVariable var) const
void AddSymmetryOrbit(IntegerVariable sum_var, absl::Span< const IntegerVariable > orbit)
~LinearConstraintSymmetrizer()
bool IsOrbitSumVar(IntegerVariable var) const
Returns true iff var is one of the sum_var passed to AddSymmetryOrbit().
bool AppearInFoldedProblem(IntegerVariable var) const
Simple class to add statistics by name and print them at the end.
void TransferToManager(LinearConstraintManager *manager)
Empty the local pool and add all its content to the manager.
void AddCut(LinearConstraint ct, absl::string_view name, const util_intops::StrongVector< IntegerVariable, double > &lp_solution)
Adds a cut to the local pool.
double ComputeActivity(const LinearConstraint &constraint, const util_intops::StrongVector< IntegerVariable, double > &values)
void DivideByGCD(LinearConstraint *constraint)
constexpr IntegerValue kMaxIntegerValue(std::numeric_limits< IntegerValue::ValueType >::max() - 1)
IntType IntTypeAbs(IntType t)
double ComputeL2Norm(const LinearConstraint &ct)
Returns sqrt(sum square(coeff)).
IntegerValue CeilRatio(IntegerValue dividend, IntegerValue positive_divisor)
IntegerValue ComputeInfinityNorm(const LinearConstraint &ct)
Returns the maximum absolute value of the coefficients.
std::vector< IntegerVariable > NegationOf(absl::Span< const IntegerVariable > vars)
Returns the vector of the negated variables.
bool PossibleOverflow(const IntegerTrail &integer_trail, const LinearConstraint &constraint)
PositiveOnlyIndex GetPositiveOnlyIndex(IntegerVariable var)
void MakeAllVariablesPositive(LinearConstraint *constraint)
Makes all variables "positive" by transforming a variable to its negation.
bool NoDuplicateVariable(const LinearConstraint &ct)
Returns false if duplicate variables are found in ct.
bool VariableIsPositive(IntegerVariable i)
double ToDouble(IntegerValue value)
double ScalarProduct(const LinearConstraint &ct1, const LinearConstraint &ct2)
In SWIG mode, we don't want anything besides these top-level includes.
bool AtMinOrMaxInt64(int64_t x)
Checks if x is equal to the min or the max value of an int64_t.
int64_t CapSub(int64_t x, int64_t y)
int64_t CapProd(int64_t x, int64_t y)
uint64_t Hash(uint64_t num, uint64_t c)
VariableStatusRow statuses
LinearConstraint constraint
std::unique_ptr< IntegerValue[]> coeffs
std::unique_ptr< IntegerVariable[]> vars
std::string DebugString() const
absl::Span< const IntegerVariable > VarsAsSpan() const