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

Commit ce3dfc0

Browse files
committed
Merge branch 'u/saraedum/ticket/15898' of git://trac.sagemath.org/sage into ticket/15898-DirichletGroup_unique
Conflicts: src/sage/modular/dirichlet.py
2 parents f55df77 + 3d01887 commit ce3dfc0

File tree

1 file changed

+116
-75
lines changed

1 file changed

+116
-75
lines changed

src/sage/modular/dirichlet.py

+116-75
Original file line numberDiff line numberDiff line change
@@ -47,10 +47,14 @@
4747
4848
- Craig Citro (2008-02-16): speed up __call__ method for
4949
Dirichlet characters, miscellaneous fixes
50+
51+
- Julian Rueth (2014-03-06): use UniqueFactory to cache DirichletGroups
52+
5053
"""
5154

5255
########################################################################
5356
# Copyright (C) 2004,2005,2006 William Stein <[email protected]>
57+
# 2014 Julian Rueth <[email protected]>
5458
#
5559
# Distributed under the terms of the GNU General Public License (GPL)
5660
#
@@ -78,6 +82,7 @@
7882
from sage.rings.arith import binomial, bernoulli
7983
from sage.structure.element import MultiplicativeGroupElement
8084
from sage.structure.sequence import Sequence
85+
from sage.structure.factory import UniqueFactory
8186

8287
def trivial_character(N, base_ring=rings.RationalField()):
8388
r"""
@@ -1580,55 +1585,41 @@ def element(self):
15801585
return v
15811586

15821587

1583-
_cache = {}
1584-
def DirichletGroup(modulus, base_ring=None, zeta=None, zeta_order=None,
1585-
names=None, integral=False):
1588+
class DirichletGroupFactory(UniqueFactory):
15861589
r"""
1587-
The group of Dirichlet characters modulo `N` with values in
1588-
the subgroup `\langle \zeta_n\rangle` of the
1589-
multiplicative group of the ``base_ring``. If the
1590-
base_ring is omitted then we use `\QQ(\zeta_n)`,
1591-
where `n` is the exponent of
1592-
`(\ZZ/N\ZZ)^*`. If `\zeta` is omitted
1593-
then we compute and use a maximal-order zeta in base_ring, if
1594-
possible.
1590+
The group of Dirichlet characters modulo `N` with values in the subgroup
1591+
`\langle \zeta_n\rangle` of the multiplicative group of the ``base_ring``.
1592+
If ``base_ring`` is omitted then we use `\QQ(\zeta_n)`, where `n` is the
1593+
exponent of `(\ZZ/N\ZZ)^*`. If `\zeta` is omitted then we compute and use a
1594+
maximal-order zeta in ``base_ring``, if possible.
15951595
15961596
INPUT:
15971597
1598+
- ``N`` - an integer
15981599
1599-
- ``modulus`` - int
1600-
1601-
- ``base_ring`` - Ring (optional), where characters
1602-
take their values (should be an integral domain).
1600+
- ``base_ring`` - a ring (optional), where characters take their values
1601+
(should be an integral domain)
16031602
1604-
- ``zeta`` - Element (optional), element of
1605-
base_ring; zeta is a root of unity
1603+
- ``zeta`` - an element (optional), a root of unity in ``base_ring``
16061604
1607-
- ``zeta_order`` - int (optional), the order of zeta
1605+
- ``zeta_order`` - an integer (optional), the order of zeta
16081606
1609-
- ``names`` - ignored (needed so G.... =
1610-
DirichletGroup(...) notation works)
1611-
1612-
- ``integral`` - boolean (default:
1613-
``False``). If ``True``, return the group
1614-
with base_ring the ring of integers in the smallest choice of
1615-
CyclotomicField. Ignored if base_ring is not
1616-
``None``.
1607+
- ``names`` - ignored (needed so ``G.... = DirichletGroup(...)`` notation
1608+
works)
16171609
1610+
- ``integral`` - a boolean (default: ``False``). If ``True``, return the
1611+
group with ``base_ring`` the ring of integers in the smallest choice of
1612+
:meth:`sage.rings.number_field.number_field.CyclotomicField`. Ignored if
1613+
``base_ring`` is not ``None``.
16181614
16191615
OUTPUT:
16201616
1621-
1622-
- ``DirichletGroup`` - a group of Dirichlet
1623-
characters.
1624-
1617+
a group of Dirichlet characters
16251618
16261619
EXAMPLES:
16271620
16281621
The default base ring is a cyclotomic field of order the exponent
1629-
of `(\ZZ/N\ZZ)^*`.
1630-
1631-
::
1622+
of `(\ZZ/N\ZZ)^*`::
16321623
16331624
sage: DirichletGroup(20)
16341625
Group of Dirichlet characters of modulus 20 over Cyclotomic Field of order 4 and degree 2
@@ -1650,13 +1641,13 @@ def DirichletGroup(modulus, base_ring=None, zeta=None, zeta_order=None,
16501641
[Dirichlet character modulo 20 of conductor 1 mapping 11 |--> 1, 17 |--> 1, Dirichlet character modulo 20 of conductor 4 mapping 11 |--> -1, 17 |--> 1, Dirichlet character modulo 20 of conductor 5 mapping 11 |--> 1, 17 |--> -1, Dirichlet character modulo 20 of conductor 20 mapping 11 |--> -1, 17 |--> -1]
16511642
16521643
Next we construct the group of Dirichlet character mod 20, but with
1653-
values in Q(zeta_n)::
1644+
values in `\QQ(\zeta_n)`::
16541645
16551646
sage: G = DirichletGroup(20)
16561647
sage: G.1
16571648
Dirichlet character modulo 20 of conductor 5 mapping 11 |--> 1, 17 |--> zeta4
16581649
1659-
We next compute several invariants of G::
1650+
We next compute several invariants of ``G``::
16601651
16611652
sage: G.gens()
16621653
(Dirichlet character modulo 20 of conductor 4 mapping 11 |--> -1, 17 |--> 1, Dirichlet character modulo 20 of conductor 5 mapping 11 |--> 1, 17 |--> zeta4)
@@ -1668,9 +1659,7 @@ def DirichletGroup(modulus, base_ring=None, zeta=None, zeta_order=None,
16681659
4
16691660
16701661
In this example we create a Dirichlet character with values in a
1671-
number field. We have to give zeta, but not its order.
1672-
1673-
::
1662+
number field. We have to give ``zeta``, but not its order::
16741663
16751664
sage: R.<x> = PolynomialRing(QQ)
16761665
sage: K.<a> = NumberField(x^4 + 1)
@@ -1691,18 +1680,14 @@ def DirichletGroup(modulus, base_ring=None, zeta=None, zeta_order=None,
16911680
sage: loads(G.dumps()) == G
16921681
True
16931682
1694-
We compute a Dirichlet group over a large prime field.
1695-
1696-
::
1683+
We compute a Dirichlet group over a large prime field::
16971684
16981685
sage: p = next_prime(10^40)
16991686
sage: g = DirichletGroup(19, GF(p)); g
17001687
Group of Dirichlet characters of modulus 19 over Finite Field of size 10000000000000000000000000000000000000121
17011688
17021689
Note that the root of unity has small order, i.e., it is not the
1703-
largest order root of unity in the field.
1704-
1705-
::
1690+
largest order root of unity in the field::
17061691
17071692
sage: g.zeta_order()
17081693
2
@@ -1732,42 +1717,98 @@ def DirichletGroup(modulus, base_ring=None, zeta=None, zeta_order=None,
17321717
Group of Dirichlet characters of modulus 60 over Maximal Order in Cyclotomic Field of order 4 and degree 2
17331718
sage: parent(DirichletGroup(60, integral=True).gens()[2].values_on_gens()[2])
17341719
Maximal Order in Cyclotomic Field of order 4 and degree 2
1720+
1721+
TESTS:
1722+
1723+
Dirichlet groups are cached, creating two groups with the same parameters
1724+
yields the same object::
1725+
1726+
sage: DirichletGroup(60) is DirichletGroup(60)
1727+
True
1728+
17351729
"""
1736-
modulus = rings.Integer(modulus)
1730+
def create_key(self, N, base_ring=None, zeta=None, zeta_order=None, names=None, integral=False):
1731+
"""
1732+
Create a key that uniquely determines a Dirichlet group.
17371733
1738-
if base_ring is None:
1739-
if not (zeta is None and zeta_order is None):
1740-
raise ValueError("zeta and zeta_order must be None if base_ring not specified.")
1741-
e = rings.IntegerModRing(modulus).unit_group_exponent()
1742-
base_ring = rings.CyclotomicField(e)
1743-
if integral:
1744-
base_ring = base_ring.ring_of_integers()
1734+
TESTS::
17451735
1746-
if not is_Ring(base_ring):
1747-
raise TypeError("base_ring (=%s) must be a ring"%base_ring)
1736+
sage: DirichletGroup.create_key(60)
1737+
(Cyclotomic Field of order 4 and degree 2, 60, zeta4, 4)
17481738
1749-
if zeta is None:
1750-
e = rings.IntegerModRing(modulus).unit_group_exponent()
1751-
try:
1752-
zeta = base_ring.zeta(e)
1739+
An example to illustrate that ``base_ring`` is a part of the key::
1740+
1741+
sage: k = DirichletGroup.create_key(2, base_ring=QQ); k
1742+
(Rational Field, 2, 1, 1)
1743+
sage: l = DirichletGroup.create_key(2, base_ring=CC); l
1744+
(Complex Field with 53 bits of precision, 2, 1.00000000000000, 1)
1745+
sage: k == l
1746+
False
1747+
sage: G = DirichletGroup.create_object(None, k); G
1748+
Group of Dirichlet characters of modulus 2 over Rational Field
1749+
sage: H = DirichletGroup.create_object(None, l); H
1750+
Group of Dirichlet characters of modulus 2 over Complex Field with 53 bits of precision
1751+
sage: G == H
1752+
False
1753+
1754+
If ``base_ring`` was not be a part of the key, the keys would compare
1755+
equal and the caching would be broken::
1756+
1757+
sage: k = k[1:]; k
1758+
(2, 1, 1)
1759+
sage: l = l[1:]; l
1760+
(2, 1.00000000000000, 1)
1761+
sage: k == l
1762+
True
1763+
sage: DirichletGroup(2, base_ring=QQ) is DirichletGroup(2, base_ring=CC)
1764+
False
1765+
1766+
"""
1767+
modulus = rings.Integer(N)
1768+
1769+
if base_ring is None:
1770+
if not (zeta is None and zeta_order is None):
1771+
raise ValueError, "zeta and zeta_order must be None if base_ring not specified."
1772+
e = rings.IntegerModRing(modulus).unit_group_exponent()
1773+
base_ring = rings.CyclotomicField(e)
1774+
if integral:
1775+
base_ring = base_ring.ring_of_integers()
1776+
1777+
if not is_Ring(base_ring):
1778+
raise TypeError, "base_ring (=%s) must be a ring"%base_ring
1779+
1780+
if zeta is None:
1781+
e = rings.IntegerModRing(modulus).unit_group_exponent()
1782+
try:
1783+
zeta = base_ring.zeta(e)
1784+
zeta_order = zeta.multiplicative_order()
1785+
except (TypeError, ValueError, ArithmeticError):
1786+
zeta = base_ring.zeta(base_ring.zeta_order())
1787+
n = zeta.multiplicative_order()
1788+
zeta_order = arith.GCD(e,n)
1789+
zeta = zeta**(n//zeta_order)
1790+
1791+
elif zeta_order is None:
17531792
zeta_order = zeta.multiplicative_order()
1754-
except (TypeError, ValueError, ArithmeticError):
1755-
zeta = base_ring.zeta(base_ring.zeta_order())
1756-
n = zeta.multiplicative_order()
1757-
zeta_order = arith.GCD(e,n)
1758-
zeta = zeta**(n//zeta_order)
1759-
1760-
elif zeta_order is None:
1761-
zeta_order = zeta.multiplicative_order()
1762-
1763-
key = (base_ring, modulus, zeta, zeta_order)
1764-
if key in _cache:
1765-
x = _cache[key]()
1766-
if not x is None: return x
1767-
1768-
R = DirichletGroup_class(modulus, zeta, zeta_order)
1769-
_cache[key] = weakref.ref(R)
1770-
return R
1793+
1794+
return (base_ring, modulus, zeta, zeta_order)
1795+
1796+
def create_object(self, version, key, **extra_args):
1797+
"""
1798+
Create the object from the key (extra arguments are ignored). This is
1799+
only called if the object was not found in the cache.
1800+
1801+
TESTS::
1802+
1803+
sage: K = CyclotomicField(4)
1804+
sage: DirichletGroup.create_object(None, (K, 60, K.gen(), 4))
1805+
Group of Dirichlet characters of modulus 60 over Cyclotomic Field of order 4 and degree 2
1806+
1807+
"""
1808+
base_ring, modulus, zeta, zeta_order = key
1809+
return DirichletGroup_class(modulus, zeta, zeta_order)
1810+
1811+
DirichletGroup = DirichletGroupFactory("DirichletGroup")
17711812

17721813
def is_DirichletGroup(x):
17731814
"""

0 commit comments

Comments
 (0)