1 /********************* */
2 /*! \file term_database.cpp
4 ** Top contributors (to current version):
5 ** Andrew Reynolds, Mathias Preiner, Tim King
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 databse class
15 #include "theory/quantifiers/term_database.h"
17 #include "options/base_options.h"
18 #include "options/quantifiers_options.h"
19 #include "options/smt_options.h"
20 #include "options/theory_options.h"
21 #include "options/uf_options.h"
22 #include "theory/quantifiers/ematching/trigger_term_info.h"
23 #include "theory/quantifiers/quantifiers_attributes.h"
24 #include "theory/quantifiers/term_util.h"
25 #include "theory/quantifiers_engine.h"
26 #include "theory/theory_engine.h"
29 using namespace CVC4::kind
;
30 using namespace CVC4::context
;
31 using namespace CVC4::theory::inst
;
35 namespace quantifiers
{
37 TermDb::TermDb(QuantifiersState
& qs
,
38 QuantifiersInferenceManager
& qim
,
39 QuantifiersEngine
* qe
)
43 d_inactive_map(qs
.getSatContext())
45 d_consistent_ee
= true;
46 d_true
= NodeManager::currentNM()->mkConst(true);
47 d_false
= NodeManager::currentNM()->mkConst(false);
54 void TermDb::registerQuantifier( Node q
) {
55 Assert(q
[0].getNumChildren()
56 == d_quantEngine
->getTermUtil()->getNumInstantiationConstants(q
));
57 for( unsigned i
=0; i
<q
[0].getNumChildren(); i
++ ){
58 Node ic
= d_quantEngine
->getTermUtil()->getInstantiationConstant( q
, i
);
59 setTermInactive( ic
);
63 unsigned TermDb::getNumOperators() { return d_ops
.size(); }
64 Node
TermDb::getOperator(unsigned i
)
66 Assert(i
< d_ops
.size());
71 unsigned TermDb::getNumGroundTerms(Node f
) const
73 std::map
<Node
, std::vector
<Node
> >::const_iterator it
= d_op_map
.find(f
);
74 if( it
!=d_op_map
.end() ){
75 return it
->second
.size();
81 Node
TermDb::getGroundTerm(Node f
, unsigned i
) const
83 std::map
<Node
, std::vector
<Node
> >::const_iterator it
= d_op_map
.find(f
);
84 if (it
!= d_op_map
.end())
86 Assert(i
< it
->second
.size());
96 unsigned TermDb::getNumTypeGroundTerms(TypeNode tn
) const
98 std::map
<TypeNode
, std::vector
<Node
> >::const_iterator it
=
100 if( it
!=d_type_map
.end() ){
101 return it
->second
.size();
107 Node
TermDb::getTypeGroundTerm(TypeNode tn
, unsigned i
) const
109 std::map
<TypeNode
, std::vector
<Node
> >::const_iterator it
=
111 if (it
!= d_type_map
.end())
113 Assert(i
< it
->second
.size());
114 return it
->second
[i
];
123 Node
TermDb::getOrMakeTypeGroundTerm(TypeNode tn
, bool reqVar
)
125 std::map
<TypeNode
, std::vector
<Node
> >::const_iterator it
=
127 if (it
!= d_type_map
.end())
129 Assert(!it
->second
.empty());
132 return it
->second
[0];
134 for (const Node
& v
: it
->second
)
142 return getOrMakeTypeFreshVariable(tn
);
145 Node
TermDb::getOrMakeTypeFreshVariable(TypeNode tn
)
147 std::unordered_map
<TypeNode
, Node
, TypeNodeHashFunction
>::iterator it
=
149 if (it
== d_type_fv
.end())
151 std::stringstream ss
;
152 ss
<< language::SetLanguage(options::outputLanguage());
154 Node k
= NodeManager::currentNM()->mkSkolem(
155 ss
.str(), tn
, "is a termDb fresh variable");
156 Trace("mkVar") << "TermDb:: Make variable " << k
<< " : " << tn
158 if (options::instMaxLevel() != -1)
160 QuantAttributes::setInstantiationLevelAttr(k
, 0);
171 Node
TermDb::getMatchOperator( Node n
) {
172 Kind k
= n
.getKind();
173 //datatype operators may be parametric, always assume they are
174 if (k
== SELECT
|| k
== STORE
|| k
== UNION
|| k
== INTERSECTION
175 || k
== SUBSET
|| k
== SETMINUS
|| k
== MEMBER
|| k
== SINGLETON
176 || k
== APPLY_SELECTOR_TOTAL
|| k
== APPLY_SELECTOR
|| k
== APPLY_TESTER
177 || k
== SEP_PTO
|| k
== HO_APPLY
|| k
== SEQ_NTH
)
179 //since it is parametric, use a particular one as op
180 TypeNode tn
= n
[0].getType();
181 Node op
= n
.getOperator();
182 std::map
< Node
, std::map
< TypeNode
, Node
> >::iterator ito
= d_par_op_map
.find( op
);
183 if( ito
!=d_par_op_map
.end() ){
184 std::map
< TypeNode
, Node
>::iterator it
= ito
->second
.find( tn
);
185 if( it
!=ito
->second
.end() ){
189 Trace("par-op") << "Parametric operator : " << k
<< ", " << n
.getOperator() << ", " << tn
<< " : " << n
<< std::endl
;
190 d_par_op_map
[op
][tn
] = n
;
193 else if (inst::TriggerTermInfo::isAtomicTriggerKind(k
))
195 return n
.getOperator();
201 void TermDb::addTerm(Node n
)
203 if (d_processed
.find(n
) != d_processed
.end())
207 d_processed
.insert(n
);
208 if (!TermUtil::hasInstConstAttr(n
))
210 Trace("term-db-debug") << "register term : " << n
<< std::endl
;
211 d_type_map
[n
.getType()].push_back(n
);
212 // if this is an atomic trigger, consider adding it
213 if (inst::TriggerTermInfo::isAtomicTrigger(n
))
215 Trace("term-db") << "register term in db " << n
<< std::endl
;
217 Node op
= getMatchOperator(n
);
218 Trace("term-db-debug") << " match operator is : " << op
<< std::endl
;
219 if (d_op_map
.find(op
) == d_op_map
.end())
223 d_op_map
[op
].push_back(n
);
224 // If we are higher-order, we may need to register more terms.
237 for (const Node
& nc
: n
)
244 void TermDb::computeArgReps( TNode n
) {
245 if (d_arg_reps
.find(n
) == d_arg_reps
.end())
247 eq::EqualityEngine
* ee
= d_qstate
.getEqualityEngine();
248 for (const TNode
& nc
: n
)
250 TNode r
= ee
->hasTerm(nc
) ? ee
->getRepresentative(nc
) : nc
;
251 d_arg_reps
[n
].push_back( r
);
256 void TermDb::computeUfEqcTerms( TNode f
) {
257 Assert(f
== getOperatorRepresentative(f
));
258 if (d_func_map_eqc_trie
.find(f
) != d_func_map_eqc_trie
.end())
262 d_func_map_eqc_trie
[f
].clear();
263 // get the matchable operators in the equivalence class of f
264 std::vector
<TNode
> ops
;
268 ops
.insert(ops
.end(), d_ho_op_slaves
[f
].begin(), d_ho_op_slaves
[f
].end());
270 eq::EqualityEngine
* ee
= d_qstate
.getEqualityEngine();
273 for (const Node
& n
: d_op_map
[ff
])
275 if (hasTermCurrent(n
) && isTermActive(n
))
278 TNode r
= ee
->hasTerm(n
) ? ee
->getRepresentative(n
) : TNode(n
);
279 d_func_map_eqc_trie
[f
].d_data
[r
].addTerm(n
, d_arg_reps
[n
]);
285 void TermDb::computeUfTerms( TNode f
) {
286 if (d_op_nonred_count
.find(f
) != d_op_nonred_count
.end())
291 Assert(f
== getOperatorRepresentative(f
));
292 d_op_nonred_count
[f
] = 0;
293 // get the matchable operators in the equivalence class of f
294 std::vector
<TNode
> ops
;
298 ops
.insert(ops
.end(), d_ho_op_slaves
[f
].begin(), d_ho_op_slaves
[f
].end());
300 Trace("term-db-debug") << "computeUfTerms for " << f
<< std::endl
;
301 unsigned congruentCount
= 0;
302 unsigned nonCongruentCount
= 0;
303 unsigned alreadyCongruentCount
= 0;
304 unsigned relevantCount
= 0;
305 NodeManager
* nm
= NodeManager::currentNM();
308 std::map
<Node
, std::vector
<Node
> >::iterator it
= d_op_map
.find(ff
);
309 if (it
== d_op_map
.end())
311 // no terms for this operator
314 Trace("term-db-debug") << "Adding terms for operator " << ff
<< std::endl
;
315 for (const Node
& n
: it
->second
)
317 // to be added to term index, term must be relevant, and exist in EE
318 if (!hasTermCurrent(n
) || !d_qstate
.hasTerm(n
))
320 Trace("term-db-debug") << n
<< " is not relevant." << std::endl
;
325 if (!isTermActive(n
))
327 Trace("term-db-debug") << n
<< " is already redundant." << std::endl
;
328 alreadyCongruentCount
++;
333 Trace("term-db-debug") << "Adding term " << n
<< " with arg reps : ";
334 for (unsigned i
= 0, size
= d_arg_reps
[n
].size(); i
< size
; i
++)
336 Trace("term-db-debug") << d_arg_reps
[n
][i
] << " ";
337 if (std::find(d_func_map_rel_dom
[f
][i
].begin(),
338 d_func_map_rel_dom
[f
][i
].end(),
340 == d_func_map_rel_dom
[f
][i
].end())
342 d_func_map_rel_dom
[f
][i
].push_back(d_arg_reps
[n
][i
]);
345 Trace("term-db-debug") << std::endl
;
346 Assert(d_qstate
.hasTerm(n
));
347 Trace("term-db-debug")
348 << " and value : " << d_qstate
.getRepresentative(n
) << std::endl
;
349 Node at
= d_func_map_trie
[f
].addOrGetTerm(n
, d_arg_reps
[n
]);
350 Assert(d_qstate
.hasTerm(at
));
351 Trace("term-db-debug2") << "...add term returned " << at
<< std::endl
;
352 if (at
!= n
&& d_qstate
.areEqual(at
, n
))
355 Trace("term-db-debug") << n
<< " is redundant." << std::endl
;
359 if (d_qstate
.areDisequal(at
, n
))
361 std::vector
<Node
> lits
;
362 lits
.push_back(nm
->mkNode(EQUAL
, at
, n
));
366 // operators might be disequal
369 Node atf
= getMatchOperator(at
);
370 Node nf
= getMatchOperator(n
);
373 if (at
.getKind() == APPLY_UF
&& n
.getKind() == APPLY_UF
)
375 lits
.push_back(atf
.eqNode(nf
).negate());
387 Assert(at
.getNumChildren() == n
.getNumChildren());
388 for (unsigned k
= 0, size
= at
.getNumChildren(); k
< size
; k
++)
392 lits
.push_back(nm
->mkNode(EQUAL
, at
[k
], n
[k
]).negate());
395 Node lem
= lits
.size() == 1 ? lits
[0] : nm
->mkNode(OR
, lits
);
396 if (Trace
.isOn("term-db-lemma"))
398 Trace("term-db-lemma") << "Disequal congruent terms : " << at
<< " "
399 << n
<< "!!!!" << std::endl
;
400 if (!d_qstate
.getValuation().needCheck())
402 Trace("term-db-lemma") << " all theories passed with no lemmas."
404 // we should be a full effort check, prior to theory combination
406 Trace("term-db-lemma") << " add lemma : " << lem
<< std::endl
;
408 d_qim
.addPendingLemma(lem
);
409 d_qstate
.notifyInConflict();
410 d_consistent_ee
= false;
415 d_op_nonred_count
[f
]++;
417 if (Trace
.isOn("tdb"))
419 Trace("tdb") << "Term db size [" << f
<< "] : " << nonCongruentCount
421 Trace("tdb") << (nonCongruentCount
+ congruentCount
) << " / "
422 << (nonCongruentCount
+ congruentCount
423 + alreadyCongruentCount
)
425 Trace("tdb") << relevantCount
<< " / " << it
->second
.size() << std::endl
;
430 void TermDb::addTermHo(Node n
)
432 Assert(options::ufHo());
433 if (n
.getType().isFunction())
435 // nothing special to do with functions
438 NodeManager
* nm
= NodeManager::currentNM();
440 std::vector
<Node
> args
;
441 while (curr
.getKind() == HO_APPLY
)
443 args
.insert(args
.begin(), curr
[1]);
448 std::map
<Node
, Node
>::iterator itp
= d_ho_fun_op_purify
.find(curr
);
450 if (itp
== d_ho_fun_op_purify
.end())
452 psk
= nm
->mkSkolem("pfun",
454 "purify for function operator term indexing");
455 d_ho_fun_op_purify
[curr
] = psk
;
456 // we do not add it to d_ops since it is an internal operator
462 std::vector
<Node
> children
;
463 children
.push_back(psk
);
464 children
.insert(children
.end(), args
.begin(), args
.end());
465 Node p_n
= nm
->mkNode(APPLY_UF
, children
);
466 Trace("term-db") << "register term in db (via purify) " << p_n
468 // also add this one internally
469 d_op_map
[psk
].push_back(p_n
);
470 // maintain backwards mapping
471 d_ho_purify_to_term
[p_n
] = n
;
474 if (!args
.empty() && curr
.isVar())
476 // also add standard application version
477 args
.insert(args
.begin(), curr
);
478 Node uf_n
= nm
->mkNode(APPLY_UF
, args
);
483 Node
TermDb::getOperatorRepresentative( TNode op
) const {
484 std::map
< TNode
, TNode
>::const_iterator it
= d_ho_op_rep
.find( op
);
485 if( it
!=d_ho_op_rep
.end() ){
492 bool TermDb::inRelevantDomain( TNode f
, unsigned i
, TNode r
) {
493 if( options::ufHo() ){
494 f
= getOperatorRepresentative( f
);
497 Assert(!d_qstate
.getEqualityEngine()->hasTerm(r
)
498 || d_qstate
.getEqualityEngine()->getRepresentative(r
) == r
);
499 std::map
< Node
, std::map
< unsigned, std::vector
< Node
> > >::iterator it
= d_func_map_rel_dom
.find( f
);
500 if( it
!= d_func_map_rel_dom
.end() ){
501 std::map
< unsigned, std::vector
< Node
> >::iterator it2
= it
->second
.find( i
);
502 if( it2
!=it
->second
.end() ){
503 return std::find( it2
->second
.begin(), it2
->second
.end(), r
)!=it2
->second
.end();
512 Node
TermDb::evaluateTerm2(TNode n
,
513 std::map
<TNode
, Node
>& visited
,
514 std::vector
<Node
>& exp
,
515 bool useEntailmentTests
,
519 std::map
< TNode
, Node
>::iterator itv
= visited
.find( n
);
520 if( itv
!= visited
.end() ){
523 size_t prevSize
= exp
.size();
524 Trace("term-db-eval") << "evaluate term : " << n
<< std::endl
;
526 if( n
.getKind()==FORALL
|| n
.getKind()==BOUND_VARIABLE
){
529 else if (d_qstate
.hasTerm(n
))
531 Trace("term-db-eval") << "...exists in ee, return rep" << std::endl
;
532 ret
= d_qstate
.getRepresentative(n
);
537 exp
.push_back(n
.eqNode(ret
));
542 else if (n
.hasOperator())
544 std::vector
<TNode
> args
;
545 bool ret_set
= false;
546 Kind k
= n
.getKind();
547 std::vector
<Node
> tempExp
;
548 for (unsigned i
= 0, nchild
= n
.getNumChildren(); i
< nchild
; i
++)
550 TNode c
= evaluateTerm2(n
[i
],
562 else if (c
== d_true
|| c
== d_false
)
565 if ((k
== AND
&& c
== d_false
) || (k
== OR
&& c
== d_true
))
572 else if (k
== ITE
&& i
== 0)
574 ret
= evaluateTerm2(n
[c
== d_true
? 1 : 2],
587 exp
.insert(exp
.end(), tempExp
.begin(), tempExp
.end());
589 Trace("term-db-eval") << " child " << i
<< " : " << c
<< std::endl
;
594 // if we short circuited
598 exp
.insert(exp
.end(), tempExp
.begin(), tempExp
.end());
603 // get the (indexed) operator of n, if it exists
604 TNode f
= getMatchOperator(n
);
605 // if it is an indexed term, return the congruent term
608 // if f is congruent to a term indexed by this class
609 TNode nn
= getCongruentTerm(f
, args
);
610 Trace("term-db-eval") << " got congruent term " << nn
611 << " from DB for " << n
<< std::endl
;
616 Assert(nn
.getNumChildren() == n
.getNumChildren());
617 for (unsigned i
= 0, nchild
= nn
.getNumChildren(); i
< nchild
; i
++)
621 exp
.push_back(nn
[i
].eqNode(n
[i
]));
625 ret
= d_qstate
.getRepresentative(nn
);
626 Trace("term-db-eval") << "return rep" << std::endl
;
629 Assert(!ret
.isNull());
634 exp
.push_back(nn
.eqNode(ret
));
640 Trace("term-db-eval") << "return rewrite" << std::endl
;
641 // a theory symbol or a new UF term
642 if (n
.getMetaKind() == metakind::PARAMETERIZED
)
644 args
.insert(args
.begin(), n
.getOperator());
646 ret
= NodeManager::currentNM()->mkNode(n
.getKind(), args
);
647 ret
= Rewriter::rewrite(ret
);
648 if (ret
.getKind() == EQUAL
)
650 if (d_qstate
.areDisequal(ret
[0], ret
[1]))
655 if (useEntailmentTests
)
657 if (ret
.getKind() == EQUAL
|| ret
.getKind() == GEQ
)
659 TheoryEngine
* te
= d_quantEngine
->getTheoryEngine();
660 for (unsigned j
= 0; j
< 2; j
++)
662 std::pair
<bool, Node
> et
= te
->entailmentCheck(
663 options::TheoryOfMode::THEORY_OF_TYPE_BASED
,
664 j
== 0 ? ret
: ret
.negate());
667 ret
= j
== 0 ? d_true
: d_false
;
670 exp
.push_back(et
.second
);
680 // must have the term
681 if (reqHasTerm
&& !ret
.isNull())
683 Kind k
= ret
.getKind();
684 if (k
!= OR
&& k
!= AND
&& k
!= EQUAL
&& k
!= ITE
&& k
!= NOT
687 if (!d_qstate
.hasTerm(ret
))
693 Trace("term-db-eval") << "evaluated term : " << n
<< ", got : " << ret
694 << ", reqHasTerm = " << reqHasTerm
<< std::endl
;
695 // clear the explanation if failed
696 if (computeExp
&& ret
.isNull())
698 exp
.resize(prevSize
);
704 TNode
TermDb::getEntailedTerm2(TNode n
,
705 std::map
<TNode
, TNode
>& subs
,
709 Trace("term-db-entail") << "get entailed term : " << n
<< std::endl
;
710 if (d_qstate
.hasTerm(n
))
712 Trace("term-db-entail") << "...exists in ee, return rep " << std::endl
;
714 }else if( n
.getKind()==BOUND_VARIABLE
){
716 std::map
< TNode
, TNode
>::iterator it
= subs
.find( n
);
717 if( it
!=subs
.end() ){
718 Trace("term-db-entail") << "...substitution is : " << it
->second
<< std::endl
;
720 Assert(d_qstate
.hasTerm(it
->second
));
721 Assert(d_qstate
.getRepresentative(it
->second
) == it
->second
);
724 return getEntailedTerm2(it
->second
, subs
, subsRep
, hasSubs
);
727 }else if( n
.getKind()==ITE
){
728 for( unsigned i
=0; i
<2; i
++ ){
729 if (isEntailed2(n
[0], subs
, subsRep
, hasSubs
, i
== 0))
731 return getEntailedTerm2(n
[i
== 0 ? 1 : 2], subs
, subsRep
, hasSubs
);
735 if( n
.hasOperator() ){
736 TNode f
= getMatchOperator( n
);
738 std::vector
< TNode
> args
;
739 for( unsigned i
=0; i
<n
.getNumChildren(); i
++ ){
740 TNode c
= getEntailedTerm2(n
[i
], subs
, subsRep
, hasSubs
);
742 return TNode::null();
744 c
= d_qstate
.getRepresentative(c
);
745 Trace("term-db-entail") << " child " << i
<< " : " << c
<< std::endl
;
748 TNode nn
= getCongruentTerm(f
, args
);
749 Trace("term-db-entail") << " got congruent term " << nn
<< " for " << n
<< std::endl
;
754 return TNode::null();
757 Node
TermDb::evaluateTerm(TNode n
,
758 bool useEntailmentTests
,
761 std::map
< TNode
, Node
> visited
;
762 std::vector
<Node
> exp
;
763 return evaluateTerm2(n
, visited
, exp
, useEntailmentTests
, false, reqHasTerm
);
766 Node
TermDb::evaluateTerm(TNode n
,
767 std::vector
<Node
>& exp
,
768 bool useEntailmentTests
,
771 std::map
<TNode
, Node
> visited
;
772 return evaluateTerm2(n
, visited
, exp
, useEntailmentTests
, true, reqHasTerm
);
775 TNode
TermDb::getEntailedTerm(TNode n
,
776 std::map
<TNode
, TNode
>& subs
,
779 return getEntailedTerm2(n
, subs
, subsRep
, true);
782 TNode
TermDb::getEntailedTerm(TNode n
)
784 std::map
< TNode
, TNode
> subs
;
785 return getEntailedTerm2(n
, subs
, false, false);
788 bool TermDb::isEntailed2(
789 TNode n
, std::map
<TNode
, TNode
>& subs
, bool subsRep
, bool hasSubs
, bool pol
)
791 Trace("term-db-entail") << "Check entailed : " << n
<< ", pol = " << pol
<< std::endl
;
792 Assert(n
.getType().isBoolean());
793 if( n
.getKind()==EQUAL
&& !n
[0].getType().isBoolean() ){
794 TNode n1
= getEntailedTerm2(n
[0], subs
, subsRep
, hasSubs
);
796 TNode n2
= getEntailedTerm2(n
[1], subs
, subsRep
, hasSubs
);
801 Assert(d_qstate
.hasTerm(n1
));
802 Assert(d_qstate
.hasTerm(n2
));
804 return d_qstate
.areEqual(n1
, n2
);
806 return d_qstate
.areDisequal(n1
, n2
);
811 }else if( n
.getKind()==NOT
){
812 return isEntailed2(n
[0], subs
, subsRep
, hasSubs
, !pol
);
813 }else if( n
.getKind()==OR
|| n
.getKind()==AND
){
814 bool simPol
= ( pol
&& n
.getKind()==OR
) || ( !pol
&& n
.getKind()==AND
);
815 for( unsigned i
=0; i
<n
.getNumChildren(); i
++ ){
816 if (isEntailed2(n
[i
], subs
, subsRep
, hasSubs
, pol
))
828 //Boolean equality here
829 }else if( n
.getKind()==EQUAL
|| n
.getKind()==ITE
){
830 for( unsigned i
=0; i
<2; i
++ ){
831 if (isEntailed2(n
[0], subs
, subsRep
, hasSubs
, i
== 0))
833 unsigned ch
= ( n
.getKind()==EQUAL
|| i
==0 ) ? 1 : 2;
834 bool reqPol
= ( n
.getKind()==ITE
|| i
==0 ) ? pol
: !pol
;
835 return isEntailed2(n
[ch
], subs
, subsRep
, hasSubs
, reqPol
);
838 }else if( n
.getKind()==APPLY_UF
){
839 TNode n1
= getEntailedTerm2(n
, subs
, subsRep
, hasSubs
);
841 Assert(d_qstate
.hasTerm(n1
));
844 }else if( n1
==d_false
){
847 return d_qstate
.getRepresentative(n1
) == (pol
? d_true
: d_false
);
850 }else if( n
.getKind()==FORALL
&& !pol
){
851 return isEntailed2(n
[1], subs
, subsRep
, hasSubs
, pol
);
856 bool TermDb::isEntailed(TNode n
, bool pol
)
858 Assert(d_consistent_ee
);
859 std::map
< TNode
, TNode
> subs
;
860 return isEntailed2(n
, subs
, false, false, pol
);
863 bool TermDb::isEntailed(TNode n
,
864 std::map
<TNode
, TNode
>& subs
,
868 Assert(d_consistent_ee
);
869 return isEntailed2(n
, subs
, subsRep
, true, pol
);
872 bool TermDb::isTermActive( Node n
) {
873 return d_inactive_map
.find( n
)==d_inactive_map
.end();
874 //return !n.getAttribute(NoMatchAttribute());
877 void TermDb::setTermInactive( Node n
) {
878 d_inactive_map
[n
] = true;
879 //Trace("term-db-debug2") << "set no match attribute" << std::endl;
880 //NoMatchAttribute nma;
881 //n.setAttribute(nma,true);
884 bool TermDb::hasTermCurrent( Node n
, bool useMode
) {
886 return d_has_map
.find( n
)!=d_has_map
.end();
888 //some assertions are not sent to EE
889 if (options::termDbMode() == options::TermDbMode::ALL
)
893 else if (options::termDbMode() == options::TermDbMode::RELEVANT
)
895 return d_has_map
.find( n
)!=d_has_map
.end();
897 Assert(false) << "TermDb::hasTermCurrent: Unknown termDbMode : " << options::termDbMode();
901 bool TermDb::isTermEligibleForInstantiation(TNode n
, TNode f
)
903 if( options::instMaxLevel()!=-1 ){
904 if( n
.hasAttribute(InstLevelAttribute()) ){
905 int fml
= f
.isNull() ? -1 : d_quantEngine
->getQuantAttributes()->getQuantInstLevel( f
);
906 unsigned ml
= fml
>=0 ? fml
: options::instMaxLevel();
908 if( n
.getAttribute(InstLevelAttribute())>ml
){
909 Trace("inst-add-debug") << "Term " << n
<< " has instantiation level " << n
.getAttribute(InstLevelAttribute());
910 Trace("inst-add-debug") << ", which is more than maximum allowed level " << ml
<< " for this quantified formula." << std::endl
;
914 if( options::instLevelInputOnly() ){
915 Trace("inst-add-debug") << "Term " << n
<< " does not have an instantiation level." << std::endl
;
920 // it cannot have instantiation constants, which originate from
921 // counterexample-guided instantiation strategies.
922 return !TermUtil::hasInstConstAttr(n
);
925 Node
TermDb::getEligibleTermInEqc( TNode r
) {
926 if( isTermEligibleForInstantiation( r
, TNode::null() ) ){
929 std::map
< Node
, Node
>::iterator it
= d_term_elig_eqc
.find( r
);
930 if( it
==d_term_elig_eqc
.end() ){
932 eq::EqualityEngine
* ee
= d_qstate
.getEqualityEngine();
933 eq::EqClassIterator eqc_i
= eq::EqClassIterator(r
, ee
);
934 while (!eqc_i
.isFinished())
938 if (isTermEligibleForInstantiation(n
, TNode::null()))
944 d_term_elig_eqc
[r
] = h
;
952 void TermDb::setHasTerm( Node n
) {
953 Trace("term-db-debug2") << "hasTerm : " << n
<< std::endl
;
954 if( d_has_map
.find( n
)==d_has_map
.end() ){
956 for( unsigned i
=0; i
<n
.getNumChildren(); i
++ ){
962 void TermDb::presolve() {
963 if( options::incrementalSolving() ){
964 // reset the caches that are SAT context-independent but user
973 bool TermDb::reset( Theory::Effort effort
){
974 d_op_nonred_count
.clear();
976 d_func_map_trie
.clear();
977 d_func_map_eqc_trie
.clear();
978 d_func_map_rel_dom
.clear();
979 d_consistent_ee
= true;
981 eq::EqualityEngine
* ee
= d_qstate
.getEqualityEngine();
983 Assert(ee
->consistent());
984 // if higher-order, add equalities for the purification terms now
988 << "TermDb::reset : assert higher-order purify equalities..."
990 for (std::pair
<const Node
, Node
>& pp
: d_ho_purify_to_term
)
992 if (ee
->hasTerm(pp
.second
)
993 && (!ee
->hasTerm(pp
.first
) || !ee
->areEqual(pp
.second
, pp
.first
)))
996 std::map
<Node
, Node
>::iterator itpe
= d_ho_purify_to_eq
.find(pp
.first
);
997 if (itpe
== d_ho_purify_to_eq
.end())
999 eq
= Rewriter::rewrite(pp
.first
.eqNode(pp
.second
));
1000 d_ho_purify_to_eq
[pp
.first
] = eq
;
1006 Trace("quant-ho") << "- assert purify equality : " << eq
<< std::endl
;
1007 ee
->assertEquality(eq
, true, eq
);
1008 if (!ee
->consistent())
1010 // In some rare cases, purification functions (in the domain of
1011 // d_ho_purify_to_term) may escape the term database. For example,
1012 // matching algorithms may construct instantiations involving these
1013 // functions. As a result, asserting these equalities internally may
1014 // cause a conflict. In this case, we insist that the purification
1015 // equality is sent out as a lemma here.
1016 Trace("term-db-lemma")
1017 << "Purify equality lemma: " << eq
<< std::endl
;
1018 d_qim
.addPendingLemma(eq
);
1019 d_qstate
.notifyInConflict();
1020 d_consistent_ee
= false;
1028 if (options::termDbMode() == options::TermDbMode::RELEVANT
)
1031 d_term_elig_eqc
.clear();
1032 eq::EqClassesIterator eqcs_i
= eq::EqClassesIterator( ee
);
1033 while( !eqcs_i
.isFinished() ){
1034 TNode r
= (*eqcs_i
);
1035 bool addedFirst
= false;
1037 //TODO: ignoring singleton eqc isn't enough, need to ensure eqc are relevant
1038 eq::EqClassIterator eqc_i
= eq::EqClassIterator(r
, ee
);
1039 while( !eqc_i
.isFinished() ){
1041 if( first
.isNull() ){
1046 setHasTerm( first
);
1054 TheoryEngine
* te
= d_quantEngine
->getTheoryEngine();
1055 const LogicInfo
& logicInfo
= te
->getLogicInfo();
1056 for (TheoryId theoryId
= THEORY_FIRST
; theoryId
< THEORY_LAST
; ++theoryId
)
1058 if (!logicInfo
.isTheoryEnabled(theoryId
))
1062 Theory
* theory
= te
->theoryOf(theoryId
);
1063 Assert(theory
!= nullptr);
1064 for (context::CDList
<Assertion
>::const_iterator
1065 it
= theory
->facts_begin(),
1066 it_end
= theory
->facts_end();
1070 setHasTerm((*it
).d_assertion
);
1075 if( options::ufHo() && options::hoMergeTermDb() ){
1076 Trace("quant-ho") << "TermDb::reset : compute equal functions..." << std::endl
;
1077 // build operator representative map
1078 d_ho_op_rep
.clear();
1079 d_ho_op_slaves
.clear();
1080 eq::EqClassesIterator eqcs_i
= eq::EqClassesIterator( ee
);
1081 while( !eqcs_i
.isFinished() ){
1082 TNode r
= (*eqcs_i
);
1083 if( r
.getType().isFunction() ){
1084 Trace("quant-ho") << " process function eqc " << r
<< std::endl
;
1086 eq::EqClassIterator eqc_i
= eq::EqClassIterator(r
, ee
);
1087 while( !eqc_i
.isFinished() ){
1096 // use its purified variable, if it exists
1097 std::map
<Node
, Node
>::iterator itp
= d_ho_fun_op_purify
.find(n
);
1098 if (itp
!= d_ho_fun_op_purify
.end())
1100 n_use
= itp
->second
;
1103 Trace("quant-ho") << " - process " << n_use
<< ", from " << n
1105 if (!n_use
.isNull() && d_op_map
.find(n_use
) != d_op_map
.end())
1110 d_ho_op_rep
[n_use
] = n_use
;
1114 Trace("quant-ho") << " have : " << n_use
<< " == " << first
1115 << ", type = " << n_use
.getType() << std::endl
;
1116 d_ho_op_rep
[n_use
] = first
;
1117 d_ho_op_slaves
[first
].push_back(n_use
);
1125 Trace("quant-ho") << "...finished compute equal functions." << std::endl
;
1129 //rebuild d_func/pred_map_trie for each operation, this will calculate all congruent terms
1130 for( std::map< Node, std::vector< Node > >::iterator it = d_op_map.begin(); it != d_op_map.end(); ++it ){
1131 computeUfTerms( it->first );
1132 if( !d_consistent_ee ){
1140 TNodeTrie
* TermDb::getTermArgTrie(Node f
)
1142 if( options::ufHo() ){
1143 f
= getOperatorRepresentative( f
);
1145 computeUfTerms( f
);
1146 std::map
<Node
, TNodeTrie
>::iterator itut
= d_func_map_trie
.find(f
);
1147 if( itut
!=d_func_map_trie
.end() ){
1148 return &itut
->second
;
1154 TNodeTrie
* TermDb::getTermArgTrie(Node eqc
, Node f
)
1156 if( options::ufHo() ){
1157 f
= getOperatorRepresentative( f
);
1159 computeUfEqcTerms( f
);
1160 std::map
<Node
, TNodeTrie
>::iterator itut
= d_func_map_eqc_trie
.find(f
);
1161 if( itut
==d_func_map_eqc_trie
.end() ){
1165 return &itut
->second
;
1167 std::map
<TNode
, TNodeTrie
>::iterator itute
=
1168 itut
->second
.d_data
.find(eqc
);
1169 if( itute
!=itut
->second
.d_data
.end() ){
1170 return &itute
->second
;
1178 TNode
TermDb::getCongruentTerm( Node f
, Node n
) {
1179 if( options::ufHo() ){
1180 f
= getOperatorRepresentative( f
);
1182 computeUfTerms( f
);
1183 std::map
<Node
, TNodeTrie
>::iterator itut
= d_func_map_trie
.find(f
);
1184 if( itut
!=d_func_map_trie
.end() ){
1185 computeArgReps( n
);
1186 return itut
->second
.existsTerm( d_arg_reps
[n
] );
1188 return TNode::null();
1192 TNode
TermDb::getCongruentTerm( Node f
, std::vector
< TNode
>& args
) {
1193 if( options::ufHo() ){
1194 f
= getOperatorRepresentative( f
);
1196 computeUfTerms( f
);
1197 return d_func_map_trie
[f
].existsTerm( args
);
1200 Node
TermDb::getHoTypeMatchPredicate(TypeNode tn
)
1202 std::map
<TypeNode
, Node
>::iterator ithp
= d_ho_type_match_pred
.find(tn
);
1203 if (ithp
!= d_ho_type_match_pred
.end())
1205 return ithp
->second
;
1207 NodeManager
* nm
= NodeManager::currentNM();
1208 TypeNode ptn
= nm
->mkFunctionType(tn
, nm
->booleanType());
1209 Node k
= nm
->mkSkolem("U", ptn
, "predicate to force higher-order types");
1210 d_ho_type_match_pred
[tn
] = k
;
1214 }/* CVC4::theory::quantifiers namespace */
1215 }/* CVC4::theory namespace */
1216 }/* CVC4 namespace */