class_docstr: In `TensorFlow <https://github.com/tensorflow/tensorflow/blob/r1.15/tensorflow/python/ops/nn_ops.py#L1657>`_,
  ``tf.keras.layers.Conv1D`` is a composite op:
  
  .. code-block::
  
      expand a dummy dim -> Conv2D -> squeeze the dummy dim
  
  In `PyTorch <https://github.com/pytorch/pytorch/blob/release/1.13/aten/src/ATen/native/Convolution.cpp#L1087>`_,
  this is also true for some backends (``mkldnn`` and ``xpu``).
  
  This decomposition wrecks the coremltools ``conv1d`` graph passes,
  so we should recompose the fragments back to MIL ``conv``, which natively supports ``conv1d``:
  
  .. code-block::
  
      Pattern 1:
          Given:
              %2 = expand_dims(%1, axes=-2) or expand_dims(%1, axes=2), %1.rank = 3
              %3 = conv(%2)
              %4 = squeeze(%3, axes=-2) or squeeze(%3, axes=2)
              ...
  
          Result:
              %4 = conv(%1)
              ...
  
      Pattern 2 (TensorFlow channel_last):
          Given:
              %2 = expand_dims(%1, axes=-3) or expand_dims(%1, axes=1), %1.rank = 3
              %3 = transpose(%2, perm=(0, 3, 1, 2))
              %4 = conv(%3)
              %5 = transpose(%4, perm=(0, 2, 3, 1))
              %6 = squeeze(%5, axes=-3) or squeeze(%5, axes=1)
              ...
  
          Result:
              %3 = transpose(%1, perm=(0, 2, 1))
              %4 = conv(%3)
              %6 = transpose(%4, perm=(0, 2, 1))
              ...
class_docstr_tok: ["In","`","TensorFlow","<","https",":","\/\/github.com\/tensorflow\/tensorflow\/blob\/r1.15\/tensorflow\/python\/ops\/nn_ops.py","#","L1657",">","`","_",",","``","tf.keras.layers.Conv1D","``","is","a","composite","op",":","..","code-block",":",":","expand","a","dummy","dim","-",">","Conv2D","-",">","squeeze","the","dummy","dim","In","`","PyTorch","<","https",":","\/\/github.com\/pytorch\/pytorch\/blob\/release\/1.13\/aten\/src\/ATen\/native\/Convolution.cpp","#","L1087",">","`","_",",","this","is","also","true","for","some","backends","(","``","mkldnn","``","and","``","xpu","``",")",".","This","decomposition","wrecks","the","coremltools","``","conv1d","``","graph","passes",",","so","we","should","recompose","the","fragments","back","to","MIL","``","conv","``",",","which","natively","supports","``","conv1d","``",":","..","code-block",":",":","Pattern","1",":","Given",":","%","2","=","expand_dims","(","%","1",",","axes=-2",")","or","expand_dims","(","%","1",",","axes=2",")",",","%","1.rank","=","3","%","3","=","conv","(","%","2",")","%","4","=","squeeze","(","%","3",",","axes=-2",")","or","squeeze","(","%","3",",","axes=2",")","...","Result",":","%","4","=","conv","(","%","1",")","...","Pattern","2","(","TensorFlow","channel_last",")",":","Given",":","%","2","=","expand_dims","(","%","1",",","axes=-3",")","or","expand_dims","(","%","1",",","axes=1",")",",","%","1.rank","=","3","%","3","=","transpose","(","%","2",",","perm=","(","0",",","3",",","1",",","2",")",")","%","4","=","conv","(","%","3",")","%","5","=","transpose","(","%","4",",","perm=","(","0",",","2",",","3",",","1",")",")","%","6","=","squeeze","(","%","5",",","axes=-3",")","or","squeeze","(","%","5",",","axes=1",")","...","Result",":","%","3","=","transpose","(","%","1",",","perm=","(","0",",","2",",","1",")",")","%","4","=","conv","(","%","3",")","%","6","=","transpose","(","%","4",",","perm=","(","0",",","2",",","1",")",")","..."]
code: def _try_apply_transform(
      expand_op: Operation,
      conv_op: Operation,
      squeeze_op: Operation,
      block: Block,
  ) -> bool:
      ops_to_remove = [expand_op, conv_op, squeeze_op]
      if not _check_no_output_connection(block, ops_to_remove):
          return False
  
      # prepare `conv1d`
      conv_kwargs = {
          "name": squeeze_op.outputs[0].name,
          "before_op": conv_op,
      }
  
      # inherit `x` from `expand_dim`
      conv_kwargs["x"] = expand_op.x
  
      # inherit `pad_type`, `groups`, `bias` from `conv2d`
      conv_kwargs["pad_type"] = conv_op.inputs["pad_type"].val
      conv_kwargs["groups"] = conv_op.inputs["groups"].val
      bias = conv_op.inputs.get("bias", None)
      if bias is not None:
          conv_kwargs["bias"] = bias
  
      # squeeze `weight`, `strides`, `pad`, `dilations` from `conv2d`
      conv_kwargs["weight"] = mb.squeeze(
          x=conv_op.inputs["weight"], axes=(-2,), before_op=conv_op
      )
      conv_kwargs["strides"] = (conv_op.inputs["strides"].val[-1],)
      conv_kwargs["pad"] = (
          conv_op.inputs["pad"].val[-2],
          conv_op.inputs["pad"].val[-1],
      )
      conv_kwargs["dilations"] = (conv_op.inputs["dilations"].val[-1],)
  
      # compose `conv1d`
      out = mb.conv(**conv_kwargs)
  
      # try replacing `expand_dim` -> `conv2d` -> `squeeze` output
      # with the new `conv1d` output
      if squeeze_op.enclosing_block.try_replace_uses_of_var_after_op(
          anchor_op=squeeze_op,
          old_var=squeeze_op.outputs[0],
          new_var=out,
      ):
          # remove `expand_dim` -> `conv2d` -> `squeeze`
          block.remove_ops(ops_to_remove)
          return True
      return False
  
imports: import copy
  import numpy
  from coremltools import _logger
  from coremltools.converters.mil.mil import Block
  from coremltools.converters.mil.mil import Builder
  from coremltools.converters.mil.mil import Operation, types
  from coremltools.converters.mil.mil.passes.graph_pass import AbstractGraphPass
  from coremltools.converters.mil.mil.passes.helper import _check_child_op_type, _check_no_output_connection, 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 5 for calling the compose_conv1d obj's underlying member method code with example usage: obj._try_apply_transform(expand_op, conv_op, squeeze_op, block) and returns: False, False, True