Skip to main content

nekolib/math/
sieve_n2_plus_n_plus_1.rs

1//! $n^2+n+1$ 型素数の篩。
2
3use std::fmt::Debug;
4
5/// $n^2+n+1$ 型素数の篩。
6///
7/// # Idea
8/// `todo!()`
9///
10/// # References
11/// - <https://inamori.hateblo.jp/entry/20110930/p1>
12#[derive(Clone, Debug)]
13pub struct SieveN2PlusNPlus1 {
14    a: Vec<usize>,
15    f: Vec<Vec<(usize, u32)>>,
16}
17
18impl SieveN2PlusNPlus1 {
19    /// 初期化する。
20    pub fn new(n: usize) -> Self {
21        let mut a: Vec<_> = (0..=n).map(|k| k * (k + 1) + 1).collect();
22        let mut f = vec![vec![]; n + 1];
23        f[1] = vec![(3, 1)];
24        for j in (4..=n).step_by(3) {
25            let (d, e) = Self::div_pow(a[j], 3);
26            f[j].push((3, e));
27            a[j] = d;
28        }
29        for i in 2..=n {
30            let p = a[i];
31            if p == 1 {
32                continue;
33            }
34            if p == i * (i + 1) + 1 {
35                f[i].push((p, 1));
36            }
37            let init1 = if p == i * (i + 1) + 1 { p + i } else { i };
38            let init2 = (n + p - 1) / p * p;
39            for j in (init1..=n).step_by(p).chain((init2..=n).step_by(p)) {
40                let (d, e) = Self::div_pow(a[j], p);
41                if e > 0 {
42                    f[j].push((p, e));
43                    a[j] = d;
44                }
45            }
46        }
47        Self { a, f }
48    }
49
50    fn div_pow(mut a: usize, p: usize) -> (usize, u32) {
51        let mut e = 0;
52        while a % p == 0 {
53            a /= p;
54            e += 1;
55        }
56        (a, e)
57    }
58
59    /// $n^2+n+1$ の形の素数を返す。
60    ///
61    /// # Examples
62    /// ```
63    /// use nekolib::math::SieveN2PlusNPlus1;
64    ///
65    /// let ss = SieveN2PlusNPlus1::new(10);
66    /// let primes: Vec<_> = ss.primes().collect();
67    /// assert_eq!(primes, [3, 7, 13, 31, 43, 73]);
68    /// ```
69    pub fn primes(&self) -> impl Iterator<Item = usize> + '_ {
70        (1..self.a.len())
71            .filter(move |&i| self.a[i] == i * (i + 1) + 1)
72            .map(|i| i * (i + 1) + 1)
73    }
74
75    /// $n^2+n+1$ が素数のとき真を返す。
76    ///
77    /// # Examples
78    /// ```
79    /// use nekolib::math::SieveN2PlusNPlus1;
80    ///
81    /// let ss = SieveN2PlusNPlus1::new(10);
82    /// assert!(ss.is_prime(3));  // 13 is prime
83    /// assert!(!ss.is_prime(4));  // 21 = 3 * 7
84    /// ```
85    pub fn is_prime(&self, n: usize) -> bool {
86        n > 0 && self.a[n] == n * (n + 1) + 1
87    }
88
89    /// $n^2+n+1$ を素因数分解する。
90    ///
91    /// 底の昇順とは限らないので注意。
92    ///
93    /// # Examples
94    /// ```
95    /// use nekolib::math::SieveN2PlusNPlus1;
96    ///
97    /// let ss = SieveN2PlusNPlus1::new(20);
98    /// assert_eq!(ss.factors(0).next(), None);
99    /// assert_eq!(ss.factors(7).collect::<Vec<_>>(), [(3, 1), (19, 1)]);
100    /// assert_eq!(ss.factors(18).collect::<Vec<_>>(), [(7, 3)]);
101    /// ```
102    pub fn factors(&self, n: usize) -> impl Iterator<Item = (usize, u32)> + '_ {
103        self.f[n].iter().cloned()
104    }
105
106    /// $n^2+1$ を素因数を列挙する。重複あり。
107    ///
108    /// 底の昇順とは限らないので注意。
109    ///
110    /// # Examples
111    /// ```
112    /// use nekolib::math::SieveN2PlusNPlus1;
113    ///
114    /// let ss = SieveN2PlusNPlus1::new(20);
115    /// assert_eq!(ss.factors_dup(0).next(), None);
116    /// assert_eq!(ss.factors_dup(6).collect::<Vec<_>>(), [43]);
117    /// assert_eq!(ss.factors_dup(18).collect::<Vec<_>>(), [7, 7, 7]);
118    /// ```
119    pub fn factors_dup(&self, n: usize) -> impl Iterator<Item = usize> + '_ {
120        self.factors(n).flat_map(|(p, e)| std::iter::repeat(p).take(e as usize))
121    }
122}
123
124#[test]
125fn test() {
126    use linear_sieve::LinearSieve;
127
128    let n = 3000;
129    let ls = LinearSieve::new(n * (n + 1) + 1);
130    let ss = SieveN2PlusNPlus1::new(n);
131    for i in 0..=n {
132        assert_eq!(ls.is_prime(i * (i + 1) + 1), ss.is_prime(i));
133
134        {
135            // factors
136            let expected: Vec<_> = ls.factors_dup(i * (i + 1) + 1).collect();
137            let mut actual: Vec<_> = ss.factors_dup(i).collect();
138            actual.sort_unstable();
139            assert_eq!(actual, expected);
140        }
141    }
142}