47
47
48
48
- Craig Citro (2008-02-16): speed up __call__ method for
49
49
Dirichlet characters, miscellaneous fixes
50
+
51
+ - Julian Rueth (2014-03-06): use UniqueFactory to cache DirichletGroups
52
+
50
53
"""
51
54
52
55
########################################################################
53
56
# Copyright (C) 2004,2005,2006 William Stein <[email protected] >
57
+ # 2014 Julian Rueth <[email protected] >
54
58
#
55
59
# Distributed under the terms of the GNU General Public License (GPL)
56
60
#
78
82
from sage .rings .arith import binomial , bernoulli
79
83
from sage .structure .element import MultiplicativeGroupElement
80
84
from sage .structure .sequence import Sequence
85
+ from sage .structure .factory import UniqueFactory
81
86
82
87
def trivial_character (N , base_ring = rings .RationalField ()):
83
88
r"""
@@ -1580,55 +1585,41 @@ def element(self):
1580
1585
return v
1581
1586
1582
1587
1583
- _cache = {}
1584
- def DirichletGroup (modulus , base_ring = None , zeta = None , zeta_order = None ,
1585
- names = None , integral = False ):
1588
+ class DirichletGroupFactory (UniqueFactory ):
1586
1589
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.
1595
1595
1596
1596
INPUT:
1597
1597
1598
+ - ``N`` - an integer
1598
1599
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)
1603
1602
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``
1606
1604
1607
- - ``zeta_order`` - int (optional), the order of zeta
1605
+ - ``zeta_order`` - an integer (optional), the order of zeta
1608
1606
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)
1617
1609
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``.
1618
1614
1619
1615
OUTPUT:
1620
1616
1621
-
1622
- - ``DirichletGroup`` - a group of Dirichlet
1623
- characters.
1624
-
1617
+ a group of Dirichlet characters
1625
1618
1626
1619
EXAMPLES:
1627
1620
1628
1621
The default base ring is a cyclotomic field of order the exponent
1629
- of `(\ZZ/N\ZZ)^*`.
1630
-
1631
- ::
1622
+ of `(\ZZ/N\ZZ)^*`::
1632
1623
1633
1624
sage: DirichletGroup(20)
1634
1625
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,
1650
1641
[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]
1651
1642
1652
1643
Next we construct the group of Dirichlet character mod 20, but with
1653
- values in Q( zeta_n)::
1644
+ values in `\QQ(\ zeta_n)` ::
1654
1645
1655
1646
sage: G = DirichletGroup(20)
1656
1647
sage: G.1
1657
1648
Dirichlet character modulo 20 of conductor 5 mapping 11 |--> 1, 17 |--> zeta4
1658
1649
1659
- We next compute several invariants of G ::
1650
+ We next compute several invariants of ``G`` ::
1660
1651
1661
1652
sage: G.gens()
1662
1653
(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,
1668
1659
4
1669
1660
1670
1661
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::
1674
1663
1675
1664
sage: R.<x> = PolynomialRing(QQ)
1676
1665
sage: K.<a> = NumberField(x^4 + 1)
@@ -1691,18 +1680,14 @@ def DirichletGroup(modulus, base_ring=None, zeta=None, zeta_order=None,
1691
1680
sage: loads(G.dumps()) == G
1692
1681
True
1693
1682
1694
- We compute a Dirichlet group over a large prime field.
1695
-
1696
- ::
1683
+ We compute a Dirichlet group over a large prime field::
1697
1684
1698
1685
sage: p = next_prime(10^40)
1699
1686
sage: g = DirichletGroup(19, GF(p)); g
1700
1687
Group of Dirichlet characters of modulus 19 over Finite Field of size 10000000000000000000000000000000000000121
1701
1688
1702
1689
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::
1706
1691
1707
1692
sage: g.zeta_order()
1708
1693
2
@@ -1732,42 +1717,98 @@ def DirichletGroup(modulus, base_ring=None, zeta=None, zeta_order=None,
1732
1717
Group of Dirichlet characters of modulus 60 over Maximal Order in Cyclotomic Field of order 4 and degree 2
1733
1718
sage: parent(DirichletGroup(60, integral=True).gens()[2].values_on_gens()[2])
1734
1719
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
+
1735
1729
"""
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.
1737
1733
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::
1745
1735
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 )
1748
1738
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 :
1753
1792
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" )
1771
1812
1772
1813
def is_DirichletGroup (x ):
1773
1814
"""
0 commit comments