code: def find_measurable_index_mixture(fgraph, node):
      r"""Identify mixture sub-graphs and replace them with a place-holder `Op`.
  
      The basic idea is to find ``stack(mixture_comps)[I_rv]``, where
      ``mixture_comps`` is a ``list`` of `MeasurableVariable`\s and ``I_rv`` is a
      `MeasurableVariable` with a discrete and finite support.
      From these terms, new terms ``Z_rv[i] = mixture_comps[i][i == I_rv]`` are
      created for each ``i`` in ``enumerate(mixture_comps)``.
      """
      rv_map_feature: Optional[PreserveRVMappings] = getattr(
          fgraph, "preserve_rv_mappings", None
      )
  
      if rv_map_feature is None:
          return None  # pragma: no cover
  
      mixing_indices = node.inputs[1:]
  
      # TODO: Add check / test case for Advanced Boolean indexing
      if isinstance(node.op, (AdvancedSubtensor, AdvancedSubtensor1)):
          # We don't support (non-scalar) integer array indexing as it can pick repeated values,
          # but the Mixture logprob assumes all mixture values are independent
          if any(
              indices.dtype.startswith("int")
              and sum(1 - b for b in indices.type.broadcastable) > 0
              for indices in mixing_indices
              if not isinstance(indices, SliceConstant)
          ):
              return None
  
      old_mixture_rv = node.default_output()
      mixture_rvs, join_axis = get_stack_mixture_vars(node)
  
      # We don't support symbolic join axis
      if mixture_rvs is None or not isinstance(
          join_axis, (NoneTypeT, Constant)
      ):
          return None
  
      if rv_map_feature.request_measurable(mixture_rvs) != mixture_rvs:
          return None
  
      # Replace this sub-graph with a `MixtureRV`
      mix_op = MixtureRV(
          1 + len(mixing_indices),
          old_mixture_rv.dtype,
          old_mixture_rv.broadcastable,
      )
      new_node = mix_op.make_node(
          *([join_axis] + mixing_indices + mixture_rvs)
      )
  
      new_mixture_rv = new_node.default_output()
  
      if pytensor.config.compute_test_value != "off":
          # We can't use `MixtureRV` to compute a test value; instead, we'll use
          # the original node's test value.
          if not hasattr(old_mixture_rv.tag, "test_value"):
              compute_test_value(node)
  
          new_mixture_rv.tag.test_value = old_mixture_rv.tag.test_value
  
      return [new_mixture_rv]
  
imports: from typing import List, Optional, Tuple, Union, cast
  import pytensor
  import pytensor.tensor
  from pytensor.graph.basic import Apply, Constant, Variable
  from pytensor.graph.fg import FunctionGraph
  from pytensor.graph.op import Op, compute_test_value
  from pytensor.graph.rewriting.basic import EquilibriumGraphRewriter, node_rewriter
  from pytensor.ifelse import IfElse, ifelse
  from pytensor.scalar import Switch
  from pytensor.scalar import switch
  from pytensor.tensor.basic import Join, MakeVector, switch
  from pytensor.tensor.random.rewriting import local_dimshuffle_rv_lift, local_rv_size_lift, local_subtensor_rv_lift
  from pytensor.tensor.rewriting.shape import ShapeFeature
  from pytensor.tensor.shape import shape_tuple
  from pytensor.tensor.subtensor import AdvancedSubtensor, AdvancedSubtensor1, as_index_literal, get_canonical_form_slice, is_basic_idx
  from pytensor.tensor.type import TensorType
  from pytensor.tensor.type_other import NoneConst, NoneTypeT, SliceConstant, SliceType
  from pytensor.tensor.variable import TensorVariable
  from pymc.logprob.abstract import MeasurableElemwise, MeasurableVariable, _logprob, _logprob_helper
  from pymc.logprob.rewriting import PreserveRVMappings, assume_measured_ir_outputs, local_lift_DiracDelta, measurable_ir_rewrites_db, subtensor_ops
  from pymc.logprob.utils import check_potential_measurability, replace_rvs_by_values
  from pymc.pytensorf import constant_fold
label_desc: Use image node_id 5 for calling a global function with example usage: find_measurable_index_mixture(fgraph, node) and returns: list, None, None, None, None