1 |
|
/****************************************************************************** |
2 |
|
* Top contributors (to current version): |
3 |
|
* Andrew Reynolds, Francois Bobot, Haniel Barbosa |
4 |
|
* |
5 |
|
* This file is part of the cvc5 project. |
6 |
|
* |
7 |
|
* Copyright (c) 2009-2021 by the authors listed in the file AUTHORS |
8 |
|
* in the top-level source directory and their institutional affiliations. |
9 |
|
* All rights reserved. See the file COPYING in the top-level source |
10 |
|
* directory for licensing information. |
11 |
|
* **************************************************************************** |
12 |
|
* |
13 |
|
* Definition of TPTP parser. |
14 |
|
*/ |
15 |
|
|
16 |
|
// Do not #include "parser/antlr_input.h" directly. Rely on the header. |
17 |
|
#include "parser/tptp/tptp.h" |
18 |
|
|
19 |
|
#include <algorithm> |
20 |
|
#include <set> |
21 |
|
|
22 |
|
#include "api/cpp/cvc5.h" |
23 |
|
#include "base/check.h" |
24 |
|
#include "options/options.h" |
25 |
|
#include "options/options_public.h" |
26 |
|
#include "parser/parser.h" |
27 |
|
#include "smt/command.h" |
28 |
|
#include "theory/logic_info.h" |
29 |
|
|
30 |
|
// ANTLR defines these, which is really bad! |
31 |
|
#undef true |
32 |
|
#undef false |
33 |
|
|
34 |
|
namespace cvc5 { |
35 |
|
namespace parser { |
36 |
|
|
37 |
41 |
Tptp::Tptp(api::Solver* solver, |
38 |
|
SymbolManager* sm, |
39 |
|
bool strictMode, |
40 |
41 |
bool parseOnly) |
41 |
|
: Parser(solver, sm, strictMode, parseOnly), |
42 |
|
d_cnf(false), |
43 |
|
d_fof(false), |
44 |
41 |
d_hol(false) |
45 |
|
{ |
46 |
41 |
addTheory(Tptp::THEORY_CORE); |
47 |
|
|
48 |
|
/* Try to find TPTP dir */ |
49 |
|
// From tptp4x FileUtilities |
50 |
|
//----Try the TPTP directory, and TPTP variations |
51 |
41 |
char* home = getenv("TPTP"); |
52 |
41 |
if(home == NULL) { |
53 |
41 |
home = getenv("TPTP_HOME"); |
54 |
|
// //----If no TPTP_HOME, try the tptp user (aaargh) |
55 |
|
// if(home == NULL && (PasswdEntry = getpwnam("tptp")) != NULL) { |
56 |
|
// home = PasswdEntry->pw_dir; |
57 |
|
// } |
58 |
|
//----Now look in the TPTP directory from there |
59 |
41 |
if(home != NULL) { |
60 |
|
d_tptpDir = home; |
61 |
|
d_tptpDir.append("/TPTP/"); |
62 |
|
} |
63 |
|
} else { |
64 |
|
d_tptpDir = home; |
65 |
|
//add trailing "/" |
66 |
|
if(d_tptpDir[d_tptpDir.size() - 1] != '/') { |
67 |
|
d_tptpDir.append("/"); |
68 |
|
} |
69 |
|
} |
70 |
41 |
d_hasConjecture = false; |
71 |
41 |
} |
72 |
|
|
73 |
123 |
Tptp::~Tptp() { |
74 |
48 |
for( unsigned i=0; i<d_in_created.size(); i++ ){ |
75 |
7 |
d_in_created[i]->free(d_in_created[i]); |
76 |
|
} |
77 |
82 |
} |
78 |
|
|
79 |
41 |
void Tptp::addTheory(Theory theory) { |
80 |
41 |
switch(theory) { |
81 |
41 |
case THEORY_CORE: |
82 |
|
//TPTP (CNF and FOF) is unsorted so we define this common type |
83 |
|
{ |
84 |
82 |
std::string d_unsorted_name = "$$unsorted"; |
85 |
41 |
d_unsorted = d_solver->mkUninterpretedSort(d_unsorted_name); |
86 |
82 |
preemptCommand(new DeclareSortCommand(d_unsorted_name, 0, d_unsorted)); |
87 |
|
} |
88 |
|
// propositionnal |
89 |
41 |
defineType("Bool", d_solver->getBooleanSort()); |
90 |
41 |
defineVar("$true", d_solver->mkTrue()); |
91 |
41 |
defineVar("$false", d_solver->mkFalse()); |
92 |
41 |
addOperator(api::AND); |
93 |
41 |
addOperator(api::EQUAL); |
94 |
41 |
addOperator(api::IMPLIES); |
95 |
|
// addOperator(api::ITE); //only for tff thf |
96 |
41 |
addOperator(api::NOT); |
97 |
41 |
addOperator(api::OR); |
98 |
41 |
addOperator(api::XOR); |
99 |
41 |
addOperator(api::APPLY_UF); |
100 |
|
//Add quantifiers? |
101 |
41 |
break; |
102 |
|
|
103 |
|
default: |
104 |
|
std::stringstream ss; |
105 |
|
ss << "internal error: Tptp::addTheory(): unhandled theory " << theory; |
106 |
|
throw ParserException(ss.str()); |
107 |
|
} |
108 |
41 |
} |
109 |
|
|
110 |
|
|
111 |
|
/* The include are managed in the lexer but called in the parser */ |
112 |
|
// Inspired by http://www.antlr3.org/api/C/interop.html |
113 |
|
|
114 |
7 |
bool newInputStream(std::string fileName, pANTLR3_LEXER lexer, std::vector< pANTLR3_INPUT_STREAM >& inc ) { |
115 |
7 |
Debug("parser") << "Including " << fileName << std::endl; |
116 |
|
// Create a new input stream and take advantage of built in stream stacking |
117 |
|
// in C target runtime. |
118 |
|
// |
119 |
|
pANTLR3_INPUT_STREAM in; |
120 |
|
#ifdef CVC5_ANTLR3_OLD_INPUT_STREAM |
121 |
|
in = antlr3AsciiFileStreamNew((pANTLR3_UINT8) fileName.c_str()); |
122 |
|
#else /* CVC5_ANTLR3_OLD_INPUT_STREAM */ |
123 |
7 |
in = antlr3FileStreamNew((pANTLR3_UINT8) fileName.c_str(), ANTLR3_ENC_8BIT); |
124 |
|
#endif /* CVC5_ANTLR3_OLD_INPUT_STREAM */ |
125 |
7 |
if(in == NULL) { |
126 |
|
Debug("parser") << "Can't open " << fileName << std::endl; |
127 |
|
return false; |
128 |
|
} |
129 |
|
// Same thing as the predefined PUSHSTREAM(in); |
130 |
7 |
lexer->pushCharStream(lexer,in); |
131 |
|
// restart it |
132 |
|
//lexer->rec->state->tokenStartCharIndex = -10; |
133 |
|
//lexer->emit(lexer); |
134 |
|
|
135 |
|
// Note that the input stream is not closed when it EOFs, I don't bother |
136 |
|
// to do it here, but it is up to you to track streams created like this |
137 |
|
// and destroy them when the whole parse session is complete. Remember that you |
138 |
|
// don't want to do this until all tokens have been manipulated all the way through |
139 |
|
// your tree parsers etc as the token does not store the text it just refers |
140 |
|
// back to the input stream and trying to get the text for it will abort if you |
141 |
|
// close the input stream too early. |
142 |
|
// |
143 |
7 |
inc.push_back( in ); |
144 |
|
|
145 |
|
//TODO what said before |
146 |
7 |
return true; |
147 |
|
} |
148 |
|
|
149 |
7 |
void Tptp::includeFile(std::string fileName) { |
150 |
|
// security for online version |
151 |
7 |
if(!canIncludeFile()) { |
152 |
|
parseError("include-file feature was disabled for this run."); |
153 |
|
} |
154 |
|
|
155 |
|
// Get the lexer |
156 |
7 |
AntlrInput * ai = static_cast<AntlrInput *>(getInput()); |
157 |
7 |
pANTLR3_LEXER lexer = ai->getAntlr3Lexer(); |
158 |
|
|
159 |
|
// push the inclusion scope; will be popped by our special popCharStream |
160 |
|
// would be necessary for handling symbol filtering in inclusions |
161 |
|
//pushScope(); |
162 |
|
|
163 |
|
// get the name of the current stream "Does it work inside an include?" |
164 |
7 |
const std::string inputName = ai->getInputStreamName(); |
165 |
|
|
166 |
|
// Test in the directory of the actual parsed file |
167 |
7 |
std::string currentDirFileName; |
168 |
7 |
if(inputName != "<stdin>") { |
169 |
|
// TODO: Use dirname or Boost::filesystem? |
170 |
7 |
size_t pos = inputName.rfind('/'); |
171 |
7 |
if(pos != std::string::npos) { |
172 |
|
currentDirFileName = std::string(inputName, 0, pos + 1); |
173 |
|
} |
174 |
7 |
currentDirFileName.append(fileName); |
175 |
7 |
if(newInputStream(currentDirFileName,lexer, d_in_created)) { |
176 |
7 |
return; |
177 |
|
} |
178 |
|
} else { |
179 |
|
currentDirFileName = "<unknown current directory for stdin>"; |
180 |
|
} |
181 |
|
|
182 |
|
if(d_tptpDir.empty()) { |
183 |
|
parseError("Couldn't open included file: " + fileName |
184 |
|
+ " at " + currentDirFileName + " and the TPTP directory is not specified (environment variable TPTP)"); |
185 |
|
}; |
186 |
|
|
187 |
|
std::string tptpDirFileName = d_tptpDir + fileName; |
188 |
|
if(! newInputStream(tptpDirFileName,lexer, d_in_created)) { |
189 |
|
parseError("Couldn't open included file: " + fileName |
190 |
|
+ " at " + currentDirFileName + " or " + tptpDirFileName); |
191 |
|
} |
192 |
|
} |
193 |
|
|
194 |
3 |
void Tptp::checkLetBinding(const std::vector<api::Term>& bvlist, |
195 |
|
api::Term lhs, |
196 |
|
api::Term rhs, |
197 |
|
bool formula) |
198 |
|
{ |
199 |
3 |
if (lhs.getKind() != api::APPLY_UF) |
200 |
|
{ |
201 |
|
parseError("malformed let: LHS must be a flat function application"); |
202 |
|
} |
203 |
6 |
const std::multiset<api::Term> vars{lhs.begin(), lhs.end()}; |
204 |
3 |
if (formula && !lhs.getSort().isBoolean()) |
205 |
|
{ |
206 |
|
parseError("malformed let: LHS must be formula"); |
207 |
|
} |
208 |
11 |
for (const cvc5::api::Term& var : vars) |
209 |
|
{ |
210 |
8 |
if (var.hasOp()) |
211 |
|
{ |
212 |
|
parseError("malformed let: LHS must be flat, illegal child: " + |
213 |
|
var.toString()); |
214 |
|
} |
215 |
|
} |
216 |
|
|
217 |
|
// ensure all let-bound variables appear on the LHS, and appear only once |
218 |
8 |
for (const api::Term& bound_var : bvlist) |
219 |
|
{ |
220 |
5 |
const size_t count = vars.count(bound_var); |
221 |
5 |
if (count == 0) { |
222 |
|
parseError( |
223 |
|
"malformed let: LHS must make use of all quantified variables, " |
224 |
|
"missing `" + |
225 |
|
bound_var.toString() + "'"); |
226 |
5 |
} else if (count >= 2) { |
227 |
|
parseError("malformed let: LHS cannot use same bound variable twice: " + |
228 |
|
bound_var.toString()); |
229 |
|
} |
230 |
|
} |
231 |
3 |
} |
232 |
|
|
233 |
5236 |
api::Term Tptp::parseOpToExpr(ParseOp& p) |
234 |
|
{ |
235 |
10472 |
api::Term expr; |
236 |
5236 |
if (!p.d_expr.isNull()) |
237 |
|
{ |
238 |
|
return p.d_expr; |
239 |
|
} |
240 |
|
// if it has a kind, it's a builtin one and this function should not have been |
241 |
|
// called |
242 |
5236 |
Assert(p.d_kind == api::NULL_EXPR); |
243 |
5236 |
if (isDeclared(p.d_name)) |
244 |
|
{ // already appeared |
245 |
5152 |
expr = getVariable(p.d_name); |
246 |
|
} |
247 |
|
else |
248 |
|
{ |
249 |
|
api::Sort t = |
250 |
168 |
p.d_type == d_solver->getBooleanSort() ? p.d_type : d_unsorted; |
251 |
84 |
expr = bindVar(p.d_name, t, true); // must define at level zero |
252 |
84 |
preemptCommand(new DeclareFunctionCommand(p.d_name, expr, t)); |
253 |
|
} |
254 |
5236 |
return expr; |
255 |
|
} |
256 |
|
|
257 |
894 |
api::Term Tptp::applyParseOp(ParseOp& p, std::vector<api::Term>& args) |
258 |
|
{ |
259 |
894 |
if (Debug.isOn("parser")) |
260 |
|
{ |
261 |
|
Debug("parser") << "applyParseOp: " << p << " to:" << std::endl; |
262 |
|
for (std::vector<api::Term>::iterator i = args.begin(); i != args.end(); |
263 |
|
++i) |
264 |
|
{ |
265 |
|
Debug("parser") << "++ " << *i << std::endl; |
266 |
|
} |
267 |
|
} |
268 |
894 |
Assert(!args.empty()); |
269 |
|
// If operator already defined, just build application |
270 |
894 |
if (!p.d_expr.isNull()) |
271 |
|
{ |
272 |
|
// this happens with some arithmetic kinds, which are wrapped around |
273 |
|
// lambdas. |
274 |
27 |
args.insert(args.begin(), p.d_expr); |
275 |
27 |
return d_solver->mkTerm(api::APPLY_UF, args); |
276 |
|
} |
277 |
867 |
bool isBuiltinKind = false; |
278 |
|
// the builtin kind of the overall return expression |
279 |
867 |
api::Kind kind = api::NULL_EXPR; |
280 |
|
// First phase: piece operator together |
281 |
867 |
if (p.d_kind == api::NULL_EXPR) |
282 |
|
{ |
283 |
|
// A non-built-in function application, get the expression |
284 |
1010 |
api::Term v; |
285 |
505 |
if (isDeclared(p.d_name)) |
286 |
|
{ // already appeared |
287 |
439 |
v = getVariable(p.d_name); |
288 |
|
} |
289 |
|
else |
290 |
|
{ |
291 |
132 |
std::vector<api::Sort> sorts(args.size(), d_unsorted); |
292 |
|
api::Sort t = |
293 |
132 |
p.d_type == d_solver->getBooleanSort() ? p.d_type : d_unsorted; |
294 |
66 |
t = d_solver->mkFunctionSort(sorts, t); |
295 |
66 |
v = bindVar(p.d_name, t, true); // must define at level zero |
296 |
66 |
preemptCommand(new DeclareFunctionCommand(p.d_name, v, t)); |
297 |
|
} |
298 |
|
// args might be rationals, in which case we need to create |
299 |
|
// distinct constants of the "unsorted" sort to represent them |
300 |
1213 |
for (size_t i = 0; i < args.size(); ++i) |
301 |
|
{ |
302 |
2124 |
if (args[i].getSort().isReal() |
303 |
2124 |
&& v.getSort().getFunctionDomainSorts()[i] == d_unsorted) |
304 |
|
{ |
305 |
|
args[i] = convertRatToUnsorted(args[i]); |
306 |
|
} |
307 |
|
} |
308 |
505 |
Assert(!v.isNull()); |
309 |
505 |
checkFunctionLike(v); |
310 |
505 |
kind = getKindForFunction(v); |
311 |
505 |
args.insert(args.begin(), v); |
312 |
|
} |
313 |
|
else |
314 |
|
{ |
315 |
362 |
kind = p.d_kind; |
316 |
362 |
isBuiltinKind = true; |
317 |
|
} |
318 |
867 |
Assert(kind != api::NULL_EXPR); |
319 |
|
// Second phase: apply parse op to the arguments |
320 |
867 |
if (isBuiltinKind) |
321 |
|
{ |
322 |
362 |
if (!hol() && (kind == api::EQUAL || kind == api::DISTINCT)) |
323 |
|
{ |
324 |
|
// need hol if these operators are applied over function args |
325 |
201 |
for (std::vector<api::Term>::iterator i = args.begin(); i != args.end(); |
326 |
|
++i) |
327 |
|
{ |
328 |
134 |
if ((*i).getSort().isFunction()) |
329 |
|
{ |
330 |
|
parseError("Cannot apply equalty to functions unless THF."); |
331 |
|
} |
332 |
|
} |
333 |
|
} |
334 |
1086 |
if (!strictModeEnabled() && (kind == api::AND || kind == api::OR) |
335 |
424 |
&& args.size() == 1) |
336 |
|
{ |
337 |
|
// Unary AND/OR can be replaced with the argument. |
338 |
|
return args[0]; |
339 |
|
} |
340 |
362 |
if (kind == api::MINUS && args.size() == 1) |
341 |
|
{ |
342 |
|
return d_solver->mkTerm(api::UMINUS, args[0]); |
343 |
|
} |
344 |
362 |
if (kind == api::TO_REAL) |
345 |
|
{ |
346 |
|
// If the type is real, this is a no-op. We require this special |
347 |
|
// case in the TPTP parser since TO_REAL is designed to match the |
348 |
|
// SMT-LIB operator, meaning it can only be applied to integers, whereas |
349 |
|
// the TPTP to_real / to_rat do not have the same semantics. |
350 |
11 |
api::Sort s = args[0].getSort(); |
351 |
8 |
if (s.isReal()) |
352 |
|
{ |
353 |
5 |
return args[0]; |
354 |
|
} |
355 |
|
} |
356 |
357 |
return d_solver->mkTerm(kind, args); |
357 |
|
} |
358 |
|
|
359 |
|
// check if partially applied function, in this case we use HO_APPLY |
360 |
505 |
if (args.size() >= 2) |
361 |
|
{ |
362 |
1010 |
api::Sort argt = args[0].getSort(); |
363 |
505 |
if (argt.isFunction()) |
364 |
|
{ |
365 |
505 |
unsigned arity = argt.getFunctionArity(); |
366 |
505 |
if (args.size() - 1 < arity) |
367 |
|
{ |
368 |
|
if (!hol()) |
369 |
|
{ |
370 |
|
parseError("Cannot partially apply functions unless THF."); |
371 |
|
} |
372 |
|
Debug("parser") << "Partial application of " << args[0]; |
373 |
|
Debug("parser") << " : #argTypes = " << arity; |
374 |
|
Debug("parser") << ", #args = " << args.size() - 1 << std::endl; |
375 |
|
// must curry the partial application |
376 |
|
return d_solver->mkTerm(api::HO_APPLY, args); |
377 |
|
} |
378 |
|
} |
379 |
|
} |
380 |
505 |
return d_solver->mkTerm(kind, args); |
381 |
|
} |
382 |
|
|
383 |
70 |
api::Term Tptp::mkDecimal( |
384 |
|
std::string& snum, std::string& sden, bool pos, size_t exp, bool posE) |
385 |
|
{ |
386 |
|
// the numerator and the denominator |
387 |
140 |
std::stringstream ssn; |
388 |
140 |
std::stringstream ssd; |
389 |
70 |
if (exp != 0) |
390 |
|
{ |
391 |
16 |
if (posE) |
392 |
|
{ |
393 |
|
// see if we need to pad zeros on the end, e.g. 1.2E5 ---> 120000 |
394 |
10 |
if (exp >= sden.size()) |
395 |
|
{ |
396 |
10 |
ssn << snum << sden; |
397 |
4953 |
for (size_t i = 0, nzero = (exp - sden.size()); i < nzero; i++) |
398 |
|
{ |
399 |
4943 |
ssn << "0"; |
400 |
|
} |
401 |
10 |
ssd << "0"; |
402 |
|
} |
403 |
|
else |
404 |
|
{ |
405 |
|
ssn << snum << sden.substr(0, exp); |
406 |
|
ssd << sden.substr(exp); |
407 |
|
} |
408 |
|
} |
409 |
|
else |
410 |
|
{ |
411 |
|
// see if we need to pad zeros on the beginning, e.g. 1.2E-5 ---> 0.000012 |
412 |
6 |
if (exp >= snum.size()) |
413 |
|
{ |
414 |
6 |
ssn << "0"; |
415 |
3300 |
for (size_t i = 0, nzero = (exp - snum.size()); i < nzero; i++) |
416 |
|
{ |
417 |
3294 |
ssd << "0"; |
418 |
|
} |
419 |
6 |
ssd << snum << sden; |
420 |
|
} |
421 |
|
else |
422 |
|
{ |
423 |
|
ssn << snum.substr(0, exp); |
424 |
|
ssd << snum.substr(exp) << sden; |
425 |
|
} |
426 |
|
} |
427 |
|
} |
428 |
|
else |
429 |
|
{ |
430 |
54 |
ssn << snum; |
431 |
54 |
ssd << sden; |
432 |
|
} |
433 |
140 |
std::stringstream ss; |
434 |
70 |
if (!pos) |
435 |
|
{ |
436 |
11 |
ss << "-"; |
437 |
|
} |
438 |
70 |
ss << ssn.str() << "." << ssd.str(); |
439 |
140 |
return d_solver->mkReal(ss.str()); |
440 |
|
} |
441 |
|
|
442 |
362 |
bool Tptp::hol() const { return d_hol; } |
443 |
1315 |
void Tptp::setHol() |
444 |
|
{ |
445 |
1315 |
if (d_hol) |
446 |
|
{ |
447 |
1304 |
return; |
448 |
|
} |
449 |
11 |
d_hol = true; |
450 |
11 |
d_solver->setLogic("HO_UF"); |
451 |
|
} |
452 |
|
|
453 |
1 |
void Tptp::forceLogic(const std::string& logic) |
454 |
|
{ |
455 |
1 |
Parser::forceLogic(logic); |
456 |
1 |
preemptCommand(new SetBenchmarkLogicCommand(logic)); |
457 |
1 |
} |
458 |
|
|
459 |
59 |
void Tptp::addFreeVar(api::Term var) |
460 |
|
{ |
461 |
59 |
Assert(cnf()); |
462 |
59 |
d_freeVar.push_back(var); |
463 |
59 |
} |
464 |
|
|
465 |
85 |
std::vector<api::Term> Tptp::getFreeVar() |
466 |
|
{ |
467 |
85 |
Assert(cnf()); |
468 |
85 |
std::vector<api::Term> r; |
469 |
85 |
r.swap(d_freeVar); |
470 |
85 |
return r; |
471 |
|
} |
472 |
|
|
473 |
42 |
api::Term Tptp::convertRatToUnsorted(api::Term expr) |
474 |
|
{ |
475 |
|
// Create the conversion function If they doesn't exists |
476 |
42 |
if (d_rtu_op.isNull()) { |
477 |
12 |
api::Sort t; |
478 |
|
// Conversion from rational to unsorted |
479 |
6 |
t = d_solver->mkFunctionSort(d_solver->getRealSort(), d_unsorted); |
480 |
6 |
d_rtu_op = d_solver->mkConst(t, "$$rtu"); |
481 |
6 |
preemptCommand(new DeclareFunctionCommand("$$rtu", d_rtu_op, t)); |
482 |
|
// Conversion from unsorted to rational |
483 |
6 |
t = d_solver->mkFunctionSort(d_unsorted, d_solver->getRealSort()); |
484 |
6 |
d_utr_op = d_solver->mkConst(t, "$$utr"); |
485 |
6 |
preemptCommand(new DeclareFunctionCommand("$$utr", d_utr_op, t)); |
486 |
|
} |
487 |
|
// Add the inverse in order to show that over the elements that |
488 |
|
// appear in the problem there is a bijection between unsorted and |
489 |
|
// rational |
490 |
84 |
api::Term ret = d_solver->mkTerm(api::APPLY_UF, d_rtu_op, expr); |
491 |
42 |
if (d_r_converted.find(expr) == d_r_converted.end()) { |
492 |
32 |
d_r_converted.insert(expr); |
493 |
32 |
api::Term eq = d_solver->mkTerm( |
494 |
64 |
api::EQUAL, expr, d_solver->mkTerm(api::APPLY_UF, d_utr_op, ret)); |
495 |
32 |
preemptCommand(new AssertCommand(eq)); |
496 |
|
} |
497 |
84 |
return api::Term(ret); |
498 |
|
} |
499 |
|
|
500 |
6 |
api::Term Tptp::convertStrToUnsorted(std::string str) |
501 |
|
{ |
502 |
6 |
api::Term& e = d_distinct_objects[str]; |
503 |
6 |
if (e.isNull()) |
504 |
|
{ |
505 |
6 |
e = d_solver->mkConst(d_unsorted, str); |
506 |
|
} |
507 |
6 |
return e; |
508 |
|
} |
509 |
|
|
510 |
1 |
api::Term Tptp::mkLambdaWrapper(api::Kind k, api::Sort argType) |
511 |
|
{ |
512 |
2 |
Debug("parser") << "mkLambdaWrapper: kind " << k << " and type " << argType |
513 |
1 |
<< "\n"; |
514 |
2 |
std::vector<api::Term> lvars; |
515 |
2 |
std::vector<api::Sort> domainTypes = argType.getFunctionDomainSorts(); |
516 |
2 |
for (unsigned i = 0, size = domainTypes.size(); i < size; ++i) |
517 |
|
{ |
518 |
|
// the introduced variable is internal (not parsable) |
519 |
2 |
std::stringstream ss; |
520 |
1 |
ss << "_lvar_" << i; |
521 |
2 |
api::Term v = d_solver->mkVar(domainTypes[i], ss.str()); |
522 |
1 |
lvars.push_back(v); |
523 |
|
} |
524 |
|
// apply body of lambda to variables |
525 |
|
api::Term wrapper = |
526 |
1 |
d_solver->mkTerm(api::LAMBDA, |
527 |
2 |
d_solver->mkTerm(api::BOUND_VAR_LIST, lvars), |
528 |
3 |
d_solver->mkTerm(k, lvars)); |
529 |
|
|
530 |
2 |
return wrapper; |
531 |
|
} |
532 |
|
|
533 |
1311 |
api::Term Tptp::getAssertionExpr(FormulaRole fr, api::Term expr) |
534 |
|
{ |
535 |
1311 |
switch (fr) { |
536 |
1286 |
case FR_AXIOM: |
537 |
|
case FR_HYPOTHESIS: |
538 |
|
case FR_DEFINITION: |
539 |
|
case FR_ASSUMPTION: |
540 |
|
case FR_LEMMA: |
541 |
|
case FR_THEOREM: |
542 |
|
case FR_NEGATED_CONJECTURE: |
543 |
|
case FR_PLAIN: |
544 |
|
// it's a usual assert |
545 |
1286 |
return expr; |
546 |
22 |
case FR_CONJECTURE: |
547 |
|
// it should be negated when asserted |
548 |
22 |
return d_solver->mkTerm(api::NOT, expr); |
549 |
3 |
case FR_UNKNOWN: |
550 |
|
case FR_FI_DOMAIN: |
551 |
|
case FR_FI_FUNCTORS: |
552 |
|
case FR_FI_PREDICATES: |
553 |
|
case FR_TYPE: |
554 |
|
// it does not correspond to an assertion |
555 |
3 |
return d_nullExpr; |
556 |
|
break; |
557 |
|
} |
558 |
|
Assert(false); // unreachable |
559 |
|
return d_nullExpr; |
560 |
|
} |
561 |
|
|
562 |
41 |
api::Term Tptp::getAssertionDistinctConstants() |
563 |
|
{ |
564 |
82 |
std::vector<api::Term> constants; |
565 |
47 |
for (std::pair<const std::string, api::Term>& cs : d_distinct_objects) |
566 |
|
{ |
567 |
6 |
constants.push_back(cs.second); |
568 |
|
} |
569 |
41 |
if (constants.size() > 1) |
570 |
|
{ |
571 |
3 |
return d_solver->mkTerm(api::DISTINCT, constants); |
572 |
|
} |
573 |
38 |
return d_nullExpr; |
574 |
|
} |
575 |
|
|
576 |
1311 |
Command* Tptp::makeAssertCommand(FormulaRole fr, api::Term expr, bool cnf) |
577 |
|
{ |
578 |
|
// For SZS ontology compliance. |
579 |
|
// if we're in cnf() though, conjectures don't result in "Theorem" or |
580 |
|
// "CounterSatisfiable". |
581 |
1311 |
if (!cnf && (fr == FR_NEGATED_CONJECTURE || fr == FR_CONJECTURE)) { |
582 |
22 |
d_hasConjecture = true; |
583 |
22 |
Assert(!expr.isNull()); |
584 |
|
} |
585 |
1311 |
if( expr.isNull() ){ |
586 |
3 |
return new EmptyCommand("Untreated role for expression"); |
587 |
|
}else{ |
588 |
1308 |
return new AssertCommand(expr); |
589 |
|
} |
590 |
|
} |
591 |
|
|
592 |
|
} // namespace parser |
593 |
29334 |
} // namespace cvc5 |