use crate::integer::Integer;
use crate::natural::Natural;
use malachite_base::num::arithmetic::traits::{CheckedRoot, UnsignedAbs};
use malachite_base::num::basic::traits::NegativeOne;
use malachite_base::num::factorization::traits::{ExpressAsPower, IsPower, Primes};
use malachite_base::num::logic::traits::SignificantBits;
fn negative_power_root(abs: &Natural, exp: u64) -> Option<Natural> {
abs.checked_root(exp)
}
fn odd_prime_exponents(abs: &Natural) -> impl Iterator<Item = u64> {
u64::primes_less_than_or_equal_to(&abs.significant_bits()).skip(1)
}
impl IsPower for Integer {
fn is_power(&self) -> bool {
if *self >= 0 {
return self.unsigned_abs_ref().is_power();
}
let abs = self.unsigned_abs();
abs == 1u32 || odd_prime_exponents(&abs).any(|p| negative_power_root(&abs, p).is_some())
}
}
impl ExpressAsPower for Integer {
fn express_as_power(&self) -> Option<(Self, u64)> {
if *self >= 0 {
return self
.unsigned_abs_ref()
.express_as_power()
.map(|(root, exp)| (Self::from(root), exp));
}
let abs = self.unsigned_abs();
if abs == 1u32 {
return Some((Self::NEGATIVE_ONE, 3));
}
odd_prime_exponents(&abs)
.find_map(|p| negative_power_root(&abs, p).map(|root| (-Self::from(root), p)))
}
}