use crate::Rational;
use crate::rational_polynomial::conversion::string::from_string::from_string_with;
use crate::rational_polynomial::conversion::string::to_string::Language;
use alloc::string::String;
use alloc::vec::Vec;
use core::ops::Deref;
use malachite_base::named::Named;
#[cfg(feature = "test_build")]
use malachite_base::num::arithmetic::traits::CoprimeWith;
use malachite_base::num::arithmetic::traits::{DivExact, Gcd, GcdAssign, LcmAssign};
use malachite_base::num::basic::traits::{One, Two, Zero};
use malachite_base::num::conversion::traits::ExactFrom;
use malachite_base::polynomial::Polynomial;
use malachite_base::vars::{Var, VarScheme};
use malachite_nz::integer::Integer;
use malachite_nz::integer_polynomial::IntegerPolynomial;
use malachite_nz::natural::Natural;
pub mod exhaustive;
#[cfg(feature = "random")]
pub mod random;
pub mod arithmetic;
pub mod comparison;
pub mod conversion;
pub mod logic;
#[derive(Clone, Eq, Hash, PartialEq)]
#[cfg_attr(feature = "serde", derive(Deserialize, Serialize))]
#[cfg_attr(
feature = "serde",
serde(try_from = "SerdeRationalPolynomial", into = "SerdeRationalPolynomial")
)]
pub struct RationalPolynomial {
numerator: IntegerPolynomial,
denominator: Natural,
}
#[cfg_attr(feature = "serde", derive(Serialize, Deserialize))]
pub(crate) struct SerdeRationalPolynomial {
#[cfg_attr(feature = "serde", serde(rename = "n"))]
pub(crate) numerator: IntegerPolynomial,
#[cfg_attr(feature = "serde", serde(rename = "d"))]
pub(crate) denominator: Natural,
}
impl Zero for RationalPolynomial {
const ZERO: Self = Self {
numerator: IntegerPolynomial::ZERO,
denominator: Natural::ONE,
};
}
impl Default for RationalPolynomial {
#[inline]
fn default() -> Self {
Self::ZERO
}
}
impl RationalPolynomial {
#[cfg(feature = "test_build")]
pub fn is_valid(&self) -> bool {
if !self.numerator.is_valid() || self.denominator == 0u32 {
return false;
}
if self.numerator == IntegerPolynomial::ZERO {
return self.denominator == 1u32;
}
content(&self.numerator).coprime_with(&self.denominator)
}
fn canonicalize(numerator: IntegerPolynomial, denominator: Natural) -> Self {
if numerator == IntegerPolynomial::ZERO {
return Self::ZERO;
}
let gcd = content(&numerator).gcd(&denominator);
if gcd == 1u32 {
return Self {
numerator,
denominator,
};
}
let gcd = Integer::from(gcd);
Self {
numerator: IntegerPolynomial::from_coefficients_asc(
numerator
.into_coefficients_asc()
.into_iter()
.map(|c| c.div_exact(&gcd))
.collect(),
),
denominator: denominator.div_exact(Natural::exact_from(gcd)),
}
}
pub fn negative_one() -> Self {
Self {
numerator: IntegerPolynomial::negative_one(),
denominator: Natural::ONE,
}
}
pub fn one_half() -> Self {
Self {
numerator: IntegerPolynomial::one(),
denominator: Natural::TWO,
}
}
#[inline]
pub const fn numerator_ref(&self) -> &IntegerPolynomial {
&self.numerator
}
#[inline]
pub const fn denominator_ref(&self) -> &Natural {
&self.denominator
}
#[inline]
pub fn into_numerator_and_denominator(self) -> (IntegerPolynomial, Natural) {
(self.numerator, self.denominator)
}
#[inline]
pub fn from_numerator_and_denominator(
numerator: IntegerPolynomial,
denominator: Natural,
) -> Self {
assert_ne!(denominator, 0u32, "the denominator may not be zero");
Self::canonicalize(numerator, denominator)
}
pub fn to_coefficients_asc(&self) -> Vec<Rational> {
let denominator = Integer::from(self.denominator.clone());
self.numerator
.coefficients_asc()
.iter()
.map(|n| Rational::from_integers_ref(n, &denominator))
.collect()
}
}
fn content(p: &IntegerPolynomial) -> Natural {
let mut gcd = Natural::ZERO;
for c in p.coefficients_asc() {
gcd.gcd_assign(c.unsigned_abs_ref());
}
gcd
}
impl Polynomial for RationalPolynomial {
type Coefficient = Rational;
type CoefficientOutput<'a>
= Rational
where
Self: 'a;
fn one() -> Self {
Self {
numerator: IntegerPolynomial::one(),
denominator: Natural::ONE,
}
}
fn two() -> Self {
Self {
numerator: IntegerPolynomial::two(),
denominator: Natural::ONE,
}
}
fn x() -> Self {
Self {
numerator: IntegerPolynomial::x(),
denominator: Natural::ONE,
}
}
fn from_coefficients_asc(coefficients: Vec<Rational>) -> Self {
let mut denominator = Natural::ONE;
for c in &coefficients {
denominator.lcm_assign(c.denominator_ref());
}
let numerator = IntegerPolynomial::from_coefficients_asc(
coefficients
.into_iter()
.map(|c| {
let negative = c < 0u32;
let (n, d) = c.into_numerator_and_denominator();
let n = Integer::from(n) * Integer::from((&denominator).div_exact(d));
if negative { -n } else { n }
})
.collect(),
);
Self::canonicalize(numerator, denominator)
}
fn into_coefficients_asc(self) -> Vec<Rational> {
let denominator = Integer::from(self.denominator);
self.numerator
.into_coefficients_asc()
.into_iter()
.map(|n| Rational::from_integers_ref(&n, &denominator))
.collect()
}
#[inline]
fn degree(&self) -> Option<u64> {
self.numerator.degree()
}
#[inline]
fn len(&self) -> u64 {
self.numerator.len()
}
#[inline]
fn coefficient(&self, index: u64) -> Rational {
Rational::from_integers_ref(
self.numerator.coefficient(index),
&Integer::from(self.denominator.clone()),
)
}
#[inline]
fn leading_coefficient(&self) -> Rational {
Rational::from_integers_ref(
self.numerator.leading_coefficient(),
&Integer::from(self.denominator.clone()),
)
}
#[inline]
fn is_monic(&self) -> bool {
*self.numerator.leading_coefficient() == self.denominator
}
fn mutate_coefficient<F: FnOnce(&mut Rational) -> T, T>(&mut self, index: u64, f: F) -> T {
let mut coefficients = self.to_coefficients_asc();
let index = usize::exact_from(index);
if index >= coefficients.len() {
coefficients.resize(index + 1, Rational::ZERO);
}
let out = f(&mut coefficients[index]);
*self = Self::from_coefficients_asc(coefficients);
out
}
fn zero_coefficients(&mut self, start: u64, end: u64) {
self.numerator.zero_coefficients(start, end);
let numerator = core::mem::take(&mut self.numerator);
let denominator = core::mem::take(&mut self.denominator);
*self = Self::canonicalize(numerator, denominator);
}
fn truncate(&self, len: u64) -> Self {
if len >= self.len() {
self.clone()
} else {
Self::canonicalize(self.numerator.truncate(len), self.denominator.clone())
}
}
fn truncate_assign(&mut self, len: u64) {
if len < self.len() {
self.numerator.truncate_assign(len);
let numerator = core::mem::take(&mut self.numerator);
let denominator = core::mem::take(&mut self.denominator);
*self = Self::canonicalize(numerator, denominator);
}
}
fn reverse(&self, len: u64) -> Self {
let numerator = self.numerator.reverse(len);
if len >= self.len() {
Self {
numerator,
denominator: self.denominator.clone(),
}
} else {
Self::canonicalize(numerator, self.denominator.clone())
}
}
fn reverse_assign(&mut self, len: u64) {
let truncated = len < self.len();
self.numerator.reverse_assign(len);
if truncated {
let numerator = core::mem::take(&mut self.numerator);
let denominator = core::mem::take(&mut self.denominator);
*self = Self::canonicalize(numerator, denominator);
}
}
fn to_string_with<S: VarScheme + ?Sized>(&self, var: Var<'_, S>) -> String {
let mut s = String::new();
self.write_with_var(var, Language::Plain, &mut s).unwrap();
s
}
fn to_latex_string_with<S: VarScheme + ?Sized>(&self, var: Var<'_, S>) -> String {
let mut s = String::new();
self.write_with_var(var, Language::Latex, &mut s).unwrap();
s
}
fn to_typst_string_with<S: VarScheme + ?Sized>(&self, var: Var<'_, S>) -> String {
let mut s = String::new();
self.write_with_var(var, Language::Typst, &mut s).unwrap();
s
}
#[inline]
fn from_string_with<S: VarScheme + ?Sized>(var: Var<'_, S>, s: &str) -> Option<Self> {
from_string_with(var, s)
}
}
impl_named!(RationalPolynomial);
#[derive(Clone, Debug, Eq, Hash, PartialEq)]
#[cfg_attr(feature = "serde", derive(Deserialize, Serialize))]
#[cfg_attr(feature = "serde", serde(transparent))]
pub struct ShortlexRationalPolynomial(pub RationalPolynomial);
#[derive(Clone, Debug, Eq, Hash, PartialEq)]
pub struct ShortlexRationalPolynomialRef<'a>(pub &'a RationalPolynomial);
impl ShortlexRationalPolynomial {
pub const fn as_ref(&self) -> ShortlexRationalPolynomialRef<'_> {
ShortlexRationalPolynomialRef(&self.0)
}
}
impl Deref for ShortlexRationalPolynomial {
type Target = RationalPolynomial;
fn deref(&self) -> &RationalPolynomial {
&self.0
}
}
impl Deref for ShortlexRationalPolynomialRef<'_> {
type Target = RationalPolynomial;
fn deref(&self) -> &RationalPolynomial {
self.0
}
}