code: def spm_cross(x, y=None, *args):
      """Multi-dimensional outer product
  
      Parameters
      ----------
      - `x` [np.ndarray] || [Categorical] (optional)
          The values to perfrom the outer-product with. If empty, then the outer-product
          is taken between x and itself. If y is not empty, then outer product is taken
          between x and the various dimensions of y.
      - `args` [np.ndarray] || [Categorical] (optional)
          Remaining arrays to perform outer-product with. These extra arrays are recursively
          multiplied with the 'initial' outer product (that between X and x).
  
      Returns
      -------
      - `z` [np.ndarray] || [Categorical]
            The result of the outer-product
      """
  
      if len(args) == 0 and y is None:
          if utils.is_obj_array(x):
              z = spm_cross(*list(x))
          elif np.issubdtype(x.dtype, np.number):
              z = x
          else:
              raise ValueError(f"Invalid input to spm_cross ({x})")
          return z
  
      if utils.is_obj_array(x):
          x = spm_cross(*list(x))
  
      if y is not None and utils.is_obj_array(y):
          y = spm_cross(*list(y))
  
      reshape_dims = tuple(
          list(x.shape) + list(np.ones(y.ndim, dtype=int))
      )
      A = x.reshape(reshape_dims)
  
      reshape_dims = tuple(
          list(np.ones(x.ndim, dtype=int)) + list(y.shape)
      )
      B = y.reshape(reshape_dims)
      z = np.squeeze(A * B)
  
      for x in args:
          z = spm_cross(z, x)
      return z
  
imports: import numpy
  from scipy import special
  from pymdp import utils
  from itertools import chain
label_desc: Use image node_id 4 for calling a global function with example usage: spm_cross(x, y) and returns: z, z