1 /********************* */
2 /*! \file theory_datatypes.cpp
4 ** Top contributors (to current version):
5 ** Andrew Reynolds, Morgan Deters, 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 the theory of datatypes
14 ** Implementation of the theory of datatypes.
16 #include "theory/datatypes/theory_datatypes.h"
20 #include "base/check.h"
21 #include "expr/dtype.h"
22 #include "expr/kind.h"
23 #include "options/datatypes_options.h"
24 #include "options/quantifiers_options.h"
25 #include "options/smt_options.h"
26 #include "options/theory_options.h"
27 #include "theory/datatypes/datatypes_rewriter.h"
28 #include "theory/datatypes/theory_datatypes_type_rules.h"
29 #include "theory/datatypes/theory_datatypes_utils.h"
30 #include "theory/quantifiers_engine.h"
31 #include "theory/theory_model.h"
32 #include "theory/type_enumerator.h"
33 #include "theory/valuation.h"
36 using namespace CVC4::kind
;
37 using namespace CVC4::context
;
43 TheoryDatatypes::TheoryDatatypes(Context
* c
,
47 const LogicInfo
& logicInfo
,
48 ProofNodeManager
* pnm
)
49 : Theory(THEORY_DATATYPES
, c
, u
, out
, valuation
, logicInfo
, pnm
),
59 d_collectTermsCache(c
),
60 d_collectTermsCacheU(u
),
63 d_lemmas_produced_c(u
),
64 d_sygusExtension(nullptr)
67 d_true
= NodeManager::currentNM()->mkConst( true );
68 d_zero
= NodeManager::currentNM()->mkConst( Rational(0) );
72 TheoryDatatypes::~TheoryDatatypes() {
73 for(std::map
< Node
, EqcInfo
* >::iterator i
= d_eqc_info
.begin(), iend
= d_eqc_info
.end();
75 EqcInfo
* current
= (*i
).second
;
76 Assert(current
!= NULL
);
81 TheoryRewriter
* TheoryDatatypes::getTheoryRewriter() { return &d_rewriter
; }
83 bool TheoryDatatypes::needsEqualityEngine(EeSetupInfo
& esi
)
85 esi
.d_notify
= &d_notify
;
86 esi
.d_name
= "theory::datatypes::ee";
90 void TheoryDatatypes::finishInit()
92 Assert(d_equalityEngine
!= nullptr);
93 // The kinds we are treating as function application in congruence
94 d_equalityEngine
->addFunctionKind(kind::APPLY_CONSTRUCTOR
);
95 d_equalityEngine
->addFunctionKind(kind::APPLY_SELECTOR_TOTAL
);
96 d_equalityEngine
->addFunctionKind(kind::APPLY_TESTER
);
97 // We could but don't do congruence for DT_SIZE and DT_HEIGHT_BOUND here.
98 // It also could make sense in practice to do congruence for APPLY_UF, but
100 if (getQuantifiersEngine() && options::sygus())
102 d_sygusExtension
.reset(
103 new SygusExtension(this, getQuantifiersEngine(), getSatContext()));
104 // do congruence on evaluation functions
105 d_equalityEngine
->addFunctionKind(kind::DT_SYGUS_EVAL
);
109 TheoryDatatypes::EqcInfo
* TheoryDatatypes::getOrMakeEqcInfo( TNode n
, bool doMake
){
110 if( !hasEqcInfo( n
) ){
115 std::map
< Node
, EqcInfo
* >::iterator eqc_i
= d_eqc_info
.find( n
);
117 if( eqc_i
!= d_eqc_info
.end() ){
120 ei
= new EqcInfo( getSatContext() );
123 if( n
.getKind()==APPLY_CONSTRUCTOR
){
124 ei
->d_constructor
= n
;
128 d_selector_apps
[n
] = 0;
135 std::map
< Node
, EqcInfo
* >::iterator eqc_i
= d_eqc_info
.find( n
);
136 return (*eqc_i
).second
;
140 TNode
TheoryDatatypes::getEqcConstructor( TNode r
) {
141 if( r
.getKind()==APPLY_CONSTRUCTOR
){
144 EqcInfo
* ei
= getOrMakeEqcInfo( r
, false );
145 if( ei
&& !ei
->d_constructor
.get().isNull() ){
146 return ei
->d_constructor
.get();
153 void TheoryDatatypes::check(Effort e
) {
154 if (done() && e
<EFFORT_FULL
) {
157 Assert(d_pending
.empty() && d_pending_merge
.empty());
158 d_addedLemma
= false;
160 if( e
== EFFORT_LAST_CALL
){
161 Assert(d_sygusExtension
!= nullptr);
162 std::vector
< Node
> lemmas
;
163 d_sygusExtension
->check(lemmas
);
164 doSendLemmas( lemmas
);
168 TimerStat::CodeTimer
checkTimer(d_checkTime
);
170 Trace("datatypes-check") << "Check effort " << e
<< std::endl
;
171 while(!done() && !d_conflict
) {
172 // Get all the assertions
173 Assertion assertion
= get();
174 TNode fact
= assertion
.d_assertion
;
175 Trace("datatypes-assert") << "Assert " << fact
<< std::endl
;
177 TNode atom CVC4_UNUSED
= fact
.getKind() == kind::NOT
? fact
[0] : fact
;
179 // extra debug check to make sure that the rewriter did its job correctly
180 Assert(atom
.getKind() != kind::EQUAL
181 || (atom
[0].getKind() != kind::TUPLE_UPDATE
182 && atom
[1].getKind() != kind::TUPLE_UPDATE
183 && atom
[0].getKind() != kind::RECORD_UPDATE
184 && atom
[1].getKind() != kind::RECORD_UPDATE
))
185 << "tuple/record escaped into datatypes decision procedure; should "
186 "have been rewritten away";
189 assertFact( fact
, fact
);
193 if( e
== EFFORT_FULL
&& !d_conflict
&& !d_addedLemma
&& !d_valuation
.needCheck() ) {
195 Assert(d_pending
.empty() && d_pending_merge
.empty());
198 Trace("datatypes-proc") << "Check cycles..." << std::endl
;
200 Trace("datatypes-proc") << "...finish check cycles" << std::endl
;
202 if( d_conflict
|| d_addedLemma
){
205 }while( d_addedFact
);
208 Trace("datatypes-debug") << "Check for splits " << e
<< endl
;
211 std::map
< TypeNode
, Node
> rec_singletons
;
212 eq::EqClassesIterator eqcs_i
= eq::EqClassesIterator(d_equalityEngine
);
213 while( !eqcs_i
.isFinished() ){
215 //TODO : avoid irrelevant (pre-registered but not asserted) terms here?
216 TypeNode tn
= n
.getType();
217 if( tn
.isDatatype() ){
218 Trace("datatypes-debug") << "Process equivalence class " << n
<< std::endl
;
219 EqcInfo
* eqc
= getOrMakeEqcInfo( n
);
220 //if there are more than 1 possible constructors for eqc
221 if( !hasLabel( eqc
, n
) ){
222 Trace("datatypes-debug") << "No constructor..." << std::endl
;
224 const DType
& dt
= tt
.getDType();
225 Trace("datatypes-debug")
226 << "Datatype " << dt
.getName() << " is "
227 << dt
.isInterpretedFinite(tt
) << " "
228 << dt
.isRecursiveSingleton(tt
) << std::endl
;
229 bool continueProc
= true;
230 if( dt
.isRecursiveSingleton( tt
) ){
231 Trace("datatypes-debug") << "Check recursive singleton..." << std::endl
;
232 //handle recursive singleton case
233 std::map
< TypeNode
, Node
>::iterator itrs
= rec_singletons
.find( tn
);
234 if( itrs
!=rec_singletons
.end() ){
235 Node eq
= n
.eqNode( itrs
->second
);
236 if( d_singleton_eq
.find( eq
)==d_singleton_eq
.end() ){
237 d_singleton_eq
[eq
] = true;
240 std::vector
< Node
> assumptions
;
241 //if there is at least one uninterpreted sort occurring within the datatype and the logic is not quantified, add lemmas ensuring cardinality is more than one,
242 // do not infer the equality if at least one sort was processed.
243 //otherwise, if the logic is quantified, under the assumption that all uninterpreted sorts have cardinality one,
244 // infer the equality.
245 for( unsigned i
=0; i
<dt
.getNumRecursiveSingletonArgTypes( tt
); i
++ ){
246 TypeNode type
= dt
.getRecursiveSingletonArgType(tt
, i
);
247 if( getQuantifiersEngine() ){
248 // under the assumption that the cardinality of this type is one
249 Node a
= getSingletonLemma(type
, true);
250 assumptions
.push_back( a
.negate() );
253 // assert that the cardinality of this type is more than one
254 getSingletonLemma(type
, false);
258 Node assumption
= n
.eqNode(itrs
->second
);
259 assumptions
.push_back(assumption
);
260 Node lemma
= assumptions
.size()==1 ? assumptions
[0] : NodeManager::currentNM()->mkNode( OR
, assumptions
);
261 Trace("dt-singleton") << "*************Singleton equality lemma " << lemma
<< std::endl
;
262 doSendLemma( lemma
);
266 rec_singletons
[tn
] = n
;
268 //do splitting for quantified logics (incomplete anyways)
269 continueProc
= ( getQuantifiersEngine()!=NULL
);
272 Trace("datatypes-debug") << "Get possible cons..." << std::endl
;
274 std::vector
< bool > pcons
;
275 getPossibleCons( eqc
, n
, pcons
);
276 //std::map< int, bool > sel_apps;
277 //getSelectorsForCons( n, sel_apps );
278 //check if we do not need to resolve the constructor type for this equivalence class.
279 // this is if there are no selectors for this equivalence class, and its possible values are infinite,
280 // then do not split.
283 bool needSplit
= true;
284 for( unsigned int j
=0; j
<pcons
.size(); j
++ ) {
289 Trace("datatypes-debug") << j
<< " compute finite..."
291 bool ifin
= dt
[j
].isInterpretedFinite(tt
);
292 Trace("datatypes-debug") << "...returned " << ifin
296 if( !eqc
|| !eqc
->d_selectors
){
300 if( fconsIndex
==-1 ){
306 //if we want to force an assignment of constructors to all ground eqc
308 if( !needSplit
&& options::dtForceAssignment() && d_dtfCounter
%2==0 ){
309 Trace("datatypes-force-assign") << "Force assignment for " << n
<< std::endl
;
311 consIndex
= fconsIndex
!=-1 ? fconsIndex
: consIndex
;
315 if( dt
.getNumConstructors()==1 ){
316 //this may not be necessary?
317 //if only one constructor, then this term must be this constructor
318 Node t
= utils::mkTester(n
, 0, dt
);
319 d_pending
.push_back( t
);
320 d_pending_exp
[ t
] = d_true
;
321 Trace("datatypes-infer") << "DtInfer : 1-cons (full) : " << t
<< std::endl
;
322 d_infer
.push_back( t
);
324 Assert(consIndex
!= -1 || dt
.isSygus());
325 if( options::dtBinarySplit() && consIndex
!=-1 ){
326 Node test
= utils::mkTester(n
, consIndex
, dt
);
327 Trace("dt-split") << "*************Split for possible constructor " << dt
[consIndex
] << " for " << n
<< endl
;
328 test
= Rewriter::rewrite( test
);
329 NodeBuilder
<> nb(kind::OR
);
330 nb
<< test
<< test
.notNode();
332 doSendLemma( lemma
);
333 d_out
->requirePhase( test
, true );
335 Trace("dt-split") << "*************Split for constructors on " << n
<< endl
;
336 Node lemma
= utils::mkSplit(n
, dt
);
337 Trace("dt-split-debug") << "Split lemma is : " << lemma
<< std::endl
;
338 d_out
->lemma(lemma
, LemmaProperty::SEND_ATOMS
);
341 if( !options::dtBlastSplits() ){
346 Trace("dt-split-debug") << "Do not split constructor for " << n
<< " : " << n
.getType() << " " << dt
.getNumConstructors() << std::endl
;
350 Trace("datatypes-debug") << "Has constructor " << eqc
->d_constructor
.get() << std::endl
;
357 // clear pending facts: we added a lemma, so internal inferences are
358 // no longer necessary
360 d_pending_exp
.clear();
364 // we did not add a lemma, process internal inferences. This loop
366 Trace("datatypes-debug") << "Flush pending facts..." << std::endl
;
371 if( options::dtRewriteErrorSel() ){
372 bool innerAddedFact = false;
375 innerAddedFact = !d_pending.empty() || !d_pending_merge.empty();
377 }while( !d_conflict && innerAddedFact );
381 }while( !d_conflict
&& !d_addedLemma
&& d_addedFact
);
382 Trace("datatypes-debug") << "Finished, conflict=" << d_conflict
<< ", lemmas=" << d_addedLemma
<< std::endl
;
384 Trace("dt-model-debug") << std::endl
;
385 printModelDebug("dt-model-debug");
389 Trace("datatypes-check") << "Finished check effort " << e
<< std::endl
;
390 if( Debug
.isOn("datatypes") || Debug
.isOn("datatypes-split") ) {
391 Notice() << "TheoryDatatypes::check(): done" << endl
;
395 bool TheoryDatatypes::needsCheckLastEffort() {
396 return d_sygusExtension
!= nullptr;
399 void TheoryDatatypes::flushPendingFacts(){
401 //pending lemmas: used infrequently, only for definitional lemmas
402 if( !d_pending_lem
.empty() ){
404 while( i
<(int)d_pending_lem
.size() ){
405 doSendLemma( d_pending_lem
[i
] );
408 d_pending_lem
.clear();
412 while( !d_conflict
&& i
<(int)d_pending
.size() ){
413 Node fact
= d_pending
[i
];
414 Node exp
= d_pending_exp
[ fact
];
415 Trace("datatypes-debug") << "Assert fact (#" << (i
+1) << "/" << d_pending
.size() << ") " << fact
<< " with explanation " << exp
<< std::endl
;
416 //check to see if we have to communicate it to the rest of the system
417 if( mustCommunicateFact( fact
, exp
) ){
419 if( exp
.isNull() || exp
==d_true
){
420 Trace("dt-lemma-debug") << "Trivial explanation." << std::endl
;
422 Trace("dt-lemma-debug") << "Get explanation..." << std::endl
;
423 std::vector
< TNode
> assumptions
;
424 //if( options::dtRExplainLemmas() ){
425 explain( exp
, assumptions
);
429 //Trace("dt-lemma-debug") << "Explanation : " << ee_exp << std::endl;
430 if( assumptions
.empty() ){
433 std::vector
< Node
> children
;
434 for (const TNode
& assumption
: assumptions
)
436 children
.push_back(assumption
.negate());
438 children
.push_back( fact
);
439 lem
= NodeManager::currentNM()->mkNode( OR
, children
);
442 Trace("dt-lemma") << "Datatypes lemma : " << lem
<< std::endl
;
445 assertFact( fact
, exp
);
448 Trace("datatypes-debug") << "Finished fact " << fact
<< ", now = " << d_conflict
<< " " << d_pending
.size() << std::endl
;
452 d_pending_exp
.clear();
455 void TheoryDatatypes::doPendingMerges(){
457 //do all pending merges
459 while( i
<(int)d_pending_merge
.size() ){
460 Assert(d_pending_merge
[i
].getKind() == EQUAL
);
461 merge( d_pending_merge
[i
][0], d_pending_merge
[i
][1] );
465 d_pending_merge
.clear();
468 bool TheoryDatatypes::doSendLemma( Node lem
) {
469 if( d_lemmas_produced_c
.find( lem
)==d_lemmas_produced_c
.end() ){
470 Trace("dt-lemma-send") << "TheoryDatatypes::doSendLemma : " << lem
<< std::endl
;
471 d_lemmas_produced_c
[lem
] = true;
476 Trace("dt-lemma-send") << "TheoryDatatypes::doSendLemma : duplicate : "
481 bool TheoryDatatypes::doSendLemmas( std::vector
< Node
>& lemmas
){
483 for (const Node
& lem
: lemmas
)
485 bool cret
= doSendLemma(lem
);
492 void TheoryDatatypes::assertFact( Node fact
, Node exp
){
493 Assert(d_pending_merge
.empty());
494 Trace("datatypes-debug") << "TheoryDatatypes::assertFact : " << fact
<< std::endl
;
495 bool polarity
= fact
.getKind() != kind::NOT
;
496 TNode atom
= polarity
? fact
: fact
[0];
497 if (atom
.getKind() == kind::EQUAL
) {
498 d_equalityEngine
->assertEquality(atom
, polarity
, exp
);
500 d_equalityEngine
->assertPredicate(atom
, polarity
, exp
);
503 // could be sygus-specific
504 if (d_sygusExtension
)
506 std::vector
< Node
> lemmas
;
507 d_sygusExtension
->assertFact(atom
, polarity
, lemmas
);
508 doSendLemmas( lemmas
);
510 //add to tester if applicable
512 int tindex
= utils::isTester(atom
, t_arg
);
515 Trace("dt-tester") << "Assert tester : " << atom
<< " for " << t_arg
<< std::endl
;
516 Node rep
= getRepresentative( t_arg
);
517 EqcInfo
* eqc
= getOrMakeEqcInfo( rep
, true );
518 addTester( tindex
, fact
, eqc
, rep
, t_arg
);
519 Trace("dt-tester") << "Done assert tester." << std::endl
;
522 Trace("dt-tester") << "Done pending merges." << std::endl
;
523 if( !d_conflict
&& polarity
){
524 if (d_sygusExtension
)
526 Trace("dt-tester") << "Assert tester to sygus : " << atom
<< std::endl
;
527 //Assert( !d_sygus_util->d_conflict );
528 std::vector
< Node
> lemmas
;
529 d_sygusExtension
->assertTester(tindex
, t_arg
, atom
, lemmas
);
530 Trace("dt-tester") << "Done assert tester to sygus." << std::endl
;
531 doSendLemmas( lemmas
);
535 Trace("dt-tester-debug") << "Assert (non-tester) : " << atom
<< std::endl
;
537 Trace("datatypes-debug") << "TheoryDatatypes::assertFact : finished " << fact
<< std::endl
;
540 void TheoryDatatypes::preRegisterTerm(TNode n
) {
541 Debug("datatypes-prereg") << "TheoryDatatypes::preRegisterTerm() " << n
<< endl
;
543 switch (n
.getKind()) {
545 // Add the trigger for equality
546 d_equalityEngine
->addTriggerEquality(n
);
548 case kind::APPLY_TESTER
:
549 // Get triggered for both equal and dis-equal
550 d_equalityEngine
->addTriggerPredicate(n
);
553 // Function applications/predicates
554 d_equalityEngine
->addTerm(n
);
555 if (d_sygusExtension
)
557 std::vector
< Node
> lemmas
;
558 d_sygusExtension
->preRegisterTerm(n
, lemmas
);
559 doSendLemmas( lemmas
);
561 // d_equalityEngine->addTriggerTerm(n, THEORY_DATATYPES);
567 TrustNode
TheoryDatatypes::expandDefinition(Node n
)
569 NodeManager
* nm
= NodeManager::currentNM();
570 // must ensure the type is well founded and has no nested recursion if
571 // the option dtNestedRec is not set to true.
572 TypeNode tn
= n
.getType();
575 const DType
& dt
= tn
.getDType();
576 if (!dt
.isWellFounded())
578 std::stringstream ss
;
579 ss
<< "Cannot handle non-well-founded datatype " << dt
.getName();
580 throw LogicException(ss
.str());
582 if (!options::dtNestedRec())
584 if (dt
.hasNestedRecursion())
586 std::stringstream ss
;
587 ss
<< "Cannot handle nested-recursive datatype " << dt
.getName();
588 throw LogicException(ss
.str());
595 case kind::APPLY_SELECTOR
:
597 Node selector
= n
.getOperator();
598 // APPLY_SELECTOR always applies to an external selector, cindexOf is
600 size_t cindex
= utils::cindexOf(selector
);
601 const DType
& dt
= utils::datatypeOf(selector
);
602 const DTypeConstructor
& c
= dt
[cindex
];
604 TypeNode ndt
= n
[0].getType();
605 if (options::dtSharedSelectors())
607 size_t selectorIndex
= utils::indexOf(selector
);
608 Trace("dt-expand") << "...selector index = " << selectorIndex
610 Assert(selectorIndex
< c
.getNumArgs());
611 selector_use
= c
.getSelectorInternal(ndt
, selectorIndex
);
613 selector_use
= selector
;
615 Node sel
= nm
->mkNode(kind::APPLY_SELECTOR_TOTAL
, selector_use
, n
[0]);
616 if (options::dtRewriteErrorSel())
622 Node tester
= c
.getTester();
623 Node tst
= nm
->mkNode(APPLY_TESTER
, tester
, n
[0]);
624 tst
= Rewriter::rewrite(tst
);
629 mkExpDefSkolem(selector
, ndt
, n
.getType());
631 nm
->mkNode(kind::APPLY_UF
, d_exp_def_skolem
[ndt
][selector
], n
[0]);
632 if (tst
== nm
->mkConst(false))
638 ret
= nm
->mkNode(kind::ITE
, tst
, sel
, sk
);
641 Trace("dt-expand") << "Expand def : " << n
<< " to " << ret
649 Assert(tn
.isDatatype());
650 const DType
& dt
= tn
.getDType();
651 NodeBuilder
<> b(APPLY_CONSTRUCTOR
);
652 b
<< dt
[0].getConstructor();
653 size_t size
, updateIndex
;
654 if (n
.getKind() == TUPLE_UPDATE
)
656 Assert(tn
.isTuple());
657 size
= tn
.getTupleLength();
658 updateIndex
= n
.getOperator().getConst
<TupleUpdate
>().getIndex();
662 Assert(tn
.isRecord());
663 const DTypeConstructor
& recCons
= dt
[0];
664 size
= recCons
.getNumArgs();
665 // get the index for the name
666 updateIndex
= recCons
.getSelectorIndexForName(
667 n
.getOperator().getConst
<RecordUpdate
>().getField());
669 Debug("tuprec") << "expr is " << n
<< std::endl
;
670 Debug("tuprec") << "updateIndex is " << updateIndex
<< std::endl
;
671 Debug("tuprec") << "t is " << tn
<< std::endl
;
672 Debug("tuprec") << "t has arity " << size
<< std::endl
;
673 for (size_t i
= 0; i
< size
; ++i
)
675 if (i
== updateIndex
)
678 Debug("tuprec") << "arg " << i
<< " gets updated to " << n
[1]
684 APPLY_SELECTOR_TOTAL
, dt
[0].getSelectorInternal(tn
, i
), n
[0]);
685 Debug("tuprec") << "arg " << i
<< " copies "
686 << b
[b
.getNumChildren() - 1] << std::endl
;
690 Debug("tuprec") << "return " << ret
<< std::endl
;
695 if (!ret
.isNull() && n
!= ret
)
697 return TrustNode::mkTrustRewrite(n
, ret
, nullptr);
699 return TrustNode::null();
702 void TheoryDatatypes::presolve()
704 Debug("datatypes") << "TheoryDatatypes::presolve()" << endl
;
707 TrustNode
TheoryDatatypes::ppRewrite(TNode in
)
709 Debug("tuprec") << "TheoryDatatypes::ppRewrite(" << in
<< ")" << endl
;
711 if( in
.getKind()==EQUAL
){
713 std::vector
< Node
> rew
;
714 if (utils::checkClash(in
[0], in
[1], rew
))
716 nn
= NodeManager::currentNM()->mkConst(false);
720 nn
= rew
.size()==0 ? d_true
:
721 ( rew
.size()==1 ? rew
[0] : NodeManager::currentNM()->mkNode( kind::AND
, rew
) );
725 return TrustNode::mkTrustRewrite(in
, nn
, nullptr);
730 return TrustNode::null();
733 void TheoryDatatypes::addSharedTerm(TNode t
) {
734 Debug("datatypes") << "TheoryDatatypes::addSharedTerm(): "
735 << t
<< " " << t
.getType().isBoolean() << endl
;
736 d_equalityEngine
->addTriggerTerm(t
, THEORY_DATATYPES
);
737 Debug("datatypes") << "TheoryDatatypes::addSharedTerm() finished" << std::endl
;
741 void TheoryDatatypes::propagate(Effort effort
){
746 bool TheoryDatatypes::propagate(TNode literal
){
747 Debug("dt::propagate") << "TheoryDatatypes::propagate(" << literal
<< ")" << std::endl
;
748 // If already in conflict, no more propagation
750 Debug("dt::propagate") << "TheoryDatatypes::propagate(" << literal
<< "): already in conflict" << std::endl
;
753 Trace("dt-prop") << "dtPropagate " << literal
<< std::endl
;
755 bool ok
= d_out
->propagate(literal
);
757 Trace("dt-conflict") << "CONFLICT: Eq engine propagate conflict " << std::endl
;
763 void TheoryDatatypes::addAssumptions( std::vector
<TNode
>& assumptions
, std::vector
<TNode
>& tassumptions
) {
764 std::vector
<TNode
> ntassumptions
;
765 for( unsigned i
=0; i
<tassumptions
.size(); i
++ ){
767 if( tassumptions
[i
].getKind()==AND
){
768 for( unsigned j
=0; j
<tassumptions
[i
].getNumChildren(); j
++ ){
769 explain( tassumptions
[i
][j
], ntassumptions
);
772 if( std::find( assumptions
.begin(), assumptions
.end(), tassumptions
[i
] )==assumptions
.end() ){
773 assumptions
.push_back( tassumptions
[i
] );
777 if( !ntassumptions
.empty() ){
778 addAssumptions( assumptions
, ntassumptions
);
782 void TheoryDatatypes::explainEquality( TNode a
, TNode b
, bool polarity
, std::vector
<TNode
>& assumptions
) {
784 std::vector
<TNode
> tassumptions
;
785 d_equalityEngine
->explainEquality(a
, b
, polarity
, tassumptions
);
786 addAssumptions( assumptions
, tassumptions
);
790 void TheoryDatatypes::explainPredicate( TNode p
, bool polarity
, std::vector
<TNode
>& assumptions
) {
791 std::vector
<TNode
> tassumptions
;
792 d_equalityEngine
->explainPredicate(p
, polarity
, tassumptions
);
793 addAssumptions( assumptions
, tassumptions
);
797 void TheoryDatatypes::explain(TNode literal
, std::vector
<TNode
>& assumptions
){
798 Debug("datatypes-explain") << "Explain " << literal
<< std::endl
;
799 bool polarity
= literal
.getKind() != kind::NOT
;
800 TNode atom
= polarity
? literal
: literal
[0];
801 if (atom
.getKind() == kind::EQUAL
) {
802 explainEquality( atom
[0], atom
[1], polarity
, assumptions
);
803 } else if( atom
.getKind() == kind::AND
&& polarity
){
804 for( unsigned i
=0; i
<atom
.getNumChildren(); i
++ ){
805 explain( atom
[i
], assumptions
);
808 Assert(atom
.getKind() != kind::AND
);
809 explainPredicate( atom
, polarity
, assumptions
);
813 TrustNode
TheoryDatatypes::explain(TNode literal
)
815 Node exp
= explainLit(literal
);
816 return TrustNode::mkTrustPropExp(literal
, exp
, nullptr);
819 Node
TheoryDatatypes::explainLit(TNode literal
)
821 std::vector
< TNode
> assumptions
;
822 explain( literal
, assumptions
);
823 return mkAnd( assumptions
);
826 Node
TheoryDatatypes::explain( std::vector
< Node
>& lits
) {
827 std::vector
< TNode
> assumptions
;
828 for( unsigned i
=0; i
<lits
.size(); i
++ ){
829 explain( lits
[i
], assumptions
);
831 return mkAnd( assumptions
);
834 /** Conflict when merging two constants */
835 void TheoryDatatypes::conflict(TNode a
, TNode b
){
836 Node eq
= a
.eqNode(b
);
837 d_conflictNode
= explainLit(eq
);
838 Trace("dt-conflict") << "CONFLICT: Eq engine conflict : " << d_conflictNode
<< std::endl
;
839 d_out
->conflict( d_conflictNode
);
843 /** called when a new equivalance class is created */
844 void TheoryDatatypes::eqNotifyNewClass(TNode t
){
845 if( t
.getKind()==APPLY_CONSTRUCTOR
){
846 getOrMakeEqcInfo( t
, true );
850 /** called when two equivalance classes have merged */
851 void TheoryDatatypes::eqNotifyMerge(TNode t1
, TNode t2
)
853 if( t1
.getType().isDatatype() ){
854 Trace("datatypes-debug")
855 << "NotifyMerge : " << t1
<< " " << t2
<< std::endl
;
856 d_pending_merge
.push_back( t1
.eqNode( t2
) );
860 void TheoryDatatypes::merge( Node t1
, Node t2
){
864 Trace("datatypes-debug") << "Merge " << t1
<< " " << t2
<< std::endl
;
865 EqcInfo
* eqc2
= getOrMakeEqcInfo( t2
);
867 bool checkInst
= false;
868 if( !eqc2
->d_constructor
.get().isNull() ){
869 trep2
= eqc2
->d_constructor
.get();
871 EqcInfo
* eqc1
= getOrMakeEqcInfo( t1
);
873 Trace("datatypes-debug") << " merge eqc info " << eqc2
<< " into " << eqc1
<< std::endl
;
874 if( !eqc1
->d_constructor
.get().isNull() ){
875 trep1
= eqc1
->d_constructor
.get();
878 TNode cons1
= eqc1
->d_constructor
.get();
879 TNode cons2
= eqc2
->d_constructor
.get();
880 //if both have constructor, then either clash or unification
881 if( !cons1
.isNull() && !cons2
.isNull() ){
882 Trace("datatypes-debug") << " constructors : " << cons1
<< " " << cons2
<< std::endl
;
883 Node unifEq
= cons1
.eqNode( cons2
);
884 std::vector
< Node
> rew
;
885 if (utils::checkClash(cons1
, cons2
, rew
))
887 d_conflictNode
= explainLit(unifEq
);
888 Trace("dt-conflict") << "CONFLICT: Clash conflict : " << d_conflictNode
<< std::endl
;
889 d_out
->conflict( d_conflictNode
);
896 for( int i
=0; i
<(int)cons1
.getNumChildren(); i
++ ) {
897 if( !areEqual( cons1
[i
], cons2
[i
] ) ){
898 Node eq
= cons1
[i
].eqNode( cons2
[i
] );
899 d_pending
.push_back( eq
);
900 d_pending_exp
[ eq
] = unifEq
;
901 Trace("datatypes-infer") << "DtInfer : cons-inj : " << eq
<< " by " << unifEq
<< std::endl
;
902 d_infer
.push_back( eq
);
903 d_infer_exp
.push_back( unifEq
);
907 for( unsigned i=0; i<rew.size(); i++ ){
908 d_pending.push_back( rew[i] );
909 d_pending_exp[ rew[i] ] = unifEq;
910 Trace("datatypes-infer") << "DtInfer : cons-inj : " << rew[i] << " by " << unifEq << std::endl;
911 d_infer.push_back( rew[i] );
912 d_infer_exp.push_back( unifEq );
917 Trace("datatypes-debug") << " instantiated : " << eqc1
->d_inst
<< " " << eqc2
->d_inst
<< std::endl
;
918 eqc1
->d_inst
= eqc1
->d_inst
|| eqc2
->d_inst
;
919 if( !cons2
.isNull() ){
920 if( cons1
.isNull() ){
921 Trace("datatypes-debug") << " must check if it is okay to set the constructor." << std::endl
;
923 addConstructor( eqc2
->d_constructor
.get(), eqc1
, t1
);
930 Trace("datatypes-debug") << " no eqc info for " << t1
<< ", must create" << std::endl
;
931 //just copy the equivalence class information
932 eqc1
= getOrMakeEqcInfo( t1
, true );
933 eqc1
->d_inst
.set( eqc2
->d_inst
);
934 eqc1
->d_constructor
.set( eqc2
->d_constructor
);
935 eqc1
->d_selectors
.set( eqc2
->d_selectors
);
940 NodeUIntMap::iterator lbl_i
= d_labels
.find(t2
);
941 if( lbl_i
!= d_labels
.end() ){
942 Trace("datatypes-debug") << " merge labels from " << eqc2
<< " " << t2
<< std::endl
;
943 size_t n_label
= (*lbl_i
).second
;
944 for (size_t i
= 0; i
< n_label
; i
++)
946 Assert(i
< d_labels_data
[t2
].size());
947 Node t
= d_labels_data
[ t2
][i
];
948 Node t_arg
= d_labels_args
[t2
][i
];
949 unsigned tindex
= d_labels_tindex
[t2
][i
];
950 addTester( tindex
, t
, eqc1
, t1
, t_arg
);
952 Trace("datatypes-debug") << " conflict!" << std::endl
;
959 if( !eqc1
->d_selectors
&& eqc2
->d_selectors
){
960 eqc1
->d_selectors
= true;
963 NodeUIntMap::iterator sel_i
= d_selector_apps
.find(t2
);
964 if( sel_i
!= d_selector_apps
.end() ){
965 Trace("datatypes-debug") << " merge selectors from " << eqc2
<< " " << t2
<< std::endl
;
966 size_t n_sel
= (*sel_i
).second
;
967 for (size_t j
= 0; j
< n_sel
; j
++)
969 addSelector( d_selector_apps_data
[t2
][j
], eqc1
, t1
, eqc2
->d_constructor
.get().isNull() );
973 Trace("datatypes-debug") << " checking instantiate" << std::endl
;
974 instantiate( eqc1
, t1
);
980 Trace("datatypes-debug") << "Finished Merge " << t1
<< " " << t2
<< std::endl
;
984 TheoryDatatypes::EqcInfo::EqcInfo( context::Context
* c
)
986 , d_constructor( c
, Node::null() )
987 , d_selectors( c
, false )
990 bool TheoryDatatypes::hasLabel( EqcInfo
* eqc
, Node n
){
991 return ( eqc
&& !eqc
->d_constructor
.get().isNull() ) || !getLabel( n
).isNull();
994 Node
TheoryDatatypes::getLabel( Node n
) {
995 NodeUIntMap::iterator lbl_i
= d_labels
.find(n
);
996 if( lbl_i
!= d_labels
.end() ){
997 size_t n_lbl
= (*lbl_i
).second
;
998 if( n_lbl
>0 && d_labels_data
[n
][ n_lbl
-1 ].getKind()!=kind::NOT
){
999 return d_labels_data
[n
][ n_lbl
-1 ];
1002 return Node::null();
1005 int TheoryDatatypes::getLabelIndex( EqcInfo
* eqc
, Node n
){
1006 if( eqc
&& !eqc
->d_constructor
.get().isNull() ){
1007 return utils::indexOf(eqc
->d_constructor
.get().getOperator());
1009 Node lbl
= getLabel( n
);
1013 int tindex
= utils::isTester(lbl
);
1014 Assert(tindex
!= -1);
1020 bool TheoryDatatypes::hasTester( Node n
) {
1021 NodeUIntMap::iterator lbl_i
= d_labels
.find(n
);
1022 if( lbl_i
!= d_labels
.end() ){
1023 return (*lbl_i
).second
>0;
1029 void TheoryDatatypes::getPossibleCons( EqcInfo
* eqc
, Node n
, std::vector
< bool >& pcons
){
1030 TypeNode tn
= n
.getType();
1031 const DType
& dt
= tn
.getDType();
1032 int lindex
= getLabelIndex( eqc
, n
);
1033 pcons
.resize( dt
.getNumConstructors(), lindex
==-1 );
1035 pcons
[ lindex
] = true;
1037 NodeUIntMap::iterator lbl_i
= d_labels
.find(n
);
1038 if( lbl_i
!= d_labels
.end() ){
1039 size_t n_lbl
= (*lbl_i
).second
;
1040 for (size_t i
= 0; i
< n_lbl
; i
++)
1042 Assert(d_labels_data
[n
][i
].getKind() == NOT
);
1043 unsigned tindex
= d_labels_tindex
[n
][i
];
1044 pcons
[ tindex
] = false;
1050 void TheoryDatatypes::mkExpDefSkolem( Node sel
, TypeNode dt
, TypeNode rt
) {
1051 if( d_exp_def_skolem
[dt
].find( sel
)==d_exp_def_skolem
[dt
].end() ){
1052 std::stringstream ss
;
1054 d_exp_def_skolem
[dt
][ sel
] = NodeManager::currentNM()->mkSkolem( ss
.str().c_str(),
1055 NodeManager::currentNM()->mkFunctionType( dt
, rt
) );
1059 Node
TheoryDatatypes::getTermSkolemFor( Node n
) {
1060 if( n
.getKind()==APPLY_CONSTRUCTOR
){
1061 NodeMap::const_iterator it
= d_term_sk
.find( n
);
1062 if( it
==d_term_sk
.end() ){
1063 //add purification unit lemma ( k = n )
1064 Node k
= NodeManager::currentNM()->mkSkolem( "k", n
.getType(), "reference skolem for datatypes" );
1066 Node eq
= k
.eqNode( n
);
1067 Trace("datatypes-infer") << "DtInfer : ref : " << eq
<< std::endl
;
1068 d_pending_lem
.push_back( eq
);
1069 //doSendLemma( eq );
1070 //d_pending_exp[ eq ] = d_true;
1073 return (*it
).second
;
1080 void TheoryDatatypes::addTester(
1081 unsigned ttindex
, Node t
, EqcInfo
* eqc
, Node n
, Node t_arg
)
1083 Trace("datatypes-debug") << "Add tester : " << t
<< " to eqc(" << n
<< ")" << std::endl
;
1084 Debug("datatypes-labels") << "Add tester " << t
<< " " << n
<< " " << eqc
<< std::endl
;
1085 bool tpolarity
= t
.getKind()!=NOT
;
1087 bool makeConflict
= false;
1088 int prevTIndex
= getLabelIndex(eqc
, n
);
1089 if (prevTIndex
>= 0)
1091 unsigned ptu
= static_cast<unsigned>(prevTIndex
);
1092 //if we already know the constructor type, check whether it is in conflict or redundant
1093 if ((ptu
== ttindex
) != tpolarity
)
1095 if( !eqc
->d_constructor
.get().isNull() ){
1096 //conflict because equivalence class contains a constructor
1097 std::vector
< TNode
> assumptions
;
1098 explain( t
, assumptions
);
1099 explainEquality( eqc
->d_constructor
.get(), t_arg
, true, assumptions
);
1100 d_conflictNode
= mkAnd( assumptions
);
1101 Trace("dt-conflict") << "CONFLICT: Tester eq conflict : " << d_conflictNode
<< std::endl
;
1102 d_out
->conflict( d_conflictNode
);
1106 makeConflict
= true;
1107 //conflict because the existing label is contradictory
1115 //otherwise, scan list of labels
1116 NodeUIntMap::iterator lbl_i
= d_labels
.find(n
);
1117 Assert(lbl_i
!= d_labels
.end());
1118 size_t n_lbl
= (*lbl_i
).second
;
1119 std::map
< int, bool > neg_testers
;
1120 for (size_t i
= 0; i
< n_lbl
; i
++)
1122 Assert(d_labels_data
[n
][i
].getKind() == NOT
);
1123 unsigned jtindex
= d_labels_tindex
[n
][i
];
1124 if( jtindex
==ttindex
){
1125 if( tpolarity
){ //we are in conflict
1126 j
= d_labels_data
[n
][i
];
1128 makeConflict
= true;
1130 }else{ //it is redundant
1134 neg_testers
[jtindex
] = true;
1137 if( !makeConflict
){
1138 Debug("datatypes-labels") << "Add to labels " << t
<< std::endl
;
1139 d_labels
[n
] = n_lbl
+ 1;
1140 if (n_lbl
< d_labels_data
[n
].size())
1142 // reuse spot in the vector
1143 d_labels_data
[n
][n_lbl
] = t
;
1144 d_labels_args
[n
][n_lbl
] = t_arg
;
1145 d_labels_tindex
[n
][n_lbl
] = ttindex
;
1147 d_labels_data
[n
].push_back(t
);
1148 d_labels_args
[n
].push_back(t_arg
);
1149 d_labels_tindex
[n
].push_back(ttindex
);
1153 const DType
& dt
= t_arg
.getType().getDType();
1154 Debug("datatypes-labels") << "Labels at " << n_lbl
<< " / " << dt
.getNumConstructors() << std::endl
;
1156 instantiate( eqc
, n
);
1157 for (unsigned i
= 0, ncons
= dt
.getNumConstructors(); i
< ncons
; i
++)
1159 if( i
!=ttindex
&& neg_testers
.find( i
)==neg_testers
.end() ){
1160 Assert(n
.getKind() != APPLY_CONSTRUCTOR
);
1161 Node infer
= utils::mkTester(n
, i
, dt
).negate();
1162 Trace("datatypes-infer") << "DtInfer : neg label : " << infer
<< " by " << t
<< std::endl
;
1163 d_infer
.push_back( infer
);
1164 d_infer_exp
.push_back( t
);
1168 //check if we have reached the maximum number of testers
1169 // in this case, add the positive tester
1170 if (n_lbl
== dt
.getNumConstructors() - 1)
1172 std::vector
< bool > pcons
;
1173 getPossibleCons( eqc
, n
, pcons
);
1174 int testerIndex
= -1;
1175 for( unsigned i
=0; i
<pcons
.size(); i
++ ) {
1181 Assert(testerIndex
!= -1);
1182 //we must explain why each term in the set of testers for this equivalence class is equal
1183 std::vector
< Node
> eq_terms
;
1184 NodeBuilder
<> nb(kind::AND
);
1185 for (unsigned i
= 0; i
< n_lbl
; i
++)
1187 Node ti
= d_labels_data
[n
][i
];
1189 Assert(ti
.getKind() == NOT
);
1190 Node t_arg2
= d_labels_args
[n
][i
];
1191 if( std::find( eq_terms
.begin(), eq_terms
.end(), t_arg2
)==eq_terms
.end() ){
1192 eq_terms
.push_back( t_arg2
);
1193 if( t_arg2
!=t_arg
){
1194 nb
<< t_arg2
.eqNode( t_arg
);
1198 Node t_concl
= testerIndex
== -1
1199 ? NodeManager::currentNM()->mkConst(false)
1200 : utils::mkTester(t_arg
, testerIndex
, dt
);
1201 Node t_concl_exp
= ( nb
.getNumChildren() == 1 ) ? nb
.getChild( 0 ) : nb
;
1202 d_pending
.push_back( t_concl
);
1203 d_pending_exp
[ t_concl
] = t_concl_exp
;
1204 Trace("datatypes-infer") << "DtInfer : label : " << t_concl
<< " by " << t_concl_exp
<< std::endl
;
1205 d_infer
.push_back( t_concl
);
1206 d_infer_exp
.push_back( t_concl_exp
);
1214 Debug("datatypes-labels") << "Explain " << j
<< " " << t
<< std::endl
;
1215 std::vector
< TNode
> assumptions
;
1216 explain( j
, assumptions
);
1217 explain( t
, assumptions
);
1218 explainEquality( jt
[0], t_arg
, true, assumptions
);
1219 d_conflictNode
= mkAnd( assumptions
);
1220 Trace("dt-conflict") << "CONFLICT: Tester conflict : " << d_conflictNode
<< std::endl
;
1221 d_out
->conflict( d_conflictNode
);
1225 void TheoryDatatypes::addSelector( Node s
, EqcInfo
* eqc
, Node n
, bool assertFacts
) {
1226 Trace("dt-collapse-sel") << "Add selector : " << s
<< " to eqc(" << n
<< ")" << std::endl
;
1227 //check to see if it is redundant
1228 NodeUIntMap::iterator sel_i
= d_selector_apps
.find(n
);
1229 Assert(sel_i
!= d_selector_apps
.end());
1230 if( sel_i
!= d_selector_apps
.end() ){
1231 size_t n_sel
= (*sel_i
).second
;
1232 for (size_t j
= 0; j
< n_sel
; j
++)
1234 Node ss
= d_selector_apps_data
[n
][j
];
1235 if( s
.getOperator()==ss
.getOperator() && ( s
.getKind()!=DT_HEIGHT_BOUND
|| s
[1]==ss
[1] ) ){
1236 Trace("dt-collapse-sel") << "...redundant." << std::endl
;
1240 //add it to the vector
1241 //sel->push_back( s );
1242 d_selector_apps
[n
] = n_sel
+ 1;
1243 if (n_sel
< d_selector_apps_data
[n
].size())
1245 d_selector_apps_data
[n
][n_sel
] = s
;
1247 d_selector_apps_data
[n
].push_back( s
);
1250 eqc
->d_selectors
= true;
1252 if( assertFacts
&& !eqc
->d_constructor
.get().isNull() ){
1253 //conclude the collapsed merge
1254 collapseSelector( s
, eqc
->d_constructor
.get() );
1258 void TheoryDatatypes::addConstructor( Node c
, EqcInfo
* eqc
, Node n
){
1259 Trace("datatypes-debug") << "Add constructor : " << c
<< " to eqc(" << n
<< ")" << std::endl
;
1260 Assert(eqc
->d_constructor
.get().isNull());
1262 NodeUIntMap::iterator lbl_i
= d_labels
.find(n
);
1263 if( lbl_i
!= d_labels
.end() ){
1264 size_t constructorIndex
= utils::indexOf(c
.getOperator());
1265 size_t n_lbl
= (*lbl_i
).second
;
1266 for (size_t i
= 0; i
< n_lbl
; i
++)
1268 Node t
= d_labels_data
[n
][i
];
1269 if (d_labels_data
[n
][i
].getKind() == NOT
)
1271 unsigned tindex
= d_labels_tindex
[n
][i
];
1272 if (tindex
== constructorIndex
)
1274 std::vector
< TNode
> assumptions
;
1275 explain( t
, assumptions
);
1276 explainEquality( c
, t
[0][0], true, assumptions
);
1277 d_conflictNode
= mkAnd( assumptions
);
1278 Trace("dt-conflict") << "CONFLICT: Tester merge eq conflict : " << d_conflictNode
<< std::endl
;
1279 d_out
->conflict( d_conflictNode
);
1287 NodeUIntMap::iterator sel_i
= d_selector_apps
.find(n
);
1288 if( sel_i
!= d_selector_apps
.end() ){
1289 size_t n_sel
= (*sel_i
).second
;
1290 for (size_t j
= 0; j
< n_sel
; j
++)
1292 Node s
= d_selector_apps_data
[n
][j
];
1293 //collapse the selector
1294 collapseSelector( s
, c
);
1297 eqc
->d_constructor
.set( c
);
1300 Node
TheoryDatatypes::removeUninterpretedConstants( Node n
, std::map
< Node
, Node
>& visited
){
1301 std::map
< Node
, Node
>::iterator it
= visited
.find( n
);
1302 if( it
==visited
.end() ){
1304 if( n
.getKind()==UNINTERPRETED_CONSTANT
){
1305 std::map
< Node
, Node
>::iterator itu
= d_uc_to_fresh_var
.find( n
);
1306 if( itu
==d_uc_to_fresh_var
.end() ){
1307 Node k
= NodeManager::currentNM()->mkSkolem( "w", n
.getType(), "Skolem for wrongly applied selector." );
1308 d_uc_to_fresh_var
[n
] = k
;
1313 }else if( n
.getNumChildren()>0 ){
1314 std::vector
< Node
> children
;
1315 if( n
.getMetaKind() == kind::metakind::PARAMETERIZED
){
1316 children
.push_back( n
.getOperator() );
1318 bool childChanged
= false;
1319 for( unsigned i
=0; i
<n
.getNumChildren(); i
++ ){
1320 Node nc
= removeUninterpretedConstants( n
[i
], visited
);
1321 childChanged
= childChanged
|| nc
!=n
[i
];
1322 children
.push_back( nc
);
1325 ret
= NodeManager::currentNM()->mkNode( n
.getKind(), children
);
1335 void TheoryDatatypes::collapseSelector( Node s
, Node c
) {
1336 Assert(c
.getKind() == APPLY_CONSTRUCTOR
);
1337 Trace("dt-collapse-sel") << "collapse selector : " << s
<< " " << c
<< std::endl
;
1340 Node eq_exp
= c
.eqNode(s
[0]);
1341 if( s
.getKind()==kind::APPLY_SELECTOR_TOTAL
){
1342 Node selector
= s
.getOperator();
1343 size_t constructorIndex
= utils::indexOf(c
.getOperator());
1344 const DType
& dt
= utils::datatypeOf(selector
);
1345 const DTypeConstructor
& dtc
= dt
[constructorIndex
];
1346 int selectorIndex
= dtc
.getSelectorIndexInternal(selector
);
1347 wrong
= selectorIndex
<0;
1348 r
= NodeManager::currentNM()->mkNode( kind::APPLY_SELECTOR_TOTAL
, s
.getOperator(), c
);
1351 Node rr
= Rewriter::rewrite( r
);
1354 // we have inference S_i( C_j( t ) ) = t' for i != j, where t' is result of mkGroundTerm.
1355 // we must eliminate uninterpreted constants for datatypes that have uninterpreted sort subfields,
1356 // since uninterpreted constants should not appear in lemmas
1357 std::map
< Node
, Node
> visited
;
1358 rrs
= removeUninterpretedConstants( rr
, visited
);
1362 Node eq
= s
.eqNode(rrs
);
1363 Node peq
= c
.eqNode(s
[0]);
1364 Trace("datatypes-infer") << "DtInfer : collapse sel";
1365 //Trace("datatypes-infer") << ( wrong ? " wrong" : "");
1366 Trace("datatypes-infer") << " : " << eq
<< " by " << peq
<< std::endl
;
1367 d_pending
.push_back( eq
);
1368 d_pending_exp
[eq
] = peq
;
1369 d_infer
.push_back( eq
);
1370 d_infer_exp
.push_back(peq
);
1375 EqualityStatus
TheoryDatatypes::getEqualityStatus(TNode a
, TNode b
){
1376 Assert(d_equalityEngine
->hasTerm(a
) && d_equalityEngine
->hasTerm(b
));
1377 if (d_equalityEngine
->areEqual(a
, b
))
1379 // The terms are implied to be equal
1380 return EQUALITY_TRUE
;
1382 if (d_equalityEngine
->areDisequal(a
, b
, false))
1384 // The terms are implied to be dis-equal
1385 return EQUALITY_FALSE
;
1387 return EQUALITY_FALSE_IN_MODEL
;
1390 void TheoryDatatypes::addCarePairs(TNodeTrie
* t1
,
1398 Node f1
= t1
->getData();
1399 Node f2
= t2
->getData();
1400 if( !areEqual( f1
, f2
) ){
1401 Trace("dt-cg") << "Check " << f1
<< " and " << f2
<< std::endl
;
1402 vector
< pair
<TNode
, TNode
> > currentPairs
;
1403 for (unsigned k
= 0; k
< f1
.getNumChildren(); ++ k
) {
1406 Assert(d_equalityEngine
->hasTerm(x
));
1407 Assert(d_equalityEngine
->hasTerm(y
));
1408 Assert(!areDisequal(x
, y
));
1409 Assert(!areCareDisequal(x
, y
));
1410 if (!d_equalityEngine
->areEqual(x
, y
))
1412 Trace("dt-cg") << "Arg #" << k
<< " is " << x
<< " " << y
<< std::endl
;
1413 if (d_equalityEngine
->isTriggerTerm(x
, THEORY_DATATYPES
)
1414 && d_equalityEngine
->isTriggerTerm(y
, THEORY_DATATYPES
))
1416 TNode x_shared
= d_equalityEngine
->getTriggerTermRepresentative(
1417 x
, THEORY_DATATYPES
);
1418 TNode y_shared
= d_equalityEngine
->getTriggerTermRepresentative(
1419 y
, THEORY_DATATYPES
);
1420 currentPairs
.push_back(make_pair(x_shared
, y_shared
));
1424 for (unsigned c
= 0; c
< currentPairs
.size(); ++ c
) {
1425 Trace("dt-cg-pair") << "Pair : " << currentPairs
[c
].first
<< " " << currentPairs
[c
].second
<< std::endl
;
1426 addCarePair(currentPairs
[c
].first
, currentPairs
[c
].second
);
1433 if( depth
<(arity
-1) ){
1434 //add care pairs internal to each child
1435 for (std::pair
<const TNode
, TNodeTrie
>& tt
: t1
->d_data
)
1437 addCarePairs(&tt
.second
, nullptr, arity
, depth
+ 1, n_pairs
);
1440 //add care pairs based on each pair of non-disequal arguments
1441 for (std::map
<TNode
, TNodeTrie
>::iterator it
= t1
->d_data
.begin();
1442 it
!= t1
->d_data
.end();
1445 std::map
<TNode
, TNodeTrie
>::iterator it2
= it
;
1447 for( ; it2
!= t1
->d_data
.end(); ++it2
){
1448 if (!d_equalityEngine
->areDisequal(it
->first
, it2
->first
, false))
1450 if( !areCareDisequal(it
->first
, it2
->first
) ){
1451 addCarePairs( &it
->second
, &it2
->second
, arity
, depth
+1, n_pairs
);
1457 //add care pairs based on product of indices, non-disequal arguments
1458 for (std::pair
<const TNode
, TNodeTrie
>& tt1
: t1
->d_data
)
1460 for (std::pair
<const TNode
, TNodeTrie
>& tt2
: t2
->d_data
)
1462 if (!d_equalityEngine
->areDisequal(tt1
.first
, tt2
.first
, false))
1464 if (!areCareDisequal(tt1
.first
, tt2
.first
))
1466 addCarePairs(&tt1
.second
, &tt2
.second
, arity
, depth
+ 1, n_pairs
);
1475 void TheoryDatatypes::computeCareGraph(){
1476 unsigned n_pairs
= 0;
1477 Trace("dt-cg-summary") << "Compute graph for dt..." << d_functionTerms
.size() << " " << d_sharedTerms
.size() << std::endl
;
1478 Trace("dt-cg") << "Build indices..." << std::endl
;
1479 std::map
<TypeNode
, std::map
<Node
, TNodeTrie
> > index
;
1480 std::map
< Node
, unsigned > arity
;
1482 unsigned functionTerms
= d_functionTerms
.size();
1483 for( unsigned i
=0; i
<functionTerms
; i
++ ){
1484 TNode f1
= d_functionTerms
[i
];
1485 Assert(d_equalityEngine
->hasTerm(f1
));
1486 Trace("dt-cg-debug") << "...build for " << f1
<< std::endl
;
1487 //break into index based on operator, and type of first argument (since some operators are parametric)
1488 Node op
= f1
.getOperator();
1489 TypeNode tn
= f1
[0].getType();
1490 std::vector
< TNode
> reps
;
1491 bool has_trigger_arg
= false;
1492 for( unsigned j
=0; j
<f1
.getNumChildren(); j
++ ){
1493 reps
.push_back(d_equalityEngine
->getRepresentative(f1
[j
]));
1494 if (d_equalityEngine
->isTriggerTerm(f1
[j
], THEORY_DATATYPES
))
1496 has_trigger_arg
= true;
1499 //only may contribute to care pairs if has at least one trigger argument
1500 if( has_trigger_arg
){
1501 index
[tn
][op
].addTerm( f1
, reps
);
1502 arity
[op
] = reps
.size();
1506 for (std::pair
<const TypeNode
, std::map
<Node
, TNodeTrie
> >& tt
: index
)
1508 for (std::pair
<const Node
, TNodeTrie
>& t
: tt
.second
)
1510 Trace("dt-cg") << "Process index " << tt
.first
<< ", " << t
.first
<< "..."
1512 addCarePairs(&t
.second
, nullptr, arity
[t
.first
], 0, n_pairs
);
1515 Trace("dt-cg-summary") << "...done, # pairs = " << n_pairs
<< std::endl
;
1518 bool TheoryDatatypes::collectModelInfo(TheoryModel
* m
)
1520 Trace("dt-cmi") << "Datatypes : Collect model info "
1521 << d_equalityEngine
->consistent() << std::endl
;
1522 Trace("dt-model") << std::endl
;
1523 printModelDebug( "dt-model" );
1524 Trace("dt-model") << std::endl
;
1526 std::set
<Node
> termSet
;
1528 // Compute terms appearing in assertions and shared terms, and in inferred equalities
1529 computeRelevantTerms(termSet
);
1531 //combine the equality engine
1532 if (!m
->assertEqualityEngine(d_equalityEngine
, &termSet
))
1537 //get all constructors
1538 eq::EqClassesIterator eqccs_i
= eq::EqClassesIterator(d_equalityEngine
);
1539 std::vector
< Node
> cons
;
1540 std::vector
< Node
> nodes
;
1541 std::map
< Node
, Node
> eqc_cons
;
1542 while( !eqccs_i
.isFinished() ){
1543 Node eqc
= (*eqccs_i
);
1544 //for all equivalence classes that are datatypes
1545 //if( termSet.find( eqc )==termSet.end() ){
1546 // Trace("dt-cmi-debug") << "Irrelevant eqc : " << eqc << std::endl;
1548 if( eqc
.getType().isDatatype() ){
1549 EqcInfo
* ei
= getOrMakeEqcInfo( eqc
);
1550 if( ei
&& !ei
->d_constructor
.get().isNull() ){
1551 Node c
= ei
->d_constructor
.get();
1552 cons
.push_back( c
);
1553 eqc_cons
[ eqc
] = c
;
1555 //if eqc contains a symbol known to datatypes (a selector), then we must assign
1556 //should assign constructors to EQC if they have a selector or a tester
1557 bool shouldConsider
= ( ei
&& ei
->d_selectors
) || hasTester( eqc
);
1558 if( shouldConsider
){
1559 nodes
.push_back( eqc
);
1567 //unsigned orig_size = nodes.size();
1568 std::map
< TypeNode
, int > typ_enum_map
;
1569 std::vector
< TypeEnumerator
> typ_enum
;
1571 while( index
<nodes
.size() ){
1572 Node eqc
= nodes
[index
];
1574 bool addCons
= false;
1575 TypeNode tt
= eqc
.getType();
1576 const DType
& dt
= tt
.getDType();
1577 if (!d_equalityEngine
->hasTerm(eqc
))
1581 Trace("dt-cmi") << "NOTICE : Datatypes: no constructor in equivalence class " << eqc
<< std::endl
;
1582 Trace("dt-cmi") << " Type : " << eqc
.getType() << std::endl
;
1583 EqcInfo
* ei
= getOrMakeEqcInfo( eqc
);
1584 std::vector
< bool > pcons
;
1585 getPossibleCons( ei
, eqc
, pcons
);
1586 Trace("dt-cmi") << "Possible constructors : ";
1587 for( unsigned i
=0; i
<pcons
.size(); i
++ ){
1588 Trace("dt-cmi") << pcons
[i
] << " ";
1590 Trace("dt-cmi") << std::endl
;
1591 for( unsigned r
=0; r
<2; r
++ ){
1592 if( neqc
.isNull() ){
1593 for( unsigned i
=0; i
<pcons
.size(); i
++ ){
1594 //must try the infinite ones first
1595 bool cfinite
= dt
[ i
].isInterpretedFinite( tt
);
1596 if( pcons
[i
] && (r
==1)==cfinite
){
1597 neqc
= utils::getInstCons(eqc
, dt
, i
);
1605 if( !neqc
.isNull() ){
1606 Trace("dt-cmi") << "Assign : " << neqc
<< std::endl
;
1607 if (!m
->assertEquality(eqc
, neqc
, true))
1611 eqc_cons
[ eqc
] = neqc
;
1614 cons
.push_back( neqc
);
1619 for( std::map
< Node
, Node
>::iterator it
= eqc_cons
.begin(); it
!= eqc_cons
.end(); ++it
){
1620 Node eqc
= it
->first
;
1621 if( eqc
.getType().isCodatatype() ){
1622 //until models are implemented for codatatypes
1623 //throw Exception("Models for codatatypes are not supported in this version.");
1624 //must proactive expand to avoid looping behavior in model builder
1625 if( !it
->second
.isNull() ){
1626 std::map
< Node
, int > vmap
;
1627 Node v
= getCodatatypesValue( it
->first
, eqc_cons
, vmap
, 0 );
1628 Trace("dt-cmi") << " EQC(" << it
->first
<< "), constructor is " << it
->second
<< ", value is " << v
<< ", const = " << v
.isConst() << std::endl
;
1629 if (!m
->assertEquality(eqc
, v
, true))
1633 m
->assertSkeleton(v
);
1636 Trace("dt-cmi") << "Datatypes : assert representative " << it
->second
<< " for " << it
->first
<< std::endl
;
1637 m
->assertSkeleton(it
->second
);
1644 Node
TheoryDatatypes::getCodatatypesValue( Node n
, std::map
< Node
, Node
>& eqc_cons
, std::map
< Node
, int >& vmap
, int depth
){
1645 std::map
< Node
, int >::iterator itv
= vmap
.find( n
);
1646 if( itv
!=vmap
.end() ){
1647 int debruijn
= depth
- 1 - itv
->second
;
1648 return NodeManager::currentNM()->mkConst(
1649 UninterpretedConstant(n
.getType(), debruijn
));
1650 }else if( n
.getType().isDatatype() ){
1651 Node nc
= eqc_cons
[n
];
1654 Trace("dt-cmi-cdt-debug") << " map " << n
<< " -> " << depth
<< std::endl
;
1655 Assert(nc
.getKind() == APPLY_CONSTRUCTOR
);
1656 std::vector
< Node
> children
;
1657 children
.push_back( nc
.getOperator() );
1658 for( unsigned i
=0; i
<nc
.getNumChildren(); i
++ ){
1659 Node r
= getRepresentative( nc
[i
] );
1660 Node rv
= getCodatatypesValue( r
, eqc_cons
, vmap
, depth
+1 );
1661 children
.push_back( rv
);
1664 return NodeManager::currentNM()->mkNode( APPLY_CONSTRUCTOR
, children
);
1670 Node
TheoryDatatypes::getSingletonLemma( TypeNode tn
, bool pol
) {
1671 int index
= pol
? 0 : 1;
1672 std::map
< TypeNode
, Node
>::iterator it
= d_singleton_lemma
[index
].find( tn
);
1673 if( it
==d_singleton_lemma
[index
].end() ){
1676 Node v1
= NodeManager::currentNM()->mkBoundVar( tn
);
1677 Node v2
= NodeManager::currentNM()->mkBoundVar( tn
);
1678 a
= NodeManager::currentNM()->mkNode( FORALL
, NodeManager::currentNM()->mkNode( BOUND_VAR_LIST
, v1
, v2
), v1
.eqNode( v2
) );
1680 Node v1
= NodeManager::currentNM()->mkSkolem( "k1", tn
);
1681 Node v2
= NodeManager::currentNM()->mkSkolem( "k2", tn
);
1682 a
= v1
.eqNode( v2
).negate();
1683 //send out immediately as lemma
1685 Trace("dt-singleton") << "******** assert " << a
<< " to avoid singleton cardinality for type " << tn
<< std::endl
;
1687 d_singleton_lemma
[index
][tn
] = a
;
1694 void TheoryDatatypes::collectTerms( Node n
) {
1695 if (d_collectTermsCache
.find(n
) != d_collectTermsCache
.end())
1697 // already processed
1700 d_collectTermsCache
[n
] = true;
1701 Kind nk
= n
.getKind();
1702 if (nk
== APPLY_CONSTRUCTOR
)
1704 Debug("datatypes") << " Found constructor " << n
<< endl
;
1705 if (n
.getNumChildren() > 0)
1707 d_functionTerms
.push_back(n
);
1711 if (nk
== APPLY_SELECTOR_TOTAL
|| nk
== DT_SIZE
|| nk
== DT_HEIGHT_BOUND
)
1713 d_functionTerms
.push_back(n
);
1714 // we must also record which selectors exist
1715 Trace("dt-collapse-sel") << " Found selector " << n
<< endl
;
1716 Node rep
= getRepresentative(n
[0]);
1717 // record it in the selectors
1718 EqcInfo
* eqc
= getOrMakeEqcInfo(rep
, true);
1719 // add it to the eqc info
1720 addSelector(n
, eqc
, rep
);
1723 // now, do user-context-dependent lemmas
1724 if (nk
!= DT_SIZE
&& nk
!= DT_HEIGHT_BOUND
)
1726 // if not one of these kinds, there are no lemmas
1729 if (d_collectTermsCacheU
.find(n
) != d_collectTermsCacheU
.end())
1733 d_collectTermsCacheU
[n
] = true;
1735 NodeManager
* nm
= NodeManager::currentNM();
1739 Node lem
= nm
->mkNode(LEQ
, d_zero
, n
);
1740 Trace("datatypes-infer")
1741 << "DtInfer : size geq zero : " << lem
<< std::endl
;
1742 d_pending_lem
.push_back(lem
);
1744 else if (nk
== DT_HEIGHT_BOUND
&& n
[1].getConst
<Rational
>().isZero())
1746 std::vector
<Node
> children
;
1747 const DType
& dt
= n
[0].getType().getDType();
1748 for (unsigned i
= 0, ncons
= dt
.getNumConstructors(); i
< ncons
; i
++)
1750 if (utils::isNullaryConstructor(dt
[i
]))
1752 Node test
= utils::mkTester(n
[0], i
, dt
);
1753 children
.push_back(test
);
1757 if (children
.empty())
1763 lem
= n
.eqNode(children
.size() == 1 ? children
[0]
1764 : nm
->mkNode(OR
, children
));
1766 Trace("datatypes-infer") << "DtInfer : zero height : " << lem
<< std::endl
;
1767 d_pending_lem
.push_back(lem
);
1771 Node
TheoryDatatypes::getInstantiateCons(Node n
, const DType
& dt
, int index
)
1773 std::map
< int, Node
>::iterator it
= d_inst_map
[n
].find( index
);
1774 if( it
!=d_inst_map
[n
].end() ){
1778 if( n
.getKind()==APPLY_CONSTRUCTOR
&& n
.getNumChildren()==0 ){
1781 //add constructor to equivalence class
1782 Node k
= getTermSkolemFor( n
);
1783 n_ic
= utils::getInstCons(k
, dt
, index
);
1784 //Assert( n_ic==Rewriter::rewrite( n_ic ) );
1785 n_ic
= Rewriter::rewrite( n_ic
);
1786 collectTerms( n_ic
);
1787 d_equalityEngine
->addTerm(n_ic
);
1788 Debug("dt-enum") << "Made instantiate cons " << n_ic
<< std::endl
;
1790 d_inst_map
[n
][index
] = n_ic
;
1795 void TheoryDatatypes::instantiate( EqcInfo
* eqc
, Node n
){
1796 //add constructor to equivalence class if not done so already
1797 int index
= getLabelIndex( eqc
, n
);
1798 if (index
== -1 || eqc
->d_inst
)
1804 if (!eqc
->d_constructor
.get().isNull())
1807 tt
= eqc
->d_constructor
;
1814 const DType
& dt
= tt
.getType().getDType();
1815 // instantiate this equivalence class
1817 Node tt_cons
= getInstantiateCons(tt
, dt
, index
);
1823 eq
= tt
.eqNode(tt_cons
);
1824 Debug("datatypes-inst") << "DtInstantiate : " << eqc
<< " " << eq
1826 d_pending
.push_back(eq
);
1827 d_pending_exp
[eq
] = exp
;
1828 Trace("datatypes-infer-debug") << "inst : " << eqc
<< " " << n
<< std::endl
;
1829 Trace("datatypes-infer") << "DtInfer : instantiate : " << eq
<< " by " << exp
1831 d_infer
.push_back(eq
);
1832 d_infer_exp
.push_back(exp
);
1835 void TheoryDatatypes::checkCycles() {
1836 Trace("datatypes-cycle-check") << "Check acyclicity" << std::endl
;
1837 std::vector
< Node
> cdt_eqc
;
1838 eq::EqClassesIterator eqcs_i
= eq::EqClassesIterator(d_equalityEngine
);
1839 while( !eqcs_i
.isFinished() ){
1840 Node eqc
= (*eqcs_i
);
1841 TypeNode tn
= eqc
.getType();
1842 if( tn
.isDatatype() ) {
1843 if( !tn
.isCodatatype() ){
1844 if( options::dtCyclic() ){
1846 std::map
< TNode
, bool > visited
;
1847 std::map
< TNode
, bool > proc
;
1848 std::vector
< TNode
> expl
;
1849 Trace("datatypes-cycle-check") << "...search for cycle starting at " << eqc
<< std::endl
;
1850 Node cn
= searchForCycle( eqc
, eqc
, visited
, proc
, expl
);
1851 Trace("datatypes-cycle-check") << "...finish." << std::endl
;
1852 //if we discovered a different cycle while searching this one
1853 if( !cn
.isNull() && cn
!=eqc
){
1858 cn
= searchForCycle( cn
, cn
, visited
, proc
, expl
);
1862 if( !cn
.isNull() ) {
1863 Assert(expl
.size() > 0);
1864 d_conflictNode
= mkAnd( expl
);
1865 Trace("dt-conflict") << "CONFLICT: Cycle conflict : " << d_conflictNode
<< std::endl
;
1866 d_out
->conflict( d_conflictNode
);
1873 cdt_eqc
.push_back( eqc
);
1878 Trace("datatypes-cycle-check") << "Check uniqueness" << std::endl
;
1879 //process codatatypes
1880 if( cdt_eqc
.size()>1 && options::cdtBisimilar() ){
1881 printModelDebug("dt-cdt-debug");
1882 Trace("dt-cdt-debug") << "Process " << cdt_eqc
.size() << " co-datatypes" << std::endl
;
1883 std::vector
< std::vector
< Node
> > part_out
;
1884 std::vector
< TNode
> exp
;
1885 std::map
< Node
, Node
> cn
;
1886 std::map
< Node
, std::map
< Node
, int > > dni
;
1887 for( unsigned i
=0; i
<cdt_eqc
.size(); i
++ ){
1888 cn
[cdt_eqc
[i
]] = cdt_eqc
[i
];
1890 separateBisimilar( cdt_eqc
, part_out
, exp
, cn
, dni
, 0, false );
1891 Trace("dt-cdt-debug") << "Done separate bisimilar." << std::endl
;
1892 if( !part_out
.empty() ){
1893 Trace("dt-cdt-debug") << "Process partition size " << part_out
.size() << std::endl
;
1894 for( unsigned i
=0; i
<part_out
.size(); i
++ ){
1895 std::vector
< Node
> part
;
1896 part
.push_back( part_out
[i
][0] );
1897 for( unsigned j
=1; j
<part_out
[i
].size(); j
++ ){
1898 Trace("dt-cdt") << "Codatatypes : " << part_out
[i
][0] << " and " << part_out
[i
][j
] << " must be equal!!" << std::endl
;
1899 part
.push_back( part_out
[i
][j
] );
1900 std::vector
< std::vector
< Node
> > tpart_out
;
1903 cn
[part_out
[i
][0]] = part_out
[i
][0];
1904 cn
[part_out
[i
][j
]] = part_out
[i
][j
];
1906 separateBisimilar( part
, tpart_out
, exp
, cn
, dni
, 0, true );
1907 Assert(tpart_out
.size() == 1 && tpart_out
[0].size() == 2);
1909 //merge based on explanation
1910 Trace("dt-cdt") << " exp is : ";
1911 for( unsigned k
=0; k
<exp
.size(); k
++ ){
1912 Trace("dt-cdt") << exp
[k
] << " ";
1914 Trace("dt-cdt") << std::endl
;
1915 Node eq
= part_out
[i
][0].eqNode( part_out
[i
][j
] );
1916 Node eqExp
= mkAnd( exp
);
1917 d_pending
.push_back( eq
);
1918 d_pending_exp
[ eq
] = eqExp
;
1919 Trace("datatypes-infer") << "DtInfer : cdt-bisimilar : " << eq
<< " by " << eqExp
<< std::endl
;
1920 d_infer
.push_back( eq
);
1921 d_infer_exp
.push_back( eqExp
);
1928 //everything is in terms of representatives
1929 void TheoryDatatypes::separateBisimilar( std::vector
< Node
>& part
, std::vector
< std::vector
< Node
> >& part_out
,
1930 std::vector
< TNode
>& exp
,
1931 std::map
< Node
, Node
>& cn
,
1932 std::map
< Node
, std::map
< Node
, int > >& dni
, int dniLvl
, bool mkExp
){
1934 Trace("dt-cdt-debug") << "Separate bisimilar : " << std::endl
;
1935 for( unsigned i
=0; i
<part
.size(); i
++ ){
1936 Trace("dt-cdt-debug") << " " << part
[i
] << ", current = " << cn
[part
[i
]] << std::endl
;
1939 Assert(part
.size() > 1);
1940 std::map
< Node
, std::vector
< Node
> > new_part
;
1941 std::map
< Node
, std::vector
< Node
> > new_part_c
;
1942 std::map
< int, std::vector
< Node
> > new_part_rec
;
1944 std::map
< Node
, Node
> cn_cons
;
1945 for( unsigned j
=0; j
<part
.size(); j
++ ){
1946 Node c
= cn
[part
[j
]];
1947 std::map
< Node
, int >::iterator it_rec
= dni
[part
[j
]].find( c
);
1948 if( it_rec
!=dni
[part
[j
]].end() ){
1950 if( !mkExp
){ Trace("dt-cdt-debug") << " - " << part
[j
] << " is looping at index " << it_rec
->second
<< std::endl
; }
1951 new_part_rec
[ it_rec
->second
].push_back( part
[j
] );
1953 if( c
.getType().isDatatype() ){
1954 Node ncons
= getEqcConstructor( c
);
1955 if( ncons
.getKind()==APPLY_CONSTRUCTOR
) {
1956 Node cc
= ncons
.getOperator();
1957 cn_cons
[part
[j
]] = ncons
;
1959 explainEquality( c
, ncons
, true, exp
);
1961 new_part
[cc
].push_back( part
[j
] );
1962 if( !mkExp
){ Trace("dt-cdt-debug") << " - " << part
[j
] << " is datatype " << ncons
<< "." << std::endl
; }
1964 new_part_c
[c
].push_back( part
[j
] );
1965 if( !mkExp
){ Trace("dt-cdt-debug") << " - " << part
[j
] << " is unspecified datatype." << std::endl
; }
1969 if( !mkExp
){ Trace("dt-cdt-debug") << " - " << part
[j
] << " is term " << c
<< "." << std::endl
; }
1970 new_part_c
[c
].push_back( part
[j
] );
1974 //direct add for constants
1975 for( std::map
< Node
, std::vector
< Node
> >::iterator it
= new_part_c
.begin(); it
!= new_part_c
.end(); ++it
){
1976 if( it
->second
.size()>1 ){
1977 std::vector
< Node
> vec
;
1978 vec
.insert( vec
.begin(), it
->second
.begin(), it
->second
.end() );
1979 part_out
.push_back( vec
);
1982 //direct add for recursive
1983 for( std::map
< int, std::vector
< Node
> >::iterator it
= new_part_rec
.begin(); it
!= new_part_rec
.end(); ++it
){
1984 if( it
->second
.size()>1 ){
1985 std::vector
< Node
> vec
;
1986 vec
.insert( vec
.begin(), it
->second
.begin(), it
->second
.end() );
1987 part_out
.push_back( vec
);
1989 //add back : could match a datatype?
1992 //recurse for the datatypes
1993 for( std::map
< Node
, std::vector
< Node
> >::iterator it
= new_part
.begin(); it
!= new_part
.end(); ++it
){
1994 if( it
->second
.size()>1 ){
1995 //set dni to check for loops
1996 std::map
< Node
, Node
> dni_rem
;
1997 for( unsigned i
=0; i
<it
->second
.size(); i
++ ){
1998 Node n
= it
->second
[i
];
1999 dni
[n
][cn
[n
]] = dniLvl
;
2003 //we will split based on the arguments of the datatype
2004 std::vector
< std::vector
< Node
> > split_new_part
;
2005 split_new_part
.push_back( it
->second
);
2007 unsigned nChildren
= cn_cons
[it
->second
[0]].getNumChildren();
2008 //for each child of constructor
2009 unsigned cindex
= 0;
2010 while( cindex
<nChildren
&& !split_new_part
.empty() ){
2011 if( !mkExp
){ Trace("dt-cdt-debug") << "Split argument #" << cindex
<< " of " << it
->first
<< "..." << std::endl
; }
2012 std::vector
< std::vector
< Node
> > next_split_new_part
;
2013 for( unsigned j
=0; j
<split_new_part
.size(); j
++ ){
2015 for( unsigned k
=0; k
<split_new_part
[j
].size(); k
++ ){
2016 Node n
= split_new_part
[j
][k
];
2017 cn
[n
] = getRepresentative( cn_cons
[n
][cindex
] );
2019 explainEquality( cn
[n
], cn_cons
[n
][cindex
], true, exp
);
2022 std::vector
< std::vector
< Node
> > c_part_out
;
2023 separateBisimilar( split_new_part
[j
], c_part_out
, exp
, cn
, dni
, dniLvl
+1, mkExp
);
2024 next_split_new_part
.insert( next_split_new_part
.end(), c_part_out
.begin(), c_part_out
.end() );
2026 split_new_part
.clear();
2027 split_new_part
.insert( split_new_part
.end(), next_split_new_part
.begin(), next_split_new_part
.end() );
2030 part_out
.insert( part_out
.end(), split_new_part
.begin(), split_new_part
.end() );
2032 for( std::map
< Node
, Node
>::iterator it2
= dni_rem
.begin(); it2
!= dni_rem
.end(); ++it2
){
2033 dni
[it2
->first
].erase( it2
->second
);
2039 //postcondition: if cycle detected, explanation is why n is a subterm of on
2040 Node
TheoryDatatypes::searchForCycle( TNode n
, TNode on
,
2041 std::map
< TNode
, bool >& visited
, std::map
< TNode
, bool >& proc
,
2042 std::vector
< TNode
>& explanation
, bool firstTime
) {
2043 Trace("datatypes-cycle-check2") << "Search for cycle " << n
<< " " << on
<< endl
;
2047 nn
= getRepresentative( n
);
2049 explainEquality( n
, nn
, true, explanation
);
2053 nn
= getRepresentative( n
);
2055 if( proc
.find( nn
)!=proc
.end() ){
2056 return Node::null();
2058 Trace("datatypes-cycle-check2") << "...representative : " << nn
<< " " << ( visited
.find( nn
) == visited
.end() ) << " " << visited
.size() << std::endl
;
2059 if( visited
.find( nn
) == visited
.end() ) {
2060 Trace("datatypes-cycle-check2") << " visit : " << nn
<< std::endl
;
2062 TNode nncons
= getEqcConstructor(nn
);
2063 if (nncons
.getKind() == APPLY_CONSTRUCTOR
)
2065 for (unsigned i
= 0; i
< nncons
.getNumChildren(); i
++)
2068 searchForCycle(nncons
[i
], on
, visited
, proc
, explanation
, false);
2070 //add explanation for why the constructor is connected
2073 explainEquality(n
, nncons
, true, explanation
);
2076 }else if( !cn
.isNull() ){
2081 Trace("datatypes-cycle-check2") << " unvisit : " << nn
<< std::endl
;
2083 visited
.erase( nn
);
2084 return Node::null();
2086 TypeNode tn
= nn
.getType();
2087 if( tn
.isDatatype() ) {
2088 if( !tn
.isCodatatype() ){
2092 return Node::null();
2096 bool TheoryDatatypes::mustCommunicateFact( Node n
, Node exp
){
2097 //the datatypes decision procedure makes "internal" inferences apart from the equality engine :
2098 // (1) Unification : C( t1...tn ) = C( s1...sn ) => ti = si
2099 // (2) Label : ~is_C1( t ) ... ~is_C{i-1}( t ) ~is_C{i+1}( t ) ... ~is_Cn( t ) => is_Ci( t )
2100 // (3) Instantiate : is_C( t ) => t = C( sel_1( t ) ... sel_n( t ) )
2101 // (4) collapse selector : S( C( t1...tn ) ) = t'
2102 // (5) collapse term size : size( C( t1...tn ) ) = 1 + size( t1 ) + ... + size( tn )
2103 // (6) non-negative size : 0 <= size( t )
2104 //We may need to communicate outwards if the conclusions involve other theories. Also communicate (6) and OR conclusions.
2105 Trace("dt-lemma-debug") << "Compute for " << exp
<< " => " << n
<< std::endl
;
2106 bool addLemma
= false;
2107 if( options::dtInferAsLemmas() && exp
!=d_true
){
2109 }else if( n
.getKind()==EQUAL
){
2110 TypeNode tn
= n
[0].getType();
2111 if( !tn
.isDatatype() ){
2114 const DType
& dt
= tn
.getDType();
2115 addLemma
= dt
.involvesExternalType();
2117 }else if( n
.getKind()==LEQ
|| n
.getKind()==OR
){
2121 Trace("dt-lemma-debug") << "Communicate " << n
<< std::endl
;
2124 Trace("dt-lemma-debug") << "Do not need to communicate " << n
<< std::endl
;
2129 bool TheoryDatatypes::hasTerm(TNode a
) { return d_equalityEngine
->hasTerm(a
); }
2131 bool TheoryDatatypes::areEqual( TNode a
, TNode b
){
2134 }else if( hasTerm( a
) && hasTerm( b
) ){
2135 return d_equalityEngine
->areEqual(a
, b
);
2141 bool TheoryDatatypes::areDisequal( TNode a
, TNode b
){
2144 }else if( hasTerm( a
) && hasTerm( b
) ){
2145 return d_equalityEngine
->areDisequal(a
, b
, false);
2147 //TODO : constants here?
2152 bool TheoryDatatypes::areCareDisequal( TNode x
, TNode y
) {
2153 Assert(d_equalityEngine
->hasTerm(x
));
2154 Assert(d_equalityEngine
->hasTerm(y
));
2155 if (d_equalityEngine
->isTriggerTerm(x
, THEORY_DATATYPES
)
2156 && d_equalityEngine
->isTriggerTerm(y
, THEORY_DATATYPES
))
2159 d_equalityEngine
->getTriggerTermRepresentative(x
, THEORY_DATATYPES
);
2161 d_equalityEngine
->getTriggerTermRepresentative(y
, THEORY_DATATYPES
);
2162 EqualityStatus eqStatus
= d_valuation
.getEqualityStatus(x_shared
, y_shared
);
2163 if( eqStatus
==EQUALITY_FALSE_AND_PROPAGATED
|| eqStatus
==EQUALITY_FALSE
|| eqStatus
==EQUALITY_FALSE_IN_MODEL
){
2170 TNode
TheoryDatatypes::getRepresentative( TNode a
){
2172 return d_equalityEngine
->getRepresentative(a
);
2178 bool TheoryDatatypes::getCurrentSubstitution( int effort
, std::vector
< Node
>& vars
, std::vector
< Node
>& subs
, std::map
< Node
, std::vector
< Node
> >& exp
) {
2182 void TheoryDatatypes::printModelDebug( const char* c
){
2183 if(! (Trace
.isOn(c
))) {
2187 Trace( c
) << "Datatypes model : " << std::endl
;
2188 eq::EqClassesIterator eqcs_i
= eq::EqClassesIterator(d_equalityEngine
);
2189 while( !eqcs_i
.isFinished() ){
2190 Node eqc
= (*eqcs_i
);
2191 //if( !eqc.getType().isBoolean() ){
2192 if( eqc
.getType().isDatatype() ){
2193 Trace( c
) << "DATATYPE : ";
2195 Trace( c
) << eqc
<< " : " << eqc
.getType() << " : " << std::endl
;
2196 Trace( c
) << " { ";
2197 //add terms to model
2198 eq::EqClassIterator eqc_i
= eq::EqClassIterator(eqc
, d_equalityEngine
);
2199 while( !eqc_i
.isFinished() ){
2200 if( (*eqc_i
)!=eqc
){
2201 Trace( c
) << (*eqc_i
) << " ";
2205 Trace( c
) << "}" << std::endl
;
2206 if( eqc
.getType().isDatatype() ){
2207 EqcInfo
* ei
= getOrMakeEqcInfo( eqc
);
2209 Trace( c
) << " Instantiated : " << ei
->d_inst
.get() << std::endl
;
2210 Trace( c
) << " Constructor : ";
2211 if( !ei
->d_constructor
.get().isNull() ){
2212 Trace( c
)<< ei
->d_constructor
.get();
2214 Trace( c
) << std::endl
<< " Labels : ";
2215 if( hasLabel( ei
, eqc
) ){
2216 Trace( c
) << getLabel( eqc
);
2218 NodeUIntMap::iterator lbl_i
= d_labels
.find(eqc
);
2219 if( lbl_i
!= d_labels
.end() ){
2220 for (size_t j
= 0; j
< (*lbl_i
).second
; j
++)
2222 Trace( c
) << d_labels_data
[eqc
][j
] << " ";
2226 Trace( c
) << std::endl
;
2227 Trace( c
) << " Selectors : " << ( ei
->d_selectors
? "yes, " : "no " );
2228 NodeUIntMap::iterator sel_i
= d_selector_apps
.find(eqc
);
2229 if( sel_i
!= d_selector_apps
.end() ){
2230 for (size_t j
= 0; j
< (*sel_i
).second
; j
++)
2232 Trace( c
) << d_selector_apps_data
[eqc
][j
] << " ";
2235 Trace( c
) << std::endl
;
2243 Node
TheoryDatatypes::mkAnd( std::vector
< TNode
>& assumptions
) {
2244 if( assumptions
.empty() ){
2246 }else if( assumptions
.size()==1 ){
2247 return assumptions
[0];
2249 return NodeManager::currentNM()->mkNode( AND
, assumptions
);
2253 void TheoryDatatypes::computeRelevantTerms(std::set
<Node
>& termSet
,
2256 // Compute terms appearing in assertions and shared terms
2257 std::set
<Kind
> irrKinds
;
2258 // testers are not relevant for model construction
2259 irrKinds
.insert(APPLY_TESTER
);
2260 computeRelevantTermsInternal(termSet
, irrKinds
, includeShared
);
2262 Trace("dt-cmi") << "Have " << termSet
.size() << " relevant terms..."
2265 //also include non-singleton equivalence classes TODO : revisit this
2266 eq::EqClassesIterator eqcs_i
= eq::EqClassesIterator(d_equalityEngine
);
2267 while( !eqcs_i
.isFinished() ){
2268 TNode r
= (*eqcs_i
);
2269 bool addedFirst
= false;
2271 TypeNode rtn
= r
.getType();
2272 if (!rtn
.isBoolean())
2274 eq::EqClassIterator eqc_i
= eq::EqClassIterator(r
, d_equalityEngine
);
2275 while (!eqc_i
.isFinished())
2281 // always include all datatypes
2282 if (rtn
.isDatatype())
2293 termSet
.insert(first
);
2302 Trace("dt-cmi") << "After adding non-singletons, has " << termSet
.size()
2303 << " relevant terms..." << std::endl
;
2306 std::pair
<bool, Node
> TheoryDatatypes::entailmentCheck(TNode lit
)
2308 Trace("dt-entail") << "Check entailed : " << lit
<< std::endl
;
2309 Node atom
= lit
.getKind()==NOT
? lit
[0] : lit
;
2310 bool pol
= lit
.getKind()!=NOT
;
2311 if( atom
.getKind()==APPLY_TESTER
){
2314 Node r
= d_equalityEngine
->getRepresentative(n
);
2315 EqcInfo
* ei
= getOrMakeEqcInfo( r
, false );
2316 int l_index
= getLabelIndex( ei
, r
);
2317 int t_index
= static_cast<int>(utils::indexOf(atom
.getOperator()));
2318 Trace("dt-entail") << " Tester indices are " << t_index
<< " and " << l_index
<< std::endl
;
2319 if( l_index
!=-1 && (l_index
==t_index
)==pol
){
2320 std::vector
< TNode
> exp_c
;
2321 if( ei
&& !ei
->d_constructor
.get().isNull() ){
2322 explainEquality( n
, ei
->d_constructor
.get(), true, exp_c
);
2324 Node lbl
= getLabel( n
);
2325 Assert(!lbl
.isNull());
2326 exp_c
.push_back( lbl
);
2327 Assert(areEqual(n
, lbl
[0]));
2328 explainEquality( n
, lbl
[0], true, exp_c
);
2330 Node exp
= mkAnd( exp_c
);
2331 Trace("dt-entail") << " entailed, explanation is " << exp
<< std::endl
;
2332 return make_pair(true, exp
);
2336 return make_pair(false, Node::null());
2339 } /* namepsace CVC4::theory::datatypes */
2340 } /* namepsace CVC4::theory */
2341 } /* namepsace CVC4 */