docstr: Tests the refactored (Categorical-less) version of `update_posterior_policies`, using only the expected utility component of the expected free energy
docstr_tok: ["Tests","the","refactored","(","Categorical-less",")","version","of","`","update_posterior_policies","`",",","using","only","the","expected","utility","component","of","the","expected","free","energy"]
code: def test_update_posterior_policies_utility(self):
      """
      Tests the refactored (Categorical-less) version of `update_posterior_policies`, using only the expected utility component of the expected free energy
      """
  
      """Test with single observation modality, single hidden state factor and single timestep"""
  
      num_obs = [3]
      num_states = [3]
      num_controls = [3]
  
      qs = utils.obj_array_uniform(num_states)
      A = utils.random_A_matrix(num_obs, num_states)
      B = utils.random_B_matrix(num_states, num_controls)
      C = utils.obj_array_zeros(num_obs)
      C[0][0] = 1.0
      C[0][1] = -2.0
  
      policies = control.construct_policies(
          num_states, num_controls, policy_len=1
      )
  
      q_pi, efe = control.update_posterior_policies(
          qs,
          A,
          B,
          C,
          policies,
          use_utility=True,
          use_states_info_gain=False,
          use_param_info_gain=False,
          pA=None,
          pB=None,
          gamma=16.0,
      )
  
      factor_idx = 0
      modality_idx = 0
      t_idx = 0
  
      efe_valid = np.zeros(len(policies))
  
      for idx, policy in enumerate(policies):
          qs_pi = control.get_expected_states(qs, B, policy)
  
          qo_pi = control.get_expected_obs(qs_pi, A)
  
          lnC = maths.spm_log_single(
              maths.softmax(C[modality_idx][:, np.newaxis])
          )
          efe_valid[idx] += qo_pi[t_idx][modality_idx].dot(lnC)
  
      q_pi_valid = maths.softmax(efe_valid * 16.0)
  
      self.assertTrue(np.allclose(efe, efe_valid))
      self.assertTrue(np.allclose(q_pi, q_pi_valid))
  
      """Test with multiple observation modalities, multiple hidden state factors and single timestep"""
  
      num_obs = [3, 3]
      num_states = [3, 2]
      num_controls = [3, 1]
  
      qs = utils.random_single_categorical(num_states)
      A = utils.random_A_matrix(num_obs, num_states)
      B = utils.random_B_matrix(num_states, num_controls)
      C = utils.obj_array_zeros(num_obs)
      C[0][0] = 1.0
      C[0][1] = -2.0
      C[1][2] = 4.0
  
      policies = control.construct_policies(
          num_states, num_controls, policy_len=1
      )
  
      q_pi, efe = control.update_posterior_policies(
          qs,
          A,
          B,
          C,
          policies,
          use_utility=True,
          use_states_info_gain=False,
          use_param_info_gain=False,
          pA=None,
          pB=None,
          gamma=16.0,
      )
  
      t_idx = 0
  
      efe_valid = np.zeros(len(policies))
  
      for idx, policy in enumerate(policies):
          qs_pi = control.get_expected_states(qs, B, policy)
          qo_pi = control.get_expected_obs(qs_pi, A)
  
          for modality_idx in range(len(A)):
              lnC = maths.spm_log_single(
                  maths.softmax(C[modality_idx][:, np.newaxis])
              )
              efe_valid[idx] += qo_pi[t_idx][modality_idx].dot(lnC)
  
      q_pi_valid = maths.softmax(efe_valid * 16.0)
  
      self.assertTrue(np.allclose(efe, efe_valid))
      self.assertTrue(np.allclose(q_pi, q_pi_valid))
  
      """Test with multiple observation modalities, multiple hidden state factors and multiple timesteps"""
  
      num_obs = [3, 3]
      num_states = [3, 2]
      num_controls = [3, 1]
  
      qs = utils.random_single_categorical(num_states)
      A = utils.random_A_matrix(num_obs, num_states)
      B = utils.random_B_matrix(num_states, num_controls)
      C = utils.obj_array_zeros(num_obs)
      C[0][0] = 1.0
      C[0][1] = -2.0
      C[1][2] = 4.0
  
      policies = control.construct_policies(
          num_states, num_controls, policy_len=3
      )
  
      q_pi, efe = control.update_posterior_policies(
          qs,
          A,
          B,
          C,
          policies,
          use_utility=True,
          use_states_info_gain=False,
          use_param_info_gain=False,
          pA=None,
          pB=None,
          gamma=16.0,
      )
  
      efe_valid = np.zeros(len(policies))
  
      for idx, policy in enumerate(policies):
          qs_pi = control.get_expected_states(qs, B, policy)
          qo_pi = control.get_expected_obs(qs_pi, A)
  
          for t_idx in range(3):
              for modality_idx in range(len(A)):
                  lnC = maths.spm_log_single(
                      maths.softmax(C[modality_idx][:, np.newaxis])
                  )
                  efe_valid[idx] += qo_pi[t_idx][modality_idx].dot(lnC)
  
      q_pi_valid = maths.softmax(efe_valid * 16.0)
  
      self.assertTrue(np.allclose(efe, efe_valid))
      self.assertTrue(np.allclose(q_pi, q_pi_valid))
  
imports: import os
  import unittest
  import numpy
  from pymdp import utils, maths
  from pymdp import control
label_desc: Use image node_id 7 for calling the TestControl obj's underlying member method code with example usage: obj.test_update_posterior_policies_utility() without return types