Quadratic forms overview

AUTHORS:

sage.quadratic_forms.quadratic_form.DiagonalQuadraticForm(R, diag)[source]

Return 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]); Q
Quadratic form in 4 variables over Integer Ring with coefficients:
[ 1 0 0 0 ]
[ * 3 0 0 ]
[ * * 5 0 ]
[ * * * 7 ]
>>> from sage.all import *
>>> Q = DiagonalQuadraticForm(ZZ, [Integer(1),Integer(3),Integer(5),Integer(7)]); 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)[source]

Bases: 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.

  1. QuadraticForm(R, n, entries), where

    • R – ring for which the quadratic form is defined

    • n – integer \(\geq 0\)

    • entries – list of \(n(n+1)/2\) coefficients of the quadratic form in \(R\) (given lexicographically, or equivalently, by rows of the matrix)

  2. QuadraticForm(p), where

    • p – a homogeneous polynomial of degree \(2\)

  3. QuadraticForm(R, n), where

    • R – a ring

    • n – a symmetric \(n \times n\) matrix with even diagonal (relative to \(R\))

  4. 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]); Q
Quadratic form in 3 variables over Integer Ring with coefficients:
[ 1 2 3 ]
[ * 4 5 ]
[ * * 6 ]
>>> from sage.all import *
>>> Q = QuadraticForm(ZZ, Integer(3), [Integer(1),Integer(2),Integer(3),Integer(4),Integer(5),Integer(6)]); 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]); 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
>>> from sage.all import *
>>> Q = QuadraticForm(QQ, Integer(3), [Integer(1),Integer(2),Integer(3),Integer(4)/Integer(3),Integer(5),Integer(6)]); Q
Quadratic form in 3 variables over Rational Field with coefficients:
[ 1 2 3 ]
[ * 4/3 5 ]
[ * * 6 ]
>>> Q[Integer(0),Integer(0)]
1
>>> Q[Integer(0),Integer(0)].parent()
Rational Field

sage: Q = QuadraticForm(QQ, 7, range(28)); 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 ]
>>> from sage.all import *
>>> Q = QuadraticForm(QQ, Integer(7), range(Integer(28))); 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 ]
>>> from sage.all import *
>>> Q = QuadraticForm(QQ, Integer(2), range(Integer(1),Integer(4)))
>>> A = Matrix(ZZ, Integer(2), Integer(2), [-Integer(1),Integer(0),Integer(0),Integer(1)])
>>> 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 ]
>>> from sage.all import *
>>> m = matrix(Integer(2), Integer(2), [Integer(1),Integer(2),Integer(3),Integer(4)])
>>> m + m.transpose()
[2 5]
[5 8]
>>> QuadraticForm(m + m.transpose())
Quadratic form in 2 variables over Integer Ring with coefficients:
[ 1 5 ]
[ * 4 ]

sage: P.<x,y,z> = QQ[]
sage: p = x^2 + 2*x*y + x*z/2 + y^2 + y*z/3
sage: QuadraticForm(p)
Quadratic form in 3 variables over Rational Field with coefficients:
[ 1 2 1/2 ]
[ * 1 1/3 ]
[ * * 0 ]
>>> from sage.all import *
>>> P = QQ['x, y, z']; (x, y, z,) = P._first_ngens(3)
>>> p = x**Integer(2) + Integer(2)*x*y + x*z/Integer(2) + y**Integer(2) + y*z/Integer(3)
>>> QuadraticForm(p)
Quadratic form in 3 variables over Rational Field with coefficients:
[ 1 2 1/2 ]
[ * 1 1/3 ]
[ * * 0 ]

sage: QuadraticForm(ZZ, m + m.transpose())
Quadratic form in 2 variables over Integer Ring with coefficients:
[ 1 5 ]
[ * 4 ]
>>> from sage.all import *
>>> 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 ]
>>> from sage.all import *
>>> 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)[source]

Return 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]
>>> from sage.all import *
>>> Q = DiagonalQuadraticForm(ZZ, [Integer(1),Integer(2),Integer(3),Integer(4)])
>>> 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()[source]

Use the GHY formula to compute the mass of a (maximal?) quadratic lattice. This works for any number field.

REFERENCES:

See [GHY, Prop 7.4 and 7.5, p121] and [GY, Thrm 10.20, p25].

OUTPUT: a rational number

EXAMPLES:

sage: Q = DiagonalQuadraticForm(ZZ, [1,1,1])
sage: Q.GHY_mass__maximal()
>>> from sage.all import *
>>> Q = DiagonalQuadraticForm(ZZ, [Integer(1),Integer(1),Integer(1)])
>>> Q.GHY_mass__maximal()
Gram_det()[source]

Return 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
>>> from sage.all import *
>>> Q = QuadraticForm(ZZ, Integer(2), [Integer(1),Integer(2),Integer(3)])
>>> Q.Gram_det()
2
Gram_matrix()[source]

Return a (symmetric) Gram matrix \(A\) for the quadratic form \(Q\), meaning that

\[Q(x) = x^t\cdot A\cdot 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
>>> from sage.all import *
>>> Q = DiagonalQuadraticForm(ZZ, [Integer(1),Integer(3),Integer(5),Integer(7)])
>>> A = Q.Gram_matrix(); A
[1 0 0 0]
[0 3 0 0]
[0 0 5 0]
[0 0 0 7]
>>> A.base_ring()
Integer Ring
Gram_matrix_rational()[source]

Return a (symmetric) Gram matrix \(A\) for the quadratic form \(Q\), meaning that

\[Q(x) = x^t\cdot A\cdot 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
>>> from sage.all import *
>>> Q = DiagonalQuadraticForm(ZZ, [Integer(1),Integer(3),Integer(5),Integer(7)])
>>> A = Q.Gram_matrix_rational(); A
[1 0 0 0]
[0 3 0 0]
[0 0 5 0]
[0 0 0 7]
>>> A.base_ring()
Rational Field
Hessian_matrix()[source]

Return the Hessian matrix \(A\) for which \(Q(X) = (1/2) X^t\cdot A\cdot X\).

EXAMPLES:

sage: Q = QuadraticForm(QQ, 2, range(1,4)); 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
>>> from sage.all import *
>>> Q = QuadraticForm(QQ, Integer(2), range(Integer(1),Integer(4))); Q
Quadratic form in 2 variables over Rational Field with coefficients:
[ 1 2 ]
[ * 3 ]
>>> Q.Hessian_matrix()
[2 2]
[2 6]
>>> Q.matrix().base_ring()
Rational Field
Kitaoka_mass_at_2()[source]

Return 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”.

OUTPUT: a rational number > 0

EXAMPLES:

sage: Q = DiagonalQuadraticForm(ZZ, [1,1,1])
sage: Q.Kitaoka_mass_at_2()   # WARNING:  WE NEED TO CHECK THIS CAREFULLY!
1/2
>>> from sage.all import *
>>> Q = DiagonalQuadraticForm(ZZ, [Integer(1),Integer(1),Integer(1)])
>>> Q.Kitaoka_mass_at_2()   # WARNING:  WE NEED TO CHECK THIS CAREFULLY!
1/2
Pall_mass_density_at_odd_prime(p)[source]

Return 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
>>> from sage.all import *
>>> Q = QuadraticForm(ZZ, Integer(3), [Integer(1),Integer(0),Integer(0),Integer(1),Integer(0),Integer(1)])
>>> Q.Pall_mass_density_at_odd_prime(Integer(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()[source]

Return 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.

OUTPUT: a rational number

EXAMPLES:

sage: Q = DiagonalQuadraticForm(ZZ, [1,1,1])
sage: Q.Watson_mass_at_2()  # WARNING:  WE NEED TO CHECK THIS CAREFULLY!        # needs sage.symbolic
384
>>> from sage.all import *
>>> Q = DiagonalQuadraticForm(ZZ, [Integer(1),Integer(1),Integer(1)])
>>> Q.Watson_mass_at_2()  # WARNING:  WE NEED TO CHECK THIS CAREFULLY!        # needs sage.symbolic
384
add_symmetric(c, i, j, in_place=False)[source]

Perform the substitution \(x_j \longmapsto x_j + c\cdot x_i\), which has the effect (on associated matrices) of symmetrically adding \(c\) times the \(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 method local_normal_form().

INPUT:

  • c – an element of self.base_ring()

  • i, j – integers \(\geq 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: this coefficient cannot be coerced
to an element of the base ring for the quadratic form
>>> from sage.all import *
>>> Q = QuadraticForm(ZZ, Integer(3), range(Integer(1),Integer(7))); Q
Quadratic form in 3 variables over Integer Ring with coefficients:
[ 1 2 3 ]
[ * 4 5 ]
[ * * 6 ]
>>> Q.add_symmetric(-Integer(1), Integer(1), Integer(0))
Quadratic form in 3 variables over Integer Ring with coefficients:
[ 1 0 3 ]
[ * 3 2 ]
[ * * 6 ]
>>> Q.add_symmetric(-Integer(3)/Integer(2), Integer(2), Integer(0))     # ERROR: -3/2 isn't in the base ring ZZ
Traceback (most recent call last):
...
RuntimeError: this coefficient cannot 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 ]
>>> from sage.all import *
>>> Q = QuadraticForm(QQ, Integer(3), range(Integer(1),Integer(7))); Q
Quadratic form in 3 variables over Rational Field with coefficients:
[ 1 2 3 ]
[ * 4 5 ]
[ * * 6 ]
>>> Q.add_symmetric(-Integer(3)/Integer(2), Integer(2), Integer(0))
Quadratic form in 3 variables over Rational Field with coefficients:
[ 1 2 0 ]
[ * 4 2 ]
[ * * 15/4 ]
adjoint()[source]

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 ]
>>> from sage.all import *
>>> Q = QuadraticForm(ZZ, Integer(2), [Integer(1),Integer(2),Integer(5)])
>>> 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 ]
>>> from sage.all import *
>>> Q = QuadraticForm(ZZ, Integer(3), [Integer(1), Integer(0), -Integer(1), Integer(2), -Integer(1), Integer(5)])
>>> Q.adjoint()
Quadratic form in 3 variables over Integer Ring with coefficients:
[ 39 2 8 ]
[ * 19 4 ]
[ * * 8 ]
adjoint_primitive()[source]

Return 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 ]
>>> from sage.all import *
>>> Q = QuadraticForm(ZZ, Integer(2), [Integer(1),Integer(2),Integer(3)])
>>> Q.adjoint_primitive()
Quadratic form in 2 variables over Integer Ring with coefficients:
[ 3 -2 ]
[ *  1 ]
anisotropic_primes()[source]

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()                                                    # needs sage.libs.pari
[2, -1]

sage: Q = DiagonalQuadraticForm(ZZ, [1,1,1,1])
sage: Q.anisotropic_primes()                                                    # needs sage.libs.pari
[2, -1]

sage: Q = DiagonalQuadraticForm(ZZ, [1,1,1,1,1])
sage: Q.anisotropic_primes()                                                    # needs sage.libs.pari
[-1]
>>> from sage.all import *
>>> Q = DiagonalQuadraticForm(ZZ, [Integer(1),Integer(1),Integer(1)])
>>> Q.anisotropic_primes()                                                    # needs sage.libs.pari
[2, -1]

>>> Q = DiagonalQuadraticForm(ZZ, [Integer(1),Integer(1),Integer(1),Integer(1)])
>>> Q.anisotropic_primes()                                                    # needs sage.libs.pari
[2, -1]

>>> Q = DiagonalQuadraticForm(ZZ, [Integer(1),Integer(1),Integer(1),Integer(1),Integer(1)])
>>> Q.anisotropic_primes()                                                    # needs sage.libs.pari
[-1]
antiadjoint()[source]

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()                                                           # needs sage.symbolic
Traceback (most recent call last):
...
ValueError: not an adjoint
>>> from sage.all import *
>>> Q = QuadraticForm(ZZ, Integer(3), [Integer(1), Integer(0), -Integer(1), Integer(2), -Integer(1), Integer(5)])
>>> Q.adjoint().antiadjoint()
Quadratic form in 3 variables over Integer Ring with coefficients:
[ 1 0 -1 ]
[ * 2 -1 ]
[ * * 5 ]
>>> Q.antiadjoint()                                                           # needs sage.symbolic
Traceback (most recent call last):
...
ValueError: not an adjoint
automorphism_group()[source]

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 (
[ 0  0  1]  [1 0 0]  [ 1  0  0]
[-1  0  0]  [0 0 1]  [ 0 -1  0]
[ 0  1  0], [0 1 0], [ 0  0  1]
)
>>> from sage.all import *
>>> Q = DiagonalQuadraticForm(ZZ, [Integer(1),Integer(1),Integer(1)])
>>> Q.automorphism_group()
Matrix group over Rational Field with 3 generators (
[ 0  0  1]  [1 0 0]  [ 1  0  0]
[-1  0  0]  [0 0 1]  [ 0 -1  0]
[ 0  1  0], [0 1 0], [ 0  0  1]
)

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]
)
>>> from sage.all import *
>>> DiagonalQuadraticForm(ZZ, [Integer(1),Integer(3),Integer(5),Integer(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]
)
>>> from sage.all import *
>>> Q = QuadraticForm(ZZ, Integer(3), [Integer(2), Integer(1), Integer(2), Integer(2), Integer(1), Integer(3)])
>>> Q.automorphism_group()
Matrix group over Rational Field with 1 generators (
[-1  0  0]
[ 0 -1  0]
[ 0  0 -1]
)
automorphisms()[source]

Return the list of the automorphisms of the quadratic form.

OUTPUT: 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())                                                    # needs sage.libs.gap
48
>>> from sage.all import *
>>> Q = DiagonalQuadraticForm(ZZ, [Integer(1),Integer(1),Integer(1)])
>>> Q.number_of_automorphisms()
48
>>> Integer(2)**Integer(3) * factorial(Integer(3))
48
>>> len(Q.automorphisms())                                                    # needs sage.libs.gap
48

sage: Q = DiagonalQuadraticForm(ZZ, [1,3,5,7])
sage: Q.number_of_automorphisms()
16
sage: aut = Q.automorphisms()                                                   # needs sage.libs.gap
sage: len(aut)                                                                  # needs sage.libs.gap
16
sage: all(Q(M) == Q for M in aut)                                               # needs sage.libs.gap
True

sage: Q = QuadraticForm(ZZ, 3, [2, 1, 2, 2, 1, 3])
sage: sorted(Q.automorphisms())                                                 # needs sage.libs.gap
[
[-1  0  0]  [1 0 0]
[ 0 -1  0]  [0 1 0]
[ 0  0 -1], [0 0 1]
]
>>> from sage.all import *
>>> Q = DiagonalQuadraticForm(ZZ, [Integer(1),Integer(3),Integer(5),Integer(7)])
>>> Q.number_of_automorphisms()
16
>>> aut = Q.automorphisms()                                                   # needs sage.libs.gap
>>> len(aut)                                                                  # needs sage.libs.gap
16
>>> all(Q(M) == Q for M in aut)                                               # needs sage.libs.gap
True

>>> Q = QuadraticForm(ZZ, Integer(3), [Integer(2), Integer(1), Integer(2), Integer(2), Integer(1), Integer(3)])
>>> sorted(Q.automorphisms())                                                 # needs sage.libs.gap
[
[-1  0  0]  [1 0 0]
[ 0 -1  0]  [0 1 0]
[ 0  0 -1], [0 0 1]
]
base_change_to(*args, **kwds)[source]

Deprecated: Use change_ring() instead. See Issue #35248 for details.

base_ring()[source]

Return the ring over which the quadratic form is defined.

EXAMPLES:

sage: Q = QuadraticForm(ZZ, 2, [1,2,3])
sage: Q.base_ring()
Integer Ring
>>> from sage.all import *
>>> Q = QuadraticForm(ZZ, Integer(2), [Integer(1),Integer(2),Integer(3)])
>>> Q.base_ring()
Integer Ring
basiclemma(M)[source]

Find a number represented by self and coprime to \(M\).

EXAMPLES:

sage: Q = QuadraticForm(ZZ, 2, [2, 1, 3])
sage: Q.basiclemma(6)
71
>>> from sage.all import *
>>> Q = QuadraticForm(ZZ, Integer(2), [Integer(2), Integer(1), Integer(3)])
>>> Q.basiclemma(Integer(6))
71
basiclemmavec(M)[source]

Find 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
>>> from sage.all import *
>>> Q = QuadraticForm(ZZ, Integer(2), [Integer(2), Integer(1), Integer(5)])
>>> Q.basiclemmavec(Integer(10))
(6, 5)
>>> Q(_)
227
basis_of_short_vectors(show_lengths=False)[source]

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))
>>> from sage.all import *
>>> Q = DiagonalQuadraticForm(ZZ, [Integer(1),Integer(3),Integer(5),Integer(7)])
>>> Q.basis_of_short_vectors()
((1, 0, 0, 0), (0, 1, 0, 0), (0, 0, 1, 0), (0, 0, 0, 1))
>>> 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())
>>> from sage.all import *
>>> v = Q.basis_of_short_vectors()[Integer(0)]
>>> v
(1, 0, 0, 0)
>>> v[Integer(0)] = Integer(0)
Traceback (most recent call last):
...
ValueError: vector is immutable; please change a copy instead (use copy())
bilinear_map(v, w)[source]

Return 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
>>> from sage.all import *
>>> Q = QuadraticForm(ZZ, Integer(3), [Integer(1),Integer(4),Integer(0),Integer(1),Integer(4),Integer(1)])
>>> v = vector(ZZ, (Integer(1),Integer(2),Integer(0)))
>>> w = vector(ZZ, (Integer(0),Integer(1),Integer(1)))
>>> 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
>>> from sage.all import *
>>> Q = QuadraticForm(QQ, Integer(2), [Integer(1)/Integer(2),Integer(2),Integer(1)])
>>> v = vector(QQ, (Integer(1),Integer(1)))
>>> w = vector(QQ, (Integer(1)/Integer(2),Integer(2)))
>>> 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
>>> from sage.all import *
>>> Q = DiagonalQuadraticForm(ZZ, [Integer(1),Integer(7),Integer(7)])
>>> v = vector((Integer(1),Integer(2)))
>>> w = vector((Integer(1),Integer(1),Integer(1)))
>>> 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: # needs sage.rings.finite_rings
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
>>> from sage.all import *
>>> # needs sage.rings.finite_rings
>>> Q = DiagonalQuadraticForm(GF(Integer(2)), [Integer(1),Integer(1),Integer(1)])
>>> v = vector((Integer(1),Integer(1),Integer(1)))
>>> w = vector((Integer(1),Integer(1),Integer(1)))
>>> Q.bilinear_map(v, w)
Traceback (most recent call last):
...
TypeError: not defined for rings of characteristic 2
change_ring(R)[source]

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.change_ring(IntegerModRing(5)); Q1
Quadratic form in 2 variables over Ring of integers modulo 5 with coefficients:
[ 1 0 ]
[ * 1 ]

sage: Q1([35,11])
1
>>> from sage.all import *
>>> Q = DiagonalQuadraticForm(ZZ, [Integer(1),Integer(1)]); Q
Quadratic form in 2 variables over Integer Ring with coefficients:
[ 1 0 ]
[ * 1 ]

>>> Q1 = Q.change_ring(IntegerModRing(Integer(5))); Q1
Quadratic form in 2 variables over Ring of integers modulo 5 with coefficients:
[ 1 0 ]
[ * 1 ]

>>> Q1([Integer(35),Integer(11)])
1
cholesky_decomposition(bit_prec=53)[source]

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:

  • 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 precision bit_prec

Todo

If we only care about working over the real double field (RDF), then we can use the method cholesky() 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]
>>> from sage.all import *
>>> Q = DiagonalQuadraticForm(ZZ, [Integer(1),Integer(1),Integer(1)])
>>> 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]
>>> from sage.all import *
>>> Q = QuadraticForm(QQ, Integer(3), range(Integer(1),Integer(7))); Q
Quadratic form in 3 variables over Rational Field with coefficients:
[ 1 2 3 ]
[ * 4 5 ]
[ * * 6 ]
>>> Q.cholesky_decomposition()
[ 1.00000000000000  1.00000000000000  1.50000000000000]
[0.000000000000000  3.00000000000000 0.333333333333333]
[0.000000000000000 0.000000000000000  3.41666666666667]
clifford_conductor()[source]

Return 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: # needs sage.libs.pari
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()                 # needs sage.libs.pari
2
sage: QuadraticForm(ZZ, 3, [2, -2, 0, 2, 0, 5]).clifford_conductor()            # needs sage.libs.pari
30
>>> from sage.all import *
>>> # needs sage.libs.pari
>>> Q = QuadraticForm(ZZ, Integer(3), [Integer(1), Integer(0), -Integer(1), Integer(2), -Integer(1), Integer(5)])
>>> Q.clifford_invariant(Integer(2))
1
>>> Q.clifford_invariant(Integer(37))
-1
>>> Q.clifford_conductor()
37

>>> DiagonalQuadraticForm(ZZ, [Integer(1), Integer(1), Integer(1)]).clifford_conductor()                 # needs sage.libs.pari
2
>>> QuadraticForm(ZZ, Integer(3), [Integer(2), -Integer(2), Integer(0), Integer(2), Integer(0), Integer(5)]).clifford_conductor()            # needs sage.libs.pari
30

For hyperbolic spaces, the Clifford conductor is 1:

sage: # needs sage.libs.pari
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
>>> from sage.all import *
>>> # needs sage.libs.pari
>>> H = QuadraticForm(ZZ, Integer(2), [Integer(0), Integer(1), Integer(0)])
>>> H.clifford_conductor()
1
>>> (H + H).clifford_conductor()
1
>>> (H + H + H).clifford_conductor()
1
>>> (H + H + H + H).clifford_conductor()
1
clifford_invariant(p)[source]

Return the Clifford invariant.

This is 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: # needs sage.libs.pari
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
>>> from sage.all import *
>>> # needs sage.libs.pari
>>> H = QuadraticForm(ZZ, Integer(2), [Integer(0), Integer(1), Integer(0)])
>>> H.clifford_invariant(Integer(2))
1
>>> (H + H).clifford_invariant(Integer(2))
1
>>> (H + H + H).clifford_invariant(Integer(2))
1
>>> (H + H + H + H).clifford_invariant(Integer(2))
1
coefficients()[source]

Return 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]
>>> from sage.all import *
>>> Q = QuadraticForm(ZZ, Integer(2), [Integer(1),Integer(2),Integer(3)])
>>> Q.coefficients()
[1, 2, 3]
complementary_subform_to_vector(v)[source]

Find the \((n-1)\)-dimensional quadratic form orthogonal to the vector \(v\).

Note

This is usually not a direct summand!

Note

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 – list of self.dim() integers

OUTPUT: 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:
[ 7 0 0 ]
[ * 5 0 ]
[ * * 3 ]
>>> from sage.all import *
>>> Q1 = DiagonalQuadraticForm(ZZ, [Integer(1),Integer(3),Integer(5),Integer(7)])
>>> Q1.complementary_subform_to_vector([Integer(1),Integer(0),Integer(0),Integer(0)])
Quadratic form in 3 variables over Integer Ring with coefficients:
[ 7 0 0 ]
[ * 5 0 ]
[ * * 3 ]

sage: Q1.complementary_subform_to_vector([1,1,0,0])
Quadratic form in 3 variables over Integer Ring with coefficients:
[ 7 0 0 ]
[ * 5 0 ]
[ * * 12 ]
>>> from sage.all import *
>>> Q1.complementary_subform_to_vector([Integer(1),Integer(1),Integer(0),Integer(0)])
Quadratic form in 3 variables over Integer Ring with coefficients:
[ 7 0 0 ]
[ * 5 0 ]
[ * * 12 ]

sage: Q1.complementary_subform_to_vector([1,1,1,1])
Quadratic form in 3 variables over Integer Ring with coefficients:
[ 880 -480 -160 ]
[ * 624 -96 ]
[ * * 240 ]
>>> from sage.all import *
>>> Q1.complementary_subform_to_vector([Integer(1),Integer(1),Integer(1),Integer(1)])
Quadratic form in 3 variables over Integer Ring with coefficients:
[ 880 -480 -160 ]
[ * 624 -96 ]
[ * * 240 ]
compute_definiteness()[source]

Compute 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-dimensional form is considered both positive definite and negative definite.

OUTPUT: boolean

EXAMPLES:

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
>>> from sage.all import *
>>> Q = DiagonalQuadraticForm(ZZ, [Integer(1),Integer(1),Integer(1),Integer(1),Integer(1)])
>>> Q.compute_definiteness()
>>> Q.is_positive_definite()
True
>>> Q.is_negative_definite()
False
>>> Q.is_indefinite()
False
>>> 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
>>> from sage.all import *
>>> Q = DiagonalQuadraticForm(ZZ, [])
>>> Q.compute_definiteness()
>>> Q.is_positive_definite()
True
>>> Q.is_negative_definite()
True
>>> Q.is_indefinite()
False
>>> 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
>>> from sage.all import *
>>> Q = DiagonalQuadraticForm(ZZ, [Integer(1),Integer(0),-Integer(1)])
>>> Q.compute_definiteness()
>>> Q.is_positive_definite()
False
>>> Q.is_negative_definite()
False
>>> Q.is_indefinite()
False
>>> Q.is_definite()
False
compute_definiteness_string_by_determinants()[source]

Compute the (positive) definiteness of a quadratic form by looking at the signs of all of its upper-left subdeterminants. See also compute_definiteness() for more documentation.

OUTPUT: string describing the definiteness

EXAMPLES:

sage: Q = DiagonalQuadraticForm(ZZ, [1,1,1,1,1])
sage: Q.compute_definiteness_string_by_determinants()
'pos_def'
>>> from sage.all import *
>>> Q = DiagonalQuadraticForm(ZZ, [Integer(1),Integer(1),Integer(1),Integer(1),Integer(1)])
>>> Q.compute_definiteness_string_by_determinants()
'pos_def'

sage: Q = DiagonalQuadraticForm(ZZ, [])
sage: Q.compute_definiteness_string_by_determinants()
'zero'
>>> from sage.all import *
>>> Q = DiagonalQuadraticForm(ZZ, [])
>>> Q.compute_definiteness_string_by_determinants()
'zero'

sage: Q = DiagonalQuadraticForm(ZZ, [1,0,-1])
sage: Q.compute_definiteness_string_by_determinants()
'degenerate'
>>> from sage.all import *
>>> Q = DiagonalQuadraticForm(ZZ, [Integer(1),Integer(0),-Integer(1)])
>>> Q.compute_definiteness_string_by_determinants()
'degenerate'

sage: Q = DiagonalQuadraticForm(ZZ, [1,-1])
sage: Q.compute_definiteness_string_by_determinants()
'indefinite'
>>> from sage.all import *
>>> Q = DiagonalQuadraticForm(ZZ, [Integer(1),-Integer(1)])
>>> Q.compute_definiteness_string_by_determinants()
'indefinite'

sage: Q = DiagonalQuadraticForm(ZZ, [-1,-1])
sage: Q.compute_definiteness_string_by_determinants()
'neg_def'
>>> from sage.all import *
>>> Q = DiagonalQuadraticForm(ZZ, [-Integer(1),-Integer(1)])
>>> Q.compute_definiteness_string_by_determinants()
'neg_def'
content()[source]

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 ]
>>> from sage.all import *
>>> Q = DiagonalQuadraticForm(ZZ, [Integer(1), Integer(1)])
>>> Q.matrix().gcd()
2
>>> Q.content()
1
>>> DiagonalQuadraticForm(ZZ, [Integer(1), Integer(1)]).is_primitive()
True
>>> DiagonalQuadraticForm(ZZ, [Integer(2), Integer(4)]).is_primitive()
False
>>> DiagonalQuadraticForm(ZZ, [Integer(2), Integer(4)]).primitive()
Quadratic form in 2 variables over Integer Ring with coefficients:
[ 1 0 ]
[ * 2 ]
conway_cross_product_doubled_power(p)[source]

Compute twice the power of \(p\) which evaluates the ‘cross product’ term in Conway’s mass formula.

INPUT:

  • p – a prime number > 0

OUTPUT: a rational number

EXAMPLES:

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
>>> from sage.all import *
>>> Q = DiagonalQuadraticForm(ZZ, range(Integer(1),Integer(8)))
>>> Q.conway_cross_product_doubled_power(Integer(2))
18
>>> Q.conway_cross_product_doubled_power(Integer(3))
10
>>> Q.conway_cross_product_doubled_power(Integer(5))
6
>>> Q.conway_cross_product_doubled_power(Integer(7))
6
>>> Q.conway_cross_product_doubled_power(Integer(11))
0
>>> Q.conway_cross_product_doubled_power(Integer(13))
0
conway_diagonal_factor(p)[source]

Compute the diagonal factor of Conway’s \(p\)-mass.

INPUT:

  • p – a prime number > 0

OUTPUT: a rational number > 0

EXAMPLES:

sage: Q = DiagonalQuadraticForm(ZZ, range(1,6))
sage: Q.conway_diagonal_factor(3)
81/256
>>> from sage.all import *
>>> Q = DiagonalQuadraticForm(ZZ, range(Integer(1),Integer(6)))
>>> Q.conway_diagonal_factor(Integer(3))
81/256
conway_mass()[source]

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()                                                           # needs sage.symbolic
1/48

sage: Q = DiagonalQuadraticForm(ZZ, [7,1,1])
sage: Q.conway_mass()                                                           # needs sage.symbolic
3/16

sage: Q = QuadraticForm(ZZ, 3, [7, 2, 2, 2, 0, 2]) + DiagonalQuadraticForm(ZZ, [1])
sage: Q.conway_mass()                                                           # needs sage.symbolic
3/32

sage: Q = QuadraticForm(Matrix(ZZ, 2, [2,1,1,2]))
sage: Q.conway_mass()                                                           # needs sage.symbolic
1/12
>>> from sage.all import *
>>> Q = DiagonalQuadraticForm(ZZ, [Integer(1),Integer(1),Integer(1)])
>>> Q.conway_mass()                                                           # needs sage.symbolic
1/48

>>> Q = DiagonalQuadraticForm(ZZ, [Integer(7),Integer(1),Integer(1)])
>>> Q.conway_mass()                                                           # needs sage.symbolic
3/16

>>> Q = QuadraticForm(ZZ, Integer(3), [Integer(7), Integer(2), Integer(2), Integer(2), Integer(0), Integer(2)]) + DiagonalQuadraticForm(ZZ, [Integer(1)])
>>> Q.conway_mass()                                                           # needs sage.symbolic
3/32

>>> Q = QuadraticForm(Matrix(ZZ, Integer(2), [Integer(2),Integer(1),Integer(1),Integer(2)]))
>>> Q.conway_mass()                                                           # needs sage.symbolic
1/12
conway_octane_of_this_unimodular_Jordan_block_at_2()[source]

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 \(\leq 2\) and the \(1 \times 1\) blocks are all in the upper leftmost position.

OUTPUT: integer \(0 \leq x \leq 7\)

EXAMPLES:

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
>>> from sage.all import *
>>> Q = DiagonalQuadraticForm(ZZ, [Integer(1),Integer(3),Integer(5),Integer(7)])
>>> Q.conway_octane_of_this_unimodular_Jordan_block_at_2()
0
>>> Q = DiagonalQuadraticForm(ZZ, [Integer(1),Integer(5),Integer(13)])
>>> Q.conway_octane_of_this_unimodular_Jordan_block_at_2()
3
>>> Q = DiagonalQuadraticForm(ZZ, [Integer(3),Integer(7),Integer(13)])
>>> Q.conway_octane_of_this_unimodular_Jordan_block_at_2()
7
conway_p_mass(p)[source]

Compute Conway’s \(p\)-mass.

INPUT:

  • p – a prime number > 0

OUTPUT: a rational number > 0

EXAMPLES:

sage: Q = DiagonalQuadraticForm(ZZ, range(1, 6))
sage: Q.conway_p_mass(2)
16/3
sage: Q.conway_p_mass(3)
729/256
>>> from sage.all import *
>>> Q = DiagonalQuadraticForm(ZZ, range(Integer(1), Integer(6)))
>>> Q.conway_p_mass(Integer(2))
16/3
>>> Q.conway_p_mass(Integer(3))
729/256
conway_species_list_at_2()[source]

Return an integer called the ‘species’ which determines the type of the orthogonal group over the finite field \(\GF{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 dimensional form is always 0+, so we interpret the return value of zero as positive here! =)

OUTPUT: list of integers

EXAMPLES:

sage: Q = DiagonalQuadraticForm(ZZ, range(1,10))
sage: Q.conway_species_list_at_2()
[1, 5, 1, 1, 1, 1]
>>> from sage.all import *
>>> Q = DiagonalQuadraticForm(ZZ, range(Integer(1),Integer(10)))
>>> 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]
>>> from sage.all import *
>>> Q = DiagonalQuadraticForm(ZZ, range(Integer(1),Integer(8)))
>>> Q.conway_species_list_at_2()
[1, 3, 1, 1, 1]
conway_species_list_at_odd_prime(p)[source]

Return an integer called the ‘species’ which determines the type of the orthogonal group over the finite field \(\GF{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 dimensional form is always 0+, so we interpret the return value of zero as positive here! =)

INPUT:

  • p – a positive prime number

OUTPUT: list of integers

EXAMPLES:

sage: Q = DiagonalQuadraticForm(ZZ, range(1,10))
sage: Q.conway_species_list_at_odd_prime(3)
[6, 2, 1]
>>> from sage.all import *
>>> Q = DiagonalQuadraticForm(ZZ, range(Integer(1),Integer(10)))
>>> Q.conway_species_list_at_odd_prime(Integer(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]
>>> from sage.all import *
>>> Q = DiagonalQuadraticForm(ZZ, range(Integer(1),Integer(8)))
>>> Q.conway_species_list_at_odd_prime(Integer(3))
[5, 2]
>>> Q.conway_species_list_at_odd_prime(Integer(5))
[-6, 1]
conway_standard_mass()[source]

Return the infinite product of the standard mass factors.

OUTPUT: a rational number > 0

EXAMPLES:

sage: Q = QuadraticForm(ZZ, 3, [2, -2, 0, 3, -5, 4])
sage: Q.conway_standard_mass()                                                  # needs sage.symbolic
1/6
>>> from sage.all import *
>>> Q = QuadraticForm(ZZ, Integer(3), [Integer(2), -Integer(2), Integer(0), Integer(3), -Integer(5), Integer(4)])
>>> Q.conway_standard_mass()                                                  # needs sage.symbolic
1/6

sage: Q = DiagonalQuadraticForm(ZZ, [1,1,1])
sage: Q.conway_standard_mass()                                                  # needs sage.symbolic
1/6
>>> from sage.all import *
>>> Q = DiagonalQuadraticForm(ZZ, [Integer(1),Integer(1),Integer(1)])
>>> Q.conway_standard_mass()                                                  # needs sage.symbolic
1/6
conway_standard_p_mass(p)[source]

Compute the standard (generic) Conway-Sloane \(p\)-mass.

INPUT:

  • p – a prime number > 0

OUTPUT: a rational number > 0

EXAMPLES:

sage: Q = DiagonalQuadraticForm(ZZ, [1,1,1])
sage: Q.conway_standard_p_mass(2)
2/3
>>> from sage.all import *
>>> Q = DiagonalQuadraticForm(ZZ, [Integer(1),Integer(1),Integer(1)])
>>> Q.conway_standard_p_mass(Integer(2))
2/3
conway_type_factor()[source]

This is a special factor only present in the mass formula when \(p=2\).

OUTPUT: a rational number

EXAMPLES:

sage: Q = DiagonalQuadraticForm(ZZ, range(1,8))
sage: Q.conway_type_factor()
4
>>> from sage.all import *
>>> Q = DiagonalQuadraticForm(ZZ, range(Integer(1),Integer(8)))
>>> Q.conway_type_factor()
4
count_congruence_solutions(p, k, m, zvec, nzvec)[source]

Count 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 – integer > 0

  • m – integer (depending only on mod \(p^k\))

  • zvec, nzvec – lists 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
>>> from sage.all import *
>>> Q = DiagonalQuadraticForm(ZZ, [Integer(1),Integer(2),Integer(3)])
>>> Q.count_congruence_solutions(Integer(3), Integer(1), Integer(0), None, None)
15
count_congruence_solutions__bad_type(p, k, m, zvec, nzvec)[source]

Count 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 – integer > 0

  • m – integer (depending only on mod \(p^k\))

  • zvec, nzvec – lists 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
>>> from sage.all import *
>>> Q = DiagonalQuadraticForm(ZZ, [Integer(1),Integer(2),Integer(3)])
>>> Q.count_congruence_solutions__bad_type(Integer(3), Integer(1), Integer(0), None, None)
2
count_congruence_solutions__bad_type_I(p, k, m, zvec, nzvec)[source]

Count 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 – integer > 0

  • m – integer (depending only on mod \(p^k\))

  • zvec, nzvec – lists 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
>>> from sage.all import *
>>> Q = DiagonalQuadraticForm(ZZ, [Integer(1),Integer(2),Integer(3)])
>>> Q.count_congruence_solutions__bad_type_I(Integer(3), Integer(1), Integer(0), None, None)
0
count_congruence_solutions__bad_type_II(p, k, m, zvec, nzvec)[source]

Count 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 – integer > 0

  • m – integer (depending only on mod \(p^k\))

  • zvec, nzvec – lists 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
>>> from sage.all import *
>>> Q = DiagonalQuadraticForm(ZZ, [Integer(1),Integer(2),Integer(3)])
>>> Q.count_congruence_solutions__bad_type_II(Integer(3), Integer(1), Integer(0), None, None)
2
count_congruence_solutions__good_type(p, k, m, zvec, nzvec)[source]

Count 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 – integer > 0

  • m – integer (depending only on mod \(p^k\))

  • zvec, nzvec – lists 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
>>> from sage.all import *
>>> Q = DiagonalQuadraticForm(ZZ, [Integer(1),Integer(2),Integer(3)])
>>> Q.count_congruence_solutions__good_type(Integer(3), Integer(1), Integer(0), None, None)
12
count_congruence_solutions__zero_type(p, k, m, zvec, nzvec)[source]

Count 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 – integer > 0

  • m – integer (depending only on mod \(p^k\))

  • zvec, nzvec – lists 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
>>> from sage.all import *
>>> Q = DiagonalQuadraticForm(ZZ, [Integer(1),Integer(2),Integer(3)])
>>> Q.count_congruence_solutions__zero_type(Integer(3), Integer(1), Integer(0), None, None)
1
count_congruence_solutions_as_vector(p, k, m, zvec, nzvec)[source]

Return 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:

  1. \(x_i = 0\) (mod \(p\)) for all \(i\) in zvec

  2. \(x_i \neq 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 – integer > 0

  • m – integer (depending only on mod \(p^k\))

  • zvec, nzvec – lists of integers in range(self.dim()), or None

OUTPUT:

a list of six integers \(\geq 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]
>>> from sage.all import *
>>> Q = DiagonalQuadraticForm(ZZ, [Integer(1),Integer(2),Integer(3)])
>>> Q.count_congruence_solutions_as_vector(Integer(3), Integer(1), Integer(1), [], [])
[0, 0, 0, 0, 0, 0]
>>> Q.count_congruence_solutions_as_vector(Integer(3), Integer(1), Integer(1), None, [])
[0, 0, 0, 0, 0, 0]
>>> Q.count_congruence_solutions_as_vector(Integer(3), Integer(1), Integer(1), [], None)
[6, 6, 0, 0, 0, 0]
>>> Q.count_congruence_solutions_as_vector(Integer(3), Integer(1), Integer(1), None, None)
[6, 6, 0, 0, 0, 0]
>>> Q.count_congruence_solutions_as_vector(Integer(3), Integer(1), Integer(2), None, None)
[6, 6, 0, 0, 0, 0]
>>> Q.count_congruence_solutions_as_vector(Integer(3), Integer(1), Integer(0), None, None)
[15, 12, 1, 2, 0, 2]
count_modp_solutions__by_Gauss_sum(p, m)[source]

Return the number of solutions of \(Q(x) = m\) (mod \(p\)) of a non-degenerate quadratic form over the finite field \(\ZZ/p\ZZ\), 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 – integer

OUTPUT: integer \(\geq 0\)

EXAMPLES:

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]
>>> from sage.all import *
>>> Q = DiagonalQuadraticForm(ZZ, [Integer(1),Integer(1),Integer(1)])
>>> [Q.count_modp_solutions__by_Gauss_sum(Integer(3), m)  for m in range(Integer(3))]
[9, 6, 12]

>>> Q = DiagonalQuadraticForm(ZZ, [Integer(1),Integer(1),Integer(2)])
>>> [Q.count_modp_solutions__by_Gauss_sum(Integer(3), m)  for m in range(Integer(3))]
[9, 12, 6]
delta()[source]

Return the omega of the adjoint form.

This is the same as the omega of the reciprocal form.

EXAMPLES:

sage: Q = DiagonalQuadraticForm(ZZ, [1,1,37])
sage: Q.delta()
148
>>> from sage.all import *
>>> Q = DiagonalQuadraticForm(ZZ, [Integer(1),Integer(1),Integer(37)])
>>> Q.delta()
148
det()[source]

Return the determinant of the Gram matrix of \(2\cdot 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
>>> from sage.all import *
>>> Q = QuadraticForm(ZZ, Integer(2), [Integer(1),Integer(2),Integer(3)])
>>> Q.det()
8
dim()[source]

Return 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
>>> from sage.all import *
>>> Q = QuadraticForm(ZZ, Integer(2), [Integer(1),Integer(2),Integer(3)])
>>> Q.dim()
2
>>> parent(Q.dim())
Integer Ring
>>> Q = QuadraticForm(Q.matrix())
>>> Q.dim()
2
>>> parent(Q.dim())
Integer Ring
disc()[source]

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
>>> from sage.all import *
>>> DiagonalQuadraticForm(ZZ, [Integer(1)]).disc()
1
>>> DiagonalQuadraticForm(ZZ, [Integer(1),Integer(1)]).disc()
-4
>>> DiagonalQuadraticForm(ZZ, [Integer(1),Integer(1),Integer(1)]).disc()
4
>>> DiagonalQuadraticForm(ZZ, [Integer(1),Integer(1),Integer(1),Integer(1)]).disc()
16
discrec()[source]

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]
>>> from sage.all import *
>>> Q = DiagonalQuadraticForm(ZZ, [Integer(1),Integer(1),Integer(37)])
>>> Q.disc()
148
>>> Q.discrec()
5476
>>> [Integer(4) * Integer(37), Integer(4) * Integer(37)**Integer(2)]
[148, 5476]
divide_variable(c, i, in_place=False)[source]

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 self.base_ring()

  • i – integer \(\geq 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 ]
>>> from sage.all import *
>>> Q = DiagonalQuadraticForm(ZZ, [Integer(1),Integer(9),Integer(5),Integer(7)])
>>> Q.divide_variable(Integer(3), Integer(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)[source]

Perform the substitution \(x_i \longmapsto x_i + c\cdot x_j\) (replacing the original form if the in_place flag is True).

INPUT:

  • c – an element of self.base_ring()

  • i, j – integers \(\geq 0\)

OUTPUT:

a QuadraticForm (by default, otherwise none)

EXAMPLES:

sage: Q = QuadraticForm(ZZ, 4, range(1,11)); 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 ]
>>> from sage.all import *
>>> Q = QuadraticForm(ZZ, Integer(4), range(Integer(1),Integer(11))); Q
Quadratic form in 4 variables over Integer Ring with coefficients:
[ 1 2 3 4 ]
[ * 5 6 7 ]
[ * * 8 9 ]
[ * * * 10 ]

>>> Q.elementary_substitution(c=Integer(1), i=Integer(0), j=Integer(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)); R
Quadratic form in 4 variables over Integer Ring with coefficients:
[ 1 2 3 4 ]
[ * 5 6 7 ]
[ * * 8 9 ]
[ * * * 10 ]
>>> from sage.all import *
>>> R = QuadraticForm(ZZ, Integer(4), range(Integer(1),Integer(11))); 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]); 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 ]
>>> from sage.all import *
>>> M = Matrix(ZZ, Integer(4), Integer(4), [Integer(1),Integer(0),Integer(0),Integer(1), Integer(0),Integer(1),Integer(0),Integer(0), Integer(0),Integer(0),Integer(1),Integer(0), Integer(0),Integer(0),Integer(0),Integer(1)]); M
[1 0 0 1]
[0 1 0 0]
[0 0 1 0]
[0 0 0 1]
>>> R(M)
Quadratic form in 4 variables over Integer Ring with coefficients:
[ 1 2 3 6 ]
[ * 5 6 9 ]
[ * * 8 12 ]
[ * * * 15 ]
extract_variables(QF, var_indices)[source]

Extract the variables (in order) whose indices are listed in var_indices, to give a new quadratic form.

INPUT:

  • var_indices – list of integers \(\geq 0\)

OUTPUT: a QuadraticForm

EXAMPLES:

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 ]
>>> from sage.all import *
>>> Q = QuadraticForm(ZZ, Integer(4), range(Integer(10))); Q
Quadratic form in 4 variables over Integer Ring with coefficients:
[ 0 1 2 3 ]
[ * 4 5 6 ]
[ * * 7 8 ]
[ * * * 9 ]
>>> Q.extract_variables([Integer(1),Integer(3)])
Quadratic form in 2 variables over Integer Ring with coefficients:
[ 4 6 ]
[ * 9 ]
find_entry_with_minimal_scale_at_prime(p)[source]

Find 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 > 0

OUTPUT: a pair of integers \(\geq 0\)

EXAMPLES:

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)
>>> from sage.all import *
>>> Q = QuadraticForm(ZZ, Integer(2), [Integer(6), Integer(2), Integer(20)]); Q
Quadratic form in 2 variables over Integer Ring with coefficients:
  [ 6 2 ]
  [ * 20 ]
>>> Q.find_entry_with_minimal_scale_at_prime(Integer(2))
(0, 1)
>>> Q.find_entry_with_minimal_scale_at_prime(Integer(3))
(1, 1)
>>> Q.find_entry_with_minimal_scale_at_prime(Integer(5))
(0, 0)
find_p_neighbor_from_vec(p, y, return_matrix=False)[source]

Return the \(p\)-neighbor of self defined by y.

Let \((L,q)\) be a lattice with \(b(L,L) \subseteq \ZZ\) which is maximal at \(p\). Let \(y \in L\) with \(b(y,y) \in p^2\ZZ\) then the \(p\)-neighbor of \(L\) at \(y\) is given by \(\ZZ y/p + L_y\) where \(L_y = \{x \in L | b(x,y) \in p \ZZ \}\) and \(b(x,y) = q(x+y)-q(x)-q(y)\) is the bilinear form associated to \(q\).

INPUT:

  • p – a prime number

  • y – a vector with \(q(y) \in p \ZZ\)

  • odd – boolean (default: False); if \(p=2\), return also odd neighbors

  • return_matrix – boolean (default: False); return the transformation matrix instead of the quadratic form

EXAMPLES:

sage: # needs sage.libs.pari
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:
[ 1 0 0 0 ]
[ * 1 4 4 ]
[ * * 5 12 ]
[ * * * 9 ]
sage: B = Q.find_p_neighbor_from_vec(3, v, return_matrix=True)
sage: Q(B) == X
True
>>> from sage.all import *
>>> # needs sage.libs.pari
>>> Q = DiagonalQuadraticForm(ZZ, [Integer(1),Integer(1),Integer(1),Integer(1)])
>>> v = vector([Integer(0),Integer(2),Integer(1),Integer(1)])
>>> X = Q.find_p_neighbor_from_vec(Integer(3), v); X
Quadratic form in 4 variables over Integer Ring with coefficients:
[ 1 0 0 0 ]
[ * 1 4 4 ]
[ * * 5 12 ]
[ * * * 9 ]
>>> B = Q.find_p_neighbor_from_vec(Integer(3), v, return_matrix=True)
>>> Q(B) == X
True

Since the base ring and the domain are not yet separate, for rational, half integral forms we just pretend the base ring is \(\ZZ\):

sage: # needs sage.libs.pari
sage: Q = QuadraticForm(QQ, matrix.diagonal([1,1,1,1]))
sage: v = vector([1,1,1,1])
sage: Q.find_p_neighbor_from_vec(2, v)
Quadratic form in 4 variables over Rational Field with coefficients:
[ 1/2 1 1 1 ]
[ * 1 1 2 ]
[ * * 1 2 ]
[ * * * 2 ]
>>> from sage.all import *
>>> # needs sage.libs.pari
>>> Q = QuadraticForm(QQ, matrix.diagonal([Integer(1),Integer(1),Integer(1),Integer(1)]))
>>> v = vector([Integer(1),Integer(1),Integer(1),Integer(1)])
>>> Q.find_p_neighbor_from_vec(Integer(2), v)
Quadratic form in 4 variables over Rational Field with coefficients:
[ 1/2 1 1 1 ]
[ * 1 1 2 ]
[ * * 1 2 ]
[ * * * 2 ]
find_primitive_p_divisible_vector__next(p, v=None)[source]

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.

Return vectors whose last nonzero 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
sage: v = Q.find_primitive_p_divisible_vector__next(2) ; v
(0, 1)
sage: v = Q.find_primitive_p_divisible_vector__next(2, v) ; v
(1, 0)
sage: Q = QuadraticForm(QQ, matrix.diagonal([1,1,1,1]))
sage: v = Q.find_primitive_p_divisible_vector__next(2)
sage: Q(v)
2
>>> from sage.all import *
>>> Q = QuadraticForm(ZZ, Integer(2), [Integer(10),Integer(1),Integer(4)])
>>> v = Q.find_primitive_p_divisible_vector__next(Integer(5)); v
(1, 1)
>>> v = Q.find_primitive_p_divisible_vector__next(Integer(5), v); v
(1, 0)
>>> v = Q.find_primitive_p_divisible_vector__next(Integer(5), v); v
>>> v = Q.find_primitive_p_divisible_vector__next(Integer(2)) ; v
(0, 1)
>>> v = Q.find_primitive_p_divisible_vector__next(Integer(2), v) ; v
(1, 0)
>>> Q = QuadraticForm(QQ, matrix.diagonal([Integer(1),Integer(1),Integer(1),Integer(1)]))
>>> v = Q.find_primitive_p_divisible_vector__next(Integer(2))
>>> Q(v)
2
find_primitive_p_divisible_vector__random(p)[source]

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.

EXAMPLES:

sage: Q = QuadraticForm(ZZ, 2, [10,1,4])
sage: v = Q.find_primitive_p_divisible_vector__random(5)
sage: tuple(v) in ((1, 0), (1, 1), (2, 0), (2, 2), (3, 0), (3, 3), (4, 0), (4, 4))
True
sage: 5.divides(Q(v))
True
sage: Q = QuadraticForm(QQ, matrix.diagonal([1,1,1,1]))
sage: v = Q.find_primitive_p_divisible_vector__random(2)
sage: Q(v)
2
>>> from sage.all import *
>>> Q = QuadraticForm(ZZ, Integer(2), [Integer(10),Integer(1),Integer(4)])
>>> v = Q.find_primitive_p_divisible_vector__random(Integer(5))
>>> tuple(v) in ((Integer(1), Integer(0)), (Integer(1), Integer(1)), (Integer(2), Integer(0)), (Integer(2), Integer(2)), (Integer(3), Integer(0)), (Integer(3), Integer(3)), (Integer(4), Integer(0)), (Integer(4), Integer(4)))
True
>>> Integer(5).divides(Q(v))
True
>>> Q = QuadraticForm(QQ, matrix.diagonal([Integer(1),Integer(1),Integer(1),Integer(1)]))
>>> v = Q.find_primitive_p_divisible_vector__random(Integer(2))
>>> Q(v)
2
static from_polynomial(poly)[source]

Construct a QuadraticForm from a multivariate polynomial. Inverse of polynomial().

EXAMPLES:

sage: R.<x,y,z> = ZZ[]
sage: f = 5*x^2 - x*z - 3*y*z - 2*y^2 + 9*z^2
sage: Q = QuadraticForm.from_polynomial(f); Q
Quadratic form in 3 variables over Integer Ring with coefficients:
[ 5 0 -1 ]
[ * -2 -3 ]
[ * * 9 ]
sage: Q.polynomial()
5*x0^2 - 2*x1^2 - x0*x2 - 3*x1*x2 + 9*x2^2
sage: Q.polynomial()(R.gens()) == f
True
>>> from sage.all import *
>>> R = ZZ['x, y, z']; (x, y, z,) = R._first_ngens(3)
>>> f = Integer(5)*x**Integer(2) - x*z - Integer(3)*y*z - Integer(2)*y**Integer(2) + Integer(9)*z**Integer(2)
>>> Q = QuadraticForm.from_polynomial(f); Q
Quadratic form in 3 variables over Integer Ring with coefficients:
[ 5 0 -1 ]
[ * -2 -3 ]
[ * * 9 ]
>>> Q.polynomial()
5*x0^2 - 2*x1^2 - x0*x2 - 3*x1*x2 + 9*x2^2
>>> Q.polynomial()(R.gens()) == f
True

The method fails if the given polynomial is not a quadratic form:

sage: QuadraticForm.from_polynomial(x^3 + x*z + 5*y^2)
Traceback (most recent call last):
...
ValueError: polynomial has monomials of degree != 2
>>> from sage.all import *
>>> QuadraticForm.from_polynomial(x**Integer(3) + x*z + Integer(5)*y**Integer(2))
Traceback (most recent call last):
...
ValueError: polynomial has monomials of degree != 2
gcd()[source]

Return 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
>>> from sage.all import *
>>> Q = QuadraticForm(ZZ, Integer(4), range(Integer(1), Integer(21), Integer(2)))
>>> Q.gcd()
1

>>> Q = QuadraticForm(ZZ, Integer(4), range(Integer(0), Integer(20), Integer(2)))
>>> Q.gcd()
2
static genera(sig_pair, determinant, max_scale=None, even=False)[source]

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 nonnegative integers giving the signature

  • determinant – integer; the sign is ignored

  • max_scale – (default: None) an integer; the maximum scale of a jordan block

  • even – 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]
>>> from sage.all import *
>>> QuadraticForm.genera((Integer(4),Integer(0)), Integer(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()[source]

Return the genus of two times a quadratic form over \(\ZZ\).

These are defined by a collection of local genus symbols (a la Chapter 15 of Conway-Sloane [CS1999]), 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
>>> from sage.all import *
>>> Q = DiagonalQuadraticForm(ZZ, [Integer(1),Integer(2),Integer(3),Integer(4)])
>>> 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
>>> from sage.all import *
>>> Q = QuadraticForm(ZZ, Integer(4), range(Integer(10)))
>>> 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)[source]

Determine if the given quadratic form has a Jordan decomposition equivalent to that of self.

INPUT:

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: # needs sage.libs.pari
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
>>> from sage.all import *
>>> Q1 = QuadraticForm(ZZ, Integer(3), [Integer(1), Integer(0), -Integer(1), Integer(1), Integer(0), Integer(3)])
>>> Q2 = QuadraticForm(ZZ, Integer(3), [Integer(1), Integer(0), Integer(0), Integer(2), -Integer(2), Integer(6)])
>>> Q3 = QuadraticForm(ZZ, Integer(3), [Integer(1), Integer(0), Integer(0), Integer(1), Integer(0), Integer(11)])
>>> [Q1.level(), Q2.level(), Q3.level()]
[44, 44, 44]

>>> # needs sage.libs.pari
>>> Q1.has_equivalent_Jordan_decomposition_at_prime(Q2, Integer(2))
False
>>> Q1.has_equivalent_Jordan_decomposition_at_prime(Q2, Integer(11))
False
>>> Q1.has_equivalent_Jordan_decomposition_at_prime(Q3, Integer(2))
False
>>> Q1.has_equivalent_Jordan_decomposition_at_prime(Q3, Integer(11))
True
>>> Q2.has_equivalent_Jordan_decomposition_at_prime(Q3, Integer(2))
True
>>> Q2.has_equivalent_Jordan_decomposition_at_prime(Q3, Integer(11))
False
has_integral_Gram_matrix()[source]

Return 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
>>> from sage.all import *
>>> Q = QuadraticForm(ZZ, Integer(2), [Integer(7),Integer(8),Integer(9)])
>>> Q.has_integral_Gram_matrix()
True

sage: Q = QuadraticForm(ZZ, 2, [4,5,6])
sage: Q.has_integral_Gram_matrix()
False
>>> from sage.all import *
>>> Q = QuadraticForm(ZZ, Integer(2), [Integer(4),Integer(5),Integer(6)])
>>> Q.has_integral_Gram_matrix()
False
hasse_conductor()[source]

Return the Hasse conductor.

This is the product of all primes where the Hasse invariant equals \(-1\).

EXAMPLES:

sage: # needs sage.libs.pari
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()                    # needs sage.libs.pari
1
sage: QuadraticForm(ZZ, 3, [2, -2, 0, 2, 0, 5]).hasse_conductor()               # needs sage.libs.pari
10
>>> from sage.all import *
>>> # needs sage.libs.pari
>>> Q = QuadraticForm(ZZ, Integer(3), [Integer(1), Integer(0), -Integer(1), Integer(2), -Integer(1), Integer(5)])
>>> Q.hasse_invariant(Integer(2))
-1
>>> Q.hasse_invariant(Integer(37))
-1
>>> Q.hasse_conductor()
74

>>> DiagonalQuadraticForm(ZZ, [Integer(1), Integer(1), Integer(1)]).hasse_conductor()                    # needs sage.libs.pari
1
>>> QuadraticForm(ZZ, Integer(3), [Integer(2), -Integer(2), Integer(0), Integer(2), Integer(0), Integer(5)]).hasse_conductor()               # needs sage.libs.pari
10
hasse_invariant(p)[source]

Compute 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 \(\QQ_p\) for this to make sense.

Warning

This is different from the O’Meara Hasse invariant, which allows \(i \leq j\) in the product. That is given by the method hasse_invariant__OMeara().

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)]                           # needs sage.libs.pari
[1, 1, 1, 1, 1, 1, 1, 1]
sage: [Q.hasse_invariant__OMeara(p) for p in prime_range(20)]                   # needs sage.libs.pari
[1, 1, 1, 1, 1, 1, 1, 1]
>>> from sage.all import *
>>> Q = QuadraticForm(ZZ, Integer(2), [Integer(1),Integer(2),Integer(3)])
>>> Q.rational_diagonal_form()
Quadratic form in 2 variables over Rational Field with coefficients:
[ 1 0 ]
[ * 2 ]
>>> [Q.hasse_invariant(p) for p in prime_range(Integer(20))]                           # needs sage.libs.pari
[1, 1, 1, 1, 1, 1, 1, 1]
>>> [Q.hasse_invariant__OMeara(p) for p in prime_range(Integer(20))]                   # needs sage.libs.pari
[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)]                           # needs sage.libs.pari
[1, 1, 1, 1, 1, 1, 1, 1]
sage: [Q.hasse_invariant__OMeara(p) for p in prime_range(20)]                   # needs sage.libs.pari
[-1, 1, 1, 1, 1, 1, 1, 1]
>>> from sage.all import *
>>> Q = DiagonalQuadraticForm(ZZ, [Integer(1),-Integer(1)])
>>> [Q.hasse_invariant(p) for p in prime_range(Integer(20))]                           # needs sage.libs.pari
[1, 1, 1, 1, 1, 1, 1, 1]
>>> [Q.hasse_invariant__OMeara(p) for p in prime_range(Integer(20))]                   # needs sage.libs.pari
[-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)]                           # needs sage.libs.pari
[1, 1, 1, 1, 1, 1, 1, 1]
sage: [Q.hasse_invariant__OMeara(p) for p in prime_range(20)]                   # needs sage.libs.pari
[-1, 1, 1, 1, 1, 1, 1, 1]
>>> from sage.all import *
>>> Q = DiagonalQuadraticForm(ZZ, [Integer(1),-Integer(1),Integer(5)])
>>> [Q.hasse_invariant(p) for p in prime_range(Integer(20))]                           # needs sage.libs.pari
[1, 1, 1, 1, 1, 1, 1, 1]
>>> [Q.hasse_invariant__OMeara(p) for p in prime_range(Integer(20))]                   # needs sage.libs.pari
[-1, 1, 1, 1, 1, 1, 1, 1]

sage: x = polygen(ZZ, 'x')
sage: K.<a> = NumberField(x^2 - 23)                                             # needs sage.rings.number_field
sage: Q = DiagonalQuadraticForm(K, [-a, a + 2])                                 # needs sage.rings.number_field
sage: [Q.hasse_invariant(p) for p in K.primes_above(19)]                        # needs sage.rings.number_field
[-1, 1]
>>> from sage.all import *
>>> x = polygen(ZZ, 'x')
>>> K = NumberField(x**Integer(2) - Integer(23), names=('a',)); (a,) = K._first_ngens(1)# needs sage.rings.number_field
>>> Q = DiagonalQuadraticForm(K, [-a, a + Integer(2)])                                 # needs sage.rings.number_field
>>> [Q.hasse_invariant(p) for p in K.primes_above(Integer(19))]                        # needs sage.rings.number_field
[-1, 1]
hasse_invariant__OMeara(p)[source]

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 \leq 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)]                           # needs sage.libs.pari
[1, 1, 1, 1, 1, 1, 1, 1]
sage: [Q.hasse_invariant__OMeara(p) for p in prime_range(20)]                   # needs sage.libs.pari
[1, 1, 1, 1, 1, 1, 1, 1]
>>> from sage.all import *
>>> Q = QuadraticForm(ZZ, Integer(2), [Integer(1),Integer(2),Integer(3)])
>>> Q.rational_diagonal_form()
Quadratic form in 2 variables over Rational Field with coefficients:
[ 1 0 ]
[ * 2 ]
>>> [Q.hasse_invariant(p) for p in prime_range(Integer(20))]                           # needs sage.libs.pari
[1, 1, 1, 1, 1, 1, 1, 1]
>>> [Q.hasse_invariant__OMeara(p) for p in prime_range(Integer(20))]                   # needs sage.libs.pari
[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)]                           # needs sage.libs.pari
[1, 1, 1, 1, 1, 1, 1, 1]
sage: [Q.hasse_invariant__OMeara(p) for p in prime_range(20)]                   # needs sage.libs.pari
[-1, 1, 1, 1, 1, 1, 1, 1]
>>> from sage.all import *
>>> Q = DiagonalQuadraticForm(ZZ, [Integer(1),-Integer(1)])
>>> [Q.hasse_invariant(p) for p in prime_range(Integer(20))]                           # needs sage.libs.pari
[1, 1, 1, 1, 1, 1, 1, 1]
>>> [Q.hasse_invariant__OMeara(p) for p in prime_range(Integer(20))]                   # needs sage.libs.pari
[-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)]                           # needs sage.libs.pari
[-1, 1, 1, 1, 1, 1, 1, 1]
sage: [Q.hasse_invariant__OMeara(p) for p in prime_range(20)]                   # needs sage.libs.pari
[-1, 1, 1, 1, 1, 1, 1, 1]
>>> from sage.all import *
>>> Q = DiagonalQuadraticForm(ZZ,[Integer(1),-Integer(1),-Integer(1)])
>>> [Q.hasse_invariant(p) for p in prime_range(Integer(20))]                           # needs sage.libs.pari
[-1, 1, 1, 1, 1, 1, 1, 1]
>>> [Q.hasse_invariant__OMeara(p) for p in prime_range(Integer(20))]                   # needs sage.libs.pari
[-1, 1, 1, 1, 1, 1, 1, 1]

sage: x = polygen(ZZ, 'x')
sage: K.<a> = NumberField(x^2 - 23)                                             # needs sage.rings.number_field
sage: Q = DiagonalQuadraticForm(K, [-a, a + 2])                                 # needs sage.rings.number_field
sage: [Q.hasse_invariant__OMeara(p) for p in K.primes_above(19)]                # needs sage.rings.number_field
[1, 1]
>>> from sage.all import *
>>> x = polygen(ZZ, 'x')
>>> K = NumberField(x**Integer(2) - Integer(23), names=('a',)); (a,) = K._first_ngens(1)# needs sage.rings.number_field
>>> Q = DiagonalQuadraticForm(K, [-a, a + Integer(2)])                                 # needs sage.rings.number_field
>>> [Q.hasse_invariant__OMeara(p) for p in K.primes_above(Integer(19))]                # needs sage.rings.number_field
[1, 1]
is_adjoint()[source]

Determine 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()                                                            # needs sage.symbolic
False
sage: Q.adjoint().is_adjoint()
True
>>> from sage.all import *
>>> Q = QuadraticForm(ZZ, Integer(3), [Integer(1), Integer(0), -Integer(1), Integer(2), -Integer(1), Integer(5)])
>>> Q.is_adjoint()                                                            # needs sage.symbolic
False
>>> Q.adjoint().is_adjoint()
True
is_anisotropic(p)[source]

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)                                                       # needs sage.libs.pari
True
sage: Q.is_anisotropic(3)                                                       # needs sage.libs.pari
True
sage: Q.is_anisotropic(5)                                                       # needs sage.libs.pari
False
>>> from sage.all import *
>>> Q = DiagonalQuadraticForm(ZZ, [Integer(1),Integer(1)])
>>> Q.is_anisotropic(Integer(2))                                                       # needs sage.libs.pari
True
>>> Q.is_anisotropic(Integer(3))                                                       # needs sage.libs.pari
True
>>> Q.is_anisotropic(Integer(5))                                                       # needs sage.libs.pari
False

sage: Q = DiagonalQuadraticForm(ZZ, [1,-1])
sage: Q.is_anisotropic(2)                                                       # needs sage.libs.pari
False
sage: Q.is_anisotropic(3)                                                       # needs sage.libs.pari
False
sage: Q.is_anisotropic(5)                                                       # needs sage.libs.pari
False
>>> from sage.all import *
>>> Q = DiagonalQuadraticForm(ZZ, [Integer(1),-Integer(1)])
>>> Q.is_anisotropic(Integer(2))                                                       # needs sage.libs.pari
False
>>> Q.is_anisotropic(Integer(3))                                                       # needs sage.libs.pari
False
>>> Q.is_anisotropic(Integer(5))                                                       # needs sage.libs.pari
False

sage: [DiagonalQuadraticForm(ZZ,                                                # needs sage.libs.pari
....:                        [1, -least_quadratic_nonresidue(p)]).is_anisotropic(p)
....:  for p in prime_range(3, 30)]
[True, True, True, True, True, True, True, True, True]
>>> from sage.all import *
>>> [DiagonalQuadraticForm(ZZ,                                                # needs sage.libs.pari
...                        [Integer(1), -least_quadratic_nonresidue(p)]).is_anisotropic(p)
...  for p in prime_range(Integer(3), Integer(30))]
[True, True, True, True, True, True, True, True, True]

sage: [DiagonalQuadraticForm(ZZ, [1, -least_quadratic_nonresidue(p),            # needs sage.libs.pari
....:                             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]
>>> from sage.all import *
>>> [DiagonalQuadraticForm(ZZ, [Integer(1), -least_quadratic_nonresidue(p),            # needs sage.libs.pari
...                             p, -p*least_quadratic_nonresidue(p)]).is_anisotropic(p)
...  for p in prime_range(Integer(3), Integer(30))]
[True, True, True, True, True, True, True, True, True]
is_definite()[source]

Determines if the given quadratic form is (positive or negative) definite.

Note

A degenerate form is considered neither definite nor indefinite.

Note

The zero-dimensional form is considered indefinite.

OUTPUT: boolean

EXAMPLES:

sage: Q = DiagonalQuadraticForm(ZZ, [-1,-3,-5])
sage: Q.is_definite()
True

sage: Q = DiagonalQuadraticForm(ZZ, [1,-3,5])
sage: Q.is_definite()
False
>>> from sage.all import *
>>> Q = DiagonalQuadraticForm(ZZ, [-Integer(1),-Integer(3),-Integer(5)])
>>> Q.is_definite()
True

>>> Q = DiagonalQuadraticForm(ZZ, [Integer(1),-Integer(3),Integer(5)])
>>> Q.is_definite()
False
is_even(allow_rescaling_flag=True)[source]

Return 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
>>> from sage.all import *
>>> Q = QuadraticForm(ZZ, Integer(2), [Integer(1), Integer(0), Integer(1)])
>>> Q.is_even()
False
>>> Q = QuadraticForm(ZZ, Integer(2), [Integer(1), Integer(1), Integer(1)])
>>> Q.is_even()
True
is_globally_equivalent_to(other, return_matrix=False)[source]

Determine 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 that self(M) == other.

INPUT:

  • self, other – positive definite integral quadratic forms

  • return_matrix – boolean (default: False); return the transformation matrix instead of a boolean

OUTPUT:

  • if return_matrix is False: a boolean

  • if return_matrix is True: either False 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)                                           # needs sage.libs.pari
True
sage: MM = Q.is_globally_equivalent_to(Q1, return_matrix=True)                  # needs sage.libs.pari
sage: Q(MM) == Q1                                                               # needs sage.libs.pari
True
>>> from sage.all import *
>>> Q = DiagonalQuadraticForm(ZZ, [Integer(1),Integer(1),Integer(1),Integer(1)])
>>> M = Matrix(ZZ, Integer(4), Integer(4), [Integer(1),Integer(2),Integer(0),Integer(0), Integer(0),Integer(1),Integer(0),Integer(0), Integer(0),Integer(0),Integer(1),Integer(0), Integer(0),Integer(0),Integer(0),Integer(1)])
>>> Q1 = Q(M)
>>> Q.is_globally_equivalent_to(Q1)                                           # needs sage.libs.pari
True
>>> MM = Q.is_globally_equivalent_to(Q1, return_matrix=True)                  # needs sage.libs.pari
>>> Q(MM) == Q1                                                               # needs sage.libs.pari
True

sage: # needs sage.libs.pari
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
>>> from sage.all import *
>>> # needs sage.libs.pari
>>> Q1 = QuadraticForm(ZZ, Integer(3), [Integer(1), Integer(0), -Integer(1), Integer(2), -Integer(1), Integer(5)])
>>> Q2 = QuadraticForm(ZZ, Integer(3), [Integer(2), Integer(1), Integer(2), Integer(2), Integer(1), Integer(3)])
>>> Q3 = QuadraticForm(ZZ, Integer(3), [Integer(8), Integer(6), Integer(5), Integer(3), Integer(4), Integer(2)])
>>> Q1.is_globally_equivalent_to(Q2)
False
>>> Q1.is_globally_equivalent_to(Q2, return_matrix=True)
False
>>> Q1.is_globally_equivalent_to(Q3)
True
>>> M = Q1.is_globally_equivalent_to(Q3, True); M
[-1 -1  0]
[ 1  1  1]
[-1  0  0]
>>> Q1(M) == Q3
True

sage: Q = DiagonalQuadraticForm(ZZ, [1, -1])
sage: Q.is_globally_equivalent_to(Q)                                            # needs sage.libs.pari
Traceback (most recent call last):
...
ValueError: not a definite form in QuadraticForm.is_globally_equivalent_to()
>>> from sage.all import *
>>> Q = DiagonalQuadraticForm(ZZ, [Integer(1), -Integer(1)])
>>> Q.is_globally_equivalent_to(Q)                                            # needs sage.libs.pari
Traceback (most recent call last):
...
ValueError: not a definite form in QuadraticForm.is_globally_equivalent_to()

ALGORITHM: this uses the PARI function pari:qfisom, implementing an algorithm by Plesken and Souvignier.

is_hyperbolic(p)[source]

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 criterion 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: # needs sage.libs.pari
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
>>> from sage.all import *
>>> # needs sage.libs.pari
>>> Q = DiagonalQuadraticForm(ZZ, [Integer(1),Integer(1)])
>>> Q.is_hyperbolic(-Integer(1))
False
>>> Q.is_hyperbolic(Integer(2))
False
>>> Q.is_hyperbolic(Integer(3))
False
>>> Q.is_hyperbolic(Integer(5))     # Here -1 is a square, so it's true.
True
>>> Q.is_hyperbolic(Integer(7))
False
>>> Q.is_hyperbolic(Integer(13))    # Here -1 is a square, so it's true.
True
is_indefinite()[source]

Determines if the given quadratic form is indefinite.

Note

A degenerate form is considered neither definite nor indefinite.

Note

The zero-dimensional form is not considered indefinite.

OUTPUT: boolean

EXAMPLES:

sage: Q = DiagonalQuadraticForm(ZZ, [-1,-3,-5])
sage: Q.is_indefinite()
False
>>> from sage.all import *
>>> Q = DiagonalQuadraticForm(ZZ, [-Integer(1),-Integer(3),-Integer(5)])
>>> Q.is_indefinite()
False

sage: Q = DiagonalQuadraticForm(ZZ, [1,-3,5])
sage: Q.is_indefinite()
True
>>> from sage.all import *
>>> Q = DiagonalQuadraticForm(ZZ, [Integer(1),-Integer(3),Integer(5)])
>>> Q.is_indefinite()
True
is_isotropic(p)[source]

Check if \(Q\) is isotropic 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_isotropic(2)                                                         # needs sage.libs.pari
False
sage: Q.is_isotropic(3)                                                         # needs sage.libs.pari
False
sage: Q.is_isotropic(5)                                                         # needs sage.libs.pari
True
>>> from sage.all import *
>>> Q = DiagonalQuadraticForm(ZZ, [Integer(1),Integer(1)])
>>> Q.is_isotropic(Integer(2))                                                         # needs sage.libs.pari
False
>>> Q.is_isotropic(Integer(3))                                                         # needs sage.libs.pari
False
>>> Q.is_isotropic(Integer(5))                                                         # needs sage.libs.pari
True

sage: Q = DiagonalQuadraticForm(ZZ, [1,-1])
sage: Q.is_isotropic(2)                                                         # needs sage.libs.pari
True
sage: Q.is_isotropic(3)                                                         # needs sage.libs.pari
True
sage: Q.is_isotropic(5)                                                         # needs sage.libs.pari
True
>>> from sage.all import *
>>> Q = DiagonalQuadraticForm(ZZ, [Integer(1),-Integer(1)])
>>> Q.is_isotropic(Integer(2))                                                         # needs sage.libs.pari
True
>>> Q.is_isotropic(Integer(3))                                                         # needs sage.libs.pari
True
>>> Q.is_isotropic(Integer(5))                                                         # needs sage.libs.pari
True

sage: [DiagonalQuadraticForm(ZZ,                                                # needs sage.libs.pari
....:                        [1, -least_quadratic_nonresidue(p)]).is_isotropic(p)
....:  for p in prime_range(3, 30)]
[False, False, False, False, False, False, False, False, False]
>>> from sage.all import *
>>> [DiagonalQuadraticForm(ZZ,                                                # needs sage.libs.pari
...                        [Integer(1), -least_quadratic_nonresidue(p)]).is_isotropic(p)
...  for p in prime_range(Integer(3), Integer(30))]
[False, False, False, False, False, False, False, False, False]

sage: [DiagonalQuadraticForm(ZZ, [1, -least_quadratic_nonresidue(p),            # needs sage.libs.pari
....:                             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]
>>> from sage.all import *
>>> [DiagonalQuadraticForm(ZZ, [Integer(1), -least_quadratic_nonresidue(p),            # needs sage.libs.pari
...                             p, -p*least_quadratic_nonresidue(p)]).is_isotropic(p)
...  for p in prime_range(Integer(3), Integer(30))]
[False, False, False, False, False, False, False, False, False]
is_locally_equivalent_to(other, check_primes_only=False, force_jordan_equivalence_test=False)[source]

Determine 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:

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)                                          # needs sage.libs.pari
False
sage: Q1.is_locally_equivalent_to(Q2)                                           # needs sage.libs.pari
True
>>> from sage.all import *
>>> Q1 = QuadraticForm(ZZ, Integer(3), [Integer(1), Integer(0), -Integer(1), Integer(2), -Integer(1), Integer(5)])
>>> Q2 = QuadraticForm(ZZ, Integer(3), [Integer(2), Integer(1), Integer(2), Integer(2), Integer(1), Integer(3)])
>>> Q1.is_globally_equivalent_to(Q2)                                          # needs sage.libs.pari
False
>>> Q1.is_locally_equivalent_to(Q2)                                           # needs sage.libs.pari
True
is_locally_represented_number(m)[source]

Determine if the rational number \(m\) is locally represented by the quadratic form.

INPUT:

  • m – integer

OUTPUT: boolean

EXAMPLES:

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
>>> from sage.all import *
>>> Q = DiagonalQuadraticForm(ZZ, [Integer(1),Integer(1),Integer(1)])
>>> Q.is_locally_represented_number(Integer(2))
True
>>> Q.is_locally_represented_number(Integer(7))
False
>>> Q.is_locally_represented_number(-Integer(1))
False
>>> Q.is_locally_represented_number(Integer(28))
False
>>> Q.is_locally_represented_number(Integer(0))
True
is_locally_represented_number_at_place(m, p)[source]

Determine if the rational number \(m\) is locally represented by the quadratic form at the (possibly infinite) prime \(p\).

INPUT:

  • m – integer

  • p – a prime number > 0 or ‘infinity’

OUTPUT: boolean

EXAMPLES:

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
>>> from sage.all import *
>>> Q = DiagonalQuadraticForm(ZZ, [Integer(1),Integer(1),Integer(1)])
>>> Q.is_locally_represented_number_at_place(Integer(7), infinity)
True
>>> Q.is_locally_represented_number_at_place(Integer(7), Integer(2))
False
>>> Q.is_locally_represented_number_at_place(Integer(7), Integer(3))
True
>>> Q.is_locally_represented_number_at_place(Integer(7), Integer(5))
True
>>> Q.is_locally_represented_number_at_place(-Integer(1), infinity)
False
>>> Q.is_locally_represented_number_at_place(-Integer(1), Integer(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
>>> from sage.all import *
>>> Q = DiagonalQuadraticForm(ZZ, [Integer(1),Integer(1),Integer(1),Integer(1),-Integer(1)])
>>> Q.is_locally_represented_number_at_place(Integer(7), infinity)     # long time (8.5 s)
True
>>> Q.is_locally_represented_number_at_place(Integer(7), Integer(2))            # long time
True
>>> Q.is_locally_represented_number_at_place(Integer(7), Integer(3))            # long time
True
>>> Q.is_locally_represented_number_at_place(Integer(7), Integer(5))            # long time
True
is_locally_universal_at_all_places()[source]

Determine if the quadratic form represents \(\ZZ_p\) for all finite/non-archimedean primes, and represents all real numbers.

OUTPUT: boolean

EXAMPLES:

sage: Q = DiagonalQuadraticForm(ZZ, [1,3,5,7])
sage: Q.is_locally_universal_at_all_places()
False
>>> from sage.all import *
>>> Q = DiagonalQuadraticForm(ZZ, [Integer(1),Integer(3),Integer(5),Integer(7)])
>>> 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
>>> from sage.all import *
>>> Q = DiagonalQuadraticForm(ZZ, [Integer(1),Integer(1),Integer(1),Integer(1)])
>>> 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
>>> from sage.all import *
>>> Q = DiagonalQuadraticForm(ZZ, [Integer(1),Integer(1),Integer(1),Integer(1),-Integer(1)])
>>> Q.is_locally_universal_at_all_places()        # long time (8.5 s)
True
is_locally_universal_at_all_primes()[source]

Determine if the quadratic form represents \(\ZZ_p\) for all finite/non-archimedean primes.

OUTPUT: boolean

EXAMPLES:

sage: Q = DiagonalQuadraticForm(ZZ, [1,3,5,7])
sage: Q.is_locally_universal_at_all_primes()
True
>>> from sage.all import *
>>> Q = DiagonalQuadraticForm(ZZ, [Integer(1),Integer(3),Integer(5),Integer(7)])
>>> 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
>>> from sage.all import *
>>> Q = DiagonalQuadraticForm(ZZ, [Integer(1),Integer(1),Integer(1),Integer(1)])
>>> Q.is_locally_universal_at_all_primes()
True

sage: Q = DiagonalQuadraticForm(ZZ, [1,1,1])
sage: Q.is_locally_universal_at_all_primes()
False
>>> from sage.all import *
>>> Q = DiagonalQuadraticForm(ZZ, [Integer(1),Integer(1),Integer(1)])
>>> Q.is_locally_universal_at_all_primes()
False
is_locally_universal_at_prime(p)[source]

Determine if the (integer-valued/rational) quadratic form represents all of \(\ZZ_p\).

INPUT:

  • p – a positive prime number or “infinity”

OUTPUT: boolean

EXAMPLES:

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
>>> from sage.all import *
>>> Q = DiagonalQuadraticForm(ZZ, [Integer(1),Integer(3),Integer(5),Integer(7)])
>>> Q.is_locally_universal_at_prime(Integer(2))
True
>>> Q.is_locally_universal_at_prime(Integer(3))
True
>>> Q.is_locally_universal_at_prime(Integer(5))
True
>>> 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
>>> from sage.all import *
>>> Q = DiagonalQuadraticForm(ZZ, [Integer(1),Integer(1),Integer(1)])
>>> Q.is_locally_universal_at_prime(Integer(2))
False
>>> Q.is_locally_universal_at_prime(Integer(3))
True
>>> Q.is_locally_universal_at_prime(Integer(5))
True
>>> Q.is_locally_universal_at_prime(infinity)
False

sage: Q = DiagonalQuadraticForm(ZZ, [1,1,-1])
sage: Q.is_locally_universal_at_prime(infinity)
True
>>> from sage.all import *
>>> Q = DiagonalQuadraticForm(ZZ, [Integer(1),Integer(1),-Integer(1)])
>>> Q.is_locally_universal_at_prime(infinity)
True
is_negative_definite()[source]

Determines if the given quadratic form is negative-definite.

Note

A degenerate form is considered neither definite nor indefinite.

Note

The zero-dimensional form is considered both positive definite and negative definite.

OUTPUT: boolean

EXAMPLES:

sage: Q = DiagonalQuadraticForm(ZZ, [-1,-3,-5])
sage: Q.is_negative_definite()
True
>>> from sage.all import *
>>> Q = DiagonalQuadraticForm(ZZ, [-Integer(1),-Integer(3),-Integer(5)])
>>> Q.is_negative_definite()
True

sage: Q = DiagonalQuadraticForm(ZZ, [1,-3,5])
sage: Q.is_negative_definite()
False
>>> from sage.all import *
>>> Q = DiagonalQuadraticForm(ZZ, [Integer(1),-Integer(3),Integer(5)])
>>> Q.is_negative_definite()
False
is_odd(allow_rescaling_flag=True)[source]

Return 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
>>> from sage.all import *
>>> Q = QuadraticForm(ZZ, Integer(2), [Integer(1), Integer(0), Integer(1)])
>>> Q.is_odd()
True
>>> Q = QuadraticForm(ZZ, Integer(2), [Integer(1), Integer(1), Integer(1)])
>>> Q.is_odd()
False
is_positive_definite()[source]

Determines if the given quadratic form is positive-definite.

Note

A degenerate form is considered neither definite nor indefinite.

Note

The zero-dimensional form is considered both positive definite and negative definite.

OUTPUT: boolean

EXAMPLES:

sage: Q = DiagonalQuadraticForm(ZZ, [1,3,5])
sage: Q.is_positive_definite()
True
>>> from sage.all import *
>>> Q = DiagonalQuadraticForm(ZZ, [Integer(1),Integer(3),Integer(5)])
>>> Q.is_positive_definite()
True

sage: Q = DiagonalQuadraticForm(ZZ, [1,-3,5])
sage: Q.is_positive_definite()
False
>>> from sage.all import *
>>> Q = DiagonalQuadraticForm(ZZ, [Integer(1),-Integer(3),Integer(5)])
>>> Q.is_positive_definite()
False
is_primitive()[source]

Determine if the given integer-valued form is primitive.

This means 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
>>> from sage.all import *
>>> Q = QuadraticForm(ZZ, Integer(2), [Integer(2),Integer(3),Integer(4)])
>>> Q.is_primitive()
True
>>> Q = QuadraticForm(ZZ, Integer(2), [Integer(2),Integer(4),Integer(8)])
>>> Q.is_primitive()
False
is_rationally_isometric(other, return_matrix=False)[source]

Determine if two regular quadratic forms over a number field are isometric.

INPUT:

  • other – a quadratic form over a number field

  • return_matrix – boolean (default: False); return the transformation matrix instead of a boolean; this is currently only implemented for forms over QQ

OUTPUT:

  • if return_matrix is False: a boolean

  • if return_matrix is True: either False or the transformation matrix

EXAMPLES:

sage: V = DiagonalQuadraticForm(QQ, [1, 1, 2])
sage: W = DiagonalQuadraticForm(QQ, [2, 2, 2])
sage: V.is_rationally_isometric(W)                                              # needs sage.libs.pari
True
>>> from sage.all import *
>>> V = DiagonalQuadraticForm(QQ, [Integer(1), Integer(1), Integer(2)])
>>> W = DiagonalQuadraticForm(QQ, [Integer(2), Integer(2), Integer(2)])
>>> V.is_rationally_isometric(W)                                              # needs sage.libs.pari
True

sage: # needs sage.rings.number_field
sage: x = polygen(ZZ, 'x')
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
>>> from sage.all import *
>>> # needs sage.rings.number_field
>>> x = polygen(ZZ, 'x')
>>> K = NumberField(x**Integer(2) - Integer(3), names=('a',)); (a,) = K._first_ngens(1)
>>> V = QuadraticForm(K, Integer(4), [Integer(1), Integer(0), Integer(0), Integer(0), Integer(2)*a, Integer(0), Integer(0), a, Integer(0), Integer(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 ]
>>> W = QuadraticForm(K, Integer(4), [Integer(1), Integer(2)*a, Integer(4), Integer(6), Integer(3), Integer(10), Integer(2), Integer(1), Integer(2), Integer(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 ]
>>> V.is_rationally_isometric(W)
False

sage: # needs sage.rings.number_field
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
>>> from sage.all import *
>>> # needs sage.rings.number_field
>>> K = NumberField(x**Integer(4) + Integer(2)*x + Integer(6), names=('a',)); (a,) = K._first_ngens(1)
>>> V = DiagonalQuadraticForm(K, [a, Integer(2), Integer(3), Integer(2), Integer(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 ]
>>> W = DiagonalQuadraticForm(K, [a, a, a, Integer(2), Integer(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 ]
>>> V.is_rationally_isometric(W)
False

sage: # needs sage.rings.number_field
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

sage: # needs sage.rings.number_field
sage: V = DiagonalQuadraticForm(QQ, [1, 1, 2])
sage: W = DiagonalQuadraticForm(QQ, [2, 2, 2])
sage: T = V.is_rationally_isometric(W, True); T
[   0    0    1]
[-1/2 -1/2    0]
[ 1/2 -1/2    0]
sage: V.Gram_matrix() == T.transpose() * W.Gram_matrix() * T
True

sage: T = W.is_rationally_isometric(V, True); T                                 # needs sage.rings.number_field
[ 0 -1  1]
[ 0 -1 -1]
[ 1  0  0]
sage: W.Gram_matrix() == T.T * V.Gram_matrix() * T                              # needs sage.rings.number_field
True
>>> from sage.all import *
>>> # needs sage.rings.number_field
>>> K = NumberField(x**Integer(2) - Integer(3), names=('a',)); (a,) = K._first_ngens(1)
>>> V = DiagonalQuadraticForm(K, [-Integer(1), a, -Integer(2)*a])
>>> W = DiagonalQuadraticForm(K, [-Integer(1), -a, Integer(2)*a])
>>> V.is_rationally_isometric(W)
True

>>> # needs sage.rings.number_field
>>> V = DiagonalQuadraticForm(QQ, [Integer(1), Integer(1), Integer(2)])
>>> W = DiagonalQuadraticForm(QQ, [Integer(2), Integer(2), Integer(2)])
>>> T = V.is_rationally_isometric(W, True); T
[   0    0    1]
[-1/2 -1/2    0]
[ 1/2 -1/2    0]
>>> V.Gram_matrix() == T.transpose() * W.Gram_matrix() * T
True

>>> T = W.is_rationally_isometric(V, True); T                                 # needs sage.rings.number_field
[ 0 -1  1]
[ 0 -1 -1]
[ 1  0  0]
>>> W.Gram_matrix() == T.T * V.Gram_matrix() * T                              # needs sage.rings.number_field
True

sage: L = QuadraticForm(QQ, 3, [2, 2, 0, 2, 2, 5])
sage: M = QuadraticForm(QQ, 3, [2, 2, 0, 3, 2, 3])
sage: L.is_rationally_isometric(M, True)                                        # needs sage.libs.pari
False
>>> from sage.all import *
>>> L = QuadraticForm(QQ, Integer(3), [Integer(2), Integer(2), Integer(0), Integer(2), Integer(2), Integer(5)])
>>> M = QuadraticForm(QQ, Integer(3), [Integer(2), Integer(2), Integer(0), Integer(3), Integer(2), Integer(3)])
>>> L.is_rationally_isometric(M, True)                                        # needs sage.libs.pari
False

sage: A = DiagonalQuadraticForm(QQ, [1, 5])
sage: B = QuadraticForm(QQ, 2, [1, 12, 81])
sage: T = A.is_rationally_isometric(B, True); T                                 # needs sage.libs.pari
[  1  -2]
[  0 1/3]
sage: A.Gram_matrix() == T.T * B.Gram_matrix() * T                              # needs sage.libs.pari
True
>>> from sage.all import *
>>> A = DiagonalQuadraticForm(QQ, [Integer(1), Integer(5)])
>>> B = QuadraticForm(QQ, Integer(2), [Integer(1), Integer(12), Integer(81)])
>>> T = A.is_rationally_isometric(B, True); T                                 # needs sage.libs.pari
[  1  -2]
[  0 1/3]
>>> A.Gram_matrix() == T.T * B.Gram_matrix() * T                              # needs sage.libs.pari
True

sage: C = DiagonalQuadraticForm(QQ, [1, 5, 9])
sage: D = DiagonalQuadraticForm(QQ, [6, 30, 1])
sage: T = C.is_rationally_isometric(D, True); T                                 # needs sage.libs.pari
[   0 -5/6  1/2]
[   0  1/6  1/2]
[  -1    0    0]
sage: C.Gram_matrix() == T.T * D.Gram_matrix() * T                              # needs sage.libs.pari
True
>>> from sage.all import *
>>> C = DiagonalQuadraticForm(QQ, [Integer(1), Integer(5), Integer(9)])
>>> D = DiagonalQuadraticForm(QQ, [Integer(6), Integer(30), Integer(1)])
>>> T = C.is_rationally_isometric(D, True); T                                 # needs sage.libs.pari
[   0 -5/6  1/2]
[   0  1/6  1/2]
[  -1    0    0]
>>> C.Gram_matrix() == T.T * D.Gram_matrix() * T                              # needs sage.libs.pari
True

sage: E = DiagonalQuadraticForm(QQ, [1, 1])
sage: F = QuadraticForm(QQ, 2, [17, 94, 130])
sage: T = F.is_rationally_isometric(E, True); T                                 # needs sage.libs.pari
[     -4 -189/17]
[     -1  -43/17]
sage: F.Gram_matrix() == T.T * E.Gram_matrix() * T                              # needs sage.libs.pari
True
>>> from sage.all import *
>>> E = DiagonalQuadraticForm(QQ, [Integer(1), Integer(1)])
>>> F = QuadraticForm(QQ, Integer(2), [Integer(17), Integer(94), Integer(130)])
>>> T = F.is_rationally_isometric(E, True); T                                 # needs sage.libs.pari
[     -4 -189/17]
[     -1  -43/17]
>>> F.Gram_matrix() == T.T * E.Gram_matrix() * T                              # needs sage.libs.pari
True
is_zero(v, p=0)[source]

Determine 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
>>> from sage.all import *
>>> Q1 = QuadraticForm(ZZ, Integer(3), [Integer(1), Integer(0), -Integer(1), Integer(2), -Integer(1), Integer(5)])
>>> Q1.is_zero([Integer(0),Integer(1),Integer(0)], Integer(2))
True
>>> Q1.is_zero([Integer(1),Integer(1),Integer(1)], Integer(2))
True
>>> Q1.is_zero([Integer(1),Integer(1),Integer(0)], Integer(2))
False
is_zero_nonsingular(v, p=0)[source]

Determine 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
>>> from sage.all import *
>>> Q1 = QuadraticForm(ZZ, Integer(3), [Integer(1), Integer(0), -Integer(1), Integer(2), -Integer(1), Integer(5)])
>>> Q1.is_zero_nonsingular([Integer(1),Integer(1),Integer(1)], Integer(2))
True
>>> Q1.is_zero([Integer(1), Integer(19), Integer(2)], Integer(37))
True
>>> Q1.is_zero_nonsingular([Integer(1), Integer(19), Integer(2)], Integer(37))
False
is_zero_singular(v, p=0)[source]

Determine 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
>>> from sage.all import *
>>> Q1 = QuadraticForm(ZZ, Integer(3), [Integer(1), Integer(0), -Integer(1), Integer(2), -Integer(1), Integer(5)])
>>> Q1.is_zero([Integer(1),Integer(1),Integer(1)], Integer(2))
True
>>> Q1.is_zero_singular([Integer(1),Integer(1),Integer(1)], Integer(2))
False
>>> Q1.is_zero_singular([Integer(1), Integer(19), Integer(2)], Integer(37))
True
jordan_blocks_by_scale_and_unimodular(p, safe_flag=True)[source]

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 \(2 \times 2\) blocks are listed after the \(1 \times 1\) 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 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:

  • 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 ])]
>>> from sage.all import *
>>> Q = DiagonalQuadraticForm(ZZ, [Integer(1),Integer(9),Integer(5),Integer(7)])
>>> Q.jordan_blocks_by_scale_and_unimodular(Integer(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 ])]
>>> from sage.all import *
>>> Q2 = QuadraticForm(ZZ, Integer(2), [Integer(1),Integer(1),Integer(1)])
>>> Q2.jordan_blocks_by_scale_and_unimodular(Integer(2))
[(-1, Quadratic form in 2 variables over Integer Ring with coefficients:
        [ 2 2 ]
        [ * 2 ])]
>>> Q = Q2 + Q2.scale_by_factor(Integer(2))
>>> Q.jordan_blocks_by_scale_and_unimodular(Integer(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)[source]

Return 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 > 0

OUTPUT: list of \(p\)-unimodular quadratic forms

EXAMPLES:

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: the given quadratic form has a Jordan component with a negative scale exponent

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 ]]
>>> from sage.all import *
>>> Q = QuadraticForm(ZZ, Integer(3), [Integer(2), -Integer(2), Integer(0), Integer(3), -Integer(5), Integer(4)])
>>> Q.jordan_blocks_in_unimodular_list_by_scale_power(Integer(2))
Traceback (most recent call last):
...
TypeError: the given quadratic form has a Jordan component with a negative scale exponent

>>> Q.scale_by_factor(Integer(2)).jordan_blocks_in_unimodular_list_by_scale_power(Integer(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 ]]

>>> Q.jordan_blocks_in_unimodular_list_by_scale_power(Integer(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()[source]

Determines the level of the quadratic form over a PID, which is a generator for the smallest ideal \(N\) of \(R\) such that \(N\cdot (\) the matrix of \(2*Q\) \()^{(-1)}\) is in \(R\) with diagonal in \(2R\).

Over \(\ZZ\) this returns a nonnegative 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
>>> from sage.all import *
>>> Q = QuadraticForm(ZZ, Integer(2), range(Integer(1),Integer(4)))
>>> Q.level()
8

>>> Q1 = QuadraticForm(QQ, Integer(2), range(Integer(1),Integer(4)))
>>> 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

>>> Q = DiagonalQuadraticForm(ZZ, [Integer(1),Integer(3),Integer(5),Integer(7)])
>>> Q.level()
420
level__Tornaria()[source]

Return the level of the quadratic form.

This is defined as

  • level(\(B\)) for even dimension,

  • level(\(B\))/4 for odd dimension,

where \(2Q(x) = x^t\cdot B\cdot 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
>>> from sage.all import *
>>> DiagonalQuadraticForm(ZZ, [Integer(1)]).level__Tornaria()
1
>>> DiagonalQuadraticForm(ZZ, [Integer(1),Integer(1)]).level__Tornaria()
4
>>> DiagonalQuadraticForm(ZZ, [Integer(1),Integer(1),Integer(1)]).level__Tornaria()
1
>>> DiagonalQuadraticForm(ZZ, [Integer(1),Integer(1),Integer(1),Integer(1)]).level__Tornaria()
4
level_ideal()[source]

Determine the level of the quadratic form (over \(R\)), which is the smallest ideal \(N\) of \(R\) such that \(N \cdot (\) the matrix of \(2Q\) \()^{(-1)}\) is in \(R\) with diagonal in \(2R\). (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
>>> from sage.all import *
>>> Q = QuadraticForm(ZZ, Integer(2), range(Integer(1),Integer(4)))
>>> Q.level_ideal()
Principal ideal (8) of Integer Ring

>>> Q1 = QuadraticForm(QQ, Integer(2), range(Integer(1),Integer(4)))
>>> Q1.level_ideal()
Principal ideal (1) of Rational Field

>>> Q = DiagonalQuadraticForm(ZZ, [Integer(1),Integer(3),Integer(5),Integer(7)])
>>> Q.level_ideal()
Principal ideal (420) of Integer Ring
list_external_initializations()[source]

Return 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: # needs sage.libs.pari
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()
[]
>>> from sage.all import *
>>> Q = QuadraticForm(ZZ, Integer(2), [Integer(1),Integer(0),Integer(5)])
>>> Q.list_external_initializations()
[]

>>> # needs sage.libs.pari
>>> T = Q.theta_series()
>>> Q.list_external_initializations()
[]
>>> Q = QuadraticForm(ZZ, Integer(2), [Integer(1),Integer(0),Integer(5)], unsafe_initialization=False,
...                   number_of_automorphisms=Integer(3), determinant=Integer(0))
>>> Q.list_external_initializations()
[]

sage: # needs sage.libs.pari
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']
>>> from sage.all import *
>>> # needs sage.libs.pari
>>> Q = QuadraticForm(ZZ, Integer(2), [Integer(1),Integer(0),Integer(5)], unsafe_initialization=False,
...                   number_of_automorphisms=Integer(3), determinant=Integer(0))
>>> Q.list_external_initializations()
[]
>>> Q = QuadraticForm(ZZ, Integer(2), [Integer(1),Integer(0),Integer(5)], unsafe_initialization=True,
...                   number_of_automorphisms=Integer(3), determinant=Integer(0))
>>> Q.list_external_initializations()
['number_of_automorphisms', 'determinant']
lll()[source]

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()                                                                   # needs sage.libs.pari
Quadratic form in 4 variables over Integer Ring with coefficients:
[ 1 0 1 0 ]
[ * 4 3 3 ]
[ * * 6 3 ]
[ * * * 6 ]
>>> from sage.all import *
>>> Q = QuadraticForm(ZZ, Integer(4), range(Integer(1),Integer(11)))
>>> Q.is_definite()
True
>>> Q.lll()                                                                   # needs sage.libs.pari
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)[source]

Find 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:

  • self – quadratic form \(Q\), assumed to be block diagonal and \(p\)-integral

  • p – a prime number

  • m – integer

  • Zvec, NZvec – non-repeating lists of integers in range(self.dim()) or None

OUTPUT: a rational number

EXAMPLES:

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
>>> from sage.all import *
>>> Q = DiagonalQuadraticForm(ZZ, [Integer(1),Integer(2),Integer(3)])
>>> Q.local_badII_density_congruence(Integer(2), Integer(1), None, None)
0
>>> Q.local_badII_density_congruence(Integer(2), Integer(2), None, None)
0
>>> Q.local_badII_density_congruence(Integer(2), Integer(4), None, None)
0
>>> Q.local_badII_density_congruence(Integer(3), Integer(1), None, None)
0
>>> Q.local_badII_density_congruence(Integer(3), Integer(6), None, None)
0
>>> Q.local_badII_density_congruence(Integer(3), Integer(9), None, None)
0
>>> Q.local_badII_density_congruence(Integer(3), Integer(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
>>> from sage.all import *
>>> Q = DiagonalQuadraticForm(ZZ, [Integer(1),Integer(3),Integer(3),Integer(9),Integer(9)])
>>> Q.local_badII_density_congruence(Integer(3), Integer(1), None, None)
0
>>> Q.local_badII_density_congruence(Integer(3), Integer(3), None, None)
0
>>> Q.local_badII_density_congruence(Integer(3), Integer(6), None, None)
0
>>> Q.local_badII_density_congruence(Integer(3), Integer(9), None, None)
4/27
>>> Q.local_badII_density_congruence(Integer(3), Integer(18), None, None)
4/9
local_badI_density_congruence(p, m, Zvec=None, NZvec=None)[source]

Find 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:

  • self – quadratic form \(Q\), assumed to be block diagonal and \(p\)-integral

  • p – a prime number

  • m – integer

  • Zvec, NZvec – non-repeating lists of integers in range(self.dim()) or None

OUTPUT: a rational number

EXAMPLES:

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
>>> from sage.all import *
>>> Q = DiagonalQuadraticForm(ZZ, [Integer(1),Integer(2),Integer(3)])
>>> Q.local_badI_density_congruence(Integer(2), Integer(1), None, None)
0
>>> Q.local_badI_density_congruence(Integer(2), Integer(2), None, None)
1
>>> Q.local_badI_density_congruence(Integer(2), Integer(4), None, None)
0
>>> Q.local_badI_density_congruence(Integer(3), Integer(1), None, None)
0
>>> Q.local_badI_density_congruence(Integer(3), Integer(6), None, None)
0
>>> Q.local_badI_density_congruence(Integer(3), Integer(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
>>> from sage.all import *
>>> Q = DiagonalQuadraticForm(ZZ, [Integer(1),Integer(1),Integer(1),Integer(1)])
>>> Q.local_badI_density_congruence(Integer(2), Integer(1), None, None)
0
>>> Q.local_badI_density_congruence(Integer(2), Integer(2), None, None)
0
>>> Q.local_badI_density_congruence(Integer(2), Integer(4), None, None)
0
>>> Q.local_badI_density_congruence(Integer(3), Integer(2), None, None)
0
>>> Q.local_badI_density_congruence(Integer(3), Integer(6), None, None)
0
>>> Q.local_badI_density_congruence(Integer(3), Integer(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
>>> from sage.all import *
>>> Q = DiagonalQuadraticForm(ZZ, [Integer(1),Integer(3),Integer(3),Integer(9)])
>>> Q.local_badI_density_congruence(Integer(3), Integer(1), None, None)
0
>>> Q.local_badI_density_congruence(Integer(3), Integer(3), None, None)
4/3
>>> Q.local_badI_density_congruence(Integer(3), Integer(6), None, None)
4/3
>>> Q.local_badI_density_congruence(Integer(3), Integer(9), None, None)
0
>>> Q.local_badI_density_congruence(Integer(3), Integer(18), None, None)
0
local_bad_density_congruence(p, m, Zvec=None, NZvec=None)[source]

Find the Bad-type local density of \(Q\) representing \(m\) at \(p\), allowing certain congruence conditions mod \(p\).

INPUT:

  • self – quadratic form \(Q\), assumed to be block diagonal and \(p\)-integral

  • p – a prime number

  • m – integer

  • Zvec, NZvec – non-repeating lists of integers in range(self.dim()) or None

OUTPUT: a rational number

EXAMPLES:

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
>>> from sage.all import *
>>> Q = DiagonalQuadraticForm(ZZ, [Integer(1),Integer(2),Integer(3)])
>>> Q.local_bad_density_congruence(Integer(2), Integer(1), None, None)
0
>>> Q.local_bad_density_congruence(Integer(2), Integer(2), None, None)
1
>>> Q.local_bad_density_congruence(Integer(2), Integer(4), None, None)
0
>>> Q.local_bad_density_congruence(Integer(3), Integer(1), None, None)
0
>>> Q.local_bad_density_congruence(Integer(3), Integer(6), None, None)
0
>>> Q.local_bad_density_congruence(Integer(3), Integer(9), None, None)
0
>>> Q.local_bad_density_congruence(Integer(3), Integer(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
>>> from sage.all import *
>>> Q = DiagonalQuadraticForm(ZZ, [Integer(1),Integer(3),Integer(3),Integer(9),Integer(9)])
>>> Q.local_bad_density_congruence(Integer(3), Integer(1), None, None)
0
>>> Q.local_bad_density_congruence(Integer(3), Integer(3), None, None)
4/3
>>> Q.local_bad_density_congruence(Integer(3), Integer(6), None, None)
4/3
>>> Q.local_bad_density_congruence(Integer(3), Integer(9), None, None)
4/27
>>> Q.local_bad_density_congruence(Integer(3), Integer(18), None, None)
4/9
>>> Q.local_bad_density_congruence(Integer(3), Integer(27), None, None)
8/27
local_density(p, m)[source]

Return the local density.

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 – integer

OUTPUT: a rational number

EXAMPLES:

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
>>> from sage.all import *
>>> Q = DiagonalQuadraticForm(ZZ, [Integer(1),Integer(1),Integer(1),Integer(1)])   # NOTE: This is already in local normal form for *all* primes p!
>>> Q.local_density(p=Integer(2), m=Integer(1))
1
>>> Q.local_density(p=Integer(3), m=Integer(1))
8/9
>>> Q.local_density(p=Integer(5), m=Integer(1))
24/25
>>> Q.local_density(p=Integer(7), m=Integer(1))
48/49
>>> Q.local_density(p=Integer(11), m=Integer(1))
120/121
local_density_congruence(p, m, Zvec=None, NZvec=None)[source]

Find the local density of \(Q\) representing \(m\) at \(p\), allowing certain congruence conditions mod \(p\).

INPUT:

  • self – quadratic form \(Q\), assumed to be block diagonal and \(p\)-integral

  • p – a prime number

  • m – integer

  • Zvec, NZvec – non-repeating lists of integers in range(self.dim()) or None

OUTPUT: a rational number

EXAMPLES:

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
>>> from sage.all import *
>>> Q = DiagonalQuadraticForm(ZZ, [Integer(1),Integer(1),Integer(1),Integer(1)])
>>> Q.local_density_congruence(p=Integer(2), m=Integer(1), Zvec=None, NZvec=None)
1
>>> Q.local_density_congruence(p=Integer(3), m=Integer(1), Zvec=None, NZvec=None)
8/9
>>> Q.local_density_congruence(p=Integer(5), m=Integer(1), Zvec=None, NZvec=None)
24/25
>>> Q.local_density_congruence(p=Integer(7), m=Integer(1), Zvec=None, NZvec=None)
48/49
>>> Q.local_density_congruence(p=Integer(11), m=Integer(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
>>> from sage.all import *
>>> Q = DiagonalQuadraticForm(ZZ, [Integer(1),Integer(2),Integer(3)])
>>> Q.local_density_congruence(Integer(2), Integer(1), None, None)
1
>>> Q.local_density_congruence(Integer(2), Integer(2), None, None)
1
>>> Q.local_density_congruence(Integer(2), Integer(4), None, None)
3/2
>>> Q.local_density_congruence(Integer(3), Integer(1), None, None)
2/3
>>> Q.local_density_congruence(Integer(3), Integer(6), None, None)
4/3
>>> Q.local_density_congruence(Integer(3), Integer(9), None, None)
14/9
>>> Q.local_density_congruence(Integer(3), Integer(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
>>> from sage.all import *
>>> Q = DiagonalQuadraticForm(ZZ, [Integer(1),Integer(3),Integer(3),Integer(9),Integer(9)])
>>> Q.local_density_congruence(Integer(3), Integer(1), None, None)
2
>>> Q.local_density_congruence(Integer(3), Integer(3), None, None)
4/3
>>> Q.local_density_congruence(Integer(3), Integer(6), None, None)
4/3
>>> Q.local_density_congruence(Integer(3), Integer(9), None, None)
2/9
>>> Q.local_density_congruence(Integer(3), Integer(18), None, None)
4/9
local_genus_symbol(p)[source]

Return the Conway-Sloane genus symbol of 2 times a quadratic form defined over \(\ZZ\) at a prime number \(p\).

This is defined (in the class Genus_Symbol_p_adic_ring) to be a list of tuples (one for each Jordan component \(p^m\cdot 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 \(\ZZ/8\ZZ\) = 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) [CS1999] for a discussion of this convention.

INPUT:

  • p – a prime number > 0

OUTPUT:

a Conway-Sloane genus symbol at \(p\), which is an instance of the class Genus_Symbol_p_adic_ring.

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
>>> from sage.all import *
>>> Q = DiagonalQuadraticForm(ZZ, [Integer(1),Integer(2),Integer(3),Integer(4)])
>>> Q.local_genus_symbol(Integer(2))
Genus symbol at 2:    [2^-2 4^1 8^1]_6
>>> Q.local_genus_symbol(Integer(3))
Genus symbol at 3:     1^3 3^-1
>>> Q.local_genus_symbol(Integer(5))
Genus symbol at 5:     1^4
local_good_density_congruence(p, m, Zvec=None, NZvec=None)[source]

Find the Good-type local density of \(Q\) representing \(m\) at \(p\). (Front end routine for parity specific routines for \(p\).)

Todo

Add documentation about the additional congruence conditions Zvec and NZvec.

INPUT:

  • self – quadratic form \(Q\), assumed to be block diagonal and \(p\)-integral

  • p – a prime number

  • m – integer

  • Zvec, NZvec – non-repeating lists of integers in range(self.dim()) or None

OUTPUT: a rational number

EXAMPLES:

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
>>> from sage.all import *
>>> Q = DiagonalQuadraticForm(ZZ, [Integer(1),Integer(2),Integer(3)])
>>> Q.local_good_density_congruence(Integer(2), Integer(1), None, None)
1
>>> Q.local_good_density_congruence(Integer(3), Integer(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
>>> from sage.all import *
>>> Q = DiagonalQuadraticForm(ZZ, [Integer(1),Integer(1),Integer(1),Integer(1)])
>>> Q.local_good_density_congruence(Integer(2), Integer(1), None, None)
1
>>> Q.local_good_density_congruence(Integer(3), Integer(1), None, None)
8/9
local_good_density_congruence_even(m, Zvec, NZvec)[source]

Find 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 \(1 \times 1\), and so there the indices and Jordan blocks coincide.

Todo

Add type checking for Zvec and NZvec, and that \(Q\) is in local normal form.

INPUT:

  • self – quadratic form \(Q\), assumed to be block diagonal and 2-integral

  • p – a prime number

  • m – integer

  • Zvec, NZvec – non-repeating lists of integers in range(self.dim()) or None

OUTPUT: a rational number

EXAMPLES:

sage: Q = DiagonalQuadraticForm(ZZ, [1,2,3])
sage: Q.local_good_density_congruence_even(1, None, None)
1
>>> from sage.all import *
>>> Q = DiagonalQuadraticForm(ZZ, [Integer(1),Integer(2),Integer(3)])
>>> Q.local_good_density_congruence_even(Integer(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
>>> from sage.all import *
>>> Q = DiagonalQuadraticForm(ZZ, [Integer(1),Integer(1),Integer(1),Integer(1)])
>>> Q.local_good_density_congruence_even(Integer(1), None, None)
1
>>> Q.local_good_density_congruence_even(Integer(2), None, None)
3/2
>>> Q.local_good_density_congruence_even(Integer(3), None, None)
1
>>> Q.local_good_density_congruence_even(Integer(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)                                                        # needs sage.libs.pari
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 = Q.local_normal_form(2)                                          # needs sage.libs.pari sage.rings.padics
sage: Q_local.local_good_density_congruence_even(1, None, None)                 # needs sage.libs.pari sage.rings.padics
3/4
sage: Q_local.local_good_density_congruence_even(2, None, None)                 # needs sage.libs.pari sage.rings.padics
9/8
sage: Q_local.local_good_density_congruence_even(5, None, None)                 # needs sage.libs.pari sage.rings.padics
3/4
>>> from sage.all import *
>>> Q = QuadraticForm(ZZ, Integer(4), range(Integer(10)))
>>> Q[Integer(0),Integer(0)] = Integer(5)
>>> Q[Integer(1),Integer(1)] = Integer(10)
>>> Q[Integer(2),Integer(2)] = Integer(15)
>>> Q[Integer(3),Integer(3)] = Integer(20)
>>> Q
Quadratic form in 4 variables over Integer Ring with coefficients:
[ 5 1 2 3 ]
[ * 10 5 6 ]
[ * * 15 8 ]
[ * * * 20 ]
>>> Q.theta_series(Integer(20))                                                        # needs sage.libs.pari
1 + 2*q^5 + 2*q^10 + 2*q^14 + 2*q^15 + 2*q^16 + 2*q^18 + O(q^20)
>>> Q_local = Q.local_normal_form(Integer(2))                                          # needs sage.libs.pari sage.rings.padics
>>> Q_local.local_good_density_congruence_even(Integer(1), None, None)                 # needs sage.libs.pari sage.rings.padics
3/4
>>> Q_local.local_good_density_congruence_even(Integer(2), None, None)                 # needs sage.libs.pari sage.rings.padics
9/8
>>> Q_local.local_good_density_congruence_even(Integer(5), None, None)                 # needs sage.libs.pari sage.rings.padics
3/4
local_good_density_congruence_odd(p, m, Zvec, NZvec)[source]

Find 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.

Todo

Add type checking for Zvec, NZvec, and that \(Q\) is in local normal form.

INPUT:

  • self – quadratic form \(Q\), assumed to be diagonal and \(p\)-integral

  • p – a prime number

  • m – integer

  • Zvec, NZvec – non-repeating lists of integers in range(self.dim()) or None

OUTPUT: a rational number

EXAMPLES:

sage: Q = DiagonalQuadraticForm(ZZ, [1,2,3])
sage: Q.local_good_density_congruence_odd(3, 1, None, None)
2/3
>>> from sage.all import *
>>> Q = DiagonalQuadraticForm(ZZ, [Integer(1),Integer(2),Integer(3)])
>>> Q.local_good_density_congruence_odd(Integer(3), Integer(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
>>> from sage.all import *
>>> Q = DiagonalQuadraticForm(ZZ, [Integer(1),Integer(1),Integer(1),Integer(1)])
>>> Q.local_good_density_congruence_odd(Integer(3), Integer(1), None, None)
8/9
local_normal_form(p)[source]

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 \(\leq 2\) and are arranged by increasing scale, and then by increasing norm. This is equivalent to saying that we put the \(1 \times 1\) blocks before the \(2 \times 2\) 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 ]
>>> from sage.all import *
>>> Q = QuadraticForm(ZZ, Integer(2), [Integer(10),Integer(4),Integer(1)])
>>> Q.local_normal_form(Integer(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 ]
>>> from sage.all import *
>>> Q.local_normal_form(Integer(3))
Quadratic form in 2 variables over Integer Ring with coefficients:
  [ 10 0 ]
  [ * 15 ]

>>> Q.local_normal_form(Integer(2))
Quadratic form in 2 variables over Integer Ring with coefficients:
  [ 1 0 ]
  [ * 6 ]
local_primitive_density(p, m)[source]

Return 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 – integer

OUTPUT: a rational number

EXAMPLES:

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)                                                        # needs sage.libs.pari
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
>>> from sage.all import *
>>> Q = QuadraticForm(ZZ, Integer(4), range(Integer(10)))
>>> Q[Integer(0),Integer(0)] = Integer(5)
>>> Q[Integer(1),Integer(1)] = Integer(10)
>>> Q[Integer(2),Integer(2)] = Integer(15)
>>> Q[Integer(3),Integer(3)] = Integer(20)
>>> Q
Quadratic form in 4 variables over Integer Ring with coefficients:
[ 5 1 2 3 ]
[ * 10 5 6 ]
[ * * 15 8 ]
[ * * * 20 ]
>>> Q.theta_series(Integer(20))                                                        # needs sage.libs.pari
1 + 2*q^5 + 2*q^10 + 2*q^14 + 2*q^15 + 2*q^16 + 2*q^18 + O(q^20)
>>> Q.local_normal_form(Integer(2))
Quadratic form in 4 variables over Integer Ring with coefficients:
[ 0 1 0 0 ]
[ * 0 0 0 ]
[ * * 0 1 ]
[ * * * 0 ]

>>> Q.local_primitive_density(Integer(2), Integer(1))
3/4
>>> Q.local_primitive_density(Integer(5), Integer(1))
24/25

>>> Q.local_primitive_density(Integer(2), Integer(5))
3/4
>>> Q.local_density(Integer(2), Integer(5))
3/4
local_primitive_density_congruence(p, m, Zvec=None, NZvec=None)[source]

Find 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:

  • self – quadratic form \(Q\), assumed to be block diagonal and \(p\)-integral

  • p – a prime number

  • m – integer

  • Zvec, NZvec – non-repeating lists of integers in range(self.dim()) or None

OUTPUT: a rational number

EXAMPLES:

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
>>> from sage.all import *
>>> Q = DiagonalQuadraticForm(ZZ, [Integer(1),Integer(1),Integer(1),Integer(1)])
>>> Q.local_primitive_density_congruence(p=Integer(2), m=Integer(1), Zvec=None, NZvec=None)
1
>>> Q.local_primitive_density_congruence(p=Integer(3), m=Integer(1), Zvec=None, NZvec=None)
8/9
>>> Q.local_primitive_density_congruence(p=Integer(5), m=Integer(1), Zvec=None, NZvec=None)
24/25
>>> Q.local_primitive_density_congruence(p=Integer(7), m=Integer(1), Zvec=None, NZvec=None)
48/49
>>> Q.local_primitive_density_congruence(p=Integer(11), m=Integer(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
>>> from sage.all import *
>>> Q = DiagonalQuadraticForm(ZZ, [Integer(1),Integer(2),Integer(3)])
>>> Q.local_primitive_density_congruence(Integer(2), Integer(1), None, None)
1
>>> Q.local_primitive_density_congruence(Integer(2), Integer(2), None, None)
1
>>> Q.local_primitive_density_congruence(Integer(2), Integer(4), None, None)
1
>>> Q.local_primitive_density_congruence(Integer(3), Integer(1), None, None)
2/3
>>> Q.local_primitive_density_congruence(Integer(3), Integer(6), None, None)
4/3
>>> Q.local_primitive_density_congruence(Integer(3), Integer(9), None, None)
4/3
>>> Q.local_primitive_density_congruence(Integer(3), Integer(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
>>> from sage.all import *
>>> Q = DiagonalQuadraticForm(ZZ, [Integer(1),Integer(3),Integer(3),Integer(9),Integer(9)])
>>> Q.local_primitive_density_congruence(Integer(3), Integer(1), None, None)
2
>>> Q.local_primitive_density_congruence(Integer(3), Integer(3), None, None)
4/3
>>> Q.local_primitive_density_congruence(Integer(3), Integer(6), None, None)
4/3
>>> Q.local_primitive_density_congruence(Integer(3), Integer(9), None, None)
4/27
>>> Q.local_primitive_density_congruence(Integer(3), Integer(18), None, None)
4/9
>>> Q.local_primitive_density_congruence(Integer(3), Integer(27), None, None)
8/27
>>> Q.local_primitive_density_congruence(Integer(3), Integer(81), None, None)
8/27
>>> Q.local_primitive_density_congruence(Integer(3), Integer(243), None, None)
8/27
local_representation_conditions(recompute_flag=False, silent_flag=False)[source]

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 \(\ZZ_p\), and are labeled by the \(\QQ_p\) square-classes \(t\cdot (\QQ_p)^2\) with \(t\) given as follows:

  • for \(p > 2\), [ *  1  u  p  u p  *  *  *  * ],

  • for \(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 \(\QQ_p\) square-class is not represented, while a positive number \(x\) indicates that \(t\cdot p^{(2\cdot x)} (\ZZ_p)^2\) is locally represented but \(t\cdot p^{(2\cdot (x-1))}\) \((\ZZ_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\cdot u\cdot r^2\) with \(u = 1\) (mod 8)

  • \(2^5\cdot u\cdot r^2\) with \(u = 3\) (mod 8)

  • \(2\cdot u\cdot 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.

OUTPUT:

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]
>>> from sage.all import *
>>> Q = DiagonalQuadraticForm(ZZ, [])
>>> Q.local_representation_conditions()
This 0-dimensional form only represents zero.

>>> Q = DiagonalQuadraticForm(ZZ, [Integer(5)])
>>> Q.local_representation_conditions()
This 1-dimensional form only represents square multiples of 5.

>>> Q1 = DiagonalQuadraticForm(ZZ, [Integer(1),Integer(1)])
>>> 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]

>>> Q1 = DiagonalQuadraticForm(ZZ, [Integer(1),Integer(1),Integer(1)])
>>> 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]

>>> Q1 = DiagonalQuadraticForm(ZZ, [Integer(1),Integer(1),Integer(1),Integer(1)])
>>> 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]

>>> Q1 = DiagonalQuadraticForm(ZZ, [Integer(1),Integer(3),Integer(3),Integer(3)])
>>> 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]

>>> Q2 = DiagonalQuadraticForm(ZZ, [Integer(2),Integer(3),Integer(3),Integer(3)])
>>> 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]

>>> Q3 = DiagonalQuadraticForm(ZZ, [Integer(1),Integer(3),Integer(5),Integer(7)])
>>> 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)[source]

Find the Zero-type local density of \(Q\) representing \(m\) at \(p\), allowing certain congruence conditions mod \(p\).

INPUT:

  • self – quadratic form \(Q\), assumed to be block diagonal and \(p\)-integral

  • p – a prime number

  • m – integer

  • Zvec, NZvec – non-repeating lists of integers in range(self.dim()) or None

OUTPUT: a rational number

EXAMPLES:

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
>>> from sage.all import *
>>> Q = DiagonalQuadraticForm(ZZ, [Integer(1),Integer(2),Integer(3)])
>>> Q.local_zero_density_congruence(Integer(2), Integer(2), None, None)
0
>>> Q.local_zero_density_congruence(Integer(2), Integer(4), None, None)
1/2
>>> Q.local_zero_density_congruence(Integer(3), Integer(6), None, None)
0
>>> Q.local_zero_density_congruence(Integer(3), Integer(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
>>> from sage.all import *
>>> Q = DiagonalQuadraticForm(ZZ, [Integer(1),Integer(1),Integer(1),Integer(1)])
>>> Q.local_zero_density_congruence(Integer(2), Integer(2), None, None)
0
>>> Q.local_zero_density_congruence(Integer(2), Integer(4), None, None)
1/4
>>> Q.local_zero_density_congruence(Integer(3), Integer(6), None, None)
0
>>> Q.local_zero_density_congruence(Integer(3), Integer(9), None, None)
8/81
mass__by_Siegel_densities(odd_algorithm='Pall', even_algorithm='Watson')[source]

Return the mass of transformations (det 1 and -1).

Warning

This is broken right now…

INPUT:

  • odd_algorithm – algorithm to be used when \(p>2\); 'Pall' (only one choice for now)

  • even_algorithm – algorithm to be used when \(p=2\); either 'Kitaoka' or 'Watson' (the default)

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                                      # needs sage.symbolic
1/384
sage: m - (2^Q.dim() * factorial(Q.dim()))^(-1)                                 # needs sage.symbolic
0
>>> from sage.all import *
>>> Q = DiagonalQuadraticForm(ZZ, [Integer(1),Integer(1),Integer(1),Integer(1)])
>>> m = Q.mass__by_Siegel_densities(); m                                      # needs sage.symbolic
1/384
>>> m - (Integer(2)**Q.dim() * factorial(Q.dim()))**(-Integer(1))                                 # needs sage.symbolic
0

sage: Q = DiagonalQuadraticForm(ZZ, [1,1,1])
sage: m = Q.mass__by_Siegel_densities(); m                                      # needs sage.symbolic
1/48
sage: m - (2^Q.dim() * factorial(Q.dim()))^(-1)                                 # needs sage.symbolic
0
>>> from sage.all import *
>>> Q = DiagonalQuadraticForm(ZZ, [Integer(1),Integer(1),Integer(1)])
>>> m = Q.mass__by_Siegel_densities(); m                                      # needs sage.symbolic
1/48
>>> m - (Integer(2)**Q.dim() * factorial(Q.dim()))**(-Integer(1))                                 # needs sage.symbolic
0
mass_at_two_by_counting_mod_power(k)[source]

Compute 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\).

Todo

Remove this routine, or try to compile it!

INPUT:

  • k – integer \(\geq 1\)

OUTPUT: a rational number

EXAMPLES:

sage: Q = DiagonalQuadraticForm(ZZ, [1,1,1])
sage: Q.mass_at_two_by_counting_mod_power(1)
4
>>> from sage.all import *
>>> Q = DiagonalQuadraticForm(ZZ, [Integer(1),Integer(1),Integer(1)])
>>> Q.mass_at_two_by_counting_mod_power(Integer(1))
4
matrix()[source]

Return the Hessian matrix \(A\) for which \(Q(X) = (1/2) X^t\cdot A\cdot X\).

EXAMPLES:

sage: Q = QuadraticForm(ZZ, 3, range(6))
sage: Q.matrix()
[ 0  1  2]
[ 1  6  4]
[ 2  4 10]
>>> from sage.all import *
>>> Q = QuadraticForm(ZZ, Integer(3), range(Integer(6)))
>>> Q.matrix()
[ 0  1  2]
[ 1  6  4]
[ 2  4 10]
minkowski_reduction()[source]

Find a Minkowski-reduced form equivalent to the given one.

This means that

\[Q(v_k) \leq Q(s_1\cdot v_1 + ... + s_n\cdot v_n)\]

for all \(s_i\) where \(\gcd(s_k, ... s_n) = 1\).

Note

When \(Q\) has dim \(\leq 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]
)
>>> from sage.all import *
>>> Q = QuadraticForm(ZZ, Integer(4), [Integer(30), Integer(17), Integer(11), Integer(12), Integer(29), Integer(25), Integer(62), Integer(64), Integer(25), Integer(110)])
>>> Q
Quadratic form in 4 variables over Integer Ring with coefficients:
[ 30 17 11 12 ]
[ * 29 25 62 ]
[ * * 64 25 ]
[ * * * 110 ]
>>> Q.minkowski_reduction()
(
Quadratic form in 4 variables over Integer Ring with coefficients:
[ 30 17 11 -5 ]
[ * 29 25 4 ]
[ * * 64 0 ]
[ * * * 77 ]                                                       ,
<BLANKLINE>
[ 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 ]