1 /********************* */
2 /*! \file term_database_sygus.cpp
4 ** Top contributors (to current version):
5 ** Andrew Reynolds, Andres Noetzli, Mathias Preiner
6 ** This file is part of the CVC4 project.
7 ** Copyright (c) 2009-2020 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
12 ** \brief Implementation of term database sygus class
15 #include "theory/quantifiers/sygus/term_database_sygus.h"
17 #include "base/check.h"
18 #include "expr/sygus_datatype.h"
19 #include "options/base_options.h"
20 #include "options/datatypes_options.h"
21 #include "options/quantifiers_options.h"
22 #include "printer/printer.h"
23 #include "theory/arith/arith_msum.h"
24 #include "theory/datatypes/sygus_datatype_utils.h"
25 #include "theory/quantifiers/quantifiers_attributes.h"
26 #include "theory/quantifiers/term_database.h"
27 #include "theory/quantifiers/term_util.h"
28 #include "theory/quantifiers_engine.h"
30 using namespace CVC4::kind
;
34 namespace quantifiers
{
36 std::ostream
& operator<<(std::ostream
& os
, EnumeratorRole r
)
40 case ROLE_ENUM_POOL
: os
<< "POOL"; break;
41 case ROLE_ENUM_SINGLE_SOLUTION
: os
<< "SINGLE_SOLUTION"; break;
42 case ROLE_ENUM_MULTI_SOLUTION
: os
<< "MULTI_SOLUTION"; break;
43 case ROLE_ENUM_CONSTRAINED
: os
<< "CONSTRAINED"; break;
44 default: os
<< "enum_" << static_cast<unsigned>(r
); break;
49 TermDbSygus::TermDbSygus(context::Context
* c
, QuantifiersEngine
* qe
)
51 d_syexp(new SygusExplain(this)),
52 d_ext_rw(new ExtendedRewriter(true)),
53 d_eval(new Evaluator
),
54 d_funDefEval(new FunDefEvaluator
),
55 d_eval_unfold(new SygusEvalUnfold(this))
57 d_true
= NodeManager::currentNM()->mkConst( true );
58 d_false
= NodeManager::currentNM()->mkConst( false );
61 bool TermDbSygus::reset( Theory::Effort e
) {
65 TNode
TermDbSygus::getFreeVar( TypeNode tn
, int i
, bool useSygusType
) {
68 TypeNode builtinType
= tn
;
71 const DType
& dt
= tn
.getDType();
72 if (!dt
.getSygusType().isNull())
74 builtinType
= dt
.getSygusType();
82 NodeManager
* nm
= NodeManager::currentNM();
83 while( i
>=(int)d_fv
[sindex
][tn
].size() ){
85 if( tn
.isDatatype() ){
86 const DType
& dt
= tn
.getDType();
87 ss
<< "fv_" << dt
.getName() << "_" << i
;
89 ss
<< "fv_" << tn
<< "_" << i
;
91 Assert(!vtn
.isNull());
92 Node v
= nm
->mkSkolem(ss
.str(), vtn
, "for sygus invariance testing");
93 // store its id, which is unique per builtin type, regardless of how it is
95 d_fvId
[v
] = d_fvTypeIdCounter
[builtinType
];
96 d_fvTypeIdCounter
[builtinType
]++;
97 Trace("sygus-db-debug") << "Free variable id " << v
<< " = " << d_fvId
[v
]
98 << ", " << builtinType
<< std::endl
;
99 d_fv
[sindex
][tn
].push_back( v
);
101 return d_fv
[sindex
][tn
][i
];
104 TNode
TermDbSygus::getFreeVarInc( TypeNode tn
, std::map
< TypeNode
, int >& var_count
, bool useSygusType
) {
105 std::map
< TypeNode
, int >::iterator it
= var_count
.find( tn
);
106 if( it
==var_count
.end() ){
108 return getFreeVar( tn
, 0, useSygusType
);
110 int index
= it
->second
;
112 return getFreeVar( tn
, index
, useSygusType
);
116 bool TermDbSygus::isFreeVar(Node n
) const
118 return d_fvId
.find(n
) != d_fvId
.end();
120 size_t TermDbSygus::getFreeVarId(Node n
) const
122 std::map
<Node
, size_t>::const_iterator it
= d_fvId
.find(n
);
123 if (it
== d_fvId
.end())
125 Assert(false) << "TermDbSygus::isFreeVar: " << n
126 << " is not a cached free variable.";
132 bool TermDbSygus::hasFreeVar( Node n
, std::map
< Node
, bool >& visited
){
133 if( visited
.find( n
)==visited
.end() ){
135 if( isFreeVar( n
) ){
138 for( unsigned i
=0; i
<n
.getNumChildren(); i
++ ){
139 if( hasFreeVar( n
[i
], visited
) ){
147 bool TermDbSygus::hasFreeVar( Node n
) {
148 std::map
< Node
, bool > visited
;
149 return hasFreeVar( n
, visited
);
152 Node
TermDbSygus::getProxyVariable(TypeNode tn
, Node c
)
154 Assert(tn
.isDatatype());
155 Assert(tn
.getDType().isSygus());
156 Assert(tn
.getDType().getSygusType().isComparableTo(c
.getType()));
158 std::map
<Node
, Node
>::iterator it
= d_proxy_vars
[tn
].find(c
);
159 if (it
== d_proxy_vars
[tn
].end())
161 SygusTypeInfo
& ti
= getTypeInfo(tn
);
162 int anyC
= ti
.getAnyConstantConsNum();
166 k
= NodeManager::currentNM()->mkSkolem("sy", tn
, "sygus proxy");
167 SygusPrintProxyAttribute spa
;
168 k
.setAttribute(spa
, c
);
172 const DType
& dt
= tn
.getDType();
173 k
= NodeManager::currentNM()->mkNode(
174 APPLY_CONSTRUCTOR
, dt
[anyC
].getConstructor(), c
);
176 d_proxy_vars
[tn
][c
] = k
;
182 Node
TermDbSygus::mkGeneric(const DType
& dt
,
184 std::map
<TypeNode
, int>& var_count
,
185 std::map
<int, Node
>& pre
,
188 Assert(c
< dt
.getNumConstructors());
189 Assert(dt
.isSygus());
190 Assert(!dt
[c
].getSygusOp().isNull());
191 std::vector
< Node
> children
;
192 Trace("sygus-db-debug") << "mkGeneric " << dt
.getName() << " " << c
<< "..."
194 for (unsigned i
= 0, nargs
= dt
[c
].getNumArgs(); i
< nargs
; i
++)
197 std::map
< int, Node
>::iterator it
= pre
.find( i
);
200 Trace("sygus-db-debug") << "From pre: " << a
<< std::endl
;
202 TypeNode tna
= dt
[c
].getArgType(i
);
203 a
= getFreeVarInc( tna
, var_count
, true );
205 Trace("sygus-db-debug")
206 << " child " << i
<< " : " << a
<< " : " << a
.getType() << std::endl
;
208 children
.push_back( a
);
210 Node ret
= datatypes::utils::mkSygusTerm(dt
, c
, children
, doBetaRed
);
211 Trace("sygus-db-debug") << "mkGeneric returns " << ret
<< std::endl
;
215 Node
TermDbSygus::mkGeneric(const DType
& dt
,
217 std::map
<int, Node
>& pre
,
220 std::map
<TypeNode
, int> var_count
;
221 return mkGeneric(dt
, c
, var_count
, pre
, doBetaRed
);
224 Node
TermDbSygus::mkGeneric(const DType
& dt
, int c
, bool doBetaRed
)
226 std::map
<int, Node
> pre
;
227 return mkGeneric(dt
, c
, pre
, doBetaRed
);
230 struct CanonizeBuiltinAttributeId
233 using CanonizeBuiltinAttribute
=
234 expr::Attribute
<CanonizeBuiltinAttributeId
, Node
>;
236 Node
TermDbSygus::canonizeBuiltin(Node n
)
238 std::map
<TypeNode
, int> var_count
;
239 return canonizeBuiltin(n
, var_count
);
242 Node
TermDbSygus::canonizeBuiltin(Node n
, std::map
<TypeNode
, int>& var_count
)
244 // has it already been computed?
245 if (var_count
.empty() && n
.hasAttribute(CanonizeBuiltinAttribute()))
247 Node ret
= n
.getAttribute(CanonizeBuiltinAttribute());
248 Trace("sygus-db-canon") << "cached " << n
<< " : " << ret
<< "\n";
251 Trace("sygus-db-canon") << " CanonizeBuiltin : compute for " << n
<< "\n";
253 // it is symbolic if it represents "any constant"
254 if (n
.getKind() == APPLY_SELECTOR_TOTAL
)
256 ret
= getFreeVarInc(n
[0].getType(), var_count
, true);
258 else if (n
.getKind() != APPLY_CONSTRUCTOR
)
264 Assert(n
.getKind() == APPLY_CONSTRUCTOR
);
265 bool childChanged
= false;
266 std::vector
<Node
> children
;
267 children
.push_back(n
.getOperator());
268 for (unsigned j
= 0, size
= n
.getNumChildren(); j
< size
; ++j
)
270 Node child
= canonizeBuiltin(n
[j
], var_count
);
271 children
.push_back(child
);
272 childChanged
= childChanged
|| child
!= n
[j
];
276 ret
= NodeManager::currentNM()->mkNode(APPLY_CONSTRUCTOR
, children
);
279 // cache if we had a fresh variable count
280 if (var_count
.empty())
282 n
.setAttribute(CanonizeBuiltinAttribute(), ret
);
284 Trace("sygus-db-canon") << " ...normalized " << n
<< " --> " << ret
286 Assert(ret
.getType().isComparableTo(n
.getType()));
290 struct SygusToBuiltinAttributeId
293 typedef expr::Attribute
<SygusToBuiltinAttributeId
, Node
>
294 SygusToBuiltinAttribute
;
296 Node
TermDbSygus::sygusToBuiltin(Node n
, TypeNode tn
)
300 // if its a constant, we use the datatype utility version
301 return datatypes::utils::sygusToBuiltin(n
);
303 Assert(n
.getType().isComparableTo(tn
));
304 if (!tn
.isDatatype())
308 // has it already been computed?
309 if (n
.hasAttribute(SygusToBuiltinAttribute()))
311 return n
.getAttribute(SygusToBuiltinAttribute());
313 Trace("sygus-db-debug") << "SygusToBuiltin : compute for " << n
314 << ", type = " << tn
<< std::endl
;
315 const DType
& dt
= tn
.getDType();
320 if (n
.getKind() == APPLY_CONSTRUCTOR
)
322 unsigned i
= datatypes::utils::indexOf(n
.getOperator());
323 Assert(n
.getNumChildren() == dt
[i
].getNumArgs());
324 std::map
<int, Node
> pre
;
325 for (unsigned j
= 0, size
= n
.getNumChildren(); j
< size
; j
++)
327 pre
[j
] = sygusToBuiltin(n
[j
], dt
[i
].getArgType(j
));
328 Trace("sygus-db-debug")
329 << "sygus to builtin " << n
[j
] << " is " << pre
[j
] << std::endl
;
331 Node ret
= mkGeneric(dt
, i
, pre
);
332 Trace("sygus-db-debug")
333 << "SygusToBuiltin : Generic is " << ret
<< std::endl
;
335 n
.setAttribute(SygusToBuiltinAttribute(), ret
);
338 if (n
.hasAttribute(SygusPrintProxyAttribute()))
340 // this variable was associated by an attribute to a builtin node
341 return n
.getAttribute(SygusPrintProxyAttribute());
343 Assert(isFreeVar(n
));
344 // map to builtin variable type
345 size_t fv_num
= getFreeVarId(n
);
346 Assert(!dt
.getSygusType().isNull());
347 TypeNode vtn
= dt
.getSygusType();
348 Node ret
= getFreeVar(vtn
, fv_num
);
349 Trace("sygus-db-debug") << "SygusToBuiltin: variable for " << n
<< " is "
350 << ret
<< ", fv_num=" << fv_num
<< std::endl
;
354 unsigned TermDbSygus::getSygusTermSize( Node n
){
355 if (n
.getKind() != APPLY_CONSTRUCTOR
)
360 for (unsigned i
= 0; i
< n
.getNumChildren(); i
++)
362 sum
+= getSygusTermSize(n
[i
]);
364 const DType
& dt
= datatypes::utils::datatypeOf(n
.getOperator());
365 int cindex
= datatypes::utils::indexOf(n
.getOperator());
366 Assert(cindex
>= 0 && cindex
< (int)dt
.getNumConstructors());
367 unsigned weight
= dt
[cindex
].getWeight();
371 bool TermDbSygus::registerSygusType(TypeNode tn
)
373 std::map
<TypeNode
, bool>::iterator it
= d_registerStatus
.find(tn
);
374 if (it
!= d_registerStatus
.end())
376 // already registered
379 d_registerStatus
[tn
] = false;
380 // it must be a sygus datatype
381 if (!tn
.isDatatype())
385 const DType
& dt
= tn
.getDType();
390 d_registerStatus
[tn
] = true;
391 SygusTypeInfo
& sti
= d_tinfo
[tn
];
392 sti
.initialize(this, tn
);
396 void TermDbSygus::registerEnumerator(Node e
,
398 SynthConjecture
* conj
,
399 EnumeratorRole erole
)
401 if (d_enum_to_conjecture
.find(e
) != d_enum_to_conjecture
.end())
403 // already registered
406 Trace("sygus-db") << "Register enumerator : " << e
<< std::endl
;
408 TypeNode et
= e
.getType();
409 registerSygusType(et
);
410 d_enum_to_conjecture
[e
] = conj
;
411 d_enum_to_synth_fun
[e
] = f
;
412 NodeManager
* nm
= NodeManager::currentNM();
414 Trace("sygus-db") << " registering symmetry breaking clauses..."
416 // depending on if we are using symbolic constructors, introduce symmetry
417 // breaking lemma templates for each relevant subtype of the grammar
418 SygusTypeInfo
& eti
= getTypeInfo(et
);
419 std::vector
<TypeNode
> sf_types
;
420 eti
.getSubfieldTypes(sf_types
);
421 // for each type of subfield type of this enumerator
422 for (unsigned i
= 0, ntypes
= sf_types
.size(); i
< ntypes
; i
++)
424 std::vector
<unsigned> rm_indices
;
425 TypeNode stn
= sf_types
[i
];
426 Assert(stn
.isDatatype());
427 SygusTypeInfo
& sti
= getTypeInfo(stn
);
428 const DType
& dt
= stn
.getDType();
429 int anyC
= sti
.getAnyConstantConsNum();
430 for (unsigned j
= 0, ncons
= dt
.getNumConstructors(); j
< ncons
; j
++)
432 bool isAnyC
= static_cast<int>(j
) == anyC
;
433 if (anyC
!= -1 && !isAnyC
)
435 // if we are using the any constant constructor, do not use any
437 Node c_op
= sti
.getConsNumConst(j
);
440 rm_indices
.push_back(j
);
444 for (unsigned& rindex
: rm_indices
)
446 // make the apply-constructor corresponding to an application of the
447 // constant or "any constant" constructor
448 // we call getInstCons since in the case of any constant constructors, it
449 // is necessary to generate a term of the form any_constant( x.0 ) for a
450 // fresh variable x.0.
451 Node fv
= getFreeVar(stn
, 0);
452 Node exc_val
= datatypes::utils::getInstCons(fv
, dt
, rindex
);
453 // should not include the constuctor in any subterm
454 Node x
= getFreeVar(stn
, 0);
455 Trace("sygus-db") << "Construct symmetry breaking lemma from " << x
456 << " == " << exc_val
<< std::endl
;
457 Node lem
= getExplain()->getExplanationForEquality(x
, exc_val
);
460 << "Cegqi::Lemma : exclude symbolic cons lemma (template) : " << lem
462 // the size of the subterm we are blocking is the weight of the
463 // constructor (usually zero)
464 registerSymBreakLemma(e
, lem
, stn
, dt
[rindex
].getWeight());
467 Trace("sygus-db") << " ...finished" << std::endl
;
469 // determine if we are actively-generated
470 bool isActiveGen
= false;
471 if (options::sygusActiveGenMode() != options::SygusActiveGenMode::NONE
)
473 if (erole
== ROLE_ENUM_MULTI_SOLUTION
|| erole
== ROLE_ENUM_CONSTRAINED
)
475 // If the enumerator is a solution for a conjecture with multiple
476 // functions, we do not use active generation. If we did, we would have to
477 // generate a "product" of two actively-generated enumerators. That is,
478 // given a conjecture with two functions-to-synthesize with enumerators
479 // e_f and e_g, and if these enumerators generated:
480 // e_f -> t1, ..., tn
481 // e_g -> s1, ..., sm
482 // The sygus module in charge of this conjecture would expect
483 // constructCandidates calls of the form
484 // (e_f,e_g) -> (ti, sj)
485 // for each i,j. We instead use passive enumeration in this case.
487 // If the enumerator is constrained, it cannot be actively generated.
489 else if (erole
== ROLE_ENUM_POOL
)
491 // If the enumerator is used for generating a pool of values, we always
492 // use active generation.
495 else if (erole
== ROLE_ENUM_SINGLE_SOLUTION
)
497 // If the enumerator is the single function-to-synthesize, if auto is
498 // enabled, we infer whether it is better to enable active generation.
499 if (options::sygusActiveGenMode() == options::SygusActiveGenMode::AUTO
)
501 // We use active generation if the grammar of the enumerator does not
502 // have ITE and is not Boolean. Experimentally, it is better to
503 // use passive generation for these cases since it enables useful
504 // search space pruning techniques, e.g. evaluation unfolding,
505 // conjecture-specific symmetry breaking. Also, if sygus-stream is
506 // enabled, we always use active generation, since the use cases of
507 // sygus stream are to find many solutions to an easy problem, where
508 // the bottleneck often becomes the large number of "exclude the current
509 // solution" clauses.
510 const DType
& dt
= et
.getDType();
511 if (options::sygusStream()
512 || (!eti
.hasIte() && !dt
.getSygusType().isBoolean()))
524 Unreachable() << "Unknown enumerator mode in registerEnumerator";
527 Trace("sygus-db") << "isActiveGen for " << e
<< ", role = " << erole
528 << " returned " << isActiveGen
<< std::endl
;
529 // Currently, actively-generated enumerators are either basic or variable
531 bool isVarAgnostic
= isActiveGen
532 && options::sygusActiveGenMode()
533 == options::SygusActiveGenMode::VAR_AGNOSTIC
;
534 d_enum_var_agnostic
[e
] = isVarAgnostic
;
537 // requires variable subclasses
538 eti
.initializeVarSubclasses();
539 // If no subclass has more than one variable, do not use variable agnostic
541 bool useVarAgnostic
= !eti
.isSubclassVarTrivial();
545 << "...disabling variable agnostic for " << e
546 << " since it has no subclass with more than one variable."
548 d_enum_var_agnostic
[e
] = false;
552 d_enum_active_gen
[e
] = isActiveGen
;
553 d_enum_basic
[e
] = isActiveGen
&& !isVarAgnostic
;
555 // We make an active guard if we will be explicitly blocking solutions for
556 // the enumerator. This is the case if the role of the enumerator is to
557 // populate a pool of terms, or (some cases) of when it is actively generated.
558 if (isActiveGen
|| erole
== ROLE_ENUM_POOL
)
561 Node ag
= nm
->mkSkolem("eG", nm
->booleanType());
562 // must ensure it is a literal immediately here
563 ag
= d_quantEngine
->getValuation().ensureLiteral(ag
);
564 // must ensure that it is asserted as a literal before we begin solving
565 Node lem
= nm
->mkNode(OR
, ag
, ag
.negate());
566 d_quantEngine
->getOutputChannel().requirePhase(ag
, true);
567 d_quantEngine
->getOutputChannel().lemma(lem
);
568 d_enum_to_active_guard
[e
] = ag
;
572 bool TermDbSygus::isEnumerator(Node e
) const
574 return d_enum_to_conjecture
.find(e
) != d_enum_to_conjecture
.end();
577 SynthConjecture
* TermDbSygus::getConjectureForEnumerator(Node e
) const
579 std::map
<Node
, SynthConjecture
*>::const_iterator itm
=
580 d_enum_to_conjecture
.find(e
);
581 if (itm
!= d_enum_to_conjecture
.end()) {
587 Node
TermDbSygus::getSynthFunForEnumerator(Node e
) const
589 std::map
<Node
, Node
>::const_iterator itsf
= d_enum_to_synth_fun
.find(e
);
590 if (itsf
!= d_enum_to_synth_fun
.end())
597 Node
TermDbSygus::getActiveGuardForEnumerator(Node e
) const
599 std::map
<Node
, Node
>::const_iterator itag
= d_enum_to_active_guard
.find(e
);
600 if (itag
!= d_enum_to_active_guard
.end()) {
606 bool TermDbSygus::usingSymbolicConsForEnumerator(Node e
) const
608 std::map
<Node
, bool>::const_iterator itus
= d_enum_to_using_sym_cons
.find(e
);
609 if (itus
!= d_enum_to_using_sym_cons
.end())
616 bool TermDbSygus::isVariableAgnosticEnumerator(Node e
) const
618 std::map
<Node
, bool>::const_iterator itus
= d_enum_var_agnostic
.find(e
);
619 if (itus
!= d_enum_var_agnostic
.end())
626 bool TermDbSygus::isBasicEnumerator(Node e
) const
628 std::map
<Node
, bool>::const_iterator itus
= d_enum_basic
.find(e
);
629 if (itus
!= d_enum_basic
.end())
636 bool TermDbSygus::isPassiveEnumerator(Node e
) const
638 std::map
<Node
, bool>::const_iterator itus
= d_enum_active_gen
.find(e
);
639 if (itus
!= d_enum_active_gen
.end())
641 return !itus
->second
;
646 void TermDbSygus::getEnumerators(std::vector
<Node
>& mts
)
648 for (std::map
<Node
, SynthConjecture
*>::iterator itm
=
649 d_enum_to_conjecture
.begin();
650 itm
!= d_enum_to_conjecture
.end();
653 mts
.push_back( itm
->first
);
657 void TermDbSygus::registerSymBreakLemma(
658 Node e
, Node lem
, TypeNode tn
, unsigned sz
, bool isTempl
)
660 d_enum_to_sb_lemmas
[e
].push_back(lem
);
661 d_sb_lemma_to_type
[lem
] = tn
;
662 d_sb_lemma_to_size
[lem
] = sz
;
663 d_sb_lemma_to_isTempl
[lem
] = isTempl
;
666 bool TermDbSygus::hasSymBreakLemmas(std::vector
<Node
>& enums
) const
668 if (!d_enum_to_sb_lemmas
.empty())
670 for (std::pair
<const Node
, std::vector
<Node
> > sb
: d_enum_to_sb_lemmas
)
672 enums
.push_back(sb
.first
);
679 void TermDbSygus::getSymBreakLemmas(Node e
, std::vector
<Node
>& lemmas
) const
681 std::map
<Node
, std::vector
<Node
> >::const_iterator itsb
=
682 d_enum_to_sb_lemmas
.find(e
);
683 if (itsb
!= d_enum_to_sb_lemmas
.end())
685 lemmas
.insert(lemmas
.end(), itsb
->second
.begin(), itsb
->second
.end());
689 TypeNode
TermDbSygus::getTypeForSymBreakLemma(Node lem
) const
691 std::map
<Node
, TypeNode
>::const_iterator it
= d_sb_lemma_to_type
.find(lem
);
692 Assert(it
!= d_sb_lemma_to_type
.end());
695 unsigned TermDbSygus::getSizeForSymBreakLemma(Node lem
) const
697 std::map
<Node
, unsigned>::const_iterator it
= d_sb_lemma_to_size
.find(lem
);
698 Assert(it
!= d_sb_lemma_to_size
.end());
702 bool TermDbSygus::isSymBreakLemmaTemplate(Node lem
) const
704 std::map
<Node
, bool>::const_iterator it
= d_sb_lemma_to_isTempl
.find(lem
);
705 Assert(it
!= d_sb_lemma_to_isTempl
.end());
709 void TermDbSygus::clearSymBreakLemmas(Node e
) { d_enum_to_sb_lemmas
.erase(e
); }
711 bool TermDbSygus::isRegistered(TypeNode tn
) const
713 return d_tinfo
.find(tn
) != d_tinfo
.end();
716 TypeNode
TermDbSygus::sygusToBuiltinType( TypeNode tn
) {
717 std::map
<TypeNode
, SygusTypeInfo
>::iterator it
= d_tinfo
.find(tn
);
718 Assert(it
!= d_tinfo
.end());
719 return it
->second
.getBuiltinType();
722 void TermDbSygus::toStreamSygus(const char* c
, Node n
)
732 std::stringstream ss
;
733 Printer::getPrinter(options::outputLanguage())->toStreamSygus(ss
, n
);
734 Trace(c
) << ss
.str();
739 SygusTypeInfo
& TermDbSygus::getTypeInfo(TypeNode tn
)
741 AlwaysAssert(d_tinfo
.find(tn
) != d_tinfo
.end());
745 Node
TermDbSygus::rewriteNode(Node n
) const
747 Node res
= Rewriter::rewrite(n
);
750 // constant, we are done
753 if (options::sygusRecFun())
755 if (d_funDefEval
->hasDefinitions())
757 // If recursive functions are enabled, then we use the recursive function
758 // evaluation utility.
759 Node fres
= d_funDefEval
->evaluate(res
);
764 // It may have failed, in which case there are undefined symbols in res or
765 // we reached the limit of evaluations. In this case, we revert to the
766 // result of rewriting in the return statement below.
772 unsigned TermDbSygus::getSelectorWeight(TypeNode tn
, Node sel
)
774 std::map
<TypeNode
, std::map
<Node
, unsigned> >::iterator itsw
=
775 d_sel_weight
.find(tn
);
776 if (itsw
== d_sel_weight
.end())
778 d_sel_weight
[tn
].clear();
779 itsw
= d_sel_weight
.find(tn
);
780 const DType
& dt
= tn
.getDType();
781 Trace("sygus-db") << "Compute selector weights for " << dt
.getName()
783 for (unsigned i
= 0, size
= dt
.getNumConstructors(); i
< size
; i
++)
785 unsigned cw
= dt
[i
].getWeight();
786 for (unsigned j
= 0, size2
= dt
[i
].getNumArgs(); j
< size2
; j
++)
788 Node csel
= dt
[i
].getSelectorInternal(tn
, j
);
789 std::map
<Node
, unsigned>::iterator its
= itsw
->second
.find(csel
);
790 if (its
== itsw
->second
.end() || cw
< its
->second
)
792 d_sel_weight
[tn
][csel
] = cw
;
793 Trace("sygus-db") << " w(" << csel
<< ") <= " << cw
<< std::endl
;
798 Assert(itsw
->second
.find(sel
) != itsw
->second
.end());
799 return itsw
->second
[sel
];
802 TypeNode
TermDbSygus::getArgType(const DTypeConstructor
& c
, unsigned i
) const
804 Assert(i
< c
.getNumArgs());
805 return c
.getArgType(i
);
808 bool TermDbSygus::isTypeMatch(const DTypeConstructor
& c1
,
809 const DTypeConstructor
& c2
)
811 if( c1
.getNumArgs()!=c2
.getNumArgs() ){
814 for( unsigned i
=0; i
<c1
.getNumArgs(); i
++ ){
815 if( getArgType( c1
, i
)!=getArgType( c2
, i
) ){
823 bool TermDbSygus::isSymbolicConsApp(Node n
) const
825 if (n
.getKind() != APPLY_CONSTRUCTOR
)
829 TypeNode tn
= n
.getType();
830 Assert(tn
.isDatatype());
831 const DType
& dt
= tn
.getDType();
832 Assert(dt
.isSygus());
833 unsigned cindex
= datatypes::utils::indexOf(n
.getOperator());
834 Node sygusOp
= dt
[cindex
].getSygusOp();
835 // it is symbolic if it represents "any constant"
836 return sygusOp
.getAttribute(SygusAnyConstAttribute());
839 bool TermDbSygus::canConstructKind(TypeNode tn
,
841 std::vector
<TypeNode
>& argts
,
844 Assert(isRegistered(tn
));
845 SygusTypeInfo
& ti
= getTypeInfo(tn
);
846 int c
= ti
.getKindConsNum(k
);
847 const DType
& dt
= tn
.getDType();
850 for (unsigned i
= 0, nargs
= dt
[c
].getNumArgs(); i
< nargs
; i
++)
852 argts
.push_back(dt
[c
].getArgType(i
));
856 if (!options::sygusSymBreakAgg())
860 if (sygusToBuiltinType(tn
).isBoolean())
864 // ite( b1, b2, b3 ) <---- and( or( ~b1, b2 ), or( b1, b3 ) )
865 std::vector
<TypeNode
> conj_types
;
866 if (canConstructKind(tn
, AND
, conj_types
, true) && conj_types
.size() == 2)
869 std::vector
<TypeNode
> disj_types
[2];
870 for (unsigned cc
= 0; cc
< 2; cc
++)
872 if (!canConstructKind(conj_types
[cc
], OR
, disj_types
[cc
], true)
873 || disj_types
[cc
].size() != 2)
881 for (unsigned r
= 0; r
< 2; r
++)
883 for (unsigned d
= 0, size
= disj_types
[r
].size(); d
< size
; d
++)
885 TypeNode dtn
= disj_types
[r
][d
];
886 // must have negation that occurs in the other conjunct
887 std::vector
<TypeNode
> ntypes
;
888 if (canConstructKind(dtn
, NOT
, ntypes
) && ntypes
.size() == 1)
890 TypeNode ntn
= ntypes
[0];
891 for (unsigned dd
= 0, inner_size
= disj_types
[1 - r
].size();
895 if (disj_types
[1 - r
][dd
] == ntn
)
897 argts
.push_back(ntn
);
898 argts
.push_back(disj_types
[r
][d
]);
899 argts
.push_back(disj_types
[1 - r
][1 - dd
]);
900 if (Trace
.isOn("sygus-cons-kind"))
902 Trace("sygus-cons-kind")
903 << "Can construct kind " << k
<< " in " << tn
904 << " via child types:" << std::endl
;
905 for (unsigned i
= 0; i
< 3; i
++)
907 Trace("sygus-cons-kind")
908 << " " << argts
[i
] << std::endl
;
921 // could try aggressive inferences here, such as
922 // (and b1 b2) <---- (not (or (not b1) (not b2)))
923 // (or b1 b2) <---- (not (and (not b1) (not b2)))
927 bool TermDbSygus::involvesDivByZero( Node n
, std::map
< Node
, bool >& visited
){
928 if( visited
.find( n
)==visited
.end() ){
930 Kind k
= n
.getKind();
931 if( k
==DIVISION
|| k
==DIVISION_TOTAL
|| k
==INTS_DIVISION
|| k
==INTS_DIVISION_TOTAL
||
932 k
==INTS_MODULUS
|| k
==INTS_MODULUS_TOTAL
){
933 if( n
[1].isConst() ){
935 == d_quantEngine
->getTermUtil()->getTypeValue(n
[1].getType(), 0))
940 // if it has free variables it might be a non-zero constant
941 if( !hasFreeVar( n
[1] ) ){
946 for( unsigned i
=0; i
<n
.getNumChildren(); i
++ ){
947 if( involvesDivByZero( n
[i
], visited
) ){
955 bool TermDbSygus::involvesDivByZero( Node n
) {
956 std::map
< Node
, bool > visited
;
957 return involvesDivByZero( n
, visited
);
960 Node
TermDbSygus::getAnchor( Node n
) {
961 if( n
.getKind()==APPLY_SELECTOR_TOTAL
){
962 return getAnchor( n
[0] );
968 unsigned TermDbSygus::getAnchorDepth( Node n
) {
969 if( n
.getKind()==APPLY_SELECTOR_TOTAL
){
970 return 1+getAnchorDepth( n
[0] );
976 Node
TermDbSygus::evaluateBuiltin(TypeNode tn
,
978 const std::vector
<Node
>& args
,
983 return Rewriter::rewrite( bn
);
985 Assert(isRegistered(tn
));
986 SygusTypeInfo
& ti
= getTypeInfo(tn
);
987 const std::vector
<Node
>& varlist
= ti
.getVarList();
988 Assert(varlist
.size() == args
.size());
991 if (tryEval
&& options::sygusEvalOpt())
993 // Try evaluating, which is much faster than substitution+rewriting.
994 // This may fail if there is a subterm of bn under the
995 // substitution that is not constant, or if an operator in bn is not
996 // supported by the evaluator
997 res
= d_eval
->eval(bn
, varlist
, args
);
1001 // must do substitution
1003 bn
.substitute(varlist
.begin(), varlist
.end(), args
.begin(), args
.end());
1005 // Call the rewrite node function, which may involve recursive function
1007 return rewriteNode(res
);
1010 Node
TermDbSygus::evaluateWithUnfolding(
1011 Node n
, std::unordered_map
<Node
, Node
, NodeHashFunction
>& visited
)
1013 std::unordered_map
<Node
, Node
, NodeHashFunction
>::iterator it
=
1015 if( it
==visited
.end() ){
1017 while (ret
.getKind() == DT_SYGUS_EVAL
1018 && ret
[0].getKind() == APPLY_CONSTRUCTOR
)
1020 if (ret
== n
&& ret
[0].isConst())
1022 // use rewriting, possibly involving recursive functions
1023 ret
= rewriteNode(ret
);
1027 ret
= d_eval_unfold
->unfold(ret
);
1030 if( ret
.getNumChildren()>0 ){
1031 std::vector
< Node
> children
;
1032 if( ret
.getMetaKind() == kind::metakind::PARAMETERIZED
){
1033 children
.push_back( ret
.getOperator() );
1035 bool childChanged
= false;
1036 for( unsigned i
=0; i
<ret
.getNumChildren(); i
++ ){
1037 Node nc
= evaluateWithUnfolding(ret
[i
], visited
);
1038 childChanged
= childChanged
|| nc
!=ret
[i
];
1039 children
.push_back( nc
);
1042 ret
= NodeManager::currentNM()->mkNode( ret
.getKind(), children
);
1044 if (options::sygusExtRew())
1046 ret
= getExtRewriter()->extendedRewrite(ret
);
1048 // use rewriting, possibly involving recursive functions
1049 ret
= rewriteNode(ret
);
1058 Node
TermDbSygus::evaluateWithUnfolding(Node n
)
1060 std::unordered_map
<Node
, Node
, NodeHashFunction
> visited
;
1061 return evaluateWithUnfolding(n
, visited
);
1064 bool TermDbSygus::isEvaluationPoint(Node n
) const
1066 if (n
.getKind() != DT_SYGUS_EVAL
)
1074 for (unsigned i
= 1, nchild
= n
.getNumChildren(); i
< nchild
; i
++)
1076 if (!n
[i
].isConst())
1084 }/* CVC4::theory::quantifiers namespace */
1085 }/* CVC4::theory namespace */
1086 }/* CVC4 namespace */