Skip to content
This repository was archived by the owner on Jan 30, 2023. It is now read-only.

Commit 557591c

Browse files
committed
#31345: implementation of Selmer groups of number fields
1 parent 13b4090 commit 557591c

File tree

5 files changed

+260
-52
lines changed

5 files changed

+260
-52
lines changed

src/sage/rings/number_field/number_field.py

+148-27
Original file line numberDiff line numberDiff line change
@@ -4753,9 +4753,8 @@ def _S_class_group_quotient_matrix(self, S):
47534753
assert A[:c] == 1 and A[c:] == 0
47544754
return Q[:c, :a]
47554755

4756-
def selmer_group(self, S, m, proof=True, orders=False):
4757-
r"""
4758-
Compute the group `K(S,m)`.
4756+
def selmer_generators(self, S, m, proof=True, orders=False):
4757+
r"""Compute generators of the group `K(S,m)`.
47594758
47604759
INPUT:
47614760
@@ -4791,14 +4790,23 @@ def selmer_group(self, S, m, proof=True, orders=False):
47914790
outside of `S`, but may contain it properly when not all
47924791
primes dividing `m` are in `S`.
47934792
4793+
.. NOTE::
4794+
4795+
When `m=p` is prime, see also the method
4796+
:meth:`NumberField_generic.selmer_space` which gives
4797+
additional output: as well as generators, it gives an
4798+
abstract vector space over `\F_p` isomorphic to `K(S,p)`
4799+
and maps implementing the isomorphism between this space
4800+
and `K(S,p)` as a subgroup of `K^*/(K^*)^p`.
4801+
47944802
EXAMPLES::
47954803
47964804
sage: K.<a> = QuadraticField(-5)
4797-
sage: K.selmer_group((), 2)
4805+
sage: K.selmer_generators((), 2)
47984806
[-1, 2]
47994807
48004808
The previous example shows that the group generated by the
4801-
output may be strictly larger than the 'true' Selmer group of
4809+
output may be strictly larger than the group of
48024810
elements giving extensions unramified outside `S`, since that
48034811
has order just 2, generated by `-1`::
48044812
@@ -4812,31 +4820,31 @@ def selmer_group(self, S, m, proof=True, orders=False):
48124820
sage: K.<a> = QuadraticField(-5)
48134821
sage: P2 = K.ideal(2, -a+1)
48144822
sage: P3 = K.ideal(3, a+1)
4815-
sage: K.selmer_group((), 2, orders=True)
4823+
sage: K.selmer_generators((), 2, orders=True)
48164824
([-1, 2], [2, 2])
4817-
sage: K.selmer_group((), 4, orders=True)
4825+
sage: K.selmer_generators((), 4, orders=True)
48184826
([-1, 4], [2, 2])
4819-
sage: K.selmer_group([P2], 2)
4827+
sage: K.selmer_generators([P2], 2)
48204828
[2, -1]
4821-
sage: K.selmer_group((P2,P3), 4)
4829+
sage: K.selmer_generators((P2,P3), 4)
48224830
[2, -a - 1, -1]
4823-
sage: K.selmer_group((P2,P3), 4, orders=True)
4831+
sage: K.selmer_generators((P2,P3), 4, orders=True)
48244832
([2, -a - 1, -1], [4, 4, 2])
4825-
sage: K.selmer_group([P2], 3)
4833+
sage: K.selmer_generators([P2], 3)
48264834
[2]
4827-
sage: K.selmer_group([P2, P3], 3)
4835+
sage: K.selmer_generators([P2, P3], 3)
48284836
[2, -a - 1]
4829-
sage: K.selmer_group([P2, P3, K.ideal(a)], 3) # random signs
4837+
sage: K.selmer_generators([P2, P3, K.ideal(a)], 3) # random signs
48304838
[2, a + 1, a]
48314839
48324840
Example over `\QQ` (as a number field)::
48334841
48344842
sage: K.<a> = NumberField(polygen(QQ))
4835-
sage: K.selmer_group([],5)
4843+
sage: K.selmer_generators([],5)
48364844
[]
4837-
sage: K.selmer_group([K.prime_above(p) for p in [2,3,5]],2)
4845+
sage: K.selmer_generators([K.prime_above(p) for p in [2,3,5]],2)
48384846
[2, 3, 5, -1]
4839-
sage: K.selmer_group([K.prime_above(p) for p in [2,3,5]],6, orders=True)
4847+
sage: K.selmer_generators([K.prime_above(p) for p in [2,3,5]],6, orders=True)
48404848
([2, 3, 5, -1], [6, 6, 6, 2])
48414849
48424850
TESTS::
@@ -4845,15 +4853,15 @@ def selmer_group(self, S, m, proof=True, orders=False):
48454853
sage: P2 = K.ideal(2, -a+1)
48464854
sage: P3 = K.ideal(3, a+1)
48474855
sage: P5 = K.ideal(a)
4848-
sage: S = K.selmer_group([P2, P3, P5], 3)
4856+
sage: S = K.selmer_generators([P2, P3, P5], 3)
48494857
sage: S in ([2, a + 1, a], [2, a + 1, -a], [2, -a - 1, a], [2, -a - 1, -a]) or S
48504858
True
48514859
48524860
Verify that :trac:`14489` is fixed;
48534861
the representation depends on the PARI version::
48544862
48554863
sage: K.<a> = NumberField(x^3 - 381 * x + 127)
4856-
sage: gens = K.selmer_group(K.primes_above(13), 2)
4864+
sage: gens = K.selmer_generators(K.primes_above(13), 2)
48574865
sage: len(gens) == 8
48584866
True
48594867
sage: gens[:5]
@@ -4873,9 +4881,10 @@ def selmer_group(self, S, m, proof=True, orders=False):
48734881
48744882
sage: K.<a> = QuadraticField(-5)
48754883
sage: p = K.primes_above(2)[0]
4876-
sage: S = K.selmer_group((), 4)
4884+
sage: S = K.selmer_generators((), 4)
48774885
sage: all(4.divides(x.valuation(p)) for x in S)
48784886
True
4887+
48794888
"""
48804889
units, clgp_gens = self._S_class_group_and_units(tuple(S), proof=proof)
48814890
gens = []
@@ -4921,6 +4930,9 @@ def selmer_group(self, S, m, proof=True, orders=False):
49214930
else:
49224931
return gens
49234932

4933+
# For backwards compatibility:
4934+
selmer_group = selmer_generators
4935+
49244936
def selmer_group_iterator(self, S, m, proof=True):
49254937
r"""
49264938
Return an iterator through elements of the finite group `K(S,m)`.
@@ -4936,7 +4948,7 @@ def selmer_group_iterator(self, S, m, proof=True):
49364948
OUTPUT:
49374949
49384950
An iterator yielding the distinct elements of `K(S,m)`. See
4939-
the docstring for :meth:`NumberField_generic.selmer_group` for
4951+
the docstring for :meth:`NumberField_generic.selmer_generators` for
49404952
more information.
49414953
49424954
EXAMPLES::
@@ -4961,12 +4973,116 @@ def selmer_group_iterator(self, S, m, proof=True):
49614973
sage: list(K.selmer_group_iterator([K.prime_above(p) for p in [11,13]],2))
49624974
[1, -1, 13, -13, 11, -11, 143, -143]
49634975
"""
4964-
KSgens, ords = self.selmer_group(S=S, m=m, proof=proof, orders=True)
4976+
KSgens, ords = self.selmer_generators(S=S, m=m, proof=proof, orders=True)
49654977
one = self.one()
49664978
from sage.misc.all import cartesian_product_iterator
49674979
for ev in cartesian_product_iterator([range(o) for o in ords]):
49684980
yield prod([p ** e for p, e in zip(KSgens, ev)], one)
49694981

4982+
def selmer_space(self, S, p, proof=None):
4983+
r"""Compute the group `K(S,p)` as a vector space with maps to and from `K^*`.
4984+
4985+
INPUT:
4986+
4987+
- ``S`` -- a set of primes ideals of ``self``
4988+
4989+
- ``p`` -- a prime number
4990+
4991+
- ``proof`` -- if False, assume the GRH in computing the class group
4992+
4993+
OUTPUT:
4994+
4995+
(tuple) ``KSp``, ``KSp_gens``, ``from_KSp``, ``to_KSp`` where
4996+
4997+
- ``KSp`` is an abstract vector space over `GF(p)` isomorphic to `K(S,p)`;
4998+
4999+
- ``KSp_gens`` is a list of elements of `K^*` generating `K(S,p)`;
5000+
5001+
- ``from_KSp`` is a function from ``KSp`` to `K^*`
5002+
implementing the isomorphism from the abstract `K(S,p)` to
5003+
`K(S,p)` as a subgroup of `K^*/(K^*)^p`;
5004+
5005+
- ``to_KSP`` is a partial function from `K^*` to ``KSp``,
5006+
defined on elements `a` whose image in `K^*/(K^*)^p` lies in
5007+
`K(S,p)`, mapping them via the inverse isomorphism to the
5008+
abstract vector space ``KSp``.
5009+
5010+
The group `K(S,p)` is the finite subgroup of `K^*/(K^*)^p$
5011+
consisting of elements whose valuation at all orimes not in
5012+
`S` is a multiple of `p`. It contains the subgroup of those
5013+
`a\in K^*` such that `K(\sqrt[p]{a})/K` is unramified at all
5014+
primes of `K` outside of `S`, but may contain it properly when
5015+
not all primes dividing `p` are in `S`.
5016+
5017+
EXAMPLES:
5018+
5019+
A real quadratic field with class number 2, where the fundamental
5020+
unit is a generator, and the class group provides another
5021+
generator when `p==2`::
5022+
5023+
sage: K.<a> = QuadraticField(-5)
5024+
sage: K.class_number()
5025+
2
5026+
sage: P2 = K.ideal(2, -a+1)
5027+
sage: P3 = K.ideal(3, a+1)
5028+
sage: P5 = K.ideal(a)
5029+
sage: KS2, gens, fromKS2, toKS2 = K.selmer_space([P2, P3, P5], 2)
5030+
sage: KS2
5031+
Vector space of dimension 4 over Finite Field of size 2
5032+
sage: gens
5033+
[a + 1, a, 2, -1]
5034+
5035+
Each generator must have even valuation at primes not in `S`::
5036+
5037+
sage: [K.ideal(g).factor() for g in gens]
5038+
[(Fractional ideal (2, a + 1)) * (Fractional ideal (3, a + 1)),
5039+
Fractional ideal (-a),
5040+
(Fractional ideal (2, a + 1))^2,
5041+
1]
5042+
5043+
sage: toKS2(10)
5044+
(0, 0, 1, 1)
5045+
sage: fromKS2([0,0,1,1])
5046+
-2
5047+
sage: K(10/(-2)).is_square()
5048+
True
5049+
5050+
sage: KS3, gens, fromKS3, toKS3 = K.selmer_space([P2, P3, P5], 3)
5051+
sage: KS3
5052+
Vector space of dimension 3 over Finite Field of size 3
5053+
sage: gens
5054+
[1/2, 1/4*a + 1/4, a]
5055+
5056+
An example to show that the group 'K(S,2)` may be strictly
5057+
larger than the group of elements giving extensions unramified
5058+
outside `S`. In this case, with `K` of class number `2` and
5059+
`S` empty, there is only one quadratic extension of `K`
5060+
unramified outside `S`, the Hilbert Class Field
5061+
`K(\sqrt{-1})`::
5062+
5063+
sage: K.<a> = QuadraticField(-5)
5064+
sage: KS2, gens, fromKS2, toKS2 = K.selmer_space([], 2)
5065+
sage: KS2
5066+
Vector space of dimension 2 over Finite Field of size 2
5067+
sage: gens
5068+
[2, -1]
5069+
sage: for v in KS2:
5070+
....: if not v:
5071+
....: continue
5072+
....: a = fromKS2(v)
5073+
....: print((a,K.extension(x^2-a, 'roota').relative_discriminant().factor()))
5074+
....:
5075+
(2, (Fractional ideal (2, a + 1))^4)
5076+
(-1, 1)
5077+
(-2, (Fractional ideal (2, a + 1))^4)
5078+
5079+
sage: K.hilbert_class_field('b')
5080+
Number Field in b with defining polynomial x^2 + 1 over its base field
5081+
5082+
"""
5083+
from sage.rings.number_field.selmer_group import pSelmerGroup
5084+
return pSelmerGroup(self, S, p, proof)
5085+
49705086
def composite_fields(self, other, names=None, both_maps=False, preserve_embedding=True):
49715087
"""
49725088
Return the possible composite number fields formed from
@@ -5493,7 +5609,7 @@ def elements_of_norm(self, n, proof=None):
54935609
- ``n`` -- integer in this number field
54945610
54955611
- ``proof`` -- boolean (default: ``True``, unless you called
5496-
``number_field_proof`` and set it otherwise)
5612+
:meth:`proof.number_field` and set it otherwise)
54975613
54985614
OUTPUT:
54995615
@@ -6904,6 +7020,7 @@ def S_unit_group(self, proof=None, S=None):
69047020
INPUT:
69057021
69067022
- ``proof`` (bool, default True) flag passed to ``pari``.
7023+
69077024
- ``S`` - list or tuple of prime ideals, or an ideal, or a single
69087025
ideal or element from which an ideal can be constructed, in
69097026
which case the support is used. If None, the global unit
@@ -11657,12 +11774,15 @@ def is_galois(self):
1165711774
return True
1165811775

1165911776
def class_number(self, proof=None):
11660-
r"""
11661-
Return the size of the class group of self.
11777+
r"""Return the size of the class group of self.
11778+
11779+
INPUT:
1166211780
11663-
If proof = False (*not* the default!) and the discriminant of the
11664-
field is negative, then the following warning from the PARI manual
11665-
applies:
11781+
- ``proof`` -- boolean (default: ``True``, unless you called
11782+
:meth:`proof.number_field` and set it otherwise). If
11783+
``proof`` is ``False`` (*not* the default!), and the
11784+
discriminant of the field is negative, then the following
11785+
warning from the PARI manual applies:
1166611786
1166711787
.. warning::
1166811788
@@ -11701,6 +11821,7 @@ def class_number(self, proof=None):
1170111821
<type 'sage.rings.integer.Integer'>
1170211822
sage: type(CyclotomicField(10).class_number())
1170311823
<type 'sage.rings.integer.Integer'>
11824+
1170411825
"""
1170511826
proof = proof_flag(proof)
1170611827
try:

src/sage/rings/number_field/number_field_ideal.py

+2
Original file line numberDiff line numberDiff line change
@@ -1861,6 +1861,8 @@ def prime_factors(self):
18611861
"""
18621862
return [x[0] for x in self.factor()]
18631863

1864+
support = prime_factors
1865+
18641866
def _div_(self, other):
18651867
"""
18661868
Return the quotient self / other.

src/sage/rings/polynomial/polynomial_quotient_ring.py

+13-10
Original file line numberDiff line numberDiff line change
@@ -1138,7 +1138,7 @@ def _S_decomposition(self, S):
11381138
Compute the decomposition of self into a product of number fields.
11391139
11401140
This is an internal function used by
1141-
:meth:`S_class_group`, :meth:`S_units` and :meth:`selmer_group`.
1141+
:meth:`S_class_group`, :meth:`S_units` and :meth:`selmer_generators`.
11421142
11431143
EXAMPLES::
11441144
@@ -1632,7 +1632,7 @@ def units(self, proof=True):
16321632
"""
16331633
return self.S_units((), proof=proof)
16341634

1635-
def selmer_group(self, S, m, proof=True):
1635+
def selmer_generators(self, S, m, proof=True):
16361636
r"""
16371637
If self is an étale algebra `D` over a number field `K` (i.e.
16381638
a quotient of `K[x]` by a squarefree polynomial) and `S` is a
@@ -1658,19 +1658,19 @@ def selmer_group(self, S, m, proof=True):
16581658
sage: K.<a> = QuadraticField(-5)
16591659
sage: R.<x> = K[]
16601660
sage: D.<T> = R.quotient(x)
1661-
sage: D.selmer_group((), 2)
1661+
sage: D.selmer_generators((), 2)
16621662
[-1, 2]
1663-
sage: D.selmer_group([K.ideal(2, -a+1)], 2)
1663+
sage: D.selmer_generators([K.ideal(2, -a+1)], 2)
16641664
[2, -1]
1665-
sage: D.selmer_group([K.ideal(2, -a+1), K.ideal(3, a+1)], 2)
1665+
sage: D.selmer_generators([K.ideal(2, -a+1), K.ideal(3, a+1)], 2)
16661666
[2, a + 1, -1]
1667-
sage: D.selmer_group((K.ideal(2, -a+1),K.ideal(3, a+1)), 4)
1667+
sage: D.selmer_generators((K.ideal(2, -a+1),K.ideal(3, a+1)), 4)
16681668
[2, a + 1, -1]
1669-
sage: D.selmer_group([K.ideal(2, -a+1)], 3)
1669+
sage: D.selmer_generators([K.ideal(2, -a+1)], 3)
16701670
[2]
1671-
sage: D.selmer_group([K.ideal(2, -a+1), K.ideal(3, a+1)], 3)
1671+
sage: D.selmer_generators([K.ideal(2, -a+1), K.ideal(3, a+1)], 3)
16721672
[2, a + 1]
1673-
sage: D.selmer_group([K.ideal(2, -a+1), K.ideal(3, a+1), K.ideal(a)], 3)
1673+
sage: D.selmer_generators([K.ideal(2, -a+1), K.ideal(3, a+1), K.ideal(a)], 3)
16741674
[2, a + 1, a]
16751675
16761676
"""
@@ -1679,7 +1679,7 @@ def selmer_group(self, S, m, proof=True):
16791679

16801680
component_selmer_groups = []
16811681
for D_iso, S_iso in iso_classes:
1682-
sel = D_iso.selmer_group(S_iso, m, proof=proof)
1682+
sel = D_iso.selmer_generators(S_iso, m, proof=proof)
16831683
component_selmer_groups.append(sel)
16841684

16851685
gens = []
@@ -1696,6 +1696,9 @@ def selmer_group(self, S, m, proof=True):
16961696

16971697
return gens
16981698

1699+
# For backwards compatibility:
1700+
selmer_group = selmer_generators
1701+
16991702
def _factor_multivariate_polynomial(self, f, proof=True):
17001703
r"""
17011704
Return the factorization of ``f`` over this ring.

0 commit comments

Comments
 (0)