class_docstr: Circular experience replay buffer for `CounterfactualRL` (DDPG). When the buffer is filled, then the oldest
  experience is replaced by the new one (FIFO). The experience batch size is kept constant and inferred when
  the first batch of data is stored. Allowing flexible batch size can generate `tensorflow` warning due to
  the `tf.function` retracing, which can lead to a drop in performance.
class_docstr_tok: ["Circular","experience","replay","buffer","for","`","CounterfactualRL","`","(","DDPG",")",".","When","the","buffer","is","filled",",","then","the","oldest","experience","is","replaced","by","the","new","one","(","FIFO",")",".","The","experience","batch","size","is","kept","constant","and","inferred","when","the","first","batch","of","data","is","stored",".","Allowing","flexible","batch","size","can","generate","`","tensorflow","`","warning","due","to","the","`","tf.function","`","retracing",",","which","can","lead","to","a","drop","in","performance","."]
docstr: Sample a batch of experience form the replay buffer.
  
  Returns
  -------
  A batch experience. For a description of the keys and values returned, see parameter descriptions         in :py:meth:`alibi.explainers.cfrl_base.ReplayBuffer.append` method. The batch size returned is the same         as the one passed in the :py:meth:`alibi.explainers.cfrl_base.ReplayBuffer.append`.
code: def sample(self) -> Dict[str, Optional[np.ndarray]]:
      """
          Sample a batch of experience form the replay buffer.
  
          Returns
          -------
          A batch experience. For a description of the keys and values returned, see parameter descriptions \
          in :py:meth:`alibi.explainers.cfrl_base.ReplayBuffer.append` method. The batch size returned is the same \
          as the one passed in the :py:meth:`alibi.explainers.cfrl_base.ReplayBuffer.append`.
          """
      # Generate random indices to be sampled.
      rand_idx = np.random.randint(
          low=0,
          high=self.len * self.batch_size,
          size=(self.batch_size,),
      )
  
      # Extract data form buffers.
      X = self.X[rand_idx]  # input array
      Y_m = self.Y_m[rand_idx]  # model's prediction
      Y_t = self.Y_t[rand_idx]  # counterfactual target
      Z = self.Z[rand_idx]  # input embedding
      Z_cf_tilde = self.Z_cf_tilde[
          rand_idx
      ]  # noised counterfactual embedding
      C = (
          self.C[rand_idx] if (self.C is not None) else None
      )  # conditional array if exists
      R_tilde = self.R_tilde[rand_idx]  # noised counterfactual reward
  
      return {
          "X": X,
          "Y_m": Y_m,
          "Y_t": Y_t,
          "Z": Z,
          "Z_cf_tilde": Z_cf_tilde,
          "C": C,
          "R_tilde": R_tilde,
      }
  
imports: import logging
  import os
  from abc import ABC, abstractmethod
  from copy import deepcopy
  from typing import TYPE_CHECKING, Any, Callable, Dict, Optional, Tuple, Union, cast
  import numpy
  from tqdm import tqdm
  from alibi.api.defaults import DEFAULT_DATA_CFRL, DEFAULT_META_CFRL
  from alibi.api.interfaces import Explainer, Explanation, FitMixin
  from alibi.explainers.backends.cfrl_base import generate_empty_condition, get_classification_reward, get_hard_distribution, identity_function
  from alibi.utils.frameworks import Framework, has_pytorch, has_tensorflow
label_desc: Use image node_id 3 for calling the ReplayBuffer obj's underlying member method code with example usage: obj.sample() and returns: dict