1use crate::test::cartesian_power;
2
3pub fn monoid<S: PartialEq + Clone, const N: usize>(
8 items: &[S; N],
9 f: &impl Fn(S, S) -> S,
10 zero: S, ) -> Result<(), &'static str> {
12 semigroup(items, f)?;
13 identity(items, f, zero)?;
14 Ok(())
15}
16
17pub fn semigroup<S: PartialEq + Clone, const N: usize>(
21 items: &[S; N],
22 f: &impl Fn(S, S) -> S,
23) -> Result<(), &'static str> {
24 associativity(items, f)?;
25 Ok(())
26}
27
28pub fn semiring<S: PartialEq + Clone, const N: usize>(
35 items: &[S; N],
36 f: &impl Fn(S, S) -> S,
37 g: &impl Fn(S, S) -> S,
38 zero: S, one: S, ) -> Result<(), &'static str> {
41 commutative_monoid(items, f, zero.clone())?;
42 monoid(items, g, one)?;
43
44 absorbing_element(items, g, zero)?;
45
46 distributive(items, f, g)?;
47
48 Ok(())
49}
50
51pub fn ring<S: PartialEq + Clone, const N: usize>(
55 items: &[S; N],
56 f: &impl Fn(S, S) -> S,
57 g: &impl Fn(S, S) -> S,
58 zero: S, one: S, b: &impl Fn(S) -> S,
61) -> Result<(), &'static str> {
62 semiring(items, f, g, zero.clone(), one)?;
63 inverse(items, f, zero, b)?;
64 Ok(())
65}
66
67pub fn integral_domain<S: PartialEq + Clone, const N: usize>(
71 items: &[S; N],
72 f: &impl Fn(S, S) -> S,
73 g: &impl Fn(S, S) -> S,
74 zero: S, one: S, inverse_f: &impl Fn(S) -> S, ) -> Result<(), &'static str> {
78 commutative_ring(items, f, g, zero.clone(), one, inverse_f)?;
79 no_nonzero_zero_divisors(items, g, zero)?;
80 Ok(())
81}
82
83pub fn no_nonzero_zero_divisors<S: PartialEq + Clone, const N: usize>(
87 items: &[S; N],
88 f: &impl Fn(S, S) -> S,
89 zero: S,
90) -> Result<(), &'static str> {
91 for a in items {
92 for b in items {
93 if *a != zero && *b != zero {
94 if f(a.clone(), b.clone()) == zero {
95 return Err("No nonzero zero divisors check failed.");
96 };
97 if f(b.clone(), a.clone()) == zero {
98 return Err("No nonzero zero divisors check failed.");
99 };
100 }
101 }
102 }
103 Ok(())
104}
105
106pub fn commutative_ring<S: PartialEq + Clone, const N: usize>(
110 items: &[S; N],
111 f: &impl Fn(S, S) -> S, g: &impl Fn(S, S) -> S, zero: S, one: S, inverse_f: &impl Fn(S) -> S,
116) -> Result<(), &'static str> {
117 semiring(items, f, g, zero.clone(), one)?;
118 inverse(items, f, zero, inverse_f)?;
119 commutativity(items, g)?;
120 Ok(())
121}
122
123pub fn field<S: PartialEq + Clone, const N: usize>(
127 items: &[S; N],
128 f: &impl Fn(S, S) -> S,
129 g: &impl Fn(S, S) -> S,
130 zero: S, one: S, inverse_f: &impl Fn(S) -> S, inverse_g: &impl Fn(S) -> S, ) -> Result<(), &'static str> {
135 commutative_ring(items, f, g, zero.clone(), one.clone(), inverse_f)?;
136 nonzero_inverse(items, g, one, zero, inverse_g)?;
137 Ok(())
138}
139
140pub fn commutative_monoid<S: PartialEq + Clone, const N: usize>(
144 items: &[S; N],
145 f: &impl Fn(S, S) -> S,
146 zero: S,
147) -> Result<(), &'static str> {
148 monoid(items, f, zero)?;
149 commutativity(items, f)?;
150 Ok(())
151}
152
153pub fn group<S: PartialEq + Clone, const N: usize>(
159 items: &[S; N],
160 f: &impl Fn(S, S) -> S,
161 zero: S, b: &impl Fn(S) -> S, ) -> Result<(), &'static str> {
164 monoid(items, f, zero.clone())?;
165 inverse(items, f, zero, b)?;
166 Ok(())
167}
168
169pub fn abelian_group<S: PartialEq + Clone, const N: usize>(
173 items: &[S; N],
174 f: &impl Fn(S, S) -> S,
175 zero: S,
176 b: &impl Fn(S) -> S, ) -> Result<(), &'static str> {
178 group(items, f, zero, b)?;
179 commutativity(items, f)?;
180 Ok(())
181}
182
183pub fn distributive<S: PartialEq + Clone, const N: usize>(
189 items: &[S; N],
190 f: &impl Fn(S, S) -> S,
191 g: &impl Fn(S, S) -> S,
192) -> Result<(), &'static str> {
193 left_distributes(items, f, g)?;
194 right_distributes(items, f, g)?;
195 Ok(())
196}
197
198pub fn left_distributes<S: PartialEq + Clone, const N: usize>(
202 items: &[S; N],
203 f: impl Fn(S, S) -> S,
204 g: impl Fn(S, S) -> S,
205) -> Result<(), &'static str> {
206 for [a, b, c] in cartesian_power(items) {
207 if g(a.clone(), f(b.clone(), c.clone()))
208 != f(g(a.clone(), b.clone()), g(a.clone(), c.clone()))
209 {
210 return Err("Left distributive property check failed.");
211 }
212 }
213 Ok(())
214}
215
216pub fn right_distributes<S: PartialEq + Clone, const N: usize>(
220 items: &[S; N],
221 f: impl Fn(S, S) -> S,
222 g: impl Fn(S, S) -> S,
223) -> Result<(), &'static str> {
224 for [a, b, c] in cartesian_power(items) {
225 if g(f(b.clone(), c.clone()), a.clone())
226 != f(g(b.clone(), a.clone()), g(c.clone(), a.clone()))
227 {
228 return Err("Right distributive property check failed.");
229 }
230 }
231 Ok(())
232}
233
234pub fn absorbing_element<S: PartialEq + Clone, const N: usize>(
238 items: &[S; N],
239 f: impl Fn(S, S) -> S,
240 z: S, ) -> Result<(), &'static str> {
242 for a in items {
243 if f(a.clone(), z.clone()) != z.clone() {
245 return Err("Absorbing element property check failed.");
246 }
247
248 if f(z.clone(), a.clone()) != z.clone() {
250 return Err("Absorbing element property check failed.");
251 }
252 }
253 Ok(())
254}
255
256pub fn inverse<S: PartialEq + Clone, const N: usize>(
260 items: &[S; N],
261 f: impl Fn(S, S) -> S,
262 e: S, b: impl Fn(S) -> S, ) -> Result<(), &'static str> {
265 for a in items {
267 if f(a.clone(), b(a.clone())) != e {
268 return Err("Inverse check failed.");
269 }
270 if f(b(a.clone()), a.clone()) != e {
271 return Err("Inverse check failed.");
272 }
273 }
274 Ok(())
275}
276
277pub fn nonzero_inverse<S: PartialEq + Clone, const N: usize>(
281 items: &[S; N],
282 f: impl Fn(S, S) -> S,
283 e: S,
284 zero: S,
285 b: impl Fn(S) -> S,
286) -> Result<(), &'static str> {
287 for a in items {
289 if *a != zero {
290 if f(a.clone(), b(a.clone())) != e {
291 return Err("Nonzero inverse check failed.");
292 }
293 if f(b(a.clone()), a.clone()) != e {
294 return Err("Nonzero inverse check failed.");
295 }
296 }
297 }
298 Ok(())
299}
300
301pub fn identity<S: PartialEq + Clone, const N: usize>(
305 items: &[S; N],
306 f: impl Fn(S, S) -> S,
307 e: S,
308) -> Result<(), &'static str> {
309 for a in items {
311 if f(e.clone(), a.clone()) != a.clone() {
312 return Err("Left Identity check failed.");
313 }
314 if f(a.clone(), e.clone()) != a.clone() {
315 return Err("Right Identity check failed.");
316 }
317 }
318 Ok(())
319}
320
321pub fn associativity<S: PartialEq + Clone, const N: usize>(
325 items: &[S; N],
326 f: impl Fn(S, S) -> S,
327) -> Result<(), &'static str> {
328 for [a, b, c] in cartesian_power(items) {
329 if f(a.clone(), f(b.clone(), c.clone())) != f(f(a.clone(), b.clone()), c.clone())
331 {
333 return Err("Associativity check failed.");
334 }
335 }
336 Ok(())
337}
338
339pub fn commutativity<S: PartialEq + Clone, const N: usize>(
343 items: &[S; N],
344 f: impl Fn(S, S) -> S,
345) -> Result<(), &'static str> {
346 for [x, y] in cartesian_power(items) {
347 if f(x.clone(), y.clone()) != f(y.clone(), x.clone()) {
348 return Err("Commutativity check failed.");
350 }
351 }
352 Ok(())
353}
354
355pub fn idempotency<S: PartialEq + Clone, const N: usize>(
359 items: &[S; N],
360 f: impl Fn(S, S) -> S,
361) -> Result<(), &'static str> {
362 for x in items {
363 if f(x.clone(), x.clone()) != x.clone() {
364 return Err("Idempotency check failed.");
365 }
366 }
367 Ok(())
368}
369
370pub fn linearity<S: PartialEq + Clone, R: PartialEq + Clone>(
379 items: &[S],
380 f: impl Fn(S, S) -> S,
381 g: impl Fn(R, R) -> R,
382 q: impl Fn(S) -> R,
383) -> Result<(), &'static str> {
384 for [a, b] in cartesian_power(items) {
385 if q(f(a.clone(), b.clone())) != g(q(b.clone()), q(a.clone())) {
386 return Err("Linearity check failed.");
388 }
389 }
390 Ok(())
391}
392
393pub fn bilinearity<S: PartialEq + Clone, R: PartialEq + Clone, T: PartialEq + Clone>(
403 items_f: &[S],
404 items_h: &[T],
405 f: impl Fn(S, S) -> S,
406 h: impl Fn(T, T) -> T,
407 g: impl Fn(R, R) -> R,
408 q: impl Fn(S, T) -> R,
409) -> Result<(), &'static str> {
410 for [a, b] in cartesian_power(items_f) {
411 for [c, d] in cartesian_power(items_h) {
412 if q(f(a.clone(), b.clone()), c.clone())
413 != g(q(a.clone(), c.clone()), q(b.clone(), c.clone()))
414 || q(a.clone(), h(c.clone(), d.clone()))
415 != g(q(a.clone(), c.clone()), q(a.clone(), d.clone()))
416 {
417 return Err("Bilinearity check failed.");
420 }
421 }
422 }
423 Ok(())
424}
425
426#[cfg(feature = "alloc")]
439pub fn get_single_function_properties<S: PartialEq + Clone, const N: usize>(
440 items: &[S; N],
441 f: impl Fn(S, S) -> S,
442 e: S,
444 b: impl Fn(S) -> S,
446 z: S,
448) -> alloc::vec::Vec<&'static str> {
449 let mut properties_satisfied = alloc::vec::Vec::new();
451
452 if associativity(items, &f).is_ok() {
454 properties_satisfied.push("associativity");
455 }
456 if commutativity(items, &f).is_ok() {
457 properties_satisfied.push("commutativity");
458 }
459 if idempotency(items, &f).is_ok() {
460 properties_satisfied.push("idempotency");
461 }
462 if identity(items, &f, e.clone()).is_ok() {
463 properties_satisfied.push("identity");
464 }
465 if inverse(items, &f, e, b).is_ok() {
466 properties_satisfied.push("inverse");
467 }
468 if absorbing_element(items, &f, z).is_ok() {
469 properties_satisfied.push("absorbing_element");
470 }
471
472 properties_satisfied
473}
474
475#[cfg(test)]
480mod test {
481 use std::collections::HashSet;
482
483 use crate::algebra::*;
484
485 static TEST_ITEMS: &[u32; 14] = &[0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13];
486 static TEST_ITEMS_NONZERO: &[u32; 13] = &[1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13];
487 static TEST_MOD_PRIME_7: &[u32; 7] = &[0, 1, 2, 3, 4, 5, 6];
488 static TEST_BOOLS: &[bool; 2] = &[false, true];
489
490 #[test]
491 fn test_associativity() {
492 assert!(associativity(TEST_ITEMS, u32::max).is_ok());
494 assert!(associativity(TEST_ITEMS, u32::wrapping_pow).is_err());
495 }
496
497 #[test]
498 fn test_left_distributes() {
499 assert!(left_distributes(TEST_ITEMS, u32::wrapping_sub, u32::wrapping_mul).is_ok());
502 assert!(left_distributes(TEST_ITEMS, u32::wrapping_sub, u32::wrapping_pow).is_err());
503 }
504
505 #[test]
506 fn test_right_distributes() {
507 assert!(right_distributes(TEST_ITEMS, u32::wrapping_sub, u32::wrapping_mul).is_ok());
510 assert!(right_distributes(TEST_ITEMS, u32::wrapping_sub, u32::wrapping_pow).is_err());
511 }
512
513 #[test]
514 fn test_nonzero_inverse() {
515 assert!(
517 nonzero_inverse(TEST_ITEMS, u32::wrapping_add, 0, 0, |x| {
518 0u32.wrapping_sub(x)
519 })
520 .is_ok()
521 );
522 assert!(
523 nonzero_inverse(TEST_ITEMS, u32::wrapping_sub, 0, 0, |x| {
524 0u32.wrapping_add(x)
525 })
526 .is_ok()
527 );
528 assert!(
529 right_distributes(TEST_ITEMS_NONZERO, u32::wrapping_div, u32::wrapping_mul).is_err()
530 );
531 }
532
533 #[test]
534 fn test_idempotency() {
535 assert!(idempotency(TEST_ITEMS, u32::max).is_ok());
537
538 assert!(idempotency(TEST_ITEMS, u32::wrapping_add).is_err());
539 }
540
541 #[test]
542 fn test_commutativity() {
543 assert!(commutativity(TEST_ITEMS, u32::max).is_ok());
545 assert!(commutativity(TEST_ITEMS_NONZERO, u32::wrapping_div).is_err());
546 }
548
549 #[test]
550 fn test_commutative_ring() {
551 assert!(
553 commutative_ring(
554 TEST_ITEMS,
555 &u32::wrapping_add,
556 &u32::wrapping_mul,
557 0,
558 1,
559 &|x| 0u32.wrapping_sub(x),
560 )
561 .is_ok()
562 );
563
564 assert!(
566 commutative_ring(
567 TEST_ITEMS,
568 &u32::wrapping_add,
569 &u32::wrapping_pow,
570 0,
571 1,
572 &|x| 0u32.wrapping_sub(x),
573 )
574 .is_err()
575 );
576
577 assert!(
579 commutative_ring(
580 &[[[1, 2], [3, 4]], [[5, 6], [7, 8]], [[9, 10], [11, 12]]],
581 &|a, b| {
582 [
583 [a[0][0] + b[0][0], a[0][1] + b[0][1]],
584 [a[1][0] + b[1][0], a[1][0] + b[1][1]],
585 ]
586 },
587 &|a, b| {
588 [
589 [
590 a[0][0] * b[0][0] + a[0][1] * b[1][0],
591 a[0][0] * b[0][1] + a[0][1] * b[1][1],
592 ],
593 [
594 a[1][0] * b[0][0] + a[1][1] * b[1][0],
595 a[1][0] * b[0][1] + a[1][1] * b[1][1],
596 ],
597 ]
598 },
599 [[0, 0], [0, 0]],
600 [[1, 0], [0, 1]],
601 &|a| {
602 [
603 [
604 -a[0][0] / (a[0][0] * a[1][1] - a[0][1] * a[1][1]),
605 -a[0][1] / (a[0][0] * a[1][1] - a[0][1] * a[1][1]),
606 ],
607 [
608 -a[1][0] / (a[0][0] * a[1][1] - a[0][1] * a[1][1]),
609 -a[1][1] / (a[0][0] * a[1][1] - a[0][1] * a[1][1]),
610 ],
611 ]
612 },
613 )
614 .is_err()
615 );
616 }
617
618 #[test]
619 fn test_commutative_monoid() {
620 assert!(commutative_monoid(TEST_ITEMS, &u32::wrapping_add, 0).is_ok());
622
623 assert!(commutative_monoid(TEST_ITEMS, &u32::wrapping_mul, 1).is_ok());
625 assert!(commutative_monoid(TEST_ITEMS, &u32::wrapping_add, 0).is_ok());
626
627 assert!(commutative_monoid(TEST_BOOLS, &|a, b| a & b, true).is_ok()); assert!(commutative_monoid(TEST_ITEMS, &u32::wrapping_sub, 0).is_err());
632
633 assert!(commutative_monoid(TEST_ITEMS_NONZERO, &u32::wrapping_add, 1).is_err()); assert!(commutative_monoid(TEST_ITEMS, &u32::wrapping_pow, 3).is_err());
638 }
639
640 #[test]
641 fn test_semigroup() {
642 assert!(semigroup(TEST_ITEMS_NONZERO, &u32::wrapping_add).is_ok());
644 assert!(semigroup(TEST_ITEMS, &u32::wrapping_add).is_ok());
646 assert!(semigroup(TEST_ITEMS, &u32::wrapping_mul).is_ok());
648 assert!(semigroup(TEST_BOOLS, &|a, b| a & b).is_ok()); assert!(
652 semigroup(
653 &[[[1, 2], [3, 4]], [[5, 6], [7, 8]], [[9, 10], [11, 12]]],
654 &|a, b| {
655 [
656 [
657 a[0][0] * b[0][0] + a[0][1] * b[1][0],
658 a[0][0] * b[0][1] + a[0][1] * b[1][1],
659 ],
660 [
661 a[1][0] * b[0][0] + a[1][1] * b[1][0],
662 a[1][0] * b[0][1] + a[1][1] * b[1][1],
663 ],
664 ]
665 },
666 )
667 .is_ok()
668 );
669 assert!(semigroup(TEST_ITEMS, &u32::wrapping_pow).is_err());
671 }
672
673 #[test]
674 fn test_identity() {
675 assert!(identity(TEST_ITEMS, u32::wrapping_add, 0).is_ok());
677
678 assert!(identity(TEST_ITEMS, u32::wrapping_add, 5).is_err());
679 }
680
681 #[test]
682 fn test_inverse() {
683 assert!(inverse(TEST_ITEMS, u32::wrapping_add, 0, |x| 0u32.wrapping_sub(x)).is_ok());
685
686 assert!(inverse(TEST_ITEMS, u32::wrapping_add, 0, |x| 0u32.wrapping_add(x)).is_err());
687 }
688
689 #[test]
690 fn test_distributive() {
691 assert!(distributive(TEST_ITEMS, &u32::wrapping_add, &u32::wrapping_mul).is_ok());
693 assert!(distributive(TEST_ITEMS, &u32::wrapping_add, &u32::max).is_err());
694 }
695
696 #[test]
697 fn test_linearity() {
698 assert!(
701 linearity(TEST_ITEMS, u32::wrapping_add, u32::wrapping_add, |x| {
702 u32::wrapping_mul(x, 5)
703 })
704 .is_ok()
705 );
706 assert!(
707 linearity(TEST_ITEMS, u32::wrapping_add, u32::wrapping_add, |x| {
708 u32::pow(x, 5)
709 })
710 .is_err()
711 );
712 }
713
714 #[test]
715 fn test_bilinearity() {
716 assert!(
719 bilinearity(
720 TEST_ITEMS,
721 TEST_ITEMS,
722 u32::wrapping_add,
723 u32::wrapping_add,
724 u32::wrapping_add,
725 u32::wrapping_mul
726 )
727 .is_ok()
728 );
729 assert!(
730 bilinearity(
731 TEST_ITEMS,
732 TEST_ITEMS,
733 u32::wrapping_add,
734 u32::wrapping_add,
735 u32::wrapping_add,
736 u32::pow
737 )
738 .is_err()
739 );
740 }
741
742 #[test]
743 fn test_group() {
744 assert!(group(TEST_ITEMS, &u32::wrapping_add, 0, &|x| 0u32.wrapping_sub(x)).is_ok());
746 assert!(group(TEST_MOD_PRIME_7, &modulo_add_7, 0, &modulo_sub_7).is_ok());
748 assert!(group(TEST_ITEMS, &modulo_add_14, 0, &modulo_sub_14).is_ok());
750 assert!(
752 group(TEST_ITEMS_NONZERO, &u32::wrapping_mul, 1, &|x| 1u32
753 .wrapping_div(x))
754 .is_err()
755 );
756 }
757
758 #[test]
759 fn test_abelian_group() {
760 assert!(
762 abelian_group(TEST_ITEMS, &u32::wrapping_add, 0, &|x| 0u32.wrapping_sub(x)).is_ok()
763 );
764 assert!(abelian_group(TEST_MOD_PRIME_7, &modulo_add_7, 0, &modulo_sub_7).is_ok());
766 assert!(
768 abelian_group(TEST_ITEMS_NONZERO, &u32::wrapping_mul, 1, &|x| 1u32
769 .wrapping_div(x))
770 .is_err()
771 );
772 assert!(
774 abelian_group(
775 &[[[1, 2], [3, 4]], [[5, 6], [7, 8]], [[9, 10], [11, 12]]],
776 &|a, b| {
777 [
778 [
779 a[0][0] * b[0][0] + a[0][1] * b[1][0],
780 a[0][0] * b[0][1] + a[0][1] * b[1][1],
781 ],
782 [
783 a[1][0] * b[0][0] + a[1][1] * b[1][0],
784 a[1][0] * b[0][1] + a[1][1] * b[1][1],
785 ],
786 ]
787 },
788 [[1, 0], [0, 1]],
789 &|a| {
790 [
791 [
792 -a[0][0] / (a[0][0] * a[1][1] - a[0][1] * a[1][1]),
793 -a[0][1] / (a[0][0] * a[1][1] - a[0][1] * a[1][1]),
794 ],
795 [
796 -a[1][0] / (a[0][0] * a[1][1] - a[0][1] * a[1][1]),
797 -a[1][1] / (a[0][0] * a[1][1] - a[0][1] * a[1][1]),
798 ],
799 ]
800 },
801 )
802 .is_err()
803 );
804 }
805
806 #[test]
807 fn test_monoid() {
808 assert!(monoid(TEST_ITEMS, &u32::wrapping_add, 0).is_ok());
810 assert!(monoid(TEST_ITEMS_NONZERO, &u32::wrapping_mul, 1).is_ok());
812 assert!(monoid(TEST_ITEMS, &u32::wrapping_mul, 1).is_ok());
813 assert!(
815 monoid(
816 &[[[1, 2], [3, 4]], [[5, 6], [7, 8]], [[9, 10], [11, 12]]],
817 &|a, b| {
818 [
819 [
820 a[0][0] * b[0][0] + a[0][1] * b[1][0],
821 a[0][0] * b[0][1] + a[0][1] * b[1][1],
822 ],
823 [
824 a[1][0] * b[0][0] + a[1][1] * b[1][0],
825 a[1][0] * b[0][1] + a[1][1] * b[1][1],
826 ],
827 ]
828 },
829 [[1, 0], [0, 1]],
830 )
831 .is_ok()
832 );
833 assert!(monoid(TEST_ITEMS_NONZERO, &u32::wrapping_add, 1).is_err());
835 }
836
837 #[test]
838 fn test_absorbing() {
839 assert!(absorbing_element(TEST_ITEMS, u32::wrapping_mul, 0).is_ok());
841 assert!(absorbing_element(TEST_ITEMS, u32::wrapping_mul, 5).is_err());
842 }
843
844 fn modulo_add_7(a: u32, b: u32) -> u32 {
847 u32::wrapping_add(a, b) % 7
848 }
849
850 fn modulo_add_14(a: u32, b: u32) -> u32 {
853 u32::wrapping_add(a, b) % 14
854 }
855
856 fn modulo_sub_7(a: u32) -> u32 {
859 u32::wrapping_sub(7, a) % 7
860 }
861
862 fn modulo_sub_14(a: u32) -> u32 {
865 u32::wrapping_sub(14, a) % 14
866 }
867
868 fn modulo_mult_7(a: u32, b: u32) -> u32 {
871 u32::wrapping_mul(a, b) % 7
872 }
873
874 fn modulo_mult_14(a: u32, b: u32) -> u32 {
877 u32::wrapping_mul(a, b) % 14
878 }
879
880 #[test]
881 fn test_additive_inverse_7() {
882 assert_eq!(0, modulo_sub_7(0));
884 assert_eq!(1, modulo_sub_7(6));
885 assert_eq!(2, modulo_sub_7(5));
886 assert_eq!(3, modulo_sub_7(4));
887 assert_eq!(4, modulo_sub_7(3));
888 assert_eq!(6, modulo_sub_7(1));
889 }
890
891 #[test]
892 fn test_modulo_mu14() {
893 assert_eq!(0, modulo_mult_14(2, 7));
895 assert_eq!(3, modulo_mult_14(1, 3));
896 assert_eq!(2, modulo_mult_14(2, 1));
897 assert_eq!(3, modulo_mult_14(3, 1));
898 assert_eq!(4, modulo_mult_14(2, 2));
899 assert_eq!(6, modulo_mult_14(2, 3));
900 assert_eq!(9, modulo_mult_14(3, 3));
901 }
902 #[test]
903 fn test_modulo_mu7() {
904 assert_eq!(0, modulo_mult_7(0, 0));
906 assert_eq!(3, modulo_mult_7(1, 3));
907 assert_eq!(2, modulo_mult_7(2, 1));
908 assert_eq!(2, modulo_mult_7(3, 3));
909 assert_eq!(2, modulo_mult_7(3, 3));
910 assert_eq!(5, modulo_mult_7(3, 4));
911 assert_eq!(1, modulo_mult_7(3, 5));
912 }
913
914 #[test]
915 fn test_no_nonzero_zero_divisors() {
916 assert!(no_nonzero_zero_divisors(TEST_MOD_PRIME_7, &modulo_mult_7, 0).is_ok());
918 assert!(no_nonzero_zero_divisors(TEST_ITEMS, &modulo_mult_7, 0).is_err());
920 }
921
922 #[test]
923 fn test_integral_domain() {
924 assert!(
926 integral_domain(
927 TEST_MOD_PRIME_7,
928 &modulo_add_7,
929 &modulo_mult_7,
930 0,
931 1,
932 &modulo_sub_7,
933 )
934 .is_ok()
935 );
936 assert!(
938 integral_domain(
939 TEST_ITEMS,
940 &modulo_add_14,
941 &modulo_mult_14,
942 0,
943 1,
944 &modulo_sub_14,
945 )
946 .is_err()
947 );
948 }
949
950 #[test]
951 fn test_field() {
952 assert!(
956 field(
957 TEST_BOOLS,
958 &|a, b| a ^ b, &|a, b| a & b, false,
961 true,
962 &|x| x, &|_x| true )
966 .is_ok()
967 );
968
969 assert!(
970 field(
971 TEST_ITEMS,
972 &u32::wrapping_add,
973 &u32::wrapping_mul,
974 0,
975 1,
976 &|x| 0u32.wrapping_sub(x),
977 &|x| 0u32.wrapping_sub(x) )
979 .is_err()
980 );
981 }
982
983 #[test]
984 fn test_ring() {
985 assert!(
987 ring(
988 TEST_ITEMS,
989 &u32::wrapping_add,
990 &u32::wrapping_mul,
991 0,
992 1,
993 &|x| 0u32.wrapping_sub(x),
994 )
995 .is_ok()
996 );
997 assert!(
998 ring(
999 TEST_ITEMS,
1000 &u32::wrapping_add,
1001 &u32::wrapping_mul,
1002 0,
1003 5,
1004 &|x| 0u32.wrapping_sub(x),
1005 )
1006 .is_err()
1007 );
1008 }
1009
1010 #[cfg(feature = "alloc")]
1011 #[test]
1012 fn test_semiring() {
1013 use alloc::borrow::ToOwned;
1014 use alloc::format;
1015
1016 assert!(semiring(TEST_ITEMS, &u32::wrapping_add, &u32::wrapping_mul, 0, 1).is_ok());
1018
1019 assert!(semiring(&[false, true], &|x, y| x | y, &|x, y| x & y, false, true).is_ok());
1021
1022 assert!(
1024 semiring(
1025 &[0.0, 1.0, 2.0, 3.0, 4.0, 5.0, 6.0, f64::INFINITY],
1026 &f64::min,
1027 &|x, y| x + y,
1028 f64::INFINITY,
1029 0.0,
1030 )
1031 .is_ok()
1032 );
1033
1034 assert!(
1036 semiring(
1037 &[0.0, 1.0, 2.0, 3.0, 4.0, 5.0, 6.0, f64::NEG_INFINITY],
1038 &f64::max,
1039 &|x, y| x + y,
1040 f64::NEG_INFINITY,
1041 0.0,
1042 )
1043 .is_ok()
1044 );
1045
1046 assert!(
1048 semiring(
1049 &[
1050 HashSet::from([]),
1051 HashSet::from(["".to_owned()]),
1052 HashSet::from(["a".to_owned()]),
1053 HashSet::from(["aa".to_owned(), "bb".to_owned()]),
1054 HashSet::from(["ab".to_owned(), "bb".to_owned(), "cc".to_owned()]),
1055 HashSet::from(["ba".to_owned()]),
1056 HashSet::from(["bb".to_owned()]),
1057 ],
1058 &|x, y| x.union(&y).cloned().collect(),
1059 &|x, y| {
1060 let mut new_set = HashSet::new();
1061
1062 #[expect(
1063 clippy::disallowed_methods,
1064 reason = "nondeterministic iteration order, fine to collect into set"
1065 )]
1066 for a in x.iter() {
1067 for b in y.iter() {
1068 new_set.insert(format!("{a}{b}"));
1069 }
1070 }
1071 new_set
1072 },
1073 HashSet::from([]),
1074 HashSet::from(["".to_owned()]),
1075 )
1076 .is_ok()
1077 );
1078 }
1079
1080 #[test]
1081 fn test_get_single_function_properties() {
1082 let test_properties_satisfied = get_single_function_properties(
1084 TEST_ITEMS,
1085 u32::wrapping_add,
1086 0,
1087 |x| 0u32.wrapping_sub(x),
1088 0,
1089 );
1090 let correct_properties = &["associativity", "commutativity", "identity", "inverse"];
1091 assert_eq!(test_properties_satisfied, correct_properties);
1092
1093 let test_properties_satisfied = get_single_function_properties(
1095 &[0.0, 1.0, 2.0, 3.0, 4.0, 5.0, 6.0, f64::INFINITY],
1096 f64::max,
1097 0.0,
1098 |x| x,
1099 f64::INFINITY,
1100 );
1101 let correct_properties = &[
1102 "associativity",
1103 "commutativity",
1104 "idempotency",
1105 "identity",
1106 "absorbing_element",
1107 ];
1108 assert_eq!(test_properties_satisfied, correct_properties);
1109
1110 let f = |x: u32, _y: u32| x;
1112 let test_properties_satisfied =
1113 get_single_function_properties(TEST_ITEMS, f, 0, |x| 0u32.wrapping_sub(x), 0);
1114 let correct_properties = &["associativity", "idempotency"];
1115 assert_eq!(test_properties_satisfied, correct_properties);
1116 }
1117}