Skip to content

Commit f40ab15

Browse files
author
Release Manager
committed
gh-37164: Fixes and simplifications for `.ramified_primes()`, `.discriminant()` and `.is_isomorphic` of quaternion algebras 1. Removed unnecessary product and factorization for `.ramified_primes()` 2. Adapted `is_isomorphic` to reduce unnecessary calculations 3. Fixed a bug in `.discriminant()` and `.ramified_primes()` where rational invariants caused errors 4. Removed `.hilbert_conductor` from `sage.arith.misc` import list and added `.hilbert_symbol` 5. Reduced restriction of `.ramified_primes()` to rational quaternion algebras in docstring in preparation for planned `.ramified_places()` function over number fields (currently being worked on) In more detail: 1. The original workflow for `.ramified_primes()` went as follows: - Call `.discriminant()`, which calls `.hilbert_conductor` - Inside `.hilbert_conductor`, the ramified primes are computed and their product (the discriminant of the quaternion algebra) is returned - Finally, factor the discriminant back into its prime factors Hence we have a redundant product and, more crucially, a redundant prime factorization. This fix modifies `.ramified_primes()` to instead directly build the list computed in `.hilbert_conductor()` (up to a bug fix described in 3.) and return it; the list might not always be sorted by magnitude of primes, so an optional argument `sorted` (set to `False` by default) allows to enforce this (small to large) sorting. Furthermore, `.discriminant()` has been adapted to directly take the product of the list returned by `.ramified_primes()` (only in the rational case, for now - see 5.) 2. Since the `.discriminant()`-function needs to compute all (finite) ramified primes (this was also true before this PR, it was just hidden inside `.hilbert_conductor()` instead), the function `.is_isomorphic()` now compares the unsorted lists of finite ramified primes to decide whether two rational quaternion algebras are isomorphic. 3. The function `sage.arith.misc.hilbert_conductor` requires its arguments to be integers (to create certain lists of prime divisors); since it was originally used to determine the discriminant (and, as explained in 1., the ramified primes), it raises an error when the invariants are proper rational numbers. To get around the analogous error for the method `.hilbert_symbol`, we instead look at the numerators and denominators of both invariants separately, using the fact that we can (purely on a mathematical level) rescale both invariants by the squares of their respective denominators without leaving the isomorphism class of the algebra. 4. The only call to `sage.arith.misc.hilbert_conductor` in quaternion_algebra.py was given in the old computation of the discriminant (the other `.hilbert_conductor` in the code, also in `.discriminant()`, refers to the one in `sage.rings.number_field`), so it was removed from the import list. The new approach to `.ramified_primes()` requires `sage.arith.misc.hilbert_symbol`, which was added to the import list. 5. As of now the `.ramified_primes()`-method is only supported for rational quaternion algebras. I'm currently working on a version over number fields, but once it works correctly this will be implemented as a new function `.ramified_places` (Update: see #37173) ~~to distinguish between different formats (prime numbers vs ideals) over $\mathbb{Q}$~~ (Update: this wasn't really feasible, see the issues discussed in #7596; thanks to @yyyyx4 for pointing me towards this discussion) ~~and, furthermore,~~ to not cause confusion using the term "primes" for the Archimedean real places where a quaternion algebra might ramify. Hence the implementation restriction in the docstring of `.ramified_primes()` was removed, but the method still throws a ValueError if not called with a quaternion algebra defined over the rational numbers. #sd123 URL: #37164 Reported by: Sebastian Spindler Reviewer(s): grhkm21, Sebastian Spindler
2 parents ad3f10b + f5fc230 commit f40ab15

File tree

1 file changed

+23
-12
lines changed

1 file changed

+23
-12
lines changed

src/sage/algebras/quatalg/quaternion_algebra.py

Lines changed: 23 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -36,10 +36,11 @@
3636
# ****************************************************************************
3737

3838
from sage.arith.misc import (hilbert_conductor_inverse,
39-
hilbert_conductor,
39+
hilbert_symbol,
4040
factor,
4141
gcd,
4242
kronecker as kronecker_symbol,
43+
prime_divisors,
4344
valuation)
4445
from sage.rings.real_mpfr import RR
4546
from sage.rings.integer import Integer
@@ -1032,9 +1033,8 @@ def inner_product_matrix(self):
10321033
@cached_method
10331034
def discriminant(self):
10341035
"""
1035-
Given a quaternion algebra `A` defined over a number field,
1036-
return the discriminant of `A`, i.e. the
1037-
product of the ramified primes of `A`.
1036+
Return the discriminant of this quaternion algebra, i.e. the product of the finite
1037+
primes it ramifies at.
10381038
10391039
EXAMPLES::
10401040
@@ -1059,25 +1059,36 @@ def discriminant(self):
10591059
except NotImplementedError:
10601060
raise ValueError("base field must be rational numbers or number field")
10611061
else:
1062-
return hilbert_conductor(self._a, self._b)
1062+
return ZZ.prod(self.ramified_primes())
10631063

1064+
@cached_method
10641065
def ramified_primes(self):
10651066
"""
1066-
Return the primes that ramify in this quaternion algebra.
1067+
Return the (finite) primes that ramify in this rational quaternion algebra.
1068+
1069+
OUTPUT:
10671070
1068-
Currently only implemented over the rational numbers.
1071+
The list of prime numbers at which ``self`` ramifies (given as integers), sorted by their
1072+
magnitude (small to large).
10691073
10701074
EXAMPLES::
10711075
10721076
sage: QuaternionAlgebra(QQ, -1, -1).ramified_primes()
10731077
[2]
1078+
1079+
sage: QuaternionAlgebra(QQ, -58, -69).ramified_primes()
1080+
[3, 23, 29]
10741081
"""
1075-
# TODO: more examples
1076-
return [f[0] for f in factor(self.discriminant())]
1082+
if not is_RationalField(self.base_ring()):
1083+
raise ValueError("base field must be the rational numbers")
1084+
1085+
return sorted([p for p in set([2]).union(prime_divisors(self._a.numerator()),
1086+
prime_divisors(self._a.denominator()), prime_divisors(self._b.numerator()),
1087+
prime_divisors(self._b.denominator())) if hilbert_symbol(self._a, self._b, p) == -1])
10771088

10781089
def is_isomorphic(self, A) -> bool:
1079-
r"""
1080-
Return ``True`` if ``self`` and ``A`` are isomorphic quaternion algebras over Q.
1090+
"""
1091+
Return ``True`` if (and only if) ``self`` and ``A`` are isomorphic quaternion algebras over Q.
10811092
10821093
INPUT:
10831094
@@ -1098,7 +1109,7 @@ def is_isomorphic(self, A) -> bool:
10981109
if self.base_ring() != QQ or A.base_ring() != QQ:
10991110
raise NotImplementedError("isomorphism check only implemented for rational quaternion algebras")
11001111

1101-
return self.discriminant() == A.discriminant()
1112+
return self.ramified_primes() == A.ramified_primes()
11021113

11031114
def _magma_init_(self, magma):
11041115
"""

0 commit comments

Comments
 (0)