1use crate::math::mod_ops::inv::mod_inv;
3
4pub fn garner(r: Vec<u64>, mut m: Vec<u64>, modulo: u64) -> Option<u64> {
13 assert_eq!(r.len(), m.len());
14 assert!(!r.is_empty());
15
16 m.push(modulo);
17
18 let n = r.len();
19 let mut coeffs = vec![1; n + 1];
20 let mut constants = vec![0; n + 1];
21
22 for k in 0..n {
23 let t = ((r[k] + m[k] - constants[k]) % m[k] * mod_inv(coeffs[k], m[k])?) % m[k];
24
25 for i in k + 1..n + 1 {
26 constants[i] += t * coeffs[i] % m[i];
27 constants[i] %= m[i];
28 coeffs[i] *= m[k];
29 coeffs[i] %= m[i];
30 }
31 }
32
33 Some(*constants.last().unwrap())
34}
35
36#[cfg(test)]
37mod tests {
38 use crate::iter::collect::CollectVec;
39
40 use super::*;
41
42 #[test]
43 fn test() {
44 let m = vec![17, 23, 29, 35];
45 let modulo = 31;
46
47 for x in 0..=1000 {
48 let r = m.iter().map(|&m| x % m).collect_vec();
49 assert_eq!(garner(r, m.clone(), modulo).unwrap(), x % modulo);
50 }
51 }
52
53 #[test]
54 fn test_failure() {
55 assert_eq!(garner(vec![1, 2], vec![6, 8], 100), None);
56 }
57}