-
Notifications
You must be signed in to change notification settings - Fork 47
/
Copy pathbdd_tag.cpp
220 lines (189 loc) · 4.99 KB
/
bdd_tag.cpp
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
// TODO: support multiple thread
#include "bdd_tag.h"
#include "debug.h"
#include <assert.h>
#include <cstring>
#include <iostream>
#include <sstream>
#include <stack>
#define VEC_CAP (1 << 16)
#define LB_WIDTH BDD_LB_WIDTH
#define MAX_LB ((1 << LB_WIDTH) - 1)
#define LB_MASK MAX_LB
#define LEN_LB BDD_LEN_LB
#define ROOT 0
BDDTag::BDDTag() {
nodes.reserve(VEC_CAP);
nodes.push_back(TagNode(ROOT, 0, 0));
};
BDDTag::~BDDTag(){};
lb_type BDDTag::alloc_node(lb_type parent, tag_off begin, tag_off end) {
lb_type lb = nodes.size();
if (lb < MAX_LB) {
nodes.push_back(TagNode(parent, begin, end));
return lb;
} else {
return ROOT;
}
}
lb_type BDDTag::insert_n_zeros(lb_type cur_lb, size_t num,
lb_type last_one_lb) {
while (num != 0) {
lb_type next = nodes[cur_lb].left;
size_t next_size = nodes[next].get_seg_size();
if (next == 0) {
tag_off off = nodes[cur_lb].seg.end;
lb_type new_lb = alloc_node(last_one_lb, off, off + num);
nodes[cur_lb].left = new_lb;
cur_lb = new_lb;
num = 0;
} else if (next_size > num) {
tag_off off = nodes[cur_lb].seg.end;
lb_type new_lb = alloc_node(last_one_lb, off, off + num);
nodes[cur_lb].left = new_lb;
cur_lb = new_lb;
nodes[next].seg.begin = off + num;
num = 0;
} else {
cur_lb = next;
num -= next_size;
}
}
return cur_lb;
}
lb_type BDDTag::insert_n_ones(lb_type cur_lb, size_t num, lb_type last_one_lb) {
while (num != 0) {
lb_type next = nodes[cur_lb].right;
tag_off last_end = nodes[cur_lb].seg.end;
if (next == 0) {
tag_off off = last_end;
lb_type new_lb = alloc_node(last_one_lb, off, off + num);
nodes[cur_lb].right = new_lb;
cur_lb = new_lb;
num = 0;
} else {
tag_off next_end = nodes[next].seg.end;
size_t next_size = next_end - last_end;
if (next_size > num) {
tag_off off = last_end;
lb_type new_lb = alloc_node(last_one_lb, off, off + num);
nodes[cur_lb].right = new_lb;
nodes[new_lb].right = next;
nodes[next].parent = new_lb;
nodes[next].seg.begin = off + num;
cur_lb = new_lb;
num = 0;
} else {
cur_lb = next;
num -= next_size;
}
}
}
return cur_lb;
}
lb_type BDDTag::insert(tag_off pos) {
lb_type cur_lb = insert_n_zeros(ROOT, pos, ROOT);
cur_lb = insert_n_ones(cur_lb, 1, ROOT);
return cur_lb;
}
void BDDTag::set_sign(lb_type lb) { nodes[lb].seg.sign = true; }
bool BDDTag::get_sign(lb_type lb) { return nodes[lb].seg.sign; }
void BDDTag::set_size(lb_type lb, size_t size) {
nodes[lb].seg.end += (size - 1);
}
lb_type BDDTag::combine(lb_type l1, lb_type l2) {
if (l1 == 0)
return l2;
if (l2 == 0 || l1 == l2)
return l1;
bool has_len_lb = BDD_HAS_LEN_LB(l1) || BDD_HAS_LEN_LB(l2);
l1 = l1 & LB_MASK;
l2 = l2 & LB_MASK;
if (l1 > l2) {
lb_type tmp = l2;
l2 = l1;
l1 = tmp;
}
// get all the segments
std::stack<lb_type> lb_st;
lb_type last_begin = MAX_LB;
while (l1 > 0 && l1 != l2) {
tag_off b1 = nodes[l1].seg.begin;
tag_off b2 = nodes[l2].seg.begin;
if (b1 < b2) {
if (b2 < last_begin) {
lb_st.push(l2);
last_begin = b2;
}
l2 = nodes[l2].parent;
} else {
if (b1 < last_begin) {
lb_st.push(l1);
last_begin = b1;
}
l1 = nodes[l1].parent;
}
}
lb_type cur_lb;
if (l1 > 0) {
cur_lb = l1;
} else {
cur_lb = l2;
}
while (!lb_st.empty()) {
tag_seg cur_seg = nodes[cur_lb].seg;
lb_type next = lb_st.top();
lb_st.pop();
tag_seg next_seg = nodes[next].seg;
if (cur_seg.end >= next_seg.begin) {
if (next_seg.end > cur_seg.end) {
size_t size = next_seg.end - cur_seg.end;
cur_lb = insert_n_ones(cur_lb, size, cur_lb);
}
} else {
lb_type last_lb = cur_lb;
size_t gap = next_seg.begin - cur_seg.end;
cur_lb = insert_n_zeros(cur_lb, gap, last_lb);
size_t size = next_seg.end - next_seg.begin;
cur_lb = insert_n_ones(cur_lb, size, last_lb);
}
if (next_seg.sign) {
nodes[cur_lb].seg.sign = true;
}
}
if (has_len_lb) {
cur_lb |= LEN_LB;
}
return cur_lb;
}
const std::vector<tag_seg> BDDTag::find(lb_type lb) {
lb = lb & LB_MASK;
std::vector<tag_seg> tag_list;
tag_off last_begin = MAX_LB;
while (lb > 0) {
if (nodes[lb].seg.begin < last_begin) {
tag_list.push_back(nodes[lb].seg);
last_begin = nodes[lb].seg.begin;
}
lb = nodes[lb].parent;
}
if (tag_list.size() > 1) {
std::reverse(tag_list.begin(), tag_list.end());
}
return tag_list;
};
std::string BDDTag::to_string(lb_type lb) {
lb = lb & LB_MASK;
std::string ss = "";
ss += "{";
std::vector<tag_seg> tags = find(lb);
char buf[100];
for (std::vector<tag_seg>::iterator it = tags.begin(); it != tags.end();
++it) {
sprintf(buf, "(%d, %d) ", it->begin, it->end);
std::string s(buf);
ss += s;
}
ss += "}";
return ss;
}