一些理论

椭圆曲线的定义

形如 \(y^2+a_1xy+a_3y=x^3+a_2x^2+a_4x+a_6\) 的三次曲线叫做椭圆曲线。许多椭圆曲线都有唯一对应的 \(a,b\) 满足 \(y^2=x^3+ax+b\)接下来不做特殊说明的椭圆曲线默认为定义在 \(\mathbb Q\) 上的,且形式为 \(y^2=x^3+ax+b\)

椭圆曲线上的点是可以做加法和数乘的。两个点的和 和 过它们的直线经过椭圆曲线的第三个点关于 \(x\) 轴对称。对自己加法就是数乘,此时这条直线变为过它的椭圆曲线的切线。

定义无穷远点 \(O\),加法规则为 \(P+O=P,P+(-P)=O\)\(-P\) 就是 \(P\)\(x\) 轴对称。

椭圆曲线的秩(rank)定义为曲线上能够给出全体有理点的、线性无关的基。

它的 conductor 是一个重要标识,并且一定是判别式 \(-16(4a^3+27b^2)\) 的因子。

\(P=(x,y)\) 的高度(Neron-Tate height)是一个接近 \(\ln\max(|x(P)_{num}|,|x(P)_{den}|)\) 的值。它的定义是 \(h(P)=\lim_{n\rightarrow+\infty}\frac{\ln\max(|x(nP)_{num}|,|x(nP)_{den}|)}{n^2}\)。这是因为将 \(P\) 自乘大致会让 \(x\) 的分母和分子的位数乘上 \(4\)

同构(isogeny)是对于相同 conductor 的曲线之间的一种双射。

挠群(torsion group)是一些点的集合,这些点的高度均为 \(0\),并且存在一个正整数,使得它数乘上这些点会得到无穷远点。这个集合通常写作 \(E(\mathbb Q)_{\text{tors}}\)。有定理表明挠群的大小只有有限中可能。同构一定是基于挠群的点构造的。

Mordell-Weil 定理表明

\[E(\mathbb Q)\cong E(\mathbb Q)_{\text{tors}}\times\mathbb Z^{\text{rank}(E)} \]

Siegel 定理表明一个椭圆曲线上的整数点个数是有限的。

有一个数据库把所有 conductor \(<5\times10^5\) 的曲线全部收集了。这里展示了所有曲线的 conductor、同构、整数点等等信息。

一些常见三次问题

例 1.

找到所有相邻的三个正整数,使得他们的积可以被表示为两个相邻正整数的积。

Solution.

显然对应的曲线是 \(y^2+y=x^3-x\),数据库标识为 37a1,有生成元 \((0,0)\) 和平凡挠群。从这个点可以生成的正整数点仅有 \((2,2),(6,14)\)。因此唯一答案为 \(1\times2\times3=2\times3\)\(6\times7\times8=14\times15\)

例 2.

找到一个三边长均为有理数的直角三角形,使得其面积为 \(6\)

Solution.

为了日后方便,我们设这个三角形的面积为 \(n\)(此处 \(n=6\))。

设三边长分别为 \(a,b,c\)。于是 \(ab=2n,a^2+b^2=c^2\)

考虑 \((a+b)^2\)\((a-b)^2\),它们满足 \((a+b)^2=c^2+4n,(a-b)^2=c^2-4n\),并且两者均为有理数的平方。

现在假设 \(d=c(a+b)(a-b)\)。我们有 \(d^2=c^2(c^2+4n)(c^2-4n)\)。做换元 \(x=\frac{c^2}4,y=\frac d8\),我们得到 \(y^2=x^3-n^2x\)

这是一条椭圆曲线。在 \(n=6\) 的情况下找到一个生成元,并且倍增后找到解。

my_sqrt(n)=return(sqrtint(numerator(n))/sqrtint(denominator(n)));
getres(poi)=hyp=my_sqrt(poi[1])*2;n=sqrtint(poi[1]^2-poi[2]^2/poi[1]);if(hyp==0,return([0,0,0]));apb=hyp^2+4*n;amb=hyp^2-4*n;apb=my_sqrt(apb);amb=my_sqrt(amb);return([(apb+amb)/2,(apb-amb)/2,hyp]);
descend(E,limit)=covers=ell2cover(E);[hyperell,trans]=covers[#covers];poi=hyperellratpoints(hyperell,limit,1);if(poi==[],return([]));[x,y]=poi[1];return([eval(trans)]);
check_double_point_worker(n,dbl_P)=[dbl_x,dbl_y]=dbl_P;denom=denominator(dbl_x);localprec(log(denom)/log(10)+10);rot=polroots((x^4+2*n^2*x^2+n^4)-dbl_x*(4*x^3-4*n^2*x));\
for(i=1,#rot,if(abs(imag(rot[i]))<0.1,orig_x=round(real(rot[i])*denom)/denom;y=orig_x^3-n^2*orig_x;if(issquare(y),return([orig_x,my_sqrt(y)]))));return([]);
check_double_point(n,dbl_P)=E=ellinit([-n^2,0]);ans=check_double_point_worker(n,dbl_P);if(ans!=[],return(ans));dbl_P=elladd(E,dbl_P,[n,0]);\
ans=check_double_point_worker(n,dbl_P);if(ans!=[],return(ans));dbl_P=elladd(E,dbl_P,[-n,0]);ans=check_double_point_worker(n,dbl_P);if(ans!=[],return(ans),return(dbl_P));
try_isogeny_0(n)=F=ellinit([4*n^2,0]);gens=descend(F,5*10^5);if(gens==[],return([]));for(i=1,#gens,gens[i]=ellmul(F,gens[i],2);\
denom=denominator(gens[i][1]);localprec(log(denom)/log(10)+10);kill(x);gens[i][1]=round(real(polroots(x^2-n^2-gens[i][1]*x)[1])*denom)/denom;\
gens[i][2]=my_sqrt(gens[i][1]^3-n^2*gens[i][1]);gens[i]=check_double_point(n,gens[i]));return(gens);
try_isogeny_n(n)=F=ellinit([-11*n^2,-14*n^3]);gens=descend(F,5*10^5);if(gens==[],return([]));for(i=1,#gens,gens[i]=ellmul(F,gens[i],2);\
denom=denominator(gens[i][1]);localprec(log(denom)/log(10)+10);kill(x);gens[i][1]=round(real(polroots(x^2-n*x+2*n^2-gens[i][1]*(x-n))[1])*denom)/denom;\
gens[i][2]=my_sqrt(gens[i][1]^3-n^2*gens[i][1]);gens[i]=check_double_point(n,gens[i]));return(gens);
try_isogeny_negn(n)=F=ellinit([-11*n^2,14*n^3]);gens=descend(F,5*10^5);if(gens==[],return([]));for(i=1,#gens,gens[i]=ellmul(F,gens[i],2);\
denom=denominator(gens[i][1]);localprec(log(denom)/log(10)+10);kill(x);gens[i][1]=round(real(polroots(x^2+n*x+2*n^2-gens[i][1]*(x+n))[1])*denom)/denom;\
gens[i][2]=my_sqrt(gens[i][1]^3-n^2*gens[i][1]);gens[i]=check_double_point(n,gens[i]));return(gens);
findgen(n)=E=ellinit([-n^2,0]);default(debug,0);gens=ellrank(E);gens[4]=descend(E,5*10^4);if(length(gens[4])==gens[1],return(gens[4]));gens=try_isogeny_0(n);if(gens!=[],return(gens));\
gens=try_isogeny_n(n);if(gens!=[],return(gens));gens=try_isogeny_negn(n);if(gens!=[],return(gens),print1("[heegner] ");default(debug,1);return([ellheegner(E)]));

getres(ellmul(ellinit([-6^2,0]),findgen(6),2))

结果:

[4653/851, 3404/1551, 7776485/1319901]

例 3.

找到 \(\frac x{y+z}+\frac y{z+x}+\frac z{x+y}=6\) 的最小正整数解。

Solution.

参考这篇文章

my_sqrt(n)=return(sqrtint(numerator(n))/sqrtint(denominator(n)));
gettors(E,n)=[fulln,struct,P]=elltors(E);return(ellmul(E,P[1],fulln/n));
tamagawa(E)=gr=ellglobalred(E);l=[[gr[4][i,1],gr[5][i][4]]|i<-[1..#gr[4][,1]]];return(prod(i=1,#l,l[i][2]));
expectedheight(E)=return(elltors(E)[1]^2*ellL1(E,1)/E.omega[1]/tamagawa(E));
descend(E,limit,rankub=1)=poi=ellrank(E,limit\50000)[4];if(poi!=[],return(poi));covers=ell2cover(E);[hyperell,trans]=covers[#covers];poi=hyperellratpoints(hyperell,limit,1);if(poi==[],return([]));[x,y]=poi[1];P=eval(trans);if(ellorder(E,P)==0,return(P),return([]));
mkc(n)=return(ellinit([0,4*n^2+12*n-3,0,32*(n+3),0]));
mkc2(n)=return(ellinit([0,4*n^2+12*n-3,0,-128*n-384,-512*n^3-3072*n^2-4224*n+1152]));
mkc3(n)=return(ellinit([0,4*n^2+12*n-3,0,-320*n^2-1248*n-1104,-1024*n^4-7168*n^3-18944*n^2-24576*n-15040]));
mkc6(n)=return(ellinit([0,4*n^2+12*n-3,0,-640*n^3-6080*n^2-18528*n-18384,-2048*n^5-39936*n^4-281088*n^3-935936*n^2-1503744*n-941248]));
heegner(n)=localprec(19);eh1=expectedheight(mkc(n));eh2=expectedheight(mkc2(n));eh3=expectedheight(mkc3(n));eh6=expectedheight(mkc6(n));\
iso2=eh1>eh2;iso3=eh1>eh3;if(iso2,if(iso3,return(map_III(n,mkc(n),map_II(n,mkc3(n),ellheegner(mkc6(n))))),return(map_II(n,mkc(n),ellheegner(mkc2(n))))),\
if(iso3,return(map_III(n,mkc(n),ellheegner(mkc3(n)))),return(ellheegner(mkc(n)))));
map_II(n,E,P)=[F,map]=ellisogeny(E,gettors(E,2));P=ellmul(ellinit(F),P,2);denom=denominator(P[1]);localprec(log(denom)/log(10)+10);kill(x);\
P[1]=round(real(polroots(map[1]-P[1]*map[3]^2)[1])*denom)/denom;P[2]=my_sqrt(P[1]^3+E[2]*P[1]^2+E[4]*P[1]+E[5]);return(P);
map_III(n,E,P)=[F,map]=ellisogeny(E,gettors(E,3));P=ellmul(ellinit(F),P,3);denom=denominator(P[1]);localprec(log(denom)/log(10)+10);kill(x);\
P[1]=round(real(polroots(map[1]-P[1]*map[3]^2)[1])*denom)/denom;P[2]=my_sqrt(P[1]^3+E[2]*P[1]^2+E[4]*P[1]+E[5]);return(P);
try_isogeny_II(n,rankub)=F=mkc2(n);gens=descend(F,5*10^5);if(gens==[],return([]));for(i=1,#gens,gens[i]=map_II(n,mkc(n),gens[i]));return(gens);
try_isogeny_III(n,rankub)=F=mkc3(n);gens=descend(F,5*10^5);if(gens==[],return([]));for(i=1,#gens,gens[i]=map_III(n,mkc(n),gens[i]));return(gens);
try_isogeny_VI(n,rankub)=F=mkc6(n);gens=descend(F,5*10^5);if(gens==[],return([]));for(i=1,#gens,gens[i]=map_III(n,mkc(n),map_II(n,mkc3(n),gens[i])));return(gens);
findgen_worker(n)=E=mkc(n);default(debug,0);gens=ellrank(E);rankub=gens[2];if(issquare(n-15/4)&&gens[2]==1,t=my_sqrt(n-15/4)-1/2;return([[-4*(t^2+t+1)^2,4*(2*t+1)*(t^2+t+1)*(3*t^2+3*t+7)]]));gens[4]=descend(E,5*10^4);if(length(gens[4])==rankub,return(gens[4]));\
gens=try_isogeny_II(n);if(length(gens)==rankub,return(gens));gens=try_isogeny_III(n);if(length(gens)==rankub,return(gens));gens=try_isogeny_VI(n);if(length(gens)==rankub,return(gens),if(rankub>=2,return([]),print1("[heegner] ");default(debug,1);return([heegner(n)])));
findgen(n,reg_only=0)=if(reg_only>=1,gens=ellrank(mkc(n),5);if(gens[2]==length(gens[4]),return(prod(i=1,gens[2],ellheight(mkc(n),gens[4][i]))),return(expectedheight(mkc(n)))));return(findgen_worker(n));
getxyz(N,P)=a=8*(N+3)-P[1]+P[2];b=8*(N+3)-P[1]-P[2];c=-8*(N+3)-2*(N+2)*P[1];g=gcd([a,b,c]);return([a/g,b/g,c/g]);
check_pos(n,P)=x=P[1];return(x^2+4*n*(n+3)*x+16*(n+3)^2>0&&x<-4*(n+3)/(n+2));
solvexyz(n,height_only=0)=if(n%2==1,return([]));E=mkc(n);gens=findgen(n);if(#gens==0,return([]));if(#gens>1,error("Not yet implemented"));Preal=gens[1];now_prec=n*log(n)^2;tors=gettors(E,6);mul=1;\
while(1,localprec(round(now_prec));P=Preal*1.0;nowP=P;mul=1;while(mul<now_prec/3,if(check_pos(n,nowP),break);if(check_pos(n,elladd(E,nowP,tors)),mul=-mul;break);mul=mul+1;nowP=elladd(E,nowP,P);if(mul%1000==0,print1(".")));if(abs(mul)>=now_prec/3,now_prec=now_prec*log(n),break));\
add_tors=mul<0;mul=abs(mul);print1(mul,"*P");if(add_tors,print1("+tors"));localprec(38);h=3/2*ellheight(E,Preal)*mul^2-4*log(n)-9;print(" gives a positive solution, height>",h,", decimal digits>",h/log(10));\
if(height_only>=1,return(h));Preal=ellmul(E,Preal,mul);if(add_tors,return(getxyz(n,elladd(E,Preal,tors))),return(getxyz(n,Preal)));

solvexyz(6)

结果:

[2250324022012683866886426461942494811141200084921223218461967377588564477616220767789632257358521952443049813799712386367623925971447, 1218343242702905855792264237868803223073090298310121297526752830558323845503910071851999217959704024280699759290559009162035102974023, 20260869859883222379931520298326390700152988332214525711323500132179943287700005601210288797153868533207131302477269470450828233936557]

这道题得到的解比上一道题大,因为在上一道题中 \(2P\) 一定可以出解这条性质不成立,取而代之的是一个 \(O(n^2)\) 级别的 \(m\) 满足 \(mP\) 可以出解。例如 \(n=896\),本身点的 \(h(P)\approx128.76\),而且还要乘上 \(m=161477\) 才能得到解。这就导致最终的解有 \(1458098074613\pm10\) 位(具体是多少目前没有文献参考)。而 \(n=6\)(也就是这里的情况)需要 \(11P\) 才能得到解。