use crate::natural::InnerNatural::{Large, Small};
use crate::natural::Natural;
use malachite_base::num::arithmetic::traits::{CheckedRoot, DivAssignMod, DivMod, GcdAssign};
use malachite_base::num::basic::traits::One;
use malachite_base::num::factorization::traits::{
ExpressAsPower, Factor, IsPower, IsPrime, Primes,
};
use malachite_base::num::logic::traits::SignificantBits;
const PRIMES: [u32; 168] = [
2, 3, 5, 7, 11, 13, 17, 19, 23, 29, 31, 37, 41, 43, 47, 53, 59, 61, 67, 71, 73, 79, 83, 89, 97,
101, 103, 107, 109, 113, 127, 131, 137, 139, 149, 151, 157, 163, 167, 173, 179, 181, 191, 193,
197, 199, 211, 223, 227, 229, 233, 239, 241, 251, 257, 263, 269, 271, 277, 281, 283, 293, 307,
311, 313, 317, 331, 337, 347, 349, 353, 359, 367, 373, 379, 383, 389, 397, 401, 409, 419, 421,
431, 433, 439, 443, 449, 457, 461, 463, 467, 479, 487, 491, 499, 503, 509, 521, 523, 541, 547,
557, 563, 569, 571, 577, 587, 593, 599, 601, 607, 613, 617, 619, 631, 641, 643, 647, 653, 659,
661, 673, 677, 683, 691, 701, 709, 719, 727, 733, 739, 743, 751, 757, 761, 769, 773, 787, 797,
809, 811, 821, 823, 827, 829, 839, 853, 857, 859, 863, 877, 881, 883, 887, 907, 911, 919, 929,
937, 941, 947, 953, 967, 971, 977, 983, 991, 997,
];
fn get_perfect_power_natural(n: &Natural) -> Option<(Natural, u64)> {
let mut pow_2 = n.trailing_zeros().unwrap();
if pow_2 == 1 {
return None;
}
if pow_2.is_prime() {
return n.checked_root(pow_2).map(|root| (root, pow_2));
}
let mut q = n >> pow_2;
for &prime in PRIMES.iter().skip(1) {
let prime = Natural::from(prime);
let (new_q, r) = (&q).div_mod(&prime);
if r == 0u32 {
q = new_q;
if q.div_assign_mod(&prime) != 0u32 {
return None; }
let mut pow_p = 2u64;
loop {
let (new_q, r) = (&q).div_mod(&prime);
if r == 0 {
q = new_q;
pow_p += 1;
} else {
break;
}
}
pow_2.gcd_assign(pow_p);
if pow_2 == 1 {
return None; }
if q == 1u32 || pow_2.is_prime() {
return n.checked_root(pow_2).map(|root| (root, pow_2));
}
}
}
if pow_2 == 0 {
let bits = n.significant_bits();
for nth in u64::primes() {
if nth > bits {
return None;
}
if let Some(root) = n.checked_root(nth) {
return Some((root, nth));
}
}
} else {
for (nth, _) in pow_2.factor() {
if let Some(root) = n.checked_root(nth) {
return Some((root, nth));
}
}
}
None
}
fn get_perfect_power_natural_bool(n: &Natural) -> bool {
let mut pow_2 = n.trailing_zeros().unwrap();
if pow_2 == 1 {
return false;
}
if pow_2.is_prime() {
return n.checked_root(pow_2).is_some();
}
let mut q = n >> pow_2;
for &prime in PRIMES.iter().skip(1) {
let prime = Natural::from(prime);
let (new_q, r) = (&q).div_mod(&prime);
if r == 0 {
q = new_q;
if q.div_assign_mod(&prime) != 0u32 {
return false; }
let mut pow_p = 2u64;
loop {
let (new_q, r) = (&q).div_mod(&prime);
if r == 0 {
q = new_q;
pow_p += 1;
} else {
break;
}
}
pow_2.gcd_assign(pow_p);
if pow_2 == 1 {
return false; }
if q == Natural::ONE || pow_2.is_prime() {
return n.checked_root(pow_2).is_some();
}
}
}
if pow_2 == 0 {
let bits = n.significant_bits();
for nth in u64::primes() {
if nth > bits {
return false;
}
if n.checked_root(nth).is_some() {
return true;
}
}
} else {
for (nth, _) in pow_2.factor() {
if n.checked_root(nth).is_some() {
return true;
}
}
}
false
}
fn express_as_power_natural(n: &Natural) -> Option<(Natural, u64)> {
let (mut base, mut exp) = get_perfect_power_natural(n)?;
while base > 3u32 {
match get_perfect_power_natural(&base) {
Some((base2, exp2)) => {
base = base2;
exp *= exp2;
}
None => break,
}
}
Some((base, exp))
}
#[inline]
fn is_power_natural(n: &Natural) -> bool {
get_perfect_power_natural_bool(n)
}
impl ExpressAsPower for Natural {
fn express_as_power(&self) -> Option<(Self, u64)> {
match self {
Self(Small(small)) => small
.express_as_power()
.map(|(root, exp)| (Self::from(root), exp)),
Self(Large(_)) => express_as_power_natural(self),
}
}
}
impl IsPower for Natural {
fn is_power(&self) -> bool {
match self {
Self(Small(small)) => small.is_power(),
Self(Large(_)) => is_power_natural(self),
}
}
}