Le confinement que nous vivons ce printemps a fait fleurir sur les réseaux sociaux recettes de cuisine et memes mathématiques.
On en trouve de plus ou moins simples, comme celui-ci :
Vous observez cependant qu'il se ramène à un système linéaire échelonné.
OMG! Il y a quelques ruses avec le nombre de noix de coco ou de bananes ; il n'empêche.
Celui qui m'intéresse aujourd'hui est un peu plus sophistiqué :
En formules, il s'agit de trouver des nombres entiers strictement positifs $x$, $y$, $z$ tels que $$ \frac{x}{y+z}+\frac{y}{x+z}+\frac{z}{x+y} = 4. $$
On se débarrasse des fractions en la récrivant sous forme polynomiale: $$ x(x+y)(x+z) + y(y+z)(y+x) + z (z+x)(z+y) $$ $$= 4 (x+y)(y+z)(z+x). $$
R.<x,y,z> = QQ[]
n=4
E = numerator(x/(y+z)+y/(x+z)+z/(x+y)-n)
E
x^3 - 3*x^2*y - 3*x*y^2 + y^3 - 3*x^2*z - 5*x*y*z - 3*y^2*z - 3*x*z^2 - 3*y*z^2 + z^3
Il s'agit d'une équation homogène en trois variables $x,y,z$, de degré $3$. Elle décrit une surface dans l'espace à 3 dimensions.
P=implicit_plot3d(E, (x,-3,3), (y,-3,3), (z,-3,3), plot_points=50, color='red')
P.show()
Sa nature conique suggère de la considérer dans le plan projectif $\mathbf P_2$.
Si on veut la tracer, on peut fixer une des coordonnées homogènes ; on obtient alors une cubique plane.
var ("u v")
P2=implicit_plot(E(u,v,1),(u,-5,5),(v,-5,5))
P2.show()
On a perdu les points à l'infini, correspondant à $z=0$. Ils correspondent dans le dessin à trois directions asymptotiques $y=-x$, $y=(2+\sqrt 3)x$ et $y=(2-\sqrt 3)x$.
factor(E(x,y,0))
(x + y) * (x^2 - 4*x*y + y^2)
P2\
+implicit_plot(u+v-.2,(u,-5,5),(v,-5,5),color='red') \
+implicit_plot(u-(2+sqrt(3.0)) *v-4,(u,-5,5),(v,-5,5),color='red') \
+implicit_plot(v-(2+sqrt(3.0))*u-4,(u,-5,5),(v,-5,5),color='red')
Ce genre de courbe (ou d'équation diophantienne) est bien étudiée depuis le 18e siècle, et même avant : après tout, la première équation étudiée par Fermat, $x^3+y^3=z^3$ était de ce genre (c'est Euler qui a prouvé que celle-là n'avait pas de solution entière non triviale).
L'équation a $6$ solutions « évidentes » lorsqu'un des dénominateurs de l'équation initiale s'annule: $$ \frac x{y+z}+ \frac{y}{x+z}+\frac z{x+y}=4,$$ qu'on voit bien si on la récrit sous forme polynomiale $$ x(x+z)(y+z) + y(y+x)(y+z) + z(z+x)(z+y) $$ $$= 4 (x+y)(x+z)(y+z). $$
Par exemple si $x+y=0$, cela donne $x(x+z)(y+z)=0$. De fait :
E(x,-x,z)
-x^2*z + z^3
… et alors $z\in\{x,-x,0\}$.
Comme on a imposé $z=1$ (par homogénéité, $z\neq0$), l'une de ces solutions évidentes est « à l'infini » et il nous en reste $5$.
pts = [(1,-1),(-1,1),(-1,-1),(0,-1),(-1,0)]
rnge=P2.get_axes_range()
P3=point(pts,color='black',size=20)
P2+P3
Ce qu'on sait aussi faire, pour étudier de telles équations, c'est faire de la géométrie avec leurs solutions.
On considère deux points $A$ et $B$ sur la courbe et on trace la droite $(AB)$ qui les joint. Cette droite coupe la courbe cubique en trois points, on en connaît déjà deux, d'où un troisième point sur la courbe !
def extendedline(pA,pB,range):
"Si la droite (pA-pB) rencontre la fenêtre indiquée, renvoie les deux points d'intersection"
pC=[]
if pA[0] != pB[0]:
for rx in ['xmin','xmax']:
t = (range[rx]-pA[0])/(pB[0]-pA[0])
ry=(1-t)*pA[1]+t*pB[1]
if ry >= range['ymin'] and ry<=range['ymax']:
pC.append(((1-t)*pA[0]+t*pB[0],(1-t)*pA[1]+t*pB[1]))
if pA[1] != pB[1]:
for ry in ['ymin','ymax']:
t = (range[ry]-pA[1])/(pB[1]-pA[1])
rx=(1-t)*pA[0]+t*pB[0]
if rx >= range['xmin'] and rx<=range['xmax']:
pC.append(((1-t)*pA[0]+t*pB[0],(1-t)*pA[1]+t*pB[1]))
return(pC)
def all_lines(pts,rnge):
l4=[]
for n1 in range(len(pts)):
for n2 in range(n1+1,len(pts)):
l=extendedline(pts[n1],pts[n2],rnge)
if l not in l4:
l4.append(l)
return(map(lambda l:line(l,color='red'), l4))
P4=sum(all_lines(pts,rnge))
P2+P3+P4
À ce stade, la géométrie semble avoir atteint ses limites…
Mon petit doigt me dit que le point de coordonnées $(-1/4,11/4)$ est sur la courbe :
E(-1/4,11/4,1)
0
P2+point((-1/4,11/4),size=40,color='red')+P3
pts.append((-1/4,11/4))
l=extendedline(pts[5],pts[2],rnge)
(P2+line(l,color='red')+points(pts,color='black')).show(xmin=-3,xmax=3,ymin=-3,ymax=3)
def third_point(p,q,E):
var('t')
L=E((1-t)*p[0]+t*q[0],(1-t)*p[1]+t*q[1],1)
for n in L.roots():
if n[0]!=0 and n[0] != 1:
return((1-n[0])*p[0]+n[0]*q[0],(1-n[0])*p[1]+n[0]*q[1])
r=third_point(pts[5],pts[2],E)
r
(-5/9, 11/9)
On peut ajouter ce point et recommencer la construction.
pts.append(third_point(pts[5],pts[2],E))
P2+points(pts,color='black') +sum(all_lines(pts,rnge))
def add_points(pts,E):
newpts=pts.copy()
for n1 in range(len(pts)):
for n2 in range(n1+1,len(pts)):
r=third_point(pts[n1],pts[n2],E)
if r and r not in newpts:
newpts.append(r)
return(newpts)
pts = [(1,-1),(-1,1),(-1,-1),(0,-1),(-1,0),(-1/4,11/4)]
add_points(pts,E)
[(1, -1), (-1, 1), (-1, -1), (0, -1), (-1, 0), (-1/4, 11/4), (9/11, -5/11), (-11/5, -9/5), (-5/9, 11/9), (-1/11, 4/11), (-4, -11)]
Partons des points que nous connaissons, et essayons d'en produire ad lib…
pts
[(1, -1), (-1, 1), (-1, -1), (0, -1), (-1, 0), (-1/4, 11/4)]
def solve_pts(pts,E, check=False):
goon=True
m = 0
while goon:
M = len(pts)
print(len(pts),' points…')
for n1 in range(0,M):
for n2 in range(max(m,n1+1),M):
r=third_point(pts[n1],pts[n2],E)
if r and r not in pts:
pts.append(r)
if check:
print(ln(numerator(r[0])*1.0),'chiffres…')
if r[0]>0 and r[1]>0:
return(r)
goon=False
m=M
solve_pts(pts,E,check=False)
6 points… 11 points… 22 points… 41 points… 77 points…
(36875131794129999827197811565225474825492979968971970996283137471637224634055579/4373612677928697257861252602371390152816537558161613618621437993378423467772036, 154476802108746166441951315019919837485664325669565431700026634898253202035277999/4373612677928697257861252602371390152816537558161613618621437993378423467772036)
r=pts[-1]
x1,y1,z1=numerator(r[0]),numerator(r[1]), denominator(r[0])
print('x =',x1,',\ny =',y1,',\nz =',z1)
x = 36875131794129999827197811565225474825492979968971970996283137471637224634055579 , y = 154476802108746166441951315019919837485664325669565431700026634898253202035277999 , z = 4373612677928697257861252602371390152816537558161613618621437993378423467772036
E(x1,y1,z1)
0
Qu'est-ce c'est que ce cirque !?
On peut donner un peu de consistance au procédé de construction de points par sécante et introduction du troisième point d'intersection. En lui-même, ce procédé ne se comporte pas très bien. Parfois, la sécante ne coupe la courbe qu'en deux points. Mais cela s'explique par deux raisons :
Si on restaure les points à l'infini et tient compte des multiplicités, on dispose d'une loi bien définie, $(P,Q)\mapsto P\circ Q$.
Malgré tout, cette loi n'a pas de très bonnes propriétés, quoiqu'une simple modification en fasse une loi de groupe !
Fixons un point $O$ sur la courbe.
Théorème. — Il existe une unique loi de groupe abélien, d'origine $O$, sur l'ensemble des points de la courbe pour laquelle $P+Q+(P\circ Q)=O$ dès que $P,Q$ sont deux points de la courbe.
$Q=-P$ signifie que $O,P,Q$ sont alignés.
Cette loi de groupe est ainsi définie par la condition que $O, (P+Q), (P\circ Q)$ sont alignés.
L'associativité de cette loi est un théorème qu'on peut démontrer non trivialement à l'aide du théorème de Pascal, ou bien trivialement par le calcul formel.
Remarque. — Si $O,P,Q$ sont à coordonnées rationnelles, $P\circ Q$ et $P+Q$ le sont également, ainsi que $-P$. On obtient ainsi une loi de groupe sur les solutions rationnelles de l'équation initiale
Théorème (Mordell, 1922). — Le groupe abélien des solutions rationnelles est un groupe abélien de type fini.
Il a donc un sous-groupe de torsion, fini, et un rang.
f=EllipticCurve_from_cubic(E)
EC=f.codomain()
EC
Elliptic Curve defined by y^2 + x*y = x^3 + 69*x^2 + 1365*x + 8281 over Rational Field
EC.label()
'910c1'
f
Scheme morphism: From: Projective Plane Curve over Rational Field defined by x^3 - 3*x^2*y - 3*x*y^2 + y^3 - 3*x^2*z - 5*x*y*z - 3*y^2*z - 3*x*z^2 - 3*y*z^2 + z^3 To: Elliptic Curve defined by y^2 + x*y = x^3 + 69*x^2 + 1365*x + 8281 over Rational Field Defn: Defined on coordinates by sending (x : y : z) to (-x - z : x : 6/91*x - 1/91*y + 6/91*z)
f.inverse()
Scheme morphism: From: Elliptic Curve defined by y^2 + x*y = x^3 + 69*x^2 + 1365*x + 8281 over Rational Field To: Projective Plane Curve over Rational Field defined by x^3 - 3*x^2*y - 3*x*y^2 + y^3 - 3*x^2*z - 5*x*y*z - 3*y^2*z - 3*x*z^2 - 3*y*z^2 + z^3 Defn: Defined on coordinates by sending (x : y : z) to (y : -6*x - 91*z : -x - y)
L'origine choisie par SageMath est le point $(-1:0:1)$.
f.inverse()(EC(0))
(-1 : 0 : 1)
Proposition. — Le sous-groupe de torsion du groupe de Mordell de cette courbe est formé des six solutions évidentes.
list(map(f.inverse(),EC.torsion_points()))
[(1 : -1 : 1), (0 : -1 : 1), (-1 : 1 : 0), (-1 : -1 : 1), (-1 : 0 : 1), (-1 : 1 : 1)]
Il est donc isomorphe à $\mathbf Z/6\mathbf Z$.
Proposition. — Le rang du groupe de Mordell de cette courbe est égal à $1$.
EC.rank()
1
SageMath peut même en calculer un générateur (modulo la torsion):
f.inverse()(EC.gens()[0])
(-4 : -11 : 1)
Le problème est donc résolu : tous les points rationnels de la courbe sont produits par le procédé de sécante à partir de ce générateur et des six points évidents. Le point $(-1/4:11/4:1)$ qu'on avait mystérieusement ajouté était en fait l'un des 12 générateurs possibles…
gP=EC.gens()[0]
for x in EC.torsion_points():
print(f.inverse()(gP+x), f.inverse()(-gP+x))
(9/11 : -5/11 : 1) (11/9 : -5/9 : 1) (11/4 : -1/4 : 1) (-11 : -4 : 1) (-1/11 : 4/11 : 1) (4/11 : -1/11 : 1) (-11/5 : -9/5 : 1) (-9/5 : -11/5 : 1) (-4 : -11 : 1) (-1/4 : 11/4 : 1) (-5/9 : 11/9 : 1) (-5/11 : 9/11 : 1)
Et c'est là que le problème devient vraiment difficile !
ECp=EC.plot(xmin=-50,xmax=20,ymin=-200,ymax=200)
ECp.show()
f.inverse()
Scheme morphism: From: Elliptic Curve defined by y^2 + x*y = x^3 + 69*x^2 + 1365*x + 8281 over Rational Field To: Projective Plane Curve over Rational Field defined by x^3 - 3*x^2*y - 3*x*y^2 + y^3 - 3*x^2*z - 5*x*y*z - 3*y^2*z - 3*x*z^2 - 3*y*z^2 + z^3 Defn: Defined on coordinates by sending (x : y : z) to (y : -6*x - 91*z : -x - y)
Autrement dit, les points de cette courbe qui nous intéressent correspondent aux deux domaines :
ECp+line([(-91/6,-200),(-91/6,200)],color='red')+line([(-50,50),(20,-20)],color='red')
On voit qu'il ne reste de cette courbe qu'une toute petite zone :
ECp2=EC.plot(xmin=-50,xmax=-40.12,ymin=0,ymax=20,color='red')
ECp3=ECp+ECp2+line([(-50,50),(20,-20)],color='red')
ECp3.show(xmin=-50,xmax=20,ymin=-200,ymax=200)
Il s'agit donc de trouver les multiples « du » générateur $P$ qui appartiennent à cette zone. Pour cela, on calcule $kP+T$, où $T$ parcourt les six points de torsion et $k=\pm1,\dots$. C'est seulement pour $k=9$ qu'on tombe dans la zone voulue.
def isOK(k):
kgP=k*gP
sols = []
for tP in EC.torsion_points():
Qf=f.inverse()(tP+kgP)
Qf.clear_denominators()
if ((Qf[0] > 0) and (Qf[1] > 0) and (Qf[2]>0)) or ((Qf[0] < 0) and (Qf[1] < 0) and (Qf[2]<0)):
print ('finv (',tP,'+',k,gP,') \n =',Qf)
sols.append(Qf)
Qf=f.inverse()(tP-kgP)
Qf.clear_denominators()
if ((Qf[0] > 0) and (Qf[1] > 0) and (Qf[2]>0)) or ((Qf[0] < 0) and (Qf[1] < 0) and (Qf[2]<0)):
print ('finv (',tP,'-',k,gP,') \n =',Qf)
sols.append(Qf)
return(sols)
sols=[]
k=0
while not(sols):
k=k+1
sols=isOK(k)
finv ( (-13 : 0 : 1) + 9 (-39 : 52 : 1) ) = (4373612677928697257861252602371390152816537558161613618621437993378423467772036 : 36875131794129999827197811565225474825492979968971970996283137471637224634055579 : 154476802108746166441951315019919837485664325669565431700026634898253202035277999) finv ( (-13 : 0 : 1) - 9 (-39 : 52 : 1) ) = (4373612677928697257861252602371390152816537558161613618621437993378423467772036 : 154476802108746166441951315019919837485664325669565431700026634898253202035277999 : 36875131794129999827197811565225474825492979968971970996283137471637224634055579) finv ( (-13 : 13 : 1) + 9 (-39 : 52 : 1) ) = (36875131794129999827197811565225474825492979968971970996283137471637224634055579 : 154476802108746166441951315019919837485664325669565431700026634898253202035277999 : 4373612677928697257861252602371390152816537558161613618621437993378423467772036) finv ( (-13 : 13 : 1) - 9 (-39 : 52 : 1) ) = (154476802108746166441951315019919837485664325669565431700026634898253202035277999 : 36875131794129999827197811565225474825492979968971970996283137471637224634055579 : 4373612677928697257861252602371390152816537558161613618621437993378423467772036) finv ( (0 : 1 : 0) + 9 (-39 : 52 : 1) ) = (154476802108746166441951315019919837485664325669565431700026634898253202035277999 : 4373612677928697257861252602371390152816537558161613618621437993378423467772036 : 36875131794129999827197811565225474825492979968971970996283137471637224634055579) finv ( (0 : 1 : 0) - 9 (-39 : 52 : 1) ) = (36875131794129999827197811565225474825492979968971970996283137471637224634055579 : 4373612677928697257861252602371390152816537558161613618621437993378423467772036 : 154476802108746166441951315019919837485664325669565431700026634898253202035277999)
On peut chercher des solutions pour de plus grandes valeurs de $k$, peut-être seront-elles plus simples…
sols=[]
k=k+1
while not(sols):
k=k+1
sols=isOK(k)
finv ( (-14 : 7 : 1) + 13 (-39 : 52 : 1) ) = (32343421153825592353880655285224263330451946573450847101645239147091638517651250940206853612606768544181415355352136077327300271806129063833025389772729796460799697289 : 184386514670723295219914666691038096275031765336404340516686430257803895506237580602582859039981257570380161221662398153794290821569045182385603418867509209632768359835 : 16666476865438449865846131095313531540647604679654766832109616387367203990642764342248100534807579493874453954854925352739900051220936419971671875594417036870073291371) finv ( (-14 : 7 : 1) - 13 (-39 : 52 : 1) ) = (16666476865438449865846131095313531540647604679654766832109616387367203990642764342248100534807579493874453954854925352739900051220936419971671875594417036870073291371 : 184386514670723295219914666691038096275031765336404340516686430257803895506237580602582859039981257570380161221662398153794290821569045182385603418867509209632768359835 : 32343421153825592353880655285224263330451946573450847101645239147091638517651250940206853612606768544181415355352136077327300271806129063833025389772729796460799697289) finv ( (0 : -91 : 1) + 13 (-39 : 52 : 1) ) = (16666476865438449865846131095313531540647604679654766832109616387367203990642764342248100534807579493874453954854925352739900051220936419971671875594417036870073291371 : 32343421153825592353880655285224263330451946573450847101645239147091638517651250940206853612606768544181415355352136077327300271806129063833025389772729796460799697289 : 184386514670723295219914666691038096275031765336404340516686430257803895506237580602582859039981257570380161221662398153794290821569045182385603418867509209632768359835) finv ( (0 : -91 : 1) - 13 (-39 : 52 : 1) ) = (32343421153825592353880655285224263330451946573450847101645239147091638517651250940206853612606768544181415355352136077327300271806129063833025389772729796460799697289 : 16666476865438449865846131095313531540647604679654766832109616387367203990642764342248100534807579493874453954854925352739900051220936419971671875594417036870073291371 : 184386514670723295219914666691038096275031765336404340516686430257803895506237580602582859039981257570380161221662398153794290821569045182385603418867509209632768359835) finv ( (0 : 91 : 1) + 13 (-39 : 52 : 1) ) = (184386514670723295219914666691038096275031765336404340516686430257803895506237580602582859039981257570380161221662398153794290821569045182385603418867509209632768359835 : 16666476865438449865846131095313531540647604679654766832109616387367203990642764342248100534807579493874453954854925352739900051220936419971671875594417036870073291371 : 32343421153825592353880655285224263330451946573450847101645239147091638517651250940206853612606768544181415355352136077327300271806129063833025389772729796460799697289) finv ( (0 : 91 : 1) - 13 (-39 : 52 : 1) ) = (184386514670723295219914666691038096275031765336404340516686430257803895506237580602582859039981257570380161221662398153794290821569045182385603418867509209632768359835 : 32343421153825592353880655285224263330451946573450847101645239147091638517651250940206853612606768544181415355352136077327300271806129063833025389772729796460799697289 : 16666476865438449865846131095313531540647604679654766832109616387367203990642764342248100534807579493874453954854925352739900051220936419971671875594417036870073291371)
Pas vraiment !
Théorème (Néron, Tate). — Le nombre de chiffres qu'il faut pour écrire un point de la forme $T\pm kP$ est de l'ordre de $k^2$.
Plus précisément : À un terme d'erreur borné près, le nombre de chiffres qu'il faut pour écrire un point du groupe de Mordell--Weil est une forme quadratique définie positive sur ce groupe (modulo torsion).