code: def test_doesnt_predict_eos_if_shorter_than_min_len(self):
      # beam 0 will always predict EOS. The other beams will predict
      # non-eos scores.
      for batch_sz in [1, 3]:
          beam_sz = 5
          n_words = 100
          _non_eos_idxs = [47, 51, 13, 88, 99]
          valid_score_dist = torch.log_softmax(
              torch.tensor([6.0, 5.0, 4.0, 3.0, 2.0, 1.0]), dim=0
          )
          min_length = 5
          eos_idx = 2
          lengths = torch.randint(0, 30, (batch_sz,))
          beam = BeamSearch(
              beam_sz,
              batch_sz,
              0,
              1,
              2,
              3,
              1,
              2,
              GlobalScorerStub(),
              min_length,
              30,
              False,
              0,
              set(),
              False,
              0.0,
              False,
          )
          device_init = torch.zeros(1, 1)
          beam.initialize(device_init, lengths)
          all_attns = []
          for i in range(min_length + 4):
              # non-interesting beams are going to get dummy values
              word_probs = torch.full(
                  (batch_sz * beam_sz, n_words), -float("inf")
              )
              if i == 0:
                  # "best" prediction is eos - that should be blocked
                  word_probs[0::beam_sz, eos_idx] = valid_score_dist[0]
                  # include at least beam_sz predictions OTHER than EOS
                  # that are greater than -1e20
                  for j, score in zip(
                      _non_eos_idxs, valid_score_dist[1:]
                  ):
                      word_probs[0::beam_sz, j] = score
              else:
                  # predict eos in beam 0
                  word_probs[0::beam_sz, eos_idx] = valid_score_dist[0]
                  # provide beam_sz other good predictions
                  for k, (j, score) in enumerate(
                      zip(_non_eos_idxs, valid_score_dist[1:])
                  ):
                      beam_idx = min(beam_sz - 1, k)
                      word_probs[beam_idx::beam_sz, j] = score
  
              attns = torch.randn(batch_sz * beam_sz, 1, 53)
              all_attns.append(attns)
              beam.advance(word_probs, attns)
              if i < min_length:
                  expected_score_dist = (i + 1) * valid_score_dist[
                      1:
                  ].unsqueeze(0)
                  self.assertTrue(
                      beam.topk_log_probs.allclose(expected_score_dist)
                  )
              elif i == min_length:
                  # now the top beam has ended and no others have
                  self.assertTrue(
                      all(
                          [
                              subbeam[0]
                              for subbeam in beam.is_finished_list
                          ]
                      )
                  )
                  self.assertTrue(
                      ~all(
                          [
                              subbeam[1]
                              for subbeam in beam.is_finished_list
                          ]
                      )
                  )
              else:  # i > min_length
                  # not of interest, but want to make sure it keeps running
                  # since only beam 0 terminates and n_best = 2
                  pass
  
imports: import unittest
  from onmt.translate.beam_search import BeamSearch, GNMTGlobalScorer
  from onmt.translate.beam_search import BeamSearchLM
  from copy import deepcopy
  import torch
label_desc: Use image node_id 4 for calling the TestBeamSearch obj's underlying member method code with example usage: obj.test_doesnt_predict_eos_if_shorter_than_min_len() without return types