[Rd] The C function getQ0 returns a non-positive covariance matrix and causes errors in arima()

Raphael Rossignol raphael.rossignol at math.u-psud.fr
Wed Jul 20 13:54:02 CEST 2011


Hi,

the function makeARIMA(), designed to construct some state space  
representation of an ARIMA model, uses a C function called getQ0,  
which can be found at the end of arima.c in R source files (library  
stats). getQ0 takes two arguments, phi and theta, and returns the  
covariance matrix of the state prediction error at time zero. The  
reference for getQ0 (cited by help(arima)) is:
Gardner, G, Harvey, A. C. and Phillips, G. D. A. (1980) Algorithm
      AS154. An algorithm for exact maximum likelihood estimation of
      autoregressive-moving average models by means of Kalman filtering.
      _Applied Statistics_ *29*, 311-322.
where it is called subroutine STARMA (and coded in fortran 77).

My problem is that getQ0 returns incorrect covariance matrices in  
certain cases. Indeed, below is an example of a  
SARIMA(1,0,1)x(1,0,0)_12 where getQ0 gives a covariance matrix which  
possess negative eigenvalues ! Below, I obtain getQ0 results through  
makeARIMA().
Example:
> s <- 12
> phis <- 0.95
> phi1 <- 0.0001
> phi <- c(phi1,rep(0,s-2),phis,-phi1*phis)
> theta <- 0.7
> out <- makeARIMA(phi,theta,NULL)
> min(eigen(out$Pn)$value)
[1] -19.15890

There are consequences of this "bug" in the functions KalmanLike() and  
arima(). Indeed, arima() in its default behaviour uses first CSS  
method to get the initial value for an MLE search through optim. To  
compute the likelihood, it uses getQ0 at the initialization of the  
Kalman Filter. It may happen that getQ0 returns a covariance matrix  
which possesses negative eigenvalues and that this gives a negative  
gain in the Kalman filter, which in turn gives a likelihood equal to  
NaN. Here is a reproducible example where I forced the use of 'ML'.
> set.seed(1)
> x <- arima.sim(100,model=list(ar=phi,ma=theta))
> KalmanLike(x,mod=out,fast=FALSE)
$Lik
ssq
NaN

$s2
      ssq
0.971436

> arima(x,order=c(1,0,1),seasonal=list(period=12,order=c(1,0,0)),include.mean=FALSE,init=c(phi1,theta,phis),method='ML')
Erreur dans optim(init[mask], armafn, method = optim.method, hessian =  
TRUE,  :
   valeur non-finie fournie par optim

If needed, I can send a more natural example in which the above  
behaviour is obtained. This error message ("Error in optim ...  
non-finite finite-difference value") was already noted in the  
following message, which remained without answer:
https://stat.ethz.ch/pipermail/r-devel/2009-February/052009.html

I could not figure out whether there is a real bug in getQ0 or if this  
is due to some numerical instability. However, I tried to replace  
getQ0 in two ways. The first one is to compute first the covariance  
matrix of (X_{t-1},...,X_{t-p},Z_t,...,Z_{t-q}) and this is achieved  
through the method of difference equations (page 93 of Brockwell and  
Davis). This way was apparently suggested by a referee to Gardner et  
al. paper (see page 314 of their paper).
Q0bis <- function(phi,theta){
   ## Computes the initial covariance matrix for the state space  
representation of Gardner et al.
   p <- length(phi)
   q <- length(theta)
   r <- max(p,q+1)
   ttheta <- c(1,theta,rep(0,max(p,q+1)-q-1))
   A1 <- matrix(0,r,p)
   B <- (col(A1)+row(A1)<=p+1)
   C <- (col(A1)+row(A1)-1)
   A1[B] <- phi[C[B]]
   A2 <- matrix(0,r,q+1)
   C <- (col(A2)+row(A2)-1)
   B <- (C<=q+1)
   A2[B] <- ttheta[C[B]]
   A <- cbind(A1,A2)
   if (p==0) {
     S <- diag(q+1)
   }
   else {
     ## Compute the autocovariance function of U, the AR part of X
     r2 <- max(p+q,p+1)
     tphi <- c(1,-phi)
     C1 <- matrix(0,r2,r2)
     F <- row(C1)-col(C1)+1
     E <- (1<=F)&(F<=p+1)
     C1[E] <- tphi[F[E]]
     C2 <- matrix(0,r2,r2)
     F <- col(C2)+row(C2)-1
     E <- (F<=p+1) & col(C2)>=2
     C2[E] <- tphi[F[E]]
     Gam <- (C1+C2)
     g <- matrix(0,r2,1)
     g[1] <- 1
     rU <- solve(Gam,g)
     SU <- toeplitz(rU[1:(p+q),1])
     ## End of the difference equations method
     ## Then, compute correlation matrix of X
     A2 <- matrix(0,p,p+q)
     C <- col(A2)-row(A2)+1
     B <- (1<=C)&(C<=q+1)
     A2[B] <- ttheta[C[B]]
     SX <- A2%*%SU%*%t(A2)
     ## Now, compute correlation matrix between X and Z
     C1 <- matrix(0,q,q)
     F <- row(C1)-col(C1)+1
     E <- (F>=1) & (F<=p+1)
     C1[E] <- tphi[F[E]]
     g <- matrix(0,q,1)
     if (q) g[1:q,1] <- ttheta[1:q]
     rXZ <- forwardsolve(C1,g)
     SXZ <- matrix(0, p, q+1)
     F <- col(SXZ)-row(SXZ)
     E <- F>=1
     SXZ[E] <- rXZ[F[E]]
     S <- rbind(cbind(SX,SXZ),cbind(t(SXZ),diag(q+1)))
   }
   Q0 <- A%*%S%*%t(A)
}

The second way is to resolve brutally the equation of Gardner et al.  
in the form (12), page 314 of their paper.

Q0ter <- function(phi,theta){
   p <- length(phi)
   q <- length(theta)
   r <- max(p,q+1)
   T <- matrix(0,r,r)
   if (p) T[1:p,1] <- phi
   if (r) T[1:(r-1),2:r] <- diag(r-1)
   V <- matrix(0,r,r)
   ttheta <- c(1,theta)
   V[1:(q+1),1:(q+1)] <- ttheta%x%t(ttheta)
   V <- matrix(V,ncol=1)
   S <- diag(r*r)-T%x%T
   Q0 <- solve(S,V)
   Q0 <- matrix(Q0,ncol=r)
}

My conclusion for now is that these two other ways give the same  
answers (as returned by all.equal) and sometimes different answers  
than getQ0. It may happen that they give a Q0 with negative  
eigenvalues, but they are very very small, and then, the likelihood  
computed by KalmanLike is a number (and not NaN). Here is a function  
allowing to compare the three methods
test <- function(phi,theta){
   out <- makeARIMA(phi,theta,NULL)
   Q0bis <- Q0bis(phi,theta)
   Q0ter <- Q0ter(phi,theta)
   mod <- out
   modbis <- out
   modter <- out
   modbis$Pn <- Q0bis
   modter$Pn <- Q0ter
   set.seed(1)
   x <- arima.sim(100,model=list(ar=phi,ma=theta))
   s <- KalmanLike(x,mod=mod,fast=FALSE)
   sbis <- KalmanLike(x,modbis)
   ster <- KalmanLike(x,modter)
   test12 <- all.equal(out$Pn,Q0bis)
   test13 <- all.equal(out$Pn,Q0ter)
   test23 <- all.equal(Q0bis,Q0ter)
    
list(eigen=min(eigen(out$Pn)$value),eigenbis=min(eigen(Q0bis)$value),eigenter=min(eigen(Q0ter)$value),test12=test12,test13=test13,test23=test23,s=s,sbis=sbis,ster=ster)
}

And the test on the values of phi and theta above:
> test(phi,theta)
$eigen
[1] -19.15890

$eigenbis
[1] -9.680598e-23

$eigenter
[1] 1.859864e-23

$test12
[1] "Mean relative difference: 0.4255719"

$test13
[1] "Mean relative difference: 0.4255724"

$test23
[1] TRUE

$s
$s$Lik
ssq
NaN

$s$s2
      ssq
0.971436


$sbis
$sbis$Lik
       ssq
0.1322859

$sbis$s2
       ssq
0.9789775


$ster
$ster$Lik
       ssq
0.1322859

$ster$s2
       ssq
0.9789775



Here are my questions:
1) Does someone understand this strange behaviour of Q0 ?
2) Should I report this as a bug ?

By the way, Q0bis is only twice slower than makeARIMA() (but it is not  
optimised), and Q0ter is 50 times slower than Q0bis.

For information:
> sessionInfo()

R version 2.10.1 (2009-12-14)
x86_64-pc-linux-gnu

locale:
  [1] LC_CTYPE=fr_FR.utf8       LC_NUMERIC=C
  [3] LC_TIME=fr_FR.utf8        LC_COLLATE=fr_FR.utf8
  [5] LC_MONETARY=C             LC_MESSAGES=fr_FR.utf8
  [7] LC_PAPER=fr_FR.utf8       LC_NAME=C
  [9] LC_ADDRESS=C              LC_TELEPHONE=C
[11] LC_MEASUREMENT=fr_FR.utf8 LC_IDENTIFICATION=C

attached base packages:
[1] stats     graphics  grDevices utils     datasets  methods   base


Best,

Raphael Rossignol

--
Assistant Professor of Mathematics
Univ. Paris-Sud 11



More information about the R-devel mailing list