Path: blob/master/src/sage/quadratic_forms/ternary.pyx
8817 views
#*****************************************************************************1# Copyright (C) 2012 Gustavo Rama2#3# Distributed under the terms of the GNU General Public License (GPL)4#5# This code is distributed in the hope that it will be useful,6# but WITHOUT ANY WARRANTY; without even the implied warranty of7# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU8# General Public License for more details.9#10# The full text of the GPL is available at:11#12# http://www.gnu.org/licenses/13#*****************************************************************************14151617from sage.rings.integer_ring import ZZ18from sage.matrix.constructor import matrix, identity_matrix, diagonal_matrix19from sage.modules.free_module_element import vector20from sage.rings.arith import inverse_mod21from sage.quadratic_forms.extras import extend_to_primitive22from sage.rings.finite_rings.integer_mod import mod23from sage.misc.prandom import randint24from sage.rings.arith import xgcd,gcd25from sage.functions.other import ceil, floor26from __builtin__ import max27282930def red_mfact(a,b):31"""32Auxiliar function for reduction that finds the reduction factor of a, b integers.3334INPUT:35- a, b integers3637OUTPUT:38Integer3940EXAMPLES::4142sage: from sage.quadratic_forms.ternary import red_mfact43sage: red_mfact(0, 3)44045sage: red_mfact(-5, 100)4694748"""4950if a:51return (-b + abs(a))//(2*a)52else:53return 05455def _reduced_ternary_form_eisenstein_with_matrix(a1, a2, a3, a23, a13, a12):56"""57Find the coefficients of the equivalent unique reduced ternary form according to the conditions58of Dickson's "Studies in the Theory of Numbers", pp164-171, and the tranformation matrix.59See TernaryQF.is_eisenstein_reduced for the conditions.6061EXAMPLES::6263sage: from sage.quadratic_forms.ternary import _reduced_ternary_form_eisenstein_with_matrix64sage: Q = TernaryQF([293, 315, 756, 908, 929, 522])65sage: qr, M = _reduced_ternary_form_eisenstein_with_matrix(293, 315, 756, 908, 929, 522)66sage: qr67(1, 2, 2, -1, 0, -1)68sage: M69[ -54 137 -38]70[ -23 58 -16]71[ 47 -119 33]72sage: Qr = TernaryQF(qr)73sage: Qr.is_eisenstein_reduced()74True75sage: Q(M) == Qr76True777879"""8081M = identity_matrix(3)8283loop=18485while loop:868788# adjust89v=a1+a2+a23+a13+a1290if (v<0):91M*=matrix(ZZ,3,[1,0,1,0,1,1,0,0,1])92a3+=v93a23+=a12+2*a294a13+=a12+2*a19596# cuadred 1297m=red_mfact(a1,a12)98M*=matrix(ZZ,3,[1,m,0,0,1,0,0,0,1])99t=a1*m100a12+=t101a2+=a12*m102a12+=t103a23+=a13*m104105# cuadred 23106m=red_mfact(a2,a23)107M*=matrix(ZZ,3,[1,0,0,0,1,m,0,0,1])108t=a2*m109a23+=t110a3+=a23*m111a23+=t112a13+=a12*m113114# cuadred 13115m=red_mfact(a1,a13)116M*=matrix(ZZ,3,[1,0,m,0,1,0,0,0,1])117t=a1*m118a13+=t119a3+=a13*m120a13+=t121a23+=a12*m122123# order 12124if a1 > a2 or (a1 == a2 and abs(a23) > abs(a13)):125M*=matrix(ZZ,3,[0,-1,0,-1,0,0,0,0,-1])126[a1,a2]=[a2,a1]127[a13,a23]=[a23,a13]128129# order 23130if a2 > a3 or (a2 == a3 and abs(a13) > abs(a12)):131M*=matrix(ZZ,3,[-1,0,0,0,0,-1,0,-1,0])132[a2,a3]=[a3,a2]133[a13,a12]=[a12,a13]134135# order 12136if a1 > a2 or (a1 == a2 and abs(a23) > abs(a13)):137M*=matrix(ZZ,3,[0,-1,0,-1,0,0,0,0,-1])138[a1,a2]=[a2,a1]139[a13,a23]=[a23,a13]140141# signs142if (a23*a13*a12>0):143# a23, a13, a12 positive144145if (a23<0):146M*=diagonal_matrix([-1,1,1])147a23=-a23148if (a13<0):149M*=diagonal_matrix([1,-1,1])150a13=-a13151if (a12<0):152M*=diagonal_matrix([1,1,-1])153a12=-a12154155else:156# a23, a13, a12 nonpositive157158[s1,s2,s3]=[(a23>0),(a13>0),(a12>0)]159if ((s1+s2+s3)%2):160if (a23==0):161s1=1162else:163if (a13==0):164s2=1165else:166if (a12==0):167s3=1168if s1:169M*=diagonal_matrix([-1,1,1])170a23=-a23171if s2:172M*=diagonal_matrix([1,-1,1])173a13=-a13174if s3:175M*=diagonal_matrix([1,1,-1])176a12=-a12177178loop = not (abs(a23) <= a2 and abs(a13) <= a1 and abs(a12) <= a1 and a1+a2+a23+a13+a12>=0)179180181################182################183184185186# adj 3187if a1+a2+a23+a13+a12 == 0 and 2*a1+2*a13+a12 > 0:188M*=matrix(ZZ,3,[-1,0,1,0,-1,1,0,0,1])189# a3 += a1+a2+a23+a13+a12190a23=-2*a2-a23-a12191a13=-2*a1-a13-a12192193# adj 5.12194if a1 == -a12 and a13 != 0:195M*=matrix(ZZ,3,[-1,-1,0,0,-1,0,0,0,1])196#a2 += a1+a12197a23=-a23-a13198a13=-a13199a12=-a12 # = 2*a1+a12200201# adj 5.13202if a1 == -a13 and a12 != 0:203M*=matrix(ZZ,3,[-1,0,-1,0,1,0,0,0,-1])204# a3 += a1+a13205a23=-a23-a12206a13=-a13 # = 2*a1+a13207a12=-a12208209# adj 5.23210if a2 == -a23 and a12 != 0:211M*=matrix(ZZ,3,[1,0,0,0,-1,-1,0,0,-1])212# a3 += a2+a23213a23=-a23 # = 2*a2+a23214a13=-a13-a12215a12=-a12216217# adj 4.12218if a1 == a12 and a13 > 2*a23:219M*=matrix(ZZ,3,[-1,-1,0,0,1,0,0,0,-1])220# a 2 += a1-a12221a23 = -a23 + a13222# a12 = 2*a1 - a12223224# adj 4.13225if a1 == a13 and a12 > 2*a23:226M*=matrix(ZZ,3,[-1,0,-1,0,-1,0,0,0,1])227# a3 += a1-a13228a23 = -a23 + a12229# a13 = 2*a1 - a13230231# adj 4.23232if a2 == a23 and a12 > 2*a13:233M*=matrix(ZZ,3,[-1,0,0,0,-1,-1,0,0,1])234# a3 += a2-a23235# a23 = 2*a2 - a23236a13 = -a13 + a12237238# order 12239if a1 == a2 and abs(a23) > abs(a13):240M*=matrix(ZZ,3,[0,-1,0,-1,0,0,0,0,-1])241[a1,a2]=[a2,a1]242[a13,a23]=[a23,a13]243244# order 23245if a2 == a3 and abs(a13) > abs(a12):246M*=matrix(ZZ,3,[-1,0,0,0,0,-1,0,-1,0])247[a13,a12]=[a12,a13]248249# order 12250if a1 == a2 and abs(a23) > abs(a13):251M*=matrix(ZZ,3,[0,-1,0,-1,0,0,0,0,-1])252[a13,a23]=[a23,a13]253254return((a1,a2,a3,a23,a13,a12),M)255256def _reduced_ternary_form_eisenstein_without_matrix(a1, a2, a3, a23, a13, a12):257"""258Find the coefficients of the equivalent unique reduced ternary form according to the conditions259of Dickson's "Studies in the Theory of Numbers", pp164-171.260See TernaryQF.is_eisenstein_reduced for the conditions.261262EXAMPLES::263264sage: from sage.quadratic_forms.ternary import _reduced_ternary_form_eisenstein_without_matrix265sage: Q = TernaryQF([293, 315, 756, 908, 929, 522])266sage: qr = _reduced_ternary_form_eisenstein_without_matrix(293, 315, 756, 908, 929, 522)267sage: qr268(1, 2, 2, -1, 0, -1)269sage: Qr = TernaryQF(qr)270sage: Qr.is_eisenstein_reduced()271True272273"""274275loop=1276277while loop:278279# adjust280v=a1+a2+a23+a13+a12281if (v<0):282a3+=v283a23+=a12+2*a2284a13+=a12+2*a1285286# cuadred 12287m=red_mfact(a1,a12)288t=a1*m289a12+=t290a2+=a12*m291a12+=t292a23+=a13*m293294# cuadred 23295m=red_mfact(a2,a23)296t=a2*m297a23+=t298a3+=a23*m299a23+=t300a13+=a12*m301302# cuadred 13303m=red_mfact(a1,a13)304t=a1*m305a13+=t306a3+=a13*m307a13+=t308a23+=a12*m309310# order 12311if a1 > a2 or (a1 == a2 and abs(a23) > abs(a13)):312[a1,a2]=[a2,a1]313[a13,a23]=[a23,a13]314315# order 23316if a2 > a3 or (a2 == a3 and abs(a13) > abs(a12)):317[a2,a3]=[a3,a2]318[a13,a12]=[a12,a13]319320# order 12321if a1 > a2 or (a1 == a2 and abs(a23) > abs(a13)):322[a1,a2]=[a2,a1]323[a13,a23]=[a23,a13]324325# signs326if a23*a13*a12 > 0:327# a23, a13, a12 positive328329if (a23<0):330a23=-a23331if (a13<0):332a13=-a13333if (a12<0):334a12=-a12335336else:337# a23, a13, a12 nonpositive338339[s1,s2,s3]=[(a23>0),(a13>0),(a12>0)]340if ((s1+s2+s3)%2):341if (a23==0):342s1=1343else:344if (a13==0):345s2=1346else:347if (a12==0):348s3=1349if s1:350a23=-a23351if s2:352a13=-a13353if s3:354a12=-a12355356loop = not (abs(a23) <= a2 and abs(a13) <= a1 and abs(a12) <= a1 and a1+a2+a23+a13+a12 >= 0)357358359################360################361362363364# adj 3365if a1+a2+a23+a13+a12 == 0 and 2*a1+2*a13+a12 > 0:366# a3 += a1+a2+a23+a13+a12367a23=-2*a2-a23-a12368a13=-2*a1-a13-a12369370# adj 5.12371if a1 == -a12 and a13 != 0:372#a2 += a1+a12373a23=-a23-a13374a13=-a13375a12=-a12 # = 2*a1+a12376377# adj 5.13378if a1 == -a13 and a12 != 0:379# a3 += a1+a13380a23=-a23-a12381a13=-a13 # = 2*a1+a13382a12=-a12383384# adj 5.23385if a2 == -a23 and a12 != 0:386# a3 += a2+a23387a23=-a23 # = 2*a2+a23388a13=-a13-a12389a12=-a12390391# adj 4.12392if a1 == a12 and a13 > 2*a23:393# a 2 += a1-a12394a23 = -a23 + a13395# a12 = 2*a1 - a12396397# adj 4.13398if a1 == a13 and a12 > 2*a23:399# a3 += a1-a13400a23 = -a23 + a12401# a13 = 2*a1 - a13402403# adj 4.23404if a2 == a23 and a12 > 2*a13:405# a3 += a2-a23406# a23 = 2*a2 - a23407a13 = -a13 + a12408409# order 12410if a1 == a2 and abs(a23) > abs(a13):411[a1,a2]=[a2,a1]412[a13,a23]=[a23,a13]413414# order 23415if a2 == a3 and abs(a13) > abs(a12):416[a13,a12]=[a12,a13]417418# order 12419if a1 == a2 and abs(a23) > abs(a13):420[a13,a23]=[a23,a13]421422return((a1,a2,a3,a23,a13,a12))423424425def primitivize(long long v0, long long v1, long long v2, p):426"""427Given a 3-tuple v not singular mod p, it returns a primitive 3-tuple version of v mod p.428429EXAMPLES::430431sage: from sage.quadratic_forms.ternary import primitivize432sage: primitivize(12, 13, 14, 5)433(3, 2, 1)434sage: primitivize(12, 13, 15, 5)435(4, 1, 0)436437"""438439if v2%p != 0:440v2_inv = inverse_mod(v2, p)441return v2_inv*v0%p, v2_inv*v1%p, 1442elif v1%p != 0:443return inverse_mod(v1, p)*v0%p, 1, 0444else:445return 1, 0, 0446447def evaluate(a, b, c, r, s, t, v):448"""449Function to evaluate the ternary quadratic form (a, b, c, r, s, t) in a 3-tuple v.450451EXAMPLES::452453sage: from sage.quadratic_forms.ternary import evaluate454sage: Q = TernaryQF([1, 2, 3, -1, 0, 0])455sage: v = (1, -1, 19)456sage: Q(v)4571105458sage: evaluate(1, 2, 3, -1, 0, 0, v)4591105460461"""462463return a*v[0]**2+b*v[1]**2+c*v[2]**2+r*v[2]*v[1]+s*v[2]*v[0]+t*v[1]*v[0]464465def _find_zeros_mod_p_2(a, b, c, r, s, t):466"""467Function to find the zeros mod 2 of a ternary quadratic form.468469EXAMPLES::470471sage: Q = TernaryQF([1, 2, 2, -1, 0, 0])472sage: from sage.quadratic_forms.ternary import _find_zeros_mod_p_2473sage: zeros = _find_zeros_mod_p_2(1, 2, 2, -1, 0, 0)474sage: zeros475[(0, 1, 0), (0, 0, 1), (1, 1, 1)]476sage: Q((0, 1, 0))4772478sage: Q((0, 0, 1))4792480sage: Q((1, 1, 1))4814482483"""484485zeros=[]486v=(1,0,0)487if evaluate(a,b,c,r,s,t,v)%2==0:488zeros.append(v)489for i in range(2):490v=(i,1,0)491if evaluate(a,b,c,r,s,t,v)%2==0:492zeros.append(v)493for i in range(2):494for j in range(2):495v=(i,j,1)496if evaluate(a,b,c,r,s,t,v)%2==0:497zeros.append(v)498return zeros499500def pseudorandom_primitive_zero_mod_p(a, b, c, r, s, t, p):501"""502Find a zero of the form (a, b, 1) of the ternary quadratic form given by the coefficients (a, b, c, r, s, t)503mod p, where p is a odd prime that doesn't divide the discriminant.504505EXAMPLES::506507sage: Q = TernaryQF([1, 2, 2, -1, 0, 0])508sage: p = 1009509sage: from sage.quadratic_forms.ternary import pseudorandom_primitive_zero_mod_p510sage: v = pseudorandom_primitive_zero_mod_p(1, 2, 2, -1, 0, 0, p)511sage: v[2]5121513sage: Q(v)%p5140515516"""517518#[a,b,c,r,s,t] = Q.coefficients()519while True:520521r1 = randint(0,p-1)522r2 = randint(0,p-1)523alpha = (b*r1**2+t*r1+a)%p524if alpha != 0:525526beta = (2*b*r1*r2+t*r2+r*r1+s)%p527gamma = (b*r2**2+r*r2+c)%p528disc = beta**2-4*alpha*gamma529if mod(disc,p).is_square():530531z = (-beta+mod(disc,p).sqrt().lift())*(2*alpha).inverse_mod(p)532#return vector((z,r1*z+r2,1))%p533return z%p, (r1*z+r2)%p, 1534535def _find_zeros_mod_p_odd(long long a, long long b, long long c, long long r, long long s, long long t, long long p, v):536"""537Find the zeros mod p, where p is an odd prime, of a ternary quadratic form given by its coefficients and a given zero of the form v.538The prime p doesn't divides the discriminant of the form.539540EXAMPLES::541542sage: from sage.quadratic_forms.ternary import _find_zeros_mod_p_odd543sage: Q = TernaryQF([1, 2, 2, -1, 0, 0])544sage: p = 1009545sage: v = (817, 974, 1)546sage: Q(v)%10095470548sage: zeros_1009 = _find_zeros_mod_p_odd(1, 2, 2, -1, 0, 0, 1009, v)549sage: len(zeros_1009)5501010551sage: zeros_1009.sort()552sage: zeros_1009[0]553(0, 32, 1)554sage: Q((0, 32, 1))5552018556557"""558559cdef long long a_i560cdef long long c_i561cdef long long a_inf562cdef long long c_inf563cdef long long i564cdef long long l565cdef long long x0566cdef long long y0567568zeros=[v]569x0=v[0]570y0=v[1]571more=False572for i in xrange(p):573a_i=(a*x0**2+b*i**2-2*b*i*y0+b*y0**2-t*i*x0+t*x0*y0-2*a*x0+t*i-t*y0+s*x0-r*i+r*y0+a+c-s)%p574#b_i=(-2*b*i**2+2*b*i*y0+t*i*x0+2*a*x0-2*t*i+t*y0+r*i-2*a+s)%p575if a_i==0:576w=((x0-1)%p,(y0-i)%p,1)577if w==v:578more=True579else:580zeros.append(w)581else:582c_i=(b*i**2+t*i+a)%p583l=c_i*ZZ(a_i).inverse_mod(p)584w = primitivize(l*(x0-1)+1, l*(y0-i)+i, l , p)585if (w[0]==v[0] and w[1]==v[1] and w[2]==v[2]):586more=True587else:588zeros.append(w)589if more:590a_inf=(a*x0**2+b*y0**2+t*x0*y0-2*b*y0-t*x0+s*x0+r*y0+b+c-r)%p591#b_inf=(2*b*y0+t*x0-2*b+r)%p592if a_inf==0:593w=(x0%p,(y0-1)%p,1)594zeros.append(w)595else:596c_inf=b%p597l=c_inf*ZZ(a_inf).inverse_mod(p)598w = primitivize(l*x0, l*(y0-1)+1, l, p)599zeros.append(w)600601return zeros602603604605def _find_zeros_mod_p(a, b, c, r, s, t, p):606"""607Finds the zeros mod p of the ternary quadratic form given by the coefficients (a, b, c, r, s, t), where p is608a prime that doesn't divides the discriminant of the form.609610EXAMPLES::611612sage: from sage.quadratic_forms.ternary import _find_zeros_mod_p613sage: Q = TernaryQF([1, 2, 2, -1, 0, 0])614sage: p = 1009615sage: zeros_1009 = _find_zeros_mod_p(1, 2, 2, -1, 0, 0, p)616sage: len(zeros_1009)6171010618sage: zeros_1009.sort()619sage: zeros_1009[0]620(0, 32, 1)621sage: Q((0, 32, 1))6222018623sage: zeros_2 = _find_zeros_mod_p(1, 2, 2, -1, 0, 0, 2)624sage: zeros_2625[(0, 1, 0), (0, 0, 1), (1, 1, 1)]626627"""628629if p==2:630return _find_zeros_mod_p_2(a, b, c, r, s, t)631else:632v = pseudorandom_primitive_zero_mod_p(a, b, c, r, s, t, p)633return _find_zeros_mod_p_odd(a, b, c, r, s, t, p, v)634635636def _find_all_ternary_qf_by_level_disc(long long N, long long d):637"""638Find the coefficients of all the reduced ternary quadratic forms given its discriminant d and level N.639If N|4d and d|N^2, then it may be some forms with that discriminant and level.640641EXAMPLES::642643sage: from sage.quadratic_forms.ternary import _find_all_ternary_qf_by_level_disc644sage: _find_all_ternary_qf_by_level_disc(44, 11)645[(1, 1, 3, 0, -1, 0), (1, 1, 4, 1, 1, 1)]646sage: _find_all_ternary_qf_by_level_disc(44, 11^2 * 16)647[(3, 15, 15, -14, -2, -2), (4, 11, 12, 0, -4, 0)]648sage: Q = TernaryQF([1, 1, 3, 0, -1, 0])649sage: Q.is_eisenstein_reduced()650True651sage: Q.reciprocal_reduced()652Ternary quadratic form with integer coefficients:653[4 11 12]654[0 -4 0]655sage: _find_all_ternary_qf_by_level_disc(44, 22)656[]657sage: _find_all_ternary_qf_by_level_disc(44, 33)658Traceback (most recent call last):659...660ValueError: There are no ternary forms of this level and discriminant661662663"""664665cdef long long a666cdef long long b667cdef long long c668cdef long long r669cdef long long s670cdef long long t671cdef long long m672cdef long long mu673cdef long long g674cdef long long u675cdef long long v676cdef long long g1677cdef long long m_q678cdef double a_max679cdef double r_max680cdef double b_max681cdef long long stu2682cdef long long mg683684685686l=[]687688if (4*d)%N!=0:689raise ValueError, "There are no ternary forms of this level and discriminant"690else:691m=4*d//N692693if (N**2)%d!=0:694raise ValueError, "There are no ternary forms of this level and discriminant"695else:696mu=N*N//d697698m_2=m%2699mu_2=mu%2700701a=1702a_max=(d/2.)**(1/3.)703while a<=a_max:704705[g,u,v]=xgcd(4*a,m)706g1=(ZZ(g).squarefree_part()*g).sqrtrem()[0]707t=0708while t<=a:709710alpha=max(a,m/4/a)711b=alpha+((((u*t*t//g)-alpha))%(m//g))712b_max=(d/2.0/a)**(1/2.)713while b<=b_max:714715s=0716beta=g//gcd(g,2*t)717while s<=a:718719r = -b+((((2*s*t*u//g)+b))%(m//g))720if s*t==0:721r_max=0722else:723r_max=b724while r<=r_max:725726if (d-r*s*t+a*r*r+b*s*s)%(4*a*b-t**2)==0:727728c=(d-r*s*t+a*r*r+b*s*s)//(4*a*b-t**2)729if r <= 0:730is_reduced = True731if r < -b:732is_reduced = False733elif not (b <= c and 0 <= a+b+r-s-t):734is_reduced = False735elif a == b and abs(r) > abs(s):736is_reduced = False737elif b == c and abs(s) > abs(t):738is_reduced = False739elif a+b+r-s-t == 0 and 2*a-2*s-t > 0:740is_reduced = False741elif a == t and s != 0:742is_reduced = False743elif a == s and t != 0:744is_reduced = False745elif b == -r and t != 0:746is_reduced = False747if is_reduced:748m_q=gcd((4*b*c-r**2, 4*a*c-s**2, 4*a*b-t**2, 2*s*t-4*a*r, -2*r*t+4*b*s, -2*r*s+4*c*t))749if m_q==m:750l.append((ZZ(a), ZZ(b), ZZ(c), ZZ(r), ZZ(-s), ZZ(-t)))751else:752is_reduced=True753if not (b <= c and 0 <= a+b+r+s+t):754is_reduced = False755elif a == b and abs(r) > abs(s):756is_reduced = False757elif b == c and abs(s) > abs(t):758is_reduced = False759elif a+b+r+s+t == 0 and 2*a+2*s+t > 0:760is_reduced = False761elif a == t and s > 2*r:762is_reduced = False763elif a == s and t > 2*r:764is_reduced = False765elif b == r and t > 2*s:766is_reduced = False767if is_reduced:768m_q=gcd((4*b*c-r**2, 4*a*c-s**2, 4*a*b-t**2, 2*s*t-4*a*r, 2*r*t-4*b*s, 2*r*s-4*c*t))769if m_q==m:770l.append((ZZ(a), ZZ(b), ZZ(c), ZZ(r), ZZ(s), ZZ(t)))771r+=(m//g)772s+=beta773b+=m//g774t+=g1775776a+=1777return l778779780781def _find_a_ternary_qf_by_level_disc(long long N, long long d):782"""783Find the coefficients of a reduced ternary quadratic form given its discriminant d and level N.784If N|4d and d|N^2, then it may be a form with that discriminant and level.785786EXAMPLES::787788sage: from sage.quadratic_forms.ternary import _find_a_ternary_qf_by_level_disc789sage: _find_a_ternary_qf_by_level_disc(44, 11)790(1, 1, 3, 0, -1, 0)791sage: _find_a_ternary_qf_by_level_disc(44, 11^2 * 16)792(3, 15, 15, -14, -2, -2)793sage: Q = TernaryQF([1, 1, 3, 0, -1, 0])794sage: Q.is_eisenstein_reduced()795True796sage: Q.level()79744798sage: Q.disc()79911800sage: _find_a_ternary_qf_by_level_disc(44, 22)801sage: _find_a_ternary_qf_by_level_disc(44, 33)802Traceback (most recent call last):803...804ValueError: There are no ternary forms of this level and discriminant805806"""807808cdef long long a809cdef long long b810cdef long long c811cdef long long r812cdef long long s813cdef long long t814cdef long long m815cdef long long mu816cdef long long g817cdef long long u818cdef long long v819cdef long long g1820cdef long long m_q821cdef double a_max822cdef double r_max823cdef double b_max824cdef long long stu2825cdef long long mg826827828829if (4*d)%N!=0:830raise ValueError, "There are no ternary forms of this level and discriminant"831else:832m=4*d//N833834if (N**2)%d!=0:835raise ValueError, "There are no ternary forms of this level and discriminant"836else:837mu=N*N//d838839m_2=m%2840mu_2=mu%2841842a=1843a_max=(d/2.)**(1/3.)844while a<=a_max:845846[g,u,v]=xgcd(4*a,m)847g1=(ZZ(g).squarefree_part()*g).sqrtrem()[0]848t=0849while t<=a:850851alpha=max(a,m/4/a)852b=alpha+((((u*t*t//g)-alpha))%(m//g))853b_max=(d/2.0/a)**(1/2.)854while b<=b_max:855856s=0857beta=g//gcd(g,2*t)858while s<=a:859860r = -b+((((2*s*t*u//g)+b))%(m//g))861if s*t==0:862r_max=0863else:864r_max=b865while r<=r_max:866867if (d-r*s*t+a*r*r+b*s*s)%(4*a*b-t**2)==0:868869c=(d-r*s*t+a*r*r+b*s*s)//(4*a*b-t**2)870if r <= 0:871is_reduced = True872if r < -b:873is_reduced = False874elif not (b <= c and 0 <= a+b+r-s-t):875is_reduced = False876elif a == b and abs(r) > abs(s):877is_reduced = False878elif b == c and abs(s) > abs(t):879is_reduced = False880elif a+b+r-s-t == 0 and 2*a-2*s-t > 0:881is_reduced = False882elif a == t and s != 0:883is_reduced = False884elif a == s and t != 0:885is_reduced = False886elif b == -r and t != 0:887is_reduced = False888if is_reduced:889m_q=gcd((4*b*c-r**2, 4*a*c-s**2, 4*a*b-t**2, 2*s*t-4*a*r, -2*r*t+4*b*s, -2*r*s+4*c*t))890if m_q==m:891return ZZ(a), ZZ(b), ZZ(c), ZZ(r), ZZ(-s), ZZ(-t)892else:893is_reduced = True894if not (b <= c and 0 <= a+b+r+s+t):895is_reduced = False896elif a == b and abs(r) > abs(s):897is_reduced = False898elif b == c and abs(s) > abs(t):899is_reduced = False900elif a+b+r+s+t == 0 and 2*a+2*s+t > 0:901is_reduced = False902elif a==t and s > 2*r:903is_reduced = False904elif a == s and t>2*r:905is_reduced = False906elif b == r and t > 2*s:907is_reduced = False908if is_reduced:909m_q=gcd((4*b*c-r**2, 4*a*c-s**2, 4*a*b-t**2, 2*s*t-4*a*r, 2*r*t-4*b*s, 2*r*s-4*c*t))910if m_q==m:911return ZZ(a), ZZ(b), ZZ(c), ZZ(r), ZZ(s), ZZ(t)912r+=(m//g)913s+=beta914b+=m//g915t+=g1916917a+=1918919920921def extend(v):922"""923Return the coefficients of a matrix M such that M has determinant gcd(v) and the first column is v.924925EXAMPLES::926927sage: from sage.quadratic_forms.ternary import extend928sage: v = (6, 4, 12)929sage: m = extend(v)930sage: M = matrix(3, m)931sage: M932[ 6 1 0]933[ 4 1 0]934[12 0 1]935sage: M.det()9362937sage: v = (-12, 20, 30)938sage: m = extend(v)939sage: M = matrix(3, m)940sage: M941[-12 1 0]942[ 20 -2 1]943[ 30 0 -7]944sage: M.det()9452946947"""948949b1 = xgcd(v[0], v[1])950b2 = xgcd(b1[1], b1[2])951b3 = xgcd(b1[0], v[2])952953return v[0], -b1[2], -b2[1]*b3[2], v[1], b1[1], -b2[2]*b3[2], v[2], 0, b3[1]954955956def _find_p_neighbor_from_vec(a, b, c, r, s, t, p, v, mat = False):957"""958Finds the coefficients of the reduced equivalent of the p-neighbor959of the ternary quadratic given by Q = (a, b, c, r, s, t) form associated960to a given vector v satisfying:9619621. Q(v) = 0 mod p9639642. v is a non-singular point of the conic Q(v) = 0 mod p.965966Reference: Gonzalo Tornaria's Thesis, Thrm 3.5, p34.967968EXAMPLES:969970sage: from sage.quadratic_forms.ternary import _find_p_neighbor_from_vec971sage: Q = TernaryQF([1, 3, 3, -2, 0, -1])972sage: Q973Ternary quadratic form with integer coefficients:974[1 3 3]975[-2 0 -1]976sage: Q.disc()97729978sage: v = (9, 7, 1)979sage: v in Q.find_zeros_mod_p(11)980True981sage: q11, M = _find_p_neighbor_from_vec(1, 3, 3, -2, 0, -1, 11, v, mat = True)982sage: Q11 = TernaryQF(q11)983sage: Q11984Ternary quadratic form with integer coefficients:985[1 2 4]986[-1 -1 0]987sage: M = matrix(3, M)988sage: M989[ -1 -5/11 7/11]990[ 0 -10/11 3/11]991[ 0 -3/11 13/11]992sage: Q(M) == Q11993True994995"""996997v0, w0, u0, v1, w1, u1, v2, w2, u2 = extend(v)998999m00 = 2*a*v0**2 + 2*b*v1**2 + 2*c*v2**2 + 2*r*v1*v2 + 2*s*v0*v2 + 2*t*v0*v11000m11 = 2*a*w0**2 + 2*b*w1**2 + 2*t*w0*w11001m22 = 2*a*u0**2 + 2*b*u1**2 + 2*c*u2**2 + 2*r*u1*u2 + 2*s*u0*u2 + 2*t*u0*u11002m01 = 2*a*v0*w0 + 2*b*v1*w1 + r*v2*w1 + s*v2*w0 + t*v0*w1 + t*v1*w01003m02 = 2*a*u0*v0 + 2*b*u1*v1 + 2*c*u2*v2 + r*u1*v2 + r*u2*v1 + s*u0*v2 + s*u2*v0 + t*u0*v1 + t*u1*v01004m12 = 2*a*u0*w0 + 2*b*u1*w1 + r*u2*w1 + s*u2*w0 + t*u0*w1 + t*u1*w0100510061007if m02%p!=0:10081009m0 = (-m00/m02/2) % p**21010m1 = (-m01/m02) % p10111012b00 = m0**2*m22/p**2 + 2*m0*m02/p**2 + m00/p**21013b11 = m1**2*m22 + 2*m1*m12 + m111014b22 = m22*p**21015b01 = m0*m1*m22/p + m0*m12/p + m02*m1/p + m01/p1016b02 = m0*m22 + m021017b12 = m1*m22*p + m12*p10181019if mat:1020q, Mr = _reduced_ternary_form_eisenstein_with_matrix(ZZ(b00/2), ZZ(b11/2), ZZ(b22/2), ZZ(b12), ZZ(b02), ZZ(b01))1021r00, r01, r02, r10, r11, r12, r20, r21, r22 = Mr.list()1022t00 = p*r20*u0 + (m0*u0/p + v0/p)*r00 + (m1*u0 + w0)*r101023t01 = p*r21*u0 + (m0*u0/p + v0/p)*r01 + (m1*u0 + w0)*r111024t02 = p*r22*u0 + (m0*u0/p + v0/p)*r02 + (m1*u0 + w0)*r121025t10 = p*r20*u1 + (m0*u1/p + v1/p)*r00 + (m1*u1 + w1)*r101026t11 = p*r21*u1 + (m0*u1/p + v1/p)*r01 + (m1*u1 + w1)*r111027t12 = p*r22*u1 + (m0*u1/p + v1/p)*r02 + (m1*u1 + w1)*r121028t20 = p*r20*u2 + (m0*u2/p + v2/p)*r00 + (m1*u2 + w2)*r101029t21 = p*r21*u2 + (m0*u2/p + v2/p)*r01 + (m1*u2 + w2)*r111030t22 = p*r22*u2 + (m0*u2/p + v2/p)*r02 + (m1*u2 + w2)*r121031return q, (t00, t01, t02, t10, t11, t12, t20, t21, t22)1032else:1033return _reduced_ternary_form_eisenstein_without_matrix(ZZ(b00/2), ZZ(b11/2), ZZ(b22/2), ZZ(b12), ZZ(b02), ZZ(b01))10341035if m01%p!=0:10361037m0 = (-m00/m01/2) % p**21038m1 = (-m02/m01) % p10391040b00 = m0**2*m11/p**2 + 2*m0*m01/p**2 + m00/p**21041b11 = m1**2*m11 + 2*m1*m12 + m221042b22 = m11*p**21043b01 = m0*m1*m11/p + m0*m12/p + m01*m1/p + m02/p1044b02 = m0*m11 + m011045b12 = m1*m11*p + m12*p10461047if mat:1048q, Mr = _reduced_ternary_form_eisenstein_with_matrix(ZZ(b00/2), ZZ(b11/2), ZZ(b22/2), ZZ(b12), ZZ(b02), ZZ(b01))1049r00, r01, r02, r10, r11, r12, r20, r21, r22 = Mr.list()1050t00 = p*r20*w0 + (m0*w0/p + v0/p)*r00 + (m1*w0 + u0)*r101051t01 = p*r21*w0 + (m0*w0/p + v0/p)*r01 + (m1*w0 + u0)*r111052t02 = p*r22*w0 + (m0*w0/p + v0/p)*r02 + (m1*w0 + u0)*r121053t10 = p*r20*w1 + (m0*w1/p + v1/p)*r00 + (m1*w1 + u1)*r101054t11 = p*r21*w1 + (m0*w1/p + v1/p)*r01 + (m1*w1 + u1)*r111055t12 = p*r22*w1 + (m0*w1/p + v1/p)*r02 + (m1*w1 + u1)*r121056t20 = p*r20*w2 + (m0*w2/p + v2/p)*r00 + (m1*w2 + u2)*r101057t21 = p*r21*w2 + (m0*w2/p + v2/p)*r01 + (m1*w2 + u2)*r111058t22 = p*r22*w2 + (m0*w2/p + v2/p)*r02 + (m1*w2 + u2)*r121059return q, (t00, t01, t02, t10, t11, t12, t20, t21, t22)1060else:1061return _reduced_ternary_form_eisenstein_without_matrix(ZZ(b00/2), ZZ(b11/2), ZZ(b22/2), ZZ(b12), ZZ(b02), ZZ(b01))106210631064def _basic_lemma_vec(a, b, c, r, s, t, n):1065"""1066Find a vector v such that the ternary quadratic form given by (a, b, c, r, s, t) evaluated at v is1067coprime with n a prime or 1.10681069EXAMPLES::10701071sage: from sage.quadratic_forms.ternary import _basic_lemma_vec1072sage: Q = TernaryQF([5, 2, 3, -1, 0, 0])1073sage: v = _basic_lemma_vec(5, 2, 3, -1, 0, 0, 5)1074sage: v1075(0, 1, 0)1076sage: Q(v)1077210781079"""10801081if n == 1:1082return 0, 0, 010831084if a%n != 0:1085return 1, 0, 01086elif b%n != 0:1087return 0, 1, 01088elif c%n != 0:1089return 0, 0, 110901091if r%n != 0:1092return 0, 1, 11093elif s%n != 0:1094return 1, 0, 11095elif t%n != 0:1096return 1, 1, 010971098raise ValueError, "not primitive form"10991100def _basic_lemma(a, b, c, r, s, t, n):1101"""1102Finds a number represented by the ternary quadratic form given by the coefficients (a, b, c, r, s, t)1103and coprime to the prime n.11041105EXAMPLES::11061107sage: from sage.quadratic_forms.ternary import _basic_lemma1108sage: Q = TernaryQF([5, 2, 3, -1, 0, 0])1109sage: _basic_lemma(5, 2, 3, -1, 0, 0, 5)1110211111112"""11131114if n == 1:1115return 011161117if a%n != 0:1118return a1119elif b%n != 0:1120return b1121elif c%n != 0:1122return c11231124if r%n != 0:1125return b + c + r1126elif s%n != 0:1127return a + c + s1128elif t%n != 0:1129return a + b + t11301131raise ValueError, "not primitive form"1132113311341135