code: def test_linucb_model_update_equations(self):
      # make sure that the model parameters match hand-computed values
      scorer = DisjointLinearRegressionUCB(self.num_arms, self.x_dim)
      policy = Policy(scorer=scorer, sampler=GreedyActionSampler())
      trainer = DisjointLinUCBTrainer(policy)
      trainer.training_step(self.batch, 0)
      trainer.on_train_epoch_end()
      # the feature matrix (computed by hand)
      for arm in range(self.num_arms):
          x = self.batch[arm].context_arm_features.numpy()
          npt.assert_allclose(scorer.A[arm].numpy(), x.T @ x, rtol=1e-5)
          npt.assert_allclose(
              scorer.b[arm].numpy(),
              x.T @ self.batch[arm].reward.squeeze().numpy(),
              rtol=1e-5,
          )
  
      for arm in range(self.num_arms):
          npt.assert_allclose(
              (np.eye(self.x_dim) + scorer.A[arm].numpy())
              @ scorer.inv_A[arm].numpy(),
              np.eye(self.x_dim),
              atol=1e-2,
              rtol=1e-3,
          )
          npt.assert_equal(
              scorer.A[arm].numpy(),
              scorer.coefs_valid_for_A[arm].numpy(),
          )
  
file_path: ReAgent/reagent/test/training/cb/test_disjoint_linucb.py
imports: import copy
  import unittest
  import numpy
  import numpy.testing
  import torch
  from reagent.core.types import CBInput
  from reagent.gym.policies.policy import Policy
  from reagent.gym.policies.samplers.discrete_sampler import GreedyActionSampler
  from reagent.models.disjoint_linucb_predictor import DisjointLinearRegressionUCB
  from reagent.training.cb.disjoint_linucb_trainer import DisjointLinUCBTrainer
  from reagent.training.parameters import DisjointLinUCBTrainerParameters
label_desc: Use image node_id 4 for calling the TestDisjointLinUCB obj's underlying member method code with example usage: obj.test_linucb_model_update_equations() without return types