1 /*++ 2 Copyright (c) 2011 Microsoft Corporation 3 4 Module Name: 5 6 sat_solver.cpp 7 8 Abstract: 9 10 SAT solver main class. 11 12 Author: 13 14 Leonardo de Moura (leonardo) 2011-05-21. 15 16 Revision History: 17 18 --*/ 19 20 21 #include <cmath> 22 #ifndef SINGLE_THREAD 23 #include <thread> 24 #endif 25 #include "util/luby.h" 26 #include "util/trace.h" 27 #include "util/max_cliques.h" 28 #include "util/gparams.h" 29 #include "sat/sat_solver.h" 30 #include "sat/sat_integrity_checker.h" 31 #include "sat/sat_lookahead.h" 32 #include "sat/sat_ddfw.h" 33 #include "sat/sat_prob.h" 34 #include "sat/sat_anf_simplifier.h" 35 #include "sat/sat_cut_simplifier.h" 36 #if defined(_MSC_VER) && !defined(_M_ARM) && !defined(_M_ARM64) 37 # include <xmmintrin.h> 38 #endif 39 40 #define ENABLE_TERNARY true 41 42 namespace sat { 43 44 solver(params_ref const & p,reslimit & l)45 solver::solver(params_ref const & p, reslimit& l): 46 solver_core(l), 47 m_checkpoint_enabled(true), 48 m_config(p), 49 m_par(nullptr), 50 m_drat(*this), 51 m_cls_allocator_idx(false), 52 m_cleaner(*this), 53 m_simplifier(*this, p), 54 m_scc(*this, p), 55 m_asymm_branch(*this, p), 56 m_probing(*this, p), 57 m_mus(*this), 58 m_binspr(*this), 59 m_inconsistent(false), 60 m_searching(false), 61 m_conflict(justification(0)), 62 m_num_frozen(0), 63 m_activity_inc(128), 64 m_case_split_queue(m_activity), 65 m_qhead(0), 66 m_scope_lvl(0), 67 m_search_lvl(0), 68 m_fast_glue_avg(), 69 m_slow_glue_avg(), 70 m_fast_glue_backup(), 71 m_slow_glue_backup(), 72 m_trail_avg(), 73 m_params(p), 74 m_par_id(0), 75 m_par_syncing_clauses(false) { 76 init_reason_unknown(); 77 updt_params(p); 78 m_best_phase_size = 0; 79 m_conflicts_since_gc = 0; 80 m_conflicts_since_init = 0; 81 m_next_simplify = 0; 82 m_num_checkpoints = 0; 83 m_simplifications = 0; 84 m_touch_index = 0; 85 m_ext = nullptr; 86 m_cuber = nullptr; 87 m_local_search = nullptr; 88 m_mc.set_solver(this); 89 mk_var(false, false); 90 } 91 ~solver()92 solver::~solver() { 93 m_ext = nullptr; 94 SASSERT(m_config.m_num_threads > 1 || check_invariant()); 95 CTRACE("sat", !m_clauses.empty(), tout << "Delete clauses\n";); 96 del_clauses(m_clauses); 97 CTRACE("sat", !m_learned.empty(), tout << "Delete learned\n";); 98 del_clauses(m_learned); 99 dealloc(m_cuber); 100 m_cuber = nullptr; 101 } 102 del_clauses(clause_vector & clauses)103 void solver::del_clauses(clause_vector& clauses) { 104 for (clause * cp : clauses) 105 dealloc_clause(cp); 106 clauses.reset(); 107 ++m_stats.m_non_learned_generation; 108 } 109 set_extension(extension * ext)110 void solver::set_extension(extension* ext) { 111 m_ext = ext; 112 if (ext) { 113 ext->set_solver(this); 114 for (unsigned i = num_user_scopes(); i-- > 0;) 115 ext->user_push(); 116 for (unsigned i = num_scopes(); i-- > 0;) 117 ext->push(); 118 } 119 } 120 copy(solver const & src,bool copy_learned)121 void solver::copy(solver const & src, bool copy_learned) { 122 pop_to_base_level(); 123 del_clauses(m_clauses); 124 del_clauses(m_learned); 125 m_watches.reset(); 126 m_assignment.reset(); 127 m_justification.reset(); 128 m_decision.reset(); 129 m_eliminated.reset(); 130 m_external.reset(); 131 m_var_scope.reset(); 132 m_activity.reset(); 133 m_mark.reset(); 134 m_lit_mark.reset(); 135 m_best_phase.reset(); 136 m_phase.reset(); 137 m_prev_phase.reset(); 138 m_assigned_since_gc.reset(); 139 m_last_conflict.reset(); 140 m_last_propagation.reset(); 141 m_participated.reset(); 142 m_canceled.reset(); 143 m_reasoned.reset(); 144 m_case_split_queue.reset(); 145 m_simplifier.reset_todos(); 146 m_qhead = 0; 147 m_trail.reset(); 148 m_scopes.reset(); 149 mk_var(false, false); 150 151 if (src.inconsistent()) { 152 set_conflict(); 153 return; 154 } 155 156 // create new vars 157 for (bool_var v = num_vars(); v < src.num_vars(); v++) { 158 bool ext = src.m_external[v]; 159 bool dvar = src.m_decision[v]; 160 VERIFY(v == mk_var(ext, dvar)); 161 if (src.was_eliminated(v)) { 162 set_eliminated(v, true); 163 } 164 m_phase[v] = src.m_phase[v]; 165 m_best_phase[v] = src.m_best_phase[v]; 166 m_prev_phase[v] = src.m_prev_phase[v]; 167 168 // inherit activity: 169 m_activity[v] = src.m_activity[v]; 170 m_case_split_queue.activity_changed_eh(v, false); 171 } 172 173 // 174 // register the extension before performing assignments. 175 // the assignments may call back into the extension. 176 // 177 if (src.get_extension()) { 178 m_ext = src.get_extension()->copy(this); 179 } 180 181 unsigned trail_sz = src.init_trail_size(); 182 for (unsigned i = 0; i < trail_sz; ++i) { 183 assign_unit(src.m_trail[i]); 184 } 185 186 // copy binary clauses 187 { 188 unsigned sz = src.m_watches.size(); 189 for (unsigned l_idx = 0; l_idx < sz; ++l_idx) { 190 literal l = ~to_literal(l_idx); 191 if (src.was_eliminated(l.var())) continue; 192 watch_list const & wlist = src.m_watches[l_idx]; 193 for (auto & wi : wlist) { 194 if (!wi.is_binary_clause()) 195 continue; 196 literal l2 = wi.get_literal(); 197 if (l.index() > l2.index() || 198 src.was_eliminated(l2.var())) 199 continue; 200 201 watched w1(l2, wi.is_learned()); 202 watched w2(l, wi.is_learned()); 203 m_watches[(~l).index()].push_back(w1); 204 m_watches[(~l2).index()].push_back(w2); 205 } 206 } 207 } 208 209 { 210 literal_vector buffer; 211 // copy clauses 212 for (clause* c : src.m_clauses) { 213 buffer.reset(); 214 for (literal l : *c) buffer.push_back(l); 215 mk_clause_core(buffer); 216 } 217 218 // copy high quality lemmas 219 unsigned num_learned = 0; 220 for (clause* c : src.m_learned) { 221 if (c->glue() <= 2 || (c->size() <= 40 && c->glue() <= 8) || copy_learned) { 222 buffer.reset(); 223 for (literal l : *c) buffer.push_back(l); 224 clause* c1 = mk_clause_core(buffer.size(), buffer.data(), sat::status::redundant()); 225 if (c1) { 226 ++num_learned; 227 c1->set_glue(c->glue()); 228 c1->set_psm(c->psm()); 229 } 230 } 231 } 232 IF_VERBOSE(2, verbose_stream() << "(sat.copy :learned " << num_learned << ")\n";); 233 } 234 m_best_phase_size = src.m_best_phase_size; 235 if (m_best_phase_size > 0) { 236 for (bool_var v = 0; v < num_vars(); ++v) { 237 m_best_phase[v] = src.m_best_phase[v]; 238 } 239 } 240 241 m_user_scope_literals.reset(); 242 m_user_scope_literals.append(src.m_user_scope_literals); 243 244 m_mc = src.m_mc; 245 m_stats.m_units = init_trail_size(); 246 } 247 248 // ----------------------- 249 // 250 // Variable & Clause creation 251 // 252 // ----------------------- 253 reset_var(bool_var v,bool ext,bool dvar)254 void solver::reset_var(bool_var v, bool ext, bool dvar) { 255 m_watches[2*v].reset(); 256 m_watches[2*v+1].reset(); 257 m_assignment[2*v] = l_undef; 258 m_assignment[2*v+1] = l_undef; 259 m_justification[v] = justification(UINT_MAX); 260 m_decision[v] = dvar; 261 m_eliminated[v] = false; 262 m_external[v] = ext; 263 m_var_scope[v] = scope_lvl(); 264 m_touched[v] = 0; 265 m_activity[v] = 0; 266 m_mark[v] = false; 267 m_lit_mark[2*v] = false; 268 m_lit_mark[2*v+1] = false; 269 m_phase[v] = false; 270 m_best_phase[v] = false; 271 m_prev_phase[v] = false; 272 m_assigned_since_gc[v] = false; 273 m_last_conflict[v] = 0; 274 m_last_propagation[v] = 0; 275 m_participated[v] = 0; 276 m_canceled[v] = 0; 277 m_reasoned[v] = 0; 278 m_case_split_queue.mk_var_eh(v); 279 m_simplifier.insert_elim_todo(v); 280 } 281 mk_var(bool ext,bool dvar)282 bool_var solver::mk_var(bool ext, bool dvar) { 283 m_model_is_current = false; 284 m_stats.m_mk_var++; 285 bool_var v = m_justification.size(); 286 if (!m_free_vars.empty()) { 287 v = m_free_vars.back(); 288 m_free_vars.pop_back(); 289 m_active_vars.push_back(v); 290 reset_var(v, ext, dvar); 291 return v; 292 } 293 m_active_vars.push_back(v); 294 m_watches.push_back(watch_list()); 295 m_watches.push_back(watch_list()); 296 m_assignment.push_back(l_undef); 297 m_assignment.push_back(l_undef); 298 m_justification.push_back(justification(UINT_MAX)); 299 m_decision.push_back(dvar); 300 m_eliminated.push_back(false); 301 m_external.push_back(ext); 302 m_var_scope.push_back(scope_lvl()); 303 m_touched.push_back(0); 304 m_activity.push_back(0); 305 m_mark.push_back(false); 306 m_lit_mark.push_back(false); 307 m_lit_mark.push_back(false); 308 m_phase.push_back(false); 309 m_best_phase.push_back(false); 310 m_prev_phase.push_back(false); 311 m_assigned_since_gc.push_back(false); 312 m_last_conflict.push_back(0); 313 m_last_propagation.push_back(0); 314 m_participated.push_back(0); 315 m_canceled.push_back(0); 316 m_reasoned.push_back(0); 317 m_case_split_queue.mk_var_eh(v); 318 m_simplifier.insert_elim_todo(v); 319 SASSERT(!was_eliminated(v)); 320 return v; 321 } 322 set_non_external(bool_var v)323 void solver::set_non_external(bool_var v) { 324 m_external[v] = false; 325 } 326 set_external(bool_var v)327 void solver::set_external(bool_var v) { 328 m_external[v] = true; 329 } 330 set_eliminated(bool_var v,bool f)331 void solver::set_eliminated(bool_var v, bool f) { 332 if (m_eliminated[v] == f) 333 return; 334 if (!f) 335 reset_var(v, m_external[v], m_decision[v]); 336 else if (f && m_ext) 337 m_ext->set_eliminated(v); 338 m_eliminated[v] = f; 339 } 340 341 mk_clause(unsigned num_lits,literal * lits,sat::status st)342 clause* solver::mk_clause(unsigned num_lits, literal * lits, sat::status st) { 343 m_model_is_current = false; 344 345 for (unsigned i = 0; i < num_lits; i++) 346 VERIFY(!was_eliminated(lits[i])); 347 348 DEBUG_CODE({ 349 for (unsigned i = 0; i < num_lits; i++) { 350 CTRACE("sat", was_eliminated(lits[i]), tout << lits[i] << " was eliminated\n";); 351 SASSERT(!was_eliminated(lits[i])); 352 } 353 }); 354 355 if (m_user_scope_literals.empty()) { 356 return mk_clause_core(num_lits, lits, st); 357 } 358 else { 359 m_aux_literals.reset(); 360 m_aux_literals.append(num_lits, lits); 361 m_aux_literals.append(m_user_scope_literals); 362 return mk_clause_core(m_aux_literals.size(), m_aux_literals.data(), st); 363 } 364 } 365 mk_clause(literal l1,literal l2,sat::status st)366 clause* solver::mk_clause(literal l1, literal l2, sat::status st) { 367 literal ls[2] = { l1, l2 }; 368 return mk_clause(2, ls, st); 369 } 370 mk_clause(literal l1,literal l2,literal l3,sat::status st)371 clause* solver::mk_clause(literal l1, literal l2, literal l3, sat::status st) { 372 literal ls[3] = { l1, l2, l3 }; 373 return mk_clause(3, ls, st); 374 } 375 del_clause(clause & c)376 void solver::del_clause(clause& c) { 377 if (!c.is_learned()) { 378 m_stats.m_non_learned_generation++; 379 } 380 if (c.frozen()) { 381 --m_num_frozen; 382 } 383 if (!c.was_removed() && m_config.m_drat && !m_drat.is_cleaned(c)) { 384 m_drat.del(c); 385 } 386 dealloc_clause(&c); 387 if (m_searching) 388 m_stats.m_del_clause++; 389 } 390 drat_explain_conflict()391 void solver::drat_explain_conflict() { 392 if (m_config.m_drat && m_ext) { 393 extension::scoped_drating _sd(*m_ext); 394 bool unique_max; 395 m_conflict_lvl = get_max_lvl(m_not_l, m_conflict, unique_max); 396 resolve_conflict_for_unsat_core(); 397 } 398 } 399 drat_log_unit(literal lit,justification j)400 void solver::drat_log_unit(literal lit, justification j) { 401 if (!m_ext) 402 return; 403 extension::scoped_drating _sd(*m_ext.get()); 404 if (j.get_kind() == justification::EXT_JUSTIFICATION) 405 fill_ext_antecedents(lit, j, false); 406 m_drat.add(lit, m_searching); 407 } 408 drat_log_clause(unsigned num_lits,literal const * lits,sat::status st)409 void solver::drat_log_clause(unsigned num_lits, literal const* lits, sat::status st) { 410 m_drat.add(num_lits, lits, st); 411 } 412 mk_clause_core(unsigned num_lits,literal * lits,sat::status st)413 clause * solver::mk_clause_core(unsigned num_lits, literal * lits, sat::status st) { 414 bool redundant = st.is_redundant(); 415 TRACE("sat", tout << "mk_clause: " << mk_lits_pp(num_lits, lits) << (redundant?" learned":" aux") << "\n";); 416 if (!redundant || !st.is_sat()) { 417 unsigned old_sz = num_lits; 418 bool keep = simplify_clause(num_lits, lits); 419 TRACE("sat_mk_clause", tout << "mk_clause (after simp), keep: " << keep << "\n" << mk_lits_pp(num_lits, lits) << "\n";); 420 if (!keep) { 421 return nullptr; // clause is equivalent to true. 422 } 423 // if an input clause is simplified, then log the simplified version as learned 424 if (m_config.m_drat && old_sz > num_lits) 425 drat_log_clause(num_lits, lits, st); 426 427 ++m_stats.m_non_learned_generation; 428 if (!m_searching) { 429 m_mc.add_clause(num_lits, lits); 430 } 431 } 432 433 434 switch (num_lits) { 435 case 0: 436 set_conflict(); 437 return nullptr; 438 case 1: 439 if (m_config.m_drat && (!st.is_sat() || st.is_input())) 440 drat_log_clause(num_lits, lits, st); 441 assign_unit(lits[0]); 442 return nullptr; 443 case 2: 444 mk_bin_clause(lits[0], lits[1], st); 445 if (redundant && m_par) 446 m_par->share_clause(*this, lits[0], lits[1]); 447 return nullptr; 448 case 3: 449 if (ENABLE_TERNARY) 450 return mk_ter_clause(lits, st); 451 Z3_fallthrough; 452 default: 453 return mk_nary_clause(num_lits, lits, st); 454 } 455 } 456 mk_bin_clause(literal l1,literal l2,sat::status st)457 void solver::mk_bin_clause(literal l1, literal l2, sat::status st) { 458 bool redundant = st.is_redundant(); 459 m_touched[l1.var()] = m_touch_index; 460 m_touched[l2.var()] = m_touch_index; 461 462 if (redundant && find_binary_watch(get_wlist(~l1), ~l2) && value(l1) == l_undef) { 463 assign_unit(l1); 464 return; 465 } 466 if (redundant && find_binary_watch(get_wlist(~l2), ~l1) && value(l2) == l_undef) { 467 assign_unit(l2); 468 return; 469 } 470 watched* w0 = redundant ? find_binary_watch(get_wlist(~l1), l2) : nullptr; 471 if (w0) { 472 TRACE("sat", tout << "found binary " << l1 << " " << l2 << "\n";); 473 if (w0->is_learned() && !redundant) { 474 w0->set_learned(false); 475 w0 = find_binary_watch(get_wlist(~l2), l1); 476 VERIFY(w0); 477 w0->set_learned(false); 478 } 479 if (propagate_bin_clause(l1, l2) && !at_base_lvl() && !redundant) 480 push_reinit_stack(l1, l2); 481 else if (has_variables_to_reinit(l1, l2)) 482 push_reinit_stack(l1, l2); 483 return; 484 } 485 if (m_config.m_drat) 486 m_drat.add(l1, l2, st); 487 if (propagate_bin_clause(l1, l2)) { 488 if (at_base_lvl()) 489 return; 490 push_reinit_stack(l1, l2); 491 } 492 else if (has_variables_to_reinit(l1, l2)) 493 push_reinit_stack(l1, l2); 494 m_stats.m_mk_bin_clause++; 495 get_wlist(~l1).push_back(watched(l2, redundant)); 496 get_wlist(~l2).push_back(watched(l1, redundant)); 497 } 498 has_variables_to_reinit(clause const & c) const499 bool solver::has_variables_to_reinit(clause const& c) const { 500 for (auto lit : c) 501 if (m_var_scope[lit.var()] > 0) 502 return true; 503 return false; 504 } 505 has_variables_to_reinit(literal l1,literal l2) const506 bool solver::has_variables_to_reinit(literal l1, literal l2) const { 507 if (at_base_lvl()) 508 return false; 509 if (m_var_scope[l1.var()] > 0) 510 return true; 511 if (m_var_scope[l2.var()] > 0) 512 return true; 513 return false; 514 } 515 propagate_bin_clause(literal l1,literal l2)516 bool solver::propagate_bin_clause(literal l1, literal l2) { 517 if (value(l2) == l_false) { 518 m_stats.m_bin_propagate++; 519 assign(l1, justification(lvl(l2), l2)); 520 return true; 521 } 522 if (value(l1) == l_false) { 523 m_stats.m_bin_propagate++; 524 assign(l2, justification(lvl(l1), l1)); 525 return true; 526 } 527 return false; 528 } 529 push_reinit_stack(clause & c)530 void solver::push_reinit_stack(clause & c) { 531 SASSERT(!at_base_lvl()); 532 TRACE("sat_reinit", tout << "adding to reinit stack: " << c << "\n";); 533 m_clauses_to_reinit.push_back(clause_wrapper(c)); 534 c.set_reinit_stack(true); 535 } 536 push_reinit_stack(literal l1,literal l2)537 void solver::push_reinit_stack(literal l1, literal l2) { 538 TRACE("sat_reinit", tout << "adding to reinit stack: " << l1 << " " << l2 << "\n";); 539 m_clauses_to_reinit.push_back(clause_wrapper(l1, l2)); 540 } 541 mk_ter_clause(literal * lits,sat::status st)542 clause * solver::mk_ter_clause(literal * lits, sat::status st) { 543 VERIFY(ENABLE_TERNARY); 544 m_stats.m_mk_ter_clause++; 545 clause * r = alloc_clause(3, lits, st.is_redundant()); 546 bool reinit = attach_ter_clause(*r, st); 547 if (reinit || has_variables_to_reinit(*r)) push_reinit_stack(*r); 548 if (st.is_redundant()) 549 m_learned.push_back(r); 550 else 551 m_clauses.push_back(r); 552 for (literal l : *r) { 553 m_touched[l.var()] = m_touch_index; 554 } 555 return r; 556 } 557 attach_ter_clause(clause & c,sat::status st)558 bool solver::attach_ter_clause(clause & c, sat::status st) { 559 VERIFY(ENABLE_TERNARY); 560 bool reinit = false; 561 if (m_config.m_drat) m_drat.add(c, st); 562 TRACE("sat_verbose", tout << c << "\n";); 563 SASSERT(!c.was_removed()); 564 m_watches[(~c[0]).index()].push_back(watched(c[1], c[2])); 565 m_watches[(~c[1]).index()].push_back(watched(c[0], c[2])); 566 m_watches[(~c[2]).index()].push_back(watched(c[0], c[1])); 567 if (!at_base_lvl()) 568 reinit = propagate_ter_clause(c); 569 return reinit; 570 } 571 propagate_ter_clause(clause & c)572 bool solver::propagate_ter_clause(clause& c) { 573 bool reinit = false; 574 if (value(c[1]) == l_false && value(c[2]) == l_false) { 575 m_stats.m_ter_propagate++; 576 assign(c[0], justification(std::max(lvl(c[1]), lvl(c[2])), c[1], c[2])); 577 reinit = !c.is_learned(); 578 } 579 else if (value(c[0]) == l_false && value(c[2]) == l_false) { 580 m_stats.m_ter_propagate++; 581 assign(c[1], justification(std::max(lvl(c[0]), lvl(c[2])), c[0], c[2])); 582 reinit = !c.is_learned(); 583 } 584 else if (value(c[0]) == l_false && value(c[1]) == l_false) { 585 m_stats.m_ter_propagate++; 586 assign(c[2], justification(std::max(lvl(c[0]), lvl(c[1])), c[0], c[1])); 587 reinit = !c.is_learned(); 588 } 589 return reinit; 590 } 591 mk_nary_clause(unsigned num_lits,literal * lits,sat::status st)592 clause * solver::mk_nary_clause(unsigned num_lits, literal * lits, sat::status st) { 593 m_stats.m_mk_clause++; 594 clause * r = alloc_clause(num_lits, lits, st.is_redundant()); 595 SASSERT(!st.is_redundant() || r->is_learned()); 596 bool reinit = attach_nary_clause(*r, st.is_sat() && st.is_redundant()); 597 if (reinit || has_variables_to_reinit(*r)) push_reinit_stack(*r); 598 if (st.is_redundant()) { 599 m_learned.push_back(r); 600 } 601 else { 602 m_clauses.push_back(r); 603 } 604 if (m_config.m_drat) { 605 m_drat.add(*r, st); 606 } 607 for (literal l : *r) { 608 m_touched[l.var()] = m_touch_index; 609 } 610 return r; 611 } 612 attach_nary_clause(clause & c,bool is_asserting)613 bool solver::attach_nary_clause(clause & c, bool is_asserting) { 614 bool reinit = false; 615 clause_offset cls_off = cls_allocator().get_offset(&c); 616 if (!at_base_lvl()) { 617 if (is_asserting) { 618 unsigned w2_idx = select_learned_watch_lit(c); 619 std::swap(c[1], c[w2_idx]); 620 } 621 else { 622 unsigned w1_idx = select_watch_lit(c, 0); 623 std::swap(c[0], c[w1_idx]); 624 unsigned w2_idx = select_watch_lit(c, 1); 625 std::swap(c[1], c[w2_idx]); 626 } 627 628 if (value(c[0]) == l_false) { 629 m_stats.m_propagate++; 630 unsigned level = lvl(c[0]); 631 for (unsigned i = c.size(); i-- > 2; ) { 632 level = std::max(level, lvl(c[i])); 633 } 634 assign(c[1], justification(level, cls_off)); 635 reinit |= !c.is_learned(); 636 } 637 else if (value(c[1]) == l_false) { 638 m_stats.m_propagate++; 639 unsigned level = lvl(c[1]); 640 for (unsigned i = c.size(); i-- > 2; ) { 641 level = std::max(level, lvl(c[i])); 642 } 643 assign(c[0], justification(level, cls_off)); 644 reinit |= !c.is_learned(); 645 } 646 } 647 unsigned some_idx = c.size() >> 1; 648 literal block_lit = c[some_idx]; 649 VERIFY(!c.frozen()); 650 DEBUG_CODE(for (auto const& w : m_watches[(~c[0]).index()]) SASSERT(!w.is_clause() || w.get_clause_offset() != cls_off);); 651 DEBUG_CODE(for (auto const& w : m_watches[(~c[1]).index()]) SASSERT(!w.is_clause() || w.get_clause_offset() != cls_off);); 652 SASSERT(c[0] != c[1]); 653 m_watches[(~c[0]).index()].push_back(watched(block_lit, cls_off)); 654 m_watches[(~c[1]).index()].push_back(watched(block_lit, cls_off)); 655 return reinit; 656 } 657 attach_clause(clause & c,bool & reinit)658 void solver::attach_clause(clause & c, bool & reinit) { 659 SASSERT(c.size() > 2); 660 reinit = false; 661 if (ENABLE_TERNARY && c.size() == 3) 662 reinit = attach_ter_clause(c, c.is_learned() ? sat::status::redundant() : sat::status::asserted()); 663 else 664 reinit = attach_nary_clause(c, c.is_learned() && !c.on_reinit_stack()); 665 } 666 set_learned(clause & c,bool redundant)667 void solver::set_learned(clause& c, bool redundant) { 668 if (c.is_learned() != redundant) 669 c.set_learned(redundant); 670 } 671 set_learned1(literal l1,literal l2,bool redundant)672 void solver::set_learned1(literal l1, literal l2, bool redundant) { 673 for (watched& w : get_wlist(~l1)) { 674 if (w.is_binary_clause() && l2 == w.get_literal() && !w.is_learned()) { 675 w.set_learned(redundant); 676 break; 677 } 678 } 679 } 680 shrink(clause & c,unsigned old_sz,unsigned new_sz)681 void solver::shrink(clause& c, unsigned old_sz, unsigned new_sz) { 682 SASSERT(new_sz > 2); 683 SASSERT(old_sz >= new_sz); 684 if (old_sz != new_sz) { 685 c.shrink(new_sz); 686 for (literal l : c) { 687 m_touched[l.var()] = m_touch_index; 688 } 689 if (m_config.m_drat) { 690 m_drat.add(c, status::redundant()); 691 c.restore(old_sz); 692 m_drat.del(c); 693 c.shrink(new_sz); 694 } 695 } 696 } 697 memory_pressure()698 bool solver::memory_pressure() { 699 return 3*cls_allocator().get_allocation_size()/2 + memory::get_allocation_size() > memory::get_max_memory_size(); 700 } 701 702 struct solver::cmp_activity { 703 solver& s; cmp_activitysat::solver::cmp_activity704 cmp_activity(solver& s):s(s) {} operator ()sat::solver::cmp_activity705 bool operator()(bool_var v1, bool_var v2) const { 706 return s.m_activity[v1] > s.m_activity[v2]; 707 } 708 }; 709 should_defrag()710 bool solver::should_defrag() { 711 if (m_defrag_threshold > 0) --m_defrag_threshold; 712 return m_defrag_threshold == 0 && m_config.m_gc_defrag; 713 } 714 defrag_clauses()715 void solver::defrag_clauses() { 716 m_defrag_threshold = 2; 717 if (memory_pressure()) return; 718 pop(scope_lvl()); 719 IF_VERBOSE(2, verbose_stream() << "(sat-defrag)\n"); 720 clause_allocator& alloc = m_cls_allocator[!m_cls_allocator_idx]; 721 ptr_vector<clause> new_clauses, new_learned; 722 for (clause* c : m_clauses) c->unmark_used(); 723 for (clause* c : m_learned) c->unmark_used(); 724 725 svector<bool_var> vars; 726 for (unsigned i = 0; i < num_vars(); ++i) vars.push_back(i); 727 std::stable_sort(vars.begin(), vars.end(), cmp_activity(*this)); 728 literal_vector lits; 729 for (bool_var v : vars) lits.push_back(literal(v, false)), lits.push_back(literal(v, true)); 730 // walk clauses, reallocate them in an order that defragments memory and creates locality. 731 for (literal lit : lits) { 732 watch_list& wlist = m_watches[lit.index()]; 733 for (watched& w : wlist) { 734 if (w.is_clause()) { 735 clause& c1 = get_clause(w); 736 clause_offset offset; 737 if (c1.was_used()) { 738 offset = c1.get_new_offset(); 739 } 740 else { 741 clause* c2 = alloc.copy_clause(c1); 742 c1.mark_used(); 743 if (c1.is_learned()) { 744 new_learned.push_back(c2); 745 } 746 else { 747 new_clauses.push_back(c2); 748 } 749 offset = get_offset(*c2); 750 c1.set_new_offset(offset); 751 } 752 w = watched(w.get_blocked_literal(), offset); 753 } 754 } 755 } 756 757 // reallocate ternary clauses. 758 for (clause* c : m_clauses) { 759 if (!c->was_used()) { 760 SASSERT(c->size() == 3); 761 new_clauses.push_back(alloc.copy_clause(*c)); 762 } 763 dealloc_clause(c); 764 } 765 766 for (clause* c : m_learned) { 767 if (!c->was_used()) { 768 SASSERT(c->size() == 3); 769 new_learned.push_back(alloc.copy_clause(*c)); 770 } 771 dealloc_clause(c); 772 } 773 m_clauses.swap(new_clauses); 774 m_learned.swap(new_learned); 775 776 cls_allocator().finalize(); 777 m_cls_allocator_idx = !m_cls_allocator_idx; 778 779 reinit_assumptions(); 780 } 781 782 set_learned(literal l1,literal l2,bool redundant)783 void solver::set_learned(literal l1, literal l2, bool redundant) { 784 set_learned1(l1, l2, redundant); 785 set_learned1(l2, l1, redundant); 786 } 787 788 /** 789 \brief Select a watch literal starting the search at the given position. 790 This method is only used for clauses created during the search. 791 792 I use the following rules to select a watch literal. 793 794 1- select a literal l in idx >= starting_at such that value(l) = l_true, 795 and for all l' in idx' >= starting_at . value(l') = l_true implies lvl(l) <= lvl(l') 796 797 The purpose of this rule is to make the clause inactive for as long as possible. A clause 798 is inactive when it contains a literal assigned to true. 799 800 2- if there isn't a literal assigned to true, then select an unassigned literal l in idx >= starting_at 801 802 3- if there isn't a literal l in idx >= starting_at such that value(l) = l_true or 803 value(l) = l_undef (that is, all literals at positions >= starting_at are assigned 804 to false), then peek the literal l such that for all l' starting at starting_at 805 lvl(l) >= lvl(l') 806 807 Without rule 3, boolean propagation is incomplete, that is, it may miss possible propagations. 808 809 \remark The method select_lemma_watch_lit is used to select the watch literal for regular learned clauses. 810 */ select_watch_lit(clause const & cls,unsigned starting_at) const811 unsigned solver::select_watch_lit(clause const & cls, unsigned starting_at) const { 812 SASSERT(cls.size() >= 2); 813 unsigned min_true_idx = UINT_MAX; 814 unsigned max_false_idx = UINT_MAX; 815 unsigned unknown_idx = UINT_MAX; 816 unsigned n = cls.size(); 817 for (unsigned i = starting_at; i < n; i++) { 818 literal l = cls[i]; 819 switch(value(l)) { 820 case l_false: 821 if (max_false_idx == UINT_MAX || lvl(l) > lvl(cls[max_false_idx])) 822 max_false_idx = i; 823 break; 824 case l_undef: 825 unknown_idx = i; 826 break; 827 case l_true: 828 if (min_true_idx == UINT_MAX || lvl(l) < lvl(cls[min_true_idx])) 829 min_true_idx = i; 830 break; 831 } 832 } 833 if (min_true_idx != UINT_MAX) 834 return min_true_idx; 835 if (unknown_idx != UINT_MAX) 836 return unknown_idx; 837 SASSERT(max_false_idx != UINT_MAX); 838 return max_false_idx; 839 } 840 841 /** 842 \brief The learned clauses (lemmas) produced by the SAT solver 843 have the property that the first literal will be implied by it 844 after backtracking. All other literals are assigned to (or 845 implied to be) false when the learned clause is created. The 846 first watch literal will always be the first literal. The 847 second watch literal is computed by this method. It should be 848 the literal with the highest decision level. 849 850 // TODO: do we really need this? strength the conflict resolution 851 */ select_learned_watch_lit(clause const & cls) const852 unsigned solver::select_learned_watch_lit(clause const & cls) const { 853 SASSERT(cls.size() >= 2); 854 unsigned max_false_idx = UINT_MAX; 855 unsigned num_lits = cls.size(); 856 for (unsigned i = 1; i < num_lits; i++) { 857 literal l = cls[i]; 858 CTRACE("sat", value(l) != l_false, tout << l << ":=" << value(l);); 859 SASSERT(value(l) == l_false); 860 if (max_false_idx == UINT_MAX || lvl(l) > lvl(cls[max_false_idx])) 861 max_false_idx = i; 862 } 863 return max_false_idx; 864 } 865 866 template<bool lvl0> simplify_clause_core(unsigned & num_lits,literal * lits) const867 bool solver::simplify_clause_core(unsigned & num_lits, literal * lits) const { 868 std::sort(lits, lits+num_lits); 869 literal prev = null_literal; 870 unsigned i = 0; 871 unsigned j = 0; 872 for (; i < num_lits; i++) { 873 literal curr = lits[i]; 874 lbool val = value(curr); 875 if (!lvl0 && lvl(curr) > 0) 876 val = l_undef; 877 switch (val) { 878 case l_false: 879 break; // ignore literal 880 case l_undef: 881 if (curr == ~prev) 882 return false; // clause is equivalent to true 883 if (curr != prev) { 884 prev = curr; 885 if (i != j) 886 std::swap(lits[j], lits[i]); 887 j++; 888 } 889 break; 890 case l_true: 891 return false; // clause is equivalent to true 892 } 893 } 894 num_lits = j; 895 return true; 896 } 897 simplify_clause(unsigned & num_lits,literal * lits) const898 bool solver::simplify_clause(unsigned & num_lits, literal * lits) const { 899 if (at_base_lvl()) 900 return simplify_clause_core<true>(num_lits, lits); 901 else 902 return simplify_clause_core<false>(num_lits, lits); 903 } 904 detach_bin_clause(literal l1,literal l2,bool redundant)905 void solver::detach_bin_clause(literal l1, literal l2, bool redundant) { 906 get_wlist(~l1).erase(watched(l2, redundant)); 907 get_wlist(~l2).erase(watched(l1, redundant)); 908 if (m_config.m_drat) m_drat.del(l1, l2); 909 } 910 detach_clause(clause & c)911 void solver::detach_clause(clause & c) { 912 if (ENABLE_TERNARY && c.size() == 3) 913 detach_ter_clause(c); 914 else 915 detach_nary_clause(c); 916 } 917 detach_nary_clause(clause & c)918 void solver::detach_nary_clause(clause & c) { 919 clause_offset cls_off = get_offset(c); 920 erase_clause_watch(get_wlist(~c[0]), cls_off); 921 erase_clause_watch(get_wlist(~c[1]), cls_off); 922 } 923 detach_ter_clause(clause & c)924 void solver::detach_ter_clause(clause & c) { 925 erase_ternary_watch(get_wlist(~c[0]), c[1], c[2]); 926 erase_ternary_watch(get_wlist(~c[1]), c[0], c[2]); 927 erase_ternary_watch(get_wlist(~c[2]), c[0], c[1]); 928 } 929 930 // ----------------------- 931 // 932 // Basic 933 // 934 // ----------------------- 935 set_conflict(justification c,literal not_l)936 void solver::set_conflict(justification c, literal not_l) { 937 if (m_inconsistent) 938 return; 939 m_inconsistent = true; 940 m_conflict = c; 941 m_not_l = not_l; 942 } 943 assign_core(literal l,justification j)944 void solver::assign_core(literal l, justification j) { 945 SASSERT(value(l) == l_undef); 946 TRACE("sat_assign_core", tout << l << " " << j << "\n";); 947 if (j.level() == 0) { 948 if (m_config.m_drat) 949 drat_log_unit(l, j); 950 951 j = justification(0); // erase justification for level 0 952 } 953 else { 954 VERIFY(!at_base_lvl()); 955 } 956 m_assignment[l.index()] = l_true; 957 m_assignment[(~l).index()] = l_false; 958 bool_var v = l.var(); 959 m_justification[v] = j; 960 m_phase[v] = !l.sign(); 961 m_assigned_since_gc[v] = true; 962 m_trail.push_back(l); 963 964 switch (m_config.m_branching_heuristic) { 965 case BH_VSIDS: 966 break; 967 case BH_CHB: 968 m_last_propagation[v] = m_stats.m_conflict; 969 break; 970 } 971 972 if (m_config.m_anti_exploration) { 973 uint64_t age = m_stats.m_conflict - m_canceled[v]; 974 if (age > 0) { 975 double decay = pow(0.95, static_cast<double>(age)); 976 set_activity(v, static_cast<unsigned>(m_activity[v] * decay)); 977 // NB. MapleSAT does not update canceled. 978 m_canceled[v] = m_stats.m_conflict; 979 } 980 } 981 982 if (m_config.m_propagate_prefetch) { 983 #if defined(__GNUC__) || defined(__clang__) 984 __builtin_prefetch((const char*)((m_watches[l.index()].data()))); 985 #else 986 #if !defined(_M_ARM) && !defined(_M_ARM64) 987 _mm_prefetch((const char*)((m_watches[l.index()].data())), _MM_HINT_T1); 988 #endif 989 #endif 990 } 991 992 SASSERT(!l.sign() || !m_phase[v]); 993 SASSERT(l.sign() || m_phase[v]); 994 SASSERT(!l.sign() || value(v) == l_false); 995 SASSERT(l.sign() || value(v) == l_true); 996 SASSERT(value(l) == l_true); 997 SASSERT(value(~l) == l_false); 998 } 999 status(clause const & c) const1000 lbool solver::status(clause const & c) const { 1001 bool found_undef = false; 1002 for (literal lit : c) { 1003 switch (value(lit)) { 1004 case l_true: 1005 return l_true; 1006 case l_undef: 1007 found_undef = true; 1008 break; 1009 default: 1010 break; 1011 } 1012 } 1013 return found_undef ? l_undef : l_false; 1014 } 1015 1016 // ----------------------- 1017 // 1018 // Propagation 1019 // 1020 // ----------------------- 1021 propagate_core(bool update)1022 bool solver::propagate_core(bool update) { 1023 while (m_qhead < m_trail.size() && !m_inconsistent) { 1024 do { 1025 checkpoint(); 1026 m_cleaner.dec(); 1027 literal l = m_trail[m_qhead]; 1028 m_qhead++; 1029 if (!propagate_literal(l, update)) 1030 return false; 1031 } while (m_qhead < m_trail.size()); 1032 1033 if (m_ext && (!is_probing() || at_base_lvl())) 1034 m_ext->unit_propagate(); 1035 } 1036 if (m_inconsistent) 1037 return false; 1038 1039 SASSERT(m_qhead == m_trail.size()); 1040 SASSERT(!m_inconsistent); 1041 return true; 1042 } 1043 propagate(bool update)1044 bool solver::propagate(bool update) { 1045 unsigned qhead = m_qhead; 1046 bool r = propagate_core(update); 1047 if (m_config.m_branching_heuristic == BH_CHB) { 1048 update_chb_activity(r, qhead); 1049 } 1050 CASSERT("sat_propagate", check_invariant()); 1051 CASSERT("sat_missed_prop", check_missed_propagation()); 1052 return r; 1053 } 1054 propagate_literal(literal l,bool update)1055 bool solver::propagate_literal(literal l, bool update) { 1056 literal l1, l2; 1057 lbool val1, val2; 1058 bool keep; 1059 unsigned curr_level = lvl(l); 1060 TRACE("sat_propagate", tout << "propagating: " << l << "@" << curr_level << " " << m_justification[l.var()] << "\n"; ); 1061 1062 literal not_l = ~l; 1063 SASSERT(value(l) == l_true); 1064 SASSERT(value(not_l) == l_false); 1065 watch_list& wlist = m_watches[l.index()]; 1066 m_asymm_branch.dec(wlist.size()); 1067 m_probing.dec(wlist.size()); 1068 watch_list::iterator it = wlist.begin(); 1069 watch_list::iterator it2 = it; 1070 watch_list::iterator end = wlist.end(); 1071 #define CONFLICT_CLEANUP() { \ 1072 for (; it != end; ++it, ++it2) \ 1073 *it2 = *it; \ 1074 wlist.set_end(it2); \ 1075 } 1076 for (; it != end; ++it) { 1077 switch (it->get_kind()) { 1078 case watched::BINARY: 1079 l1 = it->get_literal(); 1080 switch (value(l1)) { 1081 case l_false: 1082 CONFLICT_CLEANUP(); 1083 set_conflict(justification(curr_level, not_l), ~l1); 1084 return false; 1085 case l_undef: 1086 m_stats.m_bin_propagate++; 1087 assign_core(l1, justification(curr_level, not_l)); 1088 break; 1089 case l_true: 1090 break; // skip 1091 } 1092 *it2 = *it; 1093 it2++; 1094 break; 1095 case watched::TERNARY: 1096 l1 = it->get_literal1(); 1097 l2 = it->get_literal2(); 1098 val1 = value(l1); 1099 val2 = value(l2); 1100 if (val1 == l_false && val2 == l_undef) { 1101 m_stats.m_ter_propagate++; 1102 assign_core(l2, justification(std::max(curr_level, lvl(l1)), l1, not_l)); 1103 } 1104 else if (val1 == l_undef && val2 == l_false) { 1105 m_stats.m_ter_propagate++; 1106 assign_core(l1, justification(std::max(curr_level, lvl(l2)), l2, not_l)); 1107 } 1108 else if (val1 == l_false && val2 == l_false) { 1109 CONFLICT_CLEANUP(); 1110 set_conflict(justification(std::max(curr_level, lvl(l1)), l1, not_l), ~l2); 1111 return false; 1112 } 1113 *it2 = *it; 1114 it2++; 1115 break; 1116 case watched::CLAUSE: { 1117 if (value(it->get_blocked_literal()) == l_true) { 1118 TRACE("propagate_clause_bug", tout << "blocked literal " << it->get_blocked_literal() << "\n"; 1119 tout << get_clause(it) << "\n";); 1120 *it2 = *it; 1121 it2++; 1122 break; 1123 } 1124 clause_offset cls_off = it->get_clause_offset(); 1125 clause& c = get_clause(cls_off); 1126 TRACE("propagate_clause_bug", tout << "processing... " << c << "\nwas_removed: " << c.was_removed() << "\n";); 1127 if (c[0] == not_l) 1128 std::swap(c[0], c[1]); 1129 CTRACE("propagate_bug", c[1] != not_l, tout << "l: " << l << " " << c << "\n";); 1130 if (c.was_removed() || c.size() == 1 || c[1] != not_l) { 1131 // Remark: this method may be invoked when the watch lists are not in a consistent state, 1132 // and may contain dead/removed clauses, or clauses with removed literals. 1133 // See: method propagate_unit at sat_simplifier.cpp 1134 // So, we must check whether the clause was marked for deletion, or 1135 // c[1] != not_l 1136 *it2 = *it; 1137 it2++; 1138 break; 1139 } 1140 if (value(c[0]) == l_true) { 1141 it2->set_clause(c[0], cls_off); 1142 it2++; 1143 break; 1144 } 1145 VERIFY(c[1] == not_l); 1146 literal* l_it = c.begin() + 2; 1147 literal* l_end = c.end(); 1148 unsigned assign_level = curr_level; 1149 unsigned max_index = 1; 1150 for (; l_it != l_end; ++l_it) { 1151 if (value(*l_it) != l_false) { 1152 c[1] = *l_it; 1153 *l_it = not_l; 1154 DEBUG_CODE(for (auto const& w : m_watches[(~c[1]).index()]) VERIFY(!w.is_clause() || w.get_clause_offset() != cls_off);); 1155 m_watches[(~c[1]).index()].push_back(watched(c[0], cls_off)); 1156 goto end_clause_case; 1157 } 1158 } 1159 SASSERT(value(c[0]) == l_false || value(c[0]) == l_undef); 1160 if (assign_level != scope_lvl()) { 1161 for (unsigned i = 2; i < c.size(); ++i) { 1162 unsigned level = lvl(c[i]); 1163 if (level > assign_level) { 1164 assign_level = level; 1165 max_index = i; 1166 } 1167 } 1168 IF_VERBOSE(20, verbose_stream() << "lower assignment level " << assign_level << " scope: " << scope_lvl() << "\n"); 1169 } 1170 1171 if (value(c[0]) == l_false) { 1172 assign_level = std::max(assign_level, lvl(c[0])); 1173 c.mark_used(); 1174 CONFLICT_CLEANUP(); 1175 set_conflict(justification(assign_level, cls_off)); 1176 return false; 1177 } 1178 else { 1179 if (max_index != 1) { 1180 IF_VERBOSE(20, verbose_stream() << "swap watch for: " << c[1] << " " << c[max_index] << "\n"); 1181 std::swap(c[1], c[max_index]); 1182 m_watches[(~c[1]).index()].push_back(watched(c[0], cls_off)); 1183 } 1184 else { 1185 *it2 = *it; 1186 it2++; 1187 } 1188 m_stats.m_propagate++; 1189 c.mark_used(); 1190 assign_core(c[0], justification(assign_level, cls_off)); 1191 if (update && c.is_learned() && c.glue() > 2) { 1192 unsigned glue; 1193 if (num_diff_levels_below(c.size(), c.begin(), c.glue() - 1, glue)) { 1194 c.set_glue(glue); 1195 } 1196 } 1197 } 1198 end_clause_case: 1199 break; 1200 } 1201 case watched::EXT_CONSTRAINT: 1202 SASSERT(m_ext); 1203 keep = m_ext->propagated(l, it->get_ext_constraint_idx()); 1204 if (m_inconsistent) { 1205 if (!keep) { 1206 ++it; 1207 } 1208 CONFLICT_CLEANUP(); 1209 return false; 1210 } 1211 if (keep) { 1212 *it2 = *it; 1213 it2++; 1214 } 1215 break; 1216 default: 1217 UNREACHABLE(); 1218 break; 1219 } 1220 } 1221 wlist.set_end(it2); 1222 if (m_ext && m_external[l.var()] && (!is_probing() || at_base_lvl())) 1223 m_ext->asserted(l); 1224 1225 return true; 1226 } 1227 display_lookahead_scores(std::ostream & out)1228 void solver::display_lookahead_scores(std::ostream& out) { 1229 lookahead lh(*this); 1230 lh.display_lookahead_scores(out); 1231 } 1232 cube(bool_var_vector & vars,literal_vector & lits,unsigned backtrack_level)1233 lbool solver::cube(bool_var_vector& vars, literal_vector& lits, unsigned backtrack_level) { 1234 bool is_first = !m_cuber; 1235 if (is_first) { 1236 m_cuber = alloc(lookahead, *this); 1237 } 1238 lbool result = m_cuber->cube(vars, lits, backtrack_level); 1239 m_cuber->update_cube_statistics(m_aux_stats); 1240 switch (result) { 1241 case l_false: 1242 dealloc(m_cuber); 1243 m_cuber = nullptr; 1244 if (is_first) { 1245 pop_to_base_level(); 1246 set_conflict(); 1247 } 1248 break; 1249 case l_true: { 1250 lits.reset(); 1251 pop_to_base_level(); 1252 model const& mdl = m_cuber->get_model(); 1253 for (bool_var v = 0; v < mdl.size(); ++v) { 1254 if (value(v) != l_undef) { 1255 continue; 1256 } 1257 literal l(v, false); 1258 if (mdl[v] != l_true) l.neg(); 1259 if (inconsistent()) 1260 return l_undef; 1261 push(); 1262 assign_core(l, justification(scope_lvl())); 1263 propagate(false); 1264 } 1265 mk_model(); 1266 break; 1267 } 1268 default: 1269 break; 1270 } 1271 return result; 1272 } 1273 1274 1275 // ----------------------- 1276 // 1277 // Search 1278 // 1279 // ----------------------- check(unsigned num_lits,literal const * lits)1280 lbool solver::check(unsigned num_lits, literal const* lits) { 1281 init_reason_unknown(); 1282 pop_to_base_level(); 1283 m_stats.m_units = init_trail_size(); 1284 IF_VERBOSE(2, verbose_stream() << "(sat.solver)\n";); 1285 SASSERT(at_base_lvl()); 1286 1287 if (m_config.m_ddfw_search) { 1288 m_cleaner(true); 1289 return do_ddfw_search(num_lits, lits); 1290 } 1291 if (m_config.m_prob_search) { 1292 m_cleaner(true); 1293 return do_prob_search(num_lits, lits); 1294 } 1295 if (m_config.m_local_search) { 1296 m_cleaner(true); 1297 return do_local_search(num_lits, lits); 1298 } 1299 if ((m_config.m_num_threads > 1 || m_config.m_local_search_threads > 0 || 1300 m_config.m_ddfw_threads > 0) && !m_par && !m_ext) { 1301 SASSERT(scope_lvl() == 0); 1302 return check_par(num_lits, lits); 1303 } 1304 flet<bool> _searching(m_searching, true); 1305 m_clone = nullptr; 1306 if (m_mc.empty() && gparams::get_ref().get_bool("model_validate", false)) { 1307 1308 m_clone = alloc(solver, m_no_drat_params, m_rlimit); 1309 m_clone->copy(*this); 1310 m_clone->set_extension(nullptr); 1311 } 1312 try { 1313 init_search(); 1314 if (check_inconsistent()) return l_false; 1315 propagate(false); 1316 if (check_inconsistent()) return l_false; 1317 init_assumptions(num_lits, lits); 1318 propagate(false); 1319 if (check_inconsistent()) return l_false; 1320 if (m_config.m_force_cleanup) do_cleanup(true); 1321 TRACE("sat", display(tout);); 1322 1323 if (m_config.m_gc_burst) { 1324 // force gc 1325 m_conflicts_since_gc = m_gc_threshold + 1; 1326 do_gc(); 1327 } 1328 1329 if (m_config.m_enable_pre_simplify) { 1330 do_simplify(); 1331 if (check_inconsistent()) return l_false; 1332 } 1333 1334 if (m_config.m_max_conflicts == 0) { 1335 IF_VERBOSE(SAT_VB_LVL, verbose_stream() << "(sat \"abort: max-conflicts = 0\")\n";); 1336 TRACE("sat", display(tout); m_mc.display(tout);); 1337 return l_undef; 1338 } 1339 1340 log_stats(); 1341 if (m_config.m_max_conflicts > 0 && m_config.m_burst_search > 0) { 1342 m_restart_threshold = m_config.m_burst_search; 1343 lbool r = bounded_search(); 1344 log_stats(); 1345 if (r != l_undef) 1346 return r; 1347 1348 pop_reinit(scope_lvl()); 1349 m_conflicts_since_restart = 0; 1350 m_restart_threshold = m_config.m_restart_initial; 1351 } 1352 1353 lbool is_sat = search(); 1354 log_stats(); 1355 return is_sat; 1356 } 1357 catch (const abort_solver &) { 1358 m_reason_unknown = "sat.giveup"; 1359 IF_VERBOSE(SAT_VB_LVL, verbose_stream() << "(sat \"abort giveup\")\n";); 1360 return l_undef; 1361 } 1362 } 1363 should_cancel()1364 bool solver::should_cancel() { 1365 if (limit_reached() || memory_exceeded()) { 1366 return true; 1367 } 1368 if (m_config.m_restart_max <= m_restarts) { 1369 m_reason_unknown = "sat.max.restarts"; 1370 IF_VERBOSE(SAT_VB_LVL, verbose_stream() << "(sat \"abort: max-restarts\")\n";); 1371 return true; 1372 } 1373 if (m_config.m_inprocess_max <= m_simplifications) { 1374 m_reason_unknown = "sat.max.inprocess"; 1375 IF_VERBOSE(SAT_VB_LVL, verbose_stream() << "(sat \"abort: max-inprocess\")\n";); 1376 return true; 1377 } 1378 if (reached_max_conflicts()) { 1379 return true; 1380 } 1381 return false; 1382 } 1383 1384 enum par_exception_kind { 1385 DEFAULT_EX, 1386 ERROR_EX 1387 }; 1388 invoke_local_search(unsigned num_lits,literal const * lits)1389 lbool solver::invoke_local_search(unsigned num_lits, literal const* lits) { 1390 literal_vector _lits(num_lits, lits); 1391 for (literal lit : m_user_scope_literals) _lits.push_back(~lit); 1392 struct scoped_ls { 1393 solver& s; 1394 scoped_ls(solver& s): s(s) {} 1395 ~scoped_ls() { 1396 dealloc(s.m_local_search); 1397 s.m_local_search = nullptr; 1398 } 1399 }; 1400 scoped_ls _ls(*this); 1401 if (inconsistent()) 1402 return l_false; 1403 scoped_limits scoped_rl(rlimit()); 1404 SASSERT(m_local_search); 1405 m_local_search->add(*this); 1406 m_local_search->updt_params(m_params); 1407 scoped_rl.push_child(&(m_local_search->rlimit())); 1408 lbool r = m_local_search->check(_lits.size(), _lits.data(), nullptr); 1409 if (r == l_true) { 1410 m_model = m_local_search->get_model(); 1411 m_model_is_current = true; 1412 } 1413 return r; 1414 } 1415 do_local_search(unsigned num_lits,literal const * lits)1416 lbool solver::do_local_search(unsigned num_lits, literal const* lits) { 1417 SASSERT(!m_local_search); 1418 m_local_search = alloc(local_search); 1419 return invoke_local_search(num_lits, lits); 1420 } 1421 do_ddfw_search(unsigned num_lits,literal const * lits)1422 lbool solver::do_ddfw_search(unsigned num_lits, literal const* lits) { 1423 if (m_ext) return l_undef; 1424 SASSERT(!m_local_search); 1425 m_local_search = alloc(ddfw); 1426 return invoke_local_search(num_lits, lits); 1427 } 1428 do_prob_search(unsigned num_lits,literal const * lits)1429 lbool solver::do_prob_search(unsigned num_lits, literal const* lits) { 1430 if (m_ext) return l_undef; 1431 if (num_lits > 0 || !m_user_scope_literals.empty()) return l_undef; 1432 SASSERT(!m_local_search); 1433 m_local_search = alloc(prob); 1434 return invoke_local_search(num_lits, lits); 1435 } 1436 1437 #ifdef SINGLE_THREAD check_par(unsigned num_lits,literal const * lits)1438 lbool solver::check_par(unsigned num_lits, literal const* lits) { 1439 return l_undef; 1440 } 1441 #else check_par(unsigned num_lits,literal const * lits)1442 lbool solver::check_par(unsigned num_lits, literal const* lits) { 1443 if (!rlimit().inc()) { 1444 return l_undef; 1445 } 1446 if (m_ext) 1447 return l_undef; 1448 1449 scoped_ptr_vector<i_local_search> ls; 1450 scoped_ptr_vector<solver> uw; 1451 int num_extra_solvers = m_config.m_num_threads - 1; 1452 int num_local_search = static_cast<int>(m_config.m_local_search_threads); 1453 int num_ddfw = m_ext ? 0 : static_cast<int>(m_config.m_ddfw_threads); 1454 int num_threads = num_extra_solvers + 1 + num_local_search + num_ddfw; 1455 for (int i = 0; i < num_local_search; ++i) { 1456 local_search* l = alloc(local_search); 1457 l->updt_params(m_params); 1458 l->add(*this); 1459 l->set_seed(m_config.m_random_seed + i); 1460 ls.push_back(l); 1461 } 1462 1463 vector<reslimit> lims(num_ddfw); 1464 // set up ddfw search 1465 for (int i = 0; i < num_ddfw; ++i) { 1466 ddfw* d = alloc(ddfw); 1467 d->updt_params(m_params); 1468 d->set_seed(m_config.m_random_seed + i); 1469 d->add(*this); 1470 ls.push_back(d); 1471 } 1472 int local_search_offset = num_extra_solvers; 1473 int main_solver_offset = num_extra_solvers + num_local_search + num_ddfw; 1474 1475 #define IS_AUX_SOLVER(i) (0 <= i && i < num_extra_solvers) 1476 #define IS_LOCAL_SEARCH(i) (local_search_offset <= i && i < main_solver_offset) 1477 #define IS_MAIN_SOLVER(i) (i == main_solver_offset) 1478 1479 sat::parallel par(*this); 1480 par.reserve(num_threads, 1 << 12); 1481 par.init_solvers(*this, num_extra_solvers); 1482 for (unsigned i = 0; i < ls.size(); ++i) { 1483 par.push_child(ls[i]->rlimit()); 1484 } 1485 for (reslimit& rl : lims) { 1486 par.push_child(rl); 1487 } 1488 for (unsigned i = 0; i < uw.size(); ++i) { 1489 uw[i]->set_par(&par, 0); 1490 } 1491 int finished_id = -1; 1492 std::string ex_msg; 1493 par_exception_kind ex_kind = DEFAULT_EX; 1494 unsigned error_code = 0; 1495 lbool result = l_undef; 1496 bool canceled = false; 1497 std::mutex mux; 1498 1499 auto worker_thread = [&](int i) { 1500 try { 1501 lbool r = l_undef; 1502 if (IS_AUX_SOLVER(i)) { 1503 r = par.get_solver(i).check(num_lits, lits); 1504 } 1505 else if (IS_LOCAL_SEARCH(i)) { 1506 r = ls[i-local_search_offset]->check(num_lits, lits, &par); 1507 } 1508 else { 1509 r = check(num_lits, lits); 1510 } 1511 bool first = false; 1512 { 1513 std::lock_guard<std::mutex> lock(mux); 1514 if (finished_id == -1) { 1515 finished_id = i; 1516 first = true; 1517 result = r; 1518 } 1519 } 1520 if (first) { 1521 for (unsigned j = 0; j < ls.size(); ++j) { 1522 ls[j]->rlimit().cancel(); 1523 } 1524 for (auto& rl : lims) { 1525 rl.cancel(); 1526 } 1527 for (int j = 0; j < num_extra_solvers; ++j) { 1528 if (i != j) { 1529 par.cancel_solver(j); 1530 } 1531 } 1532 if (!IS_MAIN_SOLVER(i)) { 1533 canceled = !rlimit().inc(); 1534 if (!canceled) { 1535 rlimit().cancel(); 1536 } 1537 } 1538 } 1539 } 1540 catch (z3_error & err) { 1541 error_code = err.error_code(); 1542 ex_kind = ERROR_EX; 1543 } 1544 catch (z3_exception & ex) { 1545 ex_msg = ex.msg(); 1546 ex_kind = DEFAULT_EX; 1547 } 1548 }; 1549 1550 if (!rlimit().inc()) { 1551 set_par(nullptr, 0); 1552 return l_undef; 1553 } 1554 1555 vector<std::thread> threads(num_threads); 1556 for (int i = 0; i < num_threads; ++i) { 1557 threads[i] = std::thread([&, i]() { worker_thread(i); }); 1558 } 1559 for (auto & th : threads) { 1560 th.join(); 1561 } 1562 1563 if (IS_AUX_SOLVER(finished_id)) { 1564 m_stats = par.get_solver(finished_id).m_stats; 1565 } 1566 if (result == l_true && IS_AUX_SOLVER(finished_id)) { 1567 set_model(par.get_solver(finished_id).get_model(), true); 1568 } 1569 else if (result == l_false && IS_AUX_SOLVER(finished_id)) { 1570 m_core.reset(); 1571 m_core.append(par.get_solver(finished_id).get_core()); 1572 } 1573 if (result == l_true && IS_LOCAL_SEARCH(finished_id)) { 1574 set_model(ls[finished_id - local_search_offset]->get_model(), true); 1575 } 1576 if (!canceled) { 1577 rlimit().reset_cancel(); 1578 } 1579 set_par(nullptr, 0); 1580 ls.reset(); 1581 uw.reset(); 1582 if (finished_id == -1) { 1583 switch (ex_kind) { 1584 case ERROR_EX: throw z3_error(error_code); 1585 default: throw default_exception(std::move(ex_msg)); 1586 } 1587 } 1588 return result; 1589 1590 } 1591 #endif 1592 1593 /* 1594 \brief import lemmas/units from parallel sat solvers. 1595 */ exchange_par()1596 void solver::exchange_par() { 1597 if (m_par && at_base_lvl() && m_config.m_num_threads > 1) m_par->get_clauses(*this); 1598 if (m_par && at_base_lvl() && m_config.m_num_threads > 1) { 1599 // SASSERT(scope_lvl() == search_lvl()); 1600 // TBD: import also dependencies of assumptions. 1601 unsigned sz = init_trail_size(); 1602 unsigned num_in = 0, num_out = 0; 1603 literal_vector in, out; 1604 for (unsigned i = m_par_limit_out; i < sz; ++i) { 1605 literal lit = m_trail[i]; 1606 if (lit.var() < m_par_num_vars) { 1607 ++num_out; 1608 out.push_back(lit); 1609 } 1610 } 1611 m_par_limit_out = sz; 1612 m_par->exchange(*this, out, m_par_limit_in, in); 1613 for (unsigned i = 0; !inconsistent() && i < in.size(); ++i) { 1614 literal lit = in[i]; 1615 SASSERT(lit.var() < m_par_num_vars); 1616 if (lvl(lit.var()) != 0 || value(lit) != l_true) { 1617 ++num_in; 1618 assign_unit(lit); 1619 } 1620 } 1621 if (num_in > 0 || num_out > 0) { 1622 IF_VERBOSE(2, verbose_stream() << "(sat-sync out: " << num_out << " in: " << num_in << ")\n";); 1623 } 1624 } 1625 } 1626 set_par(parallel * p,unsigned id)1627 void solver::set_par(parallel* p, unsigned id) { 1628 m_par = p; 1629 m_par_num_vars = num_vars(); 1630 m_par_limit_in = 0; 1631 m_par_limit_out = 0; 1632 m_par_id = id; 1633 m_par_syncing_clauses = false; 1634 } 1635 next_var()1636 bool_var solver::next_var() { 1637 bool_var next; 1638 1639 if (m_rand() < static_cast<int>(m_config.m_random_freq * random_gen::max_value())) { 1640 if (num_vars() == 0) 1641 return null_bool_var; 1642 next = m_rand() % num_vars(); 1643 TRACE("random_split", tout << "next: " << next << " value(next): " << value(next) << "\n";); 1644 if (value(next) == l_undef && !was_eliminated(next)) 1645 return next; 1646 } 1647 1648 while (!m_case_split_queue.empty()) { 1649 if (m_config.m_anti_exploration) { 1650 next = m_case_split_queue.min_var(); 1651 auto age = m_stats.m_conflict - m_canceled[next]; 1652 while (age > 0) { 1653 set_activity(next, static_cast<unsigned>(m_activity[next] * pow(0.95, static_cast<double>(age)))); 1654 m_canceled[next] = m_stats.m_conflict; 1655 next = m_case_split_queue.min_var(); 1656 age = m_stats.m_conflict - m_canceled[next]; 1657 } 1658 } 1659 next = m_case_split_queue.next_var(); 1660 if (value(next) == l_undef && !was_eliminated(next)) 1661 return next; 1662 } 1663 1664 return null_bool_var; 1665 } 1666 decide()1667 bool solver::decide() { 1668 bool_var next = next_var(); 1669 if (next == null_bool_var) 1670 return false; 1671 push(); 1672 m_stats.m_decision++; 1673 lbool lphase = m_ext ? m_ext->get_phase(next) : l_undef; 1674 bool phase = lphase == l_true; 1675 1676 if (lphase == l_undef) { 1677 switch (m_config.m_phase) { 1678 case PS_ALWAYS_TRUE: 1679 phase = true; 1680 break; 1681 case PS_ALWAYS_FALSE: 1682 phase = false; 1683 break; 1684 case PS_BASIC_CACHING: 1685 phase = m_phase[next]; 1686 break; 1687 case PS_FROZEN: 1688 phase = m_best_phase[next]; 1689 break; 1690 case PS_SAT_CACHING: 1691 if (m_search_state == s_unsat) { 1692 phase = m_phase[next]; 1693 } 1694 else { 1695 phase = m_best_phase[next]; 1696 } 1697 break; 1698 case PS_RANDOM: 1699 phase = (m_rand() % 2) == 0; 1700 break; 1701 default: 1702 UNREACHABLE(); 1703 phase = false; 1704 break; 1705 } 1706 } 1707 1708 literal next_lit(next, !phase); 1709 TRACE("sat_decide", tout << scope_lvl() << ": next-case-split: " << next_lit << "\n";); 1710 assign_scoped(next_lit); 1711 return true; 1712 } 1713 bounded_search()1714 lbool solver::bounded_search() { 1715 flet<bool> _disable_simplify(m_simplify_enabled, false); 1716 flet<bool> _restart_enabled(m_restart_enabled, false); 1717 return search(); 1718 } 1719 basic_search()1720 lbool solver::basic_search() { 1721 lbool is_sat = l_undef; 1722 while (is_sat == l_undef && !should_cancel()) { 1723 if (inconsistent()) is_sat = resolve_conflict_core(); 1724 else if (should_propagate()) propagate(true); 1725 else if (do_cleanup(false)) continue; 1726 else if (should_gc()) do_gc(); 1727 else if (should_rephase()) do_rephase(); 1728 else if (should_restart()) { if (!m_restart_enabled) return l_undef; do_restart(!m_config.m_restart_fast); } 1729 else if (should_simplify()) do_simplify(); 1730 else if (!decide()) is_sat = final_check(); 1731 } 1732 return is_sat; 1733 } 1734 search()1735 lbool solver::search() { 1736 if (!m_ext || !m_ext->tracking_assumptions()) 1737 return basic_search(); 1738 while (true) { 1739 pop_to_base_level(); 1740 reinit_assumptions(); 1741 lbool r = basic_search(); 1742 if (r != l_false) 1743 return r; 1744 if (!m_ext->should_research(m_core)) 1745 return r; 1746 } 1747 } 1748 should_propagate() const1749 bool solver::should_propagate() const { 1750 return !inconsistent() && m_qhead < m_trail.size(); 1751 } 1752 final_check()1753 lbool solver::final_check() { 1754 if (m_ext) { 1755 switch (m_ext->check()) { 1756 case check_result::CR_DONE: 1757 mk_model(); 1758 return l_true; 1759 case check_result::CR_CONTINUE: 1760 break; 1761 case check_result::CR_GIVEUP: 1762 throw abort_solver(); 1763 } 1764 return l_undef; 1765 } 1766 else { 1767 mk_model(); 1768 return l_true; 1769 } 1770 } 1771 1772 check_inconsistent()1773 bool solver::check_inconsistent() { 1774 if (inconsistent()) { 1775 if (tracking_assumptions() && at_search_lvl()) 1776 resolve_conflict(); 1777 else if (m_config.m_drat && at_base_lvl()) 1778 resolve_conflict(); 1779 return true; 1780 } 1781 else { 1782 return false; 1783 } 1784 } 1785 1786 init_assumptions(unsigned num_lits,literal const * lits)1787 void solver::init_assumptions(unsigned num_lits, literal const* lits) { 1788 if (num_lits == 0 && m_user_scope_literals.empty()) { 1789 return; 1790 } 1791 1792 SASSERT(at_base_lvl()); 1793 reset_assumptions(); 1794 push(); 1795 1796 propagate(false); 1797 if (inconsistent()) { 1798 return; 1799 } 1800 1801 TRACE("sat", 1802 tout << literal_vector(num_lits, lits) << "\n"; 1803 if (!m_user_scope_literals.empty()) { 1804 tout << "user literals: " << m_user_scope_literals << "\n"; 1805 } 1806 m_mc.display(tout); 1807 ); 1808 1809 for (unsigned i = 0; !inconsistent() && i < m_user_scope_literals.size(); ++i) { 1810 literal nlit = ~m_user_scope_literals[i]; 1811 assign_scoped(nlit); 1812 } 1813 1814 for (unsigned i = 0; !inconsistent() && i < num_lits; ++i) { 1815 literal lit = lits[i]; 1816 set_external(lit.var()); 1817 SASSERT(is_external(lit.var())); 1818 add_assumption(lit); 1819 assign_scoped(lit); 1820 } 1821 1822 m_search_lvl = scope_lvl(); 1823 SASSERT(m_search_lvl == 1); 1824 } 1825 update_min_core()1826 void solver::update_min_core() { 1827 if (!m_min_core_valid || m_core.size() < m_min_core.size()) { 1828 m_min_core.reset(); 1829 m_min_core.append(m_core); 1830 m_min_core_valid = true; 1831 } 1832 } 1833 reset_assumptions()1834 void solver::reset_assumptions() { 1835 m_assumptions.reset(); 1836 m_assumption_set.reset(); 1837 m_ext_assumption_set.reset(); 1838 } 1839 add_assumption(literal lit)1840 void solver::add_assumption(literal lit) { 1841 m_assumption_set.insert(lit); 1842 m_assumptions.push_back(lit); 1843 set_external(lit.var()); 1844 } 1845 reassert_min_core()1846 void solver::reassert_min_core() { 1847 SASSERT(m_min_core_valid); 1848 pop_to_base_level(); 1849 push(); 1850 reset_assumptions(); 1851 TRACE("sat", tout << "reassert: " << m_min_core << "\n";); 1852 for (literal lit : m_min_core) { 1853 SASSERT(is_external(lit.var())); 1854 add_assumption(lit); 1855 assign_scoped(lit); 1856 } 1857 propagate(false); 1858 SASSERT(inconsistent()); 1859 } 1860 reinit_assumptions()1861 void solver::reinit_assumptions() { 1862 if (tracking_assumptions() && at_base_lvl() && !inconsistent()) { 1863 TRACE("sat", tout << "assumptions: " << m_assumptions << " user scopes: " << m_user_scope_literals << "\n";); 1864 if (!propagate(false)) return; 1865 push(); 1866 for (literal lit : m_user_scope_literals) { 1867 if (inconsistent()) break; 1868 assign_scoped(~lit); 1869 } 1870 for (literal lit : m_assumptions) { 1871 if (inconsistent()) break; 1872 assign_scoped(lit); 1873 } 1874 init_ext_assumptions(); 1875 1876 if (!inconsistent()) 1877 propagate(false); 1878 TRACE("sat", 1879 tout << "consistent: " << !inconsistent() << "\n"; 1880 for (literal a : m_assumptions) { 1881 index_set s; 1882 if (m_antecedents.find(a.var(), s)) { 1883 tout << a << ": "; display_index_set(tout, s) << "\n"; 1884 } 1885 } 1886 for (literal lit : m_user_scope_literals) { 1887 tout << "user " << lit << "\n"; 1888 } 1889 ); 1890 } 1891 } 1892 init_ext_assumptions()1893 void solver::init_ext_assumptions() { 1894 if (m_ext && m_ext->tracking_assumptions()) { 1895 m_ext_assumption_set.reset(); 1896 if (!inconsistent()) 1897 m_ext->add_assumptions(m_ext_assumption_set); 1898 } 1899 } 1900 tracking_assumptions() const1901 bool solver::tracking_assumptions() const { 1902 return !m_assumptions.empty() || !m_user_scope_literals.empty() || (m_ext && m_ext->tracking_assumptions()); 1903 } 1904 is_assumption(literal l) const1905 bool solver::is_assumption(literal l) const { 1906 return tracking_assumptions() && (m_assumption_set.contains(l) || m_ext_assumption_set.contains(l)); 1907 } 1908 set_activity(bool_var v,unsigned new_act)1909 void solver::set_activity(bool_var v, unsigned new_act) { 1910 unsigned old_act = m_activity[v]; 1911 m_activity[v] = new_act; 1912 if (!was_eliminated(v) && value(v) == l_undef && new_act != old_act) { 1913 m_case_split_queue.activity_changed_eh(v, new_act > old_act); 1914 } 1915 } 1916 is_assumption(bool_var v) const1917 bool solver::is_assumption(bool_var v) const { 1918 return is_assumption(literal(v, false)) || is_assumption(literal(v, true)); 1919 } 1920 init_search()1921 void solver::init_search() { 1922 m_model_is_current = false; 1923 m_phase_counter = 0; 1924 m_search_state = s_unsat; 1925 m_search_unsat_conflicts = m_config.m_search_unsat_conflicts; 1926 m_search_sat_conflicts = m_config.m_search_sat_conflicts; 1927 m_search_next_toggle = m_search_unsat_conflicts; 1928 m_best_phase_size = 0; 1929 m_rephase_lim = 0; 1930 m_rephase_inc = 0; 1931 m_reorder_lim = m_config.m_reorder_base; 1932 m_reorder_inc = 0; 1933 m_conflicts_since_restart = 0; 1934 m_force_conflict_analysis = false; 1935 m_restart_threshold = m_config.m_restart_initial; 1936 m_luby_idx = 1; 1937 m_gc_threshold = m_config.m_gc_initial; 1938 m_defrag_threshold = 2; 1939 m_restarts = 0; 1940 m_last_position_log = 0; 1941 m_restart_logs = 0; 1942 m_simplifications = 0; 1943 m_conflicts_since_init = 0; 1944 m_next_simplify = m_config.m_simplify_delay; 1945 m_min_d_tk = 1.0; 1946 m_search_lvl = 0; 1947 if (m_learned.size() <= 2*m_clauses.size()) 1948 m_conflicts_since_gc = 0; 1949 m_restart_next_out = 0; 1950 m_asymm_branch.init_search(); 1951 m_stopwatch.reset(); 1952 m_stopwatch.start(); 1953 m_core.reset(); 1954 m_min_core_valid = false; 1955 m_min_core.reset(); 1956 m_simplifier.init_search(); 1957 m_mc.init_search(*this); 1958 if (m_ext) 1959 m_ext->init_search(); 1960 TRACE("sat", display(tout);); 1961 } 1962 should_simplify() const1963 bool solver::should_simplify() const { 1964 return m_conflicts_since_init >= m_next_simplify && m_simplify_enabled; 1965 } 1966 /** 1967 \brief Apply all simplifications. 1968 */ do_simplify()1969 void solver::do_simplify() { 1970 if (!should_simplify()) { 1971 return; 1972 } 1973 log_stats(); 1974 m_simplifications++; 1975 1976 TRACE("sat", tout << "simplify\n";); 1977 1978 pop(scope_lvl()); 1979 struct report { 1980 solver& s; 1981 stopwatch m_watch; 1982 report(solver& s):s(s) { 1983 m_watch.start(); 1984 s.log_stats(); 1985 IF_VERBOSE(2, verbose_stream() << "(sat.simplify :simplifications " << s.m_simplifications << ")\n";); 1986 } 1987 ~report() { 1988 m_watch.stop(); 1989 s.log_stats(); 1990 } 1991 }; 1992 report _rprt(*this); 1993 SASSERT(at_base_lvl()); 1994 1995 m_cleaner(m_config.m_force_cleanup); 1996 CASSERT("sat_simplify_bug", check_invariant()); 1997 1998 m_scc(); 1999 CASSERT("sat_simplify_bug", check_invariant()); 2000 2001 if (m_ext) { 2002 m_ext->pre_simplify(); 2003 } 2004 2005 m_simplifier(false); 2006 2007 CASSERT("sat_simplify_bug", check_invariant()); 2008 CASSERT("sat_missed_prop", check_missed_propagation()); 2009 if (!m_learned.empty()) { 2010 m_simplifier(true); 2011 CASSERT("sat_missed_prop", check_missed_propagation()); 2012 CASSERT("sat_simplify_bug", check_invariant()); 2013 } 2014 sort_watch_lits(); 2015 CASSERT("sat_simplify_bug", check_invariant()); 2016 2017 m_probing(); 2018 CASSERT("sat_missed_prop", check_missed_propagation()); 2019 CASSERT("sat_simplify_bug", check_invariant()); 2020 m_asymm_branch(false); 2021 2022 CASSERT("sat_missed_prop", check_missed_propagation()); 2023 CASSERT("sat_simplify_bug", check_invariant()); 2024 if (m_ext) { 2025 m_ext->clauses_modifed(); 2026 m_ext->simplify(); 2027 } 2028 if (m_config.m_lookahead_simplify && !m_ext) { 2029 lookahead lh(*this); 2030 lh.simplify(true); 2031 lh.collect_statistics(m_aux_stats); 2032 } 2033 2034 reinit_assumptions(); 2035 if (inconsistent()) return; 2036 2037 if (m_next_simplify == 0) { 2038 m_next_simplify = m_config.m_next_simplify1; 2039 } 2040 else { 2041 m_next_simplify = static_cast<unsigned>(m_conflicts_since_init * m_config.m_simplify_mult2); 2042 if (m_next_simplify > m_conflicts_since_init + m_config.m_simplify_max) 2043 m_next_simplify = m_conflicts_since_init + m_config.m_simplify_max; 2044 } 2045 2046 if (m_par) { 2047 m_par->from_solver(*this); 2048 if (m_par->to_solver(*this)) { 2049 m_activity_inc = 128; 2050 } 2051 } 2052 2053 if (m_config.m_binspr && !inconsistent()) { 2054 m_binspr(); 2055 } 2056 2057 if (m_config.m_anf_simplify && m_simplifications > m_config.m_anf_delay && !inconsistent()) { 2058 anf_simplifier anf(*this); 2059 anf_simplifier::config cfg; 2060 cfg.m_enable_exlin = m_config.m_anf_exlin; 2061 anf(); 2062 anf.collect_statistics(m_aux_stats); 2063 // TBD: throttle anf_delay based on yield 2064 } 2065 2066 if (m_cut_simplifier && m_simplifications > m_config.m_cut_delay && !inconsistent()) { 2067 (*m_cut_simplifier)(); 2068 } 2069 2070 if (m_config.m_inprocess_out.is_non_empty_string()) { 2071 std::ofstream fout(m_config.m_inprocess_out.str()); 2072 if (fout) { 2073 display_dimacs(fout); 2074 } 2075 throw solver_exception("output generated"); 2076 } 2077 } 2078 set_root(literal l,literal r)2079 bool solver::set_root(literal l, literal r) { 2080 return !m_ext || m_ext->set_root(l, r); 2081 } 2082 flush_roots()2083 void solver::flush_roots() { 2084 if (m_ext) m_ext->flush_roots(); 2085 } 2086 sort_watch_lits()2087 void solver::sort_watch_lits() { 2088 for (watch_list & wlist : m_watches) { 2089 std::stable_sort(wlist.begin(), wlist.end(), watched_lt()); 2090 } 2091 } 2092 set_model(model const & mdl,bool is_current)2093 void solver::set_model(model const& mdl, bool is_current) { 2094 m_model.reset(); 2095 m_model.append(mdl); 2096 m_model_is_current = is_current; 2097 } 2098 mk_model()2099 void solver::mk_model() { 2100 m_model.reset(); 2101 m_model_is_current = true; 2102 unsigned num = num_vars(); 2103 m_model.resize(num, l_undef); 2104 for (bool_var v = 0; v < num; v++) { 2105 if (!was_eliminated(v)) { 2106 m_model[v] = value(v); 2107 m_phase[v] = value(v) == l_true; 2108 m_best_phase[v] = value(v) == l_true; 2109 } 2110 } 2111 TRACE("sat_mc_bug", m_mc.display(tout);); 2112 2113 #if 0 2114 IF_VERBOSE(2, for (bool_var v = 0; v < num; v++) verbose_stream() << v << ": " << m_model[v] << "\n";); 2115 for (auto p : big::s_del_bin) { 2116 if (value(p.first) != l_true && value(p.second) != l_true) { 2117 IF_VERBOSE(2, verbose_stream() << "binary violation: " << p.first << " " << p.second << "\n"); 2118 } 2119 } 2120 #endif 2121 2122 if (m_clone) { 2123 IF_VERBOSE(10, verbose_stream() << "\"checking model\"\n";); 2124 if (!check_clauses(m_model)) { 2125 throw solver_exception("check model failed"); 2126 } 2127 } 2128 2129 if (m_config.m_drat) { 2130 m_drat.check_model(m_model); 2131 } 2132 2133 m_mc(m_model); 2134 2135 if (m_clone && !check_clauses(m_model)) { 2136 IF_VERBOSE(1, verbose_stream() << "failure checking clauses on transformed model\n";); 2137 IF_VERBOSE(10, m_mc.display(verbose_stream())); 2138 IF_VERBOSE(1, for (bool_var v = 0; v < num; v++) verbose_stream() << v << ": " << m_model[v] << "\n";); 2139 2140 throw solver_exception("check model failed"); 2141 } 2142 2143 TRACE("sat", for (bool_var v = 0; v < num; v++) tout << v << ": " << m_model[v] << "\n";); 2144 2145 if (m_clone) { 2146 IF_VERBOSE(1, verbose_stream() << "\"checking model (on original set of clauses)\"\n";); 2147 if (!m_clone->check_model(m_model)) { 2148 IF_VERBOSE(1, m_mc.display(verbose_stream())); 2149 IF_VERBOSE(1, display_units(verbose_stream())); 2150 throw solver_exception("check model failed (for cloned solver)"); 2151 } 2152 } 2153 } 2154 check_clauses(model const & m) const2155 bool solver::check_clauses(model const& m) const { 2156 bool ok = true; 2157 for (clause const* cp : m_clauses) { 2158 clause const & c = *cp; 2159 if (!c.satisfied_by(m)) { 2160 IF_VERBOSE(1, verbose_stream() << "failed clause " << c.id() << ": " << c << "\n";); 2161 TRACE("sat", tout << "failed: " << c << "\n"; 2162 tout << "assumptions: " << m_assumptions << "\n"; 2163 tout << "trail: " << m_trail << "\n"; 2164 tout << "model: " << m << "\n"; 2165 m_mc.display(tout); 2166 ); 2167 for (literal l : c) { 2168 if (was_eliminated(l.var())) IF_VERBOSE(1, verbose_stream() << "eliminated: " << l << "\n";); 2169 } 2170 ok = false; 2171 } 2172 } 2173 unsigned l_idx = 0; 2174 for (watch_list const& wlist : m_watches) { 2175 literal l = ~to_literal(l_idx); 2176 if (value_at(l, m) != l_true) { 2177 for (watched const& w : wlist) { 2178 if (!w.is_binary_non_learned_clause()) 2179 continue; 2180 literal l2 = w.get_literal(); 2181 if (l.index() > l2.index()) 2182 continue; 2183 if (value_at(l2, m) != l_true) { 2184 IF_VERBOSE(1, verbose_stream() << "failed binary: " << l << " := " << value_at(l, m) << " " << l2 << " := " << value_at(l2, m) << "\n"); 2185 IF_VERBOSE(1, verbose_stream() << "elim l1: " << was_eliminated(l.var()) << " elim l2: " << was_eliminated(l2) << "\n"); 2186 TRACE("sat", m_mc.display(tout << "failed binary: " << l << " " << l2 << "\n");); 2187 ok = false; 2188 } 2189 } 2190 } 2191 ++l_idx; 2192 } 2193 for (literal l : m_assumptions) { 2194 if (value_at(l, m) != l_true) { 2195 VERIFY(is_external(l.var())); 2196 IF_VERBOSE(1, verbose_stream() << "assumption: " << l << " does not model check " << value_at(l, m) << "\n";); 2197 TRACE("sat", 2198 tout << l << " does not model check\n"; 2199 tout << "trail: " << m_trail << "\n"; 2200 tout << "model: " << m << "\n"; 2201 m_mc.display(tout); 2202 ); 2203 ok = false; 2204 } 2205 } 2206 if (m_ext && !m_ext->check_model(m)) { 2207 ok = false; 2208 } 2209 return ok; 2210 } 2211 check_model(model const & m) const2212 bool solver::check_model(model const & m) const { 2213 bool ok = check_clauses(m); 2214 if (ok && !m_mc.check_model(m)) { 2215 ok = false; 2216 TRACE("sat", tout << "model: " << m << "\n"; m_mc.display(tout);); 2217 IF_VERBOSE(0, verbose_stream() << "model check failed\n"); 2218 } 2219 return ok; 2220 } 2221 should_restart() const2222 bool solver::should_restart() const { 2223 if (m_conflicts_since_restart <= m_restart_threshold) return false; 2224 if (scope_lvl() < 2 + search_lvl()) return false; 2225 if (m_case_split_queue.empty()) return false; 2226 if (m_config.m_restart != RS_EMA) return true; 2227 return 2228 m_fast_glue_avg + search_lvl() <= scope_lvl() && 2229 m_config.m_restart_margin * m_slow_glue_avg <= m_fast_glue_avg; 2230 } 2231 log_stats()2232 void solver::log_stats() { 2233 m_restart_logs++; 2234 2235 std::stringstream strm; 2236 strm << "(sat.stats " << std::setw(6) << m_stats.m_conflict << " " 2237 << std::setw(6) << m_stats.m_decision << " " 2238 << std::setw(4) << m_stats.m_restart 2239 << mk_stat(*this) 2240 << " " << std::setw(6) << std::setprecision(2) << m_stopwatch.get_current_seconds() << ")\n"; 2241 std::string str(strm.str()); 2242 svector<size_t> nums; 2243 for (size_t i = 0; i < str.size(); ++i) { 2244 while (i < str.size() && str[i] != ' ') ++i; 2245 while (i < str.size() && str[i] == ' ') ++i; 2246 // position of first character after space 2247 if (i < str.size()) { 2248 nums.push_back(i); 2249 } 2250 } 2251 bool same = m_last_positions.size() == nums.size(); 2252 size_t diff = 0; 2253 for (unsigned i = 0; i < nums.size() && same; ++i) { 2254 if (m_last_positions[i] > nums[i]) diff += m_last_positions[i] - nums[i]; 2255 if (m_last_positions[i] < nums[i]) diff += nums[i] - m_last_positions[i]; 2256 } 2257 if (m_last_positions.empty() || 2258 m_restart_logs >= 20 + m_last_position_log || 2259 (m_restart_logs >= 6 + m_last_position_log && (!same || diff > 3))) { 2260 m_last_position_log = m_restart_logs; 2261 // conflicts restarts learned gc time 2262 // decisions clauses units memory 2263 int adjust[9] = { -3, -3, -3, -1, -3, -2, -1, -2, -1 }; 2264 char const* tag[9] = { ":conflicts ", ":decisions ", ":restarts ", ":clauses/bin ", ":learned/bin ", ":units ", ":gc ", ":memory ", ":time" }; 2265 std::stringstream l1, l2; 2266 l1 << "(sat.stats "; 2267 l2 << "(sat.stats "; 2268 size_t p1 = 11, p2 = 11; 2269 SASSERT(nums.size() == 9); 2270 for (unsigned i = 0; i < 9 && i < nums.size(); ++i) { 2271 size_t p = nums[i]; 2272 if (i & 0x1) { 2273 // odd positions 2274 for (; p2 < p + adjust[i]; ++p2) l2 << " "; 2275 p2 += strlen(tag[i]); 2276 l2 << tag[i]; 2277 } 2278 else { 2279 // even positions 2280 for (; p1 < p + adjust[i]; ++p1) l1 << " "; 2281 p1 += strlen(tag[i]); 2282 l1 << tag[i]; 2283 } 2284 } 2285 for (; p1 + 2 < str.size(); ++p1) l1 << " "; 2286 for (; p2 + 2 < str.size(); ++p2) l2 << " "; 2287 l1 << ")\n"; 2288 l2 << ")\n"; 2289 IF_VERBOSE(1, verbose_stream() << l1.str() << l2.str()); 2290 m_last_positions.reset(); 2291 m_last_positions.append(nums); 2292 } 2293 IF_VERBOSE(1, verbose_stream() << str); 2294 } 2295 do_restart(bool to_base)2296 void solver::do_restart(bool to_base) { 2297 m_stats.m_restart++; 2298 m_restarts++; 2299 if (m_conflicts_since_init >= m_restart_next_out && get_verbosity_level() >= 1) { 2300 if (0 == m_restart_next_out) { 2301 m_restart_next_out = 1; 2302 } 2303 else { 2304 m_restart_next_out = std::min(m_conflicts_since_init + 50000, (3*m_restart_next_out)/2 + 1); 2305 } 2306 log_stats(); 2307 } 2308 TRACE("sat", tout << "restart " << restart_level(to_base) << "\n";); 2309 IF_VERBOSE(30, display_status(verbose_stream());); 2310 TRACE("sat", tout << "restart " << restart_level(to_base) << "\n";); 2311 pop_reinit(restart_level(to_base)); 2312 set_next_restart(); 2313 } 2314 restart_level(bool to_base)2315 unsigned solver::restart_level(bool to_base) { 2316 SASSERT(!m_case_split_queue.empty()); 2317 if (to_base || scope_lvl() == search_lvl()) 2318 return scope_lvl() - search_lvl(); 2319 else { 2320 bool_var next = m_case_split_queue.min_var(); 2321 2322 // Implementations of Marijn's idea of reusing the 2323 // trail when the next decision literal has lower precedence. 2324 // pop trail from top 2325 #if 0 2326 unsigned n = 0; 2327 do { 2328 bool_var prev = scope_literal(scope_lvl() - n - 1).var(); 2329 if (m_case_split_queue.more_active(prev, next)) break; 2330 ++n; 2331 } 2332 while (n < scope_lvl() - search_lvl()); 2333 return n; 2334 #endif 2335 // pop trail from bottom 2336 unsigned n = search_lvl(); 2337 for (; n < scope_lvl() && m_case_split_queue.more_active(scope_literal(n).var(), next); ++n) { 2338 } 2339 return n - search_lvl(); 2340 } 2341 } 2342 update_activity(bool_var v,double p)2343 void solver::update_activity(bool_var v, double p) { 2344 unsigned new_act = (unsigned) (num_vars() * m_config.m_activity_scale * p); 2345 set_activity(v, new_act); 2346 } 2347 set_next_restart()2348 void solver::set_next_restart() { 2349 m_conflicts_since_restart = 0; 2350 switch (m_config.m_restart) { 2351 case RS_GEOMETRIC: 2352 m_restart_threshold = static_cast<unsigned>(m_restart_threshold * m_config.m_restart_factor); 2353 break; 2354 case RS_LUBY: 2355 m_luby_idx++; 2356 m_restart_threshold = m_config.m_restart_initial * get_luby(m_luby_idx); 2357 break; 2358 case RS_EMA: 2359 m_restart_threshold = m_config.m_restart_initial; 2360 break; 2361 case RS_STATIC: 2362 break; 2363 default: 2364 UNREACHABLE(); 2365 break; 2366 } 2367 CASSERT("sat_restart", check_invariant()); 2368 } 2369 2370 2371 // ----------------------- 2372 // 2373 // Conflict resolution 2374 // 2375 // ----------------------- 2376 resolve_conflict()2377 bool solver::resolve_conflict() { 2378 while (true) { 2379 lbool r = resolve_conflict_core(); 2380 CASSERT("sat_check_marks", check_marks()); 2381 // after pop, clauses are reinitialized, this may trigger another conflict. 2382 if (r == l_false) 2383 return false; 2384 if (!inconsistent()) 2385 return true; 2386 } 2387 } 2388 2389 resolve_conflict_core()2390 lbool solver::resolve_conflict_core() { 2391 m_conflicts_since_init++; 2392 m_conflicts_since_restart++; 2393 m_conflicts_since_gc++; 2394 m_stats.m_conflict++; 2395 if (m_step_size > m_config.m_step_size_min) { 2396 m_step_size -= m_config.m_step_size_dec; 2397 } 2398 2399 bool unique_max; 2400 m_conflict_lvl = get_max_lvl(m_not_l, m_conflict, unique_max); 2401 justification js = m_conflict; 2402 2403 if (m_conflict_lvl <= 1 && tracking_assumptions()) { 2404 TRACE("sat", tout << "unsat core\n";); 2405 resolve_conflict_for_unsat_core(); 2406 return l_false; 2407 } 2408 2409 if (m_conflict_lvl == 0) { 2410 drat_explain_conflict(); 2411 if (m_config.m_drat) 2412 drat_log_clause(0, nullptr, sat::status::redundant()); 2413 TRACE("sat", tout << "conflict level is 0\n";); 2414 return l_false; 2415 } 2416 2417 // force_conflict_analysis is used instead of relying on normal propagation to assign m_not_l 2418 // at the backtracking level. This is the case where the external theories miss propagations 2419 // that only get triggered after decisions. 2420 2421 if (allow_backtracking() && unique_max && !m_force_conflict_analysis) { 2422 TRACE("sat", tout << "unique max " << js << " " << m_not_l << "\n";); 2423 pop_reinit(m_scope_lvl - m_conflict_lvl + 1); 2424 m_force_conflict_analysis = true; 2425 ++m_stats.m_backtracks; 2426 return l_undef; 2427 } 2428 m_force_conflict_analysis = false; 2429 2430 updt_phase_of_vars(); 2431 2432 if (m_ext) { 2433 switch (m_ext->resolve_conflict()) { 2434 case l_true: 2435 learn_lemma_and_backjump(); 2436 return l_undef; 2437 case l_undef: 2438 break; 2439 case l_false: 2440 // backjumping was taken care of internally. 2441 return l_undef; 2442 } 2443 } 2444 2445 m_lemma.reset(); 2446 2447 unsigned idx = skip_literals_above_conflict_level(); 2448 2449 // save space for first uip 2450 m_lemma.push_back(null_literal); 2451 2452 TRACE("sat_conflict_detail", 2453 tout << "resolve: " << m_not_l << " " 2454 << " js: " << js 2455 << " idx: " << idx 2456 << " trail: " << m_trail.size() 2457 << " @" << m_conflict_lvl << "\n";); 2458 2459 unsigned num_marks = 0; 2460 literal consequent = null_literal; 2461 if (m_not_l != null_literal) { 2462 TRACE("sat_conflict_detail", tout << "not_l: " << m_not_l << "\n";); 2463 process_antecedent(m_not_l, num_marks); 2464 consequent = ~m_not_l; 2465 } 2466 2467 do { 2468 TRACE("sat_conflict_detail", tout << "processing consequent: " << consequent << " @" << (consequent==null_literal?m_conflict_lvl:lvl(consequent)) << "\n"; 2469 tout << "num_marks: " << num_marks << "\n"; 2470 display_justification(tout, js) << "\n";); 2471 2472 switch (js.get_kind()) { 2473 case justification::NONE: 2474 break; 2475 case justification::BINARY: 2476 process_antecedent(~(js.get_literal()), num_marks); 2477 break; 2478 case justification::TERNARY: 2479 process_antecedent(~(js.get_literal1()), num_marks); 2480 process_antecedent(~(js.get_literal2()), num_marks); 2481 break; 2482 case justification::CLAUSE: { 2483 clause & c = get_clause(js); 2484 unsigned i = 0; 2485 if (consequent != null_literal) { 2486 SASSERT(c[0] == consequent || c[1] == consequent); 2487 if (c[0] == consequent) { 2488 i = 1; 2489 } 2490 else { 2491 process_antecedent(~c[0], num_marks); 2492 i = 2; 2493 } 2494 } 2495 unsigned sz = c.size(); 2496 for (; i < sz; i++) 2497 process_antecedent(~c[i], num_marks); 2498 break; 2499 } 2500 case justification::EXT_JUSTIFICATION: { 2501 fill_ext_antecedents(consequent, js, false); 2502 TRACE("sat", tout << "ext antecedents: " << m_ext_antecedents << "\n";); 2503 for (literal l : m_ext_antecedents) 2504 process_antecedent(l, num_marks); 2505 2506 #if 0 2507 if (m_ext_antecedents.size() <= 1) { 2508 for (literal& l : m_ext_antecedents) 2509 l.neg(); 2510 m_ext_antecedents.push_back(consequent); 2511 mk_clause(m_ext_antecedents.size(), m_ext_antecedents.c_ptr(), sat::status::redundant()); 2512 } 2513 #endif 2514 break; 2515 } 2516 default: 2517 UNREACHABLE(); 2518 break; 2519 } 2520 2521 bool_var c_var; 2522 while (true) { 2523 consequent = m_trail[idx]; 2524 c_var = consequent.var(); 2525 if (is_marked(c_var)) { 2526 if (lvl(c_var) == m_conflict_lvl) { 2527 break; 2528 } 2529 SASSERT(lvl(c_var) < m_conflict_lvl); 2530 } 2531 CTRACE("sat", idx == 0, 2532 for (literal lit : m_trail) 2533 if (is_marked(lit.var())) 2534 tout << "missed " << lit << "@" << lvl(lit) << "\n";); 2535 CTRACE("sat", idx == 0, display(tout);); 2536 if (idx == 0) 2537 IF_VERBOSE(0, verbose_stream() << "num-conflicts: " << m_stats.m_conflict << "\n"); 2538 VERIFY(idx > 0); 2539 idx--; 2540 } 2541 SASSERT(lvl(consequent) == m_conflict_lvl); 2542 js = m_justification[c_var]; 2543 idx--; 2544 num_marks--; 2545 reset_mark(c_var); 2546 2547 TRACE("sat", display_justification(tout << consequent << " ", js) << "\n";); 2548 } 2549 while (num_marks > 0); 2550 2551 m_lemma[0] = ~consequent; 2552 learn_lemma_and_backjump(); 2553 2554 return l_undef; 2555 } 2556 learn_lemma_and_backjump()2557 void solver::learn_lemma_and_backjump() { 2558 TRACE("sat_lemma", tout << "new lemma size: " << m_lemma.size() << "\n" << m_lemma << "\n";); 2559 2560 if (m_lemma.empty()) { 2561 pop_reinit(m_scope_lvl); 2562 mk_clause_core(0, nullptr, sat::status::redundant()); 2563 return; 2564 } 2565 2566 if (m_config.m_minimize_lemmas) { 2567 minimize_lemma(); 2568 reset_lemma_var_marks(); 2569 if (m_config.m_dyn_sub_res) 2570 dyn_sub_res(); 2571 TRACE("sat_lemma", tout << "new lemma (after minimization) size: " << m_lemma.size() << "\n" << m_lemma << "\n";); 2572 } 2573 else { 2574 reset_lemma_var_marks(); 2575 } 2576 2577 unsigned backtrack_lvl = lvl(m_lemma[0]); 2578 unsigned backjump_lvl = 0; 2579 for (unsigned i = m_lemma.size(); i-- > 1;) { 2580 unsigned level = lvl(m_lemma[i]); 2581 backjump_lvl = std::max(level, backjump_lvl); 2582 } 2583 // with scope tracking and chronological backtracking, 2584 // consequent may not be at highest decision level. 2585 if (backtrack_lvl < backjump_lvl) { 2586 backtrack_lvl = backjump_lvl; 2587 for (unsigned i = m_lemma.size(); i-- > 1;) { 2588 if (lvl(m_lemma[i]) == backjump_lvl) { 2589 TRACE("sat", tout << "swap " << m_lemma[0] << "@" << lvl(m_lemma[0]) << m_lemma[1] << "@" << backjump_lvl << "\n";); 2590 std::swap(m_lemma[i], m_lemma[0]); 2591 break; 2592 } 2593 } 2594 } 2595 2596 unsigned glue = num_diff_levels(m_lemma.size(), m_lemma.data()); 2597 m_fast_glue_avg.update(glue); 2598 m_slow_glue_avg.update(glue); 2599 2600 // compute whether to use backtracking or backjumping 2601 unsigned num_scopes = m_scope_lvl - backjump_lvl; 2602 2603 if (use_backjumping(num_scopes)) { 2604 ++m_stats.m_backjumps; 2605 pop_reinit(num_scopes); 2606 } 2607 else { 2608 TRACE("sat", tout << "backtrack " << (m_scope_lvl - backtrack_lvl + 1) << " scopes\n";); 2609 ++m_stats.m_backtracks; 2610 pop_reinit(m_scope_lvl - backtrack_lvl + 1); 2611 } 2612 clause * lemma = mk_clause_core(m_lemma.size(), m_lemma.data(), sat::status::redundant()); 2613 if (lemma) { 2614 lemma->set_glue(glue); 2615 } 2616 if (m_par && lemma) { 2617 m_par->share_clause(*this, *lemma); 2618 } 2619 m_lemma.reset(); 2620 TRACE("sat_conflict_detail", tout << "consistent " << (!m_inconsistent) << " scopes: " << scope_lvl() << " backtrack: " << backtrack_lvl << " backjump: " << backjump_lvl << "\n";); 2621 decay_activity(); 2622 updt_phase_counters(); 2623 } 2624 use_backjumping(unsigned num_scopes) const2625 bool solver::use_backjumping(unsigned num_scopes) const { 2626 return 2627 num_scopes > 0 && 2628 (num_scopes <= m_config.m_backtrack_scopes || !allow_backtracking()); 2629 } 2630 allow_backtracking() const2631 bool solver::allow_backtracking() const { 2632 return m_conflicts_since_init > m_config.m_backtrack_init_conflicts; 2633 } 2634 process_antecedent_for_unsat_core(literal antecedent)2635 void solver::process_antecedent_for_unsat_core(literal antecedent) { 2636 bool_var var = antecedent.var(); 2637 SASSERT(var < num_vars()); 2638 TRACE("sat", tout << antecedent << " " << (is_marked(var)?"+":"-") << "\n";); 2639 if (!is_marked(var)) { 2640 mark(var); 2641 m_unmark.push_back(var); 2642 if (is_assumption(antecedent)) { 2643 m_core.push_back(antecedent); 2644 } 2645 } 2646 } 2647 process_consequent_for_unsat_core(literal consequent,justification const & js)2648 void solver::process_consequent_for_unsat_core(literal consequent, justification const& js) { 2649 TRACE("sat", tout << "processing consequent: "; 2650 if (consequent == null_literal) tout << "null\n"; 2651 else tout << consequent << "\n"; 2652 display_justification(tout << "js kind: ", js) << "\n";); 2653 switch (js.get_kind()) { 2654 case justification::NONE: 2655 break; 2656 case justification::BINARY: 2657 SASSERT(consequent != null_literal); 2658 process_antecedent_for_unsat_core(~(js.get_literal())); 2659 break; 2660 case justification::TERNARY: 2661 SASSERT(consequent != null_literal); 2662 process_antecedent_for_unsat_core(~(js.get_literal1())); 2663 process_antecedent_for_unsat_core(~(js.get_literal2())); 2664 break; 2665 case justification::CLAUSE: { 2666 clause & c = get_clause(js); 2667 unsigned i = 0; 2668 if (consequent != null_literal) { 2669 SASSERT(c[0] == consequent || c[1] == consequent); 2670 if (c[0] == consequent) { 2671 i = 1; 2672 } 2673 else { 2674 process_antecedent_for_unsat_core(~c[0]); 2675 i = 2; 2676 } 2677 } 2678 unsigned sz = c.size(); 2679 for (; i < sz; i++) 2680 process_antecedent_for_unsat_core(~c[i]); 2681 break; 2682 } 2683 case justification::EXT_JUSTIFICATION: { 2684 fill_ext_antecedents(consequent, js, false); 2685 for (literal l : m_ext_antecedents) { 2686 process_antecedent_for_unsat_core(l); 2687 } 2688 break; 2689 } 2690 default: 2691 UNREACHABLE(); 2692 break; 2693 } 2694 } 2695 resolve_conflict_for_unsat_core()2696 void solver::resolve_conflict_for_unsat_core() { 2697 TRACE("sat_verbose", display(tout); 2698 unsigned level = 0; 2699 for (literal l : m_trail) { 2700 if (level != lvl(l)) { 2701 level = lvl(l); 2702 tout << level << ": "; 2703 } 2704 tout << l; 2705 if (m_mark[l.var()]) { 2706 tout << "*"; 2707 } 2708 tout << " "; 2709 } 2710 tout << "\n"; 2711 tout << "conflict level: " << m_conflict_lvl << "\n"; 2712 ); 2713 2714 m_core.reset(); 2715 if (!m_config.m_drat && m_conflict_lvl == 0) { 2716 return; 2717 } 2718 SASSERT(m_unmark.empty()); 2719 DEBUG_CODE({ 2720 for (literal lit : m_trail) { 2721 SASSERT(!is_marked(lit.var())); 2722 }}); 2723 2724 unsigned old_size = m_unmark.size(); 2725 int idx = skip_literals_above_conflict_level(); 2726 2727 literal consequent = m_not_l; 2728 if (m_not_l != null_literal) { 2729 justification js = m_justification[m_not_l.var()]; 2730 TRACE("sat", tout << "not_l: " << m_not_l << "\n"; 2731 display_justification(tout, js) << "\n";); 2732 2733 process_antecedent_for_unsat_core(m_not_l); 2734 if (is_assumption(~m_not_l)) { 2735 m_core.push_back(~m_not_l); 2736 } 2737 else { 2738 process_consequent_for_unsat_core(m_not_l, js); 2739 } 2740 consequent = ~m_not_l; 2741 } 2742 2743 justification js = m_conflict; 2744 2745 int init_sz = init_trail_size(); 2746 while (true) { 2747 process_consequent_for_unsat_core(consequent, js); 2748 while (idx >= init_sz) { 2749 consequent = m_trail[idx]; 2750 if (is_marked(consequent.var()) && lvl(consequent) == m_conflict_lvl) 2751 break; 2752 idx--; 2753 } 2754 if (idx < init_sz) { 2755 break; 2756 } 2757 SASSERT(lvl(consequent) == m_conflict_lvl); 2758 js = m_justification[consequent.var()]; 2759 idx--; 2760 } 2761 reset_unmark(old_size); 2762 if (m_core.size() > 1) { 2763 unsigned j = 0; 2764 for (unsigned i = 0; i < m_core.size(); ++i) { 2765 if (lvl(m_core[i]) > 0) m_core[j++] = m_core[i]; 2766 } 2767 m_core.shrink(j); 2768 } 2769 2770 if (m_config.m_core_minimize) { 2771 if (m_min_core_valid && m_min_core.size() < m_core.size()) { 2772 IF_VERBOSE(2, verbose_stream() << "(sat.updating core " << m_min_core.size() << " " << m_core.size() << ")\n";); 2773 m_core.reset(); 2774 m_core.append(m_min_core); 2775 } 2776 // TBD: 2777 // apply optional clause minimization by detecting subsumed literals. 2778 // initial experiment suggests it has no effect. 2779 m_mus(); // ignore return value on cancelation. 2780 set_model(m_mus.get_model(), !m_mus.get_model().empty()); 2781 IF_VERBOSE(2, verbose_stream() << "(sat.core: " << m_core << ")\n";); 2782 } 2783 } 2784 2785 get_max_lvl(literal not_l,justification js,bool & unique_max)2786 unsigned solver::get_max_lvl(literal not_l, justification js, bool& unique_max) { 2787 unique_max = true; 2788 unsigned level = 0; 2789 2790 if (not_l != null_literal) { 2791 level = lvl(not_l); 2792 } 2793 2794 switch (js.get_kind()) { 2795 case justification::NONE: 2796 level = std::max(level, js.level()); 2797 return level; 2798 case justification::BINARY: 2799 level = update_max_level(js.get_literal(), level, unique_max); 2800 return level; 2801 case justification::TERNARY: 2802 level = update_max_level(js.get_literal1(), level, unique_max); 2803 level = update_max_level(js.get_literal2(), level, unique_max); 2804 return level; 2805 case justification::CLAUSE: 2806 for (literal l : get_clause(js)) 2807 level = update_max_level(l, level, unique_max); 2808 return level; 2809 case justification::EXT_JUSTIFICATION: 2810 if (not_l != null_literal) 2811 not_l.neg(); 2812 fill_ext_antecedents(not_l, js, true); 2813 for (literal l : m_ext_antecedents) 2814 level = update_max_level(l, level, unique_max); 2815 return level; 2816 default: 2817 UNREACHABLE(); 2818 return 0; 2819 } 2820 } 2821 2822 /** 2823 \brief Skip literals from levels above m_conflict_lvl. 2824 It returns an index idx such that lvl(m_trail[idx]) <= m_conflict_lvl, and 2825 for all idx' > idx, lvl(m_trail[idx']) > m_conflict_lvl 2826 */ skip_literals_above_conflict_level()2827 unsigned solver::skip_literals_above_conflict_level() { 2828 unsigned idx = m_trail.size(); 2829 if (idx == 0) { 2830 return idx; 2831 } 2832 idx--; 2833 // skip literals from levels above the conflict level 2834 while (lvl(m_trail[idx]) > m_conflict_lvl) { 2835 SASSERT(idx > 0); 2836 idx--; 2837 } 2838 return idx; 2839 } 2840 process_antecedent(literal antecedent,unsigned & num_marks)2841 void solver::process_antecedent(literal antecedent, unsigned & num_marks) { 2842 bool_var var = antecedent.var(); 2843 unsigned var_lvl = lvl(var); 2844 SASSERT(var < num_vars()); 2845 TRACE("sat_verbose", tout << "process " << var << "@" << var_lvl << " marked " << is_marked(var) << " conflict " << m_conflict_lvl << "\n";); 2846 if (!is_marked(var) && var_lvl > 0) { 2847 mark(var); 2848 switch (m_config.m_branching_heuristic) { 2849 case BH_VSIDS: 2850 inc_activity(var); 2851 break; 2852 case BH_CHB: 2853 m_last_conflict[var] = m_stats.m_conflict; 2854 break; 2855 default: 2856 break; 2857 } 2858 if (var_lvl == m_conflict_lvl) 2859 num_marks++; 2860 else 2861 m_lemma.push_back(~antecedent); 2862 } 2863 } 2864 2865 2866 /** 2867 \brief js is an external justification. Collect its antecedents and store at m_ext_antecedents. 2868 */ fill_ext_antecedents(literal consequent,justification js,bool probing)2869 void solver::fill_ext_antecedents(literal consequent, justification js, bool probing) { 2870 SASSERT(js.is_ext_justification()); 2871 SASSERT(m_ext); 2872 auto idx = js.get_ext_justification_idx(); 2873 m_ext_antecedents.reset(); 2874 m_ext->get_antecedents(consequent, idx, m_ext_antecedents, probing); 2875 } 2876 is_two_phase() const2877 bool solver::is_two_phase() const { 2878 return m_config.m_phase == PS_SAT_CACHING; 2879 } 2880 is_sat_phase() const2881 bool solver::is_sat_phase() const { 2882 return is_two_phase() && m_search_state == s_sat; 2883 } 2884 updt_phase_of_vars()2885 void solver::updt_phase_of_vars() { 2886 if (m_config.m_phase == PS_FROZEN) 2887 return; 2888 unsigned from_lvl = m_conflict_lvl; 2889 unsigned head = from_lvl == 0 ? 0 : m_scopes[from_lvl - 1].m_trail_lim; 2890 unsigned sz = m_trail.size(); 2891 for (unsigned i = head; i < sz; i++) { 2892 bool_var v = m_trail[i].var(); 2893 TRACE("forget_phase", tout << "forgetting phase of v" << v << "\n";); 2894 m_phase[v] = m_rand() % 2 == 0; 2895 } 2896 if (is_sat_phase() && head >= m_best_phase_size) { 2897 m_best_phase_size = head; 2898 IF_VERBOSE(12, verbose_stream() << "sticky trail: " << head << "\n"); 2899 for (unsigned i = 0; i < head; ++i) { 2900 bool_var v = m_trail[i].var(); 2901 m_best_phase[v] = m_phase[v]; 2902 } 2903 } 2904 } 2905 should_toggle_search_state()2906 bool solver::should_toggle_search_state() { 2907 if (m_search_state == s_unsat) { 2908 m_trail_avg.update(m_trail.size()); 2909 } 2910 return 2911 (m_phase_counter >= m_search_next_toggle) && 2912 (m_search_state == s_sat || m_trail.size() > 0.50*m_trail_avg); 2913 } 2914 do_toggle_search_state()2915 void solver::do_toggle_search_state() { 2916 2917 if (is_two_phase()) { 2918 m_best_phase_size = 0; 2919 std::swap(m_fast_glue_backup, m_fast_glue_avg); 2920 std::swap(m_slow_glue_backup, m_slow_glue_avg); 2921 if (m_search_state == s_sat) { 2922 m_search_unsat_conflicts += m_config.m_search_unsat_conflicts; 2923 } 2924 else { 2925 m_search_sat_conflicts += m_config.m_search_sat_conflicts; 2926 } 2927 } 2928 2929 if (m_search_state == s_unsat) { 2930 m_search_state = s_sat; 2931 m_search_next_toggle = m_search_sat_conflicts; 2932 } 2933 else { 2934 m_search_state = s_unsat; 2935 m_search_next_toggle = m_search_unsat_conflicts; 2936 } 2937 2938 m_phase_counter = 0; 2939 } 2940 should_rephase()2941 bool solver::should_rephase() { 2942 return m_conflicts_since_init > m_rephase_lim; 2943 } 2944 do_rephase()2945 void solver::do_rephase() { 2946 switch (m_config.m_phase) { 2947 case PS_ALWAYS_TRUE: 2948 for (auto& p : m_phase) p = true; 2949 break; 2950 case PS_ALWAYS_FALSE: 2951 for (auto& p : m_phase) p = false; 2952 break; 2953 case PS_FROZEN: 2954 break; 2955 case PS_BASIC_CACHING: 2956 switch (m_rephase_lim % 4) { 2957 case 0: 2958 for (auto& p : m_phase) p = (m_rand() % 2) == 0; 2959 break; 2960 case 1: 2961 for (auto& p : m_phase) p = false; 2962 break; 2963 case 2: 2964 for (auto& p : m_phase) p = !p; 2965 break; 2966 default: 2967 break; 2968 } 2969 break; 2970 case PS_SAT_CACHING: 2971 if (m_search_state == s_sat) { 2972 for (unsigned i = 0; i < m_phase.size(); ++i) { 2973 m_phase[i] = m_best_phase[i]; 2974 } 2975 } 2976 break; 2977 case PS_RANDOM: 2978 for (auto& p : m_phase) p = (m_rand() % 2) == 0; 2979 break; 2980 default: 2981 UNREACHABLE(); 2982 break; 2983 } 2984 m_rephase_inc += m_config.m_rephase_base; 2985 m_rephase_lim += m_rephase_inc; 2986 } 2987 should_reorder()2988 bool solver::should_reorder() { 2989 return m_conflicts_since_init > m_reorder_lim; 2990 } 2991 do_reorder()2992 void solver::do_reorder() { 2993 IF_VERBOSE(1, verbose_stream() << "(reorder)\n"); 2994 m_activity_inc = 128; 2995 svector<bool_var> vars; 2996 for (bool_var v = num_vars(); v-- > 0; ) { 2997 if (!was_eliminated(v) && value(v) == l_undef) { 2998 vars.push_back(v); 2999 } 3000 } 3001 #if 1 3002 // 3003 // exp(logits[i]) / sum(exp(logits)) 3004 // = 3005 // exp(log(exp(logits[i]) / sum(exp(logits)))) 3006 // = 3007 // exp(log(exp(logits[i])) - log(sum(exp(logits)))) 3008 // = 3009 // exp(logits[i] - lse) 3010 svector<double> logits(vars.size(), 0.0); 3011 double itau = m_config.m_reorder_itau; 3012 double lse = 0; 3013 double mid = m_rand.max_value()/2; 3014 double max = 0; 3015 for (double& f : logits) { 3016 f = itau * (m_rand() - mid)/mid; 3017 if (f > max) max = f; 3018 } 3019 for (double f : logits) { 3020 lse += log(f - max); 3021 } 3022 lse = max + exp(lse); 3023 3024 for (unsigned i = 0; i < vars.size(); ++i) { 3025 update_activity(vars[i], exp(logits[i] - lse)); 3026 } 3027 #else 3028 shuffle(vars.size(), vars.c_ptr(), m_rand); 3029 for (bool_var v : vars) { 3030 update_activity(v, m_rand(10)/10.0); 3031 } 3032 #endif 3033 m_reorder_inc += m_config.m_reorder_base; 3034 m_reorder_lim += m_reorder_inc; 3035 } 3036 updt_phase_counters()3037 void solver::updt_phase_counters() { 3038 m_phase_counter++; 3039 if (should_toggle_search_state()) { 3040 do_toggle_search_state(); 3041 } 3042 } 3043 3044 /** 3045 \brief Return the number of different levels in lits. 3046 All literals in lits must be assigned. 3047 */ num_diff_levels(unsigned num,literal const * lits)3048 unsigned solver::num_diff_levels(unsigned num, literal const * lits) { 3049 m_diff_levels.reserve(scope_lvl() + 1, false); 3050 unsigned r = 0; 3051 for (unsigned i = 0; i < num; i++) { 3052 SASSERT(value(lits[i]) != l_undef); 3053 unsigned lit_lvl = lvl(lits[i]); 3054 if (!m_diff_levels[lit_lvl]) { 3055 m_diff_levels[lit_lvl] = true; 3056 r++; 3057 } 3058 } 3059 // reset m_diff_levels. 3060 for (unsigned i = 0; i < num; i++) 3061 m_diff_levels[lvl(lits[i])] = false; 3062 return r; 3063 } 3064 num_diff_levels_below(unsigned num,literal const * lits,unsigned max_glue,unsigned & glue)3065 bool solver::num_diff_levels_below(unsigned num, literal const* lits, unsigned max_glue, unsigned& glue) { 3066 m_diff_levels.reserve(scope_lvl() + 1, false); 3067 glue = 0; 3068 unsigned i = 0; 3069 for (; i < num && glue < max_glue; i++) { 3070 SASSERT(value(lits[i]) != l_undef); 3071 unsigned lit_lvl = lvl(lits[i]); 3072 if (!m_diff_levels[lit_lvl]) { 3073 m_diff_levels[lit_lvl] = true; 3074 glue++; 3075 } 3076 } 3077 // reset m_diff_levels. 3078 for (; i-- > 0; ) 3079 m_diff_levels[lvl(lits[i])] = false; 3080 return glue < max_glue; 3081 } 3082 num_diff_false_levels_below(unsigned num,literal const * lits,unsigned max_glue,unsigned & glue)3083 bool solver::num_diff_false_levels_below(unsigned num, literal const* lits, unsigned max_glue, unsigned& glue) { 3084 m_diff_levels.reserve(scope_lvl() + 1, false); 3085 glue = 0; 3086 unsigned i = 0; 3087 for (; i < num && glue < max_glue; i++) { 3088 if (value(lits[i]) == l_false) { 3089 unsigned lit_lvl = lvl(lits[i]); 3090 if (!m_diff_levels[lit_lvl]) { 3091 m_diff_levels[lit_lvl] = true; 3092 glue++; 3093 } 3094 } 3095 } 3096 // reset m_diff_levels. 3097 for (; i-- > 0;) { 3098 literal lit = lits[i]; 3099 if (value(lit) == l_false) { 3100 VERIFY(lvl(lit) < m_diff_levels.size()); 3101 m_diff_levels[lvl(lit)] = false; 3102 } 3103 } 3104 return glue < max_glue; 3105 } 3106 3107 3108 /** 3109 \brief Process an antecedent for lemma minimization. 3110 */ process_antecedent_for_minimization(literal antecedent)3111 bool solver::process_antecedent_for_minimization(literal antecedent) { 3112 bool_var var = antecedent.var(); 3113 unsigned var_lvl = lvl(var); 3114 if (!is_marked(var) && var_lvl > 0) { 3115 if (m_lvl_set.may_contain(var_lvl)) { 3116 mark(var); 3117 m_unmark.push_back(var); 3118 m_lemma_min_stack.push_back(antecedent); 3119 } 3120 else { 3121 return false; 3122 } 3123 } 3124 return true; 3125 } 3126 3127 /** 3128 \brief Return true if lit is implied by other marked literals 3129 and/or literals assigned at the base level. 3130 The set lvl_set is used as an optimization. 3131 The idea is to stop the recursive search with a failure 3132 as soon as we find a literal assigned in a level that is not in lvl_set. 3133 */ implied_by_marked(literal lit)3134 bool solver::implied_by_marked(literal lit) { 3135 m_lemma_min_stack.reset(); // avoid recursive function 3136 m_lemma_min_stack.push_back(lit); 3137 unsigned old_size = m_unmark.size(); 3138 3139 while (!m_lemma_min_stack.empty()) { 3140 lit = m_lemma_min_stack.back(); 3141 bool_var var = lit.var(); 3142 m_lemma_min_stack.pop_back(); 3143 justification const& js = m_justification[var]; 3144 switch(js.get_kind()) { 3145 case justification::NONE: 3146 // it is a decision variable from a previous scope level 3147 if (lvl(var) > 0) { 3148 reset_unmark(old_size); 3149 return false; 3150 } 3151 break; 3152 case justification::BINARY: 3153 if (!process_antecedent_for_minimization(~(js.get_literal()))) { 3154 reset_unmark(old_size); 3155 return false; 3156 } 3157 break; 3158 case justification::TERNARY: 3159 if (!process_antecedent_for_minimization(~(js.get_literal1())) || 3160 !process_antecedent_for_minimization(~(js.get_literal2()))) { 3161 reset_unmark(old_size); 3162 return false; 3163 } 3164 break; 3165 case justification::CLAUSE: { 3166 clause & c = get_clause(js); 3167 unsigned i = 0; 3168 if (c[0].var() == var) { 3169 i = 1; 3170 } 3171 else { 3172 SASSERT(c[1].var() == var); 3173 if (!process_antecedent_for_minimization(~c[0])) { 3174 reset_unmark(old_size); 3175 return false; 3176 } 3177 i = 2; 3178 } 3179 unsigned sz = c.size(); 3180 for (; i < sz; i++) { 3181 if (!process_antecedent_for_minimization(~c[i])) { 3182 reset_unmark(old_size); 3183 return false; 3184 } 3185 } 3186 break; 3187 } 3188 case justification::EXT_JUSTIFICATION: { 3189 literal consequent(var, value(var) == l_false); 3190 fill_ext_antecedents(consequent, js, false); 3191 for (literal l : m_ext_antecedents) { 3192 if (!process_antecedent_for_minimization(l)) { 3193 reset_unmark(old_size); 3194 return false; 3195 } 3196 } 3197 break; 3198 } 3199 default: 3200 UNREACHABLE(); 3201 break; 3202 } 3203 TRACE("sat_conflict", 3204 display_justification(tout << var << " ",js) << "\n";); 3205 } 3206 return true; 3207 } 3208 3209 /** 3210 \brief Restore the size of m_unmark to old_size, and 3211 unmark variables at positions [old_size, m_unmark.size()). 3212 */ reset_unmark(unsigned old_size)3213 void solver::reset_unmark(unsigned old_size) { 3214 unsigned curr_size = m_unmark.size(); 3215 for(unsigned i = old_size; i < curr_size; i++) 3216 reset_mark(m_unmark[i]); 3217 m_unmark.shrink(old_size); 3218 } 3219 3220 /** 3221 \brief Store the levels of the literals at m_lemma in the 3222 approximated set m_lvl_set. 3223 */ updt_lemma_lvl_set()3224 void solver::updt_lemma_lvl_set() { 3225 m_lvl_set.reset(); 3226 for (literal l : m_lemma) 3227 m_lvl_set.insert(lvl(l)); 3228 } 3229 3230 /** 3231 \brief Minimize lemma using binary resolution 3232 */ minimize_lemma_binres()3233 bool solver::minimize_lemma_binres() { 3234 SASSERT(!m_lemma.empty()); 3235 SASSERT(m_unmark.empty()); 3236 unsigned sz = m_lemma.size(); 3237 unsigned num_reduced = 0; 3238 for (unsigned i = 1; i < sz; ++i) { 3239 mark_lit(m_lemma[i]); 3240 } 3241 watch_list const& wlist = get_wlist(m_lemma[0]); 3242 for (watched const& w : wlist) { 3243 if (w.is_binary_clause() && is_marked_lit(w.get_literal())) { 3244 unmark_lit(~w.get_literal()); 3245 num_reduced++; 3246 } 3247 } 3248 if (num_reduced > 0) { 3249 unsigned j = 1; 3250 for (unsigned i = 1; i < sz; ++i) { 3251 if (is_marked_lit(m_lemma[i])) { 3252 m_lemma[j++] = m_lemma[i]; 3253 unmark_lit(m_lemma[i]); 3254 } 3255 } 3256 m_lemma.shrink(j); 3257 } 3258 3259 return num_reduced > 0; 3260 } 3261 3262 /** 3263 \brief Minimize the number of literals in m_lemma. The main idea is to remove 3264 literals that are implied by other literals in m_lemma and/or literals 3265 assigned at level 0. 3266 */ minimize_lemma()3267 bool solver::minimize_lemma() { 3268 SASSERT(!m_lemma.empty()); 3269 SASSERT(m_unmark.empty()); 3270 updt_lemma_lvl_set(); 3271 3272 unsigned sz = m_lemma.size(); 3273 unsigned i = 1; // the first literal is the FUIP 3274 unsigned j = 1; 3275 for (; i < sz; i++) { 3276 literal l = m_lemma[i]; 3277 if (implied_by_marked(l)) { 3278 m_unmark.push_back(l.var()); 3279 } 3280 else { 3281 m_lemma[j++] = m_lemma[i]; 3282 } 3283 } 3284 3285 reset_unmark(0); 3286 m_lemma.shrink(j); 3287 m_stats.m_minimized_lits += sz - j; 3288 return j < sz; 3289 } 3290 3291 /** 3292 \brief Reset the mark of the variables in the current lemma. 3293 */ reset_lemma_var_marks()3294 void solver::reset_lemma_var_marks() { 3295 if (m_config.m_branching_heuristic == BH_VSIDS) { 3296 update_lrb_reasoned(); 3297 } 3298 literal_vector::iterator it = m_lemma.begin(); 3299 literal_vector::iterator end = m_lemma.end(); 3300 SASSERT(!is_marked((*it).var())); 3301 ++it; 3302 for(; it != end; ++it) { 3303 bool_var var = (*it).var(); 3304 reset_mark(var); 3305 } 3306 } 3307 update_lrb_reasoned()3308 void solver::update_lrb_reasoned() { 3309 unsigned sz = m_lemma.size(); 3310 SASSERT(!is_marked(m_lemma[0].var())); 3311 mark(m_lemma[0].var()); 3312 for (unsigned i = m_lemma.size(); i-- > 0; ) { 3313 justification js = m_justification[m_lemma[i].var()]; 3314 switch (js.get_kind()) { 3315 case justification::NONE: 3316 break; 3317 case justification::BINARY: 3318 update_lrb_reasoned(js.get_literal()); 3319 break; 3320 case justification::TERNARY: 3321 update_lrb_reasoned(js.get_literal1()); 3322 update_lrb_reasoned(js.get_literal2()); 3323 break; 3324 case justification::CLAUSE: { 3325 clause & c = get_clause(js); 3326 for (literal l : c) { 3327 update_lrb_reasoned(l); 3328 } 3329 break; 3330 } 3331 case justification::EXT_JUSTIFICATION: { 3332 fill_ext_antecedents(~m_lemma[i], js, true); 3333 for (literal l : m_ext_antecedents) { 3334 update_lrb_reasoned(l); 3335 } 3336 break; 3337 } 3338 } 3339 } 3340 reset_mark(m_lemma[0].var()); 3341 for (unsigned i = m_lemma.size(); i-- > sz; ) { 3342 reset_mark(m_lemma[i].var()); 3343 } 3344 m_lemma.shrink(sz); 3345 } 3346 update_lrb_reasoned(literal lit)3347 void solver::update_lrb_reasoned(literal lit) { 3348 bool_var v = lit.var(); 3349 if (!is_marked(v)) { 3350 mark(v); 3351 m_reasoned[v]++; 3352 inc_activity(v); 3353 m_lemma.push_back(lit); 3354 } 3355 } 3356 3357 /** 3358 \brief Apply dynamic subsumption resolution to new lemma. 3359 Only binary and ternary clauses are used. 3360 */ dyn_sub_res()3361 bool solver::dyn_sub_res() { 3362 unsigned sz = m_lemma.size(); 3363 for (unsigned i = 0; i < sz; i++) { 3364 mark_lit(m_lemma[i]); 3365 } 3366 3367 literal l0 = m_lemma[0]; 3368 // l0 is the FUIP, and we never remove the FUIP. 3369 // 3370 // In the following loop, we use unmark_lit(l) to remove a 3371 // literal from m_lemma. 3372 3373 for (unsigned i = 0; i < sz; i++) { 3374 literal l = m_lemma[i]; 3375 if (!is_marked_lit(l)) 3376 continue; // literal was eliminated 3377 // first use watch lists 3378 watch_list const & wlist = get_wlist(~l); 3379 for (watched const& w : wlist) { 3380 // In this for-loop, the conditions l0 != ~l2 and l0 != ~l3 3381 // are not really needed if the solver does not miss unit propagations. 3382 // However, we add them anyway because we don't want to rely on this 3383 // property of the propagator. 3384 // For example, if this property is relaxed in the future, then the code 3385 // without the conditions l0 != ~l2 and l0 != ~l3 may remove the FUIP 3386 if (w.is_binary_clause()) { 3387 literal l2 = w.get_literal(); 3388 if (is_marked_lit(~l2) && l0 != ~l2) { 3389 // eliminate ~l2 from lemma because we have the clause l \/ l2 3390 unmark_lit(~l2); 3391 } 3392 } 3393 else if (w.is_ternary_clause()) { 3394 literal l2 = w.get_literal1(); 3395 literal l3 = w.get_literal2(); 3396 if (is_marked_lit(l2) && is_marked_lit(~l3) && l0 != ~l3) { 3397 // eliminate ~l3 from lemma because we have the clause l \/ l2 \/ l3 3398 unmark_lit(~l3); 3399 } 3400 else if (is_marked_lit(~l2) && is_marked_lit(l3) && l0 != ~l2) { 3401 // eliminate ~l2 from lemma because we have the clause l \/ l2 \/ l3 3402 unmark_lit(~l2); 3403 } 3404 } 3405 else { 3406 // May miss some binary/ternary clauses, but that is ok. 3407 // I sort the watch lists at every simplification round. 3408 break; 3409 } 3410 } 3411 // try to use cached implication if available 3412 literal_vector * implied_lits = m_probing.cached_implied_lits(~l); 3413 if (implied_lits) { 3414 for (literal l2 : *implied_lits) { 3415 // Here, we must check l0 != ~l2. 3416 // l \/ l2 is an implied binary clause. 3417 // However, it may have been deduced using a lemma that has been deleted. 3418 // For example, consider the following sequence of events: 3419 // 3420 // 1. Initial clause database: 3421 // 3422 // l \/ ~p1 3423 // p1 \/ ~p2 3424 // p2 \/ ~p3 3425 // p3 \/ ~p4 3426 // q1 \/ q2 \/ p1 \/ p2 \/ p3 \/ p4 \/ l2 3427 // q1 \/ ~q2 \/ p1 \/ p2 \/ p3 \/ p4 \/ l2 3428 // ~q1 \/ q2 \/ p1 \/ p2 \/ p3 \/ p4 \/ l2 3429 // ~q1 \/ ~q2 \/ p1 \/ p2 \/ p3 \/ p4 \/ l2 3430 // ... 3431 // 3432 // 2. Now suppose we learned the lemma 3433 // 3434 // p1 \/ p2 \/ p3 \/ p4 \/ l2 (*) 3435 // 3436 // 3. Probing is executed and we notice hat (~l => l2) when we assign l to false. 3437 // That is, l \/ l2 is an implied clause. Note that probing does not add 3438 // this clause to the clause database (there are too many). 3439 // 3440 // 4. Lemma (*) is deleted (garbage collected). 3441 // 3442 // 5. l is decided to be false, p1, p2, p3 and p4 are propagated using BCP, 3443 // but l2 is not since the lemma (*) was deleted. 3444 // 3445 // Probing module still "knows" that l \/ l2 is valid binary clause 3446 // 3447 // 6. A new lemma is created where ~l2 is the FUIP and the lemma also contains l. 3448 // If we remove l0 != ~l2 may try to delete the FUIP. 3449 if (is_marked_lit(~l2) && l0 != ~l2) { 3450 // eliminate ~l2 from lemma because we have the clause l \/ l2 3451 unmark_lit(~l2); 3452 } 3453 } 3454 } 3455 } 3456 3457 // can't eliminat FUIP 3458 SASSERT(is_marked_lit(m_lemma[0])); 3459 3460 unsigned j = 0; 3461 for (unsigned i = 0; i < sz; i++) { 3462 literal l = m_lemma[i]; 3463 if (is_marked_lit(l)) { 3464 unmark_lit(l); 3465 m_lemma[j] = l; 3466 j++; 3467 } 3468 } 3469 3470 m_stats.m_dyn_sub_res += sz - j; 3471 3472 SASSERT(j >= 1); 3473 m_lemma.shrink(j); 3474 return j < sz; 3475 } 3476 3477 3478 // ----------------------- 3479 // 3480 // Backtracking 3481 // 3482 // ----------------------- push()3483 void solver::push() { 3484 SASSERT(!inconsistent()); 3485 TRACE("sat_verbose", tout << "q:" << m_qhead << " trail: " << m_trail.size() << "\n";); 3486 SASSERT(m_qhead == m_trail.size()); 3487 m_scopes.push_back(scope()); 3488 scope & s = m_scopes.back(); 3489 m_scope_lvl++; 3490 s.m_trail_lim = m_trail.size(); 3491 s.m_clauses_to_reinit_lim = m_clauses_to_reinit.size(); 3492 s.m_inconsistent = m_inconsistent; 3493 if (m_ext) { 3494 m_vars_lim.push(m_active_vars.size()); 3495 m_ext->push(); 3496 } 3497 } 3498 pop_reinit(unsigned num_scopes)3499 void solver::pop_reinit(unsigned num_scopes) { 3500 pop(num_scopes); 3501 exchange_par(); 3502 reinit_assumptions(); 3503 m_stats.m_units = init_trail_size(); 3504 } 3505 pop_vars(unsigned num_scopes)3506 void solver::pop_vars(unsigned num_scopes) { 3507 //integrity_checker check(*this); 3508 //check.check_reinit_stack(); 3509 m_vars_to_reinit.reset(); 3510 unsigned old_num_vars = m_vars_lim.pop(num_scopes); 3511 if (old_num_vars == m_active_vars.size()) 3512 return; 3513 unsigned free_vars_head = m_free_vars.size(); 3514 unsigned sz = m_active_vars.size(), j = old_num_vars; 3515 unsigned new_lvl = m_scopes.size() - num_scopes; 3516 3517 gc_reinit_stack(num_scopes); 3518 3519 // check.check_reinit_stack(); 3520 init_visited(); 3521 unsigned old_sz = m_scopes[new_lvl].m_clauses_to_reinit_lim; 3522 for (unsigned i = m_clauses_to_reinit.size(); i-- > old_sz; ) { 3523 clause_wrapper const& cw = m_clauses_to_reinit[i]; 3524 for (unsigned j = cw.size(); j-- > 0; ) 3525 mark_visited(cw[j].var()); 3526 } 3527 for (literal lit : m_lemma) 3528 mark_visited(lit.var()); 3529 3530 auto is_active = [&](bool_var v) { 3531 return value(v) != l_undef && lvl(v) <= new_lvl; 3532 }; 3533 3534 for (unsigned i = old_num_vars; i < sz; ++i) { 3535 bool_var v = m_active_vars[i]; 3536 if (is_visited(v) || is_active(v)) { 3537 m_vars_to_reinit.push_back(v); 3538 m_active_vars[j++] = v; 3539 m_var_scope[v] = new_lvl; 3540 } 3541 else { 3542 set_eliminated(v, true); 3543 if (!is_external(v) || true) { 3544 m_free_vars.push_back(v); 3545 } 3546 } 3547 } 3548 m_active_vars.shrink(j); 3549 3550 auto cleanup_watch = [&](literal lit) { 3551 for (auto const& w : get_wlist(lit)) { 3552 IF_VERBOSE(0, verbose_stream() << "cleanup: " << lit << " " << w.is_binary_clause() << "\n"); 3553 } 3554 }; 3555 for (unsigned i = m_free_vars.size(); i-- > free_vars_head; ) { 3556 bool_var v = m_free_vars[i]; 3557 cleanup_watch(literal(v, false)); 3558 cleanup_watch(literal(v, true)); 3559 3560 } 3561 TRACE("sat", 3562 tout << "clauses to reinit: " << (m_clauses_to_reinit.size() - old_sz) << "\n"; 3563 tout << "new level: " << new_lvl << "\n"; 3564 tout << "vars to reinit: " << m_vars_to_reinit << "\n"; 3565 tout << "free vars: " << bool_var_vector(m_free_vars.size() - free_vars_head, m_free_vars.data() + free_vars_head) << "\n"; 3566 for (unsigned i = m_clauses_to_reinit.size(); i-- > old_sz; ) 3567 tout << "reinit: " << m_clauses_to_reinit[i] << "\n"; 3568 display(tout);); 3569 } 3570 shrink_vars(unsigned v)3571 void solver::shrink_vars(unsigned v) { 3572 unsigned j = 0; 3573 for (bool_var w : m_free_vars) 3574 if (w < v) 3575 m_free_vars[j++] = w; 3576 m_free_vars.shrink(j); 3577 3578 for (bool_var w = m_justification.size(); w-- > v;) { 3579 m_case_split_queue.del_var_eh(w); 3580 m_probing.reset_cache(literal(w, true)); 3581 m_probing.reset_cache(literal(w, false)); 3582 } 3583 m_watches.shrink(2*v); 3584 m_assignment.shrink(2*v); 3585 m_justification.shrink(v); 3586 m_decision.shrink(v); 3587 m_eliminated.shrink(v); 3588 m_external.shrink(v); 3589 m_var_scope.shrink(v); 3590 m_touched.shrink(v); 3591 m_activity.shrink(v); 3592 m_mark.shrink(v); 3593 m_lit_mark.shrink(2*v); 3594 m_phase.shrink(v); 3595 m_best_phase.shrink(v); 3596 m_prev_phase.shrink(v); 3597 m_assigned_since_gc.shrink(v); 3598 m_simplifier.reset_todos(); 3599 } 3600 pop(unsigned num_scopes)3601 void solver::pop(unsigned num_scopes) { 3602 if (num_scopes == 0) 3603 return; 3604 unsigned free_vars_head = m_free_vars.size(); 3605 if (m_ext) { 3606 pop_vars(num_scopes); 3607 m_ext->pop(num_scopes); 3608 } 3609 SASSERT(num_scopes <= scope_lvl()); 3610 unsigned new_lvl = scope_lvl() - num_scopes; 3611 scope & s = m_scopes[new_lvl]; 3612 m_inconsistent = false; // TBD: use model seems to make this redundant: s.m_inconsistent; 3613 unassign_vars(s.m_trail_lim, new_lvl); 3614 for (unsigned i = m_free_vars.size(); i-- > free_vars_head; ) 3615 m_case_split_queue.del_var_eh(m_free_vars[i]); 3616 m_scope_lvl -= num_scopes; 3617 reinit_clauses(s.m_clauses_to_reinit_lim); 3618 m_scopes.shrink(new_lvl); 3619 if (m_ext) 3620 m_ext->pop_reinit(); 3621 } 3622 unassign_vars(unsigned old_sz,unsigned new_lvl)3623 void solver::unassign_vars(unsigned old_sz, unsigned new_lvl) { 3624 SASSERT(old_sz <= m_trail.size()); 3625 SASSERT(m_replay_assign.empty()); 3626 for (unsigned i = m_trail.size(); i-- > old_sz; ) { 3627 literal l = m_trail[i]; 3628 bool_var v = l.var(); 3629 if (lvl(v) <= new_lvl) { 3630 m_replay_assign.push_back(l); 3631 continue; 3632 } 3633 m_assignment[l.index()] = l_undef; 3634 m_assignment[(~l).index()] = l_undef; 3635 SASSERT(value(v) == l_undef); 3636 m_case_split_queue.unassign_var_eh(v); 3637 if (m_config.m_anti_exploration) { 3638 m_canceled[v] = m_stats.m_conflict; 3639 } 3640 } 3641 m_trail.shrink(old_sz); 3642 m_qhead = m_trail.size(); 3643 if (!m_replay_assign.empty()) IF_VERBOSE(20, verbose_stream() << "replay assign: " << m_replay_assign.size() << "\n"); 3644 CTRACE("sat", !m_replay_assign.empty(), tout << "replay-assign: " << m_replay_assign << "\n";); 3645 for (unsigned i = m_replay_assign.size(); i-- > 0; ) { 3646 literal lit = m_replay_assign[i]; 3647 m_trail.push_back(lit); 3648 } 3649 3650 m_replay_assign.reset(); 3651 } 3652 reinit_clauses(unsigned old_sz)3653 void solver::reinit_clauses(unsigned old_sz) { 3654 unsigned sz = m_clauses_to_reinit.size(); 3655 SASSERT(old_sz <= sz); 3656 unsigned j = old_sz; 3657 for (unsigned i = old_sz; i < sz; i++) { 3658 clause_wrapper cw = m_clauses_to_reinit[i]; 3659 bool reinit = false; 3660 if (cw.is_binary()) { 3661 if (propagate_bin_clause(cw[0], cw[1]) && !at_base_lvl()) 3662 m_clauses_to_reinit[j++] = cw; 3663 else if (has_variables_to_reinit(cw[0], cw[1])) 3664 m_clauses_to_reinit[j++] = cw; 3665 } 3666 else { 3667 clause & c = *(cw.get_clause()); 3668 if (ENABLE_TERNARY && c.size() == 3) { 3669 if (!at_base_lvl() && propagate_ter_clause(c)) 3670 m_clauses_to_reinit[j++] = cw; 3671 else if (has_variables_to_reinit(c)) 3672 m_clauses_to_reinit[j++] = cw; 3673 else 3674 c.set_reinit_stack(false); 3675 continue; 3676 } 3677 detach_clause(c); 3678 attach_clause(c, reinit); 3679 if (!at_base_lvl() && reinit) 3680 // clause propagated literal, must keep it in the reinit stack. 3681 m_clauses_to_reinit[j++] = cw; 3682 else if (has_variables_to_reinit(c)) 3683 m_clauses_to_reinit[j++] = cw; 3684 else 3685 c.set_reinit_stack(false); 3686 } 3687 } 3688 m_clauses_to_reinit.shrink(j); 3689 } 3690 3691 // 3692 // All new clauses that are added to the solver 3693 // are relative to the user-scope literals. 3694 // 3695 user_push()3696 void solver::user_push() { 3697 pop_to_base_level(); 3698 m_free_var_freeze.push_back(m_free_vars); 3699 m_free_vars.reset(); // resetting free_vars forces new variables to be assigned above new_v 3700 bool_var new_v = mk_var(true, false); 3701 literal lit = literal(new_v, false); 3702 m_user_scope_literals.push_back(lit); 3703 m_cut_simplifier = nullptr; // for simplicity, wipe it out 3704 if (m_ext) 3705 m_ext->user_push(); 3706 TRACE("sat", tout << "user_push: " << lit << "\n";); 3707 } 3708 user_pop(unsigned num_scopes)3709 void solver::user_pop(unsigned num_scopes) { 3710 unsigned old_sz = m_user_scope_literals.size() - num_scopes; 3711 bool_var max_var = m_user_scope_literals[old_sz].var(); 3712 m_user_scope_literals.shrink(old_sz); 3713 3714 pop_to_base_level(); 3715 if (m_ext) 3716 m_ext->user_pop(num_scopes); 3717 3718 gc_vars(max_var); 3719 TRACE("sat", display(tout);); 3720 3721 m_qhead = 0; 3722 unsigned j = 0; 3723 for (bool_var v : m_free_vars) 3724 if (v < max_var) 3725 m_free_vars[j++] = v; 3726 m_free_vars.shrink(j); 3727 m_free_vars.append(m_free_var_freeze[old_sz]); 3728 m_free_var_freeze.shrink(old_sz); 3729 scoped_suspend_rlimit _sp(m_rlimit); 3730 propagate(false); 3731 } 3732 pop_to_base_level()3733 void solver::pop_to_base_level() { 3734 reset_assumptions(); 3735 pop(scope_lvl()); 3736 } 3737 3738 // ----------------------- 3739 // 3740 // Misc 3741 // 3742 // ----------------------- 3743 updt_params(params_ref const & p)3744 void solver::updt_params(params_ref const & p) { 3745 m_params.append(p); 3746 m_config.updt_params(p); 3747 m_simplifier.updt_params(p); 3748 m_asymm_branch.updt_params(p); 3749 m_probing.updt_params(p); 3750 m_scc.updt_params(p); 3751 m_rand.set_seed(m_config.m_random_seed); 3752 m_step_size = m_config.m_step_size_init; 3753 m_drat.updt_config(); 3754 m_fast_glue_avg.set_alpha(m_config.m_fast_glue_avg); 3755 m_slow_glue_avg.set_alpha(m_config.m_slow_glue_avg); 3756 m_fast_glue_backup.set_alpha(m_config.m_fast_glue_avg); 3757 m_slow_glue_backup.set_alpha(m_config.m_slow_glue_avg); 3758 m_trail_avg.set_alpha(m_config.m_slow_glue_avg); 3759 3760 if (m_config.m_cut_simplify && !m_cut_simplifier && m_user_scope_literals.empty()) { 3761 m_cut_simplifier = alloc(cut_simplifier, *this); 3762 } 3763 } 3764 collect_param_descrs(param_descrs & d)3765 void solver::collect_param_descrs(param_descrs & d) { 3766 config::collect_param_descrs(d); 3767 simplifier::collect_param_descrs(d); 3768 asymm_branch::collect_param_descrs(d); 3769 probing::collect_param_descrs(d); 3770 scc::collect_param_descrs(d); 3771 } 3772 collect_statistics(statistics & st) const3773 void solver::collect_statistics(statistics & st) const { 3774 m_stats.collect_statistics(st); 3775 m_cleaner.collect_statistics(st); 3776 m_simplifier.collect_statistics(st); 3777 m_scc.collect_statistics(st); 3778 m_asymm_branch.collect_statistics(st); 3779 m_probing.collect_statistics(st); 3780 if (m_ext) m_ext->collect_statistics(st); 3781 if (m_local_search) m_local_search->collect_statistics(st); 3782 if (m_cut_simplifier) m_cut_simplifier->collect_statistics(st); 3783 st.copy(m_aux_stats); 3784 } 3785 reset_statistics()3786 void solver::reset_statistics() { 3787 m_stats.reset(); 3788 m_cleaner.reset_statistics(); 3789 m_simplifier.reset_statistics(); 3790 m_asymm_branch.reset_statistics(); 3791 m_probing.reset_statistics(); 3792 m_aux_stats.reset(); 3793 } 3794 3795 // ----------------------- 3796 // 3797 // Activity related stuff 3798 // 3799 // ----------------------- 3800 rescale_activity()3801 void solver::rescale_activity() { 3802 SASSERT(m_config.m_branching_heuristic == BH_VSIDS); 3803 for (unsigned& act : m_activity) { 3804 act >>= 14; 3805 } 3806 m_activity_inc >>= 14; 3807 } 3808 update_chb_activity(bool is_sat,unsigned qhead)3809 void solver::update_chb_activity(bool is_sat, unsigned qhead) { 3810 SASSERT(m_config.m_branching_heuristic == BH_CHB); 3811 double multiplier = m_config.m_reward_offset * (is_sat ? m_config.m_reward_multiplier : 1.0); 3812 for (unsigned i = qhead; i < m_trail.size(); ++i) { 3813 auto v = m_trail[i].var(); 3814 auto d = m_stats.m_conflict - m_last_conflict[v] + 1; 3815 if (d == 0) d = 1; 3816 auto reward = multiplier / d; 3817 auto activity = m_activity[v]; 3818 set_activity(v, static_cast<unsigned>(m_step_size * reward + ((1.0 - m_step_size) * activity))); 3819 } 3820 } 3821 move_to_front(bool_var b)3822 void solver::move_to_front(bool_var b) { 3823 if (b >= num_vars()) 3824 return; 3825 bool_var next = m_case_split_queue.min_var(); 3826 auto next_act = m_activity[next]; 3827 set_activity(b, next_act + 1); 3828 } 3829 3830 // ----------------------- 3831 // 3832 // Iterators 3833 // 3834 // ----------------------- collect_bin_clauses(svector<bin_clause> & r,bool redundant,bool learned_only) const3835 void solver::collect_bin_clauses(svector<bin_clause> & r, bool redundant, bool learned_only) const { 3836 SASSERT(redundant || !learned_only); 3837 unsigned sz = m_watches.size(); 3838 for (unsigned l_idx = 0; l_idx < sz; l_idx++) { 3839 literal l = to_literal(l_idx); 3840 l.neg(); 3841 for (watched const& w : m_watches[l_idx]) { 3842 if (!w.is_binary_clause()) 3843 continue; 3844 if (!redundant && w.is_learned()) 3845 continue; 3846 else if (redundant && learned_only && !w.is_learned()) 3847 continue; 3848 literal l2 = w.get_literal(); 3849 if (l.index() > l2.index()) 3850 continue; 3851 TRACE("cleanup_bug", tout << "collected: " << l << " " << l2 << "\n";); 3852 r.push_back(bin_clause(l, l2)); 3853 } 3854 } 3855 } 3856 3857 // ----------------------- 3858 // 3859 // Debugging 3860 // 3861 // ----------------------- check_invariant() const3862 bool solver::check_invariant() const { 3863 if (!m_rlimit.inc()) return true; 3864 integrity_checker checker(*this); 3865 VERIFY(checker()); 3866 VERIFY(!m_ext || m_ext->validate()); 3867 return true; 3868 } 3869 check_marks() const3870 bool solver::check_marks() const { 3871 for (bool_var v = 0; v < num_vars(); v++) { 3872 SASSERT(!is_marked(v)); 3873 } 3874 return true; 3875 } 3876 display_model(std::ostream & out) const3877 std::ostream& solver::display_model(std::ostream& out) const { 3878 unsigned num = num_vars(); 3879 for (bool_var v = 0; v < num; v++) { 3880 out << v << ": " << m_model[v] << "\n"; 3881 } 3882 return out; 3883 } 3884 display_binary(std::ostream & out) const3885 void solver::display_binary(std::ostream & out) const { 3886 unsigned sz = m_watches.size(); 3887 for (unsigned l_idx = 0; l_idx < sz; l_idx++) { 3888 literal l = to_literal(l_idx); 3889 l.neg(); 3890 for (watched const& w : m_watches[l_idx]) { 3891 if (!w.is_binary_clause()) 3892 continue; 3893 literal l2 = w.get_literal(); 3894 if (l.index() > l2.index()) 3895 continue; 3896 out << "(" << l << " " << l2 << ")"; 3897 if (w.is_learned()) out << "*"; 3898 out << "\n"; 3899 } 3900 } 3901 } 3902 display_units(std::ostream & out) const3903 void solver::display_units(std::ostream & out) const { 3904 unsigned level = 0; 3905 for (literal lit : m_trail) { 3906 if (lvl(lit) > level) { 3907 level = lvl(lit); 3908 out << level << ": "; 3909 } 3910 else { 3911 out << " "; 3912 } 3913 out << lit << " "; 3914 if (lvl(lit) < level) { 3915 out << "@" << lvl(lit) << " "; 3916 } 3917 display_justification(out, m_justification[lit.var()]) << "\n"; 3918 } 3919 } 3920 display(std::ostream & out) const3921 void solver::display(std::ostream & out) const { 3922 out << "(sat\n"; 3923 display_units(out); 3924 display_binary(out); 3925 out << m_clauses << m_learned; 3926 if (m_ext) { 3927 m_ext->display(out); 3928 } 3929 out << ")\n"; 3930 } 3931 display_justification(std::ostream & out,justification const & js) const3932 std::ostream& solver::display_justification(std::ostream & out, justification const& js) const { 3933 switch (js.get_kind()) { 3934 case justification::NONE: 3935 out << "none @" << js.level(); 3936 break; 3937 case justification::BINARY: 3938 out << "binary " << js.get_literal() << "@" << lvl(js.get_literal()); 3939 break; 3940 case justification::TERNARY: 3941 out << "ternary " << js.get_literal1() << "@" << lvl(js.get_literal1()) << " "; 3942 out << js.get_literal2() << "@" << lvl(js.get_literal2()); 3943 break; 3944 case justification::CLAUSE: { 3945 out << "("; 3946 bool first = true; 3947 for (literal l : get_clause(js)) { 3948 if (first) first = false; else out << " "; 3949 out << l << "@" << lvl(l); 3950 } 3951 out << ")"; 3952 break; 3953 } 3954 case justification::EXT_JUSTIFICATION: 3955 if (m_ext) 3956 m_ext->display_justification(out << "ext ", js.get_ext_justification_idx()); 3957 break; 3958 default: 3959 break; 3960 } 3961 return out; 3962 } 3963 3964 num_clauses() const3965 unsigned solver::num_clauses() const { 3966 unsigned num_cls = m_trail.size(); // units; 3967 unsigned l_idx = 0; 3968 for (auto const& wl : m_watches) { 3969 literal l = ~to_literal(l_idx++); 3970 for (auto const& w : wl) { 3971 if (w.is_binary_clause() && l.index() < w.get_literal().index()) 3972 num_cls++; 3973 } 3974 } 3975 return num_cls + m_clauses.size() + m_learned.size(); 3976 } 3977 num_binary(unsigned & given,unsigned & redundant) const3978 void solver::num_binary(unsigned& given, unsigned& redundant) const { 3979 given = redundant = 0; 3980 unsigned l_idx = 0; 3981 for (auto const& wl : m_watches) { 3982 literal l = ~to_literal(l_idx++); 3983 for (auto const& w : wl) { 3984 if (w.is_binary_clause() && l.index() < w.get_literal().index()) { 3985 if (w.is_learned()) ++redundant; else ++given; 3986 } 3987 } 3988 } 3989 } 3990 display_dimacs(std::ostream & out) const3991 void solver::display_dimacs(std::ostream & out) const { 3992 out << "p cnf " << num_vars() << " " << num_clauses() << "\n"; 3993 for (literal lit : m_trail) { 3994 out << dimacs_lit(lit) << " 0\n"; 3995 } 3996 unsigned l_idx = 0; 3997 for (auto const& wlist : m_watches) { 3998 literal l = ~to_literal(l_idx++); 3999 for (auto const& w : wlist) { 4000 if (w.is_binary_clause() && l.index() < w.get_literal().index()) 4001 out << dimacs_lit(l) << " " << dimacs_lit(w.get_literal()) << " 0\n"; 4002 } 4003 } 4004 clause_vector const * vs[2] = { &m_clauses, &m_learned }; 4005 for (unsigned i = 0; i < 2; i++) { 4006 clause_vector const & cs = *(vs[i]); 4007 for (auto cp : cs) { 4008 for (literal l : *cp) { 4009 out << dimacs_lit(l) << " "; 4010 } 4011 out << "0\n"; 4012 } 4013 } 4014 } 4015 display_wcnf(std::ostream & out,unsigned sz,literal const * lits,unsigned const * weights) const4016 void solver::display_wcnf(std::ostream & out, unsigned sz, literal const* lits, unsigned const* weights) const { 4017 unsigned max_weight = 0; 4018 for (unsigned i = 0; i < sz; ++i) 4019 max_weight += weights[i]; 4020 ++max_weight; 4021 4022 if (m_ext) 4023 throw default_exception("wcnf is only supported for pure CNF problems"); 4024 4025 out << "p wcnf " << num_vars() << " " << num_clauses() + sz << " " << max_weight << "\n"; 4026 out << "c soft " << sz << "\n"; 4027 4028 for (literal lit : m_trail) 4029 out << max_weight << " " << dimacs_lit(lit) << " 0\n"; 4030 unsigned l_idx = 0; 4031 for (watch_list const& wlist : m_watches) { 4032 literal l = ~to_literal(l_idx); 4033 for (watched const& w : wlist) { 4034 if (w.is_binary_clause() && l.index() < w.get_literal().index()) 4035 out << max_weight << " " << dimacs_lit(l) << " " << dimacs_lit(w.get_literal()) << " 0\n"; 4036 } 4037 ++l_idx; 4038 } 4039 clause_vector const * vs[2] = { &m_clauses, &m_learned }; 4040 for (unsigned i = 0; i < 2; i++) { 4041 clause_vector const & cs = *(vs[i]); 4042 for (clause const* cp : cs) { 4043 clause const & c = *cp; 4044 out << max_weight << " "; 4045 for (literal l : c) 4046 out << dimacs_lit(l) << " "; 4047 out << "0\n"; 4048 } 4049 } 4050 for (unsigned i = 0; i < sz; ++i) { 4051 out << weights[i] << " " << lits[i] << " 0\n"; 4052 } 4053 out.flush(); 4054 } 4055 display_watches(std::ostream & out,literal lit) const4056 void solver::display_watches(std::ostream & out, literal lit) const { 4057 display_watch_list(out << lit << ": ", get_wlist(lit)) << "\n"; 4058 } 4059 display_watches(std::ostream & out) const4060 void solver::display_watches(std::ostream & out) const { 4061 unsigned l_idx = 0; 4062 for (watch_list const& wlist : m_watches) { 4063 literal l = to_literal(l_idx++); 4064 if (!wlist.empty()) 4065 display_watch_list(out << l << ": ", wlist) << "\n"; 4066 } 4067 } 4068 display_watch_list(std::ostream & out,watch_list const & wl) const4069 std::ostream& solver::display_watch_list(std::ostream& out, watch_list const& wl) const { 4070 return sat::display_watch_list(out, cls_allocator(), wl, m_ext.get()); 4071 } 4072 display_assignment(std::ostream & out) const4073 void solver::display_assignment(std::ostream & out) const { 4074 out << m_trail << "\n"; 4075 } 4076 4077 /** 4078 \brief Return true, if c is a clause containing one unassigned literal. 4079 */ is_unit(clause const & c) const4080 bool solver::is_unit(clause const & c) const { 4081 bool found_undef = false; 4082 for (literal l : c) { 4083 switch (value(l)) { 4084 case l_undef: 4085 if (found_undef) 4086 return false; 4087 found_undef = true; 4088 break; 4089 case l_true: 4090 return false; 4091 case l_false: 4092 break; 4093 } 4094 } 4095 return found_undef; 4096 } 4097 4098 /** 4099 \brief Return true, if all literals in c are assigned to false. 4100 */ is_empty(clause const & c) const4101 bool solver::is_empty(clause const & c) const { 4102 for (literal lit : c) 4103 if (value(lit) != l_false) 4104 return false; 4105 return true; 4106 } 4107 check_missed_propagation(clause_vector const & cs) const4108 bool solver::check_missed_propagation(clause_vector const & cs) const { 4109 for (clause* cp : cs) { 4110 clause const & c = *cp; 4111 if (c.frozen()) 4112 continue; 4113 if (is_empty(c) || is_unit(c)) { 4114 TRACE("sat_missed_prop", tout << "missed_propagation: " << c << "\n"; 4115 for (literal l : c) tout << l << ": " << value(l) << "\n";); 4116 UNREACHABLE(); 4117 } 4118 SASSERT(!is_empty(c)); 4119 SASSERT(!is_unit(c)); 4120 } 4121 return true; 4122 } 4123 check_missed_propagation() const4124 bool solver::check_missed_propagation() const { 4125 if (inconsistent()) 4126 return true; 4127 return check_missed_propagation(m_clauses) && check_missed_propagation(m_learned); 4128 } 4129 4130 // ----------------------- 4131 // 4132 // Simplification 4133 // 4134 // ----------------------- do_cleanup(bool force)4135 bool solver::do_cleanup(bool force) { 4136 if (m_conflicts_since_init == 0 && !force) 4137 return false; 4138 if (at_base_lvl() && !inconsistent() && m_cleaner(force)) { 4139 if (m_ext) 4140 m_ext->clauses_modifed(); 4141 return true; 4142 } 4143 return false; 4144 } 4145 simplify(bool redundant)4146 void solver::simplify(bool redundant) { 4147 if (!at_base_lvl() || inconsistent()) 4148 return; 4149 m_simplifier(redundant); 4150 m_simplifier.finalize(); 4151 if (m_ext) 4152 m_ext->clauses_modifed(); 4153 } 4154 scc_bin()4155 unsigned solver::scc_bin() { 4156 if (!at_base_lvl() || inconsistent()) 4157 return 0; 4158 unsigned r = m_scc(); 4159 if (r > 0 && m_ext) 4160 m_ext->clauses_modifed(); 4161 return r; 4162 } 4163 4164 // ----------------------- 4165 // 4166 // Extraction of mutexes 4167 // 4168 // ----------------------- 4169 4170 struct neg_literal { negatesat::neg_literal4171 unsigned negate(unsigned idx) { 4172 return (~to_literal(idx)).index(); 4173 } 4174 }; 4175 find_mutexes(literal_vector const & lits,vector<literal_vector> & mutexes)4176 lbool solver::find_mutexes(literal_vector const& lits, vector<literal_vector> & mutexes) { 4177 max_cliques<neg_literal> mc; 4178 m_user_bin_clauses.reset(); 4179 m_binary_clause_graph.reset(); 4180 collect_bin_clauses(m_user_bin_clauses, true, false); 4181 hashtable<literal_pair, pair_hash<literal_hash, literal_hash>, default_eq<literal_pair> > seen_bc; 4182 for (auto const& b : m_user_bin_clauses) { 4183 literal l1 = b.first; 4184 literal l2 = b.second; 4185 literal_pair p(l1, l2); 4186 if (!seen_bc.contains(p)) { 4187 seen_bc.insert(p); 4188 mc.add_edge(l1.index(), l2.index()); 4189 } 4190 } 4191 vector<unsigned_vector> _mutexes; 4192 literal_vector _lits(lits); 4193 if (m_ext) { 4194 // m_ext->find_mutexes(_lits, mutexes); 4195 } 4196 unsigned_vector ps; 4197 for (literal lit : _lits) { 4198 ps.push_back(lit.index()); 4199 } 4200 mc.cliques(ps, _mutexes); 4201 for (auto const& mux : _mutexes) { 4202 literal_vector clique; 4203 for (auto const& idx : mux) { 4204 clique.push_back(to_literal(idx)); 4205 } 4206 mutexes.push_back(clique); 4207 } 4208 return l_true; 4209 } 4210 4211 // ----------------------- 4212 // 4213 // Consequence generation. 4214 // 4215 // ----------------------- 4216 prune_unfixed(sat::literal_vector & lambda,sat::model const & m)4217 static void prune_unfixed(sat::literal_vector& lambda, sat::model const& m) { 4218 for (unsigned i = 0; i < lambda.size(); ++i) { 4219 if ((m[lambda[i].var()] == l_false) != lambda[i].sign()) { 4220 lambda[i] = lambda.back(); 4221 lambda.pop_back(); 4222 --i; 4223 } 4224 } 4225 } 4226 4227 // Algorithm 7: Corebased Algorithm with Chunking 4228 back_remove(sat::literal_vector & lits,sat::literal l)4229 static void back_remove(sat::literal_vector& lits, sat::literal l) { 4230 for (unsigned i = lits.size(); i > 0; ) { 4231 --i; 4232 if (lits[i] == l) { 4233 lits[i] = lits.back(); 4234 lits.pop_back(); 4235 return; 4236 } 4237 } 4238 UNREACHABLE(); 4239 } 4240 brute_force_consequences(sat::solver & s,sat::literal_vector const & asms,sat::literal_vector const & gamma,vector<sat::literal_vector> & conseq)4241 static void brute_force_consequences(sat::solver& s, sat::literal_vector const& asms, sat::literal_vector const& gamma, vector<sat::literal_vector>& conseq) { 4242 for (literal lit : gamma) { 4243 sat::literal_vector asms1(asms); 4244 asms1.push_back(~lit); 4245 lbool r = s.check(asms1.size(), asms1.data()); 4246 if (r == l_false) { 4247 conseq.push_back(s.get_core()); 4248 } 4249 } 4250 } 4251 core_chunking(sat::solver & s,model const & m,sat::bool_var_vector const & vars,sat::literal_vector const & asms,vector<sat::literal_vector> & conseq,unsigned K)4252 static lbool core_chunking(sat::solver& s, model const& m, sat::bool_var_vector const& vars, sat::literal_vector const& asms, vector<sat::literal_vector>& conseq, unsigned K) { 4253 sat::literal_vector lambda; 4254 for (bool_var v : vars) { 4255 lambda.push_back(sat::literal(v, m[v] == l_false)); 4256 } 4257 while (!lambda.empty()) { 4258 IF_VERBOSE(1, verbose_stream() << "(sat-backbone-core " << lambda.size() << " " << conseq.size() << ")\n";); 4259 unsigned k = std::min(K, lambda.size()); 4260 sat::literal_vector gamma, omegaN; 4261 for (unsigned i = 0; i < k; ++i) { 4262 sat::literal l = lambda[lambda.size() - i - 1]; 4263 gamma.push_back(l); 4264 omegaN.push_back(~l); 4265 } 4266 while (true) { 4267 sat::literal_vector asms1(asms); 4268 asms1.append(omegaN); 4269 lbool r = s.check(asms1.size(), asms1.data()); 4270 if (r == l_true) { 4271 IF_VERBOSE(1, verbose_stream() << "(sat) " << omegaN << "\n";); 4272 prune_unfixed(lambda, s.get_model()); 4273 break; 4274 } 4275 sat::literal_vector const& core = s.get_core(); 4276 sat::literal_vector occurs; 4277 IF_VERBOSE(1, verbose_stream() << "(core " << core.size() << ")\n";); 4278 for (unsigned i = 0; i < omegaN.size(); ++i) { 4279 if (core.contains(omegaN[i])) { 4280 occurs.push_back(omegaN[i]); 4281 } 4282 } 4283 if (occurs.size() == 1) { 4284 sat::literal lit = occurs.back(); 4285 sat::literal nlit = ~lit; 4286 conseq.push_back(core); 4287 back_remove(lambda, ~lit); 4288 back_remove(gamma, ~lit); 4289 s.mk_clause(1, &nlit); 4290 } 4291 for (unsigned i = 0; i < omegaN.size(); ++i) { 4292 if (occurs.contains(omegaN[i])) { 4293 omegaN[i] = omegaN.back(); 4294 omegaN.pop_back(); 4295 --i; 4296 } 4297 } 4298 if (omegaN.empty() && occurs.size() > 1) { 4299 brute_force_consequences(s, asms, gamma, conseq); 4300 for (unsigned i = 0; i < gamma.size(); ++i) { 4301 back_remove(lambda, gamma[i]); 4302 } 4303 break; 4304 } 4305 } 4306 } 4307 return l_true; 4308 } 4309 4310 get_consequences(literal_vector const & asms,bool_var_vector const & vars,vector<literal_vector> & conseq)4311 lbool solver::get_consequences(literal_vector const& asms, bool_var_vector const& vars, vector<literal_vector>& conseq) { 4312 literal_vector lits; 4313 lbool is_sat = l_true; 4314 4315 if (m_config.m_restart_max != UINT_MAX && !m_model_is_current) { 4316 return get_bounded_consequences(asms, vars, conseq); 4317 } 4318 if (!m_model_is_current) { 4319 is_sat = check(asms.size(), asms.data()); 4320 } 4321 if (is_sat != l_true) { 4322 return is_sat; 4323 } 4324 model mdl = get_model(); 4325 for (unsigned i = 0; i < vars.size(); ++i) { 4326 bool_var v = vars[i]; 4327 switch (get_model()[v]) { 4328 case l_true: lits.push_back(literal(v, false)); break; 4329 case l_false: lits.push_back(literal(v, true)); break; 4330 default: break; 4331 } 4332 } 4333 4334 if (false && asms.empty()) { 4335 is_sat = core_chunking(*this, mdl, vars, asms, conseq, 100); 4336 } 4337 else { 4338 is_sat = get_consequences(asms, lits, conseq); 4339 } 4340 set_model(mdl, !mdl.empty()); 4341 return is_sat; 4342 } 4343 fixup_consequence_core()4344 void solver::fixup_consequence_core() { 4345 index_set s; 4346 TRACE("sat", tout << m_core << "\n";); 4347 for (unsigned i = 0; i < m_core.size(); ++i) { 4348 TRACE("sat", tout << m_core[i] << ": "; display_index_set(tout, m_antecedents.find(m_core[i].var())) << "\n";); 4349 s |= m_antecedents.find(m_core[i].var()); 4350 } 4351 m_core.reset(); 4352 for (unsigned idx : s) { 4353 m_core.push_back(to_literal(idx)); 4354 } 4355 TRACE("sat", tout << m_core << "\n";); 4356 } 4357 reached_max_conflicts()4358 bool solver::reached_max_conflicts() { 4359 if (m_config.m_max_conflicts == 0 || m_conflicts_since_init > m_config.m_max_conflicts) { 4360 if (m_reason_unknown != "sat.max.conflicts") { 4361 m_reason_unknown = "sat.max.conflicts"; 4362 IF_VERBOSE(SAT_VB_LVL, verbose_stream() << "(sat \"abort: max-conflicts = " << m_conflicts_since_init << "\")\n";); 4363 } 4364 return !inconsistent(); 4365 } 4366 return false; 4367 } 4368 4369 get_bounded_consequences(literal_vector const & asms,bool_var_vector const & vars,vector<literal_vector> & conseq)4370 lbool solver::get_bounded_consequences(literal_vector const& asms, bool_var_vector const& vars, vector<literal_vector>& conseq) { 4371 bool_var_set unfixed_vars; 4372 unsigned num_units = 0, num_iterations = 0; 4373 for (bool_var v : vars) { 4374 unfixed_vars.insert(v); 4375 } 4376 TRACE("sat", tout << asms << "\n";); 4377 m_antecedents.reset(); 4378 pop_to_base_level(); 4379 if (inconsistent()) return l_false; 4380 flet<bool> _searching(m_searching, true); 4381 init_search(); 4382 propagate(false); 4383 if (inconsistent()) return l_false; 4384 if (asms.empty()) { 4385 bool_var v = mk_var(true, false); 4386 literal lit(v, false); 4387 init_assumptions(1, &lit); 4388 } 4389 else { 4390 init_assumptions(asms.size(), asms.data()); 4391 } 4392 propagate(false); 4393 if (check_inconsistent()) return l_false; 4394 4395 extract_fixed_consequences(num_units, asms, unfixed_vars, conseq); 4396 4397 do_simplify(); 4398 if (check_inconsistent()) { 4399 fixup_consequence_core(); 4400 return l_false; 4401 } 4402 4403 while (true) { 4404 ++num_iterations; 4405 SASSERT(!inconsistent()); 4406 4407 lbool r = bounded_search(); 4408 if (r != l_undef) { 4409 fixup_consequence_core(); 4410 return r; 4411 } 4412 4413 extract_fixed_consequences(num_units, asms, unfixed_vars, conseq); 4414 4415 do_restart(true); 4416 do_simplify(); 4417 if (check_inconsistent()) { 4418 fixup_consequence_core(); 4419 return l_false; 4420 } 4421 do_gc(); 4422 4423 if (should_cancel()) { 4424 return l_undef; 4425 } 4426 } 4427 } 4428 get_consequences(literal_vector const & asms,literal_vector const & lits,vector<literal_vector> & conseq)4429 lbool solver::get_consequences(literal_vector const& asms, literal_vector const& lits, vector<literal_vector>& conseq) { 4430 TRACE("sat", tout << asms << "\n";); 4431 m_antecedents.reset(); 4432 literal_set unfixed_lits(lits), assumptions(asms); 4433 bool_var_set unfixed_vars; 4434 for (literal lit : lits) { 4435 unfixed_vars.insert(lit.var()); 4436 } 4437 4438 pop_to_base_level(); 4439 if (inconsistent()) return l_false; 4440 init_search(); 4441 propagate(false); 4442 if (inconsistent()) return l_false; 4443 if (asms.empty()) { 4444 bool_var v = mk_var(true, false); 4445 literal lit(v, false); 4446 init_assumptions(1, &lit); 4447 } 4448 else { 4449 init_assumptions(asms.size(), asms.data()); 4450 } 4451 propagate(false); 4452 if (check_inconsistent()) return l_false; 4453 SASSERT(search_lvl() == 1); 4454 4455 unsigned num_iterations = 0; 4456 extract_fixed_consequences(unfixed_lits, assumptions, unfixed_vars, conseq); 4457 update_unfixed_literals(unfixed_lits, unfixed_vars); 4458 while (!unfixed_lits.empty()) { 4459 if (scope_lvl() > search_lvl()) { 4460 pop(scope_lvl() - search_lvl()); 4461 } 4462 propagate(false); 4463 ++num_iterations; 4464 checkpoint(); 4465 unsigned num_resolves = 0; 4466 unsigned num_fixed = 0; 4467 unsigned num_assigned = 0; 4468 lbool is_sat = l_true; 4469 for (literal lit : unfixed_lits) { 4470 if (value(lit) != l_undef) { 4471 ++num_fixed; 4472 if (lvl(lit) <= 1 && value(lit) == l_true) { 4473 extract_fixed_consequences(lit, assumptions, unfixed_vars, conseq); 4474 } 4475 continue; 4476 } 4477 push(); 4478 ++num_assigned; 4479 assign_scoped(~lit); 4480 propagate(false); 4481 while (inconsistent()) { 4482 if (!resolve_conflict()) { 4483 TRACE("sat", display(tout << "inconsistent\n");); 4484 m_inconsistent = false; 4485 is_sat = l_undef; 4486 break; 4487 } 4488 propagate(false); 4489 ++num_resolves; 4490 } 4491 } 4492 4493 extract_fixed_consequences(unfixed_lits, assumptions, unfixed_vars, conseq); 4494 4495 if (is_sat == l_true) { 4496 if (scope_lvl() == search_lvl() && num_resolves > 0) { 4497 IF_VERBOSE(1, verbose_stream() << "(sat.get-consequences backjump)\n";); 4498 is_sat = l_undef; 4499 } 4500 else { 4501 is_sat = bounded_search(); 4502 if (is_sat == l_undef) { 4503 do_restart(true); 4504 propagate(false); 4505 } 4506 extract_fixed_consequences(unfixed_lits, assumptions, unfixed_vars, conseq); 4507 } 4508 } 4509 if (is_sat == l_false) { 4510 TRACE("sat", tout << "unsat\n";); 4511 m_inconsistent = false; 4512 } 4513 if (is_sat == l_true) { 4514 delete_unfixed(unfixed_lits, unfixed_vars); 4515 } 4516 update_unfixed_literals(unfixed_lits, unfixed_vars); 4517 IF_VERBOSE(1, verbose_stream() << "(sat.get-consequences" 4518 << " iterations: " << num_iterations 4519 << " variables: " << unfixed_lits.size() 4520 << " fixed: " << conseq.size() 4521 << " status: " << is_sat 4522 << " pre-assigned: " << num_fixed 4523 << " unfixed: " << lits.size() - conseq.size() - unfixed_lits.size() 4524 << ")\n";); 4525 4526 if (!unfixed_lits.empty() && m_config.m_restart_max <= num_iterations) { 4527 return l_undef; 4528 } 4529 } 4530 return l_true; 4531 } 4532 delete_unfixed(literal_set & unfixed_lits,bool_var_set & unfixed_vars)4533 void solver::delete_unfixed(literal_set& unfixed_lits, bool_var_set& unfixed_vars) { 4534 literal_set to_keep; 4535 for (literal lit : unfixed_lits) { 4536 if (value(lit) == l_true) { 4537 to_keep.insert(lit); 4538 } 4539 else { 4540 unfixed_vars.remove(lit.var()); 4541 } 4542 } 4543 unfixed_lits = to_keep; 4544 } 4545 update_unfixed_literals(literal_set & unfixed_lits,bool_var_set & unfixed_vars)4546 void solver::update_unfixed_literals(literal_set& unfixed_lits, bool_var_set& unfixed_vars) { 4547 literal_vector to_delete; 4548 for (literal lit : unfixed_lits) { 4549 if (!unfixed_vars.contains(lit.var())) { 4550 to_delete.push_back(lit); 4551 } 4552 } 4553 for (unsigned i = 0; i < to_delete.size(); ++i) { 4554 unfixed_lits.remove(to_delete[i]); 4555 } 4556 } 4557 4558 extract_fixed_consequences(unsigned & start,literal_set const & assumptions,bool_var_set & unfixed,vector<literal_vector> & conseq)4559 void solver::extract_fixed_consequences(unsigned& start, literal_set const& assumptions, bool_var_set& unfixed, vector<literal_vector>& conseq) { 4560 SASSERT(!inconsistent()); 4561 unsigned sz = m_trail.size(); 4562 for (unsigned i = start; i < sz && lvl(m_trail[i]) <= 1; ++i) { 4563 extract_fixed_consequences(m_trail[i], assumptions, unfixed, conseq); 4564 } 4565 start = sz; 4566 } 4567 extract_fixed_consequences(literal_set const & unfixed_lits,literal_set const & assumptions,bool_var_set & unfixed_vars,vector<literal_vector> & conseq)4568 void solver::extract_fixed_consequences(literal_set const& unfixed_lits, literal_set const& assumptions, bool_var_set& unfixed_vars, vector<literal_vector>& conseq) { 4569 for (literal lit: unfixed_lits) { 4570 TRACE("sat", tout << "extract: " << lit << " " << value(lit) << " " << lvl(lit) << "\n";); 4571 4572 if (lvl(lit) <= 1 && value(lit) == l_true) { 4573 extract_fixed_consequences(lit, assumptions, unfixed_vars, conseq); 4574 } 4575 } 4576 } 4577 check_domain(literal lit,literal lit2)4578 bool solver::check_domain(literal lit, literal lit2) { 4579 if (!m_antecedents.contains(lit2.var())) { 4580 SASSERT(value(lit2) == l_true); 4581 SASSERT(m_todo_antecedents.empty() || m_todo_antecedents.back() != lit2); 4582 m_todo_antecedents.push_back(lit2); 4583 return false; 4584 } 4585 else { 4586 return true; 4587 } 4588 } 4589 extract_assumptions(literal lit,index_set & s)4590 bool solver::extract_assumptions(literal lit, index_set& s) { 4591 justification js = m_justification[lit.var()]; 4592 TRACE("sat", tout << lit << " " << js << "\n";); 4593 bool all_found = true; 4594 switch (js.get_kind()) { 4595 case justification::NONE: 4596 break; 4597 case justification::BINARY: 4598 if (!check_domain(lit, ~js.get_literal())) return false; 4599 s |= m_antecedents.find(js.get_literal().var()); 4600 break; 4601 case justification::TERNARY: 4602 if (!check_domain(lit, ~js.get_literal1()) || 4603 !check_domain(lit, ~js.get_literal2())) return false; 4604 s |= m_antecedents.find(js.get_literal1().var()); 4605 s |= m_antecedents.find(js.get_literal2().var()); 4606 break; 4607 case justification::CLAUSE: { 4608 clause & c = get_clause(js); 4609 for (literal l : c) { 4610 if (l != lit) { 4611 if (check_domain(lit, ~l) && all_found) { 4612 s |= m_antecedents.find(l.var()); 4613 } 4614 else { 4615 all_found = false; 4616 } 4617 } 4618 } 4619 break; 4620 } 4621 case justification::EXT_JUSTIFICATION: { 4622 fill_ext_antecedents(lit, js, true); 4623 for (literal l : m_ext_antecedents) { 4624 if (check_domain(lit, l) && all_found) { 4625 s |= m_antecedents.find(l.var()); 4626 } 4627 else { 4628 all_found = false; 4629 } 4630 } 4631 break; 4632 } 4633 default: 4634 UNREACHABLE(); 4635 break; 4636 } 4637 TRACE("sat", display_index_set(tout << lit << ": " , s) << "\n";); 4638 return all_found; 4639 } 4640 display_index_set(std::ostream & out,index_set const & s) const4641 std::ostream& solver::display_index_set(std::ostream& out, index_set const& s) const { 4642 for (unsigned idx : s) { 4643 out << to_literal(idx) << " "; 4644 } 4645 return out; 4646 } 4647 4648 extract_fixed_consequences1(literal lit,literal_set const & assumptions,bool_var_set & unfixed,vector<literal_vector> & conseq)4649 bool solver::extract_fixed_consequences1(literal lit, literal_set const& assumptions, bool_var_set& unfixed, vector<literal_vector>& conseq) { 4650 index_set s; 4651 if (m_antecedents.contains(lit.var())) { 4652 return true; 4653 } 4654 if (assumptions.contains(lit)) { 4655 s.insert(lit.index()); 4656 } 4657 else { 4658 if (!extract_assumptions(lit, s)) { 4659 SASSERT(!m_todo_antecedents.empty()); 4660 return false; 4661 } 4662 add_assumption(lit); 4663 } 4664 m_antecedents.insert(lit.var(), s); 4665 if (unfixed.contains(lit.var())) { 4666 literal_vector cons; 4667 cons.push_back(lit); 4668 for (unsigned idx : s) { 4669 cons.push_back(to_literal(idx)); 4670 } 4671 unfixed.remove(lit.var()); 4672 conseq.push_back(cons); 4673 } 4674 return true; 4675 } 4676 extract_fixed_consequences(literal lit,literal_set const & assumptions,bool_var_set & unfixed,vector<literal_vector> & conseq)4677 void solver::extract_fixed_consequences(literal lit, literal_set const& assumptions, bool_var_set& unfixed, vector<literal_vector>& conseq) { 4678 SASSERT(m_todo_antecedents.empty()); 4679 m_todo_antecedents.push_back(lit); 4680 while (!m_todo_antecedents.empty()) { 4681 if (extract_fixed_consequences1(m_todo_antecedents.back(), assumptions, unfixed, conseq)) { 4682 m_todo_antecedents.pop_back(); 4683 } 4684 } 4685 } 4686 4687 // ----------------------- 4688 // 4689 // Statistics 4690 // 4691 // ----------------------- 4692 display_status(std::ostream & out) const4693 void solver::display_status(std::ostream & out) const { 4694 unsigned num_bin = 0; 4695 unsigned num_ext = 0; 4696 unsigned num_lits = 0; 4697 unsigned l_idx = 0; 4698 for (watch_list const& wlist : m_watches) { 4699 literal l = ~to_literal(l_idx++); 4700 for (watched const& w : wlist) { 4701 switch (w.get_kind()) { 4702 case watched::BINARY: 4703 if (l.index() < w.get_literal().index()) { 4704 num_lits += 2; 4705 num_bin++; 4706 } 4707 break; 4708 case watched::EXT_CONSTRAINT: 4709 num_ext++; 4710 break; 4711 default: 4712 break; 4713 } 4714 } 4715 } 4716 unsigned num_elim = 0; 4717 for (bool_var v = 0; v < num_vars(); v++) { 4718 if (m_eliminated[v]) 4719 num_elim++; 4720 } 4721 unsigned num_ter = 0; 4722 unsigned num_cls = 0; 4723 clause_vector const * vs[2] = { &m_clauses, &m_learned }; 4724 for (unsigned i = 0; i < 2; i++) { 4725 clause_vector const & cs = *(vs[i]); 4726 for (clause* cp : cs) { 4727 clause & c = *cp; 4728 if (ENABLE_TERNARY && c.size() == 3) 4729 num_ter++; 4730 else 4731 num_cls++; 4732 num_lits += c.size(); 4733 } 4734 } 4735 unsigned total_cls = num_cls + num_ter + num_bin; 4736 double mem = static_cast<double>(memory::get_allocation_size())/static_cast<double>(1024*1024); 4737 out << "(sat-status\n"; 4738 out << " :inconsistent " << (m_inconsistent ? "true" : "false") << "\n"; 4739 out << " :vars " << num_vars() << "\n"; 4740 out << " :elim-vars " << num_elim << "\n"; 4741 out << " :lits " << num_lits << "\n"; 4742 out << " :assigned " << m_trail.size() << "\n"; 4743 out << " :binary-clauses " << num_bin << "\n"; 4744 out << " :ternary-clauses " << num_ter << "\n"; 4745 out << " :clauses " << num_cls << "\n"; 4746 out << " :del-clause " << m_stats.m_del_clause << "\n"; 4747 out << " :avg-clause-size " << (total_cls == 0 ? 0.0 : static_cast<double>(num_lits) / static_cast<double>(total_cls)) << "\n"; 4748 out << " :memory " << std::fixed << std::setprecision(2) << mem << ")" << std::endl; 4749 } 4750 collect_statistics(statistics & st) const4751 void stats::collect_statistics(statistics & st) const { 4752 st.update("sat mk clause 2ary", m_mk_bin_clause); 4753 st.update("sat mk clause 3ary", m_mk_ter_clause); 4754 st.update("sat mk clause nary", m_mk_clause); 4755 st.update("sat mk var", m_mk_var); 4756 st.update("sat gc clause", m_gc_clause); 4757 st.update("sat del clause", m_del_clause); 4758 st.update("sat conflicts", m_conflict); 4759 st.update("sat decisions", m_decision); 4760 st.update("sat propagations 2ary", m_bin_propagate); 4761 st.update("sat propagations 3ary", m_ter_propagate); 4762 st.update("sat propagations nary", m_propagate); 4763 st.update("sat restarts", m_restart); 4764 st.update("sat minimized lits", m_minimized_lits); 4765 st.update("sat subs resolution dyn", m_dyn_sub_res); 4766 st.update("sat blocked correction sets", m_blocked_corr_sets); 4767 st.update("sat units", m_units); 4768 st.update("sat elim bool vars res", m_elim_var_res); 4769 st.update("sat elim bool vars bdd", m_elim_var_bdd); 4770 st.update("sat backjumps", m_backjumps); 4771 st.update("sat backtracks", m_backtracks); 4772 } 4773 reset()4774 void stats::reset() { 4775 memset(this, 0, sizeof(*this)); 4776 } 4777 display(std::ostream & out) const4778 void mk_stat::display(std::ostream & out) const { 4779 unsigned given, redundant; 4780 m_solver.num_binary(given, redundant); 4781 out << " " << std::setw(5) << m_solver.m_clauses.size() + given << "/" << given; 4782 out << " " << std::setw(5) << (m_solver.m_learned.size() + redundant - m_solver.m_num_frozen) << "/" << redundant; 4783 out << " " << std::setw(3) << m_solver.init_trail_size(); 4784 out << " " << std::setw(7) << m_solver.m_stats.m_gc_clause << " "; 4785 out << " " << std::setw(7) << mem_stat(); 4786 } 4787 operator <<(std::ostream & out,mk_stat const & stat)4788 std::ostream & operator<<(std::ostream & out, mk_stat const & stat) { 4789 stat.display(out); 4790 return out; 4791 } 4792 all_distinct(literal_vector const & lits)4793 bool solver::all_distinct(literal_vector const& lits) { 4794 init_visited(); 4795 for (literal l : lits) { 4796 if (is_visited(l.var())) { 4797 return false; 4798 } 4799 mark_visited(l.var()); 4800 } 4801 return true; 4802 } 4803 all_distinct(clause const & c)4804 bool solver::all_distinct(clause const& c) { 4805 init_visited(); 4806 for (literal l : c) { 4807 if (is_visited(l.var())) { 4808 return false; 4809 } 4810 mark_visited(l.var()); 4811 } 4812 return true; 4813 } 4814 init_visited()4815 void solver::init_visited() { 4816 if (m_visited.empty()) { 4817 m_visited_ts = 0; 4818 } 4819 m_visited_ts++; 4820 if (m_visited_ts == 0) { 4821 m_visited_ts = 1; 4822 m_visited.reset(); 4823 } 4824 while (m_visited.size() < 2*num_vars()) { 4825 m_visited.push_back(0); 4826 } 4827 } 4828 4829 4830 4831 }; 4832