code: def spm_MDP_G(A, x):
      """
      Calculates the Bayesian surprise in the same way as spm_MDP_G.m does in
      the original matlab code.
  
      Parameters
      ----------
      A (numpy ndarray or array-object):
          array assigning likelihoods of observations/outcomes under the various
          hidden state configurations
  
      x (numpy ndarray or array-object):
          Categorical distribution presenting probabilities of hidden states
          (this can also be interpreted as the predictive density over hidden
          states/causes if you're calculating the expected Bayesian surprise)
  
      Returns
      -------
      G (float):
          the (expected or not) Bayesian surprise under the density specified by x --
          namely, this scores how much an expected observation would update beliefs
          about hidden states x, were it to be observed.
      """
  
      num_modalities = len(A)
  
      # Probability distribution over the hidden causes: i.e., Q(x)
      qx = spm_cross(x)
      G = 0
      qo = 0
      idx = np.array(np.where(qx > np.exp(-16))).T
  
      if utils.is_obj_array(A):
          # Accumulate expectation of entropy: i.e., E_{Q(o, s)}[lnP(o|x)]
          for i in idx:
              # Probability over outcomes for this combination of causes
              po = np.ones(1)
              for modality_idx, A_m in enumerate(A):
                  index_vector = [slice(0, A_m.shape[0])] + list(i)
                  po = spm_cross(po, A_m[tuple(index_vector)])
  
              po = po.ravel()
              qo += qx[tuple(i)] * po
              G += qx[tuple(i)] * po.dot(np.log(po + np.exp(-16)))
      else:
          for i in idx:
              po = np.ones(1)
              index_vector = [slice(0, A.shape[0])] + list(i)
              po = spm_cross(po, A[tuple(index_vector)])
              po = po.ravel()
              qo += qx[tuple(i)] * po
              G += qx[tuple(i)] * po.dot(np.log(po + np.exp(-16)))
  
      # Subtract negative entropy of expectations: i.e., E_{Q(o)}[lnQ(o)]
      G = G - qo.dot(spm_log_single(qo))  # type: ignore
  
      return G
  
imports: import numpy
  from scipy import special
  from pymdp import utils
  from itertools import chain
label_desc: Use image node_id 18 for calling a global function with example usage: spm_MDP_G(A, x) and returns: G