code: def log_joint(self, x):
          
          T, D = self.T, self.D_latent
          assert x.shape == (T, D)
  
          # prior log p(x) -- quadratic terms
          J_diag, J_upper_diag = self.sparse_J_prior
          lp = -0.5 * np.sum(x * symm_block_tridiag_matmul(J_diag, J_upper_diag, x))
  
          # prior log p(x) -- linear terms
          _, h_init, log_Z_init = self.info_init_params
          _, _, _, h1, h2, log_Z_dyn = self.info_dynamics_params
          lp += x[0].dot(h_init)
          lp += np.sum(x[:-1] * h1)
          lp += np.sum(x[1:] * h2)
  
          # prior log p(x) -- normalization constants
          lp += log_Z_init
          lp += np.sum(log_Z_dyn)
  
          # likelihood log p(y | x)
          lp += self.log_conditional_likelihood(x)
  
          return lp
docs: Compute the log joint probability p(x, y)