def canonicalize(g, dummies, msym, *v): """ canonicalize tensor formed by tensors Parameters ========== g : permutation representing the tensor dummies : list representing the dummy indices it can be a list of dummy indices of the same type or a list of lists of dummy indices, one list for each type of index; the dummy indices must come after the free indices, and put in order contravariant, covariant [d0, -d0, d1,-d1,...] msym : symmetry of the metric(s) it can be an integer or a list; in the first case it is the symmetry of the dummy index metric; in the second case it is the list of the symmetries of the index metric for each type v : list, (base_i, gens_i, n_i, sym_i) for tensors of type `i` base_i, gens_i : BSGS for tensors of this type. The BSGS should have minimal base under lexicographic ordering; if not, an attempt is made do get the minimal BSGS; in case of failure, canonicalize_naive is used, which is much slower. n_i : number of tensors of type `i`. sym_i : symmetry under exchange of component tensors of type `i`. Both for msym and sym_i the cases are * None no symmetry * 0 commuting * 1 anticommuting Returns ======= 0 if the tensor is zero, else return the array form of the permutation representing the canonical form of the tensor. Algorithm ========= First one uses canonical_free to get the minimum tensor under lexicographic order, using only the slot symmetries. If the component tensors have not minimal BSGS, it is attempted to find it; if the attempt fails canonicalize_naive is used instead. Compute the residual slot symmetry keeping fixed the free indices using tensor_gens(base, gens, list_free_indices, sym). Reduce the problem eliminating the free indices. Then use double_coset_can_rep and lift back the result reintroducing the free indices. Examples ======== one type of index with commuting metric; `A_{a b}` and `B_{a b}` antisymmetric and commuting `T = A_{d0 d1} * B^{d0}{}_{d2} * B^{d2 d1}` `ord = [d0,-d0,d1,-d1,d2,-d2]` order of the indices g = [1, 3, 0, 5, 4, 2, 6, 7] `T_c = 0` >>> from sympy.combinatorics.tensor_can import get_symmetric_group_sgs, canonicalize, bsgs_direct_product >>> from sympy.combinatorics import Permutation >>> base2a, gens2a = get_symmetric_group_sgs(2, 1) >>> t0 = (base2a, gens2a, 1, 0) >>> t1 = (base2a, gens2a, 2, 0) >>> g = Permutation([1, 3, 0, 5, 4, 2, 6, 7]) >>> canonicalize(g, range(6), 0, t0, t1) 0 same as above, but with `B_{a b}` anticommuting `T_c = -A^{d0 d1} * B_{d0}{}^{d2} * B_{d1 d2}` can = [0,2,1,4,3,5,7,6] >>> t1 = (base2a, gens2a, 2, 1) >>> canonicalize(g, range(6), 0, t0, t1) [0, 2, 1, 4, 3, 5, 7, 6] two types of indices `[a,b,c,d,e,f]` and `[m,n]`, in this order, both with commuting metric `f^{a b c}` antisymmetric, commuting `A_{m a}` no symmetry, commuting `T = f^c{}_{d a} * f^f{}_{e b} * A_m{}^d * A^{m b} * A_n{}^a * A^{n e}` ord = [c,f,a,-a,b,-b,d,-d,e,-e,m,-m,n,-n] g = [0,7,3, 1,9,5, 11,6, 10,4, 13,2, 12,8, 14,15] The canonical tensor is `T_c = -f^{c a b} * f^{f d e} * A^m{}_a * A_{m d} * A^n{}_b * A_{n e}` can = [0,2,4, 1,6,8, 10,3, 11,7, 12,5, 13,9, 15,14] >>> base_f, gens_f = get_symmetric_group_sgs(3, 1) >>> base1, gens1 = get_symmetric_group_sgs(1) >>> base_A, gens_A = bsgs_direct_product(base1, gens1, base1, gens1) >>> t0 = (base_f, gens_f, 2, 0) >>> t1 = (base_A, gens_A, 4, 0) >>> dummies = [range(2, 10), range(10, 14)] >>> g = Permutation([0, 7, 3, 1, 9, 5, 11, 6, 10, 4, 13, 2, 12, 8, 14, 15]) >>> canonicalize(g, dummies, [0, 0], t0, t1) [0, 2, 4, 1, 6, 8, 10, 3, 11, 7, 12, 5, 13, 9, 15, 14] """ from sympy.combinatorics.testutil import canonicalize_naive if not isinstance(msym, list): if not msym in [0, 1, None]: raise ValueError('msym must be 0, 1 or None') num_types = 1 else: num_types = len(msym) if not all(msymx in [0, 1, None] for msymx in msym): raise ValueError('msym entries must be 0, 1 or None') if len(dummies) != num_types: raise ValueError( 'dummies and msym must have the same number of elements') size = g.size num_tensors = 0 v1 = [] for i in range(len(v)): base_i, gens_i, n_i, sym_i = v[i] # check that the BSGS is minimal; # this property is used in double_coset_can_rep; # if it is not minimal use canonicalize_naive if not _is_minimal_bsgs(base_i, gens_i): mbsgs = get_minimal_bsgs(base_i, gens_i) if not mbsgs: can = canonicalize_naive(g, dummies, msym, *v) return can base_i, gens_i = mbsgs v1.append((base_i, gens_i, [[]] * n_i, sym_i)) num_tensors += n_i if num_types == 1 and not isinstance(msym, list): dummies = [dummies] msym = [msym] flat_dummies = [] for dumx in dummies: flat_dummies.extend(dumx) if flat_dummies and flat_dummies != list( range(flat_dummies[0], flat_dummies[-1] + 1)): raise ValueError('dummies is not valid') # slot symmetry of the tensor size1, sbase, sgens = gens_products(*v1) if size != size1: raise ValueError('g has size %d, generators have size %d' % (size, size1)) free = [i for i in range(size - 2) if i not in flat_dummies] num_free = len(free) # g1 minimal tensor under slot symmetry g1 = canonical_free(sbase, sgens, g, num_free) if not flat_dummies: return g1 # save the sign of g1 sign = 0 if g1[-1] == size - 1 else 1 # the free indices are kept fixed. # Determine free_i, the list of slots of tensors which are fixed # since they are occupied by free indices, which are fixed. start = 0 for i in range(len(v)): free_i = [] base_i, gens_i, n_i, sym_i = v[i] len_tens = gens_i[0].size - 2 # for each component tensor get a list od fixed islots for j in range(n_i): # get the elements corresponding to the component tensor h = g1[start:(start + len_tens)] fr = [] # get the positions of the fixed elements in h for k in free: if k in h: fr.append(h.index(k)) free_i.append(fr) start += len_tens v1[i] = (base_i, gens_i, free_i, sym_i) # BSGS of the tensor with fixed free indices # if tensor_gens fails in gens_product, use canonicalize_naive size, sbase, sgens = gens_products(*v1) # reduce the permutations getting rid of the free indices pos_free = [g1.index(x) for x in range(num_free)] size_red = size - num_free g1_red = [x - num_free for x in g1 if x in flat_dummies] if sign: g1_red.extend([size_red - 1, size_red - 2]) else: g1_red.extend([size_red - 2, size_red - 1]) map_slots = _get_map_slots(size, pos_free) sbase_red = [map_slots[i] for i in sbase if i not in pos_free] sgens_red = [ _af_new([map_slots[i] for i in y._array_form if i not in pos_free]) for y in sgens ] dummies_red = [[x - num_free for x in y] for y in dummies] transv_red = get_transversals(sbase_red, sgens_red) g1_red = _af_new(g1_red) g2 = double_coset_can_rep(dummies_red, msym, sbase_red, sgens_red, transv_red, g1_red) if g2 == 0: return 0 # lift to the case with the free indices g3 = _lift_sgens(size, pos_free, free, g2) return g3
def test_riemann_products(): baser, gensr = riemann_bsgs base1, gens1 = get_symmetric_group_sgs(1) base2, gens2 = get_symmetric_group_sgs(2) base2a, gens2a = get_symmetric_group_sgs(2, 1) # R^{a b d0}_d0 = 0 g = Permutation([0, 1, 2, 3, 4, 5]) can = canonicalize(g, list(range(2, 4)), 0, (baser, gensr, 1, 0)) assert can == 0 # R^{d0 b a}_d0 ; ord = [a,b,d0,-d0}; g = [2,1,0,3,4,5] # T_c = -R^{a d0 b}_d0; can = [0,2,1,3,5,4] g = Permutation([2, 1, 0, 3, 4, 5]) can = canonicalize(g, list(range(2, 4)), 0, (baser, gensr, 1, 0)) assert can == [0, 2, 1, 3, 5, 4] # R^d1_d2^b_d0 * R^{d0 a}_d1^d2; ord=[a,b,d0,-d0,d1,-d1,d2,-d2] # g = [4,7,1,3,2,0,5,6,8,9] # T_c = -R^{a d0 d1 d2}* R^b_{d0 d1 d2} # can = [0,2,4,6,1,3,5,7,9,8] g = Permutation([4, 7, 1, 3, 2, 0, 5, 6, 8, 9]) can = canonicalize(g, list(range(2, 8)), 0, (baser, gensr, 2, 0)) assert can == [0, 2, 4, 6, 1, 3, 5, 7, 9, 8] can1 = canonicalize_naive(g, list(range(2, 8)), 0, (baser, gensr, 2, 0)) assert can == can1 # A symmetric commuting # R^{d6 d5}_d2^d1 * R^{d4 d0 d2 d3} * A_{d6 d0} A_{d3 d1} * A_{d4 d5} # g = [12,10,5,2, 8,0,4,6, 13,1, 7,3, 9,11,14,15] # T_c = -R^{d0 d1 d2 d3} * R_d0^{d4 d5 d6} * A_{d1 d4}*A_{d2 d5}*A_{d3 d6} g = Permutation([12, 10, 5, 2, 8, 0, 4, 6, 13, 1, 7, 3, 9, 11, 14, 15]) can = canonicalize(g, list(range(14)), 0, ((baser, gensr, 2, 0)), (base2, gens2, 3, 0)) assert can == [0, 2, 4, 6, 1, 8, 10, 12, 3, 9, 5, 11, 7, 13, 15, 14] # R^{d2 a0 a2 d0} * R^d1_d2^{a1 a3} * R^{a4 a5}_{d0 d1} # ord = [a0,a1,a2,a3,a4,a5,d0,-d0,d1,-d1,d2,-d2] # 0 1 2 3 4 5 6 7 8 9 10 11 # can = [0, 6, 2, 8, 1, 3, 7, 10, 4, 5, 9, 11, 12, 13] # T_c = R^{a0 d0 a2 d1}*R^{a1 a3}_d0^d2*R^{a4 a5}_{d1 d2} g = Permutation([10, 0, 2, 6, 8, 11, 1, 3, 4, 5, 7, 9, 12, 13]) can = canonicalize(g, list(range(6, 12)), 0, (baser, gensr, 3, 0)) assert can == [0, 6, 2, 8, 1, 3, 7, 10, 4, 5, 9, 11, 12, 13] #can1 = canonicalize_naive(g, list(range(6,12)), 0, (baser, gensr, 3, 0)) #assert can == can1 # A^n_{i, j} antisymmetric in i,j # A_m0^d0_a1 * A_m1^a0_d0; ord = [m0,m1,a0,a1,d0,-d0] # g = [0,4,3,1,2,5,6,7] # T_c = -A_{m a1}^d0 * A_m1^a0_d0 # can = [0,3,4,1,2,5,7,6] base, gens = bsgs_direct_product(base1, gens1, base2a, gens2a) dummies = list(range(4, 6)) g = Permutation([0, 4, 3, 1, 2, 5, 6, 7]) can = canonicalize(g, dummies, 0, (base, gens, 2, 0)) assert can == [0, 3, 4, 1, 2, 5, 7, 6] # A^n_{i, j} symmetric in i,j # A^m0_a0^d2 * A^n0_d2^d1 * A^n1_d1^d0 * A_{m0 d0}^a1 # ordering: first the free indices; then first n, then d # ord=[n0,n1,a0,a1, m0,-m0,d0,-d0,d1,-d1,d2,-d2] # 0 1 2 3 4 5 6 7 8 9 10 11] # g = [4,2,10, 0,11,8, 1,9,6, 5,7,3, 12,13] # if the dummy indices m_i and d_i were separated, # one gets # T_c = A^{n0 d0 d1} * A^n1_d0^d2 * A^m0^a0_d1 * A_m0^a1_d2 # can = [0, 6, 8, 1, 7, 10, 4, 2, 9, 5, 3, 11, 12, 13] # If they are not, so can is # T_c = A^{n0 m0 d0} A^n1_m0^d1 A^{d2 a0}_d0 A_d2^a1_d1 # can = [0, 4, 6, 1, 5, 8, 10, 2, 7, 11, 3, 9, 12, 13] # case with single type of indices base, gens = bsgs_direct_product(base1, gens1, base2, gens2) dummies = list(range(4, 12)) g = Permutation([4, 2, 10, 0, 11, 8, 1, 9, 6, 5, 7, 3, 12, 13]) can = canonicalize(g, dummies, 0, (base, gens, 4, 0)) assert can == [0, 4, 6, 1, 5, 8, 10, 2, 7, 11, 3, 9, 12, 13] # case with separated indices dummies = [list(range(4, 6)), list(range(6, 12))] sym = [0, 0] can = canonicalize(g, dummies, sym, (base, gens, 4, 0)) assert can == [0, 6, 8, 1, 7, 10, 4, 2, 9, 5, 3, 11, 12, 13] # case with separated indices with the second type of index # with antisymmetric metric: there is a sign change sym = [0, 1] can = canonicalize(g, dummies, sym, (base, gens, 4, 0)) assert can == [0, 6, 8, 1, 7, 10, 4, 2, 9, 5, 3, 11, 13, 12]
def test_canonicalize1(): base1, gens1 = get_symmetric_group_sgs(1) base1a, gens1a = get_symmetric_group_sgs(1, 1) base2, gens2 = get_symmetric_group_sgs(2) base3, gens3 = get_symmetric_group_sgs(3) base2a, gens2a = get_symmetric_group_sgs(2, 1) base3a, gens3a = get_symmetric_group_sgs(3, 1) # A_d0*A^d0; ord = [d0,-d0]; g = [1,0,2,3] # T_c = A^d0*A_d0; can = [0,1,2,3] g = Permutation([1, 0, 2, 3]) can = canonicalize(g, [0, 1], 0, (base1, gens1, 2, 0)) assert can == list(range(4)) # A commuting # A_d0*A_d1*A_d2*A^d2*A^d1*A^d0; ord=[d0,-d0,d1,-d1,d2,-d2] # g = [1,3,5,4,2,0,6,7] # T_c = A^d0*A_d0*A^d1*A_d1*A^d2*A_d2; can = list(range(8)) g = Permutation([1, 3, 5, 4, 2, 0, 6, 7]) can = canonicalize(g, list(range(6)), 0, (base1, gens1, 6, 0)) assert can == list(range(8)) # A anticommuting # A_d0*A_d1*A_d2*A^d2*A^d1*A^d0; ord=[d0,-d0,d1,-d1,d2,-d2] # g = [1,3,5,4,2,0,6,7] # T_c 0; can = 0 g = Permutation([1, 3, 5, 4, 2, 0, 6, 7]) can = canonicalize(g, list(range(6)), 0, (base1, gens1, 6, 1)) assert can == 0 can1 = canonicalize_naive(g, list(range(6)), 0, (base1, gens1, 6, 1)) assert can1 == 0 # A commuting symmetric # A^{d0 b}*A^a_d1*A^d1_d0; ord=[a,b,d0,-d0,d1,-d1] # g = [2,1,0,5,4,3,6,7] # T_c = A^{a d0}*A^{b d1}*A_{d0 d1}; can = [0,2,1,4,3,5,6,7] g = Permutation([2, 1, 0, 5, 4, 3, 6, 7]) can = canonicalize(g, list(range(2, 6)), 0, (base2, gens2, 3, 0)) assert can == [0, 2, 1, 4, 3, 5, 6, 7] # A, B commuting symmetric # A^{d0 b}*A^d1_d0*B^a_d1; ord=[a,b,d0,-d0,d1,-d1] # g = [2,1,4,3,0,5,6,7] # T_c = A^{b d0}*A_d0^d1*B^a_d1; can = [1,2,3,4,0,5,6,7] g = Permutation([2, 1, 4, 3, 0, 5, 6, 7]) can = canonicalize(g, list(range(2, 6)), 0, (base2, gens2, 2, 0), (base2, gens2, 1, 0)) assert can == [1, 2, 3, 4, 0, 5, 6, 7] # A commuting symmetric # A^{d1 d0 b}*A^{a}_{d1 d0}; ord=[a,b, d0,-d0,d1,-d1] # g = [4,2,1,0,5,3,6,7] # T_c = A^{a d0 d1}*A^{b}_{d0 d1}; can = [0,2,4,1,3,5,6,7] g = Permutation([4, 2, 1, 0, 5, 3, 6, 7]) can = canonicalize(g, list(range(2, 6)), 0, (base3, gens3, 2, 0)) assert can == [0, 2, 4, 1, 3, 5, 6, 7] # A^{d3 d0 d2}*A^a0_{d1 d2}*A^d1_d3^a1*A^{a2 a3}_d0 # ord = [a0,a1,a2,a3,d0,-d0,d1,-d1,d2,-d2,d3,-d3] # 0 1 2 3 4 5 6 7 8 9 10 11 # g = [10,4,8, 0,7,9, 6,11,1, 2,3,5, 12,13] # T_c = A^{a0 d0 d1}*A^a1_d0^d2*A^{a2 a3 d3}*A_{d1 d2 d3} # can = [0,4,6, 1,5,8, 2,3,10, 7,9,11, 12,13] g = Permutation([10, 4, 8, 0, 7, 9, 6, 11, 1, 2, 3, 5, 12, 13]) can = canonicalize(g, list(range(4, 12)), 0, (base3, gens3, 4, 0)) assert can == [0, 4, 6, 1, 5, 8, 2, 3, 10, 7, 9, 11, 12, 13] # A commuting symmetric, B antisymmetric # A^{d0 d1 d2} * A_{d2 d3 d1} * B_d0^d3 # ord = [d0,-d0,d1,-d1,d2,-d2,d3,-d3] # g = [0,2,4,5,7,3,1,6,8,9] # in this esxample and in the next three, # renaming dummy indices and using symmetry of A, # T = A^{d0 d1 d2} * A_{d0 d1 d3} * B_d2^d3 # can = 0 g = Permutation([0, 2, 4, 5, 7, 3, 1, 6, 8, 9]) can = canonicalize(g, list(range(8)), 0, (base3, gens3, 2, 0), (base2a, gens2a, 1, 0)) assert can == 0 # A anticommuting symmetric, B anticommuting # A^{d0 d1 d2} * A_{d2 d3 d1} * B_d0^d3 # T_c = A^{d0 d1 d2} * A_{d0 d1}^d3 * B_{d2 d3} # can = [0,2,4, 1,3,6, 5,7, 8,9] can = canonicalize(g, list(range(8)), 0, (base3, gens3, 2, 1), (base2a, gens2a, 1, 0)) assert can == [0, 2, 4, 1, 3, 6, 5, 7, 8, 9] # A anticommuting symmetric, B antisymmetric commuting, antisymmetric metric # A^{d0 d1 d2} * A_{d2 d3 d1} * B_d0^d3 # T_c = -A^{d0 d1 d2} * A_{d0 d1}^d3 * B_{d2 d3} # can = [0,2,4, 1,3,6, 5,7, 9,8] can = canonicalize(g, list(range(8)), 1, (base3, gens3, 2, 1), (base2a, gens2a, 1, 0)) assert can == [0, 2, 4, 1, 3, 6, 5, 7, 9, 8] # A anticommuting symmetric, B anticommuting anticommuting, # no metric symmetry # A^{d0 d1 d2} * A_{d2 d3 d1} * B_d0^d3 # T_c = A^{d0 d1 d2} * A_{d0 d1 d3} * B_d2^d3 # can = [0,2,4, 1,3,7, 5,6, 8,9] can = canonicalize(g, list(range(8)), None, (base3, gens3, 2, 1), (base2a, gens2a, 1, 0)) assert can == [0, 2, 4, 1, 3, 7, 5, 6, 8, 9] # Gamma anticommuting # Gamma_{mu nu} * gamma^rho * Gamma^{nu mu alpha} # ord = [alpha, rho, mu,-mu,nu,-nu] # g = [3,5,1,4,2,0,6,7] # T_c = -Gamma^{mu nu} * gamma^rho * Gamma_{alpha mu nu} # can = [2,4,1,0,3,5,7,6]] g = Permutation([3, 5, 1, 4, 2, 0, 6, 7]) t0 = (base2a, gens2a, 1, None) t1 = (base1, gens1, 1, None) t2 = (base3a, gens3a, 1, None) can = canonicalize(g, list(range(2, 6)), 0, t0, t1, t2) assert can == [2, 4, 1, 0, 3, 5, 7, 6] # Gamma_{mu nu} * Gamma^{gamma beta} * gamma_rho * Gamma^{nu mu alpha} # ord = [alpha, beta, gamma, -rho, mu,-mu,nu,-nu] # 0 1 2 3 4 5 6 7 # g = [5,7,2,1,3,6,4,0,8,9] # T_c = Gamma^{mu nu} * Gamma^{beta gamma} * gamma_rho * Gamma^alpha_{mu nu} # can = [4,6,1,2,3,0,5,7,8,9] t0 = (base2a, gens2a, 2, None) g = Permutation([5, 7, 2, 1, 3, 6, 4, 0, 8, 9]) can = canonicalize(g, list(range(4, 8)), 0, t0, t1, t2) assert can == [4, 6, 1, 2, 3, 0, 5, 7, 8, 9] # f^a_{b,c} antisymmetric in b,c; A_mu^a no symmetry # f^c_{d a} * f_{c e b} * A_mu^d * A_nu^a * A^{nu e} * A^{mu b} # ord = [mu,-mu,nu,-nu,a,-a,b,-b,c,-c,d,-d, e, -e] # 0 1 2 3 4 5 6 7 8 9 10 11 12 13 # g = [8,11,5, 9,13,7, 1,10, 3,4, 2,12, 0,6, 14,15] # T_c = -f^{a b c} * f_a^{d e} * A^mu_b * A_{mu d} * A^nu_c * A_{nu e} # can = [4,6,8, 5,10,12, 0,7, 1,11, 2,9, 3,13, 15,14] g = Permutation([8, 11, 5, 9, 13, 7, 1, 10, 3, 4, 2, 12, 0, 6, 14, 15]) base_f, gens_f = bsgs_direct_product(base1, gens1, base2a, gens2a) base_A, gens_A = bsgs_direct_product(base1, gens1, base1, gens1) t0 = (base_f, gens_f, 2, 0) t1 = (base_A, gens_A, 4, 0) can = canonicalize(g, [list(range(4)), list(range(4, 14))], [0, 0], t0, t1) assert can == [4, 6, 8, 5, 10, 12, 0, 7, 1, 11, 2, 9, 3, 13, 15, 14]
def canonicalize(g, dummies, msym, *v): """ canonicalize tensor formed by tensors Parameters ========== g : permutation representing the tensor dummies : list representing the dummy indices it can be a list of dummy indices of the same type or a list of lists of dummy indices, one list for each type of index; the dummy indices must come after the free indices, and put in order contravariant, covariant [d0, -d0, d1,-d1,...] msym : symmetry of the metric(s) it can be an integer or a list; in the first case it is the symmetry of the dummy index metric; in the second case it is the list of the symmetries of the index metric for each type v : list, (base_i, gens_i, n_i, sym_i) for tensors of type `i` base_i, gens_i : BSGS for tensors of this type. The BSGS should have minimal base under lexicographic ordering; if not, an attempt is made do get the minimal BSGS; in case of failure, canonicalize_naive is used, which is much slower. n_i : number of tensors of type `i`. sym_i : symmetry under exchange of component tensors of type `i`. Both for msym and sym_i the cases are * None no symmetry * 0 commuting * 1 anticommuting Returns ======= 0 if the tensor is zero, else return the array form of the permutation representing the canonical form of the tensor. Algorithm ========= First one uses canonical_free to get the minimum tensor under lexicographic order, using only the slot symmetries. If the component tensors have not minimal BSGS, it is attempted to find it; if the attempt fails canonicalize_naive is used instead. Compute the residual slot symmetry keeping fixed the free indices using tensor_gens(base, gens, list_free_indices, sym). Reduce the problem eliminating the free indices. Then use double_coset_can_rep and lift back the result reintroducing the free indices. Examples ======== one type of index with commuting metric; `A_{a b}` and `B_{a b}` antisymmetric and commuting `T = A_{d0 d1} * B^{d0}{}_{d2} * B^{d2 d1}` `ord = [d0,-d0,d1,-d1,d2,-d2]` order of the indices g = [1,3,0,5,4,2,6,7] `T_c = 0` >>> from sympy.combinatorics.tensor_can import get_symmetric_group_sgs, canonicalize, bsgs_direct_product >>> from sympy.combinatorics import Permutation >>> base2a, gens2a = get_symmetric_group_sgs(2, 1) >>> t0 = (base2a, gens2a, 1, 0) >>> t1 = (base2a, gens2a, 2, 0) >>> g = Permutation([1,3,0,5,4,2,6,7]) >>> canonicalize(g, range(6), 0, t0, t1) 0 same as above, but with `B_{a b}` anticommuting `T_c = -A^{d0 d1} * B_{d0}{}^{d2} * B_{d1 d2}` can = [0,2,1,4,3,5,7,6] >>> t1 = (base2a, gens2a, 2, 1) >>> canonicalize(g, range(6), 0, t0, t1) [0, 2, 1, 4, 3, 5, 7, 6] two types of indices `[a,b,c,d,e,f]` and `[m,n]`, in this order, both with commuting metric `f^{a b c}` antisymmetric, commuting `A_{m a}` no symmetry, commuting `T = f^c{}_{d a} * f^f{}_{e b} * A_m{}^d * A^{m b} * A_n{}^a * A^{n e}` ord = [c,f,a,-a,b,-b,d,-d,e,-e,m,-m,n,-n] g = [0,7,3, 1,9,5, 11,6, 10,4, 13,2, 12,8, 14,15] The canonical tensor is `T_c = -f^{c a b} * f^{f d e} * A^m{}_a * A_{m d} * A^n{}_b * A_{n e}` can = [0,2,4, 1,6,8, 10,3, 11,7, 12,5, 13,9, 15,14] >>> base_f, gens_f = get_symmetric_group_sgs(3, 1) >>> base1, gens1 = get_symmetric_group_sgs(1) >>> base_A, gens_A = bsgs_direct_product(base1, gens1, base1, gens1) >>> t0 = (base_f, gens_f, 2, 0) >>> t1 = (base_A, gens_A, 4, 0) >>> dummies = [range(2, 10), range(10, 14)] >>> g = Permutation([0,7,3,1,9,5,11,6,10,4,13,2,12,8,14,15]) >>> canonicalize(g, dummies, [0, 0], t0, t1) [0, 2, 4, 1, 6, 8, 10, 3, 11, 7, 12, 5, 13, 9, 15, 14] """ from sympy.combinatorics.testutil import canonicalize_naive if not isinstance(msym, list): if not msym in [0, 1, None]: raise ValueError('msym must be 0, 1 or None') num_types = 1 else: num_types = len(msym) if not all(msymx in [0, 1, None] for msymx in msym): raise ValueError('msym entries must be 0, 1 or None') if len(dummies) != num_types: raise ValueError( 'dummies and msym must have the same number of elements') size = g.size num_tensors = 0 v1 = [] for i in range(len(v)): base_i, gens_i, n_i, sym_i = v[i] # check that the BSGS is minimal; # this property is used in double_coset_can_rep; # if it is not minimal use canonicalize_naive if not _is_minimal_bsgs(base_i, gens_i): mbsgs = get_minimal_bsgs(base_i, gens_i) if not mbsgs: can = canonicalize_naive(g, dummies, msym, *v) return can base_i, gens_i = mbsgs v1.append((base_i, gens_i, [[]] * n_i, sym_i)) num_tensors += n_i if num_types == 1 and not isinstance(msym, list): dummies = [dummies] msym = [msym] flat_dummies = [] for dumx in dummies: flat_dummies.extend(dumx) if flat_dummies and flat_dummies != list(range(flat_dummies[0], flat_dummies[-1] + 1)): raise ValueError('dummies is not valid') # slot symmetry of the tensor size1, sbase, sgens = gens_products(*v1) if size != size1: raise ValueError( 'g has size %d, generators have size %d' % (size, size1)) free = [i for i in range(size - 2) if i not in flat_dummies] num_free = len(free) # g1 minimal tensor under slot symmetry g1 = canonical_free(sbase, sgens, g, num_free) if not flat_dummies: return g1 # save the sign of g1 sign = 0 if g1[-1] == size - 1 else 1 # the free indices are kept fixed. # Determine free_i, the list of slots of tensors which are fixed # since they are occupied by free indices, which are fixed. start = 0 for i in range(len(v)): free_i = [] base_i, gens_i, n_i, sym_i = v[i] len_tens = gens_i[0].size - 2 # for each component tensor get a list od fixed islots for j in range(n_i): # get the elements corresponding to the component tensor h = g1[start:(start + len_tens)] fr = [] # get the positions of the fixed elements in h for k in free: if k in h: fr.append(h.index(k)) free_i.append(fr) start += len_tens v1[i] = (base_i, gens_i, free_i, sym_i) # BSGS of the tensor with fixed free indices # if tensor_gens fails in gens_product, use canonicalize_naive size, sbase, sgens = gens_products(*v1) # reduce the permutations getting rid of the free indices pos_dummies = [g1.index(x) for x in flat_dummies] pos_free = [g1.index(x) for x in range(num_free)] size_red = size - num_free g1_red = [x - num_free for x in g1 if x in flat_dummies] if sign: g1_red.extend([size_red - 1, size_red - 2]) else: g1_red.extend([size_red - 2, size_red - 1]) map_slots = _get_map_slots(size, pos_free) sbase_red = [map_slots[i] for i in sbase if i not in pos_free] sgens_red = [_af_new([map_slots[i] for i in y._array_form if i not in pos_free]) for y in sgens] dummies_red = [[x - num_free for x in y] for y in dummies] transv_red = get_transversals(sbase_red, sgens_red) g1_red = _af_new(g1_red) g2 = double_coset_can_rep( dummies_red, msym, sbase_red, sgens_red, transv_red, g1_red) if g2 == 0: return 0 # lift to the case with the free indices g3 = _lift_sgens(size, pos_free, free, g2) return g3
def test_riemann_products(): baser, gensr = riemann_bsgs base1, gens1 = get_symmetric_group_sgs(1) base2, gens2 = get_symmetric_group_sgs(2) base2a, gens2a = get_symmetric_group_sgs(2, 1) # R^{a b d0}_d0 = 0 g = Permutation([0,1,2,3,4,5]) can = canonicalize(g, list(range(2,4)), 0, (baser, gensr, 1, 0)) assert can == 0 # R^{d0 b a}_d0 ; ord = [a,b,d0,-d0}; g = [2,1,0,3,4,5] # T_c = -R^{a d0 b}_d0; can = [0,2,1,3,5,4] g = Permutation([2,1,0,3,4,5]) can = canonicalize(g, list(range(2, 4)), 0, (baser, gensr, 1, 0)) assert can == [0,2,1,3,5,4] # R^d1_d2^b_d0 * R^{d0 a}_d1^d2; ord=[a,b,d0,-d0,d1,-d1,d2,-d2] # g = [4,7,1,3,2,0,5,6,8,9] # T_c = -R^{a d0 d1 d2}* R^b_{d0 d1 d2} # can = [0,2,4,6,1,3,5,7,9,8] g = Permutation([4,7,1,3,2,0,5,6,8,9]) can = canonicalize(g, list(range(2,8)), 0, (baser, gensr, 2, 0)) assert can == [0,2,4,6,1,3,5,7,9,8] can1 = canonicalize_naive(g, list(range(2,8)), 0, (baser, gensr, 2, 0)) assert can == can1 # A symmetric commuting # R^{d6 d5}_d2^d1 * R^{d4 d0 d2 d3} * A_{d6 d0} A_{d3 d1} * A_{d4 d5} # g = [12,10,5,2, 8,0,4,6, 13,1, 7,3, 9,11,14,15] # T_c = -R^{d0 d1 d2 d3} * R_d0^{d4 d5 d6} * A_{d1 d4}*A_{d2 d5}*A_{d3 d6} g = Permutation([12,10,5,2,8,0,4,6,13,1,7,3,9,11,14,15]) can = canonicalize(g, list(range(14)), 0, ((baser,gensr,2,0)), (base2,gens2,3,0)) assert can == [0, 2, 4, 6, 1, 8, 10, 12, 3, 9, 5, 11, 7, 13, 15, 14] # R^{d2 a0 a2 d0} * R^d1_d2^{a1 a3} * R^{a4 a5}_{d0 d1} # ord = [a0,a1,a2,a3,a4,a5,d0,-d0,d1,-d1,d2,-d2] # 0 1 2 3 4 5 6 7 8 9 10 11 # can = [0, 6, 2, 8, 1, 3, 7, 10, 4, 5, 9, 11, 12, 13] # T_c = R^{a0 d0 a2 d1}*R^{a1 a3}_d0^d2*R^{a4 a5}_{d1 d2} g = Permutation([10,0,2,6,8,11,1,3,4,5,7,9,12,13]) can = canonicalize(g, list(range(6,12)), 0, (baser, gensr, 3, 0)) assert can == [0, 6, 2, 8, 1, 3, 7, 10, 4, 5, 9, 11, 12, 13] #can1 = canonicalize_naive(g, list(range(6,12)), 0, (baser, gensr, 3, 0)) #assert can == can1 # A^n_{i, j} antisymmetric in i,j # A_m0^d0_a1 * A_m1^a0_d0; ord = [m0,m1,a0,a1,d0,-d0] # g = [0,4,3,1,2,5,6,7] # T_c = -A_{m a1}^d0 * A_m1^a0_d0 # can = [0,3,4,1,2,5,7,6] base, gens = bsgs_direct_product(base1, gens1, base2a, gens2a) dummies = list(range(4, 6)) g = Permutation([0,4,3,1,2,5,6,7]) can = canonicalize(g, dummies, 0, (base, gens, 2, 0)) assert can == [0, 3, 4, 1, 2, 5, 7, 6] # A^n_{i, j} symmetric in i,j # A^m0_a0^d2 * A^n0_d2^d1 * A^n1_d1^d0 * A_{m0 d0}^a1 # ordering: first the free indices; then first n, then d # ord=[n0,n1,a0,a1, m0,-m0,d0,-d0,d1,-d1,d2,-d2] # 0 1 2 3 4 5 6 7 8 9 10 11] # g = [4,2,10, 0,11,8, 1,9,6, 5,7,3, 12,13] # if the dummy indices m_i and d_i were separated, # one gets # T_c = A^{n0 d0 d1} * A^n1_d0^d2 * A^m0^a0_d1 * A_m0^a1_d2 # can = [0, 6, 8, 1, 7, 10, 4, 2, 9, 5, 3, 11, 12, 13] # If they are not, so can is # T_c = A^{n0 m0 d0} A^n1_m0^d1 A^{d2 a0}_d0 A_d2^a1_d1 # can = [0, 4, 6, 1, 5, 8, 10, 2, 7, 11, 3, 9, 12, 13] # case with single type of indices base, gens = bsgs_direct_product(base1, gens1, base2, gens2) dummies = list(range(4, 12)) g = Permutation([4,2,10, 0,11,8, 1,9,6, 5,7,3, 12,13]) can = canonicalize(g, dummies, 0, (base, gens, 4, 0)) assert can == [0, 4, 6, 1, 5, 8, 10, 2, 7, 11, 3, 9, 12, 13] # case with separated indices dummies = [list(range(4, 6)), list(range(6,12))] sym = [0, 0] can = canonicalize(g, dummies, sym, (base, gens, 4, 0)) assert can == [0, 6, 8, 1, 7, 10, 4, 2, 9, 5, 3, 11, 12, 13] # case with separated indices with the second type of index # with antisymmetric metric: there is a sign change sym = [0, 1] can = canonicalize(g, dummies, sym, (base, gens, 4, 0)) assert can == [0, 6, 8, 1, 7, 10, 4, 2, 9, 5, 3, 11, 13, 12]
def test_canonicalize1(): base1, gens1 = get_symmetric_group_sgs(1) base1a, gens1a = get_symmetric_group_sgs(1, 1) base2, gens2 = get_symmetric_group_sgs(2) base3, gens3 = get_symmetric_group_sgs(3) base2a, gens2a = get_symmetric_group_sgs(2, 1) base3a, gens3a = get_symmetric_group_sgs(3, 1) # A_d0*A^d0; ord = [d0,-d0]; g = [1,0,2,3] # T_c = A^d0*A_d0; can = [0,1,2,3] g = Permutation([1,0,2,3]) can = canonicalize(g, [0, 1], 0, (base1, gens1, 2, 0)) assert can == list(range(4)) # A commuting # A_d0*A_d1*A_d2*A^d2*A^d1*A^d0; ord=[d0,-d0,d1,-d1,d2,-d2] # g = [1,3,5,4,2,0,6,7] # T_c = A^d0*A_d0*A^d1*A_d1*A^d2*A_d2; can = list(range(8)) g = Permutation([1,3,5,4,2,0,6,7]) can = canonicalize(g, list(range(6)), 0, (base1, gens1, 6, 0)) assert can == list(range(8)) # A anticommuting # A_d0*A_d1*A_d2*A^d2*A^d1*A^d0; ord=[d0,-d0,d1,-d1,d2,-d2] # g = [1,3,5,4,2,0,6,7] # T_c 0; can = 0 g = Permutation([1,3,5,4,2,0,6,7]) can = canonicalize(g, list(range(6)), 0, (base1, gens1, 6, 1)) assert can == 0 can1 = canonicalize_naive(g, list(range(6)), 0, (base1, gens1, 6, 1)) assert can1 == 0 # A commuting symmetric # A^{d0 b}*A^a_d1*A^d1_d0; ord=[a,b,d0,-d0,d1,-d1] # g = [2,1,0,5,4,3,6,7] # T_c = A^{a d0}*A^{b d1}*A_{d0 d1}; can = [0,2,1,4,3,5,6,7] g = Permutation([2,1,0,5,4,3,6,7]) can = canonicalize(g, list(range(2,6)), 0, (base2, gens2, 3, 0)) assert can == [0,2,1,4,3,5,6,7] # A, B commuting symmetric # A^{d0 b}*A^d1_d0*B^a_d1; ord=[a,b,d0,-d0,d1,-d1] # g = [2,1,4,3,0,5,6,7] # T_c = A^{b d0}*A_d0^d1*B^a_d1; can = [1,2,3,4,0,5,6,7] g = Permutation([2,1,4,3,0,5,6,7]) can = canonicalize(g, list(range(2,6)), 0, (base2,gens2,2,0), (base2,gens2,1,0)) assert can == [1,2,3,4,0,5,6,7] # A commuting symmetric # A^{d1 d0 b}*A^{a}_{d1 d0}; ord=[a,b, d0,-d0,d1,-d1] # g = [4,2,1,0,5,3,6,7] # T_c = A^{a d0 d1}*A^{b}_{d0 d1}; can = [0,2,4,1,3,5,6,7] g = Permutation([4,2,1,0,5,3,6,7]) can = canonicalize(g, list(range(2,6)), 0, (base3, gens3, 2, 0)) assert can == [0,2,4,1,3,5,6,7] # A^{d3 d0 d2}*A^a0_{d1 d2}*A^d1_d3^a1*A^{a2 a3}_d0 # ord = [a0,a1,a2,a3,d0,-d0,d1,-d1,d2,-d2,d3,-d3] # 0 1 2 3 4 5 6 7 8 9 10 11 # g = [10,4,8, 0,7,9, 6,11,1, 2,3,5, 12,13] # T_c = A^{a0 d0 d1}*A^a1_d0^d2*A^{a2 a3 d3}*A_{d1 d2 d3} # can = [0,4,6, 1,5,8, 2,3,10, 7,9,11, 12,13] g = Permutation([10,4,8, 0,7,9, 6,11,1, 2,3,5, 12,13]) can = canonicalize(g, list(range(4,12)), 0, (base3, gens3, 4, 0)) assert can == [0,4,6, 1,5,8, 2,3,10, 7,9,11, 12,13] # A commuting symmetric, B antisymmetric # A^{d0 d1 d2} * A_{d2 d3 d1} * B_d0^d3 # ord = [d0,-d0,d1,-d1,d2,-d2,d3,-d3] # g = [0,2,4,5,7,3,1,6,8,9] # in this esxample and in the next three, # renaming dummy indices and using symmetry of A, # T = A^{d0 d1 d2} * A_{d0 d1 d3} * B_d2^d3 # can = 0 g = Permutation([0,2,4,5,7,3,1,6,8,9]) can = canonicalize(g, list(range(8)), 0, (base3, gens3,2,0), (base2a,gens2a,1,0)) assert can == 0 # A anticommuting symmetric, B anticommuting # A^{d0 d1 d2} * A_{d2 d3 d1} * B_d0^d3 # T_c = A^{d0 d1 d2} * A_{d0 d1}^d3 * B_{d2 d3} # can = [0,2,4, 1,3,6, 5,7, 8,9] can = canonicalize(g, list(range(8)), 0, (base3, gens3,2,1), (base2a,gens2a,1,0)) assert can == [0,2,4, 1,3,6, 5,7, 8,9] # A anticommuting symmetric, B antisymmetric commuting, antisymmetric metric # A^{d0 d1 d2} * A_{d2 d3 d1} * B_d0^d3 # T_c = -A^{d0 d1 d2} * A_{d0 d1}^d3 * B_{d2 d3} # can = [0,2,4, 1,3,6, 5,7, 9,8] can = canonicalize(g, list(range(8)), 1, (base3, gens3,2,1), (base2a,gens2a,1,0)) assert can == [0,2,4, 1,3,6, 5,7, 9,8] # A anticommuting symmetric, B anticommuting anticommuting, # no metric symmetry # A^{d0 d1 d2} * A_{d2 d3 d1} * B_d0^d3 # T_c = A^{d0 d1 d2} * A_{d0 d1 d3} * B_d2^d3 # can = [0,2,4, 1,3,7, 5,6, 8,9] can = canonicalize(g, list(range(8)), None, (base3, gens3,2,1), (base2a,gens2a,1,0)) assert can == [0,2,4,1,3,7,5,6,8,9] # Gamma anticommuting # Gamma_{mu nu} * gamma^rho * Gamma^{nu mu alpha} # ord = [alpha, rho, mu,-mu,nu,-nu] # g = [3,5,1,4,2,0,6,7] # T_c = -Gamma^{mu nu} * gamma^rho * Gamma_{alpha mu nu} # can = [2,4,1,0,3,5,7,6]] g = Permutation([3,5,1,4,2,0,6,7]) t0 = (base2a, gens2a, 1, None) t1 = (base1, gens1, 1, None) t2 = (base3a, gens3a, 1, None) can = canonicalize(g, list(range(2, 6)), 0, t0, t1, t2) assert can == [2,4,1,0,3,5,7,6] # Gamma_{mu nu} * Gamma^{gamma beta} * gamma_rho * Gamma^{nu mu alpha} # ord = [alpha, beta, gamma, -rho, mu,-mu,nu,-nu] # 0 1 2 3 4 5 6 7 # g = [5,7,2,1,3,6,4,0,8,9] # T_c = Gamma^{mu nu} * Gamma^{beta gamma} * gamma_rho * Gamma^alpha_{mu nu} # can = [4,6,1,2,3,0,5,7,8,9] t0 = (base2a, gens2a, 2, None) g = Permutation([5,7,2,1,3,6,4,0,8,9]) can = canonicalize(g, list(range(4, 8)), 0, t0, t1, t2) assert can == [4,6,1,2,3,0,5,7,8,9] # f^a_{b,c} antisymmetric in b,c; A_mu^a no symmetry # f^c_{d a} * f_{c e b} * A_mu^d * A_nu^a * A^{nu e} * A^{mu b} # ord = [mu,-mu,nu,-nu,a,-a,b,-b,c,-c,d,-d, e, -e] # 0 1 2 3 4 5 6 7 8 9 10 11 12 13 # g = [8,11,5, 9,13,7, 1,10, 3,4, 2,12, 0,6, 14,15] # T_c = -f^{a b c} * f_a^{d e} * A^mu_b * A_{mu d} * A^nu_c * A_{nu e} # can = [4,6,8, 5,10,12, 0,7, 1,11, 2,9, 3,13, 15,14] g = Permutation([8,11,5, 9,13,7, 1,10, 3,4, 2,12, 0,6, 14,15]) base_f, gens_f = bsgs_direct_product(base1, gens1, base2a, gens2a) base_A, gens_A = bsgs_direct_product(base1, gens1, base1, gens1) t0 = (base_f, gens_f, 2, 0) t1 = (base_A, gens_A, 4, 0) can = canonicalize(g, [list(range(4)), list(range(4, 14))], [0, 0], t0, t1) assert can == [4,6,8, 5,10,12, 0,7, 1,11, 2,9, 3,13, 15,14]