use crate::integer_polynomial::IntegerPolynomial;
use crate::integer_polynomial::arithmetic::coefficient::PolynomialCoefficient;
use crate::integer_polynomial::arithmetic::mul_middle::fft::mul_middle_to_out_fft;
use crate::integer_polynomial::arithmetic::square::classical::square_to_out_classical;
use crate::integer_polynomial::arithmetic::square::karatsuba::square_to_out_karatsuba;
use crate::integer_polynomial::arithmetic::square::kronecker::square_to_out_kronecker;
use crate::integer_polynomial::arithmetic::square::schonhage_strassen::*;
use crate::integer_polynomial::arithmetic::square::tiny::{
square_to_out_tiny_1, square_to_out_tiny_2,
};
use crate::integer_polynomial::arithmetic::vec::max_bits::vec_max_bits;
use crate::integer_polynomial::arithmetic::vec::{
TinyKernel, classical_preferred, fft_preferred, karatsuba_preferred,
schonhage_strassen_preferred, tiny_kernel,
};
use alloc::vec;
use alloc::vec::Vec;
use malachite_base::num::arithmetic::traits::{Square, SquareAssign};
use malachite_base::num::conversion::traits::ExactFrom;
pub mod classical;
pub mod karatsuba;
pub mod kronecker;
pub mod schonhage_strassen;
pub mod tiny;
crate_test_fn! {square_to_out<C: PolynomialCoefficient>(out: &mut [C], xs: &[C]) {
if xs.len() == 1 {
out[0] = xs[0].square_ref();
return;
}
let bits = vec_max_bits(xs).0;
let len = u64::exact_from(xs.len());
if fft_preferred(len, bits, bits, 80, 160)
&& mul_middle_to_out_fft(out, xs, xs, 0, (xs.len() << 1) - 1)
{
return;
}
match tiny_kernel(bits, bits, len, len < 50 + 3 * bits) {
Some(TinyKernel::OneWord) => square_to_out_tiny_1(out, xs),
Some(TinyKernel::TwoWord) => square_to_out_tiny_2(out, xs),
None if classical_preferred(len, bits, bits) => {
square_to_out_classical(out, xs);
}
None if karatsuba_preferred(len, bits, bits) => {
square_to_out_karatsuba(out, xs);
}
None if schonhage_strassen_preferred(len, len, bits, bits, 4097) => {
square_to_out_schonhage_strassen(out, xs);
}
None => square_to_out_kronecker(out, xs),
}
}}
pub(crate) fn square_ref<C: PolynomialCoefficient>(xs: &[C]) -> Vec<C> {
if xs.is_empty() {
return Vec::new();
}
let mut out = vec![C::ZERO; (xs.len() << 1) - 1];
square_to_out(&mut out, xs);
out
}
impl Square for IntegerPolynomial {
type Output = Self;
#[inline]
fn square(mut self) -> Self {
self.square_assign();
self
}
}
impl Square for &IntegerPolynomial {
type Output = IntegerPolynomial;
#[inline]
fn square(self) -> IntegerPolynomial {
IntegerPolynomial {
coefficients: square_ref(&self.coefficients),
}
}
}
impl SquareAssign for IntegerPolynomial {
#[inline]
fn square_assign(&mut self) {
if let [c] = self.coefficients.as_mut_slice() {
c.square_assign();
} else {
self.coefficients = square_ref(&self.coefficients);
}
}
}