Path: blob/master/sage/quadratic_forms/quadratic_form.py
4072 views
"""1Quadratic Forms Overview23AUTHORS:45- Jon Hanke (2007-06-19)6- Anna Haensch (2010-07-01): Formatting and ReSTification7"""89#*****************************************************************************10# Copyright (C) 2007 William Stein and Jonathan Hanke11#12# Distributed under the terms of the GNU General Public License (GPL)13#14# This code is distributed in the hope that it will be useful,15# but WITHOUT ANY WARRANTY; without even the implied warranty of16# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU17# General Public License for more details.18#19# The full text of the GPL is available at:20#21# http://www.gnu.org/licenses/22#*****************************************************************************2324from warnings import warn25from copy import deepcopy2627from sage.matrix.constructor import matrix28from sage.matrix.matrix_space import MatrixSpace29from sage.matrix.matrix import is_Matrix30from sage.rings.integer_ring import IntegerRing, ZZ31from sage.rings.ring import Ring32from sage.misc.functional import ideal, denominator, is_even, is_field33from sage.rings.arith import GCD, LCM34from sage.rings.principal_ideal_domain import is_PrincipalIdealDomain35from sage.rings.ring import is_Ring36from sage.matrix.matrix import is_Matrix37from sage.structure.element import is_Vector38from sage.rings.polynomial.polynomial_ring_constructor import PolynomialRing39from sage.modules.free_module_element import vector4041from sage.quadratic_forms.quadratic_form__evaluate import QFEvaluateVector, QFEvaluateMatrix42434445def QuadraticForm__constructor(R, n=None, entries=None):46"""47Wrapper for the QuadraticForm class constructor. This is meant48for internal use within the QuadraticForm class code only. You49should instead directly call QuadraticForm().5051EXAMPLES::5253sage: from sage.quadratic_forms.quadratic_form import QuadraticForm__constructor54sage: QuadraticForm__constructor(ZZ, 3) ## Makes a generic quadratic form over the integers55Quadratic form in 3 variables over Integer Ring with coefficients:56[ 0 0 0 ]57[ * 0 0 ]58[ * * 0 ]5960"""61return QuadraticForm(R, n, entries)626364def is_QuadraticForm(Q):65"""66Determines if the object Q is an element of the QuadraticForm class.6768EXAMPLES::6970sage: Q = QuadraticForm(ZZ, 2, [1,2,3])71sage: is_QuadraticForm(Q) ##random -- deprecated72True73sage: is_QuadraticForm(2) ##random -- deprecated74False7576"""77return isinstance(Q, QuadraticForm)78798081class QuadraticForm():82r"""83The ``QuadraticForm`` class represents a quadratic form in n variables with84coefficients in the ring R.8586INPUT:8788The constructor may be called in any of the following ways.8990#. ``QuadraticForm(R, n, entries)``, where9192- `R` -- ring for which the quadratic form is defined93- `n` -- an integer >= 094- ``entries`` -- a list of `n(n+1)/2` coefficients of the quadratic form95in `R` (given lexographically, or equivalently, by rows of the matrix)9697#. ``QuadraticForm(R, n)``, where9899- `R` -- a ring100- `n` -- a symmetric `n \times n` matrix with even diagonal (relative to101`R`)102103#. ``QuadraticForm(R)``, where104105- `R` -- a symmetric `n \times n` matrix with even diagonal (relative to106its base ring)107108If the keyword argument ``unsafe_initialize`` is True, then the subsequent109fields may by used to force the external initialization of various fields110of the quadratic form. Currently the only fields which can be set are:111112- ``number_of_automorphisms``113- ``determinant``114115116OUTPUT:117118quadratic form119120EXAMPLES::121122sage: Q = QuadraticForm(ZZ, 3, [1,2,3,4,5,6])123sage: Q124Quadratic form in 3 variables over Integer Ring with coefficients:125[ 1 2 3 ]126[ * 4 5 ]127[ * * 6 ]128129::130131sage: Q = QuadraticForm(QQ, 3, [1,2,3,4/3 ,5,6])132sage: Q133Quadratic form in 3 variables over Rational Field with coefficients:134[ 1 2 3 ]135[ * 4/3 5 ]136[ * * 6 ]137sage: Q[0,0]1381139sage: Q[0,0].parent()140Rational Field141142::143144sage: Q = QuadraticForm(QQ, 7, range(28))145sage: Q146Quadratic form in 7 variables over Rational Field with coefficients:147[ 0 1 2 3 4 5 6 ]148[ * 7 8 9 10 11 12 ]149[ * * 13 14 15 16 17 ]150[ * * * 18 19 20 21 ]151[ * * * * 22 23 24 ]152[ * * * * * 25 26 ]153[ * * * * * * 27 ]154155::156157sage: Q = QuadraticForm(QQ, 2, range(1,4))158sage: A = Matrix(ZZ,2,2,[-1,0,0,1])159sage: Q(A)160Quadratic form in 2 variables over Rational Field with coefficients:161[ 1 -2 ]162[ * 3 ]163164::165166sage: m = matrix(2,2,[1,2,3,4])167sage: m + m.transpose()168[2 5]169[5 8]170sage: QuadraticForm(m + m.transpose())171Quadratic form in 2 variables over Integer Ring with coefficients:172[ 1 5 ]173[ * 4 ]174175::176177sage: QuadraticForm(ZZ, m + m.transpose())178Quadratic form in 2 variables over Integer Ring with coefficients:179[ 1 5 ]180[ * 4 ]181182::183184sage: QuadraticForm(QQ, m + m.transpose())185Quadratic form in 2 variables over Rational Field with coefficients:186[ 1 5 ]187[ * 4 ]188"""189190## Import specialized methods:191## ---------------------------192193## Routines to compute the p-adic local normal form194from sage.quadratic_forms.quadratic_form__local_normal_form import \195find_entry_with_minimal_scale_at_prime, \196local_normal_form, \197jordan_blocks_by_scale_and_unimodular, \198jordan_blocks_in_unimodular_list_by_scale_power199200## Routines to perform elementary variable substitutions201from sage.quadratic_forms.quadratic_form__variable_substitutions import \202swap_variables, \203multiply_variable, \204divide_variable, \205scale_by_factor, \206extract_variables, \207elementary_substitution, \208add_symmetric209210## Routines to compute p-adic field invariants211from sage.quadratic_forms.quadratic_form__local_field_invariants import \212rational_diagonal_form, \213signature_vector, \214signature, \215hasse_invariant, \216hasse_invariant__OMeara, \217is_hyperbolic, \218is_anisotropic, \219is_isotropic, \220anisotropic_primes, \221compute_definiteness, \222compute_definiteness_string_by_determinants, \223is_positive_definite, \224is_negative_definite, \225is_indefinite, \226is_definite227228## Routines to compute local densities by the reduction procedure229from sage.quadratic_forms.quadratic_form__local_density_congruence import \230count_modp_solutions__by_Gauss_sum, \231local_good_density_congruence_odd, \232local_good_density_congruence_even, \233local_good_density_congruence, \234local_zero_density_congruence, \235local_badI_density_congruence, \236local_badII_density_congruence, \237local_bad_density_congruence, \238local_density_congruence, \239local_primitive_density_congruence240241## Routines to compute local densities by counting solutions of various types242from sage.quadratic_forms.quadratic_form__count_local_2 import \243count_congruence_solutions_as_vector, \244count_congruence_solutions, \245count_congruence_solutions__good_type, \246count_congruence_solutions__zero_type, \247count_congruence_solutions__bad_type, \248count_congruence_solutions__bad_type_I, \249count_congruence_solutions__bad_type_II250251## Routines to be called by the user to compute local densities252from sage.quadratic_forms.quadratic_form__local_density_interfaces import \253local_density, \254local_primitive_density255256## Routines for computing with ternary forms257from sage.quadratic_forms.quadratic_form__ternary_Tornaria import \258disc, \259content, \260adjoint, \261antiadjoint, \262is_adjoint, \263reciprocal, \264omega, \265delta, \266level__Tornaria, \267discrec, \268hasse_conductor, \269clifford_invariant, \270clifford_conductor, \271basiclemma, \272basiclemmavec, \273xi, \274xi_rec, \275lll, \276representation_number_list, \277representation_vector_list, \278is_zero, \279is_zero_nonsingular, \280is_zero_singular281282## Routines to compute the theta function283from sage.quadratic_forms.quadratic_form__theta import \284theta_series, \285theta_series_degree_2, \286theta_by_pari, \287theta_by_cholesky288289## Routines to compute the product of all local densities290from sage.quadratic_forms.quadratic_form__siegel_product import \291siegel_product292293## Routines to compute p-neighbors294from sage.quadratic_forms.quadratic_form__neighbors import \295find_primitive_p_divisible_vector__random, \296find_primitive_p_divisible_vector__next, \297find_p_neighbor_from_vec298299## Routines to reduce a given quadratic form300from sage.quadratic_forms.quadratic_form__reduction_theory import \301reduced_binary_form1, \302reduced_ternary_form__Dickson, \303reduced_binary_form, \304minkowski_reduction, \305minkowski_reduction_for_4vars__SP306## Wrappers for Conway-Sloane genus routines (in ./genera/)307from sage.quadratic_forms.quadratic_form__genus import \308global_genus_symbol, \309local_genus_symbol, \310CS_genus_symbol_list311312313## Routines to compute local masses for ZZ.314from sage.quadratic_forms.quadratic_form__mass import \315shimura_mass__maximal, \316GHY_mass__maximal317from sage.quadratic_forms.quadratic_form__mass__Siegel_densities import \318mass__by_Siegel_densities, \319Pall_mass_density_at_odd_prime, \320Watson_mass_at_2, \321Kitaoka_mass_at_2, \322mass_at_two_by_counting_mod_power323from sage.quadratic_forms.quadratic_form__mass__Conway_Sloane_masses import \324parity, \325is_even, \326is_odd, \327conway_species_list_at_odd_prime, \328conway_species_list_at_2, \329conway_octane_of_this_unimodular_Jordan_block_at_2, \330conway_diagonal_factor, \331conway_cross_product_doubled_power, \332conway_type_factor, \333conway_p_mass, \334conway_standard_p_mass, \335conway_standard_mass, \336conway_mass337# conway_generic_mass, \338# conway_p_mass_adjustment339340## Routines to check local representability of numbers341from sage.quadratic_forms.quadratic_form__local_representation_conditions import \342local_representation_conditions, \343is_locally_universal_at_prime, \344is_locally_universal_at_all_primes, \345is_locally_universal_at_all_places, \346is_locally_represented_number_at_place, \347is_locally_represented_number348349## Routines to make a split local covering of the given quadratic form.350from sage.quadratic_forms.quadratic_form__split_local_covering import \351cholesky_decomposition, \352vectors_by_length, \353complementary_subform_to_vector, \354split_local_cover355356## Routines to make automorphisms of the given quadratic form.357from sage.quadratic_forms.quadratic_form__automorphisms import \358basis_of_short_vectors, \359short_vector_list_up_to_length, \360short_primitive_vector_list_up_to_length, \361automorphisms, \362number_of_automorphisms, \363number_of_automorphisms__souvigner, \364set_number_of_automorphisms365366## Routines to test the local and global equivalence/isometry of two quadratic forms.367from sage.quadratic_forms.quadratic_form__equivalence_testing import \368is_globally_equivalent__souvigner, \369is_globally_equivalent_to, \370is_locally_equivalent_to, \371has_equivalent_Jordan_decomposition_at_prime372373def __init__(self, R, n=None, entries=None, unsafe_initialization=False, number_of_automorphisms=None, determinant=None):374"""375EXAMPLES::376377sage: s = QuadraticForm(ZZ, 4, range(10))378sage: s == loads(dumps(s))379True380"""381## Deal with: QuadraticForm(ring, matrix)382matrix_init_flag = False383if isinstance(R, Ring):384if is_Matrix(n):385## Test if n is symmetric and has even diagonal386if not self._is_even_symmetric_matrix_(n, R):387raise TypeError, "Oops! The matrix is not a symmetric with even diagonal defined over R."388389## Rename the matrix and ring390M = n391M_ring = R392matrix_init_flag = True393394395## Deal with: QuadraticForm(matrix)396if is_Matrix(R) and (n == None):397398## Test if R is symmetric and has even diagonal399if not self._is_even_symmetric_matrix_(R):400raise TypeError, "Oops! The matrix is not a symmetric with even diagonal."401402## Rename the matrix and ring403M = R404M_ring = R.base_ring()405matrix_init_flag = True406407## Perform the quadratic form initialization408if matrix_init_flag == True:409self.__n = M.nrows()410self.__base_ring = M_ring411self.__coeffs = []412for i in range(M.nrows()):413for j in range(i, M.nrows()):414if (i == j):415self.__coeffs += [ M_ring(M[i,j] / 2) ]416else:417self.__coeffs += [ M_ring(M[i,j]) ]418419return420421## -----------------------------------------------------------422423## Verify the size of the matrix is an integer >= 0424try:425n = int(n)426except:427raise TypeError, "Oops! The size " + str(n) + " must be an integer."428if (n < 0):429raise TypeError, "Oops! The size " + str(n) + " must be a non-negative integer."430431## TODO: Verify that R is a ring...432433## Store the relevant variables434N = int(n*(n+1))/2435self.__n = int(n)436self.__base_ring = R437self.__coeffs = [self.__base_ring(0) for i in range(N)]438439## Check if entries is a list for the current size, and if so, write the upper-triangular matrix440if isinstance(entries, list) and (len(entries) == N):441for i in range(N):442self.__coeffs[i] = self.__base_ring(entries[i])443elif (entries != None):444raise TypeError, "Oops! The entries " + str(entries) + "must be a list of size n(n+1)/2."445446## -----------------------------------------------------------447448## Process possible forced initialization of various fields449self._external_initialization_list = []450if unsafe_initialization:451452## Set the number of automorphisms453if number_of_automorphisms != None:454self.set_number_of_automorphisms(number_of_automorphisms)455#self.__number_of_automorphisms = number_of_automorphisms456#self.__external_initialization_list.append('number_of_automorphisms')457458## Set the determinant459if determinant != None:460self.__det = determinant461self._external_initialization_list.append('determinant')462463464def list_external_initializations(self):465"""466Returns a list of the fields which were set externally at467creation, and not created through the usual QuadraticForm468methods. These fields are as good as the external process469that made them, and are thus not guaranteed to be correct.470471EXAMPLES::472473sage: Q = QuadraticForm(ZZ, 2, [1,0,5])474sage: Q.list_external_initializations()475[]476sage: T = Q.theta_series()477sage: Q.list_external_initializations()478[]479sage: Q = QuadraticForm(ZZ, 2, [1,0,5], unsafe_initialization=False, number_of_automorphisms=3, determinant=0)480sage: Q.list_external_initializations()481[]482483::484485sage: Q = QuadraticForm(ZZ, 2, [1,0,5], unsafe_initialization=False, number_of_automorphisms=3, determinant=0)486sage: Q.list_external_initializations()487[]488sage: Q = QuadraticForm(ZZ, 2, [1,0,5], unsafe_initialization=True, number_of_automorphisms=3, determinant=0)489sage: Q.list_external_initializations()490['number_of_automorphisms', 'determinant']491"""492return deepcopy(self._external_initialization_list)493494495def _pari_(self):496"""497Return a pari-formatted Hessian matrix for Q.498499EXAMPLES::500501sage: Q = QuadraticForm(ZZ, 2, [1,0,5])502sage: Q._pari_()503[2, 0; 0, 10]504505"""506return self.matrix()._pari_()507508509def __repr__(self):510"""511Give a text representation for the quadratic form given as an upper-triangular matrix of coefficients.512513EXAMPLES::514515sage: QuadraticForm(ZZ, 2, [1,3,5])516Quadratic form in 2 variables over Integer Ring with coefficients:517[ 1 3 ]518[ * 5 ]519520"""521n = self.dim()522out_str = "Quadratic form in " + str(n) + " variables over " + str(self.base_ring()) + " with coefficients: \n"523for i in range(n):524out_str += "[ "525for j in range(n):526if (i > j):527out_str += "* "528else:529out_str += str(self[i,j]) + " "530out_str += "]\n"531return out_str532533534def _latex_(self):535"""536Give a LaTeX representation for the quadratic form given as an upper-triangular matrix of coefficients.537538EXAMPLES::539540sage: Q = QuadraticForm(ZZ, 2, [2,3,5])541sage: Q._latex_()542'Quadratic form in 2 variables over Integer Ring with coefficients: \\newline\\left[ \\begin{array}{cc}2 & 3 & * & 5 & \\end{array} \\right]'543544"""545n = self.dim()546out_str = ""547out_str += "Quadratic form in " + str(n) + " variables over " + str(self.base_ring())548out_str += " with coefficients: \\newline"549out_str += "\\left[ \\begin{array}{" + n * "c" + "}"550for i in range(n):551for j in range(n):552if (i > j):553out_str += " * & "554else:555out_str += str(self[i,j]) + " & "556# if i < (n-1):557# out_str += "\\"558out_str += "\\end{array} \\right]"559return out_str560561562563def __getitem__(self, ij):564"""565Return the coefficient `a_{ij}` of `x_i * x_j`.566567EXAMPLES::568569sage: Q = QuadraticForm(ZZ, 3, [1,2,3,4,5,6])570sage: matrix(ZZ, 3, 3, [Q[i,j] for i in range(3) for j in range(3)])571[1 2 3]572[2 4 5]573[3 5 6]574575"""576## Unpack the list of indices577i, j = ij578i = int(i)579j = int(j)580581## Ensure we're using upper-triangular coordinates582if i > j:583tmp = i584i = j585j = tmp586587return self.__coeffs[i*self.__n - i*(i-1)/2 + j - i]588589590def __setitem__(self, ij, coeff):591"""592Set the coefficient `a_{ij}` in front of `x_i * x_j`.593594EXAMPLES::595596sage: Q = QuadraticForm(ZZ, 3, [1,2,3,4,5,6])597sage: Q598Quadratic form in 3 variables over Integer Ring with coefficients:599[ 1 2 3 ]600[ * 4 5 ]601[ * * 6 ]602sage: Q[2,1] = 17603sage: Q604Quadratic form in 3 variables over Integer Ring with coefficients:605[ 1 2 3 ]606[ * 4 17 ]607[ * * 6 ]608609"""610## Unpack the list of indices611i, j = ij612i = int(i)613j = int(j)614615## TO DO: Verify that 0 <= i, j <= (n-1)616617## Ensure we're using upper-triangular coordinates618if i > j:619tmp = i620i = j621j = tmp622623## Set the entry624try:625self.__coeffs[i*self.__n - i*(i-1)/2 + j -i] = self.__base_ring(coeff)626except:627raise RuntimeError, "Oops! This coefficient can't be coerced to an element of the base ring for the quadratic form."628629630######################################631# TO DO: def __cmp__(self, other):632######################################633634def __eq__(self, right):635"""636Determines if two quadratic forms are equal.637638EXAMPLES::639640sage: Q = QuadraticForm(ZZ, 2, [1,4,10])641sage: Q == Q642True643644sage: Q1 = QuadraticForm(QQ, 2, [1,4,10])645sage: Q == Q1646False647648sage: Q2 = QuadraticForm(ZZ, 2, [1,4,-10])649sage: Q == Q1650False651sage: Q == Q2652False653sage: Q1 == Q2654False655656"""657if not isinstance(right, QuadraticForm):658return False659return (self.__base_ring == right.__base_ring) and (self.__coeffs == right.__coeffs)660661662def __add__(self, right):663"""664Returns the direct sum of two quadratic forms.665666EXAMPLES::667sage: Q = QuadraticForm(ZZ, 2, [1,4,10])668sage: Q669Quadratic form in 2 variables over Integer Ring with coefficients:670[ 1 4 ]671[ * 10 ]672sage: Q2 = QuadraticForm(ZZ, 2, [1,4,-10])673sage: Q + Q2674Quadratic form in 4 variables over Integer Ring with coefficients:675[ 1 4 0 0 ]676[ * 10 0 0 ]677[ * * 1 4 ]678[ * * * -10 ]679680"""681if not isinstance(right, QuadraticForm):682raise TypeError, "Oops! Can't add these objects since they're not both quadratic forms. =("683elif (self.base_ring() != right.base_ring()):684raise TypeError, "Oops! Can't add these since the quadratic forms don't have the same base rings... =("685else:686Q = QuadraticForm(self.base_ring(), self.dim() + right.dim())687n = self.dim()688m = right.dim()689690for i in range(n):691for j in range(i,n):692Q[i,j] = self[i,j]693694for i in range(m):695for j in range(i,m):696Q[n+i,n+j] = right[i,j]697698return Q699700701def sum_by_coefficients_with(self, right):702"""703Returns the sum (on coefficients) of two quadratic forms of the same size.704705EXAMPLES::706707sage: Q = QuadraticForm(ZZ, 2, [1,4,10])708sage: Q709Quadratic form in 2 variables over Integer Ring with coefficients:710[ 1 4 ]711[ * 10 ]712sage: Q+Q713Quadratic form in 4 variables over Integer Ring with coefficients:714[ 1 4 0 0 ]715[ * 10 0 0 ]716[ * * 1 4 ]717[ * * * 10 ]718719sage: Q2 = QuadraticForm(ZZ, 2, [1,4,-10])720sage: Q.sum_by_coefficients_with(Q2)721Quadratic form in 2 variables over Integer Ring with coefficients:722[ 2 8 ]723[ * 0 ]724725"""726if not isinstance(right, QuadraticForm):727raise TypeError, "Oops! Can't add these objects since they're not both quadratic forms. =("728elif (self.__n != right.__n):729raise TypeError, "Oops! Can't add these since the quadratic forms don't have the same sizes... =("730elif (self.__base_ring != right.__base_ring):731raise TypeError, "Oops! Can't add these since the quadratic forms don't have the same base rings... =("732else:733return QuadraticForm(self.__base_ring, self.__n, [self.__coeffs[i] + right.__coeffs[i] for i in range(len(self.__coeffs))])734735736## ======================== CHANGE THIS TO A TENSOR PRODUCT?!? Even in Characteristic 2?!? =======================737# def __mul__(self, right):738# """739# Multiply (on the right) the quadratic form Q by an element of the ring that Q is defined over.740#741# EXAMPLES::742# sage: Q = QuadraticForm(ZZ, 2, [1,4,10])743# sage: Q*2744# Quadratic form in 2 variables over Integer Ring with coefficients:745# [ 2 8 ]746# [ * 20 ]747#748# sage: Q+Q == Q*2749# True750#751# """752# try:753# c = self.base_ring()(right)754# except:755# raise TypeError, "Oh no! The multiplier cannot be coerced into the base ring of the quadratic form. =("756#757# return QuadraticForm(self.base_ring(), self.dim(), [c * self.__coeffs[i] for i in range(len(self.__coeffs))])758# =========================================================================================================================759760761762def __call__(self, v):763"""764Evaluate this quadratic form Q on a vector or matrix of elements765coercible to the base ring of the quadratic form. If a vector766is given then the output will be the ring element Q(`v`), but if a767matrix is given then the output will be the quadratic form Q'768which in matrix notation is given by:769770.. math::771Q' = v^t * Q * v.772773774EXAMPLES::775776## Evaluate a quadratic form at a vector:777## --------------------------------------778sage: Q = QuadraticForm(QQ, 3, range(6))779sage: Q780Quadratic form in 3 variables over Rational Field with coefficients:781[ 0 1 2 ]782[ * 3 4 ]783[ * * 5 ]784sage: Q([1,2,3])78589786sage: Q([1,0,0])7870788sage: Q([1,1,1])78915790791::792793## Evaluate a quadratic form using a column matrix:794## ------------------------------------------------795sage: Q = QuadraticForm(QQ, 2, range(1,4))796sage: A = Matrix(ZZ,2,2,[-1,0,0,1])797sage: Q(A)798Quadratic form in 2 variables over Rational Field with coefficients:799[ 1 -2 ]800[ * 3 ]801sage: Q([1,0])8021803sage: type(Q([1,0]))804<type 'sage.rings.rational.Rational'>805sage: Q = QuadraticForm(QQ, 2, range(1,4))806sage: Q(matrix(2, [1,0]))807Quadratic form in 1 variables over Rational Field with coefficients:808[ 1 ]809810::811812## Simple 2x2 change of variables:813## -------------------------------814sage: Q = QuadraticForm(ZZ, 2, [1,0,1])815sage: Q816Quadratic form in 2 variables over Integer Ring with coefficients:817[ 1 0 ]818[ * 1 ]819sage: M = Matrix(ZZ, 2, 2, [1,1,0,1])820sage: M821[1 1]822[0 1]823sage: Q(M)824Quadratic form in 2 variables over Integer Ring with coefficients:825[ 1 2 ]826[ * 2 ]827828::829830## Some more tests:831## ----------------832sage: Q = DiagonalQuadraticForm(ZZ, [1,1,1])833sage: Q([1,2,3])83414835sage: v = vector([1,2,3])836sage: Q(v)83714838sage: t = tuple([1,2,3])839sage: Q(v)84014841sage: M = Matrix(ZZ, 3, [1,2,3])842sage: Q(M)843Quadratic form in 1 variables over Integer Ring with coefficients:844[ 14 ]845846"""847## If we are passed a matrix A, return the quadratic form Q(A(x))848## (In matrix notation: A^t * Q * A)849n = self.dim()850851if is_Matrix(v):852## Check that v has the correct number of rows853if v.nrows() != n:854raise TypeError, "Oops! The matrix must have " + str(n) + " rows. =("855856## Create the new quadratic form857m = v.ncols()858Q2 = QuadraticForm(self.base_ring(), m)859return QFEvaluateMatrix(self, v, Q2)860861elif (is_Vector(v) or isinstance(v, (list, tuple))):862## Check the vector/tuple/list has the correct length863if not (len(v) == n):864raise TypeError, "Oops! Your vector needs to have length " + str(n) + " ."865866## TO DO: Check that the elements can be coerced into the base ring of Q -- on first elt.867if len(v) > 0:868try:869x = self.base_ring()(v[0])870except:871raise TypeError, "Oops! Your vector is not coercible to the base ring of the quadratic form... =("872873## Attempt to evaluate Q[v]874return QFEvaluateVector(self, v)875876else:877raise(TypeError, "Oops! Presently we can only evaluate a quadratic form on a list, tuple, vector or matrix.")878879880881882## =====================================================================================================883884def _is_even_symmetric_matrix_(self, A, R=None):885"""886Tests if a matrix is symmetric, defined over R, and has even diagonal in R.887888INPUT:889A -- matrix890891R -- ring892893EXAMPLES::894895sage: Q = QuadraticForm(ZZ, 2, [2,3,5])896sage: A = Q.matrix()897sage: A898[ 4 3]899[ 3 10]900sage: Q._is_even_symmetric_matrix_(A)901True902sage: A[0,0] = 1903sage: Q._is_even_symmetric_matrix_(A)904False905906"""907if not is_Matrix(A):908raise TypeError, "A is not a matrix."909910ring_coerce_test = True911if R == None: ## This allows us to omit the ring from the variables, and take it from the matrix912R = A.base_ring()913ring_coerce_test = False914915if not isinstance(R, Ring):916raise TypeError, "R is not a ring."917918if not A.is_square():919return False920921## Test that the matrix is symmetric922n = A.nrows()923for i in range(n):924for j in range(i+1, n):925if A[i,j] != A[j,i]:926return False927928## Test that all entries coerce to R929if not ((A.base_ring() == R) or (ring_coerce_test == True)):930try:931for i in range(n):932for j in range(i, n):933x = R(A[i,j])934except:935return False936937## Test that the diagonal is even (if 1/2 isn't in R)938if not R(2).is_unit():939for i in range(n):940if not is_even(R(A[i,i])):941return False942943return True944945946## =====================================================================================================947948def matrix(self):949"""950Returns the Hessian matrix A for which Q(X) = `(1/2) * X^t * A * X`.951952EXAMPLES::953954sage: Q = QuadraticForm(ZZ, 3, range(6))955sage: Q.matrix()956[ 0 1 2]957[ 1 6 4]958[ 2 4 10]959960"""961return self.Hessian_matrix()962963964def Hessian_matrix(self):965"""966Returns the Hessian matrix A for which Q(X) = `(1/2) * X^t * A * X`.967968EXAMPLES::969970sage: Q = QuadraticForm(QQ, 2, range(1,4))971sage: Q972Quadratic form in 2 variables over Rational Field with coefficients:973[ 1 2 ]974[ * 3 ]975sage: Q.Hessian_matrix()976[2 2]977[2 6]978sage: Q.matrix().base_ring()979Rational Field980981"""982mat_entries = []983for i in range(self.dim()):984for j in range(self.dim()):985if (i == j):986mat_entries += [ 2 * self[i,j] ]987else:988mat_entries += [ self[i,j] ]989990return matrix(self.base_ring(), self.dim(), self.dim(), mat_entries)991992993def Gram_matrix_rational(self):994"""995Returns a (symmetric) Gram matrix A for the quadratic form Q,996meaning that997998.. math::9991000Q(x) = x^t * A * x,10011002defined over the fraction field of the base ring.10031004EXAMPLES::10051006sage: Q = DiagonalQuadraticForm(ZZ, [1,3,5,7])1007sage: A = Q.Gram_matrix_rational(); A1008[1 0 0 0]1009[0 3 0 0]1010[0 0 5 0]1011[0 0 0 7]1012sage: A.base_ring()1013Rational Field10141015"""1016return (ZZ(1) / ZZ(2)) * self.matrix()101710181019def Gram_matrix(self):1020"""1021Returns a (symmetric) Gram matrix A for the quadratic form Q,1022meaning that10231024.. math::10251026Q(x) = x^t * A * x,10271028defined over the base ring of Q. If this is not possible,1029then a TypeError is raised.10301031EXAMPLES::10321033sage: Q = DiagonalQuadraticForm(ZZ, [1,3,5,7])1034sage: A = Q.Gram_matrix(); A1035[1 0 0 0]1036[0 3 0 0]1037[0 0 5 0]1038[0 0 0 7]1039sage: A.base_ring()1040Integer Ring10411042"""1043A = (ZZ(1) / ZZ(2)) * self.matrix()1044n = self.dim()10451046## Test to see if it has an integral Gram matrix1047Int_flag = True1048for i in range(n):1049for j in range(i,n):1050Int_flag = Int_flag and A[i,j] in self.base_ring()10511052## Return the Gram matrix, or an error1053if Int_flag:1054return MatrixSpace(self.base_ring(), n, n)(A)1055else:1056raise TypeError, "Oops! This form does not have an integral Gram matrix. =("105710581059def has_integral_Gram_matrix(self):1060"""1061Returns whether the quadratic form has an integral Gram matrix (with respect to its base ring).10621063A warning is issued if the form is defined over a field, since in that case the return is trivially true.10641065EXAMPLES::10661067sage: Q = QuadraticForm(ZZ, 2, [7,8,9])1068sage: Q.has_integral_Gram_matrix()1069True10701071::10721073sage: Q = QuadraticForm(ZZ, 2, [4,5,6])1074sage: Q.has_integral_Gram_matrix()1075False10761077"""1078## Warning over fields1079if is_field(self.base_ring()):1080warn("Warning -- A quadratic form over a field always has integral Gram matrix. Do you really want to do this?!?")10811082## Determine integrality of the Gram matrix1083flag = True1084try:1085self.Gram_matrix()1086except:1087flag = False10881089return flag109010911092def gcd(self):1093"""1094Returns the greatest common divisor of the coefficients of the1095quadratic form (as a polynomial).10961097EXAMPLES::10981099sage: Q = QuadraticForm(ZZ, 4, range(1, 21, 2))1100sage: Q.gcd()1101111021103::11041105sage: Q = QuadraticForm(ZZ, 4, range(0, 20, 2))1106sage: Q.gcd()110721108"""1109if self.base_ring() != ZZ:1110raise TypeError, "Oops! The given quadratic form must be defined over ZZ."11111112return GCD(self.coefficients())111311141115def polynomial(self,names='x'):1116r"""1117Returns the polynomial in 'n' variables of the quadratic form in the ring 'R[names].'11181119INPUT:11201121-'self' - a quadratic form over a commatitive ring.1122-'names' - the name of the variables. Digits will be appended to the name for each different canonical1123variable e.g x1, x2, x3 etc.11241125OUTPUT:11261127The polynomial form of the quadratic form.11281129EXAMPLES::11301131sage: Q = DiagonalQuadraticForm(QQ,[1, 3, 5, 7])1132sage: P = Q.polynomial(); P11332*x0^2 + 6*x1^2 + 10*x2^2 + 14*x3^211341135::11361137sage: F.<a> = NumberField(x^2 - 5)1138sage: Z = F.ring_of_integers()1139sage: Q = QuadraticForm(Z,3,[2*a, 3*a, 0 , 1 - a, 0, 2*a + 4])1140sage: P = Q.polynomial(names='y'); P11414*a*y0^2 + 6*a*y0*y1 + (-2*a + 2)*y1^2 + (4*a + 8)*y2^21142sage: Q = QuadraticForm(F,4,[a, 3*a, 0, 1 - a, a - 3, 0, 2*a + 4, 4 + a, 0, 1])1143sage: Q.polynomial(names='z')1144(2*a)*z0^2 + (6*a)*z0*z1 + (2*a - 6)*z1^2 + (2*a + 8)*z2^2 + (-2*a + 2)*z0*z3 + (4*a + 8)*z1*z3 + 2*z3^21145sage: B.<i,j,k> = QuaternionAlgebra(F,-1,-1)1146sage: Q = QuadraticForm(B, 3, [2*a, 3*a, i, 1 - a, 0, 2*a + 4])1147sage: Q.polynomial()1148Traceback (most recent call last):1149...1150ValueError: Can only create polynomial rings over commutative rings.11511152"""1153M = self.matrix()1154n = self.dim()1155B = self.base_ring()1156try:1157R = PolynomialRing(self.base_ring(),names,n)1158except:1159raise ValueError, 'Can only create polynomial rings over commutative rings.'1160V = vector(R.gens())1161P = (V*M).dot_product(V)1162return P11631164116511661167def is_primitive(self):1168"""1169Determines if the given integer-valued form is primitive1170(i.e. not an integer (>1) multiple of another integer-valued1171quadratic form).11721173EXAMPLES::11741175sage: Q = QuadraticForm(ZZ, 2, [2,3,4])1176sage: Q.is_primitive()1177True1178sage: Q = QuadraticForm(ZZ, 2, [2,4,8])1179sage: Q.is_primitive()1180False11811182"""1183return (self.gcd() == 1)118411851186def primitive(self):1187"""1188Returns a primitive version of an integer-valued quadratic form, defined over `ZZ`.11891190EXAMPLES::11911192sage: Q = QuadraticForm(ZZ, 2, [2,3,4])1193sage: Q.primitive()1194Quadratic form in 2 variables over Integer Ring with coefficients:1195[ 2 3 ]1196[ * 4 ]1197sage: Q = QuadraticForm(ZZ, 2, [2,4,8])1198sage: Q.primitive()1199Quadratic form in 2 variables over Integer Ring with coefficients:1200[ 1 2 ]1201[ * 4 ]12021203"""1204if self.base_ring() != ZZ:1205raise TypeError, "Oops! The given quadratic form must be defined over ZZ."12061207g = self.gcd()1208return QuadraticForm(self.base_ring(), self.dim(), [ZZ(x/g) for x in self.coefficients()])1209121012111212def adjoint_primitive(self):1213"""1214Returns the primitive adjoint of the quadratic form, which is1215the smallest discriminant integer-valued quadratic form whose1216matrix is a scalar multiple of the inverse of the matrix of1217the given quadratic form.12181219EXAMPLES::12201221sage: Q = QuadraticForm(ZZ, 2, [1,2,3])1222sage: Q.adjoint_primitive()1223Quadratic form in 2 variables over Integer Ring with coefficients:1224[ 3 -2 ]1225[ * 1 ]12261227"""1228return QuadraticForm(self.Hessian_matrix().adjoint()).primitive()1229123012311232def dim(self):1233"""1234Gives the number of variables of the quadratic form.12351236EXAMPLES::12371238sage: Q = QuadraticForm(ZZ, 2, [1,2,3])1239sage: Q.dim()1240212411242"""1243return self.__n124412451246def base_ring(self):1247"""1248Gives the ring over which the quadratic form is defined.12491250EXAMPLES::12511252sage: Q = QuadraticForm(ZZ, 2, [1,2,3])1253sage: Q.base_ring()1254Integer Ring12551256"""1257return self.__base_ring125812591260def coefficients(self):1261"""1262Gives the matrix of upper triangular coefficients,1263by reading across the rows from the main diagonal.12641265EXAMPLES::12661267sage: Q = QuadraticForm(ZZ, 2, [1,2,3])1268sage: Q.coefficients()1269[1, 2, 3]12701271"""1272return self.__coeffs127312741275def det(self):1276"""1277Gives the determinant of the Gram matrix of 2*Q, or1278equivalently the determinant of the Hessian matrix of Q.12791280(Note: This is always defined over the same ring as the1281quadratic form.)12821283EXAMPLES::12841285sage: Q = QuadraticForm(ZZ, 2, [1,2,3])1286sage: Q.det()1287812881289"""1290try:1291return self.__det1292except:1293## Compute the determinant1294if self.dim() == 0:1295new_det = self.base_ring()(1)1296else:1297new_det = self.matrix().det()12981299## Cache and return the determinant1300self.__det = new_det1301return new_det130213031304def Gram_det(self):1305"""1306Gives the determinant of the Gram matrix of Q.13071308(Note: This is defined over the fraction field of the ring of1309the quadratic form, but is often not defined over the same1310ring as the quadratic form.)13111312EXAMPLES::13131314sage: Q = QuadraticForm(ZZ, 2, [1,2,3])1315sage: Q.Gram_det()1316213171318"""1319return self.det() / ZZ(2**self.dim())132013211322def base_change_to(self, R):1323"""1324Alters the quadratic form to have all coefficients1325defined over the new base_ring R. Here R must be1326coercible to from the current base ring.13271328Note: This is preferable to performing an explicit1329coercion through the base_ring() method, which does1330not affect the individual coefficients. This is1331particularly useful for performing fast modular1332arithmetic evaluations.13331334INPUT:1335R -- a ring13361337OUTPUT:1338quadratic form13391340EXAMPLES::13411342sage: Q = DiagonalQuadraticForm(ZZ,[1,1]); Q1343Quadratic form in 2 variables over Integer Ring with coefficients:1344[ 1 0 ]1345[ * 1 ]13461347::13481349sage: Q1 = Q.base_change_to(IntegerModRing(5)); Q11350Quadratic form in 2 variables over Ring of integers modulo 5 with coefficients:1351[ 1 0 ]1352[ * 1 ]13531354sage: Q1([35,11])1355113561357"""1358## Check that a canonical coercion is possible1359if not is_Ring(R):1360raise TypeError, "Oops! R is not a ring. =("1361if not R.has_coerce_map_from(self.base_ring()):1362raise TypeError, "Oops! There is no canonical coercion from " + str(self.base_ring()) + " to R."13631364## Return the coerced form1365return QuadraticForm(R, self.dim(), [R(x) for x in self.coefficients()])136613671368def level(self):1369r"""1370Determines the level of the quadratic form over a PID, which is a1371generator for the smallest ideal `N` of `R` such that N * (the matrix of13722*Q)^(-1) is in R with diagonal in 2*R.13731374Over `\ZZ` this returns a non-negative number.13751376(Caveat: This always returns the unit ideal when working over a field!)13771378EXAMPLES::13791380sage: Q = QuadraticForm(ZZ, 2, range(1,4))1381sage: Q.level()1382813831384sage: Q1 = QuadraticForm(QQ, 2, range(1,4))1385sage: Q1.level() # random1386UserWarning: Warning -- The level of a quadratic form over a field is always 1. Do you really want to do this?!?1387113881389sage: Q = DiagonalQuadraticForm(ZZ, [1,3,5,7])1390sage: Q.level()139142013921393"""1394## Try to return the cached level1395try:1396return self.__level1397except:13981399## Check that the base ring is a PID1400if not is_PrincipalIdealDomain(self.base_ring()):1401raise TypeError, "Oops! The level (as a number) is only defined over a Principal Ideal Domain. Try using level_ideal()."140214031404## Warn the user if the form is defined over a field!1405if self.base_ring().is_field():1406warn("Warning -- The level of a quadratic form over a field is always 1. Do you really want to do this?!?")1407#raise RuntimeError, "Warning -- The level of a quadratic form over a field is always 1. Do you really want to do this?!?"140814091410## Check invertibility and find the inverse1411try:1412mat_inv = self.matrix()**(-1)1413except:1414raise TypeError, "Oops! The quadratic form is degenerate (i.e. det = 0). =("14151416## Compute the level1417inv_denoms = []1418for i in range(self.dim()):1419for j in range(i, self.dim()):1420if (i == j):1421inv_denoms += [denominator(mat_inv[i,j] / 2)]1422else:1423inv_denoms += [denominator(mat_inv[i,j])]1424lvl = LCM(inv_denoms)1425lvl = ideal(self.base_ring()(lvl)).gen()1426##############################################################1427## To do this properly, the level should be the inverse of the1428## fractional ideal (over R) generated by the entries whose1429## denominators we take above. =)1430##############################################################14311432## Normalize the result over ZZ1433if self.base_ring() == IntegerRing():1434lvl = abs(lvl)14351436## Cache and return the level1437self.__level = lvl1438return lvl1439144014411442def level_ideal(self):1443"""1444Determines the level of the quadratic form (over R), which is the1445smallest ideal N of R such that N * (the matrix of 2*Q)^(-1) is1446in R with diagonal in 2*R.1447(Caveat: This always returns the principal ideal when working over a field!)14481449WARNING: THIS ONLY WORKS OVER A PID RING OF INTEGERS FOR NOW!1450(Waiting for Sage fractional ideal support.)14511452EXAMPLES::14531454sage: Q = QuadraticForm(ZZ, 2, range(1,4))1455sage: Q.level_ideal()1456Principal ideal (8) of Integer Ring14571458::14591460sage: Q1 = QuadraticForm(QQ, 2, range(1,4))1461sage: Q1.level_ideal()1462Principal ideal (1) of Rational Field14631464::14651466sage: Q = DiagonalQuadraticForm(ZZ, [1,3,5,7])1467sage: Q.level_ideal()1468Principal ideal (420) of Integer Ring14691470"""1471##############################################################1472## To do this properly, the level should be the inverse of the1473## fractional ideal (over R) generated by the entries whose1474## denominators we take above. =)1475##############################################################14761477return ideal(self.base_ring()(self.level()))1478147914801481## =====================================================================================================14821483def DiagonalQuadraticForm(R, diag):1484"""1485Returns a quadratic form over `R` which is a sum of squares.14861487INPUT:14881489- `R` -- ring1490- ``diag`` -- list/tuple of elements coercible to R14911492OUTPUT:14931494quadratic form14951496EXAMPLES::14971498sage: Q = DiagonalQuadraticForm(ZZ, [1,3,5,7])1499sage: Q1500Quadratic form in 4 variables over Integer Ring with coefficients:1501[ 1 0 0 0 ]1502[ * 3 0 0 ]1503[ * * 5 0 ]1504[ * * * 7 ]15051506"""1507Q = QuadraticForm(R, len(diag))1508for i in range(len(diag)):1509Q[i,i] = diag[i]1510return Q151115121513