https://github.com/cran/mvtnorm
Raw File
Tip revision: 427535142f38f9c7b81db6dee073196a8d0159b3 authored by Torsten Hothorn on 07 December 2012, 00:00:00 UTC
version 0.9-9994
Tip revision: 4275351
miwa.c

/*
 * Test program for calculating
 *    orthant probabilities.
 *
 * Command format:
 *   orthant m [ngrd [rho [h]]]
 *
 * Required functions
 *   void gridcalc()
 *   double orthant()
 *
 * Note
 *   An exact value is given only for rho=0.5 and h=0.
 * 
 */

#include  "miwa.h"
#define UEPS    1.0e-8
#define PEPS    1.0e-8

#define SMLHGRD 16  /* small number of grid points */
extern void gridcalc(struct GRID *grid);

extern double orthant(int m, double r[][MAXM][MAXM], double h[][MAXM],
                      int *ncone, struct GRID *grid);


#define REPS    (1.0e-6)  /* rho < REPS means rho=0 */

extern double orschm(int m, double *r, double *h, struct GRID *g);

/* coefficients b[] for cubic polynomial */
static void b_calc(int j, struct GRID *g, double *f, double *df,
                   double *b)
{
  b[0] = f[j-1];
  b[1] = df[j-1];
  b[2] = 3.0*(-f[j-1]+f[j])/g->w2[j] - (2.0*df[j-1]+df[j])/g->w[j];
  b[3] = 2.0*(f[j-1]-f[j])/g->w3[j] + (df[j-1]+df[j])/g->w2[j];
}


/* integral of f(x)*phi(x) from g->z[j-1] to g->z[j-1]+dz */
static double dlt_f(int j, struct GRID *g,
                    double np, double nd, double dz,
                    double *b)
{
  double q0, q1, q2, q3;

  q0 = np - g->p[j-1];
  q1 = -nd + g->d[j-1] - g->z[j-1]*q0;
  q2 = -dz*nd - g->z[j-1]*q1 + q0;
  q3 = -dz*dz*nd - g->z[j-1]*q2 + 2.0*q1;
  return (b[0]*q0 + b[1]*q1 + b[2]*q2 + b[3]*q3);
}


double orschm(int m, double *r, double *h, struct GRID *g)
{
  static int    id[MAXM][MAXGRD];
  static double c[MAXM], d[MAXM], b[MAXGRD][4], fgrd[MAXGRD];
  static double z[MAXM][MAXGRD], np[MAXM][MAXGRD], nd[MAXM][MAXGRD];
  static double f[MAXGRD], df[MAXGRD];
  int    i, j, k, ngrd=g->n;
  double detr, detr1=1.0, dz, fbase;

  /* Cholesky decompositon */
  for(i=1; i<m; i++){

    /* detr=det/det1: determinant ratio */
    detr = 1.0 - r[i-1]*r[i-1]/detr1;
    c[i] = h[i]/sqrt(detr);
    d[i] = -r[i-1]/sqrt(detr1*detr);
    detr1 = detr;
  }


  /* normal densities and probabilities at upper limits
   * z[i][j]:  upper limit of integration for the next stage
   * nd[i][j]: normal density at z[i][j]
   * np[i][j]: lower probability at z[i][j]
   */
  for(i=1; i < m-1; i++)
    for(j=0; j <= ngrd; j++){
      z[i][j] = c[i] + d[i]*g->z[j];
      nd[i][j] = nrml_dn(z[i][j]);
      np[i][j] = nrml_cd(z[i][j]);
    }

  /* Check where z[i][k]=c[i]+d[i]*(g->z[k]) is located.
   *   id[i][k] = j      if g->z[j-1] < z[i][k] <= g->z[j]
   *   id[i][k] = 0      if z[i][k] <= g->z[0]=-8
   *   id[i][k] = ngrd+1 if 8=g->z[ngrd] < z[i][k]
   */
  for(i=1; i < m-1; i++){
    if(d[i] > 0){
      for(j=0, k=0; j <= ngrd; j++)
        for( ; z[i][k] <= g->z[j] && k <= ngrd; k++)
          id[i][k] = j;
      for( ; k <= ngrd; k++)
        id[i][k] = ngrd+1;
    }
    else{
      for(j=0, k=ngrd; j <= ngrd; j++)
        for( ; z[i][k] <= g->z[j] && k >= 0; k--)
          id[i][k] = j;
      for( ; k >= 0; k--)
        id[i][k] = ngrd+1;
    }
  }
  
  /* first stage: i=m-1 */
  for(j=0; j <= ngrd; j++){
    z[m-1][j] = c[m-1] + d[m-1]*g->z[j];
    f[j] = nrml_cd(z[m-1][j]);
    df[j] = d[m-1] * nrml_dn(z[m-1][j]);
  }

  /* intermediate stages: i=m-2, ..., 1 */
  for(i=m-2; i > 0; i--){

    /* integrated values fgrd[j] at g->z[j] */
    for(j=1, fgrd[0]=0.0; j <= ngrd; j++){
      b_calc(j, g, f, df, b[j]);
      fgrd[j] = fgrd[j-1]
        + b[j][0] * g->q[j][0] + b[j][1] * g->q[j][1]
        + b[j][2] * g->q[j][2] + b[j][3] * g->q[j][3];
    }

    for(k=0; k <= ngrd; k++){
      /* lower than g->z[0]=-8 */
      if(id[i][k] < 1)
        f[k] = df[k] = 0.0;
      /* greater than g->z[ngrd]=8 */
      else if(id[i][k] > ngrd){
        df[k] = 0.0;
        f[k] = fgrd[ngrd];
      }
      /* between g->z[0] and g->z[ngrd] */
      else{
        j = id[i][k];
        dz = z[i][k] - g->z[j-1];
        df[k] =  nd[i][k] * d[i]
          * (b[j][0] + dz*(b[j][1] + dz*(b[j][2] + dz*b[j][3])));
        f[k] = fgrd[j-1]
          + dlt_f(j, g, np[i][k], nd[i][k], dz, b[j]);
      }
    }
  }

  /* last stage: h[0] = c[0] */
  for(j=1, fbase=0.0; j <= ngrd && g->z[j] <= h[0]; j++){
    b_calc(j, g, f, df, b[j]);
    fbase += b[j][0] * g->q[j][0] + b[j][1] * g->q[j][1]
      + b[j][2] * g->q[j][2] + b[j][3] * g->q[j][3];
  }
  if(j <= ngrd && g->z[j-1] < h[0]){
    b_calc(j, g, f, df, b[j]);
    np[0][0] = nrml_cd(h[0]);
    nd[0][0] = nrml_dn(h[0]);
    dz = h[0] - g->z[j-1];
    fbase += dlt_f(j, g, np[0][0], nd[0][0], dz, b[j]);
  }

  return (fbase);
}


double orthant(int m, double r[][MAXM][MAXM], double h[][MAXM],
               int *ncone, struct GRID *grid)
{
  int     i, j, u, v, ns, nzs, stg, srch, plus;
  int     nz[MAXM][MAXM], sgn[MAXM][MAXM], nxt[MAXM], dlt[MAXM];
  double  rvec[MAXM], hvec[MAXM], c[MAXM];
  double  p=0.0, r1k, r1ik, rik, ruk;

  /* initialisation */
  stg = 0;      /* stage pointer: 0 <= stg <= m-2 */
  srch = 1;     /* swich for searching non-zero coefficients */
  dlt[0] = 1;   /* plus or minus contribution of each cone */
  *ncone = 0;   /* number of sub-cones */

  /* rvec[]: sub-diagonal cor coef for orthoscheme prob
   * hvec[]: upper bound vecter for orthoscheme prob
   */
  hvec[0] = h[0][0];

  while(stg >= 0){

    /* calculate orthoscheme probability */
    if(stg == m-2){
      rvec[stg] = r[stg][stg][stg+1];
      hvec[stg+1] = h[stg][stg+1];
      p += dlt[stg]*orschm(m, rvec, hvec, grid);
      (*ncone)++;
      srch = 0;
      stg--;
    }

    /* search for non-zero cor coeff rho[] */
    else if(srch == 1){
      for(plus=nz[stg][0]=0, j=1, i=stg+1; i < m; i++){
        if(r[stg][stg][i] > REPS){
          plus = 1;         /* plus=0 if no positive rho's */
          nz[stg][0]++;     /* nz[stg][0] = no of non-zero rho's */
          nz[stg][j] = i;   /* address of non-zero rho */
          sgn[stg][j] = 1;  /* sign of rho */
          j++;
        }
        else if(r[stg][stg][i] < -REPS){
          nz[stg][0]++;
          nz[stg][j] = i;
          sgn[stg][j] = -1;
          j++;
        }
      }

      if(nz[stg][0] == 0)
        nxt[stg] = 0;
      else{
        nxt[stg] = 1;
        /* if all the non-rero rho's are negative */
        if(plus == 0)
          for(j=1; j <= nz[stg][0]; j++)
            sgn[stg][j] = 1;
      }

      srch = 0;
    }

    /* back to the previous stage */
    else if(nxt[stg] > nz[stg][0])
      stg--;

    /* if all cor coeff's are zero */
    else if(nz[stg][0] == 0){
      rvec[stg] = 0.0;
      hvec[stg+1] = h[stg][stg+1];
      for(i=stg+2; i < m; i++)
        h[stg+1][i] = h[stg][i];
      for(i=stg+1; i < m-1; i++)
        for(j=i+1; j < m; j++)
          r[stg+1][i][j] = r[stg][i][j];
      dlt[stg+1] = dlt[stg];
      nxt[stg]++;
      stg++;
      srch = 1;
    }

    /* calculate cor coeff's for the next stage */
    else{
      ns=nxt[stg];
      nzs=nz[stg][ns];

      r1k = r[stg][stg][nzs];
      rvec[stg] = sgn[stg][ns] * r1k;
      hvec[stg+1] = sgn[stg][ns] * h[stg][nzs];
      for(i=stg+1, j=stg+2; j < m; i++, j++){
        if(i == nzs)
          i++;
        r1ik = r[stg][stg][i]/r1k;
        if (i < nzs)
          rik = r[stg][i][nzs];
        else
          rik = r[stg][nzs][i];

        c[j] = sqrt(1.0 - 2.0*r1ik*rik + r1ik*r1ik);
        h[stg+1][j] = (h[stg][i] - r1ik*h[stg][nzs])/c[j];
        r[stg+1][stg+1][j] = sgn[stg][ns]/c[j]*(rik - r1ik);
      }
        
      for(i=stg+1, j=stg+2; j < m-1; i++, j++){
        if(i == nzs)
          i++;
        for(u=i+1, v=j+1; v < m; u++, v++){
          if(u == nzs)
            u++;
          if (i < nzs)
            rik = r[stg][i][nzs];
          else
            rik = r[stg][nzs][i];
          if (u < nzs)
            ruk = r[stg][u][nzs];
          else
            ruk = r[stg][nzs][u];

          r[stg+1][j][v] = 
            (r[stg][i][u]
             - r[stg][stg][u]/r1k*rik - r[stg][stg][i]/r1k*ruk
             + r[stg][stg][i]*r[stg][stg][u]/r1k/r1k) /c[j]/c[v];
        }
      }          
      
      dlt[stg+1] = sgn[stg][ns]*dlt[stg];
      nxt[stg]++;
      stg++;
      srch = 1;
    }
  }

  return (p);
}


#define MAXITR  51  /* maximum number of iterations */


double nrml_lq(double p, double ueps, double peps, int *itr)
{
  double y, u, f, f1, f2, r, delta;

  y = -log(4.0 * p * (1.0 - p));
  u = sqrt(y * (2.0611786 - 5.7262204/(y+11.640595)));
  if(p < 0.5)
    u = -u;

  for(*itr=1, delta=0.0; *itr < MAXITR; (*itr)++){
    f = nrml_cd(u) - p;
    if(fabs(delta) < ueps && fabs(f) < peps)
      break;

    f1 = exp(-0.5*u*u) * 0.39894228040143268;
    f2 = -u * f1;
    r = f1*f1 - 2*f*f2;
    if(r > 0)
      delta = 2*f / (-f1-sqrt(r));
    else
      delta = -f1/f2;

    u += delta;
  }
  return(u);
}


void gridcalc(struct GRID *g)
{
  int     hgrd=(g->n)/2, ngrd=2*hgrd, nres=(hgrd<100)?3:6;
  int     i, itr;
  double  pdelta;

  g->z[0] = -8.0;
  g->z[hgrd] = 0.0;
  g->z[ngrd] = 8.0;
  g->p[0] = 0.0;
  g->p[hgrd] = 0.5;
  g->p[ngrd] = 1.0;
  g->d[0] = 0.0;
  g->d[hgrd] = 0.3989422804014327;
  g->d[ngrd] = 0.0;


  /* If #{grid points} is very small,
   *   integrate between [-5, 5].
   */
  if(hgrd < SMLHGRD){
    g->z[0] = -5.0;
    g->z[ngrd] = 5.0;
    nres = 0;
  }

  pdelta = (nrml_cd(2.5)-0.5) / (hgrd-nres);
    
  for(i=1; i < hgrd-nres; i++){
    g->z[hgrd+i] = 2.0*nrml_lq(0.5+i*pdelta, UEPS, PEPS, &itr);
    g->z[hgrd-i] = - g->z[hgrd+i];
    g->p[hgrd+i] = nrml_cd(g->z[hgrd+i]);
    g->p[hgrd-i] = 1.0 - g->p[hgrd+i];
    g->d[hgrd-i] = g->d[hgrd+i] = nrml_dn(g->z[hgrd+i]);
  }    
  
  for(i=0; i < nres; i++){
    g->z[ngrd-nres+i] = 5.0 + i*3.0/nres;
    g->z[nres-i] = - g->z[ngrd-nres+i];
    g->p[ngrd-nres+i] = nrml_cd(g->z[ngrd-nres+i]);
    g->p[nres-i] = 1.0 - g->p[ngrd-nres+i];
    g->d[nres-i] = g->d[ngrd-nres+i] = nrml_dn(g->z[ngrd-nres+i]);
  }
  
  g->w[0] = g->w2[0] = g->w3[0] = 0.0;
  g->q[0][0] = g->q[0][1] = g->q[0][2] = g->q[0][3] = 0.0;
  for(i=1; i <= ngrd; i++){
    g->w[i] = g->z[i] - g->z[i-1];
    g->w2[i] = g->w[i] * g->w[i];
    g->w3[i] = g->w[i] * g->w2[i];
    g->q[i][0] = g->p[i] - g->p[i-1];
    g->q[i][1] = - g->d[i] + g->d[i-1] - g->z[i-1] * g->q[i][0];
    g->q[i][2] = - g->w[i] * g->d[i]
      - g->z[i-1] * g->q[i][1] + g->q[i][0];
    g->q[i][3] = - g->w2[i] * g->d[i]
      - g->z[i-1] * g->q[i][2] + 2.0 * g->q[i][1];
    if (i == 1) Rprintf("");
  }

  g->n = ngrd;
  return;
}

int checkall(int *vector,int length,int value)
 {
       int returnvalue=1, i = 0;
       for (i=0; i< length ; i++)
       {
           if (vector[i]!=value)
           {
             returnvalue=0;
           }
       }
      return(returnvalue);
 }


/*
 *  interface to R
 * 
 *  Author: Xuefei Mi <mi@biostat.uni-hannover.de>
 *
 */
 
SEXP C_miwa(SEXP steps, SEXP corr, SEXP upper, SEXP lower, SEXP infin) {

    SEXP answer;
    int dim;
    /* int diml; ### was not used */
    int i,ii, j,k,l,i5,i6,i7,i8, ncone;
    int infinlength;

/* 
infinvalue is used to take the value of infin.
*/
    
    
    double *dupper,*dlower, *dcorr, output,*f, r[MAXM][MAXM][MAXM], hv[MAXM][MAXM], d[MAXM][MAXM];
    int *infinvalue;
    struct GRID   grid;

    dim = LENGTH(upper);
    dupper = REAL(upper);
    dcorr = REAL(corr);
    /* diml = LENGTH(lower); ### was not used */
    dlower = REAL(lower);
    infinvalue = INTEGER(infin);
    infinlength = LENGTH(infin);

 
  for (i = 0; i < dim - 1; i++) {
        for(j = i + 1; j < dim; j++) {
            r[0][i][j] = dcorr[i * dim + j];
        
          /* debug checking for correlation matrix
            Rprintf("r %f\n", r[0][i][j]);
          */
        }
    }

    grid.n = INTEGER(steps)[0];
    gridcalc(&grid);

 
 PROTECT(answer = allocVector(REALSXP, 1));



/*
 branch happens here. if only one sided, then just call orthant function once

*/   
 if (checkall(infinvalue,infinlength,-1)==1 )
 {
  REAL(answer)[0]=1;
 }else if (checkall(infinvalue,infinlength,0)==1 )
 {
    for (i = 0; i < dim; i++) 
    {
        hv[0][i] = dupper[i];
    }
    REAL(answer)[0] = orthant(dim, r, hv, &ncone, &grid);
  
 
 }else if (checkall(infinvalue,infinlength,1)==1 )
 {
    for (i = 0; i < dim; i++) 
    {
        hv[0][i] = -dlower[i];
    }
    REAL(answer)[0] = orthant(dim, r, hv, &ncone, &grid);
  
 
 } else 
 {
    for (i = 0; i < dim; i++) 
    {
        hv[0][i] = dupper[i];
    }
    f=dlower;
  
  /*
                   # circle number 0
  */                   
                   output= orthant(dim, r, hv, &ncone, &grid);
  /*
                   # circle number 1
  */                
                   for (i = 0; i < dim; i++)
                   {
                     for (ii = 0; ii < dim; ii++) 
                          {
                             d[0][ii] = dupper[ii];
                           }
                     d[0][i]=f[i];
                    output=output-orthant(dim, r, d, &ncone, &grid);
                   }
  /*          
                   # circle number 2
  */           
                   for (i = 0; i < (dim-1) ; i++)
                   {
                     for (j=(i+1); j < dim; j++ )
                     {
                         for (ii = 0; ii < dim; ii++) 
                               {
                                  d[0][ii] = dupper[ii];
                               }
                    d[0][i]=f[i];
                    d[0][j]=f[j];
                    output=output + orthant(dim, r, d, &ncone, &grid);
                    }
                   }
  /* 
                   # circle number 3
  */                 
                     if (dim>2) 
                     {
                      for (i = 0; i < (dim-2) ; i++ )
                      {
                       for (j=(i+1); j < (dim-1); j++ )
                       {
                         for (k=(j+1); k < dim; k++)
                           {
                          
                           for (ii = 0; ii < dim; ii++) 
                               {
                                  d[0][ii] = dupper[ii];
                               }
                              d[0][i]=f[i];
                              d[0][j]=f[j];
                              d[0][k]=f[k];
                             output=output - orthant(dim, r, d, &ncone, &grid);
                           }
                        }   
                       }
                     }
                  
                     if (dim>3) 
                     {
                      for (i = 0; i < (dim-3) ; i++)
                      {
                        for (j=(i+1); j < (dim-2); j++ )
                       {
                         for (k=(j+1); k < (dim-1); k++)
                           {
                            for (l=(k+1); l < (dim); l++) 
                             {
                             
                            
                                 for (ii = 0; ii < dim; ii++) 
                                     {
                                        d[0][ii] = dupper[ii];
                                     }
                                    d[0][i]=f[i];
                                    d[0][j]=f[j];
                                    d[0][k]=f[k];
                                    d[0][l]=f[l];
                                 
                                  output=output+orthant(dim, r, d, &ncone, &grid);
                              }
                           }
                        }   
                       }
                     }
                  
                    if (dim>4) 
                     {
                                           
                         for (i5 = 0; i5 < (dim-4) ; i5++)
                      {        
                          for (i =(i5+1); i < (dim-3) ; i++)
                      {
                        for (j=(i+1); j < (dim-2); j++ )
                       {
                         for (k=(j+1); k < (dim-1); k++)
                           {
                            for (l=(k+1); l < (dim); l++) 
                             {
                                
                            
                                 for (ii = 0; ii < dim; ii++) 
                                     {
                                        d[0][ii] = dupper[ii];
                                     }
                                    d[0][i5]=f[i5];
                                    d[0][i]=f[i];
                                    d[0][j]=f[j];
                                    d[0][k]=f[k];
                                    d[0][l]=f[l];
                                 
                            output=output-orthant(dim, r, d, &ncone, &grid);
                             }
                           }
                        }   
                       }
                       }
                     }
                   
                    
                    if (dim>5) 
                     {
                     
                          for (i6 = 0; i6 < (dim-5) ; i6++)
                      {                 
                          for (i5 = (i6+1); i5 < (dim-4) ; i5++)
                      {        
                          for (i =(i5+1); i < (dim-3) ; i++)
                      {
                          for (j=(i+1); j < (dim-2); j++ )
                       {
                          for (k=(j+1); k < (dim-1); k++)
                           {
                            for (l=(k+1); l < (dim); l++) 
                             {
                            
                             for (ii = 0; ii < dim; ii++) 
                                     {
                                        d[0][ii] = dupper[ii];
                                     }
                                    d[0][i6]=f[i6];
                                    d[0][i5]=f[i5];
                                    d[0][i]=f[i];
                                    d[0][j]=f[j];
                                    d[0][k]=f[k];
                                    d[0][l]=f[l];
                                 
                            output=output+orthant(dim, r, d, &ncone, &grid);
                            
                            
                             }
                           }
                        }   
                       }
                       }
                     }
                     }
                     
                      
                    if (dim>6) 
                     { 
                       
                          for (i7 = 0; i7 < (dim-6) ; i7++)
                      {        
                          for (i6 = (i7+1); i6 < (dim-5) ; i6++)
                      {                 
                          for (i5 = (i6+1); i5 < (dim-4) ; i5++)
                      {        
                          for (i =(i5+1); i < (dim-3) ; i++)
                      {
                          for (j=(i+1); j < (dim-2); j++ )
                       {
                          for (k=(j+1); k < (dim-1); k++)
                           {
                            for (l=(k+1); l < (dim); l++) 
                             {
                            
                            
                             for (ii = 0; ii < dim; ii++) 
                                     {
                                        d[0][ii] = dupper[ii];
                                     }
                                    d[0][i7]=f[i7];
                                    d[0][i6]=f[i6];
                                    d[0][i5]=f[i5];
                                    d[0][i]=f[i];
                                    d[0][j]=f[j];
                                    d[0][k]=f[k];
                                    d[0][l]=f[l];
                                 
                            output=output-orthant(dim, r, d, &ncone, &grid);
                             
                             }
                           }
                        }   
                       }
                       }
                     }
                     }
                     }
                     
                     if (dim>7) 
                     { 
                                            
                          for (i8 = 0; i8 < (dim-7) ; i8++)
                      {     
                          for (i7 = (i8+1); i7 < (dim-6) ; i7++)
                      {        
                          for (i6 = (i7+1); i6 < (dim-5) ; i6++)
                      {                 
                          for (i5 = (i6+1); i5 < (dim-4) ; i5++)
                      {        
                          for (i =(i5+1); i < (dim-3) ; i++)
                      {
                          for (j=(i+1); j < (dim-2); j++ )
                       {
                          for (k=(j+1); k < (dim-1); k++)
                           {
                            for (l=(k+1); l < (dim); l++) 
                             {
                                                      
                             for (ii = 0; ii < dim; ii++) 
                                     {
                                        d[0][ii] = dupper[ii];
                                     }
                                    d[0][i8]=f[i8];
                                    d[0][i7]=f[i7];
                                    d[0][i6]=f[i6];
                                    d[0][i5]=f[i5];
                                    d[0][i]=f[i];
                                    d[0][j]=f[j];
                                    d[0][k]=f[k];
                                    d[0][l]=f[l];
                                 
                            output=output+orthant(dim, r, d, &ncone, &grid);
                             
                             }
                           }
                        }   
                       }
                       }
                     }
                     }
                     }
                     }
                     
                     
                    
                  
             
              
            
  
  
     REAL(answer)[0]=output;
 }  
    UNPROTECT(1);


    return(answer);

}
back to top