/* The functions here are derived from the Fortran in VSGARCMX.FOR, from the Fiorentini, Calzolari and Panattoni GARCH implementation (Journal of Applied Econometrics, 1996), the original notice for which is reproduced infra. The relevant code was extracted from its original Monte Carlo context, translated to C using f2c, and then edited extensively to turn it into more idiomatic C, and to convert from fixed-size arrays to dynamic memory allocation. I have also modified the comments at certain places in the code, where reference is made to the equations in the FCP paper. The comments in the Fortran apparently pertained to a draft of the paper; I have updated them relative to the paper as published in JAE, 1996, pp. 399-417. Allin Cottrell, Wake Forest University, March 2004. */ /* Gabriele FIORENTINI, Giorgio CALZOLARI, Lorenzo PANATTONI Journal of APPLIED ECONOMETRICS, 1996 mixed gradient algorithm garch(p,q) estimates of a linear equation SEE BOLLERSLEV, JOE 31(1986), 307-327. */ #include "libgretl.h" #include "libset.h" #include "fcp.h" #include "f2c.h" #include "clapack_double.h" #undef FDEBUG #define ABNUM 3 /* max number of GARCH lags */ #define SMALL_HT 1.0e-7 int global_np; double gscale; int gncoeff; #define vix(i,j) ((i) + global_np * (j)) /* private functions */ static int invert (double *g, int dim); static double garch_ll (double *c, int nc, double *res2, double *res, double *yhat, const double *y, const double **X, int nexo, int t1, int t2, const double *param, double *b, double *a0, int q, int p, double *h); static int vcv_setup (int t1, int t2, double *c, int nc, double *res2, double *res, int *count, const double **g, double *grad, double *param, int nparam, double *a0, int q, int p, double *h, double **dhdp, double *zt, double ***H, double *vco, int code); static int garch_info_matrix (int t1, int t2, const double **X, int nexo, double *yhat, double *c, int nc, double *res2, double *res, const double *y, double toler, int *count, double *vcv, const double **g, double *grad, double *param, int nparam, double *b, double *a0, int q, int p, double *h, double **dhdp, double *zt); static int garch_full_hessian (int t1, int t2, const double **X, int nexo, double *yhat, double *c, int nc, double *res2, double *res, const double *y, double toler, int *count, double *vcv, const double **g, double *grad, double *param, int nparam, double *b, double *a0, int q, int p, double *h, double **dhdp, double *zt); static int vs_allocate (double ***pdhdp, double ***pg, double **pparam, double **pgrad, double **pc, double **paux, double **pvch, double **pparpre, double **pyhat, int np, int nrc, int T) { double *param = NULL, *grad = NULL; double *c = NULL, *aux = NULL, *vch = NULL, *parpre = NULL; double **D = NULL, **G = NULL; double *yhat = NULL; int t; param = malloc(np * sizeof *param); grad = malloc(np * sizeof *grad); parpre = malloc(np * sizeof *parpre); if (param == NULL || grad == NULL || parpre == NULL) { goto bailout; } c = malloc(nrc * sizeof *c); aux = malloc(nrc * sizeof *aux); yhat = malloc(T * sizeof *yhat); if (c == NULL || aux == NULL || yhat == NULL) { goto bailout; } vch = malloc(np * np * sizeof *vch); if (vch == NULL) { goto bailout; } D = doubles_array_new(np, T); if (D == NULL) { goto bailout; } G = doubles_array_new(nrc, T); if (G == NULL) { goto bailout; } for (t=0; t tol2 * tol2) { /* not converged yet */ continue; } sumgra = 0.0; for (i=0; i= 1.0e-4) { pprintf(prn, "\nParameters and gradients at iteration %d:\n\n", ittot); for (i=0; i 0.0) { sderr = sqrt(vcv[vix(i,i)]); } else { sderr = 0.0; } amax[i+1] = param[i]; amax[i+1+nparam] = sderr; } } } garch_exit: vs_free(dhdp, nparam, g, nc, param, grad, c, aux, vch, parpre, yhat); return err; } /* Compute the GARCH log-likelihood. Parameters are passed in the "param" array. res, res2 and ht are be computed here (res2 holds squared residuals). */ static double garch_ll (double *c, int nc, double *res2, double *res, double *yhat, const double *y, const double **X, int nx, int t1, int t2, const double *param, double *b, double *a0, int q, int p, double *h) { int i, t, lag; int n = t2 - t1 + 1; double uncvar, ll; const double *alpha = param + nc + 1; const double *beta = param + nc + q + 1; for (i=0; i q)? p : q; for (t = t1-lag; t < t1; ++t) { res[t] = 0.0; res2[t] = h[t] = uncvar; } for (t=t1; t<=t2; t++) { h[t] = *a0; for (i=1; i<=q; i++) { h[t] += res2[t-i] * alpha[i-1]; } for (i=1; i<=p; i++) { h[t] += h[t-i] * beta[i-1]; } /* arbitrary */ if (h[t] <= 0.0) { h[t] = SMALL_HT; } } ll = 0.0; for (t=t1; t<=t2; t++) { double hts = h[t] * gscale * gscale; ll -= 0.5 * log(hts) + 0.5 * res2[t] / h[t] + LN_SQRT_2_PI; } return ll; } /* Check that the values of the parameters of the conditional variance, ht, are in the set of the admissible values. If a0 is less or equal than zero it is set to SMALL_HT. If alpha and beta are less than zero they are set to zero; also if the sum of alpha and beta is > 1.0, then alpha and beta are normalized (divided by sum). */ static void check_ht (double *b, int np) { double sum = 0.0; int i; if (b[0] <= 0.0) { b[0] = SMALL_HT; } for (i=1; i 1.0) { for (i=1; i q)? p : q; n = t2 - t1 + 1; #ifdef FDEBUG fprintf(stderr, "make vcv: lag=%d, nc=%d, nparam=%d\n", lag, nc, nparam); #endif asum2 = malloc(nc * sizeof *asum2); if (asum2 == NULL) { return 1; } if (count != NULL) { ++(*count); } for (i=0; i 0) { for (i=0; i 5) { nexp = 5; } cappa = pow(2.0, nexp); d0 = s2; d0 /= cappa; dac = d0 * .001; dub = d0 * 4.0; if (*count == 1) { ll1 = -garch_ll(c, nc, res2, res, yhat, y, X, nx, t1, t2, param, b, a0, q, p, h); #ifdef FFDEBUG fprintf(stderr, "count=1, ll1=%.9g\n", ll1); #endif } for (i=0; i ll1) { goto L307; } d1 = 0.0; d2 = d0; d3 = d0 + d0; for (i=0; i 0.0) { goto L400; } if (ll3 <= ll1) { goto L341; } L329: d3 = d2; ll3 = ll2; d2 = d1; ll2 = ll1; d1 -= dub; for (i=0; i 100) { goto L490; } goto L325; L341: d1 = d2; ll1 = ll2; d2 = d3; ll2 = ll3; d3 += dub; for (i=0; i 100) { goto L490; } goto L325; L400: d23s = d23 * (d2 + d3); d31s = d31 * (d3 + d1); d12s = d12 * (d1 + d2); ds = (d23s * ll1 + d31s * ll2 + d12s * ll3) * .5 / di; for (i=0; i 100) { goto L490; } a1s = (d = d1 - ds, fabs(d)); a2s = (d = d2 - ds, fabs(d)); a3s = (d = d3 - ds, fabs(d)); dm = a1s; if (a3s < dm) { dm = a3s; } if (dub >= dm) { goto L422; } if (ds < d1 - dub) { goto L329; } if (ds > d3 + dub) { goto L341; } L422: if (a1s < dac || a2s < dac || a3s < dac) { goto L490; } if (ll1 < ll2 || ll1 < ll3) { goto L434; } d1 = ds; ll1 = fs; goto L459; L434: if (ll2 < ll3 || ll2 < ll1) { goto L447; } d2 = ds; ll2 = fs; goto L459; L447: d3 = ds; ll3 = fs; L459: if (d2 <= d3) { goto L463; } dd = d2; ff = ll2; d2 = d3; ll2 = ll3; d3 = dd; ll3 = ff; L463: if (d1 <= d2) { goto L325; } dd = d1; ff = ll1; d1 = d2; ll1 = ll2; d2 = dd; ll2 = ff; goto L459; L490: if (fs <= ll1) { goto L491; } fs = ll1; ds = d1; L491: if (fs <= ll2) { goto L492; } fs = ll2; ds = d2; L492: if (fs <= ll3) { goto L496; } fs = ll3; ds = d3; L496: for (i=0; i q)? p : q; H = malloc(np * sizeof *H); if (H == NULL) { return NULL; } for (i=0; i q)? p : q; /* calculate the full Hessian */ vcv_setup(t1, t2, c, nc, res2, res, count, g, grad, param, nparam, a0, q, p, h, dhdp, zt, H, vcv, VCV_HESSIAN); /* invert the Hessian */ err = invert(vcv, nparam); if (err) { fprintf(stderr, "garch_full_hessian: matrix inversion failed\n"); } /* Start iteration here */ /* calculate the step for the new coefficients */ s2 = 0.0; for (i=0; i 5) { nexp = 5; } cappa = pow(2.0, nexp); d0 = s2; d0 /= cappa; dac = d0 * .001; dub = d0 * 4.0; if (*count == 1) { ll1 = -garch_ll(c, nc, res2, res, yhat, y, X, nx, t1, t2, param, b, a0, q, p, h); #ifdef FDEBUG fprintf(stderr, "hess: ll1 = %.9g\n", ll1); #endif } for (i=0; i ll1) { goto L307; } d1 = 0.0; d2 = d0; d3 = d0 + d0; for (i=0; i 0.0) { goto L400; } if (ll3 <= ll1) { goto L341; } L329: d3 = d2; ll3 = ll2; d2 = d1; ll2 = ll1; d1 -= dub; for (i=0; i 100) { goto L490; } goto L325; L341: d1 = d2; ll1 = ll2; d2 = d3; ll2 = ll3; d3 += dub; for (i=0; i 100) { goto L490; } goto L325; L400: d23s = d23 * (d2 + d3); d31s = d31 * (d3 + d1); d12s = d12 * (d1 + d2); ds = (d23s * ll1 + d31s * ll2 + d12s * ll3) * .5 / di; for (i=0; i 100) { goto L490; } a1s = (d = d1 - ds, fabs(d)); a2s = (d = d2 - ds, fabs(d)); a3s = (d = d3 - ds, fabs(d)); dm = a1s; if (a3s < dm) { dm = a3s; } if (dub >= dm) { goto L422; } if (ds < d1 - dub) { goto L329; } if (ds > d3 + dub) { goto L341; } L422: if (a1s < dac || a2s < dac || a3s < dac) { goto L490; } if (ll1 < ll2 || ll1 < ll3) { goto L434; } d1 = ds; ll1 = fs; goto L459; L434: if (ll2 < ll3 || ll2 < ll1) { goto L447; } d2 = ds; ll2 = fs; goto L459; L447: d3 = ds; ll3 = fs; L459: if (d2 <= d3) { goto L463; } dd = d2; ff = ll2; d2 = d3; ll2 = ll3; d3 = dd; ll3 = ff; L463: if (d1 <= d2) { goto L325; } dd = d1; ff = ll1; d1 = d2; ll1 = ll2; d2 = dd; ll2 = ff; goto L459; L490: if (fs <= ll1) { goto L491; } fs = ll1; ds = d1; L491: if (fs <= ll2) { goto L492; } fs = ll2; ds = d2; L492: if (fs <= ll3) { goto L496; } fs = ll3; ds = d3; L496: for (i=0; i