// Copyright © 2024 Mikhail Hogrefe
//
// This file is part of Malachite.
//
// Malachite is free software: you can redistribute it and/or modify it under the terms of the GNU
// Lesser General Public License (LGPL) as published by the Free Software Foundation; either version
// 3 of the License, or (at your option) any later version. See .
use malachite_base::num::arithmetic::kronecker_symbol::{
jacobi_symbol_unsigned_double_fast_2, jacobi_symbol_unsigned_simple,
};
use malachite_base::num::arithmetic::traits::{ModPowerOf2, UnsignedAbs};
use malachite_base::num::basic::integers::PrimitiveInt;
use malachite_base::num::basic::signeds::PrimitiveSigned;
use malachite_base::num::basic::unsigneds::PrimitiveUnsigned;
use malachite_base::num::comparison::traits::PartialOrdAbs;
use malachite_base::num::conversion::traits::{HasHalf, JoinHalves, WrappingFrom};
use malachite_base::test_util::generators::{
signed_gen, signed_gen_var_13, signed_pair_gen, signed_pair_gen_var_10, signed_pair_gen_var_8,
signed_pair_gen_var_9, signed_triple_gen, signed_triple_gen_var_6, signed_triple_gen_var_7,
unsigned_gen, unsigned_gen_var_22, unsigned_pair_gen_var_27, unsigned_pair_gen_var_40,
unsigned_pair_gen_var_41, unsigned_pair_gen_var_42, unsigned_quadruple_gen_var_12,
unsigned_triple_gen_var_19, unsigned_triple_gen_var_22, unsigned_triple_gen_var_23,
};
use malachite_base::test_util::num::arithmetic::kronecker_symbol::{
jacobi_symbol_unsigned_double_fast_1, jacobi_symbol_unsigned_double_simple,
jacobi_symbol_unsigned_fast_1, jacobi_symbol_unsigned_fast_2_1,
jacobi_symbol_unsigned_fast_2_2, jacobi_symbol_unsigned_fast_2_3,
jacobi_symbol_unsigned_fast_2_4,
};
use std::panic::catch_unwind;
#[test]
fn test_jacobi_symbol() {
fn test_u(a: T, n: T, s: i8) {
assert_eq!(a.legendre_symbol(n), s);
assert_eq!(a.jacobi_symbol(n), s);
assert_eq!(a.kronecker_symbol(n), s);
assert_eq!(jacobi_symbol_unsigned_simple(a, n), s);
assert_eq!(jacobi_symbol_unsigned_fast_1(a, n), s);
assert_eq!(jacobi_symbol_unsigned_fast_2_1(a, n), s);
assert_eq!(jacobi_symbol_unsigned_fast_2_2(a, n), s);
assert_eq!(jacobi_symbol_unsigned_fast_2_3(a, n), s);
assert_eq!(jacobi_symbol_unsigned_fast_2_4(a, n), s);
}
test_u::(0, 1, 1);
test_u::(0, 3, 0);
test_u::(1, 3, 1);
test_u::(2, 3, -1);
test_u::(0, 5, 0);
test_u::(1, 5, 1);
test_u::(2, 5, -1);
test_u::(3, 5, -1);
test_u::(4, 5, 1);
test_u::(0, 7, 0);
test_u::(1, 7, 1);
test_u::(2, 7, 1);
test_u::(3, 7, -1);
test_u::(4, 7, 1);
test_u::(5, 7, -1);
test_u::(6, 7, -1);
test_u::(0, 9, 0);
test_u::(1, 9, 1);
test_u::(2, 9, 1);
test_u::(3, 9, 0);
test_u::(4, 9, 1);
test_u::(5, 9, 1);
test_u::(6, 9, 0);
test_u::(7, 9, 1);
test_u::(8, 9, 1);
test_u::(7, 7, 0);
test_u::(8, 7, 1);
test_u::(9, 7, 1);
test_u::(10, 7, -1);
test_u::(11, 7, 1);
test_u::(12, 7, -1);
test_u::(13, 7, -1);
test_u::(9, 9, 0);
test_u::(10, 9, 1);
test_u::(11, 9, 1);
test_u::(12, 9, 0);
test_u::(13, 9, 1);
test_u::(14, 9, 1);
test_u::(15, 9, 0);
test_u::(16, 9, 1);
test_u::(17, 9, 1);
test_u::(1001, 9907, -1);
test_u::(10908, 9907, -1);
fn test_s + PrimitiveSigned>(
a: S,
n: S,
s: i8,
) {
assert_eq!(a.legendre_symbol(n), s);
assert_eq!(a.jacobi_symbol(n), s);
assert_eq!(a.kronecker_symbol(n), s);
}
test_s::(0, 1, 1);
test_s::(0, 3, 0);
test_s::(1, 3, 1);
test_s::(2, 3, -1);
test_s::(0, 5, 0);
test_s::(1, 5, 1);
test_s::(2, 5, -1);
test_s::(3, 5, -1);
test_s::(4, 5, 1);
test_s::(0, 7, 0);
test_s::(1, 7, 1);
test_s::(2, 7, 1);
test_s::(3, 7, -1);
test_s::(4, 7, 1);
test_s::(5, 7, -1);
test_s::(6, 7, -1);
test_s::(0, 9, 0);
test_s::(1, 9, 1);
test_s::(2, 9, 1);
test_s::(3, 9, 0);
test_s::(4, 9, 1);
test_s::(5, 9, 1);
test_s::(6, 9, 0);
test_s::(7, 9, 1);
test_s::(8, 9, 1);
test_s::(7, 7, 0);
test_s::(8, 7, 1);
test_s::(9, 7, 1);
test_s::(10, 7, -1);
test_s::(11, 7, 1);
test_s::(12, 7, -1);
test_s::(13, 7, -1);
test_s::(9, 9, 0);
test_s::(10, 9, 1);
test_s::(11, 9, 1);
test_s::(12, 9, 0);
test_s::(13, 9, 1);
test_s::(14, 9, 1);
test_s::(15, 9, 0);
test_s::(16, 9, 1);
test_s::(17, 9, 1);
test_s::(-7, 7, 0);
test_s::(-6, 7, 1);
test_s::(-5, 7, 1);
test_s::(-4, 7, -1);
test_s::(-3, 7, 1);
test_s::(-2, 7, -1);
test_s::(-1, 7, -1);
test_s::(-9, 9, 0);
test_s::(-8, 9, 1);
test_s::(-7, 9, 1);
test_s::(-6, 9, 0);
test_s::(-5, 9, 1);
test_s::(-4, 9, 1);
test_s::(-3, 9, 0);
test_s::(-2, 9, 1);
test_s::(-1, 9, 1);
test_s::(1001, 9907, -1);
test_s::(10908, 9907, -1);
test_s::(-8906, 9907, -1);
}
fn jacobi_symbol_fail_helper() {
assert_panic!(T::ONE.jacobi_symbol(T::TWO));
}
fn jacobi_symbol_fail_helper_signed() {
assert_panic!(T::ONE.jacobi_symbol(T::NEGATIVE_ONE));
}
#[test]
fn jacobi_symbol_fail() {
apply_fn_to_primitive_ints!(jacobi_symbol_fail_helper);
apply_fn_to_signeds!(jacobi_symbol_fail_helper_signed);
}
#[test]
fn test_jacobi_symbol_unsigned_double() {
fn test + JoinHalves + PrimitiveUnsigned>(
x_1: T,
x_0: T,
y_1: T,
y_0: T,
s: i8,
) {
assert_eq!(
jacobi_symbol_unsigned_double_simple::(x_1, x_0, y_1, y_0),
s
);
assert_eq!(jacobi_symbol_unsigned_double_fast_1(x_1, x_0, y_1, y_0), s);
assert_eq!(jacobi_symbol_unsigned_double_fast_2(x_1, x_0, y_1, y_0), s);
}
// - fast_1: y_1 == T::ZERO || y_0 == T::ZERO first time
// - fast_2: y_1 == T::ZERO && y_0 == T::ONE
test::(0, 0, 0, 1, 1);
// - fast_1: y_1 != T::ZERO && y_0 != T::ZERO first time
// - fast_1: x_1 != T::ZERO && x_0 != T::ZERO
// - fast_1: x_0 != T::ZERO first time
// - fast_1: c != T::WIDTH first time
// - fast_1: diff_0 != T::ZERO && diff_1 != T::ZERO
// - fast_1: diff_1.get_highest_bit()
// - fast_1: y_1 != T::ZERO && y_0 != T::ZERO second time
// - fast_1: x_0 == T::ZERO second time
// - fast_1: c != T::WIDTH second time
// - fast_1: bit.even()
// - fast_2: y_1 != T::ZERO || y_0 != T::ONE
// - fast_2: x_0 != T::ZERO first time
// - fast_2: x_0.odd()
// - fast_2: x_1 == T::ZERO second time
// - fast_2: y_1 != T::ZERO
// - fast_2: skip_loop
// - fast_2: y_0 != T::ONE second time
// - fast_2: x_0 == T::ZERO fourth time
// - fast_2: x_1 != T::ZERO fourth time
// - fast_2: !bit.get_bit(1)
test::(0, 3, 2, 3, 1);
// - fast_1: x_1 == T::ZERO || x_0 == T::ZERO
// - fast_2: x_0 == T::ZERO first time
// - fast_2: x_1 == T::ZERO first time
test::(0, 0, 0, 3, 0);
// - fast_1: t != T::ZERO
// - fast_1: c == T::WIDTH third time
// - fast_2: y_0 == T::ONE second time
test::(0, 1, 1, 1, 1);
// - fast_1: c != T::WIDTH third time
test::(0, 1, 1, 3, 1);
// - fast_1: x_0 == T::ZERO first time
// - fast_2: x_1 != T::ZERO first time
// - fast_2: y_0 == T::ONE first time
test::(1, 0, 0, 3, 1);
// - fast_1: bit.odd()
// - fast_2: x_1 != T::ZERO second time
// - fast_2: !skip_loop
// - fast_2: x_0 != T::ZERO fourth time
// - fast_2: bit.get_bit(1)
test::(1, 1, 0, 3, -1);
// - fast_1: t == T::ZERO
// - fast_2: x_1 == y_1 first time
// - fast_2: x_1 == y_1 second time
// - fast_2: x_0 >= y_0
// - fast_2: x_0 == T::ZERO third time
test::(1, 1, 1, 1, 0);
// - fast_1: y_1 == T::ZERO || y_0 == T::ZERO second time
test::(0, 1, 2, 1, 1);
// - fast_1: x_0 != T::ZERO second time
// - fast_1: c == T::WIDTH second time
// - fast_2: x_1 != y_1 first time
// - fast_2: x_1 != T::ZERO third time
// - fast_2: y_0 == T::ZERO
test::(1, 1, 2, 1, 1);
// - fast_1: !diff_1.get_highest_bit()
test::(2, 1, 0, 3, 0);
// - fast_1: diff_0 == T::ZERO || diff_1 == T::ZERO
test::(2, 1, 2, 1, 0);
// - fast_1: c == T::WIDTH first time
// - fast_2: x_0.even()
// - fast_2: y_0 != T::ZERO
test::(242, 128, 173, 173, -1);
// - fast_2: y_1 == T::ZERO
test::(0, 1, 0, 3, 1);
// - fast_2: x_0 < y_0
// - fast_2: x_0 != T::ZERO third time
// - fast_2: x_0 == T::ONE
test::(1, 1, 1, 3, 1);
// - fast_2: x_0 != T::ONE
test::(1, 1, 1, 7, -1);
// - fast_2: x_1 != y_1 second time
test::(1, 1, 2, 3, 1);
// - fast_2: x_0 == T::ZERO second time
test::(2, 1, 1, 1, 1);
// - fast_2: x_0 != T::ZERO second time
// - fast_2: x_1 == T::ZERO third time
test::(2, 1, 1, 3, -1);
// - fast_2: y_0 != T::ONE first time
test::(3, 0, 0, 3, 0);
}
// Odd n is already tested in test_jacobi_symbol, so here we just test even n
#[test]
fn test_kronecker_symbol() {
fn test_u(a: T, n: T, s: i8) {
assert_eq!(a.kronecker_symbol(n), s);
}
test_u::(0, 2, 0);
test_u::(1, 2, 1);
test_u::(2, 2, 0);
test_u::(3, 2, -1);
test_u::(4, 2, 0);
test_u::(5, 2, -1);
test_u::(6, 2, 0);
test_u::(7, 2, 1);
test_u::(0, 4, 0);
test_u::(1, 4, 1);
test_u::(2, 4, 0);
test_u::(3, 4, 1);
test_u::(0, 6, 0);
test_u::(1, 6, 1);
test_u::(2, 6, 0);
test_u::(3, 6, 0);
test_u::(4, 6, 0);
test_u::(5, 6, 1);
test_u::(6, 6, 0);
test_u::(7, 6, 1);
test_u::(8, 6, 0);
test_u::(9, 6, 0);
test_u::(10, 6, 0);
test_u::(11, 6, 1);
test_u::(12, 6, 0);
test_u::(13, 6, -1);
test_u::(14, 6, 0);
test_u::(15, 6, 0);
test_u::(16, 6, 0);
test_u::(17, 6, -1);
test_u::(18, 6, 0);
test_u::(19, 6, -1);
test_u::(20, 6, 0);
test_u::(21, 6, 0);
test_u::(22, 6, 0);
test_u::(23, 6, -1);
test_u::(1001, 9908, -1);
test_u::(10909, 9908, -1);
fn test_s + PrimitiveSigned>(
a: S,
n: S,
s: i8,
) {
assert_eq!(a.kronecker_symbol(n), s);
}
test_s::(0, 2, 0);
test_s::(1, 2, 1);
test_s::(2, 2, 0);
test_s::(3, 2, -1);
test_s::(4, 2, 0);
test_s::(5, 2, -1);
test_s::(6, 2, 0);
test_s::(7, 2, 1);
test_s::(0, 4, 0);
test_s::(1, 4, 1);
test_s::(2, 4, 0);
test_s::(3, 4, 1);
test_s::(0, 6, 0);
test_s::(1, 6, 1);
test_s::(2, 6, 0);
test_s::(3, 6, 0);
test_s::(4, 6, 0);
test_s::(5, 6, 1);
test_s::(6, 6, 0);
test_s::(7, 6, 1);
test_s::(8, 6, 0);
test_s::(9, 6, 0);
test_s::(10, 6, 0);
test_s::(11, 6, 1);
test_s::(12, 6, 0);
test_s::(13, 6, -1);
test_s::(14, 6, 0);
test_s::(15, 6, 0);
test_s::(16, 6, 0);
test_s::(17, 6, -1);
test_s::(18, 6, 0);
test_s::(19, 6, -1);
test_s::(20, 6, 0);
test_s::(21, 6, 0);
test_s::(22, 6, 0);
test_s::(23, 6, -1);
test_s::(-1, 2, 1);
test_s::(-2, 2, 0);
test_s::(-3, 2, -1);
test_s::(-4, 2, 0);
test_s::(-5, 2, -1);
test_s::(-6, 2, 0);
test_s::(-7, 2, 1);
test_s::(-1, 4, 1);
test_s::(-2, 4, 0);
test_s::(-3, 4, 1);
test_s::(-1, 6, -1);
test_s::(-2, 6, 0);
test_s::(-3, 6, 0);
test_s::(-4, 6, 0);
test_s::(-5, 6, -1);
test_s::(-6, 6, 0);
test_s::(-7, 6, -1);
test_s::(-8, 6, 0);
test_s::(-9, 6, 0);
test_s::(-10, 6, 0);
test_s::(-11, 6, -1);
test_s::(-12, 6, 0);
test_s::(-13, 6, 1);
test_s::(-14, 6, 0);
test_s::(-15, 6, 0);
test_s::(-16, 6, 0);
test_s::(-17, 6, 1);
test_s::(-18, 6, 0);
test_s::(-19, 6, 1);
test_s::(-20, 6, 0);
test_s::(-21, 6, 0);
test_s::(-22, 6, 0);
test_s::(-23, 6, 1);
test_s::(0, -2, 0);
test_s::(1, -2, 1);
test_s::(2, -2, 0);
test_s::(3, -2, -1);
test_s::(4, -2, 0);
test_s::(5, -2, -1);
test_s::(6, -2, 0);
test_s::(7, -2, 1);
test_s::(0, -4, 0);
test_s::(1, -4, 1);
test_s::(2, -4, 0);
test_s::(3, -4, 1);
test_s::(0, -6, 0);
test_s::(1, -6, 1);
test_s::(2, -6, 0);
test_s::(3, -6, 0);
test_s::