class_docstr: edge : b x N x K x C x C semimarkov potentials
docstr: Compute forward pass by linear scan
docstr_tok: ["Compute","forward","pass","by","linear","scan"]
code: def logpartition(
      self, log_potentials, lengths=None, force_grad=False
  ):
      "Compute forward pass by linear scan"
  
      # Setup
      semiring = self.semiring
      ssize = semiring.size()
      log_potentials.requires_grad_(True)
      log_potentials, batch, N, K, C, lengths = self._check_potentials(
          log_potentials, lengths
      )
      log_N, bin_N = self._bin_length(N - 1)
      init = self._chart(
          (batch, bin_N, K - 1, K - 1, C, C), log_potentials, force_grad
      )
  
      # Init.
      mask = torch.zeros(
          *init.shape, device=log_potentials.device
      ).bool()
      mask[:, :, :, 0, 0].diagonal(0, -2, -1).fill_(True)
      init = semiring.fill(init, mask, semiring.one)
  
      # Length mask
      big = torch.zeros(
          ssize,
          batch,
          bin_N,
          K,
          C,
          C,
          dtype=log_potentials.dtype,
          device=log_potentials.device,
      )
      big[:, :, : N - 1] = log_potentials
      c = init[:, :, :].view(ssize, batch * bin_N, K - 1, K - 1, C, C)
      lp = big[:, :, :].view(ssize, batch * bin_N, K, C, C)
      mask = torch.arange(bin_N).view(1, bin_N).expand(batch, bin_N)
      mask = mask.to(log_potentials.device)
      mask = mask >= (lengths - 1).view(batch, 1)
      mask = mask.view(batch * bin_N, 1, 1, 1).to(lp.device)
      lp.data[:] = semiring.fill(lp.data, mask, semiring.zero)
      c.data[:, :, :, 0] = semiring.fill(
          c.data[:, :, :, 0], (~mask), semiring.zero
      )
      c[:, :, : K - 1, 0] = semiring.sum(
          torch.stack([c.data[:, :, : K - 1, 0], lp[:, :, 1:K]], dim=-1)
      )
      mask = torch.zeros(
          *init.shape, device=log_potentials.device
      ).bool()
      mask_length = (
          torch.arange(bin_N).view(1, bin_N, 1).expand(batch, bin_N, C)
      )
      mask_length = mask_length.to(log_potentials.device)
      for k in range(1, K - 1):
          mask_length_k = mask_length < (lengths - 1 - (k - 1)).view(
              batch, 1, 1
          )
          mask_length_k = semiring.convert(mask_length_k)
          mask[:, :, :, k - 1, k].diagonal(0, -2, -1).masked_fill_(
              mask_length_k, True
          )
      init = semiring.fill(init, mask, semiring.one)
  
      K_1 = K - 1
  
      # Order n, n-1
      chart = (
          init.permute(0, 1, 2, 3, 5, 4, 6)
          .contiguous()
          .view(-1, batch, bin_N, K_1 * C, K_1 * C)
      )
  
      for n in range(1, log_N + 1):
          chart = semiring.matmul(chart[:, :, 1::2], chart[:, :, 0::2])
  
      final = chart.view(-1, batch, K_1, C, K_1, C)
      v = semiring.sum(
          semiring.sum(final[:, :, 0, :, 0, :].contiguous())
      )
      return v, [log_potentials]
  
file_path: pytorch-struct/torch_struct/semimarkov.py
imports: import torch
  from .helpers import _Struct
label_desc: Use image node_id 2 for calling the SemiMarkov obj's underlying member method code with example usage: obj.logpartition(log_potentials, lengths, force_grad) and returns: v,  list