1use super::{Bounded, One, Zero, magma::*};
4
5#[codesnip::entry("MaxOperation")]
6pub use self::max_operation_impl::MaxOperation;
7#[codesnip::entry("MaxOperation", include("algebra", "bounded"))]
8mod max_operation_impl {
9 use super::*;
10 use std::marker::PhantomData;
11 pub struct MaxOperation<T>
13 where
14 T: Clone + Ord + Bounded,
15 {
16 _marker: PhantomData<fn() -> T>,
17 }
18 impl<T> Magma for MaxOperation<T>
19 where
20 T: Clone + Ord + Bounded,
21 {
22 type T = T;
23 #[inline]
24 fn operate(x: &Self::T, y: &Self::T) -> Self::T {
25 x.max(y).clone()
26 }
27 }
28 impl<T> Unital for MaxOperation<T>
29 where
30 T: Clone + Ord + Bounded,
31 {
32 #[inline]
33 fn unit() -> Self::T {
34 <T as Bounded>::minimum()
35 }
36 }
37 impl<T> Associative for MaxOperation<T> where T: Clone + Ord + Bounded {}
38 impl<T> Commutative for MaxOperation<T> where T: Clone + Ord + Bounded {}
39 impl<T> Idempotent for MaxOperation<T> where T: Clone + Ord + Bounded {}
40
41 #[cfg(test)]
42 mod tests {
43 use super::*;
44
45 #[test]
46 fn test_max_operation() {
47 type M = MaxOperation<i32>;
48 for a in -10..=10 {
49 assert!(M::check_unital(&a));
50 assert!(M::check_idempotent(&a));
51 for b in -10..=10 {
52 assert!(M::check_commutative(&a, &b));
53 for c in -10..=10 {
54 assert!(M::check_associative(&a, &b, &c));
55 }
56 }
57 }
58 }
59 }
60}
61
62#[codesnip::entry("MinOperation")]
63pub use self::min_operation_impl::MinOperation;
64#[codesnip::entry("MinOperation", include("algebra", "bounded"))]
65mod min_operation_impl {
66 use super::*;
67 use std::marker::PhantomData;
68 pub struct MinOperation<T>
70 where
71 T: Clone + Ord + Bounded,
72 {
73 _marker: PhantomData<fn() -> T>,
74 }
75 impl<T> Magma for MinOperation<T>
76 where
77 T: Clone + Ord + Bounded,
78 {
79 type T = T;
80 #[inline]
81 fn operate(x: &Self::T, y: &Self::T) -> Self::T {
82 x.min(y).clone()
83 }
84 }
85 impl<T> Unital for MinOperation<T>
86 where
87 T: Clone + Ord + Bounded,
88 {
89 #[inline]
90 fn unit() -> Self::T {
91 <T as Bounded>::maximum()
92 }
93 }
94 impl<T> Associative for MinOperation<T> where T: Clone + Ord + Bounded {}
95 impl<T> Commutative for MinOperation<T> where T: Clone + Ord + Bounded {}
96 impl<T> Idempotent for MinOperation<T> where T: Clone + Ord + Bounded {}
97
98 #[cfg(test)]
99 mod tests {
100 use super::*;
101
102 #[test]
103 fn test_min_operation() {
104 type M = MinOperation<i32>;
105 for a in -10..=10 {
106 assert!(M::check_unital(&a));
107 assert!(M::check_idempotent(&a));
108 for b in -10..=10 {
109 assert!(M::check_commutative(&a, &b));
110 for c in -10..=10 {
111 assert!(M::check_associative(&a, &b, &c));
112 }
113 }
114 }
115 }
116 }
117}
118
119#[codesnip::entry("FirstOperation")]
120pub use self::first_operation_impl::FirstOperation;
121#[codesnip::entry("FirstOperation", include("algebra"))]
122mod first_operation_impl {
123 use super::*;
124 use std::marker::PhantomData;
125 pub struct FirstOperation<T>
127 where
128 T: Clone,
129 {
130 _marker: PhantomData<fn() -> T>,
131 }
132 impl<T> Magma for FirstOperation<T>
133 where
134 T: Clone,
135 {
136 type T = Option<T>;
137 #[inline]
138 fn operate(x: &Self::T, y: &Self::T) -> Self::T {
139 x.as_ref().or(y.as_ref()).cloned()
140 }
141 }
142 impl<T> Unital for FirstOperation<T>
143 where
144 T: Clone,
145 {
146 #[inline]
147 fn unit() -> Self::T {
148 None
149 }
150 }
151 impl<T> Associative for FirstOperation<T> where T: Clone {}
152 impl<T> Idempotent for FirstOperation<T> where T: Clone {}
153
154 #[cfg(test)]
155 mod tests {
156 use super::*;
157
158 #[test]
159 fn test_first_operation() {
160 type M = FirstOperation<i32>;
161 let iter = [Some(1), Some(2), Some(3), None];
162 for a in iter {
163 assert!(M::check_unital(&a));
164 assert!(M::check_idempotent(&a));
165 for b in iter {
166 assert_eq!(M::operate(&a, &b), [a, b].into_iter().flatten().next());
167 for c in iter {
168 assert!(M::check_associative(&a, &b, &c));
169 }
170 }
171 }
172 }
173 }
174}
175
176#[codesnip::entry("LastOperation")]
177pub use self::last_operation_impl::LastOperation;
178#[codesnip::entry("LastOperation", include("algebra"))]
179mod last_operation_impl {
180 use super::*;
181 use std::marker::PhantomData;
182 pub struct LastOperation<T>
184 where
185 T: Clone,
186 {
187 _marker: PhantomData<fn() -> T>,
188 }
189 impl<T> Magma for LastOperation<T>
190 where
191 T: Clone,
192 {
193 type T = Option<T>;
194 #[inline]
195 fn operate(x: &Self::T, y: &Self::T) -> Self::T {
196 y.as_ref().or(x.as_ref()).cloned()
197 }
198 }
199 impl<T> Unital for LastOperation<T>
200 where
201 T: Clone,
202 {
203 #[inline]
204 fn unit() -> Self::T {
205 None
206 }
207 }
208 impl<T> Associative for LastOperation<T> where T: Clone {}
209 impl<T> Idempotent for LastOperation<T> where T: Clone {}
210
211 #[cfg(test)]
212 mod tests {
213 use super::*;
214
215 #[test]
216 fn test_last_operation() {
217 type M = LastOperation<i32>;
218 let iter = [Some(1), Some(2), Some(3), None];
219 for a in iter {
220 assert!(M::check_unital(&a));
221 assert!(M::check_idempotent(&a));
222 for b in iter {
223 assert_eq!(M::operate(&a, &b), [a, b].into_iter().flatten().next_back());
224 for c in iter {
225 assert!(M::check_associative(&a, &b, &c));
226 }
227 }
228 }
229 }
230 }
231}
232
233#[codesnip::entry("AdditiveOperation")]
234pub use self::additive_operation_impl::AdditiveOperation;
235#[codesnip::entry("AdditiveOperation", include("algebra", "zero_one"))]
236mod additive_operation_impl {
237 use super::*;
238 use std::{
239 marker::PhantomData,
240 ops::{Add, Neg, Sub},
241 };
242 pub struct AdditiveOperation<T>
244 where
245 T: Clone + Zero + Add<Output = T>,
246 {
247 _marker: PhantomData<fn() -> T>,
248 }
249 impl<T> Magma for AdditiveOperation<T>
250 where
251 T: Clone + Zero + Add<Output = T>,
252 {
253 type T = T;
254 #[inline]
255 fn operate(x: &Self::T, y: &Self::T) -> Self::T {
256 x.clone() + y.clone()
257 }
258 }
259 impl<T> Unital for AdditiveOperation<T>
260 where
261 T: Clone + Zero + Add<Output = T>,
262 {
263 #[inline]
264 fn unit() -> Self::T {
265 Zero::zero()
266 }
267 }
268 impl<T> Associative for AdditiveOperation<T> where T: Clone + Zero + Add<Output = T> {}
269 impl<T> Commutative for AdditiveOperation<T> where T: Clone + Zero + Add<Output = T> {}
270 impl<T> Invertible for AdditiveOperation<T>
271 where
272 T: Clone + Zero + Add<Output = T> + Sub<Output = T> + Neg<Output = T>,
273 {
274 #[inline]
275 fn inverse(x: &Self::T) -> Self::T {
276 -x.clone()
277 }
278 #[inline]
279 fn rinv_operate(x: &Self::T, y: &Self::T) -> Self::T {
280 x.clone() - y.clone()
281 }
282 }
283
284 #[cfg(test)]
285 mod tests {
286 use super::*;
287
288 #[test]
289 fn test_additive_operation() {
290 type M = AdditiveOperation<i32>;
291 for a in -10..=10 {
292 assert!(M::check_unital(&a));
293 assert!(M::check_invertible(&a));
294 for b in -10..=10 {
295 assert!(M::check_commutative(&a, &b));
296 for c in -10..=10 {
297 assert!(M::check_associative(&a, &b, &c));
298 }
299 }
300 }
301 }
302 }
303}
304
305#[codesnip::entry("MultiplicativeOperation")]
306pub use self::multiplicative_operation_impl::MultiplicativeOperation;
307#[codesnip::entry("MultiplicativeOperation", include("algebra", "zero_one"))]
308mod multiplicative_operation_impl {
309 use super::*;
310 use std::{
311 marker::PhantomData,
312 ops::{Div, Mul},
313 };
314 pub struct MultiplicativeOperation<T>
316 where
317 T: Clone + One + Mul<Output = T>,
318 {
319 _marker: PhantomData<fn() -> T>,
320 }
321 impl<T> Magma for MultiplicativeOperation<T>
322 where
323 T: Clone + One + Mul<Output = T>,
324 {
325 type T = T;
326 #[inline]
327 fn operate(x: &Self::T, y: &Self::T) -> Self::T {
328 x.clone() * y.clone()
329 }
330 }
331 impl<T> Unital for MultiplicativeOperation<T>
332 where
333 T: Clone + One + Mul<Output = T>,
334 {
335 #[inline]
336 fn unit() -> Self::T {
337 One::one()
338 }
339 }
340 impl<T> Associative for MultiplicativeOperation<T> where T: Clone + One + Mul<Output = T> {}
341 impl<T> Commutative for MultiplicativeOperation<T> where T: Clone + One + Mul<Output = T> {}
342 impl<T> Invertible for MultiplicativeOperation<T>
343 where
344 T: Clone + One + Mul<Output = T> + Div<Output = T>,
345 {
346 #[inline]
347 fn inverse(x: &Self::T) -> Self::T {
348 Self::unit().div(x.clone())
349 }
350 #[inline]
351 fn rinv_operate(x: &Self::T, y: &Self::T) -> Self::T {
352 (x.clone()).div(y.clone())
353 }
354 }
355
356 #[cfg(test)]
357 mod tests {
358 use super::*;
359 use crate::num::mint_basic::MInt998244353;
360
361 #[test]
362 fn test_multiplicative_operation() {
363 type MInt = MInt998244353;
364 type M = MultiplicativeOperation<MInt>;
365 let iter = (-10..=10).map(MInt::from);
366 for a in iter.clone() {
367 assert!(M::check_unital(&a));
368 if !a.is_zero() {
369 assert!(M::check_invertible(&a));
370 }
371 for b in iter.clone() {
372 assert!(M::check_commutative(&a, &b));
373 for c in iter.clone() {
374 assert!(M::check_associative(&a, &b, &c));
375 }
376 }
377 }
378 }
379 }
380}
381
382#[codesnip::entry("LinearOperation")]
383pub use self::linear_operation_impl::LinearOperation;
384#[codesnip::entry("LinearOperation", include("algebra", "zero_one"))]
385mod linear_operation_impl {
386 use super::*;
387 use std::{
388 marker::PhantomData,
389 ops::{Add, Div, Mul, Neg, Sub},
390 };
391 pub struct LinearOperation<T>
393 where
394 T: Clone + Zero + Add<Output = T> + One + Mul<Output = T>,
395 {
396 _marker: PhantomData<fn() -> T>,
397 }
398 impl<T> LinearOperation<T>
399 where
400 T: Clone + Zero + Add<Output = T> + One + Mul<Output = T>,
401 {
402 pub fn apply(f: &(T, T), x: &T) -> T {
403 f.0.clone() * x.clone() + f.1.clone()
404 }
405 }
406 impl<T> Magma for LinearOperation<T>
407 where
408 T: Clone + Zero + One + Add<Output = T> + Mul<Output = T>,
409 {
410 type T = (T, T);
411 #[inline]
412 fn operate(x: &Self::T, y: &Self::T) -> Self::T {
413 (
414 y.0.clone() * x.0.clone(),
415 y.0.clone() * x.1.clone() + y.1.clone(),
416 )
417 }
418 }
419 impl<T> Unital for LinearOperation<T>
420 where
421 T: Clone + Zero + One + Add<Output = T> + Mul<Output = T>,
422 {
423 #[inline]
424 fn unit() -> Self::T {
425 (One::one(), Zero::zero())
426 }
427 }
428 impl<T> Associative for LinearOperation<T> where
429 T: Clone + Zero + One + Add<Output = T> + Mul<Output = T>
430 {
431 }
432 impl<T> Invertible for LinearOperation<T>
433 where
434 T: Clone
435 + Zero
436 + One
437 + Add<Output = T>
438 + Sub<Output = T>
439 + Neg<Output = T>
440 + Mul<Output = T>
441 + Div<Output = T>,
442 {
443 fn inverse(x: &Self::T) -> Self::T {
444 let y = <T as One>::one().div(x.0.clone());
445 (y.clone(), -y.mul(x.1.clone()))
446 }
447 }
448
449 #[cfg(test)]
450 mod tests {
451 use super::*;
452 use crate::num::mint_basic::MInt998244353;
453
454 #[test]
455 fn test_linear_operation() {
456 type MInt = MInt998244353;
457 type M = LinearOperation<MInt>;
458 let iter = (-5..=5).flat_map(|x| (-5..=5).map(move |y| (MInt::from(x), MInt::from(y))));
459 for a in iter.clone() {
460 assert!(M::check_unital(&a));
461 if !a.0.is_zero() {
462 assert!(M::check_invertible(&a));
463 }
464 for b in iter.clone() {
465 for c in iter.clone() {
466 assert!(M::check_associative(&a, &b, &c));
467 }
468 for x in (-5..=5).map(MInt::from) {
469 assert_eq!(
470 M::apply(&M::operate(&a, &b), &x),
471 M::apply(&b, &M::apply(&a, &x))
472 );
473 }
474 }
475 }
476 }
477 }
478}
479
480#[codesnip::entry("BitAndOperation")]
481pub use self::bitand_operation_impl::{BitAndIdentity, BitAndOperation};
482#[codesnip::entry("BitAndOperation", include("algebra"))]
483mod bitand_operation_impl {
484 use super::*;
485 use std::{marker::PhantomData, ops::BitAnd};
486 pub struct BitAndOperation<T>
488 where
489 T: Clone + BitAndIdentity,
490 {
491 _marker: PhantomData<fn() -> T>,
492 }
493 pub trait BitAndIdentity: Sized + BitAnd<Output = Self> {
494 fn all_one() -> Self;
495 }
496 #[macro_export]
497 macro_rules! impl_bitand_identity {
498 ([$($wh:tt)*], $t:ty, $all_one:expr) => {
499 impl<$($wh)*> BitAndIdentity for $t {
500 #[inline]
501 fn all_one() -> Self {
502 $all_one
503 }
504 }
505 };
506 ($t:ty, $all_one:expr) => {
507 impl BitAndIdentity for $t {
508 #[inline]
509 fn all_one() -> Self {
510 $all_one
511 }
512 }
513 };
514 }
515 impl_bitand_identity!(bool, true);
516 impl_bitand_identity!(usize, usize::MAX);
517 impl_bitand_identity!(u8, u8::MAX);
518 impl_bitand_identity!(u16, u16::MAX);
519 impl_bitand_identity!(u32, u32::MAX);
520 impl_bitand_identity!(u64, u64::MAX);
521 impl_bitand_identity!(u128, u128::MAX);
522 impl_bitand_identity!(isize, -1);
523 impl_bitand_identity!(i8, -1);
524 impl_bitand_identity!(i16, -1);
525 impl_bitand_identity!(i32, -1);
526 impl_bitand_identity!(i64, -1);
527 impl_bitand_identity!(i128, -1);
528 impl<T> Magma for BitAndOperation<T>
529 where
530 T: Clone + BitAndIdentity,
531 {
532 type T = T;
533 #[inline]
534 fn operate(x: &Self::T, y: &Self::T) -> Self::T {
535 x.clone() & y.clone()
536 }
537 }
538 impl<T> Unital for BitAndOperation<T>
539 where
540 T: Clone + BitAndIdentity,
541 {
542 #[inline]
543 fn unit() -> Self::T {
544 BitAndIdentity::all_one()
545 }
546 }
547 impl<T> Associative for BitAndOperation<T> where T: Clone + BitAndIdentity {}
548 impl<T> Commutative for BitAndOperation<T> where T: Clone + BitAndIdentity {}
549 impl<T> Idempotent for BitAndOperation<T> where T: Clone + BitAndIdentity {}
550
551 #[cfg(test)]
552 mod tests {
553 use super::*;
554
555 #[test]
556 fn test_bitand_operation() {
557 let mut rng = crate::tools::Xorshift::default();
558 macro_rules! check {
559 ($ty:ty, $value:expr, $small:expr) => {{
560 type M = BitAndOperation<$ty>;
561 let alphabet: Vec<$ty> = $small;
562 let alphabet = alphabet.as_slice();
563 let triples: Vec<_> = alphabet
564 .iter()
565 .flat_map(|&a| {
566 alphabet
567 .iter()
568 .flat_map(move |&b| alphabet.iter().map(move |&c| (a, b, c)))
569 })
570 .chain((0..1000).map(|_| ($value, $value, $value)))
571 .collect();
572 for (a, b, c) in triples {
573 assert_eq!(M::operate(&a, &b), a & b);
574 assert!(M::check_unital(&a));
575 assert!(M::check_idempotent(&a));
576 assert!(M::check_commutative(&a, &b));
577 assert!(M::check_associative(&a, &b, &c));
578 }
579 }};
580 }
581 check!(bool, rng.random(0..2) == 0, vec![false, true]);
582 check!(
583 u8,
584 rng.random(..),
585 (0..=7).chain([u8::MIN, u8::MAX]).collect()
586 );
587 check!(
588 i8,
589 rng.random(..),
590 (0..=7).chain([i8::MIN, i8::MAX]).collect()
591 );
592 check!(
593 u16,
594 rng.random(..),
595 (0..=7).chain([u16::MIN, u16::MAX]).collect()
596 );
597 check!(
598 i16,
599 rng.random(..),
600 (0..=7).chain([i16::MIN, i16::MAX]).collect()
601 );
602 check!(
603 u32,
604 rng.random(..),
605 (0..=7).chain([u32::MIN, u32::MAX]).collect()
606 );
607 check!(
608 i32,
609 rng.random(..),
610 (0..=7).chain([i32::MIN, i32::MAX]).collect()
611 );
612 check!(
613 u64,
614 rng.random(..),
615 (0..=7).chain([u64::MIN, u64::MAX]).collect()
616 );
617 check!(
618 i64,
619 rng.random(..),
620 (0..=7).chain([i64::MIN, i64::MAX]).collect()
621 );
622 check!(
623 u128,
624 rng.random(..),
625 (0..=7).chain([u128::MIN, u128::MAX]).collect()
626 );
627 check!(
628 i128,
629 rng.random(..),
630 (0..=7).chain([i128::MIN, i128::MAX]).collect()
631 );
632 check!(
633 usize,
634 rng.random(..),
635 (0..=7).chain([usize::MIN, usize::MAX]).collect()
636 );
637 check!(
638 isize,
639 rng.random(..),
640 (0..=7).chain([isize::MIN, isize::MAX]).collect()
641 );
642 }
643 }
644}
645
646#[codesnip::entry("BitOrOperation")]
647pub use self::bitor_operation_impl::{BitOrIdentity, BitOrOperation};
648#[codesnip::entry("BitOrOperation", include("algebra"))]
649mod bitor_operation_impl {
650 use super::*;
651 use std::{marker::PhantomData, ops::BitOr};
652 pub struct BitOrOperation<T>
654 where
655 T: Clone + BitOrIdentity,
656 {
657 _marker: PhantomData<fn() -> T>,
658 }
659 pub trait BitOrIdentity: Sized + BitOr<Output = Self> {
660 fn all_zero() -> Self;
661 }
662 #[macro_export]
663 macro_rules! impl_bitor_identity {
664 ([$($wh:tt)*], $t:ty, $all_zero:expr) => {
665 impl<$($wh)*> BitOrIdentity for $t {
666 #[inline]
667 fn all_zero() -> Self {
668 $all_zero
669 }
670 }
671 };
672 ($t:ty, $all_zero:expr) => {
673 impl BitOrIdentity for $t {
674 #[inline]
675 fn all_zero() -> Self {
676 $all_zero
677 }
678 }
679 };
680 }
681 impl_bitor_identity!(bool, false);
682 impl_bitor_identity!(usize, 0);
683 impl_bitor_identity!(u8, 0);
684 impl_bitor_identity!(u16, 0);
685 impl_bitor_identity!(u32, 0);
686 impl_bitor_identity!(u64, 0);
687 impl_bitor_identity!(u128, 0);
688 impl_bitor_identity!(isize, 0);
689 impl_bitor_identity!(i8, 0);
690 impl_bitor_identity!(i16, 0);
691 impl_bitor_identity!(i32, 0);
692 impl_bitor_identity!(i64, 0);
693 impl_bitor_identity!(i128, 0);
694 impl<T> Magma for BitOrOperation<T>
695 where
696 T: Clone + BitOrIdentity,
697 {
698 type T = T;
699 #[inline]
700 fn operate(x: &Self::T, y: &Self::T) -> Self::T {
701 x.clone() | y.clone()
702 }
703 }
704 impl<T> Unital for BitOrOperation<T>
705 where
706 T: Clone + BitOrIdentity,
707 {
708 #[inline]
709 fn unit() -> Self::T {
710 BitOrIdentity::all_zero()
711 }
712 }
713 impl<T> Associative for BitOrOperation<T> where T: Clone + BitOrIdentity {}
714 impl<T> Commutative for BitOrOperation<T> where T: Clone + BitOrIdentity {}
715 impl<T> Idempotent for BitOrOperation<T> where T: Clone + BitOrIdentity {}
716
717 #[cfg(test)]
718 mod tests {
719 use super::*;
720
721 #[test]
722 fn test_bitor_operation() {
723 let mut rng = crate::tools::Xorshift::default();
724 macro_rules! check {
725 ($ty:ty, $value:expr, $small:expr) => {{
726 type M = BitOrOperation<$ty>;
727 let alphabet: Vec<$ty> = $small;
728 let alphabet = alphabet.as_slice();
729 let triples: Vec<_> = alphabet
730 .iter()
731 .flat_map(|&a| {
732 alphabet
733 .iter()
734 .flat_map(move |&b| alphabet.iter().map(move |&c| (a, b, c)))
735 })
736 .chain((0..1000).map(|_| ($value, $value, $value)))
737 .collect();
738 for (a, b, c) in triples {
739 assert_eq!(M::operate(&a, &b), a | b);
740 assert!(M::check_unital(&a));
741 assert!(M::check_idempotent(&a));
742 assert!(M::check_commutative(&a, &b));
743 assert!(M::check_associative(&a, &b, &c));
744 }
745 }};
746 }
747 check!(bool, rng.random(0..2) == 0, vec![false, true]);
748 check!(
749 u8,
750 rng.random(..),
751 (0..=7).chain([u8::MIN, u8::MAX]).collect()
752 );
753 check!(
754 i8,
755 rng.random(..),
756 (0..=7).chain([i8::MIN, i8::MAX]).collect()
757 );
758 check!(
759 u16,
760 rng.random(..),
761 (0..=7).chain([u16::MIN, u16::MAX]).collect()
762 );
763 check!(
764 i16,
765 rng.random(..),
766 (0..=7).chain([i16::MIN, i16::MAX]).collect()
767 );
768 check!(
769 u32,
770 rng.random(..),
771 (0..=7).chain([u32::MIN, u32::MAX]).collect()
772 );
773 check!(
774 i32,
775 rng.random(..),
776 (0..=7).chain([i32::MIN, i32::MAX]).collect()
777 );
778 check!(
779 u64,
780 rng.random(..),
781 (0..=7).chain([u64::MIN, u64::MAX]).collect()
782 );
783 check!(
784 i64,
785 rng.random(..),
786 (0..=7).chain([i64::MIN, i64::MAX]).collect()
787 );
788 check!(
789 u128,
790 rng.random(..),
791 (0..=7).chain([u128::MIN, u128::MAX]).collect()
792 );
793 check!(
794 i128,
795 rng.random(..),
796 (0..=7).chain([i128::MIN, i128::MAX]).collect()
797 );
798 check!(
799 usize,
800 rng.random(..),
801 (0..=7).chain([usize::MIN, usize::MAX]).collect()
802 );
803 check!(
804 isize,
805 rng.random(..),
806 (0..=7).chain([isize::MIN, isize::MAX]).collect()
807 );
808 }
809 }
810}
811
812#[codesnip::entry("BitXorOperation")]
813pub use self::bitxor_operation_impl::{BitXorIdentity, BitXorOperation};
814#[codesnip::entry("BitXorOperation", include("algebra"))]
815mod bitxor_operation_impl {
816 use super::*;
817 use std::{marker::PhantomData, ops::BitXor};
818 pub struct BitXorOperation<T>
820 where
821 T: Clone + BitXorIdentity,
822 {
823 _marker: PhantomData<fn() -> T>,
824 }
825 pub trait BitXorIdentity: Sized + BitXor<Output = Self> {
826 fn xor_zero() -> Self;
827 }
828 #[macro_export]
829 macro_rules! impl_bitxor_identity {
830 ([$($wh:tt)*], $t:ty, $xor_zero:expr) => {
831 impl<$($wh)*> BitXorIdentity for $t {
832 #[inline]
833 fn xor_zero() -> Self { $xor_zero }
834 }
835 };
836 ($t:ty, $xor_zero:expr) =>{
837 impl BitXorIdentity for $t {
838 #[inline]
839 fn xor_zero() -> Self { $xor_zero }
840 }
841 };
842 }
843 impl_bitxor_identity!(bool, false);
844 impl_bitxor_identity!(usize, 0);
845 impl_bitxor_identity!(u8, 0);
846 impl_bitxor_identity!(u16, 0);
847 impl_bitxor_identity!(u32, 0);
848 impl_bitxor_identity!(u64, 0);
849 impl_bitxor_identity!(u128, 0);
850 impl_bitxor_identity!(isize, 0);
851 impl_bitxor_identity!(i8, 0);
852 impl_bitxor_identity!(i16, 0);
853 impl_bitxor_identity!(i32, 0);
854 impl_bitxor_identity!(i64, 0);
855 impl_bitxor_identity!(i128, 0);
856 impl<T> Magma for BitXorOperation<T>
857 where
858 T: Clone + BitXorIdentity,
859 {
860 type T = T;
861 #[inline]
862 fn operate(x: &Self::T, y: &Self::T) -> Self::T {
863 x.clone() ^ y.clone()
864 }
865 }
866 impl<T> Unital for BitXorOperation<T>
867 where
868 T: Clone + BitXorIdentity,
869 {
870 #[inline]
871 fn unit() -> Self::T {
872 BitXorIdentity::xor_zero()
873 }
874 }
875 impl<T> Associative for BitXorOperation<T> where T: Clone + BitXorIdentity {}
876 impl<T> Commutative for BitXorOperation<T> where T: Clone + BitXorIdentity {}
877 impl<T> Invertible for BitXorOperation<T>
878 where
879 T: Clone + BitXorIdentity,
880 {
881 fn inverse(x: &Self::T) -> Self::T {
882 x.clone()
883 }
884 }
885
886 #[cfg(test)]
887 mod tests {
888 use super::*;
889
890 #[test]
891 fn test_bitxor_operation() {
892 let mut rng = crate::tools::Xorshift::default();
893 macro_rules! check {
894 ($ty:ty, $value:expr, $small:expr) => {{
895 type M = BitXorOperation<$ty>;
896 let alphabet: Vec<$ty> = $small;
897 let alphabet = alphabet.as_slice();
898 let triples: Vec<_> = alphabet
899 .iter()
900 .flat_map(|&a| {
901 alphabet
902 .iter()
903 .flat_map(move |&b| alphabet.iter().map(move |&c| (a, b, c)))
904 })
905 .chain((0..1000).map(|_| ($value, $value, $value)))
906 .collect();
907 for (a, b, c) in triples {
908 assert_eq!(M::operate(&a, &b), a ^ b);
909 assert!(M::check_unital(&a));
910 assert!(M::check_invertible(&a));
911 assert!(M::check_commutative(&a, &b));
912 assert!(M::check_associative(&a, &b, &c));
913 }
914 }};
915 }
916 check!(bool, rng.random(0..2) == 0, vec![false, true]);
917 check!(
918 u8,
919 rng.random(..),
920 (0..=7).chain([u8::MIN, u8::MAX]).collect()
921 );
922 check!(
923 i8,
924 rng.random(..),
925 (0..=7).chain([i8::MIN, i8::MAX]).collect()
926 );
927 check!(
928 u16,
929 rng.random(..),
930 (0..=7).chain([u16::MIN, u16::MAX]).collect()
931 );
932 check!(
933 i16,
934 rng.random(..),
935 (0..=7).chain([i16::MIN, i16::MAX]).collect()
936 );
937 check!(
938 u32,
939 rng.random(..),
940 (0..=7).chain([u32::MIN, u32::MAX]).collect()
941 );
942 check!(
943 i32,
944 rng.random(..),
945 (0..=7).chain([i32::MIN, i32::MAX]).collect()
946 );
947 check!(
948 u64,
949 rng.random(..),
950 (0..=7).chain([u64::MIN, u64::MAX]).collect()
951 );
952 check!(
953 i64,
954 rng.random(..),
955 (0..=7).chain([i64::MIN, i64::MAX]).collect()
956 );
957 check!(
958 u128,
959 rng.random(..),
960 (0..=7).chain([u128::MIN, u128::MAX]).collect()
961 );
962 check!(
963 i128,
964 rng.random(..),
965 (0..=7).chain([i128::MIN, i128::MAX]).collect()
966 );
967 check!(
968 usize,
969 rng.random(..),
970 (0..=7).chain([usize::MIN, usize::MAX]).collect()
971 );
972 check!(
973 isize,
974 rng.random(..),
975 (0..=7).chain([isize::MIN, isize::MAX]).collect()
976 );
977 }
978 }
979}
980
981#[codesnip::entry("LogicalLinearOperation")]
982pub use self::logical_linear_operation_impl::LogicalLinearOperation;
983#[codesnip::entry(
984 "LogicalLinearOperation",
985 include("algebra", "BitXorOperation", "BitAndOperation")
986)]
987mod logical_linear_operation_impl {
988 use super::*;
989 use std::{
990 marker::PhantomData,
991 ops::{BitAnd, BitXor},
992 };
993 pub struct LogicalLinearOperation<T>
995 where
996 T: Clone + BitXorIdentity + BitAndIdentity + BitXor<Output = T> + BitAnd<Output = T>,
997 {
998 _marker: PhantomData<fn() -> T>,
999 }
1000 impl<T> LogicalLinearOperation<T>
1001 where
1002 T: Clone + BitXorIdentity + BitAndIdentity + BitXor<Output = T> + BitAnd<Output = T>,
1003 {
1004 pub fn eval((a, b): &<Self as Magma>::T, x: &T) -> T {
1005 a.clone() & x.clone() ^ b.clone()
1006 }
1007 }
1008 impl<T> Magma for LogicalLinearOperation<T>
1009 where
1010 T: Clone + BitXorIdentity + BitAndIdentity + BitXor<Output = T> + BitAnd<Output = T>,
1011 {
1012 type T = (T, T);
1013 #[inline]
1014 fn operate(x: &Self::T, y: &Self::T) -> Self::T {
1015 (
1016 y.0.clone() & x.0.clone(),
1017 y.0.clone() & x.1.clone() ^ y.1.clone(),
1018 )
1019 }
1020 }
1021 impl<T> Unital for LogicalLinearOperation<T>
1022 where
1023 T: Clone + BitXorIdentity + BitAndIdentity + BitXor<Output = T> + BitAnd<Output = T>,
1024 {
1025 #[inline]
1026 fn unit() -> Self::T {
1027 (BitAndIdentity::all_one(), BitXorIdentity::xor_zero())
1028 }
1029 }
1030 impl<T> Associative for LogicalLinearOperation<T> where
1031 T: Clone + BitXorIdentity + BitAndIdentity + BitXor<Output = T> + BitAnd<Output = T>
1032 {
1033 }
1034
1035 #[cfg(test)]
1036 mod tests {
1037 use super::*;
1038
1039 #[test]
1040 fn test_logical_linear_operation() {
1041 type M = LogicalLinearOperation<i32>;
1042 let iter = (-3..=3).flat_map(|x| (-3..=3).map(move |y| (x, y)));
1043 for a in iter.clone() {
1044 assert!(M::check_unital(&a));
1045 for b in iter.clone() {
1046 for c in iter.clone() {
1047 assert!(M::check_associative(&a, &b, &c));
1048 }
1049 for x in -3..=3 {
1050 assert_eq!(
1051 M::eval(&M::operate(&a, &b), &x),
1052 M::eval(&b, &M::eval(&a, &x))
1053 );
1054 }
1055 }
1056 }
1057 }
1058 }
1059}
1060
1061#[codesnip::entry("TupleOperation", include("algebra"))]
1062mod tuple_operation_impl {
1063 use super::*;
1064 macro_rules! impl_tuple_operation {
1065 (@impl) => {
1066 impl Magma for () {
1067 type T = ();
1068 fn operate(_x: &Self::T, _y: &Self::T) -> Self::T {}
1069 }
1070 impl Unital for () {
1071 fn unit() -> Self::T {}
1072 }
1073 impl Associative for () {}
1074 impl Commutative for () {}
1075 impl Idempotent for () {}
1076 impl Invertible for () {
1077 fn inverse(_x: &Self::T) -> Self::T {}
1078 }
1079 };
1080 (@impl $($T:ident $i:tt)*) => {
1081 impl<$($T: Magma),*> Magma for ($($T,)*) {
1082 type T = ($(<$T as Magma>::T,)*);
1083 fn operate(x: &Self::T, y: &Self::T) -> Self::T {
1084 ($(<$T as Magma>::operate(&x.$i, &y.$i),)*)
1085 }
1086 }
1087 impl<$($T: Unital),*> Unital for ($($T,)*) {
1088 fn unit() -> Self::T {
1089 ($(<$T as Unital>::unit(),)*)
1090 }
1091 }
1092 impl<$($T: Associative),*> Associative for ($($T,)*) {}
1093 impl<$($T: Commutative),*> Commutative for ($($T,)*) {}
1094 impl<$($T: Idempotent),*> Idempotent for ($($T,)*) {}
1095 impl<$($T: Invertible),*> Invertible for ($($T,)*) {
1096 fn inverse(x: &Self::T) -> Self::T {
1097 ($(<$T as Invertible>::inverse(&x.$i),)*)
1098 }
1099 }
1100 };
1101 (@inner $($T:ident $i:tt)*; $U:ident $j:tt $($t:tt)*) => {
1102 impl_tuple_operation!(@impl $($T $i)*);
1103 impl_tuple_operation!(@inner $($T $i)* $U $j; $($t)*);
1104 };
1105 (@inner $($T:ident $i:tt)*;) => {
1106 impl_tuple_operation!(@impl $($T $i)*);
1107 };
1108 ($($t:tt)*) => {
1109 impl_tuple_operation!(@inner ; $($t)*);
1110 };
1111 }
1112 impl_tuple_operation!(A 0 B 1 C 2 D 3 E 4 F 5 G 6 H 7 I 8 J 9);
1113
1114 #[cfg(test)]
1115 mod tests {
1116 use super::*;
1117 use crate::num::mint_basic::MInt998244353;
1118
1119 #[test]
1120 fn test_tuple_operation() {
1121 type MInt = MInt998244353;
1122 type M = (AdditiveOperation<MInt>, MultiplicativeOperation<MInt>);
1123 let iter = (-5..=5).flat_map(|x| (-5..=5).map(move |y| (MInt::from(x), MInt::from(y))));
1124 for a in iter.clone() {
1125 assert!(M::check_unital(&a));
1126 if !a.1.is_zero() {
1127 assert!(M::check_invertible(&a));
1128 }
1129 for b in iter.clone() {
1130 assert!(M::check_commutative(&a, &b));
1131 for c in iter.clone() {
1132 assert!(M::check_associative(&a, &b, &c));
1133 }
1134 }
1135 }
1136 }
1137 }
1138}
1139
1140#[codesnip::entry("ArrayOperation")]
1141pub use self::array_operation_impl::ArrayOperation;
1142#[codesnip::entry("ArrayOperation", include("algebra", "array"))]
1143mod array_operation_impl {
1144 use super::*;
1145 use crate::array;
1146 use std::marker::PhantomData;
1147 pub struct ArrayOperation<M, const N: usize> {
1148 _marker: PhantomData<fn() -> M>,
1149 }
1150 impl<M, const N: usize> Magma for ArrayOperation<M, N>
1151 where
1152 M: Magma,
1153 {
1154 type T = [M::T; N];
1155 #[inline]
1156 fn operate(x: &Self::T, y: &Self::T) -> Self::T {
1157 array!(|i| M::operate(&x[i], &y[i]); N)
1158 }
1159 }
1160 impl<M, const N: usize> Unital for ArrayOperation<M, N>
1161 where
1162 M: Unital,
1163 {
1164 #[inline]
1165 fn unit() -> Self::T {
1166 array!(|| M::unit(); N)
1167 }
1168 }
1169 impl<M, const N: usize> Associative for ArrayOperation<M, N> where M: Associative {}
1170 impl<M, const N: usize> Commutative for ArrayOperation<M, N> where M: Commutative {}
1171 impl<M, const N: usize> Idempotent for ArrayOperation<M, N> where M: Idempotent {}
1172 impl<M, const N: usize> Invertible for ArrayOperation<M, N>
1173 where
1174 M: Invertible,
1175 {
1176 #[inline]
1177 fn inverse(x: &Self::T) -> Self::T {
1178 array!(|i| M::inverse(&x[i]); N)
1179 }
1180 }
1181
1182 #[cfg(test)]
1183 mod tests {
1184 use super::*;
1185
1186 #[test]
1187 fn test_array_operation() {
1188 type M = ArrayOperation<AdditiveOperation<i32>, 2>;
1189
1190 let iter = (-5..=5).flat_map(|x| (-5..=5).map(move |y| [x, y]));
1191 for a in iter.clone() {
1192 assert!(M::check_unital(&a));
1193 assert!(M::check_invertible(&a));
1194 for b in iter.clone() {
1195 assert!(M::check_commutative(&a, &b));
1196 for c in iter.clone() {
1197 assert!(M::check_associative(&a, &b, &c));
1198 }
1199 }
1200 }
1201 }
1202 }
1203}
1204
1205#[codesnip::entry("CountingOperation")]
1206pub use self::counting_operation_impl::CountingOperation;
1207#[codesnip::entry("CountingOperation", include("algebra"))]
1208mod counting_operation_impl {
1209 use super::*;
1210 use std::marker::PhantomData;
1211 pub struct CountingOperation<M> {
1212 _marker: PhantomData<fn() -> M>,
1213 }
1214 impl<M> Magma for CountingOperation<M>
1215 where
1216 M: Magma<T: PartialEq> + Idempotent,
1217 {
1218 type T = (M::T, usize);
1219 #[inline]
1220 fn operate(x: &Self::T, y: &Self::T) -> Self::T {
1221 let z = M::operate(&x.0, &y.0);
1222 match (z == x.0, z == y.0) {
1223 (true, true) => (z, x.1 + y.1),
1224 (true, false) => (z, x.1),
1225 (false, true) => (z, y.1),
1226 (false, false) => (z, 1),
1227 }
1228 }
1229 }
1230 impl<M> Unital for CountingOperation<M>
1231 where
1232 M: Unital<T: PartialEq> + Idempotent,
1233 {
1234 #[inline]
1235 fn unit() -> Self::T {
1236 (M::unit(), 0)
1237 }
1238 }
1239 impl<M> Associative for CountingOperation<M> where M: Associative<T: PartialEq> + Idempotent {}
1240 impl<M> Commutative for CountingOperation<M> where M: Commutative<T: PartialEq> + Idempotent {}
1241
1242 #[cfg(test)]
1243 mod tests {
1244 use super::*;
1245
1246 #[test]
1247 fn test_counting_operation() {
1248 type M = CountingOperation<MaxOperation<i32>>;
1249 let iter = (-5..=5).flat_map(|x| (1..=5).map(move |y| (x, y)));
1250 for a in iter.clone() {
1251 assert!(M::check_unital(&a));
1252 for b in iter.clone() {
1253 assert!(M::check_commutative(&a, &b));
1254 for c in iter.clone() {
1255 assert!(M::check_associative(&a, &b, &c));
1256 }
1257 }
1258 }
1259 }
1260 }
1261}
1262
1263#[codesnip::entry("ReverseOperation")]
1264pub use self::reverse_operation_impl::ReverseOperation;
1265#[codesnip::entry("ReverseOperation", include("algebra"))]
1266mod reverse_operation_impl {
1267 use super::*;
1268 use std::marker::PhantomData;
1269 pub struct ReverseOperation<M> {
1270 _marker: PhantomData<fn() -> M>,
1271 }
1272 impl<M> Magma for ReverseOperation<M>
1273 where
1274 M: Magma,
1275 {
1276 type T = M::T;
1277 #[inline]
1278 fn operate(x: &Self::T, y: &Self::T) -> Self::T {
1279 M::operate(y, x)
1280 }
1281 }
1282 impl<M> Unital for ReverseOperation<M>
1283 where
1284 M: Unital,
1285 {
1286 #[inline]
1287 fn unit() -> Self::T {
1288 M::unit()
1289 }
1290 }
1291 impl<M> Associative for ReverseOperation<M> where M: Associative {}
1292 impl<M> Commutative for ReverseOperation<M> where M: Commutative {}
1293 impl<M> Invertible for ReverseOperation<M>
1294 where
1295 M: Invertible,
1296 {
1297 #[inline]
1298 fn inverse(x: &Self::T) -> Self::T {
1299 M::inverse(x)
1300 }
1301 }
1302 impl<M> Idempotent for ReverseOperation<M> where M: Idempotent {}
1303
1304 #[cfg(test)]
1305 mod tests {
1306 use super::*;
1307 use crate::num::mint_basic::MInt998244353;
1308
1309 #[test]
1310 fn test_reverse_operation() {
1311 type MInt = MInt998244353;
1312 type M = ReverseOperation<LinearOperation<MInt>>;
1313 let iter = (-3..=3).flat_map(|x| (-3..=3).map(move |y| (MInt::from(x), MInt::from(y))));
1314 for a in iter.clone() {
1315 assert!(M::check_unital(&a));
1316 if !a.0.is_zero() {
1317 assert!(M::check_invertible(&a));
1318 }
1319 for b in iter.clone() {
1320 for c in iter.clone() {
1321 assert!(M::check_associative(&a, &b, &c));
1322 }
1323 }
1324 }
1325 }
1326 }
1327}
1328
1329#[codesnip::entry("TopkOperation")]
1330pub use self::topk_operation_impl::TopkOperation;
1331#[codesnip::entry("TopkOperation", include("algebra", "bounded", "array"))]
1332mod topk_operation_impl {
1333 use super::*;
1334 use std::marker::PhantomData;
1335 pub struct TopkOperation<const K: usize, T>
1336 where
1337 T: Clone + Ord + Bounded,
1338 {
1339 _marker: PhantomData<fn() -> T>,
1340 }
1341 impl<const K: usize, T> Magma for TopkOperation<K, T>
1342 where
1343 T: Clone + Ord + Bounded,
1344 {
1345 type T = [T; K];
1346 fn operate(x: &Self::T, y: &Self::T) -> Self::T {
1347 let mut i = 0;
1348 let mut j = 0;
1349 crate::array![|| if i == K || j != K && x[i] < y[j] {
1350 let t = &y[j];
1351 j += 1;
1352 t.clone()
1353 } else {
1354 let t = &x[i];
1355 i += 1;
1356 t.clone()
1357 }; K]
1358 }
1359 }
1360 impl<const K: usize, T> Unital for TopkOperation<K, T>
1361 where
1362 T: Clone + Ord + Bounded,
1363 {
1364 fn unit() -> Self::T {
1365 crate::array![|| <T as Bounded>::minimum(); K]
1366 }
1367 }
1368 impl<const K: usize, T> Associative for TopkOperation<K, T> where T: Clone + Ord + Bounded {}
1369 impl<const K: usize, T> Commutative for TopkOperation<K, T> where T: Clone + Ord + Bounded {}
1370
1371 #[cfg(test)]
1372 mod tests {
1373 use super::*;
1374 use crate::{array, tools::Xorshift};
1375
1376 #[test]
1377 fn test_topk_operation() {
1378 type M = TopkOperation<4, i64>;
1379 let mut rng = Xorshift::default();
1380 for _ in 0..100 {
1381 let mut x = [i64::MIN; 4];
1382 for _ in 0..100 {
1383 let mut y = [i64::MIN; 4];
1384 for y in &mut y {
1385 *y = rng.random(0..1000);
1386 }
1387 y.sort_unstable();
1388 y.reverse();
1389 let z = {
1390 let mut x = x.to_vec();
1391 x.extend(&y);
1392 x.sort_unstable();
1393 x.reverse();
1394 x.truncate(4);
1395 x
1396 };
1397 let zz = M::operate(&x, &y);
1398 for (z, zz) in z.iter().zip(&zz) {
1399 assert_eq!(z, zz);
1400 }
1401 x = zz;
1402 }
1403
1404 let mut g = || {
1405 if rng.random(0..3) == 0 {
1406 i64::MIN
1407 } else {
1408 rng.random(0..10)
1409 }
1410 };
1411 let mut a = array![|| g(); 4];
1412 a.sort_unstable();
1413 a.reverse();
1414 assert!(M::check_unital(&a));
1415 let mut b = array![|| g(); 4];
1416 b.sort_unstable();
1417 b.reverse();
1418 assert!(M::check_commutative(&a, &b));
1419 let mut c = array![|| g(); 4];
1420 c.sort_unstable();
1421 c.reverse();
1422 assert!(M::check_associative(&a, &b, &c));
1423 }
1424 }
1425 }
1426}
1427
1428#[codesnip::entry("BottomkOperation")]
1429pub use self::bottomk_operation_impl::BottomkOperation;
1430#[codesnip::entry("BottomkOperation", include("algebra", "bounded", "array"))]
1431mod bottomk_operation_impl {
1432 use super::*;
1433 use std::marker::PhantomData;
1434 pub struct BottomkOperation<const K: usize, T>
1435 where
1436 T: Clone + Ord + Bounded,
1437 {
1438 _marker: PhantomData<fn() -> T>,
1439 }
1440 impl<const K: usize, T> Magma for BottomkOperation<K, T>
1441 where
1442 T: Clone + Ord + Bounded,
1443 {
1444 type T = [T; K];
1445 fn operate(x: &Self::T, y: &Self::T) -> Self::T {
1446 let mut i = 0;
1447 let mut j = 0;
1448 crate::array![|| if i == K || j != K && x[i] > y[j] {
1449 let t = &y[j];
1450 j += 1;
1451 t.clone()
1452 } else {
1453 let t = &x[i];
1454 i += 1;
1455 t.clone()
1456 }; K]
1457 }
1458 }
1459 impl<const K: usize, T> Unital for BottomkOperation<K, T>
1460 where
1461 T: Clone + Ord + Bounded,
1462 {
1463 fn unit() -> Self::T {
1464 crate::array![|| <T as Bounded>::maximum(); K]
1465 }
1466 }
1467 impl<const K: usize, T> Associative for BottomkOperation<K, T> where T: Clone + Ord + Bounded {}
1468 impl<const K: usize, T> Commutative for BottomkOperation<K, T> where T: Clone + Ord + Bounded {}
1469
1470 #[cfg(test)]
1471 mod tests {
1472 use super::*;
1473 use crate::{array, tools::Xorshift};
1474
1475 #[test]
1476 fn test_bottomk_operation() {
1477 type M = BottomkOperation<4, i64>;
1478 let mut rng = Xorshift::default();
1479 for _ in 0..100 {
1480 let mut x = [i64::MAX; 4];
1481 for _ in 0..100 {
1482 let mut y = [i64::MAX; 4];
1483 for y in &mut y {
1484 *y = rng.random(0..1000);
1485 }
1486 y.sort_unstable();
1487 let z = {
1488 let mut x = x.to_vec();
1489 x.extend(&y);
1490 x.sort_unstable();
1491 x.truncate(4);
1492 x
1493 };
1494 let zz = M::operate(&x, &y);
1495 for (z, zz) in z.iter().zip(&zz) {
1496 assert_eq!(z, zz);
1497 }
1498 x = zz;
1499 }
1500
1501 let mut g = || {
1502 if rng.random(0..3) == 0 {
1503 i64::MAX
1504 } else {
1505 rng.random(0..10)
1506 }
1507 };
1508 let mut a = array![|| g(); 4];
1509 a.sort_unstable();
1510 assert!(M::check_unital(&a));
1511 let mut b = array![|| g(); 4];
1512 b.sort_unstable();
1513 assert!(M::check_commutative(&a, &b));
1514 let mut c = array![|| g(); 4];
1515 c.sort_unstable();
1516 assert!(M::check_associative(&a, &b, &c));
1517 }
1518 }
1519 }
1520}
1521
1522#[codesnip::entry("DedupedTopkOperation")]
1523pub use self::deduped_topk_operation_impl::DedupedTopkOperation;
1524#[codesnip::entry("DedupedTopkOperation", include("algebra", "bounded", "array"))]
1525mod deduped_topk_operation_impl {
1526 use super::*;
1527 use std::marker::PhantomData;
1528
1529 pub struct DedupedTopkOperation<const K: usize, T, U>
1530 where
1531 T: Clone + Ord + Bounded,
1532 U: Clone + Eq,
1533 {
1534 _marker: PhantomData<fn() -> (T, U)>,
1535 }
1536 impl<const K: usize, T, U> Magma for DedupedTopkOperation<K, T, U>
1537 where
1538 T: Clone + Ord + Bounded,
1539 U: Clone + Eq,
1540 {
1541 type T = [(T, Option<U>); K];
1542 fn operate(x: &Self::T, y: &Self::T) -> Self::T {
1543 let mut i = 0;
1544 let mut j = 0;
1545 let mut k = 0;
1546 let mut out = crate::array![|| (T::minimum(), None); K];
1547 while k < K && (i < K || j < K) {
1548 if j == K || (i < K && x[i].0 >= y[j].0) {
1549 if (0..j).all(|l| x[i].1 != y[l].1) {
1550 out[k] = x[i].clone();
1551 k += 1;
1552 }
1553 i += 1;
1554 } else {
1555 if (0..i).all(|l| y[j].1 != x[l].1) {
1556 out[k] = y[j].clone();
1557 k += 1;
1558 }
1559 j += 1;
1560 }
1561 }
1562 out
1563 }
1564 }
1565 impl<const K: usize, T, U> Unital for DedupedTopkOperation<K, T, U>
1566 where
1567 T: Clone + Ord + Bounded,
1568 U: Clone + Eq,
1569 {
1570 fn unit() -> Self::T {
1571 crate::array![|| (T::minimum(), None); K]
1572 }
1573 }
1574 impl<const K: usize, T, U> Associative for DedupedTopkOperation<K, T, U>
1575 where
1576 T: Clone + Ord + Bounded,
1577 U: Clone + Eq,
1578 {
1579 }
1580 impl<const K: usize, T, U> DedupedTopkOperation<K, T, U>
1581 where
1582 T: Clone + Ord + Bounded,
1583 U: Clone + Eq,
1584 {
1585 pub fn insert(x: &mut <Self as Magma>::T, item: (T, U)) {
1586 for i in 0..K {
1587 if x[i].0 < item.0 {
1588 let j = (i..K)
1589 .find(|&j| x[j].1.as_ref() == Some(&item.1))
1590 .unwrap_or(K - 1);
1591 for k in (i..j).rev() {
1592 x[k + 1] = x[k].clone();
1593 }
1594 x[i] = (item.0, Some(item.1));
1595 break;
1596 } else if x[i].1.as_ref() == Some(&item.1) {
1597 break;
1598 }
1599 }
1600 }
1601 pub fn topn<const N: usize, const M: usize>(
1602 x: &<Self as Magma>::T,
1603 excludes: &[U; M],
1604 ) -> [(T, Option<U>); N] {
1605 let mut out = crate::array![|| (T::minimum(), None); N];
1606 let mut i = 0;
1607 let mut j = 0;
1608 while i < K && j < N {
1609 if excludes.iter().all(|e| x[i].1.as_ref() != Some(e)) {
1610 out[j] = x[i].clone();
1611 j += 1;
1612 }
1613 i += 1;
1614 }
1615 out
1616 }
1617 }
1618
1619 #[cfg(test)]
1620 mod tests {
1621 use super::*;
1622 use crate::{array, tools::Xorshift};
1623 use std::collections::HashSet;
1624
1625 fn normalize(x: impl IntoIterator<Item = (i64, Option<i32>)>) -> [(i64, Option<i32>); 4] {
1626 let mut x: Vec<_> = x.into_iter().collect();
1627 x.sort_unstable();
1628 x.reverse();
1629 let mut used = HashSet::new();
1630 x.retain(|(_, u)| {
1631 if let Some(u) = u {
1632 if used.contains(u) {
1633 return false;
1634 }
1635 used.insert(*u);
1636 }
1637 true
1638 });
1639 x.resize_with(4, || (i64::MIN, None));
1640 x.try_into().unwrap()
1641 }
1642
1643 #[test]
1644 fn test_deduped_topk_operation() {
1645 type M = DedupedTopkOperation<4, i64, i32>;
1646 let mut rng = Xorshift::default();
1647 for _ in 0..100 {
1648 let mut x = [(i64::MIN, None); 4];
1649 for _ in 0..100 {
1650 let mut y = [(i64::MIN, None); 4];
1651 for y in &mut y {
1652 *y = (rng.random(0..1000), Some(rng.random(0i32..10)));
1653 }
1654 y = normalize(y);
1655 let z = normalize(x.iter().cloned().chain(y.iter().cloned()));
1656 let zz = M::operate(&x, &y);
1657 for (z, zz) in z.iter().zip(&zz) {
1658 assert_eq!(z.0, zz.0);
1659 }
1660 assert_eq!(
1661 zz.iter()
1662 .filter_map(|(_, u)| u.as_ref())
1663 .collect::<HashSet<_>>()
1664 .len(),
1665 zz.iter().filter_map(|(_, u)| u.as_ref()).count()
1666 );
1667 x = zz;
1668 }
1669
1670 let mut g = || {
1671 if rng.random(0..3) == 0 {
1672 (i64::MIN, None)
1673 } else {
1674 (rng.random(0..10), Some(rng.random(0i32..10)))
1675 }
1676 };
1677 let mut a = array![|| g(); 4];
1678 a = normalize(a);
1679 assert!(M::check_unital(&a));
1680 let mut b = array![|| g(); 4];
1681 b = normalize(b);
1682 let mut c = array![|| g(); 4];
1683 c = normalize(c);
1684 assert!(M::check_associative(&a, &b, &c));
1685 }
1686 }
1687
1688 #[test]
1689 fn test_deduped_topk_insert() {
1690 type M = DedupedTopkOperation<4, i64, i32>;
1691 let mut rng = Xorshift::default();
1692 for _ in 0..100 {
1693 let mut x = [(i64::MIN, None); 4];
1694 for _ in 0..100 {
1695 let t = (rng.random(0..1000), rng.random(0i32..10));
1696 let z = normalize(x.iter().cloned().chain([(t.0, Some(t.1))]));
1697 M::insert(&mut x, t);
1698 for (z, zz) in z.iter().zip(&x) {
1699 assert_eq!(z.0, zz.0);
1700 }
1701 assert_eq!(
1702 x.iter()
1703 .filter_map(|(_, u)| u.as_ref())
1704 .collect::<HashSet<_>>()
1705 .len(),
1706 x.iter().filter_map(|(_, u)| u.as_ref()).count()
1707 );
1708 }
1709 }
1710 }
1711
1712 #[test]
1713 fn test_deduped_topk_topn() {
1714 type M = DedupedTopkOperation<4, i64, i32>;
1715 let mut rng = Xorshift::default();
1716 for _ in 0..100 {
1717 let mut x = [(i64::MIN, None); 4];
1718 for x in &mut x {
1719 *x = (rng.random(0..1000), Some(rng.random(0i32..10)));
1720 }
1721 x = normalize(x.iter().cloned());
1722 for _ in 0..100 {
1723 let mut excludes = [0i32; 3];
1724 for e in &mut excludes {
1725 *e = rng.random(0i32..10);
1726 }
1727 let topn: [_; 3] = M::topn(&x, &excludes);
1728 let mut expected: Vec<_> = x
1729 .iter()
1730 .filter(|(_, u)| excludes.iter().all(|e| u.as_ref() != Some(e)))
1731 .cloned()
1732 .take(3)
1733 .collect();
1734 expected.resize_with(3, || (i64::MIN, None));
1735 for (expected, topn) in expected.iter().zip(&topn) {
1736 assert_eq!(expected.0, topn.0);
1737 }
1738 }
1739 }
1740 }
1741 }
1742}
1743
1744#[codesnip::entry("DedupedBottomkOperation")]
1745pub use self::deduped_bottomk_operation_impl::DedupedBottomkOperation;
1746#[codesnip::entry("DedupedBottomkOperation", include("algebra", "bounded", "array"))]
1747mod deduped_bottomk_operation_impl {
1748 use super::*;
1749 use std::marker::PhantomData;
1750
1751 pub struct DedupedBottomkOperation<const K: usize, T, U>
1752 where
1753 T: Clone + Ord + Bounded,
1754 U: Clone + Eq,
1755 {
1756 _marker: PhantomData<fn() -> (T, U)>,
1757 }
1758 impl<const K: usize, T, U> Magma for DedupedBottomkOperation<K, T, U>
1759 where
1760 T: Clone + Ord + Bounded,
1761 U: Clone + Eq,
1762 {
1763 type T = [(T, Option<U>); K];
1764 fn operate(x: &Self::T, y: &Self::T) -> Self::T {
1765 let mut i = 0;
1766 let mut j = 0;
1767 let mut k = 0;
1768 let mut out = crate::array![|| (T::maximum(), None); K];
1769 while k < K && (i < K || j < K) {
1770 if j == K || (i < K && x[i].0 <= y[j].0) {
1771 if (0..j).all(|l| x[i].1 != y[l].1) {
1772 out[k] = x[i].clone();
1773 k += 1;
1774 }
1775 i += 1;
1776 } else {
1777 if (0..i).all(|l| y[j].1 != x[l].1) {
1778 out[k] = y[j].clone();
1779 k += 1;
1780 }
1781 j += 1;
1782 }
1783 }
1784 out
1785 }
1786 }
1787 impl<const K: usize, T, U> Unital for DedupedBottomkOperation<K, T, U>
1788 where
1789 T: Clone + Ord + Bounded,
1790 U: Clone + Eq,
1791 {
1792 fn unit() -> Self::T {
1793 crate::array![|| (T::maximum(), None); K]
1794 }
1795 }
1796 impl<const K: usize, T, U> Associative for DedupedBottomkOperation<K, T, U>
1797 where
1798 T: Clone + Ord + Bounded,
1799 U: Clone + Eq,
1800 {
1801 }
1802 impl<const K: usize, T, U> DedupedBottomkOperation<K, T, U>
1803 where
1804 T: Clone + Ord + Bounded,
1805 U: Clone + Eq,
1806 {
1807 pub fn insert(x: &mut <Self as Magma>::T, item: (T, U)) {
1808 for i in 0..K {
1809 if x[i].0 > item.0 {
1810 let j = (i..K)
1811 .find(|&j| x[j].1.as_ref() == Some(&item.1))
1812 .unwrap_or(K - 1);
1813 for k in (i..j).rev() {
1814 x[k + 1] = x[k].clone();
1815 }
1816 x[i] = (item.0, Some(item.1));
1817 break;
1818 } else if x[i].1.as_ref() == Some(&item.1) {
1819 break;
1820 }
1821 }
1822 }
1823 pub fn bottomn<const N: usize, const M: usize>(
1824 x: &<Self as Magma>::T,
1825 excludes: &[U; M],
1826 ) -> [(T, Option<U>); N] {
1827 let mut out = crate::array![|| (T::maximum(), None); N];
1828 let mut i = 0;
1829 let mut j = 0;
1830 while i < K && j < N {
1831 if excludes.iter().all(|e| x[i].1.as_ref() != Some(e)) {
1832 out[j] = x[i].clone();
1833 j += 1;
1834 }
1835 i += 1;
1836 }
1837 out
1838 }
1839 }
1840
1841 #[cfg(test)]
1842 mod tests {
1843 use super::*;
1844 use crate::{array, tools::Xorshift};
1845 use std::collections::HashSet;
1846
1847 fn normalize(x: impl IntoIterator<Item = (i64, Option<i32>)>) -> [(i64, Option<i32>); 4] {
1848 let mut x: Vec<_> = x.into_iter().collect();
1849 x.sort_unstable();
1850 let mut used = HashSet::new();
1851 x.retain(|(_, u)| {
1852 if let Some(u) = u {
1853 if used.contains(u) {
1854 return false;
1855 }
1856 used.insert(*u);
1857 }
1858 true
1859 });
1860 x.resize_with(4, || (i64::MAX, None));
1861 x.try_into().unwrap()
1862 }
1863
1864 #[test]
1865 fn test_deduped_bottomk_operation() {
1866 type M = DedupedBottomkOperation<4, i64, i32>;
1867 let mut rng = Xorshift::default();
1868 for _ in 0..100 {
1869 let mut x = [(i64::MAX, None); 4];
1870 for _ in 0..100 {
1871 let mut y = [(i64::MAX, None); 4];
1872 for y in &mut y {
1873 *y = (rng.random(0..1000), Some(rng.random(0i32..10)));
1874 }
1875 y = normalize(y);
1876 let z = normalize(x.iter().cloned().chain(y.iter().cloned()));
1877 let zz = M::operate(&x, &y);
1878 for (z, zz) in z.iter().zip(&zz) {
1879 assert_eq!(z.0, zz.0);
1880 }
1881 assert_eq!(
1882 zz.iter()
1883 .filter_map(|(_, u)| u.as_ref())
1884 .collect::<HashSet<_>>()
1885 .len(),
1886 zz.iter().filter_map(|(_, u)| u.as_ref()).count()
1887 );
1888 x = zz;
1889 }
1890
1891 let mut g = || {
1892 if rng.random(0..3) == 0 {
1893 (i64::MAX, None)
1894 } else {
1895 (rng.random(0..10), Some(rng.random(0i32..10)))
1896 }
1897 };
1898 let mut a = array![|| g(); 4];
1899 a = normalize(a);
1900 assert!(M::check_unital(&a));
1901 let mut b = array![|| g(); 4];
1902 b = normalize(b);
1903 let mut c = array![|| g(); 4];
1904 c = normalize(c);
1905 assert!(M::check_associative(&a, &b, &c));
1906 }
1907 }
1908
1909 #[test]
1910 fn test_deduped_bottomk_insert() {
1911 type M = DedupedBottomkOperation<4, i64, i32>;
1912 let mut rng = Xorshift::default();
1913 for _ in 0..100 {
1914 let mut x = [(i64::MAX, None); 4];
1915 for _ in 0..100 {
1916 let t = (rng.random(0..1000), rng.random(0i32..10));
1917 let z = normalize(x.iter().cloned().chain([(t.0, Some(t.1))]));
1918 M::insert(&mut x, t);
1919 for (z, zz) in z.iter().zip(&x) {
1920 assert_eq!(z.0, zz.0);
1921 }
1922 assert_eq!(
1923 x.iter()
1924 .filter_map(|(_, u)| u.as_ref())
1925 .collect::<HashSet<_>>()
1926 .len(),
1927 x.iter().filter_map(|(_, u)| u.as_ref()).count()
1928 );
1929 }
1930 }
1931 }
1932
1933 #[test]
1934 fn test_deduped_bottomk_bottomn() {
1935 type M = DedupedBottomkOperation<4, i64, i32>;
1936 let mut rng = Xorshift::default();
1937 for _ in 0..100 {
1938 let mut x = [(i64::MAX, None); 4];
1939 for x in &mut x {
1940 *x = (rng.random(0..1000), Some(rng.random(0i32..10)));
1941 }
1942 x = normalize(x.iter().cloned());
1943 for _ in 0..100 {
1944 let mut excludes = [0i32; 3];
1945 for e in &mut excludes {
1946 *e = rng.random(0i32..10);
1947 }
1948 let bottomn: [_; 3] = M::bottomn(&x, &excludes);
1949 let mut expected: Vec<_> = x
1950 .iter()
1951 .filter(|(_, u)| excludes.iter().all(|e| u.as_ref() != Some(e)))
1952 .cloned()
1953 .take(3)
1954 .collect();
1955 expected.resize_with(3, || (i64::MAX, None));
1956 for (expected, bottomn) in expected.iter().zip(&bottomn) {
1957 assert_eq!(expected.0, bottomn.0);
1958 }
1959 }
1960 }
1961 }
1962 }
1963}
1964
1965#[codesnip::entry("PermutationOperation")]
1966pub use self::permutation_operation_impl::PermutationOperation;
1967#[codesnip::entry("PermutationOperation", include("algebra"))]
1968mod permutation_operation_impl {
1969 use super::*;
1970 pub enum PermutationOperation {}
1971 impl Magma for PermutationOperation {
1972 type T = Vec<usize>;
1973 fn operate(x: &Self::T, y: &Self::T) -> Self::T {
1974 let n = x.len().max(y.len());
1975 let z: Vec<_> = (0..n)
1976 .map(|i| {
1977 let j = y.get(i).cloned().unwrap_or(i);
1978 x.get(j).cloned().unwrap_or(j)
1979 })
1980 .collect();
1981 z
1982 }
1983 }
1984 impl Associative for PermutationOperation {}
1985 impl Unital for PermutationOperation {
1986 fn unit() -> Self::T {
1987 Vec::new()
1988 }
1989
1990 fn is_unit(x: &Self::T) -> bool
1991 where
1992 Self::T: PartialEq,
1993 {
1994 x.iter().enumerate().all(|(i, &x)| i == x)
1995 }
1996 }
1997 impl Invertible for PermutationOperation {
1998 fn inverse(x: &Self::T) -> Self::T {
1999 let mut y = vec![0; x.len()];
2000 for (i, x) in x.iter().enumerate() {
2001 y[*x] = i;
2002 }
2003 y
2004 }
2005 }
2006
2007 #[cfg(test)]
2008 mod tests {
2009 use super::*;
2010 use crate::tools::Xorshift;
2011
2012 #[test]
2013 fn test_permutation_operation() {
2014 type M = PermutationOperation;
2015 let mut rng = Xorshift::default();
2016 for _ in 0..100 {
2017 let mut a: Vec<usize> = (0..rng.random(0..20)).collect();
2018 let mut b: Vec<usize> = (0..rng.random(0..20)).collect();
2019 let mut c: Vec<usize> = (0..rng.random(0..20)).collect();
2020 rng.shuffle(&mut a);
2021 rng.shuffle(&mut b);
2022 rng.shuffle(&mut c);
2023 assert!(M::check_unital(&a));
2024 assert!(M::check_invertible(&a));
2025 assert!(M::check_associative(&a, &b, &c));
2026 }
2027 }
2028 }
2029}
2030
2031#[codesnip::entry("FindMajorityOperation")]
2032pub use self::find_majority_operation_impl::FindMajorityOperation;
2033#[codesnip::entry("FindMajorityOperation", include("algebra"))]
2034mod find_majority_operation_impl {
2035 use super::*;
2036 use std::{cmp::Ordering, marker::PhantomData};
2037 pub struct FindMajorityOperation<T> {
2045 _marker: PhantomData<fn() -> T>,
2046 }
2047 impl<T> Magma for FindMajorityOperation<T>
2048 where
2049 T: Clone + Eq,
2050 {
2051 type T = (Option<T>, usize);
2052 fn operate(x: &Self::T, y: &Self::T) -> Self::T {
2053 if y.0.is_none() {
2054 x.clone()
2055 } else if x.0.is_none() {
2056 y.clone()
2057 } else {
2058 match (x.0.eq(&y.0), x.1.cmp(&y.1)) {
2059 (true, _) => (x.0.clone(), x.1 + y.1),
2060 (_, Ordering::Less) => (y.0.clone(), y.1 - x.1),
2061 (_, Ordering::Equal) => (None, 0),
2062 (_, Ordering::Greater) => (x.0.clone(), x.1 - y.1),
2063 }
2064 }
2065 }
2066 }
2067 impl<T> Unital for FindMajorityOperation<T>
2068 where
2069 T: Clone + Eq,
2070 {
2071 fn unit() -> Self::T {
2072 (None, 0)
2073 }
2074 }
2075 impl<T> Associative for FindMajorityOperation<T> where T: Clone + Eq {}
2076
2077 #[cfg(test)]
2078 mod tests {
2079 use super::*;
2080 use crate::tools::testutil::{exhaustive_sequences, sample_usize};
2081 use std::collections::HashMap;
2082
2083 #[test]
2084 fn test_find_majority_operation() {
2085 type M = FindMajorityOperation<i32>;
2086 let mut rng = crate::tools::Xorshift::default();
2087 let mut cases: Vec<_> = exhaustive_sequences(-1..=1, 0..=8).collect();
2088 for n in sample_usize(&mut rng, 16, 0..=100, 1000) {
2089 cases.push(rng.random_iter(-5..=5).take(n).collect());
2090 }
2091 for values in cases {
2092 let n = values.len();
2093 let mut count = HashMap::<_, usize>::new();
2094 let mut actual = M::unit();
2095 for &value in &values {
2096 *count.entry(value).or_default() += 1;
2097 let element = (Some(value), 1);
2098 assert!(M::check_unital(&element));
2099 actual = M::operate(&actual, &element);
2100 }
2101 if let Some((&key, _)) = count.iter().find(|&(_, &count)| count * 2 > n) {
2102 assert_eq!(actual.0, Some(key));
2103 }
2104 assert!(actual.0.is_none_or(|key| values.contains(&key)));
2105 }
2106 }
2107 }
2108}
2109
2110pub use self::concatenate_operation::{ConcatenateOperation, SortedConcatenateOperation};
2111mod concatenate_operation {
2112 use super::*;
2113 use std::marker::PhantomData;
2114 pub struct ConcatenateOperation<T> {
2115 _marker: PhantomData<fn() -> T>,
2116 }
2117 impl<T> Magma for ConcatenateOperation<T>
2118 where
2119 T: Clone,
2120 {
2121 type T = Vec<T>;
2122 fn operate(x: &Self::T, y: &Self::T) -> Self::T {
2123 x.iter().chain(y.iter()).cloned().collect()
2124 }
2125 }
2126 impl<T> Unital for ConcatenateOperation<T>
2127 where
2128 T: Clone,
2129 {
2130 fn unit() -> Self::T {
2131 Vec::new()
2132 }
2133 }
2134 impl<T> Associative for ConcatenateOperation<T> where T: Clone {}
2135
2136 pub struct SortedConcatenateOperation<T> {
2137 _marker: PhantomData<fn() -> T>,
2138 }
2139 impl<T> Magma for SortedConcatenateOperation<T>
2140 where
2141 T: Clone + Ord,
2142 {
2143 type T = Vec<T>;
2144 fn operate(x: &Self::T, y: &Self::T) -> Self::T {
2145 let mut xit = x.iter().cloned().peekable();
2146 let mut yit = y.iter().cloned().peekable();
2147 let mut z = Vec::with_capacity(x.len() + y.len());
2148 loop {
2149 match (xit.peek(), yit.peek()) {
2150 (None, None) => break,
2151 (Some(_), None) => z.push(xit.next().unwrap()),
2152 (Some(x), Some(y)) if x <= y => z.push(xit.next().unwrap()),
2153 _ => z.push(yit.next().unwrap()),
2154 }
2155 }
2156 z
2157 }
2158 }
2159 impl<T> Unital for SortedConcatenateOperation<T>
2160 where
2161 T: Clone + Ord,
2162 {
2163 fn unit() -> Self::T {
2164 Vec::new()
2165 }
2166 }
2167 impl<T> Associative for SortedConcatenateOperation<T> where T: Clone + Ord {}
2168 impl<T> Commutative for SortedConcatenateOperation<T> where T: Clone + Ord {}
2169
2170 #[cfg(test)]
2171 mod tests {
2172 use super::*;
2173 use crate::{rand, tools::Xorshift};
2174
2175 #[test]
2176 fn test_concatenate_operation() {
2177 type M = ConcatenateOperation<i32>;
2178 let mut rng = Xorshift::default();
2179 for _ in 0..100 {
2180 rand!(rng, n: 0..4, a: [0..10; n], m: 0..4, b: [0..10; m], l: 0..4, c: [0..10; l]);
2181 assert!(M::check_unital(&a));
2182 assert!(M::check_associative(&a, &b, &c));
2183
2184 let ab: Vec<_> = a.iter().chain(b.iter()).cloned().collect();
2185 assert_eq!(M::operate(&a, &b), ab);
2186 }
2187 }
2188
2189 #[test]
2190 fn test_sorted_concatenate_operation() {
2191 type M = SortedConcatenateOperation<i32>;
2192 let mut rng = Xorshift::default();
2193 for _ in 0..100 {
2194 rand!(rng, n: 0..4, mut a: [0..10; n], m: 0..4, mut b: [0..10; m], l: 0..4, mut c: [0..10; l]);
2195 a.sort_unstable();
2196 b.sort_unstable();
2197 c.sort_unstable();
2198 assert!(M::check_unital(&a));
2199 assert!(M::check_commutative(&a, &b));
2200 assert!(M::check_associative(&a, &b, &c));
2201
2202 let mut ab: Vec<_> = a.iter().chain(b.iter()).cloned().collect();
2203 ab.sort_unstable();
2204 assert_eq!(M::operate(&a, &b), ab);
2205 }
2206 }
2207 }
2208}
2209
2210#[codesnip::entry("MinimumIntervalMovementOperation")]
2211pub use self::minimum_interval_movement_impl::{
2212 MinimumIntervalMovement, MinimumIntervalMovementOperation,
2213};
2214#[codesnip::entry(
2215 "MinimumIntervalMovementOperation",
2216 include("algebra", "bounded", "zero_one")
2217)]
2218mod minimum_interval_movement_impl {
2219 use super::*;
2220 use std::{
2221 marker::PhantomData,
2222 ops::{Add, Sub},
2223 };
2224
2225 pub struct MinimumIntervalMovementOperation<T> {
2226 _marker: PhantomData<fn() -> T>,
2227 }
2228 #[derive(Debug, Clone)]
2229 pub struct MinimumIntervalMovement<T> {
2230 pos_range: (T, T),
2231 move_range: (T, T),
2232 cost: T,
2233 }
2234 impl<T> MinimumIntervalMovement<T>
2235 where
2236 T: Clone + Zero,
2237 {
2238 pub fn new(l: T, r: T) -> Self {
2239 Self {
2240 pos_range: (l.clone(), r.clone()),
2241 move_range: (l, r),
2242 cost: T::zero(),
2243 }
2244 }
2245 }
2246 impl<T> MinimumIntervalMovement<T>
2247 where
2248 T: Clone + Ord + Zero,
2249 {
2250 pub fn position(&self, x: &T) -> T {
2251 x.clamp(&self.pos_range.0, &self.pos_range.1).clone()
2252 }
2253 }
2254 impl<T> MinimumIntervalMovement<T>
2255 where
2256 T: Clone + Ord + Add<Output = T> + Sub<Output = T> + Zero,
2257 {
2258 pub fn move_cost(&self, x: &T) -> T {
2259 x.max(&self.move_range.0).clone() - x.min(&self.move_range.1).clone()
2260 + self.cost.clone()
2261 }
2262 }
2263 impl<T> Magma for MinimumIntervalMovementOperation<T>
2264 where
2265 T: Clone + Ord + Add<Output = T> + Sub<Output = T> + Zero,
2266 {
2267 type T = MinimumIntervalMovement<T>;
2268 fn operate(x: &Self::T, y: &Self::T) -> Self::T {
2269 let pos_range = (
2270 (&x.pos_range.0)
2271 .clamp(&y.pos_range.0, &y.pos_range.1)
2272 .clone(),
2273 (&x.pos_range.1)
2274 .clamp(&y.pos_range.0, &y.pos_range.1)
2275 .clone(),
2276 );
2277 let move_range = (
2278 (&y.move_range.0)
2279 .clamp(&x.move_range.0, &x.move_range.1)
2280 .clone(),
2281 (&y.move_range.1)
2282 .clamp(&x.move_range.0, &x.move_range.1)
2283 .clone(),
2284 );
2285 let cost = x.cost.clone() + y.move_cost(&x.position(&move_range.0));
2286 MinimumIntervalMovement {
2287 pos_range,
2288 move_range,
2289 cost,
2290 }
2291 }
2292 }
2293 impl<T> Associative for MinimumIntervalMovementOperation<T> where
2294 T: Clone + Ord + Add<Output = T> + Sub<Output = T> + Zero
2295 {
2296 }
2297 impl<T> Unital for MinimumIntervalMovementOperation<T>
2298 where
2299 T: Clone + Ord + Add<Output = T> + Sub<Output = T> + Zero + Bounded,
2300 {
2301 fn unit() -> Self::T {
2302 MinimumIntervalMovement::new(T::minimum(), T::maximum())
2303 }
2304 }
2305
2306 #[cfg(test)]
2307 mod tests {
2308 use super::*;
2309 use crate::{chmin, tools::Xorshift};
2310 use std::collections::HashMap;
2311
2312 #[test]
2313 fn test_minimum_interval_movement_operation() {
2314 type M = MinimumIntervalMovementOperation<i32>;
2315 let mut rng = Xorshift::default();
2316 for _ in 0..100 {
2317 let mut min = M::unit();
2318 let mut cost = HashMap::new();
2319 let s: i32 = rng.random(-100..100);
2320 cost.insert(s, 0i32);
2321 for _ in 0..10 {
2322 let l = rng.random(-100..100);
2323 let r = rng.random(l..=100);
2324 let m = MinimumIntervalMovement::new(l, r);
2325 min = M::operate(&min, &m);
2326 let mut ncost = HashMap::new();
2327 for (x, c) in cost {
2328 for nx in l..=r {
2329 let nc = c + (x - nx).abs();
2330 chmin!(*ncost.entry(nx).or_insert(nc), nc);
2331 }
2332 }
2333 cost = ncost;
2334 let x = min.position(&s);
2335 let c = min.move_cost(&s);
2336 assert_eq!(Some(&c), cost.get(&x));
2337 }
2338 }
2339 }
2340 }
2341}