use crate::rational_polynomial::RationalPolynomial;
use crate::rational_polynomial::arithmetic::add::add_or_sub_coefficients;
use alloc::vec::Vec;
use core::mem::{swap, take};
use core::ptr;
use malachite_base::num::arithmetic::traits::{Content, DivExactAssign, GcdAssign, Parity};
use malachite_base::polynomial::{AddTruncated, AddTruncatedAssign, Polynomial};
use malachite_nz::integer::Integer;
use malachite_nz::integer_polynomial::IntegerPolynomial;
use malachite_nz::natural::Natural;
fn prefix(xs: &[Integer], len: u64) -> &[Integer] {
&xs[..usize::try_from(len).map_or(xs.len(), |len| len.min(xs.len()))]
}
pub(crate) fn add_or_sub_truncated(
xs: Vec<Integer>,
p_cut: bool,
a: Natural,
q: &RationalPolynomial,
len: u64,
negate_q: bool,
) -> RationalPolynomial {
add_or_sub_coefficients(
xs,
a,
prefix(q.numerator.coefficients_asc(), len),
&q.denominator,
negate_q,
p_cut || q.numerator.len() > len,
)
}
pub(crate) fn add_or_sub_truncated_owned_ref(
p: RationalPolynomial,
q: &RationalPolynomial,
len: u64,
negate_q: bool,
) -> RationalPolynomial {
let p_cut = p.numerator.len() > len;
let mut x = p.numerator;
x.truncate_assign(len);
add_or_sub_truncated(
x.into_coefficients_asc(),
p_cut,
p.denominator,
q,
len,
negate_q,
)
}
pub(crate) fn add_or_sub_truncated_ref_ref(
p: &RationalPolynomial,
q: &RationalPolynomial,
len: u64,
negate_q: bool,
) -> RationalPolynomial {
add_or_sub_truncated(
prefix(p.numerator.coefficients_asc(), len).to_vec(),
p.numerator.len() > len,
p.denominator.clone(),
q,
len,
negate_q,
)
}
fn add_truncated_owned_owned(
mut p: RationalPolynomial,
mut q: RationalPolynomial,
len: u64,
) -> RationalPolynomial {
if q.numerator.len() > p.numerator.len() {
swap(&mut p, &mut q);
}
add_or_sub_truncated_owned_ref(p, &q, len, false)
}
fn double_truncated(p: &RationalPolynomial, len: u64) -> RationalPolynomial {
let mut numerator = p.numerator.truncate(len);
let mut denominator = p.denominator.clone();
if denominator.even() {
denominator >>= 1u32;
} else {
numerator = IntegerPolynomial::from_coefficients_asc(
numerator
.coefficients_asc()
.iter()
.map(|c| c << 1u32)
.collect::<Vec<_>>(),
);
}
if p.numerator.len() > len {
let mut e = (&numerator).content();
if e != 1u32 {
e.gcd_assign(&denominator);
if e != 1u32 {
denominator.div_exact_assign(&e);
numerator.div_exact_assign(Integer::from(e));
}
}
}
RationalPolynomial {
numerator,
denominator,
}
}
impl AddTruncated<Self> for RationalPolynomial {
type Output = Self;
#[inline]
fn add_truncated(self, other: Self, len: u64) -> Self {
add_truncated_owned_owned(self, other, len)
}
}
impl AddTruncated<&Self> for RationalPolynomial {
type Output = Self;
#[inline]
fn add_truncated(self, other: &Self, len: u64) -> Self {
add_or_sub_truncated_owned_ref(self, other, len, false)
}
}
impl AddTruncated<RationalPolynomial> for &RationalPolynomial {
type Output = RationalPolynomial;
#[inline]
fn add_truncated(self, other: RationalPolynomial, len: u64) -> RationalPolynomial {
add_or_sub_truncated_owned_ref(other, self, len, false)
}
}
impl AddTruncated<&RationalPolynomial> for &RationalPolynomial {
type Output = RationalPolynomial;
fn add_truncated(self, other: &RationalPolynomial, len: u64) -> RationalPolynomial {
if ptr::eq(self, other) {
return double_truncated(self, len);
}
add_or_sub_truncated_ref_ref(self, other, len, false)
}
}
impl AddTruncatedAssign<Self> for RationalPolynomial {
#[inline]
fn add_truncated_assign(&mut self, other: Self, len: u64) {
*self = add_truncated_owned_owned(take(self), other, len);
}
}
impl AddTruncatedAssign<&Self> for RationalPolynomial {
#[inline]
fn add_truncated_assign(&mut self, other: &Self, len: u64) {
*self = add_or_sub_truncated_owned_ref(take(self), other, len, false);
}
}