1 /*********************                                                        */
2 /*! \file sygus_simple_sym.cpp
3  ** \verbatim
4  ** Top contributors (to current version):
5  **   Andrew Reynolds, Haniel Barbosa
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 simple symmetry breaking for sygus
13  **/
14 
15 #include "theory/datatypes/sygus_simple_sym.h"
16 
17 #include "theory/quantifiers_engine.h"
18 
19 using namespace std;
20 using namespace CVC4::kind;
21 
22 namespace CVC4 {
23 namespace theory {
24 namespace datatypes {
25 
SygusSimpleSymBreak(QuantifiersEngine * qe)26 SygusSimpleSymBreak::SygusSimpleSymBreak(QuantifiersEngine* qe)
27     : d_tds(qe->getTermDatabaseSygus()), d_tutil(qe->getTermUtil())
28 {
29 }
30 
31 /** Requirement trie
32  *
33  * This class is used to make queries about sygus grammars, including what
34  * constructors they contain, and their types.
35  *
36  * As a simple example, consider the trie:
37  * root:
38  *   d_req_kind = PLUS
39  *   d_children[0]:
40  *     d_req_type = A
41  *   d_children[1]:
42  *     d_req_type = A
43  * This trie is satisfied by sygus types that have a constructor whose builtin
44  * kind is PLUS and whose argument types are both A.
45  */
46 class ReqTrie
47 {
48  public:
ReqTrie()49   ReqTrie() : d_req_kind(UNDEFINED_KIND) {}
50   /** the children of this node */
51   std::map<unsigned, ReqTrie> d_children;
52   /** the (builtin) kind required by this node */
53   Kind d_req_kind;
54   /** the type that this node is required to be */
55   TypeNode d_req_type;
56   /** the constant required by this node */
57   Node d_req_const;
58   /** print this trie */
print(const char * c,int indent=0)59   void print(const char* c, int indent = 0)
60   {
61     if (d_req_kind != UNDEFINED_KIND)
62     {
63       Trace(c) << d_req_kind << " ";
64     }
65     else if (!d_req_type.isNull())
66     {
67       Trace(c) << d_req_type;
68     }
69     else if (!d_req_const.isNull())
70     {
71       Trace(c) << d_req_const;
72     }
73     else
74     {
75       Trace(c) << "_";
76     }
77     Trace(c) << std::endl;
78     for (std::map<unsigned, ReqTrie>::iterator it = d_children.begin();
79          it != d_children.end();
80          ++it)
81     {
82       for (int i = 0; i <= indent; i++)
83       {
84         Trace(c) << "  ";
85       }
86       Trace(c) << it->first << " : ";
87       it->second.print(c, indent + 1);
88     }
89   }
90   /**
91    * Are the requirements of this trie satisfied by sygus type tn?
92    * tdb is a reference to the sygus term database.
93    */
satisfiedBy(quantifiers::TermDbSygus * tdb,TypeNode tn)94   bool satisfiedBy(quantifiers::TermDbSygus* tdb, TypeNode tn)
95   {
96     if (!d_req_const.isNull())
97     {
98       if (!tdb->hasConst(tn, d_req_const))
99       {
100         return false;
101       }
102     }
103     if (!d_req_type.isNull())
104     {
105       Trace("sygus-sb-debug")
106           << "- check if " << tn << " is type " << d_req_type << std::endl;
107       if (tn != d_req_type)
108       {
109         return false;
110       }
111     }
112     if (d_req_kind != UNDEFINED_KIND)
113     {
114       Trace("sygus-sb-debug")
115           << "- check if " << tn << " has " << d_req_kind << std::endl;
116       std::vector<TypeNode> argts;
117       if (tdb->canConstructKind(tn, d_req_kind, argts))
118       {
119         for (std::map<unsigned, ReqTrie>::iterator it = d_children.begin();
120              it != d_children.end();
121              ++it)
122         {
123           if (it->first < argts.size())
124           {
125             TypeNode tnc = argts[it->first];
126             if (!it->second.satisfiedBy(tdb, tnc))
127             {
128               return false;
129             }
130           }
131           else
132           {
133             return false;
134           }
135         }
136       }
137       else
138       {
139         return false;
140       }
141     }
142     return true;
143   }
144   /** is this the empty (trivially satisfied) trie? */
empty()145   bool empty()
146   {
147     return d_req_kind == UNDEFINED_KIND && d_req_const.isNull()
148            && d_req_type.isNull() && d_children.empty();
149   }
150 };
151 
considerArgKind(TypeNode tn,TypeNode tnp,Kind k,Kind pk,int arg)152 bool SygusSimpleSymBreak::considerArgKind(
153     TypeNode tn, TypeNode tnp, Kind k, Kind pk, int arg)
154 {
155   const Datatype& pdt = ((DatatypeType)(tnp).toType()).getDatatype();
156   const Datatype& dt = ((DatatypeType)(tn).toType()).getDatatype();
157   Assert(d_tds->hasKind(tn, k));
158   Assert(d_tds->hasKind(tnp, pk));
159   Trace("sygus-sb-debug") << "Consider sygus arg kind " << k << ", pk = " << pk
160                           << ", arg = " << arg << " in " << tnp << "?"
161                           << std::endl;
162   int c = d_tds->getKindConsNum(tn, k);
163   int pc = d_tds->getKindConsNum(tnp, pk);
164   // check for associativity
165   if (k == pk && quantifiers::TermUtil::isAssoc(k))
166   {
167     // if the operator is associative, then a repeated occurrence should only
168     // occur in the leftmost argument position
169     int firstArg = getFirstArgOccurrence(pdt[pc], tn);
170     Assert(firstArg != -1);
171     if (arg == firstArg)
172     {
173       return true;
174     }
175     // the argument types of the child must be the parent's type
176     for (unsigned i = 0, nargs = dt[c].getNumArgs(); i < nargs; i++)
177     {
178       TypeNode tn = TypeNode::fromType(dt[c].getArgType(i));
179       if (tn != tnp)
180       {
181         return true;
182       }
183     }
184     Trace("sygus-sb-simple")
185         << "  sb-simple : do not consider " << k << " at child arg " << arg
186         << " of " << k
187         << " since it is associative, with first arg = " << firstArg
188         << std::endl;
189     return false;
190   }
191   // describes the shape of an alternate term to construct
192   //  we check whether this term is in the sygus grammar below
193   ReqTrie rt;
194   Assert(rt.empty());
195 
196   // construct rt by cases
197   if (pk == NOT || pk == BITVECTOR_NOT || pk == UMINUS || pk == BITVECTOR_NEG)
198   {
199     // negation normal form
200     if (pk == k)
201     {
202       rt.d_req_type = TypeNode::fromType(dt[c].getArgType(0));
203     }
204     else
205     {
206       Kind reqk = UNDEFINED_KIND;      // required kind for all children
207       std::map<unsigned, Kind> reqkc;  // required kind for some children
208       if (pk == NOT)
209       {
210         if (k == AND)
211         {
212           rt.d_req_kind = OR;
213           reqk = NOT;
214         }
215         else if (k == OR)
216         {
217           rt.d_req_kind = AND;
218           reqk = NOT;
219         }
220         else if (k == EQUAL)
221         {
222           rt.d_req_kind = XOR;
223         }
224         else if (k == XOR)
225         {
226           rt.d_req_kind = EQUAL;
227         }
228         else if (k == ITE)
229         {
230           rt.d_req_kind = ITE;
231           reqkc[1] = NOT;
232           reqkc[2] = NOT;
233           rt.d_children[0].d_req_type = TypeNode::fromType(dt[c].getArgType(0));
234         }
235         else if (k == LEQ || k == GT)
236         {
237           //  (not (~ x y)) ----->  (~ (+ y 1) x)
238           rt.d_req_kind = k;
239           rt.d_children[0].d_req_kind = PLUS;
240           rt.d_children[0].d_children[0].d_req_type =
241               TypeNode::fromType(dt[c].getArgType(1));
242           rt.d_children[0].d_children[1].d_req_const =
243               NodeManager::currentNM()->mkConst(Rational(1));
244           rt.d_children[1].d_req_type = TypeNode::fromType(dt[c].getArgType(0));
245         }
246         else if (k == LT || k == GEQ)
247         {
248           //  (not (~ x y)) ----->  (~ y (+ x 1))
249           rt.d_req_kind = k;
250           rt.d_children[0].d_req_type = TypeNode::fromType(dt[c].getArgType(1));
251           rt.d_children[1].d_req_kind = PLUS;
252           rt.d_children[1].d_children[0].d_req_type =
253               TypeNode::fromType(dt[c].getArgType(0));
254           rt.d_children[1].d_children[1].d_req_const =
255               NodeManager::currentNM()->mkConst(Rational(1));
256         }
257       }
258       else if (pk == BITVECTOR_NOT)
259       {
260         if (k == BITVECTOR_AND)
261         {
262           rt.d_req_kind = BITVECTOR_OR;
263           reqk = BITVECTOR_NOT;
264         }
265         else if (k == BITVECTOR_OR)
266         {
267           rt.d_req_kind = BITVECTOR_AND;
268           reqk = BITVECTOR_NOT;
269         }
270         else if (k == BITVECTOR_XNOR)
271         {
272           rt.d_req_kind = BITVECTOR_XOR;
273         }
274         else if (k == BITVECTOR_XOR)
275         {
276           rt.d_req_kind = BITVECTOR_XNOR;
277         }
278       }
279       else if (pk == UMINUS)
280       {
281         if (k == PLUS)
282         {
283           rt.d_req_kind = PLUS;
284           reqk = UMINUS;
285         }
286       }
287       else if (pk == BITVECTOR_NEG)
288       {
289         if (k == PLUS)
290         {
291           rt.d_req_kind = PLUS;
292           reqk = BITVECTOR_NEG;
293         }
294       }
295       if (!rt.empty() && (reqk != UNDEFINED_KIND || !reqkc.empty()))
296       {
297         int pcr = d_tds->getKindConsNum(tnp, rt.d_req_kind);
298         if (pcr != -1)
299         {
300           Assert(pcr < static_cast<int>(pdt.getNumConstructors()));
301           // must have same number of arguments
302           if (pdt[pcr].getNumArgs() == dt[c].getNumArgs())
303           {
304             for (unsigned i = 0, nargs = pdt[pcr].getNumArgs(); i < nargs; i++)
305             {
306               Kind rk = reqk;
307               if (reqk == UNDEFINED_KIND)
308               {
309                 std::map<unsigned, Kind>::iterator itr = reqkc.find(i);
310                 if (itr != reqkc.end())
311                 {
312                   rk = itr->second;
313                 }
314               }
315               if (rk != UNDEFINED_KIND)
316               {
317                 rt.d_children[i].d_req_kind = rk;
318                 rt.d_children[i].d_children[0].d_req_type =
319                     TypeNode::fromType(dt[c].getArgType(i));
320               }
321             }
322           }
323         }
324       }
325     }
326   }
327   else if (k == MINUS || k == BITVECTOR_SUB)
328   {
329     if (pk == EQUAL || pk == MINUS || pk == BITVECTOR_SUB || pk == LEQ
330         || pk == LT || pk == GEQ || pk == GT)
331     {
332       int oarg = arg == 0 ? 1 : 0;
333       //  (~ x (- y z))  ---->  (~ (+ x z) y)
334       //  (~ (- y z) x)  ---->  (~ y (+ x z))
335       rt.d_req_kind = pk;
336       rt.d_children[arg].d_req_type = TypeNode::fromType(dt[c].getArgType(0));
337       rt.d_children[oarg].d_req_kind = k == MINUS ? PLUS : BITVECTOR_PLUS;
338       rt.d_children[oarg].d_children[0].d_req_type =
339           TypeNode::fromType(pdt[pc].getArgType(oarg));
340       rt.d_children[oarg].d_children[1].d_req_type =
341           TypeNode::fromType(dt[c].getArgType(1));
342     }
343     else if (pk == PLUS || pk == BITVECTOR_PLUS)
344     {
345       //  (+ x (- y z))  -----> (- (+ x y) z)
346       //  (+ (- y z) x)  -----> (- (+ x y) z)
347       rt.d_req_kind = pk == PLUS ? MINUS : BITVECTOR_SUB;
348       int oarg = arg == 0 ? 1 : 0;
349       rt.d_children[0].d_req_kind = pk;
350       rt.d_children[0].d_children[0].d_req_type =
351           TypeNode::fromType(pdt[pc].getArgType(oarg));
352       rt.d_children[0].d_children[1].d_req_type =
353           TypeNode::fromType(dt[c].getArgType(0));
354       rt.d_children[1].d_req_type = TypeNode::fromType(dt[c].getArgType(1));
355     }
356   }
357   else if (k == ITE)
358   {
359     if (pk != ITE)
360     {
361       //  (o X (ite y z w) X')  -----> (ite y (o X z X') (o X w X'))
362       rt.d_req_kind = ITE;
363       rt.d_children[0].d_req_type = TypeNode::fromType(dt[c].getArgType(0));
364       unsigned n_args = pdt[pc].getNumArgs();
365       for (unsigned r = 1; r <= 2; r++)
366       {
367         rt.d_children[r].d_req_kind = pk;
368         for (unsigned q = 0; q < n_args; q++)
369         {
370           if ((int)q == arg)
371           {
372             rt.d_children[r].d_children[q].d_req_type =
373                 TypeNode::fromType(dt[c].getArgType(r));
374           }
375           else
376           {
377             rt.d_children[r].d_children[q].d_req_type =
378                 TypeNode::fromType(pdt[pc].getArgType(q));
379           }
380         }
381       }
382       // this increases term size but is probably a good idea
383     }
384   }
385   else if (k == NOT)
386   {
387     if (pk == ITE)
388     {
389       //  (ite (not y) z w)  -----> (ite y w z)
390       rt.d_req_kind = ITE;
391       rt.d_children[0].d_req_type = TypeNode::fromType(dt[c].getArgType(0));
392       rt.d_children[1].d_req_type = TypeNode::fromType(pdt[pc].getArgType(2));
393       rt.d_children[2].d_req_type = TypeNode::fromType(pdt[pc].getArgType(1));
394     }
395   }
396   Trace("sygus-sb-debug") << "Consider sygus arg kind " << k << ", pk = " << pk
397                           << ", arg = " << arg << "?" << std::endl;
398   if (!rt.empty())
399   {
400     rt.print("sygus-sb-debug");
401     // check if it meets the requirements
402     if (rt.satisfiedBy(d_tds, tnp))
403     {
404       Trace("sygus-sb-debug") << "...success!" << std::endl;
405       Trace("sygus-sb-simple")
406           << "  sb-simple : do not consider " << k << " as arg " << arg
407           << " of " << pk << std::endl;
408       // do not need to consider the kind in the search since there are ways to
409       // construct equivalent terms
410       return false;
411     }
412     else
413     {
414       Trace("sygus-sb-debug") << "...failed." << std::endl;
415     }
416     Trace("sygus-sb-debug") << std::endl;
417   }
418   // must consider this kind in the search
419   return true;
420 }
421 
considerConst(TypeNode tn,TypeNode tnp,Node c,Kind pk,int arg)422 bool SygusSimpleSymBreak::considerConst(
423     TypeNode tn, TypeNode tnp, Node c, Kind pk, int arg)
424 {
425   const Datatype& pdt = static_cast<DatatypeType>(tnp.toType()).getDatatype();
426   // child grammar-independent
427   if (!considerConst(pdt, tnp, c, pk, arg))
428   {
429     return false;
430   }
431   // this can probably be made child grammar independent
432   int pc = d_tds->getKindConsNum(tnp, pk);
433   if (pdt[pc].getNumArgs() == 2)
434   {
435     Kind ok;
436     int offset;
437     if (d_tutil->hasOffsetArg(pk, arg, offset, ok))
438     {
439       Trace("sygus-sb-simple-debug")
440           << pk << " has offset arg " << ok << " " << offset << std::endl;
441       int ok_arg = d_tds->getKindConsNum(tnp, ok);
442       if (ok_arg != -1)
443       {
444         Trace("sygus-sb-simple-debug")
445             << "...at argument " << ok_arg << std::endl;
446         // other operator be the same type
447         if (d_tds->isTypeMatch(pdt[ok_arg], pdt[arg]))
448         {
449           int status;
450           Node co = d_tutil->getTypeValueOffset(c.getType(), c, offset, status);
451           Trace("sygus-sb-simple-debug")
452               << c << " with offset " << offset << " is " << co
453               << ", status=" << status << std::endl;
454           if (status == 0 && !co.isNull())
455           {
456             if (d_tds->hasConst(tn, co))
457             {
458               Trace("sygus-sb-simple")
459                   << "  sb-simple : by offset reasoning, do not consider const "
460                   << c;
461               Trace("sygus-sb-simple")
462                   << " as arg " << arg << " of " << pk << " since we can use "
463                   << co << " under " << ok << " " << std::endl;
464               return false;
465             }
466           }
467         }
468       }
469     }
470   }
471   return true;
472 }
473 
considerConst(const Datatype & pdt,TypeNode tnp,Node c,Kind pk,int arg)474 bool SygusSimpleSymBreak::considerConst(
475     const Datatype& pdt, TypeNode tnp, Node c, Kind pk, int arg)
476 {
477   Assert(d_tds->hasKind(tnp, pk));
478   int pc = d_tds->getKindConsNum(tnp, pk);
479   bool ret = true;
480   Trace("sygus-sb-debug") << "Consider sygus const " << c << ", parent = " << pk
481                           << ", arg = " << arg << "?" << std::endl;
482   if (d_tutil->isIdempotentArg(c, pk, arg))
483   {
484     if (pdt[pc].getNumArgs() == 2)
485     {
486       int oarg = arg == 0 ? 1 : 0;
487       TypeNode otn = TypeNode::fromType(pdt[pc].getArgType(oarg));
488       if (otn == tnp)
489       {
490         Trace("sygus-sb-simple")
491             << "  sb-simple : " << c << " is idempotent arg " << arg << " of "
492             << pk << "..." << std::endl;
493         ret = false;
494       }
495     }
496   }
497   else
498   {
499     Node sc = d_tutil->isSingularArg(c, pk, arg);
500     if (!sc.isNull())
501     {
502       if (d_tds->hasConst(tnp, sc))
503       {
504         Trace("sygus-sb-simple")
505             << "  sb-simple : " << c << " is singular arg " << arg << " of "
506             << pk << ", evaluating to " << sc << "..." << std::endl;
507         ret = false;
508       }
509     }
510   }
511   if (ret)
512   {
513     ReqTrie rt;
514     Assert(rt.empty());
515     Node max_c = d_tutil->getTypeMaxValue(c.getType());
516     Node zero_c = d_tutil->getTypeValue(c.getType(), 0);
517     Node one_c = d_tutil->getTypeValue(c.getType(), 1);
518     if (pk == XOR || pk == BITVECTOR_XOR)
519     {
520       if (c == max_c)
521       {
522         rt.d_req_kind = pk == XOR ? NOT : BITVECTOR_NOT;
523       }
524     }
525     else if (pk == ITE)
526     {
527       if (arg == 0)
528       {
529         if (c == max_c)
530         {
531           rt.d_children[1].d_req_type = tnp;
532         }
533         else if (c == zero_c)
534         {
535           rt.d_children[2].d_req_type = tnp;
536         }
537       }
538     }
539     else if (pk == STRING_SUBSTR)
540     {
541       if (c == one_c && arg == 2)
542       {
543         rt.d_req_kind = STRING_CHARAT;
544         rt.d_children[0].d_req_type = TypeNode::fromType(pdt[pc].getArgType(0));
545         rt.d_children[1].d_req_type = TypeNode::fromType(pdt[pc].getArgType(1));
546       }
547     }
548     if (!rt.empty())
549     {
550       // check if satisfied
551       if (rt.satisfiedBy(d_tds, tnp))
552       {
553         Trace("sygus-sb-simple") << "  sb-simple : do not consider const " << c
554                                  << " as arg " << arg << " of " << pk;
555         Trace("sygus-sb-simple") << " in " << pdt.getName() << std::endl;
556         // do not need to consider the constant in the search since there are
557         // ways to construct equivalent terms
558         ret = false;
559       }
560     }
561   }
562   return ret;
563 }
564 
solveForArgument(TypeNode tn,unsigned cindex,unsigned arg)565 int SygusSimpleSymBreak::solveForArgument(TypeNode tn,
566                                           unsigned cindex,
567                                           unsigned arg)
568 {
569   // we currently do not solve for arguments
570   return -1;
571 }
572 
getFirstArgOccurrence(const DatatypeConstructor & c,TypeNode tn)573 int SygusSimpleSymBreak::getFirstArgOccurrence(const DatatypeConstructor& c,
574                                                TypeNode tn)
575 {
576   for (unsigned i = 0, nargs = c.getNumArgs(); i < nargs; i++)
577   {
578     TypeNode tni = TypeNode::fromType(c.getArgType(i));
579     if (tni == tn)
580     {
581       return i;
582     }
583   }
584   return -1;
585 }
586 
587 }  // namespace datatypes
588 }  // namespace theory
589 }  // namespace CVC4
590