/* This file is part of solidity. solidity is free software: you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation, either version 3 of the License, or (at your option) any later version. solidity is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with solidity. If not, see . */ // SPDX-License-Identifier: GPL-3.0 #include #include #include #include #include #include #include #include #include using namespace solidity::util; using std::vector; using std::string; using std::cout; using std::endl; using std::optional; using std::nullopt; using std::stringstream; using std::make_pair; const int verbose = 0; vector cutStringBySpace(string& input); optional> parseLine(std::string& line); std::pair>, size_t> readCNFFile(const string& fname); size_t getNumVars(const vector>& cls); vector cutStringBySpace(string& input) { return input | ranges::views::split(' ') | ranges::to>(); } optional> parseLine(std::string& line) { vector cl; bool end_of_clause = false; for (auto const& part: line | ranges::views::split(' ')) { if (end_of_clause) { cout << "ERROR: trailing elements after finishing `0` at the end of a clause in CNF file" << endl; exit(-1); } const long lit = std::stol(ranges::to(part)); const long var = std::abs(lit); if (var == 0) { //end of clause end_of_clause = true; continue; } assert(var > 0); const Literal l {lit > 0, (size_t)var-1}; cl.push_back(l); } if (verbose) { cout << "cl: "; for (auto const& l: cl) cout << (l.positive ? "" : "-") << (l.variable+1) << " "; cout << " end: " << (int)end_of_clause << endl; } if (end_of_clause) return cl; else return nullopt; } std::pair>, size_t> readCNFFile(const string& fname) { long vars_by_header = -1; long cls_by_header = -1; vector> cls; std::ifstream infile(fname.c_str()); std::string line; while (std::getline(infile, line)) { if (line.empty()) continue; if (line[0] == 'c') continue; if (line[0] == 'p') { assert(line.substr(0,6) == string("p cnf ")); line = line.substr(6); vector parts = cutStringBySpace(line); vars_by_header = std::stol(parts[0]); assert(vars_by_header >= 0); cls_by_header = std::stol(parts[1]); assert(cls_by_header >= 0); continue; } const auto cl = parseLine(line); if (cl) cls.push_back(cl.value()); } if (vars_by_header == -1) { cout << "ERROR: CNF did not have a header" << endl; exit(-1); } assert(cls_by_header >= 0); if (cls.size() != (size_t)cls_by_header) { cout << "ERROR: header said number of clauses will be " << cls_by_header << " but we read " << cls.size() << endl; exit(-1); } return make_pair(cls, (size_t)vars_by_header); } size_t getNumVars(const vector>& cls) { size_t largestVar = 0; for (auto const& cl: cls) for (auto const& l: cl) largestVar = std::max(largestVar, l.variable+1); return largestVar; } int main(int argc, char** argv) { if (argc != 2) { cout << "ERROR: you must give CNF a parameters" << endl; exit(-1); } const string cnf_file_name = argv[1]; auto&& [cls, max_vars_by_header] = readCNFFile(cnf_file_name); const size_t num_vars_by_cls = getNumVars(cls); vector m_variables; if (max_vars_by_header < num_vars_by_cls) { cout << "ERROR: header promises less variables than what clauses say" << endl; exit(-1); } assert(max_vars_by_header >= num_vars_by_cls); for (size_t i = 0; i < max_vars_by_header; i ++) m_variables.push_back(string("x") + std::to_string(i)); auto model = CDCL{m_variables, move(cls)}.solve(); if (model) { const size_t line_break_after = 80; size_t last_line_break = 0; stringstream ss; ss << "v"; for(auto const& m: *model) { if (ss.str().size()-last_line_break > line_break_after) { ss << endl; last_line_break = ss.str().size(); ss << "v"; } ss << " " << (m.second ? "" : "-") << m.first; } cout << ss.str() << " 0" << endl; cout << "s SATISFIABLE" << endl; } else cout << "s UNSATISFIABLE" << endl; return 0; }