def allComponents(self, N): result = 0 # First term for K in range(N - 1, self.collapse + 1): Cd = self.diff(self.Cs[0], order=K) Md = spatial_diff(self.M, order=K - N + 1) tmp = np.tensordot(Cd, Md, axes=(tuple(range(1, K - N + 2)) + (0, ), tuple(range(0, K - N + 2)))) tmp = symmetrize(tmp, list(range(len(tmp.shape)))) result = result + 2 * binomial(K, N - 1) * tmp # Second summand for K in range(N, self.collapse + 1): for J in range(N + 1, K + 2): Cd = self.diff(self.Cs[0], order=K) Md = spatial_diff(self.M, order=K - J + 1) tmp = np.tensordot(Cd, Md, axes=(tuple(range(1, K - J + 2)) + (0, ), tuple(range(0, K - J + 2)))) tmp = symmetrize(tmp, list(range(len(tmp.shape)))) tmp = spatial_diff(tmp, order=J - N) for i in range(J - N + 1): tmp = tmp.trace(0, len(tmp.shape) - 1) result = result + (-1)**J * binomial(K, J - 1) * binomial( J, N) * tmp return result
def allComponents(self, N): V = np.tensordot(self.E, self.p, axes=(1, 1)) - np.tensordot( self.F, spatial_diff(self.p, order=1), axes=((2, 0), (1, 1))) result = (N + 2) * (self.degP - 1) * np.tensordot( self.Cs[N + 2], V, axes=(0, 0)) # First M term tmp = np.tensordot(self.Cs[N + 1], self.diff(self.M, order=0).swapaxes(1, 2), axes=(0, 0)) result -= (N + 1) * symmetrize(tmp, list(range(N + 1))) # The other M terms tmp = self.sumCoefficientDerivativeContraction(self.M, N=N + 1, freeIndices=0) if tmp is not None: result -= tmp # Multiply everything we have so far by (N+1) result = (N + 1) * result # The sum with the index swapping Cd = self.diff(self.Cs[N], order=1) for K in range(0, N + 1): result -= Cd.swapaxes(K, len(self.Cs.shape) - 2) # Last term result += 2 * spatial_diff(self.diff(self.Cs[N], order=2), order=1).trace(0, N + 2) return result
def allComponents(self): # First term V = np.tensordot(self.p, self.E, axes=(1, 1)) - np.tensordot( spatial_diff(expr=self.p, order=1), self.F, axes=((0, 2), (2, 1))) result = 6 * (self.degP - 1) * np.tensordot(self.Cs[3], V, axes=(0, 1)) # Second term. In the M_: term we swap B2 and mu result -= 4 * symmetrize( np.tensordot(self.Cs[2], self.diff(expr=self.M, order=0).swapaxes(1, 2), axes=(0, 0)), [0, 1]) # Third to fifth term tmp = self.sumCoefficientDerivativeContraction(self.M, N=2) if tmp is not None: result -= 2 * tmp # Sixth summand. Need to swap the first and second axes to get into the B1 B2 order result -= self.diff(expr=self.Cs[1], order=1).swapaxes(0, 1) # Last summand tmp = self.sumCoefficientDerivativeTrace(N=1, freeIndices=1, combinatorial='K+1', alternatingSign=True) if tmp is not None: result -= tmp return result
def allComponents(self, N): # The C_A term tmpA = self.sumCoefficientDerivativeContraction( self.M, N=1, freeIndices=N, combinatorial='binomial(K+N,K)') if tmpA is not None: tmpA = symmetrize( tmpA, list(range(len(tmpA.shape) - N, len(tmpA.shape)))) # The C term tmpB = self.sumCoefficientDerivativeTrace( N=0, freeIndices=N + 1, combinatorial='binomial(K+N-1,K)', alternatingSign=True) if tmpB is not None: tmpB = (-1)**N * tmpB # Return the result if tmpA is not None and tmpB is not None: return tmpA + tmpB elif tmpA is not None: return tmpA elif tmpB is not None: return tmpB else: return np.array([0])
def allComponents(self, N): Cd = self.diff(expr=self.Cs[N], order=2) # Contract the coefficient with F result = np.tensordot(Cd, self.F, axes=(len(Cd.shape)-3,0)) # Symmetrize in alpha, beta, gamma x = len(result.shape) return symmetrize(result, [x-4, x-3, x-1])
def allComponents(self, N): result = - np.tensordot(self.Cs[N], np.eye(3), axes=0) # Subtract the second term tmp = np.tensordot(self.Cs[N], self.diff(self.F, order=0).transpose(0,3,2,1), axes=(0,0)) tmp = symmetrize(tmp, list(range(N))) result -= N * tmp # E terms tmp = self.sumCoefficientDerivativeContraction(self.E, N=N, freeIndices=1, combinatorial='K+1') if tmp is not None: result += tmp # F terms tmp = self.sumCoefficientDerivativeContraction(self.F.swapaxes(1,2)) if tmp is not None: result -= tmp return result
def allComponents(self, N): # E terms result = 0 tmp = self.coefficientDerivativeContraction(self.E, N=N, derivOrder=0, freeIndices=2) if tmp is not None: result = tmp # F terms tmp = self.sumCoefficientDerivativeContraction(self.F.swapaxes(1, 2), N=N, freeIndices=1, combinatorial='K+1') if tmp is not None: tmp = symmetrize(tmp, [len(tmp.shape) - 3, len(tmp.shape) - 2]) result -= tmp return result
def allComponents(self): result = 0 # Third summand for K in range(2, self.collapse + 1): for J in range(2, K + 1): Cd = self.diff(self.Cs[0], order=K) Md = spatial_diff(self.M, order=K - J) tmp = np.tensordot(Cd, Md, axes=(tuple(range(1, K - J + 1)) + (0, ), tuple(range(0, K - J + 1)))) tmp = symmetrize(tmp, list(range(len(tmp.shape)))) tmp = spatial_diff(tmp, order=J + 1) for i in range(J + 1): tmp = tmp.trace(0, len(tmp.shape) - 1) result = result + (-1)**J * binomial(K, J) * (J - 1) * tmp return result
def symmetrizeDerivatives(self, contraction, tensor): # Import the symmetrization method from prime.utils import symmetrize # Unfold Ks, Phis = contraction # Prepare the result from copy import deepcopy result = deepcopy(tensor) offset = len(Ks) for i, Phi in enumerate(Phis): # If there are more than one derivative indices if Phi.derivs > 1: indices = list(range(offset + 1, offset + 1 + Phi.derivs)) result = symmetrize(result, indices) offset = offset + 1 + Phi.derivs return result
def symmetrizeBlocks(self, contraction, tensor): # Import the symmetrization method from prime.utils import symmetrize # Unfold Ks, Phis = contraction # Prepare the result from copy import deepcopy result = deepcopy(tensor) # First the exchange symmetries in the velocity indices if len(Ks) > 1: result = symmetrize(result, list(range(len(Ks)))) # Now the Phi part if len(Phis) > 1: for i, Phi in enumerate(Phis): for j in range(i + 1, len(Phis)): # If the number of derivative indices is different move to the next one if Phi.derivs != Phis[j].derivs: continue # Symmetrize in the i-th and j-th block shape = tuple(range(len(Ks))) for k, P in enumerate(Phis): if k == i: shape = shape + Phis[ j].getAllIndicesAfterContraction( offset=Phis[j].new_offset) elif k == j: shape = shape + Phi.getAllIndicesAfterContraction( offset=Phi.new_offset) else: shape = shape + P.getAllIndicesAfterContraction( offset=P.new_offset) result = (result + result.transpose(shape)) / 2 return result
def allComponents(self): # First summand. It is transposed into the shape (B,mu,nu) result = 2 * (self.degP-1) * np.tensordot(np.tensordot(self.p, self.F, axes=(1, 1)), self.Cs[2], axes=(1, 0)) \ .transpose((2,0,1)) # Second summand tmp = self.sumCoefficientDerivativeContraction(self.M, N=1, freeIndices=1, combinatorial='K+1') if tmp is not None: result += tmp # Third summand tmp = self.sumCoefficientDerivativeTrace(N=1, freeIndices=2, combinatorial='(K+2)*(K+1)/2', alternatingSign=True) if tmp is not None: result -= tmp return symmetrize(result, [1, 2])
def allComponents(self, N): result = None # First term tmp = self.sumCoefficientDerivativeContraction( self.E, N=1, freeIndices=N, combinatorial='binomial(K+N,K)') if tmp is not None: result = tmp # Second term tmp = self.sumCoefficientDerivativeContraction( self.F.swapaxes(1, 2), N=1, freeIndices=N - 1, combinatorial='binomial(K+N-1,K)') if tmp is not None: # Symmetrize in the N free indices tmp = symmetrize(tmp, list(range(1, N + 1))) if result is None: result = -tmp else: result -= tmp return result
def __init__(self, intertwiners, order=3): self.intertwiners = intertwiners self.parametrization = intertwiners.parametrization self.order = order # TODO: check the order of the intertwiner # Get the constant part and reshape constInts = self.intertwiners.constant() constInts = [i.reshape((int(np.prod(i.shape[0:-1])), i.shape[-1])) for i in constInts] constIntsIdx = self.intertwiners.indices # TODO: # So far, this method is more or less a heuristics that # works for almost all the parametrizations but it is possible # that strange examples exist where this is not the case. # Then the exception will be raised. Try to come up with a # more general way to solve this. # Calculate the indices of the inverse intertwiners constInvsIdx = [[(id[0], -id[1]) for id in idx] for idx in self.intertwiners.indices] for i in range(len(constInvsIdx)): constInvsIdx[i].insert(0, constInvsIdx[i].pop(-1)) constInvsShapes = [tuple([id[0] for id in idx]) for idx in constInvsIdx] # For now, sympy does not support rank defficient matrices, so we cannot use it here. # There is already a fix merged into master, so it should be usable quite soon... #constInvs = [ np.reshape(np.array(sympy.Matrix(int).pinv()), shape) for int, shape in zip(constInts, constInvsShapes) ] constInvs = [np.reshape(np.linalg.pinv(int.astype(np.float64)), shape) for int, shape in zip(constInts, constInvsShapes)] # Check the parametrization reshapedInvs = [I.reshape((I.shape[0], int(np.prod(I.shape[1:])))) for I in constInvs] d = np.zeros((len(self.parametrization.dofs), len(self.parametrization.dofs))) for A,B in zip(constInts, reshapedInvs): d = d + np.matmul(B.astype(np.float64),A.astype(np.float64)) valid = np.all((d - np.identity(len(self.parametrization.dofs))) < 1e-10) if not valid: raise Exception("The given parametrization is invalid. The inverted intertwiners and the constant ones do not contract to the identity.") # Import the method for symmetrization from prime.utils import symmetrize # Get the orders for the cacheConsts = [ self.intertwiners.order(o) for o in range(order) ] cacheInvs = [ constInvs ] # Iteratively construct the inverse components = constInvs for N in range(1, order): # Take the first one tmp = sum([np.tensordot(constInvs[i], cacheConsts[N][i], axes=( tuple(range(1,len(constInvs[i].shape))), tuple(range(len(constInvs[i].shape)-1)) )) for i in range(len(constInvs))]) tmp = [-np.tensordot(tmp, constInvs[j], axes=((1,), (0,))) for j in range(len(constInvs))] # Add the others on top for k in range(1,N): tmp2 = sum([np.tensordot(cacheInvs[k][i], cacheConsts[N-k][i], axes=( tuple(range(1,len(constInvs[i].shape))), tuple(range(len(constInvs[i].shape)-1)) )) for i in range(len(constInvs))]) tmp2 = [np.tensordot(tmp2, constInvs[j], axes=((k+1,), (0,))) for j in range(len(constInvs))] tmp2 = [symmetrize(t, list(range(1, k+1)) + list(range(1, N-k+1))) for t in tmp2] tmp = [x-y for x,y in zip(tmp, tmp2)] # Transpose tmp = [t.transpose((0,) + tuple(range(N+1, len(t.shape))) + tuple(range(1,N+1))) for t in tmp] # Add to the list cacheInvs.append(tmp) # Contract with phis r = tmp for i in range(N): r = [np.dot(t, self.parametrization.dofs) for t in r] # Add to the components components = [x + y for x, y in zip(components, r)] # Set the result self.components = components self.indices = constInvsIdx