[GiNaC-list] [PATCH] gcd: avoid expanding large expressions
Sheplyakov Alexei
varg at theor.jinr.ru
Fri May 6 15:47:20 CEST 2005
Hello!
gcd(a, b, &ca, &cb) seems to [almost] always return gcd (and
co-factors) in expanded form. Program below demonstrates this:
/**
* gcd_demo.cpp Demonstrate bug/feature of GiNaC's gcd
*/
#include <iostream>
#include <ginac/ginac.h>
using namespace std;
using namespace GiNaC;
int main(int argc, char** argv)
{
symbol x("x");
symbol y("y");
ex ca, cb;
ex a = pow(pow(y,2)-pow(x,2), 10);
ex b = pow(pow(x,4)-pow(y,4), 12);
ex g = gcd(a, b, &ca, &cb, false);
cout << "----------------------------------------------------------" << endl;
cout << "a = " << a << endl;
cout << "b = " << b << endl;
cout << "GCD(a, b) = " << g << endl;
cout << "a co-factor = " << ca << endl;
cout << "b co-factor = " << cb << endl;
cout << "---------------------------------------------------------" << endl;
return 0;
}
The output of this program is
----------------------------------------------------------
a = (y^2-x^2)^10
b = (-y^4+x^4)^12
GCD(a, b) = -120*y^14*x^6+45*y^4*x^16-10*y^2*x^18+45*y^16*x^4-252*y^10*x^10+x^20+y^20+210*y^8*x^12-10*y^18*x^2-120*y^6*x^14+210*y^12*x^8
a co-factor = 1
b co-factor = 22*y^10*x^18+y^28+10*y^26*x^2+x^28+22*y^18*x^10+10*y^2*x^26-264*y^14*x^14+121*y^8*x^20-165*y^16*x^12+43*y^4*x^24+121*y^20*x^8+100*y^6*x^22-165*y^12*x^16+100*y^22*x^6+43*y^24*x^4
---------------------------------------------------------
Sometimes this [mis]feature causes .normal() to do a lot of unnecessary
job (in particular, if the expression consists of terms with denominators
like \prod(m_i^2-m_j^2)^n), so even with small expressions (about 500
terms) .normal() takes *really* long.
Attached patch fixes this behaviour, thus the program above will print
----------------------------------------------------------
a = (y^2-x^2)^10
b = (-y^4+x^4)^12
GCD(a, b) = (-y^2+x^2)^10
a co-factor = 1
b co-factor = (-y^2+x^2)^2*(y^2+x^2)^12
---------------------------------------------------------
--
Best regards,
Alexei
-------------- next part --------------
Index: normal.cpp
===================================================================
RCS file: /home/cvs/GiNaC/ginac/normal.cpp,v
retrieving revision 1.94.2.5
diff -r1.94.2.5 normal.cpp
1346a1347
> const ex& exp_a = a.op(1);
1348c1349,1351
< if (p.is_equal(b.op(0))) {
---
> ex pb = b.op(0);
> const ex& exp_b = b.op(1);
> if (p.is_equal(pb)) {
1350d1352
< ex exp_a = a.op(1), exp_b = b.op(1);
1364c1366,1391
< }
---
> } else {
> ex p_co, pb_co;
> ex p_gcd = gcd(p, pb, &p_co, &pb_co, check_args);
> if (p_gcd.is_equal(_ex1)) {
> // a(x) = p(x)^n, b(x) = p_b(x)^m, gcd (p, p_b) = 1 ==>
> // gcd(a,b) = 1
> if (ca)
> *ca = a;
> if (cb)
> *cb = b;
> return _ex1;
> // XXX: do I need to check for p_gcd = -1?
> } else {
> // there are common factors:
> // a(x) = g(x)^n A(x)^n, b(x) = g(x)^m B(x)^m ==>
> // gcd(a, b) = g(x)^n gcd(A(x)^n, g(x)^(n-m) B(x)^m
> if (exp_a < exp_b) {
> return power(p_gcd, exp_a)*
> gcd(power(p_co, exp_a), power(p_gcd, exp_b-exp_a)*power(pb_co, exp_b), ca, cb, false);
> } else {
> return power(p_gcd, exp_b)*
> gcd(power(p_gcd, exp_a - exp_b)*power(p_co, exp_a), power(pb_co, exp_b), ca, cb, false);
> }
> } // p_gcd.is_equal(_ex1)
> } // p.is_equal(pb)
>
1372a1400,1414
> }
>
> ex p_co, bpart_co;
> ex p_gcd = gcd(p, b, &p_co, &bpart_co, false);
>
> if (p_gcd.is_equal(_ex1)) {
> // a(x) = p(x)^n, gcd(p, b) = 1 ==> gcd(a, b) = 1
> if (ca)
> *ca = a;
> if (cb)
> *cb = b;
> return _ex1;
> } else {
> // a(x) = g(x)^n A(x)^n, b(x) = g(x) B(x) ==> gcd(a, b) = g(x) gcd(g(x)^(n-1) A(x)^n, B(x))
> return p_gcd*gcd(power(p_gcd, exp_a-1)*power(p_co, exp_a), bpart_co, ca, cb, false);
1374c1416,1417
< }
---
> } // is_exactly_a<power>(b)
>
1384a1428,1444
>
> ex p_co, apart_co;
> const ex& exp_b(b.op(1));
> ex p_gcd = gcd(a, p, &apart_co, &p_co, false);
> if (p_gcd.is_equal(_ex1)) {
> // b=p(x)^n, gcd(a, p) = 1 ==> gcd(a, b) == 1
> if (ca)
> *ca = a;
> if (cb)
> *cb = b;
> return _ex1;
> } else {
> // there are common factors:
> // a(x) = g(x) A(x), b(x) = g(x)^n B(x)^n ==> gcd = g(x) gcd(g(x)^(n-1) A(x)^n, B(x))
>
> return p_gcd*gcd(apart_co, power(p_gcd, exp_b-1)*power(p_co, exp_b), ca, cb, false);
> } // p_gcd.is_equal(_ex1)
-------------- next part --------------
A non-text attachment was scrubbed...
Name: not available
Type: application/pgp-signature
Size: 189 bytes
Desc: Digital signature
Url : http://www.cebix.net/pipermail/ginac-list/attachments/20050506/71cdb9de/attachment.pgp
More information about the GiNaC-list
mailing list