493 lines
14 KiB
C++
493 lines
14 KiB
C++
/*=============================================================================
|
|
|
|
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 <iostream>
|
|
#include <sstream>
|
|
#include <string>
|
|
|
|
#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<class T>
|
|
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;
|
|
}
|
|
|