414 const std::function<
void()>& feasible_solution_observer) {
415 if (!sat_solver_->ResetToLevelZero()) {
416 return sat_solver_->UnsatStatus();
438 const int kMaxNumInitialRestarts = 10;
439 const int64_t kNumDecisionsBeforeInitialRestarts = 1000;
443 watcher_->SetStopPropagationCallback([
this] {
444 return integer_trail_->LowerBound(objective_var_) > current_objective_lb_;
447 while (!time_limit_->LimitReached() && !shared_response_->ProblemIsSolved()) {
448 VLOG(2) <<
"LOOP " << sat_solver_->CurrentDecisionLevel();
460 const IntegerValue obj_diff =
461 integer_trail_->LowerBound(objective_var_) -
462 integer_trail_->LevelZeroLowerBound(objective_var_);
464 std::vector<Literal> reason =
466 objective_var_, integer_trail_->LowerBound(objective_var_)));
469 pseudo_costs_->UpdateBoolPseudoCosts(reason, obj_diff);
470 sat_decision_->BumpVariableActivities(reason);
471 sat_decision_->UpdateVariableActivityIncrement();
475 if (!current_branch_.empty()) {
479 const int current_level = sat_solver_->CurrentDecisionLevel();
480 const IntegerValue current_objective_lb =
481 integer_trail_->LowerBound(objective_var_);
483 CHECK_LE(current_level, current_branch_.size());
484 for (
int i = 0;
i < current_level; ++
i) {
485 CHECK(!nodes_[current_branch_[
i]].is_deleted);
486 CHECK(assignment_.LiteralIsAssigned(
487 nodes_[current_branch_[
i]].Decision()));
490 if (current_level < current_branch_.size()) {
491 nodes_[current_branch_[current_level]].UpdateObjective(
492 current_objective_lb);
503 if (current_objective_lb >
504 integer_trail_->LevelZeroLowerBound(objective_var_)) {
505 const std::vector<Literal> reason =
507 objective_var_, current_objective_lb));
509 for (
const Literal l : reason) {
510 max_level = std::max<int>(
512 sat_solver_->LiteralTrail().Info(l.Variable()).level);
514 if (max_level < current_level) {
515 nodes_[current_branch_[max_level]].UpdateObjective(
516 current_objective_lb);
522 for (
int level = current_branch_.size(); --level > 0;) {
523 UpdateParentObjective(level);
527 if (SaveLpBasisOption()) {
531 lp_constraint_->EnablePropagation(
false);
533 if (sat_solver_->ModelIsUnsat())
return sat_solver_->UnsatStatus();
537 if (!search_helper_->BeforeTakingDecision()) {
538 return sat_solver_->UnsatStatus();
544 current_objective_lb_ = shared_response_->GetInnerObjectiveLowerBound();
545 if (!current_branch_.empty()) {
546 nodes_[current_branch_[0]].UpdateObjective(current_objective_lb_);
547 for (
int i = 1;
i < current_branch_.size(); ++
i) {
548 UpdateObjectiveFromParent(
i);
552 const IntegerValue bound = nodes_[current_branch_[0]].MinObjective();
553 if (bound > current_objective_lb_) {
554 shared_response_->UpdateInnerObjectiveBounds(
555 absl::StrCat(name_,
" (", SmallProgressString(),
") "), bound,
556 integer_trail_->LevelZeroUpperBound(objective_var_));
557 current_objective_lb_ = bound;
558 if (VLOG_IS_ON(3)) DebugDisplayTree(current_branch_[0]);
566 if (num_decisions_taken_ >= num_decisions_taken_at_last_restart_ +
567 kNumDecisionsBeforeInitialRestarts &&
568 num_full_restarts_ < kMaxNumInitialRestarts) {
569 VLOG(2) <<
"lb_tree_search (initial_restart " << SmallProgressString()
571 if (!FullRestart())
return sat_solver_->UnsatStatus();
576 if (num_decisions_taken_ >=
577 num_decisions_taken_at_last_level_zero_ + 10000) {
578 if (!sat_solver_->ResetToLevelZero()) {
579 return sat_solver_->UnsatStatus();
591 while (current_branch_.size() > sat_solver_->CurrentDecisionLevel() + 1 ||
592 (current_branch_.size() > 1 &&
593 nodes_[current_branch_.back()].MinObjective() >
594 current_objective_lb_)) {
595 current_branch_.pop_back();
600 const int backtrack_level =
601 std::max(0,
static_cast<int>(current_branch_.size()) - 1);
602 sat_solver_->Backtrack(backtrack_level);
603 if (!sat_solver_->FinishPropagation()) {
604 return sat_solver_->UnsatStatus();
606 if (sat_solver_->CurrentDecisionLevel() < backtrack_level) {
611 if (sat_solver_->CurrentDecisionLevel() == 0) {
612 if (!LevelZeroLogic()) {
613 return sat_solver_->UnsatStatus();
624 const int size = current_branch_.size();
625 const int level = sat_solver_->CurrentDecisionLevel();
631 DCHECK(size == level || size == level + 1);
632 if (size == level)
break;
634 const NodeIndex node_index = current_branch_[level];
635 Node& node = nodes_[node_index];
636 DCHECK_GT(node.true_child, node_index);
637 DCHECK_GT(node.false_child, node_index);
640 node.UpdateObjective(std::max(
641 current_objective_lb_, integer_trail_->LowerBound(objective_var_)));
642 if (node.MinObjective() > current_objective_lb_)
break;
643 DCHECK_EQ(node.MinObjective(), current_objective_lb_) << level;
647 DCHECK(!node.is_deleted);
648 const Literal node_literal = node.Decision();
652 if (assignment_.LiteralIsAssigned(node_literal)) {
654 if (assignment_.LiteralIsTrue(node_literal)) {
656 new_lb = node.true_objective;
658 n = node.false_child;
659 new_lb = node.false_objective;
661 MarkAsDeletedNodeAndUnreachableSubtree(node);
665 current_branch_.pop_back();
666 if (!current_branch_.empty()) {
667 const NodeIndex parent = current_branch_.back();
668 DCHECK(!nodes_[parent].is_deleted);
669 const Literal parent_literal = nodes_[parent].Decision();
670 if (assignment_.LiteralIsTrue(parent_literal)) {
671 nodes_[parent].true_child = n;
672 nodes_[parent].UpdateTrueObjective(new_lb);
674 DCHECK(assignment_.LiteralIsFalse(parent_literal));
675 nodes_[parent].false_child = n;
676 nodes_[parent].UpdateFalseObjective(new_lb);
678 if (new_lb > current_objective_lb_) {
680 if (n < nodes_.size() && !nodes_[n].IsLeaf()) {
681 current_branch_.push_back(n);
682 nodes_[n].UpdateObjective(new_lb);
687 if (n >= nodes_.size()) {
690 num_nodes_in_tree_ = 0;
692 }
else if (nodes_[n].IsLeaf()) {
694 num_nodes_in_tree_ = 1;
695 Node root = std::move(nodes_[n]);
697 nodes_.push_back(std::move(root));
707 ExploitReducedCosts(current_branch_[level]);
708 if (node.MinObjective() > current_objective_lb_)
break;
714 num_decisions_taken_++;
715 const bool choose_true = node.true_objective <= node.false_objective;
719 next_decision = node_literal;
721 n = node.false_child;
722 next_decision = node_literal.
Negated();
731 if (SaveLpBasisOption() &&
732 (n >= nodes_.size() || !NodeHasBasis(node))) {
734 absl::MakeCleanup(UpdateLpIters(&num_lp_iters_save_basis_));
737 EnableLpAndLoadBestBasis();
738 const int level = sat_solver_->CurrentDecisionLevel();
739 if (!sat_solver_->FinishPropagation()) {
740 return sat_solver_->UnsatStatus();
742 if (sat_solver_->CurrentDecisionLevel() < level) {
748 if (assignment_.LiteralIsAssigned(next_decision)) {
752 SaveLpBasisInto(node);
755 if (n < nodes_.size()) {
756 lp_constraint_->EnablePropagation(
false);
762 absl::MakeCleanup(UpdateLpIters(&num_lp_iters_first_branch_));
763 DCHECK(!assignment_.LiteralIsAssigned(next_decision));
764 search_helper_->TakeDecision(next_decision);
767 if (current_branch_.size() != sat_solver_->CurrentDecisionLevel()) {
768 MarkBranchAsInfeasible(node, choose_true);
774 const IntegerValue lb = integer_trail_->LowerBound(objective_var_);
776 node.UpdateTrueObjective(lb);
778 node.UpdateFalseObjective(lb);
781 if (n < nodes_.size()) {
782 nodes_[n].UpdateObjective(lb);
783 }
else if (SaveLpBasisOption()) {
784 SaveLpBasisInto(nodes_[CreateNewEmptyNodeIfNeeded()]);
787 if (lb > current_objective_lb_)
break;
791 shared_response_->LogMessageWithThrottling(
792 "TreeS", absl::StrCat(
" (", SmallProgressString(),
")"));
795 if (n < nodes_.size() && !nodes_[n].IsLeaf()) {
796 current_branch_.push_back(n);
803 if (current_branch_.size() != sat_solver_->CurrentDecisionLevel()) {
809 if (!current_branch_.empty()) {
810 const Node& final_node = nodes_[current_branch_.back()];
811 if (assignment_.LiteralIsTrue(final_node.Decision())) {
812 if (final_node.true_objective > current_objective_lb_) {
816 DCHECK(assignment_.LiteralIsFalse(final_node.Decision()));
817 if (final_node.false_objective > current_objective_lb_) {
836 if (integer_trail_->LowerBound(objective_var_) > current_objective_lb_) {
840 const auto cleanup = absl::MakeCleanup(UpdateLpIters(&num_lp_iters_dive_));
842 if (current_branch_.empty()) {
843 VLOG(2) <<
"DIVE from empty tree";
845 VLOG(2) <<
"DIVE from " << NodeDebugString(current_branch_.back());
848 if (SaveLpBasisOption() && !lp_constraint_->PropagationIsEnabled()) {
850 const NodeIndex index = CreateNewEmptyNodeIfNeeded();
852 EnableLpAndLoadBestBasis();
853 const int level = sat_solver_->CurrentDecisionLevel();
854 if (!sat_solver_->FinishPropagation()) {
855 return sat_solver_->UnsatStatus();
859 if (sat_solver_->CurrentDecisionLevel() < level) {
860 Node& node = nodes_[index];
865 SaveLpBasisInto(nodes_[index]);
867 const IntegerValue obj_lb = integer_trail_->LowerBound(objective_var_);
868 if (obj_lb > current_objective_lb_) {
869 nodes_[index].UpdateObjective(obj_lb);
870 if (!current_branch_.empty()) {
871 Node& parent_node = nodes_[current_branch_.back()];
872 const Literal node_literal = parent_node.Decision();
873 DCHECK(assignment_.LiteralIsAssigned(node_literal));
874 if (assignment_.LiteralIsTrue(node_literal)) {
875 parent_node.UpdateTrueObjective(obj_lb);
877 parent_node.UpdateFalseObjective(obj_lb);
886 const int base_level = sat_solver_->CurrentDecisionLevel();
888 CHECK_EQ(base_level, current_branch_.size());
889 for (
const NodeIndex index : current_branch_) {
890 CHECK(!nodes_[index].is_deleted);
891 const Literal decision = nodes_[index].Decision();
892 if (assignment_.LiteralIsTrue(decision)) {
893 CHECK_EQ(nodes_[index].true_objective, current_objective_lb_);
895 CHECK(assignment_.LiteralIsFalse(decision));
896 CHECK_EQ(nodes_[index].false_objective, current_objective_lb_);
913 if (sat_solver_->ModelIsUnsat())
return sat_solver_->UnsatStatus();
914 LiteralIndex decision;
915 if (!search_helper_->GetDecision(search_heuristic_, &decision)) {
922 feasible_solution_observer();
926 num_decisions_taken_++;
927 if (!search_helper_->TakeDecision(
Literal(decision))) {
928 return sat_solver_->UnsatStatus();
930 if (trail_->CurrentDecisionLevel() < base_level) {
937 if (integer_trail_->LowerBound(objective_var_) > current_objective_lb_) {
942 if (trail_->CurrentDecisionLevel() <= base_level) {
950 const std::vector<Literal> reason =
952 objective_var_, integer_trail_->LowerBound(objective_var_)));
953 std::vector<Literal> decisions = ExtractDecisions(base_level, reason);
956 sat_decision_->BumpVariableActivities(reason);
957 sat_decision_->BumpVariableActivities(decisions);
958 sat_decision_->UpdateVariableActivityIncrement();
961 DCHECK_EQ(current_branch_.size(), base_level);
962 for (
const Literal d : decisions) {
963 AppendNewNodeToCurrentBranch(d);
967 if (SaveLpBasisOption() && decisions.size() == 1) {
968 SaveLpBasisInto(nodes_[CreateNewEmptyNodeIfNeeded()]);
973 if (!current_branch_.empty()) {
974 Node& n = nodes_[current_branch_.back()];
975 if (assignment_.LiteralIsTrue(n.Decision())) {
976 n.UpdateTrueObjective(integer_trail_->LowerBound(objective_var_));
978 n.UpdateFalseObjective(integer_trail_->LowerBound(objective_var_));
987 int backtrack_level = base_level;
988 DCHECK_LE(current_branch_.size(), trail_->CurrentDecisionLevel());
989 while (backtrack_level < current_branch_.size() &&
990 trail_->Decisions()[backtrack_level].literal.Index() ==
991 nodes_[current_branch_[backtrack_level]].literal_index) {
994 sat_solver_->BacktrackAndPropagateReimplications(backtrack_level);
1002 for (
int i = backtrack_level;
i < current_branch_.size(); ++
i) {
1003 ExploitReducedCosts(current_branch_[
i]);