class_docstr: Detect the pattern ``reshape_1-->transpose-->reshape_2``, where ``reshape_1`` has
  an output tensor with ``rank >= 6``, and ``reshape_2`` produces a tensor with ``rank <= 5``.
  
  In general, we can expand this pattern into a sequence of rank 4 ``reshape`` and ``transpose`` ops,
  which is supported by the Core ML runtime.
  
  .. code-block::
  
      Given:
          %1 = reshape(%x, shape=(d1, d2, d3, d4, ..., dn))
          %2 = transpose(%1, perm=(p1, p2, ..., pn))
          %3 = reshape(%2, shape=(o1, o2, o3, o4, o5))
  
      Result:
          %t1 = reshape(%x, shape=(y11, y12, y13, y14))
          %h1 = transpose(%t1, perm=[0, 2, 1, 3])
          %t2 = reshape(%h1, shape=(y21, y22, y23, 214))
          %h2 = transpose(%t2, perm=[0, 2, 1, 3])
          ....
          %hn = transpose(%tn, perm=[0, 2, 1, 3])
          %3 = reshape(%hn, shape=(o1, o2, o3, o4, o5))
class_docstr_tok: ["Detect","the","pattern","``","reshape_1","--",">","transpose","--",">","reshape_2","``",",","where","``","reshape_1","``","has","an","output","tensor","with","``","rank",">","=","6","``",",","and","``","reshape_2","``","produces","a","tensor","with","``","rank","<","=","5","``",".","In","general",",","we","can","expand","this","pattern","into","a","sequence","of","rank","4","``","reshape","``","and","``","transpose","``","ops",",","which","is","supported","by","the","Core","ML","runtime",".","..","code-block",":",":","Given",":","%","1","=","reshape","(","%","x",",","shape=","(","d1",",","d2",",","d3",",","d4",",","...",",","dn",")",")","%","2","=","transpose","(","%","1",",","perm=","(","p1",",","p2",",","...",",","pn",")",")","%","3","=","reshape","(","%","2",",","shape=","(","o1",",","o2",",","o3",",","o4",",","o5",")",")","Result",":","%","t1","=","reshape","(","%","x",",","shape=","(","y11",",","y12",",","y13",",","y14",")",")","%","h1","=","transpose","(","%","t1",",","perm=","[","0",",","2",",","1",",","3","]",")","%","t2","=","reshape","(","%","h1",",","shape=","(","y21",",","y22",",","y23",",","214",")",")","%","h2","=","transpose","(","%","t2",",","perm=","[","0",",","2",",","1",",","3","]",")","....","%","hn","=","transpose","(","%","tn",",","perm=","[","0",",","2",",","1",",","3","]",")","%","3","=","reshape","(","%","hn",",","shape=","(","o1",",","o2",",","o3",",","o4",",","o5",")",")"]
code: def _try_to_transform(ops, block):
      def _get_prod(start, end, arr, skip_indices):
          res = 1
          for i in range(start, end):
              if i in skip_indices:
                  continue
              res *= arr[i]
          return res
  
      reshape_op, transpose_op, last_reshape_op = ops[0], ops[1], ops[2]
      original_shape = reshape_op.outputs[0].shape
      original_perm = transpose_op.perm.val.tolist()
  
      # Group the consecutive axes in the perm, sometimes this could directly lower the
      # rank under 6.
      #
      # For instance:
      #
      # reshape = mb.reshape(x=x, shape=[1, 2, 3, 4, 5, 6])
      # transpose = mb.transpose(x=reshape, perm=[4, 5, 3, 2, 0, 1])
      # output = mb.reshape(x=transpose, shape=[6, 20, 6])
      #
      # Have 4 groups of axes: [4, 5], [3], [2], [0, 1]
      # We can transform the ops to
      #
      # new_reshape = mb.reshape(x=x, shape=[1*2, 3, 4, 5*6])
      # new_transpose = mb.transpose(x=reshape, perm=[3, 2, 1, 0])
      # output = mb.reshape(x=new_transpose, shape=[6, 20, 6])
      #
      # Note that, the output of new_transpose have different rank than transpose,
      # however, they have the same data layout, so the final output is still unchanged.
      group_axes = []
      i = 0
      res = []
      for i in range(len(original_perm)):
          if i > 0 and original_perm[i] == original_perm[i - 1] + 1:
              res.append(original_perm[i])
          else:
              if len(res) > 0:
                  group_axes.append(res)
              res = [original_perm[i]]
          if i == len(original_perm) - 1:
              group_axes.append(res)
  
      group_shape = []
      for axes in group_axes:
          start, end = axes[0], axes[-1] + 1
          group_shape.append(
              _get_prod(start, end, original_shape, set())
          )
  
      start_group_axis = [axes[0] for axes in group_axes]
      group_axis_order = np.argsort(start_group_axis)
      shape = np.array(group_shape)[group_axis_order].tolist()
  
      sorted_start_group_axis = np.sort(start_group_axis).tolist()
      perm = [
          sorted_start_group_axis.index(i) for i in start_group_axis
      ]
  
      rank = len(perm)
      x = reshape_op.x
  
      if rank < 6:
          # If the intermediate tensors have rank < 6,
          # we can directly use them to replace the original pattern
          x = mb.reshape(x=x, shape=shape, before_op=reshape_op)
          x = mb.transpose(x=x, perm=perm, before_op=reshape_op)
  
      else:
          # Otherwise, we need to expand the rank-N tensor into N reshape, and N transpose ops.
          # Note that all intrermediate tensors have rank 4.
          #
          # The algorithm is as followed:
          #
          # reshape shape: [d_1, d_2, ..., d_n]
          # transpose perm: [p_1, p_2, ..., p_n]
          #
          # reshape to [1, d_1*d_2*...*d_(p_1-1), d_(p_1), d_(p_1+1)*...*d_n]
          # transpose to [1, d_(p_1), d_1*d_2*...*d_(p_1-1), d_(p_1+1)*...*d_n]
          #
          # reshape to [d_(p_1), d_1*d_2*...*d_(p_2-1), d_(p_2), d_(p_2+1)*...*d_n]
          # transpose to [d_(p_1), d_(p_2), d_1*d_2*...*d_(p_2-1), d_(p_2+1)*...*d_n]
          #
          # reshape to [d_(p_1)*d_(p_2), d_1*d_2*...*d_(p_3-1), d_(p_3), d_(p_3+1)*...*d_n]
          # ....
          # so on and so forth
          leading_dim = 1
          memo = set()
          for i in range(rank):
              axis = perm[i]
              dim = shape[axis]
              memo.add(axis)
              reshape_shape = [
                  leading_dim,
                  _get_prod(0, axis, shape, memo),
                  dim,
                  _get_prod(axis + 1, rank, shape, memo),
              ]
              x = mb.reshape(
                  x=x, shape=reshape_shape, before_op=reshape_op
              )
              x = mb.transpose(
                  x=x, perm=[0, 2, 1, 3], before_op=reshape_op
              )
              leading_dim *= dim
  
      x = mb.reshape(
          x=x, shape=last_reshape_op.shape.val, before_op=reshape_op
      )
      if reshape_op.enclosing_block.try_replace_uses_of_var_after_op(
          anchor_op=reshape_op,
          old_var=last_reshape_op.outputs[0],
          new_var=x,
      ):
          # Remove all the ops at once
          block.remove_ops(ops)
          return True
      return False
  
imports: import numpy
  from coremltools.converters.mil._deployment_compatibility import AvailableTarget
  from coremltools.converters.mil.frontend._utils import value_at
  from coremltools.converters.mil.mil import Builder
  from coremltools.converters.mil.mil.block import is_current_opset_version_compatible_with
  from coremltools.converters.mil.mil.passes.graph_pass import AbstractGraphPass
  from coremltools.converters.mil.mil.passes.helper import _check_child_op_type, _check_var_scalar_value, block_context_manager
  from coremltools.converters.mil.mil.passes.pass_registry import register_pass
  from coremltools.converters.mil.mil.types.symbolic import any_symbolic
label_desc: Use image node_id 3 for calling the expand_high_rank_reshape_and_transpose obj's underlying member method code with example usage: obj._try_to_transform(ops, block) and returns: False, res, True