use crate::{
polynomial::{
Polynomial, PolynomialCoefficient, PolynomialDivSupported,
PolynomialReducingFactorSupported, PseudoDivRem,
},
traits::{
ExactDiv, ExactDivAssign, ExtendedGCD, ExtendedGCDAndLCM, ExtendedGCDResult, GCDAndLCM, GCD,
},
};
use num_integer::Integer;
use num_traits::Zero;
use std::{borrow::Cow, mem};
fn exact_mul_by_signed_power<T: PolynomialCoefficient + for<'a> ExactDiv<&'a T, Output = T>>(
factor: T,
base: T,
exponent_positive_part: usize,
exponent_negative_part: usize,
) -> T {
if exponent_positive_part >= exponent_negative_part {
factor * T::coefficient_pow_usize(base, exponent_positive_part - exponent_negative_part)
} else {
factor.exact_div(&T::coefficient_pow_usize(
base,
exponent_negative_part - exponent_positive_part,
))
}
}
impl<T: PolynomialCoefficient + for<'a> ExactDiv<&'a T, Output = T>> Polynomial<T> {
pub fn subresultant_gcd(mut self, mut rhs: Self) -> Polynomial<T> {
let need_negate = if self.len() < rhs.len() {
mem::swap(&mut self, &mut rhs);
self.degree().unwrap_or(0).is_odd() && rhs.degree().unwrap_or(0).is_odd()
} else {
false
};
if rhs.is_zero() {
return self;
}
assert!(!self.is_zero());
let one = T::make_one_coefficient_from_element(Cow::Borrowed(&self.elements[0]));
#[allow(unused_variables)]
let mut i = 3usize;
let mut f_i_2 = self; let mut n_i_2 = f_i_2.degree().expect("f_i_2 is known to be non-zero");
let mut a_i_2 = one.clone();
let mut c_i_2 = one;
let mut f_i_1 = rhs; let mut n_i_1 = f_i_1.degree().expect("f_i_1 is known to be non-zero");
loop {
let PseudoDivRem { remainder, .. } = f_i_2.pseudo_div_rem(&f_i_1);
let divisor = -a_i_2 * T::coefficient_pow_usize(-c_i_2.clone(), n_i_2 - n_i_1);
let f_i = remainder.exact_div(divisor);
let n_i = if let Some(v) = f_i.degree() {
v
} else {
break;
};
let a_i_1 = f_i_1
.nonzero_highest_power_coefficient()
.expect("f_i_1 is known to be non-zero");
let c_i_1 = exact_mul_by_signed_power(
T::coefficient_pow_usize(a_i_1.clone(), n_i_2 - n_i_1),
c_i_2,
n_i_1 + 1,
n_i_2,
);
i += 1;
f_i_2 = f_i_1;
f_i_1 = f_i;
n_i_2 = n_i_1;
n_i_1 = n_i;
a_i_2 = a_i_1;
c_i_2 = c_i_1;
}
if need_negate {
-f_i_1
} else {
f_i_1
}
}
pub fn nonzero_resultant(self, rhs: Self) -> Option<T> {
#![allow(clippy::many_single_char_names)]
fn recursive_resultant<T: PolynomialCoefficient + for<'a> ExactDiv<&'a T, Output = T>>(
u: Polynomial<T>,
v: Polynomial<T>,
i: usize,
delta_p: usize,
psi_p: T,
) -> Option<T> {
let m = u.degree().expect("known to be non-zero");
let n = v.degree().expect("known to be non-zero");
if m < n {
let retval = recursive_resultant(v, u, i, delta_p, psi_p)?;
if m.is_odd() && n.is_odd() {
Some(-retval)
} else {
Some(retval)
}
} else if n == 0 {
Some(T::coefficient_pow_usize(
v.into_iter().next().expect("known to be non-zero"),
m,
))
} else {
let r = u.clone().pseudo_div_rem(&v).remainder;
if r.is_zero() {
None
} else {
let delta = m + 1 - n;
debug_assert!(delta >= 1);
let psi;
let beta;
if i == 1 {
let one =
T::make_one_coefficient_from_element(Cow::Borrowed(&v.elements[0]));
psi = -one.clone();
beta = if delta.is_odd() { -one } else { one };
} else {
assert!(i > 1);
let f = u
.nonzero_highest_power_coefficient()
.expect("known to be non-zero");
psi = match delta_p {
0 => unreachable!(),
1 => psi_p,
_ => T::coefficient_pow_usize(-f.clone(), delta_p - 1)
.exact_div(&T::coefficient_pow_usize(psi_p, delta_p - 2)),
};
beta = f
.neg()
.mul(T::coefficient_pow_usize(psi.clone(), delta - 1));
}
let r = r.exact_div(&beta);
let l = v
.nonzero_highest_power_coefficient()
.expect("known to be non-zero");
let s = r.degree().expect("known to be non-zero");
let mut w = T::coefficient_pow_usize(beta, n);
if m.is_odd() && n.is_odd() {
w = -w;
}
w *= recursive_resultant(v, r, i + 1, delta, psi)?;
let k = n * delta + s - m;
let f = T::coefficient_pow_usize(l, k);
Some(w.exact_div(&f))
}
}
}
if self.is_zero() || rhs.is_zero() {
None
} else {
let zero = T::make_zero_coefficient_from_element(Cow::Borrowed(&self.elements[0]));
recursive_resultant(self, rhs, 1, 0, zero)
}
}
pub fn resultant(self, rhs: Self) -> T
where
T: Zero,
{
self.nonzero_resultant(rhs).unwrap_or_else(T::zero)
}
}
impl<T> GCD for Polynomial<T>
where
T: PolynomialCoefficient + PolynomialDivSupported + PolynomialReducingFactorSupported,
{
type Output = Self;
fn gcd(&self, rhs: &Self) -> Self {
self.to_reduced()
.subresultant_gcd(rhs.to_reduced())
.into_reduced()
}
fn gcd_lcm(&self, rhs: &Self) -> GCDAndLCM<Self> {
let gcd = self.gcd(rhs);
let lcm = if gcd.is_zero() {
Zero::zero()
} else {
self * rhs.exact_div(&gcd)
};
GCDAndLCM { gcd, lcm }
}
}
impl<T> ExtendedGCD for Polynomial<T>
where
T: PolynomialCoefficient + PolynomialDivSupported + PolynomialReducingFactorSupported,
{
fn extended_gcd(&self, rhs: &Self) -> ExtendedGCDResult<Self> {
let lhs = self;
let lhs_reducing_factor = if let Some(v) = lhs.nonzero_reducing_factor() {
v
} else if let Some(rhs_reducing_factor) = rhs.nonzero_reducing_factor() {
return ExtendedGCDResult {
gcd: rhs.exact_div(&rhs_reducing_factor),
x: Self::zero(),
y: rhs
.to_one_if_nonzero()
.expect("known to be nonzero")
.exact_div(rhs_reducing_factor),
};
} else {
return ExtendedGCDResult {
gcd: Self::zero(),
x: Self::zero(),
y: Self::zero(),
};
};
struct StateSet<T: PolynomialCoefficient> {
v: Polynomial<T>,
x: Polynomial<T>,
y: Polynomial<T>,
}
let mut lhs_state = StateSet {
v: lhs.exact_div(&lhs_reducing_factor),
x: lhs
.to_one_if_nonzero()
.expect("known to be nonzero")
.exact_div(lhs_reducing_factor),
y: Self::zero(),
};
let rhs_reducing_factor = if let Some(v) = rhs.nonzero_reducing_factor() {
v
} else {
return ExtendedGCDResult {
gcd: lhs_state.v,
x: lhs_state.x,
y: lhs_state.y,
};
};
let mut rhs_state = StateSet {
v: rhs.exact_div(&rhs_reducing_factor),
x: Self::zero(),
y: rhs
.to_one_if_nonzero()
.expect("known to be nonzero")
.exact_div(rhs_reducing_factor),
};
while !rhs_state.v.is_zero() {
let (quotient, remainder) = lhs_state.v.clone().div_rem(&rhs_state.v);
let mut new_state = StateSet {
v: remainder,
x: lhs_state.x - &rhs_state.x * "ient,
y: lhs_state.y - &rhs_state.y * "ient,
};
if let Some(reducing_factor) = new_state.v.nonzero_reducing_factor() {
new_state.v.exact_div_assign(&reducing_factor);
new_state.x.exact_div_assign(&reducing_factor);
new_state.y.exact_div_assign(reducing_factor);
}
lhs_state = rhs_state;
rhs_state = new_state;
}
ExtendedGCDResult {
gcd: lhs_state.v,
x: lhs_state.x,
y: lhs_state.y,
}
}
fn extended_gcd_lcm(&self, rhs: &Self) -> ExtendedGCDAndLCM<Self> {
let ExtendedGCDResult { gcd, x, y } = self.extended_gcd(rhs);
let lcm = if gcd.is_zero() {
Zero::zero()
} else {
self * rhs.exact_div(&gcd)
};
ExtendedGCDAndLCM { gcd, lcm, x, y }
}
}
#[cfg(test)]
mod tests {
use super::*;
use num_bigint::BigInt;
use num_rational::Ratio;
#[test]
fn test_gcd() {
let r = |n: i64, d: i64| Ratio::<BigInt>::new(n.into(), d.into());
let ri = |v: i64| Ratio::<BigInt>::from_integer(v.into());
fn test_case(
a: Polynomial<Ratio<BigInt>>,
b: Polynomial<Ratio<BigInt>>,
gcd: Polynomial<Ratio<BigInt>>,
lcm: Polynomial<Ratio<BigInt>>,
) {
let results = a.gcd_lcm(&b);
let extended_results = a.extended_gcd_lcm(&b);
println!("a=({}) b=({})", a, b);
println!("gcd=({}) lcm=({})", gcd, lcm);
println!(
"results.gcd=({}) results.lcm=({})",
results.gcd, results.lcm
);
println!(
"extended_results.gcd=({}) extended_results.lcm=({})",
extended_results.gcd, extended_results.lcm
);
println!(
"extended_results.x=({}) extended_results.y=({})",
extended_results.x, extended_results.y
);
assert!(gcd == results.gcd);
assert!(lcm == results.lcm);
assert!(gcd == extended_results.gcd);
assert!(lcm == extended_results.lcm);
assert!(gcd == extended_results.x * a + extended_results.y * b);
}
test_case(
vec![ri(2), ri(0), ri(0), ri(2)].into(),
vec![ri(0), r(1, 3), r(1, 3), r(1, 3)].into(),
ri(1).into(),
vec![ri(0), r(2, 3), r(2, 3), r(2, 3), r(2, 3), r(2, 3), r(2, 3)].into(),
);
test_case(
r(1, 3).into(),
vec![r(1, 3), ri(0), r(1, 3)].into(),
ri(1).into(),
vec![r(1, 9), ri(0), r(1, 9)].into(),
);
test_case(
vec![ri(0), ri(0), ri(1), ri(1)].into(),
vec![ri(0), ri(0), r(1, 3), r(1, 3)].into(),
vec![ri(0), ri(0), ri(1), ri(1)].into(),
vec![ri(0), ri(0), r(1, 3), r(1, 3)].into(),
);
test_case(
vec![ri(0), ri(1), ri(2)].into(),
vec![ri(0), r(1, 2), ri(0), ri(1)].into(),
vec![ri(0), ri(1)].into(),
vec![ri(0), r(1, 2), ri(1), ri(1), ri(2)].into(),
);
test_case(
Zero::zero(),
vec![ri(0), ri(0), ri(2), ri(2)].into(),
vec![ri(0), ri(0), ri(1), ri(1)].into(),
Zero::zero(),
);
test_case(
vec![r(1, 2), ri(1), ri(1)].into(),
vec![ri(1), ri(0), ri(1), ri(1)].into(),
ri(1).into(),
vec![r(1, 2), ri(1), r(3, 2), r(3, 2), ri(2), ri(1)].into(),
);
test_case(
vec![ri(1), ri(0), ri(1), ri(1)].into(),
vec![ri(0), ri(0), ri(1)].into(),
ri(1).into(),
vec![ri(0), ri(0), ri(1), ri(0), ri(1), ri(1)].into(),
);
test_case(
vec![ri(0), r(1, 3), r(2, 3)].into(),
vec![ri(0), ri(1), ri(1)].into(),
vec![ri(0), ri(1)].into(),
vec![ri(0), r(1, 3), ri(1), r(2, 3)].into(),
);
test_case(
vec![r(2, 3), ri(0), r(2, 3), r(2, 3)].into(),
vec![r(1, 2), ri(0), r(1, 2), r(1, 2)].into(),
vec![ri(1), ri(0), ri(1), ri(1)].into(),
vec![r(1, 3), ri(0), r(1, 3), r(1, 3)].into(),
);
test_case(
vec![r(2, 3), r(2, 3), r(2, 3)].into(),
vec![r(2, 3), r(2, 3), r(2, 3)].into(),
vec![ri(1), ri(1), ri(1)].into(),
vec![r(4, 9), r(4, 9), r(4, 9)].into(),
);
test_case(
vec![ri(1), ri(1), r(1, 2), ri(1)].into(),
r(1, 3).into(),
ri(1).into(),
vec![r(1, 3), r(1, 3), r(1, 6), r(1, 3)].into(),
);
test_case(
vec![ri(0), ri(1), ri(1)].into(),
vec![ri(0), ri(2), ri(0), ri(1)].into(),
vec![ri(0), ri(1)].into(),
vec![ri(0), ri(2), ri(2), ri(1), ri(1)].into(),
);
test_case(
vec![ri(0), ri(1), ri(1), ri(2)].into(),
vec![ri(0), r(2, 3)].into(),
vec![ri(0), ri(1)].into(),
vec![ri(0), r(2, 3), r(2, 3), r(4, 3)].into(),
);
test_case(
vec![ri(0), ri(0), ri(2)].into(),
vec![ri(0), ri(2)].into(),
vec![ri(0), ri(1)].into(),
vec![ri(0), ri(0), ri(4)].into(),
);
test_case(
vec![ri(0), r(1, 3), r(1, 3)].into(),
vec![ri(1), ri(1), ri(1), ri(1)].into(),
vec![ri(1), ri(1)].into(),
vec![ri(0), r(1, 3), r(1, 3), r(1, 3), r(1, 3)].into(),
);
test_case(
vec![ri(0), ri(0), ri(0), ri(1)].into(),
vec![ri(0), ri(2), ri(2), ri(1)].into(),
vec![ri(0), ri(1)].into(),
vec![ri(0), ri(0), ri(0), ri(2), ri(2), ri(1)].into(),
);
test_case(
vec![ri(0), ri(0), ri(2), ri(1)].into(),
vec![ri(1), ri(2)].into(),
ri(1).into(),
vec![ri(0), ri(0), ri(2), ri(5), ri(2)].into(),
);
test_case(
vec![ri(0), ri(1), ri(0), ri(2)].into(),
vec![ri(1), ri(0), ri(0), ri(2)].into(),
ri(1).into(),
vec![ri(0), ri(1), ri(0), ri(2), ri(2), ri(0), ri(4)].into(),
);
test_case(
Zero::zero(),
vec![ri(1), ri(0), ri(1), r(1, 2)].into(),
vec![ri(2), ri(0), ri(2), ri(1)].into(),
Zero::zero(),
);
test_case(
vec![ri(1), ri(0), ri(0), ri(1)].into(),
vec![ri(1), ri(0), ri(1)].into(),
ri(1).into(),
vec![ri(1), ri(0), ri(1), ri(1), ri(0), ri(1)].into(),
);
test_case(
vec![r(1, 2), ri(0), ri(0), ri(1)].into(),
vec![ri(0), r(1, 3), r(2, 3), r(2, 3)].into(),
ri(1).into(),
vec![ri(0), r(1, 6), r(1, 3), r(1, 3), r(1, 3), r(2, 3), r(2, 3)].into(),
);
test_case(
Zero::zero(),
vec![ri(0), ri(0), ri(2)].into(),
vec![ri(0), ri(0), ri(1)].into(),
Zero::zero(),
);
test_case(
vec![r(1, 2), ri(1), ri(1), ri(1)].into(),
vec![ri(2), ri(1), ri(1), ri(2)].into(),
ri(1).into(),
vec![ri(1), r(5, 2), r(7, 2), ri(5), ri(4), ri(3), ri(2)].into(),
);
test_case(
vec![ri(2), ri(1), ri(1), ri(1)].into(),
vec![ri(0), r(1, 2), ri(0), ri(1)].into(),
ri(1).into(),
vec![ri(0), ri(1), r(1, 2), r(5, 2), r(3, 2), ri(1), ri(1)].into(),
);
test_case(
vec![r(2, 3), ri(0), ri(0), r(2, 3)].into(),
vec![r(1, 3), ri(0), r(1, 3), r(2, 3)].into(),
vec![ri(1), ri(1)].into(),
vec![r(2, 9), r(-2, 9), r(4, 9), r(2, 9), r(-2, 9), r(4, 9)].into(),
);
test_case(
vec![ri(1), ri(1), ri(1), ri(1)].into(),
vec![ri(0), r(1, 2), ri(1), r(1, 2)].into(),
vec![ri(1), ri(1)].into(),
vec![ri(0), r(1, 2), ri(1), ri(1), ri(1), r(1, 2)].into(),
);
test_case(
vec![ri(0), r(1, 2), r(1, 2), ri(1)].into(),
vec![ri(0), ri(2)].into(),
vec![ri(0), ri(1)].into(),
vec![ri(0), ri(1), ri(1), ri(2)].into(),
);
test_case(
vec![ri(0), ri(1), ri(0), ri(1)].into(),
vec![ri(0), ri(2), ri(0), ri(2)].into(),
vec![ri(0), ri(1), ri(0), ri(1)].into(),
vec![ri(0), ri(2), ri(0), ri(2)].into(),
);
test_case(
vec![ri(0), ri(1), ri(1), ri(2)].into(),
vec![ri(1), r(1, 2), r(1, 2), r(1, 2)].into(),
ri(1).into(),
vec![ri(0), ri(1), r(3, 2), ri(3), ri(2), r(3, 2), ri(1)].into(),
);
test_case(
Zero::zero(),
vec![ri(0), ri(0), r(2, 3), r(2, 3)].into(),
vec![ri(0), ri(0), ri(1), ri(1)].into(),
Zero::zero(),
);
test_case(
Zero::zero(),
vec![ri(2), ri(1), ri(0), ri(1)].into(),
vec![ri(2), ri(1), ri(0), ri(1)].into(),
Zero::zero(),
);
test_case(
vec![ri(0), ri(0), ri(2)].into(),
vec![ri(0), ri(1), ri(1), ri(2)].into(),
vec![ri(0), ri(1)].into(),
vec![ri(0), ri(0), ri(2), ri(2), ri(4)].into(),
);
test_case(
vec![r(2, 3), ri(0), ri(0), r(2, 3)].into(),
vec![r(1, 3), ri(0), r(1, 3), r(2, 3)].into(),
vec![ri(1), ri(1)].into(),
vec![r(2, 9), r(-2, 9), r(4, 9), r(2, 9), r(-2, 9), r(4, 9)].into(),
);
test_case(
vec![r(1, 3), r(1, 3), r(1, 3)].into(),
Zero::zero(),
vec![ri(1), ri(1), ri(1)].into(),
Zero::zero(),
);
test_case(
vec![ri(0), r(2, 3), r(2, 3), r(1, 3)].into(),
vec![ri(0), r(1, 3), r(1, 3), r(1, 3)].into(),
vec![ri(0), ri(1)].into(),
vec![ri(0), r(2, 9), r(4, 9), r(5, 9), r(1, 3), r(1, 9)].into(),
);
test_case(
vec![r(1, 3), r(2, 3), r(1, 3), r(2, 3)].into(),
vec![ri(1), ri(1), ri(1), ri(1)].into(),
vec![ri(1), ri(0), ri(1)].into(),
vec![r(1, 3), ri(1), ri(1), ri(1), r(2, 3)].into(),
);
test_case(
vec![ri(1), ri(2), ri(2), ri(1)].into(),
vec![r(1, 3), r(1, 3), r(1, 3)].into(),
vec![ri(1), ri(1), ri(1)].into(),
vec![r(1, 3), r(2, 3), r(2, 3), r(1, 3)].into(),
);
test_case(
vec![ri(0), ri(1), ri(1), ri(1)].into(),
vec![ri(0), ri(2), ri(1)].into(),
vec![ri(0), ri(1)].into(),
vec![ri(0), ri(2), ri(3), ri(3), ri(1)].into(),
);
test_case(
vec![ri(1), r(1, 2), ri(0), r(1, 2)].into(),
vec![ri(0), ri(1), ri(1)].into(),
vec![ri(1), ri(1)].into(),
vec![ri(0), ri(1), r(1, 2), ri(0), r(1, 2)].into(),
);
test_case(
vec![r(2, 3), r(2, 3), r(1, 3), r(1, 3)].into(),
r(1, 3).into(),
ri(1).into(),
vec![r(2, 9), r(2, 9), r(1, 9), r(1, 9)].into(),
);
test_case(
vec![ri(0), ri(0), ri(2)].into(),
vec![ri(0), ri(1), r(1, 2), ri(1)].into(),
vec![ri(0), ri(1)].into(),
vec![ri(0), ri(0), ri(2), ri(1), ri(2)].into(),
);
test_case(
vec![ri(0), r(1, 3), r(1, 3), r(1, 3)].into(),
Zero::zero(),
vec![ri(0), ri(1), ri(1), ri(1)].into(),
Zero::zero(),
);
test_case(
vec![ri(0), ri(0), r(1, 2)].into(),
vec![ri(0), r(1, 3), r(2, 3), r(2, 3)].into(),
vec![ri(0), ri(1)].into(),
vec![ri(0), ri(0), r(1, 6), r(1, 3), r(1, 3)].into(),
);
test_case(
vec![ri(0), ri(0), ri(1)].into(),
vec![ri(0), ri(1), ri(1), ri(1)].into(),
vec![ri(0), ri(1)].into(),
vec![ri(0), ri(0), ri(1), ri(1), ri(1)].into(),
);
test_case(
vec![ri(1), ri(1), ri(2), ri(1)].into(),
vec![ri(1), ri(1), ri(2), ri(1)].into(),
vec![ri(1), ri(1), ri(2), ri(1)].into(),
vec![ri(1), ri(1), ri(2), ri(1)].into(),
);
test_case(
vec![ri(0), ri(0), ri(0), r(1, 2)].into(),
vec![r(2, 3), r(1, 3), r(2, 3), r(2, 3)].into(),
ri(1).into(),
vec![ri(0), ri(0), ri(0), r(1, 3), r(1, 6), r(1, 3), r(1, 3)].into(),
);
test_case(
vec![ri(2), ri(2)].into(),
vec![r(2, 3), ri(0), ri(0), r(2, 3)].into(),
vec![ri(1), ri(1)].into(),
vec![r(4, 3), ri(0), ri(0), r(4, 3)].into(),
);
test_case(
Zero::zero(),
vec![ri(2), ri(0), ri(0), ri(1)].into(),
vec![ri(2), ri(0), ri(0), ri(1)].into(),
Zero::zero(),
);
test_case(
vec![ri(0), ri(1), ri(2), ri(2)].into(),
vec![ri(0), r(1, 2), ri(0), ri(1)].into(),
vec![ri(0), ri(1)].into(),
vec![ri(0), r(1, 2), ri(1), ri(2), ri(2), ri(2)].into(),
);
test_case(
vec![ri(0), ri(1), ri(2), ri(2)].into(),
vec![ri(0), r(1, 3), r(2, 3), r(2, 3)].into(),
vec![ri(0), r(1, 2), ri(1), ri(1)].into(),
vec![ri(0), r(2, 3), r(4, 3), r(4, 3)].into(),
);
test_case(
vec![ri(0), r(1, 2), r(1, 2), ri(1)].into(),
vec![ri(0), r(1, 3), r(1, 3), r(2, 3)].into(),
vec![ri(0), r(1, 2), r(1, 2), ri(1)].into(),
vec![ri(0), r(1, 3), r(1, 3), r(2, 3)].into(),
);
test_case(Zero::zero(), Zero::zero(), Zero::zero(), Zero::zero());
}
#[test]
fn test_resultant() {
fn test_case(lhs: &[i32], rhs: &[i32], expected: i128) {
let lhs: Polynomial<_> = lhs.iter().copied().map(BigInt::from).collect();
let rhs: Polynomial<_> = rhs.iter().copied().map(BigInt::from).collect();
let expected = BigInt::from(expected);
println!("lhs: {}", lhs);
println!("rhs: {}", rhs);
println!("expected: {}", expected);
let resultant = lhs.resultant(rhs);
println!("resultant: {}", resultant);
assert!(expected == resultant);
}
test_case(&[], &[], 0);
test_case(&[], &[0, 0, 1], 0);
test_case(&[], &[0, 0, 2], 0);
test_case(&[], &[0, 1], 0);
test_case(&[], &[0, 1, 1], 0);
test_case(&[], &[0, 1, 2], 0);
test_case(&[], &[0, 2], 0);
test_case(&[], &[0, 2, 1], 0);
test_case(&[], &[0, 2, 2], 0);
test_case(&[], &[1], 0);
test_case(&[], &[1, 0, 1], 0);
test_case(&[], &[1, 0, 2], 0);
test_case(&[], &[1, 1], 0);
test_case(&[], &[1, 1, 1], 0);
test_case(&[], &[1, 1, 2], 0);
test_case(&[], &[1, 2], 0);
test_case(&[], &[1, 2, 1], 0);
test_case(&[], &[1, 2, 2], 0);
test_case(&[], &[2], 0);
test_case(&[], &[2, 0, 1], 0);
test_case(&[], &[2, 0, 2], 0);
test_case(&[], &[2, 1], 0);
test_case(&[], &[2, 1, 1], 0);
test_case(&[], &[2, 1, 2], 0);
test_case(&[], &[2, 2], 0);
test_case(&[], &[2, 2, 1], 0);
test_case(&[], &[2, 2, 2], 0);
test_case(&[0, 0, 1], &[], 0);
test_case(&[0, 0, 1], &[0, 0, 1], 0);
test_case(&[0, 0, 1], &[0, 0, 2], 0);
test_case(&[0, 0, 1], &[0, 1], 0);
test_case(&[0, 0, 1], &[0, 1, 1], 0);
test_case(&[0, 0, 1], &[0, 1, 2], 0);
test_case(&[0, 0, 1], &[0, 2], 0);
test_case(&[0, 0, 1], &[0, 2, 1], 0);
test_case(&[0, 0, 1], &[0, 2, 2], 0);
test_case(&[0, 0, 1], &[1], 1);
test_case(&[0, 0, 1], &[1, 0, 1], 1);
test_case(&[0, 0, 1], &[1, 0, 2], 1);
test_case(&[0, 0, 1], &[1, 1], 1);
test_case(&[0, 0, 1], &[1, 1, 1], 1);
test_case(&[0, 0, 1], &[1, 1, 2], 1);
test_case(&[0, 0, 1], &[1, 2], 1);
test_case(&[0, 0, 1], &[1, 2, 1], 1);
test_case(&[0, 0, 1], &[1, 2, 2], 1);
test_case(&[0, 0, 1], &[2], 4);
test_case(&[0, 0, 1], &[2, 0, 1], 4);
test_case(&[0, 0, 1], &[2, 0, 2], 4);
test_case(&[0, 0, 1], &[2, 1], 4);
test_case(&[0, 0, 1], &[2, 1, 1], 4);
test_case(&[0, 0, 1], &[2, 1, 2], 4);
test_case(&[0, 0, 1], &[2, 2], 4);
test_case(&[0, 0, 1], &[2, 2, 1], 4);
test_case(&[0, 0, 1], &[2, 2, 2], 4);
test_case(&[0, 0, 2], &[], 0);
test_case(&[0, 0, 2], &[0, 0, 1], 0);
test_case(&[0, 0, 2], &[0, 0, 2], 0);
test_case(&[0, 0, 2], &[0, 1], 0);
test_case(&[0, 0, 2], &[0, 1, 1], 0);
test_case(&[0, 0, 2], &[0, 1, 2], 0);
test_case(&[0, 0, 2], &[0, 2], 0);
test_case(&[0, 0, 2], &[0, 2, 1], 0);
test_case(&[0, 0, 2], &[0, 2, 2], 0);
test_case(&[0, 0, 2], &[1], 1);
test_case(&[0, 0, 2], &[1, 0, 1], 4);
test_case(&[0, 0, 2], &[1, 0, 2], 4);
test_case(&[0, 0, 2], &[1, 1], 2);
test_case(&[0, 0, 2], &[1, 1, 1], 4);
test_case(&[0, 0, 2], &[1, 1, 2], 4);
test_case(&[0, 0, 2], &[1, 2], 2);
test_case(&[0, 0, 2], &[1, 2, 1], 4);
test_case(&[0, 0, 2], &[1, 2, 2], 4);
test_case(&[0, 0, 2], &[2], 4);
test_case(&[0, 0, 2], &[2, 0, 1], 16);
test_case(&[0, 0, 2], &[2, 0, 2], 16);
test_case(&[0, 0, 2], &[2, 1], 8);
test_case(&[0, 0, 2], &[2, 1, 1], 16);
test_case(&[0, 0, 2], &[2, 1, 2], 16);
test_case(&[0, 0, 2], &[2, 2], 8);
test_case(&[0, 0, 2], &[2, 2, 1], 16);
test_case(&[0, 0, 2], &[2, 2, 2], 16);
test_case(&[0, 1], &[], 0);
test_case(&[0, 1], &[0, 0, 1], 0);
test_case(&[0, 1], &[0, 0, 2], 0);
test_case(&[0, 1], &[0, 1], 0);
test_case(&[0, 1], &[0, 1, 1], 0);
test_case(&[0, 1], &[0, 1, 2], 0);
test_case(&[0, 1], &[0, 2], 0);
test_case(&[0, 1], &[0, 2, 1], 0);
test_case(&[0, 1], &[0, 2, 2], 0);
test_case(&[0, 1], &[1], 1);
test_case(&[0, 1], &[1, 0, 1], 1);
test_case(&[0, 1], &[1, 0, 2], 1);
test_case(&[0, 1], &[1, 1], 1);
test_case(&[0, 1], &[1, 1, 1], 1);
test_case(&[0, 1], &[1, 1, 2], 1);
test_case(&[0, 1], &[1, 2], 1);
test_case(&[0, 1], &[1, 2, 1], 1);
test_case(&[0, 1], &[1, 2, 2], 1);
test_case(&[0, 1], &[2], 2);
test_case(&[0, 1], &[2, 0, 1], 2);
test_case(&[0, 1], &[2, 0, 2], 2);
test_case(&[0, 1], &[2, 1], 2);
test_case(&[0, 1], &[2, 1, 1], 2);
test_case(&[0, 1], &[2, 1, 2], 2);
test_case(&[0, 1], &[2, 2], 2);
test_case(&[0, 1], &[2, 2, 1], 2);
test_case(&[0, 1], &[2, 2, 2], 2);
test_case(&[0, 1, 1], &[], 0);
test_case(&[0, 1, 1], &[0, 0, 1], 0);
test_case(&[0, 1, 1], &[0, 0, 2], 0);
test_case(&[0, 1, 1], &[0, 1], 0);
test_case(&[0, 1, 1], &[0, 1, 1], 0);
test_case(&[0, 1, 1], &[0, 1, 2], 0);
test_case(&[0, 1, 1], &[0, 2], 0);
test_case(&[0, 1, 1], &[0, 2, 1], 0);
test_case(&[0, 1, 1], &[0, 2, 2], 0);
test_case(&[0, 1, 1], &[1], 1);
test_case(&[0, 1, 1], &[1, 0, 1], 2);
test_case(&[0, 1, 1], &[1, 0, 2], 3);
test_case(&[0, 1, 1], &[1, 1], 0);
test_case(&[0, 1, 1], &[1, 1, 1], 1);
test_case(&[0, 1, 1], &[1, 1, 2], 2);
test_case(&[0, 1, 1], &[1, 2], -1);
test_case(&[0, 1, 1], &[1, 2, 1], 0);
test_case(&[0, 1, 1], &[1, 2, 2], 1);
test_case(&[0, 1, 1], &[2], 4);
test_case(&[0, 1, 1], &[2, 0, 1], 6);
test_case(&[0, 1, 1], &[2, 0, 2], 8);
test_case(&[0, 1, 1], &[2, 1], 2);
test_case(&[0, 1, 1], &[2, 1, 1], 4);
test_case(&[0, 1, 1], &[2, 1, 2], 6);
test_case(&[0, 1, 1], &[2, 2], 0);
test_case(&[0, 1, 1], &[2, 2, 1], 2);
test_case(&[0, 1, 1], &[2, 2, 2], 4);
test_case(&[0, 1, 2], &[], 0);
test_case(&[0, 1, 2], &[0, 0, 1], 0);
test_case(&[0, 1, 2], &[0, 0, 2], 0);
test_case(&[0, 1, 2], &[0, 1], 0);
test_case(&[0, 1, 2], &[0, 1, 1], 0);
test_case(&[0, 1, 2], &[0, 1, 2], 0);
test_case(&[0, 1, 2], &[0, 2], 0);
test_case(&[0, 1, 2], &[0, 2, 1], 0);
test_case(&[0, 1, 2], &[0, 2, 2], 0);
test_case(&[0, 1, 2], &[1], 1);
test_case(&[0, 1, 2], &[1, 0, 1], 5);
test_case(&[0, 1, 2], &[1, 0, 2], 6);
test_case(&[0, 1, 2], &[1, 1], 1);
test_case(&[0, 1, 2], &[1, 1, 1], 3);
test_case(&[0, 1, 2], &[1, 1, 2], 4);
test_case(&[0, 1, 2], &[1, 2], 0);
test_case(&[0, 1, 2], &[1, 2, 1], 1);
test_case(&[0, 1, 2], &[1, 2, 2], 2);
test_case(&[0, 1, 2], &[2], 4);
test_case(&[0, 1, 2], &[2, 0, 1], 18);
test_case(&[0, 1, 2], &[2, 0, 2], 20);
test_case(&[0, 1, 2], &[2, 1], 6);
test_case(&[0, 1, 2], &[2, 1, 1], 14);
test_case(&[0, 1, 2], &[2, 1, 2], 16);
test_case(&[0, 1, 2], &[2, 2], 4);
test_case(&[0, 1, 2], &[2, 2, 1], 10);
test_case(&[0, 1, 2], &[2, 2, 2], 12);
test_case(&[0, 2], &[], 0);
test_case(&[0, 2], &[0, 0, 1], 0);
test_case(&[0, 2], &[0, 0, 2], 0);
test_case(&[0, 2], &[0, 1], 0);
test_case(&[0, 2], &[0, 1, 1], 0);
test_case(&[0, 2], &[0, 1, 2], 0);
test_case(&[0, 2], &[0, 2], 0);
test_case(&[0, 2], &[0, 2, 1], 0);
test_case(&[0, 2], &[0, 2, 2], 0);
test_case(&[0, 2], &[1], 1);
test_case(&[0, 2], &[1, 0, 1], 4);
test_case(&[0, 2], &[1, 0, 2], 4);
test_case(&[0, 2], &[1, 1], 2);
test_case(&[0, 2], &[1, 1, 1], 4);
test_case(&[0, 2], &[1, 1, 2], 4);
test_case(&[0, 2], &[1, 2], 2);
test_case(&[0, 2], &[1, 2, 1], 4);
test_case(&[0, 2], &[1, 2, 2], 4);
test_case(&[0, 2], &[2], 2);
test_case(&[0, 2], &[2, 0, 1], 8);
test_case(&[0, 2], &[2, 0, 2], 8);
test_case(&[0, 2], &[2, 1], 4);
test_case(&[0, 2], &[2, 1, 1], 8);
test_case(&[0, 2], &[2, 1, 2], 8);
test_case(&[0, 2], &[2, 2], 4);
test_case(&[0, 2], &[2, 2, 1], 8);
test_case(&[0, 2], &[2, 2, 2], 8);
test_case(&[0, 2, 1], &[], 0);
test_case(&[0, 2, 1], &[0, 0, 1], 0);
test_case(&[0, 2, 1], &[0, 0, 2], 0);
test_case(&[0, 2, 1], &[0, 1], 0);
test_case(&[0, 2, 1], &[0, 1, 1], 0);
test_case(&[0, 2, 1], &[0, 1, 2], 0);
test_case(&[0, 2, 1], &[0, 2], 0);
test_case(&[0, 2, 1], &[0, 2, 1], 0);
test_case(&[0, 2, 1], &[0, 2, 2], 0);
test_case(&[0, 2, 1], &[1], 1);
test_case(&[0, 2, 1], &[1, 0, 1], 5);
test_case(&[0, 2, 1], &[1, 0, 2], 9);
test_case(&[0, 2, 1], &[1, 1], -1);
test_case(&[0, 2, 1], &[1, 1, 1], 3);
test_case(&[0, 2, 1], &[1, 1, 2], 7);
test_case(&[0, 2, 1], &[1, 2], -3);
test_case(&[0, 2, 1], &[1, 2, 1], 1);
test_case(&[0, 2, 1], &[1, 2, 2], 5);
test_case(&[0, 2, 1], &[2], 4);
test_case(&[0, 2, 1], &[2, 0, 1], 12);
test_case(&[0, 2, 1], &[2, 0, 2], 20);
test_case(&[0, 2, 1], &[2, 1], 0);
test_case(&[0, 2, 1], &[2, 1, 1], 8);
test_case(&[0, 2, 1], &[2, 1, 2], 16);
test_case(&[0, 2, 1], &[2, 2], -4);
test_case(&[0, 2, 1], &[2, 2, 1], 4);
test_case(&[0, 2, 1], &[2, 2, 2], 12);
test_case(&[0, 2, 2], &[], 0);
test_case(&[0, 2, 2], &[0, 0, 1], 0);
test_case(&[0, 2, 2], &[0, 0, 2], 0);
test_case(&[0, 2, 2], &[0, 1], 0);
test_case(&[0, 2, 2], &[0, 1, 1], 0);
test_case(&[0, 2, 2], &[0, 1, 2], 0);
test_case(&[0, 2, 2], &[0, 2], 0);
test_case(&[0, 2, 2], &[0, 2, 1], 0);
test_case(&[0, 2, 2], &[0, 2, 2], 0);
test_case(&[0, 2, 2], &[1], 1);
test_case(&[0, 2, 2], &[1, 0, 1], 8);
test_case(&[0, 2, 2], &[1, 0, 2], 12);
test_case(&[0, 2, 2], &[1, 1], 0);
test_case(&[0, 2, 2], &[1, 1, 1], 4);
test_case(&[0, 2, 2], &[1, 1, 2], 8);
test_case(&[0, 2, 2], &[1, 2], -2);
test_case(&[0, 2, 2], &[1, 2, 1], 0);
test_case(&[0, 2, 2], &[1, 2, 2], 4);
test_case(&[0, 2, 2], &[2], 4);
test_case(&[0, 2, 2], &[2, 0, 1], 24);
test_case(&[0, 2, 2], &[2, 0, 2], 32);
test_case(&[0, 2, 2], &[2, 1], 4);
test_case(&[0, 2, 2], &[2, 1, 1], 16);
test_case(&[0, 2, 2], &[2, 1, 2], 24);
test_case(&[0, 2, 2], &[2, 2], 0);
test_case(&[0, 2, 2], &[2, 2, 1], 8);
test_case(&[0, 2, 2], &[2, 2, 2], 16);
test_case(&[1], &[], 0);
test_case(&[1], &[0, 0, 1], 1);
test_case(&[1], &[0, 0, 2], 1);
test_case(&[1], &[0, 1], 1);
test_case(&[1], &[0, 1, 1], 1);
test_case(&[1], &[0, 1, 2], 1);
test_case(&[1], &[0, 2], 1);
test_case(&[1], &[0, 2, 1], 1);
test_case(&[1], &[0, 2, 2], 1);
test_case(&[1], &[1], 1);
test_case(&[1], &[1, 0, 1], 1);
test_case(&[1], &[1, 0, 2], 1);
test_case(&[1], &[1, 1], 1);
test_case(&[1], &[1, 1, 1], 1);
test_case(&[1], &[1, 1, 2], 1);
test_case(&[1], &[1, 2], 1);
test_case(&[1], &[1, 2, 1], 1);
test_case(&[1], &[1, 2, 2], 1);
test_case(&[1], &[2], 1);
test_case(&[1], &[2, 0, 1], 1);
test_case(&[1], &[2, 0, 2], 1);
test_case(&[1], &[2, 1], 1);
test_case(&[1], &[2, 1, 1], 1);
test_case(&[1], &[2, 1, 2], 1);
test_case(&[1], &[2, 2], 1);
test_case(&[1], &[2, 2, 1], 1);
test_case(&[1], &[2, 2, 2], 1);
test_case(&[1, 0, 1], &[], 0);
test_case(&[1, 0, 1], &[0, 0, 1], 1);
test_case(&[1, 0, 1], &[0, 0, 2], 4);
test_case(&[1, 0, 1], &[0, 1], 1);
test_case(&[1, 0, 1], &[0, 1, 1], 2);
test_case(&[1, 0, 1], &[0, 1, 2], 5);
test_case(&[1, 0, 1], &[0, 2], 4);
test_case(&[1, 0, 1], &[0, 2, 1], 5);
test_case(&[1, 0, 1], &[0, 2, 2], 8);
test_case(&[1, 0, 1], &[1], 1);
test_case(&[1, 0, 1], &[1, 0, 1], 0);
test_case(&[1, 0, 1], &[1, 0, 2], 1);
test_case(&[1, 0, 1], &[1, 1], 2);
test_case(&[1, 0, 1], &[1, 1, 1], 1);
test_case(&[1, 0, 1], &[1, 1, 2], 2);
test_case(&[1, 0, 1], &[1, 2], 5);
test_case(&[1, 0, 1], &[1, 2, 1], 4);
test_case(&[1, 0, 1], &[1, 2, 2], 5);
test_case(&[1, 0, 1], &[2], 4);
test_case(&[1, 0, 1], &[2, 0, 1], 1);
test_case(&[1, 0, 1], &[2, 0, 2], 0);
test_case(&[1, 0, 1], &[2, 1], 5);
test_case(&[1, 0, 1], &[2, 1, 1], 2);
test_case(&[1, 0, 1], &[2, 1, 2], 1);
test_case(&[1, 0, 1], &[2, 2], 8);
test_case(&[1, 0, 1], &[2, 2, 1], 5);
test_case(&[1, 0, 1], &[2, 2, 2], 4);
test_case(&[1, 0, 2], &[], 0);
test_case(&[1, 0, 2], &[0, 0, 1], 1);
test_case(&[1, 0, 2], &[0, 0, 2], 4);
test_case(&[1, 0, 2], &[0, 1], 1);
test_case(&[1, 0, 2], &[0, 1, 1], 3);
test_case(&[1, 0, 2], &[0, 1, 2], 6);
test_case(&[1, 0, 2], &[0, 2], 4);
test_case(&[1, 0, 2], &[0, 2, 1], 9);
test_case(&[1, 0, 2], &[0, 2, 2], 12);
test_case(&[1, 0, 2], &[1], 1);
test_case(&[1, 0, 2], &[1, 0, 1], 1);
test_case(&[1, 0, 2], &[1, 0, 2], 0);
test_case(&[1, 0, 2], &[1, 1], 3);
test_case(&[1, 0, 2], &[1, 1, 1], 3);
test_case(&[1, 0, 2], &[1, 1, 2], 2);
test_case(&[1, 0, 2], &[1, 2], 6);
test_case(&[1, 0, 2], &[1, 2, 1], 9);
test_case(&[1, 0, 2], &[1, 2, 2], 8);
test_case(&[1, 0, 2], &[2], 4);
test_case(&[1, 0, 2], &[2, 0, 1], 9);
test_case(&[1, 0, 2], &[2, 0, 2], 4);
test_case(&[1, 0, 2], &[2, 1], 9);
test_case(&[1, 0, 2], &[2, 1, 1], 11);
test_case(&[1, 0, 2], &[2, 1, 2], 6);
test_case(&[1, 0, 2], &[2, 2], 12);
test_case(&[1, 0, 2], &[2, 2, 1], 17);
test_case(&[1, 0, 2], &[2, 2, 2], 12);
test_case(&[1, 1], &[], 0);
test_case(&[1, 1], &[0, 0, 1], 1);
test_case(&[1, 1], &[0, 0, 2], 2);
test_case(&[1, 1], &[0, 1], -1);
test_case(&[1, 1], &[0, 1, 1], 0);
test_case(&[1, 1], &[0, 1, 2], 1);
test_case(&[1, 1], &[0, 2], -2);
test_case(&[1, 1], &[0, 2, 1], -1);
test_case(&[1, 1], &[0, 2, 2], 0);
test_case(&[1, 1], &[1], 1);
test_case(&[1, 1], &[1, 0, 1], 2);
test_case(&[1, 1], &[1, 0, 2], 3);
test_case(&[1, 1], &[1, 1], 0);
test_case(&[1, 1], &[1, 1, 1], 1);
test_case(&[1, 1], &[1, 1, 2], 2);
test_case(&[1, 1], &[1, 2], -1);
test_case(&[1, 1], &[1, 2, 1], 0);
test_case(&[1, 1], &[1, 2, 2], 1);
test_case(&[1, 1], &[2], 2);
test_case(&[1, 1], &[2, 0, 1], 3);
test_case(&[1, 1], &[2, 0, 2], 4);
test_case(&[1, 1], &[2, 1], 1);
test_case(&[1, 1], &[2, 1, 1], 2);
test_case(&[1, 1], &[2, 1, 2], 3);
test_case(&[1, 1], &[2, 2], 0);
test_case(&[1, 1], &[2, 2, 1], 1);
test_case(&[1, 1], &[2, 2, 2], 2);
test_case(&[1, 1, 1], &[], 0);
test_case(&[1, 1, 1], &[0, 0, 1], 1);
test_case(&[1, 1, 1], &[0, 0, 2], 4);
test_case(&[1, 1, 1], &[0, 1], 1);
test_case(&[1, 1, 1], &[0, 1, 1], 1);
test_case(&[1, 1, 1], &[0, 1, 2], 3);
test_case(&[1, 1, 1], &[0, 2], 4);
test_case(&[1, 1, 1], &[0, 2, 1], 3);
test_case(&[1, 1, 1], &[0, 2, 2], 4);
test_case(&[1, 1, 1], &[1], 1);
test_case(&[1, 1, 1], &[1, 0, 1], 1);
test_case(&[1, 1, 1], &[1, 0, 2], 3);
test_case(&[1, 1, 1], &[1, 1], 1);
test_case(&[1, 1, 1], &[1, 1, 1], 0);
test_case(&[1, 1, 1], &[1, 1, 2], 1);
test_case(&[1, 1, 1], &[1, 2], 3);
test_case(&[1, 1, 1], &[1, 2, 1], 1);
test_case(&[1, 1, 1], &[1, 2, 2], 1);
test_case(&[1, 1, 1], &[2], 4);
test_case(&[1, 1, 1], &[2, 0, 1], 3);
test_case(&[1, 1, 1], &[2, 0, 2], 4);
test_case(&[1, 1, 1], &[2, 1], 3);
test_case(&[1, 1, 1], &[2, 1, 1], 1);
test_case(&[1, 1, 1], &[2, 1, 2], 1);
test_case(&[1, 1, 1], &[2, 2], 4);
test_case(&[1, 1, 1], &[2, 2, 1], 1);
test_case(&[1, 1, 1], &[2, 2, 2], 0);
test_case(&[1, 1, 2], &[], 0);
test_case(&[1, 1, 2], &[0, 0, 1], 1);
test_case(&[1, 1, 2], &[0, 0, 2], 4);
test_case(&[1, 1, 2], &[0, 1], 1);
test_case(&[1, 1, 2], &[0, 1, 1], 2);
test_case(&[1, 1, 2], &[0, 1, 2], 4);
test_case(&[1, 1, 2], &[0, 2], 4);
test_case(&[1, 1, 2], &[0, 2, 1], 7);
test_case(&[1, 1, 2], &[0, 2, 2], 8);
test_case(&[1, 1, 2], &[1], 1);
test_case(&[1, 1, 2], &[1, 0, 1], 2);
test_case(&[1, 1, 2], &[1, 0, 2], 2);
test_case(&[1, 1, 2], &[1, 1], 2);
test_case(&[1, 1, 2], &[1, 1, 1], 1);
test_case(&[1, 1, 2], &[1, 1, 2], 0);
test_case(&[1, 1, 2], &[1, 2], 4);
test_case(&[1, 1, 2], &[1, 2, 1], 4);
test_case(&[1, 1, 2], &[1, 2, 2], 2);
test_case(&[1, 1, 2], &[2], 4);
test_case(&[1, 1, 2], &[2, 0, 1], 11);
test_case(&[1, 1, 2], &[2, 0, 2], 8);
test_case(&[1, 1, 2], &[2, 1], 7);
test_case(&[1, 1, 2], &[2, 1, 1], 8);
test_case(&[1, 1, 2], &[2, 1, 2], 4);
test_case(&[1, 1, 2], &[2, 2], 8);
test_case(&[1, 1, 2], &[2, 2, 1], 9);
test_case(&[1, 1, 2], &[2, 2, 2], 4);
test_case(&[1, 2], &[], 0);
test_case(&[1, 2], &[0, 0, 1], 1);
test_case(&[1, 2], &[0, 0, 2], 2);
test_case(&[1, 2], &[0, 1], -1);
test_case(&[1, 2], &[0, 1, 1], -1);
test_case(&[1, 2], &[0, 1, 2], 0);
test_case(&[1, 2], &[0, 2], -2);
test_case(&[1, 2], &[0, 2, 1], -3);
test_case(&[1, 2], &[0, 2, 2], -2);
test_case(&[1, 2], &[1], 1);
test_case(&[1, 2], &[1, 0, 1], 5);
test_case(&[1, 2], &[1, 0, 2], 6);
test_case(&[1, 2], &[1, 1], 1);
test_case(&[1, 2], &[1, 1, 1], 3);
test_case(&[1, 2], &[1, 1, 2], 4);
test_case(&[1, 2], &[1, 2], 0);
test_case(&[1, 2], &[1, 2, 1], 1);
test_case(&[1, 2], &[1, 2, 2], 2);
test_case(&[1, 2], &[2], 2);
test_case(&[1, 2], &[2, 0, 1], 9);
test_case(&[1, 2], &[2, 0, 2], 10);
test_case(&[1, 2], &[2, 1], 3);
test_case(&[1, 2], &[2, 1, 1], 7);
test_case(&[1, 2], &[2, 1, 2], 8);
test_case(&[1, 2], &[2, 2], 2);
test_case(&[1, 2], &[2, 2, 1], 5);
test_case(&[1, 2], &[2, 2, 2], 6);
test_case(&[1, 2, 1], &[], 0);
test_case(&[1, 2, 1], &[0, 0, 1], 1);
test_case(&[1, 2, 1], &[0, 0, 2], 4);
test_case(&[1, 2, 1], &[0, 1], 1);
test_case(&[1, 2, 1], &[0, 1, 1], 0);
test_case(&[1, 2, 1], &[0, 1, 2], 1);
test_case(&[1, 2, 1], &[0, 2], 4);
test_case(&[1, 2, 1], &[0, 2, 1], 1);
test_case(&[1, 2, 1], &[0, 2, 2], 0);
test_case(&[1, 2, 1], &[1], 1);
test_case(&[1, 2, 1], &[1, 0, 1], 4);
test_case(&[1, 2, 1], &[1, 0, 2], 9);
test_case(&[1, 2, 1], &[1, 1], 0);
test_case(&[1, 2, 1], &[1, 1, 1], 1);
test_case(&[1, 2, 1], &[1, 1, 2], 4);
test_case(&[1, 2, 1], &[1, 2], 1);
test_case(&[1, 2, 1], &[1, 2, 1], 0);
test_case(&[1, 2, 1], &[1, 2, 2], 1);
test_case(&[1, 2, 1], &[2], 4);
test_case(&[1, 2, 1], &[2, 0, 1], 9);
test_case(&[1, 2, 1], &[2, 0, 2], 16);
test_case(&[1, 2, 1], &[2, 1], 1);
test_case(&[1, 2, 1], &[2, 1, 1], 4);
test_case(&[1, 2, 1], &[2, 1, 2], 9);
test_case(&[1, 2, 1], &[2, 2], 0);
test_case(&[1, 2, 1], &[2, 2, 1], 1);
test_case(&[1, 2, 1], &[2, 2, 2], 4);
test_case(&[1, 2, 2], &[], 0);
test_case(&[1, 2, 2], &[0, 0, 1], 1);
test_case(&[1, 2, 2], &[0, 0, 2], 4);
test_case(&[1, 2, 2], &[0, 1], 1);
test_case(&[1, 2, 2], &[0, 1, 1], 1);
test_case(&[1, 2, 2], &[0, 1, 2], 2);
test_case(&[1, 2, 2], &[0, 2], 4);
test_case(&[1, 2, 2], &[0, 2, 1], 5);
test_case(&[1, 2, 2], &[0, 2, 2], 4);
test_case(&[1, 2, 2], &[1], 1);
test_case(&[1, 2, 2], &[1, 0, 1], 5);
test_case(&[1, 2, 2], &[1, 0, 2], 8);
test_case(&[1, 2, 2], &[1, 1], 1);
test_case(&[1, 2, 2], &[1, 1, 1], 1);
test_case(&[1, 2, 2], &[1, 1, 2], 2);
test_case(&[1, 2, 2], &[1, 2], 2);
test_case(&[1, 2, 2], &[1, 2, 1], 1);
test_case(&[1, 2, 2], &[1, 2, 2], 0);
test_case(&[1, 2, 2], &[2], 4);
test_case(&[1, 2, 2], &[2, 0, 1], 17);
test_case(&[1, 2, 2], &[2, 0, 2], 20);
test_case(&[1, 2, 2], &[2, 1], 5);
test_case(&[1, 2, 2], &[2, 1, 1], 9);
test_case(&[1, 2, 2], &[2, 1, 2], 10);
test_case(&[1, 2, 2], &[2, 2], 4);
test_case(&[1, 2, 2], &[2, 2, 1], 5);
test_case(&[1, 2, 2], &[2, 2, 2], 4);
test_case(&[2], &[], 0);
test_case(&[2], &[0, 0, 1], 4);
test_case(&[2], &[0, 0, 2], 4);
test_case(&[2], &[0, 1], 2);
test_case(&[2], &[0, 1, 1], 4);
test_case(&[2], &[0, 1, 2], 4);
test_case(&[2], &[0, 2], 2);
test_case(&[2], &[0, 2, 1], 4);
test_case(&[2], &[0, 2, 2], 4);
test_case(&[2], &[1], 1);
test_case(&[2], &[1, 0, 1], 4);
test_case(&[2], &[1, 0, 2], 4);
test_case(&[2], &[1, 1], 2);
test_case(&[2], &[1, 1, 1], 4);
test_case(&[2], &[1, 1, 2], 4);
test_case(&[2], &[1, 2], 2);
test_case(&[2], &[1, 2, 1], 4);
test_case(&[2], &[1, 2, 2], 4);
test_case(&[2], &[2], 1);
test_case(&[2], &[2, 0, 1], 4);
test_case(&[2], &[2, 0, 2], 4);
test_case(&[2], &[2, 1], 2);
test_case(&[2], &[2, 1, 1], 4);
test_case(&[2], &[2, 1, 2], 4);
test_case(&[2], &[2, 2], 2);
test_case(&[2], &[2, 2, 1], 4);
test_case(&[2], &[2, 2, 2], 4);
test_case(&[2, 0, 1], &[], 0);
test_case(&[2, 0, 1], &[0, 0, 1], 4);
test_case(&[2, 0, 1], &[0, 0, 2], 16);
test_case(&[2, 0, 1], &[0, 1], 2);
test_case(&[2, 0, 1], &[0, 1, 1], 6);
test_case(&[2, 0, 1], &[0, 1, 2], 18);
test_case(&[2, 0, 1], &[0, 2], 8);
test_case(&[2, 0, 1], &[0, 2, 1], 12);
test_case(&[2, 0, 1], &[0, 2, 2], 24);
test_case(&[2, 0, 1], &[1], 1);
test_case(&[2, 0, 1], &[1, 0, 1], 1);
test_case(&[2, 0, 1], &[1, 0, 2], 9);
test_case(&[2, 0, 1], &[1, 1], 3);
test_case(&[2, 0, 1], &[1, 1, 1], 3);
test_case(&[2, 0, 1], &[1, 1, 2], 11);
test_case(&[2, 0, 1], &[1, 2], 9);
test_case(&[2, 0, 1], &[1, 2, 1], 9);
test_case(&[2, 0, 1], &[1, 2, 2], 17);
test_case(&[2, 0, 1], &[2], 4);
test_case(&[2, 0, 1], &[2, 0, 1], 0);
test_case(&[2, 0, 1], &[2, 0, 2], 4);
test_case(&[2, 0, 1], &[2, 1], 6);
test_case(&[2, 0, 1], &[2, 1, 1], 2);
test_case(&[2, 0, 1], &[2, 1, 2], 6);
test_case(&[2, 0, 1], &[2, 2], 12);
test_case(&[2, 0, 1], &[2, 2, 1], 8);
test_case(&[2, 0, 1], &[2, 2, 2], 12);
test_case(&[2, 0, 2], &[], 0);
test_case(&[2, 0, 2], &[0, 0, 1], 4);
test_case(&[2, 0, 2], &[0, 0, 2], 16);
test_case(&[2, 0, 2], &[0, 1], 2);
test_case(&[2, 0, 2], &[0, 1, 1], 8);
test_case(&[2, 0, 2], &[0, 1, 2], 20);
test_case(&[2, 0, 2], &[0, 2], 8);
test_case(&[2, 0, 2], &[0, 2, 1], 20);
test_case(&[2, 0, 2], &[0, 2, 2], 32);
test_case(&[2, 0, 2], &[1], 1);
test_case(&[2, 0, 2], &[1, 0, 1], 0);
test_case(&[2, 0, 2], &[1, 0, 2], 4);
test_case(&[2, 0, 2], &[1, 1], 4);
test_case(&[2, 0, 2], &[1, 1, 1], 4);
test_case(&[2, 0, 2], &[1, 1, 2], 8);
test_case(&[2, 0, 2], &[1, 2], 10);
test_case(&[2, 0, 2], &[1, 2, 1], 16);
test_case(&[2, 0, 2], &[1, 2, 2], 20);
test_case(&[2, 0, 2], &[2], 4);
test_case(&[2, 0, 2], &[2, 0, 1], 4);
test_case(&[2, 0, 2], &[2, 0, 2], 0);
test_case(&[2, 0, 2], &[2, 1], 10);
test_case(&[2, 0, 2], &[2, 1, 1], 8);
test_case(&[2, 0, 2], &[2, 1, 2], 4);
test_case(&[2, 0, 2], &[2, 2], 16);
test_case(&[2, 0, 2], &[2, 2, 1], 20);
test_case(&[2, 0, 2], &[2, 2, 2], 16);
test_case(&[2, 1], &[], 0);
test_case(&[2, 1], &[0, 0, 1], 4);
test_case(&[2, 1], &[0, 0, 2], 8);
test_case(&[2, 1], &[0, 1], -2);
test_case(&[2, 1], &[0, 1, 1], 2);
test_case(&[2, 1], &[0, 1, 2], 6);
test_case(&[2, 1], &[0, 2], -4);
test_case(&[2, 1], &[0, 2, 1], 0);
test_case(&[2, 1], &[0, 2, 2], 4);
test_case(&[2, 1], &[1], 1);
test_case(&[2, 1], &[1, 0, 1], 5);
test_case(&[2, 1], &[1, 0, 2], 9);
test_case(&[2, 1], &[1, 1], -1);
test_case(&[2, 1], &[1, 1, 1], 3);
test_case(&[2, 1], &[1, 1, 2], 7);
test_case(&[2, 1], &[1, 2], -3);
test_case(&[2, 1], &[1, 2, 1], 1);
test_case(&[2, 1], &[1, 2, 2], 5);
test_case(&[2, 1], &[2], 2);
test_case(&[2, 1], &[2, 0, 1], 6);
test_case(&[2, 1], &[2, 0, 2], 10);
test_case(&[2, 1], &[2, 1], 0);
test_case(&[2, 1], &[2, 1, 1], 4);
test_case(&[2, 1], &[2, 1, 2], 8);
test_case(&[2, 1], &[2, 2], -2);
test_case(&[2, 1], &[2, 2, 1], 2);
test_case(&[2, 1], &[2, 2, 2], 6);
test_case(&[2, 1, 1], &[], 0);
test_case(&[2, 1, 1], &[0, 0, 1], 4);
test_case(&[2, 1, 1], &[0, 0, 2], 16);
test_case(&[2, 1, 1], &[0, 1], 2);
test_case(&[2, 1, 1], &[0, 1, 1], 4);
test_case(&[2, 1, 1], &[0, 1, 2], 14);
test_case(&[2, 1, 1], &[0, 2], 8);
test_case(&[2, 1, 1], &[0, 2, 1], 8);
test_case(&[2, 1, 1], &[0, 2, 2], 16);
test_case(&[2, 1, 1], &[1], 1);
test_case(&[2, 1, 1], &[1, 0, 1], 2);
test_case(&[2, 1, 1], &[1, 0, 2], 11);
test_case(&[2, 1, 1], &[1, 1], 2);
test_case(&[2, 1, 1], &[1, 1, 1], 1);
test_case(&[2, 1, 1], &[1, 1, 2], 8);
test_case(&[2, 1, 1], &[1, 2], 7);
test_case(&[2, 1, 1], &[1, 2, 1], 4);
test_case(&[2, 1, 1], &[1, 2, 2], 9);
test_case(&[2, 1, 1], &[2], 4);
test_case(&[2, 1, 1], &[2, 0, 1], 2);
test_case(&[2, 1, 1], &[2, 0, 2], 8);
test_case(&[2, 1, 1], &[2, 1], 4);
test_case(&[2, 1, 1], &[2, 1, 1], 0);
test_case(&[2, 1, 1], &[2, 1, 2], 4);
test_case(&[2, 1, 1], &[2, 2], 8);
test_case(&[2, 1, 1], &[2, 2, 1], 2);
test_case(&[2, 1, 1], &[2, 2, 2], 4);
test_case(&[2, 1, 2], &[], 0);
test_case(&[2, 1, 2], &[0, 0, 1], 4);
test_case(&[2, 1, 2], &[0, 0, 2], 16);
test_case(&[2, 1, 2], &[0, 1], 2);
test_case(&[2, 1, 2], &[0, 1, 1], 6);
test_case(&[2, 1, 2], &[0, 1, 2], 16);
test_case(&[2, 1, 2], &[0, 2], 8);
test_case(&[2, 1, 2], &[0, 2, 1], 16);
test_case(&[2, 1, 2], &[0, 2, 2], 24);
test_case(&[2, 1, 2], &[1], 1);
test_case(&[2, 1, 2], &[1, 0, 1], 1);
test_case(&[2, 1, 2], &[1, 0, 2], 6);
test_case(&[2, 1, 2], &[1, 1], 3);
test_case(&[2, 1, 2], &[1, 1, 1], 1);
test_case(&[2, 1, 2], &[1, 1, 2], 4);
test_case(&[2, 1, 2], &[1, 2], 8);
test_case(&[2, 1, 2], &[1, 2, 1], 9);
test_case(&[2, 1, 2], &[1, 2, 2], 10);
test_case(&[2, 1, 2], &[2], 4);
test_case(&[2, 1, 2], &[2, 0, 1], 6);
test_case(&[2, 1, 2], &[2, 0, 2], 4);
test_case(&[2, 1, 2], &[2, 1], 8);
test_case(&[2, 1, 2], &[2, 1, 1], 4);
test_case(&[2, 1, 2], &[2, 1, 2], 0);
test_case(&[2, 1, 2], &[2, 2], 12);
test_case(&[2, 1, 2], &[2, 2, 1], 10);
test_case(&[2, 1, 2], &[2, 2, 2], 4);
test_case(&[2, 2], &[], 0);
test_case(&[2, 2], &[0, 0, 1], 4);
test_case(&[2, 2], &[0, 0, 2], 8);
test_case(&[2, 2], &[0, 1], -2);
test_case(&[2, 2], &[0, 1, 1], 0);
test_case(&[2, 2], &[0, 1, 2], 4);
test_case(&[2, 2], &[0, 2], -4);
test_case(&[2, 2], &[0, 2, 1], -4);
test_case(&[2, 2], &[0, 2, 2], 0);
test_case(&[2, 2], &[1], 1);
test_case(&[2, 2], &[1, 0, 1], 8);
test_case(&[2, 2], &[1, 0, 2], 12);
test_case(&[2, 2], &[1, 1], 0);
test_case(&[2, 2], &[1, 1, 1], 4);
test_case(&[2, 2], &[1, 1, 2], 8);
test_case(&[2, 2], &[1, 2], -2);
test_case(&[2, 2], &[1, 2, 1], 0);
test_case(&[2, 2], &[1, 2, 2], 4);
test_case(&[2, 2], &[2], 2);
test_case(&[2, 2], &[2, 0, 1], 12);
test_case(&[2, 2], &[2, 0, 2], 16);
test_case(&[2, 2], &[2, 1], 2);
test_case(&[2, 2], &[2, 1, 1], 8);
test_case(&[2, 2], &[2, 1, 2], 12);
test_case(&[2, 2], &[2, 2], 0);
test_case(&[2, 2], &[2, 2, 1], 4);
test_case(&[2, 2], &[2, 2, 2], 8);
test_case(&[2, 2, 1], &[], 0);
test_case(&[2, 2, 1], &[0, 0, 1], 4);
test_case(&[2, 2, 1], &[0, 0, 2], 16);
test_case(&[2, 2, 1], &[0, 1], 2);
test_case(&[2, 2, 1], &[0, 1, 1], 2);
test_case(&[2, 2, 1], &[0, 1, 2], 10);
test_case(&[2, 2, 1], &[0, 2], 8);
test_case(&[2, 2, 1], &[0, 2, 1], 4);
test_case(&[2, 2, 1], &[0, 2, 2], 8);
test_case(&[2, 2, 1], &[1], 1);
test_case(&[2, 2, 1], &[1, 0, 1], 5);
test_case(&[2, 2, 1], &[1, 0, 2], 17);
test_case(&[2, 2, 1], &[1, 1], 1);
test_case(&[2, 2, 1], &[1, 1, 1], 1);
test_case(&[2, 2, 1], &[1, 1, 2], 9);
test_case(&[2, 2, 1], &[1, 2], 5);
test_case(&[2, 2, 1], &[1, 2, 1], 1);
test_case(&[2, 2, 1], &[1, 2, 2], 5);
test_case(&[2, 2, 1], &[2], 4);
test_case(&[2, 2, 1], &[2, 0, 1], 8);
test_case(&[2, 2, 1], &[2, 0, 2], 20);
test_case(&[2, 2, 1], &[2, 1], 2);
test_case(&[2, 2, 1], &[2, 1, 1], 2);
test_case(&[2, 2, 1], &[2, 1, 2], 10);
test_case(&[2, 2, 1], &[2, 2], 4);
test_case(&[2, 2, 1], &[2, 2, 1], 0);
test_case(&[2, 2, 1], &[2, 2, 2], 4);
test_case(&[2, 2, 2], &[], 0);
test_case(&[2, 2, 2], &[0, 0, 1], 4);
test_case(&[2, 2, 2], &[0, 0, 2], 16);
test_case(&[2, 2, 2], &[0, 1], 2);
test_case(&[2, 2, 2], &[0, 1, 1], 4);
test_case(&[2, 2, 2], &[0, 1, 2], 12);
test_case(&[2, 2, 2], &[0, 2], 8);
test_case(&[2, 2, 2], &[0, 2, 1], 12);
test_case(&[2, 2, 2], &[0, 2, 2], 16);
test_case(&[2, 2, 2], &[1], 1);
test_case(&[2, 2, 2], &[1, 0, 1], 4);
test_case(&[2, 2, 2], &[1, 0, 2], 12);
test_case(&[2, 2, 2], &[1, 1], 2);
test_case(&[2, 2, 2], &[1, 1, 1], 0);
test_case(&[2, 2, 2], &[1, 1, 2], 4);
test_case(&[2, 2, 2], &[1, 2], 6);
test_case(&[2, 2, 2], &[1, 2, 1], 4);
test_case(&[2, 2, 2], &[1, 2, 2], 4);
test_case(&[2, 2, 2], &[2], 4);
test_case(&[2, 2, 2], &[2, 0, 1], 12);
test_case(&[2, 2, 2], &[2, 0, 2], 16);
test_case(&[2, 2, 2], &[2, 1], 6);
test_case(&[2, 2, 2], &[2, 1, 1], 4);
test_case(&[2, 2, 2], &[2, 1, 2], 4);
test_case(&[2, 2, 2], &[2, 2], 8);
test_case(&[2, 2, 2], &[2, 2, 1], 4);
test_case(&[2, 2, 2], &[2, 2, 2], 0);
}
#[test]
fn test_multivariable_resultant() {
let bi = |v: i64| BigInt::from(v);
let lhs: Polynomial<Polynomial<BigInt>> =
vec![bi(-2).into(), bi(0).into(), bi(1).into()].into();
let rhs: Polynomial<Polynomial<BigInt>> = vec![
vec![bi(-2), bi(0), bi(1)].into(),
vec![bi(0), bi(-2)].into(),
bi(1).into(),
]
.into();
let expected: Polynomial<BigInt> = vec![bi(0), bi(0), bi(-8), bi(0), bi(1)].into();
println!("lhs = {}", lhs);
println!("rhs = {}", rhs);
println!("expected = {}", expected);
let resultant = lhs.resultant(rhs);
println!("resultant = {}", resultant);
assert!(expected == resultant);
}
}