code: def test_online_training(self, name, cls):
      n_arms = 5
      total_n_obs = 100
      min_num_obs_per_arm = 15
      b = cls(n_arms=n_arms, min_num_obs_per_arm=min_num_obs_per_arm)
      total_obs_per_arm = torch.zeros(n_arms)
      total_success_per_arm = torch.zeros(n_arms)
      true_ctrs = torch.rand(size=(n_arms,))
      for _ in range(total_n_obs):
          chosen_arm = b.get_action()
          reward = torch.bernoulli(true_ctrs[int(chosen_arm)])
          b.add_single_observation(chosen_arm, reward)
          total_obs_per_arm[int(chosen_arm)] += 1
          total_success_per_arm[int(chosen_arm)] += reward
      # each arm has at least the required number of observations
      self.assertLessEqual(
          min_num_obs_per_arm, b.total_n_obs_per_arm.min().item()
      )
      online_scores = b()
      offline_scores = cls.get_scores_from_batch(
          total_obs_per_arm,
          total_success_per_arm,
          total_success_per_arm,
      )
      if isinstance(b, BaseUCB):
          npt.assert_array_equal(
              online_scores.numpy(), offline_scores.numpy()
          )  # UCB scores computed by online and offline algorithms match
      elif isinstance(b, NormalGammaThompson):
          b_batch = cls(n_arms=n_arms)
          b_batch.add_batch_observations(
              total_obs_per_arm,
              total_success_per_arm,
              total_success_per_arm,  # squared rewards are same as rewards
          )
  
          # make sure that posterior parameters are the same
          npt.assert_allclose(
              b_batch.gamma_rates.numpy(),
              b.gamma_rates.numpy(),
              rtol=1e-5,
          )
          npt.assert_allclose(
              b_batch.mus.numpy(), b.mus.numpy(), rtol=1e-5
          )
          npt.assert_array_equal(
              b_batch.total_n_obs_per_arm.numpy(),
              b.total_n_obs_per_arm.numpy(),
          )
          npt.assert_array_equal(
              b_batch.total_sum_reward_per_arm.numpy(),
              b.total_sum_reward_per_arm.numpy(),
          )
          npt.assert_array_equal(
              b_batch.total_sum_reward_squared_per_arm.numpy(),
              b.total_sum_reward_squared_per_arm.numpy(),
          )
  
      elif isinstance(b, BaseThompsonSampling):
          npt.assert_raises(
              AssertionError,
              npt.assert_array_equal,
              online_scores.numpy(),
              offline_scores.numpy(),
          )
  
imports: import unittest
  from io import BytesIO
  from itertools import cycle
  from unittest import mock
  import numpy
  import numpy.testing
  import torch
  from parameterized.parameterized import parameterized
  from pytorch_lightning import seed_everything
  from reagent.mab.mab_algorithm import get_arm_indices, place_values_at_indices, randomized_argmax, reindex_multiple_tensors
  from reagent.mab.simulation import BernoilliMAB, compare_bandit_algos, multiple_evaluations_bandit_algo, single_evaluation_bandit_algo
  from reagent.mab.thompson_sampling import BaseThompsonSampling, BernoulliBetaThompson, NormalGammaThompson
  from reagent.mab.ucb import BaseUCB, MetricUCB, UCB1, UCBTuned
label_desc: Use image node_id 4 for calling the TestMAB obj's underlying member method code with example usage: obj.test_online_training(name, cls) without return types