use std::fmt::Debug;
use proptest::prelude::*;
use proptest::sample::SizeRange;
use crate::anf::AnfSet;
use crate::anf::Simplifiable;
impl<P> Arbitrary for AnfSet<P>
where
P: Arbitrary + Clone + Eq + Into<AnfSet<P>> + Ord + Simplifiable + 'static,
{
type Parameters = SizeRange;
type Strategy = BoxedStrategy<Self>;
fn arbitrary_with(args: Self::Parameters) -> Self::Strategy {
proptest::collection::vec(any::<P>(), args)
.prop_map(|properties| {
properties
.into_iter()
.map(|property| property.into())
.fold(Self::empty(), |a, b| a | b)
})
.boxed()
}
}
pub trait ArbitraryElement: Sized {
type Element;
type Strategy: Strategy<Value = Self::Element>;
fn arbitrary_element(set: &AnfSet<Self>) -> Self::Strategy;
}
#[derive(Debug)]
pub struct SetAndElement<S, E> {
pub set: S,
pub element: E,
}
impl<P, E> Arbitrary for SetAndElement<AnfSet<P>, E>
where
P: ArbitraryElement<Element = E>,
AnfSet<P>: Arbitrary<Parameters = SizeRange> + Clone + Debug + 'static,
E: Debug,
{
type Parameters = ();
type Strategy = BoxedStrategy<Self>;
fn arbitrary_with(_args: Self::Parameters) -> Self::Strategy {
any_with::<AnfSet<P>>((1..10).into())
.prop_filter("nonempty set", |set| !set.is_empty())
.prop_flat_map(move |set| {
let element = P::arbitrary_element(&set);
(Just(set), element)
})
.prop_map(|(set, element)| SetAndElement { set, element })
.boxed()
}
}
#[doc(hidden)]
pub use indoc::indoc as __indoc;
#[doc(hidden)]
pub use proptest_attr_macro::proptest as __proptest;
#[macro_export]
macro_rules! test_anf_set {
($typ:ty) => {
#[$crate::proptest::__proptest]
fn complement_distributes_over_symmetric_difference(
a: $crate::anf::AnfSet<$typ>,
b: $crate::anf::AnfSet<$typ>,
) {
let lhs = a.clone() ^ b.clone();
let rhs = !a.clone() ^ !b.clone();
assert_eq!(
lhs, rhs,
$crate::proptest::__indoc! {"
Given set A
{}
and set B
{}
A ⊕ B
{}
and !A ⊕ !B
{}
should be equal"},
a, b, lhs, rhs,
);
}
#[$crate::proptest::__proptest]
fn difference_annhilates(a: $crate::anf::AnfSet<$typ>) {
let diff = a.clone() - a.clone();
assert!(
diff.is_empty(),
$crate::proptest::__indoc! {"
Given set
{}
A \\ A
{}
should be empty"},
a,
diff,
);
}
#[$crate::proptest::__proptest]
fn difference_has_unit(a: $crate::anf::AnfSet<$typ>) {
let lhs = a.clone();
let rhs = a.clone() - $crate::anf::AnfSet::empty();
assert_eq!(
lhs, rhs,
$crate::proptest::__indoc! {"
Given set A
{}
A \\ ∅
{}
should be the same"},
lhs, rhs,
);
}
#[$crate::proptest::__proptest]
fn difference_has_zero(a: $crate::anf::AnfSet<$typ>) {
let diff = a.clone() - $crate::anf::AnfSet::universe();
assert!(
diff.is_empty(),
$crate::proptest::__indoc! {"
Given set A
{}
A \\ 1
{}
should be empty"},
a,
diff,
);
}
#[$crate::proptest::__proptest]
fn intersection_has_unit(a: $crate::anf::AnfSet<$typ>) {
let intersection = a.clone() & $crate::anf::AnfSet::universe();
assert_eq!(
a, intersection,
$crate::proptest::__indoc! {"
Given set A
{}
A ∩ 1
{}
should be the same"},
a, intersection,
);
}
#[$crate::proptest::__proptest]
fn intersection_has_zero(a: $crate::anf::AnfSet<$typ>) {
let intersection = a.clone() & $crate::anf::AnfSet::empty();
assert!(
intersection.is_empty(),
$crate::proptest::__indoc! {"
Intersection with empty
of {}
with ∅
should be empty
got {}"},
a,
intersection,
);
}
#[$crate::proptest::__proptest]
fn intersection_is_idempotent(a: $crate::anf::AnfSet<$typ>) {
let lhs = a.clone() & a.clone();
let rhs = a.clone();
assert_eq!(
lhs, rhs,
$crate::proptest::__indoc! {"
Given set A
{}
A ∩ A
{}
should be same"},
a, lhs,
);
}
#[$crate::proptest::__proptest]
fn intersection_is_symmetric(a: $crate::anf::AnfSet<$typ>, b: $crate::anf::AnfSet<$typ>) {
let lhs = a.clone() & b.clone();
let rhs = b.clone() & a.clone();
assert_eq!(
lhs, rhs,
$crate::proptest::__indoc! {"
Given set A
{}
and set B
{}
A ∩ B
{}
and B ∩ A
{}
should be same"},
a, b, lhs, rhs,
);
}
#[$crate::proptest::__proptest]
fn intersection_left_distributes_over_symmetric_difference(
a: $crate::anf::AnfSet<$typ>,
b: $crate::anf::AnfSet<$typ>,
c: $crate::anf::AnfSet<$typ>,
) {
let lhs = a.clone() & (b.clone() ^ c.clone());
let rhs = (a.clone() & b.clone()) ^ (a.clone() & c.clone());
assert_eq!(
lhs, rhs,
$crate::proptest::__indoc! {"
Given set A
{}
set B
{}
and set C
{}
A ∩ (B ⊕ C)
{}
and (A ∩ B) ⊕ (A ∩ C)
{}
should be same"},
a, b, c, lhs, rhs,
);
}
#[$crate::proptest::__proptest]
fn intersection_right_distributes_over_symmetric_difference(
a: $crate::anf::AnfSet<$typ>,
b: $crate::anf::AnfSet<$typ>,
c: $crate::anf::AnfSet<$typ>,
) {
let lhs = (a.clone() ^ b.clone()) & c.clone();
let rhs = (a.clone() & c.clone()) ^ (b.clone() & c.clone());
assert_eq!(
lhs, rhs,
$crate::proptest::__indoc! {"
Given set A
{}
set B
{}
and set C
{}
(A ⊕ B) ∩ C
{}
and (A ∩ C) ⊕ (B ∩ C)
{}
should be same"},
a, b, c, lhs, rhs,
);
}
#[$crate::proptest::__proptest]
fn intersection_with_complement_is_empty(a: $crate::anf::AnfSet<$typ>) {
let negated = !a.clone();
let intersection = a.clone() & negated.clone();
assert!(
intersection.is_empty(),
$crate::proptest::__indoc! {"
Intersection with negation
of {}
with {}
should be empty
got {}"},
a,
negated,
intersection,
);
}
#[$crate::proptest::__proptest]
fn symmetric_difference_annhilates(a: $crate::anf::AnfSet<$typ>) {
let diff = a.clone() ^ a.clone();
assert!(
diff.is_empty(),
$crate::proptest::__indoc! {"
Given set
{}
A ⊕ A
{}
should be empty"},
a,
diff,
);
}
#[$crate::proptest::__proptest]
fn symmetric_difference_has_unit(a: $crate::anf::AnfSet<$typ>) {
let diff = a.clone() ^ $crate::anf::AnfSet::empty();
assert_eq!(
a, diff,
$crate::proptest::__indoc! {"
Given set A
{}
A ⊕ ∅
{}
should be the same"},
a, diff,
);
}
#[$crate::proptest::__proptest]
fn symmetric_difference_is_union_minus_intersection(
a: $crate::anf::AnfSet<$typ>,
b: $crate::anf::AnfSet<$typ>,
) {
let lhs = a.clone() ^ b.clone();
let rhs = (a.clone() | b.clone()) - (a.clone() & b.clone());
assert_eq!(
lhs, rhs,
$crate::proptest::__indoc! {"
Given set A
{}
and set B
{}
A ⊕ B
{}
and (A ∪ B) \\ (A ∩ B)
{}
should be equal"},
a, b, lhs, rhs,
);
}
#[$crate::proptest::__proptest]
fn symmetric_difference_is_union_of_differences(
a: $crate::anf::AnfSet<$typ>,
b: $crate::anf::AnfSet<$typ>,
) {
let lhs = a.clone() ^ b.clone();
let rhs = (a.clone() - b.clone()) | (b.clone() - a.clone());
assert_eq!(
lhs, rhs,
$crate::proptest::__indoc! {"
Given set A
{}
and set B
{}
A ⊕ B
{}
and (A \\ B) ∪ (B \\ A)
{}
should be equal"},
a, b, lhs, rhs,
);
}
#[$crate::proptest::__proptest]
fn symmetric_difference_with_complement_is_universe(a: $crate::anf::AnfSet<$typ>) {
let lhs = a.clone() ^ !a.clone();
let rhs = $crate::anf::AnfSet::universe();
assert_eq!(
lhs, rhs,
$crate::proptest::__indoc! {"
Given set A
{}
A ⊕ !A
{}
should be the universe"},
a, lhs,
);
}
#[$crate::proptest::__proptest]
fn union_has_unit(a: $crate::anf::AnfSet<$typ>) {
let union = a.clone() | $crate::anf::AnfSet::empty();
assert_eq!(
a, union,
$crate::proptest::__indoc! {"
Given set A
{}
A ∪ ∅
{}
should be the same"},
a, union,
);
}
#[$crate::proptest::__proptest]
fn union_is_idempotent(a: $crate::anf::AnfSet<$typ>) {
let lhs = a.clone() | a.clone();
let rhs = a.clone();
assert_eq!(
lhs, rhs,
$crate::proptest::__indoc! {"
Given set A
{}
A ∪ A
{}
should be same"},
a, lhs,
);
}
#[$crate::proptest::__proptest]
fn union_is_symmetric(a: $crate::anf::AnfSet<$typ>, b: $crate::anf::AnfSet<$typ>) {
let lhs = a.clone() | b.clone();
let rhs = b.clone() | a.clone();
assert_eq!(
lhs, rhs,
$crate::proptest::__indoc! {"
Given set A
{}
and set B
{}
A ∪ B
{}
and B ∪ A
{}
should be same"},
a, b, lhs, rhs,
);
}
};
}
#[macro_export]
macro_rules! test_anf_set_with_elements {
($typ:ty) => {
#[$crate::proptest::__proptest]
fn difference_membership(
a: $crate::proptest::SetAndElement<$crate::anf::AnfSet<$typ>, _>,
b: $crate::anf::AnfSet<$typ>,
) {
let diff = a.set.clone() - b.clone();
if b.contains(&a.element) {
assert!(
!diff.contains(&a.element),
$crate::proptest::__indoc! {"
Difference {}
of {}
and {}
should not contain {}"},
diff,
a.set,
b,
a.element,
);
} else {
assert!(
diff.contains(&a.element),
$crate::proptest::__indoc! {"
Difference {}
of {}
and {}
should contain {}"},
diff,
a.set,
b,
a.element,
);
}
}
#[$crate::proptest::__proptest]
fn intersection_membership(
a: $crate::proptest::SetAndElement<$crate::anf::AnfSet<$typ>, _>,
b: $crate::anf::AnfSet<$typ>,
) {
let intersection = a.set.clone() & b.clone();
if b.contains(&a.element) {
assert!(
intersection.contains(&a.element),
$crate::proptest::__indoc! {"
Intersection {}
of {}
and {}
should contain {}"},
intersection,
a.set,
b,
a.element,
);
} else {
assert!(
!intersection.contains(&a.element),
$crate::proptest::__indoc! {"
Intersection {}
of {}
and {}
should not contain {}"},
intersection,
a.set,
b,
a.element,
);
}
}
#[$crate::proptest::__proptest]
fn set_element_in_set(a: $crate::proptest::SetAndElement<$crate::anf::AnfSet<$typ>, _>) {
assert!(
a.set.contains(&a.element),
$crate::proptest::__indoc! {"
Set {}
should contain {}"},
a.set,
a.element,
);
}
#[$crate::proptest::__proptest]
fn union_membership(
a: $crate::proptest::SetAndElement<$crate::anf::AnfSet<$typ>, _>,
b: $crate::anf::AnfSet<$typ>,
) {
let union = a.set.clone() | b.clone();
assert!(
union.contains(&a.element),
$crate::proptest::__indoc! {"
Union {}
of {}
and {}
should contain {}"},
union,
a.set,
b,
a.element,
);
}
#[$crate::proptest::__proptest]
fn union_with_complement_is_universe(a: $crate::anf::AnfSet<$typ>) {
let negated = !a.clone();
let union = a.clone() | negated.clone();
let universe = $crate::anf::AnfSet::universe();
assert_eq!(
union, universe,
$crate::proptest::__indoc! {"
Union with negation
of {}
with {}
should be the universe
got {}"},
a, negated, union,
);
}
};
}