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