Skip to content

Commit

Permalink
Trac #24108: quadratic_form_from_invariants()
Browse files Browse the repository at this point in the history
This is algorithm 3.4.3 from Markus Kirschmer's "Definite quadratic and
hermitian forms with small class number"  It returns a global quadratic
form corresponding to a given set of local invariants.

URL: https://trac.sagemath.org/24108
Reported by: annahaensch
Ticket author(s): Simon Brandhorst
Reviewer(s): Travis Scrimshaw
  • Loading branch information
Release Manager committed Nov 15, 2019
2 parents e9e14ad + afa1d73 commit 94b6add
Show file tree
Hide file tree
Showing 2 changed files with 100 additions and 2 deletions.
2 changes: 1 addition & 1 deletion src/sage/quadratic_forms/all.py
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,7 @@

from .ternary_qf import TernaryQF, find_all_ternary_qf_by_level_disc, find_a_ternary_qf_by_level_disc

from .quadratic_form import QuadraticForm, DiagonalQuadraticForm
from .quadratic_form import QuadraticForm, DiagonalQuadraticForm, quadratic_form_from_invariants

from .random_quadraticform import random_quadraticform, random_quadraticform_with_conditions, random_ternaryqf, random_ternaryqf_with_conditions

Expand Down
100 changes: 99 additions & 1 deletion src/sage/quadratic_forms/quadratic_form.py
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,7 @@
- Jon Hanke (2007-06-19)
- Anna Haensch (2010-07-01): Formatting and ReSTification
- Simon Brandhorst (2019-10-15): :meth:``quadratic_form_from_invariants``
"""

#*****************************************************************************
Expand All @@ -28,7 +29,7 @@
from sage.rings.ring import Ring
from sage.misc.functional import denominator, is_even, is_field
from sage.arith.all import GCD, LCM
from sage.rings.all import Ideal
from sage.rings.all import Ideal, QQ
from sage.rings.ring import is_Ring, PrincipalIdealDomain
from sage.structure.sage_object import SageObject
from sage.structure.element import is_Vector
Expand Down Expand Up @@ -75,6 +76,103 @@ def is_QuadraticForm(Q):
return isinstance(Q, QuadraticForm)


def quadratic_form_from_invariants(F, rk, det, P, sminus):
r"""
Return a rational quadratic form with given invariants.
INPUT:
- ``F`` -- the base field; currently only ``QQ`` is allowed
- ``rk`` -- integer; the rank
- ``det`` -- rational; the determinant
- ``P`` -- a list of primes where Cassel's Hasse invariant
is negative
- ``sminus`` -- integer; the number of negative eigenvalues
of any Gram matrix
OUTPUT:
- a quadratic form with the specified invariants
Let `(a_1, \ldots, a_n)` be the gram marix of a regular quadratic space.
Then Cassel's Hasse invariant is defined as
.. MATH::
\prod_{i<j} (a_i,a_j),
where `(a_i,a_j)` denotes the Hilbert symbol.
ALGORITHM:
We follow [Kir2016]_.
EXAMPLES::
sage: P = [3,5]
sage: q = quadratic_form_from_invariants(QQ,2,-15,P,1)
sage: q
Quadratic form in 2 variables over Rational Field with coefficients:
[ 5 0 ]
[ * -3 ]
sage: all(q.hasse_invariant(p)==-1 for p in P)
True
"""
from sage.arith.misc import hilbert_symbol
# normalize input
if F!=QQ:
raise NotImplementedError('base field must be QQ. If you want this over any field, implement weak approximation.')
P = [ZZ(p) for p in P]
rk = ZZ(rk)
d = QQ(det).squarefree_part()
sminus = ZZ(sminus)
# check if the invariants define a global quadratic form
if d.sign() != (-1)**sminus:
raise ValueError("invariants do not define a rational quadratic form")
if rk == 1 and len(P) != 0:
raise ValueError("invariants do not define a rational quadratic form")
if rk == 2:
for p in P:
if QQ(-d).is_padic_square(p):
raise ValueError("invariants do not define a rational quadratic form")
if sminus % 4 in (2, 3) and len(P) % 2 == 0:
raise ValueError("invariants do not define a rational quadratic form")
D = []
while rk >= 2:
if rk >= 4:
if sminus > 0:
a = ZZ(-1)
else:
a = ZZ(1)
elif rk == 3:
Pprime = [p for p in P if hilbert_symbol(-1, -d, p)==1]
Pprime += [p for p in (2*d).prime_divisors()
if hilbert_symbol(-1, -d, p)==-1 and p not in P]
if sminus > 0:
a = ZZ(-1)
else:
a = ZZ(1)
for p in Pprime:
if d.valuation(p) % 2 == 0:
a *= p
assert all((a*d).valuation(p)%2==1 for p in Pprime)
elif rk == 2:
S = P
if sminus == 2:
S += [-1]
a = QQ.hilbert_symbol_negative_at_S(S,-d)
a = ZZ(a)
P = [p for p in P if hilbert_symbol(a, -d, p) == 1]
P += [p for p in (2*a*d).prime_divisors()
if hilbert_symbol(a, -d, p)==-1 and p not in P]
sminus = max(0, sminus-1)
rk = rk - 1
d = a*d
D.append(a.squarefree_part())
d = d.squarefree_part()
D.append(d)
return DiagonalQuadraticForm(QQ,D)


class QuadraticForm(SageObject):
r"""
Expand Down

0 comments on commit 94b6add

Please sign in to comment.