/*============================================================================= This file is part of FLINT. FLINT is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation; either version 2 of the License, or (at your option) any later version. FLINT is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with FLINT; if not, write to the Free Software Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA =============================================================================*/ /****************************************************************************** Copyright (C) 2013 Tom Bachmann ******************************************************************************/ #include #include #include #include "fmpz_polyxx.h" #include "nmod_polyxx.h" #include "flintxx/test/helpers.h" using namespace flint; void test_init() { fmpz_polyxx p(10); tassert(p.length() == 0); tassert(fmpz_polyxx::zero().is_zero()); tassert(fmpz_polyxx::one().is_one()); } void test_manipulation() { fmpz_polyxx p, q; tassert(p.get_coeff(5) == 0); p.set_coeff(5, 17); tassert(p.degree() == 5); q.set_coeff(5, 17u); p.set_coeff(0, fmpzxx(1)); q.coeff(0) = 1; tassert(p == q); tassert(p.lead() == 17); tassert(p.length() == 6); p.zero_coeffs(0, 6); tassert(p.is_zero() && !p.is_one() && !p.is_unit()); p.set_coeff(0, 1); tassert(p.is_one() && p.is_unit()); p.set_coeff(0, -1); tassert(p.is_unit()); const fmpz_polyxx pc = p; tassert(p.get_coeff(0) == pc.get_coeff(0)); tassert((p*q).coeff(0) == p.get_coeff(0)*q.get_coeff(0)); tassert((p*q).lead() == p.lead()*q.lead()); } void test_assignment() { fmpz_polyxx p, q; p = 1; tassert(p.is_one()); q = UWORD(0); tassert(q.is_zero()); tassert(p != q); p = q; tassert(p == q); p = "4 0 0 0 1"; q.set_coeff(3, 1); tassert(p == q); // TODO XXX this does not always fail? //assert_exception(p = "4 1 2"); assert_exception(p = "2 1 2"); } void test_conversion() { fmpz_polyxx p; p.set_coeff(3, 1); tassert(p.to_string() == "4 0 0 0 1"); tassert(p.pretty("x") == "x^3"); tassert(p == fmpz_polyxx("4 0 0 0 1")); } void test_arithmetic() { fmpz_polyxx p, q; p = 1; q = "4 0 0 0 1"; tassert((p + q).to_string() == "4 1 0 0 1"); tassert((p - q).to_string() == "4 1 0 0 -1"); tassert((-p).to_string() == "1 -1"); fmpzxx two(2); tassert(two * q == 2 * q && 2u * q == q * 2 && (two * q).to_string() == "4 0 0 0 2"); q *= 2; tassert(q / two == q / 2u && q / 2 == q / two && (q / two).to_string() == "4 0 0 0 1"); // q == "4 0 0 0 2" q.set_coeff(1, 17); // q == "4 0 17 0 2" tassert((q % fmpzxx(5)).to_string() == "4 0 2 0 2"); p = "3 1 0 1"; tassert((p*q).to_string() == "6 0 17 0 19 0 2"); tassert((p*q) / p == q); tassert(p + q % q == p); tassert(p(fmpzxx(1) + fmpzxx(1)) == 5); q = "3 0 0 1"; tassert(p(q).to_string() == "5 1 0 0 0 1"); } // Won't compile if the expression is not done using addmul template bool is_ternary(const T&) { return T::ev_traits_t::temp_rule_t::TERNARY_OP_MARKER + 1; } // test stuff which we should get automatically - addmul, references etc void test_extras() { // TODO addmul when we have it } ulong pow(ulong base, ulong exp) { ulong res = 1; while(exp-- > 0) res *= base; return base; } void test_functions() { // test swap fmpz_polyxx p, q; p = 1; q = 0; swap(p, q); tassert(p.is_zero() && q.is_one()); // p = 0, q = 1 fmpz_polyxx f, g, xp1; f = "4 2 0 0 1"; // f = x^3 + 2 g = "5 1 2 3 4 5"; xp1 = "2 1 1"; fmpzxx two(2); // test lazy functions tassert(reverse(q, 4).pretty("x") == "x^3"); tassert(mul_2exp(f, 3u) == f * 8); tassert(f == fdiv_2exp(mul_2exp(f, 3u), 3u)); tassert(tdiv(-f, two) == tdiv(-f, 2) && tdiv(-f, 2) == tdiv(-f, 2u) && tdiv(-f, two).to_string() == "4 -1 0 0 0"); tassert(f == divexact(2*f, two) && f == divexact(2*f, 2u) && f == divexact(2*f, 2)); tassert(-f == tdiv_2exp(-8*f - q, 3u)); tassert(smod(5*f, fmpzxx(3)).to_string() == "4 1 0 0 -1"); tassert(f == fmpz_polyxx::bit_unpack(bit_pack(f, 10u), 10u)); tassert(f == fmpz_polyxx::bit_unpack_unsigned(bit_pack(f, 10u), 10u)); tassert(mul_classical(f, g) == f*g); tassert(mul_karatsuba(f, g) == f*g); tassert(mul_SS(f, g) == f*g); tassert(mul_KS(f, g) == f*g); fmpz_polyxx res; res = f*g; res.truncate(3); tassert(mullow_classical(f, g, 3) == res); tassert(mullow_karatsuba_n(f, g, 3) == res); tassert(mullow_KS(f, g, 3) == res); tassert(mullow_SS(f, g, 3) == res); tassert(mullow(f, g, 3) == res); res = f*g; res.zero_coeffs(0, 5); tassert(mulhigh_classical(f, g, 5) == res); tassert(mulhigh_karatsuba_n(f, g, 6) == res); res = mulhigh_n(f, g, 5); res.zero_coeffs(0, 5); tassert(res == mulhigh_classical(f, g, 5)); tassert(mulmid_classical(g, f).to_string() == "2 9 12"); tassert(sqr(f) == f*f); tassert(sqr_KS(f) == f*f); tassert(sqr_karatsuba(f) == f*f); tassert(sqr_classical(f) == f*f); res = sqr(f);res.truncate(4); tassert(sqrlow(f, 4) == res); tassert(sqrlow_KS(f, 4) == res); tassert(sqrlow_karatsuba_n(f, 4) == res); tassert(sqrlow_classical(f, 4) == res); tassert(pow(f, 3u) == f*f*f); tassert(pow_multinomial(f, 3u) == f*f*f); tassert(pow_binexp(f, 3u) == f*f*f); tassert(pow_addchains(f, 3u) == f*f*f); res = pow(f, 10u); res.truncate(10); tassert(pow_trunc(f, 10u, 10) == res); fmpz_polyxx binomial; binomial = "2 1 2"; tassert(pow_binomial(binomial, 3u) == binomial*binomial*binomial); fmpz_polyxx x; x = "2 0 1"; tassert(shift_left(f, 5) == f*pow(x, 5u)); tassert(shift_right(shift_left(f, 5), 5) == f); tassert(height(g) == 5); tassert(twonorm(g) == 7); tassert(resultant(f, g) == 1797); tassert(gcd(f, g).is_one()); tassert(gcd_subresultant(f, g).is_one()); tassert(gcd_heuristic(f, g).is_one()); tassert(gcd_modular(f, g).is_one()); fmpz_polyxx r, s;fmpzxx number; res = 1797; ltupleref(number, r, s) = xgcd(f, g); tassert(r*f + s*g == res && number == 1797); r = 0; s = 0; number = 0; ltupleref(number, r, s) = xgcd_modular(f, g); tassert(r*f + s*g == res && number == 1797); tassert(lcm(f, g) == f*g); tassert(content(2*g) == 2); tassert(primitive_part(2*g) == g); tassert(div_basecase(f*g, g) == f); tassert(div_divconquer(f*g, g) == f); tassert(rem_basecase(f + g, g) == f); res = 1; tassert(div_root(f*(x - res), fmpzxx(1)) == f); tassert(inv_series(xp1, 5).to_string() == "5 1 -1 1 -1 1"); tassert(inv_series(xp1, 10) == inv_series_newton(xp1, 10)); tassert(derivative(xp1).is_one()); tassert((compose(xp1, f) - f).is_one()); tassert((compose_divconquer(xp1, f) - f).is_one()); tassert((compose_horner(xp1, f) - f).is_one()); tassert(evaluate(xp1, fmpzxx(1)) == 2); tassert(evaluate_horner(xp1, fmpzxx(1)) == 2); tassert(evaluate_divconquer(xp1, fmpzxx(1)) == 2); tassert(evaluate_mod(xp1, 1u, 10u) == 2); fmpz_vecxx xs(3), ys(3); xs[0] = 0; xs[1] = 1; xs[2] = 2; ys[0] = 1; ys[1] = 2; ys[2] = 3; tassert(evaluate(xp1, xs) == ys); tassert(f(xp1) == taylor_shift(f, fmpzxx(1))); tassert(f(xp1) == taylor_shift_horner(f, fmpzxx(1))); tassert(f(xp1) == taylor_shift_divconquer(f, fmpzxx(1))); fmpz_polyxx inner;inner = "3 0 -1 5"; res = g(inner); res.truncate(10); tassert(compose_series(g, inner, 10) == res); tassert(compose_series_horner(g, inner, 10) == res); tassert(compose_series_brent_kung(g, inner, 10) == res); res = "2 0 1"; tassert(compose_series(inner, revert_series(inner, 10), 10) == res); tassert(compose_series(inner, revert_series_lagrange(inner, 10), 10) == res); tassert(compose_series(inner, revert_series_lagrange_fast(inner, 10), 10) == res); tassert(compose_series(inner, revert_series_newton(inner, 10), 10) == res); tassert(sqrt(f*f) == f); tassert(sqrt_classical(f*f) == f); assert_exception(sqrt(f*f + xp1).evaluate()); assert_exception(sqrt_classical(f*f + xp1).evaluate()); res = "5 32 0 0 0 1"; tassert(bound_roots(res) >= 2); // test immediate functions p.set_coeff(3, 1); p.truncate(2); tassert(p.is_zero()); tassert(f.max_limbs() == 1); tassert(g.max_bits() == 3); r = 0; s = 0; ltupleref(r, s) = divrem(g, f); tassert(r*f + s == g); tassert(r.to_string() == "2 4 5"); r = 0; s = 0; ltupleref(r, s) = divrem_basecase(g, f); tassert(r*f + s == g); tassert(r.to_string() == "2 4 5"); r = 0; s = 0; ltupleref(r, s) = divrem_divconquer(g, f); tassert(r*f + s == g); tassert(r.to_string() == "2 4 5"); bool does_divide; ltupleref(does_divide, res) = divides(f*g, g); tassert(does_divide && res == f); tassert(div_series(f, xp1, 10) * xp1 % pow(x, 10u) == f); f *= 2; ulong d = 0; ltupleref(r, s, d) = pseudo_divrem(g, f); tassert(r*f + s == g*pow(2, d)); r = 0; r = 0; d = 0; ltupleref(r, s, d) = pseudo_divrem_basecase(g, f); tassert(r*f + s == g*pow(2, d)); r = 0; r = 0; d = 0; ltupleref(r, s, d) = pseudo_divrem_divconquer(g, f); tassert(r*f + s == g*pow(2, d)); tassert(pseudo_div(g, f).get<0>() == r); tassert(pseudo_rem(g, f).get<0>() == s); r = 0; r = 0; ltupleref(r, s) = pseudo_divrem_cohen(g, f); tassert(r*f + s == g*4); tassert(pseudo_rem_cohen(g, f).to_string() == "3 -28 -32 12"); f = "4 1 0 0 1"; slong r1, r2; f.signature(r1, r2); tassert(r1 == 1 && r2 == 1); // test static functions frandxx state; tassert(fmpz_polyxx::randtest(state, 4, 10).length() <= 4); tassert(fmpz_polyxx::randtest_unsigned(state, 4, 10).get_coeff(0) >= 0); tassert(fmpz_polyxx::randtest_not_zero(state, 4, 10).is_zero() == false); tassert(fmpz_polyxx::interpolate(xs, ys) == xp1); xs[0] = 0;xs[1] = -1; xs[2] = -1; tassert(fmpz_polyxx::product_roots(xs) == x*xp1*xp1); } void test_member_functions() { // just a sample, since they all come from macros fmpz_polyxx f, g; f = "4 2 0 0 1"; g = "5 1 2 3 4 5"; tassert(f.bit_pack(17u) == bit_pack(f, 17u)); tassert(f.divrem(g) == divrem(f, g)); tassert(f.derivative() == derivative(f)); tassert(f.bound_roots() == bound_roots(f)); tassert(f.content() == content(f)); tassert(f.pow_trunc(15u, 10) == pow_trunc(f, 15u, 10)); } void test_factoring() { fmpz_polyxx f, g; // two irreducible polynomials f = "4 1 17 0 1"; g = "6 2 0 2 0 0 1"; // TODO are these deterministic? fmpz_poly_factorxx f1, f2; f1.insert(f, 1); f2.insert(g, 2); f1.content() = 7; f1.concat(f2); tassert(f1 == factor_zassenhaus(7*f*g*g)); f1.realloc(0); f1.insert(f, 1); f1.insert(g, 2); f1.content() = 1; tassert(f1 == factor_squarefree(f*g*g)); // TODO test set_factor_zassenhaus_recombination if(0) print(f1); // make sure this compiles } void test_hensel() { mp_limb_t pl = 1031; frandxx state; nmod_polyxx gl(nmod_polyxx::randtest_irreducible(pl, state, 5).make_monic()); nmod_polyxx hl(nmod_polyxx::randtest_irreducible(pl, state, 6).make_monic()); while(gl.length() != 5) gl = nmod_polyxx::randtest_irreducible(pl, state, 5).make_monic(); while(hl.length() != 5) hl = nmod_polyxx::randtest_irreducible(pl, state, 5).make_monic(); nmod_polyxx al(pl), bl(pl); ltupleref(_, al, bl) = xgcd(gl, hl); tassert((al*gl + bl*hl).is_one()); fmpz_polyxx f = fmpz_polyxx::lift(gl*hl); fmpz_polyxx g = fmpz_polyxx::lift(gl); fmpz_polyxx h = fmpz_polyxx::lift(hl); fmpz_polyxx a = fmpz_polyxx::lift(al); fmpz_polyxx b = fmpz_polyxx::lift(bl); fmpz_polyxx G, H, A, B; fmpzxx p(pl), p1(1031); tassert(((f - g*h) % p).is_zero()); //ltupleref(G, H, A, B) = hensel_lift(f, g, h, a, b, p, p1); fmpz_poly_hensel_lift(G._poly(), H._poly(), A._poly(), B._poly(), f._poly(), g._poly(), h._poly(), a._poly(), b._poly(), p._fmpz(), p1._fmpz()); tassert(((f - G*H) % (p1*p)).is_zero()); tassert(((A*G + B*H) % (p1*p)).is_one()); tassert(ltupleref(G, H) == hensel_lift_without_inverse(f, g, h, a, b, p, p1)); tassert(ltupleref(A, B) == hensel_lift_only_inverse(G, H, a, b, p, p1)); nmod_poly_factorxx local_fac = factor(gl*hl); fmpz_poly_factorxx lifted_fac = hensel_lift_once(f, local_fac, 3); tassert(lifted_fac.size() == 2 && lifted_fac.exp(0) == 1 && lifted_fac.exp(1) == 1); tassert(((lifted_fac.p(0)*lifted_fac.p(1) - f) % p.pow(3u)).is_zero()); } void test_printing() { frandxx state; fmpz_polyxx f = fmpz_polyxx::randtest(state, 4, 10); test_print_read(f); test_print_read_pretty(f); } void test_unified_access() { fmpz_polyxx a = fmpz_polyxx::from_ground(1); const fmpz_polyxx& b = a; tassert(b.lead() == 1 && b.coeff(0) == 1); } int main() { std::cout << "fmpz_polyxx...."; test_init(); test_manipulation(); test_assignment(); test_conversion(); test_arithmetic(); test_functions(); test_member_functions(); test_extras(); test_factoring(); test_hensel(); test_printing(); test_unified_access(); std::cout << "PASS" << std::endl; return 0; }