Ticket #3397: 3397-2008-07-30-main.patch

File 3397-2008-07-30-main.patch, 186.1 KB (added by jhpalmieri, 11 years ago)

new version of Steenrod algebra package, incorporating changes suggested by was

  • sage/algebras/all.py

    # HG changeset patch
    # User J. H. Palmieri <palmieri@math.washington.edu>
    # Date 1217464162 25200
    # Node ID 9fbc77f226c83c4eadb469a2c209e4bbf1008c69
    # Parent  c25e04ebfb67678948024df2a820350c4b503acf
    Steenrod algebra
    
    diff -r c25e04ebfb67 -r 9fbc77f226c8 sage/algebras/all.py
    a b from quaternion_algebra import (Quaterni 
    3131     hilbert_symbol, fundamental_discriminant)
    3232from quaternion_order import QuaternionOrderWithBasis, QuaternionDefiningOrder
    3333from quaternion_order_ideal import QuaternionOrderLeftIdeal, QuaternionOrderRightIdeal, QuaternionOrderTwoSidedIdeal
     34from steenrod_algebra import SteenrodAlgebra
     35from steenrod_algebra_element import Sq
     36from steenrod_algebra_bases import steenrod_algebra_basis
    3437
    3538   
    3639def is_R_algebra(Q, R):
  • new file sage/algebras/steenrod_algebra.py

    diff -r c25e04ebfb67 -r 9fbc77f226c8 sage/algebras/steenrod_algebra.py
    - +  
     1r"""
     2The Steenrod algebra
     3
     4AUTHORS:
     5    - John H. Palmieri (2008-07-30: version 0.9)
     6
     7This package defines the mod $p$ Steenrod algebra $\mathcal{A}_p$,
     8some of its properties, and ways to define elements of it.
     9
     10From a topological point of view, $\mathcal{A}_p$ is the algebra of
     11stable cohomology operations on mod $p$ cohomology; thus for any
     12topological space $X$, its mod $p$ cohomology algebra
     13$H^*(X,\mathbf{F}_p)$ is a module over $\mathcal{A}_p$.
     14
     15From an algebraic point of view, $\mathcal{A}_p$ is an
     16$\mathbf{F}_p$-algebra; when $p=2$, it is generated by elements
     17$\text{Sq}^i$ for $i\geq 0$ (the \emph{Steenrod squares}), and when
     18$p$ is odd, it is generated by elements $\mathcal{P}^i$ for $i \geq 0$
     19(the \emph{Steenrod reduced $p$th powers}) along with an element
     20$\beta$ (the \emph{mod $p$ Bockstein}).  The Steenrod algebra is
     21graded: $\text{Sq}^i$ is in degree $i$ for each $i$, $\beta$ is in
     22degree 1, and $\mathcal{P}^i$ is in degree $2(p-1)i$.
     23
     24The unit element is $\text{Sq}^0$ when $p=2$ and $\mathcal{P}^0$ when
     25$p$ is odd.  The generating elements also satisfy the \emph{Adem
     26relations}.  At the prime 2, these have the form
     27\[
     28\text{Sq}^a \text{Sq}^b
     29  = \sum_{c=0}^{[a/2]} \binom{b-c-1}{a-2c} \text{Sq}^{a+b-c} \text{Sq}^c.
     30\]
     31At odd primes, they are a bit more complicated.  See Steenrod and
     32Epstein [SE] for full details.  These relations lead to the existence
     33of the \emph{Serre-Cartan} basis for $\mathcal{A}_p$.
     34
     35The mod $p$ Steenrod algebra has the structure of a Hopf algebra, and
     36Milnor [Mil] has a beautiful description of the dual, leading to a
     37construction of the \emph{Milnor basis} for $\mathcal{A}_p$.  In this
     38package, elements in the Steenrod algebra are represented, by default,
     39using the Milnor basis.
     40
     41See the documentation for \code{SteenrodAlgebra} for many more details
     42and examples.
     43   
     44REFERENCES:
     45
     46    [Mil] J. W. Milnor, "The Steenrod algebra and its dual," Ann. of Math.
     47          (2) 67 (1958), 150--171.
     48
     49    [SE]  N. E. Steenrod and D. B. A. Epstein, Cohomology operations, Ann.
     50          of Math. Stud. 50 (Princeton University Press, 1962).
     51"""
     52
     53#*****************************************************************************
     54#       Copyright (C) 2008 John H. Palmieri <palmieri@math.washington.edu>
     55#  Distributed under the terms of the GNU General Public License (GPL)
     56#*****************************************************************************
     57
     58from sage.rings.ring import Algebra
     59from sage.algebras.algebra_element import AlgebraElement
     60from sage.structure.parent_gens import ParentWithGens
     61from sage.structure.element import RingElement
     62from sage.rings.all import GF
     63from sage.misc.functional import parent
     64from sage.rings.integer import Integer
     65
     66class SteenrodAlgebra_generic(Algebra):
     67    r"""
     68    The mod $p$ Steenrod algebra.
     69
     70    Users should not call this, but use the function 'SteenrodAlgebra'
     71    instead.  See that function for extensive documentation.
     72
     73    EXAMPLES:
     74        sage: sage.algebras.steenrod_algebra.SteenrodAlgebra_generic()
     75        mod 2 Steenrod algebra
     76        sage: sage.algebras.steenrod_algebra.SteenrodAlgebra_generic(5)
     77        mod 5 Steenrod algebra
     78        sage: sage.algebras.steenrod_algebra.SteenrodAlgebra_generic(5, 'adem')
     79        mod 5 Steenrod algebra
     80    """
     81
     82    def __init__(self, p=2, basis='milnor'):
     83        """
     84        INPUT:
     85            p -- positive prime integer (optional, default = 2)
     86            basis -- string (optional, default = 'milnor')
     87       
     88        OUTPUT:
     89            mod p Steenrod algebra with basis
     90
     91        EXAMPLES:
     92            sage: SteenrodAlgebra()   # 2 is the default prime
     93            mod 2 Steenrod algebra
     94            sage: SteenrodAlgebra(5)
     95            mod 5 Steenrod algebra
     96            sage: SteenrodAlgebra(2, 'milnor').Sq(0,1)
     97            Sq(0,1)
     98            sage: SteenrodAlgebra(2, 'adem').Sq(0,1)
     99            Sq^{2} Sq^{1} + Sq^{3}
     100        """
     101        from sage.rings.arith import is_prime
     102        if is_prime(p):
     103            self.prime = p
     104            ParentWithGens.__init__(self, GF(p))
     105            self._basis_name = basis
     106        else:
     107            raise ValueError, "%s is not prime." % p
     108
     109
     110    def _repr_(self):
     111        """
     112        Printed representation of the Steenrod algebra.
     113
     114        EXAMPLES:
     115            sage: SteenrodAlgebra(3)
     116            mod 3 Steenrod algebra
     117            sage: B = SteenrodAlgebra(2003)
     118            sage: B
     119            mod 2003 Steenrod algebra
     120            sage: B._repr_()
     121            'mod 2003 Steenrod algebra'
     122        """
     123        return "mod %d Steenrod algebra" % self.prime
     124   
     125
     126    def _latex_(self):
     127        """
     128        LaTeX representation of the Steenrod algebra.
     129       
     130        EXAMPLES:
     131            sage: C = SteenrodAlgebra(3)
     132            sage: C
     133            mod 3 Steenrod algebra
     134            sage: C._latex_()
     135            '\\mathcal{A}_{3}'
     136        """
     137        return "\\mathcal{A}_{%s}" % self.prime
     138   
     139
     140    def ngens(self):
     141        """
     142        Number of generators of the Steenrod algebra.
     143
     144        This returns infinity, since the Steenrod algebra is infinitely
     145        generated.
     146
     147        EXAMPLES:
     148            sage: A = SteenrodAlgebra(3)
     149            sage: A.ngens()
     150            +Infinity
     151        """
     152        from sage.rings.infinity import Infinity
     153        return Infinity
     154
     155
     156    def gens(self):
     157        """
     158        List of generators for the Steenrod algebra.  Not implemented
     159        (mainly because the list of generators is infinite).
     160
     161        EXAMPLES:
     162            sage: A3 = SteenrodAlgebra(3, 'adem')
     163            sage: A3.gens()
     164            Traceback (most recent call last):
     165            ...
     166            NotImplementedError: 'gens' is not implemented for the Steenrod algebra.
     167        """
     168        raise NotImplementedError, "'gens' is not implemented " + \
     169            "for the Steenrod algebra."
     170
     171
     172    def gen(self, i=0):
     173        """
     174        The ith generator of the Steenrod algebra.
     175
     176        INPUT:
     177            i -- non-negative integer
     178
     179        OUTPUT:
     180            the ith generator of the Steenrod algebra
     181
     182       
     183        The $i$th generator is $Sq(2^i)$ at the prime 2; when $p$ is
     184        odd, the 0th generator is beta = Q(0), and for $i>0$, the
     185        $i$th generator is $P(p^{i-1})$.
     186
     187        EXAMPLES:
     188            sage: A = SteenrodAlgebra(2)
     189            sage: A.gen(4)
     190            Sq(16)
     191            sage: A.gen(200)
     192            Sq(1606938044258990275541962092341162602522202993782792835301376)
     193            sage: B = SteenrodAlgebra(5)
     194            sage: B.gen(0)
     195            Q_0
     196            sage: B.gen(2)
     197            P(5)
     198        """
     199        if not isinstance(i, (Integer, int)) and i >= 0:
     200            raise ValueError, "%s is not a non-negative integer" % i
     201        if self.prime == 2:
     202            return self.Sq(self.prime**i)
     203        else:
     204            if i == 0:
     205                return self.Q(0)
     206            else:
     207                return self.P(self.prime**(i-1))
     208
     209    def __cmp__(self,right):
     210        """
     211        Two Steenrod algebras are equal iff their associated primes are equal.
     212
     213        EXAMPLES:
     214            sage: A = SteenrodAlgebra(2)
     215            sage: B = SteenrodAlgebra(2, 'adem')
     216            sage: cmp(A, B)
     217            0
     218            sage: A.__cmp__(B)
     219            0
     220            sage: A is B
     221            False
     222            sage: C = SteenrodAlgebra(17)
     223            sage: cmp(A,C)
     224            -1
     225        """
     226        if type(self) == type(right) and self.prime == right.prime:
     227            return 0
     228        else:
     229            return -1
     230
     231
     232    def __call__(self, x):
     233        """
     234        Try to turn x into an element of self.
     235
     236        INPUT:
     237            x -- a SteenrodAlgebra element or an element of F_p
     238
     239        OUTPUT:
     240            x as a member of self
     241
     242        Note that this provides a way of converting elements from one
     243        basis to another.
     244
     245        EXAMPLES:
     246            sage: x = Sq(2,1)
     247            sage: x
     248            Sq(2,1)
     249            sage: B = SteenrodAlgebra(2, 'adem')
     250            sage: B(x)
     251            Sq^{4} Sq^{1} + Sq^{5}
     252        """
     253        from sage.algebras.steenrod_algebra_element import SteenrodAlgebraElement
     254        if isinstance(x, SteenrodAlgebraElement) and x.parent() == self:
     255            dict = x._raw
     256            a = SteenrodAlgebraElement(dict['milnor'],
     257                                       p=x._prime,
     258                                       basis=self._basis_name)
     259            a._raw = dict
     260            return a
     261        else:
     262            return SteenrodAlgebraElement(x, p=self.prime,
     263                                          basis=self._basis_name)
     264
     265
     266    def _coerce_impl(self, x):
     267        """
     268        Return the coercion of x into this Steenrod algebra.
     269
     270        INPUT:
     271            x -- a SteenrodAlgebraElement or an element of F_p
     272
     273        OUTPUT:
     274            coercion of x into the Steenrod algebra
     275       
     276        EXAMPLES:
     277            sage: A = SteenrodAlgebra(); A
     278            mod 2 Steenrod algebra
     279            sage: A(1)     # convert 1 to an element of A
     280            Sq(0)
     281            sage: A(Sq(3))
     282            Sq(3)
     283       
     284        The algebras that coerce into the mod p Steenrod algebra are:
     285       
     286           * the mod p Steenrod algebra
     287           
     288           * its base field GF(p)
     289        """
     290        return self._coerce_try(x, [self.base_ring()])
     291       
     292
     293    def __contains__(self, x):
     294        """
     295        Instances of the class SteenrodAlgebraElement with the same
     296        prime are contained in the Steenrod algebra.
     297
     298        EXAMPLES:
     299            sage: A = SteenrodAlgebra()
     300            sage: x = Sq(2) * Sq(1); x
     301            Sq(0,1) + Sq(3)
     302            sage: x in A
     303            True
     304            sage: x in SteenrodAlgebra(5)
     305            False
     306        """
     307        from sage.algebras.steenrod_algebra_element import SteenrodAlgebraElement
     308        return (isinstance(x, SteenrodAlgebraElement) and x.parent() == self) \
     309            or (GF(self.prime).__contains__(x))
     310
     311
     312    def is_commutative(self):
     313        """
     314        The Steenrod algebra is not commutative.
     315       
     316        EXAMPLES:
     317            sage: A = SteenrodAlgebra(3)
     318            sage: A.is_commutative()
     319            False
     320        """
     321        return False
     322
     323
     324    def is_finite(self):
     325        """
     326        The Steenrod algebra is not finite.
     327       
     328        EXAMPLES:
     329            sage: A = SteenrodAlgebra(3)
     330            sage: A.is_finite()
     331            False
     332        """
     333        return False
     334
     335
     336    def order(self):
     337        """
     338        The Steenrod algebra has infinite order.
     339       
     340        EXAMPLES:
     341            sage: A = SteenrodAlgebra(3)
     342            sage: A.order()
     343            +Infinity
     344        """
     345        from sage.rings.infinity import Infinity
     346        return Infinity
     347
     348
     349    def is_division_algebra(self):
     350        """
     351        The Steenrod algebra is not a division algebra.
     352       
     353        EXAMPLES:
     354            sage: A = SteenrodAlgebra(3)
     355            sage: A.is_division_algebra()
     356            False
     357        """
     358        return False
     359   
     360
     361    def is_field(self):
     362        """
     363        The Steenrod algebra is not a field.
     364       
     365        EXAMPLES:
     366            sage: A = SteenrodAlgebra(3)
     367            sage: A.is_field()
     368            False
     369        """
     370        return False
     371   
     372
     373    def is_integral_domain(self):
     374        """
     375        The Steenrod algebra is not an integral domain.
     376       
     377        EXAMPLES:
     378            sage: A = SteenrodAlgebra(3)
     379            sage: A.is_integral_domain()
     380            False
     381        """
     382        return False
     383   
     384
     385    def is_noetherian(self):
     386        """
     387        The Steenrod algebra is not noetherian.
     388       
     389        EXAMPLES:
     390            sage: A = SteenrodAlgebra(3)
     391            sage: A.is_noetherian()
     392            False
     393        """
     394        return False
     395       
     396
     397    def category(self):
     398        """
     399        The Steenrod algebra is an algebra over $F_p$.
     400       
     401        EXAMPLES:
     402            sage: A = SteenrodAlgebra(3)
     403            sage: A.category()
     404            Category of algebras over Finite Field of size 3
     405        """
     406        from sage.categories.category_types import Algebras
     407        return Algebras(GF(self.prime))
     408
     409
     410    def basis(self, n):
     411        """
     412        Basis for self in dimension n
     413
     414        INPUT:
     415            n -- non-negative integer
     416
     417        OUTPUT:
     418            basis -- tuple of Steenrod algebra elements
     419
     420        EXAMPLES:
     421            sage: A3 = SteenrodAlgebra(3)
     422            sage: A3.basis(13)
     423            (Q_1 P(2), Q_0 P(3))
     424            sage: SteenrodAlgebra(2, 'adem').basis(12)
     425            (Sq^{12},
     426            Sq^{11} Sq^{1},
     427            Sq^{9} Sq^{2} Sq^{1},
     428            Sq^{8} Sq^{3} Sq^{1},
     429            Sq^{10} Sq^{2},
     430            Sq^{9} Sq^{3},
     431            Sq^{8} Sq^{4})
     432        """
     433        from steenrod_algebra_bases import steenrod_algebra_basis
     434        return steenrod_algebra_basis(n, basis=self._basis_name, p=self.prime)
     435
     436
     437    def P(self, *nums):
     438        r"""
     439        The element $P(a, b, c, ...)$
     440
     441        INPUT:
     442            a, b, c, ... -- non-negative integers
     443           
     444        OUTPUT:
     445            element of the Steenrod algebra given by the single basis
     446            element P(a, b, c, ...)
     447
     448        Note that at the prime 2, this is the same element as
     449        $\text{Sq}(a, b, c, ...)$.
     450
     451        EXAMPLES:
     452            sage: A = SteenrodAlgebra(2)
     453            sage: A.P(5)
     454            Sq(5)
     455            sage: B = SteenrodAlgebra(3)
     456            sage: B.P(5,1,1)
     457            P(5,1,1)
     458        """
     459        from sage.algebras.steenrod_algebra_element import SteenrodAlgebraElement
     460        if self.prime == 2:
     461            dict = {nums: 1}
     462        else:
     463            dict = {((), nums): 1}
     464        return SteenrodAlgebraElement(dict, p=self.prime,
     465                                      basis=self._basis_name)
     466
     467
     468    def Q_exp(self, *nums):
     469        r"""
     470        The element $Q_0^{e_0} Q_1^{e_1} ...$, given by specifying the exponents.
     471       
     472        INPUT:
     473            e0, e1, ... -- 0s and 1s
     474
     475        OUTPUT:
     476            The element $Q_0^{e_0} Q_1^{e_1} ...$
     477       
     478        Note that at the prime 2, $Q_n$ is the element
     479        $\text{Sq}(0,0,...,1)$, where the 1 is in the $n+1$st
     480        position.
     481       
     482        Compare this to the method 'Q', which defines a similar
     483        element, but by specifying the tuple of subscripts of terms
     484        with exponent 1.
     485
     486        EXAMPLES:
     487            sage: A2 = SteenrodAlgebra(2)
     488            sage: A5 = SteenrodAlgebra(5)
     489            sage: A2.Q_exp(0,0,1,1,0)
     490            Sq(0,0,1,1)
     491            sage: A5.Q_exp(0,0,1,1,0)
     492            Q_2 Q_3
     493            sage: A5.Q(2,3)
     494            Q_2 Q_3
     495            sage: A5.Q_exp(0,0,1,1,0) == A5.Q(2,3)
     496            True
     497        """
     498        from sage.algebras.steenrod_algebra_element import SteenrodAlgebraElement
     499        if not set(nums).issubset(set((0,1))):
     500            raise ValueError, "The tuple %s should consist " % (nums,) + \
     501                "only of 0's and 1's"
     502        else:
     503            if self.prime == 2:
     504                answer = self.Sq(0)
     505                index = 0
     506                for n in nums:
     507                    if n == 1:
     508                        answer = answer * self.pst(0,index+1)
     509                    index += 1
     510                return answer
     511            else:
     512                mono = ()
     513                index = 0
     514                for e in nums:
     515                    if e == 1:
     516                        mono = mono + (index,)
     517                    index += 1
     518                dict = {((mono), ()): 1}
     519                return SteenrodAlgebraElement(dict, p=self.prime,
     520                                              basis=self._basis_name)
     521
     522           
     523    def Q(self, *nums):
     524        r"""
     525        The element $Q_{n0} Q_{n1} ...$, given by specifying the subscripts.
     526       
     527        INPUT:
     528            n0, n1, ... -- non-negative integers
     529
     530        OUTPUT:
     531            The element $Q_{n0} Q_{n1} ...$
     532
     533        Note that at the prime 2, $Q_n$ is the element
     534        $\text{Sq}(0,0,...,1)$, where the 1 is in the $n+1$st
     535        position.
     536       
     537        Compare this to the method 'Q_exp', which defines a similar element,
     538        but by specifying the tuple of exponents.
     539
     540        EXAMPLES:
     541            sage: A2 = SteenrodAlgebra(2)
     542            sage: A5 = SteenrodAlgebra(5)
     543            sage: A2.Q(2,3)
     544            Sq(0,0,1,1)
     545            sage: A5.Q(1,4)
     546            Q_1 Q_4
     547            sage: A5.Q(1,4) == A5.Q_exp(0,1,0,0,1)
     548            True
     549        """
     550        from sage.algebras.steenrod_algebra_element import SteenrodAlgebraElement
     551        if len(nums) != len(set(nums)):
     552            return self(0)
     553        else:
     554            if self.prime == 2:
     555                if len(nums) == 0:
     556                    return Sq(0)
     557                else:
     558                    list = (1+max(nums)) * [0]
     559                    for i in nums:
     560                        list[i] = 1
     561                    return SteenrodAlgebraElement({tuple(list): 1}, p=2,
     562                                                  basis=self._basis_name)
     563            else:
     564                return SteenrodAlgebraElement({(nums, ()): 1}, p=self.prime,
     565                                              basis=self._basis_name)
     566
     567
     568    def pst(self,s,t):
     569        r"""
     570        The Margolis element $P^s_t$.
     571       
     572        INPUT:
     573            s -- non-negative integer
     574            t -- positive integer
     575            p -- positive prime number
     576       
     577        OUTPUT:
     578            element of the Steenrod algebra
     579
     580        This returns the Margolis element $P^s_t$ of the mod $p$
     581        Steenrod algebra: the element equal to
     582        $P(0,0,...,0,p^s)$, where the $p^s$ is in position
     583        $t$.
     584
     585        EXAMPLES:
     586            sage: A2 = SteenrodAlgebra(2)
     587            sage: A2.pst(3,5)
     588            Sq(0,0,0,0,8)
     589            sage: A2.pst(1,2) == Sq(4)*Sq(2) + Sq(2)*Sq(4)
     590            True
     591            sage: SteenrodAlgebra(5).pst(3,5)
     592            P(0,0,0,0,125)
     593        """
     594        from sage.algebras.steenrod_algebra_element import SteenrodAlgebraElement
     595        if not isinstance(s, (Integer, int)) and s >= 0:
     596            raise ValueError, "%s is not a non-negative integer" % s
     597        if not isinstance(t, (Integer, int)) and t > 0:
     598            raise ValueError, "%s is not a positive integer" % t
     599        nums = (0,)*(t-1) + (self.prime**s,)
     600        if self.prime == 2:
     601            return SteenrodAlgebraElement({nums: 1}, p=2, basis=self._basis_name)
     602        else:
     603            return SteenrodAlgebraElement({((), nums): 1}, p=self.prime,
     604                                          basis=self._basis_name)
     605
     606
     607class SteenrodAlgebra_mod_two(SteenrodAlgebra_generic):
     608    """
     609    The mod 2 Steenrod algebra.
     610
     611    Users should not call this, but use the function 'SteenrodAlgebra'
     612    instead.  See that function for extensive documentation.  (This
     613    differs from SteenrodAlgebra_generic only in that it has a method
     614    'Sq' for defining elements.)
     615    """
     616    def Sq(self, *nums):
     617        r"""
     618        Milnor element $\text{Sq}(a,b,c,...)$.
     619
     620        INPUT:
     621            a, b, c, ... -- non-negative integers
     622       
     623        OUTPUT:
     624            element of the Steenrod algebra
     625
     626        This returns the Milnor basis element $\text{Sq}(a, b, c, ...)$.
     627   
     628        EXAMPLES:
     629            sage: A = SteenrodAlgebra(2)
     630            sage: A.Sq(5)
     631            Sq(5)
     632            sage: A.Sq(5,0,2)
     633            Sq(5,0,2)
     634
     635        Entries must be non-negative integers; otherwise, an error results.
     636        """
     637        from sage.algebras.steenrod_algebra_element import SteenrodAlgebraElement
     638        if self.prime == 2:
     639            dict = {nums: 1}
     640            return SteenrodAlgebraElement(dict, p=2, basis=self._basis_name)
     641        else:
     642            raise ValueError, "Sq is only defined at the prime 2"
     643
     644
     645def SteenrodAlgebra(p=2, basis='milnor'):
     646    r"""
     647    The mod $p$ Steenrod algebra
     648
     649    INPUT:
     650        p -- positive prime integer (optional, default = 2)
     651        basis -- string (optional, default = 'milnor')
     652
     653    OUTPUT:
     654        mod p Steenrod algebra with given basis
     655
     656    This returns the mod $p$ Steenrod algebra, elements of which are
     657    printed using basis.
     658
     659    EXAMPLES:
     660    Some properties of the Steenrod algebra are available:
     661        sage: A = SteenrodAlgebra(2)
     662        sage: A.ngens()  # number of generators
     663        +Infinity
     664        sage: A.gen(5)   # 5th generator
     665        Sq(32)
     666        sage: A.order()
     667        +Infinity
     668        sage: A.is_finite()
     669        False
     670        sage: A.is_commutative()
     671        False
     672        sage: A.is_noetherian()
     673        False
     674        sage: A.is_integral_domain()
     675        False
     676        sage: A.is_field()
     677        False
     678        sage: A.is_division_algebra()
     679        False
     680        sage: A.category()
     681        Category of algebras over Finite Field of size 2
     682
     683    There are methods for constructing elements of the Steenrod algebra:
     684        sage: A2 = SteenrodAlgebra(2); A2
     685        mod 2 Steenrod algebra
     686        sage: A2.Sq(1,2,6)
     687        Sq(1,2,6)
     688        sage: A2.Q(3,4)  # product of Milnor primitives Q_3 and Q_4
     689        Sq(0,0,0,1,1)
     690        sage: A2.pst(2,3)  # Margolis pst element
     691        Sq(0,0,4)
     692        sage: A5 = SteenrodAlgebra(5); A5
     693        mod 5 Steenrod algebra
     694        sage: A5.P(1,2,6)
     695        P(1,2,6)
     696        sage: A5.Q(3,4)
     697        Q_3 Q_4
     698        sage: A5.Q(3,4) * A5.P(1,2,6)
     699        Q_3 Q_4 P(1,2,6)
     700        sage: A5.pst(2,3)
     701        P(0,0,25)
     702
     703    You can test whether elements are contained in the Steenrod algebra:
     704        sage: w = Sq(2) * Sq(4)
     705        sage: w in SteenrodAlgebra(2)
     706        True
     707        sage: w in SteenrodAlgebra(17)
     708        False
     709
     710    Different bases for the Steenrod algebra:
     711
     712    There are two standard vector space bases for the mod $p$ Steenrod
     713    algebra: the Milnor basis and the Serre-Cartan basis.  When $p=2$,
     714    there are also several other, less well-known, bases.  See the
     715    documentation for the function 'steenrod_algebra_basis' for full
     716    descriptions of each of the implemented bases.
     717   
     718    This package implements the following bases at all primes:   
     719
     720        * 'milnor': Milnor basis.
     721
     722        * 'serre-cartan' or 'adem' or 'admissible': Serre-Cartan basis.
     723
     724    It implements the following bases when $p=2$:
     725
     726        * 'wood_y': Wood's Y basis.
     727
     728        * 'wood_z': Wood's Z basis.
     729
     730        * 'wall', 'wall_long': Wall's basis.
     731
     732        * 'arnon_a', 'arnon_a_long': Arnon's A basis.
     733
     734        * 'arnon_c': Arnon's C basis.
     735
     736        * 'pst', 'pst_rlex', 'pst_llex', 'pst_deg', 'pst_revz': various
     737          $P^s_t$-bases.
     738
     739        * 'comm', 'comm_rlex', 'comm_llex', 'comm_deg', 'comm_revz', or
     740          these with '_long' appended: various commutator bases.
     741             
     742    When defining a Steenrod algebra, you can specify a basis.  Then
     743    elements of that Steenrod algebra are printed in that basis
     744        sage: adem = SteenrodAlgebra(2, 'adem')
     745        sage: x = adem.Sq(2,1)  # Sq(-) always means a Milnor basis element
     746        sage: x
     747        Sq^{4} Sq^{1} + Sq^{5}
     748        sage: y = Sq(0,1)    # unadorned Sq defines elements w.r.t. Milnor basis
     749        sage: y
     750        Sq(0,1)
     751        sage: adem(y)
     752        Sq^{2} Sq^{1} + Sq^{3}
     753        sage: adem5 = SteenrodAlgebra(5, 'serre-cartan')
     754        sage: adem5.P(0,2)
     755        P^{10} P^{2} + 4 P^{11} P^{1} + 4 P^{12}
     756
     757    You can get a list of basis elements in a given dimension:
     758        sage: A3 = SteenrodAlgebra(3, 'milnor')
     759        sage: A3.basis(13)
     760        (Q_1 P(2), Q_0 P(3))
     761
     762    As noted above, several of the bases ('arnon_a', 'wall', 'comm')
     763    have alternate, longer, representations.  These provide ways of
     764    expressing elements of the Steenrod algebra in terms of the
     765    $\text{Sq}^{2^n}$.
     766        sage: A_long = SteenrodAlgebra(2, 'arnon_a_long')
     767        sage: A_long(Sq(6))
     768        Sq^{1} Sq^{2} Sq^{1} Sq^{2} + Sq^{2} Sq^{4}
     769        sage: SteenrodAlgebra(2, 'wall_long')(Sq(6))
     770        Sq^{2} Sq^{1} Sq^{2} Sq^{1} + Sq^{2} Sq^{4}
     771        sage: SteenrodAlgebra(2, 'comm_deg_long')(Sq(6))
     772        s_{1} s_{2} s_{12} + s_{2} s_{4}
     773    """
     774    basis_name = get_basis_name(basis, p)
     775    if p == 2:
     776        return SteenrodAlgebra_mod_two(2, basis_name)
     777    else:
     778        return SteenrodAlgebra_generic(p, basis_name)
     779
     780# Now we specify the names of the implemented bases.  For the Milnor
     781# and Serre-Cartan bases, give a list of synonyms:
     782
     783_steenrod_milnor_basis_names = ['milnor']
     784_steenrod_serre_cartan_basis_names = ['serre_cartan', 'serre-cartan', 'sc',
     785                                         'adem', 'admissible']
     786
     787# For the other bases, use pattern-matching rather than a list of
     788# synonyms:
     789#   * Search for 'wood' and 'y' or 'wood' and 'z' to get the Wood bases.
     790#   * Search for 'arnon' and 'c' for the Arnon C basis.
     791#   * Search for 'arnon' (and no 'c') for the Arnon A basis.  Also see if
     792#     'long' is present, for the long form of the basis.
     793#   * Search for 'wall' for the Wall basis. Also see if 'long' is present.
     794#   * Search for 'pst' for P^s_t bases, then search for the order type:
     795#     'rlex', 'llex', 'deg', 'revz'.
     796#   * For commutator types, search for 'comm', an order type, and also
     797#     check to see if 'long' is present.
     798
     799def get_basis_name(basis, p):
     800    """
     801    Return canonical basis named by string basis at the prime p.
     802   
     803    INPUT:
     804        basis -- string
     805        p -- positive prime number
     806
     807    OUTPUT:
     808        basis_name -- string
     809
     810    EXAMPLES:
     811        sage: sage.algebras.steenrod_algebra.get_basis_name('adem', 2)
     812        'serre-cartan'
     813        sage: sage.algebras.steenrod_algebra.get_basis_name('milnor', 2)
     814        'milnor'
     815        sage: sage.algebras.steenrod_algebra.get_basis_name('MiLNoR', 5)
     816        'milnor'
     817        sage: sage.algebras.steenrod_algebra.get_basis_name('pst-llex', 2)
     818        'pst_llex'
     819    """
     820    basis = basis.lower()
     821    if basis in _steenrod_milnor_basis_names:
     822        result = 'milnor'
     823    elif basis in _steenrod_serre_cartan_basis_names:
     824        result = 'serre-cartan'
     825    elif p == 2 and basis.find('pst') >= 0:
     826        if basis.find('rlex') >= 0:
     827            result = 'pst_rlex'
     828        elif basis.find('llex') >= 0:
     829            result = 'pst_llex'
     830        elif basis.find('deg') >= 0:
     831            result = 'pst_deg'
     832        elif basis.find('revz') >= 0:
     833            result = 'pst_revz'
     834        else:
     835            result = 'pst_revz'
     836    elif p == 2 and basis.find('comm') >= 0:
     837        if basis.find('rlex') >= 0:
     838            result = 'comm_rlex'
     839        elif basis.find('llex') >= 0:
     840            result = 'comm_llex'
     841        elif basis.find('deg') >= 0:
     842            result = 'comm_deg'
     843        elif basis.find('revz') >= 0:
     844            result = 'comm_revz'
     845        else:
     846            result = 'comm_revz'
     847        if basis.find('long') >= 0:
     848            result = result + '_long'
     849    elif p == 2 and basis.find('wood') >= 0:
     850        if basis.find('y') >= 0:
     851            result = 'woody'
     852        else:
     853            result = 'woodz'
     854    elif p == 2 and basis.find('arnon') >= 0:
     855        if basis.find('c') >= 0:
     856            result = 'arnonc'
     857        else:
     858            result = 'arnona'
     859            if basis.find('long') >= 0:
     860                result = result + '_long'
     861    elif p == 2 and basis.find('wall') >= 0:
     862        result = 'wall'
     863        if basis.find('long') >= 0:
     864            result = result + '_long'
     865    else:
     866        raise ValueError, "%s is not a recognized basis at the prime %s." % (basis, p)
     867    return result
  • new file sage/algebras/steenrod_algebra_bases.py

    diff -r c25e04ebfb67 -r 9fbc77f226c8 sage/algebras/steenrod_algebra_bases.py
    - +  
     1r"""
     2Steenrod algebra bases
     3
     4AUTHORS:
     5    - John H. Palmieri (2008-07-30: version 0.9)
     6
     7This package defines functions for computing various bases of the
     8Steenrod algebra, and for converting between the Milnor basis and any
     9other basis.
     10
     11This packages implements a number of different bases, at least at the
     12prime 2.  The Milnor and Serre-Cartan bases are the most familiar and
     13most standard ones, and all of the others are defined in terms of one
     14of these.  The bases are described in the documentation for the
     15function \code{steenrod_algebra_basis}; also see the papers by Monks [M]
     16and Wood [W] for more information about them.  For commutator bases,
     17see the preprint by Palmieri and Zhang [PZ].
     18
     19  * 'milnor': Milnor basis.
     20
     21  * 'serre-cartan' or 'adem' or 'admissible': Serre-Cartan basis.
     22
     23The other bases are as follows; these are only defined when $p=2$:
     24
     25  * 'wood_y': Wood's Y basis.
     26
     27  * 'wood_z': Wood's Z basis.
     28
     29  * 'wall', 'wall_long': Wall's basis.
     30
     31  * 'arnon_a', 'arnon_a_long': Arnon's A basis.
     32
     33  * 'arnon_c': Arnon's C basis.
     34
     35  * 'pst', 'pst_rlex', 'pst_llex', 'pst_deg', 'pst_revz': various
     36     $P^s_t$-bases.
     37
     38  * 'comm', 'comm_rlex', 'comm_llex', 'comm_deg', 'comm_revz', or
     39     these with '_long' appended: various commutator bases.
     40
     41EXAMPLES:
     42    sage: steenrod_algebra_basis(7,'milnor')
     43    (Sq(0,0,1), Sq(1,2), Sq(4,1), Sq(7))
     44    sage: steenrod_algebra_basis(5)   # milnor basis is the default
     45    (Sq(2,1), Sq(5))
     46
     47The third (optional) argument to \code{steenrod_algebra_basis} is the prime $p$:
     48    sage: steenrod_algebra_basis(9, 'milnor', p=3)
     49    (Q_1 P(1), Q_0 P(2))
     50    sage: steenrod_algebra_basis(9, 'milnor', 3)
     51    (Q_1 P(1), Q_0 P(2))
     52    sage: steenrod_algebra_basis(17, 'milnor', 3)
     53    (Q_2, Q_1 P(3), Q_0 P(0,1), Q_0 P(4))
     54
     55Other bases:
     56    sage: steenrod_algebra_basis(7,'admissible')
     57    (Sq^{7}, Sq^{6} Sq^{1}, Sq^{4} Sq^{2} Sq^{1}, Sq^{5} Sq^{2})
     58    sage: [x.basis('milnor') for x in steenrod_algebra_basis(7,'admissible')]
     59    [Sq(7),
     60    Sq(4,1) + Sq(7),
     61    Sq(0,0,1) + Sq(1,2) + Sq(4,1) + Sq(7),
     62    Sq(1,2) + Sq(7)]
     63    sage: Aw = SteenrodAlgebra(2, basis = 'wall_long')
     64    sage: [Aw(x) for x in steenrod_algebra_basis(7,'admissible')]
     65    [Sq^{1} Sq^{2} Sq^{4},
     66    Sq^{2} Sq^{4} Sq^{1},
     67    Sq^{4} Sq^{2} Sq^{1},
     68    Sq^{4} Sq^{1} Sq^{2}]
     69    sage: steenrod_algebra_basis(13,'admissible',p=3)
     70    (beta P^{3}, P^{3} beta)
     71    sage: steenrod_algebra_basis(5,'wall')
     72    (Q^{2}_{2} Q^{0}_{0}, Q^{1}_{1} Q^{1}_{0})
     73    sage: steenrod_algebra_basis(5,'wall_long')
     74    (Sq^{4} Sq^{1}, Sq^{2} Sq^{1} Sq^{2})
     75    sage: steenrod_algebra_basis(5,'pst-rlex')
     76    (P^{0}_{1} P^{2}_{1}, P^{1}_{1} P^{0}_{2})
     77
     78This file also contains a function \code{milnor_convert} which converts
     79elements from the (default) Milnor basis representation to a
     80representation in another basis.  The output is a dictionary which
     81gives the new representation; its form depends on the chosen basis.
     82For example, in the basis of admissible sequences (a.k.a. the
     83Serre-Cartan basis), each basis element is of the form $\text{Sq}^a
     84\text{Sq}^b ...$, and so is represented by a tuple $(a,b,...)$ of
     85integers.  Thus the dictionary has such tuples as keys, with the
     86coefficient of the basis element as the associated value:
     87    sage: from sage.algebras.steenrod_algebra_bases import milnor_convert
     88    sage: milnor_convert(Sq(2)*Sq(4) + Sq(2)*Sq(5), 'admissible')
     89    {(5, 1): 1, (6, 1): 1, (6,): 1}
     90    sage: milnor_convert(Sq(2)*Sq(4) + Sq(2)*Sq(5), 'pst')
     91    {((1, 1), (2, 1)): 1, ((0, 1), (1, 1), (2, 1)): 1, ((0, 2), (2, 1)): 1}
     92
     93Users shouldn't need to call \code{milnor_convert}; they should use the
     94\code{basis} method to view a single element in another basis, or define a
     95Steenrod algebra with a different default basis and work in that
     96algebra:
     97    sage: x = Sq(2)*Sq(4) + Sq(2)*Sq(5)
     98    sage: x
     99    Sq(3,1) + Sq(4,1) + Sq(6) + Sq(7)
     100    sage: x.basis('milnor')  # 'milnor' is the default basis
     101    Sq(3,1) + Sq(4,1) + Sq(6) + Sq(7)
     102    sage: x.basis('adem')
     103    Sq^{5} Sq^{1} + Sq^{6} + Sq^{6} Sq^{1}
     104    sage: x.basis('pst')
     105    P^{0}_{1} P^{1}_{1} P^{2}_{1} + P^{0}_{2} P^{2}_{1} + P^{1}_{1} P^{2}_{1}
     106    sage: A = SteenrodAlgebra(2, basis='pst')
     107    sage: A(Sq(2) * Sq(4) + Sq(2) * Sq(5))
     108    P^{0}_{1} P^{1}_{1} P^{2}_{1} + P^{0}_{2} P^{2}_{1} + P^{1}_{1} P^{2}_{1}
     109
     110**************
     111
     112INTERNAL DOCUMENTATION:
     113
     114If you want to implement a new basis for the Steenrod algebra:
     115
     116    In the file 'steenrod_algebra.py':
     117
     118        add functionality to \code{get_basis_name}: this should accept as
     119        input various synonyms for the basis, and its output should be
     120        an element of \code{_steenrod_basis_unique_names} (see the next
     121        file).
     122
     123    In the file 'steenrod_algebra_element.py':
     124
     125        add name of basis to \code{_steenrod_basis_unique_names}
     126
     127        add functionality to \code{string_rep}, which probably involves
     128        adding a \code{BASIS_mono_to_string} function
     129
     130        add functionality to the \code{_basis_dictionary} method
     131
     132    In this file ('steenrod_algebra_bases.py'):
     133
     134        add appropriate lines to \code{steenrod_algebra_basis}
     135
     136        add a function to compute the basis in a given dimension (to be
     137        called by \code{steenrod_algebra_basis})
     138   
     139REFERENCES:
     140
     141    [M]  K. G. Monks, "Change of basis, monomial relations, and $P^s_t$
     142         bases for the Steenrod algebra," J. Pure Appl. Algebra 125 (1998),
     143         no. 1-3, 235--260.
     144         
     145    [PZ] J. H. Palmieri and J. J. Zhang, "Commutators in the Steenrod
     146         algebra," preprint (2008)
     147         
     148    [W]  R. M. W. Wood, "Problems in the Steenrod algebra," Bull. London
     149         Math. Soc. 30 (1998), no. 5, 449--517.
     150"""
     151
     152#*****************************************************************************
     153#       Copyright (C) 2008 John H. Palmieri <palmieri@math.washington.edu>
     154#  Distributed under the terms of the GNU General Public License (GPL)
     155#*****************************************************************************
     156
     157from sage.rings.integer import Integer
     158from sage.rings.all import GF
     159
     160from steenrod_algebra import SteenrodAlgebra, get_basis_name, \
     161    _steenrod_serre_cartan_basis_names, _steenrod_milnor_basis_names
     162from steenrod_algebra_element import SteenrodAlgebraElement, Sq, pst
     163
     164
     165# cache matrices from convert_to_milnor_matrix here:
     166_conversion_matrices = {}
     167
     168def convert_to_milnor_matrix(n, basis, p=2):
     169    r"""
     170    Change-of-basis matrix, 'basis' to Milnor, in dimension $n$, at the prime $p$.
     171
     172    INPUT:
     173        n -- non-negative integer, the dimension
     174        basis -- string, the basis from which to convert
     175        p -- positive prime number (optional, default 2)
     176
     177    OUTPUT:
     178        matrix -- change-of-basis matrix, a square matrix over GF(p)
     179
     180    (This is not really intended for casual users, so no error
     181    checking is made on the integer $n$, the basis name, or the prime.)
     182
     183    EXAMPLES:
     184        sage: from sage.algebras.steenrod_algebra_bases import convert_to_milnor_matrix
     185        sage: convert_to_milnor_matrix(5, 'adem')
     186        [0 1]
     187        [1 1]
     188        sage: convert_to_milnor_matrix(45, 'milnor')
     189        111 x 111 dense matrix over Finite Field of size 2
     190        sage: convert_to_milnor_matrix(12,'wall')
     191        [1 0 0 1 0 0 0]
     192        [1 1 0 0 0 1 0]
     193        [0 1 0 1 0 0 0]
     194        [0 0 0 1 0 0 0]
     195        [1 1 0 0 1 0 0]
     196        [0 0 1 1 1 0 1]
     197        [0 0 0 0 1 0 1]
     198
     199    The function takes an optional argument, the prime $p$ over which to work:
     200        sage: convert_to_milnor_matrix(17,'adem',3)
     201        [0 0 1 1]
     202        [0 0 0 1]
     203        [1 1 1 1]
     204        [0 1 0 1]
     205        sage: convert_to_milnor_matrix(48,'adem',5)
     206        [0 1]
     207        [1 1]
     208        sage: convert_to_milnor_matrix(36,'adem',3)
     209        [0 0 1]
     210        [0 1 0]
     211        [1 2 0]
     212    """
     213    if _conversion_matrices.has_key((n, basis, p)):
     214        return _conversion_matrices[(n, basis, p)]
     215    from sage.matrix.constructor import matrix
     216    milnor_base = steenrod_algebra_basis(n,'milnor',p)
     217    rows = []
     218    for poly in steenrod_algebra_basis(n,basis,p):
     219        for v in milnor_base:
     220            for m in v._basis_dictionary('milnor'):
     221                key = m
     222            if poly._raw['milnor'].has_key(key):
     223                rows = rows + [poly._raw['milnor'][key]]
     224            else:
     225                rows = rows + [0]
     226    d = len(milnor_base)
     227    _conversion_matrices[(n, basis, p)] = matrix(GF(p),d,d,rows)
     228    return matrix(GF(p),d,d,rows)
     229
     230
     231def convert_from_milnor_matrix(n, basis, p=2):
     232    r"""
     233    Change-of-basis matrix, Milnor to 'basis', in dimension $n$.
     234
     235    INPUT:
     236        n -- non-negative integer, the dimension
     237        basis -- string, the basis to which to convert
     238        p -- positive prime number (optional, default 2)
     239
     240    OUTPUT:
     241        matrix -- change-of-basis matrix, a square matrix over GF(p)
     242
     243    (This is not really intended for casual users, so no error
     244    checking is made on the integer $n$, the basis name, or the prime.)
     245
     246    EXAMPLES:
     247        sage: from sage.algebras.steenrod_algebra_bases import convert_from_milnor_matrix, convert_to_milnor_matrix
     248        sage: convert_from_milnor_matrix(12,'wall')
     249        [1 0 0 1 0 0 0]
     250        [0 0 1 1 0 0 0]
     251        [0 0 0 1 0 1 1]
     252        [0 0 0 1 0 0 0]
     253        [1 0 1 0 1 0 0]
     254        [1 1 1 0 0 0 0]
     255        [1 0 1 0 1 0 1]
     256        sage: convert_from_milnor_matrix(38,'serre_cartan')
     257        72 x 72 dense matrix over Finite Field of size 2
     258        sage: x = convert_to_milnor_matrix(20,'wood_y')
     259        sage: y = convert_from_milnor_matrix(20,'wood_y')
     260        sage: x*y
     261        [1 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0]
     262        [0 1 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0]
     263        [0 0 1 0 0 0 0 0 0 0 0 0 0 0 0 0 0]
     264        [0 0 0 1 0 0 0 0 0 0 0 0 0 0 0 0 0]
     265        [0 0 0 0 1 0 0 0 0 0 0 0 0 0 0 0 0]
     266        [0 0 0 0 0 1 0 0 0 0 0 0 0 0 0 0 0]
     267        [0 0 0 0 0 0 1 0 0 0 0 0 0 0 0 0 0]
     268        [0 0 0 0 0 0 0 1 0 0 0 0 0 0 0 0 0]
     269        [0 0 0 0 0 0 0 0 1 0 0 0 0 0 0 0 0]
     270        [0 0 0 0 0 0 0 0 0 1 0 0 0 0 0 0 0]
     271        [0 0 0 0 0 0 0 0 0 0 1 0 0 0 0 0 0]
     272        [0 0 0 0 0 0 0 0 0 0 0 1 0 0 0 0 0]
     273        [0 0 0 0 0 0 0 0 0 0 0 0 1 0 0 0 0]
     274        [0 0 0 0 0 0 0 0 0 0 0 0 0 1 0 0 0]
     275        [0 0 0 0 0 0 0 0 0 0 0 0 0 0 1 0 0]
     276        [0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 1 0]
     277        [0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 1]
     278
     279    The function takes an optional argument, the prime $p$ over which to work:
     280        sage: convert_from_milnor_matrix(17,'adem',3)
     281        [2 1 1 2]
     282        [0 2 0 1]
     283        [1 2 0 0]
     284        [0 1 0 0]
     285    """
     286    mat = convert_to_milnor_matrix(n,basis,p)
     287    if mat.nrows() != 0:
     288        return convert_to_milnor_matrix(n,basis,p).inverse()
     289    else:
     290        return mat
     291
     292
     293def make_elt_homogeneous(poly):
     294    """
     295    Break element of the Steenrod algebra into a list of homogeneous pieces.
     296
     297    INPUT:
     298        poly -- an element of the Steenrod algebra
     299
     300    OUTPUT:
     301        list of homogeneous elements of the Steenrod algebra whose sum is poly
     302
     303    EXAMPLES:
     304        sage: from sage.algebras.steenrod_algebra_bases import make_elt_homogeneous
     305        sage: make_elt_homogeneous(Sq(2)*Sq(4) + Sq(2)*Sq(5))
     306        [Sq(3,1) + Sq(6), Sq(4,1) + Sq(7)]
     307    """
     308    degrees = set([m.degree() for m in poly])   # set of degrees in poly
     309    result = []
     310    for d in degrees:
     311        result_d = 0
     312        for m in poly:
     313            if m.degree() == d:
     314                result_d = result_d + m
     315        result.append(result_d)
     316    return result
     317
     318
     319def milnor_convert(poly, basis):
     320    r"""
     321    Convert an element of the Steenrod algebra in the Milnor basis
     322    to its representation in the chosen basis.
     323
     324    INPUT:
     325        poly -- element of the Steenrod algebra
     326        basis -- basis to which to convert
     327
     328    OUTPUT:
     329        dict -- dictionary
     330
     331
     332    This returns a dictionary of terms of the form (mono: coeff),
     333    where mono is a monomial in 'basis'.  The form of mono depends on
     334    the chosen basis.
     335   
     336    EXAMPLES:
     337        sage: from sage.algebras.steenrod_algebra_bases import milnor_convert
     338        sage: milnor_convert(Sq(2)*Sq(4) + Sq(2)*Sq(5), 'adem')
     339        {(5, 1): 1, (6, 1): 1, (6,): 1}
     340        sage: A3 = SteenrodAlgebra(3)
     341        sage: a = A3.Q(1) * A3.P(2,2); a
     342        Q_1 P(2,2)
     343        sage: milnor_convert(a, 'adem')
     344        {(0, 9, 1, 2, 0): 1, (1, 9, 0, 2, 0): 2}
     345        sage: milnor_convert(2 * a, 'adem')
     346        {(0, 9, 1, 2, 0): 2, (1, 9, 0, 2, 0): 1}
     347        sage: (Sq(2)*Sq(4) + Sq(2)*Sq(5)).basis('adem')
     348        Sq^{5} Sq^{1} + Sq^{6} + Sq^{6} Sq^{1}
     349        sage: a.basis('adem')
     350        P^{9} beta P^{2} + 2 beta P^{9} P^{2}
     351        sage: milnor_convert(Sq(2)*Sq(4) + Sq(2)*Sq(5), 'pst')
     352        {((1, 1), (2, 1)): 1, ((0, 1), (1, 1), (2, 1)): 1, ((0, 2), (2, 1)): 1}
     353        sage: (Sq(2)*Sq(4) + Sq(2)*Sq(5)).basis('pst')
     354        P^{0}_{1} P^{1}_{1} P^{2}_{1} + P^{0}_{2} P^{2}_{1} + P^{1}_{1}
     355        P^{2}_{1}
     356    """
     357    from sage.matrix.constructor import matrix
     358    p = poly._prime
     359    basis_name = get_basis_name(basis, p)
     360    if basis_name.find('long') >= 0:
     361        basis_name = basis_name.rsplit('_', 1)[0]
     362    if basis_name == 'milnor': return poly._raw['milnor']
     363    dict = {}
     364    for x in make_elt_homogeneous(poly):
     365        dim = x.degree()
     366        vec = []
     367        for mono in steenrod_algebra_basis(dim,'milnor',p):
     368            if mono._raw['milnor'].keys()[0] in x._raw['milnor'].keys():
     369                for entry in mono._raw['milnor']:
     370                    coeff =  x._raw['milnor'][entry]
     371                vec = vec + [coeff]
     372            else:
     373                vec = vec + [0]
     374        new_vec = (matrix(GF(p),1,len(vec),vec)
     375                   * convert_from_milnor_matrix(dim, basis_name, p)).row(0)
     376        for (mono,coeff) in zip(steenrod_algebra_basis(dim, basis_name, p), new_vec):
     377            if coeff != 0:
     378                old_dict = mono._raw[basis_name]
     379                for entry in old_dict:
     380                    dict[entry] = coeff
     381    return dict
     382
     383def steenrod_algebra_basis(n, basis='milnor', p=2):
     384    r"""
     385    Basis for the Steenrod algebra in degree $n$.
     386
     387    INPUT:
     388        n -- non-negative integer
     389        basis -- string, which basis to use  (optional, default = 'milnor')
     390        p -- positive prime number (optional, default = 2)
     391
     392    OUTPUT:
     393        tuple of basis elements for the Steenrod algebra in dimension n
     394
     395    The choices for the string basis are as follows:
     396
     397      * 'milnor': Milnor basis.  When $p=2$, the Milnor basis consists
     398        of symbols of the form $\text{Sq}(m_1, m_2, ..., m_t)$, where each
     399        $m_i$ is a non-negative integer and if $t>1$, then the last
     400        entry $m_t > 0$.  When $p$ is odd, the Milnor basis consists
     401        of symbols of the form $Q_{e_1} Q_{e_2} ... \mathcal{P}(m_1,
     402        m_2, ..., m_t)$, where $0 \leq e_1 < e_2 < ...$, each $m_i$ is
     403        a non-negative integer, and if $t>1$, then the last entry $m_t
     404        > 0$.
     405
     406      * 'serre-cartan' or 'adem' or 'admissible': Serre-Cartan basis.
     407        The Serre-Cartan basis consists of 'admissible monomials' in
     408        the Steenrod operations.  Thus at the prime 2, it consists of
     409        monomials $\text{Sq}^{m_1} \text{Sq}^{m_2} ... \text{Sq}^{m_t}$
     410        with $m_i \geq 2m_{i+1}$ for each $i$.  At odd primes, it
     411        consists of monomials $\beta^{\epsilon_0} \mathcal{P}^{s_1}
     412        \beta^{\epsilon_1} \mathcal{P}^{s_2} ...  \mathcal{P}^{s_k}
     413        \beta^{\epsilon_k}$ with each $\epsilon_i$ either 0 or 1, $s_i
     414        \geq p s_{i+1} + \epsilon_i$, and $s_k \geq 1$.
     415
     416        When $p=2$, the element $\text{Sq}^a$ equals the Milnor
     417        element $\text{Sq}(a)$; when $p$ is odd, $\mathcal{P}^a =
     418        \mathcal{P}(a)$ and $\beta = Q_0$.  Hence for any Serre-Cartan
     419        basis element, one can represent it in the Milnor basis by
     420        computing an appropriate product using Milnor multiplication.
     421
     422    The rest of these bases are only defined when $p=2$.
     423
     424      * 'wood_y': Wood's Y basis.  For pairs of non-negative integers
     425        $(m,k)$, let $w(m,k) = \text{Sq}^{2^m (2^{k+1}-1)}$.  Wood's $Y$
     426        basis consists of monomials $w(m_0,k_0) ... w(m_t, k_t)$ with
     427        $(m_i,k_i) > (m_{i+1},k_{i+1})$, in left lex order.
     428
     429      * 'wood_z': Wood's Z basis.  For pairs of non-negative integers
     430        $(m,k)$, let $w(m,k) = \text{Sq}^{2^m (2^{k+1}-1)}$.  Wood's $Z$
     431        basis consists of monomials $w(m_0,k_0) ... w(m_t, k_t)$ with
     432        $(m_i+k_i,m_i) > (m_{i+1}+k_{i+1},m_{i+1})$, in left lex
     433        order.
     434
     435      * 'wall' or 'wall_long': Wall's basis.  For any pair of integers
     436        $(m,k)$ with $m \geq k \geq 0$, let $Q^m_k = \text{Sq}^{2^k}
     437        \text{Sq}^{2^{k+1}} ... \text{Sq}^{2^m}$.  The elements of
     438        Wall's basis are monomials $Q^{m_0}_{k_0} ... Q^{m_t}_{k_t}$
     439        with $(m_i, k_i) > (m_{i+1}, k_{i+1})$, ordered left
     440        lexicographically.
     441       
     442        (Note that $Q^m_k$ is the reverse of the element $X^m_k$ used in
     443        defining Arnon's A basis.)
     444
     445        The standard way of printing elements of the Wall basis is to
     446        write elements in terms of the $Q^m_k$.  If one sets the basis
     447        to 'wall_long' instead of 'wall', then each $Q^m_k$ is
     448        expanded as a product of factors of the form $\text{Sq}^{2^i}$.
     449
     450      * 'arnon_a' or 'arnon_a_long': Arnon's A basis.  For any pair of
     451        integers $(m,k)$ with $m \geq k \geq 0$, let $X^m_k =
     452        \text{Sq}^{2^m} \text{Sq}^{2^{m-1}} ... \text{Sq}^{2^k}$.  The
     453        elements of Arnon's A basis are monomials $X^{m_0}_{k_0}
     454        ... X^{m_t}_{k_t}$ with $(m_i, k_i) < (m_{i+1}, k_{i+1})$,
     455        ordered left lexicographically.
     456
     457        (Note that $X^m_k$ is the reverse of the element $Q^m_k$ used
     458        in defining Wall's basis.)
     459       
     460        The standard way of printing elements of Arnon's A basis is to
     461        write elements in terms of the $X^m_k$.  If one sets the basis
     462        to 'arnon_a_long' instead of 'arnon_a', then each $X^m_k$ is
     463        expanded as a product of factors of the form $\text{Sq}^{2^i}$.
     464
     465      * 'arnon_c': Arnon's C basis.  The elements of Arnon's C basis
     466        are monomials of the form $\text{Sq}^{t_1} ... \text{Sq}^{t_m}$
     467        where for each $i$, we have $t_i \leq 2t_{i+1}$ and $2^i | t_{m-i}$.
     468
     469      * 'pst', 'pst_rlex', 'pst_llex', 'pst_deg', 'pst_revz': various
     470        $P^s_t$-bases.  For integers $s \geq 0$ and $t > 0$, the element
     471        $P^s_t$ is the Milnor basis element $\text{Sq}(0, ..., 0, 2^s, 0,
     472        ...)$, with the nonzero entry in position $t$.  To obtain a
     473        $P^s_t$-basis, for each set $\{P^{s_1}_{t_1}, ...,
     474        P^{s_k}_{t_k}\}$ of (distinct) $P^s_t$'s, one chooses an
     475        ordering and forms the resulting monomial.  The set of all
     476        such monomials then forms a basis, and so one gets a basis by
     477        choosing an ordering on each monomial.
     478
     479        The strings 'rlex', 'llex', etc., correspond to the following
     480        orderings.  These are all 'global' -- they give a global
     481        ordering on the $P^s_t$'s, not different orderings depending
     482        on the monomial.  They order the $P^s_t$'s using the pair of
     483        integers $(s,t)$ as follows:
     484
     485          * 'rlex': right lexicographic ordering
     486
     487          * 'llex': left lexicographic ordering
     488
     489          * 'deg': ordered by degree, which is the same as left
     490            lexicographic ordering on the pair $(s+t,t)$
     491
     492          * 'revz': left lexicographic ordering on the pair $(s+t,s)$,
     493            which is the reverse of the ordering used (on elements in
     494            the same degrees as the $P^s_t$'s) in Wood's Z basis:
     495            'revz' stands for 'reversed Z'.  This is the default:
     496            'pst' is the same as 'pst_revz'.
     497
     498      * 'comm', 'comm_rlex', 'comm_llex', 'comm_deg', 'comm_revz', or
     499        any of these with '_long' appended: various commutator bases.
     500        Let $c_{i,1} = \text{Sq}^{2^i}$, let $c_{i,2} = [c_{i,1},
     501        c_{i+1,1}]$, and inductively define $c_{i,k} = [c_{i,k-1},
     502        c_{i+k-1,1}]$.  Thus $c_{i,k}$ is a $k$-fold iterated
     503        commutator of the elements $\text{Sq}^{2^i}$, ...,
     504        $\text{Sq}^{2^{i+k-1}}$.  Note that $\dim c_{i,k} = \dim
     505        P^i_k$.
     506
     507        To obtain a commutator basis, for each set $\{c_{s_1,t_1},
     508        ..., c_{s_k,t_k}\}$ of (distinct) $c_{s,t}$'s, one chooses an
     509        ordering and forms the resulting monomial.  The set of all
     510        such monomials then forms a basis, and so one gets a basis by
     511        choosing an ordering on each monomial.  The strings 'rlex',
     512        etc., have the same meaning as for the orderings on
     513        $P^s_t$-bases.  As with the $P^s_t$-bases, 'comm_revz' is the
     514        default: 'comm' means 'comm_revz'.
     515
     516        The commutator bases have alternative representations,
     517        obtained by appending 'long' to their names: instead of, say,
     518        $c_{2,2}$, the representation is $s_{48}$, indicating the
     519        commutator of $\text{Sq}^4$ and $\text{Sq}^8$, and $c_{0,3}$,
     520        which is equal to $[[\text{Sq}^1, \text{Sq}^2], \text{Sq}^4]$,
     521        is written as $s_{124}$.
     522
     523    EXAMPLES:
     524        sage: steenrod_algebra_basis(7,'milnor')
     525        (Sq(0,0,1), Sq(1,2), Sq(4,1), Sq(7))
     526        sage: steenrod_algebra_basis(5)   # milnor basis is the default
     527        (Sq(2,1), Sq(5))
     528
     529    The third (optional) argument to 'steenrod_algebra_basis' is the prime p:
     530        sage: steenrod_algebra_basis(9, 'milnor', p=3)
     531        (Q_1 P(1), Q_0 P(2))
     532        sage: steenrod_algebra_basis(9, 'milnor', 3)
     533        (Q_1 P(1), Q_0 P(2))
     534        sage: steenrod_algebra_basis(17, 'milnor', 3)
     535        (Q_2, Q_1 P(3), Q_0 P(0,1), Q_0 P(4))
     536
     537    Other bases:
     538        sage: steenrod_algebra_basis(7,'admissible')
     539        (Sq^{7}, Sq^{6} Sq^{1}, Sq^{4} Sq^{2} Sq^{1}, Sq^{5} Sq^{2})
     540        sage: [x.basis('milnor') for x in steenrod_algebra_basis(7,'admissible')]
     541        [Sq(7),
     542        Sq(4,1) + Sq(7),
     543        Sq(0,0,1) + Sq(1,2) + Sq(4,1) + Sq(7),
     544        Sq(1,2) + Sq(7)]
     545        sage: steenrod_algebra_basis(13,'admissible',p=3)
     546        (beta P^{3}, P^{3} beta)
     547        sage: steenrod_algebra_basis(5,'wall')
     548        (Q^{2}_{2} Q^{0}_{0}, Q^{1}_{1} Q^{1}_{0})
     549        sage: steenrod_algebra_basis(5,'wall_long')
     550        (Sq^{4} Sq^{1}, Sq^{2} Sq^{1} Sq^{2})
     551        sage: steenrod_algebra_basis(5,'pst-rlex')
     552        (P^{0}_{1} P^{2}_{1}, P^{1}_{1} P^{0}_{2})
     553    """
     554    if not (isinstance(n, (Integer, int)) and n >= 0):
     555        raise ValueError, "%s is not a non-negative integer." % n
     556    basis_name = get_basis_name(basis, p)
     557    if basis_name.find('long') >= 0:
     558        long = True
     559        basis_name = basis_name.rsplit('_', 1)[0]
     560    else:
     561        long = False
     562
     563    ## Milnor basis
     564    if basis_name == 'milnor':
     565        return milnor_basis(n,p)
     566    ## Serre-Cartan basis
     567    elif basis_name == 'serre-cartan':
     568        return serre_cartan_basis(n,p)
     569    ## Atomic bases
     570    elif p == 2 and (basis_name == 'woody' or basis_name == 'woodz'
     571                     or basis_name == 'wall' or basis_name == 'arnona'
     572                     or basis_name.find('pst') >= 0
     573                     or basis_name.find('comm') >= 0):
     574        return atomic_basis(n, basis_name, long=long)
     575    ## Arnon 'C' basis
     576    elif p == 2 and basis == 'arnonc':
     577        return arnonC_basis(n)
     578
     579
     580def restricted_partitions(n, list, no_repeats=False):
     581    """
     582    List of 'restricted' partitions of n: partitions with parts taken from list.
     583
     584    INPUT:
     585        n -- non-negative integer
     586        list -- list of positive integers
     587        no_repeats -- boolean (optional, default = False), if True, only
     588            return partitions with no repeated parts
     589
     590    This seems to be faster than RestrictedPartitions, although I
     591    don't know why.  Maybe because all I want is the list of
     592    partitions (with each partition represented as a list), not the
     593    extra stuff provided by RestrictedPartitions.
     594
     595    EXAMPLES:
     596        sage: from sage.algebras.steenrod_algebra_bases import restricted_partitions
     597        sage: restricted_partitions(10, [7,5,1])
     598        [[7, 1, 1, 1], [5, 5], [5, 1, 1, 1, 1, 1], [1, 1, 1, 1, 1, 1, 1, 1, 1, 1]]
     599        sage: restricted_partitions(10, [6,5,4,3,2,1], no_repeats=True)
     600        [[6, 4], [6, 3, 1], [5, 4, 1], [5, 3, 2], [4, 3, 2, 1]]
     601        sage: restricted_partitions(10, [6,4,2])
     602        [[6, 4], [6, 2, 2], [4, 4, 2], [4, 2, 2, 2], [2, 2, 2, 2, 2]]
     603        sage: restricted_partitions(10, [6,4,2], no_repeats=True)
     604        [[6, 4]]
     605
     606    'list' may have repeated elements.  If 'no_repeats' is False, this
     607    has no effect.  If 'no_repeats' is True, and if the repeated
     608    elements appear consecutively in 'list', then each element may be
     609    used only as many times as it appears in 'list':
     610        sage: restricted_partitions(10, [6,4,2,2], no_repeats=True)
     611        [[6, 4], [6, 2, 2]]
     612        sage: restricted_partitions(10, [6,4,2,2,2], no_repeats=True)
     613        [[6, 4], [6, 2, 2], [4, 2, 2, 2]]
     614
     615    (If the repeated elements don't appear consecutively, the results
     616    are likely meaningless, containing several partitions more than
     617    once, for example.)
     618
     619    In the following examples, 'no_repeats' is False:
     620        sage: restricted_partitions(10, [6,4,2])
     621        [[6, 4], [6, 2, 2], [4, 4, 2], [4, 2, 2, 2], [2, 2, 2, 2, 2]]
     622        sage: restricted_partitions(10, [6,4,2,2,2])
     623        [[6, 4], [6, 2, 2], [4, 4, 2], [4, 2, 2, 2], [2, 2, 2, 2, 2]]
     624        sage: restricted_partitions(10, [6,4,4,4,2,2,2,2,2,2])
     625        [[6, 4], [6, 2, 2], [4, 4, 2], [4, 2, 2, 2], [2, 2, 2, 2, 2]]
     626    """
     627    if n < 0:
     628        return []
     629    elif n == 0:
     630        return [[]]
     631    else:
     632        results = []
     633        if no_repeats:
     634            index = 1
     635        else:
     636            index = 0
     637        old_i = 0
     638        for i in list:
     639            if old_i != i:
     640                for sigma in restricted_partitions(n-i, list[index:], no_repeats):
     641                    results.append([i] + sigma)
     642            index += 1
     643            old_i = i
     644        return results
     645
     646
     647def list_to_hist(list):
     648    """
     649    Given list of positive integers [a,b,c,...], return corresponding 'histogram'.
     650
     651    That is, in the output [n1, n2, ...], n1 is the number of 1's in
     652    the original list, n2 is the number of 2's, etc.
     653
     654    INPUT:
     655        list -- list of positive integers
     656    OUTPUT:
     657        answer -- list of non-negative integers
     658
     659    EXAMPLES:
     660        sage: from sage.algebras.steenrod_algebra_bases import list_to_hist
     661        sage: list_to_hist([1,2,3,4,2,1,2])
     662        [2, 3, 1, 1]
     663        sage: list_to_hist([2,2,2,2])
     664        [0, 4]
     665    """
     666    if len(list) == 0:
     667        return list
     668    else:
     669        answer = [0] * max(list)
     670        for i in list:
     671            answer[i-1] += 1
     672        return answer
     673
     674
     675########################################################
     676# Functions for defining bases. They work like this:
     677
     678# First, check to see if the basis has been computed already: look for
     679#   the cached result in _steenrod_bases.  If so, filter the result
     680#   based on the optional argument bound.
     681
     682# Dictionary in which to cache results:
     683_steenrod_bases = {}
     684
     685# Second, if there is no cached result, build directly or recursively,
     686#   whichever is more convenient.  The details are documented for each
     687#   basis.  As each basis element is constructed, so is its dictionary
     688#   for the current basis.  For example, in 'serre_cartan_basis', each
     689#   new element is obtained by taking an element in a lower-dimensional
     690#   basis and multiplying, on the right, by Sq(last).  Call this element
     691#   'new'.  Then set new._raw['serre-cartan'] to be the dictionary of
     692#   Serre-Cartan monomials describing this element.  This makes
     693#   conversion of the element to the chosen basis instantaneous; this is
     694#   useful on its own, and crucial for computing change-of-basis
     695#   matrices for general conversion.
     696
     697# Finally, if there is no cached result, cache the result.
     698
     699
     700def xi_degrees(n,p=2):
     701    r"""
     702    Decreasing list of degrees of the xi_i's, starting in degree n.
     703
     704    INPUT:
     705        n -- integer
     706
     707    OUTPUT:
     708        list -- list of integers
     709
     710    When p=2: decreasing list of the degrees of the $\xi_i$'s with
     711    degree at most n.
     712   
     713    At odd primes: decreasing list of these degrees, each divided
     714    by 2(p-1).
     715
     716    EXAMPLES:
     717        sage: sage.algebras.steenrod_algebra_bases.xi_degrees(17)
     718        [15, 7, 3, 1]
     719        sage: sage.algebras.steenrod_algebra_bases.xi_degrees(17,p=3)
     720        [13, 4, 1]
     721        sage: sage.algebras.steenrod_algebra_bases.xi_degrees(400,p=17)
     722        [307, 18, 1]
     723    """
     724    result = []
     725    deg = 1
     726    while deg <= n:
     727        result.insert(0,deg)
     728        deg = p*deg + 1
     729    return result
     730
     731
     732def milnor_basis(n, p=2):
     733    r"""
     734    Milnor basis in dimension $n$.
     735
     736    INPUT:
     737        n -- non-negative integer
     738        p -- positive prime number (optional, default 2)
     739
     740    OUTPUT:
     741        tuple of mod p Milnor basis elements in dimension n
     742
     743    At the prime 2, the Milnor basis consists of symbols of the form
     744    $\text{Sq}(m_1, m_2, ..., m_t)$, where each $m_i$ is a
     745    non-negative integer and if $t>1$, then $m_t \neq 0$.
     746    At odd primes, it consists of symbols of the form
     747    $Q_{e_1} Q_{e_2} ... P(m_1, m_2, ..., m_t)$, where
     748    $0 \leq e_1 < e_2 < ...$, each $m_i$ is a non-negative integer,
     749    and if $t>1$, then $m_t \neq 0$.
     750
     751    EXAMPLES:
     752        sage: from sage.algebras.steenrod_algebra_bases import milnor_basis
     753        sage: milnor_basis(7)
     754        (Sq(0,0,1), Sq(1,2), Sq(4,1), Sq(7))
     755        sage: milnor_basis(7, 2)
     756        (Sq(0,0,1), Sq(1,2), Sq(4,1), Sq(7))
     757        sage: milnor_basis(9, 3)
     758        (Q_1 P(1), Q_0 P(2))
     759        sage: milnor_basis(17, 3)
     760        (Q_2, Q_1 P(3), Q_0 P(0,1), Q_0 P(4))
     761        sage: milnor_basis(48, p=5)
     762        (P(0,1), P(6))
     763        sage: len(milnor_basis(100,3))
     764        13
     765        sage: len(milnor_basis(200,7))
     766        0
     767        sage: len(milnor_basis(240,7))
     768        3
     769    """
     770    if n == 0:
     771        if p == 2:
     772            return (Sq(0),)
     773        else:
     774            return (SteenrodAlgebra(p).P(0),)
     775    else:
     776        result = []
     777        if _steenrod_bases.has_key(('milnor',n,p)):
     778            result = _steenrod_bases[('milnor',n,p)]
     779        else:
     780            if p == 2:
     781                # build basis from partitions of n, with parts taken
     782                # from the list xi_degrees(n)
     783                for sigma in restricted_partitions(n,xi_degrees(n)):
     784                    sigma_exp = list_to_hist(sigma)
     785                    deg = 1
     786                    i = 0
     787                    exponents = []
     788                    while deg <= len(sigma_exp):
     789                        exponents.insert(i,sigma_exp[deg-1])
     790                        deg = 2*deg + 1
     791                        i = i + 1
     792                    result.append(SteenrodAlgebraElement({tuple(exponents): 1}))
     793                    _steenrod_bases[('milnor',n,p)] = tuple(result)
     794            else:  # p odd
     795                # first find the P part of each basis element.
     796                # in this part of the code (the P part), all dimensions are
     797                # divided by 2(p-1).
     798                for dim in range(n/(2*(p-1)) + 1):
     799                    if dim == 0:
     800                        P_result = [[0]]
     801                    else:
     802                        P_result = []
     803                    for sigma in restricted_partitions(dim, xi_degrees(dim,p)):
     804                        sigma_exp = list_to_hist(sigma)
     805                        deg = 1
     806                        i = 0
     807                        p_mono = []
     808                        while deg <= len(sigma_exp):
     809                            p_mono.insert(i, sigma_exp[deg-1])
     810                            deg = p*deg + 1
     811                            i = i + 1
     812                        if len(p_mono) > 0:
     813                            P_result.append(p_mono)
     814                    # now find the Q part of the basis element.
     815                    # dimensions here are back to normal.
     816                    for p_mono in P_result:
     817                        deg = n - 2*dim*(p-1)
     818                        q_degrees = [1+2*(p-1)*d for d in
     819                                     xi_degrees((deg - 1)/(2*(p-1)), p)] + [1]
     820                        q_degrees_decrease = q_degrees
     821                        q_degrees.reverse()
     822                        if deg % (2*(p-1)) <= len(q_degrees):
     823                            # if this inequality fails, no way to have a partition
     824                            # with distinct parts.
     825                            for sigma in restricted_partitions(deg,
     826                                                               q_degrees_decrease,
     827                                                               no_repeats = True):
     828                                index = 0
     829                                q_mono = []
     830                                for q in q_degrees:
     831                                    if q in sigma:
     832                                        q_mono.append(index)
     833                                    index += 1
     834                                result.append(SteenrodAlgebraElement(
     835                                        {(tuple(q_mono), tuple(p_mono)): 1}, p))
     836                _steenrod_bases[('milnor',n,p)] = tuple(result)
     837        return tuple(result)
     838
     839
     840def serre_cartan_basis(n, p=2, bound=1):
     841    r"""
     842    Serre-Cartan basis in dimension $n$.
     843
     844    INPUT:
     845        n -- non-negative integer
     846        bound -- positive integer (optional)
     847        prime -- positive prime number (optional, default 2)
     848
     849    OUTPUT:
     850        tuple of mod p Serre-Cartan basis elements in dimension n
     851
     852    The Serre-Cartan basis consists of 'admissible monomials in the
     853    Steenrod squares'.  Thus at the prime 2, it consists of monomials
     854    $\text{Sq}^{m_1} \text{Sq}^{m_2} ... \text{Sq}^{m_t}$ with $m_i
     855    \geq 2m_{i+1}$ for each $i$.  At odd primes, it consists of
     856    monomials $\beta^{e_0} P^{s_1} \beta^{e_1} P^{s_2} ...  P^{s_k}
     857    \beta^{e_k}$ with each $e_i$ either 0 or 1, $s_i \geq p s_{i+1} +
     858    e_i$, and $s_k \geq 1$.
     859
     860    EXAMPLES:
     861        sage: from sage.algebras.steenrod_algebra_bases import serre_cartan_basis
     862        sage: serre_cartan_basis(7)
     863        (Sq^{7}, Sq^{6} Sq^{1}, Sq^{4} Sq^{2} Sq^{1}, Sq^{5} Sq^{2})
     864        sage: serre_cartan_basis(13,3)
     865        (beta P^{3}, P^{3} beta)
     866        sage: serre_cartan_basis(50,5)
     867        (beta P^{5} P^{1} beta, beta P^{6} beta)
     868
     869    If optional argument bound is present, include only those
     870    monomials whose last term is at least bound (when p=2), or those
     871    for which $s_k - epsilon_k >= bound$ (when p is odd).
     872        sage: serre_cartan_basis(7, bound=2)
     873        (Sq^{7}, Sq^{5} Sq^{2})
     874        sage: serre_cartan_basis(13, 3, bound=3)
     875        (beta P^{3},)
     876    """
     877    if not (isinstance(bound, (Integer, int)) and bound >= 1):
     878        raise ValueError, "%s is not a positive integer." % bound
     879    A = SteenrodAlgebra(p, 'serre-cartan')
     880    if n == 0:
     881        if p == 2:
     882            return (Sq(0),)
     883        else:
     884            return (A.P(0),)
     885    else:
     886        if _steenrod_bases.has_key(('serre-cartan',n,p)):
     887            result = []
     888            lookup = _steenrod_bases[('serre-cartan',n,p)]
     889            for vec in lookup:
     890                for mono in vec._basis_dictionary('serre-cartan'):
     891                    if (bound == 1) or \
     892                            (p == 2 and mono[-1] >= bound) or \
     893                            (p > 2 and (len(mono)<2 or mono[-2] - mono[-1] >= bound)):
     894                        result.append(vec)
     895        else:
     896            if p == 2:
     897                # Build basis recursively.  last = last term.
     898                # last is >= bound, and we will append (last,) to the end of
     899                # elements from serre_cartan_basis (n - last, bound=2 * last).
     900                # This means that 2 last <= n - last, or 3 last <= n.
     901                result = [A(Sq(n))]
     902                for last in range(bound, 1+n/3):
     903                    for vec in serre_cartan_basis(n - last, bound = 2*last):
     904                        new = vec * Sq(last)
     905                        for m in vec._basis_dictionary('serre-cartan'):
     906                            sc_mono = m
     907                        new._raw['serre-cartan'] = {sc_mono + (last,): 1}
     908                        result.append(A(new))
     909                if bound == 1: _steenrod_bases[('serre-cartan',n,p)] = tuple(result)
     910            else: # p odd
     911                if n % (2 * (p-1)) == 0 and n/(2 * (p-1)) >= bound:
     912                    a = A.P(int(n/(2 * (p-1))))
     913                    a._raw['serre-cartan'] = {(0,int(n/(2 * (p-1))),0): 1}
     914                    result = [a]
     915                elif n == 1:
     916                    a = A.Q(0)
     917                    a._raw['serre-cartan'] = {(1,): 1}
     918                    result = [a]
     919                else:
     920                    result = []
     921                # 2 cases: append P^{last}, or append P^{last} beta
     922                # case 1: append P^{last}
     923                for last in range(bound, 1+n/(2*(p - 1))):
     924                    if n - 2*(p-1)*last > 0:
     925                        for vec in serre_cartan_basis(n - 2*(p-1)*last,
     926                                                      p, p*last):
     927                            new = vec * A.P(last,)
     928                            for m in vec._basis_dictionary('serre-cartan'):
     929                                sc_mono = m
     930                            new._raw['serre-cartan'] = {sc_mono + (last,0): 1}
     931                            result.append(A(new))
     932                # case 2: append P^{last} beta
     933                if bound == 1:
     934                    bound = 0
     935                for last in range(bound+1, 1+n/(2*(p - 1))):
     936                    basis = serre_cartan_basis(n - 2*(p-1)*last - 1,
     937                                               p, p*last)
     938                    for vec in basis:
     939                        if vec == 1:
     940                            vec._raw['serre-cartan'] = {(0,): 1}
     941                        new = vec * A.P(last,) * A.Q(0)
     942                        for m in vec._basis_dictionary('serre-cartan'):
     943                            sc_mono = m
     944                        new._raw['serre-cartan'] = {sc_mono + (last,1): 1}
     945                        result.append(A(new))
     946                if bound <= 1: _steenrod_bases[('serre-cartan',n,p)] = tuple(result)
     947        return tuple(result)
     948
     949
     950def atomic_basis(n, basis, long=False):
     951    r"""
     952    Basis for dimension $n$ made of elements in 'atomic' degrees:
     953    degrees of the form $2^i (2^j - 1)$.
     954
     955    INPUT:
     956        n -- non-negative integer
     957        basis -- string, the name of the basis
     958
     959    OUTPUT:
     960        tuple of basis elements in dimension n
     961
     962    The atomic bases include Wood's Y and Z bases, Wall's basis,
     963    Arnon's A basis, the $P^s_t$-bases, and the commutator bases.
     964    (All of these bases are constructed similarly, hence their
     965    constructions have been consolidated into a single function.
     966    Also, See the documentation for 'steenrod_algebra_basis' for
     967    descriptions of them.)
     968
     969    EXAMPLES:
     970        sage: from sage.algebras.steenrod_algebra_bases import atomic_basis
     971        sage: atomic_basis(6,'woody')
     972        (Sq^{2} Sq^{3} Sq^{1}, Sq^{4} Sq^{2}, Sq^{6})
     973        sage: atomic_basis(8,'woodz')
     974        (Sq^{4} Sq^{3} Sq^{1}, Sq^{7} Sq^{1}, Sq^{6} Sq^{2}, Sq^{8})
     975        sage: atomic_basis(6,'woodz') == atomic_basis(6, 'woody')
     976        True
     977        sage: atomic_basis(9,'woodz') == atomic_basis(9, 'woody')
     978        False
     979
     980    Wall's basis:
     981        sage: atomic_basis(6,'wall')
     982        (Q^{1}_{1} Q^{1}_{0} Q^{0}_{0}, Q^{2}_{2} Q^{1}_{1}, Q^{2}_{1})
     983
     984    Elements of the Wall basis have an alternate, 'long'
     985    representation as monomials in the $\text{Sq}^{2^n}$s:   
     986        sage: atomic_basis(6, 'wall', long=True)
     987        (Sq^{2} Sq^{1} Sq^{2} Sq^{1}, Sq^{4} Sq^{2}, Sq^{2} Sq^{4})
     988
     989    Arnon's A basis:
     990        sage: atomic_basis(7,'arnona')
     991        (X^{0}_{0} X^{1}_{1} X^{2}_{2},
     992        X^{0}_{0} X^{2}_{1},
     993        X^{1}_{0} X^{2}_{2},
     994        X^{2}_{0})
     995
     996    These also have a 'long' representation:
     997        sage: atomic_basis(7,'arnona',long=True)
     998        (Sq^{1} Sq^{2} Sq^{4},
     999        Sq^{1} Sq^{4} Sq^{2},
     1000        Sq^{2} Sq^{1} Sq^{4},
     1001        Sq^{4} Sq^{2} Sq^{1})
     1002
     1003    $P^s_t$-bases:
     1004        sage: atomic_basis(7,'pst_rlex')
     1005        (P^{0}_{1} P^{1}_{1} P^{2}_{1},
     1006        P^{0}_{1} P^{1}_{2},
     1007        P^{2}_{1} P^{0}_{2},
     1008        P^{0}_{3})
     1009        sage: atomic_basis(7,'pst_llex')
     1010        (P^{0}_{1} P^{1}_{1} P^{2}_{1},
     1011        P^{0}_{1} P^{1}_{2},
     1012        P^{0}_{2} P^{2}_{1},
     1013        P^{0}_{3})
     1014        sage: atomic_basis(7,'pst_deg')
     1015        (P^{0}_{1} P^{1}_{1} P^{2}_{1},
     1016        P^{0}_{1} P^{1}_{2},
     1017        P^{0}_{2} P^{2}_{1},
     1018        P^{0}_{3})
     1019        sage: atomic_basis(7,'pst_revz')
     1020        (P^{0}_{1} P^{1}_{1} P^{2}_{1},
     1021        P^{0}_{1} P^{1}_{2},
     1022        P^{0}_{2} P^{2}_{1},
     1023        P^{0}_{3})
     1024
     1025    Commutator bases:
     1026        sage: atomic_basis(7,'comm_rlex')
     1027        (c_{0,1} c_{1,1} c_{2,1}, c_{0,1} c_{1,2}, c_{2,1} c_{0,2}, c_{0,3})
     1028        sage: atomic_basis(7,'comm_llex')
     1029        (c_{0,1} c_{1,1} c_{2,1}, c_{0,1} c_{1,2}, c_{0,2} c_{2,1}, c_{0,3})
     1030        sage: atomic_basis(7,'comm_deg')
     1031        (c_{0,1} c_{1,1} c_{2,1}, c_{0,1} c_{1,2}, c_{0,2} c_{2,1}, c_{0,3})
     1032        sage: atomic_basis(7,'comm_revz')
     1033        (c_{0,1} c_{1,1} c_{2,1}, c_{0,1} c_{1,2}, c_{0,2} c_{2,1}, c_{0,3})
     1034
     1035    Long representations of commutator bases:
     1036        sage: atomic_basis(7,'comm_revz', long=True)
     1037        (s_{1} s_{2} s_{4}, s_{1} s_{24}, s_{12} s_{4}, s_{124})
     1038    """
     1039    def degree_dictionary(n, basis):
     1040        """
     1041        Dictionary of atomic degrees for basis up to degree n.
     1042
     1043        The keys for the dictionary are the atomic degrees -- the
     1044        numbers of the form 2^i (2^j - 1) -- which are less than or
     1045        equal to n.  The value associated to such a degree depends on
     1046        basis; it has the form ((s,t), x), where (s,t) is a pair of
     1047        integers which indexes the corresponding element, and x is the
     1048        element in the Milnor basis.
     1049        """
     1050        dict = {}
     1051        if basis.find('wood') >= 0:
     1052            k=0
     1053            m=0
     1054            deg = 2**m * (2**(k+1) - 1)
     1055            while deg <= n:
     1056                dict[deg] = ((m,k), Sq(deg))
     1057                if m>0:
     1058                    m = m - 1
     1059                    k = k + 1
     1060                else:
     1061                    m = k + 1
     1062                    k = 0
     1063                deg = 2**m * (2**(k+1) - 1)
     1064        elif basis.find('wall') >= 0 or basis.find('arnon') >= 0:
     1065            k=0
     1066            m=0
     1067            deg = 2**k * (2**(m-k+1) - 1)
     1068            while deg <= n:
     1069                dict[deg] = ((m,k), Q(m,k,basis))
     1070                if k == 0:
     1071                    m = m + 1
     1072                    k = m
     1073                else:
     1074                    k = k - 1
     1075                deg = 2**k * (2**(m-k+1) - 1)
     1076        elif basis.find('pst') >= 0 or basis.find('comm') >= 0:
     1077            s=0
     1078            t=1
     1079            deg = 2**s * (2**t - 1)
     1080            while deg <= n:
     1081                if basis.find('pst') >= 0:
     1082                    dict[deg] = ((s,t), pst(s,t))
     1083                else:  # comm
     1084                    dict[deg] = ((s,t), commutator(s,t))
     1085                if s == 0:
     1086                    s = t
     1087                    t = 1
     1088                else:
     1089                    s = s - 1
     1090                    t = t + 1
     1091                deg = 2**s * (2**t - 1)
     1092        return dict
     1093   
     1094    def sorting_pair(s,t,basis):   # pair used for sorting the basis
     1095        if basis.find('wood') >= 0 and basis.find('z') >= 0:
     1096            return (-s-t,-s)
     1097        elif basis.find('wood') >= 0 or basis.find('wall') >= 0 or \
     1098                basis.find('arnon') >= 0:
     1099            return (-s,-t)
     1100        elif basis.find('rlex') >= 0:
     1101            return (t,s)
     1102        elif basis.find('llex') >= 0:
     1103            return (s,t)
     1104        elif basis.find('deg') >= 0:
     1105            return (s+t,t)
     1106        elif basis.find('revz') >= 0:
     1107            return (s+t,s)
     1108
     1109    from sage.misc.misc import prod
     1110    if long:
     1111        basis_long_name = basis + "_long"
     1112    else:
     1113        basis_long_name = basis
     1114    A = SteenrodAlgebra(2, basis_long_name)
     1115    if n == 0:
     1116        return (A.Sq(0),)
     1117    else:
     1118        result = []
     1119        if _steenrod_bases.has_key((basis,n)):
     1120            if basis == basis_long_name:
     1121                result = _steenrod_bases[(basis,n)]
     1122            else:
     1123                result = tuple([A(a) for a in _steenrod_bases[(basis,n)]])
     1124        else:
     1125            degrees_etc = degree_dictionary(n, basis)
     1126            degrees = degrees_etc.keys()
     1127            for sigma in restricted_partitions(n, degrees, no_repeats=True):
     1128                big_list = [degrees_etc[part] for part in sigma]
     1129                big_list.sort(key=lambda x: x[0],
     1130                              cmp = lambda x, y: cmp(sorting_pair(x[0], x[1], basis),
     1131                                                     sorting_pair(y[0], y[1], basis)))
     1132                # reverse = True)
     1133                # arnon: sort like wall, then reverse end result
     1134                if basis.find('arnon') >= 0:
     1135                    big_list.reverse()
     1136                list_of_pairs = [d[0] for d in big_list]
     1137                mono_list = [d[1] for d in big_list]
     1138                new = prod(mono_list)
     1139                new._raw[basis] = {tuple(list_of_pairs): 1}
     1140                result.append(A(new))
     1141            _steenrod_bases[(basis,n)] = tuple(result)
     1142        return tuple(result)
     1143
     1144
     1145def Q(m,k,basis):
     1146    r"""
     1147    Compute $Q^m_k$ (Wall basis) and $X^m_k$ (Arnon's A basis).
     1148
     1149    INPUT:
     1150        m,k -- non-negative integers with $m >= k$
     1151        basis -- 'wall' or 'arnona'
     1152       
     1153    OUTPUT:
     1154        element of Steenrod algebra
     1155
     1156    If basis is 'wall', this returns $Q^m_k = Sq(2^k) Sq(2^(k+1))
     1157    ... Sq(2^m)$.  If basis is 'arnona', it returns the reverse of
     1158    this: $X^m_k = Sq(2^m) ... Sq(2^(k+1)) Sq(2^k)$
     1159
     1160    EXAMPLES:
     1161        sage: from sage.algebras.steenrod_algebra_bases import Q
     1162        sage: Q(2,2,'wall')
     1163        Sq(4)
     1164        sage: Q(2,2,'arnona')
     1165        Sq(4)
     1166        sage: Q(3,2,'wall')
     1167        Sq(6,2) + Sq(12)
     1168        sage: Q(3,2,'arnona')
     1169        Sq(0,4) + Sq(3,3) + Sq(6,2) + Sq(12)
     1170    """
     1171    exponent = 2**k
     1172    result = Sq(exponent)
     1173    for i in range(m-k):
     1174        exponent = exponent * 2
     1175        if basis == 'wall':
     1176            result = result * Sq(exponent)
     1177        elif basis == 'arnona':
     1178            result = Sq(exponent) * result
     1179    return result
     1180
     1181
     1182def arnonC_basis(n,bound=1):
     1183    r"""
     1184    Arnon's C basis in dimension $n$.
     1185
     1186    INPUT:
     1187        n -- non-negative integer
     1188        bound -- positive integer (optional)
     1189
     1190    OUTPUT:
     1191        tuple of basis elements in dimension n
     1192
     1193    The elements of Arnon's C basis are monomials of the form
     1194    $\text{Sq}^{t_1} ... \text{Sq}^{t_m}$ where for each $i$, we
     1195    have $t_i \leq 2t_{i+1}$ and $2^i | t_{m-i}$.
     1196
     1197    EXAMPLES:
     1198        sage: from sage.algebras.steenrod_algebra_bases import arnonC_basis
     1199        sage: arnonC_basis(7)
     1200        (Sq^{7}, Sq^{2} Sq^{5}, Sq^{4} Sq^{3}, Sq^{4} Sq^{2} Sq^{1})
     1201
     1202    If optional argument bound is present, include only those
     1203    monomials whose first term is at least as large as bound:
     1204        sage: arnonC_basis(7,3)
     1205        (Sq^{7}, Sq^{4} Sq^{3}, Sq^{4} Sq^{2} Sq^{1})
     1206    """
     1207    if not (isinstance(bound, (Integer, int)) and bound >= 1):
     1208        raise ValueError, "%s is not a positive integer." % bound
     1209    A = SteenrodAlgebra(2, 'arnonc')   
     1210    if n == 0:
     1211        return (A.Sq(0),)
     1212    else:
     1213        if _steenrod_bases.has_key(('arnonc',n)):
     1214            result = []
     1215            lookup = _steenrod_bases[('arnonc',n)]
     1216            for vec in lookup:
     1217                for mono in vec._basis_dictionary('arnonc'):
     1218                    if mono[0] >= bound:
     1219                        result.append(vec)
     1220        else:
     1221            # Build basis recursively.  first = first term.
     1222            # first is >= bound, and we will prepend (first,) to the
     1223            # elements from arnonC_basis (n - first, first / 2).
     1224            # first also must be divisible by 2**(len(old-basis-elt))
     1225            # This means that 3 first <= 2 n.
     1226            result = [A(Sq(n))]
     1227            for first in range(bound,1+2*n/3):
     1228                for vec in arnonC_basis(n - first, max(first/2,1)):
     1229                    if len(vec._basis_dictionary('arnonc')) > 1: print "Error in Arnon's C basis!"
     1230                    for m in vec._basis_dictionary('arnonc'):
     1231                        arnonc_mono = m
     1232                    if first % 2**len(arnonc_mono) == 0:
     1233                        new = Sq(first) * vec
     1234                        new._raw['arnonc'] = {(first,) + arnonc_mono: 1}
     1235                        result.append(A(new))
     1236            if bound == 1: _steenrod_bases[('arnonc',n)] = tuple(result)
     1237        return tuple(result)
     1238
     1239
     1240# cache commutators here:
     1241_commutators = {}   
     1242
     1243def commutator(s,t):
     1244    r"""
     1245    $t$th iterated commutator of consecutive $\text{Sq}^{2^i}$'s.
     1246
     1247    INPUT:
     1248        s, t: integers
     1249       
     1250    OUTPUT:
     1251        element of the Steenrod algebra
     1252
     1253    If t=1, return $Sq(2^s)$.  Otherwise, return the commutator
     1254    $[commutator(s,t-1), \text{Sq}(2^{s+t-1})]$.
     1255
     1256    EXAMPLES:
     1257        sage: from sage.algebras.steenrod_algebra_bases import commutator
     1258        sage: commutator(1,2)
     1259        Sq(0,2)
     1260        sage: commutator(0,4)
     1261        Sq(0,0,0,1)
     1262        sage: commutator(2,2)
     1263        Sq(0,4) + Sq(3,3)
     1264
     1265    NOTES:
     1266        commutator(0,n) is equal to $\text{Sq}(0,...,0,1)$, with the
     1267        1 in the $n$th spot.  commutator(i,n) always has
     1268        $\text{Sq}(0,...,0,2^i)$, with $2^i$ in the $n$th spot, as a
     1269        summand, but there may be other terms, as the example of
     1270        commutator(2,2) illustrates.
     1271
     1272        That is, commutator(s,t) is equal to $P^s_t$, possibly plus
     1273        other Milnor basis elements.
     1274    """
     1275    if _commutators.has_key((s,t)):
     1276        return _commutators[(s,t)]
     1277    if t == 1:
     1278        answer = Sq(2**s)
     1279    else:
     1280        x = commutator(s,t-1)
     1281        y = Sq(2**(s+t-1))
     1282        answer = x*y + y*x
     1283    _commutators[(s,t)] = answer
     1284    return answer
     1285
     1286   
     1287#############################################################################
     1288def steenrod_basis_error_check(dim,p):
     1289    """
     1290    This performs crude error checking.
     1291
     1292    INPUT:
     1293        dim -- non-negative integer
     1294        p -- positive prime number
     1295
     1296    OUTPUT:
     1297        None
     1298
     1299    This checks to see if the different bases have the same length,
     1300    and if the change-of-basis matrices are invertible.  If something
     1301    goes wrong, an error message is printed.
     1302   
     1303    This function checks at the prime p as the dimension goes up from
     1304    0, in which case the basis functions use the saved basis
     1305    computations in lower dimensions in the computations.  It also
     1306    checks as the dimension goes down from the top, in which case it
     1307    doesn't have access to the saved computations.  (The saved
     1308    computations are deleted first: the cache _steenrod_bases is set
     1309    to {} before doing the computations.)
     1310
     1311    EXAMPLES:
     1312        sage: sage.algebras.steenrod_algebra_bases.steenrod_basis_error_check(12,2)
     1313        p=2, in decreasing order of dimension, starting in dimension 12.
     1314        down to dimension  10
     1315        down to dimension  5
     1316        p=2, now in increasing order of dimension, up to dimension 12
     1317        up to dimension  0
     1318        up to dimension  5
     1319        up to dimension  10
     1320        done checking
     1321        sage: sage.algebras.steenrod_algebra_bases.steenrod_basis_error_check(30,3)
     1322        p=3, in decreasing order of dimension, starting in dimension 30.
     1323        down to dimension  30
     1324        down to dimension  25
     1325        down to dimension  20
     1326        down to dimension  15
     1327        down to dimension  10
     1328        down to dimension  5
     1329        p=3, now in increasing order of dimension, up to dimension 30
     1330        up to dimension  0
     1331        up to dimension  5
     1332        up to dimension  10
     1333        up to dimension  15
     1334        up to dimension  20
     1335        up to dimension  25
     1336        done checking
     1337    """
     1338    global _steenrod_bases
     1339   
     1340    _steenrod_bases = {}
     1341
     1342    if p == 2:
     1343        bases = ('adem','woody', 'woodz', 'wall', 'arnona', 'arnonc',
     1344                 'pst_rlex', 'pst_llex', 'pst_deg', 'pst_revz',
     1345                 'comm_rlex', 'comm_llex', 'comm_deg', 'comm_revz')
     1346    else:
     1347        bases = ('adem', 'milnor')
     1348
     1349    print "p=%s, in decreasing order of dimension, starting in dimension %s." % (p, dim)
     1350    for i in range(dim,0,-1):
     1351        if i % 5 == 0: print "down to dimension ", i
     1352        for B in bases:
     1353            if len(steenrod_algebra_basis(i,'milnor')) != len(steenrod_algebra_basis(i,B)):
     1354                print "problem with milnor/" + B + " in dimension ", i
     1355            mat = convert_to_milnor_matrix(i,B,p)
     1356            if mat.nrows() != 0 and not mat.is_invertible():
     1357                print "%s invertibility problem in dim %s at the prime %s" % (B, i, p)
     1358
     1359    _steenrod_bases = {}
     1360
     1361    print "p=%s, now in increasing order of dimension, up to dimension %s" % (p, dim)
     1362    for i in range(dim):
     1363        if i % 5 == 0: print "up to dimension ", i
     1364        for B in bases:
     1365            if len(steenrod_algebra_basis(i,'milnor')) != len(steenrod_algebra_basis(i,B)):
     1366                print "problem with milnor/" + B + " in dimension ", i
     1367            mat = convert_to_milnor_matrix(i,B,p)
     1368            if mat.nrows() != 0 and not mat.is_invertible():
     1369                print "%s invertibility problem in dim %s at the prime %s" % (B, i, p)
     1370
     1371    print "done checking"
  • new file sage/algebras/steenrod_algebra_element.py

    diff -r c25e04ebfb67 -r 9fbc77f226c8 sage/algebras/steenrod_algebra_element.py
    - +  
     1r"""
     2Steenrod algebra elements
     3
     4AUTHORS:
     5    - John H. Palmieri (2008-07-30: version 0.9)
     6
     7This package provides for basic algebra with elements in the mod $p$
     8Steenrod algebra.  In this package, elements in the Steenrod algebra
     9are represented, by default, using the Milnor basis.
     10
     11EXAMPLES:
     12Basic arithmetic, $p=2$.  To construct an element of the mod 2
     13Steenrod algebra, use the function \code{Sq}:
     14    sage: a = Sq(1,2)
     15    sage: b = Sq(4,1)
     16    sage: z = a + b
     17    sage: z
     18    Sq(1,2) + Sq(4,1)
     19    sage: Sq(4) * Sq(1,2)
     20    Sq(1,1,1) + Sq(2,3) + Sq(5,2)
     21    sage: z**2          # non-negative exponents work as they should
     22    Sq(1,2,1) + Sq(4,1,1)
     23    sage: z**0
     24    Sq(0)
     25
     26Basic arithmetic, $p>2$.  To construct an element of the mod $p$
     27Steenrod algebra when $p$ is odd, you should first define a Steenrod
     28algebra, using the \code{SteenrodAlgebra} command:
     29    sage: SteenrodAlgebra()   # 2 is the default prime
     30    mod 2 Steenrod algebra
     31    sage: A3 = SteenrodAlgebra(3)
     32    sage: A3
     33    mod 3 Steenrod algebra
     34
     35Having done this, the newly created algebra \code{A3} has methods
     36\code{Q} and \code{P} which construct elements of \code{A3}:
     37    sage: c = A3.Q(1,3,6); c
     38    Q_1 Q_3 Q_6
     39    sage: d = A3.P(2,0,1); d
     40    P(2,0,1)
     41    sage: c * d
     42    Q_1 Q_3 Q_6 P(2,0,1)
     43    sage: e = A3.P(3)
     44    sage: d * e
     45    P(5,0,1)
     46    sage: e * d
     47    P(1,1,1) + P(5,0,1)
     48    sage: c * c
     49    0
     50    sage: e ** 3
     51    2 P(1,2)
     52
     53Note that one can construct an element like \code{c} above in one step,
     54without first constructing the algebra:
     55    sage: c = SteenrodAlgebra(3).Q(1,3,6)
     56    sage: c
     57    Q_1 Q_3 Q_6
     58
     59And of course, you can do similar constructions with the mod 2
     60Steenrod algebra:
     61    sage: A = SteenrodAlgebra(2); A
     62    mod 2 Steenrod algebra
     63    sage: A.Sq(2,3,5)
     64    Sq(2,3,5)
     65    sage: A.P(2,3,5)   # when p=2, P = Sq
     66    Sq(2,3,5)
     67    sage: A.Q(1,4)     # when p=2, this gives a product of Milnor primitives
     68    Sq(0,1,0,0,1)
     69   
     70Regardless of the prime, each element has an \code{excess}, and if the
     71element is homogeneous, a \code{degree}.  The excess of
     72$\text{Sq}(i_1,i_2,i_3,...)$ is $i_1 + i_2 + i_3 + ...$; when $p$
     73is odd, the excess of $Q_{0}^{e_0} Q_{1}^{e_1}
     74... \mathcal{P}(r_1, r_2, ...)$ is $\sum e_i + 2 \sum r_i$.  The
     75excess of a linear combination of Milnor basis elements is the minimum
     76of the excesses of those basis elements.
     77
     78The degree of $\text{Sq}(i_1,i_2,i_3,...)$ is $sum (2^n-1) i_n$, and
     79when $p$ is odd, the degree of $Q_{0}^{\epsilon_0} Q_{1}^{\epsilon_1}
     80... \mathcal{P}(r_1, r_2, ...)$ is $\sum \epsilon_i (2p^i - 1) + \sum
     81r_j (2p^j - 2)$.  The degree of a linear combination of such terms is
     82only defined if the terms all have the same degree.
     83
     84Here are some simple examples:
     85    sage: z = Sq(1,2) + Sq(4,1)
     86    sage: z.degree()
     87    7
     88    sage: (Sq(0,0,1) + Sq(5,3)).degree()
     89    Element is not homogeneous.
     90    sage: Sq(7,2,1).excess()
     91    10
     92    sage: z.excess()
     93    3
     94    sage: B = SteenrodAlgebra(3)
     95    sage: x = B.Q(1,4)
     96    sage: y = B.P(1,2,3)
     97    sage: x.degree()
     98    166
     99    sage: x.excess()
     100    2
     101    sage: y.excess()
     102    12
     103           
     104Elements have a \code{weight} in the May filtration, which (when $p=2$) is
     105related to the \code{height} function defined by Wall:
     106    sage: Sq(2,1,5).may_weight()
     107    9
     108    sage: Sq(2,1,5).wall_height()
     109    [2, 3, 2, 1, 1]
     110    sage: b = Sq(4)*Sq(8) + Sq(8)*Sq(4)
     111    sage: b.may_weight()
     112    2
     113    sage: b.wall_height()
     114    [0, 0, 1, 1]
     115
     116Odd primary May weights:   
     117    sage: A5 = SteenrodAlgebra(5)
     118    sage: a = A5.Q(1,2,4)
     119    sage: b = A5.P(1,2,1)
     120    sage: a.may_weight()
     121    10
     122    sage: b.may_weight()
     123    8
     124    sage: (a * b).may_weight()
     125    18
     126    sage: A5.P(0,0,1).may_weight()
     127    3
     128
     129Since the Steenrod algebra is a Hopf algebra, every element has an
     130antipode.
     131    sage: d = Sq(0,0,1); d
     132    Sq(0,0,1)
     133    sage: d.antipode()
     134    Sq(0,0,1)
     135    sage: Sq(4).antipode()
     136    Sq(1,1) + Sq(4)
     137    sage: (Sq(4) * Sq(2)).antipode()
     138    Sq(6)
     139    sage: SteenrodAlgebra(7).P(3,1).antipode()
     140    4 P(3,1) + 5 P(11)
     141
     142Applying the antipode twice returns the original element:
     143    sage: y = Sq(8)*Sq(4)
     144    sage: y == (y.antipode()).antipode()
     145    True
     146
     147You can treat elements of the Steenrod algebra like lists of Milnor
     148basis elements:
     149    sage: y = Sq(4) * Sq(1,2); y
     150    Sq(1,1,1) + Sq(2,3) + Sq(5,2)
     151    sage: for m in y: m
     152    Sq(1,1,1)
     153    Sq(2,3)
     154    Sq(5,2)
     155    sage: [(m.degree(),m.excess()) for m in y]
     156    [(11, 3), (11, 5), (11, 7)]
     157
     158Once you've define a Steenrod algebra, the method \code{pst} is another
     159way to define elements of it: \code{pst(s,t)} defines the Margolis element
     160$P^{s}_{t}$, the basis element $\mathcal{P}(0,...,0,p^s)$ with $p^s$
     161in position $t$:
     162    sage: A2 = SteenrodAlgebra(2)
     163    sage: Q2 = A2.pst(0,3)
     164    sage: Q2
     165    Sq(0,0,1)
     166    sage: Q2*Q2
     167    0
     168    sage: A2.pst(1,2) == Sq(2)*Sq(4) + Sq(4)*Sq(2)
     169    True
     170    sage: A5 = SteenrodAlgebra(5)
     171    sage: A5.pst(2,2)
     172    P(0,25)
     173
     174There are a number of different bases available in which to represent
     175elements of the Steenrod algebra.  When $p>2$, the choices are the
     176Milnor basis ('milnor') or the Serre-Cartan basis ('serre-cartan' or
     177'adem' or 'admissible').  When $p=2$, the choices are those, along
     178with Wood's Y basis ('wood_y'), Wood's Z basis ('wood_z'), Wall's
     179basis ('wall' or 'wall_long'), Arnon's A basis ('arnon_a' or
     180'arnon_a_long'), Arnon's C basis ('arnon_c'), various $P^s_t$ bases
     181('pst_ORDER' for various values of ORDER), and various commutator
     182bases ('comm_ORDER' or 'comm_ORDER_long' for various values of ORDER).
     183
     184See documentation for the function \code{steenrod_algebra_basis} for
     185full descriptions of these bases.
     186
     187To access representations of elements with respect to these different
     188bases, you can either use the \code{basis} method for an element, or define
     189a Steenrod algebra with respect to a particular basis and then use that:
     190    sage: c = Sq(2) * Sq(1); c
     191    Sq(0,1) + Sq(3)
     192    sage: c.basis('serre-cartan')
     193    Sq^{2} Sq^{1}
     194    sage: c.basis('milnor')
     195    Sq(0,1) + Sq(3)
     196    sage: adem = SteenrodAlgebra(2, 'serre-cartan')
     197    sage: x = Sq(7,3,1)   # top class in the subalagebra A(2)
     198    sage: adem(x)
     199    Sq^{17} Sq^{5} Sq^{1}
     200    sage: SteenrodAlgebra(2, 'pst')(x)
     201    P^{0}_{1} P^{0}_{2} P^{1}_{1} P^{0}_{3} P^{1}_{2} P^{2}_{1}
     202
     203Multiplication works within bases:
     204    sage: adem = SteenrodAlgebra(2, 'adem')
     205    sage: x = adem.Sq(5)
     206    sage: y = adem.Sq(1)
     207    sage: x * y
     208    Sq^{5} Sq^{1}
     209
     210Multiplying elements defined with respect to two different bases may
     211have unpredictable results (as far as the basis in which the result is
     212printed):
     213    sage: milnor = SteenrodAlgebra(2, 'milnor')
     214    sage: xm = milnor.Sq(5)
     215    sage: ym = milnor.Sq(1)
     216    sage: xm * ym
     217    Sq(3,1)
     218    sage: xm * y
     219    Sq^{5} Sq^{1}
     220    sage: x * ym
     221    Sq^{5} Sq^{1}
     222
     223Several of these bases ('arnon_a', 'wall', 'comm') have alternate,
     224longer, representations.  These provide ways of expressing elements of
     225the Steenrod algebra in terms of the $\text{Sq}^{2^n}$.
     226    sage: Sq(6).basis('arnon_a_long')
     227    Sq^{1} Sq^{2} Sq^{1} Sq^{2} + Sq^{2} Sq^{4}
     228    sage: Sq(6).basis('wall_long')
     229    Sq^{2} Sq^{1} Sq^{2} Sq^{1} + Sq^{2} Sq^{4}
     230    sage: SteenrodAlgebra(2,'comm_deg_long')(Sq(6))
     231    s_{1} s_{2} s_{12} + s_{2} s_{4}
     232
     233**************
     234
     235INTERNAL DOCUMENTATION:
     236
     237Here are details on the class \code{SteenrodAlgebraElement} (for people who
     238want to delve into or extend the code):
     239
     240Attributes for a \code{SteenrodAlgebraElement} self:
     241
     242  \code{self._base_field}: $GF(p)$, where $p$ is the associated prime
     243
     244  \code{self._prime}: $p$
     245 
     246  \code{self._basis}: basis in which to print this element
     247 
     248  \code{self._raw}: dictionary.  keys are basis names, taken from
     249    \code{_steenrod_basis_unique_names}, and the associated values are
     250    dictionaries themselves; if the dictionary is nonempty, it gives
     251    the representation for that element in the given basis.  If it is
     252    empty, that means that the representation in that basis hasn't
     253    been computed yet.  The representation of an element with respect
     254    to a basis (other than the Milnor basis, which is how elements are
     255    stored internally) isn't computed until requested, either by
     256    calling the method \code{_basis_dictionary('basis_name')}, or more
     257    typically, by calling the method \code{basis('basis_name')} or by
     258    defining a Steenrod algebra at that basis and applying its call
     259    method to the element.
     260   
     261    The dictionaries are defined as follows.  In the Milnor basis at
     262    the prime 2, for example, since monomials are of the form
     263    $\text{Sq}(a,b,c,...)$, then monomials are stored as tuples of
     264    integers \code{(a,b,c,...)}.  Thus if $y = \text{Sq}(5,3) +
     265    \text{Sq}(0,0,2)$, then \code{y._raw['milnor']} is \code{\{(0, 0,
     266    2): 1, (5, 3): 1\}}.  (The 1's following the colons are the
     267    coefficients of the monomials associated to the tuples.)  Each
     268    basis has its own representation as a dictionary; Arnon's C basis
     269    represents basis elements as tuples of integers, just like the
     270    Milnor basis and the Serre-Cartan basis, while the other bases
     271    represent basis elements as tuples of pairs of integers.  From the
     272    descriptions of the bases given in the file
     273    'steenrod_algebra_bases.py', it should be clear how to associate a
     274    tuple of pairs of integers to a basis element.  See also the
     275    function \code{string_rep}.
     276
     277    When the element is initially defined by calling \code{Sq} or
     278    \code{SteenrodAlgebraElement}, typically only the 'milnor' dictionary
     279    is non-empty, while if the element is defined by the function
     280    \code{steenrod_algebra_basis}, its dictionary for the given basis is
     281    also initialized correctly.  For example:
     282        sage: B = steenrod_algebra_basis(6,'adem'); B
     283        (Sq^{6}, Sq^{5} Sq^{1}, Sq^{4} Sq^{2})
     284        sage: x = B[1]; x
     285        Sq^{5} Sq^{1}
     286        sage: x._raw
     287        {'milnor': {(3, 1): 1}, 'serre-cartan': {(5, 1): 1}}
     288       
     289    Note that the keys 'milnor' and 'serre-cartan' (a synonym for
     290    'adem') have nonempty associated values.
     291   
     292    When any element is converted to another basis (by changing the
     293    basis and then printing the element), its dictionary for that
     294    basis gets stored, as well:
     295        sage: x.basis('arnona')
     296        X^{0}_{0} X^{1}_{0} X^{1}_{1}
     297        sage: x._raw
     298        {'arnona': {((0, 0), (1, 0), (1, 1)): 1},
     299        'milnor': {(3, 1): 1},
     300        'serre-cartan': {(5, 1): 1}}
     301
     302Methods for a \code{SteenrodAlgebraElement} self:
     303
     304Most of these are self-explanatory.
     305
     306    \code{_mul_}: multiply two elements.  This is done using Milnor
     307    multiplication, the code for which is in a separate file,
     308    'steenrod_milnor_multiplication'.  In a long computation, it seems
     309    that a lot of time is spent here, so one way to speed things up
     310    would be to optimize the Milnor multiplication routine.
     311
     312    \code{_basis_dictionary}: compute the dictionary of the element
     313    with respect to the given basis.  This is basically done by doing
     314    a basis conversion from the Milnor basis to the given basis.
     315    There are two parts to this function; first, some elements (e.g.,
     316    $\text{Sq}(2^n)$) may be easy to convert directly.  This is done
     317    one basis at a time, and so takes up most of the lines of code.
     318    If the element is not recognizable as being easy to convert, then
     319    the function \code{milnor_convert} from the file
     320    'steenrod_algebra_bases.py' is called.  This does linear algebra:
     321    it computes the Milnor basis and the new basis in the appropriate
     322    dimension, computes the change-of-basis matrix, etc.
     323
     324    \code{basis}: display the element in the given basis.
     325
     326    \code{milnor}: display the element in the Milnor basis.
     327
     328    \code{serre_cartan}: display the element in the Serre-Cartan basis.
     329
     330    \code{adem}: display the element in the Serre-Cartan basis.
     331
     332    \code{_repr_} and \code{_latex_} call the function
     333    \code{string_rep}, which has cases depending on the basis.
     334
     335REFERENCES:
     336
     337    [Mil] J. W. Milnor, "The Steenrod algebra and its dual," Ann. of Math.
     338          (2) 67 (1958), 150--171.
     339         
     340    [Mon] K. G. Monks, "Change of basis, monomial relations, and $P^s_t$
     341          bases for the Steenrod algebra," J. Pure Appl. Algebra 125 (1998),
     342          no. 1-3, 235--260.
     343         
     344    [Woo] R. M. W. Wood, "Problems in the Steenrod algebra," Bull. London
     345          Math. Soc. 30 (1998), no. 5, 449--517.
     346"""
     347
     348#*****************************************************************************
     349#       Copyright (C) 2008 John H. Palmieri <palmieri@math.washington.edu>
     350#  Distributed under the terms of the GNU General Public License (GPL)
     351#*****************************************************************************
     352
     353from sage.rings.ring import Algebra
     354from sage.algebras.algebra_element import AlgebraElement
     355from sage.structure.parent_gens import ParentWithGens
     356from sage.structure.element import RingElement
     357from sage.rings.all import GF
     358from sage.misc.functional import parent
     359from sage.rings.integer import Integer
     360
     361def check_and_trim(nums):
     362    """
     363    Check that list or tuple consists of non-negative integers, and
     364    strip trailing zeroes.
     365
     366    INPUT:
     367        nums -- a list or tuple
     368
     369    OUTPUT:
     370        new -- a list or tuple
     371
     372    If nums contains anything other than a non-negative integer, raise
     373    an exception, identifying the right-most problematic entry.
     374    Otherwise, return a new list or tuple, obtained from nums by
     375    omitting any zeroes from the end.
     376       
     377    EXAMPLES:
     378        sage: from sage.algebras.steenrod_algebra_element import check_and_trim
     379        sage: check_and_trim([3,4,1])
     380        [3, 4, 1]
     381        sage: a=[3,2,1,0,0]
     382        sage: check_and_trim(a)
     383        [3, 2, 1]
     384        sage: a    # check_and_trim doesn't affect its input
     385        [3, 2, 1, 0, 0]
     386        sage: check_and_trim([0]*127)
     387        []
     388        sage: check_and_trim((1,2,3,4,0,0,0))  # works on tuples, too
     389        (1, 2, 3, 4)
     390    """
     391    index = len(nums)
     392    for i in range(index-1, -1, -1):
     393        if nums[i] == 0 and i == index - 1:
     394            index = i
     395        if not (isinstance(nums[i], (Integer, int, long)) and nums[i] >= 0):
     396            print type(nums[i])
     397            raise ValueError, "%s is not a non-negative integer" % nums[i]
     398    return nums[:index]
     399
     400
     401def convert_perm(m):
     402    """
     403    Convert tuple m of non-negative integers to a permutation in one-line form.
     404
     405    INPUT:
     406        m -- tuple of non-negative integers with no repetitions
     407    OUTPUT:
     408        list -- conversion of m to a permutation of the set {1,2,...,len(m)}
     409
     410    If m=(3,7,4), then one can view m as representing the permutation
     411    of the set {3,4,7} sending 3 to 3, 4 to 7, and 7 to 4.  This
     412    function converts m to the list [1,3,2], which represents
     413    essentially the same permutation, but of the set {1,2,3}.  This
     414    list can then be passed to Permutation, and its signature can be
     415    computed.
     416
     417    EXAMPLES:
     418        sage: sage.algebras.steenrod_algebra_element.convert_perm((3,7,4))
     419        [1, 3, 2]
     420        sage: sage.algebras.steenrod_algebra_element.convert_perm((5,0,6,3))
     421        [2, 4, 1, 3]
     422    """   
     423    m2 = list(m)
     424    m2.sort()
     425    return [list(m).index(x)+1 for x in m2]
     426
     427
     428def base_p_expansion(n, p):
     429    r"""
     430    Return list of digits in the base p expansion of n.
     431
     432    INPUT:
     433        n -- non-negative integer
     434        p -- positive prime number
     435
     436    OUTPUT:
     437        list of digits in the base p expansion of n
     438
     439    EXAMPLES:
     440        sage: sage.algebras.steenrod_algebra_element.base_p_expansion(10,2)
     441        [0, 1, 0, 1]
     442        sage: sage.algebras.steenrod_algebra_element.base_p_expansion(10,3)
     443        [1, 0, 1]
     444        sage: sage.algebras.steenrod_algebra_element.base_p_expansion(10,5)
     445        [0, 2]
     446        sage: sage.algebras.steenrod_algebra_element.base_p_expansion(10,7)
     447        [3, 1]
     448        sage: sage.algebras.steenrod_algebra_element.base_p_expansion(0,7)
     449        []
     450        sage: sage.algebras.steenrod_algebra_element.base_p_expansion(100000,13)
     451        [4, 9, 6, 6, 3]
     452    """
     453    result = []
     454    while n > 0:
     455        remainder = n % p
     456        result.append(remainder)
     457        n = int((n - remainder)/p)
     458    return result
     459
     460
     461def integer_base_2_log(n):
     462    """
     463    Largest integer k so that $2^k <= n$
     464
     465    INPUT:
     466        n -- positive integer
     467
     468    OUTPUT:
     469        k -- integer
     470
     471    This returns the integer $k$ so that $2^k <= n$ and $2^{k+1} > n$.
     472
     473    EXAMPLES:
     474        sage: sage.algebras.steenrod_algebra_element.integer_base_2_log(7)
     475        2
     476        sage: sage.algebras.steenrod_algebra_element.integer_base_2_log(8)
     477        3
     478        sage: sage.algebras.steenrod_algebra_element.integer_base_2_log(9)
     479        3
     480    """
     481    answer = 0
     482    while 2**(answer+1) <= n:
     483        answer += 1
     484    return answer
     485
     486# These are for internal use only; they are the names used in the code
     487# to represent each basis.
     488_steenrod_basis_unique_names_odd =  ('serre-cartan', 'milnor')
     489_steenrod_basis_unique_names = _steenrod_basis_unique_names_odd + \
     490    ('pst_rlex', 'pst_llex', 'pst_deg', 'pst_revz',
     491     'comm_rlex', 'comm_llex', 'comm_deg', 'comm_revz',
     492     'comm_rlex_long', 'comm_llex_long', 'comm_deg_long', 'comm_revz_long',
     493     'woody', 'woodz', 'arnona', 'arnona_long', 'arnonc', 'wall', 'wall_long')
     494
     495# This dictionary is for caching Steenrod algebras at various primes,
     496# to make sure that SteenrodAlgebraElements defined at the same prime
     497# have the same parent.
     498_steenrod_algebras = {}
     499
     500class SteenrodAlgebraElement(AlgebraElement):
     501    r"""
     502    Element of the mod p Steenrod algebra.
     503
     504    At the prime 2, use the function 'Sq' to define these, as in
     505    'w=Sq(4,3,3)' or 'z=Sq(1,2)+Sq(4,1)' or 'q=Sq(8)*Sq(4) + Sq(12)'.
     506
     507    At odd primes, use the methods 'P' and 'Q' to define these, as
     508    in 'w=SteenrodAlgebra(3).Q(1,5) * SteenrodAlgebra(3).P(4,3)'.
     509
     510    EXAMPLES:
     511        sage: w = Sq(4,3,3)
     512        sage: w
     513        Sq(4,3,3)
     514
     515    The function 'Sq', together with addition, provides an easy way to
     516    define elements when $p=2$:
     517        sage: b = Sq(3) + Sq(0,1)
     518        sage: b
     519        Sq(0,1) + Sq(3)
     520
     521    When $p$ is odd, first define a Steenrod algebra to specify the
     522    prime, and then use the methods 'P' and 'Q', together with
     523    multiplication and addition:
     524        sage: A7 = SteenrodAlgebra(7)
     525        sage: u = A7.Q(0,4); u
     526        Q_0 Q_4
     527        sage: v = A7.P(1,2,3); v
     528        P(1,2,3)
     529        sage: u * v
     530        Q_0 Q_4 P(1,2,3)
     531        sage: 10 * u * v
     532        3 Q_0 Q_4 P(1,2,3)
     533        sage: u + v
     534        P(1,2,3) + Q_0 Q_4
     535    """
     536   
     537    def __init__(self, poly, p=2, basis='milnor'):
     538        r"""
     539        INPUT:
     540            poly -- dictionary with entries of form (monomial: coefficient)
     541            Each coefficient is in GF(p), and each monomial is a tuple
     542            of non-negative integers (a, b, c, ...), corresponding to
     543            the Milnor basis element Sq(a, b, c, ...).
     544
     545            At odd primes, the monomials are pairs of tuples: they are
     546            of the form ((e0, e1, e2, ...), (r1, r2, ...)),
     547            corresponding to the element $Q_{e_0} Q_{e_1} ... P(r_1, r_2, ...)$.
     548
     549            Alternatively, poly can be an integer n, in which case it
     550            is viewed as being in the field GF(p): the resulting
     551            element is n * Sq(0).
     552           
     553            p -- positive prime number (default 2)
     554
     555        OUTPUT:
     556            element of the mod p Steenrod algebra
     557
     558        EXAMPLES:
     559            sage: from sage.algebras.steenrod_algebra_element import SteenrodAlgebraElement
     560            sage: SteenrodAlgebraElement({(1,2,3): 1}, 2)
     561            Sq(1,2,3)
     562            sage: SteenrodAlgebraElement({(1,2,3): 4}, 2)
     563            0
     564            sage: SteenrodAlgebraElement({((0,3), (1,2)): 5}, 7)
     565            5 Q_0 Q_3 P(1,2)
     566            sage: SteenrodAlgebraElement({((0,3), (1,2)): 5}, p=7)
     567            5 Q_0 Q_3 P(1,2)
     568
     569        The input can also be an integer, in which case it is treated
     570        as a multiple, mod p, of the unit element P(0) (a.k.a. Sq(0)
     571        at the prime 2):
     572            sage: SteenrodAlgebraElement(3,2)
     573            Sq(0)
     574            sage: SteenrodAlgebraElement(6)   # p=2 is the default prime
     575            0
     576            sage: SteenrodAlgebraElement(6, p=5)
     577            P(0)
     578        """
     579        from sage.rings.arith import is_prime
     580        from sage.algebras.steenrod_algebra import SteenrodAlgebra
     581        if not is_prime(p):
     582            raise ValueError, "%s is not prime." % p
     583        else:
     584            # get cached Steenrod algebra at the prime p
     585            if _steenrod_algebras.has_key((p,basis)):
     586                alg = _steenrod_algebras[(p,basis)]
     587            else:
     588                _steenrod_algebras[(p,basis)] = SteenrodAlgebra(p,basis)
     589                alg = _steenrod_algebras[(p,basis)]
     590            if isinstance(poly, SteenrodAlgebraElement):
     591                if poly.parent().prime == p:
     592                    self._raw = poly._raw
     593                else:
     594                    raise ValueError, "Mismatch: %s is defined at the prime %s, \
     595not %s" % (poly, poly.parent().prime, p)
     596            # basic initializations:
     597            RingElement.__init__(self, alg)
     598            F = alg.base_ring()
     599            self._base_field = F
     600            self._prime = p
     601            self._basis = basis
     602            # now comes most of the work:
     603            if isinstance(poly, dict):
     604                new_poly = {}
     605                for mono in poly:
     606                    if p == 2:
     607                        # when p=2, mono is a tuple of integers
     608                        trimmed = check_and_trim(mono)
     609                        if new_poly.has_key(trimmed):
     610                            coeff = F(poly[mono] + new_poly[trimmed])
     611                        else:
     612                            coeff = F(poly[mono])
     613                        if not coeff.is_zero():
     614                            new_poly[trimmed] = coeff
     615                    else:
     616                        # when p is odd, mono is either an empty tuple
     617                        # or a pair of tuples
     618                        if len(mono) == 0:
     619                            if new_poly.has_key(mono):
     620                                coeff = F(poly[mono] + new_poly[mono])
     621                            else:
     622                                coeff = F(poly[mono])
     623                            if not coeff.is_zero():
     624                                new_poly[mono] = coeff
     625                        else:
     626                            # mono is a pair of tuples
     627                            mono1, mono2 = mono
     628                            multiplier = 1
     629                            # see if there are any repetitions in the Q monomial:
     630                            if len(mono1) != len(set(mono1)):
     631                                return self(0)
     632                            # if not, sort them and introduce the correct sign:
     633                            if len(mono1) > 0:
     634                                from sage.combinat.permutation import Permutation
     635                                multiplier = Permutation(
     636                                    convert_perm(mono1)).signature()
     637                                mono1 = tuple(sorted(mono1))
     638                            trimmed2 = check_and_trim(mono2)
     639                            if len(mono1) + len(trimmed2) > 0:
     640                                if new_poly.has_key((mono1,trimmed2)):
     641                                    coeff = F(multiplier * poly[mono] \
     642                                                  + new_poly[(mono1, trimmed2)])
     643                                else:
     644                                    coeff = F(multiplier * poly[mono])
     645                                if not coeff.is_zero():
     646                                    new_poly[(mono1,trimmed2)] = coeff
     647                            else:
     648                                if new_poly.has_key(()):
     649                                    coeff = F(poly[mono] + new_poly[()])
     650                                else:
     651                                    coeff = F(poly[mono])
     652                                if not coeff.is_zero():
     653                                    new_poly[()] = coeff
     654                # now define the _raw attribute: a dictionary keyed by the
     655                # basis names.  set the 'milnor' value to by new_poly
     656                self._raw = {}
     657                self._raw['milnor'] = new_poly
     658            elif isinstance(poly, (Integer, int)) or poly.parent() == F:
     659                # a scalar, i.e., a scalar multiple of Sq(0) or P(0)
     660                if F(poly) != 0:
     661                    new_poly = {(): F(poly)}
     662                else:
     663                    new_poly = {}
     664                self._raw = {}
     665                if p == 2:
     666                    basis_list = _steenrod_basis_unique_names
     667                else:
     668                    basis_list = _steenrod_basis_unique_names_odd
     669                for basis in basis_list:
     670                    self._raw[basis] = new_poly
     671            elif isinstance(poly, SteenrodAlgebraElement):
     672                self._raw = poly._raw
     673            else:
     674                raise ValueError, "%s is not of the correct form" % poly
     675   
     676
     677    def is_unit(self):
     678        """
     679        True if element has a nonzero scalar multiple of P(0) as a
     680        summand, False otherwise.
     681
     682        EXAMPLES:
     683            sage: z = Sq(4,2) + Sq(7,1) + Sq(3,0,1)
     684            sage: z.is_unit()
     685            False
     686            sage: u = 1 + Sq(3,1)
     687            sage: u == Sq(0) + Sq(3,1)
     688            True
     689            sage: u.is_unit()
     690            True
     691            sage: A5 = SteenrodAlgebra(5)
     692            sage: v = A5.P(0)
     693            sage: (v + v + v).is_unit()
     694            True
     695        """
     696        if self._raw['milnor'].has_key(()):
     697            return True
     698        else:
     699            return False
     700
     701    def is_nilpotent(self):
     702        """
     703        True if element is not a unit, False otherwise.
     704
     705        EXAMPLES:
     706            sage: z = Sq(4,2) + Sq(7,1) + Sq(3,0,1)
     707            sage: z.is_nilpotent()
     708            True
     709            sage: u = 1 + Sq(3,1)
     710            sage: u == Sq(0) + Sq(3,1)
     711            True
     712            sage: u.is_nilpotent()
     713            False
     714        """
     715        return not self.is_unit()
     716
     717
     718    def _add_(self, other):
     719        """
     720        Addition for elements of the Steenrod algebra.
     721
     722        EXAMPLES:
     723            sage: a = Sq(3,1) + Sq(6)
     724            sage: b = Sq(0,2)
     725            sage: c = Sq(6) + Sq(0,2)
     726            sage: a + b
     727            Sq(0,2) + Sq(3,1) + Sq(6)
     728            sage: b + c
     729            Sq(6)
     730            sage: A7 = SteenrodAlgebra(7)
     731            sage: x = A7.P(1,2); y = A7.Q(3,4) * A7.P(1,2)
     732            sage: x + 3 * y
     733            P(1,2) + 3 Q_3 Q_4 P(1,2)
     734            sage: x + 10 * y
     735            P(1,2) + 3 Q_3 Q_4 P(1,2)
     736        """
     737        F = self._base_field
     738        poly1 = self._raw['milnor']
     739        poly2 = other._raw['milnor']
     740        result = poly1.copy()
     741        for mono in poly2:
     742            if result.has_key(mono):
     743                coeff = F(result[mono] + poly2[mono])
     744            else:
     745                coeff = F(poly2[mono])
     746            if coeff == 0:
     747                del result[mono]
     748            else:
     749                result[mono] = coeff
     750        sum = SteenrodAlgebraElement(result, p=self._prime)
     751        return sum
     752
     753
     754    def _neg_(self):
     755        """
     756        Multiply every coefficient by the element -1 of the base field.
     757
     758        EXAMPLES:
     759            sage: a = Sq(4,2) + Sq(5)
     760            sage: -a
     761            Sq(4,2) + Sq(5)
     762            sage: A5 = SteenrodAlgebra(5)
     763            sage: b = 2 * A5.P(2,0,1)
     764            sage: b
     765            2 P(2,0,1)
     766            sage: -b
     767            3 P(2,0,1)
     768        """
     769        p = self._prime
     770        if p == 2:
     771            return self
     772        else:
     773            F = self._base_field
     774            dict = self._raw['milnor']
     775            for mono in dict:
     776                dict[mono] = F(-dict[mono])
     777            return SteenrodAlgebraElement(dict,p)
     778
     779
     780    def _sub_(self, other):
     781        """
     782        Subtraction for elements of the Steenrod algebra.
     783
     784        EXAMPLES:
     785            sage: A7 = SteenrodAlgebra(7)
     786            sage: A7.P(2,1) - A7.Q(0,3)
     787            P(2,1) + 6 Q_0 Q_3
     788        """
     789        return self._add_(other._neg_())
     790
     791
     792    def _mul_(self, other):
     793        """
     794        Multiplication for elements of the Steenrod algebra.
     795
     796        EXAMPLES:
     797            sage: Sq(2) * Sq(1)
     798            Sq(0,1) + Sq(3)
     799            sage: Sq(0) * (Sq(6,2) + Sq(9,1))
     800            Sq(6,2) + Sq(9,1)
     801            sage: 1 * (Sq(6,2) + Sq(9,1))
     802            Sq(6,2) + Sq(9,1)
     803            sage: 4 * (Sq(6,2) + Sq(9,1))
     804            0
     805            sage: A5 = SteenrodAlgebra(5)
     806            sage: A5.P(5) * A5.P(1,2)
     807            3 P(0,3) + P(6,2)
     808            sage: A5.Q(1,2,3) * A5.Q(0,5)
     809            4 Q_0 Q_1 Q_2 Q_3 Q_5
     810            sage: A5.Q(1,2,3) * A5.Q(0,3)
     811            0
     812        """
     813        from sage.algebras.steenrod_algebra import SteenrodAlgebra
     814        p = self._prime
     815        if p == 2:
     816            from steenrod_milnor_multiplication import milnor_multiplication
     817        else:
     818            from steenrod_milnor_multiplication_odd import milnor_multiplication_odd
     819        F = self._base_field
     820        poly1 = self._raw['milnor']
     821        poly2 = other._raw['milnor']
     822        result = {}
     823        for mono1 in poly1:
     824            for mono2 in poly2:
     825                if len(mono1) == 0:    # multiplying by scalar multiple of one
     826                    if result.has_key(mono2):
     827                        result[mono2] = F(result[mono2] + poly1[mono1]
     828                                          * poly2[mono2])
     829                    else:
     830                        result[mono2] = F(poly1[mono1] * poly2[mono2])
     831                elif len(mono2) == 0:    # multiplying by scalar multiple of one
     832                    if result.has_key(mono1):
     833                        result[mono1] = F(result[mono1] + poly1[mono1]
     834                                          * poly2[mono2])
     835                    else:
     836                        result[mono1] = F(poly1[mono1] * poly2[mono2])
     837                else:
     838                    if p == 2:
     839                        new_dict = milnor_multiplication(mono1, mono2)
     840                    else:
     841                        new_dict = milnor_multiplication_odd(mono1, mono2, p=p)
     842                    for new_mono in new_dict:
     843                        if result.has_key(new_mono):
     844                            result[new_mono] = F(result[new_mono]
     845                                                 + new_dict[new_mono]
     846                                                 * poly1[mono1] * poly2[mono2])
     847                        else:
     848                            result[new_mono] = F(new_dict[new_mono]
     849                                                 * poly1[mono1] * poly2[mono2])
     850        product = SteenrodAlgebraElement(result, p=p)
     851        return SteenrodAlgebra(p, basis=self._basis)(product)
     852
     853
     854    def __cmp__(self,other):
     855        """
     856        Two elements are equal iff their difference is zero.
     857
     858        EXAMPLES:
     859             sage: A5 = SteenrodAlgebra(5)
     860             sage: cmp(A5.P(0,1), A5.P(0,2))
     861             -1
     862             sage: cmp(A5.P(0,1), A5.pst(0,2))
     863             0
     864        """
     865        difference = self - other
     866        if len(difference._raw['milnor']) == 0:
     867            return 0
     868        else:
     869            return -1
     870
     871
     872    def _basis_dictionary(self,basis):
     873        r"""
     874        Dictionary of terms of the form (mono: coeff), where mono
     875        is a monomial in the given basis.
     876
     877        INPUT:
     878            basis -- string, basis in which to work
     879
     880        EXAMPLES:
     881            sage: c = Sq(2) * Sq(1)
     882            sage: c._basis_dictionary('milnor')
     883            {(0, 1): 1, (3,): 1}
     884            sage: c
     885            Sq(0,1) + Sq(3)
     886            sage: c._basis_dictionary('serre-cartan')
     887            {(2, 1): 1}
     888            sage: c.basis('serre-cartan')
     889            Sq^{2} Sq^{1}
     890            sage: d = Sq(0,0,1)
     891            sage: d._basis_dictionary('arnonc')
     892            {(7,): 1, (2, 5): 1, (4, 3): 1, (4, 2, 1): 1}
     893            sage: d.basis('arnonc')
     894            Sq^{2} Sq^{5} + Sq^{4} Sq^{2} Sq^{1} + Sq^{4} Sq^{3} + Sq^{7}
     895
     896        At odd primes:
     897            sage: e = 2 * SteenrodAlgebra(3).P(1,2)
     898            sage: e._basis_dictionary('milnor')
     899            {((), (1, 2)): 2}
     900            sage: e
     901            2 P(1,2)
     902            sage: e._basis_dictionary('serre-cartan')
     903            {(0, 7, 0, 2, 0): 2, (0, 8, 0, 1, 0): 2}
     904            sage: e.basis('adem')
     905            2 P^{7} P^{2} + 2 P^{8} P^{1}
     906
     907        Implementation: to compute this, take the Milnor representation
     908        and change bases.  Store the result in self._raw[basis], for later
     909        use; this way, an element only needs to be converted once.
     910        """
     911        def is_power_of_two(n):
     912            """
     913            True if and only n is a power of 2
     914            """
     915            while n != 0 and n%2 == 0:
     916                n = n >> 1
     917            return n == 1
     918
     919        from steenrod_algebra import _steenrod_serre_cartan_basis_names, \
     920            _steenrod_milnor_basis_names, get_basis_name
     921        from steenrod_algebra_bases import milnor_convert
     922
     923        p = self._prime
     924        basis_name = get_basis_name(basis, p)
     925        if basis_name == 'milnor':
     926            return self._raw['milnor']
     927
     928        if basis_name.find('long') >= 0:
     929            basis_name = basis_name.rsplit('_', 1)[0]
     930
     931        if self._raw.has_key(basis_name) and len(self._raw[basis_name])>0:
     932            return self._raw[basis_name]
     933        elif p == 2:
     934            dict = {}
     935            for mono in self._raw['milnor']:
     936                converted = False
     937                if dict.has_key(mono):
     938                    old_coeff = dict[mono]
     939                else:
     940                    old_coeff = 0
     941                new_coeff = old_coeff + self._raw['milnor'][mono]
     942                if len(mono) == 0:   # length 0: no conversion
     943                    if new_coeff != 0:
     944                        dict[mono] = new_coeff
     945                    else:
     946                        del dict[mono]
     947                    converted = True
     948                elif basis_name == 'serre-cartan':
     949                    if len(mono) == 1:   # length 1: Sq(n) = Sq^{n}, so no conversion
     950                        if dict.has_key(mono):
     951                            new_coeff = dict[mono] + self._raw['milnor'][mono]
     952                            if new_coeff != 0:
     953                                dict[mono] = new_coeff
     954                            else:
     955                                del dict[mono]
     956                        else:
     957                            dict[mono] = self._raw['milnor'][mono]
     958                        converted = True
     959                elif basis_name == 'woody':
     960                    if len(mono) == 1 and is_power_of_two(mono[0]):   # no conversion
     961                        if new_coeff != 0:
     962                            dict[((integer_base_2_log(mono[0]),0),)] = new_coeff
     963                        else:
     964                            del dict[((integer_base_2_log(mono[0]),0),)]
     965                        converted = True
     966                elif basis_name == 'woodz':
     967                    if len(mono) == 1 and is_power_of_two(mono[0]):   # no conversion
     968                        if new_coeff != 0:
     969                            dict[((integer_base_2_log(mono[0]),0),)] = new_coeff
     970                        else:
     971                            del dict[((integer_base_2_log(mono[0]),0),)]
     972                        converted = True
     973                elif basis_name == 'wall':
     974                    if len(mono) == 1 and is_power_of_two(mono[0]):   # no conversion
     975                        m = integer_base_2_log(mono[0])
     976                        if new_coeff != 0:
     977                            dict[((m,m),)] = new_coeff
     978                        else:
     979                            del dict[((m,m),)]
     980                        converted = True
     981                elif basis_name == 'arnona':
     982                    if len(mono) == 1 and is_power_of_two(mono[0]):   # no conversion
     983                        m = integer_base_2_log(mono[0])
     984                        if new_coeff != 0:
     985                            dict[((m,m),)] = new_coeff
     986                        else:
     987                            del dict[((m,m),)]
     988                        converted = True
     989                elif basis_name == 'arnonc':
     990                    if len(mono) == 1:   # no conversion
     991                        if dict.has_key(mono):
     992                            new_coeff = dict[mono] + self._raw['milnor'][mono]
     993                            if new_coeff != 0:
     994                                dict[mono] = new_coeff
     995                            else:
     996                                del dict[mono]
     997                        else:
     998                            dict[mono] = self._raw['milnor'][mono]
     999                        converted = True
     1000                if not converted:
     1001                    conversion = milnor_convert(  # conversion required
     1002                        SteenrodAlgebraElement({mono: 1}),
     1003                        basis)
     1004                    for new_mono in conversion:
     1005                        if dict.has_key(new_mono):
     1006                            new_coeff = dict[new_mono] + conversion[new_mono]
     1007                            if new_coeff != 0:
     1008                                dict[new_mono] = new_coeff
     1009                            else:
     1010                                del dict[new_mono]
     1011                        else:
     1012                            dict[new_mono] = conversion[new_mono]
     1013            self._raw[basis] = dict
     1014            return dict
     1015        else:  # p odd
     1016            dict = {}
     1017            for mono in self._raw['milnor']:
     1018                converted = False
     1019                if dict.has_key(mono):
     1020                    old_coeff = dict[mono]
     1021                else:
     1022                    old_coeff = 0
     1023                new_coeff = old_coeff + self._raw['milnor'][mono]
     1024                if len(mono) == 0:   # length 0: no conversion
     1025                    if new_coeff != 0:
     1026                        dict[mono] = new_coeff
     1027                    else:
     1028                        del dict[mono]
     1029                    converted = True
     1030                elif basis in _steenrod_serre_cartan_basis_names:
     1031                    if len(mono[0]) == 0 and len(mono[1]) == 1:
     1032                        # length 1: Sq(n) = Sq^{n}, so no conversion
     1033                        new_mono = (0,mono[1][0], 0)
     1034                        if dict.has_key(new_mono):
     1035                            new_coeff = dict[new_mono] + self._raw['milnor'][mono]
     1036                            if new_coeff != 0:
     1037                                dict[new_mono] = new_coeff
     1038                            else:
     1039                                del dict[new_mono]
     1040                        else:
     1041                            dict[new_mono] = self._raw['milnor'][mono]
     1042                        converted = True
     1043                if not converted:
     1044                    conversion = milnor_convert(  # conversion required
     1045                        SteenrodAlgebraElement({mono: self._raw['milnor'][mono]},
     1046                                               p),
     1047                        basis)
     1048                    for new_mono in conversion:
     1049                        if dict.has_key(new_mono):
     1050                            new_coeff = dict[new_mono] + conversion[new_mono]
     1051                            if new_coeff != 0:
     1052                                dict[new_mono] = new_coeff
     1053                            else:
     1054                                del dict[new_mono]
     1055                        else:
     1056                            dict[new_mono] = conversion[new_mono]
     1057            self._raw[basis] = dict
     1058            return dict
     1059
     1060
     1061    def basis(self,basis):
     1062        r"""
     1063        Representation of element with respect to basis.
     1064
     1065        INPUT:
     1066            basis -- string, basis in which to work.
     1067
     1068        OUTPUT:
     1069            Representation of self in given basis
     1070
     1071        The choices for basis are:
     1072       
     1073          * 'milnor' for the Milnor basis.
     1074           
     1075          * 'serre-cartan', 'serre_cartan', 'sc', 'adem', 'admissible' for
     1076                the Serre-Cartan basis.
     1077               
     1078          * 'wood_y' for Wood's Y basis.
     1079           
     1080          * 'wood_z' for Wood's Z basis.
     1081           
     1082          * 'wall' for Wall's basis.
     1083           
     1084          * 'wall_long' for Wall's basis, alternate representation
     1085           
     1086          * 'arnon_a' for Arnon's A basis.
     1087           
     1088          * 'arnon_a_long' for Arnon's A basis, alternate representation.
     1089           
     1090          * 'arnon_c' for Arnon's C basis.
     1091           
     1092          * 'pst', 'pst_rlex', 'pst_llex', 'pst_deg', 'pst_revz' for various
     1093                $P^s_t$-bases.
     1094               
     1095          * 'comm', 'comm_rlex', 'comm_llex', 'comm_deg', 'comm_revz' for
     1096                various commutator bases.
     1097               
     1098          * 'comm_long', 'comm_rlex_long', etc., for commutator bases, alternate
     1099                representations.
     1100
     1101        See documentation for the function 'steenrod_algebra_basis' for
     1102        descriptions of the different bases.
     1103
     1104        EXAMPLES:
     1105            sage: c = Sq(2) * Sq(1)
     1106            sage: c.basis('milnor')
     1107            Sq(0,1) + Sq(3)
     1108            sage: c.basis('serre-cartan')
     1109            Sq^{2} Sq^{1}
     1110            sage: d = Sq(0,0,1)
     1111            sage: d.basis('arnonc')
     1112            Sq^{2} Sq^{5} + Sq^{4} Sq^{2} Sq^{1} + Sq^{4} Sq^{3} + Sq^{7}
     1113        """
     1114        from sage.algebras.steenrod_algebra import SteenrodAlgebra
     1115        return SteenrodAlgebra(p=self._prime, basis=basis)(self)
     1116
     1117
     1118    def milnor(self):
     1119        r"""
     1120        Milnor representation of self.
     1121       
     1122        OUTPUT:
     1123            Milnor representation of self.
     1124
     1125        EXAMPLES:
     1126            sage: A = SteenrodAlgebra(2, 'adem')
     1127            sage: x = A (Sq(5) * Sq(2) * Sq(1)); x
     1128            Sq^{5} Sq^{2} Sq^{1}
     1129            sage: x.milnor()
     1130            Sq(1,0,1) + Sq(5,1)
     1131            """
     1132        return self.basis('milnor')
     1133
     1134
     1135    def serre_cartan(self):
     1136        r"""
     1137        Serre-Cartan representation of self.
     1138       
     1139        OUTPUT:
     1140            Serre-Cartan representation of self.
     1141
     1142        EXAMPLES:
     1143            sage: x = Sq(0,1); x
     1144            Sq(0,1)
     1145            sage: x.serre_cartan()
     1146            Sq^{2} Sq^{1} + Sq^{3}
     1147            sage: x.adem()  # 'adem' is a synomym for 'serre_cartan'
     1148            Sq^{2} Sq^{1} + Sq^{3}
     1149            """
     1150        return self.basis('serre-cartan')
     1151
     1152
     1153    adem = serre_cartan
     1154
     1155
     1156    def degree(self):
     1157        r"""
     1158        Degree of element.
     1159
     1160        OUTPUT:
     1161            degree -- None, or non-negative integer
     1162
     1163        The degree of $\text{Sq}(i_1,i_2,i_3,...)$ is
     1164        $i_1 + 3 i_2 + 7 i_3 + ... + (2^n - 1) i_n + ...$.
     1165        When $p$ is odd, the degree of
     1166        $Q_{0}^{e_0} Q_{1}^{e_1} ... P(r_1, r_2, ...)$
     1167        is $\sum e_i (2p^i - 1) + \sum r_j (2p^j - 2)$.
     1168       
     1169        The degree of a sum is undefined (and this returns 'None'),
     1170        unless each summand has the same degree: that is, unless the
     1171        element is homogeneous.
     1172
     1173        EXAMPLES:
     1174            sage: a = Sq(1,2,1)
     1175            sage: a.degree()
     1176            14
     1177            sage: for a in Sq(3) + Sq(5,1): a.degree()
     1178            3
     1179            8
     1180            sage: (Sq(3) + Sq(5,1)).degree()
     1181            Element is not homogeneous.
     1182            sage: B = SteenrodAlgebra(3)
     1183            sage: x = B.Q(1,4)
     1184            sage: y = B.P(1,2,3)
     1185            sage: x.degree()
     1186            166
     1187            sage: y.degree()
     1188            192
     1189        """
     1190        def p_degree(m, mult=1, prime=2):
     1191            """
     1192            For m=(n_1, n_2, n_3, ...), Sum_i 2*n_i*(p^i - 1)
     1193            """
     1194            i = 0
     1195            deg = 0
     1196            for n in m:
     1197                i += 1
     1198                deg += n*mult*(prime**i - 1)
     1199            return deg
     1200       
     1201        def q_degree(m, prime=3):
     1202            """
     1203            For m=(n_0, n_1, n_2, ...), Sum_i 2*p^{n_i} - 1
     1204            """
     1205            deg = 0
     1206            for n in m:
     1207                deg += 2*prime**n - 1
     1208            return deg
     1209       
     1210        p = self._prime
     1211        if p == 2:
     1212            degrees = [p_degree(mono) for mono in self._raw['milnor']]
     1213        else:
     1214            degrees = [q_degree(mono1, prime=p)
     1215                           + p_degree(mono2, prime=p, mult=2)
     1216                           for (mono1, mono2) in self._raw['milnor']]
     1217        if min(degrees) == max(degrees):
     1218            return min(degrees)
     1219        else:
     1220            print "Element is not homogeneous."
     1221            return None
     1222
     1223
     1224    def excess(self):
     1225        r"""
     1226        Excess of element.
     1227
     1228        OUTPUT:
     1229            excess -- non-negative integer
     1230
     1231        The excess of $\text{Sq}(a,b,c,...)$ is $a + b + c + ...$.
     1232        When $p$ is odd, the excess of $Q_{0}^{e_0}
     1233        Q_{1}^{e_1} ... P(r_1, r_2, ...)$ is $\sum e_i + 2 \sum r_i$.
     1234       
     1235        The excess of a linear combination of Milnor basis elements is
     1236        the minimum of the excesses of those basis elements.
     1237
     1238        See [Kra] for the proofs of these assertions.
     1239
     1240        EXAMPLES:
     1241            sage: a = Sq(1,2,3)
     1242            sage: a.excess()
     1243            6
     1244            sage: (Sq(0,0,1) + Sq(4,1) + Sq(7)).excess()
     1245            1
     1246            sage: [m.excess() for m in (Sq(0,0,1) + Sq(4,1) + Sq(7))]
     1247            [1, 5, 7]
     1248            sage: [m for m in (Sq(0,0,1) + Sq(4,1) + Sq(7))]
     1249            [Sq(0,0,1), Sq(4,1), Sq(7)]
     1250            sage: B = SteenrodAlgebra(7)
     1251            sage: a = B.Q(1,2,5)
     1252            sage: b = B.P(2,2,3)
     1253            sage: a.excess()
     1254            3
     1255            sage: b.excess()
     1256            14
     1257            sage: (a + b).excess()
     1258            3
     1259            sage: (a * b).excess()
     1260            17
     1261
     1262        REFERENCES:
     1263       
     1264            [Kra] D. Kraines, "On excess in the Milnor basis," Bull. London
     1265                Math. Soc. 3 (1971), 363-365.
     1266        """
     1267        def excess_odd(mono):
     1268            """
     1269            Excess of mono, where mono has the form ((s0, s1, ...), (r1, r2, ...)).
     1270
     1271            Returns the length of the first component, since that is
     1272            the number of factors, plus twice the sum of the terms in
     1273            the second component.
     1274            """
     1275            if len(mono) == 0:
     1276                return 0
     1277            else:
     1278                return len(mono[0]) + 2 * sum(mono[1])
     1279           
     1280        p = self._prime
     1281        if p == 2:
     1282            excesses = [sum(mono) for mono in self._raw['milnor']]
     1283        else:
     1284            excesses = [excess_odd(mono) for mono in self._raw['milnor']]
     1285        return min(excesses)
     1286
     1287
     1288    def may_weight(self):
     1289        r"""
     1290        May's 'weight' of element.
     1291
     1292        OUTPUT:
     1293            weight -- non-negative integer
     1294
     1295        If we let $F_* (A)$ be the May filtration of the Steenrod
     1296        algebra, the weight of an element $x$ is the integer $k$ so
     1297        that $x$ is in $F_k(A)$ and not in $F_{k+1}(A)$.  According to
     1298        Theorem 2.6 in May's thesis [May], the weight of a Milnor
     1299        basis element is computed as follows: first, to compute the
     1300        weight of $P(r_1,r2, ...)$, write each $r_i$ in base
     1301        $p$ as $r_i = \sum_j p^j r_{ij}$.  Then each nonzero binary
     1302        digit $r_{ij}$ contributes $i$ to the weight: the weight is
     1303        $\sum_{i,j} i r_{ij}$.  When $p$ is odd, the weight of $Q_i$
     1304        is $i+1$, so the weight of a product $Q_{i_1} Q_{i_2} ...$ is
     1305        equal $(i_1+1) + (i_2+1) + ...$.  Then the weight of $Q_{i_1}
     1306        Q_{i_2} ...P(r_1,r2, ...)$ is the sum of $(i_1+1) +
     1307        (i_2+1) + ...$ and $\sum_{i,j} i r_{ij}$.
     1308       
     1309        The weight of a sum of basis elements is the minimum of the
     1310        weights of the summands.
     1311
     1312        When $p=2$, we compute the weight on Milnor basis elements by
     1313        adding up the terms in their 'height' -- see the method
     1314        'wall_height' for documentation.  (When $p$ is odd, the height
     1315        of an element is not defined.)
     1316
     1317        EXAMPLES:
     1318            sage: Sq(0).may_weight()
     1319            0
     1320            sage: a = Sq(4)
     1321            sage: a.may_weight()
     1322            1
     1323            sage: b = Sq(4)*Sq(8) + Sq(8)*Sq(4)
     1324            sage: b.may_weight()
     1325            2
     1326            sage: Sq(2,1,5).wall_height()
     1327            [2, 3, 2, 1, 1]
     1328            sage: Sq(2,1,5).may_weight()
     1329            9
     1330            sage: A5 = SteenrodAlgebra(5)
     1331            sage: a = A5.Q(1,2,4)
     1332            sage: b = A5.P(1,2,1)
     1333            sage: a.may_weight()
     1334            10
     1335            sage: b.may_weight()
     1336            8
     1337            sage: (a * b).may_weight()
     1338            18
     1339            sage: A5.P(0,0,1).may_weight()
     1340            3
     1341
     1342        REFERENCES:
     1343
     1344            [May]: J. P. May, "The cohomology of restricted Lie algebras
     1345                and of Hopf algebras; application to the Steenrod
     1346                algebra." Thesis, Princeton Univ., 1964.
     1347        """
     1348        from sage.rings.infinity import Infinity
     1349        p = self._prime
     1350        if self == 0:
     1351            return Infinity
     1352        elif self.is_unit():
     1353            return 0
     1354        elif p == 2:
     1355            wt = Infinity
     1356            for mono in self:
     1357                wt = min(wt, sum(mono.wall_height()))
     1358            return wt
     1359        else: # p odd
     1360            wt = Infinity
     1361            for (mono1, mono2) in self._raw['milnor']:
     1362                P_wt = 0
     1363                index = 1
     1364                for n in mono2:
     1365                    P_wt += index * sum(base_p_expansion(n,p))
     1366                    index += 1
     1367                wt = min(wt, sum(mono1) + len(mono1) + P_wt)
     1368            return wt
     1369
     1370
     1371    def is_decomposable(self):
     1372        r"""
     1373        return True if element is decomposable, False otherwise.
     1374
     1375        OUTPUT:
     1376            decomposable -- boolean
     1377
     1378        That is, if element is in the square of the augmentation
     1379        ideal, return True; otherwise, return False.
     1380
     1381        EXAMPLES:
     1382            sage: a = Sq(6)
     1383            sage: a.is_decomposable()
     1384            True
     1385            sage: for i in range(9):
     1386            ...       if not Sq(i).is_decomposable():
     1387            ...           print Sq(i)
     1388            Sq(0)
     1389            Sq(1)
     1390            Sq(2)
     1391            Sq(4)
     1392            Sq(8)
     1393        """
     1394        return self.may_weight() > 1       
     1395
     1396
     1397    def wall_height(self):
     1398        r"""
     1399        Wall's 'height' of element.
     1400
     1401        OUTPUT:
     1402            height -- list of non-negative integers
     1403
     1404        The height of an element of the mod 2 Steenrod algebra is a
     1405        list of non-negative integers, defined as follows: if the
     1406        element is a monomial in the generators $\text{Sq}(2^i)$, then
     1407        the $i$th entry in the list is the number of times
     1408        $\text{Sq}(2^i)$ appears.  For an arbitrary element, write it
     1409        as a sum of such monomials; then its height is the maximum,
     1410        ordered right-lexicographically, of the heights of those
     1411        monomials.
     1412
     1413        When $p$ is odd, the height of an element is not defined.
     1414
     1415        According to Theorem 3 in [Wall], the height of the Milnor
     1416        basis element $\text{Sq}(r_1, r_2, ...)$ is obtained as
     1417        follows: write each $r_i$ in binary as $r_i = \sum_j 2^j r_{ij}$. 
     1418        Then each nonzero binary digit $r_{ij}$ contributes 1 to the
     1419        $k$th entry in the height, for $j \leq k \leq i+j-1$.
     1420
     1421        EXAMPLES:
     1422            sage: Sq(0).wall_height()
     1423            []
     1424            sage: a = Sq(4)
     1425            sage: a.wall_height()
     1426            [0, 0, 1]
     1427            sage: b = Sq(4)*Sq(8) + Sq(8)*Sq(4)
     1428            sage: b.wall_height()
     1429            [0, 0, 1, 1]
     1430            sage: Sq(0,0,3).wall_height()
     1431            [1, 2, 2, 1]
     1432
     1433        REFERENCES:
     1434
     1435            [Wall]: C. T. C. Wall, "Generators and relations for the
     1436                Steenrod algebra," Ann. of Math. (2) \textbf{72} (1960),
     1437                429--444.
     1438        """
     1439        def mono_degree(m):
     1440            """
     1441            If m=(n1,n2,n3, ...), returns the degree of Sq(n1,n2,n3,...).
     1442            That is, it returns sum n_i (2^i - 1).
     1443            """
     1444            i = 0
     1445            deg = 0
     1446            for n in m:
     1447                i += 1
     1448                deg += n*(2**i - 1)
     1449            return deg
     1450
     1451        if self._prime > 2:
     1452            raise NotImplementedError, "Wall height is not defined at odd primes."
     1453        if self == 0 or self == 1:
     1454            return []
     1455        result = []
     1456        for r in self._raw['milnor']:
     1457            h = [0]*(1+mono_degree(r))
     1458            i = 1
     1459            for x in r:
     1460                if x > 0:
     1461                    for j in range(1+integer_base_2_log(x)):
     1462                        if (2**j & x) != 0:
     1463                            for k in range(j,i+j):
     1464                                h[k] += 1
     1465                i=i+1
     1466            h.reverse()
     1467            result = max(h, result)
     1468        result.reverse()
     1469        return check_and_trim(result)
     1470           
     1471
     1472    def antipode(self):
     1473        r"""
     1474        Antipode of element.
     1475
     1476        OUTPUT:
     1477            antipode -- element of the Steenrod algebra
     1478
     1479        Algorithm: according to a result of Milnor's, the antipode of
     1480        $\text{Sq}(n)$ is the sum of all of the Milnor basis elements
     1481        in dimension $n$.  So: convert the element to the Serre-Cartan
     1482        basis and use this formula for the antipode of $\text{Sq}(n)$,
     1483        together with the fact that the antipode is an
     1484        antihomomorphism: if we call the antipode $c$, then $c(ab) =
     1485        c(b) c(a)$.
     1486
     1487        At odd primes, a similar method is used: the antipode of
     1488        $P(n)$ is the sum of the Milnor basis elements in
     1489        dimension $n*2(p-1)$, and the antipode of $\beta = Q_0$ is
     1490        $-Q_0$.  So convert to the Serre-Cartan basis, as in the $p=2$
     1491        case.
     1492
     1493        EXAMPLES:
     1494            sage: d = Sq(0,0,1); d
     1495            Sq(0,0,1)
     1496            sage: d.antipode()
     1497            Sq(0,0,1)
     1498            sage: Sq(4).antipode()
     1499            Sq(1,1) + Sq(4)
     1500            sage: (Sq(4) * Sq(2)).antipode()
     1501            Sq(6)
     1502            sage: A3 = SteenrodAlgebra(3)
     1503            sage: A3.P(2).antipode()
     1504            P(2)
     1505            sage: A3.P(2,1).antipode()
     1506            2 P(2,1)
     1507            sage: a = SteenrodAlgebra(7).P(3,1)
     1508            sage: a.antipode()
     1509            4 P(3,1) + 5 P(11)
     1510
     1511        Applying the antipode twice returns the original element:
     1512            sage: y = Sq(8)*Sq(4)
     1513            sage: y == (y.antipode()).antipode()
     1514            True
     1515        """
     1516        def sum_of_basis(n,p):
     1517            """
     1518            Antipode of P(n) (i.e., of Sq(n) when p=2).
     1519
     1520            INPUT:
     1521                n -- integer
     1522                p -- positive prime number
     1523           
     1524            OUTPUT:
     1525                elt -- element of the Steenrod algebra
     1526
     1527            This returns the sum of all of the elements P(...) in the
     1528            Milnor basis in dimension $n$ at the prime p
     1529            """
     1530            from steenrod_algebra_bases import steenrod_algebra_basis
     1531            return sum(steenrod_algebra_basis(n,'milnor',p=p))
     1532        from sage.algebras.steenrod_algebra import SteenrodAlgebra
     1533        from steenrod_algebra_bases import milnor_convert
     1534        result = 0
     1535        p = self._prime
     1536        if p == 2:
     1537            for mono in self._basis_dictionary('serre_cartan'):
     1538                antipode = Sq(0)
     1539                for n in mono:
     1540                    antipode = sum_of_basis(n, p) * antipode
     1541                result = result + antipode
     1542        else:
     1543            from sage.misc.functional import is_even
     1544            for mono in self._basis_dictionary('serre_cartan'):
     1545                antipode = SteenrodAlgebra(p).P(0)
     1546                index = 0
     1547                for n in mono:
     1548                    if is_even(index) and n != 0:
     1549                        antipode = -SteenrodAlgebra(p).Q(0) * antipode
     1550                    else:
     1551                        antipode = sum_of_basis(n*2*(p-1),p) * antipode
     1552                    index += 1
     1553                result = result + antipode
     1554        return result
     1555
     1556
     1557    def _repr_(self):
     1558        """
     1559        String representation of element.
     1560
     1561        OUTPUT:
     1562            string
     1563
     1564        The string depends on the basis over which the element is defined.
     1565
     1566        EXAMPLES:
     1567            sage: A7 = SteenrodAlgebra(7)
     1568            sage: x = A7.Q(0,3) * A7.P(2,2)
     1569            sage: x._repr_()
     1570            'Q_0 Q_3 P(2,2)'
     1571            sage: x
     1572            Q_0 Q_3 P(2,2)
     1573            sage: a = Sq(0,0,2)
     1574            sage: a
     1575            Sq(0,0,2)
     1576            sage: A2_adem = SteenrodAlgebra(2,'admissible')
     1577            sage: A2_adem(a)
     1578            Sq^{8} Sq^{4} Sq^{2} + Sq^{9} Sq^{4} Sq^{1} + Sq^{10} Sq^{3} Sq^{1} +
     1579            Sq^{10} Sq^{4} + Sq^{11} Sq^{2} Sq^{1} + Sq^{12} Sq^{2} + Sq^{13} Sq^{1}
     1580            + Sq^{14}
     1581            sage: SteenrodAlgebra(2, 'woodz')(a)
     1582            Sq^{6} Sq^{7} Sq^{1} + Sq^{14} + Sq^{4} Sq^{7} Sq^{3} + Sq^{4} Sq^{7}
     1583            Sq^{2} Sq^{1} + Sq^{12} Sq^{2} + Sq^{8} Sq^{6} + Sq^{8} Sq^{4} Sq^{2}
     1584            sage: SteenrodAlgebra(2, 'arnonc')(a)
     1585            Sq^{4} Sq^{2} Sq^{8} + Sq^{4} Sq^{4} Sq^{6} + Sq^{4} Sq^{6} Sq^{4} +
     1586            Sq^{6} Sq^{8} + Sq^{8} Sq^{4} Sq^{2} + Sq^{8} Sq^{6}
     1587            sage: SteenrodAlgebra(2, 'pst_llex')(a)
     1588            P^{1}_{3}
     1589            sage: SteenrodAlgebra(2, 'comm_revz')(a)
     1590            c_{0,1} c_{1,1} c_{0,3} c_{2,1} + c_{0,2} c_{0,3} c_{2,1} + c_{1,3}
     1591        """
     1592        if len(self._raw['milnor']) == 0:
     1593            return "0"
     1594        else:
     1595            return string_rep(self)
     1596
     1597
     1598    def _latex_(self):
     1599        """
     1600        LaTeX representation of element.
     1601       
     1602        OUTPUT:
     1603            string
     1604
     1605        The string depends on the basis over which the element is defined.
     1606
     1607        For any element x in the Steenrod algebra, use 'view(x)' to
     1608        see the typeset LaTeX representation.
     1609
     1610        EXAMPLES:
     1611            sage: A7 = SteenrodAlgebra(7)
     1612            sage: x = A7.Q(0,3) * A7.P(2,2)
     1613            sage: x._latex_()
     1614            'Q_{0} Q_{3} \\mathcal{P}(2,2)'
     1615            sage: latex(x)
     1616            Q_{0} Q_{3} \mathcal{P}(2,2)
     1617            sage: b = Sq(0,2)
     1618            sage: b.basis('adem')._latex_()
     1619            '\\text{Sq}^{4} \\text{Sq}^{2} + \\text{Sq}^{5} \\text{Sq}^{1} +
     1620            \\text{Sq}^{6}'
     1621            sage: b.basis('woody')._latex_()
     1622            '\\text{Sq}^{2} \\text{Sq}^{3} \\text{Sq}^{1} + \\text{Sq}^{6} +
     1623            \\text{Sq}^{4} \\text{Sq}^{2}'
     1624            sage: SteenrodAlgebra(2, 'arnona')(b)._latex_()
     1625            'X^{1}_{1} X^{2}_{2}  + X^{2}_{1}'
     1626        """
     1627        if len(self._raw['milnor']) == 0:
     1628            return "0"
     1629        else:
     1630            return string_rep(self,LaTeX=True)
     1631
     1632
     1633    def __iter__(self):
     1634        """
     1635        Iterator for looping through summands in an element of the
     1636        Steenrod algebra.
     1637
     1638        EXAMPLES:
     1639            sage: z = Sq(0,0,1) + Sq(4,1) + Sq(7)
     1640            sage: [m for m in z]
     1641            [Sq(0,0,1), Sq(4,1), Sq(7)]
     1642            sage: [m.excess() for m in z]
     1643            [1, 5, 7]
     1644            sage: for m in z: m * Sq(2)
     1645            Sq(2,0,1)
     1646            Sq(0,3) + Sq(6,1)
     1647            Sq(3,2)
     1648            sage: a = SteenrodAlgebra(5).P(5,5)
     1649            sage: a * a
     1650            P(3,6,1) + 2 P(4,11) + P(9,5,1) + 4 P(10,10)
     1651            sage: for m in a * a: m
     1652            P(3,6,1)
     1653            2 P(4,11)
     1654            P(9,5,1)
     1655            4 P(10,10)
     1656
     1657        This loops through the summands in the Milnor basis
     1658        representation of the element.  The element w defined below is
     1659        a single monomial in the Serre-Cartan basis, but a sum of four
     1660        monomials in the Milnor basis:
     1661            sage: w = Sq(4) * Sq(2) * Sq(1)
     1662            sage: A = SteenrodAlgebra(2, 'adem')
     1663            sage: w = A(Sq(4) * Sq(2) * Sq(1)); w
     1664            Sq^{4} Sq^{2} Sq^{1}
     1665            sage: for m in w: m.basis('adem')
     1666            Sq^{4} Sq^{2} Sq^{1} + Sq^{5} Sq^{2} + Sq^{6} Sq^{1} + Sq^{7}
     1667            Sq^{5} Sq^{2} + Sq^{7}
     1668            Sq^{6} Sq^{1} + Sq^{7}
     1669            Sq^{7}
     1670            sage: w.milnor()
     1671            Sq(0,0,1) + Sq(1,2) + Sq(4,1) + Sq(7)
     1672            sage: for m in w: m
     1673            Sq(0,0,1)
     1674            Sq(1,2)
     1675            Sq(4,1)
     1676            Sq(7)
     1677        """
     1678        for m in sorted(self._raw['milnor'].keys()):
     1679            yield SteenrodAlgebraElement({m: self._raw['milnor'][m]},
     1680                                         p = self._prime)
     1681       
     1682
     1683    def additive_order(self):
     1684        """
     1685        The additive order of any element of the mod p Steenrod algebra is p.
     1686
     1687        OUTPUT:
     1688            order -- positive prime number
     1689
     1690        EXAMPLES:
     1691            sage: z = Sq(4) + Sq(6) + Sq(0)
     1692            sage: z.additive_order()
     1693            2
     1694        """
     1695        return self._prime
     1696
     1697
     1698def Sq(*nums):
     1699    """
     1700    Milnor element Sq(a,b,c,...).
     1701
     1702    INPUT:
     1703        a, b, c, ... -- non-negative integers
     1704       
     1705    OUTPUT:
     1706        element of the Steenrod algebra
     1707
     1708    This returns the Milnor basis element $\text{Sq}(a, b, c, ...)$.
     1709   
     1710    EXAMPLES:
     1711        sage: Sq(5)
     1712        Sq(5)
     1713        sage: Sq(5) + Sq(2,1) + Sq(5)  # addition is mod 2:
     1714        Sq(2,1)   
     1715        sage: (Sq(4,3) + Sq(7,2)).degree()
     1716        13
     1717
     1718    Entries must be non-negative integers; otherwise, an error results.
     1719       
     1720    This function is a good way to define elements of the Steenrod algebra.
     1721    """
     1722    dict = {nums: 1}
     1723    return SteenrodAlgebraElement(dict, p=2)
     1724
     1725
     1726def pst(s,t,p=2):
     1727    """
     1728    The Margolis element $P^s_t$.
     1729
     1730    INPUT:
     1731        s -- non-negative integer
     1732        t -- positive integer
     1733        p -- positive prime number (optional, default 2)
     1734       
     1735    OUTPUT:
     1736        element of the Steenrod algebra
     1737
     1738    This returns the Margolis element $P^s_t$ of the mod p Steenrod
     1739    algebra: the element equal to $P(0,0,...,0,p^s)$, where
     1740    the $p^s$ is in position $t$.
     1741
     1742    EXAMPLES:
     1743        sage: from sage.algebras.steenrod_algebra_element import pst
     1744        sage: pst(3,5)
     1745        Sq(0,0,0,0,8)
     1746        sage: pst(1,2) + Sq(4)*Sq(2) + Sq(2)*Sq(4)
     1747        0
     1748        sage: pst(3,5,5)
     1749        P(0,0,0,0,125)
     1750        sage: pst(3,5,p=5)
     1751        P(0,0,0,0,125)
     1752    """
     1753    from sage.algebras.steenrod_algebra import SteenrodAlgebra
     1754    return SteenrodAlgebra(p).pst(s,t)
     1755
     1756
     1757def degree(x):
     1758    r"""
     1759    Degree of x.
     1760   
     1761    INPUT:
     1762        x -- element of the Steenrod algebra
     1763
     1764    OUTPUT:
     1765        degree -- non-negative integer or None
     1766   
     1767    The degree of $\text{Sq}(i_1,i_2,i_3,...)$ is
     1768    $i_1 + 3 i_2 + 7 i_3 + ... + (2^n - 1) i_n + ...$.
     1769    When $p$ is odd, the degree of
     1770    $Q_{0}^{e_0} Q_{1}^{e_1} ... P(r_1, r_2, ...)$
     1771    is $\sum e_i (2p^i - 1) + \sum r_j (2p^j - 2)$.
     1772       
     1773    The degree of a sum is undefined (and this function returns None),
     1774    unless each summand has the same degree: that is, unless the
     1775    element is homogeneous.
     1776
     1777    EXAMPLES:
     1778        sage: from sage.algebras.steenrod_algebra_element import degree
     1779        sage: a = Sq(1,2,1)
     1780        sage: degree(a)
     1781        14
     1782        sage: degree(Sq(3) + Sq(5,1))
     1783        Element is not homogeneous.
     1784        sage: B = SteenrodAlgebra(3)
     1785        sage: x = B.Q(1,4)
     1786        sage: y = B.P(1,2,3)
     1787        sage: degree(x)
     1788        166
     1789        sage: degree(y)
     1790        192
     1791    """
     1792    return x.degree()
     1793
     1794
     1795def excess(x):
     1796    r"""
     1797    Excess of x.
     1798   
     1799    INPUT:
     1800        x -- element of the Steenrod algebra
     1801
     1802    OUTPUT:
     1803        excess -- non-negative integer
     1804   
     1805    The excess of $\text{Sq}(a,b,c,...)$ is $a + b + c + ...$.
     1806    When $p$ is odd, the excess of
     1807    $Q_{0}^{e_0} Q_{1}^{e_1} ... P(r_1, r_2, ...)$
     1808    is $\sum e_i + 2 \sum r_i$.
     1809       
     1810    The excess of a linear combination of Milnor basis elements is
     1811    the minimum of the excesses of those basis elements.
     1812
     1813    EXAMPLES:
     1814        sage: from sage.algebras.steenrod_algebra_element import excess
     1815        sage: a = Sq(1,2,3)
     1816        sage: excess(a)
     1817        6
     1818        sage: excess(Sq(0,0,1) + Sq(4,1) + Sq(7))
     1819        1
     1820        sage: [excess(m) for m in (Sq(0,0,1) + Sq(4,1) + Sq(7))]
     1821        [1, 5, 7]
     1822        sage: B = SteenrodAlgebra(7)
     1823        sage: a = B.Q(1,2,5)
     1824        sage: b = B.P(2,2,3)
     1825        sage: excess(a)
     1826        3
     1827        sage: excess(b)
     1828        14
     1829        sage: excess(a + b)
     1830        3
     1831        sage: excess(a * b)
     1832        17
     1833    """
     1834    return x.excess()
     1835
     1836
     1837def milnor(x):
     1838    r"""
     1839    Milnor representation of x.
     1840
     1841    INPUT:
     1842        x -- element of the Steenrod algebra
     1843
     1844    OUTPUT:
     1845        Milnor representation of x
     1846
     1847    EXAMPLES:
     1848        sage: from sage.algebras.steenrod_algebra_element import milnor
     1849        sage: x = Sq(5) * Sq(2) * Sq(1); x.adem()
     1850        Sq^{5} Sq^{2} Sq^{1}
     1851        sage: milnor(x)
     1852        Sq(1,0,1) + Sq(5,1)
     1853    """
     1854    return x.basis('milnor')
     1855
     1856
     1857def serre_cartan(x):
     1858    r"""
     1859    Serre-Cartan representation of x.
     1860
     1861    INPUT:
     1862        x -- element of the Steenrod algebra
     1863
     1864    OUTPUT:
     1865        Serre-Cartan representation of x
     1866
     1867    EXAMPLES:
     1868        sage: from sage.algebras.steenrod_algebra_element import serre_cartan
     1869        sage: x = Sq(3,2); x
     1870        Sq(3,2)
     1871        sage: serre_cartan(x)
     1872        Sq^{7} Sq^{2}
     1873    """
     1874    return x.basis('adem')
     1875
     1876adem = serre_cartan
     1877admissible = serre_cartan
     1878
     1879## string representations
     1880
     1881def string_rep(element, LaTeX=False, sort=True):
     1882    """
     1883    String representation of element.
     1884
     1885    INPUT:
     1886        element -- element of the Steenrod algebra
     1887        LaTeX -- boolean (optional, default False), if True, output LaTeX string
     1888        sort -- boolean (optional, default True), if True, sort output
     1889
     1890    OUTPUT:
     1891        string -- string representation of element in current basis
     1892
     1893    If LaTeX is True, output a string suitable for LaTeX; otherwise,
     1894    output a plain string.  If sort is True, sort element left
     1895    lexicographically; otherwise, no sorting is done, and so the
     1896    order in which the summands are printed may be unpredictable.
     1897   
     1898    EXAMPLES:
     1899        sage: from sage.algebras.steenrod_algebra_element import string_rep
     1900        sage: a = Sq(0,0,2)
     1901        sage: A = SteenrodAlgebra(2, 'admissible')
     1902        sage: string_rep(A(a))
     1903        'Sq^{8} Sq^{4} Sq^{2} + Sq^{9} Sq^{4} Sq^{1} + Sq^{10} Sq^{3} Sq^{1} +
     1904        Sq^{10} Sq^{4} + Sq^{11} Sq^{2} Sq^{1} + Sq^{12} Sq^{2} + Sq^{13} Sq^{1}
     1905        + Sq^{14}'
     1906        sage: b = Sq(0,2)
     1907        sage: string_rep(A(b),LaTeX=True)
     1908        '\\text{Sq}^{4} \\text{Sq}^{2} + \\text{Sq}^{5} \\text{Sq}^{1} +
     1909        \\text{Sq}^{6}'
     1910        sage: A_wood_z = SteenrodAlgebra(2, 'woodz')
     1911        sage: string_rep(A_wood_z(a))
     1912        'Sq^{6} Sq^{7} Sq^{1} + Sq^{14} + Sq^{4} Sq^{7} Sq^{3} + Sq^{4} Sq^{7}
     1913        Sq^{2} Sq^{1} + Sq^{12} Sq^{2} + Sq^{8} Sq^{6} + Sq^{8} Sq^{4} Sq^{2}'
     1914        sage: string_rep(SteenrodAlgebra(2, 'arnonc')(a), sort=False)
     1915        'Sq^{4} Sq^{4} Sq^{6} + Sq^{6} Sq^{8} + Sq^{4} Sq^{2} Sq^{8} + Sq^{4}
     1916        Sq^{6} Sq^{4} + Sq^{8} Sq^{4} Sq^{2} + Sq^{8} Sq^{6}'
     1917        sage: string_rep(SteenrodAlgebra(2, 'arnonc')(a))
     1918        'Sq^{4} Sq^{2} Sq^{8} + Sq^{4} Sq^{4} Sq^{6} + Sq^{4} Sq^{6} Sq^{4} +
     1919        Sq^{6} Sq^{8} + Sq^{8} Sq^{4} Sq^{2} + Sq^{8} Sq^{6}'
     1920        sage: string_rep(SteenrodAlgebra(2, 'pst_llex')(a))
     1921        'P^{1}_{3}'
     1922        sage: Ac = SteenrodAlgebra(2, 'comm_revz')
     1923        sage: string_rep(Ac(a),LaTeX=True,sort=False)
     1924        'c_{0,2} c_{0,3} c_{2,1} + c_{1,3} + c_{0,1} c_{1,1} c_{0,3} c_{2,1}'
     1925        sage: string_rep(Ac(a),LaTeX=True)
     1926        'c_{0,1} c_{1,1} c_{0,3} c_{2,1} + c_{0,2} c_{0,3} c_{2,1} + c_{1,3}'
     1927        sage: string_rep(a)
     1928        'Sq(0,0,2)'
     1929        sage: string_rep(a,LaTeX=True)
     1930        '\\text{Sq}(0,0,2)'
     1931
     1932    Some odd primary examples:
     1933        sage: A5 = SteenrodAlgebra(5)
     1934        sage: a = A5.P(5,1); b = A5.Q(0,1,3)
     1935        sage: string_rep(b)
     1936        'Q_0 Q_1 Q_3'
     1937        sage: string_rep(a, LaTeX=True)
     1938        '\\mathcal{P}(5,1)'
     1939        sage: A5sc = SteenrodAlgebra(5, 'serre-cartan')
     1940        sage: string_rep(A5sc(a))
     1941        'P^{10} P^{1} + 4 P^{11}'
     1942    """
     1943    if len(element._raw['milnor']) == 0:
     1944        return "0"
     1945    p = element._prime
     1946
     1947    basis = element._basis
     1948    dict = element._basis_dictionary(basis)
     1949
     1950    if basis == 'milnor':
     1951        mono_to_string = milnor_mono_to_string
     1952    elif basis == 'serre-cartan':
     1953        mono_to_string = serre_cartan_mono_to_string
     1954    elif basis.find('wood') >= 0:
     1955        mono_to_string = wood_mono_to_string
     1956    elif basis == 'wall':
     1957        mono_to_string = wall_mono_to_string
     1958    elif basis == 'wall_long':
     1959        mono_to_string = wall_long_mono_to_string
     1960    elif basis == 'arnona':
     1961        mono_to_string = arnonA_mono_to_string
     1962    elif basis == 'arnona_long':
     1963        mono_to_string = arnonA_long_mono_to_string
     1964    elif basis == 'arnonc':
     1965        mono_to_string = serre_cartan_mono_to_string
     1966    elif basis.find('pst') >= 0:
     1967        mono_to_string = pst_mono_to_string
     1968    elif basis.find('comm') >= 0 and basis.find('long') >= 0:
     1969        mono_to_string = comm_long_mono_to_string
     1970    elif basis.find('comm') >= 0:
     1971        mono_to_string = comm_mono_to_string
     1972   
     1973    output = ""
     1974    if sort:
     1975        sorted_list = sorted(dict.keys())
     1976    else:
     1977        sorted_list = dict
     1978    for mono in sorted_list:
     1979        if dict[mono] != 1:
     1980            coeff = str(dict[mono]) + " "
     1981        else:
     1982            coeff = ""
     1983        output = output + coeff + mono_to_string(mono, LaTeX,
     1984                                                 p=element._prime) + " + "
     1985    return output.strip(" +")
     1986
     1987
     1988def milnor_mono_to_string(mono,LaTeX=False,p=2):
     1989    """
     1990    String representation of element of the Milnor basis.
     1991
     1992    This is used by the _repr_ and _latex_ methods.
     1993
     1994    INPUT:
     1995        mono -- if $p=2$, tuple of non-negative integers (a,b,c,...);
     1996                if $p>2$, pair of tuples of non-negative integers
     1997                ((e0, e1, e2, ...), (r1, r2, ...))
     1998        LaTeX -- boolean (optional, default False), if true, output LaTeX string
     1999        p -- positive prime number (optional, default 2)
     2000
     2001    OUTPUT:
     2002        rep -- string
     2003
     2004    This returns a string like 'Sq(a,b,c,...)' when p=2, or a
     2005    string like 'Q_e0 Q_e1 Q_e2 ... P(r1, r2, ...)' when p is odd.
     2006       
     2007    EXAMPLES:
     2008        sage: from sage.algebras.steenrod_algebra_element import milnor_mono_to_string
     2009        sage: milnor_mono_to_string((1,2,3,4))
     2010        'Sq(1,2,3,4)'
     2011        sage: milnor_mono_to_string((1,2,3,4),LaTeX=True)
     2012        '\\text{Sq}(1,2,3,4)'
     2013        sage: milnor_mono_to_string(((1,0), (2,3,1)), p=3)
     2014        'Q_1 Q_0 P(2,3,1)'
     2015        sage: milnor_mono_to_string(((1,0), (2,3,1)), LaTeX=True, p=3)
     2016        'Q_{1} Q_{0} \\mathcal{P}(2,3,1)'
     2017
     2018    The empty tuple represents the unit element Sq(0) (or P(0) at an odd prime):
     2019        sage: milnor_mono_to_string(())
     2020        'Sq(0)'
     2021        sage: milnor_mono_to_string((), p=5)
     2022        'P(0)'
     2023    """
     2024    if LaTeX:
     2025        if p == 2:
     2026            sq = "\\text{Sq}"
     2027            P = "\\text{Sq}"
     2028        else:
     2029            P = "\\mathcal{P}"
     2030    else:
     2031        if p == 2:
     2032            sq = "Sq"
     2033            P = "Sq"
     2034        else:
     2035            P = "P"
     2036    if len(mono) == 0 or (p > 2 and len(mono[0]) + len(mono[1]) == 0):
     2037        return P + "(0)"
     2038    else:
     2039        if p == 2:
     2040            string = sq + "(" + str(mono[0])
     2041            for n in mono[1:]:
     2042                string = string + "," + str(n)
     2043            string = string + ")"
     2044        else:
     2045            string = ""
     2046            if len(mono[0]) > 0:
     2047                for e in mono[0]:
     2048                    if LaTeX:
     2049                        string = string + "Q_{" + str(e) + "} "
     2050                    else:
     2051                        string = string + "Q_" + str(e) + " "
     2052            if len(mono[1]) > 0:
     2053                string = string + P + "(" + str(mono[1][0])
     2054                for n in mono[1][1:]:
     2055                    string = string + "," + str(n)
     2056                string = string + ")"
     2057        return string.strip(" ")
     2058   
     2059
     2060def serre_cartan_mono_to_string(mono,LaTeX=False,p=2):
     2061    r"""
     2062    String representation of element of the Serre-Cartan basis.
     2063
     2064    This is used by the _repr_ and _latex_ methods.
     2065
     2066    INPUT:
     2067        mono -- tuple of positive integers (a,b,c,...) when $p=2$, or tuple
     2068                (e0, n1, e1, n2, ...) when $p>2$, where each ei is 0 or 1, and
     2069                each ni is positive
     2070        LaTeX -- boolean (optional, default False), if true, output LaTeX string
     2071        p -- positive prime number (optional, default 2)
     2072
     2073    OUTPUT:
     2074        rep -- string
     2075
     2076    This returns a string like '$Sq^{a} Sq^{b} Sq^{c} ...$ when $p=2$,
     2077    or a string like $\beta^{e0} P^{n1} \beta^{e1} P^{n2} ...$ when $p$
     2078    is odd.
     2079       
     2080    EXAMPLES:
     2081        sage: from sage.algebras.steenrod_algebra_element import serre_cartan_mono_to_string
     2082        sage: serre_cartan_mono_to_string((1,2,3,4))
     2083        'Sq^{1} Sq^{2} Sq^{3} Sq^{4}'
     2084        sage: serre_cartan_mono_to_string((1,2,3,4),LaTeX=True)
     2085        '\\text{Sq}^{1} \\text{Sq}^{2} \\text{Sq}^{3} \\text{Sq}^{4}'
     2086        sage: serre_cartan_mono_to_string((0,5,1,1,0), p=3)
     2087        'P^{5} beta P^{1}'
     2088        sage: serre_cartan_mono_to_string((0,5,1,1,0), p=3, LaTeX=True)
     2089        '\\mathcal{P}^{5} \\beta \\mathcal{P}^{1}'
     2090
     2091    The empty tuple represents the unit element $Sq^0$ (or $P^0$ at an odd prime):
     2092        sage: serre_cartan_mono_to_string(())
     2093        'Sq^{0}'
     2094        sage: serre_cartan_mono_to_string((), p=7)
     2095        'P^{0}'
     2096    """
     2097    if LaTeX:
     2098        if p == 2:
     2099            sq = "\\text{Sq}"
     2100            P = "\\text{Sq}"
     2101        else:
     2102            P = "\\mathcal{P}"
     2103    else:
     2104        if p == 2:
     2105            sq = "Sq"
     2106            P = "Sq"
     2107        else:
     2108            P = "P"
     2109    if len(mono) == 0:
     2110        return P + "^{0}"
     2111    else:
     2112        if p == 2:
     2113            string = ""
     2114            for n in mono:
     2115                string = string + sq + "^{" + str(n) + "} "
     2116        else:
     2117            string = ""
     2118            index = 0
     2119            for n in mono:
     2120                from sage.misc.functional import is_even
     2121                if is_even(index):
     2122                    if n == 1:
     2123                        if LaTeX:
     2124                            string = string + "\\beta "
     2125                        else:
     2126                            string = string + "beta "
     2127                else:
     2128                    string = string + P + "^{" + str(n) + "} "
     2129                index += 1
     2130        return string.strip(" ")
     2131
     2132
     2133def wood_mono_to_string(mono,LaTeX=False,p=2):
     2134    """
     2135    String representation of element of Wood's Y and Z bases.
     2136
     2137    This is used by the _repr_ and _latex_ methods.
     2138
     2139    INPUT:
     2140        mono -- tuple of pairs of non-negative integers (s,t)
     2141
     2142    OUTPUT:
     2143        string -- concatenation of '$Sq^{2^s (2^{t+1}-1)}$' for each pair (s,t)
     2144       
     2145    EXAMPLES:
     2146        sage: from sage.algebras.steenrod_algebra_element import wood_mono_to_string
     2147        sage: wood_mono_to_string(((1,2),(3,0)))
     2148        'Sq^{14} Sq^{8}'
     2149        sage: wood_mono_to_string(((1,2),(3,0)),LaTeX=True)
     2150        '\\text{Sq}^{14} \\text{Sq}^{8}'
     2151
     2152    The empty tuple represents the unit element Sq(0):
     2153        sage: wood_mono_to_string(())
     2154        'Sq(0)'
     2155    """
     2156    if LaTeX:
     2157        sq = "\\text{Sq}"
     2158    else:
     2159        sq = "Sq"
     2160    if len(mono) == 0:
     2161        return sq + "(0)"
     2162    else:
     2163        string = ""
     2164        for (s,t) in mono:
     2165            string = string + sq + "^{" + \
     2166                str(2**s * (2**(t+1)-1)) + "} "
     2167        return string.strip(" ")
     2168
     2169
     2170def wall_mono_to_string(mono,LaTeX=False,p=2):
     2171    """
     2172    String representation of element of Wall's basis.
     2173
     2174    This is used by the _repr_ and _latex_ methods.
     2175
     2176    INPUT:
     2177        mono -- tuple of pairs of non-negative integers (m,k) with $m >= k$
     2178
     2179    OUTPUT:
     2180        string -- concatenation of '$Q^{m}_{k}$' for each pair (m,k)
     2181       
     2182    EXAMPLES:
     2183        sage: from sage.algebras.steenrod_algebra_element import wall_mono_to_string
     2184        sage: wall_mono_to_string(((1,2),(3,0)))
     2185        'Q^{1}_{2} Q^{3}_{0}'
     2186        sage: wall_mono_to_string(((1,2),(3,0)),LaTeX=True)
     2187        'Q^{1}_{2} Q^{3}_{0}'
     2188
     2189    The empty tuple represents the unit element Sq(0):
     2190        sage: wall_mono_to_string(())
     2191        'Sq(0)'
     2192    """
     2193    if LaTeX:
     2194        sq = "\\text{Sq}"
     2195    else:
     2196        sq = "Sq"
     2197    if len(mono) == 0:
     2198        return sq + "(0)"
     2199    else:
     2200        string = ""
     2201        for (m,k) in mono:
     2202            string = string + "Q^{" + str(m) + "}_{" \
     2203                + str(k) + "} "
     2204        return string.strip(" ")
     2205
     2206
     2207def wall_long_mono_to_string(mono,LaTeX=False,p=2):
     2208    """
     2209    Alternate string representation of element of Wall's basis.
     2210
     2211    This is used by the _repr_ and _latex_ methods.
     2212
     2213    INPUT:
     2214        mono -- tuple of pairs of non-negative integers (m,k) with $m >= k$
     2215
     2216    OUTPUT:
     2217        string -- concatenation of terms of the form '$Sq^(2^m)$'
     2218       
     2219    EXAMPLES:
     2220        sage: from sage.algebras.steenrod_algebra_element import wall_long_mono_to_string
     2221        sage: wall_long_mono_to_string(((1,2),(3,0)))
     2222        'Sq^{1} Sq^{2} Sq^{4} Sq^{8}'
     2223        sage: wall_long_mono_to_string(((1,2),(3,0)),LaTeX=True)
     2224        '\\text{Sq}^{1} \\text{Sq}^{2} \\text{Sq}^{4} \\text{Sq}^{8}'
     2225
     2226    The empty tuple represents the unit element Sq(0):
     2227        sage: wall_long_mono_to_string(())
     2228        'Sq(0)'
     2229    """
     2230    if LaTeX:
     2231        sq = "\\text{Sq}"
     2232    else:
     2233        sq = "Sq"
     2234    if len(mono) == 0:
     2235        return sq + "(0)"
     2236    else:
     2237        string = ""
     2238        for (m,k) in mono:
     2239            for i in range(k,m+1):
     2240                string = string + sq + "^{" + str(2**i) + "} "
     2241        return string.strip(" ")
     2242
     2243
     2244def arnonA_mono_to_string(mono,LaTeX=False,p=2):
     2245    """
     2246    String representation of element of Arnon's A basis.
     2247
     2248    This is used by the _repr_ and _latex_ methods.
     2249
     2250    INPUT:
     2251        mono -- tuple of pairs of non-negative integers (m,k) with $m >= k$
     2252
     2253    OUTPUT:
     2254        string -- concatenation of '$X^{m}_{k}$' for each pair (m,k)
     2255       
     2256    EXAMPLES:
     2257        sage: from sage.algebras.steenrod_algebra_element import arnonA_mono_to_string
     2258        sage: arnonA_mono_to_string(((1,2),(3,0)))
     2259        'X^{1}_{2} X^{3}_{0}'
     2260        sage: arnonA_mono_to_string(((1,2),(3,0)),LaTeX=True)
     2261        'X^{1}_{2} X^{3}_{0}'
     2262
     2263    The empty tuple represents the unit element Sq(0):
     2264        sage: arnonA_mono_to_string(())
     2265        'Sq(0)'
     2266    """
     2267    if LaTeX:
     2268        sq = "\\text{Sq}"
     2269    else:
     2270        sq = "Sq"
     2271    if len(mono) == 0:
     2272        return sq + "(0)"
     2273    else:
     2274        string = ""
     2275        for (m,k) in mono:
     2276            string = string + "X^{" + str(m) + "}_{" \
     2277                + str(k) + "} "
     2278        return string.strip(" ")
     2279   
     2280
     2281def arnonA_long_mono_to_string(mono,LaTeX=False,p=2):
     2282    """
     2283    Alternate string representation of element of Arnon's A basis.
     2284
     2285    This is used by the _repr_ and _latex_ methods.
     2286
     2287    INPUT:
     2288        mono -- tuple of pairs of non-negative integers (m,k) with $m >= k$
     2289
     2290    OUTPUT:
     2291        string -- concatenation of strings of the form '$Sq(2^m)$'
     2292       
     2293    EXAMPLES:
     2294        sage: from sage.algebras.steenrod_algebra_element import arnonA_long_mono_to_string
     2295        sage: arnonA_long_mono_to_string(((1,2),(3,0)))
     2296        'Sq^{8} Sq^{4} Sq^{2} Sq^{1}'
     2297        sage: arnonA_long_mono_to_string(((1,2),(3,0)),LaTeX=True)
     2298        '\\text{Sq}^{8} \\text{Sq}^{4} \\text{Sq}^{2} \\text{Sq}^{1}'
     2299
     2300    The empty tuple represents the unit element Sq(0):
     2301        sage: arnonA_long_mono_to_string(())
     2302        'Sq(0)'
     2303    """
     2304    if LaTeX:
     2305        sq = "\\text{Sq}"
     2306    else:
     2307        sq = "Sq"
     2308    if len(mono) == 0:
     2309        return sq + "(0)"
     2310    else:
     2311        string = ""
     2312        for (m,k) in mono:
     2313            for i in range(m,k-1,-1):
     2314                string = string + sq + "^{" + str(2**i) + "} "
     2315        return string.strip(" ")
     2316   
     2317
     2318def pst_mono_to_string(mono,LaTeX=False,p=2):
     2319    r"""
     2320    String representation of element of a $P^s_t$-basis.
     2321
     2322    This is used by the _repr_ and _latex_ methods.
     2323
     2324    INPUT:
     2325        mono -- tuple of pairs of integers (s,t) with $s >= 0$, $t > 0$
     2326
     2327    OUTPUT:
     2328        string -- concatenation of '$P^{s}_{t}$' for each pair (s,t)
     2329       
     2330    EXAMPLES:
     2331        sage: from sage.algebras.steenrod_algebra_element import pst_mono_to_string
     2332        sage: pst_mono_to_string(((1,2),(0,3)))
     2333        'P^{1}_{2} P^{0}_{3}'
     2334        sage: pst_mono_to_string(((1,2),(0,3)),LaTeX=True)
     2335        'P^{1}_{2} P^{0}_{3}'
     2336
     2337    The empty tuple represents the unit element Sq(0):
     2338        sage: pst_mono_to_string(())
     2339        'Sq(0)'
     2340    """
     2341    if LaTeX:
     2342        sq = "\\text{Sq}"
     2343    else:
     2344        sq = "Sq"
     2345    if len(mono) == 0:
     2346        return sq + "(0)"
     2347    else:
     2348        string = ""
     2349        for (s,t) in mono:
     2350            string = string + "P^{" + str(s) + "}_{" \
     2351                + str(t) + "} "
     2352        return string.strip(" ")
     2353
     2354
     2355def comm_mono_to_string(mono,LaTeX=False,p=2):
     2356    r"""
     2357    String representation of element of a commutator basis.
     2358
     2359    This is used by the _repr_ and _latex_ methods.
     2360
     2361    INPUT:
     2362        mono -- tuple of pairs of integers (s,t) with $s >= 0$, $t > 0$
     2363
     2364    OUTPUT:
     2365        string -- concatenation of '$c_{s,t}$' for each pair (s,t)
     2366       
     2367    EXAMPLES:
     2368        sage: from sage.algebras.steenrod_algebra_element import comm_mono_to_string
     2369        sage: comm_mono_to_string(((1,2),(0,3)))
     2370        'c_{1,2} c_{0,3}'
     2371        sage: comm_mono_to_string(((1,2),(0,3)),LaTeX=True)
     2372        'c_{1,2} c_{0,3}'
     2373
     2374    The empty tuple represents the unit element Sq(0):
     2375        sage: comm_mono_to_string(())
     2376        'Sq(0)'
     2377    """
     2378    if LaTeX:
     2379        sq = "\\text{Sq}"
     2380    else:
     2381        sq = "Sq"
     2382    if len(mono) == 0:
     2383        return sq + "(0)"
     2384    else:
     2385        string = ""
     2386        for (s,t) in mono:
     2387            string = string + "c_{" + str(s) + "," \
     2388                + str(t) + "} "
     2389        return string.strip(" ")
     2390
     2391
     2392def comm_long_mono_to_string(mono,LaTeX=False,p=2):
     2393    r"""
     2394    Alternate string representation of element of a commutator basis.
     2395
     2396    Okay in low dimensions, but gets unwieldy as the dimension increases.
     2397
     2398    INPUT:
     2399        mono -- tuple of pairs of integers (s,t) with $s >= 0$, $t > 0$
     2400
     2401    OUTPUT:
     2402        string -- concatenation of '$s_{2^s ... 2^(s+t-1)}$' for each pair (s,t)
     2403       
     2404    EXAMPLES:
     2405        sage: from sage.algebras.steenrod_algebra_element import comm_long_mono_to_string
     2406        sage: comm_long_mono_to_string(((1,2),(0,3)))
     2407        's_{24} s_{124}'
     2408        sage: comm_long_mono_to_string(((1,2),(0,3)),LaTeX=True)
     2409        's_{24} s_{124}'
     2410
     2411    The empty tuple represents the unit element Sq(0):
     2412        sage: comm_long_mono_to_string(())
     2413        'Sq(0)'
     2414    """
     2415    if LaTeX:
     2416        sq = "\\text{Sq}"
     2417    else:
     2418        sq = "Sq"
     2419    if len(mono) == 0:
     2420        return sq + "(0)"
     2421    else:
     2422        string = ""
     2423        for (s,t) in mono:
     2424            if s + t > 4:
     2425                comma = ","
     2426            else:
     2427                comma = ""
     2428            string = string + "s_{"
     2429            for i in range(t):
     2430                string = string + str(2**(s+i)) + comma
     2431            string = string.strip(",") + "} "
     2432        return string.strip(" ")
  • new file sage/algebras/steenrod_milnor_multiplication.py

    diff -r c25e04ebfb67 -r 9fbc77f226c8 sage/algebras/steenrod_milnor_multiplication.py
    - +  
     1r"""
     2Milnor multiplication for elements of the mod 2 Steenrod algebra
     3
     4AUTHORS:
     5    - John H. Palmieri (2008-07-30: version 0.9)
     6
     7See Milnor's paper [Mil] for proofs, etc.
     8
     9To multiply Milnor basis elements $\text{Sq}(r_1, r_2, ...)$ and
     10$\text{Sq}(s_1, s_2,...)$, form all possible matrices $M$ with rows
     11and columns indexed starting at 0, with position (0,0) deleted (or
     12ignored), with $s_i$ equal to the sum of column $i$ for each $i$, and
     13with $r_j$ equal to the 'weighted' sum of row $j$.  The weights are as
     14follows: elements from column $i$ are multiplied by $2^i$.  For
     15example, to multiply $\text{Sq}(2)$ and $\text{Sq}(1,1)$, form the
     16matrices
     17\[
     18\begin{Vmatrix}
     19* & 1 & 1 \\
     202 & 0 & 0
     21\end{Vmatrix}
     22\quad \text{and} \quad
     23\begin{Vmatrix}
     24* & 0 & 1 \\
     250 & 1 & 0
     26\end{Vmatrix}
     27\]
     28(The $*$ is the ignored (0,0)-entry of the matrix.)  For each such
     29matrix $M$, compute a multinomial coefficient, mod 2: for each
     30diagonal $\{m_{ij}: i+j=n\}$, compute $(\sum m_{i,j}!) / (m_{0,n}!
     31m_{1,n-1}!  ... m_{n,0}!)$.  Multiply these together for all $n$.  (To
     32compute this mod 2, view the entries of the matrix as their base 2
     33expansions; then this coefficient is zero if and only if there is some
     34diagonal containing two numbers which have a summand in common in
     35their base 2 expansion.  For example, if 3 and 10 are in the same
     36diagonal, the coefficient is zero, because $3=1+2$ and $10=2+8$: they
     37both have a summand of 2.)
     38
     39Now, for each matrix with multinomial coefficient 1, let $t_n$ be
     40the sum of the nth diagonal in the matrix; then
     41\[
     42\text{Sq}(r_1, r_2, ...) \text{Sq}(s_1, s_2, ...) = \sum \text{Sq}(t_1, t_2, ...)
     43\]
     44
     45The function \code{milnor_multiplication} takes as input two tuples
     46of non-negative integers, $r$ and $s$, which represent
     47$\text{Sq}(r)=\text{Sq}(r_1, r_2, ...)$ and
     48$\text{Sq}(s)=\text{Sq}(s_1, s_2, ...)$; it returns as output a
     49dictionary whose keys are tuples $t=(t_1, t_2, ...)$ of non-negative
     50integers, and for each tuple the associated value is the coefficient
     51of $\text{Sq}(t)$ in the product formula.  Since we are working mod 2,
     52this coefficient is 1 (if it is zero, the the element is omitted from
     53the dictionary altogether).
     54
     55EXAMPLES:
     56    sage: from sage.algebras.steenrod_milnor_multiplication import milnor_multiplication
     57    sage: milnor_multiplication((2,), (1,))
     58    {(0, 1): 1, (3,): 1}
     59    sage: milnor_multiplication((4,), (2,1))
     60    {(6, 1): 1, (0, 3): 1, (2, 0, 1): 1}
     61    sage: milnor_multiplication((2,4), (0,1))
     62    {(2, 5): 1, (2, 0, 0, 1): 1}
     63
     64These examples correspond to the following product computations:
     65\begin{gather*}
     66\text{Sq}(2) \text{Sq}(1) = \text{Sq}(0,1) + \text{Sq}(3)
     67\text{Sq}(4) \text{Sq}(2,1) = \text{Sq}(6,1) + \text{Sq}(0,3) + \text{Sq}(2,0,1)
     68\text{Sq}(2,4) \text{Sq}(0,1) = \text{Sq}(2, 5) + \text{Sq}(2, 0, 0, 1)
     69\end{gather*}
     70
     71REFERENCES:
     72
     73    [Mil] J. W. Milnor, "The Steenrod algebra and its dual, Ann. of Math.
     74          (2) \textbf{67} (1958), 150--171.
     75"""
     76
     77#*****************************************************************************
     78#       Copyright (C) 2008 John H. Palmieri <palmieri@math.washington.edu>
     79#  Distributed under the terms of the GNU General Public License (GPL)
     80#*****************************************************************************
     81
     82def milnor_multiplication(r,s):
     83    r"""
     84    Product of Milnor basis elements r and s.
     85
     86    INPUT:
     87        r -- tuple of non-negative integers
     88        s -- tuple of non-negative integers
     89
     90    OUTPUT:
     91        Dictionary of terms of the form (tuple: coeff), where 'tuple' is a
     92        tuple of non-negative integers and 'coeff' is 1.
     93
     94    This computes Milnor matrices for the product of $\text{Sq}(r)$
     95    and $\text{Sq}(s)$, computes their multinomial coefficients, and
     96    for each matrix whose coefficient is 1, add $\text{Sq}(t)$ to the
     97    output, where $t$ is the tuple formed by the diagonals sums from
     98    the matrix.
     99   
     100    EXAMPLES:
     101        sage: from sage.algebras.steenrod_milnor_multiplication import milnor_multiplication
     102        sage: milnor_multiplication((2,), (1,))
     103        {(0, 1): 1, (3,): 1}
     104        sage: milnor_multiplication((4,), (2,1))
     105        {(6, 1): 1, (0, 3): 1, (2, 0, 1): 1}
     106        sage: milnor_multiplication((2,4), (0,1))
     107        {(2, 5): 1, (2, 0, 0, 1): 1}
     108   
     109    This uses the same algorithm Monks does in his Maple package.
     110    """
     111    result = {}
     112    rows = len(r) + 1
     113    cols = len(s) + 1
     114    diags = len(r) + len(s)
     115    # initialize matrix
     116    M = range(rows)
     117    for i in range(rows):
     118        M[i] = [0]*cols
     119    for j in range(1,cols):
     120        M[0][j] = s[j-1]
     121    for i in range(1,rows):
     122        M[i][0] = r[i-1]
     123        for j in range(1,cols):
     124            M[i][j] = 0
     125    found = True
     126    while found:
     127        # check diagonals
     128        n = 1
     129        okay = 1
     130        diagonal = [0]*diags
     131        while n <= diags and okay is not None:
     132            nth_diagonal = [M[i][n-i] for i in range(max(0,n-cols+1), min(1+n,rows))]
     133            okay = multinomial(nth_diagonal)
     134            diagonal[n-1] = okay
     135            n = n + 1
     136        if okay is not None:
     137            i = diags - 1
     138            while i >= 0 and diagonal[i] == 0:
     139                i = i - 1
     140            t = tuple(diagonal[:i+1])
     141            # reduce mod two:
     142            if result.has_key(t):
     143                del result[t]
     144            else:
     145                result[t] = 1
     146        # now look for new matrices:
     147        found = False
     148        i = 1
     149        while not found and i < rows:
     150            sum = M[i][0]
     151            j = 1
     152            while not found and j < cols:
     153                # check to see if column index j is small enough
     154                if sum >= 2**j:
     155                    # now check to see if there's anything above this entry
     156                    # to add to it
     157                    temp_col_sum = 0
     158                    for k in range(i):
     159                        temp_col_sum += M[k][j]
     160                    if temp_col_sum != 0:
     161                        found = True
     162                        for row in range(1,i):
     163                            M[row][0] = r[row-1]
     164                            for col in range(1,cols):
     165                                M[0][col] = M[0][col] + M[row][col]
     166                                M[row][col] = 0
     167                        for col in range(1,j):
     168                            M[0][col] = M[0][col] + M[i][col]
     169                            M[i][col] = 0
     170                        M[0][j] = M[0][j] - 1
     171                        M[i][j] = M[i][j] + 1
     172                        M[i][0] = sum - 2**j
     173                    else:
     174                        sum = sum + M[i][j] * 2**j
     175                else:
     176                        sum = sum + M[i][j] * 2**j
     177                j = j + 1
     178            i = i + 1
     179    return result
     180
     181
     182def multinomial(list):
     183    """
     184    Multinomial coefficient of list, mod 2.
     185
     186    INPUT:
     187        list -- list of integers
     188
     189    OUTPUT:
     190        None if the multinomial coefficient is 0, or sum of list if it is 1
     191
     192    Given the input $[n_1, n_2, n_3, ...]$, this computes the
     193    multinomial coefficient $(n_1 + n_2 + n_3 + ...)! / (n_1! n_2!
     194    n_3! ...)$, mod 2.  The method is roughly this: expand each
     195    $n_i$ in binary.  If there is a 1 in the same digit for any $n_i$
     196    and $n_j$ with $i\neq j$, then the coefficient is 0; otherwise, it
     197    is 1.
     198
     199    EXAMPLES:
     200        sage: from sage.algebras.steenrod_milnor_multiplication import multinomial
     201        sage: multinomial([1,2,4])
     202        7
     203        sage: multinomial([1,2,5])
     204        sage: multinomial([1,2,12,192,256])
     205        463
     206
     207    This function does not compute any factorials, so the following are
     208    actually reasonable to do:
     209        sage: multinomial([1,65536])
     210        65537
     211        sage: multinomial([4,65535])
     212        sage: multinomial([32768,65536])
     213        98304
     214    """
     215    old_sum = list[0]
     216    okay = True
     217    i = 1
     218    while okay and i < len(list):
     219        j = 1
     220        while okay and j <= min(old_sum, list[i]):
     221            if j & old_sum == j:
     222                okay = (j & list[i] == 0)
     223            j = j << 1
     224        old_sum = old_sum + list[i]
     225        i = i + 1
     226    if okay:
     227        return old_sum
     228    else:
     229        return None
  • new file sage/algebras/steenrod_milnor_multiplication_odd.py

    diff -r c25e04ebfb67 -r 9fbc77f226c8 sage/algebras/steenrod_milnor_multiplication_odd.py
    - +  
     1r"""
     2Milnor multiplication for elements of the odd primary Steenrod algebra
     3
     4AUTHORS:
     5    - John H. Palmieri (2008-07-30: version 0.9)
     6
     7See Milnor's paper [Mil] for proofs, etc.
     8
     9Fix an odd prime $p$.  There are three steps to multiply Milnor basis
     10elements $Q_{f_1} Q_{f_2} ... \mathcal{P}(q_1, q_2, ...)$ and
     11$Q_{g_1} Q_{g_2} ... \mathcal{P}(s_1, s_2,...)$: first, use the formula
     12\[
     13\mathcal{P}(q_1, q_2, ...) Q_k = Q_k \mathcal{P}(q_1, q_2, ...)
     14  + Q_{k+1} \mathcal{P}(q_1 - p^k, q_2, ...)
     15  + Q_{k+2} \mathcal{P}(q_1, q_2 - p^k, ...)
     16  + ...
     17\]
     18Second, use the fact that the $Q_k$'s form an exterior algebra: $Q_k^2 =
     190$ for all $k$, and if $i \neq j$, then $Q_i$ and $Q_j$ anticommute:
     20$Q_i Q_j = -Q_j Q_i$.  After these two steps, the product is of the form
     21\[
     22\sum Q_{e_1} Q_{e_2} ... \mathcal{P}(r_1, r_2, ...) \mathcal{P}(s_1, s_2, ...).
     23\]
     24Finally, use Milnor matrices to multiply the pairs of
     25$\mathcal{P}(...)$ terms: form all possible matrices $M$ with rows and
     26columns indexed starting at 0, with position (0,0) deleted (or
     27ignored), with $s_i$ equal to the sum of column $i$ for each $i$, and
     28with $r_j$ equal to the 'weighted' sum of row $j$.  The weights are as
     29follows: elements from column $i$ are multiplied by $p^i$.  For
     30example when $p=5$, to multiply $\mathcal{P}(5)$ and $\mathcal{P}(1,1)$,
     31form the matrices
     32\[
     33\begin{Vmatrix}
     34* & 1 & 1 \\
     355 & 0 & 0
     36\end{Vmatrix}
     37\quad \text{and} \quad
     38\begin{Vmatrix}
     39* & 0 & 1 \\
     400 & 1 & 0
     41\end{Vmatrix}
     42\]
     43(The $*$ is the ignored (0,0)-entry of the matrix.)  For each such
     44matrix $M$, compute a multinomial coefficient, mod $p$: for each
     45diagonal $\{m_{ij}: i+j=n\}$, compute $(\sum m_{i,j}!) / (m_{0,n}!
     46m_{1,n-1}!  ... m_{n,0}!)$.  Multiply these together for all $n$.
     47
     48Now, for each matrix with nonzero multinomial coefficient $b_M$, let
     49$t_n$ be the sum of the $n$th diagonal in the matrix; then
     50\[
     51\mathcal{P}(r_1, r_2, ...) \mathcal{P}(s_1, s_2, ...)
     52     = \sum b_M \mathcal{P}(t_1, t_2, ...)
     53\]
     54For example when $p=5$, we have
     55\[
     56\mathcal{P}(5) \mathcal{P}(1,1) = \mathcal{P}(6,1) + 2 \mathcal{P}(0,2).
     57\]
     58
     59The function \code{milnor_multiplication} takes as input two pairs of
     60tuples of non-negative integers, $(g,q)$ and $(f,s)$, which represent
     61$Q_{g_1} Q_{g_2} ... \mathcal{P}(q_1, q_2, ...)$ and
     62$Q_{f_1} Q_{f_2} ... \mathcal{P}(s_1, s_2, ...)$.  It returns as output a
     63dictionary whose keys are pairs of tuples $(e,t)$ of non-negative
     64integers, and for each tuple the associated value is the coefficient
     65in the product formula.
     66
     67EXAMPLES:
     68    sage: from sage.algebras.steenrod_milnor_multiplication_odd import milnor_multiplication_odd
     69    sage: milnor_multiplication_odd(((0,2),(5,)), ((1,),(1,)), 5)
     70    {((0, 1, 2), (0, 1)): 4, ((0, 1, 2), (6,)): 4}
     71    sage: milnor_multiplication_odd(((0,2,4),()), ((1,3),()), 7)
     72    {((0, 1, 2, 3, 4), ()): 6}
     73    sage: milnor_multiplication_odd(((0,2,4),()), ((1,5),()), 7)
     74    {((0, 1, 2, 4, 5), ()): 1}
     75    sage: milnor_multiplication_odd(((),(6,)), ((),(2,)), 3)
     76    {((), (4, 1)): 1, ((), (8,)): 1, ((), (0, 2)): 1}
     77
     78These examples correspond to the following product computations:
     79\begin{gather*}
     80p=5: \quad Q_0 Q_2 \mathcal{P}(5) Q_1 \mathcal{P}(1) = 4 Q_0 Q_1 Q_2 \mathcal{P}(0,1) + 4 Q_0 Q_1 Q_2 \mathcal{P}(6) \\
     81p=7: \quad (Q_0 Q_2 Q_4) (Q_1 Q_3) = 6 Q_0 Q_1 Q_2 Q_3 Q_4 \\
     82p=7: \quad (Q_0 Q_2 Q_4) (Q_1 Q_5) = Q_0 Q_1 Q_2 Q_3 Q_5 \\
     83p=3: \quad \mathcal{P}(6) \mathcal{P}(2) = \mathcal{P}(0,2) + \mathcal{P}(4,1) + \mathcal{P}(8)
     84\end{gather*}
     85
     86REFERENCES:
     87
     88    [Mil] J. W. Milnor, "The Steenrod algebra and its dual, Ann. of Math.
     89          (2) \textbf{67} (1958), 150--171.
     90"""
     91
     92#*****************************************************************************
     93#       Copyright (C) 2008 John H. Palmieri <palmieri@math.washington.edu>
     94#  Distributed under the terms of the GNU General Public License (GPL)
     95#*****************************************************************************
     96
     97def milnor_multiplication_odd(m1,m2,p):
     98    r"""
     99    Product of Milnor basis elements defined by m1 and m2.
     100
     101    INPUT:
     102        m1 -- pair of tuples (e,r), where e is an increasing tuple of
     103            non-negative integers and r is a tuple of non-negative integers
     104        m2 -- pair of tuples (f,s), same format as m1
     105        p -- odd prime number
     106
     107    OUTPUT:
     108        Dictionary of terms of the form (tuple: coeff), where 'tuple' is a
     109        pair of tuples, as for r and s, and 'coeff' is an integer mod p.
     110
     111    This computes the product of the Milnor basis elements
     112    $Q_e1 Q_e2 ... P(r_1, r_2, ...)$ and
     113    $Q_f1 Q_f2 ... P(s_1, s_2, ...)$.
     114   
     115    EXAMPLES:
     116        sage: from sage.algebras.steenrod_milnor_multiplication_odd import milnor_multiplication_odd
     117        sage: milnor_multiplication_odd(((0,2),(5,)), ((1,),(1,)), 5)
     118        {((0, 1, 2), (0, 1)): 4, ((0, 1, 2), (6,)): 4}
     119        sage: milnor_multiplication_odd(((0,2,4),()), ((1,3),()), 7)
     120        {((0, 1, 2, 3, 4), ()): 6}
     121        sage: milnor_multiplication_odd(((0,2,4),()), ((1,5),()), 7)
     122        {((0, 1, 2, 4, 5), ()): 1}
     123        sage: milnor_multiplication_odd(((),(6,)), ((),(2,)), 3)
     124        {((), (4, 1)): 1, ((), (8,)): 1, ((), (0, 2)): 1}
     125   
     126    This uses the same algorithm Monks does in his Maple package to
     127    iterate through the possible matrices.
     128    """
     129    from sage.rings.all import GF
     130    F = GF(p)
     131    (f,s) = m2
     132    # First compute Q_e0 Q_e1 ... P(r1, r2, ...) Q_f0 Q_f1 ...
     133    # Store results (as dictionary of pairs of tuples) in 'answer'.
     134    answer = {m1: F(1)}
     135    for k in f:
     136        old_answer = answer
     137        answer = {}
     138        for mono in old_answer:
     139            if k not in mono[0]:
     140                q_mono = set(mono[0])
     141                if len(q_mono) > 0:
     142                    ind = len(q_mono.intersection(range(k,1+max(q_mono))))
     143                else:
     144                    ind = 0
     145                coeff = (-1)**ind * old_answer[mono]
     146                lst = list(mono[0])
     147                if ind == 0:
     148                    lst.append(k)
     149                else:
     150                    lst.insert(-ind,k)
     151                q_mono = tuple(lst)
     152                p_mono = mono[1]
     153                answer[(q_mono, p_mono)] = F(coeff)
     154            for i in range(1,1+len(mono[1])):
     155                if (k+i not in mono[0]) and (p**k <= mono[1][i-1]):
     156                    q_mono = set(mono[0])
     157                    if len(q_mono) > 0:
     158                        ind = len(q_mono.intersection(range(k+i,1+max(q_mono))))
     159                    else:
     160                        ind = 0
     161                    coeff = (-1)**ind
     162                    lst = list(mono[0])
     163                    if ind == 0:
     164                        lst.append(k+i)
     165                    else:
     166                        lst.insert(-ind,k+i)
     167                    q_mono = tuple(lst)
     168                    p_mono = list(mono[1])
     169                    p_mono[i-1] = p_mono[i-1] - p**k
     170                    answer[(q_mono, tuple(p_mono))] = F(coeff)
     171    # Now for the Milnor matrices.  For each entry '(e,r): coeff' in answer,
     172    # multiply r with s.  Record coefficient for matrix and multiply by coeff. 
     173    # Store in 'result'.
     174    if len(s) == 0:
     175        result = answer
     176    else:
     177        result = {}
     178        for (e, r) in answer:
     179            old_coeff = answer[(e,r)]
     180            # Milnor multiplication for r and s
     181            rows = len(r) + 1
     182            cols = len(s) + 1
     183            diags = len(r) + len(s)
     184            # initialize matrix
     185            M = range(rows)
     186            for i in range(rows):
     187                M[i] = [0]*cols
     188            for j in range(1,cols):
     189                M[0][j] = s[j-1]
     190            for i in range(1,rows):
     191                M[i][0] = r[i-1]
     192                for j in range(1,cols):
     193                    M[i][j] = 0
     194            found = True
     195            while found:
     196                # check diagonals
     197                n = 1
     198                coeff = old_coeff
     199                diagonal = [0]*diags
     200                while n <= diags and coeff != 0:
     201                    nth_diagonal = [M[i][n-i] for i in range(max(0,n-cols+1), min(1+n,rows))]
     202                    coeff = coeff * multinomial_odd(nth_diagonal,p)
     203                    diagonal[n-1] = sum(nth_diagonal)
     204                    n = n + 1
     205                if coeff != 0:
     206                    i = diags - 1
     207                    while i >= 0 and diagonal[i] == 0:
     208                        i = i - 1
     209                    t = tuple(diagonal[:i+1])
     210                    if result.has_key((e,t)):
     211                        result[(e,t)] = F(coeff + result[t])
     212                    else:
     213                        result[(e,t)] = F(coeff)
     214                    # now look for new matrices:
     215                found = False
     216                i = 1
     217                while not found and i < rows:
     218                    temp_sum = M[i][0]
     219                    j = 1
     220                    while not found and j < cols:
     221                        # check to see if column index j is small enough
     222                        if temp_sum >= p**j:
     223                            # now check to see if there's anything above this entry
     224                            # to add to it
     225                            temp_col_sum = 0
     226                            for k in range(i):
     227                                temp_col_sum += M[k][j]
     228                            if temp_col_sum != 0:
     229                                found = True
     230                                for row in range(1,i):
     231                                    M[row][0] = r[row-1]
     232                                    for col in range(1,cols):
     233                                        M[0][col] = M[0][col] + M[row][col]
     234                                        M[row][col] = 0
     235                                for col in range(1,j):
     236                                    M[0][col] = M[0][col] + M[i][col]
     237                                    M[i][col] = 0
     238                                M[0][j] = M[0][j] - 1
     239                                M[i][j] = M[i][j] + 1
     240                                M[i][0] = temp_sum - p**j
     241                            else:
     242                                temp_sum += M[i][j] * p**j
     243                        else:
     244                            temp_sum += M[i][j] * p**j
     245                        j = j + 1
     246                    i = i + 1
     247    return result
     248
     249
     250def multinomial_odd(list,p):
     251    """
     252    Multinomial coefficient of list, mod p.
     253
     254    INPUT:
     255        list -- list of integers
     256        p -- a prime number
     257
     258    OUTPUT:
     259        Associated multinomial coefficient, mod p
     260
     261    Given the input $[n_1, n_2, n_3, ...]$, this computes the
     262    multinomial coefficient $(n_1 + n_2 + n_3 + ...)! / (n_1! n_2!
     263    n_3! ...)$, mod $p$.  The method is this: expand each $n_i$ in
     264    base $p$: $n_i = \sum_j p^j n_{ij}$.  Do the same for the sum of
     265    the $n_i$'s, which we call $m$: $m = \sum_j p^j m_j$.  Then the
     266    multinomial coefficient is congruent, mod $p$, to the product of
     267    the multinomial coefficients $m_j! / (n_{1j}! n_{2j}! ...)$.
     268
     269    Furthermore, any multinomial coefficient $m! / (n_1! n_2! ...)$
     270    can be computed as a product of binomial coefficients: it equals
     271    \[
     272    \binom{n_1}{n_1} \binom{n_1 + n_2}{n_2} \binom{n_1 + n_2 + n_3}{n_3} ...
     273    \]
     274    This is convenient because Sage's binomial function returns
     275    integers, not rational numbers (as would be produced just by
     276    dividing factorials).
     277   
     278    EXAMPLES:
     279        sage: from sage.algebras.steenrod_milnor_multiplication_odd import multinomial_odd
     280        sage: multinomial_odd([1,2,4], 2)
     281        1
     282        sage: multinomial_odd([1,2,4], 7)
     283        0
     284        sage: multinomial_odd([1,2,4], 11)
     285        6
     286        sage: multinomial_odd([1,2,4], 101)
     287        4
     288        sage: multinomial_odd([1,2,4], 107)
     289        105
     290    """
     291    from sage.rings.arith import factorial
     292    from sage.rings.all import GF
     293    from sage.rings.arith import binomial
     294    from sage.algebras.steenrod_algebra_element import base_p_expansion
     295    n = sum(list)
     296    answer = 1
     297    F = GF(p)
     298    n_expansion = base_p_expansion(n,p)
     299    list_expansion = [base_p_expansion(k,p) for k in list]
     300    index = 0
     301    while answer != 0 and index < len(n_expansion):
     302        multi = F(1)
     303        partial_sum = 0
     304        for exp in list_expansion:
     305            if index < len(exp):
     306                partial_sum = partial_sum + exp[index]
     307                multi = F(multi * binomial(partial_sum, exp[index]))
     308        answer = F(answer * multi)
     309        index += 1
     310    return answer