1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
use std::ops::Index;

use crate::streams::DivisorStream;
use libbgs_util::intpow;

/// When called with phantom type marker `Ph` and a list of integers, each integer `P` is turned
/// into an implementation of `Factor<Ph> for FpNum<P>` and `Factor<Ph> for QuadNum<P>`.
#[macro_export]
macro_rules! impl_factors {
    ($mrk:ident, $($n:literal),+ $(,)?) => {$(
        impl Factor<$mrk> for FpNum<$n> {
            const FACTORS: Factorization = Factorization::new(make_factor!({$n - 1}));
        }
        impl Factor<$mrk> for QuadNum<$n> {
            const FACTORS: Factorization = Factorization::new(make_factor!({$n + 1}));
        }
    )+};
    ($mrk:ident, $start:literal..$end:literal) => {
        primes!(impl_factors, $mrk, $start..$end);
    }
}
pub use impl_factors;

/// A prime power decomposition of a positive integer.
#[derive(Clone, PartialEq, Eq, Debug)]
pub struct Factorization {
    value: u128,
    factors: &'static [(u128, usize)],
}

/// A placeholder trait for storing the length of a prime factorization; required to be separate
/// from the Factor trait in order for the trait solver to avoid cycles.
pub trait Length<S> {
    /// The length of a prime factorization, i.e., the number of unique prime factors.
    const LENGTH: usize;
}

/// Types that have a size or order which can be expressed as a product of prime powers.
/// The type parameter `S` is a phantom type to allow users of this library to provide their own
/// factorizations for `FpNum<P>`, `QuadNum<P>`, etc. for arbitrary `P`.
/// The type `S` must come from the crate implementing the factorization to satisfy Rust's
/// coherence and orphan rules, but does not affect the memory layout of any instance of an object
/// implementing `Factor`.
/// See the Rust documentation on [coherence and the orphan rule](https://doc.rust-lang.org/reference/items/implementations.html#trait-implementation-coherence).
///
/// This type can only hold factors up to `2^126`. Behavior may be undefined for factorizations
/// which contain larger factors.
pub trait Factor<S> {
    /// The prime factorization of this object.
    const FACTORS: Factorization;
}

impl<S, T: Factor<S>> Length<S> for T {
    const LENGTH: usize = T::FACTORS.len();
}

impl Factorization {
    /// Creates a new factorization from the given prime powers.
    pub const fn new(factors: &'static [(u128, usize)]) -> Factorization {
        let mut value = 1;
        let mut i = 0;
        while i < factors.len() {
            value *= intpow::<0>(factors[i].0, factors[i].1 as u128);
            i += 1;
        }
        Factorization {
            value,
            factors,
        }
    }

    /// Returns an `Iterator` yielding the maximal divisors of the number represented by this
    /// `Factorization` below `l`; that is, if this `Factorization` represents the number $n$, then
    /// this `Iterator` yields vectors representing all elements $d$ satisfying these properties:
    /// * $d | n$,
    /// * $d \leq l$, and
    /// * there are no elements $k | n$ such that $d | k$ and $k \leq l$.
    ///
    /// The iterator cannot outlive the `Factorization`, although the vectors yielded by it may.
    pub fn maximal_divisors<const L: usize>(&self, l: u128) -> impl Iterator<Item = [usize; L]> {
        DivisorStream::new(self.factors, l, true).map(|v| v.try_into().unwrap())
    }

    /// True if there the factorization represents 1.
    /// False otherwise.
    pub const fn is_empty(&self) -> bool {
        self.factors.is_empty()
    }

    /// Returns the prime power factor represented by prime number `i`, $p_i^{t_i}$.
    /// This method will `panic` if `i` is out of bounds.
    pub const fn factor(&self, i: usize) -> u128 {
        intpow::<0>(self.factors[i].0, self.factors[i].1 as u128)
    }

    /// Gets the prime powers as an array.
    /// The first element of each entry is the prime, and the second is the power.
    pub const fn factors(&self) -> &'static [(u128, usize)] {
        self.factors
    }

    /// Returns the positive integer represented by this `Factorization`.
    pub const fn value(&self) -> u128 {
        self.value
    }

    /// Converts an array of powers on the prime factors into an integer.
    pub fn from_powers(&self, ds: &[usize]) -> u128 {
        let mut total = 1;
        for (d, (p, t)) in ds.iter().zip(self.factors) {
            if d > t {
                return 0;
            } else {
                total *= intpow::<0>(*p, *d as u128);
            }
        }
        total
    }

    /// Returns the exponents on the factorization.
    pub fn exponents(&self) -> Box<[usize]> {
        self.factors.iter().map(|(_, t)| *t).collect::<Box<[usize]>>()
    }

    /// Returns the number of prime factors in the factorization.
    pub const fn len(&self) -> usize {
        self.factors.len()
    }

    /// Returns $\tau$(`&self`), the number of divisors of this integer.
    /// See OEIS sequence [A000005].
    ///
    /// [A000005]: https://oeis.org/A000005
    pub const fn tau(&self) -> u128 {
        let mut res = 1u128;
        let mut i = 0;
        while i < self.factors.len() {
            res *= (self.factors[i].1 + 1) as u128;
            i += 1;
        }
        res
    }

    /// Returns $\phi$(`&self`), the Euler totient function of this integer.
    /// The totient function $\phi(n)$ is the number of integers $\leq n$ and relatively prime to
    /// $n$. See OEIS sequence [A000010].
    ///
    /// [A000010]: https://oeis.org/A000010
    pub const fn phi(&self) -> u128 {
        let mut res = 1;
        let mut i = 0;
        while i < self.factors.len() {
            res *= intpow::<0>(self.factors[i].0, (self.factors[i].1 - 1) as u128);
            res *= self.factors[i].0 - 1;
            i += 1;
        }
        res
    }
}

impl Index<usize> for Factorization {
    type Output = (u128, usize);

    fn index(&self, index: usize) -> &(u128, usize) {
        &self.factors[index]
    }
}