1 /********************* */
2 /*! \file theory_uf_model.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 Theory UF Model
15 #include "theory/uf/theory_uf_model.h"
20 #include "expr/attribute.h"
21 #include "options/quantifiers_options.h"
22 #include "theory/quantifiers/first_order_model.h"
23 #include "theory/theory_engine.h"
24 #include "theory/uf/equality_engine.h"
25 #include "theory/uf/theory_uf.h"
29 using namespace CVC4::kind
;
30 using namespace CVC4::context
;
31 using namespace CVC4::theory
;
32 using namespace CVC4::theory::uf
;
35 void UfModelTreeNode::clear(){
37 d_value
= Node::null();
41 void UfModelTreeNode::setValue( TheoryModel
* m
, Node n
, Node v
, std::vector
< int >& indexOrder
, bool ground
, int argIndex
){
43 //overwrite value if either at leaf or this is a fresh tree
45 }else if( !d_value
.isNull() && d_value
!=v
){
46 //value is no longer constant
47 d_value
= Node::null();
49 if( argIndex
<(int)indexOrder
.size() ){
50 //take r = null when argument is the model basis
52 if( ground
|| ( !n
.isNull() && !n
[ indexOrder
[argIndex
] ].getAttribute(ModelBasisAttribute()) ) ){
53 r
= m
->getRepresentative( n
[ indexOrder
[argIndex
] ] );
55 d_data
[ r
].setValue( m
, n
, v
, indexOrder
, ground
, argIndex
+1 );
59 Node
UfModelTreeNode::getFunctionValue(std::vector
<Node
>& args
, int index
, Node argDefaultValue
, bool simplify
) {
61 Node defaultValue
= argDefaultValue
;
62 if(d_data
.find(Node::null()) != d_data
.end()) {
63 defaultValue
= d_data
[Node::null()].getFunctionValue(args
, index
+ 1, argDefaultValue
, simplify
);
66 vector
<Node
> caseArgs
;
67 map
<Node
, Node
> caseValues
;
69 for(map
< Node
, UfModelTreeNode
>::iterator it
= d_data
.begin(); it
!= d_data
.end(); ++it
) {
70 if(!it
->first
.isNull()) {
71 Node val
= it
->second
.getFunctionValue(args
, index
+ 1, defaultValue
, simplify
);
72 caseArgs
.push_back(it
->first
);
73 caseValues
[it
->first
] = val
;
77 NodeManager
* nm
= NodeManager::currentNM();
78 Node retNode
= defaultValue
;
81 // "non-simplifying" mode - expand function values to things like:
82 // IF (x=0 AND y=0 AND z=0) THEN value1
83 // ELSE IF (x=0 AND y=0 AND z=1) THEN value2
85 for(int i
= (int)caseArgs
.size() - 1; i
>= 0; --i
) {
86 Node val
= caseValues
[ caseArgs
[ i
] ];
87 if(val
.getKind() == ITE
) {
88 // use a stack to reverse the order, since we're traversing outside-in
93 } while(val
.getKind() == ITE
);
94 AlwaysAssert(val
== defaultValue
)
95 << "default values don't match when constructing function "
100 retNode
= nm
->mkNode(ITE
, nm
->mkNode(AND
, args
[index
].eqNode(caseArgs
[i
]), val
[0]), val
[1], retNode
);
103 retNode
= nm
->mkNode(ITE
, args
[index
].eqNode(caseArgs
[i
]), caseValues
[caseArgs
[i
]], retNode
);
107 // "simplifying" mode - condense function values
108 for(int i
= (int)caseArgs
.size() - 1; i
>= 0; --i
) {
109 retNode
= nm
->mkNode(ITE
, args
[index
].eqNode(caseArgs
[i
]), caseValues
[caseArgs
[i
]], retNode
);
114 Assert(!d_value
.isNull());
120 void UfModelTreeNode::update( TheoryModel
* m
){
121 if( !d_value
.isNull() ){
122 d_value
= m
->getRepresentative( d_value
);
124 std::map
< Node
, UfModelTreeNode
> old
= d_data
;
126 for( std::map
< Node
, UfModelTreeNode
>::iterator it
= old
.begin(); it
!= old
.end(); ++it
){
127 Node rep
= m
->getRepresentative( it
->first
);
128 d_data
[ rep
] = it
->second
;
129 d_data
[ rep
].update( m
);
134 void UfModelTreeNode::simplify( Node op
, Node defaultVal
, int argIndex
){
135 if( argIndex
<(int)op
.getType().getNumChildren()-1 ){
136 std::vector
< Node
> eraseData
;
137 //first process the default argument
139 std::map
< Node
, UfModelTreeNode
>::iterator it
= d_data
.find( r
);
140 if( it
!=d_data
.end() ){
141 if( !defaultVal
.isNull() && it
->second
.d_value
==defaultVal
){
142 eraseData
.push_back( r
);
144 it
->second
.simplify( op
, defaultVal
, argIndex
+1 );
145 if( !it
->second
.d_value
.isNull() && it
->second
.isTotal( op
, argIndex
+1 ) ){
146 defaultVal
= it
->second
.d_value
;
148 defaultVal
= Node::null();
149 if( it
->second
.isEmpty() ){
150 eraseData
.push_back( r
);
155 //now see if any children can be removed, and simplify the ones that cannot
156 for (auto& kv
: d_data
)
158 if (!kv
.first
.isNull())
160 if (!defaultVal
.isNull() && kv
.second
.d_value
== defaultVal
)
162 eraseData
.push_back(kv
.first
);
166 kv
.second
.simplify(op
, defaultVal
, argIndex
+ 1);
167 if (kv
.second
.isEmpty())
169 eraseData
.push_back(kv
.first
);
174 for( int i
=0; i
<(int)eraseData
.size(); i
++ ){
175 d_data
.erase( eraseData
[i
] );
181 bool UfModelTreeNode::isTotal( Node op
, int argIndex
){
182 if( argIndex
==(int)(op
.getType().getNumChildren()-1) ){
183 return !d_value
.isNull();
186 std::map
< Node
, UfModelTreeNode
>::iterator it
= d_data
.find( r
);
187 if( it
!=d_data
.end() ){
188 return it
->second
.isTotal( op
, argIndex
+1 );
195 void indent( std::ostream
& out
, int ind
){
196 for( int i
=0; i
<ind
; i
++ ){
201 void UfModelTreeNode::debugPrint( std::ostream
& out
, TheoryModel
* m
, std::vector
< int >& indexOrder
, int ind
, int arg
){
202 if( !d_data
.empty() ){
203 for( std::map
< Node
, UfModelTreeNode
>::iterator it
= d_data
.begin(); it
!= d_data
.end(); ++it
){
204 if( !it
->first
.isNull() ){
206 out
<< "if x_" << indexOrder
[arg
] << " == " << it
->first
<< std::endl
;
207 it
->second
.debugPrint( out
, m
, indexOrder
, ind
+2, arg
+1 );
210 if( d_data
.find( Node::null() )!=d_data
.end() ){
211 d_data
[ Node::null() ].debugPrint( out
, m
, indexOrder
, ind
, arg
+1 );
216 out
<< m
->getRepresentative(d_value
);
221 Node
UfModelTree::getFunctionValue( std::vector
< Node
>& args
, bool simplify
){
222 Node body
= d_tree
.getFunctionValue( args
, 0, Node::null(), simplify
);
224 body
= Rewriter::rewrite( body
);
226 Node boundVarList
= NodeManager::currentNM()->mkNode(kind::BOUND_VAR_LIST
, args
);
227 return NodeManager::currentNM()->mkNode(kind::LAMBDA
, boundVarList
, body
);
230 Node
UfModelTree::getFunctionValue( const char* argPrefix
, bool simplify
){
231 TypeNode type
= d_op
.getType();
232 std::vector
< Node
> vars
;
233 for( size_t i
=0; i
<type
.getNumChildren()-1; i
++ ){
234 std::stringstream ss
;
235 ss
<< argPrefix
<< (i
+1);
236 vars
.push_back( NodeManager::currentNM()->mkBoundVar( ss
.str(), type
[i
] ) );
238 return getFunctionValue( vars
, simplify
);