Path: blob/master/sage/algebras/steenrod/steenrod_algebra_mult.py
4145 views
r"""1Multiplication for elements of the Steenrod algebra23AUTHORS:45- John H. Palmieri (2008-07-30: version 0.9) initial version: Milnor6multiplication.7- John H. Palmieri (2010-06-30: version 1.0) multiplication of8Serre-Cartan basis elements using the Adem relations.9- Simon King (2011-10-25): Fix the use of cached functions.1011.. rubric:: Milnor multiplication, `p=2`1213See Milnor's paper [Mil] for proofs, etc.1415To multiply Milnor basis elements $\text{Sq}(r_1, r_2, ...)$ and16$\text{Sq}(s_1, s_2,...)$ at the prime 2, form all possible matrices17$M$ with rows and columns indexed starting at 0, with position (0,0)18deleted (or ignored), with $s_i$ equal to the sum of column $i$ for19each $i$, and with $r_j$ equal to the 'weighted' sum of row $j$. The20weights are as follows: elements from column $i$ are multiplied by21$2^i$. For example, to multiply $\text{Sq}(2)$ and $\text{Sq}(1,1)$,22form the matrices2324.. math::2526\begin{Vmatrix}27* & 1 & 1 \\282 & 0 & 029\end{Vmatrix}30\quad \text{and} \quad31\begin{Vmatrix}32* & 0 & 1 \\330 & 1 & 034\end{Vmatrix}3536(The $*$ is the ignored (0,0)-entry of the matrix.) For each such37matrix $M$, compute a multinomial coefficient, mod 2: for each38diagonal $\{m_{ij}: i+j=n\}$, compute $(\sum m_{i,j}!) / (m_{0,n}!39m_{1,n-1}! ... m_{n,0}!)$. Multiply these together for all $n$. (To40compute this mod 2, view the entries of the matrix as their base 241expansions; then this coefficient is zero if and only if there is some42diagonal containing two numbers which have a summand in common in43their base 2 expansion. For example, if 3 and 10 are in the same44diagonal, the coefficient is zero, because $3=1+2$ and $10=2+8$: they45both have a summand of 2.)4647Now, for each matrix with multinomial coefficient 1, let $t_n$ be48the sum of the nth diagonal in the matrix; then4950.. math::5152\text{Sq}(r_1, r_2, ...) \text{Sq}(s_1, s_2, ...) = \sum \text{Sq}(t_1, t_2, ...)5354The function :func:`milnor_multiplication` takes as input two tuples55of non-negative integers, $r$ and $s$, which represent56$\text{Sq}(r)=\text{Sq}(r_1, r_2, ...)$ and57$\text{Sq}(s)=\text{Sq}(s_1, s_2, ...)$; it returns as output a58dictionary whose keys are tuples $t=(t_1, t_2, ...)$ of non-negative59integers, and for each tuple the associated value is the coefficient60of $\text{Sq}(t)$ in the product formula. (Since we are working mod 2,61this coefficient is 1 -- if it is zero, the the element is omitted from62the dictionary altogether).6364.. rubric:: Milnor multiplication, odd primes6566As for the `p=2` case, see Milnor's paper [Mil] for proofs.6768Fix an odd prime $p$. There are three steps to multiply Milnor basis69elements $Q_{f_1} Q_{f_2} ... \mathcal{P}(q_1, q_2, ...)$ and70$Q_{g_1} Q_{g_2} ... \mathcal{P}(s_1, s_2,...)$: first, use the formula7172.. math::7374\mathcal{P}(q_1, q_2, ...) Q_k = Q_k \mathcal{P}(q_1, q_2, ...)75+ Q_{k+1} \mathcal{P}(q_1 - p^k, q_2, ...)76+ Q_{k+2} \mathcal{P}(q_1, q_2 - p^k, ...)77+ ...7879Second, use the fact that the $Q_k$'s form an exterior algebra: $Q_k^2 =800$ for all $k$, and if $i \neq j$, then $Q_i$ and $Q_j$ anticommute:81$Q_i Q_j = -Q_j Q_i$. After these two steps, the product is a linear82combination of terms of the form8384.. math::8586Q_{e_1} Q_{e_2} ... \mathcal{P}(r_1, r_2, ...) \mathcal{P}(s_1, s_2, ...).8788Finally, use Milnor matrices to multiply the pairs of89$\mathcal{P}(...)$ terms, as at the prime 2: form all possible90matrices $M$ with rows and columns indexed starting at 0, with91position (0,0) deleted (or ignored), with $s_i$ equal to the sum of92column $i$ for each $i$, and with $r_j$ equal to the weighted sum of93row $j$: elements from column $i$ are multiplied by $p^i$. For94example when $p=5$, to multiply $\mathcal{P}(5)$ and95$\mathcal{P}(1,1)$, form the matrices9697.. math::9899\begin{Vmatrix}100* & 1 & 1 \\1015 & 0 & 0102\end{Vmatrix}103\quad \text{and} \quad104\begin{Vmatrix}105* & 0 & 1 \\1060 & 1 & 0107\end{Vmatrix}108109For each such matrix $M$, compute a multinomial coefficient, mod $p$:110for each diagonal $\{m_{ij}: i+j=n\}$, compute $(\sum m_{i,j}!) /111(m_{0,n}! m_{1,n-1}! ... m_{n,0}!)$. Multiply these together for112all $n$.113114Now, for each matrix with nonzero multinomial coefficient $b_M$, let115$t_n$ be the sum of the $n$-th diagonal in the matrix; then116117.. math::118119\mathcal{P}(r_1, r_2, ...) \mathcal{P}(s_1, s_2, ...)120= \sum b_M \mathcal{P}(t_1, t_2, ...)121122For example when $p=5$, we have123124.. math::125126\mathcal{P}(5) \mathcal{P}(1,1) = \mathcal{P}(6,1) + 2 \mathcal{P}(0,2).127128The function :func:`milnor_multiplication` takes as input two pairs of129tuples of non-negative integers, $(g,q)$ and $(f,s)$, which represent130$Q_{g_1} Q_{g_2} ... \mathcal{P}(q_1, q_2, ...)$ and131$Q_{f_1} Q_{f_2} ... \mathcal{P}(s_1, s_2, ...)$. It returns as output a132dictionary whose keys are pairs of tuples $(e,t)$ of non-negative133integers, and for each tuple the associated value is the coefficient134in the product formula.135136.. rubric:: The Adem relations and admissible sequences137138If `p=2`, then the mod 2 Steenrod algebra is generated by Steenrod139squares `\text{Sq}^a` for `a \geq 0` (equal to the Milnor basis element140`\text{Sq}(a)`). The *Adem relations* are as follows: if `a < 2b`,141142.. math::143144\text{Sq}^a \text{Sq}^b = \sum_{j=0}^{a/2} \binom{b-j-1}{a-2j} \text{Sq}^{a+b-j} \text{Sq}^j145146A monomial `\text{Sq}^{i_1} \text{Sq}^{i_2} ... \text{Sq}^{i_n}` is called *admissible* if147`i_k \geq 2 i_{k+1}` for all `k`. One can use the Adem relations to148show that the admissible monomials span the Steenrod algebra, as a149vector space; with more work, one can show that the admissible150monomials are also linearly independent. They form the *Serre-Cartan*151basis for the Steenrod algebra. To multiply a collection of152admissible monomials, concatenate them and see if the result is153admissible. If it is, you're done. If not, find the first pair `\text{Sq}^a154\text{Sq}^b` where it fails to be admissible and apply the Adem relations155there. Repeat with the resulting terms. One can prove that this156process terminates in a finite number of steps, and therefore gives a157procedure for multiplying elements of the Serre-Cartan basis.158159At an odd prime `p`, the Steenrod algebra is generated by the pth160power operations `\mathcal{P}^a` (the same as `\mathcal{P}(a)` in the161Milnor basis) and the Bockstein operation `\beta` (= `Q_0` in the162Milnor basis). The odd primary *Adem relations* are as follows: if `a163< pb`,164165.. math::166167\mathcal{P}^a \mathcal{P}^b = \sum_{j=0}^{a/p} (-1)^{a+j}168\binom{(b-j)(p-1)-1}{a-pj} \mathcal{P}^{a+b-j} \mathcal{P}^j169170Also, if `a \leq pb`,171172.. math::173174\mathcal{P}^a \beta \mathcal{P}^b = \sum_{j=0}^{a/p} (-1)^{a+j}175\binom{(b-j)(p-1)}{a-pj} \beta \mathcal{P}^{a+b-j} \mathcal{P}^j +176\sum_{j=0}^{a/p} (-1)^{a+j-1} \binom{(b-j)(p-1)-1}{a-pj-1}177\mathcal{P}^{a+b-j} \beta \mathcal{P}^j178179The *admissible* monomials at an odd prime are products of the form180181.. math::182183\beta^{\epsilon_0} \mathcal{P}^{s_1} \beta^{\epsilon_1}184\mathcal{P}^{s_2} ... \mathcal{P}^{s_n} \beta^{\epsilon_n}185186where `s_k \geq \epsilon_{k+1} + p s_{k+1}` for all `k`. As at the187prime 2, these form a basis for the Steenrod algebra.188189The main function for this is :func:`make_mono_admissible_` (and in190practice, one should use the cached version,191``make_mono_admissible``), which converts a product of Steenrod192squares or pth power operations and Bocksteins into a dictionary193representing a sum of admissible monomials.194195REFERENCES:196197- [Mil] J. W. Milnor, "The Steenrod algebra and its dual", Ann. of Math.198(2) 67 (1958), 150--171.199200- [SE] N. E. Steenrod, "Cohomology operations (Lectures by201N. E. Steenrod written and revised by D. B. A. Epstein)". Annals of202Mathematics Studies, No. 50, 1962, Princeton University Press.203"""204205#*****************************************************************************206# Copyright (C) 2008-2010 John H. Palmieri <[email protected]>207# Distributed under the terms of the GNU General Public License (GPL)208#*****************************************************************************209210from sage.misc.cachefunc import cached_function211212# Milnor, p=2213214def milnor_multiplication(r,s):215r"""216Product of Milnor basis elements r and s at the prime 2.217218INPUT:219220- r - tuple of non-negative integers221- s - tuple of non-negative integers222223OUTPUT:224225Dictionary of terms of the form (tuple: coeff), where226'tuple' is a tuple of non-negative integers and 'coeff' is 1.227228This computes Milnor matrices for the product of $\text{Sq}(r)$229and $\text{Sq}(s)$, computes their multinomial coefficients, and230for each matrix whose coefficient is 1, add $\text{Sq}(t)$ to the231output, where $t$ is the tuple formed by the diagonals sums from232the matrix.233234EXAMPLES::235236sage: from sage.algebras.steenrod.steenrod_algebra_mult import milnor_multiplication237sage: milnor_multiplication((2,), (1,))238{(0, 1): 1, (3,): 1}239sage: milnor_multiplication((4,), (2,1))240{(6, 1): 1, (0, 3): 1, (2, 0, 1): 1}241sage: milnor_multiplication((2,4), (0,1))242{(2, 5): 1, (2, 0, 0, 1): 1}243244These examples correspond to the following product computations:245246.. math::247248\text{Sq}(2) \text{Sq}(1) = \text{Sq}(0,1) + \text{Sq}(3)249250\text{Sq}(4) \text{Sq}(2,1) = \text{Sq}(6,1) + \text{Sq}(0,3) + \text{Sq}(2,0,1)251252\text{Sq}(2,4) \text{Sq}(0,1) = \text{Sq}(2, 5) + \text{Sq}(2, 0, 0, 1)253254This uses the same algorithm Monks does in his Maple package: see255http://mathweb.scranton.edu/monks/software/Steenrod/steen.html.256"""257result = {}258rows = len(r) + 1259cols = len(s) + 1260diags = len(r) + len(s)261# initialize matrix262M = range(rows)263for i in range(rows):264M[i] = [0]*cols265for j in range(1,cols):266M[0][j] = s[j-1]267for i in range(1,rows):268M[i][0] = r[i-1]269for j in range(1,cols):270M[i][j] = 0271found = True272while found:273# check diagonals274n = 1275okay = 1276diagonal = [0]*diags277while n <= diags and okay is not None:278nth_diagonal = [M[i][n-i] for i in range(max(0,n-cols+1), min(1+n,rows))]279okay = multinomial(nth_diagonal)280diagonal[n-1] = okay281n = n + 1282if okay is not None:283i = diags - 1284while i >= 0 and diagonal[i] == 0:285i = i - 1286t = tuple(diagonal[:i+1])287# reduce mod two:288if t in result:289del result[t]290else:291result[t] = 1292# now look for new matrices:293found = False294i = 1295while not found and i < rows:296sum = M[i][0]297j = 1298while not found and j < cols:299# check to see if column index j is small enough300if sum >= 2**j:301# now check to see if there's anything above this entry302# to add to it303temp_col_sum = 0304for k in range(i):305temp_col_sum += M[k][j]306if temp_col_sum != 0:307found = True308for row in range(1,i):309M[row][0] = r[row-1]310for col in range(1,cols):311M[0][col] = M[0][col] + M[row][col]312M[row][col] = 0313for col in range(1,j):314M[0][col] = M[0][col] + M[i][col]315M[i][col] = 0316M[0][j] = M[0][j] - 1317M[i][j] = M[i][j] + 1318M[i][0] = sum - 2**j319else:320sum = sum + M[i][j] * 2**j321else:322sum = sum + M[i][j] * 2**j323j = j + 1324i = i + 1325return result326327def multinomial(list):328r"""329Multinomial coefficient of list, mod 2.330331INPUT:332333- list - list of integers334335OUTPUT:336337None if the multinomial coefficient is 0, or sum of list if it is 1338339Given the input $[n_1, n_2, n_3, ...]$, this computes the340multinomial coefficient $(n_1 + n_2 + n_3 + ...)! / (n_1! n_2!341n_3! ...)$, mod 2. The method is roughly this: expand each342$n_i$ in binary. If there is a 1 in the same digit for any $n_i$343and $n_j$ with $i\neq j$, then the coefficient is 0; otherwise, it344is 1.345346EXAMPLES::347348sage: from sage.algebras.steenrod.steenrod_algebra_mult import multinomial349sage: multinomial([1,2,4])3507351sage: multinomial([1,2,5])352sage: multinomial([1,2,12,192,256])353463354355This function does not compute any factorials, so the following are356actually reasonable to do::357358sage: multinomial([1,65536])35965537360sage: multinomial([4,65535])361sage: multinomial([32768,65536])36298304363"""364old_sum = list[0]365okay = True366i = 1367while okay and i < len(list):368j = 1369while okay and j <= min(old_sum, list[i]):370if j & old_sum == j:371okay = (j & list[i] == 0)372j = j << 1373old_sum = old_sum + list[i]374i = i + 1375if okay:376return old_sum377else:378return None379380# Milnor, p odd381382def milnor_multiplication_odd(m1,m2,p):383r"""384Product of Milnor basis elements defined by m1 and m2 at the odd prime p.385386INPUT:387388- m1 - pair of tuples (e,r), where e is an increasing tuple of389non-negative integers and r is a tuple of non-negative integers390- m2 - pair of tuples (f,s), same format as m1391- p - odd prime number392393OUTPUT:394395Dictionary of terms of the form (tuple: coeff), where 'tuple' is396a pair of tuples, as for r and s, and 'coeff' is an integer mod p.397398This computes the product of the Milnor basis elements399$Q_{e_1} Q_{e_2} ... P(r_1, r_2, ...)$ and400$Q_{f_1} Q_{f_2} ... P(s_1, s_2, ...)$.401402EXAMPLES::403404sage: from sage.algebras.steenrod.steenrod_algebra_mult import milnor_multiplication_odd405sage: milnor_multiplication_odd(((0,2),(5,)), ((1,),(1,)), 5)406{((0, 1, 2), (0, 1)): 4, ((0, 1, 2), (6,)): 4}407sage: milnor_multiplication_odd(((0,2,4),()), ((1,3),()), 7)408{((0, 1, 2, 3, 4), ()): 6}409sage: milnor_multiplication_odd(((0,2,4),()), ((1,5),()), 7)410{((0, 1, 2, 4, 5), ()): 1}411sage: milnor_multiplication_odd(((),(6,)), ((),(2,)), 3)412{((), (4, 1)): 1, ((), (8,)): 1, ((), (0, 2)): 1}413414These examples correspond to the following product computations:415416.. math::417418p=5: \quad Q_0 Q_2 \mathcal{P}(5) Q_1 \mathcal{P}(1) = 4 Q_0 Q_1 Q_2 \mathcal{P}(0,1) + 4 Q_0 Q_1 Q_2 \mathcal{P}(6)419420p=7: \quad (Q_0 Q_2 Q_4) (Q_1 Q_3) = 6 Q_0 Q_1 Q_2 Q_3 Q_4421422p=7: \quad (Q_0 Q_2 Q_4) (Q_1 Q_5) = Q_0 Q_1 Q_2 Q_3 Q_5423424p=3: \quad \mathcal{P}(6) \mathcal{P}(2) = \mathcal{P}(0,2) + \mathcal{P}(4,1) + \mathcal{P}(8)425426The following used to fail until the trailing zeroes were427eliminated in p_mono::428429sage: A = SteenrodAlgebra(3)430sage: a = A.P(0,3); b = A.P(12); c = A.Q(1,2)431sage: (a+b)*c == a*c + b*c432True433434Test that the bug reported in #7212 has been fixed::435436sage: A.P(36,6)*A.P(27,9,81)4372 P(13,21,83) + P(14,24,82) + P(17,20,83) + P(25,18,83) + P(26,21,82) + P(36,15,80,1) + P(49,12,83) + 2 P(50,15,82) + 2 P(53,11,83) + 2 P(63,15,81)438439This uses the same algorithm Monks does in his Maple package to440iterate through the possible matrices: see441http://mathweb.scranton.edu/monks/software/Steenrod/steen.html.442"""443from sage.rings.all import GF444F = GF(p)445(f,s) = m2446# First compute Q_e0 Q_e1 ... P(r1, r2, ...) Q_f0 Q_f1 ...447# Store results (as dictionary of pairs of tuples) in 'answer'.448answer = {m1: F(1)}449for k in f:450old_answer = answer451answer = {}452for mono in old_answer:453if k not in mono[0]:454q_mono = set(mono[0])455if len(q_mono) > 0:456ind = len(q_mono.intersection(range(k,1+max(q_mono))))457else:458ind = 0459coeff = (-1)**ind * old_answer[mono]460lst = list(mono[0])461if ind == 0:462lst.append(k)463else:464lst.insert(-ind,k)465q_mono = tuple(lst)466p_mono = mono[1]467answer[(q_mono, p_mono)] = F(coeff)468for i in range(1,1+len(mono[1])):469if (k+i not in mono[0]) and (p**k <= mono[1][i-1]):470q_mono = set(mono[0])471if len(q_mono) > 0:472ind = len(q_mono.intersection(range(k+i,1+max(q_mono))))473else:474ind = 0475coeff = (-1)**ind476lst = list(mono[0])477if ind == 0:478lst.append(k+i)479else:480lst.insert(-ind,k+i)481q_mono = tuple(lst)482p_mono = list(mono[1])483p_mono[i-1] = p_mono[i-1] - p**k484485# The next two lines were added so that p_mono won't486# have trailing zeros. This makes p_mono uniquely487# determined by P(*p_mono).488489while len(p_mono)>0 and p_mono[-1] == 0:490p_mono.pop()491492answer[(q_mono, tuple(p_mono))] = F(coeff)493# Now for the Milnor matrices. For each entry '(e,r): coeff' in answer,494# multiply r with s. Record coefficient for matrix and multiply by coeff.495# Store in 'result'.496if len(s) == 0:497result = answer498else:499result = {}500for (e, r) in answer:501old_coeff = answer[(e,r)]502# Milnor multiplication for r and s503rows = len(r) + 1504cols = len(s) + 1505diags = len(r) + len(s)506# initialize matrix507M = range(rows)508for i in range(rows):509M[i] = [0]*cols510for j in range(1,cols):511M[0][j] = s[j-1]512for i in range(1,rows):513M[i][0] = r[i-1]514for j in range(1,cols):515M[i][j] = 0516found = True517while found:518# check diagonals519n = 1520coeff = old_coeff521diagonal = [0]*diags522while n <= diags and coeff != 0:523nth_diagonal = [M[i][n-i] for i in range(max(0,n-cols+1), min(1+n,rows))]524coeff = coeff * multinomial_odd(nth_diagonal,p)525diagonal[n-1] = sum(nth_diagonal)526n = n + 1527if F(coeff) != 0:528i = diags - 1529while i >= 0 and diagonal[i] == 0:530i = i - 1531t = tuple(diagonal[:i+1])532if (e,t) in result:533result[(e,t)] = F(coeff + result[(e,t)])534else:535result[(e,t)] = F(coeff)536# now look for new matrices:537found = False538i = 1539while not found and i < rows:540temp_sum = M[i][0]541j = 1542while not found and j < cols:543# check to see if column index j is small enough544if temp_sum >= p**j:545# now check to see if there's anything above this entry546# to add to it547temp_col_sum = 0548for k in range(i):549temp_col_sum += M[k][j]550if temp_col_sum != 0:551found = True552for row in range(1,i):553M[row][0] = r[row-1]554for col in range(1,cols):555M[0][col] = M[0][col] + M[row][col]556M[row][col] = 0557for col in range(1,j):558M[0][col] = M[0][col] + M[i][col]559M[i][col] = 0560M[0][j] = M[0][j] - 1561M[i][j] = M[i][j] + 1562M[i][0] = temp_sum - p**j563else:564temp_sum += M[i][j] * p**j565else:566temp_sum += M[i][j] * p**j567j = j + 1568i = i + 1569return result570571def multinomial_odd(list,p):572r"""573Multinomial coefficient of list, mod p.574575INPUT:576577- list - list of integers578- p - a prime number579580OUTPUT:581582Associated multinomial coefficient, mod p583584Given the input $[n_1, n_2, n_3, ...]$, this computes the585multinomial coefficient $(n_1 + n_2 + n_3 + ...)! / (n_1! n_2!586n_3! ...)$, mod $p$. The method is this: expand each $n_i$ in587base $p$: $n_i = \sum_j p^j n_{ij}$. Do the same for the sum of588the $n_i$'s, which we call $m$: $m = \sum_j p^j m_j$. Then the589multinomial coefficient is congruent, mod $p$, to the product of590the multinomial coefficients $m_j! / (n_{1j}! n_{2j}! ...)$.591592Furthermore, any multinomial coefficient $m! / (n_1! n_2! ...)$593can be computed as a product of binomial coefficients: it equals594595.. math::596597\binom{n_1}{n_1} \binom{n_1 + n_2}{n_2} \binom{n_1 + n_2 + n_3}{n_3} ...598599This is convenient because Sage's binomial function returns600integers, not rational numbers (as would be produced just by601dividing factorials).602603EXAMPLES::604605sage: from sage.algebras.steenrod.steenrod_algebra_mult import multinomial_odd606sage: multinomial_odd([1,2,4], 2)6071608sage: multinomial_odd([1,2,4], 7)6090610sage: multinomial_odd([1,2,4], 11)6116612sage: multinomial_odd([1,2,4], 101)6134614sage: multinomial_odd([1,2,4], 107)615105616"""617from sage.rings.all import GF, Integer618from sage.rings.arith import binomial619n = sum(list)620answer = 1621F = GF(p)622n_expansion = Integer(n).digits(p)623list_expansion = [Integer(k).digits(p) for k in list]624index = 0625while answer != 0 and index < len(n_expansion):626multi = F(1)627partial_sum = 0628for exp in list_expansion:629if index < len(exp):630partial_sum = partial_sum + exp[index]631multi = F(multi * binomial(partial_sum, exp[index]))632answer = F(answer * multi)633index += 1634return answer635636# adem relations, serre-cartan basis, admissible sequences637638def binomial_mod2(n,k):639r"""640The binomial coefficient `\binom{n}{k}`, computed mod 2.641642INPUT:643644- `n`, `k` - integers645646OUTPUT:647648`n` choose `k`, mod 2649650EXAMPLES::651652sage: from sage.algebras.steenrod.steenrod_algebra_mult import binomial_mod2653sage: binomial_mod2(4,2)6540655sage: binomial_mod2(5,4)6561657sage: binomial_mod2(3 * 32768, 32768)6581659sage: binomial_mod2(4 * 32768, 32768)6600661"""662if n < k:663return 0664elif ((n-k) & k) == 0:665return 1666else:667return 0668669def binomial_modp(n,k,p):670r"""671The binomial coefficient `\binom{n}{k}`, computed mod `p`.672673INPUT:674675- `n`, `k` - integers676- `p` - prime number677678OUTPUT:679680`n` choose `k`, mod `p`681682EXAMPLES::683684sage: from sage.algebras.steenrod.steenrod_algebra_mult import binomial_modp685sage: binomial_modp(5,2,3)6861687sage: binomial_modp(6,2,11) # 6 choose 2 = 156884689"""690if n < k:691return 0692return multinomial_odd([n-k, k], p)693694@cached_function695def adem(a, b, c=0, p=2):696r"""697The mod `p` Adem relations698699INPUT:700701- `a`, `b`, `c` (optional) - nonnegative integers, corresponding702to either `P^a P^b` or (if `c` present) to `P^a \beta^b P^c`703- `p` - positive prime number (optional, default 2)704705OUTPUT:706707a dictionary representing the mod `p` Adem relations708applied to `P^a P^b` or (if `c` present) to `P^a \beta^b P^c`.709710.. note::711712Users should use :func:`adem` instead of this function (which713has a trailing underscore in its name): :func:`adem`714is the cached version of this one, and so will be faster.715716The mod `p` Adem relations for the mod `p` Steenrod algebra are as717follows: if `p=2`, then if `a < 2b`,718719.. math::720721\text{Sq}^a \text{Sq}^b = \sum_{j=0}^{a/2} \binom{b-j-1}{a-2j} \text{Sq}^{a+b-j} \text{Sq}^j722723If `p` is odd, then if `a < pb`,724725.. math::726727P^a P^b = \sum_{j=0}^{a/p} (-1)^{a+j} \binom{(b-j)(p-1)-1}{a-pj} P^{a+b-j} P^j728729Also for `p` odd, if `a \leq pb`,730731.. math::732733P^a \beta P^b = \sum_{j=0}^{a/p} (-1)^{a+j} \binom{(b-j)(p-1)}{a-pj} \beta P^{a+b-j} P^j734+ \sum_{j=0}^{a/p} (-1)^{a+j-1} \binom{(b-j)(p-1)-1}{a-pj-1} P^{a+b-j} \beta P^j735736EXAMPLES:737738If two arguments (`a` and `b`) are given, then computations are739done mod 2. If `a \geq 2b`, then the dictionary {(a,b): 1} is740returned. Otherwise, the right side of the mod 2 Adem relation741for `\text{Sq}^a \text{Sq}^b` is returned. For example, since742`\text{Sq}^2 \text{Sq}^2 = \text{Sq}^3 \text{Sq}^1`, we have::743744sage: from sage.algebras.steenrod.steenrod_algebra_mult import adem745sage: adem(2,2) # indirect doctest746{(3, 1): 1}747sage: adem(4,2)748{(4, 2): 1}749sage: adem(4,4)750{(6, 2): 1, (7, 1): 1}751752If `p` is given and is odd, then with two inputs `a` and `b`, the753Adem relation for `P^a P^b` is computed. With three inputs `a`,754`b`, `c`, the Adem relation for `P^a \beta^b P^c` is computed.755In either case, the keys in the output are all tuples of odd length,756with ``(i_1, i_2, ..., i_m)`` representing757758.. math::759760\beta^{i_1} P^{i_2} \beta^{i_3} P^{i_4} ... \beta^{i_m}761762For instance::763764sage: adem(3,1, p=3)765{(0, 3, 0, 1, 0): 1}766sage: adem(3,0,1, p=3)767{(0, 3, 0, 1, 0): 1}768sage: adem(1,0,1, p=7)769{(0, 2, 0): 2}770sage: adem(1,1,1, p=5)771{(1, 2, 0): 1, (0, 2, 1): 1}772sage: adem(1,1,2, p=5)773{(1, 3, 0): 2, (0, 3, 1): 1}774"""775if p == 2:776if b == 0: return {(a,): 1}777elif a == 0: return {(b,): 1}778elif a >= 2*b: return {(a,b): 1}779result = {}780for c in range(1+a/2):781if binomial_mod2(b-c-1, a-2*c) == 1:782if c == 0:783result[(a+b,)] = 1784else:785result[(a+b-c,c)] = 1786return result787# p odd788if a == 0 and b == 0:789return {(c,): 1}790if c == 0:791bockstein = 0792A = a793B = b794else:795A = a796B = c797bockstein = b # should be 0 or 1798if A == 0:799return {(bockstein, B, 0): 1}800if B == 0:801return {(0, A, bockstein): 1}802if bockstein == 0:803if A >= p*B: # admissible804return {(0,A,0,B,0): 1}805result = {}806for j in range(1 + int(a/p)):807coeff = (-1)**(A+j) * binomial_modp((B-j) * (p-1) - 1, A - p*j, p)808if coeff % p != 0:809if j == 0:810result[(0,A+B,0)] = coeff811else:812result[(0,A+B-j,0,j,0)] = coeff813else:814if A >= p*B + 1: # admissible815return {(0,A,1,B,0): 1}816result = {}817for j in range(1 + int(a/p)):818coeff = (-1)**(A+j) * binomial_modp((B-j) * (p-1), A - p*j, p)819if coeff % p != 0:820if j == 0:821result[(1,A+B,0)] = coeff822else:823result[(1,A+B-j,0,j,0)] = coeff824for j in range(1 + int((a-1)/p)):825coeff = (-1)**(A+j-1) * binomial_modp((B-j) * (p-1) - 1, A - p*j - 1, p)826if coeff % p != 0:827if j == 0:828result[(0,A+B,1)] = coeff829else:830result[(0,A+B-j,1,j,0)] = coeff831return result832833@cached_function834def make_mono_admissible(mono, p=2):835r"""836Given a tuple ``mono``, view it as a product of Steenrod837operations, and return a dictionary giving data equivalent to838writing that product as a linear combination of admissible839monomials.840841When `p=2`, the sequence (and hence the corresponding monomial)842`(i_1, i_2, ...)` is admissible if `i_j \geq 2 i_{j+1}` for all843`j`.844845When `p` is odd, the sequence `(e_1, i_1, e_2, i_2, ...)` is846admissible if `i_j \geq e_{j+1} + p i_{j+1}` for all `j`.847848INPUT:849850- ``mono`` - a tuple of non-negative integers851- `p` - prime number, optional (default 2)852853OUTPUT:854855Dictionary of terms of the form (tuple: coeff), where856'tuple' is an admissible tuple of non-negative integers and857'coeff' is its coefficient. This corresponds to a linear858combination of admissible monomials. When `p` is odd, each tuple859must have an odd length: it should be of the form `(e_1, i_1, e_2,860i_2, ..., e_k)` where each `e_j` is either 0 or 1 and each `i_j`861is a positive integer: this corresponds to the admissible monomial862863.. math::864865\beta^{e_1} \mathcal{P}^{i_2} \beta^{e_2} \mathcal{P}^{i_2} ...866\mathcal{P}^{i_k} \beta^{e_k}867868ALGORITHM:869870Given `(i_1, i_2, i_3, ...)`, apply the Adem relations to the first871pair (or triple when `p` is odd) where the sequence is inadmissible,872and then apply this function recursively to each of the resulting873tuples `(i_1, ..., i_{j-1}, NEW, i_{j+2}, ...)`, keeping track of874the coefficients.875876.. note::877878Users should use :func:`make_mono_admissible` instead of this879function (which has a trailing underscore in its name):880:func:`make_mono_admissible` is the cached version of this881one, and so will be faster.882883EXAMPLES::884885sage: from sage.algebras.steenrod.steenrod_algebra_mult import make_mono_admissible886sage: make_mono_admissible((12,)) # already admissible, indirect doctest887{(12,): 1}888sage: make_mono_admissible((2,1)) # already admissible889{(2, 1): 1}890sage: make_mono_admissible((2,2))891{(3, 1): 1}892sage: make_mono_admissible((2, 2, 2))893{(5, 1): 1}894sage: make_mono_admissible((0, 2, 0, 1, 0), p=7)895{(0, 3, 0): 3}896"""897from sage.rings.all import GF898if len(mono) == 1:899return {mono: 1}900if p==2 and len(mono) == 2:901return adem(*mono, p=p)902if p == 2:903# check to see if admissible:904admissible = True905for j in range(len(mono)-1):906if mono[j] < 2*mono[j+1]:907admissible = False908break909if admissible:910return {mono: 1}911# else j is the first index where admissibility fails912ans = {}913y = adem(mono[j], mono[j+1])914for x in y:915new = mono[:j] + x + mono[j+2:]916new = make_mono_admissible(new)917for m in new:918if m in ans:919ans[m] = ans[m] + y[x] * new[m]920if F(ans[m]) == 0:921del ans[m]922else:923ans[m] = y[x] * new[m]924return ans925# p odd926# check to see if admissible:927admissible = True928for j in range(1, len(mono)-2, 2):929if mono[j] < mono[j+1] + p*mono[j+2]:930admissible = False931break932if admissible:933return {mono: 1}934# else j is the first index where admissibility fails935ans = {}936y = adem(*mono[j:j+3], p=p)937for x in y:938new_x = list(x)939new_x[0] = mono[j-1] + x[0]940if len(mono) >= j+3:941new_x[-1] = mono[j+3] + x[-1]942if new_x[0] <= 1 and new_x[-1] <= 1:943new = mono[:j-1] + tuple(new_x) + mono[j+4:]944new = make_mono_admissible(new, p)945for m in new:946if m in ans:947ans[m] = ans[m] + y[x] * new[m]948if F(ans[m]) == 0:949del ans[m]950else:951ans[m] = y[x] * new[m]952return ans953954955