1 |
|
/****************************************************************************** |
2 |
|
* Top contributors (to current version): |
3 |
|
* Andrew Reynolds, Aina Niemetz |
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 |
|
* Implements a match trie, also known as a discrimination tree. |
14 |
|
*/ |
15 |
|
|
16 |
|
#include "expr/match_trie.h" |
17 |
|
|
18 |
|
using namespace cvc5::kind; |
19 |
|
|
20 |
|
namespace cvc5 { |
21 |
|
namespace expr { |
22 |
|
|
23 |
4737 |
bool MatchTrie::getMatches(Node n, NotifyMatch* ntm) |
24 |
|
{ |
25 |
9474 |
std::vector<Node> vars; |
26 |
9474 |
std::vector<Node> subs; |
27 |
9474 |
std::map<Node, Node> smap; |
28 |
|
|
29 |
9474 |
std::vector<std::vector<Node> > visit; |
30 |
9474 |
std::vector<MatchTrie*> visit_trie; |
31 |
9474 |
std::vector<int> visit_var_index; |
32 |
9474 |
std::vector<bool> visit_bound_var; |
33 |
|
|
34 |
4737 |
visit.push_back(std::vector<Node>{n}); |
35 |
4737 |
visit_trie.push_back(this); |
36 |
4737 |
visit_var_index.push_back(-1); |
37 |
4737 |
visit_bound_var.push_back(false); |
38 |
85427 |
while (!visit.empty()) |
39 |
|
{ |
40 |
84856 |
std::vector<Node> cvisit = visit.back(); |
41 |
44511 |
MatchTrie* curr = visit_trie.back(); |
42 |
44511 |
if (cvisit.empty()) |
43 |
|
{ |
44 |
4377 |
Assert(n |
45 |
|
== curr->d_data.substitute( |
46 |
|
vars.begin(), vars.end(), subs.begin(), subs.end())); |
47 |
4377 |
Trace("match-debug") << "notify : " << curr->d_data << std::endl; |
48 |
4377 |
if (!ntm->notify(n, curr->d_data, vars, subs)) |
49 |
|
{ |
50 |
4166 |
return false; |
51 |
|
} |
52 |
211 |
visit.pop_back(); |
53 |
211 |
visit_trie.pop_back(); |
54 |
211 |
visit_var_index.pop_back(); |
55 |
211 |
visit_bound_var.pop_back(); |
56 |
|
} |
57 |
|
else |
58 |
|
{ |
59 |
80268 |
Node cn = cvisit.back(); |
60 |
80268 |
Trace("match-debug") << "traverse : " << cn << " at depth " |
61 |
40134 |
<< visit.size() << std::endl; |
62 |
40134 |
unsigned index = visit.size() - 1; |
63 |
40134 |
int vindex = visit_var_index[index]; |
64 |
40134 |
if (vindex == -1) |
65 |
|
{ |
66 |
21950 |
if (!cn.isVar()) |
67 |
|
{ |
68 |
30154 |
Node op = cn.hasOperator() ? cn.getOperator() : cn; |
69 |
15077 |
unsigned nchild = cn.hasOperator() ? cn.getNumChildren() : 0; |
70 |
|
std::map<unsigned, MatchTrie>::iterator itu = |
71 |
15077 |
curr->d_children[op].find(nchild); |
72 |
15077 |
if (itu != curr->d_children[op].end()) |
73 |
|
{ |
74 |
|
// recurse on the operator or self |
75 |
9036 |
cvisit.pop_back(); |
76 |
9036 |
if (cn.hasOperator()) |
77 |
|
{ |
78 |
23110 |
for (const Node& cnc : cn) |
79 |
|
{ |
80 |
16251 |
cvisit.push_back(cnc); |
81 |
|
} |
82 |
|
} |
83 |
9036 |
Trace("match-debug") << "recurse op : " << op << std::endl; |
84 |
9036 |
visit.push_back(cvisit); |
85 |
9036 |
visit_trie.push_back(&itu->second); |
86 |
9036 |
visit_var_index.push_back(-1); |
87 |
9036 |
visit_bound_var.push_back(false); |
88 |
|
} |
89 |
|
} |
90 |
21950 |
visit_var_index[index]++; |
91 |
|
} |
92 |
|
else |
93 |
|
{ |
94 |
|
// clean up if we previously bound a variable |
95 |
18184 |
if (visit_bound_var[index]) |
96 |
|
{ |
97 |
2522 |
Assert(!vars.empty()); |
98 |
2522 |
smap.erase(vars.back()); |
99 |
2522 |
vars.pop_back(); |
100 |
2522 |
subs.pop_back(); |
101 |
2522 |
visit_bound_var[index] = false; |
102 |
|
} |
103 |
|
|
104 |
18184 |
if (vindex == static_cast<int>(curr->d_vars.size())) |
105 |
|
{ |
106 |
11120 |
Trace("match-debug") |
107 |
11120 |
<< "finished checking " << curr->d_vars.size() |
108 |
5560 |
<< " variables at depth " << visit.size() << std::endl; |
109 |
|
// finished |
110 |
5560 |
visit.pop_back(); |
111 |
5560 |
visit_trie.pop_back(); |
112 |
5560 |
visit_var_index.pop_back(); |
113 |
5560 |
visit_bound_var.pop_back(); |
114 |
|
} |
115 |
|
else |
116 |
|
{ |
117 |
25248 |
Trace("match-debug") << "check variable #" << vindex << " at depth " |
118 |
12624 |
<< visit.size() << std::endl; |
119 |
12624 |
Assert(vindex < static_cast<int>(curr->d_vars.size())); |
120 |
|
// recurse on variable? |
121 |
25248 |
Node var = curr->d_vars[vindex]; |
122 |
12624 |
bool recurse = true; |
123 |
|
// check if it is already bound |
124 |
12624 |
std::map<Node, Node>::iterator its = smap.find(var); |
125 |
12624 |
if (its != smap.end()) |
126 |
|
{ |
127 |
86 |
if (its->second != cn) |
128 |
|
{ |
129 |
70 |
recurse = false; |
130 |
|
} |
131 |
|
} |
132 |
12538 |
else if (!var.getType().isSubtypeOf(cn.getType())) |
133 |
|
{ |
134 |
|
recurse = false; |
135 |
|
} |
136 |
|
else |
137 |
|
{ |
138 |
12538 |
vars.push_back(var); |
139 |
12538 |
subs.push_back(cn); |
140 |
12538 |
smap[var] = cn; |
141 |
12538 |
visit_bound_var[index] = true; |
142 |
|
} |
143 |
12624 |
if (recurse) |
144 |
|
{ |
145 |
12554 |
Trace("match-debug") << "recurse var : " << var << std::endl; |
146 |
12554 |
cvisit.pop_back(); |
147 |
12554 |
visit.push_back(cvisit); |
148 |
12554 |
visit_trie.push_back(&curr->d_children[var][0]); |
149 |
12554 |
visit_var_index.push_back(-1); |
150 |
12554 |
visit_bound_var.push_back(false); |
151 |
|
} |
152 |
12624 |
visit_var_index[index]++; |
153 |
|
} |
154 |
|
} |
155 |
|
} |
156 |
|
} |
157 |
571 |
return true; |
158 |
|
} |
159 |
|
|
160 |
600 |
void MatchTrie::addTerm(Node n) |
161 |
|
{ |
162 |
600 |
Assert(!n.isNull()); |
163 |
1200 |
std::vector<Node> visit; |
164 |
600 |
visit.push_back(n); |
165 |
600 |
MatchTrie* curr = this; |
166 |
9210 |
while (!visit.empty()) |
167 |
|
{ |
168 |
8610 |
Node cn = visit.back(); |
169 |
4305 |
visit.pop_back(); |
170 |
4305 |
if (cn.hasOperator()) |
171 |
|
{ |
172 |
1546 |
curr = &(curr->d_children[cn.getOperator()][cn.getNumChildren()]); |
173 |
5251 |
for (const Node& cnc : cn) |
174 |
|
{ |
175 |
3705 |
visit.push_back(cnc); |
176 |
|
} |
177 |
|
} |
178 |
|
else |
179 |
|
{ |
180 |
5518 |
if (cn.isVar() |
181 |
5759 |
&& std::find(curr->d_vars.begin(), curr->d_vars.end(), cn) |
182 |
5759 |
== curr->d_vars.end()) |
183 |
|
{ |
184 |
783 |
curr->d_vars.push_back(cn); |
185 |
|
} |
186 |
2759 |
curr = &(curr->d_children[cn][0]); |
187 |
|
} |
188 |
|
} |
189 |
600 |
curr->d_data = n; |
190 |
600 |
} |
191 |
|
|
192 |
24 |
void MatchTrie::clear() |
193 |
|
{ |
194 |
24 |
d_children.clear(); |
195 |
24 |
d_vars.clear(); |
196 |
24 |
d_data = Node::null(); |
197 |
24 |
} |
198 |
|
|
199 |
|
} // namespace expr |
200 |
29340 |
} // namespace cvc5 |