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