use crate::algorithms;
use crate::divisibility::*;
use crate::primitive_int::StaticRing;
use crate::ring::*;
use crate::rings::poly::*;
pub fn cyclotomic_polynomial<P>(P: P, n: usize) -> El<P>
where
P: RingStore,
P::Type: PolyRing + DivisibilityRing,
{
let mut current = P.sub(P.indeterminate(), P.one());
let ZZ = StaticRing::<i128>::RING;
let mut power_of_x = 1;
for (p, e) in algorithms::int_factor::factor(&ZZ, n as i128) {
power_of_x *= ZZ.pow(p, e - 1) as usize;
current = P
.checked_div(
&P.from_terms(
P.terms(¤t)
.map(|(c, d)| (P.base_ring().clone_el(c), d * p as usize)),
),
¤t,
)
.unwrap();
}
return P.from_terms(
P.terms(¤t)
.map(|(c, d)| (P.base_ring().clone_el(c), d * power_of_x)),
);
}
#[cfg(test)]
use crate::rings::poly::dense_poly::DensePolyRing;
#[cfg(test)]
use crate::rings::poly::sparse_poly::SparsePolyRing;
#[cfg(test)]
use crate::rings::zn::zn_static::Fp;
#[test]
fn test_cyclotomic_polynomial() {
let poly_ring = DensePolyRing::new(Fp::<7>::RING, "X");
assert!(poly_ring.eq_el(
&poly_ring.from_terms([(1, 1), (1, 0)].into_iter()),
&cyclotomic_polynomial(&poly_ring, 2)
));
assert!(poly_ring.eq_el(
&poly_ring.from_terms([(1, 2), (1, 1), (1, 0)].into_iter()),
&cyclotomic_polynomial(&poly_ring, 3)
));
assert!(poly_ring.eq_el(
&poly_ring.from_terms([(1, 2), (1, 0)].into_iter()),
&cyclotomic_polynomial(&poly_ring, 4)
));
assert!(poly_ring.eq_el(
&poly_ring.from_terms([(1, 4), (1, 3), (1, 2), (1, 1), (1, 0)].into_iter()),
&cyclotomic_polynomial(&poly_ring, 5)
));
assert!(poly_ring.eq_el(
&poly_ring.from_terms([(1, 2), (6, 1), (1, 0)].into_iter()),
&cyclotomic_polynomial(&poly_ring, 6)
));
assert!(poly_ring.eq_el(
&poly_ring.from_terms([(1, 6), (6, 3), (1, 0)].into_iter()),
&cyclotomic_polynomial(&poly_ring, 18)
));
assert!(
poly_ring.eq_el(
&poly_ring.from_terms(
[
(1, 48),
(1, 47),
(1, 46),
(6, 43),
(6, 42),
(5, 41),
(6, 40),
(6, 39),
(1, 36),
(1, 35),
(1, 34),
(1, 33),
(1, 32),
(1, 31),
(6, 28),
(6, 26),
(6, 24),
(6, 22),
(6, 20),
(1, 17),
(1, 16),
(1, 15),
(1, 14),
(1, 13),
(1, 12),
(6, 9),
(6, 8),
(5, 7),
(6, 6),
(6, 5),
(1, 2),
(1, 1),
(1, 0)
]
.into_iter()
),
&cyclotomic_polynomial(&poly_ring, 105)
)
);
}
#[bench]
fn bench_cyclotomic_polynomial_3965585_dense(bencher: &mut test::Bencher) {
let poly_ring = DensePolyRing::new(Fp::<7>::RING, "X");
bencher.iter(|| {
_ = std::hint::black_box(cyclotomic_polynomial(&poly_ring, std::hint::black_box(257 * 257 * 65)));
});
}
#[bench]
fn bench_cyclotomic_polynomial_3965585_sparse(bencher: &mut test::Bencher) {
let poly_ring = SparsePolyRing::new(Fp::<7>::RING, "X");
bencher.iter(|| {
_ = std::hint::black_box(cyclotomic_polynomial(&poly_ring, std::hint::black_box(257 * 257 * 65)));
});
}