1use smallvec::SmallVec;
8use std::cmp::{Eq, Ord, Ordering, PartialEq, PartialOrd};
9use std::collections::VecDeque;
10use std::iter;
11use std::slice;
12
13#[derive(Clone, Debug, PartialEq, Eq, PartialOrd, Ord)]
15pub enum CubeVar {
16 False,
18 True,
20 DontCare,
22}
23
24const CUBE_ALLOCED_SIZE: usize = 16;
25
26#[derive(Clone, Debug)]
30pub struct Cube(SmallVec<[CubeVar; CUBE_ALLOCED_SIZE]>);
31
32#[derive(Clone, Debug, PartialEq, Eq)]
34pub enum CubeMergeResult {
35 None,
37 CancelLeft,
39 CancelRight,
41 Merge(Cube),
43 ExpandLeft(Cube),
46 ExpandRight(Cube),
49}
50
51impl Cube {
52 pub fn true_cube(vars: usize) -> Cube {
55 Cube(iter::repeat(CubeVar::DontCare).take(vars).collect())
56 }
57
58 pub fn vars(&self) -> slice::Iter<CubeVar> {
60 self.0.iter()
61 }
62
63 pub fn merge_with(&self, other: &Cube) -> CubeMergeResult {
68 if self.0.len() != other.0.len() {
72 CubeMergeResult::None
73 } else if self == other {
74 CubeMergeResult::CancelRight
75 } else {
76 let mut mismatches = 0;
77 let mut mismatch_pos = 0;
78 let mut left_covered = 0;
79 let mut right_covered = 0;
80 for (i, (lvar, rvar)) in self.0.iter().zip(other.0.iter()).enumerate() {
81 match (lvar, rvar) {
82 (&CubeVar::False, &CubeVar::True) | (&CubeVar::True, &CubeVar::False) => {
83 mismatches += 1;
84 mismatch_pos = i;
85 }
86 (&CubeVar::False, &CubeVar::DontCare)
87 | (&CubeVar::True, &CubeVar::DontCare) => {
88 left_covered += 1;
89 }
90 (&CubeVar::DontCare, &CubeVar::False)
91 | (&CubeVar::DontCare, &CubeVar::True) => {
92 right_covered += 1;
93 }
94 _ => {}
95 }
96 }
97 if mismatches == 0 && left_covered > 0 && right_covered == 0 {
98 CubeMergeResult::CancelLeft
99 } else if mismatches == 0 && right_covered > 0 && left_covered == 0 {
100 CubeMergeResult::CancelRight
101 } else if mismatches == 1 && right_covered == 0 && left_covered == 0 {
102 CubeMergeResult::Merge(self.with_var(mismatch_pos, CubeVar::DontCare))
103 } else if mismatches == 1 && right_covered > 0 && left_covered == 0 {
104 CubeMergeResult::ExpandRight(other.with_var(mismatch_pos, CubeVar::DontCare))
105 } else if mismatches == 1 && right_covered == 0 && left_covered > 0 {
106 CubeMergeResult::ExpandLeft(self.with_var(mismatch_pos, CubeVar::DontCare))
107 } else {
108 CubeMergeResult::None
109 }
110 }
111 }
112
113 pub fn with_var(&self, idx: usize, val: CubeVar) -> Cube {
116 Cube(
117 self.0
118 .iter()
119 .enumerate()
120 .map(|(i, var)| if i == idx { val.clone() } else { var.clone() })
121 .collect(),
122 )
123 }
124}
125
126impl PartialEq for Cube {
127 fn eq(&self, other: &Self) -> bool {
128 self.cmp(other) == Ordering::Equal
129 }
130}
131impl Eq for Cube {}
132impl PartialOrd for Cube {
133 fn partial_cmp(&self, other: &Self) -> Option<Ordering> {
134 Some(self.cmp(other))
135 }
136}
137impl Ord for Cube {
138 fn cmp(&self, other: &Self) -> Ordering {
139 self.0.iter().cmp(other.0.iter())
140 }
141}
142
143const CUBELIST_ALLOCED_SIZE: usize = 4;
144
145#[derive(Clone, Debug)]
155pub struct CubeList(SmallVec<[Cube; CUBE_ALLOCED_SIZE]>);
156
157impl PartialEq for CubeList {
158 fn eq(&self, other: &Self) -> bool {
159 self.0.iter().cmp(other.0.iter()) == Ordering::Equal
160 }
161}
162
163impl CubeList {
164 pub fn new() -> CubeList {
166 CubeList(SmallVec::new())
167 }
168
169 pub fn from_list(cubes: &[Cube]) -> CubeList {
171 CubeList(cubes.iter().map(|c| c.clone()).collect())
172 }
173
174 pub fn cubes(&self) -> slice::Iter<Cube> {
176 self.0.iter()
177 }
178
179 pub fn merge(&self, other: &CubeList) -> CubeList {
184 let mut out: SmallVec<[Cube; CUBE_ALLOCED_SIZE]> = SmallVec::new();
185 let mut canceled: SmallVec<[bool; CUBE_ALLOCED_SIZE]> = SmallVec::new();
186 for cube in self.0.iter().chain(other.0.iter()) {
187 out.push(cube.clone());
188 canceled.push(false);
189 }
190
191 let mut worklist = VecDeque::new();
192 for i in 0..out.len() {
193 worklist.push_back(i);
194 }
195 while let Some(i) = worklist.pop_front() {
196 if canceled[i] {
197 continue;
198 }
199 for j in 0..out.len() {
200 if i == j {
201 continue;
202 }
203 if canceled[i] {
204 break;
205 }
206 if canceled[j] {
207 continue;
208 }
209 match out[i].merge_with(&out[j]) {
210 CubeMergeResult::None => {}
211 CubeMergeResult::CancelLeft => {
212 canceled[i] = true;
213 }
214 CubeMergeResult::CancelRight => {
215 canceled[j] = true;
216 }
217 CubeMergeResult::Merge(n) => {
218 out[i] = n;
219 worklist.push_back(i);
220 canceled[j] = true;
221 }
222 CubeMergeResult::ExpandLeft(n) => {
223 out[i] = n;
224 worklist.push_back(i);
225 }
226 CubeMergeResult::ExpandRight(n) => {
227 out[j] = n;
228 worklist.push_back(j);
229 }
230 }
231 }
232 }
233
234 let out = out
235 .into_iter()
236 .zip(canceled.iter())
237 .filter(|&(_, flag)| !flag)
238 .map(|(cube, _)| cube)
239 .collect();
240 CubeList(out)
241 }
242
243 pub fn with_var(&self, idx: usize, val: CubeVar) -> CubeList {
244 CubeList(
245 self.0
246 .iter()
247 .map(|c| c.with_var(idx, val.clone()))
248 .collect(),
249 )
250 }
251}
252
253mod test {
254 use super::*;
255
256 fn make_cube(elems: &[u32]) -> Cube {
257 Cube(
258 elems
259 .iter()
260 .map(|i| match *i {
261 0 => CubeVar::False,
262 1 => CubeVar::True,
263 _ => CubeVar::DontCare,
264 })
265 .collect(),
266 )
267 }
268
269 #[test]
270 fn cube_eq() {
271 assert!(make_cube(&[1, 0, 0]) == make_cube(&[1, 0, 0]));
272 assert!(make_cube(&[1, 0, 0]) != make_cube(&[1, 0, 1]));
273 }
274
275 #[test]
276 fn cube_ord() {
277 assert!(make_cube(&[1, 0, 0]) < make_cube(&[1, 1, 0]));
278 assert!(make_cube(&[1, 0, 2]) > make_cube(&[1, 0, 1]));
279 }
280
281 #[test]
282 fn cube_with_var() {
283 assert!(make_cube(&[0, 1, 0]).with_var(2, CubeVar::True) == make_cube(&[0, 1, 1]));
284 }
285
286 #[test]
287 fn cube_merge() {
288 assert!(make_cube(&[0, 0]).merge_with(&make_cube(&[0])) == CubeMergeResult::None);
290 assert!(make_cube(&[0, 0]).merge_with(&make_cube(&[0, 0])) == CubeMergeResult::CancelRight);
292 assert!(make_cube(&[1, 0]).merge_with(&make_cube(&[0, 1])) == CubeMergeResult::None);
294 assert!(make_cube(&[1, 2]).merge_with(&make_cube(&[2, 1])) == CubeMergeResult::None);
296 assert!(
298 make_cube(&[1, 2, 2]).merge_with(&make_cube(&[1, 1, 0]))
299 == CubeMergeResult::CancelRight
300 );
301 assert!(
303 make_cube(&[1, 1, 2]).merge_with(&make_cube(&[1, 0, 0]))
304 == CubeMergeResult::ExpandRight(make_cube(&[1, 2, 0]))
305 );
306 assert!(
308 make_cube(&[1, 1, 0]).merge_with(&make_cube(&[1, 2, 2])) == CubeMergeResult::CancelLeft
309 );
310 assert!(
311 make_cube(&[1, 0, 0]).merge_with(&make_cube(&[1, 1, 2]))
312 == CubeMergeResult::ExpandLeft(make_cube(&[1, 2, 0]))
313 );
314 assert!(
316 make_cube(&[1, 1, 0]).merge_with(&make_cube(&[1, 1, 1]))
317 == CubeMergeResult::Merge(make_cube(&[1, 1, 2]))
318 );
319 assert!(make_cube(&[1, 1, 0]).merge_with(&make_cube(&[1, 0, 1])) == CubeMergeResult::None);
321 }
322
323 #[test]
324 fn cubelist_merge() {
325 assert!(
327 CubeList::new().merge(&CubeList::from_list(&[
328 make_cube(&[1, 0, 0]),
329 make_cube(&[0, 1, 1])
330 ])) == CubeList::from_list(&[make_cube(&[1, 0, 0]), make_cube(&[0, 1, 1])])
331 );
332 assert!(
334 CubeList::new().merge(&CubeList::from_list(&[
335 make_cube(&[1, 0, 0]),
336 make_cube(&[1, 1, 1]),
337 make_cube(&[1, 0, 1]),
338 make_cube(&[1, 1, 0])
339 ])) == CubeList::from_list(&[make_cube(&[1, 2, 2])])
340 );
341 assert!(
343 CubeList::new().merge(&CubeList::from_list(&[
344 make_cube(&[1, 0, 0]),
345 make_cube(&[0, 1, 1]),
346 make_cube(&[1, 0, 1])
347 ])) == CubeList::from_list(&[make_cube(&[1, 0, 2]), make_cube(&[0, 1, 1])])
348 );
349 assert!(
351 CubeList::new().merge(&CubeList::from_list(&[
352 make_cube(&[1, 0, 0]),
353 make_cube(&[1, 2, 2])
354 ])) == CubeList::from_list(&[make_cube(&[1, 2, 2])])
355 );
356 assert!(
358 CubeList::new().merge(&CubeList::from_list(&[
359 make_cube(&[1, 2, 2]),
360 make_cube(&[1, 0, 0])
361 ])) == CubeList::from_list(&[make_cube(&[1, 2, 2])])
362 );
363 }
364}