1use std::fmt::Debug;
2
3use crate::test::cartesian_power;
4
5pub fn monoid<S: Debug + PartialEq + Clone, const N: usize>(
10 items: &[S; N],
11 f: &impl Fn(S, S) -> S,
12 zero: S, ) -> Result<(), &'static str> {
14 semigroup(items, f)?;
15 identity(items, f, zero)?;
16 Ok(())
17}
18
19pub fn semigroup<S: Debug + PartialEq + Clone, const N: usize>(
23 items: &[S; N],
24 f: &impl Fn(S, S) -> S,
25) -> Result<(), &'static str> {
26 associativity(items, f)?;
27 Ok(())
28}
29
30pub fn semiring<S: Debug + PartialEq + Clone, const N: usize>(
37 items: &[S; N],
38 f: &impl Fn(S, S) -> S,
39 g: &impl Fn(S, S) -> S,
40 zero: S, one: S, ) -> Result<(), &'static str> {
43 commutative_monoid(items, f, zero.clone())?;
44 monoid(items, g, one.clone())?;
45
46 absorbing_element(items, g, zero)?;
47
48 distributive(items, f, g)?;
49
50 Ok(())
51}
52
53pub fn ring<S: Debug + PartialEq + Clone, const N: usize>(
57 items: &[S; N],
58 f: &impl Fn(S, S) -> S,
59 g: &impl Fn(S, S) -> S,
60 zero: S, one: S, b: &impl Fn(S) -> S,
63) -> Result<(), &'static str> {
64 semiring(items, f, g, zero.clone(), one)?;
65 inverse(items, f, zero, b)?;
66 Ok(())
67}
68
69pub fn integral_domain<S: Debug + PartialEq + Clone, const N: usize>(
73 items: &[S; N],
74 f: &impl Fn(S, S) -> S,
75 g: &impl Fn(S, S) -> S,
76 zero: S, one: S, inverse_f: &impl Fn(S) -> S, ) -> Result<(), &'static str> {
80 commutative_ring(items, f, g, zero.clone(), one, inverse_f)?;
81 no_nonzero_zero_divisors(items, g, zero)?;
82 Ok(())
83}
84
85pub fn no_nonzero_zero_divisors<S: Debug + PartialEq + Clone, const N: usize>(
89 items: &[S; N],
90 f: &impl Fn(S, S) -> S,
91 zero: S,
92) -> Result<(), &'static str> {
93 for a in items {
94 for b in items {
95 if *a != zero && *b != zero {
96 if f(a.clone(), b.clone()) == zero {
97 return Err("No nonzero zero divisors check failed.");
98 };
99 if f(b.clone(), a.clone()) == zero {
100 return Err("No nonzero zero divisors check failed.");
101 };
102 }
103 }
104 }
105 Ok(())
106}
107
108pub fn commutative_ring<S: Debug + PartialEq + Clone, const N: usize>(
112 items: &[S; N],
113 f: &impl Fn(S, S) -> S, g: &impl Fn(S, S) -> S, zero: S, one: S, inverse_f: &impl Fn(S) -> S,
118) -> Result<(), &'static str> {
119 semiring(items, f, g, zero.clone(), one)?;
120 inverse(items, f, zero, inverse_f)?;
121 commutativity(items, g)?;
122 Ok(())
123}
124
125pub fn field<S: Debug + PartialEq + Clone, const N: usize>(
129 items: &[S; N],
130 f: &impl Fn(S, S) -> S,
131 g: &impl Fn(S, S) -> S,
132 zero: S, one: S, inverse_f: &impl Fn(S) -> S, inverse_g: &impl Fn(S) -> S, ) -> Result<(), &'static str> {
137 commutative_ring(items, f, g, zero.clone(), one.clone(), inverse_f)?;
138 nonzero_inverse(items, g, one, zero, inverse_g)?;
139 Ok(())
140}
141
142pub fn commutative_monoid<S: Debug + PartialEq + Clone, const N: usize>(
146 items: &[S; N],
147 f: &impl Fn(S, S) -> S,
148 zero: S,
149) -> Result<(), &'static str> {
150 monoid(items, f, zero)?;
151 commutativity(items, f)?;
152 Ok(())
153}
154
155pub fn group<S: Debug + PartialEq + Clone, const N: usize>(
161 items: &[S; N],
162 f: &impl Fn(S, S) -> S,
163 zero: S, b: &impl Fn(S) -> S, ) -> Result<(), &'static str> {
166 monoid(items, f, zero.clone())?;
167 inverse(items, f, zero, b)?;
168 Ok(())
169}
170
171pub fn abelian_group<S: Debug + PartialEq + Clone, const N: usize>(
175 items: &[S; N],
176 f: &impl Fn(S, S) -> S,
177 zero: S,
178 b: &impl Fn(S) -> S, ) -> Result<(), &'static str> {
180 group(items, f, zero, b)?;
181 commutativity(items, f)?;
182 Ok(())
183}
184
185pub fn distributive<S: Debug + PartialEq + Clone, const N: usize>(
191 items: &[S; N],
192 f: &impl Fn(S, S) -> S,
193 g: &impl Fn(S, S) -> S,
194) -> Result<(), &'static str> {
195 left_distributes(items, f, g)?;
196 right_distributes(items, f, g)?;
197 Ok(())
198}
199
200pub fn left_distributes<S: Debug + PartialEq + Clone, const N: usize>(
204 items: &[S; N],
205 f: impl Fn(S, S) -> S,
206 g: impl Fn(S, S) -> S,
207) -> Result<(), &'static str> {
208 for [a, b, c] in cartesian_power(items) {
209 if g(a.clone(), f(b.clone(), c.clone()))
210 != f(g(a.clone(), b.clone()), g(a.clone(), c.clone()))
211 {
212 return Err("Left distributive property check failed.");
213 }
214 }
215 Ok(())
216}
217
218pub fn right_distributes<S: Debug + PartialEq + Clone, const N: usize>(
222 items: &[S; N],
223 f: impl Fn(S, S) -> S,
224 g: impl Fn(S, S) -> S,
225) -> Result<(), &'static str> {
226 for [a, b, c] in cartesian_power(items) {
227 if g(f(b.clone(), c.clone()), a.clone())
228 != f(g(b.clone(), a.clone()), g(c.clone(), a.clone()))
229 {
230 return Err("Right distributive property check failed.");
231 }
232 }
233 Ok(())
234}
235
236pub fn absorbing_element<S: Debug + PartialEq + Clone, const N: usize>(
240 items: &[S; N],
241 f: impl Fn(S, S) -> S,
242 z: S, ) -> Result<(), &'static str> {
244 for a in items {
245 if f(a.clone(), z.clone()) != z.clone() {
247 return Err("Absorbing element property check failed.");
248 }
249
250 if f(z.clone(), a.clone()) != z.clone() {
252 return Err("Absorbing element property check failed.");
253 }
254 }
255 Ok(())
256}
257
258pub fn inverse<S: Debug + PartialEq + Clone, const N: usize>(
262 items: &[S; N],
263 f: impl Fn(S, S) -> S,
264 e: S, b: impl Fn(S) -> S, ) -> Result<(), &'static str> {
267 for a in items {
269 if f(a.clone(), b(a.clone())) != e {
270 return Err("Inverse check failed.");
271 }
272 if f(b(a.clone()), a.clone()) != e {
273 return Err("Inverse check failed.");
274 }
275 }
276 Ok(())
277}
278
279pub fn nonzero_inverse<S: Debug + PartialEq + Clone, const N: usize>(
283 items: &[S; N],
284 f: impl Fn(S, S) -> S,
285 e: S,
286 zero: S,
287 b: impl Fn(S) -> S,
288) -> Result<(), &'static str> {
289 for a in items {
291 if *a != zero {
292 if f(a.clone(), b(a.clone())) != e {
293 return Err("Nonzero inverse check failed.");
294 }
295 if f(b(a.clone()), a.clone()) != e {
296 return Err("Nonzero inverse check failed.");
297 }
298 }
299 }
300 Ok(())
301}
302
303pub fn identity<S: Debug + PartialEq + Clone, const N: usize>(
307 items: &[S; N],
308 f: impl Fn(S, S) -> S,
309 e: S,
310) -> Result<(), &'static str> {
311 for a in items {
313 if f(e.clone(), a.clone()) != a.clone() {
314 return Err("Left Identity check failed.");
315 }
316 if f(a.clone(), e.clone()) != a.clone() {
317 return Err("Right Identity check failed.");
318 }
319 }
320 Ok(())
321}
322
323pub fn associativity<S: Debug + PartialEq + Clone, const N: usize>(
327 items: &[S; N],
328 f: impl Fn(S, S) -> S,
329) -> Result<(), &'static str> {
330 for [a, b, c] in cartesian_power(items) {
331 if f(a.clone(), f(b.clone(), c.clone())) != f(f(a.clone(), b.clone()), c.clone())
333 {
335 return Err("Associativity check failed.");
336 }
337 }
338 Ok(())
339}
340
341pub fn commutativity<S: Debug + PartialEq + Clone, const N: usize>(
345 items: &[S; N],
346 f: impl Fn(S, S) -> S,
347) -> Result<(), &'static str> {
348 for [x, y] in cartesian_power(items) {
349 if f(x.clone(), y.clone()) != f(y.clone(), x.clone()) {
350 return Err("Commutativity check failed.");
352 }
353 }
354 Ok(())
355}
356
357pub fn idempotency<S: Debug + PartialEq + Clone, const N: usize>(
361 items: &[S; N],
362 f: impl Fn(S, S) -> S,
363) -> Result<(), &'static str> {
364 for x in items {
365 if f(x.clone(), x.clone()) != x.clone() {
366 return Err("Idempotency check failed.");
367 }
368 }
369 Ok(())
370}
371
372pub fn linearity<S: Debug + PartialEq + Clone, R: Debug + PartialEq + Clone>(
381 items: &[S],
382 f: impl Fn(S, S) -> S,
383 g: impl Fn(R, R) -> R,
384 q: impl Fn(S) -> R,
385) -> Result<(), &'static str> {
386 for [a, b] in cartesian_power(items) {
387 if q(f(a.clone(), b.clone())) != g(q(b.clone()), q(a.clone())) {
388 return Err("Linearity check failed.");
390 }
391 }
392 Ok(())
393}
394
395pub fn bilinearity<
405 S: Debug + PartialEq + Clone,
406 R: Debug + PartialEq + Clone,
407 T: Debug + PartialEq + Clone,
408>(
409 items_f: &[S],
410 items_h: &[T],
411 f: impl Fn(S, S) -> S,
412 h: impl Fn(T, T) -> T,
413 g: impl Fn(R, R) -> R,
414 q: impl Fn(S, T) -> R,
415) -> Result<(), &'static str> {
416 for [a, b] in cartesian_power(items_f) {
417 for [c, d] in cartesian_power(items_h) {
418 if q(f(a.clone(), b.clone()), c.clone())
419 != g(q(a.clone(), c.clone()), q(b.clone(), c.clone()))
420 || q(a.clone(), h(c.clone(), d.clone()))
421 != g(q(a.clone(), c.clone()), q(a.clone(), d.clone()))
422 {
423 return Err("Bilinearity check failed.");
426 }
427 }
428 }
429 Ok(())
430}
431
432pub fn get_single_function_properties<S: Debug + PartialEq + Clone, const N: usize>(
445 items: &[S; N],
446 f: impl Fn(S, S) -> S,
447 e: S,
449 b: impl Fn(S) -> S,
451 z: S,
453) -> Vec<String> {
454 let mut properties_satisfied: Vec<String> = Vec::new();
456
457 if associativity(items, &f).is_ok() {
459 properties_satisfied.push("associativity".to_string());
460 }
461 if commutativity(items, &f).is_ok() {
462 properties_satisfied.push("commutativity".to_string());
463 }
464 if idempotency(items, &f).is_ok() {
465 properties_satisfied.push("idempotency".to_string());
466 }
467 if identity(items, &f, e.clone()).is_ok() {
468 properties_satisfied.push("identity".to_string());
469 }
470 if inverse(items, &f, e.clone(), b).is_ok() {
471 properties_satisfied.push("inverse".to_string());
472 }
473 if absorbing_element(items, &f, z).is_ok() {
474 properties_satisfied.push("absorbing_element".to_string());
475 }
476
477 properties_satisfied
478}
479
480#[cfg(test)]
485mod test {
486 use std::collections::HashSet;
487
488 use crate::algebra::*;
489
490 static TEST_ITEMS: &[u32; 14] = &[0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13];
491 static TEST_ITEMS_NONZERO: &[u32; 13] = &[1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13];
492 static TEST_MOD_PRIME_7: &[u32; 7] = &[0, 1, 2, 3, 4, 5, 6];
493 static TEST_BOOLS: &[bool; 2] = &[false, true];
494
495 #[test]
496 fn test_associativity() {
497 assert!(associativity(TEST_ITEMS, u32::max).is_ok());
499 assert!(associativity(TEST_ITEMS, u32::wrapping_pow).is_err());
500 }
501
502 #[test]
503 fn test_left_distributes() {
504 assert!(left_distributes(TEST_ITEMS, u32::wrapping_sub, u32::wrapping_mul).is_ok());
507 assert!(left_distributes(TEST_ITEMS, u32::wrapping_sub, u32::wrapping_pow).is_err());
508 }
509
510 #[test]
511 fn test_right_distributes() {
512 assert!(right_distributes(TEST_ITEMS, u32::wrapping_sub, u32::wrapping_mul).is_ok());
515 assert!(right_distributes(TEST_ITEMS, u32::wrapping_sub, u32::wrapping_pow).is_err());
516 }
517
518 #[test]
519 fn test_nonzero_inverse() {
520 assert!(
522 nonzero_inverse(TEST_ITEMS, u32::wrapping_add, 0, 0, |x| {
523 0u32.wrapping_sub(x)
524 })
525 .is_ok()
526 );
527 assert!(
528 nonzero_inverse(TEST_ITEMS, u32::wrapping_sub, 0, 0, |x| {
529 0u32.wrapping_add(x)
530 })
531 .is_ok()
532 );
533 assert!(
534 right_distributes(TEST_ITEMS_NONZERO, u32::wrapping_div, u32::wrapping_mul).is_err()
535 );
536 }
537
538 #[test]
539 fn test_idempotency() {
540 assert!(idempotency(TEST_ITEMS, u32::max).is_ok());
542
543 assert!(idempotency(TEST_ITEMS, u32::wrapping_add).is_err());
544 }
545
546 #[test]
547 fn test_commutativity() {
548 assert!(commutativity(TEST_ITEMS, u32::max).is_ok());
550 assert!(commutativity(TEST_ITEMS_NONZERO, u32::wrapping_div).is_err());
551 }
553
554 #[test]
555 fn test_commutative_ring() {
556 assert!(
558 commutative_ring(
559 TEST_ITEMS,
560 &u32::wrapping_add,
561 &u32::wrapping_mul,
562 0,
563 1,
564 &|x| 0u32.wrapping_sub(x),
565 )
566 .is_ok()
567 );
568
569 assert!(
571 commutative_ring(
572 TEST_ITEMS,
573 &u32::wrapping_add,
574 &u32::wrapping_pow,
575 0,
576 1,
577 &|x| 0u32.wrapping_sub(x),
578 )
579 .is_err()
580 );
581
582 assert!(
584 commutative_ring(
585 &[[[1, 2], [3, 4]], [[5, 6], [7, 8]], [[9, 10], [11, 12]]],
586 &|a, b| {
587 [
588 [a[0][0] + b[0][0], a[0][1] + b[0][1]],
589 [a[1][0] + b[1][0], a[1][0] + b[1][1]],
590 ]
591 },
592 &|a, b| {
593 [
594 [
595 a[0][0] * b[0][0] + a[0][1] * b[1][0],
596 a[0][0] * b[0][1] + a[0][1] * b[1][1],
597 ],
598 [
599 a[1][0] * b[0][0] + a[1][1] * b[1][0],
600 a[1][0] * b[0][1] + a[1][1] * b[1][1],
601 ],
602 ]
603 },
604 [[0, 0], [0, 0]],
605 [[1, 0], [0, 1]],
606 &|a| {
607 [
608 [
609 -a[0][0] / (a[0][0] * a[1][1] - a[0][1] * a[1][1]),
610 -a[0][1] / (a[0][0] * a[1][1] - a[0][1] * a[1][1]),
611 ],
612 [
613 -a[1][0] / (a[0][0] * a[1][1] - a[0][1] * a[1][1]),
614 -a[1][1] / (a[0][0] * a[1][1] - a[0][1] * a[1][1]),
615 ],
616 ]
617 },
618 )
619 .is_err()
620 );
621 }
622
623 #[test]
624 fn test_commutative_monoid() {
625 assert!(commutative_monoid(TEST_ITEMS, &u32::wrapping_add, 0).is_ok());
627
628 assert!(commutative_monoid(TEST_ITEMS, &u32::wrapping_mul, 1).is_ok());
630 assert!(commutative_monoid(TEST_ITEMS, &u32::wrapping_add, 0).is_ok());
631
632 assert!(commutative_monoid(TEST_BOOLS, &|a, b| a & b, true).is_ok()); assert!(commutative_monoid(TEST_ITEMS, &u32::wrapping_sub, 0).is_err());
637
638 assert!(commutative_monoid(TEST_ITEMS_NONZERO, &u32::wrapping_add, 1).is_err()); assert!(commutative_monoid(TEST_ITEMS, &u32::wrapping_pow, 3).is_err());
643 }
644
645 #[test]
646 fn test_semigroup() {
647 assert!(semigroup(TEST_ITEMS_NONZERO, &u32::wrapping_add).is_ok());
649 assert!(semigroup(TEST_ITEMS, &u32::wrapping_add).is_ok());
651 assert!(semigroup(TEST_ITEMS, &u32::wrapping_mul).is_ok());
653 assert!(semigroup(TEST_BOOLS, &|a, b| a & b).is_ok()); assert!(
657 semigroup(
658 &[[[1, 2], [3, 4]], [[5, 6], [7, 8]], [[9, 10], [11, 12]]],
659 &|a, b| {
660 [
661 [
662 a[0][0] * b[0][0] + a[0][1] * b[1][0],
663 a[0][0] * b[0][1] + a[0][1] * b[1][1],
664 ],
665 [
666 a[1][0] * b[0][0] + a[1][1] * b[1][0],
667 a[1][0] * b[0][1] + a[1][1] * b[1][1],
668 ],
669 ]
670 },
671 )
672 .is_ok()
673 );
674 assert!(semigroup(TEST_ITEMS, &u32::wrapping_pow).is_err());
676 }
677
678 #[test]
679 fn test_identity() {
680 assert!(identity(TEST_ITEMS, u32::wrapping_add, 0).is_ok());
682
683 assert!(identity(TEST_ITEMS, u32::wrapping_add, 5).is_err());
684 }
685
686 #[test]
687 fn test_inverse() {
688 assert!(inverse(TEST_ITEMS, u32::wrapping_add, 0, |x| 0u32.wrapping_sub(x)).is_ok());
690
691 assert!(inverse(TEST_ITEMS, u32::wrapping_add, 0, |x| 0u32.wrapping_add(x)).is_err());
692 }
693
694 #[test]
695 fn test_distributive() {
696 assert!(distributive(TEST_ITEMS, &u32::wrapping_add, &u32::wrapping_mul).is_ok());
698 assert!(distributive(TEST_ITEMS, &u32::wrapping_add, &u32::max).is_err());
699 }
700
701 #[test]
702 fn test_linearity() {
703 assert!(
706 linearity(TEST_ITEMS, u32::wrapping_add, u32::wrapping_add, |x| {
707 u32::wrapping_mul(x, 5)
708 })
709 .is_ok()
710 );
711 assert!(
712 linearity(TEST_ITEMS, u32::wrapping_add, u32::wrapping_add, |x| {
713 u32::pow(x, 5)
714 })
715 .is_err()
716 );
717 }
718
719 #[test]
720 fn test_bilinearity() {
721 assert!(
724 bilinearity(
725 TEST_ITEMS,
726 TEST_ITEMS,
727 u32::wrapping_add,
728 u32::wrapping_add,
729 u32::wrapping_add,
730 u32::wrapping_mul
731 )
732 .is_ok()
733 );
734 assert!(
735 bilinearity(
736 TEST_ITEMS,
737 TEST_ITEMS,
738 u32::wrapping_add,
739 u32::wrapping_add,
740 u32::wrapping_add,
741 u32::pow
742 )
743 .is_err()
744 );
745 }
746
747 #[test]
748 fn test_group() {
749 assert!(group(TEST_ITEMS, &u32::wrapping_add, 0, &|x| 0u32.wrapping_sub(x)).is_ok());
751 assert!(group(TEST_MOD_PRIME_7, &modulo_add_7, 0, &modulo_sub_7).is_ok());
753 assert!(group(TEST_ITEMS, &modulo_add_14, 0, &modulo_sub_14).is_ok());
755 assert!(
757 group(TEST_ITEMS_NONZERO, &u32::wrapping_mul, 1, &|x| 1u32
758 .wrapping_div(x))
759 .is_err()
760 );
761 }
762
763 #[test]
764 fn test_abelian_group() {
765 assert!(
767 abelian_group(TEST_ITEMS, &u32::wrapping_add, 0, &|x| 0u32.wrapping_sub(x)).is_ok()
768 );
769 assert!(abelian_group(TEST_MOD_PRIME_7, &modulo_add_7, 0, &modulo_sub_7).is_ok());
771 assert!(
773 abelian_group(TEST_ITEMS_NONZERO, &u32::wrapping_mul, 1, &|x| 1u32
774 .wrapping_div(x))
775 .is_err()
776 );
777 assert!(
779 abelian_group(
780 &[[[1, 2], [3, 4]], [[5, 6], [7, 8]], [[9, 10], [11, 12]]],
781 &|a, b| {
782 [
783 [
784 a[0][0] * b[0][0] + a[0][1] * b[1][0],
785 a[0][0] * b[0][1] + a[0][1] * b[1][1],
786 ],
787 [
788 a[1][0] * b[0][0] + a[1][1] * b[1][0],
789 a[1][0] * b[0][1] + a[1][1] * b[1][1],
790 ],
791 ]
792 },
793 [[1, 0], [0, 1]],
794 &|a| {
795 [
796 [
797 -a[0][0] / (a[0][0] * a[1][1] - a[0][1] * a[1][1]),
798 -a[0][1] / (a[0][0] * a[1][1] - a[0][1] * a[1][1]),
799 ],
800 [
801 -a[1][0] / (a[0][0] * a[1][1] - a[0][1] * a[1][1]),
802 -a[1][1] / (a[0][0] * a[1][1] - a[0][1] * a[1][1]),
803 ],
804 ]
805 },
806 )
807 .is_err()
808 );
809 }
810
811 #[test]
812 fn test_monoid() {
813 assert!(monoid(TEST_ITEMS, &u32::wrapping_add, 0).is_ok());
815 assert!(monoid(TEST_ITEMS_NONZERO, &u32::wrapping_mul, 1).is_ok());
817 assert!(monoid(TEST_ITEMS, &u32::wrapping_mul, 1).is_ok());
818 assert!(
820 monoid(
821 &[[[1, 2], [3, 4]], [[5, 6], [7, 8]], [[9, 10], [11, 12]]],
822 &|a, b| {
823 [
824 [
825 a[0][0] * b[0][0] + a[0][1] * b[1][0],
826 a[0][0] * b[0][1] + a[0][1] * b[1][1],
827 ],
828 [
829 a[1][0] * b[0][0] + a[1][1] * b[1][0],
830 a[1][0] * b[0][1] + a[1][1] * b[1][1],
831 ],
832 ]
833 },
834 [[1, 0], [0, 1]],
835 )
836 .is_ok()
837 );
838 assert!(monoid(TEST_ITEMS_NONZERO, &u32::wrapping_add, 1).is_err());
840 }
841
842 #[test]
843 fn test_absorbing() {
844 assert!(absorbing_element(TEST_ITEMS, u32::wrapping_mul, 0).is_ok());
846 assert!(absorbing_element(TEST_ITEMS, u32::wrapping_mul, 5).is_err());
847 }
848
849 fn modulo_add_7(a: u32, b: u32) -> u32 {
852 u32::wrapping_add(a, b) % 7
853 }
854
855 fn modulo_add_14(a: u32, b: u32) -> u32 {
858 u32::wrapping_add(a, b) % 14
859 }
860
861 fn modulo_sub_7(a: u32) -> u32 {
864 u32::wrapping_sub(7, a) % 7
865 }
866
867 fn modulo_sub_14(a: u32) -> u32 {
870 u32::wrapping_sub(14, a) % 14
871 }
872
873 fn modulo_mult_7(a: u32, b: u32) -> u32 {
876 u32::wrapping_mul(a, b) % 7
877 }
878
879 fn modulo_mult_14(a: u32, b: u32) -> u32 {
882 u32::wrapping_mul(a, b) % 14
883 }
884
885 #[test]
886 fn test_additive_inverse_7() {
887 assert_eq!(0, modulo_sub_7(0));
889 assert_eq!(1, modulo_sub_7(6));
890 assert_eq!(2, modulo_sub_7(5));
891 assert_eq!(3, modulo_sub_7(4));
892 assert_eq!(4, modulo_sub_7(3));
893 assert_eq!(6, modulo_sub_7(1));
894 }
895
896 #[test]
897 fn test_modulo_mu14() {
898 assert_eq!(0, modulo_mult_14(2, 7));
900 assert_eq!(3, modulo_mult_14(1, 3));
901 assert_eq!(2, modulo_mult_14(2, 1));
902 assert_eq!(3, modulo_mult_14(3, 1));
903 assert_eq!(4, modulo_mult_14(2, 2));
904 assert_eq!(6, modulo_mult_14(2, 3));
905 assert_eq!(9, modulo_mult_14(3, 3));
906 }
907 #[test]
908 fn test_modulo_mu7() {
909 assert_eq!(0, modulo_mult_7(0, 0));
911 assert_eq!(3, modulo_mult_7(1, 3));
912 assert_eq!(2, modulo_mult_7(2, 1));
913 assert_eq!(2, modulo_mult_7(3, 3));
914 assert_eq!(2, modulo_mult_7(3, 3));
915 assert_eq!(5, modulo_mult_7(3, 4));
916 assert_eq!(1, modulo_mult_7(3, 5));
917 }
918
919 #[test]
920 fn test_no_nonzero_zero_divisors() {
921 assert!(no_nonzero_zero_divisors(TEST_MOD_PRIME_7, &modulo_mult_7, 0).is_ok());
923 assert!(no_nonzero_zero_divisors(TEST_ITEMS, &modulo_mult_7, 0).is_err());
925 }
926
927 #[test]
928 fn test_integral_domain() {
929 assert!(
931 integral_domain(
932 TEST_MOD_PRIME_7,
933 &modulo_add_7,
934 &modulo_mult_7,
935 0,
936 1,
937 &modulo_sub_7,
938 )
939 .is_ok()
940 );
941 assert!(
943 integral_domain(
944 TEST_ITEMS,
945 &modulo_add_14,
946 &modulo_mult_14,
947 0,
948 1,
949 &modulo_sub_14,
950 )
951 .is_err()
952 );
953 }
954
955 #[test]
956 fn test_field() {
957 assert!(
961 field(
962 TEST_BOOLS,
963 &|a, b| a ^ b, &|a, b| a & b, false,
966 true,
967 &|x| x, &|_x| true )
971 .is_ok()
972 );
973
974 assert!(
975 field(
976 TEST_ITEMS,
977 &u32::wrapping_add,
978 &u32::wrapping_mul,
979 0,
980 1,
981 &|x| 0u32.wrapping_sub(x),
982 &|x| 0u32.wrapping_sub(x) )
984 .is_err()
985 );
986 }
987
988 #[test]
989 fn test_ring() {
990 assert!(
992 ring(
993 TEST_ITEMS,
994 &u32::wrapping_add,
995 &u32::wrapping_mul,
996 0,
997 1,
998 &|x| 0u32.wrapping_sub(x),
999 )
1000 .is_ok()
1001 );
1002 assert!(
1003 ring(
1004 TEST_ITEMS,
1005 &u32::wrapping_add,
1006 &u32::wrapping_mul,
1007 0,
1008 5,
1009 &|x| 0u32.wrapping_sub(x),
1010 )
1011 .is_err()
1012 );
1013 }
1014
1015 #[test]
1016 fn test_semiring() {
1017 assert!(semiring(TEST_ITEMS, &u32::wrapping_add, &u32::wrapping_mul, 0, 1).is_ok());
1019
1020 assert!(semiring(&[false, true], &|x, y| x | y, &|x, y| x & y, false, true).is_ok());
1022
1023 assert!(
1025 semiring(
1026 &[0.0, 1.0, 2.0, 3.0, 4.0, 5.0, 6.0, f64::INFINITY],
1027 &f64::min,
1028 &|x, y| x + y,
1029 f64::INFINITY,
1030 0.0,
1031 )
1032 .is_ok()
1033 );
1034
1035 assert!(
1037 semiring(
1038 &[0.0, 1.0, 2.0, 3.0, 4.0, 5.0, 6.0, f64::NEG_INFINITY],
1039 &f64::max,
1040 &|x, y| x + y,
1041 f64::NEG_INFINITY,
1042 0.0,
1043 )
1044 .is_ok()
1045 );
1046
1047 assert!(
1049 semiring(
1050 &[
1051 HashSet::from([]),
1052 HashSet::from(["".to_owned()]),
1053 HashSet::from(["a".to_owned()]),
1054 HashSet::from(["aa".to_owned(), "bb".to_owned()]),
1055 HashSet::from(["ab".to_owned(), "bb".to_owned(), "cc".to_owned()]),
1056 HashSet::from(["ba".to_owned()]),
1057 HashSet::from(["bb".to_owned()]),
1058 ],
1059 &|x, y| x.union(&y).cloned().collect(),
1060 &|x, y| {
1061 let mut new_set = HashSet::new();
1062
1063 for a in x.iter() {
1064 for b in y.iter() {
1065 new_set.insert(format!("{a}{b}"));
1066 }
1067 }
1068 new_set
1069 },
1070 HashSet::from([]),
1071 HashSet::from(["".to_owned()]),
1072 )
1073 .is_ok()
1074 );
1075 }
1076
1077 #[test]
1078 fn test_get_single_function_properties() {
1079 let test_properties_satisfied = get_single_function_properties(
1081 TEST_ITEMS,
1082 u32::wrapping_add,
1083 0,
1084 |x| 0u32.wrapping_sub(x),
1085 0,
1086 );
1087 let correct_properties = vec![
1088 "associativity".to_string(),
1089 "commutativity".to_string(),
1090 "identity".to_string(),
1091 "inverse".to_string(),
1092 ];
1093 assert_eq!(test_properties_satisfied, correct_properties);
1094
1095 let test_properties_satisfied = get_single_function_properties(
1097 &[0.0, 1.0, 2.0, 3.0, 4.0, 5.0, 6.0, f64::INFINITY],
1098 f64::max,
1099 0.0,
1100 |x| x,
1101 f64::INFINITY,
1102 );
1103 let correct_properties = vec![
1104 "associativity".to_string(),
1105 "commutativity".to_string(),
1106 "idempotency".to_string(),
1107 "identity".to_string(),
1108 "absorbing_element".to_string(),
1109 ];
1110 assert_eq!(test_properties_satisfied, correct_properties);
1111
1112 let f = |x: u32, _y: u32| x;
1114 let test_properties_satisfied =
1115 get_single_function_properties(TEST_ITEMS, f, 0, |x| 0u32.wrapping_sub(x), 0);
1116 let correct_properties = vec!["associativity".to_string(), "idempotency".to_string()];
1117 assert_eq!(test_properties_satisfied, correct_properties);
1118 }
1119}