ring_algorithm/
lib.rs

1#![cfg_attr(feature = "__internal_inject_debug", recursion_limit = "16")]
2use num_traits::{One, Zero};
3use std::ops::{Add, AddAssign, BitAnd, Mul, MulAssign, Rem, ShrAssign};
4#[cfg(feature = "__internal_inject_debug")]
5mod sealed {
6    pub trait SizedExt: std::marker::Sized + std::fmt::Debug + std::fmt::Display {}
7    impl<T> SizedExt for T where T: std::marker::Sized + std::fmt::Debug + std::fmt::Display {}
8    pub use SizedExt as Sized;
9}
10#[cfg(not(feature = "__internal_inject_debug"))]
11mod sealed {
12    pub use std::marker::Sized;
13}
14mod ring_traits;
15#[cfg(test)]
16mod test;
17pub use ring_traits::{
18    EuclideanRingOperation, EuclideanRingOperationFrom, RingNormalize, RingOperation,
19    RingOperationFrom,
20};
21
22/** calcurate $`pa`$ with mutliprecation by doubling
23```
24use ring_algorithm::times;
25assert_eq!(times::<i32, u64>(2, 16), 32);
26```
27*/
28pub fn times<T, U>(a: T, p: U) -> T
29where
30    T: sealed::Sized + Zero + for<'x> AddAssign<&'x T> + for<'x> From<<&'x T as Add>::Output>,
31    for<'x> &'x T: Add,
32    U: sealed::Sized
33        + Zero
34        + One
35        + Eq
36        + for<'x> ShrAssign<usize>
37        + for<'x> From<<&'x U as BitAnd>::Output>,
38    for<'x> &'x U: BitAnd,
39{
40    add_times(T::zero(), a, p)
41}
42
43/** calcurate $`b + pa`$ with mutliprecation by doubling
44
45This function doesn't require `T: num_traits::Zero`.
46```
47use ring_algorithm::add_times;
48assert_eq!(add_times::<i32, u64>(3, 2, 7), 17);
49```
50*/
51pub fn add_times<T, U>(b: T, a: T, mut p: U) -> T
52where
53    T: sealed::Sized + for<'x> AddAssign<&'x T> + for<'x> From<<&'x T as Add>::Output>,
54    for<'x> &'x T: Add,
55    U: sealed::Sized
56        + Zero
57        + One
58        + Eq
59        + for<'x> ShrAssign<usize>
60        + for<'x> From<<&'x U as BitAnd>::Output>,
61    for<'x> &'x U: BitAnd,
62{
63    let mut x = b;
64    let mut y = a;
65    loop {
66        if U::from(&p & &U::one()) == U::one() {
67            x += &y;
68        }
69        p >>= 1;
70        if p == U::zero() {
71            break;
72        }
73        y = T::from(&y + &y);
74    }
75    x
76}
77
78/** calcurate $`a^p`$ with exponentiation by squaring
79```
80use ring_algorithm::power;
81assert_eq!(power::<i32, u64>(2, 16), 65536);
82```
83*/
84pub fn power<T, U>(a: T, p: U) -> T
85where
86    T: sealed::Sized + One + for<'x> MulAssign<&'x T> + for<'x> From<<&'x T as Mul>::Output>,
87    for<'x> &'x T: Mul,
88    U: sealed::Sized
89        + Zero
90        + One
91        + Eq
92        + for<'x> ShrAssign<usize>
93        + for<'x> From<<&'x U as BitAnd>::Output>,
94    for<'x> &'x U: BitAnd,
95{
96    mul_power(T::one(), a, p)
97}
98
99/** calcurate $`b \cdot a^p`$ with exponentiation by squaring
100
101This function doesn't require `T: num_traits::One`.
102```
103use ring_algorithm::mul_power;
104assert_eq!(mul_power::<i32, u64>(3, 2, 7), 384);
105```
106*/
107pub fn mul_power<T, U>(b: T, a: T, mut p: U) -> T
108where
109    T: sealed::Sized + for<'x> MulAssign<&'x T> + for<'x> From<<&'x T as Mul>::Output>,
110    for<'x> &'x T: Mul,
111    U: sealed::Sized
112        + Zero
113        + One
114        + Eq
115        + for<'x> ShrAssign<usize>
116        + for<'x> From<<&'x U as BitAnd>::Output>,
117    for<'x> &'x U: BitAnd,
118{
119    let mut x = b;
120    let mut y = a;
121    loop {
122        if U::from(&p & &U::one()) == U::one() {
123            x *= &y;
124        }
125        p >>= 1;
126        if p == U::zero() {
127            break;
128        }
129        y = T::from(&y * &y);
130    }
131    x
132}
133
134/** calcurate greatest common divisor
135```
136use ring_algorithm::gcd;
137assert_eq!(gcd::<i32>(15, 21), 3);
138assert_eq!(gcd::<i32>(14, 15), 1);
139assert_eq!(gcd::<i32>(0, 42), 42);
140assert_eq!(gcd::<i32>(0, 0), 0);
141```
142*/
143pub fn gcd<T>(mut x: T, mut y: T) -> T
144where
145    T: sealed::Sized + Zero + for<'x> From<<&'x T as Rem>::Output>,
146    for<'x> &'x T: Rem,
147{
148    while !y.is_zero() {
149        let r = T::from(&x % &y);
150        x = y;
151        y = r;
152    }
153    x
154}
155
156/** test $`\gcd(x, y) = 1`$
157*/
158pub fn is_coprime<T>(x: T, y: T) -> bool
159where
160    T: sealed::Sized + Eq + Zero + One + RingNormalize + for<'x> From<<&'x T as Rem>::Output>,
161    for<'x> &'x T: Rem,
162{
163    gcd::<T>(x, y).into_normalize().is_one()
164}
165
166/** extended euclidian algorithm
167
168calcurate g (`gcd(a, b)`) and x, y ( $`g = ax + by`$ )
169```
170use ring_algorithm::{gcd, extended_euclidian_algorithm};
171let a = 314;
172let b = 271;
173let (d, x, y) = extended_euclidian_algorithm::<i32>(a, b);
174assert_eq!(d, gcd::<i32>(a, b));
175assert_eq!(d, x * a + y * b);
176```
177 */
178pub fn extended_euclidian_algorithm<T>(x: T, y: T) -> (T, T, T)
179where
180    T: sealed::Sized + Zero + One + EuclideanRingOperationFrom,
181    for<'x> &'x T: EuclideanRingOperation,
182{
183    let mut old = (x, T::one(), T::zero());
184    let mut now = (y, T::zero(), T::one());
185    while !now.0.is_zero() {
186        let q = T::from(&old.0 / &now.0);
187        let new = (
188            T::from(&old.0 - &T::from(&q * &now.0)),
189            T::from(&old.1 - &T::from(&q * &now.1)),
190            T::from(&old.2 - &T::from(&q * &now.2)),
191        );
192        old = now;
193        now = new;
194    }
195    old
196}
197
198/** extended euclidian algorithm with normalize
199```
200use ring_algorithm::{gcd, normalized_extended_euclidian_algorithm, RingNormalize};
201let a = 314;
202let b = 271;
203let (d, x, y) = normalized_extended_euclidian_algorithm::<i32>(a, b);
204assert_eq!(d, gcd::<i32>(a, b));
205assert_eq!(d, x * a + y * b);
206```
207*/
208pub fn normalized_extended_euclidian_algorithm<T>(x: T, y: T) -> (T, T, T)
209where
210    T: sealed::Sized + Zero + One + RingNormalize + EuclideanRingOperationFrom,
211    for<'x> &'x T: EuclideanRingOperation,
212{
213    let lc_x = x.leading_unit();
214    let lc_y = y.leading_unit();
215    let mut old = (x.into_normalize(), T::from(&T::one() / &lc_x), T::zero());
216    let mut now = (y.into_normalize(), T::zero(), T::from(&T::one() / &lc_y));
217    while !now.0.is_zero() {
218        let q = T::from(&old.0 / &now.0);
219        let r = T::from(&old.0 % &now.0);
220        let lc_r = r.leading_unit();
221        let new = (
222            r.into_normalize(),
223            T::from(&T::from(&old.1 - &T::from(&q * &now.1)) / &lc_r),
224            T::from(&T::from(&old.2 - &T::from(&q * &now.2)) / &lc_r),
225        );
226        old = now;
227        now = new;
228    }
229    old
230}
231
232/** calc inverse in modulo
233
234calc x ($`ax \equiv 1 \pmod{m}`$)
235```
236use ring_algorithm::modulo_inverse;
237let a = 42;
238let m = 55;
239let b = modulo_inverse::<i32>(a, m).unwrap();
240assert_eq!((a * b - 1) % m, 0);
241```
242*/
243pub fn modulo_inverse<T>(a: T, m: T) -> Option<T>
244where
245    T: sealed::Sized + Eq + Zero + One + RingNormalize + EuclideanRingOperationFrom,
246    for<'x> &'x T: EuclideanRingOperation,
247{
248    if m.is_zero() || a.is_zero() {
249        return None;
250    }
251    let (gcd, inv_a, _) = normalized_extended_euclidian_algorithm::<T>(a, m);
252    if gcd.is_one() {
253        Some(inv_a)
254    } else {
255        None
256    }
257}
258
259/** division in modulo
260
261calc x ($`bx \equiv a \pmod{m}`$)
262```
263use ring_algorithm::modulo_division;
264let a = 42;
265let b = 32;
266let m = 98;
267let x = modulo_division::<i32>(a, b, m).unwrap();
268assert_eq!((b * x - a) % m, 0);
269```
270*/
271pub fn modulo_division<T>(a: T, b: T, m: T) -> Option<T>
272where
273    T: sealed::Sized + Clone + Eq + Zero + One + RingNormalize + EuclideanRingOperationFrom,
274    for<'x> &'x T: EuclideanRingOperation,
275{
276    if m.is_zero() || b.is_zero() {
277        return None;
278    }
279    let (gcd, inv_b, _) = normalized_extended_euclidian_algorithm::<T>(b, m.clone());
280    if T::from(&a % &gcd).is_zero() {
281        let q = T::from(&a / &gcd);
282        let t = q * inv_b;
283        Some(T::from(&t % &m))
284    } else {
285        None
286    }
287}
288
289/** Chinese remainder theorem
290
291```
292use ring_algorithm::chinese_remainder_theorem;
293let u = vec![2, 3, 2];
294let m = vec![3, 5, 7];
295let a = chinese_remainder_theorem::<i32>(&u, &m).unwrap();
296for (u, m) in u.iter().zip(m.iter()) {
297    assert_eq!((a - u) % m, 0);
298}
299```
300*/
301pub fn chinese_remainder_theorem<T>(u: &[T], m: &[T]) -> Option<T>
302where
303    T: sealed::Sized + Clone + Eq + Zero + One + RingNormalize + EuclideanRingOperationFrom,
304    for<'x> &'x T: EuclideanRingOperation,
305{
306    if u.len() != m.len() {
307        return None;
308    }
309    let len = u.len();
310    let mut v = Vec::with_capacity(len);
311    v.push(u[0].clone());
312    for (i, (u_i, m_i)) in u.iter().zip(m.iter()).enumerate().skip(1) {
313        let p = (v[i - 1].clone(), m[i - 1].clone());
314        let (t, n) = m
315            .iter()
316            .zip(v.iter())
317            .rev()
318            .skip(1)
319            .fold(p, |(t, n), (m_j, v_j)| {
320                (
321                    T::from(&T::from(v_j + &T::from(m_j * &t)) % m_i),
322                    T::from(&T::from(&n * m_j) % m_i),
323                )
324            });
325        v.push(modulo_division::<T>(
326            T::from(u_i + &T::from(m_i - &t)),
327            n,
328            m_i.clone(),
329        )?);
330    }
331    let mut ret = v.pop().unwrap();
332    for (v_i, m_i) in v.iter().zip(m.iter()).rev() {
333        ret = T::from(&T::from(&ret * m_i) + v_i);
334    }
335    Some(ret)
336}
337
338/** calc subproduct tree
339
340```text
341 120
342  /\
343 6  20
344/\  /\
3452 3 4 5
346```
347
348```rust
349use ring_algorithm::build_subproduct_tree;
350let a = vec![2, 3, 4, 5];
351let b = vec![120, 6, 20, 2, 3, 4, 5];
352let r = build_subproduct_tree::<i32>(a);
353assert_eq!(b, r);
354let a = vec![2, 3, 4, 5, 6];
355let b = vec![720, 120, 6, 6, 20, 6, 1, 2, 3, 4, 5, 6, 1, 1, 1];
356let r = build_subproduct_tree::<i32>(a);
357assert_eq!(b, r);
358```
359*/
360pub fn build_subproduct_tree<T>(a: Vec<T>) -> Vec<T>
361where
362    T: sealed::Sized + Clone + One + for<'x> From<<&'x T as Mul>::Output>,
363    for<'x> &'x T: Mul,
364{
365    let mut len = a.len().next_power_of_two();
366    let mut r = vec![T::one(); 2 * len - 1];
367    a.into_iter()
368        .zip(r.iter_mut().skip(len - 1))
369        .for_each(|(a, r)| *r = a);
370    while len >= 2 {
371        let (ro, ri) = r.split_at_mut(len - 1);
372        let (_, ro) = ro.split_at_mut(len / 2 - 1);
373        ro.iter_mut()
374            .zip(ri.chunks_exact(2))
375            .for_each(|(ro, ri)| *ro = T::from(&ri[0] * &ri[1]));
376        len >>= 1;
377    }
378    r
379}
380
381/** calc subsum tree
382
383```text
384  14
385  /\
386 5  9
387/\  /\
3882 3 4 5
389```
390
391```rust
392use ring_algorithm::build_subsum_tree;
393let a = vec![2, 3, 4, 5];
394let b = vec![14, 5, 9, 2, 3, 4, 5];
395let r = build_subsum_tree::<i32>(a);
396assert_eq!(b, r);
397let a = vec![2, 3, 4, 5, 6];
398let b = vec![20, 14, 6, 5, 9, 6, 0, 2, 3, 4, 5, 6, 0, 0, 0];
399let r = build_subsum_tree::<i32>(a);
400assert_eq!(b, r);
401```
402*/
403pub fn build_subsum_tree<T>(a: Vec<T>) -> Vec<T>
404where
405    T: sealed::Sized + Clone + Zero + for<'x> From<<&'x T as Add>::Output>,
406    for<'x> &'x T: Add,
407{
408    let mut len = a.len().next_power_of_two();
409    let mut r = vec![T::zero(); 2 * len - 1];
410    a.into_iter()
411        .zip(r.iter_mut().skip(len - 1))
412        .for_each(|(a, r)| *r = a);
413    while len >= 2 {
414        let (ro, ri) = r.split_at_mut(len - 1);
415        let (_, ro) = ro.split_at_mut(len / 2 - 1);
416        ro.iter_mut()
417            .zip(ri.chunks_exact(2))
418            .for_each(|(ro, ri)| *ro = T::from(&ri[0] + &ri[1]));
419        len >>= 1;
420    }
421    r
422}
423
424fn modular_reduction_aux<T, U>(f: &U, v: &[T], sv: usize, start: usize, end: usize) -> Vec<U>
425where
426    T: sealed::Sized,
427    U: sealed::Sized + for<'x> From<<&'x U as Rem<&'x T>>::Output>,
428    for<'x> &'x U: Rem<&'x T>,
429{
430    let s = (end - start) / 2;
431    let mid = start + s;
432    let ev = sv * 2 + 1;
433    if s == 1 {
434        let f0 = U::from(f % &v[sv + start]);
435        let f1 = U::from(f % &v[sv + start + 1]);
436        vec![f0, f1]
437    } else {
438        let mut v0 = {
439            let f0 = U::from(f % &v[sv + start / s]);
440            modular_reduction_aux::<T, U>(&f0, v, ev, start, mid)
441        };
442        let mut v1 = {
443            let f1 = U::from(f % &v[sv + start / s + 1]);
444            modular_reduction_aux::<T, U>(&f1, v, ev, mid, end)
445        };
446        v0.append(&mut v1);
447        v0
448    }
449}
450
451/** modular reduction
452
453`m.len()` must be $`2^k~(k=1,2,3,\ldots)`$
454
455```
456use ring_algorithm::modular_reduction;
457let t = 997u128;
458let m = vec![2, 3, 5, 7, 11, 13, 17, 19, 23, 29, 31, 37, 41, 43, 47, 53];
459let v = modular_reduction::<u128, u128>(&t, &m);
460let w = m.iter().map(|m| t % m).collect::<Vec<_>>();
461assert_eq!(v, w);
462```
463*/
464pub fn modular_reduction<T, U>(f: &U, m: &[T]) -> Vec<U>
465where
466    T: sealed::Sized + Clone + One + for<'x> From<<&'x T as Mul>::Output>,
467    for<'x> &'x T: Mul,
468    U: sealed::Sized + for<'x> From<<&'x U as Rem<&'x T>>::Output>,
469    for<'x> &'x U: Rem<&'x T>,
470{
471    let len = m.len();
472    assert!(len >= 2 && len.is_power_of_two());
473    let v = build_subproduct_tree::<T>(m.to_vec());
474    modular_reduction_aux::<T, U>(f, &v, 1, 0, len)
475}
476
477fn crt_inverses<T>(m: &[T], big_m: &T) -> Vec<T>
478where
479    T: sealed::Sized + Clone + Eq + Zero + One + RingNormalize + EuclideanRingOperationFrom,
480    for<'x> &'x T: EuclideanRingOperation,
481{
482    let m2 = m.iter().map(|m| T::from(m * m)).collect::<Vec<_>>();
483    modular_reduction::<T, T>(big_m, &m2)
484        .into_iter()
485        .zip(m.iter())
486        .map(|(v, m)| modulo_inverse::<T>(T::from(&v / m), m.clone()).unwrap())
487        .collect()
488}
489
490fn crt_combination<T>(c: &[T], m: &[T], v: &[T], sv: usize, start: usize, end: usize) -> T
491where
492    T: sealed::Sized + Clone + Eq + Zero + One + RingNormalize + EuclideanRingOperationFrom,
493    for<'x> &'x T: EuclideanRingOperation,
494{
495    if end - start == 1 {
496        c[0].clone()
497    } else {
498        let s = (end - start) / 2;
499        let mid = start + s;
500        let ev = sv * 2 + 1;
501        let (c0, c1) = c.split_at(s);
502        let (m0, m1) = m.split_at(s);
503        let r0 = crt_combination::<T>(c0, m0, v, ev, start, mid);
504        let r1 = crt_combination::<T>(c1, m1, v, ev, mid, end);
505        T::from(&T::from(&r0 * &v[sv + start / s + 1]) + &T::from(&r1 * &v[sv + start / s]))
506    }
507}
508
509/** Chinese remainder theorem
510
511`m.len()` must be $`2^k~(k=1,2,3,\ldots)`$ and `u.len() == m.len()`
512```
513use ring_algorithm::fast_chinese_remainder_theorem;
514let u = vec![2, 3, 2, 6];
515let m = vec![3, 5, 7, 11];
516let a = fast_chinese_remainder_theorem::<i32>(&u, &m);
517for (u, m) in u.iter().zip(m.iter()) {
518    assert_eq!((a - u) % m, 0);
519}
520```
521*/
522pub fn fast_chinese_remainder_theorem<T>(u: &[T], m: &[T]) -> T
523where
524    T: sealed::Sized + Clone + Eq + Zero + One + RingNormalize + EuclideanRingOperationFrom,
525    for<'x> &'x T: EuclideanRingOperation,
526{
527    assert_eq!(u.len(), m.len());
528    let len = m.len();
529    assert!(len >= 2 && len.is_power_of_two());
530    let v = build_subproduct_tree::<T>(m.to_vec());
531    let s = crt_inverses::<T>(m, &v[0]);
532    let c = s
533        .iter()
534        .zip(u.iter())
535        .map(|(s, u)| T::from(s * u))
536        .collect::<Vec<_>>();
537    crt_combination::<T>(&c, m, &v, 1, 0, len)
538}
539
540/** calcurate $`a^p \pmod{m}`$
541
542```rust
543use ring_algorithm::modulo_power;
544let a = 314i32;
545let p = 271i32;
546let m = 42;
547assert_eq!(modulo_power(a, p, &m), 20);
548```
549*/
550pub fn modulo_power<T, U>(a: T, mut p: U, m: &T) -> T
551where
552    T: sealed::Sized
553        + One
554        + for<'x> MulAssign<&'x T>
555        + for<'x> From<<&'x T as Mul>::Output>
556        + for<'x> From<<&'x T as Rem>::Output>,
557    for<'x> &'x T: Mul + Rem,
558    U: sealed::Sized
559        + Zero
560        + One
561        + Eq
562        + for<'x> ShrAssign<usize>
563        + for<'x> From<<&'x U as BitAnd>::Output>,
564    for<'x> &'x U: BitAnd,
565{
566    let mut x = T::one();
567    let mut y = T::from(&a % m);
568    loop {
569        if U::from(&p & &U::one()) == U::one() {
570            x = T::from(&T::from(&x * &y) % m);
571        }
572        p >>= 1;
573        if p == U::zero() {
574            break;
575        }
576        y = T::from(&T::from(&y * &y) % m);
577    }
578    x
579}