Path: blob/master/src/sage/quadratic_forms/ternary_qf.py
8817 views
"""1Ternary Quadratic Form with integer coefficients.23AUTHOR:45- Gustavo Rama67Based in code of Gonzalo Tornaria89The form `a*x^2 + b*y^2 + c*z^2 + r*yz + s*xz + t*xy` is stored as a tuple (a, b, c, r, s, t) of integers.1011"""1213#*****************************************************************************14# Copyright (C) 2012 Gustavo Rama15#16# Distributed under the terms of the GNU General Public License (GPL)17#18# This code is distributed in the hope that it will be useful,19# but WITHOUT ANY WARRANTY; without even the implied warranty of20# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU21# General Public License for more details.22#23# The full text of the GPL is available at:24#25# http://www.gnu.org/licenses/26#*****************************************************************************272829from sage.structure.sage_object import SageObject30from sage.rings.all import ZZ31from sage.rings.arith import gcd, inverse_mod, kronecker_symbol32from sage.quadratic_forms.quadratic_form import QuadraticForm33from sage.matrix.constructor import matrix, identity_matrix34from sage.matrix.matrix import Matrix, is_Matrix35from sage.structure.element import is_Vector36from sage.quadratic_forms.ternary import _reduced_ternary_form_eisenstein_with_matrix37from sage.quadratic_forms.ternary import _reduced_ternary_form_eisenstein_without_matrix, _find_zeros_mod_p_odd, _find_zeros_mod_p_2, _find_p_neighbor_from_vec, _basic_lemma38from sage.quadratic_forms.ternary import _find_all_ternary_qf_by_level_disc, _find_a_ternary_qf_by_level_disc39from sage.misc.prandom import randint40from sage.rings.finite_rings.integer_mod import mod41from sage.modules.free_module_element import vector42from sage.rings.ring import is_Ring43from sage.rings.rational_field import QQ44from sage.rings.polynomial.polynomial_ring import polygen, polygens4546class TernaryQF(SageObject):47"""48The ``TernaryQF`` class represents a quadratic form in 3 variables with coefficients in Z.4950INPUT:51- `v` -- a list or tuple of 6 entries: [a,b,c,r,s,t]5253OUTPUT:54- the ternary quadratic form a*x^2 + b*y^2 + c*z^2 + r*y*z + s*x*z + t*x*y.5556EXAMPLES::5758sage: Q = TernaryQF([1, 2, 3, 4, 5, 6])59sage: Q60Ternary quadratic form with integer coefficients:61[1 2 3]62[4 5 6]63sage: A = matrix(ZZ, 3, [1, -7, 1, 0, -2, 1, 0, -1, 0])64sage: Q(A)65Ternary quadratic form with integer coefficients:66[1 187 9]67[-85 8 -31]68sage: TestSuite(TernaryQF).run()697071"""727374__slots__ = ['_a', '_b', '_c', '_r', '_s', '_t', '_automorphisms', '_number_of_automorphisms']7576possible_automorphisms = None7778def __init__(self,v):79"""80Creates the ternary quadratic form `a*x^2 + b*y^2 + c*z^2 + r*y*z + s*x*z + t*x*y.` from the81tuple v=[a,b,c,r,s,t] over `\ZZ`.8283INPUT:8485- ``v`` -- 6-tuple of integers8687EXAMPLES::8889sage: Q = TernaryQF([1, 2, 3, 4, 5, 6])90sage: Q91Ternary quadratic form with integer coefficients:92[1 2 3]93[4 5 6]949596"""9798if len(v) != 6:99# Check we have six coefficients100raise ValueError, "Ternary quadratic form must be given by a list of six coefficients"101self._a, self._b, self._c, self._r, self._s, self._t = [ZZ(x) for x in v]102self._automorphisms = None103self._number_of_automorphisms = None104105106def coefficients(self):107"""108Return the list coefficients of the ternary quadratic form.109110EXAMPLES::111112sage: Q = TernaryQF([1, 2, 3, 4, 5, 6])113sage: Q114Ternary quadratic form with integer coefficients:115[1 2 3]116[4 5 6]117sage: Q.coefficients()118(1, 2, 3, 4, 5, 6)119120"""121122return self._a, self._b, self._c, self._r, self._s, self._t123124def coefficient(self,n):125"""126Return the n-th coefficient of the ternary quadratic form, with 0<=n<=5.127128EXAMPLES::129130sage: Q = TernaryQF([1, 2, 3, 4, 5, 6])131sage: Q132Ternary quadratic form with integer coefficients:133[1 2 3]134[4 5 6]135sage: Q.coefficient(2)1363137sage: Q.coefficient(5)1386139140"""141142return self.coefficients()[n]143144def polynomial(self,names='x,y,z'):145"""146Return the polynomial associated to the ternary quadratic form.147148EXAMPLES::149150sage: Q = TernaryQF([1, 1, 0, 2, -3, -1])151sage: Q152Ternary quadratic form with integer coefficients:153[1 1 0]154[2 -3 -1]155sage: p = Q.polynomial()156sage: p157x^2 - x*y + y^2 - 3*x*z + 2*y*z158sage: p.parent()159Multivariate Polynomial Ring in x, y, z over Integer Ring160161"""162(x,y,z) = polygens(ZZ,names)163return self._a * x**2 + self._b* y**2 + self._c * z**2 + self._t * x*y + self._s * x*z + self._r * y*z164165166def _repr_(self):167"""168Display the quadratic form.169170EXAMPLES::171172sage: Q = TernaryQF([1, 1, 0, 2, -3, -1])173sage: print Q._repr_()174Ternary quadratic form with integer coefficients:175[1 1 0]176[2 -3 -1]177sage: Q = TernaryQF([0, 0, 0, 0, 0, 0]); Q178Ternary quadratic form with integer coefficients:179[0 0 0]180[0 0 0]181182183"""184rep = 'Ternary quadratic form with integer coefficients:\n'185rep+= '[' + str(self._a) + ' ' + str(self._b) + ' ' + str(self._c) + ']\n'186rep+= '[' + str(self._r) + ' ' + str(self._s) + ' ' + str(self._t) + ']'187return rep188189def __call__(self, v):190"""191Evaluate this ternary quadratic form Q on a vector of 3 elements, or matrix of elements in Z, with 3 rows. If a vector is given then the output will be an integer Q(`v`), but if a matrix is given the output will be a ternary quadratic form if the matrix has 3 columns, or a quadratic form if not. The quadratic form in matrix notation will be:192193.. math::194Q' = v^t * Q * v.195196EXAMPLES::197198sage: Q = TernaryQF([1, 1, 1, -1, -2, -3])199sage: Q((1, 1, 1))200-3201sage: M = matrix(ZZ, 3, 2, [358, 6, 2, 0, 0, 4])202sage: Q(M)203Quadratic form in 2 variables over Integer Ring with coefficients:204[ 126020 1388 ]205[ * 4 ]206sage: M = matrix(ZZ, 3, 3, [1, 3, 0, -1, 4, 2, 1, -1, -1])207sage: M208[ 1 3 0]209[-1 4 2]210[ 1 -1 -1]211sage: Q(M)212Ternary quadratic form with integer coefficients:213[5 0 7]214[12 -13 -16]215216"""217if is_Matrix(v):218## Check that v has 3 rows219if v.nrows() != 3:220raise TypeError, "Oops! The matrix must have 3 rows."221## Check if v has 3 cols222if v.ncols() == 3:223M = v.transpose() * self.matrix() * v224return TernaryQF([M[0,0]//2, M[1,1]//2, M[2,2]//2, M[1,2], M[0,2], M[0,1]])225else:226return QuadraticForm(ZZ, v.transpose() * self.matrix() * v)227elif (is_Vector(v) or isinstance(v, (list, tuple))):228## Check that v has lenght 3229if not (len(v) == 3):230raise TypeError, "Oops! Your vector needs to have length 3"231v0, v1, v2 = v232a, b, c, r, s, t = self.coefficients()233return a*v0**2 + b*v1**2 + c*v2**2 + r*v1*v2 + s*v0*v2 + t*v0*v1234else:235raise TypeError, "Oops! Presently we can only evaluate a quadratic form on a list, tuple, vector ot matrix"236237238def quadratic_form(self):239"""240Return the object QuadraticForm with the same coefficients as Q over ZZ.241242EXAMPLES::243244sage: Q = TernaryQF([1, 2, 3, 1, 1, 1])245sage: QF1 = Q.quadratic_form()246sage: QF1247Quadratic form in 3 variables over Integer Ring with coefficients:248[ 1 1 1 ]249[ * 2 1 ]250[ * * 3 ]251sage: QF2 = QuadraticForm(ZZ, 3, [1, 1, 1, 2, 1, 3])252sage: bool(QF1 == QF2)253True254"""255256257return QuadraticForm(ZZ, 3, [self._a, self._t, self._s, self._b, self._r, self._c])258259def matrix(self):260"""261Return the Hessian matrix associated to the ternary quadratic form.262That is, if Q is a ternary quadratic form, Q(x,y,z) = a*x^2 + b*y^2 + c*z^2 + r*y*z + s*x*z + t*x*y,263then the Hessian matrix associated to Q is264::265266[2*a t s]267[t 2*b r]268[s r 2*c]269270EXAMPLES::271272sage: Q = TernaryQF([1,1,2,0,-1,4])273sage: Q274Ternary quadratic form with integer coefficients:275[1 1 2]276[0 -1 4]277sage: M = Q.matrix()278sage: M279[ 2 4 -1]280[ 4 2 0]281[-1 0 4]282sage: v = vector((1, 2, 3))283sage: Q(v)28428285sage: (v*M*v.column())[0]//228628287288"""289290M = matrix(ZZ, 3, [2*self._a, self._t, self._s, self._t, 2*self._b, self._r, self._s, self._r, 2*self._c])291return M292293def disc(self):294"""295Return the discriminant of the ternary quadratic form, this is the determinant of the matrix divided by 2.296297EXAMPLES::298299sage: Q = TernaryQF([1, 1, 2, 0, -1, 4])300sage: Q.disc()301-25302sage: Q.matrix().det()303-50304305"""306307return 4*self._a*self._b*self._c + self._r*self._s*self._t - self._a*self._r**2 - self._b*self._s**2 - self._c*self._t**2308309def is_definite(self):310"""311Determines if the ternary quadratic form is definite.312313EXAMPLES::314315sage: Q = TernaryQF([10, 10, 1, -1, 2, 3])316sage: Q.is_definite()317True318sage: (-Q).is_definite()319True320sage: Q = TernaryQF([1, 1, 2, -3, 0, -1])321sage: Q.is_definite()322False323324"""325326d1 = self._a327if d1 == 0:328return False329d2 = 4*self._a*self._b-self._t**2330if d2 == 0:331return False332d3 = self.disc()333if d3 == 0:334return False335if d1 > 0:336if d2 > 0:337if d3 > 0:338return True339else:340return False341else:342return False343else:344if d2 > 0:345if d3 < 0:346return True347else:348return False349else:350return False351352def is_positive_definite(self):353"""354Determines if the ternary quadratic form is positive definite.355356EXAMPLES::357358sage: Q = TernaryQF([10, 10, 1, -1, 2, 3])359sage: Q.is_positive_definite()360True361sage: (-Q).is_positive_definite()362False363sage: Q = TernaryQF([1, 1, 0, 0, 0, 0])364sage: Q.is_positive_definite()365False366sage: Q = TernaryQF([1, 1, 1, -1, -2, -3])367sage: Q((1,1,1))368-3369sage: Q.is_positive_definite()370False371372"""373374d1 = self._a375if d1 == 0:376return False377d2 = 4*self._a*self._b-self._t**2378if d2 == 0:379return False380d3 = self.disc()381if d3 == 0:382return False383if d1 > 0:384if d2 > 0:385if d3 > 0:386return True387else:388return False389else:390return False391else:392return False393394def is_negative_definite(self):395"""396Determines if the ternary quadratic form is negatice definite.397398EXAMPLES::399400sage: Q = TernaryQF([-8, -9, -10, 1, 9, -3])401sage: Q.is_negative_definite()402True403sage: Q = TernaryQF([-4, -1, 6, -5, 1, -5])404sage: Q((0, 0, 1))4056406sage: Q.is_negative_definite()407False408409"""410411d1 = self._a412if d1 == 0:413return False414d2 = 4*self._a*self._b-self._t**2415if d2 == 0:416return False417d3 = self.disc()418if d3 == 0:419return False420if d1 < 0:421if d2 > 0:422if d3 < 0:423return True424else:425return False426else:427return False428else:429return False430431def __neg__(self):432"""433Returns the ternary quadratic form with coefficients negatives of self.434435EXAMPLES::436437sage: Q = TernaryQF([1, 1, 2, -2, 0, -1])438sage: Q439Ternary quadratic form with integer coefficients:440[1 1 2]441[-2 0 -1]442sage: -Q443Ternary quadratic form with integer coefficients:444[-1 -1 -2]445[2 0 1]446sage: Q = TernaryQF([0, 0, 0, 0, 0, 0])447sage: Q==-Q448True449450"""451452return TernaryQF([-a for a in self.coefficients()])453454def is_primitive(self):455"""456Determines if the ternary quadratic form is primitive, i.e. the greatest common divisor of the coefficients of the form is 1.457458EXAMPLES::459460sage: Q = TernaryQF([1, 2, 3, 4, 5, 6])461sage: Q.is_primitive()462True463sage: Q.content()4641465sage: Q = TernaryQF([10, 10, 10, 5, 5, 5])466sage: Q.content()4675468sage: Q.is_primitive()469False470"""471472return self.content() == 1473474def primitive(self):475"""476Returns the primitive version of the ternary quadratic form.477478EXAMPLES::479480sage: Q = TernaryQF([2, 2, 2, 1, 1, 1])481sage: Q.is_primitive()482True483sage: Q.primitive()484Ternary quadratic form with integer coefficients:485[2 2 2]486[1 1 1]487sage: Q.primitive() == Q488True489sage: Q = TernaryQF([10, 10, 10, 5, 5, 5])490sage: Q.primitive()491Ternary quadratic form with integer coefficients:492[2 2 2]493[1 1 1]494495"""496497l = self.coefficients()498g = gcd(l)499return TernaryQF([a//g for a in l])500501def scale_by_factor(self, k):502"""503Scale the values of the ternary quadratic form by the number c, if c times the content of the ternary quadratic form is an integer it returns a ternary quadratic form, otherwise returns a quadratic form of dimension 3.504505EXAMPLES::506507sage: Q = TernaryQF([2, 2, 4, 0, -2, 8])508sage: Q509Ternary quadratic form with integer coefficients:510[2 2 4]511[0 -2 8]512sage: Q.scale_by_factor(5)513Ternary quadratic form with integer coefficients:514[10 10 20]515[0 -10 40]516sage: Q.scale_by_factor(1/2)517Ternary quadratic form with integer coefficients:518[1 1 2]519[0 -1 4]520sage: Q.scale_by_factor(1/3)521Quadratic form in 3 variables over Rational Field with coefficients:522[ 2/3 8/3 -2/3 ]523[ * 2/3 0 ]524[ * * 4/3 ]525526"""527528if k*self.content() in ZZ:529530return TernaryQF([ZZ(k*self._a), ZZ(k*self._b), ZZ(k*self._c), ZZ(k*self._r), ZZ(k*self._s), ZZ(k*self._t)])531532else:533#arreglar con un try?534R = k.parent()535if is_Ring(R):536537return QuadraticForm(R, 3, [k*self._a, k*self._t, k*self._s, k*self._b, k*self._r, k*self._c])538539else:540541raise TypeError, "Oops! " + k.__repr__() + " doesn't belongs to a Ring"542543def reciprocal(self):544"""545Gives the reciprocal quadratic form associated to the given form. This is defined as the multiple of the primitive adjoint with the same content as the given form.546547EXAMPLES::548549sage: Q = TernaryQF([2, 2, 14, 0, 0, 0])550sage: Q.reciprocal()551Ternary quadratic form with integer coefficients:552[14 14 2]553[0 0 0]554sage: Q.content()5552556sage: Q.reciprocal().content()5572558sage: Q.adjoint().content()55916560561562"""563564return self.adjoint().primitive().scale_by_factor( self.content() )565566def reciprocal_reduced(self):567"""568Returns the reduced form of the reciprocal form of the given ternary quadratic form.569570EXAMPLES::571572sage: Q = TernaryQF([1, 1, 3, 0, -1, 0])573sage: Qrr = Q.reciprocal_reduced()574sage: Qrr575Ternary quadratic form with integer coefficients:576[4 11 12]577[0 -4 0]578sage: Q.is_eisenstein_reduced()579True580sage: Qr = Q.reciprocal()581sage: Qr.reduced_form_eisenstein(matrix = False) == Qrr582True583584"""585586return self.reciprocal().reduced_form_eisenstein(matrix = False)587588def divisor(self):589"""590Returns the content of the adjoint form associated to the given form.591592EXAMPLES::593594sage: Q = TernaryQF([1, 1, 17, 0, 0, 0])595sage: Q.divisor()5964597"""598599A11 = 4*self._b*self._c - self._r**2600A22 = 4*self._a*self._c - self._s**2601A33 = 4*self._a*self._b - self._t**2602A23 = self._s*self._t - 2*self._a*self._r603A13 = self._r*self._t - 2*self._b*self._s604A12 = self._r*self._s - 2*self._c*self._t605m = gcd([A11, A22, A33, 2*A12, 2*A13, 2*A23])606return m607608def __eq__(self,right):609"""610Determines if two ternary quadratic forms are equal.611612EXAMPLES::613614sage: Q = TernaryQF([1, 2, 3, 1, 2, 3])615sage: Q == Q616True617sage: Q1 = TernaryQF([1, 2, 3, 1, 2, 2])618sage: Q == Q1619False620621"""622623if not isinstance(right, TernaryQF):624return False625return self.coefficients() == right.coefficients()626627def adjoint(self):628"""629Returns the adjoint form associated to the given ternary quadratic form.630That is, the Hessian matrix of the adjoint form is twice the adjoint matrix of the Hessian matrix of the given form.631632EXAMPLES::633634sage: Q = TernaryQF([1, 1, 17, 0, 0, 1])635sage: Q.adjoint()636Ternary quadratic form with integer coefficients:637[68 68 3]638[0 0 -68]639sage: Q.adjoint().matrix() == 2*Q.matrix().adjoint()640True641642"""643644A11 = 4*self._b*self._c - self._r**2645A22 = 4*self._a*self._c - self._s**2646A33 = 4*self._a*self._b - self._t**2647A23 = self._s*self._t - 2*self._a*self._r648A13 = self._r*self._t - 2*self._b*self._s649A12 = self._r*self._s - 2*self._c*self._t650return TernaryQF([A11, A22, A33, 2*A23, 2*A13, 2*A12])651652def content(self):653"""654Returns the greatest common divisor of the coefficients of the given ternary quadratic form.655656EXAMPLES::657658sage: Q = TernaryQF([1, 1, 2, 0, 0, 0])659sage: Q.content()6601661sage: Q = TernaryQF([2, 4, 6, 0, 0, 0])662sage: Q.content()6632664sage: Q.scale_by_factor(100).content()665200666667"""668return gcd(self.coefficients())669670def omega(self):671"""672Returns the content of the adjoint of the primitive associated673ternary quadratic form.674675EXAMPLES::676677sage: Q = TernaryQF([4, 11, 12, 0, -4, 0])678sage: Q.omega()679176680sage: Q.primitive().adjoint().content()681176682683"""684685return self.primitive().adjoint().content()686687def delta(self):688"""689Returns the omega of the adjoint of the given ternary quadratic form,690which is the same as the omega of the reciprocal form.691692EXAMPLES::693694sage: Q = TernaryQF([1, 2, 2, -1, 0, -1])695sage: Q.delta()696208697sage: Q.adjoint().omega()698208699sage: Q = TernaryQF([1, -1, 1, 0, 0, 0])700sage: Q.delta()7014702sage: Q.omega()7034704705"""706707return self.adjoint().omega()708709def level(self):710"""711Returns the level of the ternary quadratic form, which is 4 times the discriminant divided by the divisor.712713EXAMPLES::714715sage: Q = TernaryQF([1, 2, 2, -1, 0, -1])716sage: Q.level()71752718sage: 4*Q.disc()/Q.divisor()71952720721"""722723return 4*self.disc()//self.divisor()724725def is_eisenstein_reduced(self):726"""727Determines if the ternary quadratic form is Eisenstein reduced.728That is, if we have a ternary quadratic form:729::730731[a b c]732[r s t]733734then735736::7377381- a<=b<=c;7392- r, s, and t are all positive or all nonpositive;7403- a>=|t|; a>=|s|; b>=|r|;7414- a+b+r+s+t>=0;7425- a=t implies s<=2*r; a=s implies t<=2*r; b=r implies t<=2*s;7436- a=-t implies s=0; a=-s implies t=0; b=-r implies t=0;7447- a+b+r+s+t=0 implies 2*a+2*s+t<=0;7458- a=b implies |r|<=|s|; b=c implies |s|<=|t|.746747EXAMPLES::748749sage: Q = TernaryQF([1, 1, 1, 0, 0, 0])750sage: Q.is_eisenstein_reduced()751True752sage: Q = TernaryQF([34, 14, 44, 12, 25, -22])753sage: Q.is_eisenstein_reduced()754False755756"""757758759[a,b,c,r,s,t]=[self._a,self._b,self._c,self._r,self._s,self._t]760761# cond 2762if not (r > 0 and t > 0 and s > 0):763if not (r <= 0 and s <= 0 and t <= 0):764return False765766# cond 1 & 4767if not (a <= b <= c and 0 <= a+b+r+s+t):768return False769770# cond 3771if not (a >= abs(s) and a >= abs(t) and b >= abs(r)):772return False773774# cond 8775if a == b and abs(r) > abs(s):776return False777if b == c and abs(s) > abs(t):778return False779if a+b+r+s+t == 0 and 2*a+2*s+t > 0:780return False781782# cond 6783# r, s, t <= 0784if r<=0:785if a == -t and s != 0:786return False787if a == -s and t != 0:788return False789if b == -r and t != 0:790return False791792# cond 7793# r, s, t > 0794if a == t and s > 2*r:795return False796if a == s and t > 2*r:797return False798if b == r and t > 2*s:799return False800801return True802803def reduced_form_eisenstein(self, matrix=True):804"""805Returns the eisenstein reduced form equivalent to the given positive ternary quadratic form,806which is unique.807808EXAMPLES::809810sage: Q = TernaryQF([293, 315, 756, 908, 929, 522])811sage: Qr, m = Q.reduced_form_eisenstein()812sage: Qr813Ternary quadratic form with integer coefficients:814[1 2 2]815[-1 0 -1]816sage: Qr.is_eisenstein_reduced()817True818sage: m819[ -54 137 -38]820[ -23 58 -16]821[ 47 -119 33]822sage: m.det()8231824sage: Q(m) == Qr825True826sage: Q = TernaryQF([12,36,3,14,-7,-19])827sage: Q.reduced_form_eisenstein(matrix = False)828Ternary quadratic form with integer coefficients:829[3 8 20]830[3 2 1]831832"""833834if matrix:835[v,M] = _reduced_ternary_form_eisenstein_with_matrix(self._a,self._b,self._c,self._r,self._s,self._t)836return TernaryQF(v), M837else:838v = _reduced_ternary_form_eisenstein_without_matrix(self._a,self._b,self._c,self._r,self._s,self._t)839return TernaryQF(v)840841def pseudorandom_primitive_zero_mod_p(self,p):842"""843Returns a tuple of the form v = (a, b, 1) such that is a zero of the given ternary quadratic844positive definite form modulo an odd prime p, where p doesn't divides the discriminant of the form.845846EXAMPLES::847848sage: Q = TernaryQF([1, 1, 11, 0, -1, 0])849sage: Q.disc()85043851sage: Q.pseudorandom_primitive_zero_mod_p(3) ## RANDOM852(1, 2, 1)853sage: Q((1, 2, 1))85415855sage: v = Q.pseudorandom_primitive_zero_mod_p(1009)856sage: Q(v) % 10098570858sage: v[2]8591860"""861862[a,b,c,r,s,t] = self.coefficients()863while True:864865r1=randint(0,p-1)866r2=randint(0,p-1)867alpha=(b*r1**2+t*r1+a)%p868if alpha != 0:869870beta=(2*b*r1*r2+t*r2+r*r1+s)%p871gamma=(b*r2**2+r*r2+c)%p872disc=beta**2-4*alpha*gamma873if mod(disc,p).is_square():874875z=(-beta+mod(disc,p).sqrt().lift())*(2*alpha).inverse_mod(p)876#return vector((z,r1*z+r2,1))%p877return z%p, (r1*z+r2)%p, 1878879880def find_zeros_mod_p(self, p):881"""882Find the zeros of the given ternary quadratic positive definite form modulo a prime p, where p doesn't divides the discriminant of the form.883884EXAMPLES::885886sage: Q = TernaryQF([4, 7, 8, -4, -1, -3])887sage: Q.is_positive_definite()888True889sage: Q.disc().factor()8903 * 13 * 19891sage: Q.find_zeros_mod_p(2)892[(1, 0, 0), (1, 1, 0), (0, 0, 1)]893sage: zeros_17 = Q.find_zeros_mod_p(17)894sage: len(zeros_17)89518896sage: [Q(v)%17 for v in zeros_17]897[0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0]898899900"""901902if p==2:903904return _find_zeros_mod_p_2(self._a, self._b, self._c, self._r, self._s, self._t)905906else:907908v = self.pseudorandom_primitive_zero_mod_p(p)909[a, b, c, r, s, t] = self.coefficients()910return _find_zeros_mod_p_odd(a, b, c, r, s, t, p, v)911912913def find_p_neighbor_from_vec(self, p, v, mat = False):914"""915Finds the reduced equivalent of the p-neighbor of this ternary quadratic form associated to a given916vector v satisfying:9179181. Q(v) = 0 mod p9199202. v is a non-singular point of the conic Q(v) = 0 mod p.921922Reference: Gonzalo Tornaria's Thesis, Thrm 3.5, p34.923924EXAMPLES::925926sage: Q = TernaryQF([1, 3, 3, -2, 0, -1])927sage: Q928Ternary quadratic form with integer coefficients:929[1 3 3]930[-2 0 -1]931sage: Q.disc()93229933sage: v = (9, 7, 1)934sage: v in Q.find_zeros_mod_p(11)935True936sage: Q11, M = Q.find_p_neighbor_from_vec(11, v, mat = True)937sage: Q11938Ternary quadratic form with integer coefficients:939[1 2 4]940[-1 -1 0]941sage: M942[ -1 -5/11 7/11]943[ 0 -10/11 3/11]944[ 0 -3/11 13/11]945sage: Q(M) == Q11946True947948"""949950if mat:951q, M = _find_p_neighbor_from_vec(self._a, self._b, self._c, self._r, self._s, self._t, p, v, mat)952M = matrix(3,M)953return TernaryQF(q), M*M.det()954else:955return TernaryQF(_find_p_neighbor_from_vec(self._a, self._b, self._c, self._r, self._s, self._t, p, v, mat))956957def find_p_neighbors(self, p, mat = False):958"""959Find a list with all the reduced equivalent of the p-neighbors of this ternary quadratic form, given by the zeros mod p of the form.960See find_p_neighbor_from_vec for more information.961962EXAMPLES::963964sage: Q0 = TernaryQF([1, 3, 3, -2, 0, -1])965sage: Q0966Ternary quadratic form with integer coefficients:967[1 3 3]968[-2 0 -1]969sage: neig = Q0.find_p_neighbors(5)970sage: len(neig)9716972sage: Q1 = TernaryQF([1, 1, 10, 1, 1, 1])973sage: Q2 = TernaryQF([1, 2, 4, -1, -1, 0])974sage: neig.count(Q0)9752976sage: neig.count(Q1)9771978sage: neig.count(Q2)9793980981"""982983z = self.find_zeros_mod_p(p)984return [self.find_p_neighbor_from_vec(p, v, mat) for v in z]985986987def basic_lemma(self, p):988"""989Finds a number represented by self and coprime to the prime p.990991EXAMPLES::992993sage: Q = TernaryQF([3, 3, 3, -2, 0, -1])994sage: Q.basic_lemma(3)9954996"""997998return _basic_lemma(self._a, self._b, self._c, self._r, self._s, self._t, p)9991000def xi(self, p):1001"""1002Return the value of the genus characters Xi_p... which may be1003missing one character. We allow -1 as a prime.10041005Reference: Dickson's "Studies in the Theory of Numbers"10061007EXAMPLES::10081009sage: Q1 = TernaryQF([26, 42, 53, -36, -17, -3])1010sage: Q2 = Q1.find_p_neighbors(2)[1]1011sage: Q1.omega()101231013sage: Q1.xi(3), Q2.xi(3)1014(-1, -1)10151016"""10171018if p == 4:1019p = -11020if p == 8:1021p = 210221023if self.omega() % p != 0:1024raise ValueError, "not a valid character"10251026if p == -1 and self.omega() % 2**4 != 0:1027raise ValueError, "not a valid character"10281029if p == 2 and self.omega() % 2**5 != 0:1030raise ValueError, "not a valid character"10311032if (p == -1) or (p == 2):1033return kronecker_symbol(p, self.basic_lemma(2))10341035return kronecker_symbol(self.basic_lemma(p), p)1036103710381039def xi_rec(self, p):1040"""1041Returns Xi(p) for the reciprocal form.10421043EXAMPLES::10441045sage: Q1 = TernaryQF([1, 1, 7, 0, 0, 0])1046sage: Q2 = Q1.find_p_neighbors(3)[0]1047sage: Q1.delta()1048281049sage: Q1.xi_rec(7), Q2.xi_rec(7)1050(1, 1)105110521053"""10541055return self.reciprocal().xi(p)105610571058def symmetry(self, v):1059"""1060Returns A the automorphism of the ternary quadratic form such that:1061::1062- A*v = -v.1063- A*u = 0, if u is orthogonal to v.1064where v is a given vector.10651066EXAMPLES::10671068sage: Q = TernaryQF([4, 5, 8, 5, 2, 2])1069sage: v = vector((1,1,1))1070sage: M = Q.symmetry(v)1071sage: M1072[ 7/13 -17/26 -23/26]1073[ -6/13 9/26 -23/26]1074[ -6/13 -17/26 3/26]1075sage: M.det()1076-11077sage: M*v1078(-1, -1, -1)1079sage: v1 = vector((23, 0, -12))1080sage: v2 = vector((0, 23, -17))1081sage: v1*Q.matrix()*v108201083sage: v2*Q.matrix()*v108401085sage: M*v1 == v11086True1087sage: M*v2 == v21088True108910901091"""10921093return identity_matrix(3) - v.column()*matrix(v)*self.matrix()/self(v)109410951096def automorphism_symmetries(self, A):1097"""1098Given the automorphism A, returns two vectors v1, v2 if A is not the identity. Such that the product of the symmetries of the ternary quadratic form given by the two vectors is A.10991100EXAMPLES::11011102sage: Q = TernaryQF([9, 12, 30, -26, -28, 20])1103sage: A = matrix(ZZ, 3, [9, 10, -10, -6, -7, 6, 2, 2, -3])1104sage: Q(A) == Q1105True1106sage: v1, v2 = Q.automorphism_symmetries(A)1107sage: v1, v21108((8, -6, 2), (1, -5/4, -1/4))1109sage: A1 = Q.symmetry(v1)1110sage: A11111[ 9 9 -13]1112[ -6 -23/4 39/4]1113[ 2 9/4 -9/4]1114sage: A2 = Q.symmetry(v2)1115sage: A21116[ 1 1 3]1117[ 0 -1/4 -15/4]1118[ 0 -1/4 1/4]1119sage: A1*A2 == A1120True1121sage: Q.automorphism_symmetries(identity_matrix(ZZ,3))1122[]11231124"""11251126if A == identity_matrix(3):1127return []1128else:1129bs = (A - 1).columns()1130for b1 in bs:1131if b1 != 0:1132break1133A1 = self.symmetry(b1)*A1134bs = (A1 - 1).columns()1135for b2 in bs:1136if b2 != 0:1137break1138return [b1, b2]11391140def automorphism_spin_norm(self,A):1141"""1142Return the spin norm of the automorphism A.11431144EXAMPLES::11451146sage: Q = TernaryQF([9, 12, 30, -26, -28, 20])1147sage: A = matrix(ZZ, 3, [9, 10, -10, -6, -7, 6, 2, 2, -3])1148sage: A.det()114911150sage: Q(A) == Q1151True1152sage: Q.automorphism_spin_norm(A)1153711541155"""11561157if A == identity_matrix(ZZ,3):1158return 11159bs = self.automorphism_symmetries(A)1160s = self(bs[0]) * self(bs[1])1161return s.squarefree_part()116211631164return [(1, 0, 0, 0, 1, 0, 0, 0, 1)]11651166def _border(self,n):1167"""1168Auxiliar function to find the automorphisms of a positive definite ternary quadratic form.1169It return a boolean whether the n-condition is true. If Q = TernaryQF([a,b,c,r,s,t]), the conditions are:1170::11711- a = t, s = 2r.11722- a = s, t = 2r.11733- b = r, t = 2s.11744- a = -t.11755- a = -s.11766- b = -r.11777- a + b + r + s + t = 0, 2a + 2s + t = 0.11788- a = b, r = s.11799- b = c, s = t.118010- r = s, r = 0.118111- r = t, r = 0.118212- s = t, s = 0.118313- r = s, s = t, t = a.118414- a = s, a = t.118515- a = b, a + b + r + s + t = 0.118616- a = b, b = c, a + b + r + s + t = 0.11871188EXAMPLES::11891190sage: Q01 = TernaryQF([5, 5, 9, 2, 4, 5])1191sage: Q01._border(1)1192True1193sage: Q02 = TernaryQF([6, 7, 8, 2, 6, 4])1194sage: Q02._border(2)1195True1196sage: Q03 = TernaryQF([6, 9, 9, 9, 3, 6])1197sage: Q03._border(3)1198True1199sage: Q04 = TernaryQF([1, 2, 3, -1, 0, -1])1200sage: Q04._border(4)1201True1202sage: Q05 = TernaryQF([2, 3, 5, -1, -2, 0])1203sage: Q05._border(5)1204True1205sage: Q06 = TernaryQF([1, 5, 7, -5, 0, 0])1206sage: Q06._border(6)1207True1208sage: Q07 = TernaryQF([1, 1, 7, -1, -1, 0])1209sage: Q07._border(7)1210True1211sage: Q08 = TernaryQF([2, 2, 5, -1, -1, -1])1212sage: Q08._border(8)1213True1214sage: Q09 = TernaryQF([3, 8, 8, 6, 2, 2])1215sage: Q09._border(9)1216True1217sage: Q10 = TernaryQF([1, 3, 4, 0, 0, 0])1218sage: Q10._border(10)1219True1220sage: Q11 = TernaryQF([3, 5, 8, 0, -1, 0])1221sage: Q11._border(11)1222True1223sage: Q12 = TernaryQF([2, 6, 7, -5, 0, 0])1224sage: Q12._border(12)1225True1226sage: Q13 = TernaryQF([1, 1, 2, 1, 1, 1])1227sage: Q13._border(13)1228True1229sage: Q14 = TernaryQF([1, 3, 4, 3, 1, 1])1230sage: Q14._border(14)1231True1232sage: Q15 = TernaryQF([3, 3, 6, -3, -3, 0])1233sage: Q15._border(15)1234True1235sage: Q16 = TernaryQF([4, 4, 4, -2, -3, -3])1236sage: Q16._border(16)1237True123812391240"""12411242a, b, c, r, s, t = self.coefficients()1243if n == 1:1244return (a == t) and (s == 2*r)1245elif n == 2:1246return (a == s) and (t == 2*r)1247elif n == 3:1248return (b == r) and (t == 2*s)1249elif n == 4:1250return (a == -t)1251elif n == 5:1252return (a == -s)1253elif n == 6:1254return (b == -r)1255elif n == 7:1256return (a + b + r + s + t == 0) and (2*a + 2*s + t == 0)1257elif n == 8:1258return (a == b) and (r == s)1259elif n == 9:1260return (b == c) and (s == t)1261elif n == 10:1262return (r == s) and (r == 0)1263elif n == 11:1264return (r == t) and (r == 0)1265elif n == 12:1266return (s == t) and (s == 0)1267elif n == 13:1268return (r == s) and (s == t) and (t == a)1269elif n == 14:1270return (a == s) and (a == t)1271elif n == 15:1272return (a == b) and (a + b + r + s + t == 0)1273elif n == 16:1274return (a == b) and (b == c) and (a + b + r + s + t == 0)12751276def _borders(self):1277"""1278Return the borders that the ternary quadratic form meet.12791280See: TernaryQF._border12811282EXAMPLES::12831284sage: Q01 = TernaryQF([5, 5, 9, 2, 4, 5])1285sage: Q01._borders()1286(1,)1287sage: Q02 = TernaryQF([6, 7, 8, 2, 6, 4])1288sage: Q02._borders()1289(2,)1290sage: Q03 = TernaryQF([6, 9, 9, 9, 3, 6])1291sage: Q03._borders()1292(3,)1293sage: Q04 = TernaryQF([1, 2, 3, -1, 0, -1])1294sage: Q04._borders()1295(4,)1296sage: Q05 = TernaryQF([2, 3, 5, -1, -2, 0])1297sage: Q05._borders()1298(5,)1299sage: Q06 = TernaryQF([1, 5, 7, -5, 0, 0])1300sage: Q06._borders()1301(6, 12)1302sage: Q07 = TernaryQF([1, 1, 7, -1, -1, 0])1303sage: Q07._borders()1304(5, 6, 7, 8, 15)1305sage: Q08 = TernaryQF([2, 2, 5, -1, -1, -1])1306sage: Q08._borders()1307(8,)1308sage: Q09 = TernaryQF([3, 8, 8, 6, 2, 2])1309sage: Q09._borders()1310(9,)1311sage: Q10 = TernaryQF([1, 3, 4, 0, 0, 0])1312sage: Q10._borders()1313(10, 11, 12)1314sage: Q11 = TernaryQF([3, 5, 8, 0, -1, 0])1315sage: Q11._borders()1316(11,)1317sage: Q12 = TernaryQF([2, 6, 7, -5, 0, 0])1318sage: Q12._borders()1319(12,)1320sage: Q13 = TernaryQF([1, 1, 2, 1, 1, 1])1321sage: Q13._borders()1322(8, 13, 14)1323sage: Q14 = TernaryQF([1, 3, 4, 3, 1, 1])1324sage: Q14._borders()1325(14,)1326sage: Q15 = TernaryQF([3, 3, 6, -3, -3, 0])1327sage: Q15._borders()1328(5, 6, 7, 8, 15)1329sage: Q16 = TernaryQF([4, 4, 4, -2, -3, -3])1330sage: Q16._borders()1331(9, 15, 16)13321333"""13341335return tuple(n for n in range(1,17) if self._border(n))13361337def _automorphisms_reduced_fast(self):1338"""1339Return the coefficients of the matrices of the automorphisms of the reduced ternary quadratic form.13401341EXAMPLES::13421343sage: Q = TernaryQF([1, 1, 7, 0, 0, 0])1344sage: Q.is_eisenstein_reduced()1345True1346sage: auts = Q._automorphisms_reduced_fast()1347sage: len(auts)134881349sage: A = matrix(3, auts[randint(0,7)])1350sage: Q(A) == Q1351True1352sage: Q = TernaryQF([3, 4, 5, 3, 3, 2])1353sage: Q._automorphisms_reduced_fast()1354[(1, 0, 0, 0, 1, 0, 0, 0, 1)]135513561357"""13581359if self._border(1):1360if self._border(2):1361if self._border(14):1362if self._border(9):1363# borders 1, 2, 9, 141364return [(1, 0, 0, 0, 1, 0, 0, 0, 1),1365(-1, -1, -1, 0, 0, 1, 0, 1, 0),1366(-1, -1, 0, 0, 1, 0, 0, 0, -1),1367(-1, 0, -1, 0, -1, 0, 0, 0, 1),1368(-1, 0, 0, 0, 0, -1, 0, -1, 0),1369(1, 0, 1, 0, 0, -1, 0, 1, 0),1370(1, 1, 0, 0, 0, 1, 0, -1, 0),1371(1, 1, 1, 0, -1, 0, 0, 0, -1)]1372else:1373# borders 1, 2, 141374return [(1, 0, 0, 0, 1, 0, 0, 0, 1),1375(-1, -1, 0, 0, 1, 0, 0, 0, -1),1376(-1, 0, -1, 0, -1, 0, 0, 0, 1),1377(1, 1, 1, 0, -1, 0, 0, 0, -1)]1378else:1379# borders 11380return [(1, 0, 0, 0, 1, 0, 0, 0, 1),1381(-1, -1, 0, 0, 1, 0, 0, 0, -1)]13821383if self._border(2):1384# borders 21385return [(1, 0, 0, 0, 1, 0, 0, 0, 1),1386(-1, 0, -1, 0, -1, 0, 0, 0, 1)]13871388if self._border(3):1389# borders 31390return [(1, 0, 0, 0, 1, 0, 0, 0, 1),1391(-1, 0, 0, 0, -1, -1, 0, 0, 1)]13921393if self._border(4):1394if self._border(10):1395if self._border(8):1396# borders 4, 8, 101397return [(1, 0, 0, 0, 1, 0, 0, 0, 1),1398(-1, 0, 0, -1, 1, 0, 0, 0, -1),1399(-1, 0, 0, 0, -1, 0, 0, 0, 1),1400(-1, 1, 0, -1, 0, 0, 0, 0, 1),1401(-1, 1, 0, 0, 1, 0, 0, 0, -1),1402(0, -1, 0, -1, 0, 0, 0, 0, -1),1403(0, -1, 0, 1, -1, 0, 0, 0, 1),1404(0, 1, 0, -1, 1, 0, 0, 0, 1),1405(0, 1, 0, 1, 0, 0, 0, 0, -1),1406(1, -1, 0, 0, -1, 0, 0, 0, -1),1407(1, -1, 0, 1, 0, 0, 0, 0, 1),1408(1, 0, 0, 1, -1, 0, 0, 0, -1)]1409else:1410# borders 4, 101411return [(1, 0, 0, 0, 1, 0, 0, 0, 1),1412(-1, 0, 0, 0, -1, 0, 0, 0, 1),1413(-1, 1, 0, 0, 1, 0, 0, 0, -1),1414(1, -1, 0, 0, -1, 0, 0, 0, -1)]1415else:1416# borders 41417return [(1, 0, 0, 0, 1, 0, 0, 0, 1),1418(1, -1, 0, 0, -1, 0, 0, 0, -1)]14191420if self._border(5):1421if self._border(6):1422if self._border(7):1423if self._border(8):1424if self._border(15):1425# borders 5, 6, 7, 8, 151426return [(1, 0, 0, 0, 1, 0, 0, 0, 1),1427(-1, 0, 0, 0, 1, -1, 0, 0, -1),1428(-1, 0, 1, 0, -1, 1, 0, 0, 1),1429(0, -1, 0, -1, 0, 0, 0, 0, -1),1430(0, -1, 1, 1, 0, 0, 0, 0, 1),1431(0, 1, -1, 1, 0, -1, 0, 0, -1),1432(0, 1, 0, -1, 0, 1, 0, 0, 1),1433(1, 0, -1, 0, -1, 0, 0, 0, -1)]1434else:1435# borders 5, 6, 71436return [(1, 0, 0, 0, 1, 0, 0, 0, 1),1437(-1, 0, 0, 0, 1, -1, 0, 0, -1),1438(-1, 0, 1, 0, -1, 1, 0, 0, 1),1439(1, 0, -1, 0, -1, 0, 0, 0, -1)]1440elif self._border(11):1441# borders 5, 111442return [(1, 0, 0, 0, 1, 0, 0, 0, 1),1443(-1, 0, 0, 0, 1, 0, 0, 0, -1),1444(-1, 0, 1, 0, -1, 0, 0, 0, 1),1445(1, 0, -1, 0, -1, 0, 0, 0, -1)]1446else:1447# borders 51448return [(1, 0, 0, 0, 1, 0, 0, 0, 1),1449(1, 0, -1, 0, -1, 0, 0, 0, -1)]14501451if self._border(6):1452if self._border(12):1453if self._border(9):1454# borders 6, 9, 121455return [(1, 0, 0, 0, 1, 0, 0, 0, 1),1456(-1, 0, 0, 0, -1, 0, 0, -1, 1),1457(-1, 0, 0, 0, -1, 1, 0, 0, 1),1458(-1, 0, 0, 0, 0, -1, 0, -1, 0),1459(-1, 0, 0, 0, 0, 1, 0, 1, 0),1460(-1, 0, 0, 0, 1, -1, 0, 0, -1),1461(-1, 0, 0, 0, 1, 0, 0, 1, -1),1462(1, 0, 0, 0, -1, 0, 0, 0, -1),1463(1, 0, 0, 0, -1, 1, 0, -1, 0),1464(1, 0, 0, 0, 0, -1, 0, 1, -1),1465(1, 0, 0, 0, 0, 1, 0, -1, 1),1466(1, 0, 0, 0, 1, -1, 0, 1, 0)]1467else:1468# borders 6, 121469return [(1, 0, 0, 0, 1, 0, 0, 0, 1),1470(-1, 0, 0, 0, -1, 1, 0, 0, 1),1471(-1, 0, 0, 0, 1, -1, 0, 0, -1),1472(1, 0, 0, 0, -1, 0, 0, 0, -1)]1473else:1474# borders 61475return [(1, 0, 0, 0, 1, 0, 0, 0, 1),1476(-1, 0, 0, 0, 1, -1, 0, 0, -1)]14771478if self._border(7):1479if self._border(8) and self._border(15):1480if self._border(16):1481if self._border(9):1482# borders 7, 8, 9, 15, 161483return [(1, 0, 0, 0, 1, 0, 0, 0, 1),1484(-1, 0, 0, -1, 0, 1, -1, 1, 0),1485(-1, 0, 0, 0, 0, -1, 0, -1, 0),1486(-1, 0, 1, -1, 1, 0, -1, 0, 0),1487(-1, 0, 1, 0, -1, 1, 0, 0, 1),1488(-1, 1, 0, -1, 0, 0, -1, 0, 1),1489(-1, 1, 0, 0, 1, 0, 0, 1, -1),1490(0, -1, 0, -1, 0, 0, 0, 0, -1),1491(0, -1, 0, 1, -1, 0, 0, -1, 1),1492(0, -1, 1, 0, -1, 0, 1, -1, 0),1493(0, -1, 1, 0, 0, 1, -1, 0, 1),1494(0, 0, -1, 0, -1, 0, -1, 0, 0),1495(0, 0, -1, 0, 1, -1, 1, 0, -1),1496(0, 0, 1, -1, 0, 1, 0, -1, 1),1497(0, 0, 1, 1, 0, 0, 0, 1, 0),1498(0, 1, -1, -1, 1, 0, 0, 1, 0),1499(0, 1, -1, 1, 0, -1, 0, 0, -1),1500(0, 1, 0, 0, 0, 1, 1, 0, 0),1501(0, 1, 0, 0, 1, -1, -1, 1, 0),1502(1, -1, 0, 0, -1, 1, 0, -1, 0),1503(1, -1, 0, 1, 0, -1, 1, 0, 0),1504(1, 0, -1, 0, 0, -1, 0, 1, -1),1505(1, 0, -1, 1, 0, 0, 1, -1, 0),1506(1, 0, 0, 1, -1, 0, 1, 0, -1)]1507else:1508# borders 7, 8, 15, 161509return [(1, 0, 0, 0, 1, 0, 0, 0, 1),1510(-1, 0, 0, -1, 0, 1, -1, 1, 0),1511(-1, 0, 1, 0, -1, 1, 0, 0, 1),1512(0, -1, 0, -1, 0, 0, 0, 0, -1),1513(0, -1, 1, 0, -1, 0, 1, -1, 0),1514(0, 1, -1, 1, 0, -1, 0, 0, -1),1515(0, 1, 0, 0, 1, -1, -1, 1, 0),1516(1, 0, -1, 1, 0, 0, 1, -1, 0)]1517else:1518# borders 7, 8, 151519return [(1, 0, 0, 0, 1, 0, 0, 0, 1),1520(-1, 0, 1, 0, -1, 1, 0, 0, 1),1521(0, -1, 0, -1, 0, 0, 0, 0, -1),1522(0, 1, -1, 1, 0, -1, 0, 0, -1)]1523elif self._border(9):1524# borders 7, 91525return [(1, 0, 0, 0, 1, 0, 0, 0, 1),1526(-1, 0, 0, 0, 0, -1, 0, -1, 0),1527(-1, 0, 1, 0, -1, 1, 0, 0, 1),1528(-1, 1, 0, 0, 1, 0, 0, 1, -1),1529(1, -1, 0, 0, -1, 1, 0, -1, 0),1530(1, 0, -1, 0, 0, -1, 0, 1, -1)]1531else:1532# borders 71533return [(1, 0, 0, 0, 1, 0, 0, 0, 1),1534(-1, 0, 1, 0, -1, 1, 0, 0, 1)]153515361537if self._border(8):1538if self._border(9):1539if self._border(10) and self._border(11) and self._border(12):1540# borders 8, 9, 10, 11, 121541return [(1, 0, 0, 0, 1, 0, 0, 0, 1),1542(-1, 0, 0, 0, -1, 0, 0, 0, 1),1543(-1, 0, 0, 0, 0, -1, 0, -1, 0),1544(-1, 0, 0, 0, 0, 1, 0, 1, 0),1545(-1, 0, 0, 0, 1, 0, 0, 0, -1),1546(0, -1, 0, -1, 0, 0, 0, 0, -1),1547(0, -1, 0, 0, 0, -1, 1, 0, 0),1548(0, -1, 0, 0, 0, 1, -1, 0, 0),1549(0, -1, 0, 1, 0, 0, 0, 0, 1),1550(0, 0, -1, -1, 0, 0, 0, 1, 0),1551(0, 0, -1, 0, -1, 0, -1, 0, 0),1552(0, 0, -1, 0, 1, 0, 1, 0, 0),1553(0, 0, -1, 1, 0, 0, 0, -1, 0),1554(0, 0, 1, -1, 0, 0, 0, -1, 0),1555(0, 0, 1, 0, -1, 0, 1, 0, 0),1556(0, 0, 1, 0, 1, 0, -1, 0, 0),1557(0, 0, 1, 1, 0, 0, 0, 1, 0),1558(0, 1, 0, -1, 0, 0, 0, 0, 1),1559(0, 1, 0, 0, 0, -1, -1, 0, 0),1560(0, 1, 0, 0, 0, 1, 1, 0, 0),1561(0, 1, 0, 1, 0, 0, 0, 0, -1),1562(1, 0, 0, 0, -1, 0, 0, 0, -1),1563(1, 0, 0, 0, 0, -1, 0, 1, 0),1564(1, 0, 0, 0, 0, 1, 0, -1, 0)]1565elif self._border(13) and self._border(14):1566# borders 8, 9, 13, 141567return [(1, 0, 0, 0, 1, 0, 0, 0, 1),1568(-1, -1, -1, 0, 0, 1, 0, 1, 0),1569(-1, -1, -1, 0, 1, 0, 1, 0, 0),1570(-1, -1, -1, 1, 0, 0, 0, 0, 1),1571(-1, 0, 0, 0, -1, 0, 1, 1, 1),1572(-1, 0, 0, 0, 0, -1, 0, -1, 0),1573(-1, 0, 0, 1, 1, 1, 0, 0, -1),1574(0, -1, 0, -1, 0, 0, 0, 0, -1),1575(0, -1, 0, 0, 0, -1, 1, 1, 1),1576(0, -1, 0, 1, 1, 1, -1, 0, 0),1577(0, 0, -1, -1, 0, 0, 1, 1, 1),1578(0, 0, -1, 0, -1, 0, -1, 0, 0),1579(0, 0, -1, 1, 1, 1, 0, -1, 0),1580(0, 0, 1, -1, -1, -1, 1, 0, 0),1581(0, 0, 1, 0, 1, 0, -1, -1, -1),1582(0, 0, 1, 1, 0, 0, 0, 1, 0),1583(0, 1, 0, -1, -1, -1, 0, 0, 1),1584(0, 1, 0, 0, 0, 1, 1, 0, 0),1585(0, 1, 0, 1, 0, 0, -1, -1, -1),1586(1, 0, 0, -1, -1, -1, 0, 1, 0),1587(1, 0, 0, 0, 0, 1, -1, -1, -1),1588(1, 1, 1, -1, 0, 0, 0, -1, 0),1589(1, 1, 1, 0, -1, 0, 0, 0, -1),1590(1, 1, 1, 0, 0, -1, -1, 0, 0)]1591else:1592# borders 8, 91593return [(1, 0, 0, 0, 1, 0, 0, 0, 1),1594(-1, 0, 0, 0, 0, -1, 0, -1, 0),1595(0, -1, 0, -1, 0, 0, 0, 0, -1),1596(0, 0, -1, 0, -1, 0, -1, 0, 0),1597(0, 0, 1, 1, 0, 0, 0, 1, 0),1598(0, 1, 0, 0, 0, 1, 1, 0, 0)]1599elif self._border(10):1600if self._border(11) and self._border(12):1601# borders 8, 10, 11, 121602return [(1, 0, 0, 0, 1, 0, 0, 0, 1),1603(-1, 0, 0, 0, -1, 0, 0, 0, 1),1604(-1, 0, 0, 0, 1, 0, 0, 0, -1),1605(0, -1, 0, -1, 0, 0, 0, 0, -1),1606(0, -1, 0, 1, 0, 0, 0, 0, 1),1607(0, 1, 0, -1, 0, 0, 0, 0, 1),1608(0, 1, 0, 1, 0, 0, 0, 0, -1),1609(1, 0, 0, 0, -1, 0, 0, 0, -1)]1610else:1611# borders 8, 101612return [(1, 0, 0, 0, 1, 0, 0, 0, 1),1613(-1, 0, 0, 0, -1, 0, 0, 0, 1),1614(0, -1, 0, -1, 0, 0, 0, 0, -1),1615(0, 1, 0, 1, 0, 0, 0, 0, -1)]1616elif self._border(14):1617# borders 8, 13, 141618return [(1, 0, 0, 0, 1, 0, 0, 0, 1),1619(-1, -1, -1, 1, 0, 0, 0, 0, 1),1620(-1, 0, 0, 1, 1, 1, 0, 0, -1),1621(0, -1, 0, -1, 0, 0, 0, 0, -1),1622(0, 1, 0, -1, -1, -1, 0, 0, 1),1623(1, 1, 1, 0, -1, 0, 0, 0, -1)]1624else:1625# borders 81626return [(1, 0, 0, 0, 1, 0, 0, 0, 1),1627(0, -1, 0, -1, 0, 0, 0, 0, -1)]16281629if self._border(9):1630if self._border(12):1631if self._border(10) and self._border(11):1632# borders 9, 10, 11, 121633return [(1, 0, 0, 0, 1, 0, 0, 0, 1),1634(-1, 0, 0, 0, -1, 0, 0, 0, 1),1635(-1, 0, 0, 0, 0, -1, 0, -1, 0),1636(-1, 0, 0, 0, 0, 1, 0, 1, 0),1637(-1, 0, 0, 0, 1, 0, 0, 0, -1),1638(1, 0, 0, 0, -1, 0, 0, 0, -1),1639(1, 0, 0, 0, 0, -1, 0, 1, 0),1640(1, 0, 0, 0, 0, 1, 0, -1, 0)]1641else:1642# borders 9, 121643return [(1, 0, 0, 0, 1, 0, 0, 0, 1),1644(-1, 0, 0, 0, 0, -1, 0, -1, 0),1645(-1, 0, 0, 0, 0, 1, 0, 1, 0),1646(1, 0, 0, 0, -1, 0, 0, 0, -1)]1647elif self._border(14):1648if self._border(13):1649# borders 9, 13, 141650return [(1, 0, 0, 0, 1, 0, 0, 0, 1),1651(-1, -1, -1, 0, 0, 1, 0, 1, 0),1652(-1, 0, 0, 0, 0, -1, 0, -1, 0),1653(1, 1, 1, 0, -1, 0, 0, 0, -1)]1654else:1655# borders 9, 141656return [(1, 0, 0, 0, 1, 0, 0, 0, 1),1657(-1, -1, -1, 0, 0, 1, 0, 1, 0),1658(-1, 0, 0, 0, 0, -1, 0, -1, 0),1659(1, 1, 1, 0, -1, 0, 0, 0, -1)]1660elif self._border(15):1661# borders 9, 15, 161662return [(1, 0, 0, 0, 1, 0, 0, 0, 1),1663(-1, 0, 0, -1, 0, 1, -1, 1, 0),1664(-1, 0, 0, 0, 0, -1, 0, -1, 0),1665(0, -1, 1, 0, -1, 0, 1, -1, 0),1666(0, -1, 1, 0, 0, 1, -1, 0, 1),1667(0, 1, -1, -1, 1, 0, 0, 1, 0),1668(0, 1, -1, 1, 0, -1, 0, 0, -1),1669(1, 0, 0, 1, -1, 0, 1, 0, -1)]1670else:1671# borders 91672return [(1, 0, 0, 0, 1, 0, 0, 0, 1),1673(-1, 0, 0, 0, 0, -1, 0, -1, 0)]16741675if self._border(10):1676if self._border(11) and self._border(12):1677# borders 10, 11, 121678return [(1, 0, 0, 0, 1, 0, 0, 0, 1),1679(-1, 0, 0, 0, -1, 0, 0, 0, 1),1680(-1, 0, 0, 0, 1, 0, 0, 0, -1),1681(1, 0, 0, 0, -1, 0, 0, 0, -1)]1682else:1683# borders 101684return [(1, 0, 0, 0, 1, 0, 0, 0, 1),1685(-1, 0, 0, 0, -1, 0, 0, 0, 1)]16861687if self._border(11):1688# borders 111689return [(1, 0, 0, 0, 1, 0, 0, 0, 1),1690(-1, 0, 0, 0, 1, 0, 0, 0, -1)]16911692if self._border(12):1693# border 121694return [(1, 0, 0, 0, 1, 0, 0, 0, 1),1695(1, 0, 0, 0, -1, 0, 0, 0, -1)]16961697if self._border(13) and self._border(14):1698# border 13, 141699return [(1, 0, 0, 0, 1, 0, 0, 0, 1),1700(1, 1, 1, 0, -1, 0, 0, 0, -1)]17011702if self._border(14):1703# border 141704return [(1, 0, 0, 0, 1, 0, 0, 0, 1),1705(1, 1, 1, 0, -1, 0, 0, 0, -1)]17061707if self._border(15):1708if self._border(16):1709# borders 15, 161710return [(1, 0, 0, 0, 1, 0, 0, 0, 1),1711(-1, 0, 0, -1, 0, 1, -1, 1, 0),1712(0, -1, 1, 0, -1, 0, 1, -1, 0),1713(0, 1, -1, 1, 0, -1, 0, 0, -1)]1714else:1715# borders 151716return [(1, 0, 0, 0, 1, 0, 0, 0, 1),1717(0, 1, -1, 1, 0, -1, 0, 0, -1)]17181719return [(1, 0, 0, 0, 1, 0, 0, 0, 1)]172017211722def _automorphisms_reduced_slow(self):1723"""1724Return the automorphisms of the reduced ternary quadratic form.1725It searches over all 3x3 matrices with coefficients -1, 0, 1,1726determinant 1 and finite order, because Eisenstein reduced forms1727are Minkowski reduced. See Cassels.17281729EXAMPLES::17301731sage: Q = TernaryQF([1, 1, 7, 0, 0, 0])1732sage: Q.is_eisenstein_reduced()1733True1734sage: auts = Q._automorphisms_reduced_slow() # long time (3s on sage.math, 2014)1735sage: len(auts) # long time173681737sage: A = auts[randint(0,7)] # long time1738sage: Q(A) == Q # long time1739True1740sage: Q = TernaryQF([3, 4, 5, 3, 3, 2])1741sage: Q._automorphisms_reduced_slow() # long time1742[1743[1 0 0]1744[0 1 0]1745[0 0 1]1746]17471748"""17491750if TernaryQF.possible_automorphisms == None:17511752I = [-1, 0, 1]1753auts = [matrix(ZZ, 3, [a, b, c, d, e, f, g, h, i]) for a in I for b in I for c in I for d in I for e in I for f in I for g in I for h in I for i in I]1754auts = [m for m in auts if m.det() == 1]1755auts = [m for m in auts if m**2 in auts]1756auts = [m for m in auts if m**2 in auts]1757auts = [m for m in auts if m**2 in auts]1758TernaryQF.possible_automorphisms = auts17591760return [m for m in TernaryQF.possible_automorphisms if self(m) == self]176117621763def automorphisms(self, slow = True):1764"""1765Returns a list with the automorphisms of the definite ternary quadratic form.17661767EXAMPLES::17681769sage: Q = TernaryQF([1, 1, 7, 0, 0, 0])1770sage: auts = Q.automorphisms()1771sage: auts1772[1773[-1 0 0] [-1 0 0] [ 0 -1 0] [ 0 -1 0] [ 0 1 0] [ 0 1 0]1774[ 0 -1 0] [ 0 1 0] [-1 0 0] [ 1 0 0] [-1 0 0] [ 1 0 0]1775[ 0 0 1], [ 0 0 -1], [ 0 0 -1], [ 0 0 1], [ 0 0 1], [ 0 0 -1],1776[ 1 0 0] [1 0 0]1777[ 0 -1 0] [0 1 0]1778[ 0 0 -1], [0 0 1]1779]1780sage: all(Q == Q(A) for A in auts)1781True1782sage: Q = TernaryQF([3, 4, 5, 3, 3, 2])1783sage: Q.automorphisms(slow = False)1784[1785[1 0 0]1786[0 1 0]1787[0 0 1]1788]1789sage: Q = TernaryQF([4, 2, 4, 3, -4, -5])1790sage: auts = Q.automorphisms(slow = False)1791sage: auts1792[1793[1 0 0] [ 2 -1 -1]1794[0 1 0] [ 3 -2 -1]1795[0 0 1], [ 0 0 -1]1796]1797sage: A = auts[1]1798sage: Q(A) == Q1799True1800sage: Qr, M_red = Q.reduced_form_eisenstein()1801sage: Qr1802Ternary quadratic form with integer coefficients:1803[1 2 3]1804[-1 0 -1]1805sage: Q(A*M_red) == Qr1806True18071808"""18091810if not self.is_definite():1811raise ValueError, "Oops, only implemented for definite forms."18121813if self._automorphisms != None:1814return self._automorphisms18151816if self.is_positive_definite():1817if self.is_eisenstein_reduced():1818if slow:1819self._automorphisms = self._automorphisms_reduced_slow()1820else:1821auts = self._automorphisms_reduced_fast()1822self._automorphisms = [matrix(ZZ, 3, A) for A in auts]1823else:1824[Qr, M] = self.reduced_form_eisenstein()1825auts = Qr.automorphisms(slow)1826M_inv = M.inverse()1827self._automorphisms = [M*m*M_inv for m in auts]1828else:1829self._automorphisms = (-self).automorphisms()1830return self._automorphisms1831183218331834def _number_of_automorphisms_reduced(self):1835"""1836Return the number of automorphisms of the reduced definite ternary quadratic form.18371838EXAMPLES::18391840sage: Q = TernaryQF([1, 1, 7, 0, 0, 0])1841sage: Q._number_of_automorphisms_reduced()184281843sage: len(Q.automorphisms(slow = False))184481845sage: Q = TernaryQF([3, 4, 5, 3, 3, 2])1846sage: Q._number_of_automorphisms_reduced()1847118481849"""18501851if self._border(1):1852if self._border(2):1853if self._border(14):1854if self._border(9):1855# borders 1, 2, 9, 141856return 81857else:1858# borders 1, 2, 141859return 41860else:1861# borders 11862return 218631864if self._border(2):1865# borders 21866return 218671868if self._border(3):1869# borders 31870return 218711872if self._border(4):1873if self._border(10):1874if self._border(8):1875# borders 4, 8, 101876return 121877else:1878# borders 4, 101879return 41880else:1881# borders 41882return 218831884if self._border(5):1885if self._border(6):1886if self._border(7):1887if self._border(8):1888if self._border(15):1889# borders 5, 6, 7, 8, 151890return 81891else:1892# borders 5, 6, 71893return 41894elif self._border(11):1895# borders 5, 111896return 41897else:1898# borders 51899return 219001901if self._border(6):1902if self._border(12):1903if self._border(9):1904# borders 6, 9, 121905return 121906else:1907# borders 6, 121908return 41909else:1910# borders 61911return 219121913if self._border(7):1914if self._border(8) and self._border(15):1915if self._border(16):1916if self._border(9):1917# borders 7, 8, 9, 15, 161918return 241919else:1920# borders 7, 8, 15, 161921return 81922else:1923# borders 7, 8, 151924return 41925elif self._border(9):1926# borders 7, 91927return 61928else:1929# borders 71930return 2193119321933if self._border(8):1934if self._border(9):1935if self._border(10) and self._border(11) and self._border(12):1936# borders 8, 9, 10, 11, 121937return 241938elif self._border(13) and self._border(14):1939# borders 8, 9, 13, 141940return 241941else:1942# borders 8, 91943return 61944elif self._border(10):1945if self._border(11) and self._border(12):1946# borders 8, 10, 11, 121947return 81948else:1949# borders 8, 101950return 41951elif self._border(14):1952# borders 8, 13, 141953return 61954else:1955# borders 81956return 219571958if self._border(9):1959if self._border(12):1960if self._border(10) and self._border(11):1961# borders 9, 10, 11, 121962return 81963else:1964# borders 9, 121965return 41966elif self._border(14):1967if self._border(13):1968# borders 9, 13, 141969return 41970else:1971# borders 9, 141972return 41973elif self._border(15):1974# borders 9, 15, 161975return 81976else:1977# borders 91978return 219791980if self._border(10):1981if self._border(11) and self._border(12):1982# borders 10, 11, 121983return 41984else:1985# borders 101986return 219871988if self._border(11):1989# borders 111990return 219911992if self._border(12):1993# border 121994return 219951996if self._border(13) and self._border(14):1997# border 13, 141998return 219992000if self._border(14):2001# border 142002return 220032004if self._border(15):2005if self._border(16):2006# borders 15, 162007return 42008else:2009# borders 152010return 220112012return 12013201420152016def number_of_automorphisms(self, slow = True):2017"""2018Return the number of automorphisms of the definite ternary quadratic form.20192020EXAMPLES::20212022sage: Q = TernaryQF([1, 1, 7, 0, 0, 0])2023sage: A = matrix(ZZ, 3, [0, 1, 0, -1, 5, 0, -8, -1, 1])2024sage: A.det()202512026sage: Q1 = Q(A)2027sage: Q12028Ternary quadratic form with integer coefficients:2029[449 33 7]2030[-14 -112 102]2031sage: Q1.number_of_automorphisms()203282033sage: Q = TernaryQF([-19, -7, -6, -12, 20, 23])2034sage: Q.is_negative_definite()2035True2036sage: Q.number_of_automorphisms(slow = False)20372420382039"""20402041if not self.is_definite():2042raise ValueError, "Oops, only implemented for definite forms."20432044if self._number_of_automorphisms != None:2045return self._number_of_automorphisms20462047if slow:2048self._number_of_automorphisms = len(self.automorphisms())2049else:2050if self.is_negative_definite():2051self._number_of_automorphisms = (-self).reduced_form_eisenstein(False)._number_of_automorphisms_reduced()2052else:2053self._number_of_automorphisms = self.reduced_form_eisenstein(False)._number_of_automorphisms_reduced()20542055return self._number_of_automorphisms205620572058def find_all_ternary_qf_by_level_disc(N, d):2059"""2060Find the coefficients of all the reduced ternary quadratic forms given its discriminant d and level N.2061If N|4d and d|N^2, then it may be some forms with that discriminant and level.20622063EXAMPLES::20642065sage: find_all_ternary_qf_by_level_disc(44, 11)2066[Ternary quadratic form with integer coefficients:2067[1 1 3]2068[0 -1 0], Ternary quadratic form with integer coefficients:2069[1 1 4]2070[1 1 1]]2071sage: find_all_ternary_qf_by_level_disc(44, 11^2 * 16)2072[Ternary quadratic form with integer coefficients:2073[3 15 15]2074[-14 -2 -2], Ternary quadratic form with integer coefficients:2075[4 11 12]2076[0 -4 0]]2077sage: Q = TernaryQF([1, 1, 3, 0, -1, 0])2078sage: Q.is_eisenstein_reduced()2079True2080sage: Q.reciprocal_reduced()2081Ternary quadratic form with integer coefficients:2082[4 11 12]2083[0 -4 0]2084sage: find_all_ternary_qf_by_level_disc(44, 22)2085[]2086sage: find_all_ternary_qf_by_level_disc(44, 33)2087Traceback (most recent call last):2088...2089ValueError: There are no ternary forms of this level and discriminant209020912092"""20932094return map(TernaryQF, _find_all_ternary_qf_by_level_disc(N, d))20952096def find_a_ternary_qf_by_level_disc(N, d):2097"""2098Find a reduced ternary quadratic form given its discriminant d and level N.2099If N|4d and d|N^2, then it may be a form with that discriminant and level.21002101EXAMPLES::21022103sage: Q1 = find_a_ternary_qf_by_level_disc(44, 11)2104sage: Q12105Ternary quadratic form with integer coefficients:2106[1 1 3]2107[0 -1 0]2108sage: Q2 = find_a_ternary_qf_by_level_disc(44, 11^2 * 16)2109sage: Q22110Ternary quadratic form with integer coefficients:2111[3 15 15]2112[-14 -2 -2]2113sage: Q1.is_eisenstein_reduced()2114True2115sage: Q1.level()2116442117sage: Q1.disc()2118112119sage: find_a_ternary_qf_by_level_disc(44, 22)2120sage: find_a_ternary_qf_by_level_disc(44, 33)2121Traceback (most recent call last):2122...2123ValueError: There are no ternary forms of this level and discriminant21242125"""21262127q = _find_a_ternary_qf_by_level_disc(N, d)2128if q != None:2129return TernaryQF(q)213021312132