| Karim BELABAS on Tue, 19 Oct 1999 15:20:16 +0200 (MET DST) |
[Date Prev] [Date Next] [Thread Prev] [Thread Next] [Date Index] [Thread Index]
| Re: ellpointtoz() bug? |
> gp> E=ellinit([0,0,1,-1,0]);
> gp> for(n=-6,6,print(n" "ellpow(E,[0,0],n)" "ellpointtoz(E,ellpow(E,[0,0],n))))
[...]
> -1 [0, -1] 2.063865930946563955426810634 + 1.225694690993395030427112415*I
> 0 [0] 0
> 1 [0, 0] 2.063865930946563955426810634 + 1.225694690993395030427112415*I
[...] which is clearly nonsense. What happens is that ellpointtoz (zell
internally) often "mistakes" a point for its opposite [notice that
[0,0] = - [0,-1]].
In fact the y coordinate is not used at all in the main algorithm [ it used
to be in 1.39, but mistakenly, since it endeavoured to give a wrong answer
from times to times. A comment acknowledged this in the code. ]
The chosen "solution" (implemented in the function as it stood in 2.0.17) was
to compute the inverse function (ellztopoint = pointell internally) at the
lowest possible precision [in fact just \wp'(z)] and set z := -z if it didn't
give back the original point.
There are two problems with this:
1) it'd be much nicer to have a nice theoretical test [if you look at the
code, the ambiguity is due to a (complex) square root taken at the end.
Changing determination only involves periods, hence is OK, but I have no idea
how to choose the sign (I'm no expert on elliptic curves...)]
2) it doesn't generalize well. E.g ellztopoint is not implemented for p-adic
fields; as it stands, ellztopoint over Q_p will always yield the same value
when taken at P or -P !
There was a third problem but it was a bug in the implementation of my
test... This is corrected by the following patch [ which formally corrects
the behaviour in your example above ].
Cheers,
Karim.
P.S: I'd be very glad to have an expert opinion on this [ and even happier
with an actual patch ! ]
P.S2: the patch is too big, but the CVS version evolved quite a bit since the
2.0.17 release (I already deleted many irrelevant chunks).
Index: src/modules/elliptic.c
===================================================================
RCS file: /home/megrez/cvsroot/pari/src/modules/elliptic.c,v
retrieving revision 1.2
retrieving revision 1.10
diff -c -r1.2 -r1.10
***************
*** 778,784 ****
zell(GEN e, GEN z, long prec)
{
long av=avma,ty,sw,fl;
! GEN t,u,p1,p2,r1,a,b,x1,u2,D = (GEN)e[12];
checkbell(e);
if (!oncurve(e,z)) err(heller1);
--- 768,774 ----
zell(GEN e, GEN z, long prec)
{
long av=avma,ty,sw,fl;
! GEN t,u,p1,p2,a,b,x1,u2,D = (GEN)e[12];
checkbell(e);
if (!oncurve(e,z)) err(heller1);
***************
*** 799,848 ****
return gerepileupto(av,t);
}
! sw=gsigne(greal(b)); fl=0;
for(;;) /* agm */
{
! GEN a0=a, b0=b, x0=x1;
! b=gsqrt(gmul(a0,b0),prec);
if (gsigne(greal(b)) != sw) b = gneg_i(b);
! a=gmul2n(gadd(gadd(a0,b0),gmul2n(b,1)),-2);
! r1=gsub(a,b);
! p1=gsqrt(gdiv(gadd(x0,r1),x0),prec);
! x1=gmul(x0,gsqr(gmul2n(gaddsg(1,p1),-1)));
! if (gexpo(gsub(x1,x0)) < gexpo(x1) - bit_accuracy(prec) + 5)
{
if (fl) break;
fl = 1;
}
else fl = 0;
}
! u=gdiv(x1,a); t=gaddsg(1,u);
! if (gexpo(t) < 5 - bit_accuracy(prec))
t = negi(gun);
else
t = gdiv(u,gsqr(gaddsg(1,gsqrt(t,prec))));
! u=gsqrt(ginv(gmul2n(a,2)),prec);
! t=glog(t,prec); t=gmul(t,u);
/* which square root? test the reciprocal function (pointell) */
if (!gcmp0(t))
{
! GEN x1;
! long bad;
! u = pointell(e,t,3); /* we don't need much precision */
! /* Either z = u (ok: keep t), or z = invell(e,u) (bad: t <-- -t) */
! x1 = gsub(z,u); bad = (gexpo((GEN)x1[1]) >= gexpo((GEN)u[1])
! || gexpo((GEN)x1[2]) >= gexpo((GEN)u[2]));
if (bad) t = gneg(t);
if (DEBUGLEVEL)
{
if (DEBUGLEVEL>4)
{
fprintferr(" z = %Z\n",z);
! fprintferr(" u = %Z\n",u);
! fprintferr(" x1 = %Z\n",x1);
}
fprintferr("ellpointtoz: %s square root\n", bad? "bad": "good");
flusherr();
--- 789,839 ----
return gerepileupto(av,t);
}
! sw = gsigne(greal(b)); fl=0;
for(;;) /* agm */
{
! GEN a0=a, b0=b, x0=x1, r1;
! b = gsqrt(gmul(a0,b0),prec);
if (gsigne(greal(b)) != sw) b = gneg_i(b);
! a = gmul2n(gadd(gadd(a0,b0),gmul2n(b,1)),-2);
! r1 = gsub(a,b);
! p1 = gsqrt(gdiv(gadd(x0,r1),x0),prec);
! x1 = gmul(x0,gsqr(gmul2n(gaddsg(1,p1),-1)));
! r1 = gsub(x1,x0);
! if (gcmp0(r1) || gexpo(r1) < gexpo(x1) - bit_accuracy(prec) + 5)
{
if (fl) break;
fl = 1;
}
else fl = 0;
}
! u = gdiv(x1,a); t = gaddsg(1,u);
! if (gcmp0(t) || gexpo(t) < 5 - bit_accuracy(prec))
t = negi(gun);
else
t = gdiv(u,gsqr(gaddsg(1,gsqrt(t,prec))));
! u = gsqrt(ginv(gmul2n(a,2)),prec);
! t = gmul(u, glog(t,prec));
/* which square root? test the reciprocal function (pointell) */
if (!gcmp0(t))
{
! GEN z1,z2;
! int bad;
! z1 = pointell(e,t,3); /* we don't need much precision */
! /* Either z = z1 (ok: keep t), or z = z2 (bad: t <-- -t) */
! z2 = invell(e, z1);
! bad = (gexpo(gsub(z,z1)) > gexpo(gsub(z,z2)));
if (bad) t = gneg(t);
if (DEBUGLEVEL)
{
if (DEBUGLEVEL>4)
{
fprintferr(" z = %Z\n",z);
! fprintferr(" z1 = %Z\n",z1);
! fprintferr(" z2 = %Z\n",z2);
}
fprintferr("ellpointtoz: %s square root\n", bad? "bad": "good");
flusherr();
__
Karim Belabas email: Karim.Belabas@math.u-psud.fr
Dep. de Mathematiques, Bat. 425
Universite Paris-Sud Tel: (00 33) 1 69 15 57 48
F-91405 Orsay (France) Fax: (00 33) 1 69 15 60 19
--
PARI/GP Home Page: http://hasse.mathematik.tu-muenchen.de/ntsw/pari/