Quadratic Forms Overview¶
AUTHORS:
- Jon Hanke (2007-06-19)
- Anna Haensch (2010-07-01): Formatting and ReSTification
-
sage.quadratic_forms.quadratic_form.
DiagonalQuadraticForm
(R, diag)¶ Returns a quadratic form over \(R\) which is a sum of squares.
INPUT:
- \(R\) – ring
diag
– list/tuple of elements coercible to R
OUTPUT:
quadratic form
EXAMPLES:
sage: Q = DiagonalQuadraticForm(ZZ, [1,3,5,7]) sage: Q Quadratic form in 4 variables over Integer Ring with coefficients: [ 1 0 0 0 ] [ * 3 0 0 ] [ * * 5 0 ] [ * * * 7 ]
-
class
sage.quadratic_forms.quadratic_form.
QuadraticForm
(R, n=None, entries=None, unsafe_initialization=False, number_of_automorphisms=None, determinant=None)¶ Bases:
sage.structure.sage_object.SageObject
The
QuadraticForm
class represents a quadratic form in n variables with coefficients in the ring R.INPUT:
The constructor may be called in any of the following ways.
QuadraticForm(R, n, entries)
, where- \(R\) – ring for which the quadratic form is defined
- \(n\) – an integer >= 0
entries
– a list of \(n(n+1)/2\) coefficients of the quadratic form in \(R\) (given lexicographically, or equivalently, by rows of the matrix)
QuadraticForm(R, n)
, where- \(R\) – a ring
- \(n\) – a symmetric \(n \times n\) matrix with even diagonal (relative to \(R\))
QuadraticForm(R)
, where- \(R\) – a symmetric \(n \times n\) matrix with even diagonal (relative to its base ring)
If the keyword argument
unsafe_initialize
is True, then the subsequent fields may by used to force the external initialization of various fields of the quadratic form. Currently the only fields which can be set are:number_of_automorphisms
determinant
OUTPUT:
quadratic form
EXAMPLES:
sage: Q = QuadraticForm(ZZ, 3, [1,2,3,4,5,6]) sage: Q Quadratic form in 3 variables over Integer Ring with coefficients: [ 1 2 3 ] [ * 4 5 ] [ * * 6 ]
sage: Q = QuadraticForm(QQ, 3, [1,2,3,4/3 ,5,6]) sage: Q Quadratic form in 3 variables over Rational Field with coefficients: [ 1 2 3 ] [ * 4/3 5 ] [ * * 6 ] sage: Q[0,0] 1 sage: Q[0,0].parent() Rational Field
sage: Q = QuadraticForm(QQ, 7, range(28)) sage: Q Quadratic form in 7 variables over Rational Field with coefficients: [ 0 1 2 3 4 5 6 ] [ * 7 8 9 10 11 12 ] [ * * 13 14 15 16 17 ] [ * * * 18 19 20 21 ] [ * * * * 22 23 24 ] [ * * * * * 25 26 ] [ * * * * * * 27 ]
sage: Q = QuadraticForm(QQ, 2, range(1,4)) sage: A = Matrix(ZZ,2,2,[-1,0,0,1]) sage: Q(A) Quadratic form in 2 variables over Rational Field with coefficients: [ 1 -2 ] [ * 3 ]
sage: m = matrix(2,2,[1,2,3,4]) sage: m + m.transpose() [2 5] [5 8] sage: QuadraticForm(m + m.transpose()) Quadratic form in 2 variables over Integer Ring with coefficients: [ 1 5 ] [ * 4 ]
sage: QuadraticForm(ZZ, m + m.transpose()) Quadratic form in 2 variables over Integer Ring with coefficients: [ 1 5 ] [ * 4 ]
sage: QuadraticForm(QQ, m + m.transpose()) Quadratic form in 2 variables over Rational Field with coefficients: [ 1 5 ] [ * 4 ]
-
CS_genus_symbol_list
(force_recomputation=False)¶ Returns the list of Conway-Sloane genus symbols in increasing order of primes dividing 2*det.
EXAMPLES:
sage: Q = DiagonalQuadraticForm(ZZ, [1,2,3,4]) sage: Q.CS_genus_symbol_list() [Genus symbol at 2: [2^-2 4^1 8^1]_6, Genus symbol at 3: 1^3 3^-1]
-
GHY_mass__maximal
()¶ Use the GHY formula to compute the mass of a (maximal?) quadratic lattice. This works for any number field.
Reference: See [GHY, Prop 7.4 and 7.5, p121] and [GY, Thrm 10.20, p25].
INPUT:
noneOUTPUT:
a rational numberEXAMPLES:
sage: Q = DiagonalQuadraticForm(ZZ, [1,1,1]) sage: Q.GHY_mass__maximal()
-
Gram_det
()¶ Gives the determinant of the Gram matrix of Q.
(Note: This is defined over the fraction field of the ring of the quadratic form, but is often not defined over the same ring as the quadratic form.)
EXAMPLES:
sage: Q = QuadraticForm(ZZ, 2, [1,2,3]) sage: Q.Gram_det() 2
-
Gram_matrix
()¶ Returns a (symmetric) Gram matrix A for the quadratic form Q, meaning that
\[Q(x) = x^t * A * x,\]defined over the base ring of Q. If this is not possible, then a TypeError is raised.
EXAMPLES:
sage: Q = DiagonalQuadraticForm(ZZ, [1,3,5,7]) sage: A = Q.Gram_matrix(); A [1 0 0 0] [0 3 0 0] [0 0 5 0] [0 0 0 7] sage: A.base_ring() Integer Ring
-
Gram_matrix_rational
()¶ Returns a (symmetric) Gram matrix A for the quadratic form Q, meaning that
\[Q(x) = x^t * A * x,\]defined over the fraction field of the base ring.
EXAMPLES:
sage: Q = DiagonalQuadraticForm(ZZ, [1,3,5,7]) sage: A = Q.Gram_matrix_rational(); A [1 0 0 0] [0 3 0 0] [0 0 5 0] [0 0 0 7] sage: A.base_ring() Rational Field
-
Hessian_matrix
()¶ Returns the Hessian matrix A for which Q(X) = \((1/2) * X^t * A * X\).
EXAMPLES:
sage: Q = QuadraticForm(QQ, 2, range(1,4)) sage: Q Quadratic form in 2 variables over Rational Field with coefficients: [ 1 2 ] [ * 3 ] sage: Q.Hessian_matrix() [2 2] [2 6] sage: Q.matrix().base_ring() Rational Field
-
Kitaoka_mass_at_2
()¶ Returns the local mass of the quadratic form when \(p=2\), according to Theorem 5.6.3 on pp108–9 of Kitaoka’s Book “The Arithmetic of Quadratic Forms”.
INPUT:
noneOUTPUT:
a rational number > 0EXAMPLES:
sage: Q = DiagonalQuadraticForm(ZZ, [1,1,1]) sage: Q.Kitaoka_mass_at_2() ## WARNING: WE NEED TO CHECK THIS CAREFULLY! 1/2
-
Pall_mass_density_at_odd_prime
(p)¶ Returns the local representation density of a form (for representing itself) defined over \(ZZ\), at some prime \(p>2\).
REFERENCES:
Pall’s article “The Weight of a Genus of Positive n-ary Quadratic Forms” appearing in Proc. Symp. Pure Math. VIII (1965), pp95–105.INPUT:
\(p\) – a prime number > 2.OUTPUT:
a rational number.EXAMPLES:
sage: Q = QuadraticForm(ZZ, 3, [1,0,0,1,0,1]) sage: Q.Pall_mass_density_at_odd_prime(3) [(0, Quadratic form in 3 variables over Integer Ring with coefficients: [ 1 0 0 ] [ * 1 0 ] [ * * 1 ])] [(0, 3, 8)] [8/9] 8/9 8/9
-
Watson_mass_at_2
()¶ Returns the local mass of the quadratic form when \(p=2\), according to Watson’s Theorem 1 of “The 2-adic density of a quadratic form” in Mathematika 23 (1976), pp 94–106.
INPUT:
noneOUTPUT:
a rational numberEXAMPLES:
sage: Q = DiagonalQuadraticForm(ZZ, [1,1,1]) sage: Q.Watson_mass_at_2() ## WARNING: WE NEED TO CHECK THIS CAREFULLY! 384
-
add_symmetric
(c, i, j, in_place=False)¶ Performs the substitution \(x_j --> x_j + c*x_i\), which has the effect (on associated matrices) of symmetrically adding \(c * j\)-th row/column to the \(i\)-th row/column.
NOTE: This is meant for compatibility with previous code, which implemented a matrix model for this class. It is used in the local_normal_form() method.
INPUT:
\(c\) – an element of Q.base_ring()
\(i\), \(j\) – integers >= 0
OUTPUT:
a QuadraticForm (by default, otherwise none)EXAMPLES:
sage: Q = QuadraticForm(ZZ, 3, range(1,7)); Q Quadratic form in 3 variables over Integer Ring with coefficients: [ 1 2 3 ] [ * 4 5 ] [ * * 6 ] sage: Q.add_symmetric(-1, 1, 0) Quadratic form in 3 variables over Integer Ring with coefficients: [ 1 0 3 ] [ * 3 2 ] [ * * 6 ] sage: Q.add_symmetric(-3/2, 2, 0) ## ERROR: -3/2 isn't in the base ring ZZ Traceback (most recent call last): ... RuntimeError: Oops! This coefficient can't be coerced to an element of the base ring for the quadratic form.
sage: Q = QuadraticForm(QQ, 3, range(1,7)); Q Quadratic form in 3 variables over Rational Field with coefficients: [ 1 2 3 ] [ * 4 5 ] [ * * 6 ] sage: Q.add_symmetric(-3/2, 2, 0) Quadratic form in 3 variables over Rational Field with coefficients: [ 1 2 0 ] [ * 4 2 ] [ * * 15/4 ]
-
adjoint
()¶ This gives the adjoint (integral) quadratic form associated to the given form, essentially defined by taking the adjoint of the matrix.
EXAMPLES:
sage: Q = QuadraticForm(ZZ, 2, [1,2,5]) sage: Q.adjoint() Quadratic form in 2 variables over Integer Ring with coefficients: [ 5 -2 ] [ * 1 ]
sage: Q = QuadraticForm(ZZ, 3, [1, 0, -1, 2, -1, 5]) sage: Q.adjoint() Quadratic form in 3 variables over Integer Ring with coefficients: [ 39 2 8 ] [ * 19 4 ] [ * * 8 ]
-
adjoint_primitive
()¶ Returns the primitive adjoint of the quadratic form, which is the smallest discriminant integer-valued quadratic form whose matrix is a scalar multiple of the inverse of the matrix of the given quadratic form.
EXAMPLES:
sage: Q = QuadraticForm(ZZ, 2, [1,2,3]) sage: Q.adjoint_primitive() Quadratic form in 2 variables over Integer Ring with coefficients: [ 3 -2 ] [ * 1 ]
-
anisotropic_primes
()¶ Return a list with all of the anisotropic primes of the quadratic form.
The infinite place is denoted by \(-1\).
EXAMPLES:
sage: Q = DiagonalQuadraticForm(ZZ, [1,1,1]) sage: Q.anisotropic_primes() [2, -1] sage: Q = DiagonalQuadraticForm(ZZ, [1,1,1,1]) sage: Q.anisotropic_primes() [2, -1] sage: Q = DiagonalQuadraticForm(ZZ, [1,1,1,1,1]) sage: Q.anisotropic_primes() [-1]
-
antiadjoint
()¶ This gives an (integral) form such that its adjoint is the given form.
EXAMPLES:
sage: Q = QuadraticForm(ZZ, 3, [1, 0, -1, 2, -1, 5]) sage: Q.adjoint().antiadjoint() Quadratic form in 3 variables over Integer Ring with coefficients: [ 1 0 -1 ] [ * 2 -1 ] [ * * 5 ] sage: Q.antiadjoint() Traceback (most recent call last): ... ValueError: not an adjoint
-
automorphism_group
()¶ Return the group of automorphisms of the quadratic form.
OUTPUT: a
MatrixGroup
EXAMPLES:
sage: Q = DiagonalQuadraticForm(ZZ, [1,1,1]) sage: Q.automorphism_group() Matrix group over Rational Field with 3 generators ( [-1 0 0] [0 0 1] [ 0 0 1] [ 0 -1 0] [0 1 0] [-1 0 0] [ 0 0 -1], [1 0 0], [ 0 1 0] )
sage: DiagonalQuadraticForm(ZZ, [1,3,5,7]).automorphism_group() Matrix group over Rational Field with 4 generators ( [-1 0 0 0] [ 1 0 0 0] [ 1 0 0 0] [ 1 0 0 0] [ 0 -1 0 0] [ 0 -1 0 0] [ 0 1 0 0] [ 0 1 0 0] [ 0 0 -1 0] [ 0 0 1 0] [ 0 0 -1 0] [ 0 0 1 0] [ 0 0 0 -1], [ 0 0 0 1], [ 0 0 0 1], [ 0 0 0 -1] )
The smallest possible automorphism group has order two, since we can always change all signs:
sage: Q = QuadraticForm(ZZ, 3, [2, 1, 2, 2, 1, 3]) sage: Q.automorphism_group() Matrix group over Rational Field with 1 generators ( [-1 0 0] [ 0 -1 0] [ 0 0 -1] )
-
automorphisms
()¶ Return the list of the automorphisms of the quadratic form.
OUTPUT: a list of matrices
EXAMPLES:
sage: Q = DiagonalQuadraticForm(ZZ, [1,1,1]) sage: Q.number_of_automorphisms() 48 sage: 2^3 * factorial(3) 48 sage: len(Q.automorphisms()) 48
sage: Q = DiagonalQuadraticForm(ZZ, [1,3,5,7]) sage: Q.number_of_automorphisms() 16 sage: aut = Q.automorphisms() sage: len(aut) 16 sage: all(Q(M) == Q for M in aut) True sage: Q = QuadraticForm(ZZ, 3, [2, 1, 2, 2, 1, 3]) sage: sorted(Q.automorphisms()) [ [-1 0 0] [1 0 0] [ 0 -1 0] [0 1 0] [ 0 0 -1], [0 0 1] ]
-
base_change_to
(R)¶ Alters the quadratic form to have all coefficients defined over the new base_ring R. Here R must be coercible to from the current base ring.
Note: This is preferable to performing an explicit coercion through the base_ring() method, which does not affect the individual coefficients. This is particularly useful for performing fast modular arithmetic evaluations.
- INPUT:
- R – a ring
- OUTPUT:
- quadratic form
EXAMPLES:
sage: Q = DiagonalQuadraticForm(ZZ,[1,1]); Q Quadratic form in 2 variables over Integer Ring with coefficients: [ 1 0 ] [ * 1 ]
sage: Q1 = Q.base_change_to(IntegerModRing(5)); Q1 Quadratic form in 2 variables over Ring of integers modulo 5 with coefficients: [ 1 0 ] [ * 1 ] sage: Q1([35,11]) 1
-
base_ring
()¶ Gives the ring over which the quadratic form is defined.
EXAMPLES:
sage: Q = QuadraticForm(ZZ, 2, [1,2,3]) sage: Q.base_ring() Integer Ring
-
basiclemma
(M)¶ Finds a number represented by self and coprime to M.
EXAMPLES:
sage: Q = QuadraticForm(ZZ, 2, [2, 1, 3]) sage: Q.basiclemma(6) 71
-
basiclemmavec
(M)¶ Finds a vector where the value of the quadratic form is coprime to M.
EXAMPLES:
sage: Q = QuadraticForm(ZZ, 2, [2, 1, 5]) sage: Q.basiclemmavec(10) (6, 5) sage: Q(_) 227
-
basis_of_short_vectors
(show_lengths=False)¶ Return a basis for \(\ZZ^n\) made of vectors with minimal lengths Q(\(v\)).
OUTPUT:
a tuple of vectors, and optionally a tuple of values for each vector.
This uses pari:qfminim.
EXAMPLES:
sage: Q = DiagonalQuadraticForm(ZZ, [1,3,5,7]) sage: Q.basis_of_short_vectors() ((1, 0, 0, 0), (0, 1, 0, 0), (0, 0, 1, 0), (0, 0, 0, 1)) sage: Q.basis_of_short_vectors(True) (((1, 0, 0, 0), (0, 1, 0, 0), (0, 0, 1, 0), (0, 0, 0, 1)), (1, 3, 5, 7))
The returned vectors are immutable:
sage: v = Q.basis_of_short_vectors()[0] sage: v (1, 0, 0, 0) sage: v[0] = 0 Traceback (most recent call last): ... ValueError: vector is immutable; please change a copy instead (use copy())
-
bilinear_map
(v, w)¶ Returns the value of the associated bilinear map on two vectors
Given a quadratic form \(Q\) over some base ring \(R\) with characteristic not equal to 2, this gives the image of two vectors with coefficients in \(R\) under the associated bilinear map \(B\), given by the relation \(2 B(v,w) = Q(v) + Q(w) - Q(v+w)\).
INPUT:
\(v, w\) – two vectors
OUTPUT:
an element of the base ring \(R\).
EXAMPLES:
First, an example over \(\ZZ\):
sage: Q = QuadraticForm(ZZ,3,[1,4,0,1,4,1]) sage: v = vector(ZZ,(1,2,0)) sage: w = vector(ZZ,(0,1,1)) sage: Q.bilinear_map(v,w) 8
This also works over \(\QQ\):
sage: Q = QuadraticForm(QQ,2,[1/2,2,1]) sage: v = vector(QQ,(1,1)) sage: w = vector(QQ,(1/2,2)) sage: Q.bilinear_map(v,w) 19/4
The vectors must have the correct length:
sage: Q = DiagonalQuadraticForm(ZZ,[1,7,7]) sage: v = vector((1,2)) sage: w = vector((1,1,1)) sage: Q.bilinear_map(v,w) Traceback (most recent call last): ... TypeError: vectors must have length 3
This does not work if the characteristic is 2:
sage: Q = DiagonalQuadraticForm(GF(2),[1,1,1]) sage: v = vector((1,1,1)) sage: w = vector((1,1,1)) sage: Q.bilinear_map(v,w) Traceback (most recent call last): ... TypeError: not defined for rings of characteristic 2
-
cholesky_decomposition
(bit_prec=53)¶ Give the Cholesky decomposition of this quadratic form \(Q\) as a real matrix of precision
bit_prec
.RESTRICTIONS:
Q must be given as a QuadraticForm defined over \(\ZZ\), \(\QQ\), or some real field. If it is over some real field, then an error is raised if the precision given is not less than the defined precision of the real field defining the quadratic form!REFERENCE:
From Cohen’s “A Course in Computational Algebraic Number Theory” book, p 103.INPUT:
bit_prec
– a natural number (default 53).OUTPUT:
an upper triangular real matrix of precisionbit_prec
.- TO DO:
- If we only care about working over the real double field (RDF), then we
can use the
cholesky()
method present for square matrices over that.
Note
There is a note in the original code reading
##///////////////////////////////////////////////////////////////////////////////////////////////// ##/// Finds the Cholesky decomposition of a quadratic form -- as an upper-triangular matrix! ##/// (It's assumed to be global, hence twice the form it refers to.) <-- Python revision asks: Is this true?!? =| ##/////////////////////////////////////////////////////////////////////////////////////////////////
EXAMPLES:
sage: Q = DiagonalQuadraticForm(ZZ, [1,1,1]) sage: Q.cholesky_decomposition() [ 1.00000000000000 0.000000000000000 0.000000000000000] [0.000000000000000 1.00000000000000 0.000000000000000] [0.000000000000000 0.000000000000000 1.00000000000000]
sage: Q = QuadraticForm(QQ, 3, range(1,7)); Q Quadratic form in 3 variables over Rational Field with coefficients: [ 1 2 3 ] [ * 4 5 ] [ * * 6 ] sage: Q.cholesky_decomposition() [ 1.00000000000000 1.00000000000000 1.50000000000000] [0.000000000000000 3.00000000000000 0.333333333333333] [0.000000000000000 0.000000000000000 3.41666666666667]
-
clifford_conductor
()¶ This is the product of all primes where the Clifford invariant is -1
Note: For ternary forms, this is the discriminant of the quaternion algebra associated to the quadratic space (i.e. the even Clifford algebra)
EXAMPLES:
sage: Q = QuadraticForm(ZZ, 3, [1, 0, -1, 2, -1, 5]) sage: Q.clifford_invariant(2) 1 sage: Q.clifford_invariant(37) -1 sage: Q.clifford_conductor() 37
sage: DiagonalQuadraticForm(ZZ, [1, 1, 1]).clifford_conductor() 2 sage: QuadraticForm(ZZ, 3, [2, -2, 0, 2, 0, 5]).clifford_conductor() 30
For hyperbolic spaces, the clifford conductor is 1:
sage: H = QuadraticForm(ZZ, 2, [0, 1, 0]) sage: H.clifford_conductor() 1 sage: (H + H).clifford_conductor() 1 sage: (H + H + H).clifford_conductor() 1 sage: (H + H + H + H).clifford_conductor() 1
-
clifford_invariant
(p)¶ This is the Clifford invariant, i.e. the class in the Brauer group of the Clifford algebra for even dimension, of the even Clifford Algebra for odd dimension.
See Lam (AMS GSM 67) p. 117 for the definition, and p. 119 for the formula relating it to the Hasse invariant.
EXAMPLES:
For hyperbolic spaces, the clifford invariant is +1:
sage: H = QuadraticForm(ZZ, 2, [0, 1, 0]) sage: H.clifford_invariant(2) 1 sage: (H + H).clifford_invariant(2) 1 sage: (H + H + H).clifford_invariant(2) 1 sage: (H + H + H + H).clifford_invariant(2) 1
-
coefficients
()¶ Gives the matrix of upper triangular coefficients, by reading across the rows from the main diagonal.
EXAMPLES:
sage: Q = QuadraticForm(ZZ, 2, [1,2,3]) sage: Q.coefficients() [1, 2, 3]
-
complementary_subform_to_vector
(v)¶ Finds the \((n-1)\)-dim’l quadratic form orthogonal to the vector \(v\).
Note: This is usually not a direct summand!
Technical Notes: There is a minor difference in the cancellation code here (form the C++ version) since the notation Q \([i,j]\) indexes coefficients of the quadratic polynomial here, not the symmetric matrix. Also, it produces a better splitting now, for the full lattice (as opposed to a sublattice in the C++ code) since we now extend \(v\) to a unimodular matrix.
INPUT:
\(v\) – a list of self.dim() integersOUTPUT:
a QuadraticForm over \(ZZ\)EXAMPLES:
sage: Q1 = DiagonalQuadraticForm(ZZ, [1,3,5,7]) sage: Q1.complementary_subform_to_vector([1,0,0,0]) Quadratic form in 3 variables over Integer Ring with coefficients: [ 3 0 0 ] [ * 5 0 ] [ * * 7 ]
sage: Q1.complementary_subform_to_vector([1,1,0,0]) Quadratic form in 3 variables over Integer Ring with coefficients: [ 12 0 0 ] [ * 5 0 ] [ * * 7 ]
sage: Q1.complementary_subform_to_vector([1,1,1,1]) Quadratic form in 3 variables over Integer Ring with coefficients: [ 624 -480 -672 ] [ * 880 -1120 ] [ * * 1008 ]
-
compute_definiteness
()¶ Computes whether the given quadratic form is positive-definite, negative-definite, indefinite, degenerate, or the zero form.
This caches one of the following strings in self.__definiteness_string: “pos_def”, “neg_def”, “indef”, “zero”, “degenerate”. It is called from all routines like:
is_positive_definite(), is_negative_definite(), is_indefinite(), etc.Note: A degenerate form is considered neither definite nor indefinite. Note: The zero-dim’l form is considered both positive definite and negative definite.
INPUT:
QuadraticFormOUTPUT:
booleanEXAMPLES:
sage: Q = DiagonalQuadraticForm(ZZ, [1,1,1,1,1]) sage: Q.compute_definiteness() sage: Q.is_positive_definite() True sage: Q.is_negative_definite() False sage: Q.is_indefinite() False sage: Q.is_definite() True
sage: Q = DiagonalQuadraticForm(ZZ, []) sage: Q.compute_definiteness() sage: Q.is_positive_definite() True sage: Q.is_negative_definite() True sage: Q.is_indefinite() False sage: Q.is_definite() True
sage: Q = DiagonalQuadraticForm(ZZ, [1,0,-1]) sage: Q.compute_definiteness() sage: Q.is_positive_definite() False sage: Q.is_negative_definite() False sage: Q.is_indefinite() False sage: Q.is_definite() False
-
compute_definiteness_string_by_determinants
()¶ Compute the (positive) definiteness of a quadratic form by looking at the signs of all of its upper-left subdeterminants. See also self.compute_definiteness() for more documentation.
INPUT:
NoneOUTPUT:
string describing the definitenessEXAMPLES:
sage: Q = DiagonalQuadraticForm(ZZ, [1,1,1,1,1]) sage: Q.compute_definiteness_string_by_determinants() 'pos_def'
sage: Q = DiagonalQuadraticForm(ZZ, []) sage: Q.compute_definiteness_string_by_determinants() 'zero'
sage: Q = DiagonalQuadraticForm(ZZ, [1,0,-1]) sage: Q.compute_definiteness_string_by_determinants() 'degenerate'
sage: Q = DiagonalQuadraticForm(ZZ, [1,-1]) sage: Q.compute_definiteness_string_by_determinants() 'indefinite'
sage: Q = DiagonalQuadraticForm(ZZ, [-1,-1]) sage: Q.compute_definiteness_string_by_determinants() 'neg_def'
-
content
()¶ Return the GCD of the coefficients of the quadratic form.
Warning
Only works over Euclidean domains (probably just \(\ZZ\)).
EXAMPLES:
sage: Q = DiagonalQuadraticForm(ZZ, [1, 1]) sage: Q.matrix().gcd() 2 sage: Q.content() 1 sage: DiagonalQuadraticForm(ZZ, [1, 1]).is_primitive() True sage: DiagonalQuadraticForm(ZZ, [2, 4]).is_primitive() False sage: DiagonalQuadraticForm(ZZ, [2, 4]).primitive() Quadratic form in 2 variables over Integer Ring with coefficients: [ 1 0 ] [ * 2 ]
-
conway_cross_product_doubled_power
(p)¶ Computes twice the power of p which evaluates the ‘cross product’ term in Conway’s mass formula.
INPUT:
\(p\) – a prime number > 0OUTPUT:
a rational numberEXAMPLES:
sage: Q = DiagonalQuadraticForm(ZZ, range(1,8)) sage: Q.conway_cross_product_doubled_power(2) 18 sage: Q.conway_cross_product_doubled_power(3) 10 sage: Q.conway_cross_product_doubled_power(5) 6 sage: Q.conway_cross_product_doubled_power(7) 6 sage: Q.conway_cross_product_doubled_power(11) 0 sage: Q.conway_cross_product_doubled_power(13) 0
-
conway_diagonal_factor
(p)¶ Computes the diagonal factor of Conway’s \(p\)-mass.
INPUT:
\(p\) – a prime number > 0OUTPUT:
a rational number > 0EXAMPLES:
sage: Q = DiagonalQuadraticForm(ZZ, range(1,6)) sage: Q.conway_diagonal_factor(3) 81/256
-
conway_mass
()¶ Compute the mass by using the Conway-Sloane mass formula.
OUTPUT:
a rational number > 0
EXAMPLES:
sage: Q = DiagonalQuadraticForm(ZZ, [1,1,1]) sage: Q.conway_mass() 1/48 sage: Q = DiagonalQuadraticForm(ZZ, [7,1,1]) sage: Q.conway_mass() 3/16 sage: Q = QuadraticForm(ZZ, 3, [7, 2, 2, 2, 0, 2]) + DiagonalQuadraticForm(ZZ, [1]) sage: Q.conway_mass() 3/32 sage: Q = QuadraticForm(Matrix(ZZ,2,[2,1,1,2])) sage: Q.conway_mass() 1/12
-
conway_octane_of_this_unimodular_Jordan_block_at_2
()¶ Determines the ‘octane’ of this full unimodular Jordan block at the prime \(p=2\). This is an invariant defined \((mod 8)\), ad.
This assumes that the form is given as a block diagonal form with unimodular blocks of size <= 2 and the 1x1 blocks are all in the upper leftmost position.
INPUT:
noneOUTPUT:
an integer 0 <= x <= 7EXAMPLES:
sage: Q = DiagonalQuadraticForm(ZZ, [1,3,5,7]) sage: Q.conway_octane_of_this_unimodular_Jordan_block_at_2() 0 sage: Q = DiagonalQuadraticForm(ZZ, [1,5,13]) sage: Q.conway_octane_of_this_unimodular_Jordan_block_at_2() 3 sage: Q = DiagonalQuadraticForm(ZZ, [3,7,13]) sage: Q.conway_octane_of_this_unimodular_Jordan_block_at_2() 7
-
conway_p_mass
(p)¶ Computes Conway’s \(p\)-mass.
INPUT:
\(p\) – a prime number > 0OUTPUT:
a rational number > 0EXAMPLES:
sage: Q = DiagonalQuadraticForm(ZZ, range(1, 6)) sage: Q.conway_p_mass(2) 16/3 sage: Q.conway_p_mass(3) 729/256
-
conway_species_list_at_2
()¶ Returns an integer called the ‘species’ which determines the type of the orthogonal group over the finite field \(F_p\).
This assumes that the given quadratic form is a unimodular Jordan block at an odd prime \(p\). When the dimension is odd then this number is always positive, otherwise it may be positive or negative.
Note: The species of a zero dim’l form is always 0+, so we interpret the return value of zero as positive here! =)
OUTPUT:
a list of integersEXAMPLES:
sage: Q = DiagonalQuadraticForm(ZZ, range(1,10)) sage: Q.conway_species_list_at_2() [1, 5, 1, 1, 1, 1]
sage: Q = DiagonalQuadraticForm(ZZ, range(1,8)) sage: Q.conway_species_list_at_2() [1, 3, 1, 1, 1]
-
conway_species_list_at_odd_prime
(p)¶ Returns an integer called the ‘species’ which determines the type of the orthogonal group over the finite field \(F_p\).
This assumes that the given quadratic form is a unimodular Jordan block at an odd prime \(p\). When the dimension is odd then this number is always positive, otherwise it may be positive or negative (or zero, but that is considered positive by convention).
Note: The species of a zero dim’l form is always 0+, so we interpret the return value of zero as positive here! =)
INPUT:
a positive prime numberOUTPUT:
a list of integersEXAMPLES:
sage: Q = DiagonalQuadraticForm(ZZ, range(1,10)) sage: Q.conway_species_list_at_odd_prime(3) [6, 2, 1]
sage: Q = DiagonalQuadraticForm(ZZ, range(1,8)) sage: Q.conway_species_list_at_odd_prime(3) [5, 2] sage: Q.conway_species_list_at_odd_prime(5) [-6, 1]
-
conway_standard_mass
()¶ Returns the infinite product of the standard mass factors.
INPUT:
noneOUTPUT:
a rational number > 0EXAMPLES:
sage: Q = QuadraticForm(ZZ, 3, [2, -2, 0, 3, -5, 4]) sage: Q.conway_standard_mass() 1/6
sage: Q = DiagonalQuadraticForm(ZZ, [1,1,1]) sage: Q.conway_standard_mass() 1/6
-
conway_standard_p_mass
(p)¶ Computes the standard (generic) Conway-Sloane \(p\)-mass.
INPUT:
\(p\) – a prime number > 0OUTPUT:
a rational number > 0EXAMPLES:
sage: Q = DiagonalQuadraticForm(ZZ, [1,1,1]) sage: Q.conway_standard_p_mass(2) 2/3
-
conway_type_factor
()¶ This is a special factor only present in the mass formula when \(p=2\).
INPUT:
noneOUTPUT:
a rational numberEXAMPLES:
sage: Q = DiagonalQuadraticForm(ZZ, range(1,8)) sage: Q.conway_type_factor() 4
-
count_congruence_solutions
(p, k, m, zvec, nzvec)¶ Counts all solutions of Q(\(x\)) \(= m (mod p^k)\) satisfying the additional congruence conditions described in QuadraticForm.count_congruence_solutions_as_vector().
INPUT:
\(p\) – prime number > 0
\(k\) – an integer > 0
\(m\) – an integer (depending only on mod \(p^k\))
zvec, nzvec – a list of integers in range(self.dim()), or None
EXAMPLES:
sage: Q = DiagonalQuadraticForm(ZZ, [1,2,3]) sage: Q.count_congruence_solutions(3, 1, 0, None, None) 15
-
count_congruence_solutions__bad_type
(p, k, m, zvec, nzvec)¶ Counts the bad-type solutions of Q(\(x\)) \(= m (mod p^k)\) satisfying the additional congruence conditions described in QuadraticForm.count_congruence_solutions_as_vector().
INPUT:
\(p\) – prime number > 0
\(k\) – an integer > 0
\(m\) – an integer (depending only on mod \(p^k\))
zvec, nzvec – a list of integers up to dim(Q)
EXAMPLES:
sage: Q = DiagonalQuadraticForm(ZZ, [1,2,3]) sage: Q.count_congruence_solutions__bad_type(3, 1, 0, None, None) 2
-
count_congruence_solutions__bad_type_I
(p, k, m, zvec, nzvec)¶ Counts the bad-typeI solutions of Q(\(x\)) = \(m (mod p^k)\) satisfying the additional congruence conditions described in QuadraticForm.count_congruence_solutions_as_vector().
INPUT:
\(p\) – prime number > 0
\(k\) – an integer > 0
\(m\) – an integer (depending only on mod \(p^k\))
zvec, nzvec – a list of integers up to dim(Q)
EXAMPLES:
sage: Q = DiagonalQuadraticForm(ZZ, [1,2,3]) sage: Q.count_congruence_solutions__bad_type_I(3, 1, 0, None, None) 0
-
count_congruence_solutions__bad_type_II
(p, k, m, zvec, nzvec)¶ Counts the bad-typeII solutions of Q(\(x\)) \(= m (mod p^k)\) satisfying the additional congruence conditions described in QuadraticForm.count_congruence_solutions_as_vector().
INPUT:
\(p\) – prime number > 0
\(k\) – an integer > 0
\(m\) – an integer (depending only on mod \(p^k\))
zvec, nzvec – a list of integers up to dim(Q)
EXAMPLES:
sage: Q = DiagonalQuadraticForm(ZZ, [1,2,3]) sage: Q.count_congruence_solutions__bad_type_II(3, 1, 0, None, None) 2
-
count_congruence_solutions__good_type
(p, k, m, zvec, nzvec)¶ Counts the good-type solutions of Q(x) = m (mod p^k) satisfying the additional congruence conditions described in QuadraticForm.count_congruence_solutions_as_vector().
INPUT:
\(p\) – prime number > 0
\(k\) – an integer > 0
\(m\) – an integer (depending only on mod \(p^k\))
zvec, nzvec – a list of integers up to dim(Q)
EXAMPLES:
sage: Q = DiagonalQuadraticForm(ZZ, [1,2,3]) sage: Q.count_congruence_solutions__good_type(3, 1, 0, None, None) 12
-
count_congruence_solutions__zero_type
(p, k, m, zvec, nzvec)¶ Counts the zero-type solutions of Q(\(x\)) = \(m (mod p^k)\) satisfying the additional congruence conditions described in QuadraticForm.count_congruence_solutions_as_vector().
INPUT:
\(p\) – prime number > 0
\(k\) – an integer > 0
\(m\) – an integer (depending only on mod \(p^k\))
zvec, nzvec – a list of integers up to dim(Q)
EXAMPLES:
sage: Q = DiagonalQuadraticForm(ZZ, [1,2,3]) sage: Q.count_congruence_solutions__zero_type(3, 1, 0, None, None) 1
-
count_congruence_solutions_as_vector
(p, k, m, zvec, nzvec)¶ Gives the number of integer solution vectors \(x\) satisfying the congruence Q(\(x\)) \(= m (mod p^k)\) of each solution type (i.e. All, Good, Zero, Bad, BadI, BadII) which satisfy the additional congruence conditions of having certain coefficients = 0 (mod \(p\)) and certain collections of coefficients not congruent to the zero vector (mod \(p\)).
A solution vector \(x\) satisfies the additional congruence conditions specified by zvec and nzvec (and therefore is counted) iff both of the following conditions hold:
- \(x[i] == 0 (mod p)\) for all \(i\) in zvec
- \(x[i] != 0 (mod p) for all i\) in nzvec
REFERENCES:
See Hanke’s (????) paper “Local Densities and explicit bounds…”, p??? for the definitions of the solution types and congruence conditions.
INPUT:
- \(p\) – prime number > 0
- \(k\) – an integer > 0
- \(m\) – an integer (depending only on mod \(p^k\))
- zvec, nzvec – a list of integers in range(self.dim()), or None
OUTPUT:
a list of six integers >= 0 representing the solution types: [All, Good, Zero, Bad, BadI, BadII]
EXAMPLES:
sage: Q = DiagonalQuadraticForm(ZZ, [1,2,3]) sage: Q.count_congruence_solutions_as_vector(3, 1, 1, [], []) [0, 0, 0, 0, 0, 0] sage: Q.count_congruence_solutions_as_vector(3, 1, 1, None, []) [0, 0, 0, 0, 0, 0] sage: Q.count_congruence_solutions_as_vector(3, 1, 1, [], None) [6, 6, 0, 0, 0, 0] sage: Q.count_congruence_solutions_as_vector(3, 1, 1, None, None) [6, 6, 0, 0, 0, 0] sage: Q.count_congruence_solutions_as_vector(3, 1, 2, None, None) [6, 6, 0, 0, 0, 0] sage: Q.count_congruence_solutions_as_vector(3, 1, 0, None, None) [15, 12, 1, 2, 0, 2]
-
count_modp_solutions__by_Gauss_sum
(p, m)¶ Returns the number of solutions of \(Q(x) = m (mod p)\) of a non-degenerate quadratic form over the finite field \(Z/pZ\), where \(p\) is a prime number > 2.
Note: We adopt the useful convention that a zero-dimensional quadratic form has exactly one solution always (i.e. the empty vector).
These are defined in Table 1 on p363 of Hanke’s “Local Densities…” paper.
INPUT:
\(p\) – a prime number > 2
\(m\) – an integer
OUTPUT:
an integer >= 0EXAMPLES:
sage: Q = DiagonalQuadraticForm(ZZ, [1,1,1]) sage: [Q.count_modp_solutions__by_Gauss_sum(3, m) for m in range(3)] [9, 6, 12]
sage: Q = DiagonalQuadraticForm(ZZ, [1,1,2]) sage: [Q.count_modp_solutions__by_Gauss_sum(3, m) for m in range(3)] [9, 12, 6]
-
delta
()¶ This is the omega of the adjoint form, which is the same as the omega of the reciprocal form.
EXAMPLES:
sage: Q = DiagonalQuadraticForm(ZZ, [1,1,37]) sage: Q.delta() 148
-
det
()¶ Gives the determinant of the Gram matrix of 2*Q, or equivalently the determinant of the Hessian matrix of Q.
(Note: This is always defined over the same ring as the quadratic form.)
EXAMPLES:
sage: Q = QuadraticForm(ZZ, 2, [1,2,3]) sage: Q.det() 8
-
dim
()¶ Gives the number of variables of the quadratic form.
EXAMPLES:
sage: Q = QuadraticForm(ZZ, 2, [1,2,3]) sage: Q.dim() 2 sage: parent(Q.dim()) Integer Ring sage: Q = QuadraticForm(Q.matrix()) sage: Q.dim() 2 sage: parent(Q.dim()) Integer Ring
-
disc
()¶ Return the discriminant of the quadratic form, defined as
- \((-1)^n {\rm det}(B)\) for even dimension \(2n\)
- \({\rm det}(B)/2\) for odd dimension
where \(2Q(x) = x^t B x\).
This agrees with the usual discriminant for binary and ternary quadratic forms.
EXAMPLES:
sage: DiagonalQuadraticForm(ZZ, [1]).disc() 1 sage: DiagonalQuadraticForm(ZZ, [1,1]).disc() -4 sage: DiagonalQuadraticForm(ZZ, [1,1,1]).disc() 4 sage: DiagonalQuadraticForm(ZZ, [1,1,1,1]).disc() 16
-
discrec
()¶ Return the discriminant of the reciprocal form.
EXAMPLES:
sage: Q = DiagonalQuadraticForm(ZZ, [1,1,37]) sage: Q.disc() 148 sage: Q.discrec() 5476 sage: [4 * 37, 4 * 37^2] [148, 5476]
-
divide_variable
(c, i, in_place=False)¶ Replace the variables \(x_i\) by \((x_i)/c\) in the quadratic form (replacing the original form if the in_place flag is True).
Here \(c\) must be an element of the base_ring defining the quadratic form, and the division must be defined in the base ring.
INPUT:
\(c\) – an element of Q.base_ring()
\(i\) – an integer >= 0
OUTPUT:
a QuadraticForm (by default, otherwise none)EXAMPLES:
sage: Q = DiagonalQuadraticForm(ZZ, [1,9,5,7]) sage: Q.divide_variable(3,1) Quadratic form in 4 variables over Integer Ring with coefficients: [ 1 0 0 0 ] [ * 1 0 0 ] [ * * 5 0 ] [ * * * 7 ]
-
elementary_substitution
(c, i, j, in_place=False)¶ Perform the substitution \(x_i --> x_i + c*x_j\) (replacing the original form if the in_place flag is True).
INPUT:
\(c\) – an element of Q.base_ring()
\(i\), \(j\) – integers >= 0
OUTPUT:
a QuadraticForm (by default, otherwise none)EXAMPLES:
sage: Q = QuadraticForm(ZZ, 4, range(1,11)) sage: Q Quadratic form in 4 variables over Integer Ring with coefficients: [ 1 2 3 4 ] [ * 5 6 7 ] [ * * 8 9 ] [ * * * 10 ] sage: Q.elementary_substitution(c=1, i=0, j=3) Quadratic form in 4 variables over Integer Ring with coefficients: [ 1 2 3 6 ] [ * 5 6 9 ] [ * * 8 12 ] [ * * * 15 ]
sage: R = QuadraticForm(ZZ, 4, range(1,11)) sage: R Quadratic form in 4 variables over Integer Ring with coefficients: [ 1 2 3 4 ] [ * 5 6 7 ] [ * * 8 9 ] [ * * * 10 ]
sage: M = Matrix(ZZ, 4, 4, [1,0,0,1,0,1,0,0,0,0,1,0,0,0,0,1]) sage: M [1 0 0 1] [0 1 0 0] [0 0 1 0] [0 0 0 1] sage: R(M) Quadratic form in 4 variables over Integer Ring with coefficients: [ 1 2 3 6 ] [ * 5 6 9 ] [ * * 8 12 ] [ * * * 15 ]
-
extract_variables
(var_indices)¶ Extract the variables (in order) whose indices are listed in var_indices, to give a new quadratic form.
INPUT:
var_indices – a list of integers >= 0OUTPUT:
a QuadraticFormEXAMPLES:
sage: Q = QuadraticForm(ZZ, 4, range(10)); Q Quadratic form in 4 variables over Integer Ring with coefficients: [ 0 1 2 3 ] [ * 4 5 6 ] [ * * 7 8 ] [ * * * 9 ] sage: Q.extract_variables([1,3]) Quadratic form in 2 variables over Integer Ring with coefficients: [ 4 6 ] [ * 9 ]
-
find_entry_with_minimal_scale_at_prime
(p)¶ Finds the entry of the quadratic form with minimal scale at the prime p, preferring diagonal entries in case of a tie. (I.e. If we write the quadratic form as a symmetric matrix M, then this entry M[i,j] has the minimal valuation at the prime p.)
Note: This answer is independent of the kind of matrix (Gram or Hessian) associated to the form.
INPUT:
\(p\) – a prime number > 0OUTPUT:
a pair of integers >= 0EXAMPLES:
sage: Q = QuadraticForm(ZZ, 2, [6, 2, 20]); Q Quadratic form in 2 variables over Integer Ring with coefficients: [ 6 2 ] [ * 20 ] sage: Q.find_entry_with_minimal_scale_at_prime(2) (0, 1) sage: Q.find_entry_with_minimal_scale_at_prime(3) (1, 1) sage: Q.find_entry_with_minimal_scale_at_prime(5) (0, 0)
-
find_p_neighbor_from_vec
(p, v)¶ Find the \(p\)-neighbor of this quadratic form associated to a given vector \(v\) satisfying:
- \(Q(v) = 0 \pmod p\)
- \(v\) is a non-singular point of the conic \(Q(v) = 0 \pmod p\).
Reference: Gonzalo Tornaria’s Thesis, Theorem 3.5, p34.
EXAMPLES:
sage: Q = DiagonalQuadraticForm(ZZ,[1,1,1,1]) sage: v = vector([0,2,1,1]) sage: X = Q.find_p_neighbor_from_vec(3,v); X Quadratic form in 4 variables over Integer Ring with coefficients: [ 3 10 0 -4 ] [ * 9 0 -6 ] [ * * 1 0 ] [ * * * 2 ]
-
find_primitive_p_divisible_vector__next
(p, v=None)¶ Find the next \(p\)-primitive vector (up to scaling) in \(L/pL\) whose value is \(p\)-divisible, where the last vector returned was \(v\). For an initial call, no \(v\) needs to be passed.
Returns vectors whose last non-zero entry is normalized to 0 or 1 (so no lines are counted repeatedly). The ordering is by increasing the first non-normalized entry. If we have tested all (lines of) vectors, then return None.
OUTPUT:
vector or None
EXAMPLES:
sage: Q = QuadraticForm(ZZ, 2, [10,1,4]) sage: v = Q.find_primitive_p_divisible_vector__next(5); v (1, 1) sage: v = Q.find_primitive_p_divisible_vector__next(5, v); v (1, 0) sage: v = Q.find_primitive_p_divisible_vector__next(5, v); v
-
find_primitive_p_divisible_vector__random
(p)¶ Find a random \(p\)-primitive vector in \(L/pL\) whose value is \(p\)-divisible.
Note
Since there are about \(p^{(n-2)}\) of these lines, we have a \(1/p\) chance of randomly finding an appropriate vector.
Warning
If there are local obstructions for this to happen, then this algorithm will never terminate… =( We should check for this too!
EXAMPLES:
sage: Q = QuadraticForm(ZZ, 2, [10,1,4]) sage: Q.find_primitive_p_divisible_vector__random(5) # random (1, 1) sage: Q.find_primitive_p_divisible_vector__random(5) # random (1, 0) sage: Q.find_primitive_p_divisible_vector__random(5) # random (2, 0) sage: Q.find_primitive_p_divisible_vector__random(5) # random (2, 2) sage: Q.find_primitive_p_divisible_vector__random(5) # random (3, 3) sage: Q.find_primitive_p_divisible_vector__random(5) # random (3, 3) sage: Q.find_primitive_p_divisible_vector__random(5) # random (2, 0)
-
gcd
()¶ Returns the greatest common divisor of the coefficients of the quadratic form (as a polynomial).
EXAMPLES:
sage: Q = QuadraticForm(ZZ, 4, range(1, 21, 2)) sage: Q.gcd() 1
sage: Q = QuadraticForm(ZZ, 4, range(0, 20, 2)) sage: Q.gcd() 2
-
static
genera
(sig_pair, determinant, max_scale=None, even=False)¶ Return a list of all global genera with the given conditions.
Here a genus is called global if it is non-empty.
INPUT:
sig_pair
– a pair of non-negative integers giving the signaturedeterminant
– an integer; the sign is ignoredmax_scale
– (default:None
) an integer; the maximum scale of a jordan blockeven
– boolean (default:False
)
OUTPUT:
A list of all (non-empty) global genera with the given conditions.
EXAMPLES:
sage: QuadraticForm.genera((4,0), 125, even=True) [Genus of None Signature: (4, 0) Genus symbol at 2: 1^-4 Genus symbol at 5: 1^1 5^3, Genus of None Signature: (4, 0) Genus symbol at 2: 1^-4 Genus symbol at 5: 1^-2 5^1 25^-1, Genus of None Signature: (4, 0) Genus symbol at 2: 1^-4 Genus symbol at 5: 1^2 5^1 25^1, Genus of None Signature: (4, 0) Genus symbol at 2: 1^-4 Genus symbol at 5: 1^3 125^1]
-
global_genus_symbol
()¶ Returns the genus of a two times a quadratic form over ZZ. These are defined by a collection of local genus symbols (a la Chapter 15 of Conway-Sloane), and a signature.
EXAMPLES:
sage: Q = DiagonalQuadraticForm(ZZ, [1,2,3,4]) sage: Q.global_genus_symbol() Genus of [2 0 0 0] [0 4 0 0] [0 0 6 0] [0 0 0 8] Signature: (4, 0) Genus symbol at 2: [2^-2 4^1 8^1]_6 Genus symbol at 3: 1^3 3^-1
sage: Q = QuadraticForm(ZZ, 4, range(10)) sage: Q.global_genus_symbol() Genus of [ 0 1 2 3] [ 1 8 5 6] [ 2 5 14 8] [ 3 6 8 18] Signature: (3, 1) Genus symbol at 2: 1^-4 Genus symbol at 563: 1^3 563^-1
-
has_equivalent_Jordan_decomposition_at_prime
(other, p)¶ Determines if the given quadratic form has a Jordan decomposition equivalent to that of self.
INPUT:
a QuadraticForm
OUTPUT:
boolean
EXAMPLES:
sage: Q1 = QuadraticForm(ZZ, 3, [1, 0, -1, 1, 0, 3]) sage: Q2 = QuadraticForm(ZZ, 3, [1, 0, 0, 2, -2, 6]) sage: Q3 = QuadraticForm(ZZ, 3, [1, 0, 0, 1, 0, 11]) sage: [Q1.level(), Q2.level(), Q3.level()] [44, 44, 44] sage: Q1.has_equivalent_Jordan_decomposition_at_prime(Q2,2) False sage: Q1.has_equivalent_Jordan_decomposition_at_prime(Q2,11) False sage: Q1.has_equivalent_Jordan_decomposition_at_prime(Q3,2) False sage: Q1.has_equivalent_Jordan_decomposition_at_prime(Q3,11) True sage: Q2.has_equivalent_Jordan_decomposition_at_prime(Q3,2) True sage: Q2.has_equivalent_Jordan_decomposition_at_prime(Q3,11) False
-
has_integral_Gram_matrix
()¶ Returns whether the quadratic form has an integral Gram matrix (with respect to its base ring).
A warning is issued if the form is defined over a field, since in that case the return is trivially true.
EXAMPLES:
sage: Q = QuadraticForm(ZZ, 2, [7,8,9]) sage: Q.has_integral_Gram_matrix() True
sage: Q = QuadraticForm(ZZ, 2, [4,5,6]) sage: Q.has_integral_Gram_matrix() False
-
hasse_conductor
()¶ This is the product of all primes where the Hasse invariant equals -1
EXAMPLES:
sage: Q = QuadraticForm(ZZ, 3, [1, 0, -1, 2, -1, 5]) sage: Q.hasse_invariant(2) -1 sage: Q.hasse_invariant(37) -1 sage: Q.hasse_conductor() 74
sage: DiagonalQuadraticForm(ZZ, [1, 1, 1]).hasse_conductor() 1 sage: QuadraticForm(ZZ, 3, [2, -2, 0, 2, 0, 5]).hasse_conductor() 10
-
hasse_invariant
(p)¶ Computes the Hasse invariant at a prime \(p\) or at infinity, as given on p55 of Cassels’s book. If Q is diagonal with coefficients \(a_i\), then the (Cassels) Hasse invariant is given by
\[c_p = \prod_{i < j} (a_i, a_j)_p\]where \((a,b)_p\) is the Hilbert symbol at \(p\). The underlying quadratic form must be non-degenerate over \(Q_p\) for this to make sense.
Warning
This is different from the O’Meara Hasse invariant, which allows \(i <= j\) in the product. That is given by the method hasse_invariant__OMeara(p).
Note
We should really rename this hasse_invariant__Cassels(), and set hasse_invariant() as a front-end to it.
INPUT:
- \(p\) – a prime number > 0 or \(-1\) for the infinite place
OUTPUT:
1 or -1
EXAMPLES:
sage: Q = QuadraticForm(ZZ, 2, [1,2,3]) sage: Q.rational_diagonal_form() Quadratic form in 2 variables over Rational Field with coefficients: [ 1 0 ] [ * 2 ] sage: [Q.hasse_invariant(p) for p in prime_range(20)] [1, 1, 1, 1, 1, 1, 1, 1] sage: [Q.hasse_invariant__OMeara(p) for p in prime_range(20)] [1, 1, 1, 1, 1, 1, 1, 1]
sage: Q = DiagonalQuadraticForm(ZZ, [1,-1]) sage: [Q.hasse_invariant(p) for p in prime_range(20)] [1, 1, 1, 1, 1, 1, 1, 1] sage: [Q.hasse_invariant__OMeara(p) for p in prime_range(20)] [-1, 1, 1, 1, 1, 1, 1, 1]
sage: Q = DiagonalQuadraticForm(ZZ, [1,-1,5]) sage: [Q.hasse_invariant(p) for p in prime_range(20)] [1, 1, 1, 1, 1, 1, 1, 1] sage: [Q.hasse_invariant__OMeara(p) for p in prime_range(20)] [-1, 1, 1, 1, 1, 1, 1, 1]
sage: K.<a>=NumberField(x^2-23) sage: Q=DiagonalQuadraticForm(K,[-a,a+2]) sage: [Q.hasse_invariant(p) for p in K.primes_above(19)] [-1, 1]
-
hasse_invariant__OMeara
(p)¶ Compute the O’Meara Hasse invariant at a prime \(p\).
This is defined on p167 of O’Meara’s book. If Q is diagonal with coefficients \(a_i\), then the (Cassels) Hasse invariant is given by
\[c_p = \prod_{i <= j} (a_i, a_j)_p\]where \((a,b)_p\) is the Hilbert symbol at \(p\).
Warning
This is different from the (Cassels) Hasse invariant, which only allows \(i < j\) in the product. That is given by the method hasse_invariant(p).
INPUT:
- \(p\) – a prime number > 0 or \(-1\) for the infinite place
OUTPUT:
1 or -1
EXAMPLES:
sage: Q = QuadraticForm(ZZ, 2, [1,2,3]) sage: Q.rational_diagonal_form() Quadratic form in 2 variables over Rational Field with coefficients: [ 1 0 ] [ * 2 ] sage: [Q.hasse_invariant(p) for p in prime_range(20)] [1, 1, 1, 1, 1, 1, 1, 1] sage: [Q.hasse_invariant__OMeara(p) for p in prime_range(20)] [1, 1, 1, 1, 1, 1, 1, 1]
sage: Q = DiagonalQuadraticForm(ZZ, [1,-1]) sage: [Q.hasse_invariant(p) for p in prime_range(20)] [1, 1, 1, 1, 1, 1, 1, 1] sage: [Q.hasse_invariant__OMeara(p) for p in prime_range(20)] [-1, 1, 1, 1, 1, 1, 1, 1]
sage: Q = DiagonalQuadraticForm(ZZ,[1,-1,-1]) sage: [Q.hasse_invariant(p) for p in prime_range(20)] [-1, 1, 1, 1, 1, 1, 1, 1] sage: [Q.hasse_invariant__OMeara(p) for p in prime_range(20)] [-1, 1, 1, 1, 1, 1, 1, 1]
sage: K.<a>=NumberField(x^2-23) sage: Q = DiagonalQuadraticForm(K,[-a,a+2]) sage: [Q.hasse_invariant__OMeara(p) for p in K.primes_above(19)] [1, 1]
-
is_adjoint
()¶ Determines if the given form is the adjoint of another form
EXAMPLES:
sage: Q = QuadraticForm(ZZ, 3, [1, 0, -1, 2, -1, 5]) sage: Q.is_adjoint() False sage: Q.adjoint().is_adjoint() True
-
is_anisotropic
(p)¶ Check if the quadratic form is anisotropic over the p-adic numbers \(\QQ_p\) or \(\RR\).
INPUT:
- \(p\) – a prime number > 0 or \(-1\) for the infinite place
OUTPUT:
boolean
EXAMPLES:
sage: Q = DiagonalQuadraticForm(ZZ, [1,1]) sage: Q.is_anisotropic(2) True sage: Q.is_anisotropic(3) True sage: Q.is_anisotropic(5) False
sage: Q = DiagonalQuadraticForm(ZZ, [1,-1]) sage: Q.is_anisotropic(2) False sage: Q.is_anisotropic(3) False sage: Q.is_anisotropic(5) False
sage: [DiagonalQuadraticForm(ZZ, [1, -least_quadratic_nonresidue(p)]).is_anisotropic(p) for p in prime_range(3, 30)] [True, True, True, True, True, True, True, True, True]
sage: [DiagonalQuadraticForm(ZZ, [1, -least_quadratic_nonresidue(p), p, -p*least_quadratic_nonresidue(p)]).is_anisotropic(p) for p in prime_range(3, 30)] [True, True, True, True, True, True, True, True, True]
-
is_definite
()¶ Determines if the given quadratic form is (positive or negative) definite.
Note: A degenerate form is considered neither definite nor indefinite. Note: The zero-dim’l form is considered indefinite.
INPUT:
NoneOUTPUT:
boolean – True or FalseEXAMPLES:
sage: Q = DiagonalQuadraticForm(ZZ, [-1,-3,-5]) sage: Q.is_definite() True
sage: Q = DiagonalQuadraticForm(ZZ, [1,-3,5]) sage: Q.is_definite() False
-
is_even
(allow_rescaling_flag=True)¶ Returns true iff after rescaling by some appropriate factor, the form represents no odd integers. For more details, see parity().
Requires that Q is defined over \(ZZ\).
EXAMPLES:
sage: Q = QuadraticForm(ZZ, 2, [1, 0, 1]) sage: Q.is_even() False sage: Q = QuadraticForm(ZZ, 2, [1, 1, 1]) sage: Q.is_even() True
-
is_globally_equivalent_to
(other, return_matrix=False, check_theta_to_precision=None, check_local_equivalence=None)¶ Determines if the current quadratic form is equivalent to the given form over ZZ. If
return_matrix
is True, then we return the transformation matrix \(M\) so thatself(M) == other
.INPUT:
self
,other
– positive definite integral quadratic formsreturn_matrix
– (boolean, defaultFalse
) return the transformation matrix instead of a boolean
OUTPUT:
- if
return_matrix
isFalse
: a boolean - if
return_matrix
isTrue
: eitherFalse
or the transformation matrix
EXAMPLES:
sage: Q = DiagonalQuadraticForm(ZZ, [1,1,1,1]) sage: M = Matrix(ZZ, 4, 4, [1,2,0,0, 0,1,0,0, 0,0,1,0, 0,0,0,1]) sage: Q1 = Q(M) sage: Q.is_globally_equivalent_to(Q1) True sage: MM = Q.is_globally_equivalent_to(Q1, return_matrix=True) sage: Q(MM) == Q1 True
sage: Q1 = QuadraticForm(ZZ, 3, [1, 0, -1, 2, -1, 5]) sage: Q2 = QuadraticForm(ZZ, 3, [2, 1, 2, 2, 1, 3]) sage: Q3 = QuadraticForm(ZZ, 3, [8, 6, 5, 3, 4, 2]) sage: Q1.is_globally_equivalent_to(Q2) False sage: Q1.is_globally_equivalent_to(Q2, return_matrix=True) False sage: Q1.is_globally_equivalent_to(Q3) True sage: M = Q1.is_globally_equivalent_to(Q3, True); M [-1 -1 0] [ 1 1 1] [-1 0 0] sage: Q1(M) == Q3 True
sage: Q = DiagonalQuadraticForm(ZZ, [1, -1]) sage: Q.is_globally_equivalent_to(Q) Traceback (most recent call last): ... ValueError: not a definite form in QuadraticForm.is_globally_equivalent_to()
ALGORITHM: this uses the PARI function
qfisom()
, implementing an algorithm by Plesken and Souvignier.
-
is_hyperbolic
(p)¶ Check if the quadratic form is a sum of hyperbolic planes over the \(p\)-adic numbers \(\QQ_p\) or over the real numbers \(\RR\).
REFERENCES:
This criteria follows from Cassels’s “Rational Quadratic Forms”:
- local invariants for hyperbolic plane (Lemma 2.4, p58)
- direct sum formulas (Lemma 2.3, p58)
INPUT:
- \(p\) – a prime number > 0 or \(-1\) for the infinite place
OUTPUT:
boolean
EXAMPLES:
sage: Q = DiagonalQuadraticForm(ZZ, [1,1]) sage: Q.is_hyperbolic(-1) False sage: Q.is_hyperbolic(2) False sage: Q.is_hyperbolic(3) False sage: Q.is_hyperbolic(5) ## Here -1 is a square, so it's true. True sage: Q.is_hyperbolic(7) False sage: Q.is_hyperbolic(13) ## Here -1 is a square, so it's true. True
-
is_indefinite
()¶ Determines if the given quadratic form is indefinite.
Note: A degenerate form is considered neither definite nor indefinite. Note: The zero-dim’l form is not considered indefinite.
INPUT:
NoneOUTPUT:
boolean – True or FalseEXAMPLES:
sage: Q = DiagonalQuadraticForm(ZZ, [-1,-3,-5]) sage: Q.is_indefinite() False
sage: Q = DiagonalQuadraticForm(ZZ, [1,-3,5]) sage: Q.is_indefinite() True
-
is_isotropic
(p)¶ Checks if Q is isotropic over the p-adic numbers \(Q_p\) or \(RR\).
INPUT:
- \(p\) – a prime number > 0 or \(-1\) for the infinite place
OUTPUT:
boolean
EXAMPLES:
sage: Q = DiagonalQuadraticForm(ZZ, [1,1]) sage: Q.is_isotropic(2) False sage: Q.is_isotropic(3) False sage: Q.is_isotropic(5) True
sage: Q = DiagonalQuadraticForm(ZZ, [1,-1]) sage: Q.is_isotropic(2) True sage: Q.is_isotropic(3) True sage: Q.is_isotropic(5) True
sage: [DiagonalQuadraticForm(ZZ, [1, -least_quadratic_nonresidue(p)]).is_isotropic(p) for p in prime_range(3, 30)] [False, False, False, False, False, False, False, False, False]
sage: [DiagonalQuadraticForm(ZZ, [1, -least_quadratic_nonresidue(p), p, -p*least_quadratic_nonresidue(p)]).is_isotropic(p) for p in prime_range(3, 30)] [False, False, False, False, False, False, False, False, False]
-
is_locally_equivalent_to
(other, check_primes_only=False, force_jordan_equivalence_test=False)¶ Determines if the current quadratic form (defined over ZZ) is locally equivalent to the given form over the real numbers and the \(p\)-adic integers for every prime p.
This works by comparing the local Jordan decompositions at every prime, and the dimension and signature at the real place.
INPUT:
a QuadraticForm
OUTPUT:
boolean
EXAMPLES:
sage: Q1 = QuadraticForm(ZZ, 3, [1, 0, -1, 2, -1, 5]) sage: Q2 = QuadraticForm(ZZ, 3, [2, 1, 2, 2, 1, 3]) sage: Q1.is_globally_equivalent_to(Q2) False sage: Q1.is_locally_equivalent_to(Q2) True
-
is_locally_represented_number
(m)¶ Determines if the rational number m is locally represented by the quadratic form.
INPUT:
\(m\) – an integerOUTPUT:
booleanEXAMPLES:
sage: Q = DiagonalQuadraticForm(ZZ, [1,1,1]) sage: Q.is_locally_represented_number(2) True sage: Q.is_locally_represented_number(7) False sage: Q.is_locally_represented_number(-1) False sage: Q.is_locally_represented_number(28) False sage: Q.is_locally_represented_number(0) True
-
is_locally_represented_number_at_place
(m, p)¶ Determines if the rational number m is locally represented by the quadratic form at the (possibly infinite) prime \(p\).
INPUT:
\(m\) – an integer
\(p\) – a prime number > 0 or ‘infinity’
OUTPUT:
booleanEXAMPLES:
sage: Q = DiagonalQuadraticForm(ZZ, [1,1,1]) sage: Q.is_locally_represented_number_at_place(7, infinity) True sage: Q.is_locally_represented_number_at_place(7, 2) False sage: Q.is_locally_represented_number_at_place(7, 3) True sage: Q.is_locally_represented_number_at_place(7, 5) True sage: Q.is_locally_represented_number_at_place(-1, infinity) False sage: Q.is_locally_represented_number_at_place(-1, 2) False
sage: Q = DiagonalQuadraticForm(ZZ, [1,1,1,1,-1]) sage: Q.is_locally_represented_number_at_place(7, infinity) # long time (8.5 s) True sage: Q.is_locally_represented_number_at_place(7, 2) # long time True sage: Q.is_locally_represented_number_at_place(7, 3) # long time True sage: Q.is_locally_represented_number_at_place(7, 5) # long time True
-
is_locally_universal_at_all_places
()¶ Determines if the quadratic form represents \(Z_p\) for all finite/non-archimedean primes, and represents all real numbers.
INPUT:
noneOUTPUT:
booleanEXAMPLES:
sage: Q = DiagonalQuadraticForm(ZZ, [1,3,5,7]) sage: Q.is_locally_universal_at_all_places() False
sage: Q = DiagonalQuadraticForm(ZZ, [1,1,1,1]) sage: Q.is_locally_universal_at_all_places() False
sage: Q = DiagonalQuadraticForm(ZZ, [1,1,1,1,-1]) sage: Q.is_locally_universal_at_all_places() # long time (8.5 s) True
-
is_locally_universal_at_all_primes
()¶ Determines if the quadratic form represents \(Z_p\) for all finite/non-archimedean primes.
INPUT:
noneOUTPUT:
booleanEXAMPLES:
sage: Q = DiagonalQuadraticForm(ZZ, [1,3,5,7]) sage: Q.is_locally_universal_at_all_primes() True
sage: Q = DiagonalQuadraticForm(ZZ, [1,1,1,1]) sage: Q.is_locally_universal_at_all_primes() True
sage: Q = DiagonalQuadraticForm(ZZ, [1,1,1]) sage: Q.is_locally_universal_at_all_primes() False
-
is_locally_universal_at_prime
(p)¶ Determines if the (integer-valued/rational) quadratic form represents all of \(Z_p\).
INPUT:
\(p\) – a positive prime number or “infinity”.OUTPUT:
booleanEXAMPLES:
sage: Q = DiagonalQuadraticForm(ZZ, [1,3,5,7]) sage: Q.is_locally_universal_at_prime(2) True sage: Q.is_locally_universal_at_prime(3) True sage: Q.is_locally_universal_at_prime(5) True sage: Q.is_locally_universal_at_prime(infinity) False
sage: Q = DiagonalQuadraticForm(ZZ, [1,1,1]) sage: Q.is_locally_universal_at_prime(2) False sage: Q.is_locally_universal_at_prime(3) True sage: Q.is_locally_universal_at_prime(5) True sage: Q.is_locally_universal_at_prime(infinity) False
sage: Q = DiagonalQuadraticForm(ZZ, [1,1,-1]) sage: Q.is_locally_universal_at_prime(infinity) True
-
is_negative_definite
()¶ Determines if the given quadratic form is negative-definite.
Note: A degenerate form is considered neither definite nor indefinite. Note: The zero-dim’l form is considered both positive definite and negative definite.
INPUT:
NoneOUTPUT:
boolean – True or FalseEXAMPLES:
sage: Q = DiagonalQuadraticForm(ZZ, [-1,-3,-5]) sage: Q.is_negative_definite() True
sage: Q = DiagonalQuadraticForm(ZZ, [1,-3,5]) sage: Q.is_negative_definite() False
-
is_odd
(allow_rescaling_flag=True)¶ Returns true iff after rescaling by some appropriate factor, the form represents some odd integers. For more details, see parity().
Requires that Q is defined over \(ZZ\).
EXAMPLES:
sage: Q = QuadraticForm(ZZ, 2, [1, 0, 1]) sage: Q.is_odd() True sage: Q = QuadraticForm(ZZ, 2, [1, 1, 1]) sage: Q.is_odd() False
-
is_positive_definite
()¶ Determines if the given quadratic form is positive-definite.
Note: A degenerate form is considered neither definite nor indefinite. Note: The zero-dim’l form is considered both positive definite and negative definite.
INPUT:
NoneOUTPUT:
boolean – True or FalseEXAMPLES:
sage: Q = DiagonalQuadraticForm(ZZ, [1,3,5]) sage: Q.is_positive_definite() True
sage: Q = DiagonalQuadraticForm(ZZ, [1,-3,5]) sage: Q.is_positive_definite() False
-
is_primitive
()¶ Determines if the given integer-valued form is primitive (i.e. not an integer (>1) multiple of another integer-valued quadratic form).
EXAMPLES:
sage: Q = QuadraticForm(ZZ, 2, [2,3,4]) sage: Q.is_primitive() True sage: Q = QuadraticForm(ZZ, 2, [2,4,8]) sage: Q.is_primitive() False
-
is_rationally_isometric
(other)¶ Determines if two regular quadratic forms over a number field are isometric.
INPUT:
a quadratic form
OUTPUT:
boolean
EXAMPLES:
sage: V=DiagonalQuadraticForm(QQ,[1,1,2]) sage: W=DiagonalQuadraticForm(QQ,[2,2,2]) sage: V.is_rationally_isometric(W) True
sage: K.<a>=NumberField(x^2-3) sage: V=QuadraticForm(K,4,[1,0,0,0,2*a,0,0,a,0,2]);V Quadratic form in 4 variables over Number Field in a with defining polynomial x^2 - 3 with coefficients: [ 1 0 0 0 ] [ * 2*a 0 0 ] [ * * a 0 ] [ * * * 2 ] sage: W=QuadraticForm(K,4,[1,2*a,4,6,3,10,2,1,2,5]);W Quadratic form in 4 variables over Number Field in a with defining polynomial x^2 - 3 with coefficients: [ 1 2*a 4 6 ] [ * 3 10 2 ] [ * * 1 2 ] [ * * * 5 ] sage: V.is_rationally_isometric(W) False
sage: K.<a>=NumberField(x^4+2*x+6) sage: V=DiagonalQuadraticForm(K,[a,2,3,2,1]);V Quadratic form in 5 variables over Number Field in a with defining polynomial x^4 + 2*x + 6 with coefficients: [ a 0 0 0 0 ] [ * 2 0 0 0 ] [ * * 3 0 0 ] [ * * * 2 0 ] [ * * * * 1 ] sage: W=DiagonalQuadraticForm(K,[a,a,a,2,1]);W Quadratic form in 5 variables over Number Field in a with defining polynomial x^4 + 2*x + 6 with coefficients: [ a 0 0 0 0 ] [ * a 0 0 0 ] [ * * a 0 0 ] [ * * * 2 0 ] [ * * * * 1 ] sage: V.is_rationally_isometric(W) False
sage: K.<a>=NumberField(x^2-3) sage: V=DiagonalQuadraticForm(K,[-1,a,-2*a]) sage: W=DiagonalQuadraticForm(K,[-1,-a,2*a]) sage: V.is_rationally_isometric(W) True
-
is_zero
(v, p=0)¶ Determines if the vector v is on the conic Q(x) = 0 (mod p).
EXAMPLES:
sage: Q1 = QuadraticForm(ZZ, 3, [1, 0, -1, 2, -1, 5]) sage: Q1.is_zero([0,1,0], 2) True sage: Q1.is_zero([1,1,1], 2) True sage: Q1.is_zero([1,1,0], 2) False
-
is_zero_nonsingular
(v, p=0)¶ Determines if the vector \(v\) is on the conic Q(\(x\)) = 0 (mod \(p\)), and that this point is non-singular point of the conic.
EXAMPLES:
sage: Q1 = QuadraticForm(ZZ, 3, [1, 0, -1, 2, -1, 5]) sage: Q1.is_zero_nonsingular([1,1,1], 2) True sage: Q1.is_zero([1, 19, 2], 37) True sage: Q1.is_zero_nonsingular([1, 19, 2], 37) False
-
is_zero_singular
(v, p=0)¶ Determines if the vector \(v\) is on the conic Q(\(x\)) = 0 (mod \(p\)), and that this point is singular point of the conic.
EXAMPLES:
sage: Q1 = QuadraticForm(ZZ, 3, [1, 0, -1, 2, -1, 5]) sage: Q1.is_zero([1,1,1], 2) True sage: Q1.is_zero_singular([1,1,1], 2) False sage: Q1.is_zero_singular([1, 19, 2], 37) True
-
jordan_blocks_by_scale_and_unimodular
(p, safe_flag=True)¶ Return a list of pairs \((s_i, L_i)\) where \(L_i\) is a maximal \(p^{s_i}\)-unimodular Jordan component which is further decomposed into block diagonals of block size \(\le 2\).
For each \(L_i\) the 2x2 blocks are listed after the 1x1 blocks (which follows from the convention of the
local_normal_form()
method).Note
The decomposition of each \(L_i\) into smaller blocks is not unique!
The
safe_flag
argument allows us to select whether we want a copy of the output, or the original output. By defaultsafe_flag = True
, so we return a copy of the cached information. If this is set toFalse
, then the routine is much faster but the return values are vulnerable to being corrupted by the user.INPUT:
- \(p\) – a prime number > 0.
OUTPUT:
A list of pairs \((s_i, L_i)\) where:
- \(s_i\) is an integer,
- \(L_i\) is a block-diagonal unimodular quadratic form over \(\ZZ_p\).
Note
These forms \(L_i\) are defined over the \(p\)-adic integers, but by a matrix over \(\ZZ\) (or \(\QQ\)?).
EXAMPLES:
sage: Q = DiagonalQuadraticForm(ZZ, [1,9,5,7]) sage: Q.jordan_blocks_by_scale_and_unimodular(3) [(0, Quadratic form in 3 variables over Integer Ring with coefficients: [ 1 0 0 ] [ * 5 0 ] [ * * 7 ]), (2, Quadratic form in 1 variables over Integer Ring with coefficients: [ 1 ])]
sage: Q2 = QuadraticForm(ZZ, 2, [1,1,1]) sage: Q2.jordan_blocks_by_scale_and_unimodular(2) [(-1, Quadratic form in 2 variables over Integer Ring with coefficients: [ 2 2 ] [ * 2 ])] sage: Q = Q2 + Q2.scale_by_factor(2) sage: Q.jordan_blocks_by_scale_and_unimodular(2) [(-1, Quadratic form in 2 variables over Integer Ring with coefficients: [ 2 2 ] [ * 2 ]), (0, Quadratic form in 2 variables over Integer Ring with coefficients: [ 2 2 ] [ * 2 ])]
-
jordan_blocks_in_unimodular_list_by_scale_power
(p)¶ Returns a list of Jordan components, whose component at index i should be scaled by the factor p^i.
This is only defined for integer-valued quadratic forms (i.e. forms with base_ring ZZ), and the indexing only works correctly for p=2 when the form has an integer Gram matrix.
INPUT:
self – a quadratic form over ZZ, which has integer Gram matrix if p == 2 \(p\) – a prime number > 0OUTPUT:
a list of p-unimodular quadratic formsEXAMPLES:
sage: Q = QuadraticForm(ZZ, 3, [2, -2, 0, 3, -5, 4]) sage: Q.jordan_blocks_in_unimodular_list_by_scale_power(2) Traceback (most recent call last): ... TypeError: Oops! The given quadratic form has a Jordan component with a negative scale exponent! This routine requires an integer-matrix quadratic form for the output indexing to work properly! sage: Q.scale_by_factor(2).jordan_blocks_in_unimodular_list_by_scale_power(2) [Quadratic form in 2 variables over Integer Ring with coefficients: [ 0 2 ] [ * 0 ], Quadratic form in 0 variables over Integer Ring with coefficients: , Quadratic form in 1 variables over Integer Ring with coefficients: [ 345 ]] sage: Q.jordan_blocks_in_unimodular_list_by_scale_power(3) [Quadratic form in 2 variables over Integer Ring with coefficients: [ 2 0 ] [ * 10 ], Quadratic form in 1 variables over Integer Ring with coefficients: [ 2 ]]
-
level
()¶ Determines the level of the quadratic form over a PID, which is a generator for the smallest ideal \(N\) of \(R\) such that N * (the matrix of 2*Q)^(-1) is in R with diagonal in 2*R.
Over \(\ZZ\) this returns a non-negative number.
(Caveat: This always returns the unit ideal when working over a field!)
EXAMPLES:
sage: Q = QuadraticForm(ZZ, 2, range(1,4)) sage: Q.level() 8 sage: Q1 = QuadraticForm(QQ, 2, range(1,4)) sage: Q1.level() # random UserWarning: Warning -- The level of a quadratic form over a field is always 1. Do you really want to do this?!? 1 sage: Q = DiagonalQuadraticForm(ZZ, [1,3,5,7]) sage: Q.level() 420
-
level__Tornaria
()¶ Return the level of the quadratic form, defined as
level(B) for even dimension level(B)/4 for odd dimensionwhere 2Q(\(x\)) \(= x^t * B * x\).
This agrees with the usual level for even dimension…
EXAMPLES:
sage: DiagonalQuadraticForm(ZZ, [1]).level__Tornaria() 1 sage: DiagonalQuadraticForm(ZZ, [1,1]).level__Tornaria() 4 sage: DiagonalQuadraticForm(ZZ, [1,1,1]).level__Tornaria() 1 sage: DiagonalQuadraticForm(ZZ, [1,1,1,1]).level__Tornaria() 4
-
level_ideal
()¶ Determines the level of the quadratic form (over R), which is the smallest ideal N of R such that N * (the matrix of 2*Q)^(-1) is in R with diagonal in 2*R. (Caveat: This always returns the principal ideal when working over a field!)
- WARNING: THIS ONLY WORKS OVER A PID RING OF INTEGERS FOR NOW!
- (Waiting for Sage fractional ideal support.)
EXAMPLES:
sage: Q = QuadraticForm(ZZ, 2, range(1,4)) sage: Q.level_ideal() Principal ideal (8) of Integer Ring
sage: Q1 = QuadraticForm(QQ, 2, range(1,4)) sage: Q1.level_ideal() Principal ideal (1) of Rational Field
sage: Q = DiagonalQuadraticForm(ZZ, [1,3,5,7]) sage: Q.level_ideal() Principal ideal (420) of Integer Ring
-
list_external_initializations
()¶ Returns a list of the fields which were set externally at creation, and not created through the usual QuadraticForm methods. These fields are as good as the external process that made them, and are thus not guaranteed to be correct.
EXAMPLES:
sage: Q = QuadraticForm(ZZ, 2, [1,0,5]) sage: Q.list_external_initializations() [] sage: T = Q.theta_series() sage: Q.list_external_initializations() [] sage: Q = QuadraticForm(ZZ, 2, [1,0,5], unsafe_initialization=False, number_of_automorphisms=3, determinant=0) sage: Q.list_external_initializations() []
sage: Q = QuadraticForm(ZZ, 2, [1,0,5], unsafe_initialization=False, number_of_automorphisms=3, determinant=0) sage: Q.list_external_initializations() [] sage: Q = QuadraticForm(ZZ, 2, [1,0,5], unsafe_initialization=True, number_of_automorphisms=3, determinant=0) sage: Q.list_external_initializations() ['number_of_automorphisms', 'determinant']
-
lll
()¶ Return an LLL-reduced form of Q (using Pari).
EXAMPLES:
sage: Q = QuadraticForm(ZZ, 4, range(1,11)) sage: Q.is_definite() True sage: Q.lll() Quadratic form in 4 variables over Integer Ring with coefficients: [ 1 0 1 0 ] [ * 4 3 3 ] [ * * 6 3 ] [ * * * 6 ]
-
local_badII_density_congruence
(p, m, Zvec=None, NZvec=None)¶ Finds the Bad-type II local density of Q representing \(m\) at \(p\). (Assuming that \(p\) > 2 and Q is given in local diagonal form.)
INPUT:
Q – quadratic form assumed to be block diagonal and p-integral
\(p\) – a prime number
\(m\) – an integer
Zvec, NZvec – non-repeating lists of integers in range(self.dim()) or None
OUTPUT:
a rational numberEXAMPLES:
sage: Q = DiagonalQuadraticForm(ZZ, [1,2,3]) sage: Q.local_badII_density_congruence(2, 1, None, None) 0 sage: Q.local_badII_density_congruence(2, 2, None, None) 0 sage: Q.local_badII_density_congruence(2, 4, None, None) 0 sage: Q.local_badII_density_congruence(3, 1, None, None) 0 sage: Q.local_badII_density_congruence(3, 6, None, None) 0 sage: Q.local_badII_density_congruence(3, 9, None, None) 0 sage: Q.local_badII_density_congruence(3, 27, None, None) 0
sage: Q = DiagonalQuadraticForm(ZZ, [1,3,3,9,9]) sage: Q.local_badII_density_congruence(3, 1, None, None) 0 sage: Q.local_badII_density_congruence(3, 3, None, None) 0 sage: Q.local_badII_density_congruence(3, 6, None, None) 0 sage: Q.local_badII_density_congruence(3, 9, None, None) 4/27 sage: Q.local_badII_density_congruence(3, 18, None, None) 4/9
-
local_badI_density_congruence
(p, m, Zvec=None, NZvec=None)¶ Finds the Bad-type I local density of Q representing \(m\) at \(p\). (Assuming that p > 2 and Q is given in local diagonal form.)
INPUT:
Q – quadratic form assumed to be block diagonal and \(p\)-integral
\(p\) – a prime number
\(m\) – an integer
Zvec, NZvec – non-repeating lists of integers in range(self.dim()) or None
OUTPUT:
a rational numberEXAMPLES:
sage: Q = DiagonalQuadraticForm(ZZ, [1,2,3]) sage: Q.local_badI_density_congruence(2, 1, None, None) 0 sage: Q.local_badI_density_congruence(2, 2, None, None) 1 sage: Q.local_badI_density_congruence(2, 4, None, None) 0 sage: Q.local_badI_density_congruence(3, 1, None, None) 0 sage: Q.local_badI_density_congruence(3, 6, None, None) 0 sage: Q.local_badI_density_congruence(3, 9, None, None) 0
sage: Q = DiagonalQuadraticForm(ZZ, [1,1,1,1]) sage: Q.local_badI_density_congruence(2, 1, None, None) 0 sage: Q.local_badI_density_congruence(2, 2, None, None) 0 sage: Q.local_badI_density_congruence(2, 4, None, None) 0 sage: Q.local_badI_density_congruence(3, 2, None, None) 0 sage: Q.local_badI_density_congruence(3, 6, None, None) 0 sage: Q.local_badI_density_congruence(3, 9, None, None) 0
sage: Q = DiagonalQuadraticForm(ZZ, [1,3,3,9]) sage: Q.local_badI_density_congruence(3, 1, None, None) 0 sage: Q.local_badI_density_congruence(3, 3, None, None) 4/3 sage: Q.local_badI_density_congruence(3, 6, None, None) 4/3 sage: Q.local_badI_density_congruence(3, 9, None, None) 0 sage: Q.local_badI_density_congruence(3, 18, None, None) 0
-
local_bad_density_congruence
(p, m, Zvec=None, NZvec=None)¶ Finds the Bad-type local density of Q representing \(m\) at \(p\), allowing certain congruence conditions mod \(p\).
INPUT:
Q – quadratic form assumed to be block diagonal and p-integral
\(p\) – a prime number
\(m\) – an integer
Zvec, NZvec – non-repeating lists of integers in range(self.dim()) or None
OUTPUT:
a rational numberEXAMPLES:
sage: Q = DiagonalQuadraticForm(ZZ, [1,2,3]) sage: Q.local_bad_density_congruence(2, 1, None, None) 0 sage: Q.local_bad_density_congruence(2, 2, None, None) 1 sage: Q.local_bad_density_congruence(2, 4, None, None) 0 sage: Q.local_bad_density_congruence(3, 1, None, None) 0 sage: Q.local_bad_density_congruence(3, 6, None, None) 0 sage: Q.local_bad_density_congruence(3, 9, None, None) 0 sage: Q.local_bad_density_congruence(3, 27, None, None) 0
sage: Q = DiagonalQuadraticForm(ZZ, [1,3,3,9,9]) sage: Q.local_bad_density_congruence(3, 1, None, None) 0 sage: Q.local_bad_density_congruence(3, 3, None, None) 4/3 sage: Q.local_bad_density_congruence(3, 6, None, None) 4/3 sage: Q.local_bad_density_congruence(3, 9, None, None) 4/27 sage: Q.local_bad_density_congruence(3, 18, None, None) 4/9 sage: Q.local_bad_density_congruence(3, 27, None, None) 8/27
-
local_density
(p, m)¶ Gives the local density – should be called by the user. =)
NOTE: This screens for imprimitive forms, and puts the quadratic form in local normal form, which is a requirement of the routines performing the computations!
INPUT:
\(p\) – a prime number > 0 \(m\) – an integerOUTPUT:
a rational numberEXAMPLES:
sage: Q = DiagonalQuadraticForm(ZZ, [1,1,1,1]) ## NOTE: This is already in local normal form for *all* primes p! sage: Q.local_density(p=2, m=1) 1 sage: Q.local_density(p=3, m=1) 8/9 sage: Q.local_density(p=5, m=1) 24/25 sage: Q.local_density(p=7, m=1) 48/49 sage: Q.local_density(p=11, m=1) 120/121
-
local_density_congruence
(p, m, Zvec=None, NZvec=None)¶ Finds the local density of Q representing \(m\) at \(p\), allowing certain congruence conditions mod \(p\).
INPUT:
Q – quadratic form assumed to be block diagonal and p-integral
\(p\) – a prime number
\(m\) – an integer
Zvec, NZvec – non-repeating lists of integers in range(self.dim()) or None
OUTPUT:
a rational numberEXAMPLES:
sage: Q = DiagonalQuadraticForm(ZZ, [1,1,1,1]) sage: Q.local_density_congruence(p=2, m=1, Zvec=None, NZvec=None) 1 sage: Q.local_density_congruence(p=3, m=1, Zvec=None, NZvec=None) 8/9 sage: Q.local_density_congruence(p=5, m=1, Zvec=None, NZvec=None) 24/25 sage: Q.local_density_congruence(p=7, m=1, Zvec=None, NZvec=None) 48/49 sage: Q.local_density_congruence(p=11, m=1, Zvec=None, NZvec=None) 120/121
sage: Q = DiagonalQuadraticForm(ZZ, [1,2,3]) sage: Q.local_density_congruence(2, 1, None, None) 1 sage: Q.local_density_congruence(2, 2, None, None) 1 sage: Q.local_density_congruence(2, 4, None, None) 3/2 sage: Q.local_density_congruence(3, 1, None, None) 2/3 sage: Q.local_density_congruence(3, 6, None, None) 4/3 sage: Q.local_density_congruence(3, 9, None, None) 14/9 sage: Q.local_density_congruence(3, 27, None, None) 2
sage: Q = DiagonalQuadraticForm(ZZ, [1,3,3,9,9]) sage: Q.local_density_congruence(3, 1, None, None) 2 sage: Q.local_density_congruence(3, 3, None, None) 4/3 sage: Q.local_density_congruence(3, 6, None, None) 4/3 sage: Q.local_density_congruence(3, 9, None, None) 2/9 sage: Q.local_density_congruence(3, 18, None, None) 4/9
-
local_genus_symbol
(p)¶ Returns the Conway-Sloane genus symbol of 2 times a quadratic form defined over ZZ at a prime number p. This is defined (in the Genus_Symbol_p_adic_ring() class in the quadratic_forms/genera subfolder) to be a list of tuples (one for each Jordan component p^m*A at p, where A is a unimodular symmetric matrix with coefficients the p-adic integers) of the following form:
If p>2 then return triples of the form [\(m\), \(n\), \(d\)] where
\(m\) = valuation of the component
\(n\) = rank of A
\(d\) = det(A) in {1,u} for normalized quadratic non-residue u.
If p=2 then return quintuples of the form [\(m\),`n`,`s`, \(d\), \(o\)] where
\(m\) = valuation of the component
\(n\) = rank of A
\(d\) = det(A) in {1,3,5,7}
\(s\) = 0 (or 1) if A is even (or odd)
- \(o\) = oddity of A (= 0 if s = 0) in Z/8Z
= the trace of the diagonalization of A
NOTE: The Conway-Sloane convention for describing the prime ‘p = -1’ is not supported here, and neither is the convention for including the ‘prime’ Infinity. See note on p370 of Conway-Sloane (3rd ed) for a discussion of this convention.
INPUT:
-\(p\) – a prime number > 0OUTPUT:
Returns a Conway-Sloane genus symbol at p, which is an instance of the Genus_Symbol_p_adic_ring class.EXAMPLES:
sage: Q = DiagonalQuadraticForm(ZZ, [1,2,3,4]) sage: Q.local_genus_symbol(2) Genus symbol at 2: [2^-2 4^1 8^1]_6 sage: Q.local_genus_symbol(3) Genus symbol at 3: 1^3 3^-1 sage: Q.local_genus_symbol(5) Genus symbol at 5: 1^4
-
local_good_density_congruence
(p, m, Zvec=None, NZvec=None)¶ Finds the Good-type local density of Q representing \(m\) at \(p\). (Front end routine for parity specific routines for p.)
TO DO: Add Documentation about the additional congruence conditions Zvec and NZvec.
INPUT:
Q – quadratic form assumed to be block diagonal and p-integral
\(p\) – a prime number
\(m\) – an integer
Zvec, NZvec – non-repeating lists of integers in range(self.dim()) or None
OUTPUT:
a rational numberEXAMPLES:
sage: Q = DiagonalQuadraticForm(ZZ, [1,2,3]) sage: Q.local_good_density_congruence(2, 1, None, None) 1 sage: Q.local_good_density_congruence(3, 1, None, None) 2/3
sage: Q = DiagonalQuadraticForm(ZZ, [1,1,1,1]) sage: Q.local_good_density_congruence(2, 1, None, None) 1 sage: Q.local_good_density_congruence(3, 1, None, None) 8/9
-
local_good_density_congruence_even
(m, Zvec, NZvec)¶ Finds the Good-type local density of Q representing \(m\) at \(p=2\). (Assuming Q is given in local diagonal form.)
The additional congruence condition arguments Zvec and NZvec can be either a list of indices or None. Zvec = [] is equivalent to Zvec = None which both impose no additional conditions, but NZvec = [] returns no solutions always while NZvec = None imposes no additional condition.
WARNING: Here the indices passed in Zvec and NZvec represent indices of the solution vector \(x\) of Q(\(x\)) = \(m (mod p^k)\), and not the Jordan components of Q. They therefore are required (and assumed) to include either all or none of the indices of a given Jordan component of Q. This is only important when \(p=2\) since otherwise all Jordan blocks are 1x1, and so there the indices and Jordan blocks coincide.
TO DO: Add type checking for Zvec, NZvec, and that Q is in local normal form.
INPUT:
Q – quadratic form assumed to be block diagonal and 2-integral
\(p\) – a prime number
\(m\) – an integer
Zvec, NZvec – non-repeating lists of integers in range(self.dim()) or None
OUTPUT:
a rational numberEXAMPLES:
sage: Q = DiagonalQuadraticForm(ZZ, [1,2,3]) sage: Q.local_good_density_congruence_even(1, None, None) 1
sage: Q = DiagonalQuadraticForm(ZZ, [1,1,1,1]) sage: Q.local_good_density_congruence_even(1, None, None) 1 sage: Q.local_good_density_congruence_even(2, None, None) 3/2 sage: Q.local_good_density_congruence_even(3, None, None) 1 sage: Q.local_good_density_congruence_even(4, None, None) 1/2
sage: Q = QuadraticForm(ZZ, 4, range(10)) sage: Q[0,0] = 5 sage: Q[1,1] = 10 sage: Q[2,2] = 15 sage: Q[3,3] = 20 sage: Q Quadratic form in 4 variables over Integer Ring with coefficients: [ 5 1 2 3 ] [ * 10 5 6 ] [ * * 15 8 ] [ * * * 20 ] sage: Q.theta_series(20) 1 + 2*q^5 + 2*q^10 + 2*q^14 + 2*q^15 + 2*q^16 + 2*q^18 + O(q^20) sage: Q.local_normal_form(2) Quadratic form in 4 variables over Integer Ring with coefficients: [ 0 1 0 0 ] [ * 0 0 0 ] [ * * 0 1 ] [ * * * 0 ] sage: Q.local_good_density_congruence_even(1, None, None) 3/4 sage: Q.local_good_density_congruence_even(2, None, None) 1 sage: Q.local_good_density_congruence_even(5, None, None) 3/4
-
local_good_density_congruence_odd
(p, m, Zvec, NZvec)¶ Finds the Good-type local density of Q representing \(m\) at \(p\). (Assuming that \(p\) > 2 and Q is given in local diagonal form.)
The additional congruence condition arguments Zvec and NZvec can be either a list of indices or None. Zvec = [] is equivalent to Zvec = None which both impose no additional conditions, but NZvec = [] returns no solutions always while NZvec = None imposes no additional condition.
TO DO: Add type checking for Zvec, NZvec, and that Q is in local normal form.
INPUT:
Q – quadratic form assumed to be diagonal and p-integral
\(p\) – a prime number
\(m\) – an integer
Zvec, NZvec – non-repeating lists of integers in range(self.dim()) or None
OUTPUT:
a rational numberEXAMPLES:
sage: Q = DiagonalQuadraticForm(ZZ, [1,2,3]) sage: Q.local_good_density_congruence_odd(3, 1, None, None) 2/3
sage: Q = DiagonalQuadraticForm(ZZ, [1,1,1,1]) sage: Q.local_good_density_congruence_odd(3, 1, None, None) 8/9
-
local_normal_form
(p)¶ Return a locally integrally equivalent quadratic form over the \(p\)-adic integers \(\ZZ_p\) which gives the Jordan decomposition.
The Jordan components are written as sums of blocks of size <= 2 and are arranged by increasing scale, and then by increasing norm. This is equivalent to saying that we put the 1x1 blocks before the 2x2 blocks in each Jordan component.
INPUT:
- \(p\) – a positive prime number.
OUTPUT:
a quadratic form over \(\ZZ\)
Warning
Currently this only works for quadratic forms defined over \(\ZZ\).
EXAMPLES:
sage: Q = QuadraticForm(ZZ, 2, [10,4,1]) sage: Q.local_normal_form(5) Quadratic form in 2 variables over Integer Ring with coefficients: [ 1 0 ] [ * 6 ]
sage: Q.local_normal_form(3) Quadratic form in 2 variables over Integer Ring with coefficients: [ 10 0 ] [ * 15 ] sage: Q.local_normal_form(2) Quadratic form in 2 variables over Integer Ring with coefficients: [ 1 0 ] [ * 6 ]
-
local_primitive_density
(p, m)¶ Gives the local primitive density – should be called by the user. =)
NOTE: This screens for imprimitive forms, and puts the quadratic form in local normal form, which is a requirement of the routines performing the computations!
INPUT:
\(p\) – a prime number > 0 \(m\) – an integerOUTPUT:
a rational numberEXAMPLES:
sage: Q = QuadraticForm(ZZ, 4, range(10)) sage: Q[0,0] = 5 sage: Q[1,1] = 10 sage: Q[2,2] = 15 sage: Q[3,3] = 20 sage: Q Quadratic form in 4 variables over Integer Ring with coefficients: [ 5 1 2 3 ] [ * 10 5 6 ] [ * * 15 8 ] [ * * * 20 ] sage: Q.theta_series(20) 1 + 2*q^5 + 2*q^10 + 2*q^14 + 2*q^15 + 2*q^16 + 2*q^18 + O(q^20) sage: Q.local_normal_form(2) Quadratic form in 4 variables over Integer Ring with coefficients: [ 0 1 0 0 ] [ * 0 0 0 ] [ * * 0 1 ] [ * * * 0 ] sage: Q.local_primitive_density(2, 1) 3/4 sage: Q.local_primitive_density(5, 1) 24/25 sage: Q.local_primitive_density(2, 5) 3/4 sage: Q.local_density(2, 5) 3/4
-
local_primitive_density_congruence
(p, m, Zvec=None, NZvec=None)¶ Finds the primitive local density of Q representing \(m\) at \(p\), allowing certain congruence conditions mod \(p\).
Note: The following routine is not used internally, but is included for consistency.
INPUT:
Q – quadratic form assumed to be block diagonal and p-integral
\(p\) – a prime number
\(m\) – an integer
Zvec, NZvec – non-repeating lists of integers in range(self.dim()) or None
OUTPUT:
a rational numberEXAMPLES:
sage: Q = DiagonalQuadraticForm(ZZ, [1,1,1,1]) sage: Q.local_primitive_density_congruence(p=2, m=1, Zvec=None, NZvec=None) 1 sage: Q.local_primitive_density_congruence(p=3, m=1, Zvec=None, NZvec=None) 8/9 sage: Q.local_primitive_density_congruence(p=5, m=1, Zvec=None, NZvec=None) 24/25 sage: Q.local_primitive_density_congruence(p=7, m=1, Zvec=None, NZvec=None) 48/49 sage: Q.local_primitive_density_congruence(p=11, m=1, Zvec=None, NZvec=None) 120/121
sage: Q = DiagonalQuadraticForm(ZZ, [1,2,3]) sage: Q.local_primitive_density_congruence(2, 1, None, None) 1 sage: Q.local_primitive_density_congruence(2, 2, None, None) 1 sage: Q.local_primitive_density_congruence(2, 4, None, None) 1 sage: Q.local_primitive_density_congruence(3, 1, None, None) 2/3 sage: Q.local_primitive_density_congruence(3, 6, None, None) 4/3 sage: Q.local_primitive_density_congruence(3, 9, None, None) 4/3 sage: Q.local_primitive_density_congruence(3, 27, None, None) 4/3
sage: Q = DiagonalQuadraticForm(ZZ, [1,3,3,9,9]) sage: Q.local_primitive_density_congruence(3, 1, None, None) 2 sage: Q.local_primitive_density_congruence(3, 3, None, None) 4/3 sage: Q.local_primitive_density_congruence(3, 6, None, None) 4/3 sage: Q.local_primitive_density_congruence(3, 9, None, None) 4/27 sage: Q.local_primitive_density_congruence(3, 18, None, None) 4/9 sage: Q.local_primitive_density_congruence(3, 27, None, None) 8/27 sage: Q.local_primitive_density_congruence(3, 81, None, None) 8/27 sage: Q.local_primitive_density_congruence(3, 243, None, None) 8/27
-
local_representation_conditions
(recompute_flag=False, silent_flag=False)¶ - WARNING: THIS ONLY WORKS CORRECTLY FOR FORMS IN >=3 VARIABLES,
- WHICH ARE LOCALLY UNIVERSAL AT ALMOST ALL PRIMES!
This class finds the local conditions for a number to be integrally represented by an integer-valued quadratic form. These conditions are stored in “self.__local_representability_conditions” and consist of a list of 9 element vectors, with one for each prime with a local obstruction (though only the first 5 are meaningful unless \(p=2\) ). The first element is always the prime \(p\) where the local obstruction occurs, and the next 8 (or 4) entries represent square-classes in the \(p\)-adic integers \(Z_p\), and are labeled by the \(Q_p\) square-classes \(t*(Q_p)^2\) with \(t\) given as follows:
\(p > 2\) ==> [ * 1 u p u p * * * * ]
\(p = 2\) ==> [ * 1 3 5 7 2 6 10 14 ]
The integer appearing in each place tells us how \(p\)-divisible a number needs to be in that square-class in order to be locally represented by Q. A negative number indicates that the entire \(Q_p\) square-class is not represented, while a positive number \(x\) indicates that \(t*p^{(2*x)} (Z_p)^2\) is locally represented but \(t*p^{(2*(x-1))}\) \((Z_p)^2\) is not.
As an example, the vector
[2 3 0 0 0 0 2 0 infinity]tells us that all positive integers are locally represented at p=2 except those of the forms:
\(2^6 * u * r^2\) with \(u = 1 (mod 8)\)
\(2^5 * u * r^2\) with \(u = 3 (mod 8)\)
\(2 * u * r^2\) with \(u = 7 (mod 8)\)
At the real numbers, the vector which looks like
[infinity, 0, infinity, None, None, None, None, None, None]means that Q is negative definite (i.e. the 0 tells us all positive reals are represented). The real vector always appears, and is listed before the other ones.
INPUT:
noneOUTPUT:
A list of 9-element vectors describing the representation obstructions at primes dividing the level.EXAMPLES:
sage: Q = DiagonalQuadraticForm(ZZ, []) sage: Q.local_representation_conditions() This 0-dimensional form only represents zero. sage: Q = DiagonalQuadraticForm(ZZ, [5]) sage: Q.local_representation_conditions() This 1-dimensional form only represents square multiples of 5. sage: Q1 = DiagonalQuadraticForm(ZZ, [1,1]) sage: Q1.local_representation_conditions() This 2-dimensional form represents the p-adic integers of even valuation for all primes p except [2]. For these and the reals, we have: Reals: [0, +Infinity] p = 2: [0, +Infinity, 0, +Infinity, 0, +Infinity, 0, +Infinity] sage: Q1 = DiagonalQuadraticForm(ZZ, [1,1,1]) sage: Q1.local_representation_conditions() This form represents the p-adic integers Z_p for all primes p except [2]. For these and the reals, we have: Reals: [0, +Infinity] p = 2: [0, 0, 0, +Infinity, 0, 0, 0, 0] sage: Q1 = DiagonalQuadraticForm(ZZ, [1,1,1,1]) sage: Q1.local_representation_conditions() This form represents the p-adic integers Z_p for all primes p except []. For these and the reals, we have: Reals: [0, +Infinity] sage: Q1 = DiagonalQuadraticForm(ZZ, [1,3,3,3]) sage: Q1.local_representation_conditions() This form represents the p-adic integers Z_p for all primes p except [3]. For these and the reals, we have: Reals: [0, +Infinity] p = 3: [0, 1, 0, 0] sage: Q2 = DiagonalQuadraticForm(ZZ, [2,3,3,3]) sage: Q2.local_representation_conditions() This form represents the p-adic integers Z_p for all primes p except [3]. For these and the reals, we have: Reals: [0, +Infinity] p = 3: [1, 0, 0, 0] sage: Q3 = DiagonalQuadraticForm(ZZ, [1,3,5,7]) sage: Q3.local_representation_conditions() This form represents the p-adic integers Z_p for all primes p except []. For these and the reals, we have: Reals: [0, +Infinity]
-
local_zero_density_congruence
(p, m, Zvec=None, NZvec=None)¶ Finds the Zero-type local density of Q representing \(m\) at \(p\), allowing certain congruence conditions mod p.
INPUT:
Q – quadratic form assumed to be block diagonal and \(p\)-integral
\(p\) – a prime number
\(m\) – an integer
Zvec, NZvec – non-repeating lists of integers in range(self.dim()) or None
OUTPUT:
a rational numberEXAMPLES:
sage: Q = DiagonalQuadraticForm(ZZ, [1,2,3]) sage: Q.local_zero_density_congruence(2, 2, None, None) 0 sage: Q.local_zero_density_congruence(2, 4, None, None) 1/2 sage: Q.local_zero_density_congruence(3, 6, None, None) 0 sage: Q.local_zero_density_congruence(3, 9, None, None) 2/9
sage: Q = DiagonalQuadraticForm(ZZ, [1,1,1,1]) sage: Q.local_zero_density_congruence(2, 2, None, None) 0 sage: Q.local_zero_density_congruence(2, 4, None, None) 1/4 sage: Q.local_zero_density_congruence(3, 6, None, None) 0 sage: Q.local_zero_density_congruence(3, 9, None, None) 8/81
-
mass__by_Siegel_densities
(odd_algorithm='Pall', even_algorithm='Watson')¶ Gives the mass of transformations (det 1 and -1).
WARNING: THIS IS BROKEN RIGHT NOW… =(
Optional Arguments:
- When p > 2 – odd_algorithm = “Pall” (only one choice for now)
- When p = 2 – even_algorithm = “Kitaoka” or “Watson”
REFERENCES:
- Nipp’s Book “Tables of Quaternary Quadratic Forms”.
- Papers of Pall (only for p>2) and Watson (for \(p=2\) – tricky!).
- Siegel, Milnor-Hussemoller, Conway-Sloane Paper IV, Kitoaka (all of which have problems…)
EXAMPLES:
sage: Q = DiagonalQuadraticForm(ZZ, [1,1,1,1]) sage: m = Q.mass__by_Siegel_densities(); m 1/384 sage: m - (2^Q.dim() * factorial(Q.dim()))^(-1) 0
sage: Q = DiagonalQuadraticForm(ZZ, [1,1,1]) sage: m = Q.mass__by_Siegel_densities(); m 1/48 sage: m - (2^Q.dim() * factorial(Q.dim()))^(-1) 0
-
mass_at_two_by_counting_mod_power
(k)¶ Computes the local mass at \(p=2\) assuming that it’s stable \((mod 2^k)\).
Note: This is way too slow to be useful, even when k=1!!!
TO DO: Remove this routine, or try to compile it!
INPUT:
k – an integer >= 1OUTPUT:
a rational numberEXAMPLES:
sage: Q = DiagonalQuadraticForm(ZZ, [1,1,1]) sage: Q.mass_at_two_by_counting_mod_power(1) 4
-
matrix
()¶ Returns the Hessian matrix A for which Q(X) = \((1/2) * X^t * A * X\).
EXAMPLES:
sage: Q = QuadraticForm(ZZ, 3, range(6)) sage: Q.matrix() [ 0 1 2] [ 1 6 4] [ 2 4 10]
-
minkowski_reduction
()¶ Find a Minkowski-reduced form equivalent to the given one. This means that
\[Q(v_k) <= Q(s_1 * v_1 + ... + s_n * v_n)\]for all \(s_i\) where GCD`(s_k, … s_n) = 1`.
Note: When Q has dim <= 4 we can take all \(s_i\) in {1, 0, -1}.
- References:
- Schulze-Pillot’s paper on “An algorithm for computing genera
- of ternary and quaternary quadratic forms”, p138.
- Donaldson’s 1979 paper “Minkowski Reduction of Integral
- Matrices”, p203.
EXAMPLES:
sage: Q = QuadraticForm(ZZ,4,[30, 17, 11, 12, 29, 25, 62, 64, 25, 110]) sage: Q Quadratic form in 4 variables over Integer Ring with coefficients: [ 30 17 11 12 ] [ * 29 25 62 ] [ * * 64 25 ] [ * * * 110 ] sage: Q.minkowski_reduction() ( Quadratic form in 4 variables over Integer Ring with coefficients: [ 30 17 11 -5 ] [ * 29 25 4 ] [ * * 64 0 ] [ * * * 77 ] , [ 1 0 0 0] [ 0 1 0 -1] [ 0 0 1 0] [ 0 0 0 1] )
sage: Q=QuadraticForm(ZZ,4,[1, -2, 0, 0, 2, 0, 0, 2, 0, 2]) sage: Q Quadratic form in 4 variables over Integer Ring with coefficients: [ 1 -2 0 0 ] [ * 2 0 0 ] [ * * 2 0 ] [ * * * 2 ] sage: Q.minkowski_reduction() ( Quadratic form in 4 variables over Integer Ring with coefficients: [ 1 0 0 0 ] [ * 1 0 0 ] [ * * 2 0 ] [ * * * 2 ] , [1 1 0 0] [0 1 0 0] [0 0 1 0] [0 0 0 1] )
sage: Q=QuadraticForm(ZZ,5,[2,2,0,0,0,2,2,0,0,2,2,0,2,2,2]) sage: Q.Gram_matrix() [2 1 0 0 0] [1 2 1 0 0] [0 1 2 1 0] [0 0 1 2 1] [0 0 0 1 2] sage: Q.minkowski_reduction() Traceback (most recent call last): ... NotImplementedError: This algorithm is only for dimensions less than 5
-
minkowski_reduction_for_4vars__SP
()¶ Find a Minkowski-reduced form equivalent to the given one. This means that
Q(\(v_k\)) <= Q(\(s_1 * v_1 + ... + s_n * v_n\))for all \(s_i\) where GCD(\(s_k, ... s_n\)) = 1.
Note: When Q has dim <= 4 we can take all \(s_i\) in {1, 0, -1}.
- References:
- Schulze-Pillot’s paper on “An algorithm for computing genera
- of ternary and quaternary quadratic forms”, p138.
- Donaldson’s 1979 paper “Minkowski Reduction of Integral
- Matrices”, p203.
EXAMPLES:
sage: Q = QuadraticForm(ZZ,4,[30,17,11,12,29,25,62,64,25,110]) sage: Q Quadratic form in 4 variables over Integer Ring with coefficients: [ 30 17 11 12 ] [ * 29 25 62 ] [ * * 64 25 ] [ * * * 110 ] sage: Q.minkowski_reduction_for_4vars__SP() ( Quadratic form in 4 variables over Integer Ring with coefficients: [ 29 -17 25 4 ] [ * 30 -11 5 ] [ * * 64 0 ] [ * * * 77 ] , [ 0 1 0 0] [ 1 0 0 -1] [ 0 0 1 0] [ 0 0 0 1] )
-
multiply_variable
(c, i, in_place=False)¶ Replace the variables \(x_i\) by \(c*x_i\) in the quadratic form (replacing the original form if the in_place flag is True).
Here \(c\) must be an element of the base_ring defining the quadratic form.
INPUT:
\(c\) – an element of Q.base_ring()
\(i\) – an integer >= 0
OUTPUT:
a QuadraticForm (by default, otherwise none)EXAMPLES:
sage: Q = DiagonalQuadraticForm(ZZ, [1,9,5,7]) sage: Q.multiply_variable(5,0) Quadratic form in 4 variables over Integer Ring with coefficients: [ 25 0 0 0 ] [ * 9 0 0 ] [ * * 5 0 ] [ * * * 7 ]
-
number_of_automorphisms
()¶ Return the number of automorphisms (of det 1 and -1) of the quadratic form.
OUTPUT:
an integer >= 2.
EXAMPLES:
sage: Q = QuadraticForm(ZZ, 3, [1, 0, 0, 1, 0, 1], unsafe_initialization=True) sage: Q.number_of_automorphisms() 48
sage: Q = DiagonalQuadraticForm(ZZ, [1,1,1,1]) sage: Q.number_of_automorphisms() 384 sage: 2^4 * factorial(4) 384
-
omega
()¶ This is the content of the adjoint of the primitive associated quadratic form.
Ref: See Dickson’s “Studies in Number Theory”.
EXAMPLES:
sage: Q = DiagonalQuadraticForm(ZZ, [1,1,37]) sage: Q.omega() 4
-
parity
(allow_rescaling_flag=True)¶ Return the parity (“even” or “odd”) of an integer-valued quadratic form over \(ZZ\), defined up to similitude/rescaling of the form so that its Jordan component of smallest scale is unimodular. After this rescaling, we say a form is even if it only represents even numbers, and odd if it represents some odd number.
If the ‘allow_rescaling_flag’ is set to False, then we require that the quadratic form have a Gram matrix with coefficients in \(ZZ\), and look at the unimodular Jordan block to determine its parity. This returns an error if the form is not integer-matrix, meaning that it has Jordan components at \(p=2\) which do not have an integer scale.
We determine the parity by looking for a 1x1 block in the 0-th Jordan component, after a possible rescaling.
INPUT:
- self – a quadratic form with base_ring \(ZZ\), which we may
- require to have integer Gram matrix.
OUTPUT:
One of the strings: “even” or “odd”
EXAMPLES:
sage: Q = QuadraticForm(ZZ, 3, [4, -2, 0, 2, 3, 2]); Q Quadratic form in 3 variables over Integer Ring with coefficients: [ 4 -2 0 ] [ * 2 3 ] [ * * 2 ] sage: Q.parity() 'even'
sage: Q = QuadraticForm(ZZ, 3, [4, -2, 0, 2, 3, 1]); Q Quadratic form in 3 variables over Integer Ring with coefficients: [ 4 -2 0 ] [ * 2 3 ] [ * * 1 ] sage: Q.parity() 'even'
sage: Q = QuadraticForm(ZZ, 3, [4, -2, 0, 2, 2, 2]); Q Quadratic form in 3 variables over Integer Ring with coefficients: [ 4 -2 0 ] [ * 2 2 ] [ * * 2 ] sage: Q.parity() 'even'
sage: Q = QuadraticForm(ZZ, 3, [4, -2, 0, 2, 2, 1]); Q Quadratic form in 3 variables over Integer Ring with coefficients: [ 4 -2 0 ] [ * 2 2 ] [ * * 1 ] sage: Q.parity() 'odd'
-
polynomial
(names='x')¶ Return the polynomial in ‘n’ variables of the quadratic form in the ring ‘R[names].’
INPUT:
-‘self’ - a quadratic form over a commutative ring. -‘names’ - the name of the variables. Digits will be appended to the name for each different canonical variable e.g x1, x2, x3 etc.OUTPUT:
The polynomial form of the quadratic form.EXAMPLES:
sage: Q = DiagonalQuadraticForm(QQ,[1, 3, 5, 7]) sage: P = Q.polynomial(); P x0^2 + 3*x1^2 + 5*x2^2 + 7*x3^2
sage: F.<a> = NumberField(x^2 - 5) sage: Z = F.ring_of_integers() sage: Q = QuadraticForm(Z,3,[2*a, 3*a, 0 , 1 - a, 0, 2*a + 4]) sage: P = Q.polynomial(names='y'); P 2*a*y0^2 + 3*a*y0*y1 + (-a + 1)*y1^2 + (2*a + 4)*y2^2 sage: Q = QuadraticForm(F,4,[a, 3*a, 0, 1 - a, a - 3, 0, 2*a + 4, 4 + a, 0, 1]) sage: Q.polynomial(names='z') (a)*z0^2 + (3*a)*z0*z1 + (a - 3)*z1^2 + (a + 4)*z2^2 + (-a + 1)*z0*z3 + (2*a + 4)*z1*z3 + z3^2 sage: B.<i,j,k> = QuaternionAlgebra(F,-1,-1) sage: Q = QuadraticForm(B, 3, [2*a, 3*a, i, 1 - a, 0, 2*a + 4]) sage: Q.polynomial() Traceback (most recent call last): ... ValueError: Can only create polynomial rings over commutative rings.
-
primitive
()¶ Returns a primitive version of an integer-valued quadratic form, defined over \(ZZ\).
EXAMPLES:
sage: Q = QuadraticForm(ZZ, 2, [2,3,4]) sage: Q.primitive() Quadratic form in 2 variables over Integer Ring with coefficients: [ 2 3 ] [ * 4 ] sage: Q = QuadraticForm(ZZ, 2, [2,4,8]) sage: Q.primitive() Quadratic form in 2 variables over Integer Ring with coefficients: [ 1 2 ] [ * 4 ]
-
rational_diagonal_form
(return_matrix=False)¶ Return a diagonal form equivalent to the given quadratic from over the fraction field of its defining ring.
INPUT:
return_matrix
– (boolean, default: False) also return the transformation matrix
OUTPUT: either
D
(ifreturn_matrix
is false) or(D,T)
(ifreturn_matrix
is true) whereD
– the diagonalized form of this quadratic form.T
– transformation matrix. This is such thatT.transpose() * self.matrix() * T
givesD.matrix()
.
Both
D
andT
are defined over the fraction field of the base ring of the given form.EXAMPLES:
sage: Q = QuadraticForm(ZZ, 2, [0,1,-1]) sage: Q Quadratic form in 2 variables over Integer Ring with coefficients: [ 0 1 ] [ * -1 ] sage: Q.rational_diagonal_form() Quadratic form in 2 variables over Rational Field with coefficients: [ 1/4 0 ] [ * -1 ]
If we start with a diagonal form, we get back the same form defined over the fraction field:
sage: Q = DiagonalQuadraticForm(ZZ, [1,3,5,7]) sage: Q.rational_diagonal_form() Quadratic form in 4 variables over Rational Field with coefficients: [ 1 0 0 0 ] [ * 3 0 0 ] [ * * 5 0 ] [ * * * 7 ]
In the following example, we check the consistency of the transformation matrix:
sage: Q = QuadraticForm(ZZ, 4, range(10)) sage: D, T = Q.rational_diagonal_form(return_matrix=True) sage: D Quadratic form in 4 variables over Rational Field with coefficients: [ -1/16 0 0 0 ] [ * 4 0 0 ] [ * * 13 0 ] [ * * * 563/52 ] sage: T [ 1 0 11 149/26] [ -1/8 1 -2 -10/13] [ 0 0 1 -29/26] [ 0 0 0 1] sage: T.transpose() * Q.matrix() * T [ -1/8 0 0 0] [ 0 8 0 0] [ 0 0 26 0] [ 0 0 0 563/26] sage: D.matrix() [ -1/8 0 0 0] [ 0 8 0 0] [ 0 0 26 0] [ 0 0 0 563/26]
sage: Q1 = QuadraticForm(ZZ, 4, [1, 1, 0, 0, 1, 0, 0, 1, 0, 18]) sage: Q1 Quadratic form in 4 variables over Integer Ring with coefficients: [ 1 1 0 0 ] [ * 1 0 0 ] [ * * 1 0 ] [ * * * 18 ] sage: Q1.rational_diagonal_form(return_matrix=True) ( Quadratic form in 4 variables over Rational Field with coefficients: [ 1 0 0 0 ] [ * 3/4 0 0 ] [ * * 1 0 ] [ * * * 18 ] , [ 1 -1/2 0 0] [ 0 1 0 0] [ 0 0 1 0] [ 0 0 0 1] )
PARI returns a singular transformation matrix for this case:
sage: Q = QuadraticForm(QQ, 2, [1/2, 1, 1/2]) sage: Q.rational_diagonal_form() Quadratic form in 2 variables over Rational Field with coefficients: [ 1/2 0 ] [ * 0 ]
This example cannot be computed by PARI:
sage: Q = QuadraticForm(RIF, 4, range(10)) sage: Q.__pari__() Traceback (most recent call last): ... TypeError sage: Q.rational_diagonal_form() Quadratic form in 4 variables over Real Interval Field with 53 bits of precision with coefficients: [ 5 0.?e-14 0.?e-13 0.?e-13 ] [ * -0.05000000000000? 0.?e-12 0.?e-12 ] [ * * 13.00000000000? 0.?e-10 ] [ * * * 10.8269230769? ]
-
reciprocal
()¶ This gives 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.
EXAMPLES:
sage: Q = DiagonalQuadraticForm(ZZ, [1,1,37]) sage: Q.reciprocal() Quadratic form in 3 variables over Integer Ring with coefficients: [ 37 0 0 ] [ * 37 0 ] [ * * 1 ] sage: Q.reciprocal().reciprocal() Quadratic form in 3 variables over Integer Ring with coefficients: [ 1 0 0 ] [ * 1 0 ] [ * * 37 ] sage: Q.reciprocal().reciprocal() == Q True
-
reduced_binary_form
()¶ Find a form which is reduced in the sense that no further binary form reductions can be done to reduce the original form.
EXAMPLES:
sage: QuadraticForm(ZZ,2,[5,5,2]).reduced_binary_form() ( Quadratic form in 2 variables over Integer Ring with coefficients: [ 2 -1 ] [ * 2 ] , [ 0 -1] [ 1 1] )
-
reduced_binary_form1
()¶ Reduce the form \(ax^2 + bxy+cy^2\) to satisfy the reduced condition \(|b| \le a \le c\), with \(b \ge 0\) if \(a = c\). This reduction occurs within the proper class, so all transformations are taken to have determinant 1.
EXAMPLES:
sage: QuadraticForm(ZZ,2,[5,5,2]).reduced_binary_form1() ( Quadratic form in 2 variables over Integer Ring with coefficients: [ 2 -1 ] [ * 2 ] , [ 0 -1] [ 1 1] )
-
reduced_ternary_form__Dickson
()¶ Find the unique reduced ternary form according to the conditions of Dickson’s “Studies in the Theory of Numbers”, pp164-171.
EXAMPLES:
sage: Q = DiagonalQuadraticForm(ZZ, [1, 1, 1]) sage: Q.reduced_ternary_form__Dickson() Traceback (most recent call last): ... NotImplementedError: TO DO
-
representation_number_list
(B)¶ Return the vector of representation numbers < B.
EXAMPLES:
sage: Q = DiagonalQuadraticForm(ZZ,[1,1,1,1,1,1,1,1]) sage: Q.representation_number_list(10) [1, 16, 112, 448, 1136, 2016, 3136, 5504, 9328, 12112]
-
representation_vector_list
(B, maxvectors=100000000)¶ Find all vectors \(v\) where \(Q(v) < B\).
This only works for positive definite quadratic forms.
EXAMPLES:
sage: Q = DiagonalQuadraticForm(ZZ, [1, 1]) sage: Q.representation_vector_list(10) [[(0, 0)], [(0, 1), (0, -1), (1, 0), (-1, 0)], [(1, 1), (-1, -1), (1, -1), (-1, 1)], [], [(0, 2), (0, -2), (2, 0), (-2, 0)], [(1, 2), (-1, -2), (1, -2), (-1, 2), (2, 1), (-2, -1), (2, -1), (-2, 1)], [], [], [(2, 2), (-2, -2), (2, -2), (-2, 2)], [(0, 3), (0, -3), (3, 0), (-3, 0)]] sage: list(map(len, _)) [1, 4, 4, 0, 4, 8, 0, 0, 4, 4] sage: Q.representation_number_list(10) [1, 4, 4, 0, 4, 8, 0, 0, 4, 4]
-
scale_by_factor
(c, change_value_ring_flag=False)¶ Scale the values of the quadratic form by the number \(c\), if this is possible while still being defined over its base ring.
If the flag is set to true, then this will alter the value ring to be the field of fractions of the original ring (if necessary).
INPUT:
\(c\) – a scalar in the fraction field of the value ring of the form.OUTPUT:
A quadratic form of the same dimensionEXAMPLES:
sage: Q = DiagonalQuadraticForm(ZZ, [3,9,18,27]) sage: Q.scale_by_factor(3) Quadratic form in 4 variables over Integer Ring with coefficients: [ 9 0 0 0 ] [ * 27 0 0 ] [ * * 54 0 ] [ * * * 81 ] sage: Q.scale_by_factor(1/3) Quadratic form in 4 variables over Integer Ring with coefficients: [ 1 0 0 0 ] [ * 3 0 0 ] [ * * 6 0 ] [ * * * 9 ]
-
set_number_of_automorphisms
(num_autos)¶ Set the number of automorphisms to be the value given. No error checking is performed, to this may lead to erroneous results.
The fact that this result was set externally is recorded in the internal list of external initializations, accessible by the method list_external_initializations().
OUTPUT: None
EXAMPLES:
sage: Q = DiagonalQuadraticForm(ZZ, [1, 1, 1]) sage: Q.list_external_initializations() [] sage: Q.set_number_of_automorphisms(-3) sage: Q.number_of_automorphisms() -3 sage: Q.list_external_initializations() ['number_of_automorphisms']
-
shimura_mass__maximal
()¶ Use Shimura’s exact mass formula to compute the mass of a maximal quadratic lattice. This works for any totally real number field, but has a small technical restriction when \(n\) is odd.
INPUT:
noneOUTPUT:
a rational numberEXAMPLES:
sage: Q = DiagonalQuadraticForm(ZZ, [1,1,1]) sage: Q.shimura_mass__maximal()
-
short_primitive_vector_list_up_to_length
(len_bound, up_to_sign_flag=False)¶ Return a list of lists of short primitive vectors \(v\), sorted by length, with Q(\(v\)) < len_bound. The list in output \([i]\) indexes all vectors of length \(i\). If the up_to_sign_flag is set to
True
, then only one of the vectors of the pair \([v, -v]\) is listed.Note
This processes the PARI/GP output to always give elements of type \(\ZZ\).
OUTPUT: a list of lists of vectors.
EXAMPLES:
sage: Q = DiagonalQuadraticForm(ZZ, [1,3,5,7]) sage: Q.short_vector_list_up_to_length(5, True) [[(0, 0, 0, 0)], [(1, 0, 0, 0)], [], [(0, 1, 0, 0)], [(1, 1, 0, 0), (1, -1, 0, 0), (2, 0, 0, 0)]] sage: Q.short_primitive_vector_list_up_to_length(5, True) [[], [(1, 0, 0, 0)], [], [(0, 1, 0, 0)], [(1, 1, 0, 0), (1, -1, 0, 0)]]
-
short_vector_list_up_to_length
(len_bound, up_to_sign_flag=False)¶ Return a list of lists of short vectors \(v\), sorted by length, with Q(\(v\)) < len_bound.
INPUT:
len_bound
– bound for the length of the vectors.up_to_sign_flag
– (default:False
) if set to True, then only one of the vectors of the pair \([v, -v]\) is listed.
OUTPUT: a list of lists of vectors such that entry
[i]
contains all vectors of length \(i\).EXAMPLES:
sage: Q = DiagonalQuadraticForm(ZZ, [1,3,5,7]) sage: Q.short_vector_list_up_to_length(3) [[(0, 0, 0, 0)], [(1, 0, 0, 0), (-1, 0, 0, 0)], []] sage: Q.short_vector_list_up_to_length(4) [[(0, 0, 0, 0)], [(1, 0, 0, 0), (-1, 0, 0, 0)], [], [(0, 1, 0, 0), (0, -1, 0, 0)]] sage: Q.short_vector_list_up_to_length(5) [[(0, 0, 0, 0)], [(1, 0, 0, 0), (-1, 0, 0, 0)], [], [(0, 1, 0, 0), (0, -1, 0, 0)], [(1, 1, 0, 0), (-1, -1, 0, 0), (1, -1, 0, 0), (-1, 1, 0, 0), (2, 0, 0, 0), (-2, 0, 0, 0)]] sage: Q.short_vector_list_up_to_length(5, True) [[(0, 0, 0, 0)], [(1, 0, 0, 0)], [], [(0, 1, 0, 0)], [(1, 1, 0, 0), (1, -1, 0, 0), (2, 0, 0, 0)]] sage: Q = QuadraticForm(matrix(6, [2, 1, 1, 1, -1, -1, 1, 2, 1, 1, -1, -1, 1, 1, 2, 0, -1, -1, 1, 1, 0, 2, 0, -1, -1, -1, -1, 0, 2, 1, -1, -1, -1, -1, 1, 2])) sage: vs = Q.short_vector_list_up_to_length(8) sage: [len(vs[i]) for i in range(len(vs))] [1, 72, 270, 720, 936, 2160, 2214, 3600] sage: vs = Q.short_vector_list_up_to_length(30) # long time (28s on sage.math, 2014) sage: [len(vs[i]) for i in range(len(vs))] # long time [1, 72, 270, 720, 936, 2160, 2214, 3600, 4590, 6552, 5184, 10800, 9360, 12240, 13500, 17712, 14760, 25920, 19710, 26064, 28080, 36000, 25920, 47520, 37638, 43272, 45900, 59040, 46800, 75600]
The cases of
len_bound < 2
led to exception or infinite runtime before.sage: Q.short_vector_list_up_to_length(-1) [] sage: Q.short_vector_list_up_to_length(0) [] sage: Q.short_vector_list_up_to_length(1) [[(0, 0, 0, 0, 0, 0)]]
In the case of quadratic forms that are not positive definite an error is raised.
sage: QuadraticForm(matrix(2, [2, 0, 0, -2])).short_vector_list_up_to_length(3) Traceback (most recent call last): ... ValueError: Quadratic form must be positive definite in order to enumerate short vectors
Check that PARI does not return vectors which are too long:
sage: Q = QuadraticForm(matrix(2, [72, 12, 12, 120])) sage: len_bound_pari = 2*22953421 - 2; len_bound_pari 45906840 sage: vs = list(Q.__pari__().qfminim(len_bound_pari)[2]) # long time (18s on sage.math, 2014) sage: v = vs[0]; v # long time [66, -623]~ sage: v.Vec() * Q.__pari__() * v # long time 45902280
-
siegel_product
(u)¶ Computes the infinite product of local densities of the quadratic form for the number \(u\).
EXAMPLES:
sage: Q = DiagonalQuadraticForm(ZZ, [1,1,1,1]) sage: Q.theta_series(11) 1 + 8*q + 24*q^2 + 32*q^3 + 24*q^4 + 48*q^5 + 96*q^6 + 64*q^7 + 24*q^8 + 104*q^9 + 144*q^10 + O(q^11) sage: Q.siegel_product(1) 8 sage: Q.siegel_product(2) ## This one is wrong -- expect 24, and the higher powers of 2 don't work... =( 24 sage: Q.siegel_product(3) 32 sage: Q.siegel_product(5) 48 sage: Q.siegel_product(6) 96 sage: Q.siegel_product(7) 64 sage: Q.siegel_product(9) 104 sage: Q.local_density(2,1) 1 sage: M = 4; len([v for v in mrange([M,M,M,M]) if Q(v) % M == 1]) / M^3 1 sage: M = 16; len([v for v in mrange([M,M,M,M]) if Q(v) % M == 1]) / M^3 # long time (2s on sage.math, 2014) 1 sage: Q.local_density(2,2) 3/2 sage: M = 4; len([v for v in mrange([M,M,M,M]) if Q(v) % M == 2]) / M^3 3/2 sage: M = 16; len([v for v in mrange([M,M,M,M]) if Q(v) % M == 2]) / M^3 # long time (2s on sage.math, 2014) 3/2
-
signature
()¶ Returns the signature of the quadratic form, defined as:
number of positive eigenvalues - number of negative eigenvaluesof the matrix of the quadratic form.
INPUT:
NoneOUTPUT:
an integerEXAMPLES:
sage: Q = DiagonalQuadraticForm(ZZ, [1,0,0,-4,3,11,3]) sage: Q.signature() 3
sage: Q = DiagonalQuadraticForm(ZZ, [1,2,-3,-4]) sage: Q.signature() 0
sage: Q = QuadraticForm(ZZ, 4, range(10)); Q Quadratic form in 4 variables over Integer Ring with coefficients: [ 0 1 2 3 ] [ * 4 5 6 ] [ * * 7 8 ] [ * * * 9 ] sage: Q.signature() 2
-
signature_vector
()¶ Returns the triple \((p, n, z)\) of integers where
- \(p\) = number of positive eigenvalues
- \(n\) = number of negative eigenvalues
- \(z\) = number of zero eigenvalues
for the symmetric matrix associated to Q.
INPUT:
(none)
OUTPUT:
a triple of integers >= 0
EXAMPLES:
sage: Q = DiagonalQuadraticForm(ZZ, [1,0,0,-4]) sage: Q.signature_vector() (1, 1, 2)
sage: Q = DiagonalQuadraticForm(ZZ, [1,2,-3,-4]) sage: Q.signature_vector() (2, 2, 0)
sage: Q = QuadraticForm(ZZ, 4, range(10)); Q Quadratic form in 4 variables over Integer Ring with coefficients: [ 0 1 2 3 ] [ * 4 5 6 ] [ * * 7 8 ] [ * * * 9 ] sage: Q.signature_vector() (3, 1, 0)
-
solve
(c=0)¶ Return a vector \(x\) such that
self(x) == c
.INPUT:
c
– (default: 0) a rational number.
OUTPUT:
- A non-zero vector \(x\) satisfying
self(x) == c
.
ALGORITHM:
Uses PARI’s qfsolve(). Algorithm described by Jeroen Demeyer; see comments on trac ticket #19112
EXAMPLES:
sage: F = DiagonalQuadraticForm(QQ, [1, -1]); F Quadratic form in 2 variables over Rational Field with coefficients: [ 1 0 ] [ * -1 ] sage: F.solve() (1, 1) sage: F.solve(1) (1, 0) sage: F.solve(2) (3/2, -1/2) sage: F.solve(3) (2, -1)
sage: F = DiagonalQuadraticForm(QQ, [1, 1, 1, 1]) sage: F.solve(7) (1, 2, -1, -1) sage: F.solve() Traceback (most recent call last): ... ArithmeticError: no solution found (local obstruction at -1)
sage: Q = QuadraticForm(QQ, 2, [17, 94, 130]) sage: x = Q.solve(5); x (17, -6) sage: Q(x) 5 sage: Q.solve(6) Traceback (most recent call last): ... ArithmeticError: no solution found (local obstruction at 3) sage: G = DiagonalQuadraticForm(QQ, [5, -3, -2]) sage: x = G.solve(10); x (3/2, -1/2, 1/2) sage: G(x) 10 sage: F = DiagonalQuadraticForm(QQ, [1, -4]) sage: x = F.solve(); x (2, 1) sage: F(x) 0
sage: F = QuadraticForm(QQ, 4, [0, 0, 1, 0, 0, 0, 1, 0, 0, 0]); F Quadratic form in 4 variables over Rational Field with coefficients: [ 0 0 1 0 ] [ * 0 0 1 ] [ * * 0 0 ] [ * * * 0 ] sage: F.solve(23) (23, 0, 1, 0)
Other fields besides the rationals are currently not supported:
sage: F = DiagonalQuadraticForm(GF(11), [1, 1]) sage: F.solve() Traceback (most recent call last): ... TypeError: solving quadratic forms is only implemented over QQ
-
split_local_cover
()¶ Tries to find subform of the given (positive definite quaternary) quadratic form Q of the form
\[d*x^2 + T(y,z,w)\]where \(d > 0\) is as small as possible.
This is done by exhaustive search on small vectors, and then comparing the local conditions of its sum with it’s complementary lattice and the original quadratic form Q.
INPUT:
noneOUTPUT:
a QuadraticForm over ZZEXAMPLES:
sage: Q1 = DiagonalQuadraticForm(ZZ, [7,5,3]) sage: Q1.split_local_cover() Quadratic form in 3 variables over Integer Ring with coefficients: [ 3 0 0 ] [ * 7 0 ] [ * * 5 ]
-
sum_by_coefficients_with
(right)¶ Returns the sum (on coefficients) of two quadratic forms of the same size.
EXAMPLES:
sage: Q = QuadraticForm(ZZ, 2, [1,4,10]) sage: Q Quadratic form in 2 variables over Integer Ring with coefficients: [ 1 4 ] [ * 10 ] sage: Q+Q Quadratic form in 4 variables over Integer Ring with coefficients: [ 1 4 0 0 ] [ * 10 0 0 ] [ * * 1 4 ] [ * * * 10 ] sage: Q2 = QuadraticForm(ZZ, 2, [1,4,-10]) sage: Q.sum_by_coefficients_with(Q2) Quadratic form in 2 variables over Integer Ring with coefficients: [ 2 8 ] [ * 0 ]
-
swap_variables
(r, s, in_place=False)¶ Switch the variables \(x_r\) and \(x_s\) in the quadratic form (replacing the original form if the in_place flag is True).
INPUT:
\(r\), \(s\) – integers >= 0OUTPUT:
a QuadraticForm (by default, otherwise none)EXAMPLES:
sage: Q = QuadraticForm(ZZ, 4, range(1,11)) sage: Q Quadratic form in 4 variables over Integer Ring with coefficients: [ 1 2 3 4 ] [ * 5 6 7 ] [ * * 8 9 ] [ * * * 10 ] sage: Q.swap_variables(0,2) Quadratic form in 4 variables over Integer Ring with coefficients: [ 8 6 3 9 ] [ * 5 2 7 ] [ * * 1 4 ] [ * * * 10 ] sage: Q.swap_variables(0,2).swap_variables(0,2) Quadratic form in 4 variables over Integer Ring with coefficients: [ 1 2 3 4 ] [ * 5 6 7 ] [ * * 8 9 ] [ * * * 10 ]
-
theta_by_cholesky
(q_prec)¶ Uses the real Cholesky decomposition to compute (the \(q\)-expansion of) the theta function of the quadratic form as a power series in \(q\) with terms correct up to the power \(q^{\text{q\_prec}}\). (So its error is \(O(q^ {\text{q\_prec} + 1})\).)
REFERENCE:
From Cohen’s “A Course in Computational Algebraic Number Theory” book, p 102.EXAMPLES:
## Check the sum of 4 squares form against Jacobi's formula sage: Q = DiagonalQuadraticForm(ZZ, [1,1,1,1]) sage: Theta = Q.theta_by_cholesky(10) sage: Theta 1 + 8*q + 24*q^2 + 32*q^3 + 24*q^4 + 48*q^5 + 96*q^6 + 64*q^7 + 24*q^8 + 104*q^9 + 144*q^10 sage: Expected = [1] + [8*sum([d for d in divisors(n) if d%4 != 0]) for n in range(1,11)] sage: Expected [1, 8, 24, 32, 24, 48, 96, 64, 24, 104, 144] sage: Theta.list() == Expected True
## Check the form x^2 + 3y^2 + 5z^2 + 7w^2 represents everything except 2 and 22. sage: Q = DiagonalQuadraticForm(ZZ, [1,3,5,7]) sage: Theta = Q.theta_by_cholesky(50) sage: Theta_list = Theta.list() sage: [m for m in range(len(Theta_list)) if Theta_list[m] == 0] [2, 22]
-
theta_by_pari
(Max, var_str='q', safe_flag=True)¶ Use PARI/GP to compute the theta function as a power series (or vector) up to the precision \(O(q^Max)\). This also caches the result for future computations.
If var_str = ‘’, then we return a vector \(v\) where \(v[i]\) counts the number of vectors of length \(i\).
The safe_flag allows us to select whether we want a copy of the output, or the original output. It is only meaningful when a vector is returned, otherwise a copy is automatically made in creating the power series. By default safe_flag = True, so we return a copy of the cached information. If this is set to False, then the routine is much faster but the return values are vulnerable to being corrupted by the user.
INPUT:
Max – an integer >=0 var_str – a stringOUTPUT:
a power series or a vectorEXAMPLES:
sage: Q = DiagonalQuadraticForm(ZZ, [1,1,1,1]) sage: Prec = 100 sage: compute = Q.theta_by_pari(Prec, '') sage: exact = [1] + [8 * sum([d for d in divisors(i) if d % 4 != 0]) for i in range(1, Prec)] sage: compute == exact True
-
theta_series
(Max=10, var_str='q', safe_flag=True)¶ Compute the theta series as a power series in the variable given in var_str (which defaults to ‘\(q\)’), up to the specified precision \(O(q^max)\).
This uses the PARI/GP function qfrep, wrapped by the theta_by_pari() method. This caches the result for future computations.
The safe_flag allows us to select whether we want a copy of the output, or the original output. It is only meaningful when a vector is returned, otherwise a copy is automatically made in creating the power series. By default safe_flag = True, so we return a copy of the cached information. If this is set to False, then the routine is much faster but the return values are vulnerable to being corrupted by the user.
TO DO: Allow the option Max=’mod_form’ to give enough coefficients to ensure we determine the theta series as a modular form. This is related to the Sturm bound, but we’ll need to be careful about this (particularly for half-integral weights!).
EXAMPLES:
sage: Q = DiagonalQuadraticForm(ZZ, [1,3,5,7]) sage: Q.theta_series() 1 + 2*q + 2*q^3 + 6*q^4 + 2*q^5 + 4*q^6 + 6*q^7 + 8*q^8 + 14*q^9 + O(q^10) sage: Q.theta_series(25) 1 + 2*q + 2*q^3 + 6*q^4 + 2*q^5 + 4*q^6 + 6*q^7 + 8*q^8 + 14*q^9 + 4*q^10 + 12*q^11 + 18*q^12 + 12*q^13 + 12*q^14 + 8*q^15 + 34*q^16 + 12*q^17 + 8*q^18 + 32*q^19 + 10*q^20 + 28*q^21 + 16*q^23 + 44*q^24 + O(q^25)
-
theta_series_degree_2
(Q, prec)¶ Compute the theta series of degree 2 for the quadratic form Q.
INPUT:
prec
– an integer.
OUTPUT:
dictionary, where:
- keys are \({\rm GL}_2(\ZZ)\)-reduced binary quadratic forms (given as triples of coefficients)
- values are coefficients
EXAMPLES:
sage: Q2 = QuadraticForm(ZZ, 4, [1,1,1,1, 1,0,0, 1,0, 1]) sage: S = Q2.theta_series_degree_2(10) sage: S[(0,0,2)] 24 sage: S[(1,0,1)] 144 sage: S[(1,1,1)] 192
AUTHORS:
- Gonzalo Tornaria (2010-03-23)
REFERENCE:
- Raum, Ryan, Skoruppa, Tornaria, ‘On Formal Siegel Modular Forms’ (preprint)
-
vectors_by_length
(bound)¶ Returns a list of short vectors together with their values.
This is a naive algorithm which uses the Cholesky decomposition, but does not use the LLL-reduction algorithm.
INPUT:
bound – an integer >= 0OUTPUT:
A list L of length (bound + 1) whose entry L \([i]\) is a list of all vectors of length \(i\).Reference: This is a slightly modified version of Cohn’s Algorithm 2.7.5 in “A Course in Computational Number Theory”, with the increment step moved around and slightly re-indexed to allow clean looping.
Note: We could speed this up for very skew matrices by using LLL first, and then changing coordinates back, but for our purposes the simpler method is efficient enough. =)
EXAMPLES:
sage: Q = DiagonalQuadraticForm(ZZ, [1,1]) sage: Q.vectors_by_length(5) [[[0, 0]], [[0, -1], [-1, 0]], [[-1, -1], [1, -1]], [], [[0, -2], [-2, 0]], [[-1, -2], [1, -2], [-2, -1], [2, -1]]]
sage: Q1 = DiagonalQuadraticForm(ZZ, [1,3,5,7]) sage: Q1.vectors_by_length(5) [[[0, 0, 0, 0]], [[-1, 0, 0, 0]], [], [[0, -1, 0, 0]], [[-1, -1, 0, 0], [1, -1, 0, 0], [-2, 0, 0, 0]], [[0, 0, -1, 0]]]
sage: Q = QuadraticForm(ZZ, 4, [1,1,1,1, 1,0,0, 1,0, 1]) sage: list(map(len, Q.vectors_by_length(2))) [1, 12, 12]
sage: Q = QuadraticForm(ZZ, 4, [1,-1,-1,-1, 1,0,0, 4,-3, 4]) sage: list(map(len, Q.vectors_by_length(3))) [1, 3, 0, 3]
-
xi
(p)¶ Return the value of the genus characters Xi_p… which may be missing one character. We allow -1 as a prime.
Reference: Dickson’s “Studies in the Theory of Numbers”
EXAMPLES:
sage: Q1 = QuadraticForm(ZZ, 3, [1, 1, 1, 14, 3, 14]) sage: Q2 = QuadraticForm(ZZ, 3, [2, -1, 0, 2, 0, 50]) sage: [Q1.omega(), Q2.omega()] [5, 5] sage: [Q1.hasse_invariant(5), Q2.hasse_invariant(5)] # equivalent over Q_5 [1, 1] sage: [Q1.xi(5), Q2.xi(5)] # not equivalent over Z_5 [1, -1]
-
xi_rec
(p)¶ Return Xi(\(p\)) for the reciprocal form.
EXAMPLES:
sage: Q1 = QuadraticForm(ZZ, 3, [1, 1, 1, 14, 3, 14]) sage: Q2 = QuadraticForm(ZZ, 3, [2, -1, 0, 2, 0, 50]) sage: [Q1.clifford_conductor(), Q2.clifford_conductor()] # equivalent over Q [3, 3] sage: Q1.is_locally_equivalent_to(Q2) # not in the same genus False sage: [Q1.delta(), Q2.delta()] [480, 480] sage: factor(480) 2^5 * 3 * 5 sage: list(map(Q1.xi_rec, [-1,2,3,5])) [-1, -1, -1, 1] sage: list(map(Q2.xi_rec, [-1,2,3,5])) [-1, -1, -1, -1]
-
sage.quadratic_forms.quadratic_form.
QuadraticForm__constructor
(R, n=None, entries=None)¶ Wrapper for the QuadraticForm class constructor. This is meant for internal use within the QuadraticForm class code only. You should instead directly call QuadraticForm().
EXAMPLES:
sage: from sage.quadratic_forms.quadratic_form import QuadraticForm__constructor sage: QuadraticForm__constructor(ZZ, 3) ## Makes a generic quadratic form over the integers Quadratic form in 3 variables over Integer Ring with coefficients: [ 0 0 0 ] [ * 0 0 ] [ * * 0 ]
-
sage.quadratic_forms.quadratic_form.
is_QuadraticForm
(Q)¶ Determines if the object Q is an element of the QuadraticForm class.
EXAMPLES:
sage: Q = QuadraticForm(ZZ, 2, [1,2,3]) sage: from sage.quadratic_forms.quadratic_form import is_QuadraticForm sage: is_QuadraticForm(Q) ##random True sage: is_QuadraticForm(2) ##random False