/*++ Copyright (c) 2011 Microsoft Corporation Module Name: dimacs_frontend.cpp Abstract: Frontend for reading dimacs input files Author: Leonardo de Moura (leonardo) 2011-07-26. Revision History: --*/ #include #include #include #include "util/timeout.h" #include "util/rlimit.h" #include "util/gparams.h" #include "sat/dimacs.h" #include "sat/sat_params.hpp" #include "sat/sat_solver.h" #include "sat/tactic/goal2sat.h" #include "ast/reg_decl_plugins.h" #include "tactic/tactic.h" #include "tactic/fd_solver/fd_solver.h" extern bool g_display_statistics; static sat::solver * g_solver = nullptr; static clock_t g_start_time; static tactic_ref g_tac; static statistics g_st; static void display_statistics() { clock_t end_time = clock(); if (g_tac && g_display_statistics) { g_tac->collect_statistics(g_st); } if (g_solver && g_display_statistics) { std::cout.flush(); std::cerr.flush(); g_solver->collect_statistics(g_st); g_st.update("total time", ((static_cast(end_time) - static_cast(g_start_time)) / CLOCKS_PER_SEC)); g_st.display_smt2(std::cout); } g_display_statistics = false; } static void on_timeout() { display_statistics(); _Exit(0); } static void STD_CALL on_ctrl_c(int) { signal (SIGINT, SIG_DFL); display_statistics(); raise(SIGINT); } static void display_model(sat::solver const & s) { sat::model const & m = s.get_model(); std::cout << "v "; for (unsigned i = 1; i < m.size(); i++) { switch (m[i]) { case l_false: std::cout << "-" << i << " "; break; case l_undef: break; case l_true: std::cout << i << " "; break; } } std::cout << "\n"; } static void display_core(sat::solver const& s, vector const& tracking_clauses) { std::cout << "v core\n"; sat::literal_vector const& c = s.get_core(); for (unsigned i = 0; i < c.size(); ++i) { sat::literal_vector const& cls = tracking_clauses[c[i].var()]; for (unsigned j = 0; j < cls.size(); ++j) { std::cout << cls[j] << " "; } std::cout << "\n"; } } static void track_clause(sat::solver& dst, sat::literal_vector& lits, sat::literal_vector& assumptions, vector& tracking_clauses) { sat::literal lit = sat::literal(dst.mk_var(true, false), false); tracking_clauses.set(lit.var(), lits); lits.push_back(~lit); dst.mk_clause(lits.size(), lits.data()); assumptions.push_back(lit); } static void track_clauses(sat::solver const& src, sat::solver& dst, sat::literal_vector& assumptions, vector& tracking_clauses) { for (sat::bool_var v = 0; v < src.num_vars(); ++v) { dst.mk_var(false, true); } sat::literal_vector lits; sat::literal lit; sat::clause * const * it = src.begin_clauses(); sat::clause * const * end = src.end_clauses(); svector bin_clauses; src.collect_bin_clauses(bin_clauses, false, false); tracking_clauses.reserve(2*src.num_vars() + static_cast(end - it) + bin_clauses.size()); for (sat::bool_var v = 1; v < src.num_vars(); ++v) { if (src.value(v) != l_undef) { bool sign = src.value(v) == l_false; lits.reset(); lits.push_back(sat::literal(v, sign)); track_clause(dst, lits, assumptions, tracking_clauses); } } for (; it != end; ++it) { lits.reset(); sat::clause& cls = *(*it); lits.append(static_cast(cls.end()-cls.begin()), cls.begin()); track_clause(dst, lits, assumptions, tracking_clauses); } for (unsigned i = 0; i < bin_clauses.size(); ++i) { lits.reset(); lits.push_back(bin_clauses[i].first); lits.push_back(bin_clauses[i].second); track_clause(dst, lits, assumptions, tracking_clauses); } } void verify_solution(char const * file_name) { params_ref p = gparams::get_module("sat"); p.set_bool("produce_models", true); reslimit limit; sat::solver solver(p, limit); std::ifstream in(file_name); if (in.bad() || in.fail()) { std::cerr << "(error \"failed to open file '" << file_name << "'\")" << std::endl; exit(ERR_OPEN_FILE); } parse_dimacs(in, std::cerr, solver); sat::model const & m = g_solver->get_model(); for (unsigned i = 1; i < m.size(); i++) { sat::literal lit(i, false); switch (m[i]) { case l_false: lit.neg(); break; case l_undef: break; case l_true: break; } solver.mk_clause(1, &lit); } lbool r = solver.check(); switch (r) { case l_false: std::cout << "model checking failed\n"; break; case l_true: std::cout << "model validated\n"; break; default: std::cout << "inconclusive model\n"; break; } } lbool solve_parallel(sat::solver& s) { params_ref p = gparams::get_module("sat"); ast_manager m; reg_decl_plugins(m); sat2goal s2g; ref mc; atom2bool_var a2b(m); for (unsigned v = 0; v < s.num_vars(); ++v) { a2b.insert(m.mk_const(symbol(v), m.mk_bool_sort()), v); } goal_ref g = alloc(goal, m); s2g(s, a2b, p, *g, mc); g_tac = mk_parallel_qffd_tactic(m, p); std::string reason_unknown; model_ref md; labels_vec labels; proof_ref pr(m); expr_dependency_ref core(m); lbool r = check_sat(*g_tac, g, md, labels, pr, core, reason_unknown); switch (r) { case l_true: if (gparams::get_ref().get_bool("model_validate", false)) { // populate the SAT solver with the model obtained from parallel execution. for (auto const& kv : a2b) { sat::literal lit; bool is_true = m.is_true((*md)(kv.m_key)); lit = sat::literal(kv.m_value, !is_true); s.mk_clause(1, &lit); } // VERIFY(l_true == s.check()); } break; case l_false: break; default: break; } display_statistics(); g_display_statistics = false; g_tac = nullptr; return r; } unsigned read_dimacs(char const * file_name) { g_start_time = clock(); register_on_timeout_proc(on_timeout); signal(SIGINT, on_ctrl_c); params_ref p = gparams::get_module("sat"); params_ref par = gparams::get_module("parallel"); p.set_bool("produce_models", true); p.set_bool("cardinality.solver", false); sat_params sp(p); reslimit limit; sat::solver solver(p, limit); g_solver = &solver; if (file_name) { std::ifstream in(file_name); if (in.bad() || in.fail()) { std::cerr << "(error \"failed to open file '" << file_name << "'\")" << std::endl; exit(ERR_OPEN_FILE); } parse_dimacs(in, std::cerr, solver); } else { parse_dimacs(std::cin, std::cerr, solver); } IF_VERBOSE(20, solver.display_status(verbose_stream());); lbool r; vector tracking_clauses; params_ref p2; p2.copy(p); p2.set_sym("drat.file", symbol::null); sat::solver solver2(p2, limit); if (p.get_bool("dimacs.core", false)) { g_solver = &solver2; sat::literal_vector assumptions; track_clauses(solver, solver2, assumptions, tracking_clauses); r = g_solver->check(assumptions.size(), assumptions.data()); } else if (par.get_bool("enable", false)) { r = solve_parallel(solver); } else { r = g_solver->check(); } switch (r) { case l_true: std::cout << "s SATISFIABLE\n"; if (file_name && gparams::get_ref().get_bool("model_validate", false)) verify_solution(file_name); display_model(*g_solver); break; case l_undef: std::cout << "s UNKNOWN\n"; break; case l_false: std::cout << "s UNSATISFIABLE\n"; if (p.get_bool("dimacs.core", false)) { display_core(*g_solver, tracking_clauses); } break; } display_statistics(); return 0; }