use crate::integer_polynomial::IntegerPolynomial;
use crate::integer_polynomial::arithmetic::coefficient::{
PolynomialCoefficient, trim_coefficients,
};
use crate::integer_polynomial::arithmetic::mul_middle::fft::mul_middle_to_out_fft;
use crate::integer_polynomial::arithmetic::square_truncated::classical::*;
use crate::integer_polynomial::arithmetic::square_truncated::karatsuba::*;
use crate::integer_polynomial::arithmetic::square_truncated::kronecker::*;
use crate::integer_polynomial::arithmetic::square_truncated::schonhage_strassen::*;
use crate::integer_polynomial::arithmetic::square_truncated::tiny::{
square_truncated_to_out_tiny_1, square_truncated_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 core::cmp::min;
use malachite_base::num::arithmetic::traits::SquareAssign;
use malachite_base::num::conversion::traits::ExactFrom;
use malachite_base::polynomial::{SquareTruncated, SquareTruncatedAssign};
pub mod classical;
pub mod karatsuba;
pub mod kronecker;
pub mod schonhage_strassen;
pub mod tiny;
crate_test_fn! {square_truncated_to_out<C: PolynomialCoefficient>(out: &mut [C], xs: &[C]) {
let n = out.len();
let xs = &xs[..min(xs.len(), n)];
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, 100, 240) && mul_middle_to_out_fft(out, xs, xs, 0, n) {
return;
}
let n = u64::exact_from(n);
let short_enough = len < 50 + (bits << 1) || (len << 2 >= 3 * n && n < 140 + 6 * bits);
match tiny_kernel(bits, bits, len, short_enough) {
Some(TinyKernel::OneWord) => square_truncated_to_out_tiny_1(out, xs),
Some(TinyKernel::TwoWord) => square_truncated_to_out_tiny_2(out, xs),
None if classical_preferred(len, bits, bits) => {
square_truncated_to_out_classical(out, xs);
}
None if karatsuba_preferred(len, bits, bits) => {
square_truncated_to_out_karatsuba(out, xs);
}
None if schonhage_strassen_preferred(len, len, bits, bits, 4097) => {
square_truncated_to_out_schonhage_strassen(out, xs);
}
None => square_truncated_to_out_kronecker(out, xs),
}
}}
pub(crate) fn square_truncated_ref<C: PolynomialCoefficient>(xs: &[C], len: u64) -> Vec<C> {
if xs.is_empty() || len == 0 {
return Vec::new();
}
let n = usize::try_from(len)
.unwrap_or(usize::MAX)
.min((xs.len() << 1) - 1);
let mut out = vec![C::ZERO; n];
square_truncated_to_out(&mut out, xs);
trim_coefficients(&mut out);
out
}
impl SquareTruncated for IntegerPolynomial {
type Output = Self;
#[inline]
fn square_truncated(mut self, len: u64) -> Self {
self.square_truncated_assign(len);
self
}
}
impl SquareTruncated for &IntegerPolynomial {
type Output = IntegerPolynomial;
#[inline]
fn square_truncated(self, len: u64) -> IntegerPolynomial {
IntegerPolynomial {
coefficients: square_truncated_ref(&self.coefficients, len),
}
}
}
impl SquareTruncatedAssign for IntegerPolynomial {
#[inline]
fn square_truncated_assign(&mut self, len: u64) {
if len != 0
&& let [c] = self.coefficients.as_mut_slice()
{
c.square_assign();
} else {
self.coefficients = square_truncated_ref(&self.coefficients, len);
}
}
}