partial_functional/monoid/
product.rs1use num_traits;
2
3use crate::semigroup::Semigroup;
4
5#[derive(Debug, Clone, Copy, PartialEq, Eq, PartialOrd, Ord)]
13pub struct Product<T>(pub T);
14
15impl<T: Semigroup + num_traits::Num> Default for Product<T> {
16 fn default() -> Self {
17 Self(num_traits::identities::One::one())
18 }
19}
20
21impl<T: PartialEq> PartialEq<T> for Product<T> {
22 fn eq(&self, other: &T) -> bool {
23 self.0 == *other
24 }
25}
26
27impl<T: PartialOrd> PartialOrd<T> for Product<T> {
28 fn partial_cmp(&self, other: &T) -> Option<std::cmp::Ordering> {
29 self.0.partial_cmp(other)
30 }
31}
32impl<T> From<T> for Product<T> {
33 fn from(value: T) -> Self {
34 Self(value)
35 }
36}
37
38impl<T: std::ops::Mul<Output = T>> Semigroup for Product<T> {
39 fn combine(self, rhs: Self) -> Self {
40 Self(self.0 * rhs.0)
41 }
42}
43
44#[cfg(test)]
45mod tests {
46 use crate::monoid::Monoid;
47
48 use super::*;
49
50 use quickcheck::{Arbitrary, Gen, TestResult};
51 use quickcheck_macros::quickcheck;
52
53 impl Arbitrary for Product<u32> {
54 fn arbitrary(g: &mut quickcheck::Gen) -> Self {
55 Product(u8::arbitrary(g).into())
56 }
57
58 fn shrink(&self) -> Box<dyn Iterator<Item = Self>> {
59 Box::new(u32::shrink(&self.0).map(|x| x.into()))
60 }
61 }
62
63 #[quickcheck]
64 fn identity_property() {
65 assert_eq!(Product::<u32>(1), Product::empty())
66 }
67
68 fn property_product_of_vec_is_same_as_product_combine(vec: Vec<u8>) -> TestResult {
69 if vec.len() < 2 {
70 return TestResult::discard();
71 }
72
73 let left: Product<u128> = vec
74 .iter()
75 .copied()
76 .map(|x| x as u128)
77 .product::<u128>()
78 .into();
79 let right = vec
80 .iter()
81 .copied()
82 .map(|x| Product::from(x as u128))
83 .fold(Product::default(), |a, x| a.combine(x));
84
85 TestResult::from_bool(left == right)
86 }
87
88 #[test]
89 fn product_of_vec_is_same_as_product_combine() {
90 let gen = Gen::new(15);
91 let mut qtest = quickcheck::QuickCheck::new().gen(gen);
92
93 qtest.quickcheck(property_product_of_vec_is_same_as_product_combine as fn(Vec<u8>) -> TestResult);
94 }
95
96 #[quickcheck]
97 fn associativity_property(x: Product<u32>, y: Product<u32>, z: Product<u32>) -> bool {
98 x.combine(y.combine(z)) == x.combine(y).combine(z)
99 }
100}