The Steenrod algebra - Algebras

Skip to content
Back to top
View this page
Edit this page

# The Steenrod algebra

AUTHORS:

- John H. Palmieri (2008-07-30): version 0.9: Initial implementation.

- John H. Palmieri (2010-06-30): version 1.0: Implemented sub-Hopf algebras and profile functions; direct multiplication of admissible sequences (rather than conversion to the Milnor basis); implemented the Steenrod algebra using CombinatorialFreeModule; improved the test suite.

This module defines the mod \(p\) Steenrod algebra \(\mathcal{A}_p\), some of its properties, and ways to define elements of it.

From a topological point of view, \(\mathcal{A}_p\) is the algebra of stable cohomology operations on mod \(p\) cohomology; thus for any topological space \(X\), its mod \(p\) cohomology algebra \(H^*(X,\mathbf{F}_p)\) is a module over \(\mathcal{A}_p\).

From an algebraic point of view, \(\mathcal{A}_p\) is an \(\mathbf{F}_p\)-algebra; when \(p=2\), it is generated by elements \(\text{Sq}^i\) for \(i\geq 0\) (the Steenrod squares), and when \(p\) is odd, it is generated by elements \(\mathcal{P}^i\) for \(i \geq 0\) (the Steenrod reduced `p`-th powers) along with an element \(\beta\) (the mod p Bockstein). The Steenrod algebra is graded: \(\text{Sq}^i\) is in degree \(i\) for each \(i\), \(\beta\) is in degree 1, and \(\mathcal{P}^i\) is in degree \(2(p-1)i\).

The unit element is \(\text{Sq}^0\) when \(p=2\) and \(\mathcal{P}^0\) when \(p\) is odd. The generating elements also satisfy the Adem relations. At the prime 2, these have the form

\[\text{Sq}^a \text{Sq}^b = \sum_{c=0}^{[a/2]} \binom{b-c-1}{a-2c} \text{Sq}^{a+b-c} \text{Sq}^c.\]

At odd primes, they are a bit more complicated; see Steenrod and Epstein [SE1962] or `sage.algebras.steenrod.steenrod_algebra_bases` for full details. These relations lead to the existence of the Serre-Cartan basis for \(\mathcal{A}_p\).

The mod \(p\) Steenrod algebra has the structure of a Hopf algebra, and Milnor [Mil1958] has a beautiful description of the dual, leading to a construction of the Milnor basis for \(\mathcal{A}_p\). In this module, elements in the Steenrod algebra are represented, by default, using the Milnor basis.

Bases for the Steenrod algebra

There are a handful of other bases studied in the literature; the paper by Monks [Mon1998] is a good reference. Here is a quick summary:

- The Milnor basis. When \(p=2\), the Milnor basis consists of symbols of the form \(\text{Sq}(m_1, m_2, ..., m_t)\), where each \(m_i\) is a nonnegative integer and if \(t>1\), then the last entry \(m_t > 0\). When \(p\) is odd, the Milnor basis consists of symbols of the form \(Q_{e_1} Q_{e_2} ... \mathcal{P}(m_1, m_2, ..., m_t)\), where \(0 \leq e_1 < e_2 < ...\), each \(m_i\) is a nonnegative integer, and if \(t>1\), then the last entry \(m_t > 0\).

  When \(p=2\), it can be convenient to use the notation \(\mathcal{P}(-)\) to mean \(\text{Sq}(-)\), so that there is consistent notation for all primes.

- The Serre-Cartan basis. This basis consists of ‘admissible monomials’ in the Steenrod operations. Thus at the prime 2, it consists of monomials \(\text{Sq}^{m_1} \text{Sq}^{m_2} ... \text{Sq}^{m_t}\) with \(m_i \geq 2m_{i+1}\) for each \(i\). At odd primes, this basis consists of monomials \(\beta^{\epsilon_0} \mathcal{P}^{s_1} \beta^{\epsilon_1} \mathcal{P}^{s_2} ... \mathcal{P}^{s_k} \beta^{\epsilon_k}\) with each \(\epsilon_i\) either 0 or 1, \(s_i \geq p s_{i+1} + \epsilon_i\), and \(s_k \geq 1\).

Most of the rest of the bases are only defined when \(p=2\). The only exceptions are the \(P^s_t\)-bases and the commutator bases, which are defined at all primes.

- Wood’s Y basis. For pairs of nonnegative integers \((m,k)\), let \(w(m,k) = \text{Sq}^{2^m (2^{k+1}-1)}\). Wood’s \(Y\) basis consists of monomials \(w(m_0,k_0) ... w(m_t, k_t)\) with \((m_i,k_i) > (m_{i+1},k_{i+1})\), in left lex order.

- Wood’s Z basis. For pairs of nonnegative integers \((m,k)\), let \(w(m,k) = \text{Sq}^{2^m (2^{k+1}-1)}\). Wood’s \(Z\) basis consists of monomials \(w(m_0,k_0) ... w(m_t, k_t)\) with \((m_i+k_i,m_i) > (m_{i+1}+k_{i+1},m_{i+1})\), in left lex order.

- Wall’s basis. For any pair of integers \((m,k)\) with \(m \geq k \geq 0\), let \(Q^m_k = \text{Sq}^{2^k} \text{Sq}^{2^{k+1}} ... \text{Sq}^{2^m}\). The elements of Wall’s basis are monomials \(Q^{m_0}_{k_0} ... Q^{m_t}_{k_t}\) with \((m_i, k_i) > (m_{i+1}, k_{i+1})\), ordered left lexicographically.

  (Note that \(Q^m_k\) is the reverse of the element \(X^m_k\) used in defining Arnon’s A basis.)

- Arnon’s A basis. For any pair of integers \((m,k)\) with \(m \geq k \geq 0\), let \(X^m_k = \text{Sq}^{2^m} \text{Sq}^{2^{m-1}} ... \text{Sq}^{2^k}\). The elements of Arnon’s A basis are monomials \(X^{m_0}_{k_0} ... X^{m_t}_{k_t}\) with \((m_i, k_i) < (m_{i+1}, k_{i+1})\), ordered left lexicographically.

  (Note that \(X^m_k\) is the reverse of the element \(Q^m_k\) used in defining Wall’s basis.)

- Arnon’s C basis. The elements of Arnon’s C basis are monomials of the form \(\text{Sq}^{t_1} ... \text{Sq}^{t_m}\) where for each \(i\), we have \(t_i \leq 2t_{i+1}\) and \(2^i | t_{m-i}\).

- \(P^s_t\) bases. Let \(p=2\). For integers \(s \geq 0\) and \(t > 0\), the element \(P^s_t\) is the Milnor basis element \(\mathcal{P}(0, ..., 0, p^s, 0, ...)\), with the nonzero entry in position \(t\). To obtain a \(P^s_t\)-basis, for each set \(\{P^{s_1}_{t_1}, ..., P^{s_k}_{t_k}\}\) of (distinct) \(P^s_t\)’s, one chooses an ordering and forms the monomials

  \[(P^{s_1}_{t_1})^{i_1} ... (P^{s_k}_{t_k})^{i_k}\]

  for all exponents \(i_j\) with \(0 < i_j < p\). When \(p=2\), the set of all such monomials then forms a basis, and when \(p\) is odd, if one multiplies each such monomial on the left by products of the form \(Q_{e_1} Q_{e_2} ...\) with \(0 \leq e_1 < e_2 < ...\), one obtains a basis.

  Thus one gets a basis by choosing an ordering on each set of \(P^s_t\)’s. There are infinitely many orderings possible, and we have implemented four of them:

  - ‘rlex’: right lexicographic ordering

  - ‘llex’: left lexicographic ordering

  - ‘deg’: ordered by degree, which is the same as left lexicographic ordering on the pair \((s+t,t)\)

  - ‘revz’: left lexicographic ordering on the pair \((s+t,s)\), which is the reverse of the ordering used (on elements in the same degrees as the \(P^s_t\)’s) in Wood’s Z basis: ‘revz’ stands for ‘reversed Z’. This is the default: ‘pst’ is the same as ‘pst_revz’.

- Commutator bases. Let \(c_{i,1} = \mathcal{P}(p^i)\), let \(c_{i,2} = [c_{i+1,1}, c_{i,1}]\), and inductively define \(c_{i,k} = [c_{i+k-1,1}, c_{i,k-1}]\). Thus \(c_{i,k}\) is a \(k\)-fold iterated commutator of the elements \(\mathcal{P}(p^i)\), …, \(\mathcal{P}(p^{i+k-1})\). Note that \(\dim c_{i,k} = \dim P^i_k\).

  Commutator bases are obtained in much the same way as \(P^s_t\)-bases: for each set \(\{c_{s_1,t_1}, ..., c_{s_k,t_k}\}\) of (distinct) \(c_{s,t}\)’s, one chooses an ordering and forms the resulting monomials

  \[c_{s_1, t_1}^{i_1} ... c_{s_k,t_k}^{i_k}\]

  for all exponents \(i_j\) with \(0 < i_j < p\). When \(p\) is odd, one also needs to left-multiply by products of the \(Q_i\)’s. As for \(P^s_t\)-bases, every ordering on each set of iterated commutators determines a basis, and the same four orderings have been defined for these bases as for the \(P^s_t\) bases: ‘rlex’, ‘llex’, ‘deg’, ‘revz’.

Sub-Hopf algebras of the Steenrod algebra

The sub-Hopf algebras of the Steenrod algebra have been classified. Milnor proved that at the prime 2, the dual of the Steenrod algebra \(A_*\) is isomorphic to a polynomial algebra

\[A_* \cong \GF{2} [\xi_1, \xi_2, \xi_3, ...].\]

The Milnor basis is dual to the monomial basis. Furthermore, any sub-Hopf algebra corresponds to a quotient of this of the form

\[A_* /(\xi_1^{2^{e_1}}, \xi_2^{2^{e_2}}, \xi_3^{2^{e_3}}, ...).\]

The list of exponents \((e_1, e_2, ...)\) may be considered a function \(e\) from the positive integers to the extended nonnegative integers (the nonnegative integers and \(\infty\)); this is called the profile function for the sub-Hopf algebra. The profile function must satisfy the condition

- \(e(r) \geq \min( e(r-i) - i, e(i))\) for all \(0 < i < r\).

At odd primes, the situation is similar: the dual is isomorphic to the tensor product of a polynomial algebra and an exterior algebra,

\[A_* = \GF{p} [\xi_1, \xi_2, \xi_3, ...] \otimes \Lambda (\tau_0, \tau_1, ...),\]

and any sub-Hopf algebra corresponds to a quotient of this of the form

\[A_* / (\xi_1^{p^{e_1}}, \xi_2^{p^{e_2}}, ...; \tau_0^{k_0}, \tau_1^{k_1}, ...).\]

Here the profile function has two pieces, \(e\) as at the prime 2, and \(k\), which maps the nonnegative integers to the set \(\{1, 2\}\). These must satisfy the following conditions:

- \(e(r) \geq \min( e(r-i) - i, e(i))\) for all \(0 < i < r\).

- if \(k(i+j) = 1\), then either \(e(i) \leq j\) or \(k(j) = 1\) for all \(i \geq 1\), \(j \geq 0\).

(See Adams-Margolis [AM1974], for example, for these results on profile functions.)

This module allows one to construct the Steenrod algebra or any of its sub-Hopf algebras, at any prime. When defining a sub-Hopf algebra, you must work with the Milnor basis or a \(P^s_t\)-basis.

Elements of the Steenrod algebra

Basic arithmetic, \(p=2\). To construct an element of the mod 2 Steenrod algebra, use the function `Sq`:

Sage

    sage: a = Sq(1,2)
    sage: b = Sq(4,1)
    sage: z = a + b
    sage: z
    Sq(1,2) + Sq(4,1)
    sage: Sq(4) * Sq(1,2)
    Sq(1,1,1) + Sq(2,3) + Sq(5,2)
    sage: z**2          # nonnegative exponents work as they should
    Sq(1,2,1) + Sq(4,1,1)
    sage: z**0
    1

Python

    >>> from sage.all import *
    >>> a = Sq(Integer(1),Integer(2))
    >>> b = Sq(Integer(4),Integer(1))
    >>> z = a + b
    >>> z
    Sq(1,2) + Sq(4,1)
    >>> Sq(Integer(4)) * Sq(Integer(1),Integer(2))
    Sq(1,1,1) + Sq(2,3) + Sq(5,2)
    >>> z**Integer(2)          # nonnegative exponents work as they should
    Sq(1,2,1) + Sq(4,1,1)
    >>> z**Integer(0)
    1

Basic arithmetic, \(p>2\). To construct an element of the mod \(p\) Steenrod algebra when \(p\) is odd, you should first define a Steenrod algebra, using the `SteenrodAlgebra` command:

Sage

    sage: A3 = SteenrodAlgebra(3)

[Python]

    >>> from sage.all import *
    >>> A3 = SteenrodAlgebra(Integer(3))

Having done this, the newly created algebra `A3` has methods `Q` and `P` which construct elements of `A3`:

Sage

    sage: c = A3.Q(1,3,6); c
    Q_1 Q_3 Q_6
    sage: d = A3.P(2,0,1); d
    P(2,0,1)
    sage: c * d
    Q_1 Q_3 Q_6 P(2,0,1)
    sage: e = A3.P(3)
    sage: d * e
    P(5,0,1)
    sage: e * d
    P(1,1,1) + P(5,0,1)
    sage: c * c
    0
    sage: e ** 3
    2 P(1,2)

Python

    >>> from sage.all import *
    >>> c = A3.Q(Integer(1),Integer(3),Integer(6)); c
    Q_1 Q_3 Q_6
    >>> d = A3.P(Integer(2),Integer(0),Integer(1)); d
    P(2,0,1)
    >>> c * d
    Q_1 Q_3 Q_6 P(2,0,1)
    >>> e = A3.P(Integer(3))
    >>> d * e
    P(5,0,1)
    >>> e * d
    P(1,1,1) + P(5,0,1)
    >>> c * c
    0
    >>> e ** Integer(3)
    2 P(1,2)

Note that one can construct an element like `c` above in one step, without first constructing the algebra:

Sage

    sage: c = SteenrodAlgebra(3).Q(1,3,6)
    sage: c
    Q_1 Q_3 Q_6

[Python]

    >>> from sage.all import *
    >>> c = SteenrodAlgebra(Integer(3)).Q(Integer(1),Integer(3),Integer(6))
    >>> c
    Q_1 Q_3 Q_6

And of course, you can do similar constructions with the mod 2 Steenrod algebra:

Sage

    sage: A = SteenrodAlgebra(2); A
    mod 2 Steenrod algebra, milnor basis
    sage: A.Sq(2,3,5)
    Sq(2,3,5)
    sage: A.P(2,3,5)   # when p=2, P = Sq
    Sq(2,3,5)
    sage: A.Q(1,4)     # when p=2, this gives a product of Milnor primitives
    Sq(0,1,0,0,1)

Python

    >>> from sage.all import *
    >>> A = SteenrodAlgebra(Integer(2)); A
    mod 2 Steenrod algebra, milnor basis
    >>> A.Sq(Integer(2),Integer(3),Integer(5))
    Sq(2,3,5)
    >>> A.P(Integer(2),Integer(3),Integer(5))   # when p=2, P = Sq
    Sq(2,3,5)
    >>> A.Q(Integer(1),Integer(4))     # when p=2, this gives a product of Milnor primitives
    Sq(0,1,0,0,1)

Associated to each element is its prime (the characteristic of the underlying base field) and its basis (the basis for the Steenrod algebra in which it lies):

Sage

    sage: a = SteenrodAlgebra(basis='milnor').Sq(1,2,1)
    sage: a.prime()
    2
    sage: a.basis_name()
    'milnor'
    sage: a.degree()
    14

[Python]

    >>> from sage.all import *
    >>> a = SteenrodAlgebra(basis='milnor').Sq(Integer(1),Integer(2),Integer(1))
    >>> a.prime()
    2
    >>> a.basis_name()
    'milnor'
    >>> a.degree()
    14

It can be viewed in other bases:

Sage

    sage: a.milnor() # same as a
    Sq(1,2,1)
    sage: a.change_basis('adem')
    Sq^9 Sq^4 Sq^1 + Sq^11 Sq^2 Sq^1 + Sq^13 Sq^1
    sage: a.change_basis('adem').change_basis('milnor')
    Sq(1,2,1)

Python

    >>> from sage.all import *
    >>> a.milnor() # same as a
    Sq(1,2,1)
    >>> a.change_basis('adem')
    Sq^9 Sq^4 Sq^1 + Sq^11 Sq^2 Sq^1 + Sq^13 Sq^1
    >>> a.change_basis('adem').change_basis('milnor')
    Sq(1,2,1)

Regardless of the prime, each element has an `excess`, and if the element is homogeneous, a `degree`. The excess of \(\text{Sq}(i_1,i_2,i_3,...)\) is \(i_1 + i_2 + i_3 + ...\); when \(p\) is odd, the excess of \(Q_{0}^{e_0} Q_{1}^{e_1} ... \mathcal{P}(r_1, r_2, ...)\) is \(\sum e_i + 2 \sum r_i\). The excess of a linear combination of Milnor basis elements is the minimum of the excesses of those basis elements.

The degree of \(\text{Sq}(i_1,i_2,i_3,...)\) is \(\sum (2^n-1) i_n\), and when \(p\) is odd, the degree of \(Q_{0}^{\epsilon_0} Q_{1}^{\epsilon_1} ... \mathcal{P}(r_1, r_2, ...)\) is \(\sum \epsilon_i (2p^i - 1) + \sum r_j (2p^j - 2)\). The degree of a linear combination of such terms is only defined if the terms all have the same degree.

Here are some simple examples:

Sage

    sage: z = Sq(1,2) + Sq(4,1)
    sage: z.degree()
    7
    sage: (Sq(0,0,1) + Sq(5,3)).degree()
    Traceback (most recent call last):
    ...
    ValueError: element is not homogeneous
    sage: Sq(7,2,1).excess()
    10
    sage: z.excess()
    3
    sage: B = SteenrodAlgebra(3)
    sage: x = B.Q(1,4)
    sage: y = B.P(1,2,3)
    sage: x.degree()
    166
    sage: x.excess()
    2
    sage: y.excess()
    12

[Python]

    >>> from sage.all import *
    >>> z = Sq(Integer(1),Integer(2)) + Sq(Integer(4),Integer(1))
    >>> z.degree()
    7
    >>> (Sq(Integer(0),Integer(0),Integer(1)) + Sq(Integer(5),Integer(3))).degree()
    Traceback (most recent call last):
    ...
    ValueError: element is not homogeneous
    >>> Sq(Integer(7),Integer(2),Integer(1)).excess()
    10
    >>> z.excess()
    3
    >>> B = SteenrodAlgebra(Integer(3))
    >>> x = B.Q(Integer(1),Integer(4))
    >>> y = B.P(Integer(1),Integer(2),Integer(3))
    >>> x.degree()
    166
    >>> x.excess()
    2
    >>> y.excess()
    12

Elements have a `weight` in the May filtration, which (when \(p=2\)) is related to the `height` function defined by Wall:

Sage

    sage: Sq(2,1,5).may_weight()
    9
    sage: Sq(2,1,5).wall_height()
    [2, 3, 2, 1, 1]
    sage: b = Sq(4)*Sq(8) + Sq(8)*Sq(4)
    sage: b.may_weight()
    2
    sage: b.wall_height()
    [0, 0, 1, 1]

Python

    >>> from sage.all import *
    >>> Sq(Integer(2),Integer(1),Integer(5)).may_weight()
    9
    >>> Sq(Integer(2),Integer(1),Integer(5)).wall_height()
    [2, 3, 2, 1, 1]
    >>> b = Sq(Integer(4))*Sq(Integer(8)) + Sq(Integer(8))*Sq(Integer(4))
    >>> b.may_weight()
    2
    >>> b.wall_height()
    [0, 0, 1, 1]

Odd primary May weights:

Sage

    sage: A5 = SteenrodAlgebra(5)
    sage: a = A5.Q(1,2,4)
    sage: b = A5.P(1,2,1)
    sage: a.may_weight()
    10
    sage: b.may_weight()
    8
    sage: (a * b).may_weight()
    18
    sage: A5.P(0,0,1).may_weight()
    3

[Python]

    >>> from sage.all import *
    >>> A5 = SteenrodAlgebra(Integer(5))
    >>> a = A5.Q(Integer(1),Integer(2),Integer(4))
    >>> b = A5.P(Integer(1),Integer(2),Integer(1))
    >>> a.may_weight()
    10
    >>> b.may_weight()
    8
    >>> (a * b).may_weight()
    18
    >>> A5.P(Integer(0),Integer(0),Integer(1)).may_weight()
    3

Since the Steenrod algebra is a Hopf algebra, every element has a coproduct and an antipode:

Sage

    sage: Sq(5).coproduct()
    1 # Sq(5) + Sq(1) # Sq(4) + Sq(2) # Sq(3) + Sq(3) # Sq(2) + Sq(4) # Sq(1) + Sq(5) # 1
    sage: Sq(5).antipode()
    Sq(2,1) + Sq(5)
    sage: d = Sq(0,0,1); d
    Sq(0,0,1)
    sage: d.antipode()
    Sq(0,0,1)
    sage: Sq(4).antipode()
    Sq(1,1) + Sq(4)
    sage: (Sq(4) * Sq(2)).antipode()
    Sq(6)
    sage: SteenrodAlgebra(7).P(3,1).antipode()
    P(3,1)

Python

    >>> from sage.all import *
    >>> Sq(Integer(5)).coproduct()
    1 # Sq(5) + Sq(1) # Sq(4) + Sq(2) # Sq(3) + Sq(3) # Sq(2) + Sq(4) # Sq(1) + Sq(5) # 1
    >>> Sq(Integer(5)).antipode()
    Sq(2,1) + Sq(5)
    >>> d = Sq(Integer(0),Integer(0),Integer(1)); d
    Sq(0,0,1)
    >>> d.antipode()
    Sq(0,0,1)
    >>> Sq(Integer(4)).antipode()
    Sq(1,1) + Sq(4)
    >>> (Sq(Integer(4)) * Sq(Integer(2))).antipode()
    Sq(6)
    >>> SteenrodAlgebra(Integer(7)).P(Integer(3),Integer(1)).antipode()
    P(3,1)

Applying the antipode twice returns the original element:

Sage

    sage: y = Sq(8)*Sq(4)
    sage: y == (y.antipode()).antipode()
    True

[Python]

    >>> from sage.all import *
    >>> y = Sq(Integer(8))*Sq(Integer(4))
    >>> y == (y.antipode()).antipode()
    True

Internal representation: you can use any element as an iterator (`for x in a: ...`), and the method `monomial_coefficients()` returns a dictionary with keys tuples representing basis elements and with corresponding value representing the coefficient of that term:

Sage

    sage: c = Sq(5).antipode(); c
    Sq(2,1) + Sq(5)
    sage: for mono, coeff in c: print((coeff, mono))
    (1, (5,))
    (1, (2, 1))
    sage: c.monomial_coefficients() == {(2, 1): 1, (5,): 1}
    True
    sage: sorted(c.monomials(), key=lambda x: tuple(x.support()))
    [Sq(2,1), Sq(5)]
    sage: sorted(c.support())
    [(2, 1), (5,)]
    sage: Adem = SteenrodAlgebra(basis='adem')
    sage: elt = Adem.Sq(10) + Adem.Sq(9) * Adem.Sq(1)
    sage: sorted(elt.monomials(), key=lambda x: tuple(x.support()))
    [Sq^9 Sq^1, Sq^10]

    sage: A7 = SteenrodAlgebra(p=7)
    sage: a = A7.P(1) * A7.P(1); a
    2 P(2)
    sage: a.leading_coefficient()
    2
    sage: a.leading_monomial()
    P(2)
    sage: a.leading_term()
    2 P(2)
    sage: a.change_basis('adem').monomial_coefficients()
    {(0, 2, 0): 2}

Python

    >>> from sage.all import *
    >>> c = Sq(Integer(5)).antipode(); c
    Sq(2,1) + Sq(5)
    >>> for mono, coeff in c: print((coeff, mono))
    (1, (5,))
    (1, (2, 1))
    >>> c.monomial_coefficients() == {(Integer(2), Integer(1)): Integer(1), (Integer(5),): Integer(1)}
    True
    >>> sorted(c.monomials(), key=lambda x: tuple(x.support()))
    [Sq(2,1), Sq(5)]
    >>> sorted(c.support())
    [(2, 1), (5,)]
    >>> Adem = SteenrodAlgebra(basis='adem')
    >>> elt = Adem.Sq(Integer(10)) + Adem.Sq(Integer(9)) * Adem.Sq(Integer(1))
    >>> sorted(elt.monomials(), key=lambda x: tuple(x.support()))
    [Sq^9 Sq^1, Sq^10]

    >>> A7 = SteenrodAlgebra(p=Integer(7))
    >>> a = A7.P(Integer(1)) * A7.P(Integer(1)); a
    2 P(2)
    >>> a.leading_coefficient()
    2
    >>> a.leading_monomial()
    P(2)
    >>> a.leading_term()
    2 P(2)
    >>> a.change_basis('adem').monomial_coefficients()
    {(0, 2, 0): 2}

The tuple in the previous output stands for the element \(\beta^0 P^2 \beta^0\), i.e., \(P^2\). Going in the other direction, if you want to specify a basis element by giving the corresponding tuple, you can use the `monomial()` method on the algebra:

Sage

    sage: SteenrodAlgebra(p=7, basis='adem').monomial((0, 2, 0))
    P^2
    sage: 10 * SteenrodAlgebra(p=7, basis='adem').monomial((0, 2, 0))
    3 P^2

[Python]

    >>> from sage.all import *
    >>> SteenrodAlgebra(p=Integer(7), basis='adem').monomial((Integer(0), Integer(2), Integer(0)))
    P^2
    >>> Integer(10) * SteenrodAlgebra(p=Integer(7), basis='adem').monomial((Integer(0), Integer(2), Integer(0)))
    3 P^2

In the following example, elements in Wood’s Z basis are certain products of the elements \(w(m,k) = \text{Sq}^{2^m (2^{k+1}-1)}\). Internally, each \(w(m,k)\) is represented by the pair \((m,k)\), and products of them are represented by tuples of such pairs.

Sage

    sage: A = SteenrodAlgebra(basis='wood_z')
    sage: t = ((2, 0), (0, 0))
    sage: A.monomial(t)
    Sq^4 Sq^1

Python

    >>> from sage.all import *
    >>> A = SteenrodAlgebra(basis='wood_z')
    >>> t = ((Integer(2), Integer(0)), (Integer(0), Integer(0)))
    >>> A.monomial(t)
    Sq^4 Sq^1

See the documentation for `SteenrodAlgebra()` for more details and examples.

sage.algebras.steenrod.steenrod_algebra.AA(n=None, p=2)

  This returns the Steenrod algebra \(A\) or its sub-Hopf algebra \(A(n)\).

  INPUT:

  - `n` – nonnegative integer (default: `None`)

  - `p` – prime number (default: 2)

  OUTPUT:

  If \(n\) is `None`, then return the full Steenrod algebra. Otherwise, return \(A(n)\).

  When \(p=2\), \(A(n)\) is the sub-Hopf algebra generated by the elements \(\text{Sq}^i\) for \(i \leq 2^n\). Its profile function is \((n+1, n, n-1, ...)\). When \(p\) is odd, \(A(n)\) is the sub-Hopf algebra generated by the elements \(Q_0\) and \(\mathcal{P}^i\) for \(i \leq p^{n-1}\). Its profile function is \(e=(n, n-1, n-2, ...)\) and \(k=(2, 2, ..., 2)\) (length \(n+1\)).

  EXAMPLES:

  Sage

      sage: from sage.algebras.steenrod.steenrod_algebra import AA as A
      sage: A()
      mod 2 Steenrod algebra, milnor basis
      sage: A(2)
      sub-Hopf algebra of mod 2 Steenrod algebra, milnor basis,
       profile function [3, 2, 1]
      sage: A(2, p=5)
      sub-Hopf algebra of mod 5 Steenrod algebra, milnor basis,
       profile function ([2, 1], [2, 2, 2])

  Python

      >>> from sage.all import *
      >>> from sage.algebras.steenrod.steenrod_algebra import AA as A
      >>> A()
      mod 2 Steenrod algebra, milnor basis
      >>> A(Integer(2))
      sub-Hopf algebra of mod 2 Steenrod algebra, milnor basis,
       profile function [3, 2, 1]
      >>> A(Integer(2), p=Integer(5))
      sub-Hopf algebra of mod 5 Steenrod algebra, milnor basis,
       profile function ([2, 1], [2, 2, 2])

sage.algebras.steenrod.steenrod_algebra.Sq(*nums)

  Milnor element Sq(a,b,c,…).

  INPUT:

  - `a`, `b`, `c`, … – nonnegative integers

  OUTPUT: element of the Steenrod algebra

  This returns the Milnor basis element \(\text{Sq}(a, b, c, ...)\).

  EXAMPLES:

  Sage

      sage: Sq(5)
      Sq(5)
      sage: Sq(5) + Sq(2,1) + Sq(5)  # addition is mod 2:
      Sq(2,1)
      sage: (Sq(4,3) + Sq(7,2)).degree()
      13

  Python

      >>> from sage.all import *
      >>> Sq(Integer(5))
      Sq(5)
      >>> Sq(Integer(5)) + Sq(Integer(2),Integer(1)) + Sq(Integer(5))  # addition is mod 2:
      Sq(2,1)
      >>> (Sq(Integer(4),Integer(3)) + Sq(Integer(7),Integer(2))).degree()
      13

  Entries must be nonnegative integers; otherwise, an error results.

  This function is a good way to define elements of the Steenrod algebra.

sage.algebras.steenrod.steenrod_algebra.SteenrodAlgebra(p=2, basis='milnor', generic='auto', **kwds)

  The mod \(p\) Steenrod algebra.

  INPUT:

  - `p` – positive prime integer (default: 2)

  - `basis` – string (default: `'milnor'`)

  - `profile` – a profile function in form specified below (default: `None`)

  - `truncation_type` – 0 or \(\infty\) or ‘auto’ (default: `'auto'`)

  - `precision` – integer or `None` (default: `None`)

  - `generic` – (default: `'auto'`)

  OUTPUT:

  mod \(p\) Steenrod algebra or one of its sub-Hopf algebras, elements of which are printed using `basis`

  See below for information about `basis`, `profile`, etc.

  EXAMPLES:

  Some properties of the Steenrod algebra are available:

  Sage

      sage: A = SteenrodAlgebra(2)
      sage: A.order()
      +Infinity
      sage: A.is_finite()
      False
      sage: A.is_commutative()
      False
      sage: A.is_noetherian()
      False
      sage: A.is_integral_domain()
      False
      sage: A.is_field()
      False
      sage: A.is_division_algebra()
      False
      sage: A.category()
      Category of supercocommutative super Hopf algebras
       with basis over Finite Field of size 2

  Python

      >>> from sage.all import *
      >>> A = SteenrodAlgebra(Integer(2))
      >>> A.order()
      +Infinity
      >>> A.is_finite()
      False
      >>> A.is_commutative()
      False
      >>> A.is_noetherian()
      False
      >>> A.is_integral_domain()
      False
      >>> A.is_field()
      False
      >>> A.is_division_algebra()
      False
      >>> A.category()
      Category of supercocommutative super Hopf algebras
       with basis over Finite Field of size 2

  There are methods for constructing elements of the Steenrod algebra:

  Sage

      sage: A2 = SteenrodAlgebra(2); A2
      mod 2 Steenrod algebra, milnor basis
      sage: A2.Sq(1,2,6)
      Sq(1,2,6)
      sage: A2.Q(3,4)  # product of Milnor primitives Q_3 and Q_4
      Sq(0,0,0,1,1)
      sage: A2.pst(2,3)  # Margolis pst element
      Sq(0,0,4)
      sage: A5 = SteenrodAlgebra(5); A5
      mod 5 Steenrod algebra, milnor basis
      sage: A5.P(1,2,6)
      P(1,2,6)
      sage: A5.Q(3,4)
      Q_3 Q_4
      sage: A5.Q(3,4) * A5.P(1,2,6)
      Q_3 Q_4 P(1,2,6)
      sage: A5.pst(2,3)
      P(0,0,25)

  [Python]

      >>> from sage.all import *
      >>> A2 = SteenrodAlgebra(Integer(2)); A2
      mod 2 Steenrod algebra, milnor basis
      >>> A2.Sq(Integer(1),Integer(2),Integer(6))
      Sq(1,2,6)
      >>> A2.Q(Integer(3),Integer(4))  # product of Milnor primitives Q_3 and Q_4
      Sq(0,0,0,1,1)
      >>> A2.pst(Integer(2),Integer(3))  # Margolis pst element
      Sq(0,0,4)
      >>> A5 = SteenrodAlgebra(Integer(5)); A5
      mod 5 Steenrod algebra, milnor basis
      >>> A5.P(Integer(1),Integer(2),Integer(6))
      P(1,2,6)
      >>> A5.Q(Integer(3),Integer(4))
      Q_3 Q_4
      >>> A5.Q(Integer(3),Integer(4)) * A5.P(Integer(1),Integer(2),Integer(6))
      Q_3 Q_4 P(1,2,6)
      >>> A5.pst(Integer(2),Integer(3))
      P(0,0,25)

  You can test whether elements are contained in the Steenrod algebra:

  Sage

      sage: w = Sq(2) * Sq(4)
      sage: w in SteenrodAlgebra(2)
      True
      sage: w in SteenrodAlgebra(17)
      False

  Python

      >>> from sage.all import *
      >>> w = Sq(Integer(2)) * Sq(Integer(4))
      >>> w in SteenrodAlgebra(Integer(2))
      True
      >>> w in SteenrodAlgebra(Integer(17))
      False

  Different bases for the Steenrod algebra:

  There are two standard vector space bases for the mod \(p\) Steenrod algebra: the Milnor basis and the Serre-Cartan basis. When \(p=2\), there are also several other, less well-known, bases. See the documentation for this module (type `sage.algebras.steenrod.steenrod_algebra?`) and the function `steenrod_algebra_basis` for full descriptions of each of the implemented bases.

  This module implements the following bases at all primes:

  - ‘milnor’: Milnor basis.

  - ‘serre-cartan’ or ‘adem’ or ‘admissible’: Serre-Cartan basis.

  - ‘pst’, ‘pst_rlex’, ‘pst_llex’, ‘pst_deg’, ‘pst_revz’: various \(P^s_t\)-bases.

  - ‘comm’, ‘comm_rlex’, ‘comm_llex’, ‘comm_deg’, ‘comm_revz’, or these with ‘_long’ appended: various commutator bases.

  It implements the following bases when \(p=2\):

  - ‘wood_y’: Wood’s Y basis.

  - ‘wood_z’: Wood’s Z basis.

  - ‘wall’, ‘wall_long’: Wall’s basis.

  - ‘arnon_a’, ‘arnon_a_long’: Arnon’s A basis.

  - ‘arnon_c’: Arnon’s C basis.

  When defining a Steenrod algebra, you can specify a basis. Then elements of that Steenrod algebra are printed in that basis:

  Sage

      sage: adem = SteenrodAlgebra(2, 'adem')
      sage: x = adem.Sq(2,1)  # Sq(-) always means a Milnor basis element
      sage: x
      Sq^4 Sq^1 + Sq^5
      sage: y = Sq(0,1)    # unadorned Sq defines elements w.r.t. Milnor basis
      sage: y
      Sq(0,1)
      sage: adem(y)
      Sq^2 Sq^1 + Sq^3
      sage: adem5 = SteenrodAlgebra(5, 'serre-cartan')
      sage: adem5.P(0,2)
      P^10 P^2 + 4 P^11 P^1 + P^12

  [Python]

      >>> from sage.all import *
      >>> adem = SteenrodAlgebra(Integer(2), 'adem')
      >>> x = adem.Sq(Integer(2),Integer(1))  # Sq(-) always means a Milnor basis element
      >>> x
      Sq^4 Sq^1 + Sq^5
      >>> y = Sq(Integer(0),Integer(1))    # unadorned Sq defines elements w.r.t. Milnor basis
      >>> y
      Sq(0,1)
      >>> adem(y)
      Sq^2 Sq^1 + Sq^3
      >>> adem5 = SteenrodAlgebra(Integer(5), 'serre-cartan')
      >>> adem5.P(Integer(0),Integer(2))
      P^10 P^2 + 4 P^11 P^1 + P^12

  If you add or multiply elements defined using different bases, the left-hand factor determines the form of the output:

  Sage

      sage: SteenrodAlgebra(basis='adem').Sq(3) + SteenrodAlgebra(basis='pst').Sq(0,1)
      Sq^2 Sq^1
      sage: SteenrodAlgebra(basis='pst').Sq(3) + SteenrodAlgebra(basis='milnor').Sq(0,1)
      P^0_1 P^1_1 + P^0_2
      sage: SteenrodAlgebra(basis='milnor').Sq(2) * SteenrodAlgebra(basis='arnonc').Sq(2)
      Sq(1,1)

  Python

      >>> from sage.all import *
      >>> SteenrodAlgebra(basis='adem').Sq(Integer(3)) + SteenrodAlgebra(basis='pst').Sq(Integer(0),Integer(1))
      Sq^2 Sq^1
      >>> SteenrodAlgebra(basis='pst').Sq(Integer(3)) + SteenrodAlgebra(basis='milnor').Sq(Integer(0),Integer(1))
      P^0_1 P^1_1 + P^0_2
      >>> SteenrodAlgebra(basis='milnor').Sq(Integer(2)) * SteenrodAlgebra(basis='arnonc').Sq(Integer(2))
      Sq(1,1)

  You can get a list of basis elements in a given dimension:

  Sage

      sage: A3 = SteenrodAlgebra(3, 'milnor')
      sage: A3.basis(13)
      Family (Q_1 P(2), Q_0 P(3))

  [Python]

      >>> from sage.all import *
      >>> A3 = SteenrodAlgebra(Integer(3), 'milnor')
      >>> A3.basis(Integer(13))
      Family (Q_1 P(2), Q_0 P(3))

  Algebras defined over different bases are not equal:

  Sage

      sage: SteenrodAlgebra(basis='milnor') == SteenrodAlgebra(basis='pst')
      False

  Python

      >>> from sage.all import *
      >>> SteenrodAlgebra(basis='milnor') == SteenrodAlgebra(basis='pst')
      False

  Bases have various synonyms, and in general Sage tries to figure out what basis you meant:

  Sage

      sage: SteenrodAlgebra(basis='MiLNOr')
      mod 2 Steenrod algebra, milnor basis
      sage: SteenrodAlgebra(basis='MiLNOr') == SteenrodAlgebra(basis='milnor')
      True
      sage: SteenrodAlgebra(basis='adem')
      mod 2 Steenrod algebra, serre-cartan basis
      sage: SteenrodAlgebra(basis='adem').basis_name()
      'serre-cartan'
      sage: SteenrodAlgebra(basis='wood---z---').basis_name()
      'woodz'

  [Python]

      >>> from sage.all import *
      >>> SteenrodAlgebra(basis='MiLNOr')
      mod 2 Steenrod algebra, milnor basis
      >>> SteenrodAlgebra(basis='MiLNOr') == SteenrodAlgebra(basis='milnor')
      True
      >>> SteenrodAlgebra(basis='adem')
      mod 2 Steenrod algebra, serre-cartan basis
      >>> SteenrodAlgebra(basis='adem').basis_name()
      'serre-cartan'
      >>> SteenrodAlgebra(basis='wood---z---').basis_name()
      'woodz'

  As noted above, several of the bases (‘arnon_a’, ‘wall’, ‘comm’) have alternate, sometimes longer, representations. These provide ways of expressing elements of the Steenrod algebra in terms of the \(\text{Sq}^{2^n}\).

  Sage

      sage: A_long = SteenrodAlgebra(2, 'arnon_a_long')
      sage: A_long(Sq(6))
      Sq^1 Sq^2 Sq^1 Sq^2 + Sq^2 Sq^4
      sage: SteenrodAlgebra(2, 'wall_long')(Sq(6))
      Sq^2 Sq^1 Sq^2 Sq^1 + Sq^2 Sq^4
      sage: SteenrodAlgebra(2, 'comm_deg_long')(Sq(6))
      s_1 s_2 s_12 + s_2 s_4

  Python

      >>> from sage.all import *
      >>> A_long = SteenrodAlgebra(Integer(2), 'arnon_a_long')
      >>> A_long(Sq(Integer(6)))
      Sq^1 Sq^2 Sq^1 Sq^2 + Sq^2 Sq^4
      >>> SteenrodAlgebra(Integer(2), 'wall_long')(Sq(Integer(6)))
      Sq^2 Sq^1 Sq^2 Sq^1 + Sq^2 Sq^4
      >>> SteenrodAlgebra(Integer(2), 'comm_deg_long')(Sq(Integer(6)))
      s_1 s_2 s_12 + s_2 s_4

  Sub-Hopf algebras of the Steenrod algebra:

  These are specified using the argument `profile`, along with, optionally, `truncation_type` and `precision`. The `profile` argument specifies the profile function for this algebra. Any sub-Hopf algebra of the Steenrod algebra is determined by its profile function. When \(p=2\), this is a map \(e\) from the positive integers to the set of nonnegative integers, plus \(\infty\), corresponding to the sub-Hopf algebra dual to this quotient of the dual Steenrod algebra:

  \[\GF{2} [\xi_1, \xi_2, \xi_3, ...] / (\xi_1^{2^{e(1)}}, \xi_2^{2^{e(2)}}, \xi_3^{2^{e(3)}}, ...).\]

  The profile function \(e\) must satisfy the condition

  - \(e(r) \geq \min( e(r-i) - i, e(i))\) for all \(0 < i < r\).

  This is specified via `profile`, and optionally `precision` and `truncation_type`. First, `profile` must have one of the following forms:

  - a list or tuple, e.g., `[3,2,1]`, corresponding to the function sending 1 to 3, 2 to 2, 3 to 1, and all other integers to the value of `truncation_type`.

  - a function from positive integers to nonnegative integers (and \(\infty\)), e.g., `lambda n: n+2`.

  - `None` or `Infinity` – use this for the profile function for the whole Steenrod algebra

  In the first and third cases, `precision` is ignored. In the second case, this function is converted to a tuple of length one less than `precision`, which has default value 100. The function is truncated at this point, and all remaining values are set to the value of `truncation_type`.

  `truncation_type` may be 0, \(\infty\), or ‘auto’. If it’s ‘auto’, then it gets converted to 0 in the first case above (when `profile` is a list), and otherwise (when `profile` is a function, `None`, or `Infinity`) it gets converted to \(\infty\).

  For example, the sub-Hopf algebra \(A(2)\) has profile function `[3,2,1,0,0,0,...]`, so it can be defined by any of the following:

  Sage

      sage: A2 = SteenrodAlgebra(profile=[3,2,1])
      sage: B2 = SteenrodAlgebra(profile=[3,2,1,0,0]) # trailing 0s ignored
      sage: A2 == B2
      True
      sage: C2 = SteenrodAlgebra(profile=lambda n: max(4-n, 0), truncation_type=0)
      sage: A2 == C2
      True

  [Python]

      >>> from sage.all import *
      >>> A2 = SteenrodAlgebra(profile=[Integer(3),Integer(2),Integer(1)])
      >>> B2 = SteenrodAlgebra(profile=[Integer(3),Integer(2),Integer(1),Integer(0),Integer(0)]) # trailing 0s ignored
      >>> A2 == B2
      True
      >>> C2 = SteenrodAlgebra(profile=lambda n: max(Integer(4)-n, Integer(0)), truncation_type=Integer(0))
      >>> A2 == C2
      True

  In the following case, the profile function is specified by a function and `truncation_type` isn’t specified, so it defaults to \(\infty\); therefore this gives a different sub-Hopf algebra:

  Sage

      sage: D2 = SteenrodAlgebra(profile=lambda n: max(4-n, 0))
      sage: A2 == D2
      False
      sage: D2.is_finite()
      False
      sage: E2 = SteenrodAlgebra(profile=lambda n: max(4-n, 0), truncation_type=Infinity)
      sage: D2 == E2
      True

  Python

      >>> from sage.all import *
      >>> D2 = SteenrodAlgebra(profile=lambda n: max(Integer(4)-n, Integer(0)))
      >>> A2 == D2
      False
      >>> D2.is_finite()
      False
      >>> E2 = SteenrodAlgebra(profile=lambda n: max(Integer(4)-n, Integer(0)), truncation_type=Infinity)
      >>> D2 == E2
      True

  The argument `precision` only needs to be specified if the profile function is defined by a function and you want to control when the profile switches from the given function to the truncation type. For example:

  Sage

      sage: D3 = SteenrodAlgebra(profile=lambda n: n, precision=3)
      sage: D3
      sub-Hopf algebra of mod 2 Steenrod algebra, milnor basis, profile function [1, 2, +Infinity, +Infinity, +Infinity, ...]
      sage: D4 = SteenrodAlgebra(profile=lambda n: n, precision=4); D4
      sub-Hopf algebra of mod 2 Steenrod algebra, milnor basis, profile function [1, 2, 3, +Infinity, +Infinity, +Infinity, ...]
      sage: D3 == D4
      False

  [Python]

      >>> from sage.all import *
      >>> D3 = SteenrodAlgebra(profile=lambda n: n, precision=Integer(3))
      >>> D3
      sub-Hopf algebra of mod 2 Steenrod algebra, milnor basis, profile function [1, 2, +Infinity, +Infinity, +Infinity, ...]
      >>> D4 = SteenrodAlgebra(profile=lambda n: n, precision=Integer(4)); D4
      sub-Hopf algebra of mod 2 Steenrod algebra, milnor basis, profile function [1, 2, 3, +Infinity, +Infinity, +Infinity, ...]
      >>> D3 == D4
      False

  When \(p\) is odd, `profile` is a pair of functions \(e\) and \(k\), corresponding to the quotient

  \[\GF{p} [\xi_1, \xi_2, \xi_3, ...] \otimes \Lambda (\tau_0, \tau_1, ...) / (\xi_1^{p^{e_1}}, \xi_2^{p^{e_2}}, ...; \tau_0^{k_0}, \tau_1^{k_1}, ...).\]

  Together, the functions \(e\) and \(k\) must satisfy the conditions

  - \(e(r) \geq \min( e(r-i) - i, e(i))\) for all \(0 < i < r\),

  - if \(k(i+j) = 1\), then either \(e(i) \leq j\) or \(k(j) = 1\) for all \(i \geq 1\), \(j \geq 0\).

  Therefore `profile` must have one of the following forms:

  - a pair of lists or tuples, the second of which takes values in the set \(\{1,2\}\), e.g., `([3,2,1,1], [1,1,2,2,1])`.

  - a pair of functions, one from the positive integers to nonnegative integers (and \(\infty\)), one from the nonnegative integers to the set \(\{1,2\}\), e.g., `(lambda n: n+2, lambda n: 1 if n<3 else 2)`.

  - `None` or `Infinity` – use this for the profile function for the whole Steenrod algebra

  You can also mix and match the first two, passing a pair with first entry a list and second entry a function, for instance. The values of `precision` and `truncation_type` are determined by the first entry.

  More examples:

  Sage

      sage: E = SteenrodAlgebra(profile=lambda n: 0 if n<3 else 3, truncation_type=0)
      sage: E.is_commutative()
      True

      sage: A2 = SteenrodAlgebra(profile=[3,2,1]) # the algebra A(2)
      sage: Sq(7,3,1) in A2
      True
      sage: Sq(8) in A2
      False
      sage: Sq(8) in SteenrodAlgebra().basis(8)
      True
      sage: Sq(8) in A2.basis(8)
      False
      sage: A2.basis(8)
      Family (Sq(1,0,1), Sq(2,2), Sq(5,1))

      sage: A5 = SteenrodAlgebra(p=5)
      sage: A51 = SteenrodAlgebra(p=5, profile=([1], [2,2]))
      sage: A5.Q(0,1) * A5.P(4) in A51
      True
      sage: A5.Q(2) in A51
      False
      sage: A5.P(5) in A51
      False

  Python

      >>> from sage.all import *
      >>> E = SteenrodAlgebra(profile=lambda n: Integer(0) if n<Integer(3) else Integer(3), truncation_type=Integer(0))
      >>> E.is_commutative()
      True

      >>> A2 = SteenrodAlgebra(profile=[Integer(3),Integer(2),Integer(1)]) # the algebra A(2)
      >>> Sq(Integer(7),Integer(3),Integer(1)) in A2
      True
      >>> Sq(Integer(8)) in A2
      False
      >>> Sq(Integer(8)) in SteenrodAlgebra().basis(Integer(8))
      True
      >>> Sq(Integer(8)) in A2.basis(Integer(8))
      False
      >>> A2.basis(Integer(8))
      Family (Sq(1,0,1), Sq(2,2), Sq(5,1))

      >>> A5 = SteenrodAlgebra(p=Integer(5))
      >>> A51 = SteenrodAlgebra(p=Integer(5), profile=([Integer(1)], [Integer(2),Integer(2)]))
      >>> A5.Q(Integer(0),Integer(1)) * A5.P(Integer(4)) in A51
      True
      >>> A5.Q(Integer(2)) in A51
      False
      >>> A5.P(Integer(5)) in A51
      False

  For sub-Hopf algebras of the Steenrod algebra, only the Milnor basis or the various \(P^s_t\)-bases may be used.

  Sage

      sage: SteenrodAlgebra(profile=[1,2,1,1], basis='adem')
      Traceback (most recent call last):
      ...
      NotImplementedError: for sub-Hopf algebras of the Steenrod algebra, only the Milnor basis and the pst bases are implemented

  [Python]

      >>> from sage.all import *
      >>> SteenrodAlgebra(profile=[Integer(1),Integer(2),Integer(1),Integer(1)], basis='adem')
      Traceback (most recent call last):
      ...
      NotImplementedError: for sub-Hopf algebras of the Steenrod algebra, only the Milnor basis and the pst bases are implemented

  The generic Steenrod algebra at the prime \(2\):

  The structure formulas for the Steenrod algebra at odd primes \(p\) also make sense when \(p\) is set to \(2\). We refer to the resulting algebra as the “generic Steenrod algebra” for the prime \(2\). The dual Hopf algebra is given by

  > \[A_* = \GF{2} [\xi_1, \xi_2, \xi_3, ...] \otimes \Lambda (\tau_0, \tau_1, ...)\]

  The degree of \(\xi_k\) is \(2^{k+1}-2\) and the degree of \(\tau_k\) is \(2^{k+1}-1\).

  The generic Steenrod algebra is an associated graded algebra of the usual Steenrod algebra that is occasionally useful. Its cohomology, for example, is the \(E_2\)-term of a spectral sequence that computes the \(E_2\)-term of the Novikov spectral sequence. It can also be obtained as a specialisation of Voevodsky’s “motivic Steenrod algebra”: in the notation of [Voe2003], Remark 12.12, it corresponds to setting \(\rho = \tau = 0\). The usual Steenrod algebra is given by \(\rho = 0\) and \(\tau = 1\).

  In Sage this algebra is constructed using the ‘generic’ keyword.

  Example:

  Sage

      sage: EA = SteenrodAlgebra(p=2,generic=True) ; EA
      generic mod 2 Steenrod algebra, milnor basis
      sage: EA[8]
      Vector space spanned by (Q_0 Q_2, Q_0 Q_1 P(2), P(1,1), P(4))
       over Finite Field of size 2

  Python

      >>> from sage.all import *
      >>> EA = SteenrodAlgebra(p=Integer(2),generic=True) ; EA
      generic mod 2 Steenrod algebra, milnor basis
      >>> EA[Integer(8)]
      Vector space spanned by (Q_0 Q_2, Q_0 Q_1 P(2), P(1,1), P(4))
       over Finite Field of size 2

class sage.algebras.steenrod.steenrod_algebra.SteenrodAlgebra_generic(p=2, basis='milnor', **kwds)

  Bases: `CombinatorialFreeModule`

  The mod \(p\) Steenrod algebra.

  Users should not call this, but use the function `SteenrodAlgebra()` instead. See that function for extensive documentation.

  EXAMPLES:

  Sage

      sage: sage.algebras.steenrod.steenrod_algebra.SteenrodAlgebra_generic()
      mod 2 Steenrod algebra, milnor basis
      sage: sage.algebras.steenrod.steenrod_algebra.SteenrodAlgebra_generic(5)
      mod 5 Steenrod algebra, milnor basis
      sage: sage.algebras.steenrod.steenrod_algebra.SteenrodAlgebra_generic(5, 'adem')
      mod 5 Steenrod algebra, serre-cartan basis

  Python

      >>> from sage.all import *
      >>> sage.algebras.steenrod.steenrod_algebra.SteenrodAlgebra_generic()
      mod 2 Steenrod algebra, milnor basis
      >>> sage.algebras.steenrod.steenrod_algebra.SteenrodAlgebra_generic(Integer(5))
      mod 5 Steenrod algebra, milnor basis
      >>> sage.algebras.steenrod.steenrod_algebra.SteenrodAlgebra_generic(Integer(5), 'adem')
      mod 5 Steenrod algebra, serre-cartan basis

  class Element

    Bases: `IndexedFreeModuleElement`

    Class for elements of the Steenrod algebra. Since the Steenrod algebra class is based on `CombinatorialFreeModule`, this is based on `IndexedFreeModuleElement`. It has new methods reflecting its role, like `degree()` for computing the degree of an element.

    EXAMPLES:

    Since this class inherits from `IndexedFreeModuleElement`, elements can be used as iterators, and there are other useful methods:

    Sage

        sage: c = Sq(5).antipode(); c
        Sq(2,1) + Sq(5)
        sage: for mono, coeff in c: print((coeff, mono))
        (1, (5,))
        (1, (2, 1))
        sage: c.monomial_coefficients() == {(2, 1): 1, (5,): 1}
        True
        sage: sorted(c.monomials(), key=lambda x: tuple(x.support()))
        [Sq(2,1), Sq(5)]
        sage: sorted(c.support())
        [(2, 1), (5,)]

    Python

        >>> from sage.all import *
        >>> c = Sq(Integer(5)).antipode(); c
        Sq(2,1) + Sq(5)
        >>> for mono, coeff in c: print((coeff, mono))
        (1, (5,))
        (1, (2, 1))
        >>> c.monomial_coefficients() == {(Integer(2), Integer(1)): Integer(1), (Integer(5),): Integer(1)}
        True
        >>> sorted(c.monomials(), key=lambda x: tuple(x.support()))
        [Sq(2,1), Sq(5)]
        >>> sorted(c.support())
        [(2, 1), (5,)]

    See the documentation for this module (type `sage.algebras.steenrod.steenrod_algebra?`) for more information about elements of the Steenrod algebra.

    additive_order()

      The additive order of any nonzero element of the mod p Steenrod algebra is p.

      OUTPUT: 1 (for the zero element) or p (for anything else)

      EXAMPLES:

      Sage

          sage: z = Sq(4) + Sq(6) + 1
          sage: z.additive_order()
          2
          sage: (Sq(3) + Sq(3)).additive_order()
          1

      Python

          >>> from sage.all import *
          >>> z = Sq(Integer(4)) + Sq(Integer(6)) + Integer(1)
          >>> z.additive_order()
          2
          >>> (Sq(Integer(3)) + Sq(Integer(3))).additive_order()
          1

    basis_name()

      The basis name associated to `self`.

      EXAMPLES:

      Sage

          sage: a = SteenrodAlgebra().Sq(3,2,1)
          sage: a.basis_name()
          'milnor'
          sage: a.change_basis('adem').basis_name()
          'serre-cartan'
          sage: a.change_basis('wood____y').basis_name()
          'woody'
          sage: b = SteenrodAlgebra(p=7).basis(36)[0]
          sage: b.basis_name()
          'milnor'
          sage: a.change_basis('adem').basis_name()
          'serre-cartan'

      Python

          >>> from sage.all import *
          >>> a = SteenrodAlgebra().Sq(Integer(3),Integer(2),Integer(1))
          >>> a.basis_name()
          'milnor'
          >>> a.change_basis('adem').basis_name()
          'serre-cartan'
          >>> a.change_basis('wood____y').basis_name()
          'woody'
          >>> b = SteenrodAlgebra(p=Integer(7)).basis(Integer(36))[Integer(0)]
          >>> b.basis_name()
          'milnor'
          >>> a.change_basis('adem').basis_name()
          'serre-cartan'

    change_basis(basis='milnor')

      Representation of element with respect to basis.

      INPUT:

      - `basis` – string; basis in which to work

      OUTPUT: representation of `self` in given basis

      The choices for `basis` are:

      - ‘milnor’ for the Milnor basis.

      - ‘serre-cartan’, ‘serre_cartan’, ‘sc’, ‘adem’, ‘admissible’ for the Serre-Cartan basis.

      - ‘wood_y’ for Wood’s Y basis.

      - ‘wood_z’ for Wood’s Z basis.

      - ‘wall’ for Wall’s basis.

      - ‘wall_long’ for Wall’s basis, alternate representation

      - ‘arnon_a’ for Arnon’s A basis.

      - ‘arnon_a_long’ for Arnon’s A basis, alternate representation.

      - ‘arnon_c’ for Arnon’s C basis.

      - ‘pst’, ‘pst_rlex’, ‘pst_llex’, ‘pst_deg’, ‘pst_revz’ for various \(P^s_t\)-bases.

      - ‘comm’, ‘comm_rlex’, ‘comm_llex’, ‘comm_deg’, ‘comm_revz’ for various commutator bases.

      - ‘comm_long’, ‘comm_rlex_long’, etc., for commutator bases, alternate representations.

      See documentation for this module (by browsing the reference manual or by typing `sage.algebras.steenrod.steenrod_algebra?`) for descriptions of the different bases.

      EXAMPLES:

      Sage

          sage: c = Sq(2) * Sq(1)
          sage: c.change_basis('milnor')
          Sq(0,1) + Sq(3)
          sage: c.change_basis('serre-cartan')
          Sq^2 Sq^1
          sage: d = Sq(0,0,1)
          sage: d.change_basis('arnonc')
          Sq^2 Sq^5 + Sq^4 Sq^2 Sq^1 + Sq^4 Sq^3 + Sq^7

      Python

          >>> from sage.all import *
          >>> c = Sq(Integer(2)) * Sq(Integer(1))
          >>> c.change_basis('milnor')
          Sq(0,1) + Sq(3)
          >>> c.change_basis('serre-cartan')
          Sq^2 Sq^1
          >>> d = Sq(Integer(0),Integer(0),Integer(1))
          >>> d.change_basis('arnonc')
          Sq^2 Sq^5 + Sq^4 Sq^2 Sq^1 + Sq^4 Sq^3 + Sq^7

    coproduct(algorithm='milnor')

      The coproduct of this element.

      INPUT:

      - `algorithm` – `None` or a string, either ‘milnor’ or ‘serre-cartan’ (or anything which will be converted to one of these by the function `get_basis_name`). If `None`, default to ‘serre-cartan’ if current basis is ‘serre-cartan’; otherwise use ‘milnor’.

      See `SteenrodAlgebra_generic.coproduct_on_basis()` for more information on computing the coproduct.

      EXAMPLES:

      Sage

          sage: a = Sq(2)
          sage: a.coproduct()
          1 # Sq(2) + Sq(1) # Sq(1) + Sq(2) # 1
          sage: b = Sq(4)
          sage: (a*b).coproduct() == (a.coproduct()) * (b.coproduct())
          True

          sage: c = a.change_basis('adem'); c.coproduct(algorithm='milnor')
          1 # Sq^2 + Sq^1 # Sq^1 + Sq^2 # 1
          sage: c = a.change_basis('adem'); c.coproduct(algorithm='adem')
          1 # Sq^2 + Sq^1 # Sq^1 + Sq^2 # 1

          sage: d = a.change_basis('comm_long'); d.coproduct()
          1 # s_2 + s_1 # s_1 + s_2 # 1

          sage: A7 = SteenrodAlgebra(p=7)
          sage: a = A7.Q(1) * A7.P(1); a
          Q_1 P(1)
          sage: a.coproduct()
          1 # Q_1 P(1) + P(1) # Q_1 + Q_1 # P(1) + Q_1 P(1) # 1
          sage: a.coproduct(algorithm='adem')
          1 # Q_1 P(1) + P(1) # Q_1 + Q_1 # P(1) + Q_1 P(1) # 1

      Python

          >>> from sage.all import *
          >>> a = Sq(Integer(2))
          >>> a.coproduct()
          1 # Sq(2) + Sq(1) # Sq(1) + Sq(2) # 1
          >>> b = Sq(Integer(4))
          >>> (a*b).coproduct() == (a.coproduct()) * (b.coproduct())
          True

          >>> c = a.change_basis('adem'); c.coproduct(algorithm='milnor')
          1 # Sq^2 + Sq^1 # Sq^1 + Sq^2 # 1
          >>> c = a.change_basis('adem'); c.coproduct(algorithm='adem')
          1 # Sq^2 + Sq^1 # Sq^1 + Sq^2 # 1

          >>> d = a.change_basis('comm_long'); d.coproduct()
          1 # s_2 + s_1 # s_1 + s_2 # 1

          >>> A7 = SteenrodAlgebra(p=Integer(7))
          >>> a = A7.Q(Integer(1)) * A7.P(Integer(1)); a
          Q_1 P(1)
          >>> a.coproduct()
          1 # Q_1 P(1) + P(1) # Q_1 + Q_1 # P(1) + Q_1 P(1) # 1
          >>> a.coproduct(algorithm='adem')
          1 # Q_1 P(1) + P(1) # Q_1 + Q_1 # P(1) + Q_1 P(1) # 1

      Once you have an element of the tensor product, you may want to extract the tensor factors of its summands.

      Sage

          sage: b = Sq(2).coproduct()
          sage: b
          1 # Sq(2) + Sq(1) # Sq(1) + Sq(2) # 1
          sage: supp = sorted(b.support()); supp
          [((), (2,)), ((1,), (1,)), ((2,), ())]
          sage: Sq(*supp[0][0])
          1
          sage: Sq(*supp[0][1])
          Sq(2)
          sage: [(Sq(*x), Sq(*y)) for x, y in supp]
          [(1, Sq(2)), (Sq(1), Sq(1)), (Sq(2), 1)]

      [Python]

          >>> from sage.all import *
          >>> b = Sq(Integer(2)).coproduct()
          >>> b
          1 # Sq(2) + Sq(1) # Sq(1) + Sq(2) # 1
          >>> supp = sorted(b.support()); supp
          [((), (2,)), ((1,), (1,)), ((2,), ())]
          >>> Sq(*supp[Integer(0)][Integer(0)])
          1
          >>> Sq(*supp[Integer(0)][Integer(1)])
          Sq(2)
          >>> [(Sq(*x), Sq(*y)) for x, y in supp]
          [(1, Sq(2)), (Sq(1), Sq(1)), (Sq(2), 1)]

      The `support` of an element does not include the coefficients, so at odd primes it may be better to use `monomial_coefficients`:

      Sage

          sage: A3 = SteenrodAlgebra(p=3)
          sage: b = (A3.P(1)**2).coproduct()
          sage: b
          2*1 # P(2) + 2*P(1) # P(1) + 2*P(2) # 1
          sage: sorted(b.support())
          [(((), ()), ((), (2,))), (((), (1,)), ((), (1,))), (((), (2,)), ((), ()))]
          sage: b.monomial_coefficients()
          {(((), ()), ((), (2,))): 2,
           (((), (1,)), ((), (1,))): 2,
           (((), (2,)), ((), ())): 2}
          sage: mc = b.monomial_coefficients()
          sage: sorted([(A3.monomial(x), A3.monomial(y), mc[x,y]) for x, y in mc])
          [(1, P(2), 2), (P(1), P(1), 2), (P(2), 1, 2)]

      Python

          >>> from sage.all import *
          >>> A3 = SteenrodAlgebra(p=Integer(3))
          >>> b = (A3.P(Integer(1))**Integer(2)).coproduct()
          >>> b
          2*1 # P(2) + 2*P(1) # P(1) + 2*P(2) # 1
          >>> sorted(b.support())
          [(((), ()), ((), (2,))), (((), (1,)), ((), (1,))), (((), (2,)), ((), ()))]
          >>> b.monomial_coefficients()
          {(((), ()), ((), (2,))): 2,
           (((), (1,)), ((), (1,))): 2,
           (((), (2,)), ((), ())): 2}
          >>> mc = b.monomial_coefficients()
          >>> sorted([(A3.monomial(x), A3.monomial(y), mc[x,y]) for x, y in mc])
          [(1, P(2), 2), (P(1), P(1), 2), (P(2), 1, 2)]

    degree()

      The degree of `self`.

      The degree of \(\text{Sq}(i_1,i_2,i_3,...)\) is

      \[i_1 + 3i_2 + 7i_3 + ... + (2^k - 1) i_k + ....\]

      At an odd prime \(p\), the degree of \(Q_k\) is \(2p^k - 1\) and the degree of \(\mathcal{P}(i_1, i_2, ...)\) is

      \[\sum_{k \geq 0} 2(p^k - 1) i_k.\]

      ALGORITHM: If `is_homogeneous()` returns True, call `SteenrodAlgebra_generic.degree_on_basis()` on the leading summand.

      EXAMPLES:

      Sage

          sage: Sq(0,0,1).degree()
          7
          sage: (Sq(0,0,1) + Sq(7)).degree()
          7
          sage: (Sq(0,0,1) + Sq(2)).degree()
          Traceback (most recent call last):
          ...
          ValueError: element is not homogeneous

          sage: A11 = SteenrodAlgebra(p=11)
          sage: A11.P(1).degree()
          20
          sage: A11.P(1,1).degree()
          260
          sage: A11.Q(2).degree()
          241

      Python

          >>> from sage.all import *
          >>> Sq(Integer(0),Integer(0),Integer(1)).degree()
          7
          >>> (Sq(Integer(0),Integer(0),Integer(1)) + Sq(Integer(7))).degree()
          7
          >>> (Sq(Integer(0),Integer(0),Integer(1)) + Sq(Integer(2))).degree()
          Traceback (most recent call last):
          ...
          ValueError: element is not homogeneous

          >>> A11 = SteenrodAlgebra(p=Integer(11))
          >>> A11.P(Integer(1)).degree()
          20
          >>> A11.P(Integer(1),Integer(1)).degree()
          260
          >>> A11.Q(Integer(2)).degree()
          241

    excess()

      Excess of element.

      OUTPUT: `excess` – nonnegative integer

      The excess of a Milnor basis element \(\text{Sq}(a,b,c,...)\) is \(a + b + c + \cdots\). When \(p\) is odd, the excess of \(Q_{0}^{e_0} Q_{1}^{e_1} \cdots P(r_1, r_2, ...)\) is \(\sum e_i + 2 \sum r_i\). The excess of a linear combination of Milnor basis elements is the minimum of the excesses of those basis elements.

      See [Kr1971] for the proofs of these assertions.

      EXAMPLES:

      Sage

          sage: a = Sq(1,2,3)
          sage: a.excess()
          6
          sage: (Sq(0,0,1) + Sq(4,1) + Sq(7)).excess()
          1
          sage: elt = Sq(0,0,1) + Sq(4,1) + Sq(7)
          sage: M = sorted(elt.monomials(), key=lambda x: tuple(x.support()))
          sage: [m.excess() for m in M]
          [1, 5, 7]
          sage: [m for m in M]
          [Sq(0,0,1), Sq(4,1), Sq(7)]
          sage: B = SteenrodAlgebra(7)
          sage: a = B.Q(1,2,5)
          sage: b = B.P(2,2,3)
          sage: a.excess()
          3
          sage: b.excess()
          14
          sage: (a + b).excess()
          3
          sage: (a * b).excess()
          17

      Python

          >>> from sage.all import *
          >>> a = Sq(Integer(1),Integer(2),Integer(3))
          >>> a.excess()
          6
          >>> (Sq(Integer(0),Integer(0),Integer(1)) + Sq(Integer(4),Integer(1)) + Sq(Integer(7))).excess()
          1
          >>> elt = Sq(Integer(0),Integer(0),Integer(1)) + Sq(Integer(4),Integer(1)) + Sq(Integer(7))
          >>> M = sorted(elt.monomials(), key=lambda x: tuple(x.support()))
          >>> [m.excess() for m in M]
          [1, 5, 7]
          >>> [m for m in M]
          [Sq(0,0,1), Sq(4,1), Sq(7)]
          >>> B = SteenrodAlgebra(Integer(7))
          >>> a = B.Q(Integer(1),Integer(2),Integer(5))
          >>> b = B.P(Integer(2),Integer(2),Integer(3))
          >>> a.excess()
          3
          >>> b.excess()
          14
          >>> (a + b).excess()
          3
          >>> (a * b).excess()
          17

    is_decomposable()

      Return `True` if element is decomposable, `False` otherwise.

      That is, if element is in the square of the augmentation ideal, return `True`; otherwise, return `False`.

      OUTPUT: boolean

      EXAMPLES:

      Sage

          sage: a = Sq(6)
          sage: a.is_decomposable()
          True
          sage: for i in range(9):
          ....:     if not Sq(i).is_decomposable():
          ....:         print(Sq(i))
          1
          Sq(1)
          Sq(2)
          Sq(4)
          Sq(8)
          sage: A3 = SteenrodAlgebra(p=3, basis='adem')
          sage: [A3.P(n) for n in range(30) if not A3.P(n).is_decomposable()]
          [1, P^1, P^3, P^9, P^27]

      Python

          >>> from sage.all import *
          >>> a = Sq(Integer(6))
          >>> a.is_decomposable()
          True
          >>> for i in range(Integer(9)):
          ...     if not Sq(i).is_decomposable():
          ...         print(Sq(i))
          1
          Sq(1)
          Sq(2)
          Sq(4)
          Sq(8)
          >>> A3 = SteenrodAlgebra(p=Integer(3), basis='adem')
          >>> [A3.P(n) for n in range(Integer(30)) if not A3.P(n).is_decomposable()]
          [1, P^1, P^3, P^9, P^27]

    is_homogeneous()

      Return `True` iff this element is homogeneous.

      EXAMPLES:

      Sage

          sage: (Sq(0,0,1) + Sq(7)).is_homogeneous()
          True
          sage: (Sq(0,0,1) + Sq(2)).is_homogeneous()
          False

      Python

          >>> from sage.all import *
          >>> (Sq(Integer(0),Integer(0),Integer(1)) + Sq(Integer(7))).is_homogeneous()
          True
          >>> (Sq(Integer(0),Integer(0),Integer(1)) + Sq(Integer(2))).is_homogeneous()
          False

    is_nilpotent()

      Return `True` if element is not a unit, `False` otherwise.

      EXAMPLES:

      Sage

          sage: z = Sq(4,2) + Sq(7,1) + Sq(3,0,1)
          sage: z.is_nilpotent()
          True
          sage: u = 1 + Sq(3,1)
          sage: u == 1 + Sq(3,1)
          True
          sage: u.is_nilpotent()
          False

      Python

          >>> from sage.all import *
          >>> z = Sq(Integer(4),Integer(2)) + Sq(Integer(7),Integer(1)) + Sq(Integer(3),Integer(0),Integer(1))
          >>> z.is_nilpotent()
          True
          >>> u = Integer(1) + Sq(Integer(3),Integer(1))
          >>> u == Integer(1) + Sq(Integer(3),Integer(1))
          True
          >>> u.is_nilpotent()
          False

    is_unit()

      Return `True` if element has a nonzero scalar multiple of \(P(0)\) as a summand, `False` otherwise.

      EXAMPLES:

      Sage

          sage: z = Sq(4,2) + Sq(7,1) + Sq(3,0,1)
          sage: z.is_unit()
          False
          sage: u = Sq(0) + Sq(3,1)
          sage: u == 1 + Sq(3,1)
          True
          sage: u.is_unit()
          True
          sage: A5 = SteenrodAlgebra(5)
          sage: v = A5.P(0)
          sage: (v + v + v).is_unit()
          True

      Python

          >>> from sage.all import *
          >>> z = Sq(Integer(4),Integer(2)) + Sq(Integer(7),Integer(1)) + Sq(Integer(3),Integer(0),Integer(1))
          >>> z.is_unit()
          False
          >>> u = Sq(Integer(0)) + Sq(Integer(3),Integer(1))
          >>> u == Integer(1) + Sq(Integer(3),Integer(1))
          True
          >>> u.is_unit()
          True
          >>> A5 = SteenrodAlgebra(Integer(5))
          >>> v = A5.P(Integer(0))
          >>> (v + v + v).is_unit()
          True

    may_weight()

      May’s ‘weight’ of element.

      OUTPUT: `weight` – nonnegative integer

      If we let \(F_* (A)\) be the May filtration of the Steenrod algebra, the weight of an element \(x\) is the integer \(k\) so that \(x\) is in \(F_k(A)\) and not in \(F_{k+1}(A)\). According to Theorem 2.6 in May’s thesis [May1964], the weight of a Milnor basis element is computed as follows: first, to compute the weight of \(P(r_1,r_2, ...)\), write each \(r_i\) in base \(p\) as \(r_i = \sum_j p^j r_{ij}\). Then each nonzero binary digit \(r_{ij}\) contributes \(i\) to the weight: the weight is \(\sum_{i,j} i r_{ij}\). When \(p\) is odd, the weight of \(Q_i\) is \(i+1\), so the weight of a product \(Q_{i_1} Q_{i_2} ...\) equals \((i_1+1) + (i_2+1) + ...\). Then the weight of \(Q_{i_1} Q_{i_2} ...P(r_1,r_2, ...)\) is the sum of \((i_1+1) + (i_2+1) + ...\) and \(\sum_{i,j} i r_{ij}\).

      The weight of a sum of Milnor basis elements is the minimum of the weights of the summands.

      When \(p=2\), we compute the weight on Milnor basis elements by adding up the terms in their ‘height’ - see `wall_height()` for documentation. (When \(p\) is odd, the height of an element is not defined.)

      EXAMPLES:

      Sage

          sage: Sq(0).may_weight()
          0
          sage: a = Sq(4)
          sage: a.may_weight()
          1
          sage: b = Sq(4)*Sq(8) + Sq(8)*Sq(4)
          sage: b.may_weight()
          2
          sage: Sq(2,1,5).wall_height()
          [2, 3, 2, 1, 1]
          sage: Sq(2,1,5).may_weight()
          9
          sage: A5 = SteenrodAlgebra(5)
          sage: a = A5.Q(1,2,4)
          sage: b = A5.P(1,2,1)
          sage: a.may_weight()
          10
          sage: b.may_weight()
          8
          sage: (a * b).may_weight()
          18
          sage: A5.P(0,0,1).may_weight()
          3

      Python

          >>> from sage.all import *
          >>> Sq(Integer(0)).may_weight()
          0
          >>> a = Sq(Integer(4))
          >>> a.may_weight()
          1
          >>> b = Sq(Integer(4))*Sq(Integer(8)) + Sq(Integer(8))*Sq(Integer(4))
          >>> b.may_weight()
          2
          >>> Sq(Integer(2),Integer(1),Integer(5)).wall_height()
          [2, 3, 2, 1, 1]
          >>> Sq(Integer(2),Integer(1),Integer(5)).may_weight()
          9
          >>> A5 = SteenrodAlgebra(Integer(5))
          >>> a = A5.Q(Integer(1),Integer(2),Integer(4))
          >>> b = A5.P(Integer(1),Integer(2),Integer(1))
          >>> a.may_weight()
          10
          >>> b.may_weight()
          8
          >>> (a * b).may_weight()
          18
          >>> A5.P(Integer(0),Integer(0),Integer(1)).may_weight()
          3

    milnor()

      Return this element in the Milnor basis; that is, as an element of the appropriate Steenrod algebra.

      This just calls the method `SteenrodAlgebra_generic.milnor()`.

      EXAMPLES:

      Sage

          sage: Adem = SteenrodAlgebra(basis='adem')
          sage: a = Adem.basis(4)[1]; a
          Sq^3 Sq^1
          sage: a.milnor()
          Sq(1,1)

      Python

          >>> from sage.all import *
          >>> Adem = SteenrodAlgebra(basis='adem')
          >>> a = Adem.basis(Integer(4))[Integer(1)]; a
          Sq^3 Sq^1
          >>> a.milnor()
          Sq(1,1)

    prime()

      The prime associated to `self`.

      EXAMPLES:

      Sage

          sage: a = SteenrodAlgebra().Sq(3,2,1)
          sage: a.prime()
          2
          sage: a.change_basis('adem').prime()
          2
          sage: b = SteenrodAlgebra(p=7).basis(36)[0]
          sage: b.prime()
          7
          sage: SteenrodAlgebra(p=3, basis='adem').one().prime()
          3

      Python

          >>> from sage.all import *
          >>> a = SteenrodAlgebra().Sq(Integer(3),Integer(2),Integer(1))
          >>> a.prime()
          2
          >>> a.change_basis('adem').prime()
          2
          >>> b = SteenrodAlgebra(p=Integer(7)).basis(Integer(36))[Integer(0)]
          >>> b.prime()
          7
          >>> SteenrodAlgebra(p=Integer(3), basis='adem').one().prime()
          3

    wall_height()

      Wall’s ‘height’ of element.

      OUTPUT: list of nonnegative integers

      The height of an element of the mod 2 Steenrod algebra is a list of nonnegative integers, defined as follows: if the element is a monomial in the generators \(\text{Sq}(2^i)\), then the \(i\)-th entry in the list is the number of times \(\text{Sq}(2^i)\) appears. For an arbitrary element, write it as a sum of such monomials; then its height is the maximum, ordered right-lexicographically, of the heights of those monomials.

      When \(p\) is odd, the height of an element is not defined.

      According to Theorem 3 in [Wal1960], the height of the Milnor basis element \(\text{Sq}(r_1, r_2, ...)\) is obtained as follows: write each \(r_i\) in binary as \(r_i = \sum_j 2^j r_{ij}\). Then each nonzero binary digit \(r_{ij}\) contributes 1 to the \(k\)-th entry in the height, for \(j \leq k \leq i+j-1\).

      EXAMPLES:

      Sage

          sage: Sq(0).wall_height()
          []
          sage: a = Sq(4)
          sage: a.wall_height()
          [0, 0, 1]
          sage: b = Sq(4)*Sq(8) + Sq(8)*Sq(4)
          sage: b.wall_height()
          [0, 0, 1, 1]
          sage: Sq(0,0,3).wall_height()
          [1, 2, 2, 1]

      Python

          >>> from sage.all import *
          >>> Sq(Integer(0)).wall_height()
          []
          >>> a = Sq(Integer(4))
          >>> a.wall_height()
          [0, 0, 1]
          >>> b = Sq(Integer(4))*Sq(Integer(8)) + Sq(Integer(8))*Sq(Integer(4))
          >>> b.wall_height()
          [0, 0, 1, 1]
          >>> Sq(Integer(0),Integer(0),Integer(3)).wall_height()
          [1, 2, 2, 1]

  P(*nums)

    The element \(P(a, b, c, \ldots)\).

    INPUT:

    - `a`, `b`, `c`, … – nonnegative integers

    OUTPUT:

    element of the Steenrod algebra given by the Milnor single basis element \(P(a, b, c, ...)\)

    Note that at the prime 2, this is the same element as \(\text{Sq}(a, b, c, ...)\).

    EXAMPLES:

    Sage

        sage: A = SteenrodAlgebra(2)
        sage: A.P(5)
        Sq(5)
        sage: B = SteenrodAlgebra(3)
        sage: B.P(5,1,1)
        P(5,1,1)
        sage: B.P(1,1,-12,1)
        Traceback (most recent call last):
        ...
        TypeError: entries must be nonnegative integers

        sage: SteenrodAlgebra(basis='serre-cartan').P(0,1)
        Sq^2 Sq^1 + Sq^3
        sage: SteenrodAlgebra(generic=True).P(2,0,1)
        P(2,0,1)

    Python

        >>> from sage.all import *
        >>> A = SteenrodAlgebra(Integer(2))
        >>> A.P(Integer(5))
        Sq(5)
        >>> B = SteenrodAlgebra(Integer(3))
        >>> B.P(Integer(5),Integer(1),Integer(1))
        P(5,1,1)
        >>> B.P(Integer(1),Integer(1),-Integer(12),Integer(1))
        Traceback (most recent call last):
        ...
        TypeError: entries must be nonnegative integers

        >>> SteenrodAlgebra(basis='serre-cartan').P(Integer(0),Integer(1))
        Sq^2 Sq^1 + Sq^3
        >>> SteenrodAlgebra(generic=True).P(Integer(2),Integer(0),Integer(1))
        P(2,0,1)

  Q(*nums)

    The element \(Q_{n0} Q_{n1} ...\) , given by specifying the subscripts.

    INPUT:

    - `n0`, `n1`, … – nonnegative integers

    OUTPUT: the element \(Q_{n0} Q_{n1} ...\)

    Note that at the prime 2, \(Q_n\) is the element \(\text{Sq}(0,0,...,1)\) , where the 1 is in the \((n+1)^{st}\) position.

    Compare this to the method `Q_exp()`, which defines a similar element, but by specifying the tuple of exponents.

    EXAMPLES:

    Sage

        sage: A2 = SteenrodAlgebra(2)
        sage: A2.Q(2,3)
        Sq(0,0,1,1)
        sage: A5 = SteenrodAlgebra(5)
        sage: A5.Q(1,4)
        Q_1 Q_4
        sage: A5.Q(1,4) == A5.Q_exp(0,1,0,0,1)
        True
        sage: H = SteenrodAlgebra(p=5, profile=[[2,1], [2,2,2]])
        sage: H.Q(2)
        Q_2
        sage: H.Q(4)
        Traceback (most recent call last):
        ...
        ValueError: element not in this algebra

    Python

        >>> from sage.all import *
        >>> A2 = SteenrodAlgebra(Integer(2))
        >>> A2.Q(Integer(2),Integer(3))
        Sq(0,0,1,1)
        >>> A5 = SteenrodAlgebra(Integer(5))
        >>> A5.Q(Integer(1),Integer(4))
        Q_1 Q_4
        >>> A5.Q(Integer(1),Integer(4)) == A5.Q_exp(Integer(0),Integer(1),Integer(0),Integer(0),Integer(1))
        True
        >>> H = SteenrodAlgebra(p=Integer(5), profile=[[Integer(2),Integer(1)], [Integer(2),Integer(2),Integer(2)]])
        >>> H.Q(Integer(2))
        Q_2
        >>> H.Q(Integer(4))
        Traceback (most recent call last):
        ...
        ValueError: element not in this algebra

  Q_exp(*nums)

    The element \(Q_0^{e_0} Q_1^{e_1} ...\) , given by specifying the exponents.

    INPUT:

    - `e0`, `e1`, … – sequence of 0s and 1s

    OUTPUT: the element \(Q_0^{e_0} Q_1^{e_1} ...\)

    Note that at the prime 2, \(Q_n\) is the element \(\text{Sq}(0,0,...,1)\) , where the 1 is in the \((n+1)^{st}\) position.

    Compare this to the method `Q()`, which defines a similar element, but by specifying the tuple of subscripts of terms with exponent 1.

    EXAMPLES:

    Sage

        sage: A2 = SteenrodAlgebra(2)
        sage: A5 = SteenrodAlgebra(5)
        sage: A2.Q_exp(0,0,1,1,0)
        Sq(0,0,1,1)
        sage: A5.Q_exp(0,0,1,1,0)
        Q_2 Q_3
        sage: A5.Q(2,3)
        Q_2 Q_3
        sage: A5.Q_exp(0,0,1,1,0) == A5.Q(2,3)
        True
        sage: SteenrodAlgebra(2,generic=True).Q_exp(1,0,1)
        Q_0 Q_2

    Python

        >>> from sage.all import *
        >>> A2 = SteenrodAlgebra(Integer(2))
        >>> A5 = SteenrodAlgebra(Integer(5))
        >>> A2.Q_exp(Integer(0),Integer(0),Integer(1),Integer(1),Integer(0))
        Sq(0,0,1,1)
        >>> A5.Q_exp(Integer(0),Integer(0),Integer(1),Integer(1),Integer(0))
        Q_2 Q_3
        >>> A5.Q(Integer(2),Integer(3))
        Q_2 Q_3
        >>> A5.Q_exp(Integer(0),Integer(0),Integer(1),Integer(1),Integer(0)) == A5.Q(Integer(2),Integer(3))
        True
        >>> SteenrodAlgebra(Integer(2),generic=True).Q_exp(Integer(1),Integer(0),Integer(1))
        Q_0 Q_2

  algebra_generators()

    alias of `gens()`.

  antipode_on_basis(t)

    The antipode of a basis element of this algebra.

    INPUT:

    - `t` – tuple, the index of a basis element of `self`

    OUTPUT:

    the antipode of the corresponding basis element, as an element of `self`.

    ALGORITHM: according to a result of Milnor’s, the antipode of \(\text{Sq}(n)\) is the sum of all of the Milnor basis elements in dimension \(n\). So: convert the element to the Serre-Cartan basis, thus writing it as a sum of products of elements \(\text{Sq}(n)\), and use Milnor’s formula for the antipode of \(\text{Sq}(n)\), together with the fact that the antipode is an antihomomorphism: if we call the antipode \(c\), then \(c(ab) = c(b) c(a)\).

    At odd primes, a similar method is used: the antipode of \(P(n)\) is the sum of the Milnor P basis elements in dimension \(n*2(p-1)\), multiplied by \((-1)^n\), and the antipode of \(\beta = Q_0\) is \(-Q_0\). So convert to the Serre-Cartan basis, as in the \(p = 2\) case. Note that in the odd prime case, there is a sign in the antihomomorphism formula: \(c(ab) = (-1)^{\deg a \deg b} c(b) c(a)\).

    EXAMPLES:

    Sage

        sage: A = SteenrodAlgebra()
        sage: A.antipode_on_basis((4,))
        Sq(1,1) + Sq(4)
        sage: A.Sq(4).antipode()
        Sq(1,1) + Sq(4)
        sage: Adem = SteenrodAlgebra(basis='adem')
        sage: Adem.Sq(4).antipode()
        Sq^3 Sq^1 + Sq^4
        sage: SteenrodAlgebra(basis='pst').Sq(3).antipode()
        P^0_1 P^1_1 + P^0_2
        sage: a = SteenrodAlgebra(basis='wall_long').Sq(10)
        sage: a.antipode()
        Sq^1 Sq^2 Sq^4 Sq^1 Sq^2 + Sq^2 Sq^4 Sq^1 Sq^2 Sq^1 + Sq^8 Sq^2
        sage: a.antipode().antipode() == a
        True

        sage: SteenrodAlgebra(p=3).P(6).antipode()
        P(2,1) + P(6)
        sage: SteenrodAlgebra(p=3).P(6).antipode().antipode()
        P(6)

    Python

        >>> from sage.all import *
        >>> A = SteenrodAlgebra()
        >>> A.antipode_on_basis((Integer(4),))
        Sq(1,1) + Sq(4)
        >>> A.Sq(Integer(4)).antipode()
        Sq(1,1) + Sq(4)
        >>> Adem = SteenrodAlgebra(basis='adem')
        >>> Adem.Sq(Integer(4)).antipode()
        Sq^3 Sq^1 + Sq^4
        >>> SteenrodAlgebra(basis='pst').Sq(Integer(3)).antipode()
        P^0_1 P^1_1 + P^0_2
        >>> a = SteenrodAlgebra(basis='wall_long').Sq(Integer(10))
        >>> a.antipode()
        Sq^1 Sq^2 Sq^4 Sq^1 Sq^2 + Sq^2 Sq^4 Sq^1 Sq^2 Sq^1 + Sq^8 Sq^2
        >>> a.antipode().antipode() == a
        True

        >>> SteenrodAlgebra(p=Integer(3)).P(Integer(6)).antipode()
        P(2,1) + P(6)
        >>> SteenrodAlgebra(p=Integer(3)).P(Integer(6)).antipode().antipode()
        P(6)

  basis(d=None)

    Return basis for `self`, either the whole basis or the basis in degree \(d\).

    INPUT:

    - `d` – integer or `None` (default: `None`)

    OUTPUT:

    If \(d\) is `None`, then return a basis of the algebra. Otherwise, return the basis in degree \(d\).

    EXAMPLES:

    Sage

        sage: A3 = SteenrodAlgebra(3)
        sage: A3.basis(13)
        Family (Q_1 P(2), Q_0 P(3))
        sage: SteenrodAlgebra(2, 'adem').basis(12)
        Family (Sq^12, Sq^11 Sq^1, Sq^9 Sq^2 Sq^1, Sq^8 Sq^3 Sq^1, Sq^10 Sq^2, Sq^9 Sq^3, Sq^8 Sq^4)

        sage: A = SteenrodAlgebra(profile=[1,2,1])
        sage: A.basis(2)
        Family ()
        sage: A.basis(3)
        Family (Sq(0,1),)
        sage: SteenrodAlgebra().basis(3)
        Family (Sq(0,1), Sq(3))
        sage: A_pst = SteenrodAlgebra(profile=[1,2,1], basis='pst')
        sage: A_pst.basis(3)
        Family (P^0_2,)

        sage: A7 = SteenrodAlgebra(p=7)
        sage: B = SteenrodAlgebra(p=7, profile=([1,2,1], [1]))
        sage: A7.basis(84)
        Family (P(7),)
        sage: B.basis(84)
        Family ()
        sage: C = SteenrodAlgebra(p=7, profile=([1], [2,2]))
        sage: A7.Q(0,1) in C.basis(14)
        True
        sage: A7.Q(2) in A7.basis(97)
        True
        sage: A7.Q(2) in C.basis(97)
        False

    Python

        >>> from sage.all import *
        >>> A3 = SteenrodAlgebra(Integer(3))
        >>> A3.basis(Integer(13))
        Family (Q_1 P(2), Q_0 P(3))
        >>> SteenrodAlgebra(Integer(2), 'adem').basis(Integer(12))
        Family (Sq^12, Sq^11 Sq^1, Sq^9 Sq^2 Sq^1, Sq^8 Sq^3 Sq^1, Sq^10 Sq^2, Sq^9 Sq^3, Sq^8 Sq^4)

        >>> A = SteenrodAlgebra(profile=[Integer(1),Integer(2),Integer(1)])
        >>> A.basis(Integer(2))
        Family ()
        >>> A.basis(Integer(3))
        Family (Sq(0,1),)
        >>> SteenrodAlgebra().basis(Integer(3))
        Family (Sq(0,1), Sq(3))
        >>> A_pst = SteenrodAlgebra(profile=[Integer(1),Integer(2),Integer(1)], basis='pst')
        >>> A_pst.basis(Integer(3))
        Family (P^0_2,)

        >>> A7 = SteenrodAlgebra(p=Integer(7))
        >>> B = SteenrodAlgebra(p=Integer(7), profile=([Integer(1),Integer(2),Integer(1)], [Integer(1)]))
        >>> A7.basis(Integer(84))
        Family (P(7),)
        >>> B.basis(Integer(84))
        Family ()
        >>> C = SteenrodAlgebra(p=Integer(7), profile=([Integer(1)], [Integer(2),Integer(2)]))
        >>> A7.Q(Integer(0),Integer(1)) in C.basis(Integer(14))
        True
        >>> A7.Q(Integer(2)) in A7.basis(Integer(97))
        True
        >>> A7.Q(Integer(2)) in C.basis(Integer(97))
        False

    With no arguments, return the basis of the whole algebra. This does not print in a very helpful way, unfortunately:

    Sage

        sage: A7.basis()
        Lazy family (Term map from basis key family of mod 7 Steenrod algebra, milnor basis
         to mod 7 Steenrod algebra, milnor basis(i))_{i in basis key family
         of mod 7 Steenrod algebra, milnor basis}
        sage: for idx, a in zip((1,..,9),A7.basis()):
        ....:      print("{} {}".format(idx, a))
        1 1
        2 Q_0
        3 P(1)
        4 Q_1
        5 Q_0 P(1)
        6 Q_0 Q_1
        7 P(2)
        8 Q_1 P(1)
        9 Q_0 P(2)
        sage: D = SteenrodAlgebra(p=3, profile=([1], [2,2]))
        sage: sorted(D.basis())
        [1, P(1), P(2), Q_0, Q_0 P(1), Q_0 P(2), Q_0 Q_1,
         Q_0 Q_1 P(1), Q_0 Q_1 P(2), Q_1, Q_1 P(1), Q_1 P(2)]

    [Python]

        >>> from sage.all import *
        >>> A7.basis()
        Lazy family (Term map from basis key family of mod 7 Steenrod algebra, milnor basis
         to mod 7 Steenrod algebra, milnor basis(i))_{i in basis key family
         of mod 7 Steenrod algebra, milnor basis}
        >>> for idx, a in zip((ellipsis_iter(Integer(1),Ellipsis,Integer(9))),A7.basis()):
        ...      print("{} {}".format(idx, a))
        1 1
        2 Q_0
        3 P(1)
        4 Q_1
        5 Q_0 P(1)
        6 Q_0 Q_1
        7 P(2)
        8 Q_1 P(1)
        9 Q_0 P(2)
        >>> D = SteenrodAlgebra(p=Integer(3), profile=([Integer(1)], [Integer(2),Integer(2)]))
        >>> sorted(D.basis())
        [1, P(1), P(2), Q_0, Q_0 P(1), Q_0 P(2), Q_0 Q_1,
         Q_0 Q_1 P(1), Q_0 Q_1 P(2), Q_1, Q_1 P(1), Q_1 P(2)]

  basis_name()

    The basis name associated to `self`.

    EXAMPLES:

    Sage

        sage: SteenrodAlgebra(p=2, profile=[1,1]).basis_name()
        'milnor'
        sage: SteenrodAlgebra(basis='serre-cartan').basis_name()
        'serre-cartan'
        sage: SteenrodAlgebra(basis='adem').basis_name()
        'serre-cartan'

    Python

        >>> from sage.all import *
        >>> SteenrodAlgebra(p=Integer(2), profile=[Integer(1),Integer(1)]).basis_name()
        'milnor'
        >>> SteenrodAlgebra(basis='serre-cartan').basis_name()
        'serre-cartan'
        >>> SteenrodAlgebra(basis='adem').basis_name()
        'serre-cartan'

  coproduct(x, algorithm='milnor')

    Return the coproduct of an element `x` of this algebra.

    INPUT:

    - `x` – element of `self`

    - `algorithm` – `None` or a string, either `'milnor'` or `'serre-cartan'` (or anything which will be converted to one of these by the function `get_basis_name`. If `None`, default to `'serre-cartan'` if current basis is `'serre-cartan'`; otherwise use `'milnor'`.

    This calls `coproduct_on_basis()` on the summands of `x` and extends linearly.

    EXAMPLES:

    Sage

        sage: SteenrodAlgebra().Sq(3).coproduct()
        1 # Sq(3) + Sq(1) # Sq(2) + Sq(2) # Sq(1) + Sq(3) # 1

    Python

        >>> from sage.all import *
        >>> SteenrodAlgebra().Sq(Integer(3)).coproduct()
        1 # Sq(3) + Sq(1) # Sq(2) + Sq(2) # Sq(1) + Sq(3) # 1

    The element \(\text{Sq}(0,1)\) is primitive:

    Sage

        sage: SteenrodAlgebra(basis='adem').Sq(0,1).coproduct()
        1 # Sq^2 Sq^1 + 1 # Sq^3 + Sq^2 Sq^1 # 1 + Sq^3 # 1
        sage: SteenrodAlgebra(basis='pst').Sq(0,1).coproduct()
        1 # P^0_2 + P^0_2 # 1

        sage: SteenrodAlgebra(p=3).P(4).coproduct()
        1 # P(4) + P(1) # P(3) + P(2) # P(2) + P(3) # P(1) + P(4) # 1
        sage: SteenrodAlgebra(p=3).P(4).coproduct(algorithm='serre-cartan')
        1 # P(4) + P(1) # P(3) + P(2) # P(2) + P(3) # P(1) + P(4) # 1
        sage: SteenrodAlgebra(p=3, basis='serre-cartan').P(4).coproduct()
        1 # P^4 + P^1 # P^3 + P^2 # P^2 + P^3 # P^1 + P^4 # 1
        sage: SteenrodAlgebra(p=11, profile=((), (2,1,2))).Q(0,2).coproduct()
        1 # Q_0 Q_2 + Q_0 # Q_2 + Q_0 Q_2 # 1 + 10*Q_2 # Q_0

    [Python]

        >>> from sage.all import *
        >>> SteenrodAlgebra(basis='adem').Sq(Integer(0),Integer(1)).coproduct()
        1 # Sq^2 Sq^1 + 1 # Sq^3 + Sq^2 Sq^1 # 1 + Sq^3 # 1
        >>> SteenrodAlgebra(basis='pst').Sq(Integer(0),Integer(1)).coproduct()
        1 # P^0_2 + P^0_2 # 1

        >>> SteenrodAlgebra(p=Integer(3)).P(Integer(4)).coproduct()
        1 # P(4) + P(1) # P(3) + P(2) # P(2) + P(3) # P(1) + P(4) # 1
        >>> SteenrodAlgebra(p=Integer(3)).P(Integer(4)).coproduct(algorithm='serre-cartan')
        1 # P(4) + P(1) # P(3) + P(2) # P(2) + P(3) # P(1) + P(4) # 1
        >>> SteenrodAlgebra(p=Integer(3), basis='serre-cartan').P(Integer(4)).coproduct()
        1 # P^4 + P^1 # P^3 + P^2 # P^2 + P^3 # P^1 + P^4 # 1
        >>> SteenrodAlgebra(p=Integer(11), profile=((), (Integer(2),Integer(1),Integer(2)))).Q(Integer(0),Integer(2)).coproduct()
        1 # Q_0 Q_2 + Q_0 # Q_2 + Q_0 Q_2 # 1 + 10*Q_2 # Q_0

  coproduct_on_basis(t, algorithm=None)

    The coproduct of a basis element of this algebra.

    INPUT:

    - `t` – tuple, the index of a basis element of self

    - `algorithm` – `None` or a string, either ‘milnor’ or ‘serre-cartan’ (or anything which will be converted to one of these by the function `get_basis_name`. If `None`, default to ‘milnor’ unless current basis is ‘serre-cartan’, in which case use ‘serre-cartan’.

    ALGORITHM: The coproduct on a Milnor basis element \(P(n_1, n_2, ...)\) is \(\sum P(i_1, i_2, ...) \otimes P(j_1, j_2, ...)\), summed over all \(i_k + j_k = n_k\) for each \(k\). At odd primes, each element \(Q_n\) is primitive: its coproduct is \(Q_n \otimes 1 + 1 \otimes Q_n\).

    One can deduce a coproduct formula for the Serre-Cartan basis from this: the coproduct on each \(P^n\) is \(\sum P^i \otimes P^{n-i}\) and at odd primes \(\beta\) is primitive. Since the coproduct is an algebra map, one can then compute the coproduct on any Serre-Cartan basis element.

    Which of these methods is used is controlled by whether `algorithm` is ‘milnor’ or ‘serre-cartan’.

    OUTPUT:

    the coproduct of the corresponding basis element, as an element of `self` tensor `self`.

    EXAMPLES:

    Sage

        sage: A = SteenrodAlgebra()
        sage: A.coproduct_on_basis((3,))
        1 # Sq(3) + Sq(1) # Sq(2) + Sq(2) # Sq(1) + Sq(3) # 1

    Python

        >>> from sage.all import *
        >>> A = SteenrodAlgebra()
        >>> A.coproduct_on_basis((Integer(3),))
        1 # Sq(3) + Sq(1) # Sq(2) + Sq(2) # Sq(1) + Sq(3) # 1

  counit_on_basis(t)

    The counit sends all elements of positive degree to zero.

    INPUT:

    - `t` – tuple, the index of a basis element of `self`

    EXAMPLES:

    Sage

        sage: A2 = SteenrodAlgebra(p=2)
        sage: A2.counit_on_basis(())
        1
        sage: A2.counit_on_basis((0,0,1))
        0
        sage: parent(A2.counit_on_basis((0,0,1)))
        Finite Field of size 2
        sage: A3 = SteenrodAlgebra(p=3)
        sage: A3.counit_on_basis(((1,2,3), (1,1,1)))
        0
        sage: A3.counit_on_basis(((), ()))
        1
        sage: A3.counit(A3.P(10,5))
        0
        sage: A3.counit(A3.P(0))
        1

    Python

        >>> from sage.all import *
        >>> A2 = SteenrodAlgebra(p=Integer(2))
        >>> A2.counit_on_basis(())
        1
        >>> A2.counit_on_basis((Integer(0),Integer(0),Integer(1)))
        0
        >>> parent(A2.counit_on_basis((Integer(0),Integer(0),Integer(1))))
        Finite Field of size 2
        >>> A3 = SteenrodAlgebra(p=Integer(3))
        >>> A3.counit_on_basis(((Integer(1),Integer(2),Integer(3)), (Integer(1),Integer(1),Integer(1))))
        0
        >>> A3.counit_on_basis(((), ()))
        1
        >>> A3.counit(A3.P(Integer(10),Integer(5)))
        0
        >>> A3.counit(A3.P(Integer(0)))
        1

  degree_on_basis(t)

    The degree of the monomial specified by the tuple `t`.

    INPUT:

    - `t` – tuple, representing basis element in the current basis

    OUTPUT: integer, the degree of the corresponding element

    The degree of \(\text{Sq}(i_1,i_2,i_3,...)\) is

    \[i_1 + 3i_2 + 7i_3 + ... + (2^k - 1) i_k + ....\]

    At an odd prime \(p\), the degree of \(Q_k\) is \(2p^k - 1\) and the degree of \(\mathcal{P}(i_1, i_2, ...)\) is

    \[\sum_{k \geq 0} 2(p^k - 1) i_k.\]

    ALGORITHM: Each basis element is represented in terms relevant to the particular basis: ‘milnor’ basis elements (at the prime 2) are given by tuples `(a,b,c,...)` corresponding to the element \(\text{Sq}(a,b,c,...)\), while ‘pst’ basis elements are given by tuples of pairs `((a, b), (c, d), ...)`, corresponding to the product \(P^a_b P^c_d ...\). The other bases have similar descriptions. The degree of each basis element is computed from this data, rather than converting the element to the Milnor basis, for example, and then computing the degree.

    EXAMPLES:

    Sage

        sage: SteenrodAlgebra().degree_on_basis((0,0,1))
        7
        sage: Sq(7).degree()
        7

        sage: A11 = SteenrodAlgebra(p=11)
        sage: A11.degree_on_basis(((), (1,1)))
        260
        sage: A11.degree_on_basis(((2,), ()))
        241

    Python

        >>> from sage.all import *
        >>> SteenrodAlgebra().degree_on_basis((Integer(0),Integer(0),Integer(1)))
        7
        >>> Sq(Integer(7)).degree()
        7

        >>> A11 = SteenrodAlgebra(p=Integer(11))
        >>> A11.degree_on_basis(((), (Integer(1),Integer(1))))
        260
        >>> A11.degree_on_basis(((Integer(2),), ()))
        241

  dimension()

    The dimension of this algebra as a vector space over \(\GF{p}\).

    If the algebra is infinite, return `+Infinity`. Otherwise, the profile function must be finite. In this case, at the prime 2, its dimension is \(2^s\), where \(s\) is the sum of the entries in the profile function. At odd primes, the dimension is \(p^s * 2^t\) where \(s\) is the sum of the \(e\) component of the profile function and \(t\) is the number of 2’s in the \(k\) component of the profile function.

    EXAMPLES:

    Sage

        sage: SteenrodAlgebra(p=7).dimension()
        +Infinity
        sage: SteenrodAlgebra(profile=[3,2,1]).dimension()
        64
        sage: SteenrodAlgebra(p=3, profile=([1,1], [])).dimension()
        9
        sage: SteenrodAlgebra(p=5, profile=([1], [2,2])).dimension()
        20

    Python

        >>> from sage.all import *
        >>> SteenrodAlgebra(p=Integer(7)).dimension()
        +Infinity
        >>> SteenrodAlgebra(profile=[Integer(3),Integer(2),Integer(1)]).dimension()
        64
        >>> SteenrodAlgebra(p=Integer(3), profile=([Integer(1),Integer(1)], [])).dimension()
        9
        >>> SteenrodAlgebra(p=Integer(5), profile=([Integer(1)], [Integer(2),Integer(2)])).dimension()
        20

  gen(i=0)

    The \(i\)-th generator of this algebra.

    INPUT:

    - `i` – nonnegative integer

    OUTPUT: the \(i\)-th generator of this algebra

    For the full Steenrod algebra, the \(i\)-th generator is \(\text{Sq}(2^i)\) at the prime 2; when \(p\) is odd, the \(0\)-th generator is \(\beta = Q(0)\), and for \(i>0\), the \(i\)-th generator is \(P(p^{i-1})\).

    For sub-Hopf algebras of the Steenrod algebra, it is not always clear what a minimal generating set is. The sub-Hopf algebra \(A(n)\) is minimally generated by the elements \(\text{Sq}^{2^i}\) for \(0 \leq i \leq n\) at the prime 2. At odd primes, \(A(n)\) is minimally generated by \(Q_0\) along with \(\mathcal{P}^{p^i}\) for \(0 \leq i \leq n-1\). So if this algebra is \(A(n)\), return the appropriate generator.

    For other sub-Hopf algebras: they are generated (but not necessarily minimally) by the \(P^s_t\)’s (and \(Q_n\)’s, if \(p\) is odd) that they contain. So order the \(P^s_t\)’s (and \(Q_n\)’s) in the algebra by degree and return the \(i\)-th one.

    EXAMPLES:

    Sage

        sage: A = SteenrodAlgebra(2)
        sage: A.gen(4)
        Sq(16)
        sage: A.gen(200)
        Sq(1606938044258990275541962092341162602522202993782792835301376)
        sage: SteenrodAlgebra(2, basis='adem').gen(2)
        Sq^4
        sage: SteenrodAlgebra(2, basis='pst').gen(2)
        P^2_1
        sage: B = SteenrodAlgebra(5)
        sage: B.gen(0)
        Q_0
        sage: B.gen(2)
        P(5)

        sage: SteenrodAlgebra(profile=[2,1]).gen(1)
        Sq(2)
        sage: SteenrodAlgebra(profile=[1,2,1]).gen(1)
        Sq(0,1)
        sage: SteenrodAlgebra(profile=[1,2,1]).gen(5)
        Traceback (most recent call last):
        ...
        ValueError: this algebra only has 4 generators, so call gen(i) with 0 <= i < 4

        sage: D = SteenrodAlgebra(profile=lambda n: n)
        sage: [D.gen(n) for n in range(5)]
        [Sq(1), Sq(0,1), Sq(0,2), Sq(0,0,1), Sq(0,0,2)]
        sage: D3 = SteenrodAlgebra(p=3, profile=(lambda n: n, lambda n: 2))
        sage: [D3.gen(n) for n in range(9)]
        [Q_0, P(1), Q_1, P(0,1), Q_2, P(0,3), P(0,0,1), Q_3, P(0,0,3)]
        sage: D3 = SteenrodAlgebra(p=3, profile=(lambda n: n, lambda n: 1 if n<1 else 2))
        sage: [D3.gen(n) for n in range(9)]
        [P(1), Q_1, P(0,1), Q_2, P(0,3), P(0,0,1), Q_3, P(0,0,3), P(0,0,0,1)]
        sage: SteenrodAlgebra(p=5, profile=[[2,1], [2,2,2]], basis='pst').gen(2)
        P^1_1

    Python

        >>> from sage.all import *
        >>> A = SteenrodAlgebra(Integer(2))
        >>> A.gen(Integer(4))
        Sq(16)
        >>> A.gen(Integer(200))
        Sq(1606938044258990275541962092341162602522202993782792835301376)
        >>> SteenrodAlgebra(Integer(2), basis='adem').gen(Integer(2))
        Sq^4
        >>> SteenrodAlgebra(Integer(2), basis='pst').gen(Integer(2))
        P^2_1
        >>> B = SteenrodAlgebra(Integer(5))
        >>> B.gen(Integer(0))
        Q_0
        >>> B.gen(Integer(2))
        P(5)

        >>> SteenrodAlgebra(profile=[Integer(2),Integer(1)]).gen(Integer(1))
        Sq(2)
        >>> SteenrodAlgebra(profile=[Integer(1),Integer(2),Integer(1)]).gen(Integer(1))
        Sq(0,1)
        >>> SteenrodAlgebra(profile=[Integer(1),Integer(2),Integer(1)]).gen(Integer(5))
        Traceback (most recent call last):
        ...
        ValueError: this algebra only has 4 generators, so call gen(i) with 0 <= i < 4

        >>> D = SteenrodAlgebra(profile=lambda n: n)
        >>> [D.gen(n) for n in range(Integer(5))]
        [Sq(1), Sq(0,1), Sq(0,2), Sq(0,0,1), Sq(0,0,2)]
        >>> D3 = SteenrodAlgebra(p=Integer(3), profile=(lambda n: n, lambda n: Integer(2)))
        >>> [D3.gen(n) for n in range(Integer(9))]
        [Q_0, P(1), Q_1, P(0,1), Q_2, P(0,3), P(0,0,1), Q_3, P(0,0,3)]
        >>> D3 = SteenrodAlgebra(p=Integer(3), profile=(lambda n: n, lambda n: Integer(1) if n<Integer(1) else Integer(2)))
        >>> [D3.gen(n) for n in range(Integer(9))]
        [P(1), Q_1, P(0,1), Q_2, P(0,3), P(0,0,1), Q_3, P(0,0,3), P(0,0,0,1)]
        >>> SteenrodAlgebra(p=Integer(5), profile=[[Integer(2),Integer(1)], [Integer(2),Integer(2),Integer(2)]], basis='pst').gen(Integer(2))
        P^1_1

  gens()

    Family of generators for this algebra.

    OUTPUT: family of elements of this algebra

    At the prime 2, the Steenrod algebra is generated by the elements \(\text{Sq}^{2^i}\) for \(i \geq 0\). At odd primes, it is generated by the elements \(Q_0\) and \(\mathcal{P}^{p^i}\) for \(i \geq 0\). So if this algebra is the entire Steenrod algebra, return an infinite family made up of these elements.

    For sub-Hopf algebras of the Steenrod algebra, it is not always clear what a minimal generating set is. The sub-Hopf algebra \(A(n)\) is minimally generated by the elements \(\text{Sq}^{2^i}\) for \(0 \leq i \leq n\) at the prime 2. At odd primes, \(A(n)\) is minimally generated by \(Q_0\) along with \(\mathcal{P}^{p^i}\) for \(0 \leq i \leq n-1\). So if this algebra is \(A(n)\), return the appropriate list of generators.

    For other sub-Hopf algebras: return a non-minimal generating set: the family of \(P^s_t\)’s and \(Q_n\)’s contained in the algebra.

    EXAMPLES:

    Sage

        sage: A3 = SteenrodAlgebra(3, 'adem')
        sage: A3.gens()
        Lazy family (<bound method SteenrodAlgebra_generic.gen of mod 3 Steenrod algebra,
         serre-cartan basis>(i))_{i in Non negative integers}
        sage: A3.gens()[0]
        beta
        sage: A3.gens()[1]
        P^1
        sage: A3.gens()[2]
        P^3
        sage: SteenrodAlgebra(profile=[3,2,1]).gens()
        Family (Sq(1), Sq(2), Sq(4))

    Python

        >>> from sage.all import *
        >>> A3 = SteenrodAlgebra(Integer(3), 'adem')
        >>> A3.gens()
        Lazy family (<bound method SteenrodAlgebra_generic.gen of mod 3 Steenrod algebra,
         serre-cartan basis>(i))_{i in Non negative integers}
        >>> A3.gens()[Integer(0)]
        beta
        >>> A3.gens()[Integer(1)]
        P^1
        >>> A3.gens()[Integer(2)]
        P^3
        >>> SteenrodAlgebra(profile=[Integer(3),Integer(2),Integer(1)]).gens()
        Family (Sq(1), Sq(2), Sq(4))

    In the following case, return a non-minimal generating set. (It is not minimal because \(\text{Sq}(0,0,1)\) is the commutator of \(\text{Sq}(1)\) and \(\text{Sq}(0,2)\).)

    Sage

        sage: SteenrodAlgebra(profile=[1,2,1]).gens()
        Family (Sq(1), Sq(0,1), Sq(0,2), Sq(0,0,1))
        sage: SteenrodAlgebra(p=5, profile=[[2,1], [2,2,2]]).gens()
        Family (Q_0, P(1), P(5))
        sage: SteenrodAlgebra(profile=lambda n: n).gens()
        Lazy family (<bound method SteenrodAlgebra_generic.gen of sub-Hopf algebra
         of mod 2 Steenrod algebra, milnor basis, profile function [1, 2, 3, ...,
         98, 99, +Infinity, +Infinity, +Infinity, ...]>(i))_{i in Non negative integers}

    [Python]

        >>> from sage.all import *
        >>> SteenrodAlgebra(profile=[Integer(1),Integer(2),Integer(1)]).gens()
        Family (Sq(1), Sq(0,1), Sq(0,2), Sq(0,0,1))
        >>> SteenrodAlgebra(p=Integer(5), profile=[[Integer(2),Integer(1)], [Integer(2),Integer(2),Integer(2)]]).gens()
        Family (Q_0, P(1), P(5))
        >>> SteenrodAlgebra(profile=lambda n: n).gens()
        Lazy family (<bound method SteenrodAlgebra_generic.gen of sub-Hopf algebra
         of mod 2 Steenrod algebra, milnor basis, profile function [1, 2, 3, ...,
         98, 99, +Infinity, +Infinity, +Infinity, ...]>(i))_{i in Non negative integers}

    You may also use `algebra_generators` instead of `gens`:

    Sage

        sage: SteenrodAlgebra(p=5, profile=[[2,1], [2,2,2]]).algebra_generators()
        Family (Q_0, P(1), P(5))

    Python

        >>> from sage.all import *
        >>> SteenrodAlgebra(p=Integer(5), profile=[[Integer(2),Integer(1)], [Integer(2),Integer(2),Integer(2)]]).algebra_generators()
        Family (Q_0, P(1), P(5))

  homogeneous_component(n)

    Return the \(n\)-th homogeneous piece of the Steenrod algebra.

    INPUT:

    - `n` – integer

    OUTPUT: a vector space spanned by the basis for this algebra in dimension \(n\)

    EXAMPLES:

    Sage

        sage: A = SteenrodAlgebra()
        sage: A.homogeneous_component(4)
        Vector space spanned by (Sq(1,1), Sq(4)) over Finite Field of size 2
        sage: SteenrodAlgebra(profile=[2,1,0]).homogeneous_component(4)
        Vector space spanned by (Sq(1,1),) over Finite Field of size 2

    Python

        >>> from sage.all import *
        >>> A = SteenrodAlgebra()
        >>> A.homogeneous_component(Integer(4))
        Vector space spanned by (Sq(1,1), Sq(4)) over Finite Field of size 2
        >>> SteenrodAlgebra(profile=[Integer(2),Integer(1),Integer(0)]).homogeneous_component(Integer(4))
        Vector space spanned by (Sq(1,1),) over Finite Field of size 2

    The notation A[n] may also be used:

    Sage

        sage: A[5]
        Vector space spanned by (Sq(2,1), Sq(5)) over Finite Field of size 2
        sage: SteenrodAlgebra(basis='wall')[4]
        Vector space spanned by (Q^1_0 Q^0_0, Q^2_2) over Finite Field of size 2
        sage: SteenrodAlgebra(p=5)[17]
        Vector space spanned by (Q_1 P(1), Q_0 P(2)) over Finite Field of size 5

    [Python]

        >>> from sage.all import *
        >>> A[Integer(5)]
        Vector space spanned by (Sq(2,1), Sq(5)) over Finite Field of size 2
        >>> SteenrodAlgebra(basis='wall')[Integer(4)]
        Vector space spanned by (Q^1_0 Q^0_0, Q^2_2) over Finite Field of size 2
        >>> SteenrodAlgebra(p=Integer(5))[Integer(17)]
        Vector space spanned by (Q_1 P(1), Q_0 P(2)) over Finite Field of size 5

    Note that A[n] is just a vector space, not a Hopf algebra, so its elements don’t have products, coproducts, or antipodes defined on them. If you want to use operations like this on elements of some A[n], then convert them back to elements of A:

    Sage

        sage: sorted(A[5].basis())
        [milnor[(2, 1)], milnor[(5,)]]
        sage: a = list(A[5].basis())[1]
        sage: a  # not in A, doesn't print like an element of A
        milnor[(5,)]
        sage: A(a) # in A
        Sq(5)
        sage: A(a) * A(a)
        Sq(7,1)
        sage: a * A(a) # only need to convert one factor
        Sq(7,1)
        sage: a.antipode() # not defined
        Traceback (most recent call last):
        ...
        AttributeError: 'CombinatorialFreeModule_with_category.element_class' object has no attribute 'antipode'...
        sage: A(a).antipode() # convert to elt of A, then compute antipode
        Sq(2,1) + Sq(5)

        sage: G = SteenrodAlgebra(p=5, profile=[[2,1], [2,2,2]], basis='pst')

    Python

        >>> from sage.all import *
        >>> sorted(A[Integer(5)].basis())
        [milnor[(2, 1)], milnor[(5,)]]
        >>> a = list(A[Integer(5)].basis())[Integer(1)]
        >>> a  # not in A, doesn't print like an element of A
        milnor[(5,)]
        >>> A(a) # in A
        Sq(5)
        >>> A(a) * A(a)
        Sq(7,1)
        >>> a * A(a) # only need to convert one factor
        Sq(7,1)
        >>> a.antipode() # not defined
        Traceback (most recent call last):
        ...
        AttributeError: 'CombinatorialFreeModule_with_category.element_class' object has no attribute 'antipode'...
        >>> A(a).antipode() # convert to elt of A, then compute antipode
        Sq(2,1) + Sq(5)

        >>> G = SteenrodAlgebra(p=Integer(5), profile=[[Integer(2),Integer(1)], [Integer(2),Integer(2),Integer(2)]], basis='pst')

  is_commutative()

    Return `True` if `self` is graded commutative, as determined by the profile function.

    In particular, a sub-Hopf algebra of the mod 2 Steenrod algebra is commutative if and only if there is an integer \(n>0\) so that its profile function \(e\) satisfies

    - \(e(i) = 0\) for \(i < n\),

    - \(e(i) \leq n\) for \(i \geq n\).

    When \(p\) is odd, there must be an integer \(n \geq 0\) so that the profile functions \(e\) and \(k\) satisfy

    - \(e(i) = 0\) for \(i < n\),

    - \(e(i) \leq n\) for \(i \geq n\).

    - \(k(i) = 1\) for \(i < n\).

    EXAMPLES:

    Sage

        sage: A = SteenrodAlgebra(p=3)
        sage: A.is_commutative()
        False
        sage: SteenrodAlgebra(profile=[2,1]).is_commutative()
        False
        sage: SteenrodAlgebra(profile=[0,2,2,1]).is_commutative()
        True

    Python

        >>> from sage.all import *
        >>> A = SteenrodAlgebra(p=Integer(3))
        >>> A.is_commutative()
        False
        >>> SteenrodAlgebra(profile=[Integer(2),Integer(1)]).is_commutative()
        False
        >>> SteenrodAlgebra(profile=[Integer(0),Integer(2),Integer(2),Integer(1)]).is_commutative()
        True

    Note that if the profile function is specified by a function, then by default it has infinite truncation type: the profile function is assumed to be infinite after the 100th term.

    Sage

        sage: SteenrodAlgebra(profile=lambda n: 1).is_commutative()
        False
        sage: SteenrodAlgebra(profile=lambda n: 1, truncation_type=0).is_commutative()
        True

        sage: SteenrodAlgebra(p=5, profile=([0,2,2,1], [])).is_commutative()
        True
        sage: SteenrodAlgebra(p=5, profile=([0,2,2,1], [1,1,2])).is_commutative()
        True
        sage: SteenrodAlgebra(p=5, profile=([0,2,1], [1,2,2,2])).is_commutative()
        False

    [Python]

        >>> from sage.all import *
        >>> SteenrodAlgebra(profile=lambda n: Integer(1)).is_commutative()
        False
        >>> SteenrodAlgebra(profile=lambda n: Integer(1), truncation_type=Integer(0)).is_commutative()
        True

        >>> SteenrodAlgebra(p=Integer(5), profile=([Integer(0),Integer(2),Integer(2),Integer(1)], [])).is_commutative()
        True
        >>> SteenrodAlgebra(p=Integer(5), profile=([Integer(0),Integer(2),Integer(2),Integer(1)], [Integer(1),Integer(1),Integer(2)])).is_commutative()
        True
        >>> SteenrodAlgebra(p=Integer(5), profile=([Integer(0),Integer(2),Integer(1)], [Integer(1),Integer(2),Integer(2),Integer(2)])).is_commutative()
        False

  is_division_algebra()

    The only way this algebra can be a division algebra is if it is the ground field \(\GF{p}\).

    EXAMPLES:

    Sage

        sage: SteenrodAlgebra(11).is_division_algebra()
        False
        sage: SteenrodAlgebra(profile=lambda n: 0, truncation_type=0).is_division_algebra()
        True

    Python

        >>> from sage.all import *
        >>> SteenrodAlgebra(Integer(11)).is_division_algebra()
        False
        >>> SteenrodAlgebra(profile=lambda n: Integer(0), truncation_type=Integer(0)).is_division_algebra()
        True

  is_field(proof=True)

    The only way this algebra can be a field is if it is the ground field \(\GF{p}\).

    EXAMPLES:

    Sage

        sage: SteenrodAlgebra(11).is_field()
        False
        sage: SteenrodAlgebra(profile=lambda n: 0, truncation_type=0).is_field()
        True

    Python

        >>> from sage.all import *
        >>> SteenrodAlgebra(Integer(11)).is_field()
        False
        >>> SteenrodAlgebra(profile=lambda n: Integer(0), truncation_type=Integer(0)).is_field()
        True

  is_finite()

    Return `True` if this algebra is finite-dimensional.

    Therefore true if the profile function is finite, and in particular the `truncation_type` must be finite.

    EXAMPLES:

    Sage

        sage: A = SteenrodAlgebra(p=3)
        sage: A.is_finite()
        False
        sage: SteenrodAlgebra(profile=[3,2,1]).is_finite()
        True
        sage: SteenrodAlgebra(profile=lambda n: n).is_finite()
        False

    Python

        >>> from sage.all import *
        >>> A = SteenrodAlgebra(p=Integer(3))
        >>> A.is_finite()
        False
        >>> SteenrodAlgebra(profile=[Integer(3),Integer(2),Integer(1)]).is_finite()
        True
        >>> SteenrodAlgebra(profile=lambda n: n).is_finite()
        False

  is_generic()

    The algebra is generic if it is based on the odd-primary relations, i.e. if its dual is a quotient of

    \[A_* = \GF{p} [\xi_1, \xi_2, \xi_3, ...] \otimes \Lambda (\tau_0, \tau_1, ...)\]

    Sage also allows this for \(p=2\). Only the usual Steenrod algebra at the prime \(2\) and its sub algebras are non-generic.

    EXAMPLES:

    Sage

        sage: SteenrodAlgebra(3).is_generic()
        True
        sage: SteenrodAlgebra(2).is_generic()
        False
        sage: SteenrodAlgebra(2, generic=True).is_generic()
        True

    Python

        >>> from sage.all import *
        >>> SteenrodAlgebra(Integer(3)).is_generic()
        True
        >>> SteenrodAlgebra(Integer(2)).is_generic()
        False
        >>> SteenrodAlgebra(Integer(2), generic=True).is_generic()
        True

  is_integral_domain(proof=True)

    The only way this algebra can be an integral domain is if it is the ground field \(\GF{p}\).

    EXAMPLES:

    Sage

        sage: SteenrodAlgebra(11).is_integral_domain()
        False
        sage: SteenrodAlgebra(profile=lambda n: 0, truncation_type=0).is_integral_domain()
        True

    Python

        >>> from sage.all import *
        >>> SteenrodAlgebra(Integer(11)).is_integral_domain()
        False
        >>> SteenrodAlgebra(profile=lambda n: Integer(0), truncation_type=Integer(0)).is_integral_domain()
        True

  is_noetherian()

    This algebra is Noetherian if and only if it is finite.

    EXAMPLES:

    Sage

        sage: SteenrodAlgebra(3).is_noetherian()
        False
        sage: SteenrodAlgebra(profile=[1,2,1]).is_noetherian()
        True
        sage: SteenrodAlgebra(profile=lambda n: n+2).is_noetherian()
        False

    Python

        >>> from sage.all import *
        >>> SteenrodAlgebra(Integer(3)).is_noetherian()
        False
        >>> SteenrodAlgebra(profile=[Integer(1),Integer(2),Integer(1)]).is_noetherian()
        True
        >>> SteenrodAlgebra(profile=lambda n: n+Integer(2)).is_noetherian()
        False

  milnor()

    Convert an element of this algebra to the Milnor basis.

    INPUT:

    - `x` – an element of this algebra

    OUTPUT: x converted to the Milnor basis

    ALGORITHM: use the method `_milnor_on_basis` and linearity.

    EXAMPLES:

    Sage

        sage: Adem = SteenrodAlgebra(basis='adem')
        sage: a = Adem.Sq(2) * Adem.Sq(1)
        sage: Adem.milnor(a)
        Sq(0,1) + Sq(3)

    Python

        >>> from sage.all import *
        >>> Adem = SteenrodAlgebra(basis='adem')
        >>> a = Adem.Sq(Integer(2)) * Adem.Sq(Integer(1))
        >>> Adem.milnor(a)
        Sq(0,1) + Sq(3)

  ngens()

    Number of generators of `self`.

    OUTPUT: number or Infinity

    The Steenrod algebra is infinitely generated. A sub-Hopf algebra may be finitely or infinitely generated; in general, it is not clear what a minimal generating set is, nor the cardinality of that set. So: if the algebra is infinite-dimensional, this returns Infinity. If the algebra is finite-dimensional and is equal to one of the sub-Hopf algebras \(A(n)\), then their minimal generating set is known, and this returns the cardinality of that set. Otherwise, any sub-Hopf algebra is (not necessarily minimally) generated by the \(P^s_t\)’s that it contains (along with the \(Q_n\)’s it contains, at odd primes), so this returns the number of \(P^s_t\)’s and \(Q_n\)’s in the algebra.

    EXAMPLES:

    Sage

        sage: A = SteenrodAlgebra(3)
        sage: A.ngens()
        +Infinity
        sage: SteenrodAlgebra(profile=lambda n: n).ngens()
        +Infinity
        sage: SteenrodAlgebra(profile=[3,2,1]).ngens() # A(2)
        3
        sage: SteenrodAlgebra(profile=[3,2,1], basis='pst').ngens()
        3
        sage: SteenrodAlgebra(p=3, profile=[[3,2,1], [2,2,2,2]]).ngens()  # A(3) at p=3
        4
        sage: SteenrodAlgebra(profile=[1,2,1,1]).ngens()
        5

    Python

        >>> from sage.all import *
        >>> A = SteenrodAlgebra(Integer(3))
        >>> A.ngens()
        +Infinity
        >>> SteenrodAlgebra(profile=lambda n: n).ngens()
        +Infinity
        >>> SteenrodAlgebra(profile=[Integer(3),Integer(2),Integer(1)]).ngens() # A(2)
        3
        >>> SteenrodAlgebra(profile=[Integer(3),Integer(2),Integer(1)], basis='pst').ngens()
        3
        >>> SteenrodAlgebra(p=Integer(3), profile=[[Integer(3),Integer(2),Integer(1)], [Integer(2),Integer(2),Integer(2),Integer(2)]]).ngens()  # A(3) at p=3
        4
        >>> SteenrodAlgebra(profile=[Integer(1),Integer(2),Integer(1),Integer(1)]).ngens()
        5

  one_basis()

    The index of the element 1 in the basis for the Steenrod algebra.

    EXAMPLES:

    Sage

        sage: SteenrodAlgebra(p=2).one_basis()
        ()
        sage: SteenrodAlgebra(p=7).one_basis()
        ((), ())

    Python

        >>> from sage.all import *
        >>> SteenrodAlgebra(p=Integer(2)).one_basis()
        ()
        >>> SteenrodAlgebra(p=Integer(7)).one_basis()
        ((), ())

  order()

    The order of this algebra.

    This is computed by computing its vector space dimension \(d\) and then returning \(p^d\).

    EXAMPLES:

    Sage

        sage: SteenrodAlgebra(p=7).order()
        +Infinity
        sage: SteenrodAlgebra(profile=[2,1]).dimension()
        8
        sage: SteenrodAlgebra(profile=[2,1]).order()
        256
        sage: SteenrodAlgebra(p=3, profile=([1], [])).dimension()
        3
        sage: SteenrodAlgebra(p=3, profile=([1], [])).order()
        27
        sage: SteenrodAlgebra(p=5, profile=([], [2, 2])).dimension()
        4
        sage: SteenrodAlgebra(p=5, profile=([], [2, 2])).order() == 5**4
        True

    Python

        >>> from sage.all import *
        >>> SteenrodAlgebra(p=Integer(7)).order()
        +Infinity
        >>> SteenrodAlgebra(profile=[Integer(2),Integer(1)]).dimension()
        8
        >>> SteenrodAlgebra(profile=[Integer(2),Integer(1)]).order()
        256
        >>> SteenrodAlgebra(p=Integer(3), profile=([Integer(1)], [])).dimension()
        3
        >>> SteenrodAlgebra(p=Integer(3), profile=([Integer(1)], [])).order()
        27
        >>> SteenrodAlgebra(p=Integer(5), profile=([], [Integer(2), Integer(2)])).dimension()
        4
        >>> SteenrodAlgebra(p=Integer(5), profile=([], [Integer(2), Integer(2)])).order() == Integer(5)**Integer(4)
        True

  prime()

    The prime associated to `self`.

    EXAMPLES:

    Sage

        sage: SteenrodAlgebra(p=2, profile=[1,1]).prime()
        2
        sage: SteenrodAlgebra(p=7).prime()
        7

    Python

        >>> from sage.all import *
        >>> SteenrodAlgebra(p=Integer(2), profile=[Integer(1),Integer(1)]).prime()
        2
        >>> SteenrodAlgebra(p=Integer(7)).prime()
        7

  product_on_basis(t1, t2)

    The product of two basis elements of this algebra.

    INPUT:

    - `t1`, `t2` – tuples, the indices of two basis elements of self

    OUTPUT:

    the product of the two corresponding basis elements, as an element of self

    ALGORITHM: If the two elements are represented in the Milnor basis, use Milnor multiplication as implemented in `sage.algebras.steenrod.steenrod_algebra_mult`. If the two elements are represented in the Serre-Cartan basis, then multiply them using Adem relations (also implemented in `sage.algebras.steenrod.steenrod_algebra_mult`). This provides a good way of checking work – multiply Milnor elements, then convert them to Adem elements and multiply those, and see if the answers correspond.

    If the two elements are represented in some other basis, then convert them both to the Milnor basis and multiply.

    EXAMPLES:

    Sage

        sage: Milnor = SteenrodAlgebra()
        sage: Milnor.product_on_basis((2,), (2,))
        Sq(1,1)
        sage: Adem = SteenrodAlgebra(basis='adem')
        sage: Adem.Sq(2) * Adem.Sq(2) # indirect doctest
        Sq^3 Sq^1

    Python

        >>> from sage.all import *
        >>> Milnor = SteenrodAlgebra()
        >>> Milnor.product_on_basis((Integer(2),), (Integer(2),))
        Sq(1,1)
        >>> Adem = SteenrodAlgebra(basis='adem')
        >>> Adem.Sq(Integer(2)) * Adem.Sq(Integer(2)) # indirect doctest
        Sq^3 Sq^1

    When multiplying elements from different bases, the left-hand factor determines the form of the output:

    Sage

        sage: Adem.Sq(2) * Milnor.Sq(2)
        Sq^3 Sq^1
        sage: Milnor.Sq(2) * Adem.Sq(2)
        Sq(1,1)

    [Python]

        >>> from sage.all import *
        >>> Adem.Sq(Integer(2)) * Milnor.Sq(Integer(2))
        Sq^3 Sq^1
        >>> Milnor.Sq(Integer(2)) * Adem.Sq(Integer(2))
        Sq(1,1)

  profile(i, component=0)

    Profile function for this algebra.

    INPUT:

    - `i` – integer

    - `component` – either 0 or 1 (default: 0)

    OUTPUT: integer or \(\infty\)

    See the documentation for `sage.algebras.steenrod.steenrod_algebra` and `SteenrodAlgebra()` for information on profile functions.

    This applies the profile function to the integer \(i\). Thus when \(p=2\), \(i\) must be a positive integer. When \(p\) is odd, there are two profile functions, \(e\) and \(k\) (in the notation of the aforementioned documentation), corresponding, respectively to `component=0` and `component=1`. So when \(p\) is odd and `component` is 0, \(i\) must be positive, while when `component` is 1, \(i\) must be nonnegative.

    EXAMPLES:

    Sage

        sage: SteenrodAlgebra().profile(3)
        +Infinity
        sage: SteenrodAlgebra(profile=[3,2,1]).profile(1)
        3
        sage: SteenrodAlgebra(profile=[3,2,1]).profile(2)
        2

    Python

        >>> from sage.all import *
        >>> SteenrodAlgebra().profile(Integer(3))
        +Infinity
        >>> SteenrodAlgebra(profile=[Integer(3),Integer(2),Integer(1)]).profile(Integer(1))
        3
        >>> SteenrodAlgebra(profile=[Integer(3),Integer(2),Integer(1)]).profile(Integer(2))
        2

    When the profile is specified by a list, the default behavior is to return zero values outside the range of the list. This can be overridden if the algebra is created with an infinite `truncation_type`:

    Sage

        sage: SteenrodAlgebra(profile=[3,2,1]).profile(9)
        0
        sage: SteenrodAlgebra(profile=[3,2,1], truncation_type=Infinity).profile(9)
        +Infinity

        sage: B = SteenrodAlgebra(p=3, profile=(lambda n: n, lambda n: 1))
        sage: B.profile(3)
        3
        sage: B.profile(3, component=1)
        1

        sage: EA = SteenrodAlgebra(generic=True, profile=(lambda n: n, lambda n: 1))
        sage: EA.profile(4)
        4
        sage: EA.profile(2, component=1)
        1

    [Python]

        >>> from sage.all import *
        >>> SteenrodAlgebra(profile=[Integer(3),Integer(2),Integer(1)]).profile(Integer(9))
        0
        >>> SteenrodAlgebra(profile=[Integer(3),Integer(2),Integer(1)], truncation_type=Infinity).profile(Integer(9))
        +Infinity

        >>> B = SteenrodAlgebra(p=Integer(3), profile=(lambda n: n, lambda n: Integer(1)))
        >>> B.profile(Integer(3))
        3
        >>> B.profile(Integer(3), component=Integer(1))
        1

        >>> EA = SteenrodAlgebra(generic=True, profile=(lambda n: n, lambda n: Integer(1)))
        >>> EA.profile(Integer(4))
        4
        >>> EA.profile(Integer(2), component=Integer(1))
        1

  pst(s, t)

    The Margolis element \(P^s_t\).

    INPUT:

    - `s` – nonnegative integer

    - `t` – positive integer

    - `p` – positive prime number

    OUTPUT: element of the Steenrod algebra

    This returns the Margolis element \(P^s_t\) of the mod \(p\) Steenrod algebra: the element equal to \(P(0,0,...,0,p^s)\), where the \(p^s\) is in position \(t\).

    EXAMPLES:

    Sage

        sage: A2 = SteenrodAlgebra(2)
        sage: A2.pst(3,5)
        Sq(0,0,0,0,8)
        sage: A2.pst(1,2) == Sq(4)*Sq(2) + Sq(2)*Sq(4)
        True
        sage: SteenrodAlgebra(5).pst(3,5)
        P(0,0,0,0,125)

    Python

        >>> from sage.all import *
        >>> A2 = SteenrodAlgebra(Integer(2))
        >>> A2.pst(Integer(3),Integer(5))
        Sq(0,0,0,0,8)
        >>> A2.pst(Integer(1),Integer(2)) == Sq(Integer(4))*Sq(Integer(2)) + Sq(Integer(2))*Sq(Integer(4))
        True
        >>> SteenrodAlgebra(Integer(5)).pst(Integer(3),Integer(5))
        P(0,0,0,0,125)

  top_class()

    Highest dimensional basis element. This is only defined if the algebra is finite.

    EXAMPLES:

    Sage

        sage: SteenrodAlgebra(2, profile=(3,2,1)).top_class()
        Sq(7,3,1)
        sage: SteenrodAlgebra(3, profile=((2,2,1),(1,2,2,2,2))).top_class()
        Q_1 Q_2 Q_3 Q_4 P(8,8,2)

    Python

        >>> from sage.all import *
        >>> SteenrodAlgebra(Integer(2), profile=(Integer(3),Integer(2),Integer(1))).top_class()
        Sq(7,3,1)
        >>> SteenrodAlgebra(Integer(3), profile=((Integer(2),Integer(2),Integer(1)),(Integer(1),Integer(2),Integer(2),Integer(2),Integer(2)))).top_class()
        Q_1 Q_2 Q_3 Q_4 P(8,8,2)

class sage.algebras.steenrod.steenrod_algebra.SteenrodAlgebra_mod_two(p=2, basis='milnor', **kwds)

  Bases: `SteenrodAlgebra_generic`

  The mod 2 Steenrod algebra.

  Users should not call this, but use the function `SteenrodAlgebra()` instead. See that function for extensive documentation. (This differs from `SteenrodAlgebra_generic` only in that it has a method `Sq()` for defining elements.)

  Sq(*nums)

    Milnor element \(\text{Sq}(a,b,c,...)\).

    INPUT:

    - `a`, `b`, `c`, … – nonnegative integers

    OUTPUT: element of the Steenrod algebra

    This returns the Milnor basis element \(\text{Sq}(a, b, c, ...)\).

    EXAMPLES:

    Sage

        sage: A = SteenrodAlgebra(2)
        sage: A.Sq(5)
        Sq(5)
        sage: A.Sq(5,0,2)
        Sq(5,0,2)

    Python

        >>> from sage.all import *
        >>> A = SteenrodAlgebra(Integer(2))
        >>> A.Sq(Integer(5))
        Sq(5)
        >>> A.Sq(Integer(5),Integer(0),Integer(2))
        Sq(5,0,2)

    Entries must be nonnegative integers; otherwise, an error results.