Ticket #7234: trac_7234.patch

File trac_7234.patch, 12.2 KB (added by fwclarke, 10 years ago)
  • new file sage/rings/finite_field_unit_group.py

    # HG changeset patch
    # User Francis Clarke <F.Clarke@Swansea.ac.uk>
    # Date 1255705828 -3600
    # Node ID 300b8d953695266cc91ffc965375470ef67fc61e
    # Parent  cd5774a1a327ae80f7d24529856c3b4d2b9ef91f
    Unit groups for finite fields
    
    diff -r cd5774a1a327 -r 300b8d953695 sage/rings/finite_field_unit_group.py
    - +  
     1r"""
     2Unit Groups of Finite Fields
     3
     4EXAMPLES::
     5
     6    sage: F.<a> = GF(81)
     7    sage: U = F.unit_group(); U
     8    Unit group with structure C80 of Finite Field in a of size 3^4
     9
     10The generator is a primitive root of unity in the field::
     11
     12    sage: U.gen()
     13    a
     14    sage: U.gen().multiplicative_order()
     15    80
     16
     17Units in the field can be converted into elements of the unit group represented
     18as elements of an abstract multiplicative group::
     19
     20    sage: U(1)
     21    1
     22    sage: U(-1)
     23    u^40
     24    sage: U(2 + a + a^3)
     25    u^11
     26
     27Subgroups of the unit group, consisting of the group of n-th roots of unity can also be constructed::
     28
     29    sage: U5 = F.unit_group(5)
     30    sage: list(U5)
     31    [1, 2*a^2 + a + 2, 2*a^3 + a + 2, 2*a^2 + 2*a + 1, a^3 + 2*a^2 + 2*a]
     32
     33The log function gives the exponent of a unit as a power of the chosen generator or of a given base::
     34
     35    sage: U.log(1 + a)
     36    28
     37    sage: U.gen()^28
     38    a + 1
     39    sage: U.log(a^2, a + a^3)
     40    38
     41    sage: (a + a^3)^38
     42    a^2
     43
     44AUTHOR:
     45
     46- Francis Clarke
     47"""
     48#*****************************************************************************
     49#       Copyright (C) 2009 William Stein, Francis Clarke
     50#
     51#  Distributed under the terms of the GNU General Public License (GPL)
     52#
     53#    This code is distributed in the hope that it will be useful,
     54#    but WITHOUT ANY WARRANTY; without even the implied warranty of
     55#    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
     56#    General Public License for more details.
     57#
     58#  The full text of the GPL is available at:
     59#
     60#                  http://www.gnu.org/licenses/
     61#*****************************************************************************
     62
     63from sage.groups.abelian_gps.abelian_group import AbelianGroup_class
     64from sage.groups.abelian_gps.abelian_group_element import AbelianGroupElement
     65from sage.rings.arith import gcd, power_mod
     66from sage.structure.sequence import Sequence
     67# from sage.structure.element import MultiplicativeGroupElement
     68
     69class FiniteFieldUnitGroup(AbelianGroup_class):
     70    """
     71    The unit group of a finite field.  Based on the implementation
     72    of the unit groups of number fields by John Cremona.
     73
     74    Author: Francis Clarke
     75    """
     76
     77    def __init__(self, field, n=None):
     78        """
     79        Create the unit group of a finite field,
     80        or the subgroup of n-th roots of unity.
     81
     82        INPUT:
     83
     84        - ``field`` - a finite field
     85
     86        - ``n`` - a positive integer dividing the order of the field,
     87           or (default) None
     88
     89
     90        EXAMPLES::
     91
     92            sage: GF(5).unit_group()
     93            Unit group with structure C4 of Finite Field of size 5
     94            sage: GF(25, 'a').unit_group(8)
     95            Group (with structure C8) of 8th roots of unity in Finite Field in a of size 5^2
     96        """
     97        # compute a generator
     98        z = field.zeta(n)
     99        if n is None:
     100            n = field.order() - 1
     101
     102        # Store the field and the generator:
     103        self.__field = field
     104        self.__gens = Sequence([z], immutable=True, universe=self, check=False)
     105     
     106        # Construct the abtract group:       
     107        AbelianGroup_class.__init__(self, 1, [n], 'u')
     108
     109
     110    def __call__(self, u):
     111        """
     112        Returns the abstract group element corresponding to the unit u.
     113
     114        INPUT:
     115
     116        - ``u`` -- Any object from which an element of the unit group's
     117          field `K` may be constructed; an error is raised if
     118          an element of `K` cannot be constructed from `u`, or if the
     119          element constructed is not a  unit.
     120
     121        EXAMPLES::
     122
     123            sage: F25.<a> = GF(25)
     124            sage: mu8 = F25.unit_group(8)
     125            sage: mu8(1 + 3*a)
     126            u^3
     127        """
     128        K = self.__field
     129        q = K.order()
     130        n = self.order()
     131
     132        try:
     133            u = K(u)
     134        except TypeError:
     135            raise ValueError, "%s is not an element of %s" % (u, K)
     136        if u == 0:
     137            raise ValueError, "%s is not a unit" % u
     138        if n != q - 1 and u**n != 1:
     139            raise ValueError, "%s is not a %s root of unity" % (u, n.ordinal_str())
     140        m = u.log(self.gen()) # Do a discrete logarithm.
     141        return AbelianGroupElement(self, [m])
     142
     143    def __contains__(self, u):
     144        """
     145        EXAMPLES::
     146
     147            sage: 3 in GF(49, 'z').unit_group()
     148            True
     149            sage: 8 in GF(73).unit_group(12)
     150            True
     151            sage: 14 in GF(7).unit_group()
     152            False
     153        """
     154        K = self.__field
     155        q = K.order()
     156        n = self.order()
     157
     158        try:
     159            u = K(u)
     160        except TypeError:
     161            return False
     162        if u == 0:
     163            return False
     164        return n == q - 1 or u**n == 1
     165
     166    def _coerce_impl(self, x):
     167        """
     168        Canonical coercion of ``x`` into this unit group.
     169        """
     170        return self(x)
     171
     172    def gens(self):
     173        """
     174        Return a generator for the unit group, as a list of length one.
     175
     176        EXAMPLES::
     177
     178            sage: GF(41).unit_group().gens()
     179            [6]
     180            sage: GF(49, 'a').unit_group(4).gens()
     181            [6*a + 4]
     182        """
     183        return self.__gens
     184
     185    def ngens(self):
     186        """
     187        Return the number of generators of the unit group.
     188
     189        EXAMPLES::
     190
     191            sage: GF(11).unit_group().ngens()
     192            1
     193        """
     194        return 1
     195
     196    def gen(self, i=0):
     197        """
     198        Return the ``i``-th generator for this unit group,
     199        where ``i`` had better be 0.
     200
     201        EXAMPLES::
     202
     203            sage: GF(41).unit_group().gen()
     204            6
     205        """
     206        if i < 0 or i >= len(self.__gens):
     207            raise IndexError
     208        return self.__gens[i]
     209
     210    def _repr_(self):
     211        """
     212        Return the string representation of this unit group.
     213
     214        EXAMPLES::
     215
     216            sage: GF(31).unit_group()
     217            Unit group with structure C30 of Finite Field of size 31
     218            sage: GF(31).unit_group(10)
     219            Group (with structure C10) of 10th roots of unity in Finite Field of size 31
     220        """
     221        K = self.__field
     222        q = K.order()
     223        n = self.order()
     224        if n == q - 1:
     225            return 'Unit group with structure %s of %s' % (
     226                self._group_notation(self.invariants()), K)
     227        elif n == 1:
     228            return 'Trivial multiplicative group {1} in %s' % K
     229        else:
     230            if n == 2:
     231                nth = 'square'
     232            elif n == 3:
     233                nth = 'cube'
     234            else:
     235                nth = n.ordinal_str()
     236            return 'Group (with structure %s) of %s roots of unity in %s' % (
     237                self._group_notation(self.invariants()), nth, K)
     238       
     239    def field(self):
     240        """
     241        Return the finite field of which this is the group of units.
     242       
     243        EXAMPLES::
     244
     245            sage: GF(13).unit_group().field()
     246            Finite Field of size 13
     247        """
     248        return self.__field
     249
     250    def list(self):
     251        """
     252        List all the element of the unit group in the order given by taking powers
     253        of the generator.
     254       
     255        EXAMPLES::
     256
     257            sage: GF(13).unit_group().list()
     258            [1, 2, 4, 8, 3, 6, 12, 11, 9, 5, 10, 7]
     259            sage: GF(23).unit_group(11).list()
     260            [1, 2, 4, 8, 16, 9, 18, 13, 3, 6, 12]
     261        """
     262        return [self.gen()**i for i in range(self.order())]
     263
     264
     265    def __iter__(self):
     266        """
     267        Return an iterator for the set of elements of the unit group
     268       
     269        EXAMPLES::
     270
     271            sage: [x for x in GF(13).unit_group()]
     272            [1, 2, 4, 8, 3, 6, 12, 11, 9, 5, 10, 7]
     273            sage: [x^6 for x in GF(25, 'a').unit_group()]
     274            [1, 2, 4, 3, 1, 2, 4, 3, 1, 2, 4, 3, 1, 2, 4, 3, 1, 2, 4, 3, 1, 2, 4, 3]
     275        """
     276        for i in xrange(self.order()):
     277            yield self.gen()**i
     278
     279    def log(self, u, base=None):
     280        """
     281        Return the exponents of the unit ``u`` with respect to the
     282        group generator, or to the given base.
     283
     284        INPUT:
     285
     286        - ``u`` -- Any object from which an element of the unit group's
     287          field `K` may be constructed; an error is raised if an element of `K`
     288          cannot be constructed from u, or if the element constructed is not a
     289          unit.
     290
     291        - ``base`` -- a generator of the group, or any object from which such
     292          an element may be constructed.  For the default value of None the
     293          group's generator is used.
     294
     295        OUTPUT:
     296
     297        the exponent of ``u`` with respect to the unit group's generator
     298        or the given base.
     299       
     300        EXAMPLES::
     301
     302            sage: U = GF(23).unit_group()
     303            sage: U.gen()
     304            5
     305            sage: U.log(7)
     306            19
     307            sage: power_mod(5, 19, 23) == 7
     308            True
     309            sage: F49.<g> = GF(49)
     310            sage: mu16 = F49.unit_group(16)
     311            sage: mu16.log(g + 3, 4*g + 3)
     312            12
     313            sage: (4*g + 3)^12
     314            g + 3
     315        """
     316        if base is None:
     317            return self(u).list()[0]
     318        else:
     319            n = self.order()
     320            k = self.log(base)
     321            if gcd(n, k) != 1:
     322                raise ValueError, "%s is not a generator" % base
     323            return (self.log(u)*power_mod(k, -1, n)).mod(n)
  • sage/rings/ring.pyx

    diff -r cd5774a1a327 -r 300b8d953695 sage/rings/ring.pyx
    a b  
    21232123            n = sage.rings.integer.Integer(n)
    21242124            m = z.multiplicative_order()
    21252125            if m % n != 0:
    2126                 raise ValueError, "No %sth root of unity in self"%n
     2126                raise ValueError, "There are no %s roots of unity in self."%n.ordinal_str()
    21272127            return z**(m.__floordiv__(n))
    21282128
    21292129    def multiplicative_generator(self):
     
    21622162                    self.__multiplicative_generator = a
    21632163                    return a
    21642164
     2165    def unit_group(self, n=None):
     2166        """
     2167        Returns the multiplicative group of units of this finite field,
     2168        if n is None, and otherwise the group of n-th roots of unity.
     2169
     2170        EXAMPLES::
     2171
     2172            sage: GF(5).unit_group()
     2173            Unit group with structure C4 of Finite Field of size 5
     2174            sage: GF(17).unit_group(4)
     2175            Group (with structure C4) of 4th roots of unity in Finite Field of size 17
     2176
     2177        If n does not divide q - 1, where q is the order of the field,
     2178        then the group of gcd(q - 1, n)-th roots is returned::
     2179
     2180            sage: GF(17).unit_group(24)
     2181            Group (with structure C8) of 8th roots of unity in Finite Field of size 17
     2182
     2183        The function works with all the various types of finite field::
     2184
     2185            sage: [(F.unit_group(), type(F)) for F in [GF(q, 'g') for q in [16, 17, 2^16, 23^4]]]
     2186            [(Unit group with structure C15 of Finite Field in g of size 2^4,
     2187              <type 'sage.rings.finite_field_givaro.FiniteField_givaro'>),
     2188             (Unit group with structure C16 of Finite Field of size 17,
     2189              <class 'sage.rings.finite_field_prime_modn.FiniteField_prime_modn'>),
     2190             (Unit group with structure C65535 of Finite Field in g of size 2^16,
     2191              <type 'sage.rings.finite_field_ntl_gf2e.FiniteField_ntl_gf2e'>),
     2192             (Unit group with structure C279840 of Finite Field in g of size 23^4,
     2193              <class 'sage.rings.finite_field_ext_pari.FiniteField_ext_pari'>)]
     2194        """
     2195        if n is not None:
     2196            n = (self.order() - 1).gcd(n)
     2197        from sage.rings.finite_field_unit_group import FiniteFieldUnitGroup
     2198        return FiniteFieldUnitGroup(self, n)
     2199
    21652200    def ngens(self):
    21662201        """
    21672202        The number of generators of the finite field.  Always 1.