Skip to content

Commit 2c6ebe5

Browse files
author
Release Manager
committed
gh-37112: Tests to see if ideal in quaternion algebra is primitive (cyclic) New methods for `QuaternionFractionalIdeal_rational`: - `QuaternionFractionalIdeal_rational.is_integral()` - `QuaternionFractionalIdeal_rational.is_primitive()` - `QuaternionFractionalIdeal_rational.primitive_decomposition()` These methods verify if an ideal in quaternion rational algebra is integral, primitive (cyclic) and decompose it as a primitive ideal. Part of the code came from [https://learningtosqi.github.io](https://learningtosqi.github.io). Also added the _Quaternion Algebras_ book by J. Voight in the bibliography. Done with @gioella #sd123 URL: #37112 Reported by: Giacomo Borin Reviewer(s): Lorenz Panny
2 parents b720abc + 09d352e commit 2c6ebe5

File tree

2 files changed

+108
-0
lines changed

2 files changed

+108
-0
lines changed

src/doc/en/reference/references/index.rst

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -6347,6 +6347,8 @@ REFERENCES:
63476347
.. [Voi2012] \J. Voight. Identifying the matrix ring: algorithms for
63486348
quaternion algebras and quadratic forms, to appear.
63496349
6350+
.. [Voi2021] \J. Voight. Quaternion algebras, Springer Nature (2021).
6351+
63506352
.. [VS06] \G.D. Villa Salvador. Topics in the Theory of Algebraic Function
63516353
Fields. Birkh\"auser, 2006.
63526354

src/sage/algebras/quatalg/quaternion_algebra.py

Lines changed: 106 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -3033,6 +3033,112 @@ def cyclic_right_subideals(self, p, alpha=None):
30333033
ans.append(J)
30343034
return ans
30353035

3036+
def is_integral(self):
3037+
r"""
3038+
Check if a quaternion fractional ideal is integral. An ideal in a quaternion algebra is
3039+
said integral if it is contained in its left order. If the left order is already defined it just
3040+
check the definition, otherwise it uses one of the alternative definition of Lemma 16.2.8 of
3041+
[Voi2021]_.
3042+
3043+
OUTPUT: a boolean.
3044+
3045+
EXAMPLES::
3046+
3047+
sage: R.<i,j,k> = QuaternionAlgebra(QQ, -1,-11)
3048+
sage: I = R.ideal([2 + 2*j + 140*k, 2*i + 4*j + 150*k, 8*j + 104*k, 152*k])
3049+
sage: I.is_integral()
3050+
True
3051+
sage: O = I.left_order()
3052+
sage: I.is_integral()
3053+
True
3054+
sage: I = R.ideal([1/2 + 2*j + 140*k, 2*i + 4*j + 150*k, 8*j + 104*k, 152*k])
3055+
sage: I.is_integral()
3056+
False
3057+
3058+
"""
3059+
if self.__left_order is not None:
3060+
return self.free_module() <= self.left_order().free_module()
3061+
elif self.__right_order is not None:
3062+
return self.free_module() <= self.right_order().free_module()
3063+
else:
3064+
self_square = self**2
3065+
return self_square.free_module() <= self.free_module()
3066+
3067+
def primitive_decomposition(self):
3068+
r"""
3069+
Let `I` = ``self``. If `I` is an integral left `\mathcal{O}`-ideal return its decomposition
3070+
as an equivalent primitive ideal and an integer such that their product is the initial ideal.
3071+
3072+
OUTPUTS: and quivalent primitive ideal to `I`, i.e. equivalent ideal not contained in `n\mathcal{O}` for any `n>0`, and the smallest integer such that `I \subset g\mathcal{O}`.
3073+
3074+
EXAMPLES::
3075+
3076+
sage: A.<i,j,k> = QuaternionAlgebra(QQ, -1,-11)
3077+
sage: I = A.ideal([1/2 + 1/2*i + 1/2*j + 3/2*k, i + k, j + k, 2*k])
3078+
sage: I.primitive_decomposition()
3079+
(Fractional ideal (1/2 + 1/2*i + 1/2*j + 3/2*k, i + k, j + k, 2*k), 1)
3080+
sage: J = A.ideal([7/2 + 7/2*i + 49/2*j + 91/2*k, 7*i + 21*k, 35*j + 35*k, 70*k])
3081+
sage: Jequiv, g = J.primitive_decomposition()
3082+
sage: Jequiv*g == J
3083+
True
3084+
sage: Jequiv, g
3085+
(Fractional ideal (1/2 + 1/2*i + 7/2*j + 13/2*k, i + 3*k, 5*j + 5*k, 10*k), 7)
3086+
3087+
TESTS:
3088+
3089+
Checks on random crafted ideals that they decompose as expected::
3090+
3091+
sage: for d in ( m for m in range(400, 750) if is_squarefree(m) ):
3092+
....: A = QuaternionAlgebra(d)
3093+
....: O = A.maximal_order()
3094+
....: for _ in range(10):
3095+
....: a = O.random_element()
3096+
....: if not a.is_constant(): # avoids a = 0
3097+
....: I = a*O + a.reduced_norm()*O
3098+
....: if I.is_integral():
3099+
....: J,g = I.primitive_decomposition()
3100+
....: assert J*g == I
3101+
....: assert J.is_primitive()
3102+
"""
3103+
if not self.is_integral():
3104+
raise ValueError("primitive ideals are defined only for integral ideals")
3105+
3106+
I_basis = self.basis_matrix()
3107+
O_basis = self.left_order().basis_matrix()
3108+
3109+
# Write I in the basis of its left order via rref
3110+
M = O_basis.solve_left(I_basis)
3111+
g = Integer(gcd(M.list()))
3112+
3113+
# If g is 1 then the ideal is primitive
3114+
if g.is_one():
3115+
return self, g
3116+
3117+
J = self.scale(1/g)
3118+
3119+
return J, g
3120+
3121+
def is_primitive(self):
3122+
r"""
3123+
Check if the quaternion fractional ideal is primitive. An integral left
3124+
$O$-ideal for some order $O$ is said primitive if for all integers $n > 1$
3125+
$I$ is not contained in $nO$.
3126+
3127+
OUTPUT: a boolean.
3128+
3129+
EXAMPLES::
3130+
3131+
sage: A.<i,j,k> = QuaternionAlgebra(QQ, -1,-11)
3132+
sage: I = A.ideal([1/2 + 1/2*i + 1/2*j + 3/2*k, i + k, j + k, 2*k])
3133+
sage: I.is_primitive()
3134+
True
3135+
sage: (2*I).is_primitive()
3136+
False
3137+
3138+
"""
3139+
_,g = self.primitive_decomposition()
3140+
return g.is_one()
3141+
30363142
#######################################################################
30373143
# Some utility functions that are needed here and are too
30383144
# specialized to go elsewhere.

0 commit comments

Comments
 (0)