Path: blob/master/src/sage/algebras/steenrod/steenrod_algebra_mult.py
8822 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)438439Associativity once failed because of a sign error::440441sage: a,b,c = A.Q_exp(0,1), A.P(3), A.Q_exp(1,1)442sage: (a*b)*c == a*(b*c)443True444445This uses the same algorithm Monks does in his Maple package to446iterate through the possible matrices: see447http://mathweb.scranton.edu/monks/software/Steenrod/steen.html.448"""449from sage.rings.all import GF450F = GF(p)451(f,s) = m2452# First compute Q_e0 Q_e1 ... P(r1, r2, ...) Q_f0 Q_f1 ...453# Store results (as dictionary of pairs of tuples) in 'answer'.454answer = {m1: F(1)}455for k in f:456old_answer = answer457answer = {}458for mono in old_answer:459if k not in mono[0]:460q_mono = set(mono[0])461if len(q_mono) > 0:462ind = len(q_mono.intersection(range(k,1+max(q_mono))))463else:464ind = 0465coeff = (-1)**ind * old_answer[mono]466lst = list(mono[0])467if ind == 0:468lst.append(k)469else:470lst.insert(-ind,k)471q_mono = tuple(lst)472p_mono = mono[1]473answer[(q_mono, p_mono)] = F(coeff)474for i in range(1,1+len(mono[1])):475if (k+i not in mono[0]) and (p**k <= mono[1][i-1]):476q_mono = set(mono[0])477if len(q_mono) > 0:478ind = len(q_mono.intersection(range(k+i,1+max(q_mono))))479else:480ind = 0481coeff = (-1)**ind * old_answer[mono]482lst = list(mono[0])483if ind == 0:484lst.append(k+i)485else:486lst.insert(-ind,k+i)487q_mono = tuple(lst)488p_mono = list(mono[1])489p_mono[i-1] = p_mono[i-1] - p**k490491# The next two lines were added so that p_mono won't492# have trailing zeros. This makes p_mono uniquely493# determined by P(*p_mono).494495while len(p_mono)>0 and p_mono[-1] == 0:496p_mono.pop()497498answer[(q_mono, tuple(p_mono))] = F(coeff)499# Now for the Milnor matrices. For each entry '(e,r): coeff' in answer,500# multiply r with s. Record coefficient for matrix and multiply by coeff.501# Store in 'result'.502if len(s) == 0:503result = answer504else:505result = {}506for (e, r) in answer:507old_coeff = answer[(e,r)]508# Milnor multiplication for r and s509rows = len(r) + 1510cols = len(s) + 1511diags = len(r) + len(s)512# initialize matrix513M = range(rows)514for i in range(rows):515M[i] = [0]*cols516for j in range(1,cols):517M[0][j] = s[j-1]518for i in range(1,rows):519M[i][0] = r[i-1]520for j in range(1,cols):521M[i][j] = 0522found = True523while found:524# check diagonals525n = 1526coeff = old_coeff527diagonal = [0]*diags528while n <= diags and coeff != 0:529nth_diagonal = [M[i][n-i] for i in range(max(0,n-cols+1), min(1+n,rows))]530coeff = coeff * multinomial_odd(nth_diagonal,p)531diagonal[n-1] = sum(nth_diagonal)532n = n + 1533if F(coeff) != 0:534i = diags - 1535while i >= 0 and diagonal[i] == 0:536i = i - 1537t = tuple(diagonal[:i+1])538if (e,t) in result:539result[(e,t)] = F(coeff + result[(e,t)])540else:541result[(e,t)] = F(coeff)542# now look for new matrices:543found = False544i = 1545while not found and i < rows:546temp_sum = M[i][0]547j = 1548while not found and j < cols:549# check to see if column index j is small enough550if temp_sum >= p**j:551# now check to see if there's anything above this entry552# to add to it553temp_col_sum = 0554for k in range(i):555temp_col_sum += M[k][j]556if temp_col_sum != 0:557found = True558for row in range(1,i):559M[row][0] = r[row-1]560for col in range(1,cols):561M[0][col] = M[0][col] + M[row][col]562M[row][col] = 0563for col in range(1,j):564M[0][col] = M[0][col] + M[i][col]565M[i][col] = 0566M[0][j] = M[0][j] - 1567M[i][j] = M[i][j] + 1568M[i][0] = temp_sum - p**j569else:570temp_sum += M[i][j] * p**j571else:572temp_sum += M[i][j] * p**j573j = j + 1574i = i + 1575return result576577def multinomial_odd(list,p):578r"""579Multinomial coefficient of list, mod p.580581INPUT:582583- list - list of integers584- p - a prime number585586OUTPUT:587588Associated multinomial coefficient, mod p589590Given the input $[n_1, n_2, n_3, ...]$, this computes the591multinomial coefficient $(n_1 + n_2 + n_3 + ...)! / (n_1! n_2!592n_3! ...)$, mod $p$. The method is this: expand each $n_i$ in593base $p$: $n_i = \sum_j p^j n_{ij}$. Do the same for the sum of594the $n_i$'s, which we call $m$: $m = \sum_j p^j m_j$. Then the595multinomial coefficient is congruent, mod $p$, to the product of596the multinomial coefficients $m_j! / (n_{1j}! n_{2j}! ...)$.597598Furthermore, any multinomial coefficient $m! / (n_1! n_2! ...)$599can be computed as a product of binomial coefficients: it equals600601.. math::602603\binom{n_1}{n_1} \binom{n_1 + n_2}{n_2} \binom{n_1 + n_2 + n_3}{n_3} ...604605This is convenient because Sage's binomial function returns606integers, not rational numbers (as would be produced just by607dividing factorials).608609EXAMPLES::610611sage: from sage.algebras.steenrod.steenrod_algebra_mult import multinomial_odd612sage: multinomial_odd([1,2,4], 2)6131614sage: multinomial_odd([1,2,4], 7)6150616sage: multinomial_odd([1,2,4], 11)6176618sage: multinomial_odd([1,2,4], 101)6194620sage: multinomial_odd([1,2,4], 107)621105622"""623from sage.rings.all import GF, Integer624from sage.rings.arith import binomial625n = sum(list)626answer = 1627F = GF(p)628n_expansion = Integer(n).digits(p)629list_expansion = [Integer(k).digits(p) for k in list]630index = 0631while answer != 0 and index < len(n_expansion):632multi = F(1)633partial_sum = 0634for exp in list_expansion:635if index < len(exp):636partial_sum = partial_sum + exp[index]637multi = F(multi * binomial(partial_sum, exp[index]))638answer = F(answer * multi)639index += 1640return answer641642# adem relations, serre-cartan basis, admissible sequences643644def binomial_mod2(n,k):645r"""646The binomial coefficient `\binom{n}{k}`, computed mod 2.647648INPUT:649650- `n`, `k` - integers651652OUTPUT:653654`n` choose `k`, mod 2655656EXAMPLES::657658sage: from sage.algebras.steenrod.steenrod_algebra_mult import binomial_mod2659sage: binomial_mod2(4,2)6600661sage: binomial_mod2(5,4)6621663sage: binomial_mod2(3 * 32768, 32768)6641665sage: binomial_mod2(4 * 32768, 32768)6660667"""668if n < k:669return 0670elif ((n-k) & k) == 0:671return 1672else:673return 0674675def binomial_modp(n,k,p):676r"""677The binomial coefficient `\binom{n}{k}`, computed mod `p`.678679INPUT:680681- `n`, `k` - integers682- `p` - prime number683684OUTPUT:685686`n` choose `k`, mod `p`687688EXAMPLES::689690sage: from sage.algebras.steenrod.steenrod_algebra_mult import binomial_modp691sage: binomial_modp(5,2,3)6921693sage: binomial_modp(6,2,11) # 6 choose 2 = 156944695"""696if n < k:697return 0698return multinomial_odd([n-k, k], p)699700@cached_function701def adem(a, b, c=0, p=2):702r"""703The mod `p` Adem relations704705INPUT:706707- `a`, `b`, `c` (optional) - nonnegative integers, corresponding708to either `P^a P^b` or (if `c` present) to `P^a \beta^b P^c`709- `p` - positive prime number (optional, default 2)710711OUTPUT:712713a dictionary representing the mod `p` Adem relations714applied to `P^a P^b` or (if `c` present) to `P^a \beta^b P^c`.715716.. note::717718Users should use :func:`adem` instead of this function (which719has a trailing underscore in its name): :func:`adem`720is the cached version of this one, and so will be faster.721722The mod `p` Adem relations for the mod `p` Steenrod algebra are as723follows: if `p=2`, then if `a < 2b`,724725.. math::726727\text{Sq}^a \text{Sq}^b = \sum_{j=0}^{a/2} \binom{b-j-1}{a-2j} \text{Sq}^{a+b-j} \text{Sq}^j728729If `p` is odd, then if `a < pb`,730731.. math::732733P^a P^b = \sum_{j=0}^{a/p} (-1)^{a+j} \binom{(b-j)(p-1)-1}{a-pj} P^{a+b-j} P^j734735Also for `p` odd, if `a \leq pb`,736737.. math::738739P^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^j740+ \sum_{j=0}^{a/p} (-1)^{a+j-1} \binom{(b-j)(p-1)-1}{a-pj-1} P^{a+b-j} \beta P^j741742EXAMPLES:743744If two arguments (`a` and `b`) are given, then computations are745done mod 2. If `a \geq 2b`, then the dictionary {(a,b): 1} is746returned. Otherwise, the right side of the mod 2 Adem relation747for `\text{Sq}^a \text{Sq}^b` is returned. For example, since748`\text{Sq}^2 \text{Sq}^2 = \text{Sq}^3 \text{Sq}^1`, we have::749750sage: from sage.algebras.steenrod.steenrod_algebra_mult import adem751sage: adem(2,2) # indirect doctest752{(3, 1): 1}753sage: adem(4,2)754{(4, 2): 1}755sage: adem(4,4)756{(6, 2): 1, (7, 1): 1}757758If `p` is given and is odd, then with two inputs `a` and `b`, the759Adem relation for `P^a P^b` is computed. With three inputs `a`,760`b`, `c`, the Adem relation for `P^a \beta^b P^c` is computed.761In either case, the keys in the output are all tuples of odd length,762with ``(i_1, i_2, ..., i_m)`` representing763764.. math::765766\beta^{i_1} P^{i_2} \beta^{i_3} P^{i_4} ... \beta^{i_m}767768For instance::769770sage: adem(3,1, p=3)771{(0, 3, 0, 1, 0): 1}772sage: adem(3,0,1, p=3)773{(0, 3, 0, 1, 0): 1}774sage: adem(1,0,1, p=7)775{(0, 2, 0): 2}776sage: adem(1,1,1, p=5)777{(1, 2, 0): 1, (0, 2, 1): 1}778sage: adem(1,1,2, p=5)779{(1, 3, 0): 2, (0, 3, 1): 1}780"""781if p == 2:782if b == 0: return {(a,): 1}783elif a == 0: return {(b,): 1}784elif a >= 2*b: return {(a,b): 1}785result = {}786for c in range(1+a/2):787if binomial_mod2(b-c-1, a-2*c) == 1:788if c == 0:789result[(a+b,)] = 1790else:791result[(a+b-c,c)] = 1792return result793# p odd794if a == 0 and b == 0:795return {(c,): 1}796if c == 0:797bockstein = 0798A = a799B = b800else:801A = a802B = c803bockstein = b # should be 0 or 1804if A == 0:805return {(bockstein, B, 0): 1}806if B == 0:807return {(0, A, bockstein): 1}808if bockstein == 0:809if A >= p*B: # admissible810return {(0,A,0,B,0): 1}811result = {}812for j in range(1 + int(a/p)):813coeff = (-1)**(A+j) * binomial_modp((B-j) * (p-1) - 1, A - p*j, p)814if coeff % p != 0:815if j == 0:816result[(0,A+B,0)] = coeff817else:818result[(0,A+B-j,0,j,0)] = coeff819else:820if A >= p*B + 1: # admissible821return {(0,A,1,B,0): 1}822result = {}823for j in range(1 + int(a/p)):824coeff = (-1)**(A+j) * binomial_modp((B-j) * (p-1), A - p*j, p)825if coeff % p != 0:826if j == 0:827result[(1,A+B,0)] = coeff828else:829result[(1,A+B-j,0,j,0)] = coeff830for j in range(1 + int((a-1)/p)):831coeff = (-1)**(A+j-1) * binomial_modp((B-j) * (p-1) - 1, A - p*j - 1, p)832if coeff % p != 0:833if j == 0:834result[(0,A+B,1)] = coeff835else:836result[(0,A+B-j,1,j,0)] = coeff837return result838839@cached_function840def make_mono_admissible(mono, p=2):841r"""842Given a tuple ``mono``, view it as a product of Steenrod843operations, and return a dictionary giving data equivalent to844writing that product as a linear combination of admissible845monomials.846847When `p=2`, the sequence (and hence the corresponding monomial)848`(i_1, i_2, ...)` is admissible if `i_j \geq 2 i_{j+1}` for all849`j`.850851When `p` is odd, the sequence `(e_1, i_1, e_2, i_2, ...)` is852admissible if `i_j \geq e_{j+1} + p i_{j+1}` for all `j`.853854INPUT:855856- ``mono`` - a tuple of non-negative integers857- `p` - prime number, optional (default 2)858859OUTPUT:860861Dictionary of terms of the form (tuple: coeff), where862'tuple' is an admissible tuple of non-negative integers and863'coeff' is its coefficient. This corresponds to a linear864combination of admissible monomials. When `p` is odd, each tuple865must have an odd length: it should be of the form `(e_1, i_1, e_2,866i_2, ..., e_k)` where each `e_j` is either 0 or 1 and each `i_j`867is a positive integer: this corresponds to the admissible monomial868869.. math::870871\beta^{e_1} \mathcal{P}^{i_2} \beta^{e_2} \mathcal{P}^{i_2} ...872\mathcal{P}^{i_k} \beta^{e_k}873874ALGORITHM:875876Given `(i_1, i_2, i_3, ...)`, apply the Adem relations to the first877pair (or triple when `p` is odd) where the sequence is inadmissible,878and then apply this function recursively to each of the resulting879tuples `(i_1, ..., i_{j-1}, NEW, i_{j+2}, ...)`, keeping track of880the coefficients.881882.. note::883884Users should use :func:`make_mono_admissible` instead of this885function (which has a trailing underscore in its name):886:func:`make_mono_admissible` is the cached version of this887one, and so will be faster.888889EXAMPLES::890891sage: from sage.algebras.steenrod.steenrod_algebra_mult import make_mono_admissible892sage: make_mono_admissible((12,)) # already admissible, indirect doctest893{(12,): 1}894sage: make_mono_admissible((2,1)) # already admissible895{(2, 1): 1}896sage: make_mono_admissible((2,2))897{(3, 1): 1}898sage: make_mono_admissible((2, 2, 2))899{(5, 1): 1}900sage: make_mono_admissible((0, 2, 0, 1, 0), p=7)901{(0, 3, 0): 3}902903Test the fix from :trac:`13796`::904905sage: SteenrodAlgebra(p=2, basis='adem').Q(2) * (Sq(6) * Sq(2)) # indirect doctest906Sq^10 Sq^4 Sq^1 + Sq^10 Sq^5 + Sq^12 Sq^3 + Sq^13 Sq^2907"""908from sage.rings.all import GF909F = GF(p)910if len(mono) == 1:911return {mono: 1}912if p==2 and len(mono) == 2:913return adem(*mono, p=p)914if p == 2:915# check to see if admissible:916admissible = True917for j in range(len(mono)-1):918if mono[j] < 2*mono[j+1]:919admissible = False920break921if admissible:922return {mono: 1}923# else j is the first index where admissibility fails924ans = {}925y = adem(mono[j], mono[j+1])926for x in y:927new = mono[:j] + x + mono[j+2:]928new = make_mono_admissible(new)929for m in new:930if m in ans:931ans[m] = ans[m] + y[x] * new[m]932if F(ans[m]) == 0:933del ans[m]934else:935ans[m] = y[x] * new[m]936return ans937# p odd938# check to see if admissible:939admissible = True940for j in range(1, len(mono)-2, 2):941if mono[j] < mono[j+1] + p*mono[j+2]:942admissible = False943break944if admissible:945return {mono: 1}946# else j is the first index where admissibility fails947ans = {}948y = adem(*mono[j:j+3], p=p)949for x in y:950new_x = list(x)951new_x[0] = mono[j-1] + x[0]952if len(mono) >= j+3:953new_x[-1] = mono[j+3] + x[-1]954if new_x[0] <= 1 and new_x[-1] <= 1:955new = mono[:j-1] + tuple(new_x) + mono[j+4:]956new = make_mono_admissible(new, p)957for m in new:958if m in ans:959ans[m] = ans[m] + y[x] * new[m]960if F(ans[m]) == 0:961del ans[m]962else:963ans[m] = y[x] * new[m]964return ans965966967