def _enumerate_row(self, ans, col, dia, rownum): if rownum == self.nrows - 1: loop = [ (self.one, ans, col, dia), ].__iter__() else: loop = self._enumerate_row(ans, col, dia, rownum + 1) for (cf, a, c, d) in loop: # fill in row #rownum for sol in WeightedIntegerVectors(self.exp[rownum], self.powers): cf2 = cf isbad = False for (i, s) in enumerate(sol): if s > 0 and rownum + i >= self.maxn: isbad = True break a[rownum, i] = s if rownum + 1 < self.nrows: cprev = c[rownum + 1, i] dprev = 0 if i == 0 else d[rownum + 1, i - 1] else: cprev = 0 dprev = 0 c[rownum, i] = cprev + s d[rownum, i] = dprev + s cf2 *= binom_modp(self.p, dprev + s, s) if cf2.is_zero(): isbad = True break if isbad: continue yield (cf2, a, c, d)
def __action_exponents(self, p, n, maxP, isconjugate=False): """ generator for exponent sequences R such that the multinomial coefficient (p r1 | p^2 r2 | p^3 r3 | ... | (p-1)n - sum rk) is not zero and R is dominated by maxP """ # Question: can we enforce sum rk <= (p-1)n? for (cf, exp, dg, psum, esum) in self.__action_exponents2(p, maxP, 0, 0): # the flag isconjugate switches between ordinary and conjugate action if isconjugate: c2 = binom_modp(p, -n * (p - 1), psum) else: c2 = binom_modp(p, psum + n * (p - 1) - esum, psum) if c2 != 0: yield (c2 * cf, exp, dg)
def decompose(p, n): """ Decompose a omega_n into a product of Dicksonians """ inv = p**(p - 2) tdeg = 2 * (p - 1) if p > 2 else 1 pmo = p - 1 # FIXME: why does this not depend on the generic/non-generic flag for p=2? for expos in PetersonPolynomials._milnor_basis(p, tdeg * n): sum = 0 cf = 1 for a in expos: sum += a cf *= binom_modp(p, sum, a) if 0 == cf: break if 0 == cf: continue cf *= binom_modp(p, -n * pmo, sum) if 0 != cf: yield [cf, expos]
def left_steenrod_action_milnor(self, a, m): qexp, Rexp = a yexp, xexp = m & 1, m >> 1 p = self._prime if len(qexp) > 1: # Q_i Q_j z = 0 for all z return self.zero() if len(qexp) == 1 and yexp == 0: # Qj(x^k) = 0 return self.zero() # compute P(Rexp)*x^xexp sum = 0 deg = xexp ppow = p cf = 1 for i in Rexp: sum = sum + i if xexp >= 0 and sum > xexp: return self.zero() cf *= binom_modp(self._prime, sum, i) cf = cf % p if 0 == cf: return self.zero() deg += i * (ppow - 1) ppow *= p rest = xexp - sum cf *= binom_modp(self._prime, rest + sum, sum) if 0 == cf: return self.zero() cf = cf % p if len(qexp) == 0: ans = self.monomial(yexp + (deg << 1)) else: # Qi(y) = x^{p^i} ans = self.monomial((deg + p**qexp[0]) << 1) return self.linear_combination(((ans, cf), ))
def _multinomials(self, smds, prime, total): try: cursmd = next(smds) r, q, p = cursmd except StopIteration: yield self._coaction_tensor(self.one(), 0, ()), total, [] return for (smd, tot2, elst) in self._multinomials(smds, prime, total): # r2,q2,p2 = smd maxexpo = tot2 for expo in range(0, maxexpo + 1): coeff = binom_modp(self._prime, tot2, expo) nr, nq, np = smd yield self._coaction_tensor( nr.map_coefficients(lambda x: coeff * x), nq, np ), tot2 - expo, elst + [ expo, ] nextpow = cursmd * smd if len(nextpow) == 0: break smd = nextpow[0]
def __action_exponents2(self, p, maxP, partialsum, expsum): idx = len(maxP) if idx > 0: ppow = p**idx opdeg = (ppow - 1) // (p - 1) idx = idx - 1 for e in range(maxP[idx] + 1): epow = e * ppow ps2 = partialsum + epow cf = binom_modp(p, ps2, epow) if cf != 0: for (c, exp, dg, ps, es) in self.__action_exponents2( p, maxP[0:idx], ps2, expsum + e): yield ( c * cf, exp + [ e, ], dg + e * opdeg, ps, es, ) else: yield (1, [], 0, partialsum, expsum)
def admissible_action(self, redpow, elem, debug=False): """ Compute redpow * elem using admissible matrices """ from yacop.utils.admissible_matrices import AdmissibleMatrices isgen = redpow.parent().is_generic() zpad = [ 0, ] * self._index ans = [] for (key, cf) in redpow: if isgen: (epart, expos) = key if len(epart) > 0: raise ValueError( "exterior multiplications not implemented yet") else: expos = key # print "redpow contains", (key,cf), "expos=",expos for (c, a, cols, diag) in AdmissibleMatrices(self._prime, expos, maxn=self._index).enumerate(): if debug: print("admissible matrix, coeff=%d\n%s" % (c, a)) for (dkey, dcf) in elem: ncf = c * dcf * cf for _ in [ 0, ]: dkey = list(dkey) + zpad + zpad if max(dkey[0::2]) != 0: raise ValueError( "exterior part not implemented yet") rexpos = dkey[1::2] zexpos = list(reversed(rexpos[0:self._index - 1])) zexpos = [-1 - _ for _ in zexpos] + [ -1 + sum(zexpos) + rexpos[self._index - 1] ] if debug: print( "%s = zeta(%s)" % (self._from_dict({tuple(dkey): dcf}), zexpos)) zrems = [ a - b for (a, b) in zip(zexpos, cols[1:] + zpad) ] if debug: print("zeta-remainder = ", zrems) for (dterm, zterm) in zip(diag, zrems): ncf *= binom_modp(self._prime, dterm + zterm, dterm) if ncf.is_zero(): break if debug: print("coefficient=", ncf) if ncf.is_zero(): continue newzeta = [a + b for (a, b) in zip(diag + zpad, zrems)] newexpo = list( reversed( [-1 - a for a in newzeta[0:self._index - 1]])) newexpo.append(1 + newzeta[self._index - 1] - sum(newexpo)) newkey = [(0, _) for _ in newexpo] newkey = [_ for j in newkey for _ in j] while newkey[-1] == 0: newkey.pop() ans.append(self._from_dict({tuple(newkey): ncf})) return self.sum(ans)
def gamma(self, n): """ the gamma(n) in the definition of omega(n) """ return binom_modp(self.p, -(self.p - 1) * n, n)
def left_steenrod_action_milnor_conj(self, a, m): """ TESTS:: sage: from yacop.modules.classifying_spaces import * sage: N = BZp(5) ; N.inject_variables() Defining y, x sage: A = SteenrodAlgebra(5) sage: P = A.P sage: for i in range(10): ....: for q in range(3): ....: Q = A.one() if q == 0 else A.Q(q) ....: for r1 in range(10): ....: for r2 in range(3): ....: op = P(r1,r2)*Q ....: po = op.antipode() ....: assert po * (x**i) == op % (x**i) ....: assert po * (y*x**i) == op % (y*x**i) """ qexp, Rexp = a yexp, xexp = m & 1, m >> 1 p = self._prime cf = 1 if len(qexp) > 1: # Q_i Q_j z = 0 for all z return self.zero() if len(qexp) == 1: if yexp == 0: # Qj(x^k) = 0 return self.zero() else: # evaluate chi(Q_k)(y*x**i) = -x**(i+p^k) first cf = p - 1 yexp = 0 xexp += p**qexp[0] # compute P(Rexp)*x^xexp sum = 0 psum = 0 deg = xexp ppow = p for i in Rexp: sum = sum + i cf *= binom_modp(self._prime, sum, i) cf = cf % p if 0 == cf: return self.zero() deg += i * (ppow - 1) psum += ppow * i ppow *= p rest = -1 - xexp - psum cf *= binom_modp(self._prime, rest + sum, sum) if 0 == cf: return self.zero() cf = cf % p ans = self.monomial(yexp + (deg << 1)) return self.linear_combination(((ans, cf), ))