use crate::integer::Integer;
use crate::integer_polynomial::arithmetic::mul::karatsuba::mul_to_out_karatsuba;
use crate::integer_polynomial::arithmetic::mul_high::classical::mul_high_to_out_classical;
use crate::integer_polynomial::arithmetic::vec::{vec_add, vec_add_assign, vec_sub_assign};
use alloc::vec;
use malachite_base::num::arithmetic::traits::{CeilingLogBase2, Parity, PowerOf2};
use malachite_base::num::basic::traits::Zero;
use malachite_base::num::conversion::traits::ExactFrom;
fn mul_high_karatsuba_recursive(
out: &mut [Integer],
xs: &[Integer],
ys: &[Integer],
temp: &mut [Integer],
length: usize,
) {
let m1 = length >> 1;
let m2 = length - m1;
let odd = length.odd();
if length <= 6 {
mul_high_to_out_classical(
&mut out[..(length << 1) - 1],
&xs[..length],
&ys[..length],
length - 1,
);
return;
}
let two_m1 = m1 << 1;
let two_m2 = m2 << 1;
vec_add(&mut out[..m1], &xs[..m1], &xs[m1..two_m1]);
if odd {
out[m1] = xs[two_m1].clone();
}
vec_add(&mut out[m2..m2 + m1], &ys[..m1], &ys[m1..two_m1]);
if odd {
out[m2 + m1] = ys[two_m1].clone();
}
{
let (high, rest) = temp.split_at_mut(two_m2);
mul_high_karatsuba_recursive(high, &out[..m2], &out[m2..two_m2], rest, m2);
}
mul_to_out_karatsuba(
&mut out[two_m1..two_m1 + two_m2 - 1],
&xs[m1..m1 + m2],
&ys[m1..m1 + m2],
);
out[two_m1 - 1] = Integer::ZERO;
mul_high_karatsuba_recursive(&mut out[..two_m1 - 1], xs, ys, &mut temp[two_m2..], m1);
vec_sub_assign(&mut temp[m2 - 1..two_m1 - 1], &out[m2 - 1..two_m1 - 1]);
vec_sub_assign(
&mut temp[m2 - 1..two_m2 - 1],
&out[two_m1 + m2 - 1..two_m1 + two_m2 - 1],
);
vec_add_assign(
&mut out[length - 1..length - 1 + m2],
&temp[m2 - 1..two_m2 - 1],
);
out[..length - 1].fill(Integer::ZERO);
}
crate_test_fn! {mul_high_to_out_karatsuba_n(out: &mut [Integer], xs: &[Integer], ys: &[Integer]) {
let len = xs.len();
assert_ne!(len, 0);
assert_eq!(ys.len(), len);
assert_eq!(out.len(), (len << 1) - 1);
if len == 1 {
out[0] = &xs[0] * &ys[0];
return;
}
let length = usize::power_of_2(u64::exact_from(len).ceiling_log_base_2());
let mut temp = vec![Integer::ZERO; length << 1];
mul_high_karatsuba_recursive(out, xs, ys, &mut temp, len);
}}