home *** CD-ROM | disk | FTP | other *** search
- /* functions - callbacks for Bayes routines in XLISP-STAT and S */
- /* XLISP-STAT 2.1 Copyright (c) 1990, by Luke Tierney */
- /* Additions to Xlisp 2.1, Copyright (c) 1989 by David Michael Betz */
- /* You may give out copies of this software; for conditions see the */
- /* file COPYING included with this distribution. */
-
- #include <stdlib.h>
- #include "xlisp.h"
- #include "osdef.h"
- #ifdef ANSI
- #include "xlproto.h"
- #include "xlsproto.h"
- #else
- #include "xlfun.h"
- #include "xlsfun.h"
- #endif ANSI
-
- #ifdef SBAYES
- # include <math.h>
- #define PRINTSTR(s) printf(s)
- #else
- /*# include "xmath.h"*/
- #define PRINTSTR(s) stdputstr(s)
- #endif SBAYES
-
- #ifdef ANSI
- void makespace(char **,int),
- install_func(LVAL,LVAL *,int,int,double,double,RVector,double),
- install_gfuncs(LVAL *,int,int,int,double,RVector),
- install_cfuncs(LVAL *,int,int,RVector,double,RVector),
- evalgfunc(RVector,double *,RVector,RMatrix),
- evalcfunc(RVector,double *,RVector,RMatrix),
- set_tilt_info(int,int,double,int,double *),
- add_tilt(RVector,double *,RVector,RMatrix,double,int);
- int in_support(LVAL *,int,double *),evalfunc(RVector,double *,RVector,RMatrix),
- minfunc(RVector,double *,RVector,RMatrix);
- #ifdef SBAYES
- void copypars(double *,double *,double *,MomIPars *,MomDPars *,double *
- double *,double *,MomIPars *,MomDPars *),
- cpmarpars(double *,double *,double *,MomIPars *,MomDPars *,double *
- double *,double *,MomIPars *,MomDPars *);
- int check_derivs(RVector,double);
- double dncmix(double *,int);
- #endif SBAYES
- #else
- void makespace(),install_func(),install_gfuncs(),install_cfuncs(),evalgfunc(),
- evalcfunc(),set_tilt_info(),add_tilt();
- int in_support(),minfunc();
- #ifdef SBAYES
- void copypars(),cpmarpars();
- int check_derivs();
- double dncmix();
- #endif SBAYES
- #endif ANSI
- /************************************************************************/
- /** **/
- /** Definitions and Globals **/
- /** **/
- /************************************************************************/
-
- #define nil 0L
- #define NULL 0L
- #define TRUE 1
- #define FALSE 0
-
- #define ROOT2PI 2.50662827463100050241
- #define PI_INV .31830988618379067153
-
- #define GRADTOL_POWER 1.0 / 3.0
- #define H_POWER 1.0 / 6.0
-
- typedef double **RMatrix, *RVector;
-
- typedef struct{
- LVAL f,*sf,*g; /* changed JKL */
- /* char *f, **sf, **g;*/
- int n, k;
- int change_sign, fderivs;
- int *gderivs;
- double typf, h, dflt;
- RVector typx, fsum, cvals, ctarget;
- RMatrix gfsum;
- } Fundata;
-
- static Fundata func, gfuncs, cfuncs;
-
- /************************************************************************/
- /** **/
- /** Memory Utilities **/
- /** **/
- /************************************************************************/
-
- /* this function is used to maintain a statically allocated piece of */
- /* memory of a specified size. If a larger piece is needed the pointer */
- /* is realloced. This allows functions using memory allocation to be */
- /* called repeatedly (but not recursively) from within the same call */
- /* from S. It attempts to avoid the danger of dangling callocs. */
-
- static void makespace(pptr, size)
- char **pptr;
- int size;
- {
- if (size <= 0) return;
- if (*pptr == nil) *pptr = calloc(size, 1);
- else *pptr = realloc(*pptr, size);
- if (size > 0 && *pptr == nil) Recover("memory allocation failed", NULL);
- }
-
- /************************************************************************/
- /** **/
- /** Functions Evaluation Routines **/
- /** **/
- /************************************************************************/
-
- /*
- * All Hessianevaluations by numerical derivatives assume the gradient is
- * evaluated first at the same location. The results are cached away.
- */
-
- /* install log posterior function */
- static void install_func(f, sf, n, change_sign, typf, h, typx, dflt)
- LVAL f, *sf; /* char *f, **sf; changed JKL */
- int n;
- double typf, h, dflt;
- RVector typx;
- {
- int i;
- static int inited = FALSE;
-
- if (! inited) {
- func.typx = nil;
- func.fsum = nil;
- inited = TRUE;
- }
- makespace((char **)&func.typx, n * sizeof(double)); /* casts added JKL */
- makespace((char **)&func.fsum, n * sizeof(double));
-
- func.f = f;
- func.sf = sf;
- func.n = n;
- func.change_sign = change_sign;
- func.typf = (typf > 0.0) ? typf : 1.0;
- func.h = (h > 0.0) ? h : pow(macheps(), H_POWER);
- for (i = 0; i < n; i++)
- func.typx[i] = (typx != nil && typx[i] > 0.0) ? typx[i] : 1.0;
- func.dflt = dflt;
- func.fderivs = 0;
- }
-
- /* install tilt functions */
- static void install_gfuncs(g, n, k, change_sign, h, typx)
- LVAL *g; /* char **g; changed JKL */
- int n, k, change_sign;
- double h;
- RVector typx;
- {
- int i;
- static int inited = FALSE;
- static double *gfsumdata = nil;
-
- if (! inited) {
- gfuncs.typx = nil;
- gfuncs.gfsum = nil;
- gfuncs.gderivs = nil;
- inited = TRUE;
- }
- makespace((char **)&gfuncs.typx, n * sizeof(double)); /* casts added JKL */
- makespace((char **)&gfuncs.gfsum, k * sizeof(double *));
- makespace((char **)&gfsumdata, k * n * sizeof(double));
- makespace((char **)&gfuncs.gderivs, k *sizeof(int));
-
- gfuncs.g = g;
- gfuncs.n = n;
- gfuncs.k = k;
- gfuncs.change_sign = change_sign;
- gfuncs.h = (h > 0.0) ? h : pow(macheps(), H_POWER);
- for (i = 0; i < n; i++)
- gfuncs.typx[i] = (typx != nil && typx[i] > 0.0) ? typx[i] : 1.0;
- for (i = 0; i < k; i++) gfuncs.gfsum[i] = gfsumdata + i * n;
- }
-
- /* install constraint functions */
- static void install_cfuncs(g, n, k, ctarget, h, typx)
- LVAL *g; /*char **g; changed JKL */
- int n, k;
- double h;
- RVector typx, ctarget;
- {
- int i;
- static int inited = FALSE;
-
- if (! inited) {
- cfuncs.typx = nil;
- cfuncs.fsum = nil;
- cfuncs.gderivs = nil;
- inited = TRUE;
- }
- makespace((char **)&cfuncs.typx, n * sizeof(double)); /* casts added JKL */
- makespace((char **)&cfuncs.fsum, n * sizeof(double));
- makespace((char **)&cfuncs.gderivs, k * sizeof(int));
-
- cfuncs.g = g;
- cfuncs.n = n;
- cfuncs.k = k;
- cfuncs.h = (h > 0.0) ? h : pow(macheps(), H_POWER);
- for (i = 0; i < n; i++)
- cfuncs.typx[i] = (typx != nil && typx[i] > 0.0) ? typx[i] : 1.0;
- cfuncs.ctarget = ctarget;
- }
-
- /* callback to test if x is in the support of the posterior */
- static int in_support(ff, n, x)
- /* char * */ LVAL *ff; /* changed JKL */
- int n;
- double *x;
- {
- char *args[1], *values[1];
- int *result;
- char *mode[1];
- long length[1];
-
- if (ff == nil || ff[0] == nil) return(TRUE);
- else {
- mode[0] = "double";
- length[0] =n;
- args[0] = (char *) x;
- call_S(ff[0], 1L, args, mode, length, 0L, 1L, values);
- result = (int *) values[0];
- return(result[0]);
- }
- }
-
- /* callback for logposterior evaluation */
- static int evalfunc(x, pval, grad, hess)
- RVector x, grad;
- double *pval;
- RMatrix hess;
- {
- char *args[1], *values[3];
- double *result, val;
- char *mode[1];
- long length[1];
- int i, j;
-
- for (i = 0; i < 3; i++) values[i] = nil;
-
- if (in_support(func.sf, func.n, x)) {
- if (pval != nil || func.fderivs > 0 || hess != nil) {
- mode[0] = "double";
- length[0] = func.n;
- args[0] = (char *) x;
- call_S(func.f, 1L, args, mode, length, 0L, 3L, values);
- result = (double *) values[0];
- val = (! func.change_sign) ? result[0] : -result[0];
- if (pval != nil) *pval = val;
- if (values[2] != nil) func.fderivs = 2;
- else if (values[1] != nil) func.fderivs = 1;
- else func.fderivs = 0;
- }
- if (grad != nil) {
- if (func.fderivs > 0) {
- result = (double *) values[1];
- for (i = 0; i < func.n; i++)
- grad[i] = (! func.change_sign) ? result[i] : -result[i];
- }
- else {
- numergrad(func.n, x, grad, func.fsum, evalfunc, func.h, func.typx);
- }
- }
- if (hess != nil) {
- if (func.fderivs == 2) {
- result = (double *) values[2];
- for (i = 0; i < func.n; i++)
- for (j = 0; j < func.n; j++)
- hess[i][j] = (! func.change_sign) ? result[i + j * func.n]
- : -result[i + j * func.n];
- }
- else {
- if (func.fderivs == 1) /* kludge to get fsum for analytic gradients */
- numergrad(func.n, x, func.fsum, func.fsum,
- evalfunc, func.h, func.typx);
- numerhess(func.n, x, hess, val, func.fsum, evalfunc, func.h, func.typx);
- }
- }
- return(TRUE);
- }
- else {
- if (pval != nil) *pval = func.dflt;
- return(FALSE);
- }
- }
-
-
- /* callback for tilt function evaluation */
- static int which_gfunc;
-
- static void evalgfunc(x, pval, grad, hess)
- RVector x, grad;
- double *pval;
- RMatrix hess;
- {
- char *args[1], *values[3];
- double *result, val;
- char *mode[1];
- long length[1];
- int i, j;
-
- for (i = 0; i < 3; i++) values[i] = nil;
-
- if (pval != nil || gfuncs.gderivs[which_gfunc] > 0 || hess != nil) {
- mode[0] = "double";
- length[0] = gfuncs.n;
- args[0] = (char *) x;
- call_S(gfuncs.g[which_gfunc], 1L, args, mode, length, 0L, 3L, values);
- result = (double *) values[0];
- val = result[0];
- if (pval != nil) *pval = result[0];
- if (values[2] != nil) gfuncs.gderivs[which_gfunc] = 2;
- else if (values[1] != nil) gfuncs.gderivs[which_gfunc] = 1;
- else gfuncs.gderivs[which_gfunc] = 0;
- }
- if (grad != nil) {
- if (gfuncs.gderivs[which_gfunc] > 0) {
- result = (double *) values[1];
- for (i = 0; i < gfuncs.n; i++) grad[i] = result[i];
- }
- else {
- #ifdef ANSI
- numergrad(gfuncs.n, x, grad, gfuncs.gfsum[which_gfunc],
- (int (*)())evalgfunc, gfuncs.h, gfuncs.typx);
- #else
- numergrad(gfuncs.n, x, grad, gfuncs.gfsum[which_gfunc], evalgfunc,
- gfuncs.h, gfuncs.typx);
- #endif ANSI
- }
- }
- if (hess != nil) {
- if (gfuncs.gderivs[which_gfunc] == 2) {
- result = (double *) values[2];
- for (i = 0; i < gfuncs.n; i++)
- for (j = 0; j < gfuncs.n; j++)
- hess[i][j] = result[i + j * gfuncs.n];
- }
- else {
- /* kludge to get fsum if analytic gradient used */
- if (gfuncs.gderivs[which_gfunc] == 1)
- #ifdef ANSI
- numergrad(gfuncs.n, x, gfuncs.gfsum[which_gfunc],
- gfuncs.gfsum[which_gfunc], (int (*)())evalgfunc, gfuncs.h, gfuncs.typx);
- numerhess(gfuncs.n, x, hess, val, gfuncs.gfsum[which_gfunc],
- (int (*)())evalgfunc, gfuncs.h, gfuncs.typx);
- #else
- numergrad(gfuncs.n, x, gfuncs.gfsum[which_gfunc],
- gfuncs.gfsum[which_gfunc], evalgfunc, gfuncs.h, gfuncs.typx);
- numerhess(gfuncs.n, x, hess, val, gfuncs.gfsum[which_gfunc], evalgfunc,
- gfuncs.h, gfuncs.typx);
- #endif ANSI
- }
- }
- }
-
- /* callback for constraint function evaluation */
- static int which_cfunc;
-
- static void evalcfunc(x, pval, grad, hess)
- RVector x, grad;
- double *pval;
- RMatrix hess;
- {
- char *args[1], *values[3];
- double *result, val;
- char *mode[1];
- long length[1];
- int i, j;
-
- if (pval != nil || cfuncs.gderivs[which_cfunc] > 0 || hess != nil) {
- mode[0] = "double";
- length[0] = cfuncs.n;
- args[0] = (char *) x;
- call_S(cfuncs.g[which_cfunc], 1L, args, mode, length, 0L, 3L, values);
- result = (double *) values[0];
- val = result[0];
- if (pval != nil) {
- *pval = result[0];
- if (cfuncs.ctarget != nil) *pval -= cfuncs.ctarget[which_cfunc];
- }
- if (values[2] != nil) cfuncs.gderivs[which_cfunc] = 2;
- else if (values[1] != nil) cfuncs.gderivs[which_cfunc] = 1;
- else cfuncs.gderivs[which_cfunc] = 0;
- }
- if (grad != nil) {
- if (cfuncs.gderivs[which_cfunc] > 0) {
- result = (double *) values[1];
- for (i = 0; i <cfuncs.n; i++) grad[i] = result[i];
- }
- else {
- #ifdef ANSI
- numergrad(cfuncs.n, x, grad, cfuncs.fsum, (int (*)())evalcfunc,
- cfuncs.h, cfuncs.typx);
- #else
- numergrad(cfuncs.n, x, grad, cfuncs.fsum, evalcfunc,
- cfuncs.h, cfuncs.typx);
- #endif ANSI
- }
- }
- if (hess != nil) {
- if (cfuncs.gderivs[which_cfunc] == 2) {
- result = (double *) values[2];
- for (i = 0; i <cfuncs.n; i++)
- for (j = 0; j <cfuncs.n; j++)
- hess[i][j] = result[i + j * cfuncs.n];
- }
- else {
- /* kludge to get fsum if analytic gradient used */
- if (cfuncs.gderivs[which_cfunc] == 1)
- #ifdef ANSI
- numergrad(cfuncs.n, x, cfuncs.fsum, cfuncs.fsum, (int (*)())evalcfunc,
- cfuncs.h, cfuncs.typx);
- numerhess(cfuncs.n, x, hess, val, cfuncs.fsum, (int (*)())evalcfunc,
- cfuncs.h, cfuncs.typx);
- #else
- numergrad(cfuncs.n, x, cfuncs.fsum, cfuncs.fsum, evalcfunc,
- cfuncs.h, cfuncs.typx);
- numerhess(cfuncs.n, x, hess, val, cfuncs.fsum, evalcfunc,
- cfuncs.h, cfuncs.typx);
- #endif ANSI
- }
- }
- }
-
- /* S front end for logposterior evaluation */
- void evalfront(ff, n, x, val, grad, phess, h, typx)
- /* char * */ LVAL *ff; /* changed JKL */
- int *n;
- double *x, *val, *grad, *phess, *typx, *h;
- {
- int i;
- static RMatrix hess = nil;
-
- install_func(ff[0], nil, *n, FALSE, 1.0, *h, typx, 0.0);
- if (phess == nil) hess = nil;
- else {
- makespace((char **)&hess, *n * sizeof(double *));
- for (i = 0; i < *n; i++, phess += *n) hess[i] = phess;
- }
- evalfunc(x, val, grad, hess);
- }
-
- #ifdef SBAYES
- /* S front end for tilt function evaluation */
- void gevalfront(gg, n, m, x, h, typx, val, grad)
- char **gg;
- int *n, *m;
- double *x, *h, *typx, *val, *grad;
- {
- int i;
-
- install_gfuncs(gg, *n, *m, FALSE, *h, typx);
- for (i = 0; i < *m; i++, val++) {
- which_gfunc = i;
- evalgfunc(x, val, grad, nil);
- if (grad != nil) grad += *n;
- }
- }
-
- /************************************************************************/
- /** **/
- /** Derivative Scaling Routines **/
- /** **/
- /************************************************************************/
-
- static int check_derivs(x, drvtol)
- RVector x;
- double drvtol;
- {
- static RVector grad = nil, work = nil;
- static RMatrix hess = nil;
- int i, error;
-
- grad = (RVector) S_alloc(func.n, sizeof(double));
- hess = (RMatrix) S_alloc(func.n, sizeof(double *));
- work = (RVector) S_alloc(func.n + func.n * func.n, sizeof(double));
-
- for (i = 0; i < func.n; i++) {
- hess[i] = work;
- work += func.n;
- }
-
- error = derivscale(func.n, x, grad, hess, func.fsum, evalfunc,
- &func.h, func.typx, drvtol, work);
- return(error);
- }
-
- void derivscalefront(ff, n, x, h, typx, tol, info)
- char **ff;
- int *n, *info;
- double *x, *h, *typx, *tol;
- {
- int i;
-
- if (*tol <= 0.0) *tol = pow(macheps(), GRADTOL_POWER);
-
- install_func(ff[0], nil, *n, TRUE, 1.0, *h, typx, 0.0);
- *info = check_derivs(x, *tol);
-
- *h = func.h;
- for (i = 0; i < *n; i++) typx[i] = func.typx[i];
- }
-
- /************************************************************************/
- /** **/
- /** Importance Sampling Routines **/
- /** **/
- /************************************************************************/
-
- /* joint density of normal-cauchy mixture */
- static double dncmix(x, n, p)
- double *x, p;
- int n;
- {
- int i;
- double dens;
-
- for (i = 0, dens = 1.0; i < n; i++) {
- dens *= p * exp(-0.5 * x[i] * x[i]) / ROOT2PI
- + (1 - p) * PI_INV / (1.0 + x[i] * x[i]);
- }
- return(dens);
- }
-
- /*
- * S front end for computing sample from transformed normal-cauchy
- * mixture and importance sampling weights
- */
- void samplefront(ff, sf, rf, p, n, x, ch, N, y, w)
- char **ff, **sf, **rf;
- int *n, *N;
- double *p, *x, *ch, *y, *w;
- {
- double val;
- int i, j, k;
- char *args[2], *values[1];
- double *result, mval, c, dens, m;
- char *mode[2];
- long length[2];
-
- /* get the random variables */
- mode[0] = "double"; mode[1] = "double";
- length[0] = 1; length[1] = 1;
- m = *N * *n; args[0] = (char *) &m; args[1] = (char *) p;
- call_S(rf[0], 2L, args, mode, length, 0L, 1L, values);
- result = (double *) values[0];
- for (i = 0; i < m; i++) y[i] = result[i];
-
- /* construct the sample and the weights */
- install_func(ff[0], sf, *n, FALSE, 1.0, -1.0, nil, 0.0);
- c = 1.0 / pow(ROOT2PI, (double) *n);
- evalfunc(x, &mval, nil, nil);
- for (i = 0; i < *N; i++, y += *n) {
- dens = dncmix(y, *n, *p);
- for (j = 0; j < *n; j++) {
- val = x[j];
- for (k = j; k < *n; k++) val += y[k] * ch[j + *n * k];
- y[j] = val;
- }
- if (evalfunc(y, &val, nil, nil)) w[i] = exp(val - mval) * c / dens;
- else w[i] = 0.0;
- }
- }
- #endif SBAYES
- /************************************************************************/
- /** **/
- /** Maximization Routines **/
- /** **/
- /************************************************************************/
- /* in xlsdef.h JKL
- typedef struct {
- int n, m, k, itnlimit, backtrack, verbose, vals_suppl, exptilt;
- int count, termcode;
- } MaxIPars;
-
- typedef struct {
- double typf, h, gradtol, steptol, maxstep, dflt, tilt, newtilt, hessadd;
- } MaxDPars;
- */
- struct {
- double tilt;
- RVector gval;
- RMatrix ggrad, ghess;
- int exptilt;
- RVector tscale;
- } tiltinfo;
-
- static void set_tilt_info(n, m, tilt, exptilt, tscale)
- int n, m;
- double tilt, *tscale;
- int exptilt;
- {
- static double *hessdata = nil, *graddata = nil;
- int i;
- static int inited = FALSE;
-
- if (! inited) {
- tiltinfo.gval = nil;
- tiltinfo.ggrad = nil;
- tiltinfo.ghess = nil;
- inited = TRUE;
- }
- makespace((char **)&tiltinfo.gval, n * sizeof(double));
- makespace((char **)&tiltinfo.ggrad, m * sizeof(double *));
- makespace((char **)&tiltinfo.ghess, n * sizeof(double *));
- makespace((char **)&graddata, n * m * sizeof(double));
- makespace((char **)&hessdata, n * n * sizeof(double));
-
- tiltinfo.tilt = tilt;
- tiltinfo.exptilt = exptilt;
- for (i = 0; i < m; i++) tiltinfo.ggrad[i] = graddata + i * n;
- for (i = 0; i < n; i++) tiltinfo.ghess[i] = hessdata + i * n;
- tiltinfo.tscale = tscale;
- }
-
- static int minfunc(x, pval, grad, hess)
- RVector x, grad;
- double *pval;
- RMatrix hess;
- {
- int k = gfuncs.k;
-
- if (evalfunc(x, pval, grad, hess) && (k > 0))
- add_tilt(x, pval, grad, hess, tiltinfo.tilt, tiltinfo.exptilt);
- return(0); /* return added JKL */
- }
-
- void constfunc(x, vals, jac, hess)
- RVector x, vals;
- RMatrix jac, hess;
- {
- int i, k = cfuncs.k;
- double *pvali, *jaci;
-
- for (i = 0; i < k; i++) {
- pvali = (vals != nil) ? vals + i : nil;
- jaci = (jac != nil) ? jac[i] : nil;
- which_cfunc = i;
- evalcfunc(x, pvali, jaci, nil);
- }
- }
-
- static void add_tilt(x, pval, grad, hess, tilt, exptilt)
- RVector x, grad;
- double *pval, tilt;
- RMatrix hess;
- int exptilt;
- {
- int i, j, k, n = func.n, m = gfuncs.k;
- double *gval, *ggrad, **ghess, etilt;
-
- if (m == 0) return;
-
- if (gfuncs.change_sign) tilt = -tilt;
-
- for (k = 0; k < m; k++) {
- gval = (pval != nil) ? tiltinfo.gval + k : nil;
- ggrad = (grad != nil) ? tiltinfo.ggrad[k] : nil;
- ghess = (hess != nil) ? tiltinfo.ghess : nil;
-
- which_gfunc = k;
- evalgfunc(x, gval, ggrad, ghess);
-
- if (exptilt) {
- etilt = (tiltinfo.tscale != nil) ? tilt / tiltinfo.tscale[k] : tilt;
- if (pval != nil) *pval += etilt * *gval;
- if (grad != nil)
- for (i = 0; i < n; i++) grad[i] += etilt * ggrad[i];
- if (hess != nil)
- for (i = 0; i < n; i++)
- for (j = 0; j < n; j++) hess[i][j] += etilt * ghess[i][j];
- }
- else {
- gval = tiltinfo.gval;
- ggrad = tiltinfo.ggrad[k];
- ghess = tiltinfo.ghess;
- if (gval[k] <= 0.0) Recover("nonpositive function value", NULL);
- if (pval != nil) *pval += tilt * log(gval[k]);
- if (grad != nil)
- for (i = 0; i < n; i++) grad[i] += tilt * ggrad[i] / gval[k];
- if (hess != nil)
- for (i = 0; i < n; i++)
- for (j = 0; j < n; j++)
- hess[i][j] +=
- tilt * (ghess[i][j] / gval[k]
- - (ggrad[i] / gval[k]) * (ggrad[j] / gval[k]));
- }
- }
- }
-
- void maxfront(ff, gf, cf, x, typx, fvals, gvals, cvals, ctarget, ipars, dpars,
- tscale, msg)
- LVAL *ff,*gf,*cf;/* char **ff, **gf, **cf; changed JKL */
- double /* *x, *typx,*/ *fvals, *gvals, *cvals, *ctarget, *tscale;
- RVector x,typx; /* changed JKL */
- MaxIPars *ipars;
- MaxDPars *dpars;
- char **msg;
- {
- static char *work = nil;
- static RMatrix H = nil, cJ = nil;
- double *pf, *grad, *c;
- int i, n, m, k;
- int (*cfun)();
-
- if (ipars->verbose > 0) PRINTSTR("maximizing...\n");
-
- n = ipars->n;
- m = ipars->m;
- k = ipars->k;
- if (k >= n) Recover("too many constraints", NULL);
-
- makespace((char **)&H, n * sizeof(double *));
- makespace((char **)&work, minworkspacesize(n, k));
-
- pf = fvals; fvals++;
- grad = fvals; fvals += n;
- for (i = 0; i < n; i++, fvals += n) H[i] = fvals;
- set_tilt_info(n, m, dpars->newtilt, ipars->exptilt, tscale);
-
- if (k == 0) {
- c = nil;
- cJ = nil;
- cfun = nil;
- }
- else {
- c = cvals;
- cvals += k;
- makespace((char **)&cJ, k * sizeof(double *));
- for (i = 0; i < k; i++) cJ[i] = cvals + i * n;
- #ifdef ANSI
- cfun = (int (*)())constfunc;
- #else
- cfun = constfunc;
- #endif ANSI
- }
-
- install_func(ff[0], nil, n, TRUE, dpars->typf, dpars->h, typx, dpars->dflt);
- install_gfuncs(gf, n, m, TRUE, dpars->h, typx);
- install_cfuncs(cf, n, k, ctarget, dpars->h, typx);
-
- minsetup(n, k, minfunc, cfun, x, dpars->typf, typx, work);
- minsetoptions(dpars->gradtol, dpars->steptol, dpars->maxstep,
- ipars->itnlimit, ipars->verbose, ipars->backtrack, TRUE);
-
- if (ipars->vals_suppl) {
- for (i = 0; i < k; i++) c[i] -= ctarget[i];
- if (dpars->newtilt != dpars->tilt) {
- add_tilt(x, pf, grad, H, dpars->newtilt - dpars->tilt, ipars->exptilt);
- dpars->tilt = dpars->newtilt;
- }
- minsupplyvalues(*pf, grad, H, c, cJ);
- }
-
- minimize();
- minresults(x, pf, nil, grad, H, c, cJ, &ipars->count, &ipars->termcode,
- &dpars->hessadd);
- msg[0] = minresultstring(ipars->termcode);
-
- for (i = 0; i < k; i++) c[i] += ctarget[i];
- ipars->vals_suppl = TRUE;
- }
-
- /************************************************************************/
- /** **/
- /** Log Laplace Approximation **/
- /** **/
- /************************************************************************/
-
- void loglapdet(fvals, cvals, ipars, dpars, val, detonly)
- double *fvals, *cvals;
- MaxIPars *ipars;
- MaxDPars *dpars;
- double *val;
- int *detonly;
- {
- int i, j, l, n = ipars->n, k = ipars->k;
- double f = -fvals[0], *hessdata = fvals + n + 1, *cgraddata = cvals + k;
- double ldL, ldcv, maxadd;
- static RMatrix hess = nil, cgrad = nil;
-
- if (k >= n) Recover("too many constraints", NULL);
-
- makespace((char **)&hess, n * sizeof(double *));
- makespace((char **)&cgrad, k * sizeof(double *));
-
- for (i = 0; i < n; i++) hess[i] = hessdata + i * n;
- for (i = 0; i < k; i++) cgrad[i] = cgraddata + i * n;
-
- choldecomp(hess, n, 0.0, &maxadd);
- /**** do something if not pos. definite ****/
-
- for (i = 0, ldL = 0.0; i < n; i++) ldL += log(hess[i][i]);
-
- if (k > 0) {
- /* forward solve for (L^-1) cgrad^T */
- for (l = 0; l < k; l++) {
- for (i = 0; i < n; i++) {
- if (hess[i][i] != 0.0) cgrad[l][i] /= hess[i][i];
- for (j = i + 1; j < n; j++) cgrad[l][j] -= hess[j][i] * cgrad[l][i];
- }
- }
-
- /* compute sigma and stdev */
- for (i = 0; i < k; i++) {
- for (j = i; j < k; j++) {
- for (l = 0, hess[i][j] = 0.0; l < n; l++)
- hess[i][j] += cgrad[i][l] * cgrad[j][l];
- hess[j][i] = hess[i][j];
- }
- }
-
- choldecomp(hess, k, 0.0, &maxadd);
- /**** do something if not pos. definite ****/
- for (i = 0, ldcv = 0.0; i < k; i++) ldcv += log(hess[i][i]);
- }
- else ldcv = 0.0;
-
- *val = (n - k) * log(ROOT2PI) - ldL - ldcv;
- if (! *detonly) *val += f;
- }
-
- #ifdef SBAYES
-
- void loglapfront(fvals, cvals, ipars, dpars, val)
- double *fvals, *cvals;
- MaxIPars *ipars;
- MaxDPars *dpars;
- double *val;
- {
- int detonly = FALSE;
-
- loglapdet(fvals, cvals, ipars, dpars, val, &detonly);
- }
-
- /************************************************************************/
- /** **/
- /** First Order Moments **/
- /** **/
- /************************************************************************/
-
- void moms1front(gf, n, m, x, hessdata, mean, stdev, sigmadata, h, typx)
- char *gf;
- int *n, *m;
- double *x, *hessdata, *mean, *stdev, *sigmadata, *h, *typx;
- {
- int i, j, k;
- RMatrix hess, sigma, delg;
- double *delgdata, maxadd;
-
- hess = (RMatrix) S_alloc(*n, sizeof(double *));
- sigma = (RMatrix) S_alloc(*m, sizeof(double *));
- delg = (RMatrix) S_alloc(*m, sizeof(double *));
- delgdata = (double *) S_alloc(*m * *n, sizeof(double));
-
- for (i = 0; i < *n; i++) hess[i] = hessdata + i * *n;
- for (i = 0; i < *m; i++) sigma[i] = sigmadata + i * *m;
- for (i = 0; i < *m; i++) delg[i] = delgdata + i * *n;
-
- gevalfront(gf, n, m, x, h, typx, mean, delgdata);
-
- /* get the cholesky decomposition L of the hessian */
- choldecomp(hess, *n, 0.0, &maxadd);
-
- /* forward solve for (L^-1) delg^T */
- for (k = 0; k < *m; k++) {
- for (i = 0; i < *n; i++) {
- if (hess[i][i] != 0.0) delg[k][i] /= hess[i][i];
- for (j = i + 1; j < *n; j++) delg[k][j] -= hess[j][i] * delg[k][i];
- }
- }
-
- /* compute sigma and stdev */
- for (i = 0; i < *m; i++) {
- for (j = i; j < *m; j++) {
- for (k = 0, sigma[i][j] = 0.0; k < *n; k++)
- sigma[i][j] += delg[i][k] * delg[j][k];
- sigma[j][i] = sigma[i][j];
- }
- stdev[i] = sqrt(sigma[i][i]);
- }
- }
-
- /************************************************************************/
- /** **/
- /** Second Order Moments **/
- /** **/
- /************************************************************************/
- /* in xlsdef.h JKL
- typedef struct {
- MaxIPars max;
- int full, covar;
- } MomIPars;
-
- typedef struct {
- MaxDPars max;
- double mgfdel;
- } MomDPars;
- */
- void moms2front(ff, gf, gnum, x, typx, fvals, gvals, ipars, dpars,
- mean, stdev, sigmadata)
- char **ff, **gf;
- int *gnum;
- double *x, *typx, *fvals, *gvals, *mean, *stdev, *sigmadata;
- MomIPars *ipars;
- MomDPars *dpars;
- {
- char *msg;
- double h, loglap0, loglap1, loglap2;
- double *tilts, *fvals1, *gvals1, *x1;
- MomDPars dp1, *dpars1 = &dp1;
- MomIPars ip1, *ipars1 = &ip1;
- int i, n, m;
-
- n = ipars->max.n;
- m = *gnum;
- h = dpars->max.h;
-
- tilts = (double *) S_alloc(m, sizeof(double));
- x1 = (double *) S_alloc(n, sizeof(double));
- fvals1 = (double *) S_alloc(1 + n + n * n, sizeof(double));
- gvals1 = (double *) S_alloc(m + n * m, sizeof(double));
-
- maxfront(ff, nil, nil, x, typx, fvals, gvals, nil, nil,
- ipars, dpars, nil, &msg);
- copypars(x, fvals, gvals, ipars, dpars, x1, fvals1, gvals1, ipars1, dpars1);
- loglapfront(fvals1, nil, ipars1, dpars1, &loglap0);
- copypars(x, fvals, gvals, ipars, dpars, x1, fvals1, gvals1, ipars1, dpars1);
- moms1front(gf, &n, &m, x1, fvals1 + n + 1, mean, stdev, sigmadata, &h, typx);
-
- if (ipars->full) {
- for (i = 0; i < m; i++) {
- copypars(x, fvals, gvals, ipars, dpars,
- x1, fvals1, gvals1, ipars1, dpars1);
- ipars1->max.m = 1;
- ipars1->max.exptilt = FALSE;
- dpars1->max.newtilt = 1.0;
- maxfront(ff, gf + i, nil, x1, typx, fvals1, gvals1, nil, nil,
- ipars1, dpars1, nil, &msg);
- loglapfront(fvals1, nil, ipars1, dpars1, &loglap1);
- loglap1 -= loglap0;
-
- copypars(x, fvals, gvals, ipars, dpars,
- x1, fvals1, gvals1, ipars1, dpars1);
- ipars1->max.m = 1;
- ipars1->max.exptilt = FALSE;
- dpars1->max.newtilt = 2.0;
- maxfront(ff, gf + i, nil, x1, typx, fvals1, gvals1, nil, nil,
- ipars1, dpars1, nil, &msg);
- loglapfront(fvals1, nil, ipars1, dpars1, &loglap2);
- loglap2 -= loglap0;
-
- mean[i] = exp(loglap1);
- stdev[i] = sqrt(exp(loglap2) - exp(2.0 * loglap1));
- if (ipars->covar) sigmadata[i + i * m] = stdev[i] * stdev[i];
- }
- if (ipars->covar) {
- char *cgf[2];
- int j;
-
- for (i = 0; i < m; i++) {
- for (j = i + 1; j < m; j++) {
- cgf[0] = gf[i];
- cgf[1] = gf[j];
- copypars(x, fvals, gvals, ipars, dpars,
- x1, fvals1, gvals1, ipars1, dpars1);
- ipars1->max.m = 2;
- ipars1->max.exptilt = FALSE;
- dpars1->max.newtilt = 1.0;
- maxfront(ff, gf + i, nil, x1, typx, fvals1, gvals1, nil, nil,
- ipars1, dpars1, nil, &msg);
- loglapfront(fvals1, nil, ipars1, dpars1, &loglap1);
- loglap1 -= loglap0;
-
- sigmadata[i + j * m] = exp(loglap1) - mean[i] * mean[j];
- sigmadata[j + i * m] = sigmadata[i + j * m];
- }
- }
- }
- }
- else {
- for (i = 0; i < m; i++)
- tilts[i] = (stdev[i] > 0.0) ? dpars->mgfdel / stdev[i] : dpars->mgfdel;
-
- for (i = 0; i < m; i++) {
- copypars(x, fvals, gvals, ipars, dpars,
- x1, fvals1, gvals1, ipars1, dpars1);
- ipars1->max.m = 1;
- ipars1->max.exptilt = TRUE;
- dpars1->max.newtilt = tilts[i];
- maxfront(ff, gf + i, nil, x1, typx, fvals1, gvals1, nil, nil,
- ipars1, dpars1, nil, &msg);
- loglapfront(fvals1, nil, ipars1, dpars1, &loglap1);
- loglap1 -= loglap0;
-
- copypars(x, fvals, gvals, ipars, dpars,
- x1, fvals1, gvals1, ipars1, dpars1);
- ipars1->max.m = 1;
- ipars1->max.exptilt = TRUE;
- dpars1->max.newtilt = -tilts[i];
- maxfront(ff, gf + i, nil, x1, typx, fvals1, gvals1, nil, nil,
- ipars1, dpars1, nil, &msg);
- loglapfront(fvals1, nil, ipars1, dpars1, &loglap2);
- loglap2 -= loglap0;
-
- mean[i] = (loglap1 - loglap2) / (2.0 * tilts[i]);
- stdev[i] = sqrt((loglap1 + loglap2) / (tilts[i] * tilts[i]));
- if (ipars->covar) sigmadata[i + i * m] = stdev[i] * stdev[i];
- }
- if (ipars->covar) {
- char *cgf[2];
- double ctilt, tscale[2];
- int j;
-
- ctilt = dpars->mgfdel;
- for (i = 0; i < m; i++) {
- for (j = i + 1; j < m; j++) {
- cgf[0] = gf[i];
- cgf[1] = gf[j];
- tscale[0] = stdev[i] > 0 ? stdev[i] : 1.0;
- tscale[1] = stdev[j] > 0 ? stdev[j] : 1.0;
-
- copypars(x, fvals, gvals, ipars, dpars,
- x1, fvals1, gvals1, ipars1, dpars1);
- ipars1->max.m = 2;
- ipars1->max.exptilt = TRUE;
- dpars1->max.newtilt = ctilt;
- maxfront(ff, cgf, nil, x1, typx, fvals1, gvals1, nil, nil,
- ipars1, dpars1, tscale, &msg);
- loglapfront(fvals1, nil, ipars1, dpars1, &loglap1);
- loglap1 -= loglap0;
-
- copypars(x, fvals, gvals, ipars, dpars,
- x1, fvals1, gvals1, ipars1, dpars1);
- ipars1->max.m = 2;
- ipars1->max.exptilt = TRUE;
- dpars1->max.newtilt = -ctilt;
- maxfront(ff, cgf, nil, x1, typx, fvals1, gvals1, nil, nil,
- ipars1, dpars1, tscale, &msg);
- loglapfront(fvals1, nil, ipars1, dpars1, &loglap2);
- loglap2 -= loglap0;
-
- sigmadata[i + j * m] = stdev[i] * stdev[j]
- * ((loglap2 + loglap1) /(2 * ctilt * ctilt) - 1.0);
- sigmadata[j + i * m] = sigmadata[i + j * m];
- }
- }
- }
- }
- }
-
- static void copypars(x, f, g, ip, dp, x1, f1, g1, ip1, dp1)
- double *x, *f, *g, *x1, *f1, *g1;
- MomIPars *ip, *ip1;
- MomDPars *dp, *dp1;
- {
- int i, n, m, nf, ng;
-
- n = ip->max.n;
- m = ip->max.m;
- nf = 1 + n + n * n;
- ng = m + n * m;
-
- for (i = 0; i < n; i++) x1[i] = x[i];
- for (i = 0; i < nf; i++) f1[i] = f[i];
- for (i = 0; i < ng; i++) g1[i] = g[i];
- *ip1 = *ip;
- *dp1 = *dp;
- }
-
- /************************************************************************/
- /** **/
- /** Laplace Margins **/
- /** **/
- /************************************************************************/
-
- void lapmar1front(ff, gf, x, typx, fvals, ipars, dpars, xmar, ymar, nmar)
- char **ff, **gf;
- double *x, *typx, *fvals, *xmar, *ymar;
- MaxIPars *ipars;
- MaxDPars *dpars;
- int *nmar;
- {
- char *msg;
- int i, n, m, mindex;
- double h, loglap0, loglap1, xmode, stdev, sigmadata, ctarget[1];
- double *fvals1, *x1, *cvals, *cvals1, *fvals2, *x2, *cvals2;
- MaxDPars dp1, dp2, *dpars1 = &dp1, *dpars2 = &dp2;
- MaxIPars ip1, ip2, *ipars1 = &ip1, *ipars2 = &ip2;
-
- n = ipars->n;
- m = 1;
- h = dpars->h;
-
- x1 = (double *) S_alloc(n + 1, sizeof(double));
- fvals1 = (double *) S_alloc(1 + n + n * n, sizeof(double));
- cvals = (double *) S_alloc(m + n * m, sizeof(double));
- cvals1 = (double *) S_alloc(m + n * m, sizeof(double));
- x2 = (double *) S_alloc(n + 1, sizeof(double));
- fvals2 = (double *) S_alloc(1 + n + n * n, sizeof(double));
- cvals2 = (double *) S_alloc(m + n * m, sizeof(double));
-
- maxfront(ff, nil, nil, x, typx, fvals, nil, nil, nil,
- ipars, dpars, nil, &msg);
- cpmarpars(x, fvals, cvals, ipars, dpars, x1, fvals1, cvals1, ipars1, dpars1);
- loglapfront(fvals1, nil, ipars1, dpars1, &loglap0);
- cpmarpars(x, fvals, cvals, ipars, dpars, x1, fvals1, cvals1, ipars1, dpars1);
- moms1front(gf, &n, &m, x1, fvals1 + n + 1, &xmode, &stdev, &sigmadata,
- &h, typx);
-
- ipars->k = 1;
- ipars->vals_suppl = FALSE;
- ctarget[0] = xmode;
- maxfront(ff, nil, gf, x, typx, fvals, nil, cvals, ctarget,
- ipars, dpars, nil, &msg);
-
- for (mindex = 0; mindex < *nmar && xmar[mindex] <= xmode; mindex++);
-
- cpmarpars(x, fvals, cvals, ipars, dpars, x1, fvals1, cvals1, ipars1, dpars1);
- for (i = mindex; i >= 0; i--) {
- ctarget[0] = xmar[i];
- maxfront(ff, nil, gf, x1, typx, fvals1, nil, cvals1, ctarget,
- ipars1, dpars1, nil, &msg);
- cpmarpars(x1, fvals1, cvals1, ipars1, dpars1, x2,
- fvals2, cvals2, ipars2, dpars2);
- loglapfront(fvals2, cvals2, ipars2, dpars2, &loglap1);
- ymar[i] = exp(loglap1 - loglap0);
- }
- cpmarpars(x, fvals, cvals, ipars, dpars, x1, fvals1, cvals1, ipars1, dpars1);
- for (i = mindex + 1; i < *nmar; i++) {
- ctarget[0] = xmar[i];
- maxfront(ff, nil, gf, x1, typx, fvals1, nil, cvals1, ctarget,
- ipars1, dpars1, nil, &msg);
- cpmarpars(x1, fvals1, cvals1, ipars1, dpars1, x2,
- fvals2, cvals2, ipars2, dpars2);
- loglapfront(fvals2, cvals2, ipars2, dpars2, &loglap1);
- ymar[i] = exp(loglap1 - loglap0);
- }
- }
-
- static void cpmarpars(x, f, g, ip, dp, x1, f1, g1, ip1, dp1)
- double *x, *f, *g, *x1, *f1, *g1;
- MaxIPars *ip, *ip1;
- MaxDPars *dp, *dp1;
- {
- int i, n, k, nf, ng;
-
- n = ip->n;
- k = ip->k;
- nf = 1 + n + n * n;
- ng = k + n * k;
-
- for (i = 0; i < n; i++) x1[i] = x[i];
- for (i = 0; i < nf; i++) f1[i] = f[i];
- for (i = 0; i < ng; i++) g1[i] = g[i];
- *ip1 = *ip;
- *dp1 = *dp;
- }
- #endif /* SBAYES */
-
- #ifdef TODO
- get hessian from gradiant for analytical gradiants
- avoid repeated derivative calls in mimimize.
- 2d margins
- use pos. definiteness info in margins
- #endif TODO
-