1use std::fmt::Debug;
10use std::fmt::Display;
11
12use bitvec::BitArr;
13use symbolic_sets::anf::AnfSet;
14use symbolic_sets::anf::Simplifiable;
15use symbolic_sets::anf::Simplification;
16use symbolic_sets::Property;
17
18const ARRAY_SIZE: usize = 1024;
24
25pub type TestSet = AnfSet<TestProperty>;
27
28pub type TestArray = BitArr!(for ARRAY_SIZE);
31
32pub trait TestSetExt {
34 fn to_array(&self) -> TestArray;
36
37 fn only(element: u16) -> TestSet;
39
40 fn is_even() -> TestSet;
42
43 fn greater_than(element: u16) -> TestSet;
45}
46
47impl TestSetExt for TestSet {
48 fn to_array(&self) -> TestArray {
49 let mut result = TestArray::ZERO;
50 if self.includes_universe() {
51 result = !result;
52 }
53 for clause in self.clauses() {
54 let mut clause_bits = !TestArray::ZERO;
55 for property in clause {
56 clause_bits &= property.to_array();
57 }
58 result ^= clause_bits;
59 }
60 result
61 }
62
63 fn only(element: u16) -> TestSet {
64 TestProperty::from(SingleNumber(element)).into()
65 }
66
67 fn is_even() -> TestSet {
68 TestProperty::from(IsEven).into()
69 }
70
71 fn greater_than(element: u16) -> TestSet {
72 TestProperty::from(GreaterThan(element)).into()
73 }
74}
75
76#[doc(hidden)]
77#[derive(Clone, Eq, Ord, PartialEq, PartialOrd)]
78pub enum TestProperty {
79 SingleNumber(SingleNumber),
80 IsEven(IsEven),
81 GreaterThan(GreaterThan),
82}
83
84impl TestProperty {
85 fn to_array(&self) -> TestArray {
86 match self {
87 TestProperty::SingleNumber(prop) => prop.to_array(),
88 TestProperty::IsEven(prop) => prop.to_array(),
89 TestProperty::GreaterThan(prop) => prop.to_array(),
90 }
91 }
92
93 fn contains(&self, element: u16) -> bool {
94 match self {
95 TestProperty::SingleNumber(prop) => prop.is_satisfied(element),
96 TestProperty::IsEven(prop) => prop.is_satisfied(element),
97 TestProperty::GreaterThan(prop) => prop.is_satisfied(element),
98 }
99 }
100}
101
102impl Debug for TestProperty {
103 fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
104 match self {
105 TestProperty::SingleNumber(prop) => write!(f, "{:?}", prop),
106 TestProperty::IsEven(prop) => write!(f, "{:?}", prop),
107 TestProperty::GreaterThan(prop) => write!(f, "{:?}", prop),
108 }
109 }
110}
111
112impl Display for TestProperty {
113 fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
114 match self {
115 TestProperty::SingleNumber(prop) => write!(f, "{}", prop),
116 TestProperty::IsEven(prop) => write!(f, "{}", prop),
117 TestProperty::GreaterThan(prop) => write!(f, "{}", prop),
118 }
119 }
120}
121
122impl Property for TestProperty {
123 type Element = u16;
124
125 fn is_satisfied(&self, element: &u16) -> bool {
126 self.contains(*element)
127 }
128}
129
130impl Simplifiable for TestProperty {
131 fn intersection(self, other: Self) -> Simplification<Self> {
132 if self < other {
133 self.intersection_ordered(other)
134 } else {
135 other.intersection_ordered(self)
136 }
137 }
138
139 fn symmetric_difference(self, other: Self) -> Simplification<Self> {
140 if self < other {
141 self.symmetric_difference_ordered(other)
142 } else {
143 other.symmetric_difference_ordered(self)
144 }
145 }
146}
147
148impl TestProperty {
149 fn intersection_ordered(self, other: Self) -> Simplification<Self> {
150 match self {
151 TestProperty::SingleNumber(prop) => prop.intersection_ordered(other),
152 TestProperty::IsEven(prop) => prop.intersection_ordered(other),
153 TestProperty::GreaterThan(prop) => prop.intersection_ordered(other),
154 }
155 }
156
157 fn symmetric_difference_ordered(self, other: Self) -> Simplification<Self> {
158 match self {
159 TestProperty::SingleNumber(prop) => prop.symmetric_difference_ordered(other),
160 TestProperty::IsEven(prop) => prop.symmetric_difference_ordered(other),
161 TestProperty::GreaterThan(prop) => prop.symmetric_difference_ordered(other),
162 }
163 }
164}
165
166#[doc(hidden)]
170#[derive(Clone, Copy, Debug, Eq, Ord, PartialEq, PartialOrd)]
171pub struct SingleNumber(u16);
172
173impl From<SingleNumber> for TestProperty {
174 fn from(prop: SingleNumber) -> TestProperty {
175 TestProperty::SingleNumber(prop)
176 }
177}
178
179impl SingleNumber {
180 fn to_array(self) -> TestArray {
181 let mut result = TestArray::ZERO;
182 result.set(self.0 as usize, true);
183 result
184 }
185
186 fn is_satisfied(self, element: u16) -> bool {
187 self.0 == element
188 }
189
190 fn intersection_ordered(self, other: TestProperty) -> Simplification<TestProperty> {
191 if other.contains(self.0) {
193 return Simplification::Replace(self.into());
195 }
196 Simplification::Remove
198 }
199
200 fn symmetric_difference_ordered(self, other: TestProperty) -> Simplification<TestProperty> {
201 Simplification::Keep(self.into(), other)
206 }
207}
208
209impl Display for SingleNumber {
210 fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
211 write!(f, "{}", self.0)
212 }
213}
214
215#[doc(hidden)]
219#[derive(Clone, Copy, Debug, Eq, Ord, PartialEq, PartialOrd)]
220pub struct IsEven;
221
222impl From<IsEven> for TestProperty {
223 fn from(prop: IsEven) -> TestProperty {
224 TestProperty::IsEven(prop)
225 }
226}
227
228impl IsEven {
229 fn to_array(self) -> TestArray {
230 let mut result = TestArray::ZERO;
231 for i in (0..ARRAY_SIZE).step_by(2) {
232 result.set(i, true);
233 }
234 result
235 }
236
237 fn is_satisfied(self, element: u16) -> bool {
238 (element % 2) == 0
239 }
240
241 fn intersection_ordered(self, other: TestProperty) -> Simplification<TestProperty> {
242 Simplification::Keep(self.into(), other)
246 }
247
248 fn symmetric_difference_ordered(self, other: TestProperty) -> Simplification<TestProperty> {
249 Simplification::Keep(self.into(), other)
253 }
254}
255
256impl Display for IsEven {
257 fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
258 write!(f, "even")
259 }
260}
261
262#[doc(hidden)]
266#[derive(Clone, Copy, Debug, Eq, Ord, PartialEq, PartialOrd)]
267pub struct GreaterThan(u16);
268
269impl From<GreaterThan> for TestProperty {
270 fn from(prop: GreaterThan) -> TestProperty {
271 TestProperty::GreaterThan(prop)
272 }
273}
274
275impl GreaterThan {
276 fn to_array(self) -> TestArray {
277 let mut result = TestArray::ZERO;
278 for i in (self.0 as usize + 1)..ARRAY_SIZE {
279 result.set(i, true);
280 }
281 result
282 }
283
284 fn is_satisfied(self, element: u16) -> bool {
285 element > self.0
286 }
287
288 fn intersection_ordered(self, other: TestProperty) -> Simplification<TestProperty> {
289 match other {
294 TestProperty::GreaterThan(other) => {
295 if self.0 > other.0 {
297 Simplification::Replace(self.into())
298 } else {
299 Simplification::Replace(other.into())
300 }
301 }
302
303 _ => Simplification::Remove,
304 }
305 }
306
307 fn symmetric_difference_ordered(self, other: TestProperty) -> Simplification<TestProperty> {
308 Simplification::Keep(self.into(), other)
313 }
314}
315
316impl Display for GreaterThan {
317 fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
318 write!(f, ">{}", self.0)
319 }
320}
321
322mod proptest_support {
326 use super::*;
327
328 use std::ops::Range;
329
330 use proptest::prelude::*;
331 use proptest::strategy::Map;
332 use symbolic_sets::proptest::ArbitraryElement;
333
334 impl Arbitrary for SingleNumber {
335 type Parameters = ();
336 type Strategy = Map<Range<u16>, fn(u16) -> SingleNumber>;
337 fn arbitrary_with(_args: Self::Parameters) -> Self::Strategy {
338 (0..ARRAY_SIZE as u16).prop_map(SingleNumber)
339 }
340 }
341
342 impl Arbitrary for IsEven {
343 type Parameters = ();
344 type Strategy = Just<IsEven>;
345 fn arbitrary_with(_args: Self::Parameters) -> Self::Strategy {
346 Just(IsEven)
347 }
348 }
349
350 impl Arbitrary for GreaterThan {
351 type Parameters = ();
352 type Strategy = Map<Range<u16>, fn(u16) -> GreaterThan>;
353 fn arbitrary_with(_args: Self::Parameters) -> Self::Strategy {
354 (0..ARRAY_SIZE as u16).prop_map(GreaterThan)
355 }
356 }
357
358 impl Arbitrary for TestProperty {
359 type Parameters = ();
360 type Strategy = BoxedStrategy<TestProperty>;
361 fn arbitrary_with(_args: Self::Parameters) -> Self::Strategy {
362 prop_oneof![
363 any::<SingleNumber>().prop_map_into(), any::<IsEven>().prop_map_into(),
365 any::<GreaterThan>().prop_map_into(),
366 ]
367 .boxed()
368 }
369 }
370
371 impl ArbitraryElement for TestProperty {
372 type Element = u16;
373 type Strategy = BoxedStrategy<u16>;
374 fn arbitrary_element(set: &TestSet) -> Self::Strategy {
375 let elements = set.to_array();
376 let size = elements.count_ones();
377 (0..size)
378 .prop_map(move |idx| {
379 elements
380 .iter_ones()
381 .nth(idx)
382 .expect("Index should be valid") as u16
383 })
384 .boxed()
385 }
386 }
387}
388
389#[cfg(test)]
390mod tests {
391 use super::*;
392 symbolic_sets::test_anf_set!(TestProperty);
393 symbolic_sets::test_anf_set_with_elements!(TestProperty);
394}