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/