code: def remove_constants_and_unused_inputs_scan(fgraph, node):
      """Move constants into the inner graph, and remove unused inputs.
  
      Constants that are in the outer graph are represented by a free symbolic
      variable in the inner graph. If we move them into the inner graph,
      constant-folding can happen in the inner graph.
      This is applied only on sequences and non-sequences,
      not on initial states.
  
      """
      if not isinstance(node.op, Scan):
          return False
      op = node.op
      op_info = op.info
      # We only need to take care of sequences and other arguments
      st = op_info.n_seqs
      st += int(
          sum(
              len(x)
              for x in chain(
                  op_info.mit_mot_in_slices, op_info.mit_sot_in_slices
              )
          )
      )
      st += op_info.n_sit_sot
      st += op_info.n_shared_outs
  
      op_ins = op.inner_inputs
      op_outs = op.inner_outputs
  
      # Corresponds to the initial states, which should stay untouched.
      # We put those variables aside, and put them back at the end.
      out_stuff_inner = op_ins[op_info.n_seqs : st]
  
      non_seqs = op_ins[st:]
      st = (
          op_info.n_seqs
          + op_info.n_mit_mot
          + op_info.n_mit_sot
          + op_info.n_sit_sot
          + op_info.n_nit_sot
          + op_info.n_shared_outs
          + 1
      )
      outer_non_seqs = node.inputs[st:]
      out_stuff_outer = node.inputs[1 + op_info.n_seqs : st]
  
      # To replace constants in the outer graph by clones in the inner graph
      givens = {}
      # All the inputs of the inner graph of the new scan
      nw_inner = []
      # Same for the outer graph, initialized w/ number of steps
      nw_outer = [node.inputs[0]]
  
      all_ins = list(graph_inputs(op_outs))
      for idx in range(op_info.n_seqs):
          node_inp = node.inputs[idx + 1]
          if (
              isinstance(node_inp, TensorConstant)
              and get_unique_constant_value(node_inp) is not None
          ):
              try:
                  # This works if input is a constant that has all entries
                  # equal
                  givens[op_ins[idx]] = node_inp[0]
              except TypeError:
                  pass
          elif op_ins[idx] in all_ins:
              # Check for identical other sequence
              identical_seqs = [
                  x
                  for x in nw_outer
                  if equal_computations([x], [node_inp])
              ]
              if identical_seqs:
                  index = node.inputs.index(identical_seqs[0]) - 1
                  givens[op_ins[idx]] = op_ins[index]
              else:
                  nw_inner.append(op_ins[idx])
                  nw_outer.append(node_inp)
  
      nw_n_seqs = len(nw_inner)
      # Add outputs stuff
      nw_inner += out_stuff_inner
      nw_outer += out_stuff_outer
  
      # Look through non sequences
      nw_inner_nonseq = []
      nw_outer_nonseq = []
      for idx, (nw_in, nw_out) in enumerate(
          zip(non_seqs, outer_non_seqs)
      ):
          if isinstance(nw_out, Constant):
              givens[nw_in] = nw_out
          elif nw_in in all_ins:
              # Indices of elements of nw_outer_nonseq that are equivalent
              # to nw_out.
              identical_nonseq_idx = [
                  i
                  for (i, x) in enumerate(nw_outer_nonseq)
                  if equal_computations([x], [nw_out])
              ]
              if identical_nonseq_idx:
                  givens[nw_in] = nw_inner_nonseq[
                      identical_nonseq_idx[0]
                  ]
              else:
                  nw_inner_nonseq.append(nw_in)
                  nw_outer_nonseq.append(nw_out)
  
      nw_inner.extend(nw_inner_nonseq)
      nw_outer.extend(nw_outer_nonseq)
  
      if len(nw_inner) != len(op_ins):
          op_outs = clone_replace(op_outs, replace=givens)
          nw_info = dataclasses.replace(
              op_info, n_seqs=nw_n_seqs, n_non_seqs=len(nw_inner_nonseq)
          )
          nwScan = Scan(
              nw_inner,
              op_outs,
              nw_info,
              mode=op.mode,
              profile=op.profile,
              truncate_gradient=op.truncate_gradient,
              # TODO: This seems questionable
              name=op.name,
              allow_gc=op.allow_gc,
          )
          nw_outs = nwScan(*nw_outer, return_list=True)
          return dict(
              [("remove", [node])] + list(zip(node.outputs, nw_outs))
          )
      else:
          return False
  
imports: import copy
  import dataclasses
  from itertools import chain
  from sys import maxsize
  from typing import Optional, cast
  import numpy
  import pytensor
  from pytensor import scalar
  from pytensor import tensor
  from pytensor.compile import optdb
  from pytensor.compile.function.types import deep_copy_op
  from pytensor.configdefaults import config
  from pytensor.graph.basic import Apply, Constant, NominalVariable, Variable, ancestors, apply_depends_on, equal_computations, graph_inputs, io_toposort
  from pytensor.graph.destroyhandler import DestroyHandler
  from pytensor.graph.features import ReplaceValidate
  from pytensor.graph.fg import FunctionGraph
  from pytensor.graph.op import compute_test_value
  from pytensor.graph.replace import clone_replace
  from pytensor.graph.rewriting.basic import GraphRewriter, copy_stack_trace, in2out, node_rewriter
  from pytensor.graph.rewriting.db import EquilibriumDB, SequenceDB
  from pytensor.graph.rewriting.utils import get_clients_at_depth
  from pytensor.graph.type import HasShape
  from pytensor.graph.utils import InconsistencyError
  from pytensor.raise_op import Assert
  from pytensor.scalar import ScalarConstant
  from pytensor.scan.op import Scan, ScanInfo
  from pytensor.scan.utils import ScanArgs, compress_outs, expand_empty, reconstruct_graph, safe_new, scan_can_remove_outs
  from pytensor.tensor.basic import Alloc, AllocEmpty, get_underlying_scalar_constant_value
  from pytensor.tensor.elemwise import DimShuffle, Elemwise
  from pytensor.tensor.exceptions import NotScalarConstantError
  from pytensor.tensor.math import Dot, dot, maximum, minimum
  from pytensor.tensor.rewriting.basic import constant_folding, local_useless_switch
  from pytensor.tensor.rewriting.elemwise import local_upcast_elemwise_constant_inputs
  from pytensor.tensor.rewriting.math import local_abs_merge, local_mul_switch_sink
  from pytensor.tensor.shape import shape
  from pytensor.tensor.subtensor import IncSubtensor, Subtensor, get_canonical_form_slice, get_idx_list, get_slice_elements, set_subtensor
  from pytensor.tensor.variable import TensorConstant, get_unique_constant_value
label_desc: Use image node_id 1 for calling a global function with example usage: remove_constants_and_unused_inputs_scan(fgraph, node) and returns: False, dict, False