Skip to content

Commit d61898d

Browse files
committed
[CP-SAT] fix rare crash
1 parent 577a152 commit d61898d

File tree

8 files changed

+38
-41
lines changed

8 files changed

+38
-41
lines changed

ortools/sat/clause.cc

Lines changed: 30 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -244,21 +244,25 @@ bool ClauseManager::Propagate(Trail* trail) {
244244
}
245245
}
246246

247-
reasons_[trail->Index()] = it->clause;
248-
if (propagation_level == 0 && lrat_proof_handler_ != nullptr) {
249-
const ClauseId clause_id = GetClauseId(it->clause);
250-
const int size = it->clause->size();
251-
std::vector<ClauseId>& unit_ids = clause_ids_scratchpad_;
252-
unit_ids.clear();
253-
for (int i = 1; i < size; ++i) {
254-
unit_ids.push_back(trail_->GetUnitClauseId(literals[i].Variable()));
247+
if (propagation_level == 0) {
248+
if (lrat_proof_handler_ != nullptr) {
249+
std::vector<ClauseId>& unit_ids = clause_ids_scratchpad_;
250+
unit_ids.clear();
251+
const int size = it->clause->size();
252+
for (int i = 1; i < size; ++i) {
253+
unit_ids.push_back(
254+
trail_->GetUnitClauseId(literals[i].Variable()));
255+
}
256+
unit_ids.push_back(GetClauseId(it->clause));
257+
const ClauseId new_clause_id = clause_id_generator_->GetNextId();
258+
lrat_proof_handler_->AddInferredClause(
259+
new_clause_id, {other_watched_literal}, unit_ids);
260+
helper.EnqueueWithUnitReason(other_watched_literal, new_clause_id);
261+
} else {
262+
trail_->EnqueueWithUnitReason(other_watched_literal);
255263
}
256-
unit_ids.push_back(clause_id);
257-
const ClauseId new_clause_id = clause_id_generator_->GetNextId();
258-
lrat_proof_handler_->AddInferredClause(
259-
new_clause_id, {other_watched_literal}, unit_ids);
260-
helper.EnqueueWithUnitReason(other_watched_literal, new_clause_id);
261264
} else {
265+
reasons_[trail->Index()] = it->clause;
262266
helper.EnqueueAtLevel(other_watched_literal, propagation_level);
263267
}
264268
*new_it++ = *it;
@@ -296,6 +300,7 @@ SatClause* ClauseManager::ReasonClauseOrNull(BooleanVariable var) const {
296300
if (!trail_->Assignment().VariableIsAssigned(var)) return nullptr;
297301
if (trail_->AssignmentType(var) != propagator_id_) return nullptr;
298302
SatClause* result = reasons_[trail_->Info(var).trail_index];
303+
DCHECK(result != nullptr) << trail_->Info(var).DebugString();
299304

300305
// Tricky: In some corner case, that clause was subsumed, so we don't want
301306
// to check it nor use it.
@@ -306,6 +311,7 @@ SatClause* ClauseManager::ReasonClauseOrNull(BooleanVariable var) const {
306311

307312
bool ClauseManager::ClauseIsUsedAsReason(SatClause* clause) const {
308313
DCHECK(clause != nullptr);
314+
if (clause->empty()) return false;
309315
return clause == ReasonClauseOrNull(clause->PropagatedLiteral().Variable());
310316
}
311317

@@ -642,13 +648,24 @@ void ClauseManager::CleanUpWatchers() {
642648
void ClauseManager::DeleteRemovedClauses() {
643649
if (!is_clean_) CleanUpWatchers();
644650

651+
if (DEBUG_MODE) {
652+
// This help debug issues, as it is easier to check for nullptr rather than
653+
// detect a pointer that has been deleted.
654+
for (int i = 0; i < reasons_.size(); ++i) {
655+
if (reasons_[i] != nullptr && reasons_[i]->empty()) {
656+
reasons_[i] = nullptr;
657+
}
658+
}
659+
}
660+
645661
int new_size = 0;
646662
const int old_size = clauses_.size();
647663
for (int i = 0; i < old_size; ++i) {
648664
if (i == to_minimize_index_) to_minimize_index_ = new_size;
649665
if (i == to_first_minimize_index_) to_first_minimize_index_ = new_size;
650666
if (i == to_probe_index_) to_probe_index_ = new_size;
651667
if (clauses_[i]->IsRemoved()) {
668+
DCHECK(!clauses_info_.contains(clauses_[i]));
652669
delete clauses_[i];
653670
} else {
654671
clauses_[new_size++] = clauses_[i];

ortools/sat/clause.h

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -313,6 +313,7 @@ class ClauseManager : public SatPropagator {
313313
// start so the clauses will be returned in round-robin order.
314314
// Note that we only minimize clauses kept forever.
315315
SatClause* NextClauseToMinimize();
316+
316317
// Returns the next clause to probe in round-robin order.
317318
SatClause* NextClauseToProbe();
318319

ortools/sat/linear_constraint.cc

Lines changed: 0 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -296,17 +296,6 @@ void DivideByGCD(LinearConstraint* constraint) {
296296
}
297297
}
298298

299-
void MakeAllCoefficientsPositive(LinearConstraint* constraint) {
300-
const int size = constraint->num_terms;
301-
for (int i = 0; i < size; ++i) {
302-
const IntegerValue coeff = constraint->coeffs[i];
303-
if (coeff < 0) {
304-
constraint->coeffs[i] = -coeff;
305-
constraint->vars[i] = NegationOf(constraint->vars[i]);
306-
}
307-
}
308-
}
309-
310299
void MakeAllVariablesPositive(LinearConstraint* constraint) {
311300
const int size = constraint->num_terms;
312301
for (int i = 0; i < size; ++i) {

ortools/sat/linear_constraint.h

Lines changed: 0 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -350,9 +350,6 @@ double ScalarProduct(const LinearConstraint& constraint1,
350350
// also tighten the constraint bounds assuming all the variables are integer.
351351
void DivideByGCD(LinearConstraint* constraint);
352352

353-
// Makes all coefficients positive by transforming a variable to its negation.
354-
void MakeAllCoefficientsPositive(LinearConstraint* constraint);
355-
356353
// Makes all variables "positive" by transforming a variable to its negation.
357354
void MakeAllVariablesPositive(LinearConstraint* constraint);
358355

ortools/sat/linear_constraint_test.cc

Lines changed: 0 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -181,14 +181,6 @@ TEST(LinearConstraintCopyTest, BasicBehavior) {
181181
EXPECT_EQ(ct, other);
182182
}
183183

184-
TEST(MakeAllCoefficientsPositiveTest, BasicBehavior) {
185-
// Note that this relies on the fact that the negation of an IntegerVariable
186-
// var is is the one with IntegerVariable(var.value() ^ 1);
187-
LinearConstraint ct = CreateUbConstraintForTest({-2, 0, -7, 0}, 10);
188-
MakeAllCoefficientsPositive(&ct);
189-
EXPECT_EQ(ct, CreateUbConstraintForTest({0, 2, 0, 7}, 10));
190-
}
191-
192184
TEST(LinearConstraintBuilderTest, DuplicateCoefficient) {
193185
Model model;
194186
model.GetOrCreate<IntegerEncoder>();

ortools/sat/linear_programming_constraint.cc

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -218,8 +218,8 @@ LinearConstraint ScatteredIntegerVector::ConvertToLinearConstraint(
218218
result.ub = upper_bound;
219219

220220
if (extra_term != std::nullopt) {
221-
result.vars[new_size] += extra_term->first;
222-
result.coeffs[new_size] += extra_term->second;
221+
result.vars[new_size] = extra_term->first;
222+
result.coeffs[new_size] = extra_term->second;
223223
++new_size;
224224
}
225225

ortools/sat/sat_inprocessing.cc

Lines changed: 4 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -1487,10 +1487,9 @@ bool BoundedVariableElimination::DoOneRound(bool log_info) {
14871487
DCHECK(
14881488
std::all_of(marked_.begin(), marked_.end(), [](bool b) { return !b; }));
14891489

1490-
// TODO(user): add a local dtime limit for the corner case where this take too
1491-
// much time. We can adapt the limit depending on how much we want to spend on
1490+
// TODO(user): adapt the dtime limit depending on how much we want to spend on
14921491
// inprocessing.
1493-
while (!time_limit_->LimitReached() && !queue_.IsEmpty()) {
1492+
while (!time_limit_->LimitReached() && !queue_.IsEmpty() && dtime_ < 10.0) {
14941493
const BooleanVariable top = queue_.Top().var;
14951494
queue_.Pop();
14961495

@@ -1538,7 +1537,6 @@ bool BoundedVariableElimination::DoOneRound(bool log_info) {
15381537
literal_to_clauses_.clear();
15391538
literal_to_num_clauses_.clear();
15401539

1541-
dtime_ += 1e-8 * num_inspected_literals_;
15421540
time_limit_->AdvanceDeterministicTime(dtime_);
15431541
log_info |= VLOG_IS_ON(2);
15441542
LOG_IF(INFO, log_info) << "BVE."
@@ -1885,10 +1883,12 @@ bool BoundedVariableElimination::CrossProduct(BooleanVariable var) {
18851883
for (const ClauseIndex i : literal_to_clauses_[lit]) {
18861884
const auto c = clauses_[i]->AsSpan();
18871885
if (!c.empty()) score += clause_weight + c.size();
1886+
dtime_ += 1e-8 * c.size();
18881887
}
18891888
for (const ClauseIndex i : literal_to_clauses_[not_lit]) {
18901889
const auto c = clauses_[i]->AsSpan();
18911890
if (!c.empty()) score += clause_weight + c.size();
1891+
dtime_ += 1.0e-8 * c.size();
18921892
}
18931893

18941894
// Compute the new score after BVE.

ortools/sat/sat_solver.cc

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -3030,6 +3030,7 @@ void SatSolver::CleanClauseDatabaseIfNeeded() {
30303030
std::vector<Entry> entries;
30313031
auto& clauses_info = *(clauses_propagator_->mutable_clauses_info());
30323032
for (auto& entry : clauses_info) {
3033+
DCHECK(!entry.first->empty()); // Should have been deleted !
30333034
entry.second.num_cleanup_rounds_since_last_bumped++;
30343035
if (clauses_propagator_->ClauseIsUsedAsReason(entry.first)) continue;
30353036

0 commit comments

Comments
 (0)