code: def expand_indices(
      indices: Tuple[Optional[Union[Variable, slice]], ...],
      shape: Tuple[TensorVariable],
  ) -> Tuple[TensorVariable]:
      """Convert basic and/or advanced indices into a single, broadcasted advanced indexing operation.
  
      Parameters
      ----------
      indices
          The indices to convert.
      shape
          The shape of the array being indexed.
  
      """
      n_non_newaxis = sum(1 for idx in indices if not is_newaxis(idx))
      n_missing_dims = len(shape) - n_non_newaxis
      full_indices = list(indices) + [slice(None)] * n_missing_dims
  
      # We need to know if a "subspace" was generated by advanced indices
      # bookending basic indices.  If so, we move the advanced indexing subspace
      # to the "front" of the shape (i.e. left-most indices/last-most
      # dimensions).
      index_types = [is_basic_idx(idx) for idx in full_indices]
  
      first_adv_idx = len(shape)
      try:
          first_adv_idx = index_types.index(False)
          first_bsc_after_adv_idx = index_types.index(
              True, first_adv_idx
          )
          index_types.index(False, first_bsc_after_adv_idx)
          moved_subspace = True
      except ValueError:
          moved_subspace = False
  
      n_basic_indices = sum(index_types)
  
      # The number of dimensions in the subspace created by the advanced indices
      n_subspace_dims = max(
          (
              getattr(idx, "ndim", 0)
              for idx, is_basic in zip(full_indices, index_types)
              if not is_basic
          ),
          default=0,
      )
  
      # The number of dimensions for each expanded index
      n_output_dims = n_subspace_dims + n_basic_indices
  
      adv_indices = []
      shape_copy = list(shape)
      n_preceding_basics = 0
      for d, idx in enumerate(full_indices):
          if not is_basic_idx(idx):
              s = shape_copy.pop(0)
  
              idx = pt.as_tensor(idx)
  
              if moved_subspace:
                  # The subspace generated by advanced indices appear as the
                  # upper dimensions in the "expanded" index space, so we need to
                  # add broadcast dimensions for the non-basic indices to the end
                  # of these advanced indices
                  expanded_idx = idx[
                      (Ellipsis,) + (None,) * n_basic_indices
                  ]
              else:
                  # In this case, we need to add broadcast dimensions for the
                  # basic indices that proceed and follow the group of advanced
                  # indices; otherwise, a contiguous group of advanced indices
                  # forms a broadcasted set of indices that are iterated over
                  # within the same subspace, which means that all their
                  # corresponding "expanded" indices have exactly the same shape.
                  expanded_idx = idx[(None,) * n_preceding_basics][
                      (Ellipsis,)
                      + (None,) * (n_basic_indices - n_preceding_basics)
                  ]
          else:
              if is_newaxis(idx):
                  n_preceding_basics += 1
                  continue
  
              s = shape_copy.pop(0)
  
              if isinstance(idx, slice) or isinstance(
                  getattr(idx, "type", None), SliceType
              ):
                  idx = as_index_literal(idx)
                  idx_slice, _ = get_canonical_form_slice(idx, s)
                  idx = pt.arange(
                      idx_slice.start, idx_slice.stop, idx_slice.step
                  )
  
              if moved_subspace:
                  # Basic indices appear in the lower dimensions
                  # (i.e. right-most) in the output, and are preceded by
                  # the subspace generated by the advanced indices.
                  expanded_idx = idx[
                      (None,) * (n_subspace_dims + n_preceding_basics)
                  ][
                      (Ellipsis,)
                      + (None,)
                      * (n_basic_indices - n_preceding_basics - 1)
                  ]
              else:
                  # In this case, we need to know when the basic indices have
                  # moved past the contiguous group of advanced indices (in the
                  # "expanded" index space), so that we can properly pad those
                  # dimensions in this basic index's shape.
                  # Don't forget that a single advanced index can introduce an
                  # arbitrary number of dimensions to the expanded index space.
  
                  # If we're currently at a basic index that's past the first
                  # advanced index, then we're necessarily past the group of
                  # advanced indices.
                  n_preceding_dims = (
                      n_subspace_dims if d > first_adv_idx else 0
                  ) + n_preceding_basics
                  expanded_idx = idx[(None,) * n_preceding_dims][
                      (Ellipsis,)
                      + (None,) * (n_output_dims - n_preceding_dims - 1)
                  ]
  
              n_preceding_basics += 1
  
          assert expanded_idx.ndim <= n_output_dims
  
          adv_indices.append(expanded_idx)
  
      return cast(
          Tuple[TensorVariable],
          tuple(pt.broadcast_arrays(*adv_indices)),
      )
  
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 2 for calling a global function with example usage: expand_indices(indices, shape) and returns: cast