code: def logdet_symm_block_tridiag(H_diag, H_upper_diag):
      
      T, D, _ = H_diag.shape
      assert H_diag.ndim == 3 and H_diag.shape[2] == D
      assert H_upper_diag.shape == (T - 1, D, D)
  
      J_init = J_11 = J_22 = np.zeros((D, D))
      h_init = h_1 = h_2 = np.zeros((D,))
      log_Z_init = 0
  
      J_21 = np.swapaxes(H_upper_diag, -1, -2)
      log_Z_pair = 0
  
      J_node = H_diag
      h_node = np.zeros((T, D))
      log_Z_node = 0
  
      logZ, _, _ = kalman_info_filter(J_init, h_init, log_Z_init,
                                      J_11, J_21, J_22, h_1, h_2, log_Z_pair,
                                      J_node, h_node, log_Z_node)
  
      # logZ = -1/2 log |J| + n/2 log 2 \pi
      logdetJ = -2 * (logZ - (T*D) / 2 * np.log(2 * np.pi))
      return logdetJ
docs: compute the log determinant of a positive definite,
      symmetric block tridiag matrix.  Use the Kalman
      info filter to do so.  Specifically, the KF computes
      the normalizer:
  
          log Z = 1/2 h^T J^{-1} h -1/2 log |J| +n/2 log 2 \pi
  
      We set h=0 to get -1/2 log |J| + n/2 log 2 \pi and from
      this we solve for log |J|.