code: 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 msym not 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 base_i, gens_i, n_i, sym_i in v:
          # 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, (base_i, gens_i, n_i, sym_i) in enumerate(v):
          free_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
  
imports: from sympy.combinatorics.permutations import Permutation, _af_rmul, _af_invert, _af_new
  from sympy.combinatorics.perm_groups import PermutationGroup, _orbit, _orbit_transversal
  from sympy.combinatorics.util import _distribute_gens_by_base, _orbits_transversals_from_bsgs
label_desc: Use image node_id 11 for calling a global function with example usage: canonicalize(g, dummies, msym) and returns: g3, g1, int, can