Ticket #8327: trac_8327-universal_cyclotomic_field-cs.patch

File trac_8327-universal_cyclotomic_field-cs.patch, 102.1 KB (added by stumpc5, 7 years ago)
  • doc/en/reference/rings_standard.rst

    # HG changeset patch
    # User Christian Stump <christian.stump at gmail.com>
    # Date 1353496409 -3600
    # Node ID 4af527f71faca630ce3c6397ea84003263b4de55
    # Parent  a2d15db97b53027c5582974c3bdc4091ec8bff44
    trac 8327: Implementation of the universal cyclotomic field
    
    diff --git a/doc/en/reference/rings_standard.rst b/doc/en/reference/rings_standard.rst
    a b Standard Commutative Rings 
    1515   
    1616   sage/rings/finite_rings/constructor
    1717   sage/rings/finite_rings/element_base
     18
     19   sage/rings/universal_cyclotomic_field/universal_cyclotomic_field
  • module_list.py

    diff --git a/module_list.py b/module_list.py
    a b ext_modules = [ 
    14701470    Extension('sage.rings.ring',
    14711471              sources = ['sage/rings/ring.pyx']),
    14721472
     1473    Extension('sage.rings.universal_cyclotomic_field.universal_cyclotomic_field_c',
     1474              sources = ['sage/rings/universal_cyclotomic_field/universal_cyclotomic_field_c.pyx'],
     1475              include_dirs = numpy_include_dirs,
     1476              depends = numpy_depends),
     1477
    14731478        ################################
    14741479        ##
    14751480        ## sage.rings.finite_rings
  • sage/modules/free_module.py

    diff --git a/sage/modules/free_module.py b/sage/modules/free_module.py
    a b import sage.rings.infinity 
    181181import sage.rings.integer
    182182import sage.structure.parent_gens as gens
    183183from sage.categories.principal_ideal_domains import PrincipalIdealDomains
     184from sage.categories.commutative_rings import CommutativeRings
    184185from sage.misc.randstate import current_randstate
    185186from sage.structure.sequence import Sequence
    186187
  • sage/rings/all.py

    diff --git a/sage/rings/all.py b/sage/rings/all.py
    a b from real_lazy import RealLazyField, RLF 
    8989# Polynomial Rings and Polynomial Quotient Rings
    9090from polynomial.all import *
    9191
     92
    9293# Algebraic numbers
    9394from qqbar import (AlgebraicRealField, is_AlgebraicRealField, AA,
    9495                   AlgebraicReal, is_AlgebraicReal,
    from residue_field import ResidueField 
    160161from misc import composite_field
    161162
    162163import tests
     164
     165# Universal Cyclotomic Field
     166from sage.rings.universal_cyclotomic_field.all import *
  • sage/rings/number_field/number_field.py

    diff --git a/sage/rings/number_field/number_field.py b/sage/rings/number_field/number_field.py
    a b AUTHORS: 
    1919- Robert Harron (2012-08): added is_CM(), complex_conjugation(), and
    2020  maximal_totally_real_subfield()
    2121
     22- Christian Stump (2012-11): added conversion to universal cyclotomic field
     23
    2224.. note::
    2325
    2426   Unlike in PARI/GP, class group computations *in Sage* do *not* by default
    def is_QuadraticField(x): 
    781783
    782784   
    783785_cyclo_cache = {}
    784 def CyclotomicField(n, names=None, embedding=True):
     786def CyclotomicField(n=0, names=None, bracket="()", embedding=True):
    785787    r"""
    786     Return the n-th cyclotomic field, where n is a positive integer.
    787    
     788    Return the `n`-th cyclotomic field, where n is a positive integer,
     789    or the universal cyclotomic field if ``n==0``.
     790
     791    For the documentation of the universal cyclotomic field, see :class:`~sage.rings.universal_cyclotomic_field.universal_cyclotomic_field.UniversalCyclotomicField`.
     792
    788793    INPUT:
    789    
    790     -  ``n`` - a positive integer
    791    
    792     -  ``names`` - name of generator (optional - defaults
    793        to zetan).
    794    
     794
     795    -  ``n`` - a nonnegative integer, default:``0``
     796
     797    -  ``names`` - name of generator (optional - defaults to zetan)
     798
     799    - ``bracket`` - Defines the brackets in the case of ``n==0``, and
     800      is ignored otherwise. Can be any even length string, with ``"()"`` being the default.
     801
    795802    -  ``embedding`` - bool or n-th root of unity in an
    796803       ambient field (default True)
    797    
    798    
    799     EXAMPLES: We create the `7`\th cyclotomic field
     804
     805    EXAMPLES:
     806
     807    If called without a parameter, we get the :class:`universal cyclotomic field<sage.rings.universal_cyclotomic_field.universal_cyclotomic_field.UniversalCyclotomicField>`::
     808
     809        sage: CyclotomicField()
     810        Universal Cyclotomic Field
     811
     812    We create the `7`\th cyclotomic field
    800813    `\QQ(\zeta_7)` with the default generator name.
    801    
     814
    802815    ::
    803    
     816
    804817        sage: k = CyclotomicField(7); k
    805818        Cyclotomic Field of order 7 and degree 6
    806819        sage: k.gen()
    807820        zeta7
    808    
     821
    809822    The default embedding sends the generator to the complex primitive
    810823    `n^{th}` root of unity of least argument.
    811    
     824
    812825    ::
    813    
     826
    814827        sage: CC(k.gen())
    815828        0.623489801858734 + 0.781831482468030*I
    816    
     829
    817830    Cyclotomic fields are of a special type.
    818    
     831
    819832    ::
    820    
     833
    821834        sage: type(k)
    822835        <class 'sage.rings.number_field.number_field.NumberField_cyclotomic_with_category'>
    823    
     836
    824837    We can specify a different generator name as follows.
    825    
     838
    826839    ::
    827    
     840
    828841        sage: k.<z7> = CyclotomicField(7); k
    829842        Cyclotomic Field of order 7 and degree 6
    830843        sage: k.gen()
    831844        z7
    832    
     845
    833846    The `n` must be an integer.
    834    
     847
    835848    ::
    836    
     849
    837850        sage: CyclotomicField(3/2)
    838851        Traceback (most recent call last):
    839852        ...
    840853        TypeError: no conversion of this rational to integer
    841    
    842     The degree must be positive.
    843    
     854
     855    The degree must be nonnegative.
     856
    844857    ::
    845    
    846         sage: CyclotomicField(0)
     858
     859        sage: CyclotomicField(-1)
    847860        Traceback (most recent call last):
    848861        ...
    849         ValueError: n (=0) must be a positive integer
    850    
     862        ValueError: n (=-1) must be a positive integer
     863
    851864    The special case `n=1` does *not* return the rational
    852865    numbers::
    853    
     866
    854867        sage: CyclotomicField(1)
    855868        Cyclotomic Field of order 1 and degree 1
    856    
     869
    857870    Due to their default embedding into `\CC`,
    858871    cyclotomic number fields are all compatible.
    859    
     872
    860873    ::
    861    
     874
    862875        sage: cf30 = CyclotomicField(30)
    863876        sage: cf5 = CyclotomicField(5)
    864877        sage: cf3 = CyclotomicField(3)
    def CyclotomicField(n, names=None, embed 
    886899        zeta9^3
    887900    """
    888901    n = ZZ(n)
    889     if n <= 0:
     902    if n == 0:
     903        from sage.rings.universal_cyclotomic_field.universal_cyclotomic_field import UniversalCyclotomicField
     904        return UniversalCyclotomicField(names=names, bracket=bracket, embedding=embedding)
     905    if n < 0:
    890906        raise ValueError, "n (=%s) must be a positive integer"%n
    891    
     907
    892908    if names is None:
    893909        names = "zeta%s"%n
    894910    names = sage.structure.parent_gens.normalize_names(1, names)
    class NumberField_generic(number_field_b 
    12561272        else:
    12571273            return w
    12581274
     1275    def _coerce_from_universal_cyclotomic_field(self, x):
     1276        """
     1277        Coerce an element of the universal cyclotomic field
     1278        into this cyclotomic field.
     1279
     1280        EXAMPLES::
     1281
     1282            sage: CF = CyclotomicField(5)
     1283            sage: UCF.<E> = UniversalCyclotomicField()
     1284
     1285            sage: CF(E(5)) # indirect doctest
     1286            zeta5
     1287
     1288            sage: CF = CyclotomicField(7)
     1289            sage: CF(E(5)) # indirect doctest
     1290            Traceback (most recent call last):
     1291            ...
     1292            TypeError: The element E(5) cannot be converted to Cyclotomic Field of order 7 and degree 6
     1293
     1294            sage: CF = CyclotomicField(10)
     1295            sage: CF(E(5)) # indirect doctest
     1296            zeta10^2
     1297
     1298        Matrices are correctly dealt with::
     1299
     1300            sage: M = Matrix(UCF,2,[E(3),E(4),E(5),E(6)]); M
     1301            [   E(3)    E(4)]
     1302            [   E(5) -E(3)^2]
     1303
     1304            sage: Matrix(CyclotomicField(60),M) # indirect doctest
     1305            [zeta60^10 - 1     zeta60^15]
     1306            [    zeta60^12     zeta60^10]
     1307
     1308        Using a non-standard embedding::
     1309
     1310            sage: CF = CyclotomicField(5,embedding=CC(exp(4*pi*i/5)))
     1311            sage: x = E(5)
     1312            sage: CC(x)
     1313            0.309016994374947 + 0.951056516295154*I
     1314            sage: CC(CF(x))
     1315            0.309016994374947 + 0.951056516295154*I
     1316
     1317            sage: UCF.<E> = UniversalCyclotomicField(embedding=None)
     1318            sage: CF(E(5))
     1319            Traceback (most recent call last):
     1320            ...
     1321            TypeError: The element E(5) cannot be converted to Cyclotomic Field of order 5 and degree 4
     1322        """
     1323        from sage.rings.universal_cyclotomic_field.universal_cyclotomic_field import UniversalCyclotomicField
     1324        assert isinstance(x,UniversalCyclotomicField.Element)
     1325        if not x.parent()._has_standard_embedding or self._n() % x.field_order():
     1326            raise TypeError("The element %s cannot be converted to %s"%(x,self))
     1327        return self(x.to_cyclotomic_field())
     1328
    12591329    def _Hom_(self, codomain, cat=None):
    12601330        """
    12611331        Return homset of homomorphisms from self to the number field
    class NumberField_cyclotomic(NumberField 
    79488018            zeta42^7 - 1
    79498019            sage: k6(b^2)
    79508020            zeta6 - 1
    7951        
    7952         Coercion of GAP cyclotomic elements is also supported::
     8021
     8022        Conversion of elements of the :class:`~sage.rings.universal_cyclotomic_field.universal_cyclotomic_field.UniversalCyclotomicField`::
     8023
     8024            sage: CF = CyclotomicField(5)
     8025            sage: UCF.<E> = UniversalCyclotomicField()
     8026            sage: CF(E(5))
     8027            zeta5
     8028
     8029            sage: CF = CyclotomicField(10)
     8030            sage: CF(E(5))
     8031            zeta10^2
     8032
     8033       Coercion of GAP cyclotomic elements is also supported::
    79538034
    79548035            sage: CyclotomicField(18)(gap('E(3)')) # indirect doctest
    79558036            zeta18^3 - 1
    class NumberField_cyclotomic(NumberField 
    79638044            sage: K(O.1^2 + O.1 - 2)
    79648045            z^2 + z - 2
    79658046        """
     8047        from sage.rings.universal_cyclotomic_field.universal_cyclotomic_field import UniversalCyclotomicField
     8048
    79668049        if isinstance(x, number_field_element.NumberFieldElement):
    79678050            if isinstance(x.parent(), NumberField_cyclotomic):
    79688051                return self._coerce_from_other_cyclotomic_field(x)
    class NumberField_cyclotomic(NumberField 
    79708053                return NumberField_absolute._element_constructor_(self, x)
    79718054        elif sage.interfaces.gap.is_GapElement(x):
    79728055            return self._coerce_from_gap(x)
     8056        elif isinstance(x,UniversalCyclotomicField.Element):
     8057            return self._coerce_from_universal_cyclotomic_field(x)
    79738058        elif isinstance(x,str):
    79748059            return self._coerce_from_str(x)
    79758060        else:
  • new file sage/rings/universal_cyclotomic_field/__init__.py

    diff --git a/sage/rings/universal_cyclotomic_field/__init__.py b/sage/rings/universal_cyclotomic_field/__init__.py
    new file mode 100644
    - +  
     1# Initialization file for universal_cyclotomic_field
  • new file sage/rings/universal_cyclotomic_field/all.py

    diff --git a/sage/rings/universal_cyclotomic_field/all.py b/sage/rings/universal_cyclotomic_field/all.py
    new file mode 100644
    - +  
     1# for lazy importing
     2from sage.misc.lazy_import import lazy_import
     3
     4lazy_import("sage.rings.universal_cyclotomic_field.universal_cyclotomic_field","UniversalCyclotomicField")
  • new file sage/rings/universal_cyclotomic_field/universal_cyclotomic_field.py

    diff --git a/sage/rings/universal_cyclotomic_field/universal_cyclotomic_field.py b/sage/rings/universal_cyclotomic_field/universal_cyclotomic_field.py
    new file mode 100644
    - +  
     1r"""
     2The universal cyclotomic field (UCF)
     3
     4Implementation of the universal cyclotomic field using the :meth:`Zumbroich basis<UniversalCyclotomicField.zumbroich_basis_indices>`.
     5The universal cyclotomic field is the smallest subfield of the complex field
     6containing all roots of unity.
     7
     8REFERENCES:
     9
     10.. [Bre97] T. Breuer "Integral bases for subfields of cyclotomic fields" AAECC 8, 279--289 (1997).
     11
     12AUTHORS:
     13
     14- Christian Stump
     15
     16.. NOTE::
     17
     18    - This function behaves exactly like the *Cyclotomics* in *GAP*.
     19    - The universal cyclotomic field is used to work with non-crystallographic
     20      reflection groups. E.g., to work with elements as matrices, computing
     21      *reflecting hyperplanes*, and *characters*.
     22    - To multiply matrices over the universal cyclotomic field, it is still
     23      *much* faster to coerce it to a cyclotomic field and to the
     24      computation there.
     25
     26.. TODO::
     27
     28    - implementation of matrices over the universal cyclotomic field.
     29    - speed improvements of the cythonized methods.
     30    - speed improvements for scalar multiples.
     31    - Remove the inheritance from Field and FieldElement as soon as
     32      the methods ``is_field(proof=True)`` is implemented in the Fields category.
     33
     34
     35EXAMPLES:
     36
     37The universal cyclotomic field is constructed using::
     38
     39    sage: UCF = UniversalCyclotomicField(); UCF
     40    Universal Cyclotomic Field
     41
     42One can as well construct it through :func:`~sage.ring.number_field.number_field.CyclotomicField`::
     43
     44    sage: UCF = CyclotomicField(); UCF
     45    Universal Cyclotomic Field
     46
     47The cyclotomics themselves are accessable through::
     48
     49    sage: UCF.gen(5)
     50    E(5)
     51    sage: UCF.gen(5,2)
     52    E(5)^2
     53
     54or the alias::
     55
     56    sage: UCF.gen(5)
     57    E(5)
     58    sage: UCF.gen(5,2)
     59    E(5)^2
     60
     61One can as well access the universal cyclotomic field using::
     62
     63    sage: UCF.<E> = UniversalCyclotomicField();
     64    sage: E(5)
     65    E(5)
     66
     67Other names are supported as well::
     68
     69    sage: UCF.<zeta> = UniversalCyclotomicField();
     70    sage: zeta(5)
     71    zeta(5)
     72
     73As are other bracketings::
     74
     75    sage: UCF.<E> = UniversalCyclotomicField(bracket='');
     76    sage: E(5)
     77    E5
     78
     79    sage: UCF.<E> = UniversalCyclotomicField(bracket="[]");
     80    sage: E(5)
     81    E[5]
     82
     83    sage: UCF.<E> = UniversalCyclotomicField(bracket="(ABCXYZ)");
     84    sage: E(5)
     85    E(ABC5XYZ)
     86
     87We use the generator "E" and the standard bracketing throughout this file::
     88
     89    sage: UCF.<E> = UniversalCyclotomicField();
     90
     91Some very first examples::
     92
     93    sage: E(2)
     94    -1
     95    sage: E(3)
     96    E(3)
     97    sage: E(6)
     98    -E(3)^2
     99
     100Equality and inequality checks::
     101
     102    sage: E(6,2) == E(6)^2 == E(3)
     103    True
     104
     105    sage: E(6)^2 != E(3)
     106    False
     107
     108Addition and multiplication::
     109
     110    sage: E(2) * E(3)
     111    -E(3)
     112    sage: f = E(2) + E(3); f
     113    2*E(3) + E(3)^2
     114
     115Inverses::
     116
     117    sage: f^-1
     118    1/3*E(3) + 2/3*E(3)^2
     119    sage: f.inverse()
     120    1/3*E(3) + 2/3*E(3)^2
     121    sage: f * f.inverse()
     122    1
     123
     124Complex conjugation::
     125
     126    sage: f.conjugate()
     127    E(3) + 2*E(3)^2
     128
     129Galois conjugation::
     130
     131    sage: f.galois_conjugates()
     132    [2*E(3) + E(3)^2, E(3) + 2*E(3)^2]
     133    sage: f.norm_of_galois_extension()
     134    3
     135
     136Coercion to the algebraic field :class:`QQbar<sage.rings.qqbar.AlgebraicField>`::
     137
     138    sage: QQbar(E(3))
     139    -0.500000000000000? + 0.866025403784439?*I
     140    sage: QQbar(f)
     141    -1.500000000000000? + 0.866025403784439?*I
     142
     143Partial conversion to the real algebraic field :class:`AA<sage.rings.qqbar.AlgebraicRealField>`::
     144
     145    sage: AA(E(5)+E(5).conjugate())
     146    0.618033988749895?
     147
     148    sage: AA(E(5))
     149    Traceback (most recent call last):
     150    ...
     151    TypeError: No conversion of E(5) to the real algebraic field AA.
     152
     153One can as well define the universal cyclotomic field without any embedding::
     154
     155    sage: UCF.<E> = UniversalCyclotomicField(embedding=None); UCF
     156    Universal Cyclotomic Field
     157
     158    sage: UCF.<E> = UniversalCyclotomicField(embedding=False); UCF
     159    Universal Cyclotomic Field
     160
     161    sage: QQbar(E(5))
     162    Traceback (most recent call last):
     163    ...
     164    TypeError: Illegal initializer for algebraic number
     165
     166Conversion to :class:`CyclotomicField<sage.rings.number_field.number_field.CyclotomicField>`:
     167
     168.. WARNING::
     169
     170    This is only possible if ``self`` has the standard embedding
     171
     172::
     173
     174    sage: UCF.<E> = UniversalCyclotomicField()
     175
     176    sage: E(5).to_cyclotomic_field()
     177    zeta5
     178
     179    sage: f = E(2) + E(3)
     180    sage: f.to_cyclotomic_field()
     181    zeta3 - 1
     182
     183    sage: CF = CyclotomicField(5)
     184    sage: CF(E(5))
     185    zeta5
     186
     187    sage: CF = CyclotomicField(7)
     188    sage: CF(E(5))
     189    Traceback (most recent call last):
     190    ...
     191    TypeError: The element E(5) cannot be converted to Cyclotomic Field of order 7 and degree 6
     192
     193    sage: CF = CyclotomicField(10)
     194    sage: CF(E(5))
     195    zeta10^2
     196
     197Conversions to and from GAP::
     198
     199    sage: a = gap('E(6)'); a
     200    -E(3)^2
     201    sage: a.parent()
     202    Gap
     203
     204    sage: b = UCF.from_gap(a); b
     205    -E(3)^2
     206    sage: b.parent()
     207    Universal Cyclotomic Field
     208
     209    sage: gap(b)
     210    -E(3)^2
     211
     212Conversions to and from the *cyclotomic field*::
     213
     214    sage: a = E(6).to_cyclotomic_field(); a
     215    zeta3 + 1
     216
     217    sage: UCF.from_cyclotomic_field(a)
     218    -E(3)^2
     219
     220One can also do basic arithmetics with matrices over the universal cyclotomic field::
     221
     222    sage: m = matrix(2,[E(3),1,1,E(4)]); m
     223    [E(3)    1]
     224    [   1 E(4)]
     225    sage: m.parent()
     226    Full MatrixSpace of 2 by 2 dense matrices over Universal Cyclotomic Field
     227
     228    sage: m^2
     229    [                       -E(3) E(12)^4 - E(12)^7 - E(12)^11]
     230    [E(12)^4 - E(12)^7 - E(12)^11                            0]
     231
     232    sage: -m
     233    [-E(3)    -1]
     234    [   -1 -E(4)]
     235
     236And compute its *characteristic polynomial*, *echelon form*, *pivots*, and thus its *rank*::
     237
     238    sage: m.charpoly()
     239    x^2 + (-E(12)^4 + E(12)^7 + E(12)^11)*x + E(12)^4 + E(12)^7 + E(12)^8
     240
     241    sage: m.echelon_form()
     242    [1 0]
     243    [0 1]
     244
     245    sage: m.pivots()
     246    (0, 1)
     247
     248    sage: m.rank()
     249    2
     250
     251The eigenvalues do not (yet) work::
     252
     253    sage: m.eigenvalues() # not implemented
     254    ...
     255    NotImplementedError:
     256
     257A long real life test. Computing ``N3`` is much faster than computing
     258``N2`` which is again 3 times faster than computing ``N1``::
     259
     260    sage: W = gap3.ComplexReflectionGroup(14)       #optional - gap3 # long time
     261    sage: UC = W.UnipotentCharacters()              #optional - gap3 # long time
     262    sage: UCF.<E> = UniversalCyclotomicField();     #optional - gap3 # long time
     263    sage: M = matrix(UCF,UC.families[2].fourierMat) #optional - gap3 # long time
     264    sage: N1 = M*M                                  #optional - gap3 # long time
     265
     266    sage: N2 = UCF._matrix_mult(M,M)                #optional - gap3 # long time
     267    sage: CF = CyclotomicField(24)                  #optional - gap3 # long time
     268    sage: M = matrix(CF,M)                          #optional - gap3 # long time
     269    sage: N3 = matrix(UCF,M*M)                      #optional - gap3 # long time
     270    sage: N1 == N2 == N3                            #optional - gap3 # long time
     271    True
     272
     273TESTS:
     274
     275As an indication that everything works, we start with a test that we
     276obtain the same answers as in GAP::
     277
     278    sage: all(str(E(n,k)).translate(None,' ') == gap.execute('E('+str(n)+')^'+str(k)).translate(None,'\n ') for n in range(1,15) for k in range(n))
     279    True
     280
     281The following didn't work first::
     282
     283    sage: str(-E(9)^4-E(9)^7).translate(None,' ') == gap.execute('-E(9)^4-E(9)^7').translate(None,'\n ')
     284    True
     285    sage: str(-E(9)^5-E(9)^8).translate(None,' ') == gap.execute('-E(9)^5-E(9)^8').translate(None,'\n ')
     286    True
     287"""
     288#*****************************************************************************
     289#       Copyright (C) 2012 Christian Stump <christian.stump@univie.ac.at>
     290#
     291#  Distributed under the terms of the GNU General Public License (GPL)
     292#                  http://www.gnu.org/licenses/
     293#*****************************************************************************
     294from sage.misc.cachefunc import cached_method
     295from sage.misc.lazy_import import lazy_import
     296
     297from random import randint, randrange, sample, choice
     298
     299import sage.structure.parent_base
     300from sage.structure.unique_representation import UniqueRepresentation
     301from sage.structure.element import parent, FieldElement, Element
     302from sage.structure.parent import Parent
     303
     304from sage.structure.element_wrapper import ElementWrapper
     305from sage.structure.sage_object import have_same_parent
     306
     307from sage.categories.morphism import SetMorphism
     308from sage.categories.sets_with_partial_maps import SetsWithPartialMaps
     309from sage.categories.sets_cat import Sets
     310from sage.categories.homset import Hom
     311
     312from sage.rings.all import ZZ, QQ, CC
     313from sage.rings.ring import Field
     314from sage.rings.qqbar import QQbar, AA
     315from sage.rings.number_field.number_field import CyclotomicField
     316from sage.rings.integer import GCD_list, LCM_list
     317
     318from sage.rings.real_mpfr import RealField, mpfr_prec_min
     319from sage.rings.complex_field import ComplexField
     320from sage.rings.real_lazy import RLF, CLF
     321
     322from sage.combinat.dict_addition import dict_linear_combination, dict_addition
     323
     324from sage.rings.universal_cyclotomic_field.universal_cyclotomic_field_c import ZumbroichBasisCython,push_down_cython,ZumbroichDecomposition,galois_conjugates_cython,push_to_higher_field,dict_multiplication,dict_vector_multiplication
     325
     326class UniversalCyclotomicField(UniqueRepresentation, Field):
     327    r"""
     328    The *universal cyclotomic field*, which is the smallest field containing
     329    the rational numbers together with all roots of unity.
     330
     331    Its elements are represented as linear combinations of the so-called
     332    *Zumbroich basis*.
     333
     334    EXAMPLES::
     335
     336        sage: UCF.<E> = UniversalCyclotomicField(); UCF
     337        Universal Cyclotomic Field
     338        sage: E(12)
     339        -E(12)^7
     340        sage: E(12) in UCF
     341        True
     342
     343    One also has access to the universal cyclotomic field using the function :func:`CyclotomicField`::
     344
     345        sage: UCF = CyclotomicField(); UCF
     346        Universal Cyclotomic Field
     347
     348    One can also construct a vector space over the universal cyclotomic field::
     349
     350        sage: UCF^3
     351        Vector space of dimension 3 over Universal Cyclotomic Field
     352    """
     353    def __init__(self,names="E",bracket="()",embedding=True):
     354        r"""
     355
     356        :param names: The string name for the root of unity
     357        :type names: optional, default:"E"
     358        :param bracket: The bracket used in string representations. Can be any even length string
     359        :type bracket: optional, default:"()"
     360        :param embedding: The given embedding of ``self`` into the complex numbers. Can be
     361            - ``True``: The standard embedding
     362            - ``None`` or ``False``: No embedding
     363            - An indexable `f(n) \in \mathbb{N}` such that `0 \leq f(n) < n` sending the generator ``E(n)`` to `e^{ 2 \pi i k / n }`.
     364        :param embedding: optional, default:``True``
     365
     366        .. WARNING::
     367
     368            The optional argument ``embedding`` is not checked for consistency.
     369
     370        TESTS::
     371
     372            sage: F = UniversalCyclotomicField()
     373            sage: TestSuite(F).run()
     374        """
     375        # the data is stored as linear combinations of elements in the Zumbroich Basis
     376        from sage.combinat.free_module import CombinatorialFreeModule
     377        from sage.categories.fields import Fields
     378        from sage.categories.algebras import Algebras
     379
     380        # getting the optional argument "names" right
     381        if names is None:
     382            names = "E"
     383        if not isinstance(names,str):
     384            if not isinstance(names,(list,tuple)):
     385                raise ValueError("The given name %s is not valid."%names)
     386            if len(names) != 1:
     387                raise ValueError("The given name %s is not valid."%names)
     388            names = names[0]
     389        if not isinstance(names,str):
     390            raise ValueError("The given name %s is not valid."%names)
     391
     392        # getting the optional argument "bracket" right
     393        if isinstance(bracket,str) and len(bracket) % 2 == 0:
     394            bracket_len = len(bracket)
     395            bracket = (bracket[:bracket_len/2],bracket[bracket_len/2:])
     396        else:
     397            raise ValueError("The given bracket %s is not a string of even length."%bracket)
     398
     399        self._data = CombinatorialFreeModule(QQ, ZumbroichBasisIndices(),prefix=names,bracket=bracket)
     400        Parent.__init__(self, base = QQ, category = (Fields(), Algebras(QQ)))
     401
     402        self._has_standard_embedding = False
     403        if embedding not in [False,None]:
     404            if embedding is True:
     405                embedding = lambda n: QQbar.zeta(n)
     406                self._has_standard_embedding = True
     407
     408            P = get_parent_of_embedding(embedding)
     409
     410           # embedding from self into P
     411            def on_basis(x):
     412                return embedding(x[0])**(int(x[1]))
     413
     414            mor = self._data.module_morphism(on_basis, codomain=P)
     415            H = SetMorphism(Hom(self, QQbar), lambda z: mor(z.value))
     416            self.register_embedding(H)
     417
     418            # define partial conversions to AA, if possible
     419            SetMorphism(
     420                    Hom(self, AA, SetsWithPartialMaps()),
     421                    lambda elem: elem._real_()
     422               ).register_as_conversion()
     423
     424        # string representations of elements
     425        def repr_term(m,type="repr"):
     426            if m[1] == 0:
     427                return '1'
     428            elif 2*m[1] == m[0]:
     429                return '-1'
     430            elif m[1] == 1:
     431                if type == "repr":
     432                    return '%s%s%s%s'%(names,bracket[0],m[0],bracket[1])
     433                elif type == "latex":
     434                    return '\\zeta_{%s}'%m[0]
     435            else:
     436                if type == "repr":
     437                    return '%s%s%s%s^%s'%(names,bracket[0],m[0],bracket[1],m[1])
     438                elif type == "latex":
     439                    return '\\zeta_{%s}^{%s}'%(m[0],m[1])
     440
     441        self._data._repr_term = lambda m: repr_term(m,type="repr")
     442        self._data._latex_term = lambda m: repr_term(m,type="latex")
     443
     444        # setting zero and one
     445        self._zero = self._from_dict({}, remove_zeros=False)
     446        self._one = self._from_dict({(1,0):QQ(1)}, remove_zeros=False)
     447
     448    @cached_method
     449    def gen(self,n, k=1):
     450        r"""
     451        Returns `\zeta^k` living in :class:`UniversalCyclotomicField`, where `\zeta` denotes the primitive `n`-th root of unity `\zeta = exp(2 \pi i / n)`.
     452
     453        :param n: positive integer.
     454        :param k: positive integer.
     455        :type n: integer
     456        :type k: integer; optional, default ``1``
     457
     458        .. NOTE::
     459
     460            - For the mathematical description of the Zumbroich basis and the
     461              algorithmic behind, see [Bre97]_.
     462
     463            - This function behaves exactly like the *Cyclotomics* in *GAP*.
     464
     465        EXAMPLES::
     466
     467            sage: UCF.<E> = UniversalCyclotomicField()
     468
     469            sage: E(3) # indirect doctest
     470            E(3)
     471            sage: E(6) # indirect doctest
     472            -E(3)^2
     473            sage: E(12) # indirect doctest
     474            -E(12)^7
     475            sage: E(6,2) # indirect doctest
     476            E(3)
     477            sage: E(6)^2 # indirect doctest
     478            E(3)
     479        """
     480        if n != ZZ(n) or not n > 0 or k != ZZ(k):
     481            raise TypeError('The argument for a root of unity is not correct.')
     482        else:
     483            g = GCD_list([n,k])
     484            n = ZZ(n/g)
     485            k = ZZ(k/g) % n
     486
     487        return self._from_dict(push_down_cython(n, ZumbroichDecomposition(n,k)), coerce=True, remove_zeros=False)
     488
     489    def _first_ngens(self,n):
     490        r"""
     491        Returns the method :meth:`gen` if ``n=1``, and raises an error otherwise.
     492
     493        This method is needed to make the following work::
     494
     495            sage: UCF.<E> = UniversalCyclotomicField() # indirect doctest
     496        """
     497        if n == 1:
     498            return (self.gen,)
     499        else:
     500            raise ValueError("This ring has only a single generator method.")
     501
     502    def _element_constructor_(self, arg):
     503        r"""
     504        The only way to get here is if there was no coercion found.
     505
     506        In this case, we give other parents the option to define a conversion
     507        using the method ``_universal_cyclotomic_field_``, or raise a TypeError otherwise.
     508
     509        TESTS::
     510
     511            sage: UCF = UniversalCyclotomicField()
     512
     513            sage: UCF(CC(5)) # indirect doctest
     514            Traceback (most recent call last):
     515            ...
     516            TypeError:  No coercion to the universal cyclotomic field found for the input 5.00000000000000 with parent Complex Field with 53 bits of precision.
     517
     518            sage: p = Permutation([2,1])
     519            sage: UCF(p)
     520            Traceback (most recent call last):
     521            ...
     522            TypeError: No coercion to the universal cyclotomic field found for the input [2, 1].
     523        """
     524        if hasattr(arg,"_universal_cyclotomic_field_"):
     525            return arg._universal_cyclotomic_field_()
     526        elif isinstance(arg,(sage.interfaces.gap3.GAP3Element,sage.interfaces.gap.GapElement)):
     527            return self.from_gap(arg)
     528
     529        error_str = "No coercion to the universal cyclotomic field found for the input %s"%str(arg)
     530        if hasattr(arg,"parent"):
     531            error_str ="%s with parent %s."%(error_str,str(arg.parent()))
     532        else:
     533            error_str ="%s."%(error_str)
     534        raise TypeError(error_str)
     535
     536    def _coerce_map_from_(self, other):
     537        r"""
     538        If ``self`` has the standard embedding and
     539        - ``other`` is a cyclotomic number field: returns
     540          the coercion thereof, taking non-standard embeddings
     541          of ``other.parent()`` into account.
     542        - ``other`` is also a universal cyclotomic field with the
     543          standard embedding: returns the obvious morphism
     544
     545        EXAMPLES::
     546
     547            sage: UCF = UniversalCyclotomicField()
     548
     549            sage: zeta = CyclotomicField(5).gen()
     550            sage: UCF(zeta) # indirect doctest
     551            E(5)
     552
     553            sage: zeta = CyclotomicField(5,embedding=CC(exp(2*pi*I/5))).gen()
     554            sage: UCF(zeta) # indirect doctest
     555            E(5)
     556
     557            sage: zeta = CyclotomicField(5,embedding=CC(exp(4*pi*I/5))).gen()
     558            sage: UCF(zeta) # indirect doctest
     559            E(5)^2
     560
     561            sage: UCF.<E> = UniversalCyclotomicField();
     562            sage: UCF2.<E2> = UniversalCyclotomicField();
     563            sage: UCF2(E(5))
     564            E2(5)
     565
     566            sage: UCF = UniversalCyclotomicField(embedding=None)
     567            sage: UCF(zeta) # indirect doctest
     568            Traceback (most recent call last):
     569            ...
     570            TypeError: No coercion to the universal cyclotomic field found for the input zeta5 with parent Cyclotomic Field of order 5 and degree 4.
     571        """
     572        from sage.rings.number_field.number_field import NumberField_cyclotomic
     573        from sage.rings.number_field.number_field_morphisms import NumberFieldEmbedding
     574        if self._has_standard_embedding:
     575            if isinstance(other,NumberField_cyclotomic):
     576                return  NumberFieldEmbedding(other, self, self.from_cyclotomic_field(other.gen()))
     577            elif isinstance(other,UniversalCyclotomicField) and other._has_standard_embedding:
     578                return SetMorphism(Hom(other,self), lambda z: self._from_dict(z._dict_()))
     579
     580    def __pow__(self,n):
     581        r"""
     582        Returns the ``n``-th power of self as a vector space.
     583
     584        EXAMPLES::
     585
     586            sage: UCF = UniversalCyclotomicField()
     587            sage: UCF^3
     588            Vector space of dimension 3 over Universal Cyclotomic Field
     589        """
     590        from sage.modules.free_module import VectorSpace
     591        return VectorSpace(self,n)
     592
     593    def is_finite(self):
     594        r"""
     595        Returns False as ``self`` is not finite.
     596
     597        EXAMPLES::
     598
     599            sage: UCF = UniversalCyclotomicField()
     600            sage: UCF.is_finite()
     601            False
     602        """
     603        return False
     604
     605    def is_subring(self,other):
     606        r"""
     607        Returns True if ``self`` is a subring of ``other``.
     608
     609
     610        .. WARNING::
     611
     612            Currently, it is only checked if ``self is other``!
     613
     614        EXAMPLES::
     615
     616            sage: UCF = UniversalCyclotomicField()
     617
     618            sage: UCF.is_subring(UCF)
     619            True
     620
     621            sage: UCF.is_subring(CC)
     622            False
     623        """
     624        return other is self
     625
     626    def _repr_(self):
     627        r"""
     628        Returns the string representation of ``self``.
     629
     630        EXAMPLES::
     631
     632            sage: UCF = UniversalCyclotomicField()
     633            sage: UCF._repr_()
     634            'Universal Cyclotomic Field'
     635        """
     636        return "Universal Cyclotomic Field"
     637
     638    def _gap_init_(self):
     639        r"""
     640        Returns gap string representation of ``self``.
     641
     642        EXAMPLES::
     643
     644            sage: UCF = UniversalCyclotomicField()
     645            sage: UCF._gap_init_()
     646            'Cyclotomics'
     647        """
     648        return 'Cyclotomics'
     649
     650    def degree(self):
     651        r"""
     652        Returns the *degree* of ``self`` as a field extension over the Rationals.
     653
     654        EXAMPLES::
     655
     656            sage: UCF = UniversalCyclotomicField()
     657            sage: UCF.degree()
     658            +Infinity
     659        """
     660        from sage.rings.infinity import infinity
     661        return infinity
     662
     663    def characteristic(self):
     664        r"""
     665        Returns ``0`` which is the *characteristic* of ``self``.
     666
     667        EXAMPLES::
     668
     669            sage: UCF = UniversalCyclotomicField()
     670            sage: UCF.characteristic()
     671            0
     672        """
     673        return ZZ(0)
     674
     675    def prime_subfield(self):
     676        r"""
     677        Returns `\QQ` which is the *prime subfield* of ``self``.
     678
     679        EXAMPLES::
     680
     681            sage: UCF = UniversalCyclotomicField()
     682            sage: UCF.prime_subfield()
     683            Rational Field
     684        """
     685        return QQ
     686
     687    def is_prime_field(self):
     688        r"""
     689        Returns False since ``self`` is not a prime field.
     690
     691        EXAMPLES::
     692
     693            sage: UCF = UniversalCyclotomicField()
     694            sage: UCF.is_prime_field()
     695            False
     696        """
     697        return False
     698
     699    def an_element(self, order = 3):
     700        r"""
     701        Returns an element of ``self`` of order ``order``.
     702
     703        :param order: a positive integer.
     704        :type order: integer; optional, default:``3``
     705
     706        EXAMPLES::
     707
     708            sage: UCF = UniversalCyclotomicField()
     709
     710            sage: UniversalCyclotomicField().an_element()
     711            E(3)
     712
     713            sage: UniversalCyclotomicField().an_element(order=6)
     714            -E(3)^2
     715
     716            sage: UniversalCyclotomicField().an_element(order=10)
     717            -E(5)^3
     718        """
     719        return self.gen(order)
     720
     721    def random_element(self, order=None):
     722        r"""
     723        Returns a (often non-trivial) pseudo-random element of ``self``.
     724
     725        :param order:
     726        :type order: integer or None; optional, default:``None``
     727
     728        EXAMPLES::
     729
     730            sage: UCF = UniversalCyclotomicField()
     731
     732            sage: UCF.random_element() # random
     733            3*E(7)^2 + E(7)^3 + 2*E(7)^4 - 5*E(7)^5
     734
     735            sage: UCF.random_element(order=4) # random
     736            -3*E(4)
     737
     738            sage: UCF.random_element(order=12) # random
     739            E(12)^7 - 4*E(12)^8 + E(12)^11
     740        """
     741        F = self
     742        seq = [-5,-4,-3,-2,-1,1,2,3,4,5]
     743        if order is not None:
     744            n = order
     745        else:
     746            n = randint(1, 17)
     747        B = ZumbroichBasisIndices().indices(n)
     748        # TODO: could this be written in a more conceptual way
     749        # by having appropriate constructors?
     750        k = randrange(len(B))
     751        B = sample(B, k)
     752        dict_in_basis = {}
     753        for key in B:
     754            dict_in_basis[ key.value ] = QQ(choice(seq))
     755        return F._from_dict(push_down_cython(n,dict_in_basis), remove_zeros=False)
     756
     757    def _from_dict(self, D, coerce=True, remove_zeros=True):
     758        r"""
     759        Returns the element in ``self`` from the given dictionary ``D``.
     760
     761        :param D: a dictionary with keys being elements in the Zumbroich basis and values being Rationals.
     762        :param coerce: if True, the values are coerced to the Rationals.
     763        :type coerce: Boolean; optional, default:``False``
     764        :param remove_zeros: if True, zeros are removed from the dict first. Should be ``True`` unless it is clear that ``D`` doesn't contain zeros.
     765        :type remove_zeros: Boolean; optional, default:``True``
     766
     767        EXAMPLES::
     768
     769            sage: UCF = UniversalCyclotomicField()
     770
     771            sage: D = dict([((1,0),2)])
     772            sage: UCF._from_dict(D)
     773            2
     774
     775            sage: D = dict([((1,0),2)],remove_zeros=False)
     776            sage: UCF._from_dict(D)
     777            2
     778
     779            sage: D = dict([((1,0),2),((3,1),1),((3,2),0)])
     780            sage: UCF._from_dict(D)
     781            2 + E(3)
     782        """
     783        if coerce:
     784            for X,a in D.iteritems():
     785                D[X] = QQ(a)
     786        elem = self.element_class(self._data._from_dict(D, remove_zeros=remove_zeros), parent=self)
     787        return elem
     788
     789    def from_base_ring(self,coeff):
     790        r"""
     791        Returns the base ring element ``coeff`` as an element in ``self``.
     792
     793        :param coeff: A rational number.
     794
     795        EXAMPLES::
     796
     797            sage: UCF = UniversalCyclotomicField()
     798
     799            sage: x = UCF.from_base_ring(2); x
     800            2
     801            sage: x.parent()
     802            Universal Cyclotomic Field
     803        """
     804        return self._from_dict({ (1,0):coeff })
     805
     806    def zero(self):
     807        r"""
     808        Returns the zero in ``self``.
     809
     810        EXAMPLES::
     811
     812            sage: UCF = UniversalCyclotomicField()
     813            sage: UCF.zero()
     814            0
     815        """
     816        return self._zero
     817
     818    def one(self):
     819        r"""
     820        Returns the one in ``self``.
     821
     822        EXAMPLES::
     823
     824            sage: UCF = UniversalCyclotomicField()
     825            sage: UCF.one()
     826            1
     827        """
     828        return self._one
     829
     830    def monomial(self, mon, check=True):
     831        r"""
     832        Returns the monomial in ``self`` associated to ``mon`` in the Zumbroich basis.
     833
     834        :param mon: an element in the Zumbroich basis
     835        :param check: if True, the monomial is checked to be in the Zumbroich basis
     836        :type check: Boolean; optional, default:``True``
     837
     838        EXAMPLES::
     839
     840            sage: UCF = UniversalCyclotomicField()
     841
     842            sage: UCF.monomial((1,0))
     843            1
     844
     845            sage: UCF.monomial((4,2))
     846            Traceback (most recent call last):
     847            ...
     848            ValueError: The given data is not a monomial of the universal cyclotomic field.
     849        """
     850        if check:
     851            if not mon in ZumbroichBasisIndices():
     852                raise ValueError("The given data is not a monomial of the universal cyclotomic field.")
     853        return self._from_dict({ mon : QQ(1) }, remove_zeros=False)
     854
     855    def sum(self, L):
     856        r"""
     857        Returns the sum of all elements (which must be coerceable into ``self``) in ``L``.
     858
     859        :param L: list or tuple of elements in ``self``
     860
     861        .. NOTE::
     862
     863            Faster than the usual sum as operated directly on dictionaries, as all steps are done together.
     864
     865        EXAMPLES::
     866
     867            sage: UCF.<E> = UniversalCyclotomicField()
     868
     869            sage: UCF.sum([ E(i) for i in range(1,5) ])
     870            E(12)^4 - E(12)^7 - E(12)^11
     871        """
     872        l = LCM_list([ other.field_order() for other in L ])
     873        large_dict_list = [ push_to_higher_field(other.value._monomial_coefficients, other.field_order(), l) for other in L ]
     874        return self._from_dict(push_down_cython(l,dict_addition(large_dict_list)), remove_zeros=False)
     875
     876    def _matrix_mult(self,M1,M2,order=None):
     877        r"""
     878        Returns the product ``M1`` `\times` ``M2`` of the two matrices ``M1`` and ``M2`` over ``self``.
     879
     880        .. WARNING::
     881
     882            This method is not for public use, but only to provide a quick test how fast we can multiply matrices.
     883
     884        EXAMPLES::
     885
     886            sage: UCF.<E> = UniversalCyclotomicField()
     887
     888            sage: M = matrix(UCF,[[E(3),E(4)],[E(5),E(6)]]); M
     889            [   E(3)    E(4)]
     890            [   E(5) -E(3)^2]
     891
     892            sage: M2 = UCF._matrix_mult(M,M); M2
     893            [-E(60)^4 - E(60)^7 - E(60)^16 - E(60)^28 - E(60)^47 - E(60)^52                                             E(12)^7 - E(12)^11]
     894            [                                            E(15)^8 - E(15)^13 -E(60)^7 - E(60)^8 - E(60)^32 - E(60)^44 - E(60)^47 - E(60)^56]
     895
     896            sage: M2 == M*M
     897            True
     898        """
     899        from sage.matrix.all import zero_matrix
     900        if not M1.nrows() == M2.ncols():
     901            raise ValueError("The given matrices cannot be multiplied.")
     902        dim1, dim, dim2 = M1.ncols(), M1.nrows(), M2.nrows()
     903        m_rows = M1.rows()
     904        m_cols = M2.columns()
     905        rows,cols = [],[]
     906        for i in xrange(dim):
     907            rows.append(tuple(x.value._monomial_coefficients for x in m_rows[i]))
     908            cols.append(tuple(x.value._monomial_coefficients for x in m_cols[i]))
     909
     910        M_new = zero_matrix(self,dim1,dim2)
     911        if order:
     912            n = order
     913        else:
     914            LCM = [ x.field_order() for x in set(M1.list()).union(M2.list()) ]
     915            n = LCM_list(LCM)
     916        for i in xrange(dim1):
     917            for j in xrange(dim2):
     918                M_new[i,j] = self._from_dict(push_down_cython(n,dict_vector_multiplication(n,rows[i],cols[j])))
     919        return M_new
     920
     921    def zumbroich_basis_indices(self, n):
     922        r"""
     923        Returns the indices of the *Zumbroich basis* of order ``n``.
     924
     925        The Zumbroich basis is a linear basis of the universal cyclotomic field
     926        that behaves very well with considering an primitive `d`-th root of unity
     927        as a (non primitive) `kd`-th root. See [Bre97]_ for further details.
     928
     929        :param n: positive integer
     930
     931        OUTPUT:
     932
     933        - a set of tuples `(n,k)` of all elements in the Zumbroich basis of order `n`.
     934
     935        EXAMPLES::
     936
     937            sage: UCF = UniversalCyclotomicField()
     938            sage: UCF.zumbroich_basis_indices(8)
     939            set([(8, 1), (8, 3), (8, 0), (8, 2)])
     940        """
     941        return ZumbroichBasisIndices().indices(n)
     942
     943    def zumbroich_basis(self,n):
     944        r"""
     945        Returns the *Zumbroich basis* of order ``n``.
     946
     947        The Zumbroich basis is a linear basis of the universal cyclotomic field
     948        that behaves very well with considering an primitive `d`-th root of unity
     949        as a (non primitive) `kd`-th root. See [Bre97]_ for further details.
     950
     951        :param n: positive integer
     952
     953        OUTPUT:
     954
     955        - the set of elements in the universal cyclotomic field forming the Zumbroich basis of order `n`.
     956
     957        EXAMPLES::
     958
     959            sage: UCF = UniversalCyclotomicField()
     960            sage: UCF.zumbroich_basis(8)
     961            set([E(8)^3, 1, E(4), E(8)])
     962
     963            sage: UCF.zumbroich_basis(9)
     964            set([E(9)^2, E(3)^2, E(9)^5, E(9)^4, E(3), E(9)^7])
     965        """
     966        return set(self.gen(n,k) for n,k in self.zumbroich_basis_indices(n))
     967
     968    def from_gap(self, elem):
     969        r"""
     970        Returns the element in ``self`` obtained from the gap by executing ``string``.
     971
     972        :param string: string representing an element in the universal cyclotomic field
     973
     974        EXAMPLES::
     975
     976            sage: UCF = UniversalCyclotomicField()
     977            sage: UCF.from_gap(gap("-E(3)^2"))
     978            -E(3)^2
     979
     980            sage: UCF = UniversalCyclotomicField()
     981            sage: UCF.from_gap(gap("E(3)^2"))
     982            E(3)^2
     983
     984            sage: UCF.from_gap(gap("1/6*E(3)")) # testing a former bug
     985            1/6*E(3)
     986        """
     987        if not isinstance(elem,(sage.interfaces.gap3.GAP3Element,sage.interfaces.gap.GapElement)):
     988            raise ValueError("The input %s is not a GAP object."%elem)
     989        if hasattr(elem,"sage"):
     990            try:
     991                return self(elem.sage())
     992            except NotImplementedError:
     993                pass
     994
     995        string = str(elem)
     996        terms = string.replace('\n','').replace('-','+-').split('+')
     997        if terms[0] == '':
     998            del terms[0]
     999        for i in range(len(terms)):
     1000            if '^' in terms[i]:
     1001                terms[i] = terms[i].replace(')^',',') + ')'
     1002            terms[i] = terms[i].replace("E","self.gen")
     1003            if '*' in terms[i]:
     1004                pos = terms[i].index('*')
     1005                fac = QQ(terms[i][:pos])
     1006                terms[i] = terms[i][pos+1:]
     1007            else:
     1008                fac = None
     1009            exec('terms[%s]='%i + terms[i])
     1010            if fac is not None:
     1011                terms[i] = fac*terms[i]
     1012        return self.sum(terms)
     1013
     1014    def from_cyclotomic_field(self, elem):
     1015        r"""
     1016        Returns the element in ``self`` coming from the element in NumberField_cyclotomic.
     1017
     1018        :param elem: an element of NumberField_cyclotomic
     1019
     1020        .. WARNING::
     1021
     1022            This method raises an error if self does not have the standard embedding.
     1023
     1024        EXAMPLES::
     1025
     1026            sage: UCF = UniversalCyclotomicField()
     1027
     1028            sage: a = CyclotomicField(6).gen(); a
     1029            zeta6
     1030            sage: UCF.from_cyclotomic_field(a)
     1031            -E(3)^2
     1032
     1033        An example with another embedding::
     1034
     1035            sage: a = CyclotomicField(5,embedding=CC(exp(4*pi*I/5))).gen(); a
     1036            zeta5
     1037            sage: UCF.from_cyclotomic_field(a)
     1038            E(5)^2
     1039
     1040        TESTS::
     1041
     1042            sage: UCF.from_cyclotomic_field(4)
     1043            Traceback (most recent call last):
     1044            ...
     1045            TypeError: The given data (4) is not a cyclotomic field element.
     1046
     1047            sage: UCF = UniversalCyclotomicField(embedding=None);
     1048            sage: a = CyclotomicField(5).gen()
     1049            sage: UCF.from_cyclotomic_field(a)
     1050            Traceback (most recent call last):
     1051            ...
     1052            TypeError: This method can only be used if Universal Cyclotomic Field uses the standard embedding.
     1053        """
     1054        from sage.rings.number_field.number_field import NumberField_cyclotomic
     1055        if not self._has_standard_embedding:
     1056            raise TypeError("This method can only be used if %s uses the standard embedding."%self)
     1057        if not hasattr(elem,'parent') or not isinstance(elem.parent(), NumberField_cyclotomic):
     1058            raise TypeError("The given data (%s) is not a cyclotomic field element."%elem)
     1059        n = elem.parent()._n()
     1060        CF = CyclotomicField(n)
     1061        elem = CF(elem)
     1062        coeff_list = elem.list()
     1063        return self._from_dict(push_down_cython(n,dict_linear_combination((ZumbroichDecomposition(n, k), coeff_list[ k ]) for k in range(len(coeff_list)) if coeff_list[k] != 0)), remove_zeros=False)
     1064
     1065    class Element(FieldElement, ElementWrapper):
     1066        r"""
     1067        An element of the universal cyclotomic field.
     1068
     1069        .. SEEALSO::
     1070
     1071            - :class:`UniversalCyclotomicField`
     1072        """
     1073
     1074        def __lt__(self,other):
     1075            r"""
     1076            Pushes the method forward to ``QQbar``.
     1077
     1078            EXAMPLES::
     1079
     1080                sage: UCF.<E> = UniversalCyclotomicField()
     1081                sage: E(3).__lt__(E(4))
     1082                True
     1083            """
     1084            return QQbar(self).__lt__(other)
     1085
     1086        def __gt__(self,other):
     1087            r"""
     1088            Pushes the method forward to ``QQbar``.
     1089
     1090            EXAMPLES::
     1091
     1092                sage: UCF.<E> = UniversalCyclotomicField()
     1093                sage: E(3).__gt__(E(4))
     1094                False
     1095            """
     1096            return QQbar(self).__gt__(other)
     1097
     1098        def __le__(self,other):
     1099            r"""
     1100            Pushes the method forward to ``QQbar``.
     1101
     1102            EXAMPLES::
     1103
     1104                sage: UCF.<E> = UniversalCyclotomicField()
     1105                sage: E(3).__le__(E(4))
     1106                True
     1107            """
     1108            return QQbar(self).__le__(other)
     1109
     1110        def __ge__(self,other):
     1111            r"""
     1112            Pushes the method forward to ``QQbar``.
     1113
     1114            EXAMPLES::
     1115
     1116                sage: UCF.<E> = UniversalCyclotomicField()
     1117                sage: E(3).__ge__(E(4))
     1118                False
     1119            """
     1120            return QQbar(self).__ge__(other)
     1121
     1122        def __eq__(self, other):
     1123            r"""
     1124            Returns ``True`` if self and other are equal.
     1125
     1126            EXAMPLES::
     1127
     1128                sage: UCF.<E> = UniversalCyclotomicField()
     1129
     1130                sage: E(3) == E(3) # indirect doctest
     1131                True
     1132
     1133                sage: E(3) == E(4) # indirect doctest
     1134                False
     1135            """
     1136            if have_same_parent(self, other):
     1137                return self.value._monomial_coefficients == other.value._monomial_coefficients
     1138            from sage.structure.element import get_coercion_model
     1139            import operator
     1140            try:
     1141                return get_coercion_model().bin_op(self, other, operator.eq)
     1142            except TypeError:
     1143                return False
     1144
     1145        def __ne__(left, right):
     1146            r"""
     1147            Returns ``True`` if self and other are not equal.
     1148
     1149            EXAMPLES::
     1150
     1151                sage: UCF.<E> = UniversalCyclotomicField()
     1152
     1153                sage: E(3) != E(3) # indirect doctest
     1154                False
     1155
     1156                sage: E(3) != E(4) # indirect doctest
     1157                True
     1158            """
     1159            return not left.__eq__(right)
     1160
     1161        # only implemented to survive the equality check for matrices
     1162        def __cmp__(self, other):
     1163            r"""
     1164            The ordering is the one on the underlying sorted list of (monomial,coefficients) pairs.
     1165
     1166            EXAMPLES::
     1167
     1168                sage: UCF.<E> = UniversalCyclotomicField()
     1169
     1170                sage: cmp(E(3),E(4)) # indirect doctest
     1171                -1
     1172
     1173                sage: cmp(UCF(3), 1) # indirect doctest
     1174                1
     1175            """
     1176            if self.__eq__(other):
     1177                return 0
     1178            if self.field_order() > other.field_order():
     1179                return 1
     1180            if self.field_order() < other.field_order():
     1181                return -1
     1182            return cmp(sorted(self), sorted(other))
     1183
     1184        def __hash__(self):
     1185            r"""
     1186            Returns the hash of ``self``.
     1187
     1188            EXAMPLES::
     1189
     1190                sage: UCF.<E> = UniversalCyclotomicField()
     1191                sage: L = set( E(n) for n in [1..1000] )
     1192                sage: all( E(n) in L for n in [1..1000] )
     1193                True
     1194            """
     1195            return hash(frozenset(self.value._monomial_coefficients.items()))
     1196
     1197        def _gap_init_(self):
     1198            r"""
     1199            Returns gap string representation of ``self``.
     1200
     1201            EXAMPLES::
     1202
     1203            sage: UCF.<X> = UniversalCyclotomicField();
     1204            sage: X(4)
     1205            X(4)
     1206            sage: X(4)._gap_init_()
     1207            'E(4)'
     1208            """
     1209            UCF = UniversalCyclotomicField()
     1210            return str(UCF._from_dict(self.value._monomial_coefficients))
     1211
     1212        def _real_(self):
     1213            r"""
     1214            Returns ``self`` in the real algebraic field, if possible. Raises an error otherwise.
     1215
     1216            EXAMPLES::
     1217
     1218                sage: UCF.<E> = UniversalCyclotomicField()
     1219
     1220                sage: x = E(5)
     1221                sage: AA(E(5)+E(5).conjugate()) # indirect doctest
     1222                0.618033988749895?
     1223
     1224                sage: AA(E(5)) # indirect doctest
     1225                Traceback (most recent call last):
     1226                ...
     1227                TypeError: No conversion of E(5) to the real algebraic field AA.
     1228            """
     1229            if self.is_real():
     1230                P = self.parent().coerce_embedding().codomain()
     1231                return AA(P(self))
     1232            raise TypeError("No conversion of %s to the real algebraic field AA."%str(self))
     1233
     1234        def _rational_(self):
     1235            r"""
     1236            Returns ``self`` in the Rationals, if possible. Raises an error otherwise.
     1237
     1238            EXAMPLES::
     1239
     1240                sage: UCF = UniversalCyclotomicField()
     1241
     1242                sage: x = UCF(4/5)._rational_(); x
     1243                4/5
     1244                sage: x.parent()
     1245                Rational Field
     1246            """
     1247            if self.is_rational():
     1248                return self.value._monomial_coefficients[(1,0)]
     1249            raise TypeError("No conversion of %s to the rational field QQ."%str(self))
     1250
     1251        def _integer_(self):
     1252            r"""
     1253            Returns ``self`` in the Integers, if possible. Raises an error otherwise.
     1254
     1255            EXAMPLES::
     1256
     1257                sage: UCF = UniversalCyclotomicField()
     1258
     1259                sage: x = UCF(5)._integer_(); x
     1260                5
     1261                sage: x.parent()
     1262                Integer Ring
     1263            """
     1264            if self.is_rational():
     1265                coeff = self.value._monomial_coefficients[(1,0)]
     1266                return ZZ(coeff)
     1267            raise TypeError("No conversion of %s to the integer ring ZZ."%str(self))
     1268
     1269        def __nonzero__(self):
     1270            r"""
     1271            Returns True if ``self`` is not zero.
     1272
     1273            EXAMPLES::
     1274
     1275                sage: UCF.<E> = UniversalCyclotomicField()
     1276
     1277                sage: E(3).is_zero()
     1278                False
     1279
     1280                sage: (E(3)-E(3)).is_zero()
     1281                True
     1282            """
     1283            return bool(self.value._monomial_coefficients)
     1284
     1285        def is_one(self):
     1286            r"""
     1287            Returns True if ``self`` is one.
     1288
     1289            EXAMPLES::
     1290
     1291                sage: UCF.<E> = UniversalCyclotomicField()
     1292
     1293                sage: E(3).is_one()
     1294                False
     1295
     1296                sage: UCF(1).is_one()
     1297                True
     1298            """
     1299            try:
     1300                x = self.value._monomial_coefficients[(1,0)]
     1301                return x == 1
     1302            except KeyError:
     1303                return False
     1304
     1305        def is_rational(self):
     1306            r"""
     1307            Returns True if ``self`` is rational.
     1308
     1309            EXAMPLES::
     1310
     1311                sage: UCF.<E> = UniversalCyclotomicField()
     1312
     1313                sage: E(3).is_rational()
     1314                False
     1315
     1316                sage: UCF(1/3).is_rational()
     1317                True
     1318
     1319                sage: UCF(0).is_rational()
     1320                True
     1321            """
     1322            return (1,0) in self.value._monomial_coefficients or self.is_zero()
     1323
     1324        def is_real(self):
     1325            r"""
     1326            Returns True if ``self`` is real.
     1327
     1328            EXAMPLES::
     1329
     1330                sage: UCF.<E> = UniversalCyclotomicField()
     1331
     1332                sage: E(5).is_real()
     1333                False
     1334
     1335                sage: (E(5)^2 + E(5)^3).is_real()
     1336                True
     1337
     1338                sage: (E(5)^4 + E(5)^3).is_real()
     1339                False
     1340            """
     1341            return self == self.conjugate()
     1342
     1343        def is_real_positive(self):
     1344            r"""
     1345            Returns True if ``self`` is real and positive.
     1346
     1347            EXAMPLES::
     1348
     1349                sage: UCF.<E> = UniversalCyclotomicField()
     1350
     1351                sage: (E(5)^2 + E(5)^3).is_real_positive()
     1352                False
     1353
     1354                sage: (-E(5)^4 - E(5)^3).is_real_positive()
     1355                False
     1356            """
     1357            return self.is_real() and AA(self) > 0
     1358
     1359        def __neg__(self):
     1360            r"""
     1361            Returns the negative of ``self``.
     1362
     1363            EXAMPLES::
     1364
     1365                sage: UCF.<E> = UniversalCyclotomicField()
     1366                sage: E(3).__neg__()
     1367                -E(3)
     1368            """
     1369            F = self.parent()
     1370            elem = F.element_class(self.value.__neg__(), parent = F)
     1371            return elem
     1372
     1373        def __invert__(self):
     1374            r"""
     1375            Returns the inverse of ``self``.
     1376
     1377            .. NOTE::
     1378
     1379                We make use of the fact that the norm of ``self``, i.e., the product of all Galois conjugates of ``self``, is rational.
     1380                Thus the inverse of ``self`` is the product of all Galois conjugates except ``self`` multiplied by the inverse of the norm of ``self``.
     1381
     1382            EXAMPLES::
     1383
     1384                sage: UCF.<E> = UniversalCyclotomicField()
     1385
     1386                sage: E(3).__invert__()
     1387                E(3)^2
     1388
     1389                sage: E(6).__invert__()
     1390                -E(3)
     1391
     1392                sage: UCF(0).__invert__()
     1393                Traceback (most recent call last):
     1394                ...
     1395                ZeroDivisionError: The given element is zero.
     1396            """
     1397            if self.is_zero():
     1398                raise ZeroDivisionError("The given element is zero.")
     1399            elif self.is_rational():
     1400                return self.parent().from_base_ring(QQ(1)/self.value._monomial_coefficients[(1,0)])
     1401            else:
     1402                inv = self.parent().prod(self.galois_conjugates()[1:])
     1403                self_norm_inv = QQ(1)/(self*inv).value._monomial_coefficients[(1,0)]
     1404                return inv*self_norm_inv
     1405
     1406        def __iter__(self):
     1407            r"""
     1408            Returns an iterator of the monomial coefficients of ``self``.
     1409
     1410            EXAMPLES::
     1411
     1412                sage: UCF.<E> = UniversalCyclotomicField()
     1413
     1414                sage: a = E(3)+E(4); a
     1415                E(12)^4 - E(12)^7 - E(12)^11
     1416
     1417                sage: for x in a: print x
     1418                ((12, 7), -1)
     1419                ((12, 4), 1)
     1420                ((12, 11), -1)
     1421            """
     1422            return self.value.__iter__()
     1423
     1424        def _dict_(self):
     1425            r"""
     1426            Returns the *monomial coefficients* of ``self`` as a dictionary.
     1427
     1428            EXAMPLES::
     1429
     1430                sage: UCF.<E> = UniversalCyclotomicField()
     1431                sage: E(6)._dict_()
     1432                {(3, 2): -1}
     1433            """
     1434            return self.value._monomial_coefficients
     1435
     1436        def inverse(self):
     1437            r"""
     1438            Returns the inverse of ``self``.
     1439
     1440            EXAMPLES::
     1441
     1442                sage: UCF.<E> = UniversalCyclotomicField()
     1443
     1444                sage: f = 2 * E(3) + E(4); f
     1445                2*E(12)^4 - E(12)^7 - E(12)^11
     1446
     1447                sage: f.inverse()
     1448                2/13*E(12)^4 - 3/13*E(12)^7 + 8/13*E(12)^8 + 1/13*E(12)^11
     1449
     1450                sage: f * f.inverse()
     1451                1
     1452            """
     1453            return self.__invert__()
     1454
     1455        def __div__(self, other):
     1456            r"""
     1457            Returns ``self `\times` ``other.inverse()``.
     1458
     1459            EXAMPLES::
     1460
     1461            sage: UCF.<E> = UniversalCyclotomicField()
     1462
     1463            sage: E(6).__div__(1)
     1464            -E(3)^2
     1465
     1466            sage: E(6).__div__(-1)
     1467            E(3)^2
     1468
     1469            sage: E(6).__div__(E(3))
     1470            -E(3)
     1471            """
     1472            return self * other**-1
     1473
     1474        def __pow__(self, k):
     1475            r"""
     1476            Returns ``self`` `{}^k`.
     1477
     1478            :param k: an integer
     1479
     1480            EXAMPLES::
     1481
     1482                sage: UCF.<E> = UniversalCyclotomicField()
     1483
     1484                sage: E(3).__pow__(3)
     1485                1
     1486                sage: E(6).__pow__(4)
     1487                E(3)^2
     1488
     1489                sage: E(6).__pow__(-2)
     1490                E(3)^2
     1491                sage: E(6).__pow__(0)
     1492                1
     1493            """
     1494            if k == 0:
     1495                return self.parent().one()
     1496            elif k == 1:
     1497                return self
     1498            elif self.is_rational():
     1499                return self.parent()._from_dict({ (1,0) : self.value._monomial_coefficients[(1,0)]**k }, remove_zeros=False)
     1500            elif len(self.value._monomial_coefficients) == 1:
     1501                mon,coeff = self.value._monomial_coefficients.iteritems().next()
     1502                n = self.field_order()
     1503                return self.parent()._from_dict(push_down_cython(n,dict_linear_combination([ (ZumbroichDecomposition(n, k*mon[1] % n), coeff**k,) ])), remove_zeros=False)
     1504            elif k < 0:
     1505                return self.__invert__().__pow__(-k)
     1506            else:
     1507                if k % 2 == 0:
     1508                    return (self*self).__pow__(k/2)
     1509                else:
     1510                    return self * self.__pow__(k-1)
     1511
     1512        def _acted_upon_(self, scalar, self_on_left = False):
     1513            r"""
     1514            Returns the action of a scalar on ``self``.
     1515
     1516            :param scalar: the rational factor by which ``self`` gets multiplied
     1517            :param self_on_left: if ``True``, the multiplication is done on the left
     1518            :type self_on_left: Boolean; optional, default:``True``
     1519
     1520            EXAMPLES::
     1521
     1522                sage: UCF.<E> = UniversalCyclotomicField()
     1523                sage: E(3)._acted_upon_(2)
     1524                2*E(3)
     1525            """
     1526            # With the current design, the coercion model does not have
     1527            # enough information to detect apriori that this method only
     1528            # accepts scalars; so it tries on some elements(), and we need
     1529            # to make sure to report an error.
     1530            if hasattr(scalar, 'parent') and scalar.parent() != self.base_ring():
     1531                # Temporary needed by coercion (see Polynomial/FractionField tests).
     1532                if self.base_ring().has_coerce_map_from(scalar.parent()):
     1533                    scalar = self.base_ring()(scalar)
     1534                else:
     1535                    return None
     1536
     1537            F = self.parent()
     1538            elem = F.element_class(self.value._acted_upon_(scalar, self_on_left = self_on_left), parent = F)
     1539            return elem
     1540
     1541        # For backward compatibility
     1542        _lmul_ = _acted_upon_
     1543        _rmul_ = _acted_upon_
     1544
     1545        def _mul_(self, other):
     1546            r"""
     1547            Returns ``self`` `\times` ``other``.
     1548
     1549            EXAMPLES::
     1550
     1551                sage: UCF.<E> = UniversalCyclotomicField()
     1552                sage: E(3)._mul_(E(4))
     1553                E(12)^7
     1554            """
     1555            F = self.parent()
     1556            if other.parent() is not F:
     1557                other = F(other)
     1558
     1559            if self.is_zero():
     1560                return self
     1561            if other.is_zero():
     1562                return other
     1563            if self.is_one():
     1564                return other
     1565            if other.is_one():
     1566                return self
     1567
     1568            D_self = self.value._monomial_coefficients
     1569            D_other = other.value._monomial_coefficients
     1570
     1571            if (1,0) in D_self:
     1572                coeff = D_self[(1,0)]
     1573                return F._from_dict(dict_linear_combination([ (D_other, coeff) ]), remove_zeros=False)
     1574            elif (1,0) in D_other:
     1575                coeff = D_other[(1,0)]
     1576                return F._from_dict(dict_linear_combination([ (D_self, coeff) ]), remove_zeros=False)
     1577
     1578            n1,n2 = self.field_order(),other.field_order()
     1579            n = LCM_list([n1,n2])
     1580            return F._from_dict(push_down_cython(n,dict_multiplication(D_self, D_other, n1, n2, n)), remove_zeros=False)
     1581
     1582        def _sub_(self, other):
     1583            r"""
     1584            Returns ``self`` `+` ``other.__neg__()``.
     1585
     1586            EXAMPLES::
     1587
     1588                sage: UCF.<E> = UniversalCyclotomicField()
     1589                sage: E(3).__sub__(E(4))
     1590                E(12)^4 + E(12)^7 + E(12)^11
     1591            """
     1592            return self + other.__neg__()
     1593
     1594        def _add_(self, other):
     1595            r"""
     1596            Returns ``self`` `+` ``other``.
     1597
     1598            EXAMPLES::
     1599
     1600                sage: UCF.<E> = UniversalCyclotomicField()
     1601                sage: E(3) + E(4) # indirect doctest
     1602                E(12)^4 - E(12)^7 - E(12)^11
     1603            """
     1604            n,m = self.field_order(),other.field_order()
     1605            l = LCM_list([ n, m ])
     1606
     1607            D_self = push_to_higher_field(self.value._monomial_coefficients, n, l)
     1608            D_other = push_to_higher_field(other.value._monomial_coefficients, m, l)
     1609
     1610            return self.parent()._from_dict(push_down_cython(l,dict_addition([D_self,D_other])), remove_zeros=False)
     1611
     1612        def minpoly(self, var='x'):
     1613            r"""
     1614            The minimal polynomial of ``self`` element over `\QQ`.
     1615
     1616            :param var: the minimal polynomial is defined over a polynomial ring
     1617               in a variable with this name
     1618
     1619            :type var: optional, default:``'x'``
     1620
     1621            .. SEEALSO::
     1622
     1623                - :meth:`~sage.rings.number_field.number_field_element_quadratic.NumberFieldElement_quadratic.minpoly`
     1624
     1625            EXAMPLES::
     1626
     1627                sage: UCF.<E> = UniversalCyclotomicField()
     1628
     1629                sage: UCF(4).minpoly()
     1630                x - 4
     1631
     1632                sage: UCF(4).minpoly(var='y')
     1633                y - 4
     1634
     1635                sage: E(3).minpoly()
     1636                x^2 + x + 1
     1637
     1638                sage: E(3).minpoly(var='y')
     1639                y^2 + y + 1
     1640
     1641            TESTS::
     1642
     1643                sage: x = UCF(4)
     1644                sage: x.minpoly() == x.to_cyclotomic_field().minpoly()
     1645                True
     1646
     1647                sage: x = E(3)
     1648                sage: x.minpoly() == x.to_cyclotomic_field().minpoly()
     1649                True
     1650
     1651                sage: x = E(3)
     1652                sage: x.minpoly(var='y') == x.to_cyclotomic_field().minpoly(var='y')
     1653                True
     1654            """
     1655            if self.is_rational():
     1656                R = QQ[var]
     1657                return R([-self._rational_(), 1])
     1658            else:
     1659                return self.to_cyclotomic_field().minpoly(var=var)
     1660
     1661        def abs(self):
     1662            r"""
     1663            Return the absolute value of this element.
     1664
     1665            EXAMPLES::
     1666
     1667                sage: UCF.<E> = UniversalCyclotomicField()
     1668
     1669                sage: E(3).abs()
     1670                1
     1671
     1672                sage: x = 2*E(3); x.abs()
     1673                2
     1674
     1675                sage: x = E(3)+E(4); x.abs()
     1676                1.931851652578137?
     1677
     1678            If no embedding is given, an error is raised::
     1679
     1680                sage: UCF.<E> = UniversalCyclotomicField(embedding=None)
     1681                sage: E(3).abs()
     1682                Traceback (most recent call last):
     1683                ...
     1684                ValueError: Universal Cyclotomic Field has no embedding defined.
     1685            """
     1686            P = self.parent().coerce_embedding()
     1687            if P is not None:
     1688                P = P.codomain()
     1689                return P(self).abs()
     1690            raise ValueError("%s has no embedding defined."%str(self.parent()))
     1691
     1692        def conjugate(self):
     1693            r"""
     1694            Returns the complex conjugate of ``self``.
     1695
     1696            EXAMPLES::
     1697
     1698                sage: UCF.<E> = UniversalCyclotomicField()
     1699
     1700                sage: E(3).conjugate()
     1701                E(3)^2
     1702
     1703                sage: E(4).conjugate()
     1704                -E(4)
     1705
     1706            .. NOTE::
     1707
     1708                the conjugate of a monomial is always a monomial or the negation thereof.
     1709            """
     1710            n = self.field_order()
     1711            return self.parent()._from_dict(dict_linear_combination((ZumbroichDecomposition(n, n - key[1]), c) for (key,c) in self), remove_zeros=False)
     1712
     1713        def galois_conjugates(self, m=None):
     1714            r"""
     1715            Returns all Galois conjugates of ``self``.
     1716
     1717            Those are the elements in the universal cyclotomic field obtained
     1718            from self by substituting `\zeta_n` by `\zeta_n^k` for all `{\rm
     1719            gcd}(n,k)=1`. Remark that for odd primes, the Galois conjugates
     1720            permutes the Zumbroich basis. The first Galois conjugate in the
     1721            list is ``self``.
     1722
     1723            :param m: if given, it must be a multiple of :meth:`field_order`;
     1724                the Galois conjugates are then computed with respect to the cyclotomics of order ``m``
     1725
     1726            OUTPUT:
     1727
     1728            - a list `[p_{i_1},...,p_{i_{max}}]`, where `p_{i_j}` is obtained
     1729              from ``self`` by substituting `E(n)` by `E(n)^{i_j}` and where
     1730              `i_j` is the `j`-th integer coprime to n
     1731
     1732            EXAMPLES::
     1733
     1734                sage: UCF.<E> = UniversalCyclotomicField()
     1735
     1736                sage: E(6).galois_conjugates()
     1737                [-E(3)^2, -E(3)]
     1738
     1739                sage: E(6).galois_conjugates(6)
     1740                [-E(3)^2, -E(3)]
     1741
     1742                sage: E(6).galois_conjugates(12)
     1743                [-E(3)^2, -E(3), -E(3)^2, -E(3)]
     1744
     1745                sage: E(8).galois_conjugates()
     1746                [E(8), E(8)^3, -E(8), -E(8)^3]
     1747
     1748                sage: E(8).galois_conjugates(16)
     1749                [E(8), E(8)^3, -E(8), -E(8)^3, E(8), E(8)^3, -E(8), -E(8)^3]
     1750
     1751                sage: E(9).galois_conjugates()
     1752                [-E(9)^4 - E(9)^7, E(9)^2, E(9)^4, E(9)^5, E(9)^7, -E(9)^2 - E(9)^5]
     1753
     1754                sage: E(11).galois_conjugates()
     1755                [E(11), E(11)^2, E(11)^3, E(11)^4, E(11)^5, E(11)^6, E(11)^7, E(11)^8, E(11)^9, E(11)^10]
     1756
     1757                sage: E(6).galois_conjugates(5)
     1758                Traceback (most recent call last):
     1759                ...
     1760                ValueError: The given integer (5) is not a multiple of the field order of -E(3)^2.
     1761            """
     1762            n = self.field_order()
     1763            if m is None:
     1764                m = n
     1765            else:
     1766                if not m%n == 0:
     1767                    raise ValueError("The given integer (%s) is not a multiple of the field order of %s."%(m,self))
     1768            coprimes = [1] + [ i for i in range(2,m) if GCD_list([m,i])==1 ]
     1769            conjugates = galois_conjugates_cython(self.value._monomial_coefficients, n, m, coprimes)
     1770            return [ self.parent()._from_dict(conjugate, remove_zeros=False) for conjugate in conjugates ]
     1771
     1772        def support(self):
     1773            r"""
     1774            Returns the support of ``self``.
     1775
     1776            EXAMPLES::
     1777
     1778                sage: UCF.<E> = UniversalCyclotomicField()
     1779                sage: E(6).support()
     1780                [(3, 2)]
     1781            """
     1782            return self.value.support()
     1783
     1784        def coefficient(self, mon):
     1785            r"""
     1786            Returns the coefficient of ``mon`` in ``self``.
     1787
     1788            :param mon: an element in the Zumbroich basis
     1789
     1790            EXAMPLES::
     1791
     1792                sage: UCF.<E> = UniversalCyclotomicField()
     1793
     1794                sage: E(6)
     1795                -E(3)^2
     1796
     1797                sage: E(6).coefficient((3,2))
     1798                -1
     1799
     1800                sage: E(6).coefficient((3,1))
     1801                0
     1802
     1803            Alternatively, one can use indexed access::
     1804
     1805                sage: E(6)[(3,2)]
     1806                -1
     1807            """
     1808            try:
     1809                return self.value._monomial_coefficients[mon]
     1810            except KeyError:
     1811                return 0
     1812
     1813        __getitem__ = coefficient
     1814
     1815        def field_order(self):
     1816            r"""
     1817            Returns the order of the smallest field containing ``self``.
     1818
     1819            EXAMPLES::
     1820
     1821                sage: UCF.<E> = UniversalCyclotomicField()
     1822
     1823                sage: E(4).field_order()
     1824                4
     1825
     1826                sage: E(6).field_order()
     1827                3
     1828            """
     1829            if bool(self.value._monomial_coefficients):
     1830                return self.value._monomial_coefficients.iterkeys().next()[0]
     1831            else:
     1832                return 1
     1833
     1834        def norm_of_galois_extension(self):
     1835            r"""
     1836            Returns the norm as a Galois extension of `\QQ`, which is
     1837            given by the product of all galois_conjugates.
     1838
     1839            EXAMPLES::
     1840
     1841                sage: UCF.<E> = UniversalCyclotomicField()
     1842
     1843                sage: E(3).norm_of_galois_extension()
     1844                1
     1845
     1846                sage: E(6).norm_of_galois_extension()
     1847                1
     1848
     1849                sage: (E(2) + E(3)).norm_of_galois_extension()
     1850                3
     1851            """
     1852            return self.parent().prod(self.galois_conjugates()).value._monomial_coefficients[(1,0)]
     1853
     1854        def to_cyclotomic_field(self):
     1855            r"""
     1856            Returns ``self`` in :class:`CyclotomicField`.
     1857
     1858            .. WARNING::
     1859
     1860                This method raises an error if ``self.parent()`` does not
     1861                have the standard embedding
     1862
     1863            EXAMPLES::
     1864
     1865                sage: UCF.<E> = UniversalCyclotomicField()
     1866
     1867                sage: E(5).to_cyclotomic_field()
     1868                zeta5
     1869
     1870            This method is as well used to convert to a cyclotomic field::
     1871
     1872                sage: CF = CyclotomicField(5)
     1873                sage: CF(E(5))
     1874                zeta5
     1875
     1876            .. SEEALSO::
     1877
     1878                :class:`CyclotomicField`
     1879            """
     1880            if not self.parent()._has_standard_embedding:
     1881                raise TypeError("This method can only be used if %s uses the standard embedding."%self)
     1882            CF = CyclotomicField(self.field_order())
     1883            zeta = CF.gen()
     1884            def on_basis(x):
     1885                return zeta**(x[1])
     1886            return self.parent()._data._apply_module_morphism(self.value, on_basis, codomain=CF)
     1887
     1888class ZumbroichBasisIndices(UniqueRepresentation, Parent):
     1889    def __init__(self):
     1890        r"""
     1891        This class is a thin wrapper to work with indices in the Zumbroich basis.
     1892
     1893        EXAMPLES::
     1894
     1895            sage: from sage.rings.universal_cyclotomic_field.universal_cyclotomic_field import ZumbroichBasisIndices
     1896
     1897            sage: ZumbroichBasisIndices()
     1898            The indices of the Zumbroich basis
     1899
     1900        One can ask for an element to play with::
     1901
     1902            sage: a = ZumbroichBasisIndices().an_element(); a
     1903            (12, 4)
     1904
     1905        The element ``a`` is indeed an element of this class::
     1906
     1907            sage: a.parent()
     1908            The indices of the Zumbroich basis
     1909
     1910        And one can check if an element is indeed contained in the Zumbroich basis::
     1911
     1912            sage: a in ZumbroichBasisIndices()
     1913            True
     1914
     1915            sage: (12,4) in ZumbroichBasisIndices()
     1916            True
     1917        """
     1918        Parent.__init__(self, category=Sets())
     1919
     1920    def _repr_(self):
     1921        r"""
     1922        Returns the string representation of ``self``.
     1923
     1924        EXAMPLES::
     1925
     1926            sage: from sage.rings.universal_cyclotomic_field.universal_cyclotomic_field import ZumbroichBasisIndices
     1927            sage: ZumbroichBasisIndices() # indirect doctest
     1928            The indices of the Zumbroich basis
     1929        """
     1930        return "The indices of the Zumbroich basis"
     1931
     1932    def an_element(self):
     1933        r"""
     1934        Returns an element of the Zumbroich basis.
     1935
     1936        EXAMPLES::
     1937
     1938            sage: from sage.rings.universal_cyclotomic_field.universal_cyclotomic_field import ZumbroichBasisIndices
     1939            sage: a = ZumbroichBasisIndices().an_element(); a
     1940            (12, 4)
     1941        """
     1942        return self.element_class((12,4),parent=self)
     1943
     1944    def __contains__(self, x):
     1945        r"""
     1946        Returns ``True`` if ``x`` is contained in ``self``.
     1947
     1948        EXAMPLES::
     1949
     1950            sage: from sage.rings.universal_cyclotomic_field.universal_cyclotomic_field import ZumbroichBasisIndices
     1951            sage: a = ZumbroichBasisIndices().an_element(); a
     1952            (12, 4)
     1953            sage: a in ZumbroichBasisIndices() # indirect doctest
     1954            True
     1955            sage: (12,4) in ZumbroichBasisIndices()
     1956            True
     1957            sage: (12,5) in ZumbroichBasisIndices()
     1958            False
     1959        """
     1960        if isinstance(x,tuple) and len(x) == 2:
     1961            n,i = int(x[0]),int(x[1])
     1962            x = self.element_class((n,int(i)),parent=self)
     1963        return x in self.indices(x[0])
     1964
     1965    def indices(self, n, m=1):
     1966        r"""
     1967        Returns the list of tuples `(n,k)` such that the set `\zeta_n^k` form a Zumbroich basis for `QQ(\zeta_n)` over `QQ(\zeta_m)`.
     1968
     1969        :param n: positive integer
     1970        :param m: positive integer dividing ``n``
     1971        :type m: optional, default:``1``
     1972
     1973        EXAMPLES::
     1974
     1975            sage: from sage.rings.universal_cyclotomic_field.universal_cyclotomic_field import ZumbroichBasisIndices
     1976
     1977            sage: ZumbroichBasisIndices().indices(6)
     1978            set([(6, 4), (6, 2)])
     1979            sage: ZumbroichBasisIndices().indices(12)
     1980            set([(12, 7), (12, 4), (12, 11), (12, 8)])
     1981            sage: ZumbroichBasisIndices().indices(24)
     1982            set([(24, 19), (24, 8), (24, 17), (24, 16), (24, 14), (24, 1), (24, 22), (24, 11)])
     1983        """
     1984        if not n%m == 0:
     1985            raise ValueError('%s does not divide %s.'%(m,n))
     1986        B = ZumbroichBasisCython(n, m)
     1987        return (set([ self.element_class((n,int(i)),parent=self) for i in B ]))
     1988
     1989    class Element(ElementWrapper):
     1990        def __getitem__(self,i):
     1991            r"""
     1992            Passes the indexing to its value.
     1993
     1994            EXAMPLES::
     1995
     1996            sage: from sage.rings.universal_cyclotomic_field.universal_cyclotomic_field import ZumbroichBasisIndices
     1997            sage: a = ZumbroichBasisIndices().an_element()
     1998            sage: a[0],a[1] # indirect doctest
     1999            (12, 4)
     2000            """
     2001            return self.value[i]
     2002
     2003def get_parent_of_embedding(embedding):
     2004    r"""
     2005    Returns the parent of an element in the image of ``embedding``.
     2006
     2007    :param embedding: A function from the positive integers `\{1,2,3,\ldots\}` into a common parent
     2008
     2009    If the images are in a real or complex field, then
     2010    it creates an image into a lazy field.
     2011
     2012    EXAMPLES::
     2013
     2014        sage: from sage.rings.universal_cyclotomic_field.universal_cyclotomic_field import get_parent_of_embedding
     2015
     2016        sage: get_parent_of_embedding(lambda n: QQbar.zeta()^n)
     2017        Algebraic Field
     2018
     2019        sage: get_parent_of_embedding(lambda n: CC(exp(2*pi*I/n)))
     2020        Complex Lazy Field
     2021    """
     2022    if callable(embedding) and isinstance(embedding(3), Element):
     2023        P = embedding(3).parent()
     2024        if not P.is_exact():
     2025            RR = RealField(mpfr_prec_min())
     2026            CC = ComplexField(mpfr_prec_min())
     2027            if RR.has_coerce_map_from(P):
     2028                P = RLF
     2029            elif CC.has_coerce_map_from(P):
     2030                P = CLF
     2031        return P
     2032    else:
     2033        raise TypeError("Embedding (type %s) must be an element." % type(embedding))
  • new file sage/rings/universal_cyclotomic_field/universal_cyclotomic_field_c.pyx

    diff --git a/sage/rings/universal_cyclotomic_field/universal_cyclotomic_field_c.pyx b/sage/rings/universal_cyclotomic_field/universal_cyclotomic_field_c.pyx
    new file mode 100644
    - +  
     1r"""
     2The cythonized low-level methods used in the implementation of the universal cyclotomic field with the Zumbroich basis.
     3
     4.. SEEALSO::
     5
     6    :class:`UniversalCyclotomicField`
     7
     8AUTHORS:
     9
     10- Christian Stump
     11"""
     12#*****************************************************************************
     13#       Copyright (C) 2012 Christian Stump <christian.stump@univie.ac.at>
     14#
     15#  Distributed under the terms of the GNU General Public License (GPL)
     16#                  http://www.gnu.org/licenses/
     17#*****************************************************************************
     18include "../../ext/stdsage.pxi"
     19include "../../ext/cdefs.pxi"
     20include "../../ext/gmp.pxi"
     21
     22import sys
     23import operator
     24
     25from cpython cimport bool, PyDict_Copy
     26from itertools import product
     27from sage.combinat.dict_addition import dict_linear_combination, dict_addition
     28from sage.categories.map cimport Map
     29from sage.rings.arith import prod, factor, lcm
     30from sage.rings.finite_rings.integer_mod cimport mod_inverse_int
     31from sage.rings.integer import LCM_list
     32from sage.rings.all import QQ
     33from sage.rings.rational cimport Rational
     34
     35import numpy as np
     36cimport numpy as np
     37
     38import cython
     39
     40DTYPE = np.int
     41ctypedef np.int_t DTYPE_t
     42
     43cdef dict factor_cache = dict()
     44cpdef cached_factor(int n):
     45    r"""
     46    Returns a cached version of the dict of a factorization.
     47
     48    :param n: a positive integer
     49
     50    EXAMPLES::
     51
     52        sage: from sage.rings.universal_cyclotomic_field.universal_cyclotomic_field_c import cached_factor
     53        sage: cached_factor(12)
     54        {2: 2, 3: 1}
     55
     56    .. WARNING::
     57
     58        Internal function, not to be used directly!
     59    """
     60    if n in factor_cache:
     61        return factor_cache[n]
     62    else:
     63        X = dict(factor(n))
     64        factor_cache[n] = X
     65        return X
     66
     67cpdef ZumbroichIndexSet(int p, int k):
     68    """
     69    Returns a list of integers depending on p and k, which is needed in the :meth:`ZumbroichBasisCython`.
     70
     71    :param p: a positive integer
     72    :param k: a positive integer
     73
     74    OUTPUT:
     75
     76    - list of indices as defined for J_{k,p} [B97] p. 283, Remark 1
     77
     78    EXAMPLES::
     79
     80        sage: from sage.rings.universal_cyclotomic_field.universal_cyclotomic_field_c import ZumbroichIndexSet
     81        sage: ZumbroichIndexSet(6,0)
     82        [1, 2, 3, 4, 5]
     83        sage: ZumbroichIndexSet(6,1)
     84        [-2, -1, 0, 1, 2]
     85    """
     86    if k == 0:
     87        if p == 2:
     88            return [ 0 ]
     89        else:
     90            return range(1,p)
     91    else:
     92        if p == 2:
     93            return [0,1]
     94        else:
     95            return range(-(p-1)/2, (p-1)/2+1)
     96
     97cdef dict zumbroich_basis_cache = dict()
     98cpdef ZumbroichBasisCython(int n, int m = 1):
     99    """
     100    Returns the Zumbroich basis of the cyclotomics of order `n` over the cyclotomics of order `m`.
     101
     102    :param n: positive integer
     103    :param m: positive integer dividing ``n``
     104    :type m: optional, default:``1``
     105
     106    OUTPUT:
     107
     108    - '\{i_1,\ldots,i_k\}` such that `\{ E(n)^{i_j} \}` is the Zumbroich basis of the cyclotomic field
     109      of order `n` over the cyclotomic field of order `m`.
     110
     111    .. NOTE::
     112
     113        The computation is based on the description in [Bre97]_.
     114
     115    EXAMPLES:
     116
     117    We compute the Zumbroich basis of the cyclotomics of order `12` over the cyclotomics of order `3`, given by `\{E(12)^0,E(12)^3\}`::
     118
     119        sage: from sage.rings.universal_cyclotomic_field.universal_cyclotomic_field_c import ZumbroichBasisCython
     120        sage: ZumbroichBasisCython(12,3)
     121        array([0, 3])
     122    """
     123    if (n,m) in zumbroich_basis_cache:
     124        return zumbroich_basis_cache[(n,m)]
     125    cdef int mu, n_fac, m_fac, k, p, i
     126    cdef list list_of_index_sets
     127    cdef tuple index_tuple
     128    cdef dict n_fac_dict, quo_fac_dict
     129
     130    n_fac_dict = cached_factor(n)
     131    quo_fac_dict = cached_factor(n/m)
     132
     133    list_of_index_sets = []
     134
     135    for p in quo_fac_dict:
     136        mu = quo_fac_dict[p]
     137        n_fac = n_fac_dict[ p ]
     138        m_fac = n_fac - mu
     139        for k in xrange(m_fac, n_fac):
     140            list_of_index_sets.append([ n*i / p**(k+1) for i in ZumbroichIndexSet(p, k) ])
     141    index_tuples = product(*list_of_index_sets)
     142    cdef int size = prod([ len(index_set) for index_set in list_of_index_sets ])
     143
     144    cdef np.ndarray[DTYPE_t,ndim=1] L = np.ndarray([size],dtype=DTYPE)
     145    cdef tuple X
     146    for i from 0 <= i < size:
     147        X = index_tuples.next()
     148        L[i] = sum(X)%n
     149    L.sort()
     150    zumbroich_basis_cache[(n,m)] = L
     151    return L
     152
     153cdef inline int find_array(int a, int * ar, int size):
     154    r"""
     155    Returns the position of a in ar.
     156
     157    .. WARNING::
     158
     159        Internal function, not to be used directly!
     160    """
     161    cdef unsigned int i
     162    for i from 0 <= i < size:
     163        if a == ar[i]:
     164            return i
     165    return size
     166
     167cpdef ZumbroichDecomposition(int n, int i):
     168    """
     169    Returns the decomposition of `E(n,i)` in the Zumbroich basis of the cyclotomics of order `n`.
     170
     171    :param n: positive integer
     172    :param i: positive integer `<` ``n``
     173
     174    OUTPUT:
     175
     176    - The decomposition of `E(n,i)` in the Zumbroich basis, as a dictionary
     177
     178    EXAMPLES::
     179
     180        sage: from sage.rings.universal_cyclotomic_field.universal_cyclotomic_field_c import ZumbroichDecomposition
     181        sage: ZumbroichDecomposition(6, 1)
     182        {(6, 4): -1}
     183    """
     184    cdef int mu, p, k, j
     185    cdef dict n_fac, i_mod_n_dict, return_dict
     186    cdef list mod_prime, list_of_i_mod_n_dict, new_list_of_i_mod_n_dict
     187
     188    n_fac = cached_factor(n)
     189    mod_prime = mod_prime_list(n,i,n_fac)
     190
     191    cdef int c = -1 if len(mod_prime) %2 else 1
     192
     193    prime_index_list = [ range(1,p) for p in mod_prime ]
     194    prime_index_tuples = product(*prime_index_list)
     195
     196    return_dict = {}
     197
     198    for tup in prime_index_tuples:
     199        k = (i + sum([ n * tup[j] / mod_prime[j] for j in
     200                       xrange(len(mod_prime))] )) % n
     201        return_dict[ (n,k) ] = c
     202
     203    return return_dict
     204
     205cpdef list ZumbroichDecomposition_list(int n, int i):
     206    """
     207    Returns the decomposition of `E(n,i)` in the Zumbroich basis of the cyclotomics of order `n`.
     208
     209    :param n: positive integer
     210    :param i: positive integer `<` ``n``
     211
     212    OUTPUT:
     213
     214    - The decomposition of `E(n,i)` in the Zumbroich basis, as an array of indices of the Zumbroich basis, together with the length of mod_prime_list at the end.
     215        It is used as follows: `\zeta_n^i = (-1)^l \sum \zeta_n^ZB(k)`, where l is the last entry of the last of the array, ZB(k) is the `k`-th entry in the Zumbroich
     216        basis and where the sum ranges over all but the last entry in the array.
     217
     218
     219    EXAMPLES::
     220
     221        sage: from sage.rings.universal_cyclotomic_field.universal_cyclotomic_field_c import ZumbroichDecomposition_list
     222        sage: from sage.rings.universal_cyclotomic_field.universal_cyclotomic_field_c import ZumbroichBasisCython
     223        sage: ZumbroichDecomposition_list(6, 1)
     224        [1, 1]
     225
     226    This reads as `\zeta_6 = (-1)^1 \zeta_6^ZB(1) = -\zeta_6^4`
     227    """
     228    cdef dict n_fac = cached_factor(n)
     229    cdef list mod_prime = mod_prime_list(n,i,n_fac)
     230    cdef int list_size = len(mod_prime)
     231
     232    cdef np.ndarray[DTYPE_t] ZB_list
     233    cdef int ZB_list_size
     234    ZB_list = ZumbroichBasisCython(n)
     235    ZB_size = len(ZB_list)
     236    cdef int *ZB_array = <int*>sage_malloc(sizeof(int) * ZB_size)
     237    cdef int j
     238    for j from 0 <= j < ZB_size:
     239        ZB_array[j] = ZB_list[j]
     240
     241    cdef int p
     242    cdef list prime_index_list = [ range(1,p) for p in mod_prime ]
     243    prime_index_tuples = product(*prime_index_list)
     244
     245    cdef int prime_prod = 1
     246    for j from 0 <= j < list_size:
     247        p = mod_prime[j]
     248        prime_prod *= p - 1
     249        mod_prime[j] = n / p
     250    cdef list return_list = []
     251    cdef int tup_sum, fac, k
     252    cdef tuple tup
     253    for tup in prime_index_tuples:
     254        tup_sum = i
     255        for j from 0 <= j < list_size:
     256            p = mod_prime[j]
     257            fac = tup[j]
     258            tup_sum += p * fac
     259        k = tup_sum % n
     260        if k < 0:
     261            k += n
     262        return_list.append(find_array(k, ZB_array, ZB_size))
     263    return_list.append(list_size)
     264
     265    return return_list
     266
     267cpdef mod_prime_list(int n, int i, dict n_fac):
     268    r"""
     269    Returns the list of prime factors of ``n`` which need to be modified in order to express `\zeta_n^i` in the Zumbroich basis.
     270
     271    For details see [Bre97]_.
     272
     273    :param n: positive integer
     274    :param i: positive integer `<` ``n``
     275
     276    EXAMPLES::
     277
     278        sage: from sage.rings.universal_cyclotomic_field.universal_cyclotomic_field_c import mod_prime_list
     279        sage: n = 12
     280        sage: n_fac = dict(n.factor())
     281        sage: for k in [1..12]: print k, mod_prime_list(n,k,n_fac)
     282        1 [2]
     283        2 [2]
     284        3 [3]
     285        4 []
     286        5 [2]
     287        6 [2, 3]
     288        7 []
     289        8 []
     290        9 [2, 3]
     291        10 [2]
     292        11 []
     293        12 [3]
     294    """
     295    cdef list mod_primes_list
     296
     297    cdef Py_ssize_t factor, count,mu,k,p,m
     298
     299    mod_primes_list = []
     300    cdef  Py_ssize_t max_mu = 0
     301
     302    for p in n_fac:
     303        mu = n_fac[p]
     304        if mu > max_mu:
     305            max_mu = mu
     306    cdef int *tmp_list = <int *>sage_malloc(max_mu * sizeof(int))
     307    if not tmp_list:
     308            raise MemoryError()
     309
     310    for p in n_fac:
     311        mu = n_fac[p]
     312        factor = p**mu
     313
     314        m = n / factor
     315
     316        count = (i * mod_inverse_int(m,factor)) % factor
     317        if count < 0:
     318            count += factor
     319        i -= count * m
     320
     321        if p == 2:
     322            if 1 == count/(factor/p):
     323                mod_primes_list.append(p)
     324            factor /= p**mu
     325        else:
     326            for k from 0 <= k < mu:
     327                factor /= p
     328                tmp_list[k] = count / factor
     329                count = count % factor
     330
     331            for k from mu-1 >= k > 0:
     332                if tmp_list[k] > (p-1) / 2:
     333                    tmp_list[k] -= p
     334                    if k == 1 and tmp_list[k-1] == p-1:
     335                        tmp_list[k-1] = 0
     336                    else:
     337                        tmp_list[k-1] += 1
     338            if tmp_list[0] == 0:
     339                mod_primes_list.append(p)
     340    sage_free(tmp_list)
     341    return mod_primes_list
     342
     343cdef res_classes(list L, int k):
     344    """
     345    Groups the elements of ``L`` by residue class modulo ``k``.
     346
     347    :param L: a list of integers
     348    :param k: positive integer
     349
     350    OUTPUT:
     351
     352    - a dictionary mapping residue classes to lists of elements of ``L``.
     353
     354    .. WARNING::
     355
     356        Internal function, not to be used directly!
     357    """
     358    cdef int x, tmp
     359    cdef dict res
     360
     361    res = {}
     362    for i in range(len(L)):
     363        x = L[i]
     364        tmp = x % k
     365        if tmp in res:
     366            res[ tmp ].append(x)
     367        else:
     368            res[ tmp ] = [ x ]
     369    return res
     370
     371cpdef push_to_higher_field(dict D, int n, int l):
     372    """
     373    Pushes an element of the universal cyclotomic field of order `n`, represented by its dictionary,
     374    to the cyclotomic field of order l. This method is used e.g. for adding/multiplying two elements in different cyclotomics.
     375
     376    :param D: a dictionary representing an element in the universal cyclotomic field
     377    :param n: the order of the cyclotomics containing ``D``
     378    :param l: a multiple of ``n``, the order of the field ``D`` is pushed
     379
     380    EXAMPLES::
     381
     382        sage: from sage.rings.universal_cyclotomic_field.universal_cyclotomic_field_c import push_to_higher_field
     383        sage: UCF.<E> = UniversalCyclotomicField()
     384
     385        sage: D = E(6)._dict_(); D
     386        {(3, 2): -1}
     387
     388        sage: push_to_higher_field(D,3,6)
     389        {(6, 4): -1}
     390    """
     391    cdef int k
     392    if n == l:
     393        return D
     394    else:
     395        return dict_linear_combination([ (ZumbroichDecomposition(l, k*l/n), D[ (n,k) ]) for _,k in D ])
     396
     397cpdef zip_key_dict(list keys, dict key_dict, int n, int m, int p, bool positive=True):
     398    """
     399    TESTS::
     400
     401        sage: from sage.rings.universal_cyclotomic_field.universal_cyclotomic_field_c import push_down_cython
     402        sage: D = { (6,4):-1 }
     403        sage: push_down_cython(6,D) # indirect doctest
     404        {(3, 2): -1}
     405
     406    .. WARNING::
     407
     408        Internal function, not to be used directly!
     409    """
     410    cdef int fac
     411    cdef int k
     412    cdef dict G
     413    cdef tuple key
     414
     415    G = {}
     416    if positive:
     417        fac = 1
     418    else:
     419        fac = -1
     420
     421    for key in keys:
     422        G[ key ] = fac * key_dict[ (n, (m+key[1]*p)%n) ]
     423    return G
     424
     425cpdef push_down_cython(int n, dict dict_in_basis):
     426    """
     427    Returns `x` in the smallest cyclotomic field containing it, as a dictionary.
     428    Implementation of the push down algorithm described in [B97].
     429
     430    :param n: a positive integer
     431    :param dict_in_basis: a dictionary representing an element of
     432       the cyclotomic field of order `n` expressed in the Zumbroich basis
     433
     434    EXAMPLES::
     435
     436        sage: from sage.rings.universal_cyclotomic_field.universal_cyclotomic_field_c import push_down_cython
     437        sage: D = { (6,4):-1 }
     438        sage: push_down_cython(6,D)
     439        {(3, 2): -1}
     440    """
     441    cdef int mu
     442    cdef int p, m, k, _
     443    cdef dict res
     444    cdef bool has_changed, should_change
     445
     446    n_fac = cached_factor(n)
     447
     448    for p in n_fac:
     449        mu = n_fac[p]
     450        has_changed = True
     451        while has_changed and mu > 0:
     452            has_changed = False
     453            m = n/p
     454
     455            should_change = True
     456            if mu > 1:
     457                for _,k in dict_in_basis:
     458                    if k % p != 0:
     459                        should_change = False
     460                if should_change:
     461                    dict_in_basis = dict([ ((m,k/p), dict_in_basis[ (n,k) ]) for n,k in dict_in_basis ])
     462                    has_changed = True
     463            else:
     464                res = res_classes([ L[1] for L in dict_in_basis ], m)
     465                for k in res:
     466                    if len(res[ k ]) != p - 1:
     467                        should_change = False
     468                if should_change:
     469                    for k in res:
     470                        res[ k ] = k
     471                        while res[ k ] % p != 0:
     472                            res[ k ] += m
     473                        res[ k ] /= p
     474                    keys = [ (m, res[k]) for k in res ]
     475
     476                    if p == 2:
     477                        dict_in_basis = zip_key_dict(keys, dict_in_basis, n, 0, p, positive=True)
     478                        has_changed = True
     479                    else:
     480                        for _,k in keys:
     481                            if should_change:
     482                                for i in range(2, p):
     483                                    if dict_in_basis[ (n, (m*i+k*p)%n) ] != dict_in_basis[ (n,(m+k*p)%n) ]:
     484                                        should_change = False
     485                        if should_change:
     486                            dict_in_basis = zip_key_dict(keys, dict_in_basis, n, m, p, positive=False)
     487                            has_changed = True
     488            if has_changed:
     489                n = m
     490                mu -= 1
     491    return dict_in_basis
     492
     493cpdef galois_conjugates_cython(dict D, int n, int m, list coprimes):
     494    """
     495    Returns all Galois conjugates of ``elem`` which lives in the cyclotomics of order ``n``, and with the ``coprimes`` already given.
     496    Observe that the product of all Galois conjugates is 1, and thus, this method is used to compute the inverse for elements in
     497    the universal cyclotomic field.
     498
     499    :param D: a dictionary representing an element in the universal cyclotomic field
     500    :param n: order of the element in ``D``
     501    :param m: a multiple of ``n`` in which field the galois conjugates should be considered
     502    :param coprimes: list of coprimes of ``n``
     503
     504    EXAMPLES::
     505
     506        sage: from sage.rings.universal_cyclotomic_field.universal_cyclotomic_field_c import galois_conjugates_cython
     507        sage: UCF.<E> = UniversalCyclotomicField()
     508
     509        sage: galois_conjugates_cython(E(12).value._monomial_coefficients, 12, 12, [1,5,7,11])
     510        [{(12, 7): -1}, {(12, 11): -1}, {(12, 7): 1}, {(12, 11): 1}]
     511
     512        sage: galois_conjugates_cython(E(12).value._monomial_coefficients, 12, 24, [1, 5, 7, 11, 13, 17, 19, 23])
     513        [{(12, 7): -1}, {(12, 11): -1}, {(12, 7): 1}, {(12, 11): 1}, {(12, 7): -1}, {(12, 11): -1}, {(12, 7): 1}, {(12, 11): 1}]
     514
     515        sage: galois_conjugates_cython(E(9).value._monomial_coefficients, 9, 9, [1, 2, 4, 5, 7, 8])
     516        [{(9, 4): -1, (9, 7): -1}, {(9, 2): 1}, {(9, 4): 1}, {(9, 5): 1}, {(9, 7): 1}, {(9, 2): -1, (9, 5): -1}]
     517    """
     518    cdef int i, k
     519    cdef list conjugates
     520
     521    if n != m:
     522        D = push_to_higher_field(D, n, m)
     523    if len(coprimes) == m-1 and m > 2:
     524        conjugates = []
     525        for i in coprimes:
     526            conjugates.append(dict([ ((m,(k*i) % m), D[(m,k)]) for m,k in D]))
     527    else:
     528        conjugates = []
     529        for i in coprimes:
     530            conjugates.append(dict_linear_combination([(ZumbroichDecomposition(m, (k*i) % m), D[(m,k)]) for m,k in D]))
     531    if n != m:
     532        conjugates = [ push_down_cython(m,D) for D in conjugates ]
     533    return conjugates
     534
     535cpdef dict_vector_multiplication(int n, tuple l1, tuple l2):
     536    r"""
     537    Returns the vector multiplication of ``l1`` and ``l2``.
     538
     539    :param l1, l2: tuples of the same length containing dictionaries representing elements in the universal cyclotomics
     540
     541    EXAMPLES::
     542
     543        sage: from sage.rings.universal_cyclotomic_field.universal_cyclotomic_field_c import dict_vector_multiplication
     544        sage: UCF.<E> = UniversalCyclotomicField()
     545
     546        sage: D1 = E(3).value._monomial_coefficients; D1
     547        {(3, 1): 1}
     548
     549        sage: D2 = E(4).value._monomial_coefficients; D2
     550        {(4, 1): 1}
     551
     552        sage: l = (D1,D2)
     553        sage: dict_vector_multiplication(12,l,l)
     554        {(12, 4): 1, (12, 8): 2}
     555    """
     556    cdef int a0,a1,b0,b1,i,k
     557    cdef list out = []
     558    cdef dict empty_dict = {}
     559    cdef dict D1, D2
     560
     561    for i in xrange(len(l1)):
     562        D1 = l1[i]
     563        D2 = l2[i]
     564        if D1 == empty_dict or D2 == empty_dict:
     565            out.append(empty_dict)
     566        else:
     567            n1 = iter(D1).next()[0]
     568            n2 = iter(D2).next()[0]
     569            out.append(dict_multiplication(D1,D2,n1,n2,n))
     570    return dict_addition(out)
     571
     572cdef int *linear_combination_pointer
     573cdef add_to_basis_linear_combination(list decomposition, int coeff, int size):
     574    r"""
     575    Adds the entries in ``decomposition`` `\times` ``coeff`` to ``linear_combination_pointer``.
     576
     577    .. WARNING::
     578
     579        Internal function, not to be used directly!
     580    """
     581    global linear_combination_pointer
     582    cdef int value, add_value,key
     583
     584    cdef int counter = 0
     585    for key in decomposition:
     586        if counter < size:
     587            add_value = linear_combination_pointer[key]
     588            add_value += coeff
     589            linear_combination_pointer[key] = add_value
     590            counter += 1
     591
     592cdef inline as_rat(int a):
     593    r"""
     594    Returns the integer ``a`` as a rational.
     595
     596    .. WARNING::
     597
     598        Internal function, not to be used directly!
     599    """
     600    cdef Rational rat = <Rational> PY_NEW(Rational)
     601    mpq_set_si(rat.value,a,1)
     602    return rat
     603
     604cpdef dict dict_multiplication(dict D1, dict D2, int n1, int n2, int n):
     605    r"""
     606    Returns the multiplication of two elements in the universal cyclotomics, both represented as a dictionary, again as a dict.
     607
     608    EXAMPLES::
     609
     610        sage: from sage.rings.universal_cyclotomic_field.universal_cyclotomic_field_c import dict_multiplication
     611        sage: UCF.<E> = UniversalCyclotomicField()
     612
     613        sage: D1 = E(3).value._monomial_coefficients; D1
     614        {(3, 1): 1}
     615
     616        sage: D2 = E(4).value._monomial_coefficients; D2
     617        {(4, 1): 1}
     618
     619        sage: dict_multiplication(D1,D2,3,4,12)
     620        {(12, 7): 1}
     621    """
     622    # the overhead of the method seems to be big, but most of the part is spent in the double for loop, and I don't know how
     623    # to improve this piece for now
     624
     625    # setting L1, L2, and Lnew to the indices of the Zumbroich basis for n1, n2, and n (which are supposed to be the order of the two dicts and their lcm)
     626    # also setting L1_size, L2_size, and Lnew_size to their sizes
     627    cdef np.ndarray[DTYPE_t] L1, L2, Lnew
     628    cdef int L1_size,L2_size,Lnew_size
     629    L1 = ZumbroichBasisCython(n1)
     630    L1_size = len(L1)
     631    L2 = ZumbroichBasisCython(n2)
     632    L2_size = len(L2)
     633    Lnew = ZumbroichBasisCython(n)
     634    Lnew_size = len(Lnew)
     635
     636    # writing L1 and L2 into c arrays
     637    cdef int *L1_array = <int*>sage_malloc(sizeof(int) * L1_size)
     638    cdef int *L2_array = <int*>sage_malloc(sizeof(int) * L2_size)
     639    cdef int j
     640    for j from 0 <= j < L1_size:
     641        L1_array[j] = L1[j]
     642    for j from 0 <= j < L2_size:
     643        L2_array[j] = L2[j]
     644
     645    # setting up pointers for the two input dicts
     646    cdef Py_ssize_t key
     647
     648    cdef int *D1_pointer = <int *>sage_malloc(L1_size * sizeof(int))
     649    for key from 0 <= key < L1_size:
     650        D1_pointer[key] = 0
     651    cdef int *D2_pointer = <int *>sage_malloc(L2_size * sizeof(int))
     652    for key from 0 <= key < L2_size:
     653        D2_pointer[key] = 0
     654
     655    # setting up pointer for the output dict
     656    global linear_combination_pointer
     657    linear_combination_pointer = <int *>sage_malloc(Lnew_size * sizeof(int))
     658    for key from 0 <= key < Lnew_size:
     659        linear_combination_pointer[key] = 0
     660
     661    #computing the lcm of the denominators in order to work with ints rather than with rationals
     662    #FIXME: there might be a faster method doing this
     663    cdef list LCM = [None]*len(D1)
     664    key = 0
     665    for X in D1:
     666        X = D1[X]
     667        if type(X) == Rational:
     668            LCM[key] = X.denom()
     669        else:
     670            LCM[key] = X
     671        key += 1
     672    cdef int denom1 = LCM_list(LCM)
     673    cdef Rational denom_rat1 = as_rat(denom1)
     674    LCM = [None]*len(D2)
     675    key = 0
     676    for X in D2:
     677        X = D2[X]
     678        if type(X) == Rational:
     679            LCM[key] = X.denom()
     680        else:
     681            LCM[key] = X
     682        key += 1
     683    cdef int denom2 = LCM_list(LCM)
     684    cdef Rational denom_rat2 = as_rat(denom2)
     685
     686    # filling the pointers for the dicts with ints from the dicts multiplied with the lcm
     687    # we use positions in the Zumbroich basis with find_array
     688    cdef Rational old_val, new_val1, new_val2
     689    new_val1 = <Rational> PY_NEW(Rational)
     690    new_val2 = <Rational> PY_NEW(Rational)
     691
     692    cdef int k
     693
     694    for X in D1:
     695        k = find_array(X[1],L1_array,L1_size)
     696        old_val = D1[X]
     697        mpq_mul(new_val1.value,old_val.value,denom_rat1.value)
     698        D1_pointer[k] = new_val1
     699    for X in D2:
     700        k = find_array(X[1],L2_array,L2_size)
     701        old_val = D2[X]
     702        mpq_mul(new_val2.value,old_val.value,denom_rat2.value)
     703        D2_pointer[k] = new_val2
     704
     705    # finally, everything is set up such that we can do the actual multiplication
     706    cdef unsigned int size
     707    cdef int fac
     708    cdef int fac1, fac2
     709
     710    # these pieces are used to cache ZumbroichDecomposition_list properly,
     711    # in the c array, the k's are stored, and in the python list the actual lists
     712    cdef int *zumbroich_decomposition_chache_index = <int *>sage_malloc(n * sizeof(int))
     713    cdef list zumbroich_decomposition_chache_values = []
     714    cdef int zumbroich_decomposition_chache_size = 0
     715    cdef int index
     716
     717    cdef list L
     718
     719    cdef Py_ssize_t counter1, couter2
     720    n1 = n / n1
     721    n2 = n / n2
     722    for counter1 from 0 <= counter1 < L1_size:
     723        fac1 = D1_pointer[counter1]
     724        if fac1 != 0:
     725            for counter2 from 0 <= counter2 < L2_size:
     726                fac2 = D2_pointer[counter2]
     727                if fac2 != 0:
     728                    k = ((n1*L1[counter1])+(n2*L2[counter2])) % n
     729                    if k < 0:
     730                        k += n
     731                    # this is the actual caching part
     732                    index = find_array(k,zumbroich_decomposition_chache_index,zumbroich_decomposition_chache_size)
     733                    if index < zumbroich_decomposition_chache_size:
     734                        L = zumbroich_decomposition_chache_values[index]
     735                    else:
     736                        L = ZumbroichDecomposition_list(n,k)
     737                        zumbroich_decomposition_chache_index[zumbroich_decomposition_chache_size] = k
     738                        zumbroich_decomposition_chache_values.append(L)
     739                        zumbroich_decomposition_chache_size += 1
     740                    fac = fac1 * fac2
     741                    size = len(L)
     742                    k = L[size-1]
     743                    if k%2 == 1:
     744                        fac = -fac
     745                    # using a different method to add the entries in L to the c array linear_combination_pointer
     746                    add_to_basis_linear_combination(L,fac,size-1)
     747
     748    # in the end, the data is stored in a dictionary
     749    cdef dict D = {}
     750    cdef Rational new_value
     751    for key from 0 <= key < Lnew_size:
     752        if linear_combination_pointer[key] != 0:
     753            old_val = as_rat(linear_combination_pointer[key])
     754            new_val = <Rational> PY_NEW(Rational)
     755            mpq_div(new_val.value,old_val.value,denom_rat1.value)
     756            mpq_div(new_val.value,new_val.value,denom_rat2.value)
     757            D[(n,Lnew[key])] = new_val
     758
     759    sage_free(linear_combination_pointer)
     760    sage_free(D1_pointer)
     761    sage_free(D2_pointer)
     762    return D
  • setup.py

    diff --git a/setup.py b/setup.py
    a b code = setup(name = 'sage', 
    986986                     'sage.rings.polynomial',
    987987                     'sage.rings.polynomial.padics',
    988988                     'sage.rings.semirings',
    989                      
     989                     'sage.rings.universal_cyclotomic_field',
     990
    990991                     'sage.tests',
    991992                     'sage.tests.french_book',
    992993