Skip to content

Commit

Permalink
gh-36184: add class groups of binary quadratic forms
Browse files Browse the repository at this point in the history
    
This patch adds an implementation of the form class group for positive
definite binary quadratic forms. (We restrict to definite forms for now
since it is the easier case: Every class contains a unique reduced
form.)

Most of the required functionality was already available in PARI or
Sage, but the types introduced in this patch make it easier to
manipulate form classes and interface with existing algorithms for
generic abelian groups.
    
URL: #36184
Reported by: Lorenz Panny
Reviewer(s): Giacomo Pope, Lorenz Panny
  • Loading branch information
Release Manager committed Dec 4, 2023
2 parents c1a3817 + 4797a51 commit 839327a
Show file tree
Hide file tree
Showing 5 changed files with 700 additions and 1 deletion.
1 change: 1 addition & 0 deletions src/doc/en/reference/quadratic_forms/index.rst
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,7 @@ Quadratic Forms

sage/quadratic_forms/quadratic_form
sage/quadratic_forms/binary_qf
sage/quadratic_forms/bqf_class_group
sage/quadratic_forms/constructions
sage/quadratic_forms/random_quadraticform
sage/quadratic_forms/special_values
Expand Down
2 changes: 2 additions & 0 deletions src/sage/quadratic_forms/all.py
Original file line number Diff line number Diff line change
@@ -1,5 +1,7 @@
from .binary_qf import BinaryQF, BinaryQF_reduced_representatives

from .bqf_class_group import BQFClassGroup

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, quadratic_form_from_invariants
Expand Down
60 changes: 60 additions & 0 deletions src/sage/quadratic_forms/binary_qf.py
Original file line number Diff line number Diff line change
Expand Up @@ -179,6 +179,49 @@ def _pari_init_(self):
"""
return 'Qfb(%s,%s,%s)' % (self._a, self._b, self._c)

@staticmethod
def principal(D):
r"""
Return the principal binary quadratic form of the given discriminant.
EXAMPLES::
sage: BinaryQF.principal(8)
x^2 - 2*y^2
sage: BinaryQF.principal(5)
x^2 + x*y - y^2
sage: BinaryQF.principal(4)
x^2 - y^2
sage: BinaryQF.principal(1)
x^2 + x*y
sage: BinaryQF.principal(-3)
x^2 + x*y + y^2
sage: BinaryQF.principal(-4)
x^2 + y^2
sage: BinaryQF.principal(-7)
x^2 + x*y + 2*y^2
sage: BinaryQF.principal(-8)
x^2 + 2*y^2
TESTS:
Some randomized testing::
sage: D = 1
sage: while D.is_square():
....: D = choice((-4,+4)) * randrange(9999) + randrange(2)
sage: Q = BinaryQF.principal(D)
sage: Q.discriminant() == D # correct discriminant
True
sage: (Q*Q).is_equivalent(Q) # idempotent (hence identity)
True
"""
D = ZZ(D)
D4 = D % 4
if D4 not in (0,1):
raise ValueError('discriminant must be congruent to 0 or 1 modulo 4')
return BinaryQF([1, D4, (D4-D)//4])

def __mul__(self, right):
"""
Gauss composition or right action by a 2x2 integer matrix.
Expand Down Expand Up @@ -1721,6 +1764,23 @@ def solve_integer(self, n, *, algorithm="general"):
sol = self.__pari__().qfbsolve(n, flag)
return tuple(map(ZZ, sol)) if sol else None

def form_class(self):
r"""
Return the class of this form modulo equivalence.
EXAMPLES::
sage: F = BinaryQF([3, -16, 161])
sage: cl = F.form_class(); cl
Class of 3*x^2 + 2*x*y + 140*y^2
sage: cl.parent()
Form Class Group of Discriminant -1676
sage: cl.parent() is BQFClassGroup(-4*419)
True
"""
from sage.quadratic_forms.bqf_class_group import BQFClassGroup
return BQFClassGroup(self.discriminant())(self)


def BinaryQF_reduced_representatives(D, primitive_only=False, proper=True):
r"""
Expand Down
Loading

0 comments on commit 839327a

Please sign in to comment.