class_docstr: This implements a simple multi-agent minibatch iterator.
  
  
  This iterator will split the input multi-agent batch into minibatches where the
  size of batch for each module_id (aka policy_id) is equal to minibatch_size. If the
  input batch is smaller than minibatch_size, then the iterator will cycle through
  the batch until it has covered num_iters epochs.
  
  Args:
      batch: The input multi-agent batch.
      minibatch_size: The size of the minibatch for each module_id.
      num_iters: The minimum number of epochs to cover. If the input batch is smaller
          than minibatch_size, then the iterator will cycle through the batch until
          it has covered at least num_iters epochs.
code: def __iter__(self):
      while min(self._num_covered_epochs.values()) < self._num_iters:
          minibatch = {}
          for (
              module_id,
              module_batch,
          ) in self._batch.policy_batches.items():
              if len(module_batch) == 0:
                  raise ValueError(
                      f"The batch for module_id {module_id} is empty! "
                      "This will create an infinite loop because we need to cover "
                      "the same number of samples for each module_id."
                  )
              s = self._start[module_id]  # start
              n_steps = self._minibatch_size
  
              samples_to_concat = []
  
              # get_len is a function that returns the length of a batch
              # if we are not slicing the batch in the batch dimension B, then
              # the length of the batch is simply the length of the batch
              # o.w the length of the batch is the length list of seq_lens.
              if module_batch._slice_seq_lens_in_B:
                  assert (
                      module_batch.get(SampleBatch.SEQ_LENS) is not None
                  ), (
                      "MiniBatchCyclicIterator requires SampleBatch.SEQ_LENS"
                      "to be present in the batch for slicing a batch in the batch "
                      "dimension B."
                  )
  
                  def get_len(b):
                      return len(b[SampleBatch.SEQ_LENS])
  
              else:
  
                  def get_len(b):
                      return len(b)
  
              # Cycle through the batch until we have enough samples.
              while n_steps >= get_len(module_batch) - s:
                  sample = module_batch[s:]
                  samples_to_concat.append(sample)
                  len_sample = get_len(sample)
                  assert (
                      len_sample > 0
                  ), "Length of a sample must be > 0!"
                  n_steps -= len_sample
                  s = 0
                  self._num_covered_epochs[module_id] += 1
  
              e = s + n_steps  # end
              if e > s:
                  samples_to_concat.append(module_batch[s:e])
  
              # concatenate all the samples, we should have minibatch_size of sample
              # after this step
              minibatch[module_id] = concat_samples(samples_to_concat)
              # roll minibatch to zero when we reach the end of the batch
              self._start[module_id] = e
  
          # Note (Kourosh): env_steps is the total number of env_steps that this
          # multi-agent batch is covering. It should be simply inherited from the
          # original multi-agent batch.
          minibatch = MultiAgentBatch(minibatch, len(self._batch))
          yield minibatch
  
imports: import math
  from typing import List
  from ray.rllib.policy.sample_batch import MultiAgentBatch, concat_samples
  from ray.rllib.policy.sample_batch import SampleBatch
  from ray.rllib.utils.annotations import DeveloperAPI
  from ray.rllib.utils.typing import EpisodeType
label_desc: Use image node_id 2 for calling the MiniBatchCyclicIterator obj's underlying member method code with example usage: obj.__iter__() and returns: len, len