1 /********************* */
2 /*! \file datatypes_sygus.cpp
3 ** \verbatim
4 ** Top contributors (to current version):
5 ** Andrew Reynolds, Tim King, Morgan Deters
6 ** This file is part of the CVC4 project.
7 ** Copyright (c) 2009-2019 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.\endverbatim
11 **
12 ** \brief Implementation of sygus utilities for theory of datatypes
13 **
14 ** Implementation of sygus utilities for theory of datatypes
15 **/
16
17 #include "theory/datatypes/datatypes_sygus.h"
18
19 #include "expr/node_manager.h"
20 #include "options/base_options.h"
21 #include "options/quantifiers_options.h"
22 #include "printer/printer.h"
23 #include "theory/datatypes/datatypes_rewriter.h"
24 #include "theory/datatypes/theory_datatypes.h"
25 #include "theory/quantifiers/sygus/sygus_explain.h"
26 #include "theory/quantifiers/sygus/term_database_sygus.h"
27 #include "theory/quantifiers/term_util.h"
28 #include "theory/theory_model.h"
29
30 using namespace CVC4;
31 using namespace CVC4::kind;
32 using namespace CVC4::context;
33 using namespace CVC4::theory;
34 using namespace CVC4::theory::datatypes;
35
SygusSymBreakNew(TheoryDatatypes * td,QuantifiersEngine * qe,context::Context * c)36 SygusSymBreakNew::SygusSymBreakNew(TheoryDatatypes* td,
37 QuantifiersEngine* qe,
38 context::Context* c)
39 : d_td(td),
40 d_tds(qe->getTermDatabaseSygus()),
41 d_ssb(qe),
42 d_testers(c),
43 d_testers_exp(c),
44 d_active_terms(c),
45 d_currTermSize(c)
46 {
47 d_zero = NodeManager::currentNM()->mkConst(Rational(0));
48 d_true = NodeManager::currentNM()->mkConst(true);
49 }
50
~SygusSymBreakNew()51 SygusSymBreakNew::~SygusSymBreakNew() {
52
53 }
54
55 /** add tester */
assertTester(int tindex,TNode n,Node exp,std::vector<Node> & lemmas)56 void SygusSymBreakNew::assertTester( int tindex, TNode n, Node exp, std::vector< Node >& lemmas ) {
57 registerTerm( n, lemmas );
58 // check if this is a relevant (sygus) term
59 if( d_term_to_anchor.find( n )!=d_term_to_anchor.end() ){
60 Trace("sygus-sb-debug2") << "Sygus : process tester : " << exp << std::endl;
61 // if not already active (may have duplicate calls for the same tester)
62 if( d_active_terms.find( n )==d_active_terms.end() ) {
63 d_testers[n] = tindex;
64 d_testers_exp[n] = exp;
65
66 // check if parent is active
67 bool do_add = true;
68 if( options::sygusSymBreakLazy() ){
69 if( n.getKind()==kind::APPLY_SELECTOR_TOTAL ){
70 NodeSet::const_iterator it = d_active_terms.find( n[0] );
71 if( it==d_active_terms.end() ){
72 do_add = false;
73 }else{
74 //this must be a proper selector
75 IntMap::const_iterator itt = d_testers.find( n[0] );
76 Assert( itt!=d_testers.end() );
77 int ptindex = (*itt).second;
78 TypeNode ptn = n[0].getType();
79 const Datatype& pdt = ((DatatypeType)ptn.toType()).getDatatype();
80 int sindex_in_parent = pdt[ptindex].getSelectorIndexInternal( n.getOperator().toExpr() );
81 // the tester is irrelevant in this branch
82 if( sindex_in_parent==-1 ){
83 do_add = false;
84 }
85 }
86 }
87 }
88 if( do_add ){
89 assertTesterInternal( tindex, n, exp, lemmas );
90 }else{
91 Trace("sygus-sb-debug2") << "...ignore inactive tester : " << exp << std::endl;
92 }
93 }else{
94 Trace("sygus-sb-debug2") << "...ignore repeated tester : " << exp << std::endl;
95 }
96 }else{
97 Trace("sygus-sb-debug2") << "...ignore non-sygus tester : " << exp << std::endl;
98 }
99 }
100
assertFact(Node n,bool polarity,std::vector<Node> & lemmas)101 void SygusSymBreakNew::assertFact( Node n, bool polarity, std::vector< Node >& lemmas ) {
102 if (n.getKind() == kind::DT_SYGUS_BOUND)
103 {
104 Node m = n[0];
105 Trace("sygus-fair") << "Have sygus bound : " << n << ", polarity=" << polarity << " on measure " << m << std::endl;
106 registerMeasureTerm( m );
107 if( options::sygusFair()==SYGUS_FAIR_DT_SIZE ){
108 std::map<Node, std::unique_ptr<SygusSizeDecisionStrategy>>::iterator its =
109 d_szinfo.find(m);
110 Assert( its!=d_szinfo.end() );
111 Node mt = its->second->getOrMkMeasureValue(lemmas);
112 //it relates the measure term to arithmetic
113 Node blem = n.eqNode( NodeManager::currentNM()->mkNode( kind::LEQ, mt, n[1] ) );
114 lemmas.push_back( blem );
115 }
116 if( polarity ){
117 unsigned s = n[1].getConst<Rational>().getNumerator().toUnsignedInt();
118 notifySearchSize( m, s, n, lemmas );
119 }
120 }else if( n.getKind() == kind::DT_HEIGHT_BOUND || n.getKind()==DT_SIZE_BOUND ){
121 //reduce to arithmetic TODO ?
122
123 }
124 }
125
getTermOrderPredicate(Node n1,Node n2)126 Node SygusSymBreakNew::getTermOrderPredicate( Node n1, Node n2 ) {
127 NodeManager* nm = NodeManager::currentNM();
128 std::vector< Node > comm_disj;
129 // (1) size of left is greater than size of right
130 Node sz_less =
131 nm->mkNode(GT, nm->mkNode(DT_SIZE, n1), nm->mkNode(DT_SIZE, n2));
132 comm_disj.push_back( sz_less );
133 // (2) ...or sizes are equal and first child is less by term order
134 std::vector<Node> sz_eq_cases;
135 Node sz_eq =
136 nm->mkNode(EQUAL, nm->mkNode(DT_SIZE, n1), nm->mkNode(DT_SIZE, n2));
137 sz_eq_cases.push_back( sz_eq );
138 if( options::sygusOpt1() ){
139 TypeNode tnc = n1.getType();
140 const Datatype& cdt = ((DatatypeType)(tnc).toType()).getDatatype();
141 for( unsigned j=0; j<cdt.getNumConstructors(); j++ ){
142 std::vector<Node> case_conj;
143 for (unsigned k = 0; k < j; k++)
144 {
145 case_conj.push_back(DatatypesRewriter::mkTester(n2, k, cdt).negate());
146 }
147 if (!case_conj.empty())
148 {
149 Node corder = nm->mkNode(
150 kind::OR,
151 DatatypesRewriter::mkTester(n1, j, cdt).negate(),
152 case_conj.size() == 1 ? case_conj[0]
153 : nm->mkNode(kind::AND, case_conj));
154 sz_eq_cases.push_back(corder);
155 }
156 }
157 }
158 Node sz_eqc = sz_eq_cases.size() == 1 ? sz_eq_cases[0]
159 : nm->mkNode(kind::AND, sz_eq_cases);
160 comm_disj.push_back( sz_eqc );
161
162 return nm->mkNode(kind::OR, comm_disj);
163 }
164
registerTerm(Node n,std::vector<Node> & lemmas)165 void SygusSymBreakNew::registerTerm( Node n, std::vector< Node >& lemmas ) {
166 if( d_is_top_level.find( n )==d_is_top_level.end() ){
167 d_is_top_level[n] = false;
168 TypeNode tn = n.getType();
169 unsigned d = 0;
170 bool is_top_level = false;
171 bool success = false;
172 if( n.getKind()==kind::APPLY_SELECTOR_TOTAL ){
173 registerTerm( n[0], lemmas );
174 std::unordered_map<Node, Node, NodeHashFunction>::iterator it =
175 d_term_to_anchor.find(n[0]);
176 if( it!=d_term_to_anchor.end() ) {
177 d_term_to_anchor[n] = it->second;
178 unsigned sel_weight =
179 d_tds->getSelectorWeight(n[0].getType(), n.getOperator());
180 d = d_term_to_depth[n[0]] + sel_weight;
181 is_top_level = computeTopLevel( tn, n[0] );
182 success = true;
183 }
184 }else if( n.isVar() ){
185 registerSizeTerm( n, lemmas );
186 if( d_register_st[n] ){
187 d_term_to_anchor[n] = n;
188 d_anchor_to_conj[n] = d_tds->getConjectureForEnumerator(n);
189 // this assertion fails if we have a sygus term in the search that is unmeasured
190 Assert(d_anchor_to_conj[n] != NULL);
191 d = 0;
192 is_top_level = true;
193 success = true;
194 }
195 }
196 if( success ){
197 Trace("sygus-sb-debug") << "Register : " << n << ", depth : " << d << ", top level = " << is_top_level << ", type = " << ((DatatypeType)tn.toType()).getDatatype().getName() << std::endl;
198 d_term_to_depth[n] = d;
199 d_is_top_level[n] = is_top_level;
200 registerSearchTerm( tn, d, n, is_top_level, lemmas );
201 }else{
202 Trace("sygus-sb-debug2") << "Term " << n << " is not part of sygus search." << std::endl;
203 }
204 }
205 }
206
computeTopLevel(TypeNode tn,Node n)207 bool SygusSymBreakNew::computeTopLevel( TypeNode tn, Node n ){
208 if( n.getType()==tn ){
209 return false;
210 }else if( n.getKind()==kind::APPLY_SELECTOR_TOTAL ){
211 return computeTopLevel( tn, n[0] );
212 }else{
213 return true;
214 }
215 }
216
assertTesterInternal(int tindex,TNode n,Node exp,std::vector<Node> & lemmas)217 void SygusSymBreakNew::assertTesterInternal( int tindex, TNode n, Node exp, std::vector< Node >& lemmas ) {
218 TypeNode ntn = n.getType();
219 if (!ntn.isDatatype())
220 {
221 // nothing to do for non-datatype types
222 return;
223 }
224 const Datatype& dt = static_cast<DatatypeType>(ntn.toType()).getDatatype();
225 if (!dt.isSygus())
226 {
227 // nothing to do for non-sygus-datatype type
228 return;
229 }
230 d_active_terms.insert(n);
231 Trace("sygus-sb-debug2") << "Sygus : activate term : " << n << " : " << exp
232 << std::endl;
233
234 // get the search size for this
235 Assert( d_term_to_anchor.find( n )!=d_term_to_anchor.end() );
236 Node a = d_term_to_anchor[n];
237 Assert( d_anchor_to_measure_term.find( a )!=d_anchor_to_measure_term.end() );
238 Node m = d_anchor_to_measure_term[a];
239 std::map<Node, std::unique_ptr<SygusSizeDecisionStrategy>>::iterator itsz =
240 d_szinfo.find(m);
241 Assert( itsz!=d_szinfo.end() );
242 unsigned ssz = itsz->second->d_curr_search_size;
243
244 if( options::sygusFair()==SYGUS_FAIR_DIRECT ){
245 if( dt[tindex].getNumArgs()>0 ){
246 // consider lower bounds for size of types
247 unsigned lb_add = d_tds->getMinConsTermSize( ntn, tindex );
248 unsigned lb_rem = n==a ? 0 : d_tds->getMinTermSize( ntn );
249 Assert( lb_add>=lb_rem );
250 d_currTermSize[a].set( d_currTermSize[a].get() + ( lb_add - lb_rem ) );
251 }
252 if( (unsigned)d_currTermSize[a].get()>ssz ){
253 if( Trace.isOn("sygus-sb-fair") ){
254 std::map< TypeNode, int > var_count;
255 Node templ = getCurrentTemplate( a, var_count );
256 Trace("sygus-sb-fair") << "FAIRNESS : we have " << d_currTermSize[a].get() << " at search size " << ssz << ", template is " << templ << std::endl;
257 }
258 // conflict
259 std::vector< Node > conflict;
260 for( NodeSet::const_iterator its = d_active_terms.begin(); its != d_active_terms.end(); ++its ){
261 Node x = *its;
262 Node xa = d_term_to_anchor[x];
263 if( xa==a ){
264 IntMap::const_iterator ittv = d_testers.find( x );
265 Assert( ittv != d_testers.end() );
266 int tindex = (*ittv).second;
267 const Datatype& dti = ((DatatypeType)x.getType().toType()).getDatatype();
268 if( dti[tindex].getNumArgs()>0 ){
269 NodeMap::const_iterator itt = d_testers_exp.find( x );
270 Assert( itt != d_testers_exp.end() );
271 conflict.push_back( (*itt).second );
272 }
273 }
274 }
275 Assert( conflict.size()==(unsigned)d_currTermSize[a].get() );
276 Assert( itsz->second->d_search_size_exp.find( ssz )!=itsz->second->d_search_size_exp.end() );
277 conflict.push_back( itsz->second->d_search_size_exp[ssz] );
278 Node conf = NodeManager::currentNM()->mkNode( kind::AND, conflict );
279 Trace("sygus-sb-fair") << "Conflict is : " << conf << std::endl;
280 lemmas.push_back( conf.negate() );
281 return;
282 }
283 }
284
285 // now, add all applicable symmetry breaking lemmas for this term
286 Assert( d_term_to_depth.find( n )!=d_term_to_depth.end() );
287 unsigned d = d_term_to_depth[n];
288 Trace("sygus-sb-fair-debug") << "Tester " << exp << " is for depth " << d << " term in search size " << ssz << std::endl;
289 //Assert( d<=ssz );
290 if( options::sygusSymBreakLazy() ){
291 // dynamic symmetry breaking
292 addSymBreakLemmasFor( ntn, n, d, lemmas );
293 }
294
295 Trace("sygus-sb-debug") << "Get simple symmetry breaking predicates...\n";
296 unsigned max_depth = ssz>=d ? ssz-d : 0;
297 unsigned min_depth = d_simple_proc[exp];
298 NodeManager* nm = NodeManager::currentNM();
299 if( min_depth<=max_depth ){
300 TNode x = getFreeVar( ntn );
301 std::vector<Node> sb_lemmas;
302 // symmetry breaking lemmas requiring predicate elimination
303 std::map<Node, bool> sb_elim_pred;
304 bool usingSymCons = d_tds->usingSymbolicConsForEnumerator(m);
305 bool isVarAgnostic = d_tds->isVariableAgnosticEnumerator(m);
306 for (unsigned ds = 0; ds <= max_depth; ds++)
307 {
308 // static conjecture-independent symmetry breaking
309 Trace("sygus-sb-debug") << " simple symmetry breaking...\n";
310 Node ipred = getSimpleSymBreakPred(
311 m, ntn, tindex, ds, usingSymCons, isVarAgnostic);
312 if (!ipred.isNull())
313 {
314 sb_lemmas.push_back(ipred);
315 if (ds == 0 && isVarAgnostic)
316 {
317 sb_elim_pred[ipred] = true;
318 }
319 }
320 // static conjecture-dependent symmetry breaking
321 Trace("sygus-sb-debug")
322 << " conjecture-dependent symmetry breaking...\n";
323 std::map<Node, quantifiers::SynthConjecture*>::iterator itc =
324 d_anchor_to_conj.find(a);
325 if (itc != d_anchor_to_conj.end())
326 {
327 quantifiers::SynthConjecture* conj = itc->second;
328 Assert(conj != NULL);
329 Node dpred = conj->getSymmetryBreakingPredicate(x, a, ntn, tindex, ds);
330 if (!dpred.isNull())
331 {
332 sb_lemmas.push_back(dpred);
333 }
334 }
335 }
336
337 // add the above symmetry breaking predicates to lemmas
338 std::unordered_map<TNode, TNode, TNodeHashFunction> cache;
339 Node rlv = getRelevancyCondition(n);
340 for (const Node& slem : sb_lemmas)
341 {
342 Node sslem = slem.substitute(x, n, cache);
343 // if we require predicate elimination
344 if (sb_elim_pred.find(slem) != sb_elim_pred.end())
345 {
346 Trace("sygus-sb-tp") << "Eliminate traversal predicates: start "
347 << sslem << std::endl;
348 sslem = eliminateTraversalPredicates(sslem);
349 Trace("sygus-sb-tp") << "Eliminate traversal predicates: finish "
350 << sslem << std::endl;
351 }
352 if (!rlv.isNull())
353 {
354 sslem = nm->mkNode(OR, rlv, sslem);
355 }
356 lemmas.push_back(sslem);
357 }
358 }
359 d_simple_proc[exp] = max_depth + 1;
360
361 // now activate the children those testers were previously asserted in this
362 // context and are awaiting activation, if they exist.
363 if( options::sygusSymBreakLazy() ){
364 Trace("sygus-sb-debug") << "Do lazy symmetry breaking...\n";
365 for( unsigned j=0; j<dt[tindex].getNumArgs(); j++ ){
366 Node sel = NodeManager::currentNM()->mkNode( APPLY_SELECTOR_TOTAL, Node::fromExpr( dt[tindex].getSelectorInternal( ntn.toType(), j ) ), n );
367 Trace("sygus-sb-debug2") << " activate child sel : " << sel << std::endl;
368 Assert( d_active_terms.find( sel )==d_active_terms.end() );
369 IntMap::const_iterator itt = d_testers.find( sel );
370 if( itt != d_testers.end() ){
371 Assert( d_testers_exp.find( sel ) != d_testers_exp.end() );
372 assertTesterInternal( (*itt).second, sel, d_testers_exp[sel], lemmas );
373 }
374 }
375 Trace("sygus-sb-debug") << "...finished" << std::endl;
376 }
377 }
378
getRelevancyCondition(Node n)379 Node SygusSymBreakNew::getRelevancyCondition( Node n ) {
380 std::map< Node, Node >::iterator itr = d_rlv_cond.find( n );
381 if( itr==d_rlv_cond.end() ){
382 Node cond;
383 if( n.getKind()==APPLY_SELECTOR_TOTAL && options::sygusSymBreakRlv() ){
384 TypeNode ntn = n[0].getType();
385 Type nt = ntn.toType();
386 const Datatype& dt = ((DatatypeType)nt).getDatatype();
387 Expr selExpr = n.getOperator().toExpr();
388 if( options::dtSharedSelectors() ){
389 std::vector< Node > disj;
390 bool excl = false;
391 for( unsigned i=0; i<dt.getNumConstructors(); i++ ){
392 int sindexi = dt[i].getSelectorIndexInternal(selExpr);
393 if (sindexi != -1)
394 {
395 disj.push_back(DatatypesRewriter::mkTester(n[0], i, dt).negate());
396 }
397 else
398 {
399 excl = true;
400 }
401 }
402 Assert( !disj.empty() );
403 if( excl ){
404 cond = disj.size() == 1 ? disj[0] : NodeManager::currentNM()->mkNode(
405 kind::AND, disj);
406 }
407 }else{
408 int sindex = Datatype::cindexOf( selExpr );
409 Assert( sindex!=-1 );
410 cond = DatatypesRewriter::mkTester(n[0], sindex, dt).negate();
411 }
412 Node c1 = getRelevancyCondition( n[0] );
413 if( cond.isNull() ){
414 cond = c1;
415 }else if( !c1.isNull() ){
416 cond = NodeManager::currentNM()->mkNode(kind::OR, cond, c1);
417 }
418 }
419 Trace("sygus-sb-debug2") << "Relevancy condition for " << n << " is " << cond << std::endl;
420 d_rlv_cond[n] = cond;
421 return cond;
422 }else{
423 return itr->second;
424 }
425 }
426
getTraversalPredicate(TypeNode tn,Node n,bool isPre)427 Node SygusSymBreakNew::getTraversalPredicate(TypeNode tn, Node n, bool isPre)
428 {
429 unsigned index = isPre ? 0 : 1;
430 std::map<Node, Node>::iterator itt = d_traversal_pred[index][tn].find(n);
431 if (itt != d_traversal_pred[index][tn].end())
432 {
433 return itt->second;
434 }
435 NodeManager* nm = NodeManager::currentNM();
436 std::vector<TypeNode> types;
437 types.push_back(tn);
438 TypeNode ptn = nm->mkPredicateType(types);
439 Node pred = nm->mkSkolem(isPre ? "pre" : "post", ptn);
440 d_traversal_pred[index][tn][n] = pred;
441 return pred;
442 }
443
eliminateTraversalPredicates(Node n)444 Node SygusSymBreakNew::eliminateTraversalPredicates(Node n)
445 {
446 NodeManager* nm = NodeManager::currentNM();
447 std::unordered_map<TNode, Node, TNodeHashFunction> visited;
448 std::unordered_map<TNode, Node, TNodeHashFunction>::iterator it;
449 std::map<Node, Node>::iterator ittb;
450 std::vector<TNode> visit;
451 TNode cur;
452 visit.push_back(n);
453 do
454 {
455 cur = visit.back();
456 visit.pop_back();
457 it = visited.find(cur);
458
459 if (it == visited.end())
460 {
461 if (cur.getKind() == APPLY_UF)
462 {
463 Assert(cur.getType().isBoolean());
464 Assert(cur.getNumChildren() == 1
465 && (cur[0].isVar() || cur[0].getKind() == APPLY_SELECTOR_TOTAL));
466 ittb = d_traversal_bool.find(cur);
467 Node ret;
468 if (ittb == d_traversal_bool.end())
469 {
470 std::stringstream ss;
471 ss << "v_" << cur;
472 ret = nm->mkSkolem(ss.str(), cur.getType());
473 d_traversal_bool[cur] = ret;
474 }
475 else
476 {
477 ret = ittb->second;
478 }
479 visited[cur] = ret;
480 }
481 else
482 {
483 visited[cur] = Node::null();
484 visit.push_back(cur);
485 for (const Node& cn : cur)
486 {
487 visit.push_back(cn);
488 }
489 }
490 }
491 else if (it->second.isNull())
492 {
493 Node ret = cur;
494 bool childChanged = false;
495 std::vector<Node> children;
496 if (cur.getMetaKind() == metakind::PARAMETERIZED)
497 {
498 children.push_back(cur.getOperator());
499 }
500 for (const Node& cn : cur)
501 {
502 it = visited.find(cn);
503 Assert(it != visited.end());
504 Assert(!it->second.isNull());
505 childChanged = childChanged || cn != it->second;
506 children.push_back(it->second);
507 }
508 if (childChanged)
509 {
510 ret = nm->mkNode(cur.getKind(), children);
511 }
512 visited[cur] = ret;
513 }
514 } while (!visit.empty());
515 Assert(visited.find(n) != visited.end());
516 Assert(!visited.find(n)->second.isNull());
517 return visited[n];
518 }
519
getSimpleSymBreakPred(Node e,TypeNode tn,int tindex,unsigned depth,bool usingSymCons,bool isVarAgnostic)520 Node SygusSymBreakNew::getSimpleSymBreakPred(Node e,
521 TypeNode tn,
522 int tindex,
523 unsigned depth,
524 bool usingSymCons,
525 bool isVarAgnostic)
526 {
527 // Compute the tuple of expressions we hash the predicate for.
528
529 // The hash value in d_simple_sb_pred for the given options
530 unsigned optHashVal = usingSymCons ? 1 : 0;
531 if (isVarAgnostic && depth == 0)
532 {
533 // variable agnostic symmetry breaking only applies at depth 0
534 optHashVal = optHashVal + 2;
535 }
536 else
537 {
538 // enumerator is only specific to variable agnostic symmetry breaking
539 e = Node::null();
540 }
541 std::map<unsigned, Node>& ssbCache =
542 d_simple_sb_pred[e][tn][tindex][optHashVal];
543 std::map<unsigned, Node>::iterator it = ssbCache.find(depth);
544 if (it != ssbCache.end())
545 {
546 return it->second;
547 }
548 // this function is only called on sygus datatype types
549 Assert(tn.isDatatype());
550 NodeManager* nm = NodeManager::currentNM();
551 Node n = getFreeVar(tn);
552 const Datatype& dt = static_cast<DatatypeType>(tn.toType()).getDatatype();
553 Assert(dt.isSygus());
554 Assert(tindex >= 0 && tindex < static_cast<int>(dt.getNumConstructors()));
555
556 Trace("sygus-sb-simple-debug")
557 << "Simple symmetry breaking for " << dt.getName() << ", constructor "
558 << dt[tindex].getName() << ", at depth " << depth << std::endl;
559
560 // get the sygus operator
561 Node sop = Node::fromExpr(dt[tindex].getSygusOp());
562 // get the kind of the constructor operator
563 Kind nk = d_tds->getConsNumKind(tn, tindex);
564 // is this the any-constant constructor?
565 bool isAnyConstant = sop.getAttribute(SygusAnyConstAttribute());
566
567 // conjunctive conclusion of lemma
568 std::vector<Node> sbp_conj;
569
570 // the number of (sygus) arguments
571 // Notice if this is an any-constant constructor, its child is not a
572 // sygus child, hence we set to 0 here.
573 unsigned dt_index_nargs = isAnyConstant ? 0 : dt[tindex].getNumArgs();
574
575 // builtin type
576 TypeNode tnb = TypeNode::fromType(dt.getSygusType());
577 // get children
578 std::vector<Node> children;
579 for (unsigned j = 0; j < dt_index_nargs; j++)
580 {
581 Node sel = nm->mkNode(
582 APPLY_SELECTOR_TOTAL,
583 Node::fromExpr(dt[tindex].getSelectorInternal(tn.toType(), j)),
584 n);
585 Assert(sel.getType().isDatatype());
586 children.push_back(sel);
587 }
588
589 if (depth == 0)
590 {
591 Trace("sygus-sb-simple-debug") << " Size..." << std::endl;
592 // fairness
593 if (options::sygusFair() == SYGUS_FAIR_DT_SIZE && !isAnyConstant)
594 {
595 Node szl = nm->mkNode(DT_SIZE, n);
596 Node szr =
597 nm->mkNode(DT_SIZE, DatatypesRewriter::getInstCons(n, dt, tindex));
598 szr = Rewriter::rewrite(szr);
599 sbp_conj.push_back(szl.eqNode(szr));
600 }
601 if (isVarAgnostic)
602 {
603 // Enforce symmetry breaking lemma template for each x_i:
604 // template z.
605 // is-x_i( z ) => pre_{x_{i-1}}( z )
606 // for args a = 1...n
607 // // pre-definition
608 // pre_{x_i}( z.a ) = a=0 ? pre_{x_i}( z ) : post_{x_i}( z.{a-1} )
609 // post_{x_i}( z ) = post_{x_i}( z.n ) OR is-x_i( z )
610
611 // Notice that we are constructing a symmetry breaking template
612 // under the condition that is-C( z ) holds in this method, where C
613 // is the tindex^{th} constructor of dt. Thus, is-x_i( z ) is either
614 // true or false below.
615
616 Node svl = Node::fromExpr(dt.getSygusVarList());
617 // for each variable
618 Assert(!e.isNull());
619 TypeNode etn = e.getType();
620 // for each variable in the sygus type
621 for (const Node& var : svl)
622 {
623 unsigned sc = d_tds->getSubclassForVar(etn, var);
624 if (d_tds->getNumSubclassVars(etn, sc) == 1)
625 {
626 // unique variable in singleton subclass, skip
627 continue;
628 }
629 // Compute the "predecessor" variable in the subclass of var.
630 Node predVar;
631 unsigned scindex = 0;
632 if (d_tds->getIndexInSubclassForVar(etn, var, scindex))
633 {
634 if (scindex > 0)
635 {
636 predVar = d_tds->getVarSubclassIndex(etn, sc, scindex - 1);
637 }
638 }
639 Node preParentOp = getTraversalPredicate(tn, var, true);
640 Node preParent = nm->mkNode(APPLY_UF, preParentOp, n);
641 Node prev = preParent;
642 // for each child
643 for (const Node& child : children)
644 {
645 TypeNode ctn = child.getType();
646 // my pre is equal to the previous
647 Node preCurrOp = getTraversalPredicate(ctn, var, true);
648 Node preCurr = nm->mkNode(APPLY_UF, preCurrOp, child);
649 // definition of pre, for each argument
650 sbp_conj.push_back(preCurr.eqNode(prev));
651 Node postCurrOp = getTraversalPredicate(ctn, var, false);
652 prev = nm->mkNode(APPLY_UF, postCurrOp, child);
653 }
654 Node postParent = getTraversalPredicate(tn, var, false);
655 Node finish = nm->mkNode(APPLY_UF, postParent, n);
656 // check if we are constructing the symmetry breaking predicate for the
657 // variable in question. If so, is-{x_i}( z ) is true.
658 int varCn = d_tds->getOpConsNum(tn, var);
659 if (varCn == static_cast<int>(tindex))
660 {
661 // the post value is true
662 prev = d_true;
663 // requirement : If I am the variable, I must have seen
664 // the variable before this one in its type class.
665 if (!predVar.isNull())
666 {
667 Node preParentPredVarOp = getTraversalPredicate(tn, predVar, true);
668 Node preParentPredVar = nm->mkNode(APPLY_UF, preParentPredVarOp, n);
669 sbp_conj.push_back(preParentPredVar);
670 }
671 }
672 // definition of post
673 sbp_conj.push_back(finish.eqNode(prev));
674 }
675 }
676 }
677
678 // if we are the "any constant" constructor, we do no symmetry breaking
679 // only do simple symmetry breaking up to depth 2
680 bool doSymBreak = options::sygusSymBreak();
681 if (isAnyConstant || depth > 2)
682 {
683 doSymBreak = false;
684 }
685 // symmetry breaking
686 if (doSymBreak)
687 {
688 // direct solving for children
689 // for instance, we may want to insist that the LHS of MINUS is 0
690 Trace("sygus-sb-simple-debug") << " Solve children..." << std::endl;
691 std::map<unsigned, unsigned> children_solved;
692 for (unsigned j = 0; j < dt_index_nargs; j++)
693 {
694 int i = d_ssb.solveForArgument(tn, tindex, j);
695 if (i >= 0)
696 {
697 children_solved[j] = i;
698 TypeNode ctn = children[j].getType();
699 const Datatype& cdt =
700 static_cast<DatatypeType>(ctn.toType()).getDatatype();
701 Assert(i < static_cast<int>(cdt.getNumConstructors()));
702 sbp_conj.push_back(DatatypesRewriter::mkTester(children[j], i, cdt));
703 }
704 }
705
706 // depth 1 symmetry breaking : talks about direct children
707 if (depth == 1)
708 {
709 if (nk != UNDEFINED_KIND)
710 {
711 Trace("sygus-sb-simple-debug")
712 << " Equality reasoning about children..." << std::endl;
713 // commutative operators
714 if (quantifiers::TermUtil::isComm(nk))
715 {
716 if (children.size() == 2
717 && children[0].getType() == children[1].getType())
718 {
719 Node order_pred = getTermOrderPredicate(children[0], children[1]);
720 sbp_conj.push_back(order_pred);
721 }
722 }
723 // operators whose arguments are non-additive (e.g. should be different)
724 std::vector<unsigned> deq_child[2];
725 if (children.size() == 2 && children[0].getType() == tn)
726 {
727 bool argDeq = false;
728 if (quantifiers::TermUtil::isNonAdditive(nk))
729 {
730 argDeq = true;
731 }
732 else
733 {
734 // other cases of rewriting x k x -> x'
735 Node req_const;
736 if (nk == GT || nk == LT || nk == XOR || nk == MINUS
737 || nk == BITVECTOR_SUB || nk == BITVECTOR_XOR
738 || nk == BITVECTOR_UREM_TOTAL)
739 {
740 // must have the zero element
741 req_const = quantifiers::TermUtil::mkTypeValue(tnb, 0);
742 }
743 else if (nk == EQUAL || nk == LEQ || nk == GEQ
744 || nk == BITVECTOR_XNOR)
745 {
746 req_const = quantifiers::TermUtil::mkTypeMaxValue(tnb);
747 }
748 // cannot do division since we have to consider when both are zero
749 if (!req_const.isNull())
750 {
751 if (d_tds->hasConst(tn, req_const))
752 {
753 argDeq = true;
754 }
755 }
756 }
757 if (argDeq)
758 {
759 deq_child[0].push_back(0);
760 deq_child[1].push_back(1);
761 }
762 }
763 if (nk == ITE || nk == STRING_STRREPL || nk == STRING_STRREPLALL)
764 {
765 deq_child[0].push_back(1);
766 deq_child[1].push_back(2);
767 }
768 if (nk == STRING_STRREPL || nk == STRING_STRREPLALL)
769 {
770 deq_child[0].push_back(0);
771 deq_child[1].push_back(1);
772 }
773 // this code adds simple symmetry breaking predicates of the form
774 // d.i != d.j, for example if we are considering an ITE constructor,
775 // we enforce that d.1 != d.2 since otherwise the ITE can be
776 // simplified.
777 for (unsigned i = 0, size = deq_child[0].size(); i < size; i++)
778 {
779 unsigned c1 = deq_child[0][i];
780 unsigned c2 = deq_child[1][i];
781 TypeNode tnc = children[c1].getType();
782 // we may only apply this symmetry breaking scheme (which introduces
783 // disequalities) if the types are infinite.
784 if (tnc == children[c2].getType() && !tnc.isInterpretedFinite())
785 {
786 Node sym_lem_deq = children[c1].eqNode(children[c2]).negate();
787 // notice that this symmetry breaking still allows for
788 // ite( C, any_constant(x), any_constant(y) )
789 // since any_constant takes a builtin argument.
790 sbp_conj.push_back(sym_lem_deq);
791 }
792 }
793
794 Trace("sygus-sb-simple-debug") << " Redundant operators..."
795 << std::endl;
796 // singular arguments (e.g. 0 for mult)
797 // redundant arguments (e.g. 0 for plus, 1 for mult)
798 // right-associativity
799 // simple rewrites
800 // explanation of why not all children of this are constant
801 std::vector<Node> exp_not_all_const;
802 // is the above explanation valid? This is set to false if
803 // one child does not have a constant, hence making the explanation
804 // false.
805 bool exp_not_all_const_valid = dt_index_nargs > 0;
806 // does the parent have an any constant constructor?
807 bool usingAnyConstCons =
808 usingSymCons && (d_tds->getAnyConstantConsNum(tn) != -1);
809 for (unsigned j = 0; j < dt_index_nargs; j++)
810 {
811 Node nc = children[j];
812 // if not already solved
813 if (children_solved.find(j) != children_solved.end())
814 {
815 continue;
816 }
817 TypeNode tnc = nc.getType();
818 int anyc_cons_num = d_tds->getAnyConstantConsNum(tnc);
819 const Datatype& cdt =
820 static_cast<DatatypeType>(tnc.toType()).getDatatype();
821 std::vector<Node> exp_const;
822 for (unsigned k = 0, ncons = cdt.getNumConstructors(); k < ncons; k++)
823 {
824 Kind nck = d_tds->getConsNumKind(tnc, k);
825 bool red = false;
826 Node tester = DatatypesRewriter::mkTester(nc, k, cdt);
827 // check if the argument is redundant
828 if (static_cast<int>(k) == anyc_cons_num)
829 {
830 exp_const.push_back(tester);
831 }
832 else if (nck != UNDEFINED_KIND)
833 {
834 Trace("sygus-sb-simple-debug") << " argument " << j << " " << k
835 << " is : " << nck << std::endl;
836 red = !d_ssb.considerArgKind(tnc, tn, nck, nk, j);
837 }
838 else
839 {
840 Node cc = d_tds->getConsNumConst(tnc, k);
841 if (!cc.isNull())
842 {
843 Trace("sygus-sb-simple-debug")
844 << " argument " << j << " " << k << " is constant : " << cc
845 << std::endl;
846 red = !d_ssb.considerConst(tnc, tn, cc, nk, j);
847 if (usingAnyConstCons)
848 {
849 // we only consider concrete constant constructors
850 // of children if we have the "any constant" constructor
851 // otherwise, we would disallow solutions for grammars
852 // like the following:
853 // A -> B+B
854 // B -> 4 | 8 | 100
855 // where A allows all constants but is not using the
856 // any constant constructor.
857 exp_const.push_back(tester);
858 }
859 }
860 else
861 {
862 // defined function?
863 }
864 }
865 if (red)
866 {
867 Trace("sygus-sb-simple-debug") << " ...redundant." << std::endl;
868 sbp_conj.push_back(tester.negate());
869 }
870 }
871 if (exp_const.empty())
872 {
873 exp_not_all_const_valid = false;
874 }
875 else
876 {
877 Node ecn = exp_const.size() == 1 ? exp_const[0]
878 : nm->mkNode(OR, exp_const);
879 exp_not_all_const.push_back(ecn.negate());
880 }
881 }
882 // explicitly handle constants and "any constant" constructors
883 // if this type admits any constant, then at least one of my
884 // children must not be a constant or the "any constant" constructor
885 if (dt.getSygusAllowConst() && exp_not_all_const_valid)
886 {
887 Assert(!exp_not_all_const.empty());
888 Node expaan = exp_not_all_const.size() == 1
889 ? exp_not_all_const[0]
890 : nm->mkNode(OR, exp_not_all_const);
891 Trace("sygus-sb-simple-debug")
892 << "Ensure not all constant: " << expaan << std::endl;
893 sbp_conj.push_back(expaan);
894 }
895 }
896 else
897 {
898 // defined function?
899 }
900 }
901 else if (depth == 2)
902 {
903 // commutative operators
904 if (quantifiers::TermUtil::isComm(nk) && children.size() == 2
905 && children[0].getType() == tn && children[1].getType() == tn)
906 {
907 // chainable
908 Node child11 = nm->mkNode(
909 APPLY_SELECTOR_TOTAL,
910 Node::fromExpr(dt[tindex].getSelectorInternal(tn.toType(), 1)),
911 children[0]);
912 Assert(child11.getType() == children[1].getType());
913 Node order_pred_trans = nm->mkNode(
914 OR,
915 DatatypesRewriter::mkTester(children[0], tindex, dt).negate(),
916 getTermOrderPredicate(child11, children[1]));
917 sbp_conj.push_back(order_pred_trans);
918 }
919 }
920 }
921
922 Node sb_pred;
923 if (!sbp_conj.empty())
924 {
925 sb_pred =
926 sbp_conj.size() == 1 ? sbp_conj[0] : nm->mkNode(kind::AND, sbp_conj);
927 Trace("sygus-sb-simple")
928 << "Simple predicate for " << tn << " index " << tindex << " (" << nk
929 << ") at depth " << depth << " : " << std::endl;
930 Trace("sygus-sb-simple") << " " << sb_pred << std::endl;
931 sb_pred = nm->mkNode(
932 kind::OR, DatatypesRewriter::mkTester(n, tindex, dt).negate(), sb_pred);
933 }
934 d_simple_sb_pred[e][tn][tindex][optHashVal][depth] = sb_pred;
935 return sb_pred;
936 }
937
getFreeVar(TypeNode tn)938 TNode SygusSymBreakNew::getFreeVar( TypeNode tn ) {
939 return d_tds->getFreeVar(tn, 0);
940 }
941
registerSearchTerm(TypeNode tn,unsigned d,Node n,bool topLevel,std::vector<Node> & lemmas)942 void SygusSymBreakNew::registerSearchTerm( TypeNode tn, unsigned d, Node n, bool topLevel, std::vector< Node >& lemmas ) {
943 //register this term
944 std::unordered_map<Node, Node, NodeHashFunction>::iterator ita =
945 d_term_to_anchor.find(n);
946 Assert( ita != d_term_to_anchor.end() );
947 Node a = ita->second;
948 Assert( !a.isNull() );
949 if( std::find( d_cache[a].d_search_terms[tn][d].begin(), d_cache[a].d_search_terms[tn][d].end(), n )==d_cache[a].d_search_terms[tn][d].end() ){
950 Trace("sygus-sb-debug") << " register search term : " << n << " at depth " << d << ", type=" << tn << ", tl=" << topLevel << std::endl;
951 d_cache[a].d_search_terms[tn][d].push_back( n );
952 if( !options::sygusSymBreakLazy() ){
953 addSymBreakLemmasFor( tn, n, d, lemmas );
954 }
955 }
956 }
957
registerSearchValue(Node a,Node n,Node nv,unsigned d,std::vector<Node> & lemmas,bool isVarAgnostic,bool doSym)958 Node SygusSymBreakNew::registerSearchValue(Node a,
959 Node n,
960 Node nv,
961 unsigned d,
962 std::vector<Node>& lemmas,
963 bool isVarAgnostic,
964 bool doSym)
965 {
966 Assert(n.getType().isComparableTo(nv.getType()));
967 TypeNode tn = n.getType();
968 if (!tn.isDatatype())
969 {
970 // don't register non-datatype terms, instead we return the
971 // selector chain n.
972 return n;
973 }
974 const Datatype& dt = ((DatatypeType)tn.toType()).getDatatype();
975 if (!dt.isSygus())
976 {
977 // don't register non-sygus-datatype terms
978 return n;
979 }
980 Assert(nv.getKind() == APPLY_CONSTRUCTOR);
981 NodeManager* nm = NodeManager::currentNM();
982 // we call the body of this function in a bottom-up fashion
983 // this ensures that the "abstraction" of the model value is available
984 if( nv.getNumChildren()>0 ){
985 unsigned cindex = DatatypesRewriter::indexOf(nv.getOperator());
986 std::vector<Node> rcons_children;
987 rcons_children.push_back(nv.getOperator());
988 bool childrenChanged = false;
989 for (unsigned i = 0, nchild = nv.getNumChildren(); i < nchild; i++)
990 {
991 Node sel = nm->mkNode(
992 APPLY_SELECTOR_TOTAL,
993 Node::fromExpr(dt[cindex].getSelectorInternal(tn.toType(), i)),
994 n);
995 Node nvc = registerSearchValue(a,
996 sel,
997 nv[i],
998 d + 1,
999 lemmas,
1000 isVarAgnostic,
1001 doSym && (!isVarAgnostic || i == 0));
1002 if (nvc.isNull())
1003 {
1004 return Node::null();
1005 }
1006 rcons_children.push_back(nvc);
1007 childrenChanged = childrenChanged || nvc != nv[i];
1008 }
1009 // reconstruct the value, which may be a skeleton
1010 if (childrenChanged)
1011 {
1012 nv = nm->mkNode(APPLY_CONSTRUCTOR, rcons_children);
1013 }
1014 }
1015 if (!doSym)
1016 {
1017 return nv;
1018 }
1019 Trace("sygus-sb-debug2") << "Registering search value " << n << " -> " << nv << std::endl;
1020 std::map<TypeNode, int> var_count;
1021 Node cnv = d_tds->canonizeBuiltin(nv, var_count);
1022 Trace("sygus-sb-debug") << " ...canonized value is " << cnv << std::endl;
1023 // must do this for all nodes, regardless of top-level
1024 if (d_cache[a].d_search_val_proc.find(cnv)
1025 == d_cache[a].d_search_val_proc.end())
1026 {
1027 d_cache[a].d_search_val_proc.insert(cnv);
1028 // get the root (for PBE symmetry breaking)
1029 Assert(d_anchor_to_conj.find(a) != d_anchor_to_conj.end());
1030 quantifiers::SynthConjecture* aconj = d_anchor_to_conj[a];
1031 Assert(aconj != NULL);
1032 Trace("sygus-sb-debug") << " ...register search value " << cnv
1033 << ", type=" << tn << std::endl;
1034 Node bv = d_tds->sygusToBuiltin(cnv, tn);
1035 Trace("sygus-sb-debug") << " ......builtin is " << bv << std::endl;
1036 Node bvr = d_tds->getExtRewriter()->extendedRewrite(bv);
1037 Trace("sygus-sb-debug") << " ......search value rewrites to " << bvr << std::endl;
1038 Trace("dt-sygus") << " * DT builtin : " << n << " -> " << bvr << std::endl;
1039 unsigned sz = d_tds->getSygusTermSize( nv );
1040 if( d_tds->involvesDivByZero( bvr ) ){
1041 quantifiers::DivByZeroSygusInvarianceTest dbzet;
1042 Trace("sygus-sb-mexp-debug") << "Minimize explanation for div-by-zero in "
1043 << bv << std::endl;
1044 registerSymBreakLemmaForValue(
1045 a, nv, dbzet, Node::null(), var_count, lemmas);
1046 return Node::null();
1047 }else{
1048 std::unordered_map<Node, Node, NodeHashFunction>::iterator itsv =
1049 d_cache[a].d_search_val[tn].find(bvr);
1050 Node bad_val_bvr;
1051 bool by_examples = false;
1052 if( itsv==d_cache[a].d_search_val[tn].end() ){
1053 // TODO (github #1210) conjecture-specific symmetry breaking
1054 // this should be generalized and encapsulated within the
1055 // SynthConjecture class.
1056 // Is it equivalent under examples?
1057 Node bvr_equiv;
1058 if (options::sygusSymBreakPbe())
1059 {
1060 if (aconj->getPbe()->hasExamples(a))
1061 {
1062 bvr_equiv = aconj->getPbe()->addSearchVal(tn, a, bvr);
1063 }
1064 }
1065 if( !bvr_equiv.isNull() ){
1066 if( bvr_equiv!=bvr ){
1067 Trace("sygus-sb-debug") << "......adding search val for " << bvr << " returned " << bvr_equiv << std::endl;
1068 Assert( d_cache[a].d_search_val[tn].find( bvr_equiv )!=d_cache[a].d_search_val[tn].end() );
1069 Trace("sygus-sb-debug") << "......search value was " << d_cache[a].d_search_val[tn][bvr_equiv] << std::endl;
1070 if( Trace.isOn("sygus-sb-exc") ){
1071 Node prev = d_tds->sygusToBuiltin( d_cache[a].d_search_val[tn][bvr_equiv], tn );
1072 Trace("sygus-sb-exc") << " ......programs " << prev << " and " << bv << " are equivalent up to examples." << std::endl;
1073 }
1074 bad_val_bvr = bvr_equiv;
1075 by_examples = true;
1076 }
1077 }
1078 //store rewritten values, regardless of whether it will be considered
1079 d_cache[a].d_search_val[tn][bvr] = nv;
1080 d_cache[a].d_search_val_sz[tn][bvr] = sz;
1081 }else{
1082 bad_val_bvr = bvr;
1083 if( Trace.isOn("sygus-sb-exc") ){
1084 Node prev_bv = d_tds->sygusToBuiltin( itsv->second, tn );
1085 Trace("sygus-sb-exc") << " ......programs " << prev_bv << " and " << bv << " rewrite to " << bvr << "." << std::endl;
1086 }
1087 }
1088
1089 if (options::sygusRewVerify())
1090 {
1091 if (bv != bvr)
1092 {
1093 // add to the sampler database object
1094 std::map<TypeNode, quantifiers::SygusSampler>::iterator its =
1095 d_sampler[a].find(tn);
1096 if (its == d_sampler[a].end())
1097 {
1098 d_sampler[a][tn].initializeSygus(
1099 d_tds, nv, options::sygusSamples(), false);
1100 its = d_sampler[a].find(tn);
1101 }
1102 // check equivalent
1103 its->second.checkEquivalent(bv, bvr);
1104 }
1105 }
1106
1107 if( !bad_val_bvr.isNull() ){
1108 Node bad_val = nv;
1109 Node bad_val_o = d_cache[a].d_search_val[tn][bad_val_bvr];
1110 Assert( d_cache[a].d_search_val_sz[tn].find( bad_val_bvr )!=d_cache[a].d_search_val_sz[tn].end() );
1111 unsigned prev_sz = d_cache[a].d_search_val_sz[tn][bad_val_bvr];
1112 bool doFlip = (prev_sz > sz);
1113 if (doFlip)
1114 {
1115 //swap : the excluded value is the previous
1116 d_cache[a].d_search_val_sz[tn][bad_val_bvr] = sz;
1117 bad_val = d_cache[a].d_search_val[tn][bad_val_bvr];
1118 bad_val_o = nv;
1119 if (Trace.isOn("sygus-sb-exc"))
1120 {
1121 Trace("sygus-sb-exc") << "Flip : exclude ";
1122 quantifiers::TermDbSygus::toStreamSygus("sygus-sb-exc", bad_val);
1123 Trace("sygus-sb-exc") << " instead of ";
1124 quantifiers::TermDbSygus::toStreamSygus("sygus-sb-exc", bad_val_o);
1125 Trace("sygus-sb-exc") << ", since its size is " << sz << " < "
1126 << prev_sz << std::endl;
1127 }
1128 sz = prev_sz;
1129 }
1130 if( Trace.isOn("sygus-sb-exc") ){
1131 Node bad_val_bv = d_tds->sygusToBuiltin( bad_val, tn );
1132 Trace("sygus-sb-exc") << " ........exclude : " << bad_val_bv;
1133 if( by_examples ){
1134 Trace("sygus-sb-exc") << " (by examples)";
1135 }
1136 Trace("sygus-sb-exc") << std::endl;
1137 }
1138 Assert( d_tds->getSygusTermSize( bad_val )==sz );
1139
1140 // generalize the explanation for why the analog of bad_val
1141 // is equivalent to bvr
1142 quantifiers::EquivSygusInvarianceTest eset;
1143 eset.init(d_tds, tn, aconj, a, bvr);
1144
1145 Trace("sygus-sb-mexp-debug") << "Minimize explanation for eval[" << d_tds->sygusToBuiltin( bad_val ) << "] = " << bvr << std::endl;
1146 registerSymBreakLemmaForValue(
1147 a, bad_val, eset, bad_val_o, var_count, lemmas);
1148
1149 // other generalization criteria go here
1150
1151 // If the exclusion was flipped, we are excluding a previous value
1152 // instead of the current one. Hence, the current value is a legal
1153 // value that we will consider.
1154 if (!doFlip)
1155 {
1156 return Node::null();
1157 }
1158 }
1159 }
1160 }
1161 return nv;
1162 }
1163
registerSymBreakLemmaForValue(Node a,Node val,quantifiers::SygusInvarianceTest & et,Node valr,std::map<TypeNode,int> & var_count,std::vector<Node> & lemmas)1164 void SygusSymBreakNew::registerSymBreakLemmaForValue(
1165 Node a,
1166 Node val,
1167 quantifiers::SygusInvarianceTest& et,
1168 Node valr,
1169 std::map<TypeNode, int>& var_count,
1170 std::vector<Node>& lemmas)
1171 {
1172 TypeNode tn = val.getType();
1173 Node x = getFreeVar(tn);
1174 unsigned sz = d_tds->getSygusTermSize(val);
1175 std::vector<Node> exp;
1176 d_tds->getExplain()->getExplanationFor(x, val, exp, et, valr, var_count, sz);
1177 Node lem =
1178 exp.size() == 1 ? exp[0] : NodeManager::currentNM()->mkNode(AND, exp);
1179 lem = lem.negate();
1180 Trace("sygus-sb-exc") << " ........exc lemma is " << lem << ", size = " << sz
1181 << std::endl;
1182 registerSymBreakLemma(tn, lem, sz, a, lemmas);
1183 }
1184
registerSymBreakLemma(TypeNode tn,Node lem,unsigned sz,Node a,std::vector<Node> & lemmas)1185 void SygusSymBreakNew::registerSymBreakLemma( TypeNode tn, Node lem, unsigned sz, Node a, std::vector< Node >& lemmas ) {
1186 // lem holds for all terms of type tn, and is applicable to terms of size sz
1187 Trace("sygus-sb-debug") << " register sym break lemma : " << lem
1188 << std::endl;
1189 Trace("sygus-sb-debug") << " anchor : " << a << std::endl;
1190 Trace("sygus-sb-debug") << " type : " << tn << std::endl;
1191 Trace("sygus-sb-debug") << " size : " << sz << std::endl;
1192 Assert( !a.isNull() );
1193 d_cache[a].d_sb_lemmas[tn][sz].push_back( lem );
1194 TNode x = getFreeVar( tn );
1195 unsigned csz = getSearchSizeForAnchor( a );
1196 int max_depth = ((int)csz)-((int)sz);
1197 NodeManager* nm = NodeManager::currentNM();
1198 for( int d=0; d<=max_depth; d++ ){
1199 std::map< unsigned, std::vector< Node > >::iterator itt = d_cache[a].d_search_terms[tn].find( d );
1200 if( itt!=d_cache[a].d_search_terms[tn].end() ){
1201 for (const TNode& t : itt->second)
1202 {
1203 if (!options::sygusSymBreakLazy()
1204 || d_active_terms.find(t) != d_active_terms.end())
1205 {
1206 Node slem = lem.substitute(x, t);
1207 Node rlv = getRelevancyCondition(t);
1208 if (!rlv.isNull())
1209 {
1210 slem = nm->mkNode(OR, rlv, slem);
1211 }
1212 lemmas.push_back(slem);
1213 }
1214 }
1215 }
1216 }
1217 }
addSymBreakLemmasFor(TypeNode tn,Node t,unsigned d,std::vector<Node> & lemmas)1218 void SygusSymBreakNew::addSymBreakLemmasFor( TypeNode tn, Node t, unsigned d, std::vector< Node >& lemmas ) {
1219 Assert( d_term_to_anchor.find( t )!=d_term_to_anchor.end() );
1220 Node a = d_term_to_anchor[t];
1221 addSymBreakLemmasFor( tn, t, d, a, lemmas );
1222 }
1223
addSymBreakLemmasFor(TypeNode tn,Node t,unsigned d,Node a,std::vector<Node> & lemmas)1224 void SygusSymBreakNew::addSymBreakLemmasFor( TypeNode tn, Node t, unsigned d, Node a, std::vector< Node >& lemmas ) {
1225 Assert( t.getType()==tn );
1226 Assert( !a.isNull() );
1227 Trace("sygus-sb-debug2") << "add sym break lemmas for " << t << " " << d
1228 << " " << a << std::endl;
1229 std::map< TypeNode, std::map< unsigned, std::vector< Node > > >::iterator its = d_cache[a].d_sb_lemmas.find( tn );
1230 Node rlv = getRelevancyCondition(t);
1231 NodeManager* nm = NodeManager::currentNM();
1232 if( its != d_cache[a].d_sb_lemmas.end() ){
1233 TNode x = getFreeVar( tn );
1234 //get symmetry breaking lemmas for this term
1235 unsigned csz = getSearchSizeForAnchor( a );
1236 int max_sz = ((int)csz) - ((int)d);
1237 Trace("sygus-sb-debug2")
1238 << "add lemmas up to size " << max_sz << ", which is (search_size) "
1239 << csz << " - (depth) " << d << std::endl;
1240 std::unordered_map<TNode, TNode, TNodeHashFunction> cache;
1241 for( std::map< unsigned, std::vector< Node > >::iterator it = its->second.begin(); it != its->second.end(); ++it ){
1242 if( (int)it->first<=max_sz ){
1243 for (const Node& lem : it->second)
1244 {
1245 Node slem = lem.substitute(x, t, cache);
1246 // add the relevancy condition for t
1247 if (!rlv.isNull())
1248 {
1249 slem = nm->mkNode(OR, rlv, slem);
1250 }
1251 lemmas.push_back(slem);
1252 }
1253 }
1254 }
1255 }
1256 Trace("sygus-sb-debug2") << "...finished." << std::endl;
1257 }
1258
preRegisterTerm(TNode n,std::vector<Node> & lemmas)1259 void SygusSymBreakNew::preRegisterTerm( TNode n, std::vector< Node >& lemmas ) {
1260 if( n.isVar() ){
1261 Trace("sygus-sb-debug") << "Pre-register variable : " << n << std::endl;
1262 registerSizeTerm( n, lemmas );
1263 }
1264 }
1265
registerSizeTerm(Node e,std::vector<Node> & lemmas)1266 void SygusSymBreakNew::registerSizeTerm(Node e, std::vector<Node>& lemmas)
1267 {
1268 if (d_register_st.find(e) != d_register_st.end())
1269 {
1270 // already registered
1271 return;
1272 }
1273 TypeNode etn = e.getType();
1274 if (!etn.isDatatype())
1275 {
1276 // not a datatype term
1277 d_register_st[e] = false;
1278 return;
1279 }
1280 const Datatype& dt = etn.getDatatype();
1281 if (!dt.isSygus())
1282 {
1283 // not a sygus datatype term
1284 d_register_st[e] = false;
1285 return;
1286 }
1287 if (!d_tds->isEnumerator(e))
1288 {
1289 // not sure if it is a size term or not (may be registered later?)
1290 return;
1291 }
1292 d_register_st[e] = true;
1293 Node ag = d_tds->getActiveGuardForEnumerator(e);
1294 if (!ag.isNull())
1295 {
1296 d_anchor_to_active_guard[e] = ag;
1297 std::map<Node, std::unique_ptr<DecisionStrategy>>::iterator itaas =
1298 d_anchor_to_ag_strategy.find(e);
1299 if (itaas == d_anchor_to_ag_strategy.end())
1300 {
1301 d_anchor_to_ag_strategy[e].reset(
1302 new DecisionStrategySingleton("sygus_enum_active",
1303 ag,
1304 d_td->getSatContext(),
1305 d_td->getValuation()));
1306 }
1307 d_td->getDecisionManager()->registerStrategy(
1308 DecisionManager::STRAT_DT_SYGUS_ENUM_ACTIVE,
1309 d_anchor_to_ag_strategy[e].get());
1310 }
1311 Node m;
1312 if (!ag.isNull())
1313 {
1314 // if it has an active guard (it is an enumerator), use itself as measure
1315 // term. This will enforce fairness on it independently.
1316 m = e;
1317 }
1318 else
1319 {
1320 // otherwise we enforce fairness in a unified way for all
1321 if (d_generic_measure_term.isNull())
1322 {
1323 // choose e as master for all future terms
1324 d_generic_measure_term = e;
1325 }
1326 m = d_generic_measure_term;
1327 }
1328 Trace("sygus-sb") << "Sygus : register size term : " << e << " with measure "
1329 << m << std::endl;
1330 registerMeasureTerm(m);
1331 d_szinfo[m]->d_anchors.push_back(e);
1332 d_anchor_to_measure_term[e] = m;
1333 NodeManager* nm = NodeManager::currentNM();
1334 if (options::sygusFair() == SYGUS_FAIR_DT_SIZE)
1335 {
1336 // update constraints on the measure term
1337 Node slem;
1338 if (options::sygusFairMax())
1339 {
1340 Node ds = nm->mkNode(DT_SIZE, e);
1341 slem = nm->mkNode(LEQ, ds, d_szinfo[m]->getOrMkMeasureValue(lemmas));
1342 }else{
1343 Node mt = d_szinfo[m]->getOrMkActiveMeasureValue(lemmas);
1344 Node new_mt = d_szinfo[m]->getOrMkActiveMeasureValue(lemmas, true);
1345 Node ds = nm->mkNode(DT_SIZE, e);
1346 slem = mt.eqNode(nm->mkNode(PLUS, new_mt, ds));
1347 }
1348 Trace("sygus-sb") << "...size lemma : " << slem << std::endl;
1349 lemmas.push_back(slem);
1350 }
1351 if (d_tds->isVariableAgnosticEnumerator(e))
1352 {
1353 // if it is variable agnostic, enforce top-level constraint that says no
1354 // variables occur pre-traversal at top-level
1355 Node varList = Node::fromExpr(dt.getSygusVarList());
1356 std::vector<Node> constraints;
1357 for (const Node& v : varList)
1358 {
1359 unsigned sc = d_tds->getSubclassForVar(etn, v);
1360 // no symmetry breaking occurs for variables in singleton subclasses
1361 if (d_tds->getNumSubclassVars(etn, sc) > 1)
1362 {
1363 Node preRootOp = getTraversalPredicate(etn, v, true);
1364 Node preRoot = nm->mkNode(APPLY_UF, preRootOp, e);
1365 constraints.push_back(preRoot.negate());
1366 }
1367 }
1368 if (!constraints.empty())
1369 {
1370 Node preNoVar = constraints.size() == 1 ? constraints[0]
1371 : nm->mkNode(AND, constraints);
1372 Node preNoVarProc = eliminateTraversalPredicates(preNoVar);
1373 Trace("sygus-sb") << "...variable order : " << preNoVarProc << std::endl;
1374 Trace("sygus-sb-tp") << "...variable order : " << preNoVarProc
1375 << std::endl;
1376 lemmas.push_back(preNoVarProc);
1377 }
1378 }
1379 }
1380
registerMeasureTerm(Node m)1381 void SygusSymBreakNew::registerMeasureTerm( Node m ) {
1382 std::map<Node, std::unique_ptr<SygusSizeDecisionStrategy>>::iterator it =
1383 d_szinfo.find(m);
1384 if( it==d_szinfo.end() ){
1385 Trace("sygus-sb") << "Sygus : register measure term : " << m << std::endl;
1386 d_szinfo[m].reset(new SygusSizeDecisionStrategy(
1387 m, d_td->getSatContext(), d_td->getValuation()));
1388 // register this as a decision strategy
1389 d_td->getDecisionManager()->registerStrategy(
1390 DecisionManager::STRAT_DT_SYGUS_ENUM_SIZE, d_szinfo[m].get());
1391 }
1392 }
1393
notifySearchSize(Node m,unsigned s,Node exp,std::vector<Node> & lemmas)1394 void SygusSymBreakNew::notifySearchSize( Node m, unsigned s, Node exp, std::vector< Node >& lemmas ) {
1395 std::map<Node, std::unique_ptr<SygusSizeDecisionStrategy>>::iterator its =
1396 d_szinfo.find(m);
1397 Assert( its!=d_szinfo.end() );
1398 if( its->second->d_search_size.find( s )==its->second->d_search_size.end() ){
1399 its->second->d_search_size[s] = true;
1400 its->second->d_search_size_exp[s] = exp;
1401 Assert( s==0 || its->second->d_search_size.find( s-1 )!=its->second->d_search_size.end() );
1402 Trace("sygus-fair") << "SygusSymBreakNew:: now considering term measure : " << s << " for " << m << std::endl;
1403 Assert( s>=its->second->d_curr_search_size );
1404 while( s>its->second->d_curr_search_size ){
1405 incrementCurrentSearchSize( m, lemmas );
1406 }
1407 Trace("sygus-fair") << "...finish increment for term measure : " << s << std::endl;
1408 /*
1409 //re-add all testers (some may now be relevant) TODO
1410 for( IntMap::const_iterator it = d_testers.begin(); it != d_testers.end(); ++it ){
1411 Node n = (*it).first;
1412 NodeMap::const_iterator itx = d_testers_exp.find( n );
1413 if( itx!=d_testers_exp.end() ){
1414 int tindex = (*it).second;
1415 Node exp = (*itx).second;
1416 assertTester( tindex, n, exp, lemmas );
1417 }else{
1418 Assert( false );
1419 }
1420 }
1421 */
1422 }
1423 }
1424
getSearchSizeFor(Node n)1425 unsigned SygusSymBreakNew::getSearchSizeFor( Node n ) {
1426 Trace("sygus-sb-debug2") << "get search size for term : " << n << std::endl;
1427 std::unordered_map<Node, Node, NodeHashFunction>::iterator ita =
1428 d_term_to_anchor.find(n);
1429 Assert( ita != d_term_to_anchor.end() );
1430 return getSearchSizeForAnchor( ita->second );
1431 }
1432
getSearchSizeForAnchor(Node a)1433 unsigned SygusSymBreakNew::getSearchSizeForAnchor( Node a ) {
1434 Trace("sygus-sb-debug2") << "get search size for anchor : " << a << std::endl;
1435 std::map< Node, Node >::iterator it = d_anchor_to_measure_term.find( a );
1436 Assert( it!=d_anchor_to_measure_term.end() );
1437 return getSearchSizeForMeasureTerm(it->second);
1438 }
1439
getSearchSizeForMeasureTerm(Node m)1440 unsigned SygusSymBreakNew::getSearchSizeForMeasureTerm(Node m)
1441 {
1442 Trace("sygus-sb-debug2") << "get search size for measure : " << m << std::endl;
1443 std::map<Node, std::unique_ptr<SygusSizeDecisionStrategy>>::iterator its =
1444 d_szinfo.find(m);
1445 Assert( its!=d_szinfo.end() );
1446 return its->second->d_curr_search_size;
1447 }
1448
incrementCurrentSearchSize(Node m,std::vector<Node> & lemmas)1449 void SygusSymBreakNew::incrementCurrentSearchSize( Node m, std::vector< Node >& lemmas ) {
1450 std::map<Node, std::unique_ptr<SygusSizeDecisionStrategy>>::iterator itsz =
1451 d_szinfo.find(m);
1452 Assert( itsz!=d_szinfo.end() );
1453 itsz->second->d_curr_search_size++;
1454 Trace("sygus-fair") << " register search size " << itsz->second->d_curr_search_size << " for " << m << std::endl;
1455 NodeManager* nm = NodeManager::currentNM();
1456 for( std::map< Node, SearchCache >::iterator itc = d_cache.begin(); itc != d_cache.end(); ++itc ){
1457 Node a = itc->first;
1458 Trace("sygus-fair-debug") << " look at anchor " << a << "..." << std::endl;
1459 // check whether a is bounded by m
1460 Assert( d_anchor_to_measure_term.find( a )!=d_anchor_to_measure_term.end() );
1461 if( d_anchor_to_measure_term[a]==m ){
1462 for( std::map< TypeNode, std::map< unsigned, std::vector< Node > > >::iterator its = itc->second.d_sb_lemmas.begin();
1463 its != itc->second.d_sb_lemmas.end(); ++its ){
1464 TypeNode tn = its->first;
1465 TNode x = getFreeVar( tn );
1466 for( std::map< unsigned, std::vector< Node > >::iterator it = its->second.begin(); it != its->second.end(); ++it ){
1467 unsigned sz = it->first;
1468 int new_depth = ((int)itsz->second->d_curr_search_size) - ((int)sz);
1469 std::map< unsigned, std::vector< Node > >::iterator itt = itc->second.d_search_terms[tn].find( new_depth );
1470 if( itt!=itc->second.d_search_terms[tn].end() ){
1471 for (const TNode& t : itt->second)
1472 {
1473 if (!options::sygusSymBreakLazy()
1474 || (d_active_terms.find(t) != d_active_terms.end()
1475 && !it->second.empty()))
1476 {
1477 Node rlv = getRelevancyCondition(t);
1478 std::unordered_map<TNode, TNode, TNodeHashFunction> cache;
1479 for (const Node& lem : it->second)
1480 {
1481 Node slem = lem.substitute(x, t, cache);
1482 slem = nm->mkNode(OR, rlv, slem);
1483 lemmas.push_back(slem);
1484 }
1485 }
1486 }
1487 }
1488 }
1489 }
1490 }
1491 }
1492 }
1493
check(std::vector<Node> & lemmas)1494 void SygusSymBreakNew::check( std::vector< Node >& lemmas ) {
1495 Trace("sygus-sb") << "SygusSymBreakNew::check" << std::endl;
1496
1497 // check for externally registered symmetry breaking lemmas
1498 std::vector<Node> anchors;
1499 if (d_tds->hasSymBreakLemmas(anchors))
1500 {
1501 for (const Node& a : anchors)
1502 {
1503 // is this a registered enumerator?
1504 if (d_register_st.find(a) != d_register_st.end())
1505 {
1506 // symmetry breaking lemmas should only be for enumerators
1507 Assert(d_register_st[a]);
1508 // If this is a non-basic enumerator, process its symmetry breaking
1509 // clauses. Since this class is not responsible for basic enumerators,
1510 // their symmetry breaking clauses are ignored.
1511 if (!d_tds->isBasicEnumerator(a))
1512 {
1513 std::vector<Node> sbl;
1514 d_tds->getSymBreakLemmas(a, sbl);
1515 for (const Node& lem : sbl)
1516 {
1517 if (d_tds->isSymBreakLemmaTemplate(lem))
1518 {
1519 // register the lemma template
1520 TypeNode tn = d_tds->getTypeForSymBreakLemma(lem);
1521 unsigned sz = d_tds->getSizeForSymBreakLemma(lem);
1522 registerSymBreakLemma(tn, lem, sz, a, lemmas);
1523 }
1524 else
1525 {
1526 Trace("dt-sygus-debug")
1527 << "DT sym break lemma : " << lem << std::endl;
1528 // it is a normal lemma
1529 lemmas.push_back(lem);
1530 }
1531 }
1532 d_tds->clearSymBreakLemmas(a);
1533 }
1534 }
1535 }
1536 if (!lemmas.empty())
1537 {
1538 return;
1539 }
1540 }
1541
1542 // register search values, add symmetry breaking lemmas if applicable
1543 std::vector<Node> es;
1544 d_tds->getEnumerators(es);
1545 bool needsRecheck = false;
1546 // for each enumerator registered to d_tds
1547 for (Node& prog : es)
1548 {
1549 if (d_register_st.find(prog) == d_register_st.end())
1550 {
1551 // not yet registered, do so now
1552 registerSizeTerm(prog, lemmas);
1553 needsRecheck = true;
1554 }
1555 else
1556 {
1557 Trace("dt-sygus-debug") << "Checking model value of " << prog << "..."
1558 << std::endl;
1559 Assert(prog.getType().isDatatype());
1560 Node progv = d_td->getValuation().getModel()->getValue( prog );
1561 if (Trace.isOn("dt-sygus"))
1562 {
1563 Trace("dt-sygus") << "* DT model : " << prog << " -> ";
1564 std::stringstream ss;
1565 Printer::getPrinter(options::outputLanguage())
1566 ->toStreamSygus(ss, progv);
1567 Trace("dt-sygus") << ss.str() << std::endl;
1568 }
1569 // first check that the value progv for prog is what we expected
1570 bool isExc = true;
1571 if (checkValue(prog, progv, 0, lemmas))
1572 {
1573 isExc = false;
1574 //debugging : ensure fairness was properly handled
1575 if( options::sygusFair()==SYGUS_FAIR_DT_SIZE ){
1576 Node prog_sz = NodeManager::currentNM()->mkNode( kind::DT_SIZE, prog );
1577 Node prog_szv = d_td->getValuation().getModel()->getValue( prog_sz );
1578 Node progv_sz = NodeManager::currentNM()->mkNode( kind::DT_SIZE, progv );
1579
1580 Trace("sygus-sb") << " Mv[" << prog << "] = " << progv << ", size = " << prog_szv << std::endl;
1581 if( prog_szv.getConst<Rational>().getNumerator().toUnsignedInt() > getSearchSizeForAnchor( prog ) ){
1582 AlwaysAssert( false );
1583 Node szlem = NodeManager::currentNM()->mkNode( kind::OR, prog.eqNode( progv ).negate(),
1584 prog_sz.eqNode( progv_sz ) );
1585 Trace("sygus-sb-warn") << "SygusSymBreak : WARNING : adding size correction : " << szlem << std::endl;
1586 lemmas.push_back(szlem);
1587 isExc = true;
1588 }
1589 }
1590
1591 // register the search value ( prog -> progv ), this may invoke symmetry
1592 // breaking
1593 if (!isExc && options::sygusSymBreakDynamic())
1594 {
1595 bool isVarAgnostic = d_tds->isVariableAgnosticEnumerator(prog);
1596 // check that it is unique up to theory-specific rewriting and
1597 // conjecture-specific symmetry breaking.
1598 Node rsv = registerSearchValue(
1599 prog, prog, progv, 0, lemmas, isVarAgnostic, true);
1600 if (rsv.isNull())
1601 {
1602 isExc = true;
1603 Trace("sygus-sb") << " SygusSymBreakNew::check: ...added new symmetry breaking lemma for " << prog << "." << std::endl;
1604 }
1605 else
1606 {
1607 Trace("dt-sygus") << " ...success." << std::endl;
1608 }
1609 }
1610 }
1611 SygusSymBreakOkAttribute ssbo;
1612 prog.setAttribute(ssbo, !isExc);
1613 }
1614 }
1615 Trace("sygus-sb") << "SygusSymBreakNew::check: finished." << std::endl;
1616 if (needsRecheck)
1617 {
1618 Trace("sygus-sb") << " SygusSymBreakNew::rechecking..." << std::endl;
1619 return check(lemmas);
1620 }
1621
1622 if (Trace.isOn("cegqi-engine") && !d_szinfo.empty())
1623 {
1624 if (lemmas.empty())
1625 {
1626 Trace("cegqi-engine") << "*** Sygus : passed datatypes check. term size(s) : ";
1627 for (std::pair<const Node, std::unique_ptr<SygusSizeDecisionStrategy>>&
1628 p : d_szinfo)
1629 {
1630 SygusSizeDecisionStrategy* s = p.second.get();
1631 Trace("cegqi-engine") << s->d_curr_search_size << " ";
1632 }
1633 Trace("cegqi-engine") << std::endl;
1634 }
1635 else
1636 {
1637 Trace("cegqi-engine")
1638 << "*** Sygus : produced symmetry breaking lemmas" << std::endl;
1639 for (const Node& lem : lemmas)
1640 {
1641 Trace("cegqi-engine-debug") << " " << lem << std::endl;
1642 }
1643 }
1644 }
1645 }
1646
checkValue(Node n,Node vn,int ind,std::vector<Node> & lemmas)1647 bool SygusSymBreakNew::checkValue(Node n,
1648 Node vn,
1649 int ind,
1650 std::vector<Node>& lemmas)
1651 {
1652 if (vn.getKind() != kind::APPLY_CONSTRUCTOR)
1653 {
1654 // all datatype terms should be constant here
1655 Assert(!vn.getType().isDatatype());
1656 return true;
1657 }
1658 NodeManager* nm = NodeManager::currentNM();
1659 if (Trace.isOn("sygus-sb-check-value"))
1660 {
1661 Node prog_sz = nm->mkNode(DT_SIZE, n);
1662 Node prog_szv = d_td->getValuation().getModel()->getValue( prog_sz );
1663 for( int i=0; i<ind; i++ ){
1664 Trace("sygus-sb-check-value") << " ";
1665 }
1666 Trace("sygus-sb-check-value") << n << " : " << vn << " : " << prog_szv
1667 << std::endl;
1668 }
1669 TypeNode tn = n.getType();
1670 const Datatype& dt = tn.getDatatype();
1671 Assert(dt.isSygus());
1672
1673 // ensure that the expected size bound is met
1674 int cindex = DatatypesRewriter::indexOf(vn.getOperator());
1675 Node tst = DatatypesRewriter::mkTester( n, cindex, dt );
1676 bool hastst = d_td->getEqualityEngine()->hasTerm(tst);
1677 Node tstrep;
1678 if (hastst)
1679 {
1680 tstrep = d_td->getEqualityEngine()->getRepresentative(tst);
1681 }
1682 if (!hastst || tstrep != d_true)
1683 {
1684 Trace("sygus-check-value") << "- has tester : " << tst << " : "
1685 << (hastst ? "true" : "false");
1686 Trace("sygus-check-value") << ", value=" << tstrep << std::endl;
1687 if( !hastst ){
1688 // This should not happen generally, it is caused by a sygus term not
1689 // being assigned a tester.
1690 Node split = DatatypesRewriter::mkSplit(n, dt);
1691 Trace("sygus-sb") << " SygusSymBreakNew::check: ...WARNING: considered "
1692 "missing split for "
1693 << n << "." << std::endl;
1694 Assert( !split.isNull() );
1695 lemmas.push_back( split );
1696 return false;
1697 }
1698 }
1699 for( unsigned i=0; i<vn.getNumChildren(); i++ ){
1700 Node sel = nm->mkNode(
1701 APPLY_SELECTOR_TOTAL,
1702 Node::fromExpr(dt[cindex].getSelectorInternal(tn.toType(), i)),
1703 n);
1704 if (!checkValue(sel, vn[i], ind + 1, lemmas))
1705 {
1706 return false;
1707 }
1708 }
1709 return true;
1710 }
1711
getCurrentTemplate(Node n,std::map<TypeNode,int> & var_count)1712 Node SygusSymBreakNew::getCurrentTemplate( Node n, std::map< TypeNode, int >& var_count ) {
1713 if( d_active_terms.find( n )!=d_active_terms.end() ){
1714 TypeNode tn = n.getType();
1715 IntMap::const_iterator it = d_testers.find( n );
1716 Assert( it != d_testers.end() );
1717 const Datatype& dt = ((DatatypeType)tn.toType()).getDatatype();
1718 int tindex = (*it).second;
1719 Assert( tindex>=0 );
1720 Assert( tindex<(int)dt.getNumConstructors() );
1721 std::vector< Node > children;
1722 children.push_back( Node::fromExpr( dt[tindex].getConstructor() ) );
1723 for( unsigned i=0; i<dt[tindex].getNumArgs(); i++ ){
1724 Node sel = NodeManager::currentNM()->mkNode( kind::APPLY_SELECTOR_TOTAL, Node::fromExpr( dt[tindex].getSelectorInternal( tn.toType(), i ) ), n );
1725 Node cc = getCurrentTemplate( sel, var_count );
1726 children.push_back( cc );
1727 }
1728 return NodeManager::currentNM()->mkNode( kind::APPLY_CONSTRUCTOR, children );
1729 }else{
1730 return d_tds->getFreeVarInc( n.getType(), var_count );
1731 }
1732 }
1733
getOrMkMeasureValue(std::vector<Node> & lemmas)1734 Node SygusSymBreakNew::SygusSizeDecisionStrategy::getOrMkMeasureValue(
1735 std::vector<Node>& lemmas)
1736 {
1737 if (d_measure_value.isNull())
1738 {
1739 d_measure_value = NodeManager::currentNM()->mkSkolem(
1740 "mt", NodeManager::currentNM()->integerType());
1741 lemmas.push_back(NodeManager::currentNM()->mkNode(
1742 kind::GEQ,
1743 d_measure_value,
1744 NodeManager::currentNM()->mkConst(Rational(0))));
1745 }
1746 return d_measure_value;
1747 }
1748
getOrMkActiveMeasureValue(std::vector<Node> & lemmas,bool mkNew)1749 Node SygusSymBreakNew::SygusSizeDecisionStrategy::getOrMkActiveMeasureValue(
1750 std::vector<Node>& lemmas, bool mkNew)
1751 {
1752 if (mkNew)
1753 {
1754 Node new_mt = NodeManager::currentNM()->mkSkolem(
1755 "mt", NodeManager::currentNM()->integerType());
1756 lemmas.push_back(NodeManager::currentNM()->mkNode(
1757 kind::GEQ, new_mt, NodeManager::currentNM()->mkConst(Rational(0))));
1758 d_measure_value_active = new_mt;
1759 }
1760 else if (d_measure_value_active.isNull())
1761 {
1762 d_measure_value_active = getOrMkMeasureValue(lemmas);
1763 }
1764 return d_measure_value_active;
1765 }
1766
mkLiteral(unsigned s)1767 Node SygusSymBreakNew::SygusSizeDecisionStrategy::mkLiteral(unsigned s)
1768 {
1769 if (options::sygusFair() == SYGUS_FAIR_NONE)
1770 {
1771 return Node::null();
1772 }
1773 if (options::sygusAbortSize() != -1
1774 && static_cast<int>(s) > options::sygusAbortSize())
1775 {
1776 std::stringstream ss;
1777 ss << "Maximum term size (" << options::sygusAbortSize()
1778 << ") for enumerative SyGuS exceeded.";
1779 throw LogicException(ss.str());
1780 }
1781 Assert(!d_this.isNull());
1782 NodeManager* nm = NodeManager::currentNM();
1783 Trace("cegqi-engine") << "******* Sygus : allocate size literal " << s
1784 << " for " << d_this << std::endl;
1785 return nm->mkNode(DT_SYGUS_BOUND, d_this, nm->mkConst(Rational(s)));
1786 }
1787
getGuardStatus(Node g)1788 int SygusSymBreakNew::getGuardStatus( Node g ) {
1789 bool value;
1790 if( d_td->getValuation().hasSatValue( g, value ) ) {
1791 if( value ){
1792 return 1;
1793 }else{
1794 return -1;
1795 }
1796 }else{
1797 return 0;
1798 }
1799 }
1800
1801