1 |
|
/****************************************************************************** |
2 |
|
* Top contributors (to current version): |
3 |
|
* Andrew Reynolds, Andres Noetzli, Mathias Preiner |
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 |
|
* Implementation of term database sygus class. |
14 |
|
*/ |
15 |
|
|
16 |
|
#include "theory/quantifiers/sygus/term_database_sygus.h" |
17 |
|
|
18 |
|
#include <sstream> |
19 |
|
|
20 |
|
#include "base/check.h" |
21 |
|
#include "expr/dtype_cons.h" |
22 |
|
#include "expr/skolem_manager.h" |
23 |
|
#include "expr/sygus_datatype.h" |
24 |
|
#include "options/base_options.h" |
25 |
|
#include "options/datatypes_options.h" |
26 |
|
#include "options/quantifiers_options.h" |
27 |
|
#include "printer/printer.h" |
28 |
|
#include "theory/datatypes/sygus_datatype_utils.h" |
29 |
|
#include "theory/quantifiers/quantifiers_attributes.h" |
30 |
|
#include "theory/quantifiers/quantifiers_inference_manager.h" |
31 |
|
#include "theory/quantifiers/quantifiers_state.h" |
32 |
|
#include "theory/quantifiers/term_util.h" |
33 |
|
#include "theory/rewriter.h" |
34 |
|
|
35 |
|
using namespace cvc5::kind; |
36 |
|
|
37 |
|
namespace cvc5 { |
38 |
|
namespace theory { |
39 |
|
namespace quantifiers { |
40 |
|
|
41 |
|
std::ostream& operator<<(std::ostream& os, EnumeratorRole r) |
42 |
|
{ |
43 |
|
switch (r) |
44 |
|
{ |
45 |
|
case ROLE_ENUM_POOL: os << "POOL"; break; |
46 |
|
case ROLE_ENUM_SINGLE_SOLUTION: os << "SINGLE_SOLUTION"; break; |
47 |
|
case ROLE_ENUM_MULTI_SOLUTION: os << "MULTI_SOLUTION"; break; |
48 |
|
case ROLE_ENUM_CONSTRAINED: os << "CONSTRAINED"; break; |
49 |
|
default: os << "enum_" << static_cast<unsigned>(r); break; |
50 |
|
} |
51 |
|
return os; |
52 |
|
} |
53 |
|
|
54 |
1151 |
TermDbSygus::TermDbSygus(QuantifiersState& qs) |
55 |
|
: d_qstate(qs), |
56 |
1151 |
d_syexp(new SygusExplain(this)), |
57 |
1151 |
d_ext_rw(new ExtendedRewriter(true)), |
58 |
1151 |
d_eval(new Evaluator), |
59 |
1151 |
d_funDefEval(new FunDefEvaluator), |
60 |
5755 |
d_eval_unfold(new SygusEvalUnfold(this)) |
61 |
|
{ |
62 |
1151 |
d_true = NodeManager::currentNM()->mkConst( true ); |
63 |
1151 |
d_false = NodeManager::currentNM()->mkConst( false ); |
64 |
1151 |
} |
65 |
|
|
66 |
1151 |
void TermDbSygus::finishInit(QuantifiersInferenceManager* qim) { d_qim = qim; } |
67 |
|
|
68 |
|
bool TermDbSygus::reset( Theory::Effort e ) { |
69 |
|
return true; |
70 |
|
} |
71 |
|
|
72 |
143080 |
TNode TermDbSygus::getFreeVar( TypeNode tn, int i, bool useSygusType ) { |
73 |
143080 |
unsigned sindex = 0; |
74 |
286160 |
TypeNode vtn = tn; |
75 |
286160 |
TypeNode builtinType = tn; |
76 |
143080 |
if (tn.isDatatype()) |
77 |
|
{ |
78 |
140373 |
const DType& dt = tn.getDType(); |
79 |
140373 |
if (!dt.getSygusType().isNull()) |
80 |
|
{ |
81 |
140373 |
builtinType = dt.getSygusType(); |
82 |
140373 |
if (useSygusType) |
83 |
|
{ |
84 |
15081 |
vtn = builtinType; |
85 |
15081 |
sindex = 1; |
86 |
|
} |
87 |
|
} |
88 |
|
} |
89 |
143080 |
NodeManager* nm = NodeManager::currentNM(); |
90 |
156824 |
while( i>=(int)d_fv[sindex][tn].size() ){ |
91 |
13744 |
std::stringstream ss; |
92 |
6872 |
if( tn.isDatatype() ){ |
93 |
4087 |
const DType& dt = tn.getDType(); |
94 |
4087 |
ss << "fv_" << dt.getName() << "_" << i; |
95 |
|
}else{ |
96 |
2785 |
ss << "fv_" << tn << "_" << i; |
97 |
|
} |
98 |
6872 |
Assert(!vtn.isNull()); |
99 |
13744 |
Node v = nm->mkBoundVar(ss.str(), vtn); |
100 |
|
// store its id, which is unique per builtin type, regardless of how it is |
101 |
|
// otherwise cached. |
102 |
6872 |
d_fvId[v] = d_fvTypeIdCounter[builtinType]; |
103 |
6872 |
d_fvTypeIdCounter[builtinType]++; |
104 |
13744 |
Trace("sygus-db-debug") << "Free variable id " << v << " = " << d_fvId[v] |
105 |
6872 |
<< ", " << builtinType << std::endl; |
106 |
6872 |
d_fv[sindex][tn].push_back( v ); |
107 |
|
} |
108 |
286160 |
return d_fv[sindex][tn][i]; |
109 |
|
} |
110 |
|
|
111 |
87749 |
TNode TermDbSygus::getFreeVarInc( TypeNode tn, std::map< TypeNode, int >& var_count, bool useSygusType ) { |
112 |
87749 |
std::map< TypeNode, int >::iterator it = var_count.find( tn ); |
113 |
87749 |
if( it==var_count.end() ){ |
114 |
34773 |
var_count[tn] = 1; |
115 |
34773 |
return getFreeVar( tn, 0, useSygusType ); |
116 |
|
}else{ |
117 |
52976 |
int index = it->second; |
118 |
52976 |
var_count[tn]++; |
119 |
52976 |
return getFreeVar( tn, index, useSygusType ); |
120 |
|
} |
121 |
|
} |
122 |
|
|
123 |
2602 |
bool TermDbSygus::isFreeVar(Node n) const |
124 |
|
{ |
125 |
2602 |
return d_fvId.find(n) != d_fvId.end(); |
126 |
|
} |
127 |
2593 |
size_t TermDbSygus::getFreeVarId(Node n) const |
128 |
|
{ |
129 |
2593 |
std::map<Node, size_t>::const_iterator it = d_fvId.find(n); |
130 |
2593 |
if (it == d_fvId.end()) |
131 |
|
{ |
132 |
|
Assert(false) << "TermDbSygus::isFreeVar: " << n |
133 |
|
<< " is not a cached free variable."; |
134 |
|
return 0; |
135 |
|
} |
136 |
2593 |
return it->second; |
137 |
|
} |
138 |
|
|
139 |
9 |
bool TermDbSygus::hasFreeVar( Node n, std::map< Node, bool >& visited ){ |
140 |
9 |
if( visited.find( n )==visited.end() ){ |
141 |
9 |
visited[n] = true; |
142 |
9 |
if( isFreeVar( n ) ){ |
143 |
9 |
return true; |
144 |
|
} |
145 |
|
for( unsigned i=0; i<n.getNumChildren(); i++ ){ |
146 |
|
if( hasFreeVar( n[i], visited ) ){ |
147 |
|
return true; |
148 |
|
} |
149 |
|
} |
150 |
|
} |
151 |
|
return false; |
152 |
|
} |
153 |
|
|
154 |
9 |
bool TermDbSygus::hasFreeVar( Node n ) { |
155 |
18 |
std::map< Node, bool > visited; |
156 |
18 |
return hasFreeVar( n, visited ); |
157 |
|
} |
158 |
|
|
159 |
22 |
Node TermDbSygus::getProxyVariable(TypeNode tn, Node c) |
160 |
|
{ |
161 |
22 |
Assert(tn.isDatatype()); |
162 |
22 |
Assert(tn.getDType().isSygus()); |
163 |
22 |
Assert(tn.getDType().getSygusType().isComparableTo(c.getType())); |
164 |
|
|
165 |
22 |
std::map<Node, Node>::iterator it = d_proxy_vars[tn].find(c); |
166 |
22 |
if (it == d_proxy_vars[tn].end()) |
167 |
|
{ |
168 |
18 |
SygusTypeInfo& ti = getTypeInfo(tn); |
169 |
18 |
int anyC = ti.getAnyConstantConsNum(); |
170 |
18 |
NodeManager* nm = NodeManager::currentNM(); |
171 |
36 |
Node k; |
172 |
18 |
if (anyC == -1) |
173 |
|
{ |
174 |
|
SkolemManager* sm = nm->getSkolemManager(); |
175 |
|
k = sm->mkDummySkolem("sy", tn, "sygus proxy"); |
176 |
|
SygusPrintProxyAttribute spa; |
177 |
|
k.setAttribute(spa, c); |
178 |
|
} |
179 |
|
else |
180 |
|
{ |
181 |
18 |
const DType& dt = tn.getDType(); |
182 |
18 |
k = nm->mkNode(APPLY_CONSTRUCTOR, dt[anyC].getConstructor(), c); |
183 |
|
} |
184 |
18 |
d_proxy_vars[tn][c] = k; |
185 |
18 |
return k; |
186 |
|
} |
187 |
4 |
return it->second; |
188 |
|
} |
189 |
|
|
190 |
517901 |
Node TermDbSygus::mkGeneric(const DType& dt, |
191 |
|
unsigned c, |
192 |
|
std::map<TypeNode, int>& var_count, |
193 |
|
std::map<int, Node>& pre, |
194 |
|
bool doBetaRed) |
195 |
|
{ |
196 |
517901 |
Assert(c < dt.getNumConstructors()); |
197 |
517901 |
Assert(dt.isSygus()); |
198 |
517901 |
Assert(!dt[c].getSygusOp().isNull()); |
199 |
1035802 |
std::vector< Node > children; |
200 |
1035802 |
Trace("sygus-db-debug") << "mkGeneric " << dt.getName() << " " << c << "..." |
201 |
517901 |
<< std::endl; |
202 |
1233687 |
for (unsigned i = 0, nargs = dt[c].getNumArgs(); i < nargs; i++) |
203 |
|
{ |
204 |
1431572 |
Node a; |
205 |
715786 |
std::map< int, Node >::iterator it = pre.find( i ); |
206 |
715786 |
if( it!=pre.end() ){ |
207 |
701637 |
a = it->second; |
208 |
701637 |
Trace("sygus-db-debug") << "From pre: " << a << std::endl; |
209 |
|
}else{ |
210 |
28298 |
TypeNode tna = dt[c].getArgType(i); |
211 |
14149 |
a = getFreeVarInc( tna, var_count, true ); |
212 |
|
} |
213 |
1431572 |
Trace("sygus-db-debug") |
214 |
715786 |
<< " child " << i << " : " << a << " : " << a.getType() << std::endl; |
215 |
715786 |
Assert(!a.isNull()); |
216 |
715786 |
children.push_back( a ); |
217 |
|
} |
218 |
517901 |
Node ret = datatypes::utils::mkSygusTerm(dt, c, children, doBetaRed); |
219 |
517901 |
Trace("sygus-db-debug") << "mkGeneric returns " << ret << std::endl; |
220 |
1035802 |
return ret; |
221 |
|
} |
222 |
|
|
223 |
517901 |
Node TermDbSygus::mkGeneric(const DType& dt, |
224 |
|
int c, |
225 |
|
std::map<int, Node>& pre, |
226 |
|
bool doBetaRed) |
227 |
|
{ |
228 |
1035802 |
std::map<TypeNode, int> var_count; |
229 |
1035802 |
return mkGeneric(dt, c, var_count, pre, doBetaRed); |
230 |
|
} |
231 |
|
|
232 |
10695 |
Node TermDbSygus::mkGeneric(const DType& dt, int c, bool doBetaRed) |
233 |
|
{ |
234 |
21390 |
std::map<int, Node> pre; |
235 |
21390 |
return mkGeneric(dt, c, pre, doBetaRed); |
236 |
|
} |
237 |
|
|
238 |
|
struct CanonizeBuiltinAttributeId |
239 |
|
{ |
240 |
|
}; |
241 |
|
using CanonizeBuiltinAttribute = |
242 |
|
expr::Attribute<CanonizeBuiltinAttributeId, Node>; |
243 |
|
|
244 |
|
Node TermDbSygus::canonizeBuiltin(Node n) |
245 |
|
{ |
246 |
|
std::map<TypeNode, int> var_count; |
247 |
|
return canonizeBuiltin(n, var_count); |
248 |
|
} |
249 |
|
|
250 |
42033 |
Node TermDbSygus::canonizeBuiltin(Node n, std::map<TypeNode, int>& var_count) |
251 |
|
{ |
252 |
|
// has it already been computed? |
253 |
42033 |
if (var_count.empty() && n.hasAttribute(CanonizeBuiltinAttribute())) |
254 |
|
{ |
255 |
68536 |
Node ret = n.getAttribute(CanonizeBuiltinAttribute()); |
256 |
34268 |
Trace("sygus-db-canon") << "cached " << n << " : " << ret << "\n"; |
257 |
34268 |
return ret; |
258 |
|
} |
259 |
7765 |
Trace("sygus-db-canon") << " CanonizeBuiltin : compute for " << n << "\n"; |
260 |
15530 |
Node ret = n; |
261 |
|
// it is symbolic if it represents "any constant" |
262 |
7765 |
if (n.getKind() == APPLY_SELECTOR_TOTAL) |
263 |
|
{ |
264 |
976 |
ret = getFreeVarInc(n[0].getType(), var_count, true); |
265 |
|
} |
266 |
6789 |
else if (n.getKind() != APPLY_CONSTRUCTOR) |
267 |
|
{ |
268 |
|
ret = n; |
269 |
|
} |
270 |
|
else |
271 |
|
{ |
272 |
6789 |
Assert(n.getKind() == APPLY_CONSTRUCTOR); |
273 |
6789 |
bool childChanged = false; |
274 |
13578 |
std::vector<Node> children; |
275 |
6789 |
children.push_back(n.getOperator()); |
276 |
17440 |
for (unsigned j = 0, size = n.getNumChildren(); j < size; ++j) |
277 |
|
{ |
278 |
21302 |
Node child = canonizeBuiltin(n[j], var_count); |
279 |
10651 |
children.push_back(child); |
280 |
10651 |
childChanged = childChanged || child != n[j]; |
281 |
|
} |
282 |
6789 |
if (childChanged) |
283 |
|
{ |
284 |
1384 |
ret = NodeManager::currentNM()->mkNode(APPLY_CONSTRUCTOR, children); |
285 |
|
} |
286 |
|
} |
287 |
|
// cache if we had a fresh variable count |
288 |
7765 |
if (var_count.empty()) |
289 |
|
{ |
290 |
5316 |
n.setAttribute(CanonizeBuiltinAttribute(), ret); |
291 |
|
} |
292 |
15530 |
Trace("sygus-db-canon") << " ...normalized " << n << " --> " << ret |
293 |
7765 |
<< std::endl; |
294 |
7765 |
Assert(ret.getType().isComparableTo(n.getType())); |
295 |
7765 |
return ret; |
296 |
|
} |
297 |
|
|
298 |
|
struct SygusToBuiltinAttributeId |
299 |
|
{ |
300 |
|
}; |
301 |
|
typedef expr::Attribute<SygusToBuiltinAttributeId, Node> |
302 |
|
SygusToBuiltinAttribute; |
303 |
|
|
304 |
42353 |
Node TermDbSygus::sygusToBuiltin(Node n, TypeNode tn) |
305 |
|
{ |
306 |
42353 |
if (n.isConst()) |
307 |
|
{ |
308 |
|
// if its a constant, we use the datatype utility version |
309 |
30833 |
return datatypes::utils::sygusToBuiltin(n); |
310 |
|
} |
311 |
11520 |
Assert(n.getType().isComparableTo(tn)); |
312 |
11520 |
if (!tn.isDatatype()) |
313 |
|
{ |
314 |
77 |
return n; |
315 |
|
} |
316 |
|
// has it already been computed? |
317 |
11443 |
if (n.hasAttribute(SygusToBuiltinAttribute())) |
318 |
|
{ |
319 |
4220 |
return n.getAttribute(SygusToBuiltinAttribute()); |
320 |
|
} |
321 |
14446 |
Trace("sygus-db-debug") << "SygusToBuiltin : compute for " << n |
322 |
7223 |
<< ", type = " << tn << std::endl; |
323 |
7223 |
const DType& dt = tn.getDType(); |
324 |
7223 |
if (!dt.isSygus()) |
325 |
|
{ |
326 |
|
return n; |
327 |
|
} |
328 |
7223 |
if (n.getKind() == APPLY_CONSTRUCTOR) |
329 |
|
{ |
330 |
4630 |
unsigned i = datatypes::utils::indexOf(n.getOperator()); |
331 |
4630 |
Assert(n.getNumChildren() == dt[i].getNumArgs()); |
332 |
9260 |
std::map<int, Node> pre; |
333 |
14112 |
for (unsigned j = 0, size = n.getNumChildren(); j < size; j++) |
334 |
|
{ |
335 |
9482 |
pre[j] = sygusToBuiltin(n[j], dt[i].getArgType(j)); |
336 |
18964 |
Trace("sygus-db-debug") |
337 |
9482 |
<< "sygus to builtin " << n[j] << " is " << pre[j] << std::endl; |
338 |
|
} |
339 |
9260 |
Node ret = mkGeneric(dt, i, pre); |
340 |
9260 |
Trace("sygus-db-debug") |
341 |
4630 |
<< "SygusToBuiltin : Generic is " << ret << std::endl; |
342 |
|
// cache |
343 |
4630 |
n.setAttribute(SygusToBuiltinAttribute(), ret); |
344 |
4630 |
return ret; |
345 |
|
} |
346 |
2593 |
if (n.hasAttribute(SygusPrintProxyAttribute())) |
347 |
|
{ |
348 |
|
// this variable was associated by an attribute to a builtin node |
349 |
|
return n.getAttribute(SygusPrintProxyAttribute()); |
350 |
|
} |
351 |
2593 |
Assert(isFreeVar(n)); |
352 |
|
// map to builtin variable type |
353 |
2593 |
size_t fv_num = getFreeVarId(n); |
354 |
2593 |
Assert(!dt.getSygusType().isNull()); |
355 |
5186 |
TypeNode vtn = dt.getSygusType(); |
356 |
5186 |
Node ret = getFreeVar(vtn, fv_num); |
357 |
5186 |
Trace("sygus-db-debug") << "SygusToBuiltin: variable for " << n << " is " |
358 |
2593 |
<< ret << ", fv_num=" << fv_num << std::endl; |
359 |
2593 |
return ret; |
360 |
|
} |
361 |
|
|
362 |
13325 |
bool TermDbSygus::registerSygusType(TypeNode tn) |
363 |
|
{ |
364 |
13325 |
std::map<TypeNode, bool>::iterator it = d_registerStatus.find(tn); |
365 |
13325 |
if (it != d_registerStatus.end()) |
366 |
|
{ |
367 |
|
// already registered |
368 |
11464 |
return it->second; |
369 |
|
} |
370 |
1861 |
d_registerStatus[tn] = false; |
371 |
|
// it must be a sygus datatype |
372 |
1861 |
if (!tn.isDatatype()) |
373 |
|
{ |
374 |
36 |
return false; |
375 |
|
} |
376 |
1825 |
const DType& dt = tn.getDType(); |
377 |
1825 |
if (!dt.isSygus()) |
378 |
|
{ |
379 |
|
return false; |
380 |
|
} |
381 |
1825 |
d_registerStatus[tn] = true; |
382 |
1825 |
SygusTypeInfo& sti = d_tinfo[tn]; |
383 |
1825 |
sti.initialize(this, tn); |
384 |
1825 |
return true; |
385 |
|
} |
386 |
|
|
387 |
459 |
void TermDbSygus::registerEnumerator(Node e, |
388 |
|
Node f, |
389 |
|
SynthConjecture* conj, |
390 |
|
EnumeratorRole erole) |
391 |
|
{ |
392 |
459 |
if (d_enum_to_conjecture.find(e) != d_enum_to_conjecture.end()) |
393 |
|
{ |
394 |
|
// already registered |
395 |
|
return; |
396 |
|
} |
397 |
459 |
Trace("sygus-db") << "Register enumerator : " << e << std::endl; |
398 |
|
// register its type |
399 |
918 |
TypeNode et = e.getType(); |
400 |
459 |
registerSygusType(et); |
401 |
459 |
d_enum_to_conjecture[e] = conj; |
402 |
459 |
d_enum_to_synth_fun[e] = f; |
403 |
459 |
NodeManager* nm = NodeManager::currentNM(); |
404 |
|
|
405 |
918 |
Trace("sygus-db") << " registering symmetry breaking clauses..." |
406 |
459 |
<< std::endl; |
407 |
|
// depending on if we are using symbolic constructors, introduce symmetry |
408 |
|
// breaking lemma templates for each relevant subtype of the grammar |
409 |
459 |
SygusTypeInfo& eti = getTypeInfo(et); |
410 |
918 |
std::vector<TypeNode> sf_types; |
411 |
459 |
eti.getSubfieldTypes(sf_types); |
412 |
|
// for each type of subfield type of this enumerator |
413 |
1445 |
for (unsigned i = 0, ntypes = sf_types.size(); i < ntypes; i++) |
414 |
|
{ |
415 |
1972 |
std::vector<unsigned> rm_indices; |
416 |
1972 |
TypeNode stn = sf_types[i]; |
417 |
986 |
Assert(stn.isDatatype()); |
418 |
986 |
SygusTypeInfo& sti = getTypeInfo(stn); |
419 |
986 |
const DType& dt = stn.getDType(); |
420 |
986 |
int anyC = sti.getAnyConstantConsNum(); |
421 |
7044 |
for (unsigned j = 0, ncons = dt.getNumConstructors(); j < ncons; j++) |
422 |
|
{ |
423 |
6058 |
bool isAnyC = static_cast<int>(j) == anyC; |
424 |
6058 |
if (anyC != -1 && !isAnyC) |
425 |
|
{ |
426 |
|
// if we are using the any constant constructor, do not use any |
427 |
|
// concrete constant |
428 |
420 |
Node c_op = sti.getConsNumConst(j); |
429 |
210 |
if (!c_op.isNull()) |
430 |
|
{ |
431 |
43 |
rm_indices.push_back(j); |
432 |
|
} |
433 |
|
} |
434 |
|
} |
435 |
1029 |
for (unsigned& rindex : rm_indices) |
436 |
|
{ |
437 |
|
// make the apply-constructor corresponding to an application of the |
438 |
|
// constant or "any constant" constructor |
439 |
|
// we call getInstCons since in the case of any constant constructors, it |
440 |
|
// is necessary to generate a term of the form any_constant( x.0 ) for a |
441 |
|
// fresh variable x.0. |
442 |
86 |
Node fv = getFreeVar(stn, 0); |
443 |
86 |
Node exc_val = datatypes::utils::getInstCons(fv, dt, rindex); |
444 |
|
// should not include the constuctor in any subterm |
445 |
86 |
Node x = getFreeVar(stn, 0); |
446 |
86 |
Trace("sygus-db") << "Construct symmetry breaking lemma from " << x |
447 |
43 |
<< " == " << exc_val << std::endl; |
448 |
86 |
Node lem = getExplain()->getExplanationForEquality(x, exc_val); |
449 |
43 |
lem = lem.negate(); |
450 |
86 |
Trace("cegqi-lemma") |
451 |
43 |
<< "Cegqi::Lemma : exclude symbolic cons lemma (template) : " << lem |
452 |
43 |
<< std::endl; |
453 |
|
// the size of the subterm we are blocking is the weight of the |
454 |
|
// constructor (usually zero) |
455 |
43 |
registerSymBreakLemma(e, lem, stn, dt[rindex].getWeight()); |
456 |
|
} |
457 |
|
} |
458 |
459 |
Trace("sygus-db") << " ...finished" << std::endl; |
459 |
|
|
460 |
|
// determine if we are actively-generated |
461 |
459 |
bool isActiveGen = false; |
462 |
459 |
if (options::sygusActiveGenMode() != options::SygusActiveGenMode::NONE) |
463 |
|
{ |
464 |
455 |
if (erole == ROLE_ENUM_MULTI_SOLUTION || erole == ROLE_ENUM_CONSTRAINED) |
465 |
|
{ |
466 |
|
// If the enumerator is a solution for a conjecture with multiple |
467 |
|
// functions, we do not use active generation. If we did, we would have to |
468 |
|
// generate a "product" of two actively-generated enumerators. That is, |
469 |
|
// given a conjecture with two functions-to-synthesize with enumerators |
470 |
|
// e_f and e_g, and if these enumerators generated: |
471 |
|
// e_f -> t1, ..., tn |
472 |
|
// e_g -> s1, ..., sm |
473 |
|
// The sygus module in charge of this conjecture would expect |
474 |
|
// constructCandidates calls of the form |
475 |
|
// (e_f,e_g) -> (ti, sj) |
476 |
|
// for each i,j. We instead use passive enumeration in this case. |
477 |
|
// |
478 |
|
// If the enumerator is constrained, it cannot be actively generated. |
479 |
|
} |
480 |
212 |
else if (erole == ROLE_ENUM_POOL) |
481 |
|
{ |
482 |
|
// If the enumerator is used for generating a pool of values, we always |
483 |
|
// use active generation. |
484 |
61 |
isActiveGen = true; |
485 |
|
} |
486 |
151 |
else if (erole == ROLE_ENUM_SINGLE_SOLUTION) |
487 |
|
{ |
488 |
|
// If the enumerator is the single function-to-synthesize, if auto is |
489 |
|
// enabled, we infer whether it is better to enable active generation. |
490 |
151 |
if (options::sygusActiveGenMode() == options::SygusActiveGenMode::AUTO) |
491 |
|
{ |
492 |
|
// We use active generation if the grammar of the enumerator does not |
493 |
|
// have ITE and does not have Boolean connectives. Experimentally, it |
494 |
|
// is better to use passive generation for these cases since it enables |
495 |
|
// useful search space pruning techniques, e.g. evaluation unfolding, |
496 |
|
// conjecture-specific symmetry breaking. Also, if sygus-stream is |
497 |
|
// enabled, we always use active generation, since the use cases of |
498 |
|
// sygus stream are to find many solutions to an easy problem, where |
499 |
|
// the bottleneck often becomes the large number of "exclude the current |
500 |
|
// solution" clauses. |
501 |
284 |
if (options::sygusStream() |
502 |
142 |
|| (!eti.hasIte() && !eti.hasBoolConnective())) |
503 |
|
{ |
504 |
47 |
isActiveGen = true; |
505 |
|
} |
506 |
|
} |
507 |
|
else |
508 |
|
{ |
509 |
9 |
isActiveGen = true; |
510 |
|
} |
511 |
|
} |
512 |
|
else |
513 |
|
{ |
514 |
|
Unreachable() << "Unknown enumerator mode in registerEnumerator"; |
515 |
|
} |
516 |
|
} |
517 |
918 |
Trace("sygus-db") << "isActiveGen for " << e << ", role = " << erole |
518 |
459 |
<< " returned " << isActiveGen << std::endl; |
519 |
|
// Currently, actively-generated enumerators are either basic or variable |
520 |
|
// agnostic. |
521 |
|
bool isVarAgnostic = isActiveGen |
522 |
459 |
&& options::sygusActiveGenMode() |
523 |
459 |
== options::SygusActiveGenMode::VAR_AGNOSTIC; |
524 |
459 |
d_enum_var_agnostic[e] = isVarAgnostic; |
525 |
459 |
if (isVarAgnostic) |
526 |
|
{ |
527 |
|
// requires variable subclasses |
528 |
1 |
eti.initializeVarSubclasses(); |
529 |
|
// If no subclass has more than one variable, do not use variable agnostic |
530 |
|
// enumeration |
531 |
1 |
bool useVarAgnostic = !eti.isSubclassVarTrivial(); |
532 |
1 |
if (!useVarAgnostic) |
533 |
|
{ |
534 |
|
Trace("sygus-db") |
535 |
|
<< "...disabling variable agnostic for " << e |
536 |
|
<< " since it has no subclass with more than one variable." |
537 |
|
<< std::endl; |
538 |
|
d_enum_var_agnostic[e] = false; |
539 |
|
isActiveGen = false; |
540 |
|
} |
541 |
|
} |
542 |
459 |
d_enum_active_gen[e] = isActiveGen; |
543 |
459 |
d_enum_basic[e] = isActiveGen && !isVarAgnostic; |
544 |
|
|
545 |
|
// We make an active guard if we will be explicitly blocking solutions for |
546 |
|
// the enumerator. This is the case if the role of the enumerator is to |
547 |
|
// populate a pool of terms, or (some cases) of when it is actively generated. |
548 |
459 |
if (isActiveGen || erole == ROLE_ENUM_POOL) |
549 |
|
{ |
550 |
119 |
SkolemManager* sm = nm->getSkolemManager(); |
551 |
|
// make the guard |
552 |
238 |
Node ag = sm->mkDummySkolem("eG", nm->booleanType()); |
553 |
|
// must ensure it is a literal immediately here |
554 |
119 |
ag = d_qstate.getValuation().ensureLiteral(ag); |
555 |
|
// must ensure that it is asserted as a literal before we begin solving |
556 |
238 |
Node lem = nm->mkNode(OR, ag, ag.negate()); |
557 |
119 |
d_qim->requirePhase(ag, true); |
558 |
119 |
d_qim->lemma(lem, InferenceId::QUANTIFIERS_SYGUS_ENUM_ACTIVE_GUARD_SPLIT); |
559 |
119 |
d_enum_to_active_guard[e] = ag; |
560 |
|
} |
561 |
|
} |
562 |
|
|
563 |
48627 |
bool TermDbSygus::isEnumerator(Node e) const |
564 |
|
{ |
565 |
48627 |
return d_enum_to_conjecture.find(e) != d_enum_to_conjecture.end(); |
566 |
|
} |
567 |
|
|
568 |
429 |
SynthConjecture* TermDbSygus::getConjectureForEnumerator(Node e) const |
569 |
|
{ |
570 |
|
std::map<Node, SynthConjecture*>::const_iterator itm = |
571 |
429 |
d_enum_to_conjecture.find(e); |
572 |
429 |
if (itm != d_enum_to_conjecture.end()) { |
573 |
429 |
return itm->second; |
574 |
|
} |
575 |
|
return nullptr; |
576 |
|
} |
577 |
|
|
578 |
307 |
Node TermDbSygus::getSynthFunForEnumerator(Node e) const |
579 |
|
{ |
580 |
307 |
std::map<Node, Node>::const_iterator itsf = d_enum_to_synth_fun.find(e); |
581 |
307 |
if (itsf != d_enum_to_synth_fun.end()) |
582 |
|
{ |
583 |
307 |
return itsf->second; |
584 |
|
} |
585 |
|
return Node::null(); |
586 |
|
} |
587 |
|
|
588 |
46825 |
Node TermDbSygus::getActiveGuardForEnumerator(Node e) const |
589 |
|
{ |
590 |
46825 |
std::map<Node, Node>::const_iterator itag = d_enum_to_active_guard.find(e); |
591 |
46825 |
if (itag != d_enum_to_active_guard.end()) { |
592 |
35356 |
return itag->second; |
593 |
|
} |
594 |
11469 |
return Node::null(); |
595 |
|
} |
596 |
|
|
597 |
5605 |
bool TermDbSygus::usingSymbolicConsForEnumerator(Node e) const |
598 |
|
{ |
599 |
5605 |
std::map<Node, bool>::const_iterator itus = d_enum_to_using_sym_cons.find(e); |
600 |
5605 |
if (itus != d_enum_to_using_sym_cons.end()) |
601 |
|
{ |
602 |
|
return itus->second; |
603 |
|
} |
604 |
5605 |
return false; |
605 |
|
} |
606 |
|
|
607 |
15573 |
bool TermDbSygus::isVariableAgnosticEnumerator(Node e) const |
608 |
|
{ |
609 |
15573 |
std::map<Node, bool>::const_iterator itus = d_enum_var_agnostic.find(e); |
610 |
15573 |
if (itus != d_enum_var_agnostic.end()) |
611 |
|
{ |
612 |
15573 |
return itus->second; |
613 |
|
} |
614 |
|
return false; |
615 |
|
} |
616 |
|
|
617 |
262 |
bool TermDbSygus::isBasicEnumerator(Node e) const |
618 |
|
{ |
619 |
262 |
std::map<Node, bool>::const_iterator itus = d_enum_basic.find(e); |
620 |
262 |
if (itus != d_enum_basic.end()) |
621 |
|
{ |
622 |
262 |
return itus->second; |
623 |
|
} |
624 |
|
return false; |
625 |
|
} |
626 |
|
|
627 |
61747 |
bool TermDbSygus::isPassiveEnumerator(Node e) const |
628 |
|
{ |
629 |
61747 |
std::map<Node, bool>::const_iterator itus = d_enum_active_gen.find(e); |
630 |
61747 |
if (itus != d_enum_active_gen.end()) |
631 |
|
{ |
632 |
58922 |
return !itus->second; |
633 |
|
} |
634 |
2825 |
return true; |
635 |
|
} |
636 |
|
|
637 |
5746 |
void TermDbSygus::getEnumerators(std::vector<Node>& mts) |
638 |
|
{ |
639 |
9867 |
for (std::map<Node, SynthConjecture*>::iterator itm = |
640 |
5746 |
d_enum_to_conjecture.begin(); |
641 |
15613 |
itm != d_enum_to_conjecture.end(); |
642 |
|
++itm) |
643 |
|
{ |
644 |
9867 |
mts.push_back( itm->first ); |
645 |
|
} |
646 |
5746 |
} |
647 |
|
|
648 |
79 |
void TermDbSygus::registerSymBreakLemma( |
649 |
|
Node e, Node lem, TypeNode tn, unsigned sz, bool isTempl) |
650 |
|
{ |
651 |
79 |
d_enum_to_sb_lemmas[e].push_back(lem); |
652 |
79 |
d_sb_lemma_to_type[lem] = tn; |
653 |
79 |
d_sb_lemma_to_size[lem] = sz; |
654 |
79 |
d_sb_lemma_to_isTempl[lem] = isTempl; |
655 |
79 |
} |
656 |
|
|
657 |
5746 |
bool TermDbSygus::hasSymBreakLemmas(std::vector<Node>& enums) const |
658 |
|
{ |
659 |
5746 |
if (!d_enum_to_sb_lemmas.empty()) |
660 |
|
{ |
661 |
376 |
for (std::pair<const Node, std::vector<Node> > sb : d_enum_to_sb_lemmas) |
662 |
|
{ |
663 |
194 |
enums.push_back(sb.first); |
664 |
|
} |
665 |
182 |
return true; |
666 |
|
} |
667 |
5564 |
return false; |
668 |
|
} |
669 |
|
|
670 |
171 |
void TermDbSygus::getSymBreakLemmas(Node e, std::vector<Node>& lemmas) const |
671 |
|
{ |
672 |
|
std::map<Node, std::vector<Node> >::const_iterator itsb = |
673 |
171 |
d_enum_to_sb_lemmas.find(e); |
674 |
171 |
if (itsb != d_enum_to_sb_lemmas.end()) |
675 |
|
{ |
676 |
51 |
lemmas.insert(lemmas.end(), itsb->second.begin(), itsb->second.end()); |
677 |
|
} |
678 |
171 |
} |
679 |
|
|
680 |
9 |
TypeNode TermDbSygus::getTypeForSymBreakLemma(Node lem) const |
681 |
|
{ |
682 |
9 |
std::map<Node, TypeNode>::const_iterator it = d_sb_lemma_to_type.find(lem); |
683 |
9 |
Assert(it != d_sb_lemma_to_type.end()); |
684 |
9 |
return it->second; |
685 |
|
} |
686 |
9 |
unsigned TermDbSygus::getSizeForSymBreakLemma(Node lem) const |
687 |
|
{ |
688 |
9 |
std::map<Node, unsigned>::const_iterator it = d_sb_lemma_to_size.find(lem); |
689 |
9 |
Assert(it != d_sb_lemma_to_size.end()); |
690 |
9 |
return it->second; |
691 |
|
} |
692 |
|
|
693 |
79 |
bool TermDbSygus::isSymBreakLemmaTemplate(Node lem) const |
694 |
|
{ |
695 |
79 |
std::map<Node, bool>::const_iterator it = d_sb_lemma_to_isTempl.find(lem); |
696 |
79 |
Assert(it != d_sb_lemma_to_isTempl.end()); |
697 |
79 |
return it->second; |
698 |
|
} |
699 |
|
|
700 |
4 |
void TermDbSygus::clearSymBreakLemmas(Node e) { d_enum_to_sb_lemmas.erase(e); } |
701 |
|
|
702 |
119715 |
bool TermDbSygus::isRegistered(TypeNode tn) const |
703 |
|
{ |
704 |
119715 |
return d_tinfo.find(tn) != d_tinfo.end(); |
705 |
|
} |
706 |
|
|
707 |
6713 |
TypeNode TermDbSygus::sygusToBuiltinType( TypeNode tn ) { |
708 |
6713 |
std::map<TypeNode, SygusTypeInfo>::iterator it = d_tinfo.find(tn); |
709 |
6713 |
Assert(it != d_tinfo.end()); |
710 |
6713 |
return it->second.getBuiltinType(); |
711 |
|
} |
712 |
|
|
713 |
8341 |
void TermDbSygus::toStreamSygus(const char* c, Node n) |
714 |
|
{ |
715 |
8341 |
if (Trace.isOn(c)) |
716 |
|
{ |
717 |
|
std::stringstream ss; |
718 |
|
toStreamSygus(ss, n); |
719 |
|
Trace(c) << ss.str(); |
720 |
|
} |
721 |
8341 |
} |
722 |
|
|
723 |
210 |
void TermDbSygus::toStreamSygus(std::ostream& out, Node n) |
724 |
|
{ |
725 |
210 |
if (n.isNull()) |
726 |
|
{ |
727 |
|
out << n; |
728 |
|
return; |
729 |
|
} |
730 |
|
// use external conversion |
731 |
210 |
out << datatypes::utils::sygusToBuiltin(n, true); |
732 |
|
} |
733 |
|
|
734 |
170975 |
SygusTypeInfo& TermDbSygus::getTypeInfo(TypeNode tn) |
735 |
|
{ |
736 |
170975 |
AlwaysAssert(d_tinfo.find(tn) != d_tinfo.end()); |
737 |
170975 |
return d_tinfo[tn]; |
738 |
|
} |
739 |
|
|
740 |
421334 |
Node TermDbSygus::rewriteNode(Node n) const |
741 |
|
{ |
742 |
842668 |
Node res = Rewriter::rewrite(n); |
743 |
421334 |
if (res.isConst()) |
744 |
|
{ |
745 |
|
// constant, we are done |
746 |
217959 |
return res; |
747 |
|
} |
748 |
203375 |
if (options::sygusRecFun()) |
749 |
|
{ |
750 |
166613 |
if (d_funDefEval->hasDefinitions()) |
751 |
|
{ |
752 |
|
// If recursive functions are enabled, then we use the recursive function |
753 |
|
// evaluation utility. |
754 |
3668 |
Node fres = d_funDefEval->evaluate(res); |
755 |
2794 |
if (!fres.isNull()) |
756 |
|
{ |
757 |
1920 |
return fres; |
758 |
|
} |
759 |
|
// It may have failed, in which case there are undefined symbols in res or |
760 |
|
// we reached the limit of evaluations. In this case, we revert to the |
761 |
|
// result of rewriting in the return statement below. |
762 |
|
} |
763 |
|
} |
764 |
201455 |
return res; |
765 |
|
} |
766 |
|
|
767 |
1056 |
unsigned TermDbSygus::getSelectorWeight(TypeNode tn, Node sel) |
768 |
|
{ |
769 |
|
std::map<TypeNode, std::map<Node, unsigned> >::iterator itsw = |
770 |
1056 |
d_sel_weight.find(tn); |
771 |
1056 |
if (itsw == d_sel_weight.end()) |
772 |
|
{ |
773 |
212 |
d_sel_weight[tn].clear(); |
774 |
212 |
itsw = d_sel_weight.find(tn); |
775 |
212 |
const DType& dt = tn.getDType(); |
776 |
424 |
Trace("sygus-db") << "Compute selector weights for " << dt.getName() |
777 |
212 |
<< std::endl; |
778 |
1186 |
for (unsigned i = 0, size = dt.getNumConstructors(); i < size; i++) |
779 |
|
{ |
780 |
974 |
unsigned cw = dt[i].getWeight(); |
781 |
2163 |
for (unsigned j = 0, size2 = dt[i].getNumArgs(); j < size2; j++) |
782 |
|
{ |
783 |
2378 |
Node csel = dt[i].getSelectorInternal(tn, j); |
784 |
1189 |
std::map<Node, unsigned>::iterator its = itsw->second.find(csel); |
785 |
1189 |
if (its == itsw->second.end() || cw < its->second) |
786 |
|
{ |
787 |
613 |
d_sel_weight[tn][csel] = cw; |
788 |
613 |
Trace("sygus-db") << " w(" << csel << ") <= " << cw << std::endl; |
789 |
|
} |
790 |
|
} |
791 |
|
} |
792 |
|
} |
793 |
1056 |
Assert(itsw->second.find(sel) != itsw->second.end()); |
794 |
1056 |
return itsw->second[sel]; |
795 |
|
} |
796 |
|
|
797 |
579918 |
TypeNode TermDbSygus::getArgType(const DTypeConstructor& c, unsigned i) const |
798 |
|
{ |
799 |
579918 |
Assert(i < c.getNumArgs()); |
800 |
579918 |
return c.getArgType(i); |
801 |
|
} |
802 |
|
|
803 |
4 |
bool TermDbSygus::isTypeMatch(const DTypeConstructor& c1, |
804 |
|
const DTypeConstructor& c2) |
805 |
|
{ |
806 |
4 |
if( c1.getNumArgs()!=c2.getNumArgs() ){ |
807 |
|
return false; |
808 |
|
}else{ |
809 |
12 |
for( unsigned i=0; i<c1.getNumArgs(); i++ ){ |
810 |
8 |
if( getArgType( c1, i )!=getArgType( c2, i ) ){ |
811 |
|
return false; |
812 |
|
} |
813 |
|
} |
814 |
4 |
return true; |
815 |
|
} |
816 |
|
} |
817 |
|
|
818 |
|
bool TermDbSygus::isSymbolicConsApp(Node n) const |
819 |
|
{ |
820 |
|
if (n.getKind() != APPLY_CONSTRUCTOR) |
821 |
|
{ |
822 |
|
return false; |
823 |
|
} |
824 |
|
TypeNode tn = n.getType(); |
825 |
|
Assert(tn.isDatatype()); |
826 |
|
const DType& dt = tn.getDType(); |
827 |
|
Assert(dt.isSygus()); |
828 |
|
unsigned cindex = datatypes::utils::indexOf(n.getOperator()); |
829 |
|
Node sygusOp = dt[cindex].getSygusOp(); |
830 |
|
// it is symbolic if it represents "any constant" |
831 |
|
return sygusOp.getAttribute(SygusAnyConstAttribute()); |
832 |
|
} |
833 |
|
|
834 |
2075 |
bool TermDbSygus::canConstructKind(TypeNode tn, |
835 |
|
Kind k, |
836 |
|
std::vector<TypeNode>& argts, |
837 |
|
bool aggr) |
838 |
|
{ |
839 |
2075 |
Assert(isRegistered(tn)); |
840 |
2075 |
SygusTypeInfo& ti = getTypeInfo(tn); |
841 |
2075 |
int c = ti.getKindConsNum(k); |
842 |
2075 |
const DType& dt = tn.getDType(); |
843 |
2075 |
if (c != -1) |
844 |
|
{ |
845 |
5686 |
for (unsigned i = 0, nargs = dt[c].getNumArgs(); i < nargs; i++) |
846 |
|
{ |
847 |
3791 |
argts.push_back(dt[c].getArgType(i)); |
848 |
|
} |
849 |
1895 |
return true; |
850 |
|
} |
851 |
360 |
if (!options::sygusSymBreakAgg()) |
852 |
|
{ |
853 |
|
return false; |
854 |
|
} |
855 |
180 |
if (sygusToBuiltinType(tn).isBoolean()) |
856 |
|
{ |
857 |
177 |
if (k == ITE) |
858 |
|
{ |
859 |
|
// ite( b1, b2, b3 ) <---- and( or( ~b1, b2 ), or( b1, b3 ) ) |
860 |
158 |
std::vector<TypeNode> conj_types; |
861 |
140 |
if (canConstructKind(tn, AND, conj_types, true) && conj_types.size() == 2) |
862 |
|
{ |
863 |
128 |
bool success = true; |
864 |
384 |
std::vector<TypeNode> disj_types[2]; |
865 |
372 |
for (unsigned cc = 0; cc < 2; cc++) |
866 |
|
{ |
867 |
750 |
if (!canConstructKind(conj_types[cc], OR, disj_types[cc], true) |
868 |
750 |
|| disj_types[cc].size() != 2) |
869 |
|
{ |
870 |
6 |
success = false; |
871 |
6 |
break; |
872 |
|
} |
873 |
|
} |
874 |
128 |
if (success) |
875 |
|
{ |
876 |
122 |
for (unsigned r = 0; r < 2; r++) |
877 |
|
{ |
878 |
122 |
for (unsigned d = 0, size = disj_types[r].size(); d < size; d++) |
879 |
|
{ |
880 |
122 |
TypeNode dtn = disj_types[r][d]; |
881 |
|
// must have negation that occurs in the other conjunct |
882 |
122 |
std::vector<TypeNode> ntypes; |
883 |
122 |
if (canConstructKind(dtn, NOT, ntypes) && ntypes.size() == 1) |
884 |
|
{ |
885 |
122 |
TypeNode ntn = ntypes[0]; |
886 |
122 |
for (unsigned dd = 0, inner_size = disj_types[1 - r].size(); |
887 |
122 |
dd < inner_size; |
888 |
|
dd++) |
889 |
|
{ |
890 |
122 |
if (disj_types[1 - r][dd] == ntn) |
891 |
|
{ |
892 |
122 |
argts.push_back(ntn); |
893 |
122 |
argts.push_back(disj_types[r][d]); |
894 |
122 |
argts.push_back(disj_types[1 - r][1 - dd]); |
895 |
122 |
if (Trace.isOn("sygus-cons-kind")) |
896 |
|
{ |
897 |
|
Trace("sygus-cons-kind") |
898 |
|
<< "Can construct kind " << k << " in " << tn |
899 |
|
<< " via child types:" << std::endl; |
900 |
|
for (unsigned i = 0; i < 3; i++) |
901 |
|
{ |
902 |
|
Trace("sygus-cons-kind") |
903 |
|
<< " " << argts[i] << std::endl; |
904 |
|
} |
905 |
|
} |
906 |
122 |
return true; |
907 |
|
} |
908 |
|
} |
909 |
|
} |
910 |
|
} |
911 |
|
} |
912 |
|
} |
913 |
|
} |
914 |
|
} |
915 |
|
} |
916 |
|
// could try aggressive inferences here, such as |
917 |
|
// (and b1 b2) <---- (not (or (not b1) (not b2))) |
918 |
|
// (or b1 b2) <---- (not (and (not b1) (not b2))) |
919 |
58 |
return false; |
920 |
|
} |
921 |
|
|
922 |
21994 |
bool TermDbSygus::involvesDivByZero( Node n, std::map< Node, bool >& visited ){ |
923 |
21994 |
if( visited.find( n )==visited.end() ){ |
924 |
20201 |
visited[n] = true; |
925 |
20201 |
Kind k = n.getKind(); |
926 |
20201 |
if( k==DIVISION || k==DIVISION_TOTAL || k==INTS_DIVISION || k==INTS_DIVISION_TOTAL || |
927 |
20011 |
k==INTS_MODULUS || k==INTS_MODULUS_TOTAL ){ |
928 |
199 |
if( n[1].isConst() ){ |
929 |
190 |
if (n[1] == TermUtil::mkTypeValue(n[1].getType(), 0)) |
930 |
|
{ |
931 |
|
return true; |
932 |
|
} |
933 |
|
}else{ |
934 |
|
// if it has free variables it might be a non-zero constant |
935 |
9 |
if( !hasFreeVar( n[1] ) ){ |
936 |
|
return true; |
937 |
|
} |
938 |
|
} |
939 |
|
} |
940 |
36608 |
for( unsigned i=0; i<n.getNumChildren(); i++ ){ |
941 |
16407 |
if( involvesDivByZero( n[i], visited ) ){ |
942 |
|
return true; |
943 |
|
} |
944 |
|
} |
945 |
|
} |
946 |
21994 |
return false; |
947 |
|
} |
948 |
|
|
949 |
5587 |
bool TermDbSygus::involvesDivByZero( Node n ) { |
950 |
11174 |
std::map< Node, bool > visited; |
951 |
11174 |
return involvesDivByZero( n, visited ); |
952 |
|
} |
953 |
|
|
954 |
2183 |
Node TermDbSygus::getAnchor( Node n ) { |
955 |
2183 |
if( n.getKind()==APPLY_SELECTOR_TOTAL ){ |
956 |
949 |
return getAnchor( n[0] ); |
957 |
|
}else{ |
958 |
1234 |
return n; |
959 |
|
} |
960 |
|
} |
961 |
|
|
962 |
|
unsigned TermDbSygus::getAnchorDepth( Node n ) { |
963 |
|
if( n.getKind()==APPLY_SELECTOR_TOTAL ){ |
964 |
|
return 1+getAnchorDepth( n[0] ); |
965 |
|
}else{ |
966 |
|
return 0; |
967 |
|
} |
968 |
|
} |
969 |
|
|
970 |
113923 |
Node TermDbSygus::evaluateBuiltin(TypeNode tn, |
971 |
|
Node bn, |
972 |
|
const std::vector<Node>& args, |
973 |
|
bool tryEval) |
974 |
|
{ |
975 |
113923 |
if (args.empty()) |
976 |
|
{ |
977 |
432 |
return Rewriter::rewrite( bn ); |
978 |
|
} |
979 |
113491 |
Assert(isRegistered(tn)); |
980 |
113491 |
SygusTypeInfo& ti = getTypeInfo(tn); |
981 |
113491 |
const std::vector<Node>& varlist = ti.getVarList(); |
982 |
113491 |
Assert(varlist.size() == args.size()); |
983 |
|
|
984 |
226982 |
Node res; |
985 |
226982 |
if (tryEval && options::sygusEvalOpt()) |
986 |
|
{ |
987 |
|
// Try evaluating, which is much faster than substitution+rewriting. |
988 |
|
// This may fail if there is a subterm of bn under the |
989 |
|
// substitution that is not constant, or if an operator in bn is not |
990 |
|
// supported by the evaluator |
991 |
113491 |
res = d_eval->eval(bn, varlist, args); |
992 |
|
} |
993 |
113491 |
if (res.isNull()) |
994 |
|
{ |
995 |
|
// must do substitution |
996 |
|
res = |
997 |
|
bn.substitute(varlist.begin(), varlist.end(), args.begin(), args.end()); |
998 |
|
} |
999 |
|
// Call the rewrite node function, which may involve recursive function |
1000 |
|
// evaluation. |
1001 |
113491 |
return rewriteNode(res); |
1002 |
|
} |
1003 |
|
|
1004 |
660618 |
Node TermDbSygus::evaluateWithUnfolding(Node n, |
1005 |
|
std::unordered_map<Node, Node>& visited) |
1006 |
|
{ |
1007 |
660618 |
std::unordered_map<Node, Node>::iterator it = visited.find(n); |
1008 |
660618 |
if( it==visited.end() ){ |
1009 |
833476 |
Node ret = n; |
1010 |
584298 |
while (ret.getKind() == DT_SYGUS_EVAL |
1011 |
1001036 |
&& ret[0].getKind() == APPLY_CONSTRUCTOR) |
1012 |
|
{ |
1013 |
83780 |
if (ret == n && ret[0].isConst()) |
1014 |
|
{ |
1015 |
|
// use rewriting, possibly involving recursive functions |
1016 |
31130 |
ret = rewriteNode(ret); |
1017 |
|
} |
1018 |
|
else |
1019 |
|
{ |
1020 |
52650 |
ret = d_eval_unfold->unfold(ret); |
1021 |
|
} |
1022 |
|
} |
1023 |
416738 |
if( ret.getNumChildren()>0 ){ |
1024 |
549152 |
std::vector< Node > children; |
1025 |
274576 |
if( ret.getMetaKind() == kind::metakind::PARAMETERIZED ){ |
1026 |
55596 |
children.push_back( ret.getOperator() ); |
1027 |
|
} |
1028 |
274576 |
bool childChanged = false; |
1029 |
851408 |
for( unsigned i=0; i<ret.getNumChildren(); i++ ){ |
1030 |
1153664 |
Node nc = evaluateWithUnfolding(ret[i], visited); |
1031 |
576832 |
childChanged = childChanged || nc!=ret[i]; |
1032 |
576832 |
children.push_back( nc ); |
1033 |
|
} |
1034 |
274576 |
if( childChanged ){ |
1035 |
107850 |
ret = NodeManager::currentNM()->mkNode( ret.getKind(), children ); |
1036 |
|
} |
1037 |
549152 |
if (options::sygusExtRew()) |
1038 |
|
{ |
1039 |
263486 |
ret = getExtRewriter()->extendedRewrite(ret); |
1040 |
|
} |
1041 |
|
// use rewriting, possibly involving recursive functions |
1042 |
274576 |
ret = rewriteNode(ret); |
1043 |
|
} |
1044 |
416738 |
visited[n] = ret; |
1045 |
416738 |
return ret; |
1046 |
|
}else{ |
1047 |
243880 |
return it->second; |
1048 |
|
} |
1049 |
|
} |
1050 |
|
|
1051 |
9055 |
Node TermDbSygus::evaluateWithUnfolding(Node n) |
1052 |
|
{ |
1053 |
18110 |
std::unordered_map<Node, Node> visited; |
1054 |
18110 |
return evaluateWithUnfolding(n, visited); |
1055 |
|
} |
1056 |
|
|
1057 |
527 |
bool TermDbSygus::isEvaluationPoint(Node n) const |
1058 |
|
{ |
1059 |
527 |
if (n.getKind() != DT_SYGUS_EVAL) |
1060 |
|
{ |
1061 |
306 |
return false; |
1062 |
|
} |
1063 |
221 |
if (!n[0].isVar()) |
1064 |
|
{ |
1065 |
|
return false; |
1066 |
|
} |
1067 |
1004 |
for (unsigned i = 1, nchild = n.getNumChildren(); i < nchild; i++) |
1068 |
|
{ |
1069 |
783 |
if (!n[i].isConst()) |
1070 |
|
{ |
1071 |
|
return false; |
1072 |
|
} |
1073 |
|
} |
1074 |
221 |
return true; |
1075 |
|
} |
1076 |
|
|
1077 |
|
} // namespace quantifiers |
1078 |
|
} // namespace theory |
1079 |
417527 |
} // namespace cvc5 |