class_docstr: RNN-T loss implementation based on WFST according
  to "Powerful and Extensible WFST Framework for RNN-Transducer Losses"
  https://ieeexplore.ieee.org/document/10096679
docstr: Get temporal schema graph for RNN-T loss (Compose-Transducer).
  Forward arc - blank, self-loops - all labels excluding blank
  
  Example graph: blank=0, num_frames=3, vocab_size=3.
  Labels: <unit>:<frame_index>. <unit> is a unit from vocab.
  
  graph::
  
          1:0                1:1                1:2
        +-----+            +-----+            +-----+
        v     |            v     |            v     |
      +---------+  0:0   +---------+  0:1   +---------+  0:2   +---+  -1:-1   #===#
      |    0    | -----> |    1    | -----> |    2    | -----> | 3 | -------> H 4 H
      +---------+        +---------+        +---------+        +---+          #===#
        ^ 2:0 |            ^ 2:1 |            ^ 2:2 |
        +-----+            +-----+            +-----+
  
  Args:
      num_frames: length of the sequence (in frames)
      vocab_size: number of labels (including blank)
      device: device for tensor to construct
  
  Returns:
      temporal schema graph (k2.Fsa).
      Labels: <unit>:<frame_index>. <unit> is a unit from vocab.
docstr_tok: ["Get","temporal","schema","graph","for","RNN-T","loss","(","Compose-Transducer",")",".","Forward","arc","-","blank",",","self-loops","-","all","labels","excluding","blank","Example","graph",":","blank=0",",","num_frames=3",",","vocab_size=3",".","Labels",":","<","unit",">",":","<","frame_index",">",".","<","unit",">","is","a","unit","from","vocab",".","graph",":",":","1:0","1:1","1:2","+","--","--","-+","+","--","--","-+","+","--","--","-+","v","|","v","|","v","|","+","--","--","--","--","-+","0:0","+","--","--","--","--","-+","0:1","+","--","--","--","--","-+","0:2","+","--","-+","-1",":","-1","#","===","#","|","0","|","--","--","-",">","|","1","|","--","--","-",">","|","2","|","--","--","-",">","|","3","|","--","--","--","-",">","H","4","H","+","--","--","--","--","-+","+","--","--","--","--","-+","+","--","--","--","--","-+","+","--","-+","#","===","#","^","2:0","|","^","2:1","|","^","2:2","|","+","--","--","-+","+","--","--","-+","+","--","--","-+","Args",":","num_frames",":","length","of","the","sequence","(","in","frames",")","vocab_size",":","number","of","labels","(","including","blank",")","device",":","device","for","tensor","to","construct","Returns",":","temporal","schema","graph","(","k2.Fsa",")",".","Labels",":","<","unit",">",":","<","frame_index",">",".","<","unit",">","is","a","unit","from","vocab","."]
code: def get_temporal_schema(
      self, num_frames: int, vocab_size: int, device: torch.device
  ) -> "k2.Fsa":
      """
      Get temporal schema graph for RNN-T loss (Compose-Transducer).
      Forward arc - blank, self-loops - all labels excluding blank
  
      Example graph: blank=0, num_frames=3, vocab_size=3.
      Labels: <unit>:<frame_index>. <unit> is a unit from vocab.
  
      graph::
  
              1:0                1:1                1:2
            +-----+            +-----+            +-----+
            v     |            v     |            v     |
          +---------+  0:0   +---------+  0:1   +---------+  0:2   +---+  -1:-1   #===#
          |    0    | -----> |    1    | -----> |    2    | -----> | 3 | -------> H 4 H
          +---------+        +---------+        +---------+        +---+          #===#
            ^ 2:0 |            ^ 2:1 |            ^ 2:2 |
            +-----+            +-----+            +-----+
  
      Args:
          num_frames: length of the sequence (in frames)
          vocab_size: number of labels (including blank)
          device: device for tensor to construct
  
      Returns:
          temporal schema graph (k2.Fsa).
          Labels: <unit>:<frame_index>. <unit> is a unit from vocab.
      """
      blank_id = self.blank
  
      fsa_temporal_arcs = torch.zeros(
          (num_frames * vocab_size + 1, 4),
          dtype=torch.int32,
          device=device,
      )
      sequence_states = torch.arange(
          0, num_frames, dtype=torch.int32, device=device
      )
      # for every state - vocab_size arcs, [0, 1, ..., vocab_size-1, 0, 1, ..., vocab_size-1, ...]
      start_states = (
          sequence_states.expand(vocab_size, num_frames)
          .transpose(0, 1)
          .flatten()
      )
      # first: make all arcs - self-loops
      fsa_temporal_arcs[:-1, 0] = start_states  # from
      fsa_temporal_arcs[:-1, 1] = start_states  # to
      fsa_temporal_arcs[:-1, 2] = (
          torch.arange(0, vocab_size, dtype=torch.int32, device=device)
          .expand(num_frames, vocab_size)
          .flatten()
      )
  
      # blank-arcs: forward
      fsa_temporal_arcs[blank_id:-1:vocab_size, 1] = (
          sequence_states + 1
      )  # blanks
  
      # transition to last final state
      fsa_temporal_arcs[-1, :3] = torch.tensor(
          (num_frames, num_frames + 1, -1),
          dtype=torch.int32,
          device=device,
      )
  
      # output symbols: position in the sequence, same as start states for arcs
      olabels = fsa_temporal_arcs[:, 0].detach().clone()
      olabels[-1] = -1  # last arc to final state
  
      fsa_temporal = k2.Fsa(fsa_temporal_arcs, olabels)
      fsa_temporal = k2.arc_sort(fsa_temporal)  # need for compose
      return fsa_temporal
  
imports: import abc
  from contextlib import nullcontext
  from typing import ContextManager
  import torch
  import torch.nn.functional
  from nemo.core.classes.loss import Loss
  from nemo.core.utils.k2_guard import k2
label_desc: Use image node_id 3 for calling the GraphRnntLoss obj's underlying member method code with example usage: obj.get_temporal_schema(num_frames, vocab_size, device) and returns: fsa_temporal