use crate::integer_polynomial::arithmetic::coefficient::PolynomialCoefficient;
use crate::natural::InnerNatural::Small;
use crate::natural::{LIMB_MAX_QUARTER, Natural, TWICE_WIDTH, WIDTH_MINUS_2};
use crate::platform::{Limb, SignedLimb};
use alloc::vec::Vec;
use core::borrow::Borrow;
use core::cmp::min;
use malachite_base::num::conversion::traits::WrappingFrom;
use malachite_base::num::logic::traits::SignificantBits;
pub mod dot_general;
pub mod max_bits;
pub mod max_limbs;
pub(crate) const COEFF_MAX: Limb = LIMB_MAX_QUARTER;
pub(crate) const SMALL_FMPZ_BITCOUNT_MAX: u64 = WIDTH_MINUS_2;
pub(crate) fn small_value<C: PolynomialCoefficient>(x: &C) -> Option<SignedLimb> {
match *x.unsigned_abs_ref() {
Natural(Small(small)) if small <= COEFF_MAX => {
let value = SignedLimb::wrapping_from(small);
Some(if x.is_negative() { -value } else { value })
}
_ => None,
}
}
pub(crate) fn small_values<T: From<SignedLimb>, C: PolynomialCoefficient>(xs: &[C]) -> Vec<T> {
xs.iter()
.map(|x| T::from(small_value(x).unwrap()))
.collect()
}
#[derive(Clone, Copy, Debug, Eq, PartialEq)]
pub(crate) enum TinyKernel {
OneWord,
TwoWord,
}
pub(crate) fn tiny_kernel(
bits1: u64,
bits2: u64,
len2: u64,
short_enough: bool,
) -> Option<TinyKernel> {
if bits1 > SMALL_FMPZ_BITCOUNT_MAX || bits2 > SMALL_FMPZ_BITCOUNT_MAX || !short_enough {
return None;
}
let rbits = bits1 + bits2 + len2.significant_bits();
if rbits <= SMALL_FMPZ_BITCOUNT_MAX {
Some(TinyKernel::OneWord)
} else if rbits < TWICE_WIDTH {
Some(TinyKernel::TwoWord)
} else {
None
}
}
pub(crate) fn vec_add<C: PolynomialCoefficient, T: Borrow<C>>(out: &mut [C], xs: &[T], ys: &[T]) {
for ((o, x), y) in out.iter_mut().zip(xs).zip(ys) {
*o = x.borrow().add_ref(y.borrow());
}
}
pub(crate) fn vec_add_assign<C: PolynomialCoefficient>(xs: &mut [C], ys: &[C]) {
for (x, y) in xs.iter_mut().zip(ys) {
*x += y;
}
}
pub(crate) fn vec_sub_assign<C: PolynomialCoefficient>(xs: &mut [C], ys: &[C]) {
for (x, y) in xs.iter_mut().zip(ys) {
*x -= y;
}
}
pub(crate) fn classical_preferred(len2: u64, bits1: u64, bits2: u64) -> bool {
len2 <= 6 && min(bits1, bits2) <= 5000
}
pub(crate) fn karatsuba_preferred(len2: u64, bits1: u64, bits2: u64) -> bool {
len2 <= 4 || (len2 <= 8 && (1500..=10000).contains(&(bits1 + bits2)))
}
pub(crate) fn schonhage_strassen_preferred(
len1: u64,
len2: u64,
bits1: u64,
bits2: u64,
max_len: u64,
) -> bool {
let bits = bits1 + bits2;
len1 + len2 <= max_len
&& match len2 {
0..=7 => false,
8..=15 => (1000..=4000).contains(&bits),
16..=100 => (800..=4000).contains(&bits),
_ => (1000..=5000).contains(&bits),
}
}
pub(crate) const fn fft_preferred(
len2: u64,
bits1: u64,
bits2: u64,
min_len: u64,
always_len: u64,
) -> bool {
let bits = bits1 + bits2;
len2 >= min_len && (bits <= 40 || bits >= 128 || len2 >= always_len)
}