code: def _group_operations(tape):
      """Divide all operations of a tape into trainable operations and blocks
      of untrainable operations after each trainable one."""
  
      # Extract tape operations list
      ops = tape.operations
      # Find the indices of trainable operations in the tape operations list
      trainables = np.where(
          [qml.operation.is_trainable(op) for op in ops]
      )[0]
      # Add the indices incremented by one to the trainable indices
      split_ids = list(
          chain.from_iterable([idx, idx + 1] for idx in trainables)
      )
  
      # Split at trainable and incremented indices to get groups after trainable
      # operations and single trainable operations (in alternating order)
      all_groups = np.split(ops, split_ids)
  
      # Collect trainable operations and groups after trainable operations
      # the first set of non-trainable ops are the ops "after the -1st" trainable op
      group_after_trainable_op = dict(
          enumerate(all_groups[::2], start=-1)
      )
      trainable_operations = list(chain.from_iterable(all_groups[1::2]))
  
      return trainable_operations, group_after_trainable_op
  
file_path: pennylane/pennylane/gradients/adjoint_metric_tensor.py
imports: from typing import Sequence, Callable
  from itertools import chain
  from functools import partial
  import numpy
  import pennylane
  from pennylane.gradients.metric_tensor import _contract_metric_tensor_with_cjac
  from pennylane.transforms import transform
label_desc: Use image node_id 2 for calling a global function with example usage: _group_operations(tape) and returns: trainable_operations,  group_after_trainable_op