code: def local_reshape_to_dimshuffle(fgraph, node):
      r"""Replace broadcastable dimensions in `Reshape` nodes with `DimShuffle`\s.
  
      The goal is to avoid using `Reshape` to add or remove broadcastable
      dimensions, and to use `DimShuffle` instead, since `DimShuffle`\s can
      cancel out and/or be removed later on.
  
      For example:
          - reshape(x, (1, n)) -> DimShuffle{x,0}(Reshape(x, (n,))
          - reshape(x, (1, m, 1, n, 1, 1))
            -> DimShuffle{x,0,x,1,x,x}(Reshape(x, (m, n)))
      """
      op = node.op
      inp = node.inputs[0]
      output = node.outputs[0]
      output_shape = node.inputs[1]
  
      dimshuffle_new_order = []
      new_output_shape = []
      index = 0  # index over the output of the new reshape
      for i in range(output.ndim):
          # Since output_shape is a symbolic vector, we trust extract_constant
          # to go through however it is formed to see if its i-th element is 1.
          # We need only_process_constants=False for that.
          dim = extract_constant(
              output_shape[i],
              only_process_constants=False,
              elemwise=False,
          )
          if dim == 1:
              dimshuffle_new_order.append("x")
          else:
              dimshuffle_new_order.append(index)
              new_output_shape.append(dim)
              index = index + 1
  
      if index != output.type.ndim:
          inner = op.__class__(len(new_output_shape))(
              inp, new_output_shape
          )
          copy_stack_trace(output, inner)
          new_node = [
              DimShuffle(
                  tuple(s == 1 for s in inner.type.shape),
                  dimshuffle_new_order,
              )(inner)
          ]
          copy_stack_trace(output, new_node)
          return new_node
  
imports: import traceback
  from io import StringIO
  from typing import Optional
  from typing import cast
  from warnings import warn
  import numpy
  import pytensor
  from pytensor.configdefaults import config
  from pytensor.graph.basic import Constant, Variable, ancestors, equal_computations
  from pytensor.graph.features import AlreadyThere, Feature
  from pytensor.graph.fg import FunctionGraph
  from pytensor.graph.rewriting.basic import GraphRewriter, check_chain, copy_stack_trace, node_rewriter
  from pytensor.graph.utils import InconsistencyError, get_variable_trace_string
  from pytensor.tensor.basic import MakeVector, as_tensor_variable, cast, constant, extract_constant, get_underlying_scalar_constant_value, register_infer_shape, stack
  from pytensor.tensor.elemwise import DimShuffle, Elemwise
  from pytensor.tensor.exceptions import NotScalarConstantError, ShapeError
  from pytensor.tensor.rewriting.basic import register_canonicalize, register_specialize, register_stabilize, register_useless, topo_constant_folding
  from pytensor.tensor.shape import Reshape, Shape, Shape_i, SpecifyShape, Unbroadcast, shape_i, specify_shape, unbroadcast
  from pytensor.tensor.subtensor import Subtensor, get_idx_list
  from pytensor.tensor.type import TensorType, discrete_dtypes, integer_dtypes
  from pytensor.tensor.type_other import NoneConst
label_desc: Use image node_id 3 for calling a global function with example usage: local_reshape_to_dimshuffle(fgraph, node) and returns: new_node