$$ \DeclareMathOperator\tr{tr} \DeclareMathOperator\vecOP{vec} \newcommand\di{\mathrm{d}} \newcommand\D{\mathrm{D}} \newcommand\Hess{\mathrm{H}} $$
I do not have much experience with matrix differentials and thus my question is whether my derivation of the observed information matrix is correct.
We consider a single log-likelihood term for a pair $(\vec y_i, \vec x_i)$ in a multivariate normal distribution
\begin{align*} \mathcal L &= - \frac 12 \log \lvert Q \rvert - \frac 12 \tr Q^{-1} (\vec y_i - F^\top \vec x_i)(\vec y_i - F^\top\vec x_i)^\top + \dots \\ &= - \frac 12 \log \lvert Q \rvert - \frac 12 \tr Q^{-1} Z + \dots \\ Z &= (\vec y_i - F^\top \vec x_i)(\vec y_i - F^\top\vec x_i)^\top \end{align*}
The first differential w.r.t. $F$ and $Q$ are
$$\di\mathcal L = \frac 12\tr (\di Q) Q^{-1} (Z - Q)Q^{-1} + \tr Q^{-1}(\vec y_i - F^\top \vec x_i)\vec x_i^\top (\di F) $$
Thus, the derivative is
$$ \D\mathcal L = \left( \vecOP\left(\vec x_i(\vec y_i - F^\top \vec x_i)^\top Q^{-1}\right)^\top, \frac 12\vecOP\left(Q^{-1} (Z - Q)Q^{-1}\right)^\top \right) $$
as in this answer. The second differential is
\begin{align*} \di^2\mathcal L &= \frac 12 \tr (\di Q)(\di Q^{-1})(Z - Q)Q^{-1} + \frac 12 \tr (\di Q)Q^{-1}(\di Z - \di Q)Q^{-1} \\ &\hspace{20pt} + \frac 12 \tr (\di Q)Q^{-1}(Z - Q)(\di Q^{-1}) + \tr (\di Q^{-1})(\vec y_i - F^\top \vec x_i)\vec x_i^\top (\di F) \\ &\hspace{20pt} - \tr Q^{-1}(\di F)^\top \vec x_i \vec x_i^\top (\di F) \\ % % % &= -\frac 12\tr (\di Q)Q^{-1}(\di Q)Q^{-1}(Z - Q)Q^{-1} - \tr (\di Q)Q^{-1}(\vec y_i - F^\top \vec x_i)\vec x_i^\top (\di F)Q^{-1} \\ &\hspace{20pt} - \frac 12 \tr (\di Q)Q^{-1}(\di Q)Q^{-1} - \frac 12 \tr (\di Q)Q^{-1}(Z - Q)Q^{-1}(\di Q)Q^{-1} \\ &\hspace{20pt} - \tr Q^{-1}(\di Q)Q^{-1}(\vec y_i - F^\top \vec x_i)\vec x_i^\top (\di F) - \tr Q^{-1}(\di F)^\top \vec x_i \vec x_i^\top (\di F) \\ % % % &= -\tr (\di Q)Q^{-1}(\di Q)Q^{-1}(Z - \frac 12 Q)Q^{-1} - 2\tr (\di Q)Q^{-1}(\vec y_i - F^\top \vec x_i)\vec x_i^\top (\di F)Q^{-1} \\ &\hspace{20pt} - \tr Q^{-1}(\di F)^\top \vec x_i \vec x_i^\top (\di F) \end{align*}
Thus, the Hessian is
$$ \Hess\mathcal L = \begin{pmatrix} -Q^{-1}\otimes \vec x_i \vec x_i^\top & -Q^{-1} \otimes \left(\vec x_i (\vec y_i - F^\top \vec x_i)^\top Q^{-1}\right) \\ -Q^{-1} \otimes \left(Q^{-1}(\vec y_i - F^\top \vec x_i)\vec x_i^\top \right) & - Q^{-1} \otimes \left(Q^{-1}\left(Z - \frac 12 Q\right)Q^{-1} \right) \end{pmatrix} $$
This code seems to confirm the above
# define parameters
options(digits = 3)
y <- c(-.1, .2)
x <- c(-.5, .25)
Qmat <- matrix(c(1 , .4 , .4, .5), 2)
Fmat <- matrix(c(.8, .2, .1, .5), 2)
library(mvtnorm)
func <- function(vals){
Fmat[] <- vals[1:4]
Qmat[upper.tri(Qmat, diag = TRUE)] <- vals[5:7]
Qmat[lower.tri(Qmat)] <- t(Qmat)[lower.tri(Qmat)]
if(any(abs(eigen(Fmat)$values) >= 1) || any(eigen(Qmat)$values <= 0))
return(NA_real_)
dmvnorm(y, crossprod(Fmat, x), Qmat, log = TRUE)
}
# compute Hessian with numerical differentiation
library(numDeriv)
o <- numDeriv::hessian(func, c(Fmat, Qmat[lower.tri(Qmat, diag = TRUE)]))
# compare block diagonal elements
library( matrixcalc)
D <- duplication.matrix(2L)
Z <- tcrossprod(y - crossprod(Fmat, x))
K <- solve(Qmat)
o[1:4, 1:4] - (- kronecker(K, tcrossprod(x)))
#R [,1] [,2] [,3] [,4]
#R [1,] 3.53e-12 -1.67e-13 -3.71e-12 -5.01e-12
#R [2,] -1.67e-13 8.34e-14 4.46e-11 -6.68e-14
#R [3,] -3.71e-12 4.46e-11 -1.62e-11 -3.34e-13
#R [4,] -5.01e-12 -6.69e-14 -3.34e-13 4.27e-12
lower_diag_block <- -kronecker(K, solve(Qmat, Z %*% K - diag(1/2, 2)))
o[5:7, 5:7] - crossprod(D, lower_diag_block %*% D)
#R [,1] [,2] [,3]
#R [1,] -7.13e-12 8.80e-12 -9.98e-10
#R [2,] 8.80e-12 -1.99e-11 3.09e-11
#R [3,] -9.98e-10 3.09e-11 -4.40e-11
# then the off diagonal blocks
off_block <-
- kronecker(K, tcrossprod(x, y - crossprod(Fmat, x)) %*% K)
o[1:4, 5:7] - off_block %*% D
#R [,1] [,2] [,3]
#R [1,] -2.77e-12 3.81e-12 3.12e-12
#R [2,] 5.49e-12 -9.39e-12 -2.55e-12
#R [3,] 1.12e-11 1.36e-11 4.85e-12
#R [4,] -4.04e-12 3.24e-12 2.33e-12
off_block <-
- kronecker(K, solve(Qmat, tcrossprod(y - crossprod(Fmat, x), x)))
o[5:7, 1:4] - crossprod(D, off_block)
#R [,1] [,2] [,3] [,4]
#R [1,] -2.77e-12 5.49e-12 1.12e-11 -4.04e-12
#R [2,] 3.81e-12 -9.39e-12 1.36e-11 3.24e-12
#R [3,] 3.12e-12 -2.55e-12 4.85e-12 2.33e-12