1
2 /*
3 * File SMTFormula.cpp.
4 *
5 * This file is part of the source code of the software program
6 * Vampire. It is protected by applicable
7 * copyright laws.
8 *
9 * This source code is distributed under the licence found here
10 * https://vprover.github.io/license.html
11 * and in the source directory
12 *
13 * In summary, you are allowed to use Vampire for non-commercial
14 * purposes but not allowed to distribute, modify, copy, create derivatives,
15 * or use in competitions.
16 * For other uses of Vampire please contact developers for a different
17 * licence, which we will make an effort to provide.
18 */
19 /**
20 * @file SMTFormula.cpp
21 * Implements class SMTFormula.
22 */
23
24 #include <ostream>
25 #include <sstream>
26
27 #include "Lib/Int.hpp"
28 #include "Lib/Metaiterators.hpp"
29 #include "Lib/Sort.hpp"
30 #include "Lib/System.hpp"
31
32 #include "SMTFormula.hpp"
33
34 namespace Shell
35 {
36
unsignedValue(unsigned val)37 SMTConstant SMTFormula::unsignedValue(unsigned val)
38 {
39 CALL("SMTFormula::unsignedValue");
40
41 return SMTConstant(Int::toString(val)+".0");
42 }
43
name(vstring name)44 SMTConstant SMTFormula::name(vstring name)
45 {
46 CALL("SMTFormula::name/1");
47
48 return SMTConstant(name);
49 }
50
name(vstring n1,vstring n2)51 SMTConstant SMTFormula::name(vstring n1, vstring n2)
52 {
53 CALL("SMTFormula::name/2");
54
55 return SMTConstant(n1 + "_" + n2);
56 }
57
58
condNumber(SMTFormula condition,unsigned value)59 SMTFormula SMTFormula::condNumber(SMTFormula condition, unsigned value)
60 {
61 CALL("SMTFormula::condNumber");
62
63 return SMTFormula("(ite " + condition._val + " " + unsignedValue(value)._val + " 0.0)");
64 }
65
66
conjunction(const SMTFormula & f1,const SMTFormula & f2)67 SMTFormula SMTFormula::conjunction(const SMTFormula& f1, const SMTFormula& f2)
68 {
69 CALL("SMTFormula::conjunction");
70
71 if(f1.isTrue()) { return f2; }
72 if(f2.isTrue()) { return f1; }
73 if(f1.isFalse() || f2.isFalse()) { return getFalse(); }
74 return SMTFormula("(and " + f1._val + " " + f2._val + ")");
75 }
76
disjunction(const SMTFormula & f1,const SMTFormula & f2)77 SMTFormula SMTFormula::disjunction(const SMTFormula& f1, const SMTFormula& f2)
78 {
79 CALL("SMTFormula::disjunction");
80
81 if(f1.isFalse()) { return f2; }
82 if(f2.isFalse()) { return f1; }
83 if(f1.isTrue() || f2.isTrue()) { getTrue(); }
84 return SMTFormula("(or " + f1._val + " " + f2._val + ")");
85 }
86
87
88
89 //helper operator implementation for pseudo-operators --> and -=-
90
operator --(int) const91 SMTFormula__HalfImpl SMTFormula::operator--(int) const { return SMTFormula__HalfImpl(*this); }
92
operator -() const93 SMTFormula__HalfEquiv SMTFormula::operator-() const { return SMTFormula__HalfEquiv(*this); }
operator -=(const SMTFormula__HalfEquiv & r) const94 SMTFormula SMTFormula::operator-=(const SMTFormula__HalfEquiv& r) const
95 { return SMTFormula("(= " + _val + " " + r.pf._val + ")"); }
96
97
98
99
100 ///////////////////////
101 // SMTBenchmark
102 //
103
addFormula(const SMTFormula & f,vstring comment)104 void SMTBenchmark::addFormula(const SMTFormula& f, vstring comment)
105 {
106 CALL("SMTBenchmark::addFormula");
107 ASS_EQ(_formulas.size(), _formulaComments.size());
108
109 _formulas.push(f);
110 _formulaComments.push(comment);
111 }
112
113 /**
114 * Remove the most recently added formula
115 */
popFormula()116 void SMTBenchmark::popFormula()
117 {
118 CALL("SMTBenchmark::popFormula");
119 ASS_EQ(_formulas.size(), _formulaComments.size());
120
121 _formulas.pop();
122 _formulaComments.pop();
123 }
124
declarePropositionalConstant(SMTConstant pred)125 void SMTBenchmark::declarePropositionalConstant(SMTConstant pred)
126 {
127 CALL("SMTBenchmark::declarePropositionalConstant");
128 ASS(!_funDecls.find(pred.toString()));
129
130 _predDecls.insert(pred.toString());
131 }
132
declareRealConstant(SMTConstant pred)133 void SMTBenchmark::declareRealConstant(SMTConstant pred)
134 {
135 CALL("SMTBenchmark::declareRealConstant");
136 ASS(!_predDecls.find(pred.toString()));
137
138 _funDecls.insert(pred.toString(), "Real");
139 }
140
output(ostream & out)141 void SMTBenchmark::output(ostream& out)
142 {
143 CALL("SMTBenchmark::output");
144
145 out << "(benchmark VampireGeneratedBenchmark" << endl;
146
147 StringMap::Iterator fdeclIt(_funDecls);
148 while(fdeclIt.hasNext()) {
149 vstring func, fType;
150 fdeclIt.next(func, fType);
151 out << ":extrafuns ((" << func << " " << fType << "))" <<endl;
152 }
153
154 static Stack<vstring> predDeclStack;
155 predDeclStack.reset();
156 predDeclStack.loadFromIterator(_predDecls.iterator());
157 sort<DefaultComparator>(predDeclStack.begin(), predDeclStack.end());
158
159 Stack<vstring>::BottomFirstIterator pdeclIt(predDeclStack);
160 while(pdeclIt.hasNext()) {
161 vstring pred = pdeclIt.next();
162 out << ":extrapreds ((" << pred << "))" <<endl;
163 }
164
165 out << ":formula ( (and " << endl;
166
167 Stack<SMTFormula>::BottomFirstIterator fit(_formulas);
168 Stack<vstring>::BottomFirstIterator fCommentIt(_formulaComments);
169
170 if(!fit.hasNext()) { out << " true" << endl; }
171
172 while(fit.hasNext()) {
173 ALWAYS(fCommentIt.hasNext());
174
175 SMTFormula form = fit.next();
176 vstring comment = fCommentIt.next();
177 out << " " << form.toString();
178 if(comment!="") {
179 out << " ; " << comment;
180 }
181 out << endl;
182 }
183
184 out << ") )" << endl;
185 out << ")" << endl;
186 }
187
188 ///////////////////////
189 // SMTSolver
190 //
191
minimize(SMTBenchmark & problem,SMTConstant costFn,SMTSolverResult & res)192 SMTSolver::MinimizationResult SMTSolver::minimize(SMTBenchmark& problem, SMTConstant costFn, SMTSolverResult& res)
193 {
194 CALL("SMTSolver::minimize");
195
196 bool approx = false;
197
198 unsigned left = 1;
199 unsigned guess = left;
200 while(tryUpperBound(problem, costFn, guess, res)!=SMTSolverResult::SAT) {
201 approx |= res.status==SMTSolverResult::UNKNOWN;
202 unsigned newGuess = guess*2;
203 if(newGuess<=guess) {
204 //we had an overflow
205 cerr << "cost overflow durint SMT minimization" << endl;
206 return FAIL;
207 }
208 left = guess;
209 guess = newGuess;
210 }
211 unsigned right = guess;
212
213 while(left!=right) {
214 unsigned middle = left + (right-left)/2;
215 if(tryUpperBound(problem, costFn, middle, res)==SMTSolverResult::SAT) {
216 right = middle;
217 }
218 else {
219 approx |= res.status==SMTSolverResult::UNKNOWN;
220 left = middle+1;
221 }
222 }
223 tryUpperBound(problem, costFn, left, res);
224 if(res.status==SMTSolverResult::UNKNOWN) {
225 //we don't even have a satisfying assignment
226 return FAIL;
227 }
228 return approx ? APPROXIMATE : EXACT;
229 }
230
tryUpperBound(SMTBenchmark & problem,SMTConstant costFn,unsigned val,SMTSolverResult & res)231 SMTSolverResult::Status SMTSolver::tryUpperBound(SMTBenchmark& problem, SMTConstant costFn, unsigned val, SMTSolverResult& res)
232 {
233 CALL("SMTSolver::tryUpperBound");
234
235 SMTFormula valFormula = SMTFormula::unsignedValue(val);
236 SMTFormula bound = SMTFormula::less(costFn, valFormula);
237
238 problem.addFormula(bound);
239
240 run(problem, res, 2);
241
242 problem.popFormula();
243
244 if(res.status==SMTSolverResult::UNKNOWN) {
245 cerr << "SMT solver gave \"unknown\" for cost value "<< val << "(possibly due to time limit)" << endl;
246 }
247
248 return res.status;
249 }
250
251 ///////////////////////
252 // YicesSolver
253 //
254
run(SMTBenchmark & problem,SMTSolverResult & res,unsigned timeout)255 void YicesSolver::run(SMTBenchmark& problem, SMTSolverResult& res, unsigned timeout)
256 {
257 CALL("YicesSolver::run");
258
259 vostringstream problemStm;
260 problem.output(problemStm);
261
262 static Stack<vstring> proverOut;
263 proverOut.reset();
264
265 vstring execName = System::guessExecutableDirectory()+"/yices";
266 if(!System::fileExists(execName)) {
267 USER_ERROR("Executable "+execName+" does not exist");
268 }
269
270 vstring cmdLine = execName+" -smt -e"; // this works for yices1.0.xx
271 if(timeout!=0) {
272 cmdLine += " --timeout="+Int::toString(timeout);
273 }
274
275 System::executeCommand(cmdLine, problemStm.str(), proverOut);
276
277 res.reset();
278
279 Stack<vstring>::Iterator oit(proverOut);
280 while(oit.hasNext()) {
281 vstring line = oit.next();
282 if(line=="") { continue; }
283 if(line=="sat") { res.status = SMTSolverResult::SAT; continue; }
284 if(line=="unsat") { res.status = SMTSolverResult::UNSAT; continue; }
285 if(line=="unknown") { res.status = SMTSolverResult::UNKNOWN; continue; }
286
287 if(line.substr(0,3)!="(= " || line.substr(line.size()-1,1)!=")") {
288 continue;
289 }
290 vstring lineCore = line.substr(3, line.size()-4);
291 size_t sep = lineCore.find(' ');
292 vstring element = lineCore.substr(0, sep);
293 vstring value = lineCore.substr(sep+1);
294
295 res.assignment.insert(element, value);
296 }
297 }
298
299
300 }
301