1 |
|
/****************************************************************************** |
2 |
|
* Top contributors (to current version): |
3 |
|
* Andrew Reynolds, Morgan Deters, Mathias Preiner |
4 |
|
* |
5 |
|
* This file is part of the cvc5 project. |
6 |
|
* |
7 |
|
* Copyright (c) 2009-2021 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. |
11 |
|
* **************************************************************************** |
12 |
|
* |
13 |
|
* Implementation of Theory UF Model. |
14 |
|
*/ |
15 |
|
|
16 |
|
#include "theory/uf/theory_uf_model.h" |
17 |
|
|
18 |
|
#include <stack> |
19 |
|
|
20 |
|
#include "expr/attribute.h" |
21 |
|
#include "theory/quantifiers/first_order_model.h" |
22 |
|
#include "theory/rewriter.h" |
23 |
|
#include "theory/theory_model.h" |
24 |
|
|
25 |
|
using namespace cvc5::kind; |
26 |
|
|
27 |
|
namespace cvc5 { |
28 |
|
namespace theory { |
29 |
|
namespace uf { |
30 |
|
|
31 |
|
//clear |
32 |
|
void UfModelTreeNode::clear(){ |
33 |
|
d_data.clear(); |
34 |
|
d_value = Node::null(); |
35 |
|
} |
36 |
|
|
37 |
|
//set value function |
38 |
148617 |
void UfModelTreeNode::setValue( TheoryModel* m, Node n, Node v, std::vector< int >& indexOrder, bool ground, int argIndex ){ |
39 |
148617 |
if( d_data.empty() ){ |
40 |
|
//overwrite value if either at leaf or this is a fresh tree |
41 |
115459 |
d_value = v; |
42 |
33158 |
}else if( !d_value.isNull() && d_value!=v ){ |
43 |
|
//value is no longer constant |
44 |
2710 |
d_value = Node::null(); |
45 |
|
} |
46 |
148617 |
if( argIndex<(int)indexOrder.size() ){ |
47 |
|
//take r = null when argument is the model basis |
48 |
248114 |
Node r; |
49 |
124057 |
if (ground |
50 |
208956 |
|| (!n.isNull() |
51 |
124057 |
&& !quantifiers::FirstOrderModel::isModelBasis( |
52 |
|
n[indexOrder[argIndex]]))) |
53 |
|
{ |
54 |
84899 |
r = m->getRepresentative( n[ indexOrder[argIndex] ] ); |
55 |
|
} |
56 |
124057 |
d_data[ r ].setValue( m, n, v, indexOrder, ground, argIndex+1 ); |
57 |
|
} |
58 |
148617 |
} |
59 |
|
|
60 |
56878 |
Node UfModelTreeNode::getFunctionValue(std::vector<Node>& args, int index, Node argDefaultValue, bool simplify) { |
61 |
56878 |
if(!d_data.empty()) { |
62 |
93152 |
Node defaultValue = argDefaultValue; |
63 |
46576 |
if(d_data.find(Node::null()) != d_data.end()) { |
64 |
39158 |
defaultValue = d_data[Node::null()].getFunctionValue(args, index + 1, argDefaultValue, simplify); |
65 |
|
} |
66 |
|
|
67 |
93152 |
std::vector<Node> caseArgs; |
68 |
93152 |
std::map<Node, Node> caseValues; |
69 |
|
|
70 |
98839 |
for (std::pair<const Node, UfModelTreeNode>& p : d_data) |
71 |
|
{ |
72 |
52263 |
if (!p.first.isNull()) |
73 |
|
{ |
74 |
|
Node val = |
75 |
26210 |
p.second.getFunctionValue(args, index + 1, defaultValue, simplify); |
76 |
13105 |
caseArgs.push_back(p.first); |
77 |
13105 |
caseValues[p.first] = val; |
78 |
|
} |
79 |
|
} |
80 |
|
|
81 |
46576 |
NodeManager* nm = NodeManager::currentNM(); |
82 |
93152 |
Node retNode = defaultValue; |
83 |
|
|
84 |
46576 |
if(!simplify) { |
85 |
|
// "non-simplifying" mode - expand function values to things like: |
86 |
|
// IF (x=0 AND y=0 AND z=0) THEN value1 |
87 |
|
// ELSE IF (x=0 AND y=0 AND z=1) THEN value2 |
88 |
|
// [...etc...] |
89 |
|
for(int i = (int)caseArgs.size() - 1; i >= 0; --i) { |
90 |
|
Node val = caseValues[ caseArgs[ i ] ]; |
91 |
|
if(val.getKind() == ITE) { |
92 |
|
// use a stack to reverse the order, since we're traversing outside-in |
93 |
|
std::stack<TNode> stk; |
94 |
|
do { |
95 |
|
stk.push(val); |
96 |
|
val = val[2]; |
97 |
|
} while(val.getKind() == ITE); |
98 |
|
AlwaysAssert(val == defaultValue) |
99 |
|
<< "default values don't match when constructing function " |
100 |
|
"definition!"; |
101 |
|
while(!stk.empty()) { |
102 |
|
val = stk.top(); |
103 |
|
stk.pop(); |
104 |
|
retNode = nm->mkNode(ITE, nm->mkNode(AND, args[index].eqNode(caseArgs[i]), val[0]), val[1], retNode); |
105 |
|
} |
106 |
|
} else { |
107 |
|
retNode = nm->mkNode(ITE, args[index].eqNode(caseArgs[i]), caseValues[caseArgs[i]], retNode); |
108 |
|
} |
109 |
|
} |
110 |
|
} else { |
111 |
|
// "simplifying" mode - condense function values |
112 |
59681 |
for(int i = (int)caseArgs.size() - 1; i >= 0; --i) { |
113 |
13105 |
retNode = nm->mkNode(ITE, args[index].eqNode(caseArgs[i]), caseValues[caseArgs[i]], retNode); |
114 |
|
} |
115 |
|
} |
116 |
46576 |
return retNode; |
117 |
|
} else { |
118 |
10302 |
Assert(!d_value.isNull()); |
119 |
10302 |
return d_value; |
120 |
|
} |
121 |
|
} |
122 |
|
|
123 |
|
//update function |
124 |
|
void UfModelTreeNode::update( TheoryModel* m ){ |
125 |
|
if( !d_value.isNull() ){ |
126 |
|
d_value = m->getRepresentative( d_value ); |
127 |
|
} |
128 |
|
std::map< Node, UfModelTreeNode > old = d_data; |
129 |
|
d_data.clear(); |
130 |
|
for( std::map< Node, UfModelTreeNode >::iterator it = old.begin(); it != old.end(); ++it ){ |
131 |
|
Node rep = m->getRepresentative( it->first ); |
132 |
|
d_data[ rep ] = it->second; |
133 |
|
d_data[ rep ].update( m ); |
134 |
|
} |
135 |
|
} |
136 |
|
|
137 |
|
//simplify function |
138 |
56878 |
void UfModelTreeNode::simplify( Node op, Node defaultVal, int argIndex ){ |
139 |
56878 |
if( argIndex<(int)op.getType().getNumChildren()-1 ){ |
140 |
93152 |
std::vector< Node > eraseData; |
141 |
|
//first process the default argument |
142 |
93152 |
Node r; |
143 |
46576 |
std::map< Node, UfModelTreeNode >::iterator it = d_data.find( r ); |
144 |
46576 |
if( it!=d_data.end() ){ |
145 |
39158 |
if( !defaultVal.isNull() && it->second.d_value==defaultVal ){ |
146 |
|
eraseData.push_back( r ); |
147 |
|
}else{ |
148 |
39158 |
it->second.simplify( op, defaultVal, argIndex+1 ); |
149 |
39158 |
if( !it->second.d_value.isNull() && it->second.isTotal( op, argIndex+1 ) ){ |
150 |
39158 |
defaultVal = it->second.d_value; |
151 |
|
}else{ |
152 |
|
defaultVal = Node::null(); |
153 |
|
if( it->second.isEmpty() ){ |
154 |
|
eraseData.push_back( r ); |
155 |
|
} |
156 |
|
} |
157 |
|
} |
158 |
|
} |
159 |
|
//now see if any children can be removed, and simplify the ones that cannot |
160 |
105768 |
for (auto& kv : d_data) |
161 |
|
{ |
162 |
59192 |
if (!kv.first.isNull()) |
163 |
|
{ |
164 |
20034 |
if (!defaultVal.isNull() && kv.second.d_value == defaultVal) |
165 |
|
{ |
166 |
6929 |
eraseData.push_back(kv.first); |
167 |
|
} |
168 |
|
else |
169 |
|
{ |
170 |
13105 |
kv.second.simplify(op, defaultVal, argIndex + 1); |
171 |
13105 |
if (kv.second.isEmpty()) |
172 |
|
{ |
173 |
|
eraseData.push_back(kv.first); |
174 |
|
} |
175 |
|
} |
176 |
|
} |
177 |
|
} |
178 |
53505 |
for( int i=0; i<(int)eraseData.size(); i++ ){ |
179 |
6929 |
d_data.erase( eraseData[i] ); |
180 |
|
} |
181 |
|
} |
182 |
56878 |
} |
183 |
|
|
184 |
|
//is total function |
185 |
2894824 |
bool UfModelTreeNode::isTotal( Node op, int argIndex ){ |
186 |
2894824 |
if( argIndex==(int)(op.getType().getNumChildren()-1) ){ |
187 |
39158 |
return !d_value.isNull(); |
188 |
|
}else{ |
189 |
5711332 |
Node r; |
190 |
2855666 |
std::map< Node, UfModelTreeNode >::iterator it = d_data.find( r ); |
191 |
2855666 |
if( it!=d_data.end() ){ |
192 |
2855666 |
return it->second.isTotal( op, argIndex+1 ); |
193 |
|
}else{ |
194 |
|
return false; |
195 |
|
} |
196 |
|
} |
197 |
|
} |
198 |
|
|
199 |
|
void indent( std::ostream& out, int ind ){ |
200 |
|
for( int i=0; i<ind; i++ ){ |
201 |
|
out << " "; |
202 |
|
} |
203 |
|
} |
204 |
|
|
205 |
|
void UfModelTreeNode::debugPrint( std::ostream& out, TheoryModel* m, std::vector< int >& indexOrder, int ind, int arg ){ |
206 |
|
if( !d_data.empty() ){ |
207 |
|
for( std::map< Node, UfModelTreeNode >::iterator it = d_data.begin(); it != d_data.end(); ++it ){ |
208 |
|
if( !it->first.isNull() ){ |
209 |
|
indent( out, ind ); |
210 |
|
out << "if x_" << indexOrder[arg] << " == " << it->first << std::endl; |
211 |
|
it->second.debugPrint( out, m, indexOrder, ind+2, arg+1 ); |
212 |
|
} |
213 |
|
} |
214 |
|
if( d_data.find( Node::null() )!=d_data.end() ){ |
215 |
|
d_data[ Node::null() ].debugPrint( out, m, indexOrder, ind, arg+1 ); |
216 |
|
} |
217 |
|
}else{ |
218 |
|
indent( out, ind ); |
219 |
|
out << "return "; |
220 |
|
out << m->getRepresentative(d_value); |
221 |
|
out << std::endl; |
222 |
|
} |
223 |
|
} |
224 |
|
|
225 |
4615 |
Node UfModelTree::getFunctionValue( std::vector< Node >& args, bool simplify ){ |
226 |
9230 |
Node body = d_tree.getFunctionValue( args, 0, Node::null(), simplify ); |
227 |
4615 |
if(simplify) { |
228 |
4615 |
body = Rewriter::rewrite( body ); |
229 |
|
} |
230 |
9230 |
Node boundVarList = NodeManager::currentNM()->mkNode(kind::BOUND_VAR_LIST, args); |
231 |
9230 |
return NodeManager::currentNM()->mkNode(kind::LAMBDA, boundVarList, body); |
232 |
|
} |
233 |
|
|
234 |
4615 |
Node UfModelTree::getFunctionValue( const char* argPrefix, bool simplify ){ |
235 |
9230 |
TypeNode type = d_op.getType(); |
236 |
9230 |
std::vector< Node > vars; |
237 |
43773 |
for( size_t i=0; i<type.getNumChildren()-1; i++ ){ |
238 |
78316 |
std::stringstream ss; |
239 |
39158 |
ss << argPrefix << (i+1); |
240 |
39158 |
vars.push_back( NodeManager::currentNM()->mkBoundVar( ss.str(), type[i] ) ); |
241 |
|
} |
242 |
9230 |
return getFunctionValue( vars, simplify ); |
243 |
|
} |
244 |
|
|
245 |
|
} // namespace uf |
246 |
|
} // namespace theory |
247 |
29340 |
} // namespace cvc5 |