#NEWLINE# def canonicalize( g , dummies , msym , * v ) : #NEWLINE# #INDENT# '\n    canonicalize tensor formed by tensors\n\n    Parameters\n    ==========\n\n    g : permutation representing the tensor\n\n    dummies : list representing the dummy indices\n      it can be a list of dummy indices of the same type\n      or a list of lists of dummy indices, one list for each\n      type of index;\n      the dummy indices must come after the free indices,\n      and put in order contravariant, covariant\n      [d0, -d0, d1,-d1,...]\n    msym :  symmetry of the metric(s)\n        it can be an integer or a list;\n        in the first case it is the symmetry of the dummy index metric;\n        in the second case it is the list of the symmetries of the\n        index metric for each type\n    v : list, (base_i, gens_i, n_i, sym_i) for tensors of type `i`\n\n    base_i, gens_i : BSGS for tensors of this type.\n        The BSGS should have minimal base under lexicographic ordering;\n        if not, an attempt is made do get the minimal BSGS;\n        in case of failure,\n        canonicalize_naive is used, which is much slower.\n\n    n_i :    number of tensors of type `i`.\n\n    sym_i :  symmetry under exchange of component tensors of type `i`.\n\n        Both for msym and sym_i the cases are\n            * None  no symmetry\n            * 0     commuting\n            * 1     anticommuting\n\n    Returns\n    =======\n\n    0 if the tensor is zero, else return the array form of\n    the permutation representing the canonical form of the tensor.\n\n    Algorithm\n    =========\n\n    First one uses canonical_free to get the minimum tensor under\n    lexicographic order, using only the slot symmetries.\n    If the component tensors have not minimal BSGS, it is attempted\n    to find it; if the attempt fails canonicalize_naive\n    is used instead.\n\n    Compute the residual slot symmetry keeping fixed the free indices\n    using tensor_gens(base, gens, list_free_indices, sym).\n\n    Reduce the problem eliminating the free indices.\n\n    Then use double_coset_can_rep and lift back the result reintroducing\n    the free indices.\n\n    Examples\n    ========\n\n    one type of index with commuting metric;\n\n    `A_{a b}` and `B_{a b}` antisymmetric and commuting\n\n    `T = A_{d0 d1} * B^{d0}{}_{d2} * B^{d2 d1}`\n\n    `ord = [d0,-d0,d1,-d1,d2,-d2]` order of the indices\n\n    g = [1, 3, 0, 5, 4, 2, 6, 7]\n\n    `T_c = 0`\n\n    >>> from sympy.combinatorics.tensor_can import get_symmetric_group_sgs, canonicalize, bsgs_direct_product\n    >>> from sympy.combinatorics import Permutation\n    >>> base2a, gens2a = get_symmetric_group_sgs(2, 1)\n    >>> t0 = (base2a, gens2a, 1, 0)\n    >>> t1 = (base2a, gens2a, 2, 0)\n    >>> g = Permutation([1, 3, 0, 5, 4, 2, 6, 7])\n    >>> canonicalize(g, range(6), 0, t0, t1)\n    0\n\n    same as above, but with `B_{a b}` anticommuting\n\n    `T_c = -A^{d0 d1} * B_{d0}{}^{d2} * B_{d1 d2}`\n\n    can = [0,2,1,4,3,5,7,6]\n\n    >>> t1 = (base2a, gens2a, 2, 1)\n    >>> canonicalize(g, range(6), 0, t0, t1)\n    [0, 2, 1, 4, 3, 5, 7, 6]\n\n    two types of indices `[a,b,c,d,e,f]` and `[m,n]`, in this order,\n    both with commuting metric\n\n    `f^{a b c}` antisymmetric, commuting\n\n    `A_{m a}` no symmetry, commuting\n\n    `T = f^c{}_{d a} * f^f{}_{e b} * A_m{}^d * A^{m b} * A_n{}^a * A^{n e}`\n\n    ord = [c,f,a,-a,b,-b,d,-d,e,-e,m,-m,n,-n]\n\n    g = [0,7,3, 1,9,5, 11,6, 10,4, 13,2, 12,8, 14,15]\n\n    The canonical tensor is\n    `T_c = -f^{c a b} * f^{f d e} * A^m{}_a * A_{m d} * A^n{}_b * A_{n e}`\n\n    can = [0,2,4, 1,6,8, 10,3, 11,7, 12,5, 13,9, 15,14]\n\n    >>> base_f, gens_f = get_symmetric_group_sgs(3, 1)\n    >>> base1, gens1 = get_symmetric_group_sgs(1)\n    >>> base_A, gens_A = bsgs_direct_product(base1, gens1, base1, gens1)\n    >>> t0 = (base_f, gens_f, 2, 0)\n    >>> t1 = (base_A, gens_A, 4, 0)\n    >>> dummies = [range(2, 10), range(10, 14)]\n    >>> g = Permutation([0, 7, 3, 1, 9, 5, 11, 6, 10, 4, 13, 2, 12, 8, 14, 15])\n    >>> canonicalize(g, dummies, [0, 0], t0, t1)\n    [0, 2, 4, 1, 6, 8, 10, 3, 11, 7, 12, 5, 13, 9, 15, 14]\n    ' #NEWLINE# from sympy.combinatorics.testutil import canonicalize_naive #NEWLINE# if ( not isinstance ( msym , list ) ) : #NEWLINE# #INDENT# if ( not ( msym in [ 0 , 1 , None ] ) ) : #NEWLINE# #INDENT# raise ValueError ( 'msym must be 0, 1 or None' ) #NEWLINE# #UNINDENT# num_types = 1 #NEWLINE# #UNINDENT# else : #NEWLINE# #INDENT# num_types = len ( msym ) #NEWLINE# if ( not all ( ( ( msymx in [ 0 , 1 , None ] ) for msymx in msym ) ) ) : #NEWLINE# #INDENT# raise ValueError ( 'msym entries must be 0, 1 or None' ) #NEWLINE# #UNINDENT# if ( len ( dummies ) != num_types ) : #NEWLINE# #INDENT# raise ValueError ( 'dummies and msym must have the same number of elements' ) #NEWLINE# #UNINDENT# #UNINDENT# size = g . size #NEWLINE# num_tensors = 0 #NEWLINE# v1 = [ ] #NEWLINE# for i in range ( len ( v ) ) : #NEWLINE# #INDENT# ( base_i , gens_i , n_i , sym_i ) = v [ i ] #NEWLINE# if ( not _is_minimal_bsgs ( base_i , gens_i ) ) : #NEWLINE# #INDENT# mbsgs = get_minimal_bsgs ( base_i , gens_i ) #NEWLINE# if ( not mbsgs ) : #NEWLINE# #INDENT# can = canonicalize_naive ( g , dummies , msym , * v ) #NEWLINE# return can #NEWLINE# #UNINDENT# ( base_i , gens_i ) = mbsgs #NEWLINE# #UNINDENT# v1 . append ( ( base_i , gens_i , ( [ [ ] ] * n_i ) , sym_i ) ) #NEWLINE# num_tensors += n_i #NEWLINE# #UNINDENT# if ( ( num_types == 1 ) and ( not isinstance ( msym , list ) ) ) : #NEWLINE# #INDENT# dummies = [ dummies ] #NEWLINE# msym = [ msym ] #NEWLINE# #UNINDENT# flat_dummies = [ ] #NEWLINE# for dumx in dummies : #NEWLINE# #INDENT# flat_dummies . extend ( dumx ) #NEWLINE# #UNINDENT# if ( flat_dummies and ( flat_dummies != list ( range ( flat_dummies [ 0 ] , ( flat_dummies [ ( - 1 ) ] + 1 ) ) ) ) ) : #NEWLINE# #INDENT# raise ValueError ( 'dummies is not valid' ) #NEWLINE# #UNINDENT# ( size1 , sbase , sgens ) = gens_products ( * v1 ) #NEWLINE# if ( size != size1 ) : #NEWLINE# #INDENT# raise ValueError ( ( 'g has size %d, generators have size %d' % ( size , size1 ) ) ) #NEWLINE# #UNINDENT# free = [ i for i in range ( ( size - 2 ) ) if ( i not in flat_dummies ) ] #NEWLINE# num_free = len ( free ) #NEWLINE# g1 = canonical_free ( sbase , sgens , g , num_free ) #NEWLINE# if ( not flat_dummies ) : #NEWLINE# #INDENT# return g1 #NEWLINE# #UNINDENT# sign = ( 0 if ( g1 [ ( - 1 ) ] == ( size - 1 ) ) else 1 ) #NEWLINE# start = 0 #NEWLINE# for i in range ( len ( v ) ) : #NEWLINE# #INDENT# free_i = [ ] #NEWLINE# ( base_i , gens_i , n_i , sym_i ) = v [ i ] #NEWLINE# len_tens = ( gens_i [ 0 ] . size - 2 ) #NEWLINE# for j in range ( n_i ) : #NEWLINE# #INDENT# h = g1 [ start : ( start + len_tens ) ] #NEWLINE# fr = [ ] #NEWLINE# for k in free : #NEWLINE# #INDENT# if ( k in h ) : #NEWLINE# #INDENT# fr . append ( h . index ( k ) ) #NEWLINE# #UNINDENT# #UNINDENT# free_i . append ( fr ) #NEWLINE# start += len_tens #NEWLINE# #UNINDENT# v1 [ i ] = ( base_i , gens_i , free_i , sym_i ) #NEWLINE# #UNINDENT# ( size , sbase , sgens ) = gens_products ( * v1 ) #NEWLINE# pos_dummies = [ g1 . index ( x ) for x in flat_dummies ] #NEWLINE# pos_free = [ g1 . index ( x ) for x in range ( num_free ) ] #NEWLINE# size_red = ( size - num_free ) #NEWLINE# g1_red = [ ( x - num_free ) for x in g1 if ( x in flat_dummies ) ] #NEWLINE# if sign : #NEWLINE# #INDENT# g1_red . extend ( [ ( size_red - 1 ) , ( size_red - 2 ) ] ) #NEWLINE# #UNINDENT# else : #NEWLINE# #INDENT# g1_red . extend ( [ ( size_red - 2 ) , ( size_red - 1 ) ] ) #NEWLINE# #UNINDENT# map_slots = _get_map_slots ( size , pos_free ) #NEWLINE# sbase_red = [ map_slots [ i ] for i in sbase if ( i not in pos_free ) ] #NEWLINE# sgens_red = [ _af_new ( [ map_slots [ i ] for i in y . _array_form if ( i not in pos_free ) ] ) for y in sgens ] #NEWLINE# dummies_red = [ [ ( x - num_free ) for x in y ] for y in dummies ] #NEWLINE# transv_red = get_transversals ( sbase_red , sgens_red ) #NEWLINE# g1_red = _af_new ( g1_red ) #NEWLINE# g2 = double_coset_can_rep ( dummies_red , msym , sbase_red , sgens_red , transv_red , g1_red ) #NEWLINE# if ( g2 == 0 ) : #NEWLINE# #INDENT# return 0 #NEWLINE# #UNINDENT# g3 = _lift_sgens ( size , pos_free , free , g2 ) #NEWLINE# return g3