[GiNaC-devel] [PATCH 4/4] [BUGFIX] pgcd(), chinrem_gcd(): use appropriate definition of the degree.
Alexei Sheplyakov
alexei.sheplyakov at gmail.com
Mon May 17 08:16:42 CEST 2010
Effect: fixes (rare) GCD miscalculation.
pgcd() treats polynomials Z_p[x_0, ..., x_n] as R[x_0, ..., x_{n - 1}], where
R = Z_p[x_n]. Therefore one should use correct definition of the degree
(i.e. compute it w.r.t. x_0, ..., x_{n-1}, but NOT w.r.t. x_n!).
One should use appropriate definition of degree (that is, w.r.t. x_0, ..., x_n)
in chinrem_gcd() too.
Thanks to Aless Lasaruk for a bug report.
---
check/pgcd_infinite_loop.cpp | 8 ++++++--
ginac/polynomial/mgcd.cpp | 12 ++++++++----
ginac/polynomial/pgcd.cpp | 10 ++++++----
3 files changed, 20 insertions(+), 10 deletions(-)
diff --git a/check/pgcd_infinite_loop.cpp b/check/pgcd_infinite_loop.cpp
index 013b746..ae39f1d 100644
--- a/check/pgcd_infinite_loop.cpp
+++ b/check/pgcd_infinite_loop.cpp
@@ -26,12 +26,16 @@ static const string srep("\
int main(int argc, char** argv)
{
- cout << "Checking for more pgcd() bugs (infinite loop) ... " << flush;
+ cout << "Checking for more pgcd() bugs (infinite loop, miscalculation) ... " << flush;
parser the_parser;
ex e = the_parser(srep);
const symbol x = ex_to<symbol>(the_parser.get_syms()["x"]);
ex g = gcd(e, e.diff(x));
+ ex should_be = the_parser(string("u^4*z^2"));
+ if (!(g-should_be).expand().is_zero()) {
+ cout << "GCD was miscomputed. " << flush;
+ return 1;
+ }
cout << "not found. " << flush;
- cout << g << endl << flush;
return 0;
}
diff --git a/ginac/polynomial/mgcd.cpp b/ginac/polynomial/mgcd.cpp
index bf30b5c..24da934 100644
--- a/ginac/polynomial/mgcd.cpp
+++ b/ginac/polynomial/mgcd.cpp
@@ -27,6 +27,7 @@
#include "primes_factory.h"
#include "divide_in_z_p.h"
#include "poly_cra.h"
+#include <numeric> // std::accumulate
#include <cln/integer.h>
@@ -58,12 +59,15 @@ ex chinrem_gcd(const ex& A_, const ex& B_, const exvector& vars)
const cln::cl_I g_lc = cln::gcd(a_lc, b_lc);
const ex& x(vars.back());
- int n = std::min(A.degree(x), B.degree(x));
+ exp_vector_t n = std::min(degree_vector(A, vars), degree_vector(B, vars));
+ const int nTot = std::accumulate(n.begin(), n.end(), 0);
const cln::cl_I A_max_coeff = to_cl_I(A.max_coefficient());
const cln::cl_I B_max_coeff = to_cl_I(B.max_coefficient());
- const cln::cl_I lcoeff_limit = (cln::cl_I(1) << n)*cln::abs(g_lc)*
+
+ const cln::cl_I lcoeff_limit = (cln::cl_I(1) << nTot)*cln::abs(g_lc)*
std::min(A_max_coeff, B_max_coeff);
+
cln::cl_I q = 0;
ex H = 0;
@@ -83,8 +87,8 @@ ex chinrem_gcd(const ex& A_, const ex& B_, const exvector& vars)
const cln::cl_I Cp_lc = integer_lcoeff(Cp, vars);
const cln::cl_I nlc = smod(recip(Cp_lc, p)*g_lcp, p);
Cp = (Cp*numeric(nlc)).expand().smod(pnum);
- int cp_deg = Cp.degree(x);
- if (cp_deg == 0)
+ exp_vector_t cp_deg = degree_vector(Cp, vars);
+ if (zerop(cp_deg))
return numeric(g_lc);
if (zerop(q)) {
H = Cp;
diff --git a/ginac/polynomial/pgcd.cpp b/ginac/polynomial/pgcd.cpp
index fac3735..a33b02d 100644
--- a/ginac/polynomial/pgcd.cpp
+++ b/ginac/polynomial/pgcd.cpp
@@ -80,7 +80,8 @@ ex pgcd(const ex& A, const ex& B, const exvector& vars, const long p)
const ex lc_gcd = euclid_gcd(AL, BL, mainvar, p);
// The estimate of degree of the gcd of Ab and Bb
- int gcd_deg = std::min(degree(Aprim, mainvar), degree(Bprim, mainvar));
+ exp_vector_t gcd_deg = std::min(degree_vector(Aprim, restvars),
+ degree_vector(Bprim, restvars));
eval_point_finder::value_type b;
eval_point_finder find_eval_point(p);
@@ -105,8 +106,11 @@ ex pgcd(const ex& A, const ex& B, const exvector& vars, const long p)
const cln::cl_I correct_lc = smod(lcb_gcd*recip(Cblc, p), p);
Cb = (Cb*numeric(correct_lc)).smod(pn);
+ const exp_vector_t img_gcd_deg = degree_vector(Cb, restvars);
+ // Test for relatively prime polynomials
+ if (zerop(img_gcd_deg))
+ return cont_gcd;
// Test for unlucky homomorphisms
- const int img_gcd_deg = Cb.degree(restvars.back());
if (img_gcd_deg < gcd_deg) {
// The degree decreased, previous homomorphisms were
// bad, so we have to start it all over.
@@ -121,8 +125,6 @@ ex pgcd(const ex& A, const ex& B, const exvector& vars, const long p)
// evaluation point is bad. Skip it.
continue;
}
- if (img_gcd_deg == 0)
- return cont_gcd;
// Image has the same degree as the previous one
// (or at least not higher than the limit)
--
1.7.1
More information about the GiNaC-devel
mailing list