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