/* * R : A Computer Language for Statistical Data Analysis * Copyright (C) 2002-2016 The R Core Team. * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation; either version 2 of the License, or * (at your option) any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program; if not, a copy is available at * https://www.R-project.org/Licenses/ */ #ifdef HAVE_CONFIG_H # include #endif #include // for abs #include #include #include "ts.h" #include "statsR.h" // for getListElement #ifndef max #define max(a,b) ((a < b)?(b):(a)) #endif #ifndef min #define min(a,b) ((a < b)?(a):(b)) #endif /* KalmanLike, internal to StructTS: .Call(C_KalmanLike, y, mod$Z, mod$a, mod$P, mod$T, mod$V, mod$h, mod$Pn, nit, FALSE, update) KalmanRun: .Call(C_KalmanLike, y, mod$Z, mod$a, mod$P, mod$T, mod$V, mod$h, mod$Pn, nit, TRUE, update) */ /* y vector length n of observations Z vector length p for observation equation y_t = Za_t + eps_t a vector length p of initial state P p x p matrix for initial state uncertainty (contemparaneous) T p x p transition matrix V p x p = RQR' h = var(eps_t) anew used for a[t|t-1] Pnew used for P[t|t -1] M used for M = P[t|t -1]Z op is FALSE for KalmanLike, TRUE for KalmanRun. The latter computes residuals and states and has a more elaborate return value. Almost no checking here! */ SEXP KalmanLike(SEXP sy, SEXP mod, SEXP sUP, SEXP op, SEXP update) { int lop = asLogical(op); mod = PROTECT(duplicate(mod)); SEXP sZ = getListElement(mod, "Z"), sa = getListElement(mod, "a"), sP = getListElement(mod, "P"), sT = getListElement(mod, "T"), sV = getListElement(mod, "V"), sh = getListElement(mod, "h"), sPn = getListElement(mod, "Pn"); if (TYPEOF(sy) != REALSXP || TYPEOF(sZ) != REALSXP || TYPEOF(sa) != REALSXP || TYPEOF(sP) != REALSXP || TYPEOF(sPn) != REALSXP || TYPEOF(sT) != REALSXP || TYPEOF(sV) != REALSXP) error(_("invalid argument type")); int n = LENGTH(sy), p = LENGTH(sa); double *y = REAL(sy), *Z = REAL(sZ), *T = REAL(sT), *V = REAL(sV), *P = REAL(sP), *a = REAL(sa), *Pnew = REAL(sPn), h = asReal(sh); double *anew = (double *) R_alloc(p, sizeof(double)); double *M = (double *) R_alloc(p, sizeof(double)); double *mm = (double *) R_alloc(p * p, sizeof(double)); // These are only used if(lop), but avoid -Wall trouble SEXP ans = R_NilValue, resid = R_NilValue, states = R_NilValue; if(lop) { PROTECT(ans = allocVector(VECSXP, 3)); SET_VECTOR_ELT(ans, 1, resid = allocVector(REALSXP, n)); SET_VECTOR_ELT(ans, 2, states = allocMatrix(REALSXP, n, p)); SEXP nm = PROTECT(allocVector(STRSXP, 3)); SET_STRING_ELT(nm, 0, mkChar("values")); SET_STRING_ELT(nm, 1, mkChar("resid")); SET_STRING_ELT(nm, 2, mkChar("states")); setAttrib(ans, R_NamesSymbol, nm); UNPROTECT(1); } double sumlog = 0.0, ssq = 0.0; int nu = 0; for (int l = 0; l < n; l++) { for (int i = 0; i < p; i++) { double tmp = 0.0; for (int k = 0; k < p; k++) tmp += T[i + p * k] * a[k]; anew[i] = tmp; } if (l > asInteger(sUP)) { for (int i = 0; i < p; i++) for (int j = 0; j < p; j++) { double tmp = 0.0; for (int k = 0; k < p; k++) tmp += T[i + p * k] * P[k + p * j]; mm[i + p * j] = tmp; } for (int i = 0; i < p; i++) for (int j = 0; j < p; j++) { double tmp = V[i + p * j]; for (int k = 0; k < p; k++) tmp += mm[i + p * k] * T[j + p * k]; Pnew[i + p * j] = tmp; } } if (!ISNAN(y[l])) { nu++; double *rr = NULL /* -Wall */; if(lop) rr = REAL(resid); double resid0 = y[l]; for (int i = 0; i < p; i++) resid0 -= Z[i] * anew[i]; double gain = h; for (int i = 0; i < p; i++) { double tmp = 0.0; for (int j = 0; j < p; j++) tmp += Pnew[i + j * p] * Z[j]; M[i] = tmp; gain += Z[i] * M[i]; } ssq += resid0 * resid0 / gain; if(lop) rr[l] = resid0 / sqrt(gain); sumlog += log(gain); for (int i = 0; i < p; i++) a[i] = anew[i] + M[i] * resid0 / gain; for (int i = 0; i < p; i++) for (int j = 0; j < p; j++) P[i + j * p] = Pnew[i + j * p] - M[i] * M[j] / gain; } else { double *rr = NULL /* -Wall */; if(lop) rr = REAL(resid); for (int i = 0; i < p; i++) a[i] = anew[i]; for (int i = 0; i < p * p; i++) P[i] = Pnew[i]; if(lop) rr[l] = NA_REAL; } if(lop) { double *rs = REAL(states); for (int j = 0; j < p; j++) rs[l + n*j] = a[j]; } } SEXP res = PROTECT(allocVector(REALSXP, 2)); REAL(res)[0] = ssq/nu; REAL(res)[1] = sumlog/nu; if(lop) { SET_VECTOR_ELT(ans, 0, res); if(asLogical(update)) setAttrib(ans, install("mod"), mod); UNPROTECT(3); return ans; } else { if(asLogical(update)) setAttrib(res, install("mod"), mod); UNPROTECT(2); return res; } } SEXP KalmanSmooth(SEXP sy, SEXP mod, SEXP sUP) { SEXP sZ = getListElement(mod, "Z"), sa = getListElement(mod, "a"), sP = getListElement(mod, "P"), sT = getListElement(mod, "T"), sV = getListElement(mod, "V"), sh = getListElement(mod, "h"), sPn = getListElement(mod, "Pn"); if (TYPEOF(sy) != REALSXP || TYPEOF(sZ) != REALSXP || TYPEOF(sa) != REALSXP || TYPEOF(sP) != REALSXP || TYPEOF(sT) != REALSXP || TYPEOF(sV) != REALSXP) error(_("invalid argument type")); SEXP ssa, ssP, ssPn, res, states = R_NilValue, sN; int n = LENGTH(sy), p = LENGTH(sa); double *y = REAL(sy), *Z = REAL(sZ), *a, *P, *T = REAL(sT), *V = REAL(sV), h = asReal(sh), *Pnew; double *at, *rt, *Pt, *gains, *resids, *Mt, *L, gn, *Nt; Rboolean var = TRUE; PROTECT(ssa = duplicate(sa)); a = REAL(ssa); PROTECT(ssP = duplicate(sP)); P = REAL(ssP); PROTECT(ssPn = duplicate(sPn)); Pnew = REAL(ssPn); PROTECT(res = allocVector(VECSXP, 2)); SEXP nm = PROTECT(allocVector(STRSXP, 2)); SET_STRING_ELT(nm, 0, mkChar("smooth")); SET_STRING_ELT(nm, 1, mkChar("var")); setAttrib(res, R_NamesSymbol, nm); UNPROTECT(1); SET_VECTOR_ELT(res, 0, states = allocMatrix(REALSXP, n, p)); at = REAL(states); SET_VECTOR_ELT(res, 1, sN = allocVector(REALSXP, n*p*p)); Nt = REAL(sN); double *anew, *mm, *M; anew = (double *) R_alloc(p, sizeof(double)); M = (double *) R_alloc(p, sizeof(double)); mm = (double *) R_alloc(p * p, sizeof(double)); Pt = (double *) R_alloc(n * p * p, sizeof(double)); gains = (double *) R_alloc(n, sizeof(double)); resids = (double *) R_alloc(n, sizeof(double)); Mt = (double *) R_alloc(n * p, sizeof(double)); L = (double *) R_alloc(p * p, sizeof(double)); for (int l = 0; l < n; l++) { for (int i = 0; i < p; i++) { double tmp = 0.0; for (int k = 0; k < p; k++) tmp += T[i + p * k] * a[k]; anew[i] = tmp; } if (l > asInteger(sUP)) { for (int i = 0; i < p; i++) for (int j = 0; j < p; j++) { double tmp = 0.0; for (int k = 0; k < p; k++) tmp += T[i + p * k] * P[k + p * j]; mm[i + p * j] = tmp; } for (int i = 0; i < p; i++) for (int j = 0; j < p; j++) { double tmp = V[i + p * j]; for (int k = 0; k < p; k++) tmp += mm[i + p * k] * T[j + p * k]; Pnew[i + p * j] = tmp; } } for (int i = 0; i < p; i++) at[l + n*i] = anew[i]; for (int i = 0; i < p*p; i++) Pt[l + n*i] = Pnew[i]; if (!ISNAN(y[l])) { double resid0 = y[l]; for (int i = 0; i < p; i++) resid0 -= Z[i] * anew[i]; double gain = h; for (int i = 0; i < p; i++) { double tmp = 0.0; for (int j = 0; j < p; j++) tmp += Pnew[i + j * p] * Z[j]; Mt[l + n*i] = M[i] = tmp; gain += Z[i] * M[i]; } gains[l] = gain; resids[l] = resid0; for (int i = 0; i < p; i++) a[i] = anew[i] + M[i] * resid0 / gain; for (int i = 0; i < p; i++) for (int j = 0; j < p; j++) P[i + j * p] = Pnew[i + j * p] - M[i] * M[j] / gain; } else { for (int i = 0; i < p; i++) { a[i] = anew[i]; Mt[l + n * i] = 0.0; } for (int i = 0; i < p * p; i++) P[i] = Pnew[i]; gains[l] = NA_REAL; resids[l] = NA_REAL; } } /* rt stores r_{t-1} */ rt = (double *) R_alloc(n * p, sizeof(double)); for (int l = n - 1; l >= 0; l--) { if (!ISNAN(gains[l])) { gn = 1/gains[l]; for (int i = 0; i < p; i++) rt[l + n * i] = Z[i] * resids[l] * gn; } else { for (int i = 0; i < p; i++) rt[l + n * i] = 0.0; gn = 0.0; } if (var) { for (int i = 0; i < p; i++) for (int j = 0; j < p; j++) Nt[l + n*i + n*p*j] = Z[i] * Z[j] * gn; } if (l < n - 1) { /* compute r_{t-1} */ for (int i = 0; i < p; i++) for (int j = 0; j < p; j++) mm[i + p * j] = ((i==j) ? 1:0) - Mt[l + n * i] * Z[j] * gn; for (int i = 0; i < p; i++) for (int j = 0; j < p; j++) { double tmp = 0.0; for (int k = 0; k < p; k++) tmp += T[i + p * k] * mm[k + p * j]; L[i + p * j] = tmp; } for (int i = 0; i < p; i++) { double tmp = 0.0; for (int j = 0; j < p; j++) tmp += L[j + p * i] * rt[l + 1 + n * j]; rt[l + n * i] += tmp; } if(var) { /* compute N_{t-1} */ for (int i = 0; i < p; i++) for (int j = 0; j < p; j++) { double tmp = 0.0; for (int k = 0; k < p; k++) tmp += L[k + p * i] * Nt[l + 1 + n*k + n*p*j]; mm[i + p * j] = tmp; } for (int i = 0; i < p; i++) for (int j = 0; j < p; j++) { double tmp = 0.0; for (int k = 0; k < p; k++) tmp += mm[i + p * k] * L[k + p * j]; Nt[l + n*i + n*p*j] += tmp; } } } for (int i = 0; i < p; i++) { double tmp = 0.0; for (int j = 0; j < p; j++) tmp += Pt[l + n*i + n*p*j] * rt[l + n * j]; at[l + n*i] += tmp; } } if (var) for (int l = 0; l < n; l++) { for (int i = 0; i < p; i++) for (int j = 0; j < p; j++) { double tmp = 0.0; for (int k = 0; k < p; k++) tmp += Pt[l + n*i + n*p*k] * Nt[l + n*k + n*p*j]; mm[i + p * j] = tmp; } for (int i = 0; i < p; i++) for (int j = 0; j < p; j++) { double tmp = Pt[l + n*i + n*p*j]; for (int k = 0; k < p; k++) tmp -= mm[i + p * k] * Pt[l + n*k + n*p*j]; Nt[l + n*i + n*p*j] = tmp; } } UNPROTECT(4); return res; } SEXP KalmanFore(SEXP nahead, SEXP mod, SEXP update) { mod = PROTECT(duplicate(mod)); SEXP sZ = getListElement(mod, "Z"), sa = getListElement(mod, "a"), sP = getListElement(mod, "P"), sT = getListElement(mod, "T"), sV = getListElement(mod, "V"), sh = getListElement(mod, "h"); if (TYPEOF(sZ) != REALSXP || TYPEOF(sa) != REALSXP || TYPEOF(sP) != REALSXP || TYPEOF(sT) != REALSXP || TYPEOF(sV) != REALSXP) error(_("invalid argument type")); int n = asInteger(nahead), p = LENGTH(sa); double *Z = REAL(sZ), *a = REAL(sa), *P = REAL(sP), *T = REAL(sT), *V = REAL(sV), h = asReal(sh); double *mm, *anew, *Pnew; anew = (double *) R_alloc(p, sizeof(double)); Pnew = (double *) R_alloc(p * p, sizeof(double)); mm = (double *) R_alloc(p * p, sizeof(double)); SEXP res, forecasts, se; PROTECT(res = allocVector(VECSXP, 2)); SET_VECTOR_ELT(res, 0, forecasts = allocVector(REALSXP, n)); SET_VECTOR_ELT(res, 1, se = allocVector(REALSXP, n)); { SEXP nm = PROTECT(allocVector(STRSXP, 2)); SET_STRING_ELT(nm, 0, mkChar("pred")); SET_STRING_ELT(nm, 1, mkChar("var")); setAttrib(res, R_NamesSymbol, nm); UNPROTECT(1); } for (int l = 0; l < n; l++) { double fc = 0.0; for (int i = 0; i < p; i++) { double tmp = 0.0; for (int k = 0; k < p; k++) tmp += T[i + p * k] * a[k]; anew[i] = tmp; fc += tmp * Z[i]; } for (int i = 0; i < p; i++) a[i] = anew[i]; REAL(forecasts)[l] = fc; for (int i = 0; i < p; i++) for (int j = 0; j < p; j++) { double tmp = 0.0; for (int k = 0; k < p; k++) tmp += T[i + p * k] * P[k + p * j]; mm[i + p * j] = tmp; } for (int i = 0; i < p; i++) for (int j = 0; j < p; j++) { double tmp = V[i + p * j]; for (int k = 0; k < p; k++) tmp += mm[i + p * k] * T[j + p * k]; Pnew[i + p * j] = tmp; } double tmp = h; for (int i = 0; i < p; i++) for (int j = 0; j < p; j++) { P[i + j * p] = Pnew[i + j * p]; tmp += Z[i] * Z[j] * P[i + j * p]; } REAL(se)[l] = tmp; } if(asLogical(update)) setAttrib(res, install("mod"), mod); UNPROTECT(2); return res; } static void partrans(int p, double *raw, double *new) { int j, k; double a, work[100]; if(p > 100) error(_("can only transform 100 pars in arima0")); /* Step one: map (-Inf, Inf) to (-1, 1) via tanh The parameters are now the pacf phi_{kk} */ for(j = 0; j < p; j++) work[j] = new[j] = tanh(raw[j]); /* Step two: run the Durbin-Levinson recursions to find phi_{j.}, j = 2, ..., p and phi_{p.} are the autoregression coefficients */ for(j = 1; j < p; j++) { a = new[j]; for(k = 0; k < j; k++) work[k] -= a * new[j - k - 1]; for(k = 0; k < j; k++) new[k] = work[k]; } } SEXP ARIMA_undoPars(SEXP sin, SEXP sarma) { int *arma = INTEGER(sarma), mp = arma[0], mq = arma[1], msp = arma[2], v, n = LENGTH(sin); double *params, *in = REAL(sin); SEXP res = allocVector(REALSXP, n); params = REAL(res); for (int i = 0; i < n; i++) params[i] = in[i]; if (mp > 0) partrans(mp, in, params); v = mp + mq; if (msp > 0) partrans(msp, in + v, params + v); return res; } SEXP ARIMA_transPars(SEXP sin, SEXP sarma, SEXP strans) { int *arma = INTEGER(sarma), trans = asLogical(strans); int mp = arma[0], mq = arma[1], msp = arma[2], msq = arma[3], ns = arma[4], i, j, p = mp + ns * msp, q = mq + ns * msq, v; double *in = REAL(sin), *params = REAL(sin), *phi, *theta; SEXP res, sPhi, sTheta; PROTECT(res = allocVector(VECSXP, 2)); SET_VECTOR_ELT(res, 0, sPhi = allocVector(REALSXP, p)); SET_VECTOR_ELT(res, 1, sTheta = allocVector(REALSXP, q)); phi = REAL(sPhi); theta = REAL(sTheta); if (trans) { int n = mp + mq + msp + msq; params = (double *) R_alloc(n, sizeof(double)); for (i = 0; i < n; i++) params[i] = in[i]; if (mp > 0) partrans(mp, in, params); v = mp + mq; if (msp > 0) partrans(msp, in + v, params + v); } if (ns > 0) { /* expand out seasonal ARMA models */ for (i = 0; i < mp; i++) phi[i] = params[i]; for (i = 0; i < mq; i++) theta[i] = params[i + mp]; for (i = mp; i < p; i++) phi[i] = 0.0; for (i = mq; i < q; i++) theta[i] = 0.0; for (j = 0; j < msp; j++) { phi[(j + 1) * ns - 1] += params[j + mp + mq]; for (i = 0; i < mp; i++) phi[(j + 1) * ns + i] -= params[i] * params[j + mp + mq]; } for (j = 0; j < msq; j++) { theta[(j + 1) * ns - 1] += params[j + mp + mq + msp]; for (i = 0; i < mq; i++) theta[(j + 1) * ns + i] += params[i + mp] * params[j + mp + mq + msp]; } } else { for (i = 0; i < mp; i++) phi[i] = params[i]; for (i = 0; i < mq; i++) theta[i] = params[i + mp]; } UNPROTECT(1); return res; } #if !defined(atanh) && defined(HAVE_DECL_ATANH) && !HAVE_DECL_ATANH extern double atanh(double x); #endif static void invpartrans(int p, double *phi, double *new) { int j, k; double a, work[100]; if(p > 100) error(_("can only transform 100 pars in arima0")); for(j = 0; j < p; j++) work[j] = new[j] = phi[j]; /* Run the Durbin-Levinson recursions backwards to find the PACF phi_{j.} from the autoregression coefficients */ for(j = p - 1; j > 0; j--) { a = new[j]; for(k = 0; k < j; k++) work[k] = (new[k] + a * new[j - k - 1]) / (1 - a * a); for(k = 0; k < j; k++) new[k] = work[k]; } for(j = 0; j < p; j++) new[j] = atanh(new[j]); } SEXP ARIMA_Invtrans(SEXP in, SEXP sarma) { int *arma = INTEGER(sarma), mp = arma[0], mq = arma[1], msp = arma[2], i, v, n = LENGTH(in); SEXP y = allocVector(REALSXP, n); double *raw = REAL(in), *new = REAL(y); for(i = 0; i < n; i++) new[i] = raw[i]; if (mp > 0) invpartrans(mp, raw, new); v = mp + mq; if (msp > 0) invpartrans(msp, raw + v, new + v); return y; } #define eps 1e-3 SEXP ARIMA_Gradtrans(SEXP in, SEXP sarma) { int *arma = INTEGER(sarma), mp = arma[0], mq = arma[1], msp = arma[2], n = LENGTH(in); SEXP y = allocMatrix(REALSXP, n, n); double *raw = REAL(in), *A = REAL(y), w1[100], w2[100], w3[100]; for (int i = 0; i < n; i++) for (int j = 0; j < n; j++) A[i + j*n] = (i == j); if(mp > 0) { for (int i = 0; i < mp; i++) w1[i] = raw[i]; partrans(mp, w1, w2); for (int i = 0; i < mp; i++) { w1[i] += eps; partrans(mp, w1, w3); for (int j = 0; j < mp; j++) A[i + j*n] = (w3[j] - w2[j])/eps; w1[i] -= eps; } } if(msp > 0) { int v = mp + mq; for (int i = 0; i < msp; i++) w1[i] = raw[i + v]; partrans(msp, w1, w2); for(int i = 0; i < msp; i++) { w1[i] += eps; partrans(msp, w1, w3); for(int j = 0; j < msp; j++) A[i + v + (j+v)*n] = (w3[j] - w2[j])/eps; w1[i] -= eps; } } return y; } SEXP ARIMA_Like(SEXP sy, SEXP mod, SEXP sUP, SEXP giveResid) { SEXP sPhi = getListElement(mod, "phi"), sTheta = getListElement(mod, "theta"), sDelta = getListElement(mod, "Delta"), sa = getListElement(mod, "a"), sP = getListElement(mod, "P"), sPn = getListElement(mod, "Pn"); if (TYPEOF(sPhi) != REALSXP || TYPEOF(sTheta) != REALSXP || TYPEOF(sDelta) != REALSXP || TYPEOF(sa) != REALSXP || TYPEOF(sP) != REALSXP || TYPEOF(sPn) != REALSXP) error(_("invalid argument type")); SEXP res, nres, sResid = R_NilValue; int n = LENGTH(sy), rd = LENGTH(sa), p = LENGTH(sPhi), q = LENGTH(sTheta), d = LENGTH(sDelta), r = rd - d; double *y = REAL(sy), *a = REAL(sa), *P = REAL(sP), *Pnew = REAL(sPn); double *phi = REAL(sPhi), *theta = REAL(sTheta), *delta = REAL(sDelta); double sumlog = 0.0, ssq = 0, *anew, *mm = NULL, *M; int nu = 0; Rboolean useResid = asLogical(giveResid); double *rsResid = NULL /* -Wall */; anew = (double *) R_alloc(rd, sizeof(double)); M = (double *) R_alloc(rd, sizeof(double)); if (d > 0) mm = (double *) R_alloc(rd * rd, sizeof(double)); if (useResid) { PROTECT(sResid = allocVector(REALSXP, n)); rsResid = REAL(sResid); } for (int l = 0; l < n; l++) { for (int i = 0; i < r; i++) { double tmp = (i < r - 1) ? a[i + 1] : 0.0; if (i < p) tmp += phi[i] * a[0]; anew[i] = tmp; } if (d > 0) { for (int i = r + 1; i < rd; i++) anew[i] = a[i - 1]; double tmp = a[0]; for (int i = 0; i < d; i++) tmp += delta[i] * a[r + i]; anew[r] = tmp; } if (l > asInteger(sUP)) { if (d == 0) { for (int i = 0; i < r; i++) { double vi = 0.0; if (i == 0) vi = 1.0; else if (i - 1 < q) vi = theta[i - 1]; for (int j = 0; j < r; j++) { double tmp = 0.0; if (j == 0) tmp = vi; else if (j - 1 < q) tmp = vi * theta[j - 1]; if (i < p && j < p) tmp += phi[i] * phi[j] * P[0]; if (i < r - 1 && j < r - 1) tmp += P[i + 1 + r * (j + 1)]; if (i < p && j < r - 1) tmp += phi[i] * P[j + 1]; if (j < p && i < r - 1) tmp += phi[j] * P[i + 1]; Pnew[i + r * j] = tmp; } } } else { /* mm = TP */ for (int i = 0; i < r; i++) for (int j = 0; j < rd; j++) { double tmp = 0.0; if (i < p) tmp += phi[i] * P[rd * j]; if (i < r - 1) tmp += P[i + 1 + rd * j]; mm[i + rd * j] = tmp; } for (int j = 0; j < rd; j++) { double tmp = P[rd * j]; for (int k = 0; k < d; k++) tmp += delta[k] * P[r + k + rd * j]; mm[r + rd * j] = tmp; } for (int i = 1; i < d; i++) for (int j = 0; j < rd; j++) mm[r + i + rd * j] = P[r + i - 1 + rd * j]; /* Pnew = mmT' */ for (int i = 0; i < r; i++) for (int j = 0; j < rd; j++) { double tmp = 0.0; if (i < p) tmp += phi[i] * mm[j]; if (i < r - 1) tmp += mm[rd * (i + 1) + j]; Pnew[j + rd * i] = tmp; } for (int j = 0; j < rd; j++) { double tmp = mm[j]; for (int k = 0; k < d; k++) tmp += delta[k] * mm[rd * (r + k) + j]; Pnew[rd * r + j] = tmp; } for (int i = 1; i < d; i++) for (int j = 0; j < rd; j++) Pnew[rd * (r + i) + j] = mm[rd * (r + i - 1) + j]; /* Pnew <- Pnew + (1 theta) %o% (1 theta) */ for (int i = 0; i <= q; i++) { double vi = (i == 0) ? 1. : theta[i - 1]; for (int j = 0; j <= q; j++) Pnew[i + rd * j] += vi * ((j == 0) ? 1. : theta[j - 1]); } } } if (!ISNAN(y[l])) { double resid = y[l] - anew[0]; for (int i = 0; i < d; i++) resid -= delta[i] * anew[r + i]; for (int i = 0; i < rd; i++) { double tmp = Pnew[i]; for (int j = 0; j < d; j++) tmp += Pnew[i + (r + j) * rd] * delta[j]; M[i] = tmp; } double gain = M[0]; for (int j = 0; j < d; j++) gain += delta[j] * M[r + j]; if(gain < 1e4) { nu++; ssq += resid * resid / gain; sumlog += log(gain); } if (useResid) rsResid[l] = resid / sqrt(gain); for (int i = 0; i < rd; i++) a[i] = anew[i] + M[i] * resid / gain; for (int i = 0; i < rd; i++) for (int j = 0; j < rd; j++) P[i + j * rd] = Pnew[i + j * rd] - M[i] * M[j] / gain; } else { for (int i = 0; i < rd; i++) a[i] = anew[i]; for (int i = 0; i < rd * rd; i++) P[i] = Pnew[i]; if (useResid) rsResid[l] = NA_REAL; } } if (useResid) { PROTECT(res = allocVector(VECSXP, 3)); SET_VECTOR_ELT(res, 0, nres = allocVector(REALSXP, 3)); REAL(nres)[0] = ssq; REAL(nres)[1] = sumlog; REAL(nres)[2] = (double) nu; SET_VECTOR_ELT(res, 1, sResid); UNPROTECT(2); return res; } else { nres = allocVector(REALSXP, 3); REAL(nres)[0] = ssq; REAL(nres)[1] = sumlog; REAL(nres)[2] = (double) nu; return nres; } } /* do differencing here */ /* arma is p, q, sp, sq, ns, d, sd */ SEXP ARIMA_CSS(SEXP sy, SEXP sarma, SEXP sPhi, SEXP sTheta, SEXP sncond, SEXP giveResid) { SEXP res, sResid = R_NilValue; double ssq = 0.0, *y = REAL(sy), tmp; double *phi = REAL(sPhi), *theta = REAL(sTheta), *w, *resid; int n = LENGTH(sy), *arma = INTEGER(sarma), p = LENGTH(sPhi), q = LENGTH(sTheta), ncond = asInteger(sncond); int ns, nu = 0; Rboolean useResid = asLogical(giveResid); w = (double *) R_alloc(n, sizeof(double)); for (int l = 0; l < n; l++) w[l] = y[l]; for (int i = 0; i < arma[5]; i++) for (int l = n - 1; l > 0; l--) w[l] -= w[l - 1]; ns = arma[4]; for (int i = 0; i < arma[6]; i++) for (int l = n - 1; l >= ns; l--) w[l] -= w[l - ns]; PROTECT(sResid = allocVector(REALSXP, n)); resid = REAL(sResid); if (useResid) for (int l = 0; l < ncond; l++) resid[l] = 0; for (int l = ncond; l < n; l++) { tmp = w[l]; for (int j = 0; j < p; j++) tmp -= phi[j] * w[l - j - 1]; for (int j = 0; j < min(l - ncond, q); j++) tmp -= theta[j] * resid[l - j - 1]; resid[l] = tmp; if (!ISNAN(tmp)) { nu++; ssq += tmp * tmp; } } if (useResid) { PROTECT(res = allocVector(VECSXP, 2)); SET_VECTOR_ELT(res, 0, ScalarReal(ssq / (double) (nu))); SET_VECTOR_ELT(res, 1, sResid); UNPROTECT(2); return res; } else { UNPROTECT(1); return ScalarReal(ssq / (double) (nu)); } } SEXP TSconv(SEXP a, SEXP b) { int na, nb, nab; SEXP ab; double *ra, *rb, *rab; PROTECT(a = coerceVector(a, REALSXP)); PROTECT(b = coerceVector(b, REALSXP)); na = LENGTH(a); nb = LENGTH(b); nab = na + nb - 1; PROTECT(ab = allocVector(REALSXP, nab)); ra = REAL(a); rb = REAL(b); rab = REAL(ab); for (int i = 0; i < nab; i++) rab[i] = 0.0; for (int i = 0; i < na; i++) for (int j = 0; j < nb; j++) rab[i + j] += ra[i] * rb[j]; UNPROTECT(3); return (ab); } /* based on code from AS154 */ static void inclu2(size_t np, double *xnext, double *xrow, double ynext, double *d, double *rbar, double *thetab) { double cbar, sbar, di, xi, xk, rbthis, dpi; size_t i, k, ithisr; /* This subroutine updates d, rbar, thetab by the inclusion of xnext and ynext. */ for (i = 0; i < np; i++) xrow[i] = xnext[i]; for (ithisr = 0, i = 0; i < np; i++) { if (xrow[i] != 0.0) { xi = xrow[i]; di = d[i]; dpi = di + xi * xi; d[i] = dpi; cbar = di / dpi; sbar = xi / dpi; for (k = i + 1; k < np; k++) { xk = xrow[k]; rbthis = rbar[ithisr]; xrow[k] = xk - xi * rbthis; rbar[ithisr++] = cbar * rbthis + sbar * xk; } xk = ynext; ynext = xk - xi * thetab[i]; thetab[i] = cbar * thetab[i] + sbar * xk; if (di == 0.0) return; } else ithisr = ithisr + np - i - 1; } } #ifdef DEBUG_Q0bis # include double chk_V(double v[], char* nm, int jj, int len) { // len = length() <==> index must be in {0, len-1} if(jj < 0 || jj >= len) REprintf(" %s[%2d]\n", nm, jj); return(v[jj]); } #endif /* Matwey V. Kornilov's implementation of algorithm by Dr. Raphael Rossignol See https://bugs.r-project.org/show_bug.cgi?id=14682 for details. */ SEXP getQ0bis(SEXP sPhi, SEXP sTheta, SEXP sTol) { SEXP res; int p = LENGTH(sPhi), q = LENGTH(sTheta); double *phi = REAL(sPhi), *theta = REAL(sTheta); // tol = REAL(sTol)[0]; int i,j, r = max(p, q + 1); /* Final result is block product * Q0 = A1 SX A1^T + A1 SXZ A2^T + (A1 SXZ A2^T)^T + A2 A2^T , * where A1 [i,j] = phi[i+j], * A2 [i,j] = ttheta[i+j], and SX, SXZ are defined below */ PROTECT(res = allocMatrix(REALSXP, r, r)); double *P = REAL(res); /* Clean P */ Memzero(P, r*r); #ifdef DEBUG_Q0bis #define _ttheta(j) chk_V(ttheta, "ttheta", j, q+1)// was r #define _tphi(j) chk_V(tphi, "tphi", j, p+1) #define _rrz(j) chk_V(rrz, "rrz", j, q) #else #define _ttheta(j) ttheta[j] #define _tphi(j) tphi[j] #define _rrz(j) rrz [j] #endif double *ttheta = (double *) R_alloc(q + 1, sizeof(double)); /* Init ttheta = c(1, theta) */ ttheta[0] = 1.; for (i = 1; i < q + 1; ++i) ttheta[i] = theta[i - 1]; if( p > 0 ) { int r2 = max(p + q, p + 1); SEXP sgam = PROTECT(allocMatrix(REALSXP, r2, r2)), sg = PROTECT(allocVector(REALSXP, r2)); double *gam = REAL(sgam); double *g = REAL(sg); double *tphi = (double *) R_alloc(p + 1, sizeof(double)); /* Init tphi = c(1, -phi) */ tphi[0] = 1.; for (i = 1; i < p + 1; ++i) tphi[i] = -phi[i - 1]; /* Compute the autocovariance function of U, the AR part of X */ /* Gam := C1 + C2 ; initialize */ Memzero(gam, r2*r2); /* C1[E] */ for (j = 0; j < r2; ++j) for (i = j; i < r2 && i - j < p + 1; ++i) gam[j*r2 + i] += _tphi(i-j); /* C2[E] */ for (i = 0; i < r2; ++i) for (j = 1; j < r2 && i + j < p + 1; ++j) gam[j*r2 + i] += _tphi(i+j); /* Initialize g = (1 0 0 .... 0) */ g[0] = 1.; for (i = 1; i < r2; ++i) g[i] = 0.; /* rU = solve(Gam, g) -> solve.default() -> .Internal(La_solve, .,) * --> fiddling with R-objects -> C and then F77_CALL(.) of dgesv, dlange, dgecon * FIXME: call these directly here, possibly even use 'info' instead of error(.) * e.g., in case of exact singularity. */ SEXP callS = PROTECT(lang4(install("solve.default"), sgam, sg, sTol)), su = PROTECT(eval(callS, R_BaseEnv)); double *u = REAL(su); /* SX = A SU A^T */ /* A[i,j] = ttheta[j-i] */ /* SU[i,j] = u[abs(i-j)] */ /* Q0 += ( A1 SX A1^T == A1 A SU A^T A1^T) */ // (relying on good compiler optimization here:) for (i = 0; i < r; ++i) for (j = i; j < r; ++j) for (int k = 0; i + k < p; ++k) for (int L = k; L - k < q + 1; ++L) for (int m = 0; j + m < p; ++m) for (int n = m; n - m < q + 1; ++n) P[r*i + j] += phi[i + k] * phi[j + m] * _ttheta(L - k) * _ttheta(n - m) * u[abs(L - n)]; UNPROTECT(4); /* Compute correlation matrix between X and Z */ /* forwardsolve(C1, g) */ /* C[i,j] = tphi[i-j] */ /* g[i] = _ttheta(i) */ double *rrz = (double *) R_alloc(q, sizeof(double)); if(q > 0) { for (i = 0; i < q; ++i) { rrz[i] = _ttheta(i); for (j = max(0, i - p); j < i; ++j) rrz[i] -= _rrz(j) * _tphi(i-j); } } /* Q0 += A1 SXZ A2^T + (A1 SXZ A2^T)^T */ /* SXZ[i,j] = rrz[j-i-1], j > 0 */ for (i = 0; i < r; ++i) for (j = i; j < r; ++j) { int k, L; for (k = 0; i + k < p; ++k) for (L = k+1; j + L < q + 1; ++L) P[r*i + j] += phi[i + k] * _ttheta(j + L) * _rrz(L - k - 1); for (k = 0; j + k < p; ++k) for (L = k+1; i + L < q + 1; ++L) P[r*i + j] += phi[j + k] * _ttheta(i + L) * _rrz(L - k - 1); } } // end if(p > 0) /* Q0 += A2 A2^T */ for (i = 0; i < r; ++i) for (j = i; j < r; ++j) for (int k = 0; j + k < q + 1; ++k) P[r*i + j] += _ttheta(i + k) * _ttheta(j + k); /* Symmetrize result */ for (i = 0; i < r; ++i) for (j = i+1; j < r; ++j) P[r*j + i] = P[r*i + j]; UNPROTECT(1); return res; } SEXP getQ0(SEXP sPhi, SEXP sTheta) { SEXP res; int p = LENGTH(sPhi), q = LENGTH(sTheta); double *phi = REAL(sPhi), *theta = REAL(sTheta); /* thetab[np], xnext[np], xrow[np]. rbar[rbar] */ /* NB: nrbar could overflow */ int r = max(p, q + 1); size_t np = r * (r + 1) / 2, nrbar = np * (np - 1) / 2, npr, npr1; size_t indi, indj, indn, i, j, ithisr, ind, ind1, ind2, im, jm; /* This is the limit using an int index. We could use size_t and get more on a 64-bit system, but there seems no practical need. */ if(r > 350) error(_("maximum supported lag is 350")); double *xnext, *xrow, *rbar, *thetab, *V; xnext = (double *) R_alloc(np, sizeof(double)); xrow = (double *) R_alloc(np, sizeof(double)); rbar = (double *) R_alloc(nrbar, sizeof(double)); thetab = (double *) R_alloc(np, sizeof(double)); V = (double *) R_alloc(np, sizeof(double)); for (ind = 0, j = 0; j < r; j++) { double vj = 0.0; if (j == 0) vj = 1.0; else if (j - 1 < q) vj = theta[j - 1]; for (i = j; i < r; i++) { double vi = 0.0; if (i == 0) vi = 1.0; else if (i - 1 < q) vi = theta[i - 1]; V[ind++] = vi * vj; } } PROTECT(res = allocMatrix(REALSXP, r, r)); double *P = REAL(res); if (r == 1) { if (p == 0) P[0] = 1.0; // PR#16419 else P[0] = 1.0 / (1.0 - phi[0] * phi[0]); UNPROTECT(1); return res; } if (p > 0) { /* The set of equations s * vec(P0) = vec(v) is solved for vec(P0). s is generated row by row in the array xnext. The order of elements in P is changed, so as to bring more leading zeros into the rows of s. */ for (i = 0; i < nrbar; i++) rbar[i] = 0.0; for (i = 0; i < np; i++) { P[i] = 0.0; thetab[i] = 0.0; xnext[i] = 0.0; } ind = 0; ind1 = -1; npr = np - r; npr1 = npr + 1; indj = npr; ind2 = npr - 1; for (j = 0; j < r; j++) { double phij = (j < p) ? phi[j] : 0.0; xnext[indj++] = 0.0; indi = npr1 + j; for (i = j; i < r; i++) { double ynext = V[ind++]; double phii = (i < p) ? phi[i] : 0.0; if (j != r - 1) { xnext[indj] = -phii; if (i != r - 1) { xnext[indi] -= phij; xnext[++ind1] = -1.0; } } xnext[npr] = -phii * phij; if (++ind2 >= np) ind2 = 0; xnext[ind2] += 1.0; inclu2(np, xnext, xrow, ynext, P, rbar, thetab); xnext[ind2] = 0.0; if (i != r - 1) { xnext[indi++] = 0.0; xnext[ind1] = 0.0; } } } ithisr = nrbar - 1; im = np - 1; for (i = 0; i < np; i++) { double bi = thetab[im]; for (jm = np - 1, j = 0; j < i; j++) bi -= rbar[ithisr--] * P[jm--]; P[im--] = bi; } /* now re-order p. */ ind = npr; for (i = 0; i < r; i++) xnext[i] = P[ind++]; ind = np - 1; ind1 = npr - 1; for (i = 0; i < npr; i++) P[ind--] = P[ind1--]; for (i = 0; i < r; i++) P[i] = xnext[i]; } else { /* P0 is obtained by backsubstitution for a moving average process. */ indn = np; ind = np; for (i = 0; i < r; i++) for (j = 0; j <= i; j++) { --ind; P[ind] = V[ind]; if (j != 0) P[ind] += P[--indn]; } } /* now unpack to a full matrix */ for (i = r - 1, ind = np; i > 0; i--) for (j = r - 1; j >= i; j--) P[r * i + j] = P[--ind]; for (i = 0; i < r - 1; i++) for (j = i + 1; j < r; j++) P[i + r * j] = P[j + r * i]; UNPROTECT(1); return res; }