class_docstr: Fold ``add``/``sub`` into ``bias`` of ``conv`` and ``conv_transpose``.
  That is, convert ``conv + add/sub`` to ``conv``, when ``add``/``sub`` is adding a constant.
  
  Two patterns are supported:
  
  .. code-block::
  
      Pattern 1:
      Given:
          %2 = conv(%1)
          ...
          %3 = add(%2, constant) # where constant has shape (1,C,1)/(C,1) for 1d conv, (1,C,1,1)/(C,1,1) for 2d conv etc
          ...
  
      Result:
          %3 = conv(%1)
          ...
  
  
      Pattern 2:
      Given:
          %2 = conv(%1)
          %3 = transpose(%2)
          ...
          %4 = add(%3, constant) # where constant has a broacasable shape
          ...
  
      Result:
          %2 = conv(%1)
          %4 = transpose(%2)
          ...
class_docstr_tok: ["Fold","``","add","``","\/","``","sub","``","into","``","bias","``","of","``","conv","``","and","``","conv_transpose","``",".","That","is",",","convert","``","conv","+","add\/sub","``","to","``","conv","``",",","when","``","add","``","\/","``","sub","``","is","adding","a","constant",".","Two","patterns","are","supported",":","..","code-block",":",":","Pattern","1",":","Given",":","%","2","=","conv","(","%","1",")","...","%","3","=","add","(","%","2",",","constant",")","#","where","constant","has","shape","(","1",",","C,1",")","\/","(","C,1",")","for","1d","conv",",","(","1",",","C,1,1",")","\/","(","C,1,1",")","for","2d","conv","etc","...","Result",":","%","3","=","conv","(","%","1",")","...","Pattern","2",":","Given",":","%","2","=","conv","(","%","1",")","%","3","=","transpose","(","%","2",")","...","%","4","=","add","(","%","3",",","constant",")","#","where","constant","has","a","broacasable","shape","...","Result",":","%","2","=","conv","(","%","1",")","%","4","=","transpose","(","%","2",")","..."]
code: def _try_to_transform_transpose_pattern(conv_op, block):
      ops_to_remove = []
  
      # conv layer
      if (
          conv_op.op_type != "conv"
          and conv_op.op_type != "conv_transpose"
      ):
          return False
      is_deconv = conv_op.op_type == "conv_transpose"
      ops_to_remove.append(conv_op)
  
      # transpose layer
      if not _check_child_op_type(conv_op, "transpose"):
          return False
      transpose_op = list(conv_op.outputs[0].child_ops)[0]
      ops_to_remove.append(transpose_op)
  
      # add/sub layer
      if not _check_child_op_type(
          transpose_op, "add"
      ) and not _check_child_op_type(transpose_op, "sub"):
          return False
      add_or_sub_op = list(transpose_op.outputs[0].child_ops)[0]
  
      ops_to_remove.append(add_or_sub_op)
  
      # get the bias
      if add_or_sub_op.x.val is None and add_or_sub_op.y.val is None:
          return False
      bias = (
          add_or_sub_op.x.val
          if add_or_sub_op.x.val is not None
          else add_or_sub_op.y.val
      )
      is_first_input = add_or_sub_op.y.val is not None
      is_sub = add_or_sub_op.op_type == "sub"
  
      # get the conv bias/weight
      conv_shape = conv_op.outputs[0].shape
      Cout = conv_shape[1]
      conv_weight = conv_op.weight.val
      conv_weight_type = conv_weight.dtype
      conv_bias = (
          np.zeros(Cout).astype(conv_weight_type)
          if conv_op.bias is None
          else conv_op.bias.val
      )
  
      # check if the bias is compatible for fusion
      is_bias_scalar = True
      if isinstance(bias, np.ndarray):
          if bias.shape == ():
              bias = bias.tolist()
          elif np.prod(bias.shape) == 1:
              bias = np.squeeze(bias).tolist()
          else:
              is_bias_scalar = False
  
      if not is_bias_scalar:
          if np.prod(bias.shape) != Cout:
              return False
          rank = transpose_op.outputs[0].rank
          cout_dim = transpose_op.perm.val.tolist().index(1) - rank
          if bias.shape[cout_dim] != Cout:
              return False
          bias = np.reshape(bias, (Cout))
  
      # compute the new bias
      if is_sub:
          if is_first_input:
              bias = -bias
          else:
              conv_bias = -conv_bias
  
      new_bias = conv_bias + bias
  
      # compute the new weight
      if is_sub and not is_first_input:
          new_weight = -conv_weight
      else:
          new_weight = conv_weight
  
      if not _check_no_output_connection(block, ops_to_remove):
          return False
  
      # create a new conv op with the new weight, bias value, copying rest of the attributes
      conv_kargs = {
          "weight": new_weight,
          "bias": new_bias,
          "before_op": conv_op,
      }
  
      for k, v in conv_op.inputs.items():
          if k in ["weight", "bias"]:
              continue
          conv_kargs[k] = v
  
      if is_deconv:
          x = mb.conv_transpose(**conv_kargs)
      else:
          x = mb.conv(**conv_kargs)
  
      # create a new transpose op
      out_name = add_or_sub_op.outputs[0].name
      tranpose_kargs = {
          "x": x,
          "name": out_name,
          "before_op": transpose_op,
      }
      for k, v in transpose_op.inputs.items():
          if k == "x":
              continue
          tranpose_kargs[k] = v
      x = mb.transpose(**tranpose_kargs)
  
      if add_or_sub_op.enclosing_block.try_replace_uses_of_var_after_op(
          anchor_op=add_or_sub_op,
          old_var=add_or_sub_op.outputs[0],
          new_var=x,
      ):
          add_or_sub_op.enclosing_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 3 for calling the fuse_conv_bias obj's underlying member method code with example usage: obj._try_to_transform_transpose_pattern(conv_op, block) and returns: False, False, False, False, False, False, True, False, False