docstr: Test for the expected utility function, for a simple single factor generative model 
  where there are imbalances in the preferences for different outcomes. Test for both single
  timestep policy horizons and multiple timestep policy horizons (planning)
docstr_tok: ["Test","for","the","expected","utility","function",",","for","a","simple","single","factor","generative","model","where","there","are","imbalances","in","the","preferences","for","different","outcomes",".","Test","for","both","single","timestep","policy","horizons","and","multiple","timestep","policy","horizons","(","planning",")"]
code: def test_expected_utility(self):
      """
      Test for the expected utility function, for a simple single factor generative model
      where there are imbalances in the preferences for different outcomes. Test for both single
      timestep policy horizons and multiple timestep policy horizons (planning)
      """
  
      """1-step policies"""
      num_states = [2]
      num_controls = [2]
  
      qs = utils.random_single_categorical(num_states)
      B = utils.construct_controllable_B(num_states, num_controls)
  
      # Single timestep
      n_step = 1
      policies = control.construct_policies(
          num_states, num_controls, policy_len=n_step
      )
  
      # Single observation modality
      num_obs = [2]
  
      # Create noiseless identity A matrix
      A = utils.to_obj_array(np.eye(num_obs[0]))
  
      # Create imbalance in preferences for observations
      C = utils.to_obj_array(utils.onehot(1, num_obs[0]))
  
      # Compute expected utility of policies
      expected_utilities = 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)
          expected_utilities[idx] += control.calc_expected_utility(
              qo_pi, C
          )
  
      self.assertGreater(expected_utilities[1], expected_utilities[0])
  
      """3-step policies"""
      # One policy entails going to state 0 two times in a row, and then state 2 at the end
      # Another policy entails going to state 1 three times in a row
  
      num_states = [3]
      num_controls = [3]
  
      qs = utils.random_single_categorical(num_states)
      B = utils.construct_controllable_B(num_states, num_controls)
  
      policies = [
          np.array([0, 0, 2]).reshape(-1, 1),
          np.array([1, 1, 1]).reshape(-1, 1),
      ]
  
      # single observation modality
      num_obs = [3]
  
      # create noiseless identity A matrix
      A = utils.to_obj_array(np.eye(num_obs[0]))
  
      # create imbalance in preferences for observations
      # This test is designed to illustrate the emergence of planning by
      # using the time-integral of the expected free energy.
      # Even though the first observation (index 0) is the most preferred, the policy
      # that frequents this observation the most is actually not optimal, because that policy
      # terminates in a less preferred state by timestep 3.
      C = utils.to_obj_array(np.array([1.2, 1.0, 0.55]))
  
      expected_utilities = 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)
          expected_utilities[idx] += control.calc_expected_utility(
              qo_pi, C
          )
  
      self.assertGreater(expected_utilities[1], expected_utilities[0])
  
imports: import os
  import unittest
  import numpy
  from pymdp import utils, maths
  from pymdp import control
label_desc: Use image node_id 3 for calling the TestControl obj's underlying member method code with example usage: obj.test_expected_utility() without return types