1 /** \file
2  * \brief Definition of class Minisat.
3  *
4  * \author Eldor Malessa, Robert Zeranski
5  *
6  * \par License:
7  * This file is part of the Open Graph Drawing Framework (OGDF).
8  *
9  * \par
10  * Copyright (C)<br>
11  * See README.md in the OGDF root directory for details.
12  *
13  * \par
14  * This program is free software; you can redistribute it and/or
15  * modify it under the terms of the GNU General Public License
16  * Version 2 or 3 as published by the Free Software Foundation;
17  * see the file LICENSE.txt included in the packaging of this file
18  * for details.
19  *
20  * \par
21  * This program is distributed in the hope that it will be useful,
22  * but WITHOUT ANY WARRANTY; without even the implied warranty of
23  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
24  * GNU General Public License for more details.
25  *
26  * \par
27  * You should have received a copy of the GNU General Public
28  * License along with this program; if not, see
29  * http://www.gnu.org/copyleft/gpl.html
30  */
31 
32 
33 #include <ogdf/basic/ArrayBuffer.h>
34 #include <ogdf/external/Minisat.h>
35 
36 namespace Minisat
37 {
38 
addMultiple(int Amount,...)39 void Clause::addMultiple(int Amount, ...)
40 {
41 	va_list params;
42 	va_start(params, Amount);
43 	for (int i = 0; i < Amount; ++i) {
44 		Internal::Var paramVar = va_arg(params, Internal::Var);
45 		Internal::Lit l;
46 		if (paramVar >= 0) {
47 			l = Internal::mkLit(paramVar-1, true);
48 		}
49 		else {
50 			l = Internal::mkLit(-(paramVar + 1), false);
51 		}
52 		m_ps.push(l);
53 	}
54 	va_end(params);
55 }
56 
newClause()57 Clause *Formula::newClause()
58 {
59 	m_Clauses.push_back(new Clause);
60 	return m_Clauses.back();
61 
62 }
63 
finalizeClause(const clause cl)64 void Formula::finalizeClause(const clause cl)
65 {
66 	for (int i = 0; i < cl->m_ps.size(); ++i) {
67 		// if an variable does not exist, it will be generated (and all between the gap)
68 		if (!(Internal::var(cl->m_ps[i]) < Solver::nVars())) {
69 			int max = Solver::nVars();
70 			for (int j = 0; j < Internal::var(cl->m_ps[i]) + 1 - max; ++j) {
71 				Solver::newVar();
72 			}
73 		}
74 	}
75 	Solver::addClause(cl->m_ps);
76 }
77 
finalizeNotExtensibleClause(const clause cl)78 bool Formula::finalizeNotExtensibleClause(const clause cl)
79 {
80 	//proves if variables from clause are valid (still known to formula)
81 	for (int i = 0; i < cl->m_ps.size(); ++i) {
82 		if (!(Internal::var(cl->m_ps[i]) < Solver::nVars())) {
83 			m_messages << "Variable " << i << " is not present.";
84 			return false;
85 		}
86 	}
87 	Solver::addClause(cl->m_ps);
88 	return true;
89 }
90 
getClause(const int pos)91 Clause *Formula::getClause( const int pos )
92 {
93 	if ( pos < (int)m_Clauses.size() )
94 		return m_Clauses[pos];
95 	else
96 		return nullptr;
97 }
98 
solve(Model & ReturnModel)99 bool Formula::solve( Model &ReturnModel )
100 {
101 	bool solv = Solver::solve();
102 
103 	if ( solv )
104 		ReturnModel.setModel ( *this );
105 
106 	return solv;
107 }
108 
109 
solve(Model & ReturnModel,double & timeLimit)110 bool Formula::solve( Model &ReturnModel, double& timeLimit )
111 {
112 	SolverStatus st;
113 	bool solv = Solver::solve(timeLimit, st);
114 
115 	if (solv)
116 		ReturnModel.setModel (*this);
117 
118 	ReturnModel.solverStatus = st;
119 
120 	return solv;
121 }
122 
123 
removeClause(int i)124 void Formula::removeClause(int i)
125 {
126 	Internal::CRef cr = Solver::clauses[i];
127 	Solver::removeClause(cr);
128 	int j, k;
129 	for (j = k = 0; j < Solver::clauses.size(); ++j) {
130 		if (j == !i) {
131 			clauses[k++] = clauses[j];
132 		}
133 	}
134 	clauses.shrink( j - k );
135 	delete &m_Clauses[i];
136 	m_Clauses.erase( m_Clauses.begin() + i );
137 }
138 
reset()139 void Formula::reset()
140 {
141 	free();
142 	Solver::assigns.clear();
143 	Solver::vardata.clear();
144 	Solver::activity.clear();
145 	Solver::seen.clear();
146 	Solver::polarity.clear();
147 	Solver::decision.clear();
148 	Solver::trail.clear();
149 	Solver::dec_vars = 0;
150 	Solver::model.clear();
151 }
152 
free()153 void Formula::free()
154 {
155 	for (auto i = 0; i < Solver::clauses.size(); ++i) {
156 		Solver::removeClause(Solver::clauses[i]);
157 	}
158 	for (auto &cl : m_Clauses) {
159 		delete cl;
160 	}
161 	Solver::clauses.shrink(Solver::clauses.size());
162 	m_Clauses.clear();
163 }
164 
readDimacs(const char * filename)165 bool Formula::readDimacs(const char *filename)
166 {
167 	std::ifstream is(filename);
168 	return is.is_open() && readDimacs(is);
169 }
170 
readDimacs(const string & filename)171 bool Formula::readDimacs(const string &filename)
172 {
173 	std::ifstream is(filename);
174 	return is.is_open() && readDimacs(is);
175 }
176 
readDimacs(std::istream & in)177 bool Formula::readDimacs(std::istream &in)
178 {
179 	std::string currentString;
180 
181 	while (!in.eof()) {
182 		in >> currentString;
183 		if (currentString == "p") {
184 			in >> currentString;
185 			if (currentString == "cnf") {
186 				break;
187 			}
188 		}
189 	}
190 	if (in.eof()) {
191 		return false;
192 	}
193 
194 	int numVars = -1;
195 	int numClauses = -1;
196 	in >> numVars >> numClauses;
197 	if (numVars < 0 || numClauses < 0) {
198 		return false;
199 	}
200 	newVars(numVars);
201 
202 	int clauseCount = 0;
203 	ogdf::ArrayBuffer<int> literals;
204 	for (int lit; in >> lit;) {
205 		if (lit) {
206 			if (lit > numVars
207 			 || -lit > numVars) {
208 				ogdf::Logger::slout() << "Literal does not represent a valid variable (index too high)" << std::endl;
209 				return false;
210 			}
211 			literals.push(lit);
212 		} else {
213 			addClause(literals);
214 			literals.clear();
215 			clauseCount++;
216 		}
217 	}
218 	if (!literals.empty()) {
219 		ogdf::Logger::slout(ogdf::Logger::Level::Minor) << "Last clause is not terminated by 0 marker, but we accept it nonetheless" << std::endl;
220 		addClause(literals);
221 	}
222 	if(clauseCount != numClauses) {
223 		ogdf::Logger::slout(ogdf::Logger::Level::Minor) << "Number of clauses differs from file header" << std::endl;
224 	}
225 
226 	return true;
227 }
228 
writeDimacs(const char * filename)229 bool Formula::writeDimacs(const char *filename)
230 {
231 	std::ofstream os(filename);
232 	return os.is_open() && writeDimacs(os);
233 }
234 
writeDimacs(const string & filename)235 bool Formula::writeDimacs(const string &filename)
236 {
237 	std::ofstream os(filename);
238 	return os.is_open() && writeDimacs(os);
239 }
240 
writeDimacs(std::ostream & f)241 bool Formula::writeDimacs(std::ostream &f)
242 {
243 	f << "p cnf " << getVariableCount() << " " << getClauseCount() << std::endl;
244 	for (auto &cl : m_Clauses) {
245 		for (int j = 0; j < cl->m_ps.size(); ++j) {
246 #if defined(OGDF_DEBUG)
247 			std::cout
248 			  << "Sign : "
249 			  << Internal::sign(cl->m_ps[j])
250 			  << "Var : "
251 			  << Internal::var(cl->m_ps[j]) + 1
252 			  << std::endl;
253 #endif
254 			f << " "
255 			  << Clause::convertLitSign(cl->m_ps[j])
256 			  << Internal::var(cl->m_ps[j]) + 1;
257 		}
258 		f << " 0" << std::endl;
259 	}
260 	return true;
261 }
262 
263 }
264