mirror of
				https://github.com/ethereum/solidity
				synced 2023-10-03 13:03:40 +00:00 
			
		
		
		
	
		
			
				
	
	
		
			189 lines
		
	
	
		
			4.6 KiB
		
	
	
	
		
			C++
		
	
	
	
	
	
			
		
		
	
	
			189 lines
		
	
	
		
			4.6 KiB
		
	
	
	
		
			C++
		
	
	
	
	
	
/*
 | 
						|
	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 <http://www.gnu.org/licenses/>.
 | 
						|
*/
 | 
						|
// SPDX-License-Identifier: GPL-3.0
 | 
						|
 | 
						|
#include <libsolutil/CDCL.h>
 | 
						|
#include <vector>
 | 
						|
#include <string>
 | 
						|
#include <iostream>
 | 
						|
#include <iomanip>
 | 
						|
#include <fstream>
 | 
						|
#include <sstream>
 | 
						|
#include <range/v3/view/split.hpp>
 | 
						|
#include <range/v3/to_container.hpp>
 | 
						|
 | 
						|
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<string> cutStringBySpace(string& input);
 | 
						|
optional<vector<Literal>> parseLine(std::string& line);
 | 
						|
std::pair<vector<vector<Literal>>, size_t> readCNFFile(const string& fname);
 | 
						|
size_t getNumVars(const vector<vector<Literal>>& cls);
 | 
						|
 | 
						|
 | 
						|
vector<string> cutStringBySpace(string& input)
 | 
						|
{
 | 
						|
    return input | ranges::views::split(' ') | ranges::to<vector<string>>();
 | 
						|
}
 | 
						|
 | 
						|
optional<vector<Literal>> parseLine(std::string& line)
 | 
						|
{
 | 
						|
	vector<Literal> 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<string>(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<vector<vector<Literal>>, size_t> readCNFFile(const string& fname)
 | 
						|
{
 | 
						|
	long vars_by_header = -1;
 | 
						|
	long cls_by_header = -1;
 | 
						|
	vector<vector<Literal>> 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<string> 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<vector<Literal>>& 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<string> 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+1;
 | 
						|
		}
 | 
						|
		cout << ss.str() << " 0" << endl;
 | 
						|
		cout << "s SATISFIABLE" << endl;
 | 
						|
	} else
 | 
						|
		cout << "s UNSATISFIABLE" << endl;
 | 
						|
 | 
						|
	return 0;
 | 
						|
}
 |