class_docstr: A replay buffer that stores episodes of transitions. The additional structure allows performing various
  calculations of total return and other values that depend on the sequential behavior of the transitions
  in the episode.
class_docstr_tok: ["A","replay","buffer","that","stores","episodes","of","transitions",".","The","additional","structure","allows","performing","various","calculations","of","total","return","and","other","values","that","depend","on","the","sequential","behavior","of","the","transitions","in","the","episode","."]
docstr: Sample a batch of transitions from the replay buffer. If the requested size is larger than the number
  of samples available in the replay buffer then the batch will return empty.
  :param size: the size of the batch to sample
  :param is_consecutive_transitions: if set True, samples a batch of consecutive transitions.
  :return: a batch (list) of selected transitions from the replay buffer
code: def sample(
      self, size: int, is_consecutive_transitions=False
  ) -> List[Transition]:
      """
      Sample a batch of transitions from the replay buffer. If the requested size is larger than the number
      of samples available in the replay buffer then the batch will return empty.
      :param size: the size of the batch to sample
      :param is_consecutive_transitions: if set True, samples a batch of consecutive transitions.
      :return: a batch (list) of selected transitions from the replay buffer
      """
      self.reader_writer_lock.lock_writing()
  
      if self.num_complete_episodes() >= 1:
          if is_consecutive_transitions:
              episode_idx = np.random.randint(
                  0, self.num_complete_episodes()
              )
              if self._buffer[episode_idx].length() <= size:
                  batch = self._buffer[episode_idx].transitions
              else:
                  transition_idx = np.random.randint(
                      size, self._buffer[episode_idx].length()
                  )
                  batch = self._buffer[episode_idx].transitions[
                      transition_idx - size : transition_idx
                  ]
          else:
              transitions_idx = np.random.randint(
                  self.num_transitions_in_complete_episodes(), size=size
              )
              batch = [self.transitions[i] for i in transitions_idx]
  
      else:
          raise ValueError(
              "The episodic replay buffer cannot be sampled since there are no complete episodes yet. "
              "There is currently 1 episodes with {} transitions".format(
                  self._buffer[0].length()
              )
          )
  
      self.reader_writer_lock.release_writing()
  
      return batch
  
imports: import ast
  import pickle
  from copy import deepcopy
  import math
  import pandas
  from typing import List, Tuple, Union
  import numpy
  import random
  from rl_coach.core_types import Transition, Episode
  from rl_coach.filters.filter import InputFilter
  from rl_coach.logger import screen
  from rl_coach.memories.memory import Memory, MemoryGranularity, MemoryParameters
  from rl_coach.utils import ReaderWriterLock, ProgressBar
  from rl_coach.core_types import CsvDataset
label_desc: Use image node_id 7 for calling the EpisodicExperienceReplay obj's underlying member method code with example usage: obj.sample(size, is_consecutive_transitions) and returns: batch