code: def local_useless_reshape(fgraph, node):
      """Remove two kinds of useless `Reshape`.
  
      - Remove `Reshape` when both the input and output have a single dimension.
      - Remove `Reshape` when reshaping to the shape of the input.
  
      """
      inp = node.inputs[0]
      output = node.outputs[0]
      output_shape = node.inputs[1]
  
      if inp.type.ndim != output.type.ndim:
          return False
  
      # Simple case: both input and output have a single dimension.
      # TODO FIXME XXX: This could hide errors if the user provides inconsistent
      # shapes.
      if (
          inp.type.ndim == 1
          and output.type.ndim == 1
          and all(
              s1 == s2
              for s1, s2 in zip(inp.type.shape, output.type.shape)
              if s1 == 1 or s2 == 1
          )
      ):
          return [inp]
  
      # Second case: all the shapes match the input shape
      # Match Reshape(x, x.shape)
      if output_shape.owner and isinstance(
          output_shape.owner.op, Shape
      ):
          shape_input = output_shape.owner.inputs[0]
          if shape_input == inp:
              return [inp]
  
      # Match Reshape(x, [x.shape[0], ..., x.shape[-1]]), accounting for
      # broadcastable and constant dimensions
      if output_shape.owner and isinstance(
          output_shape.owner.op, MakeVector
      ):
          output_shape_is = output_shape.owner.inputs
  
          shape_feature = getattr(fgraph, "shape_feature", None)
  
          nb_m1 = 0
          shape_match = [False] * inp.type.ndim
          for dim in range(inp.type.ndim):
              outshp_i = output_shape_is[dim]
              # Match Shape_i{dim}(input)
              if (
                  outshp_i.owner
                  and isinstance(outshp_i.owner.op, Shape_i)
                  and outshp_i.owner.op.i == dim
                  and outshp_i.owner.inputs[0] == inp
              ):
                  shape_match[dim] = True
                  continue
  
              # Match Shape(input)[dim]
              if (
                  outshp_i.owner
                  and isinstance(outshp_i.owner.op, Subtensor)
                  and len(outshp_i.owner.inputs) == 2
                  and extract_constant(outshp_i.owner.inputs[1]) == dim
              ):
                  subtensor_inp = outshp_i.owner.inputs[0]
                  if subtensor_inp.owner and isinstance(
                      subtensor_inp.owner.op, Shape
                  ):
                      shape_input_i = subtensor_inp.owner.inputs[0]
                      if shape_input_i == inp:
                          shape_match[dim] = True
                          continue
  
              # Match 1 if input.type.shape[dim] == 1
              cst_outshp_i = extract_constant(
                  outshp_i, only_process_constants=1
              )
              if inp.type.shape[dim] == 1 and cst_outshp_i == 1:
                  shape_match[dim] = True
                  continue
  
              # Match -1
              if cst_outshp_i == -1:
                  shape_match[dim] = True
                  nb_m1 += 1
                  continue
  
              # Match shape_of[input][dim] or its constant equivalent
              if shape_feature:
                  inpshp_i = shape_feature.get_shape(inp, dim)
                  if inpshp_i == outshp_i or (
                      extract_constant(
                          inpshp_i, only_process_constants=1
                      )
                      == extract_constant(
                          outshp_i, only_process_constants=1
                      )
                  ):
                      shape_match[dim] = True
                      continue
  
          if all(shape_match) and nb_m1 <= 1:
              return [inp]
  
          # TODO later: if all the shapes except one match, we may want to
          # consider it useless as well, like we do in the 1-dim case.
          return False
  
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 2 for calling a global function with example usage: local_useless_reshape(fgraph, node) and returns: False, list, False, list, list