Skip to content
Snippets Groups Projects
volume.c 55.26 KiB
#include <stdlib.h>
#include <ctype.h>
#include <math.h>
#include <stdio.h>
/*--------------------------------------------------------------

    This file contains six recursive C routines for calculating
    the volume and derivatives of a convex polyhedron in n 
    dimensions. The routines volume, volumef, volumeb and dvda are 
    fortran callable interfaces to their C counterparts cvolume,
    cvolumeb and cdvda.

    ROUTINE      COMMENT			CALLS 

    cvolume	 calculates volume of region    cvolume 
                 which satisfies Ax <= b.

    cvolumef	 calculates volume of region    cvolumef 
                 which satisfies Ax <= b.
                 (faster version, see below)

    cvolumeb     calculates volume and the      cvolume
                 derivative d(vol)/db(0).

    cdvda        calculates derivatives		cdvda, cvolumeb, 
                 d(vol)/da(0,j) (j=1,n).        & cvolumebj

    cdvdaf        calculates derivatives	cdvdaf, cvolumeb, 
                 d(vol)/da(0,j) (j=1,n).        & cvolumebj
                 (faster version, see below)

    cvolumebj    calculates partial volumes
                 and derivatives d(vol)/d(b(j)
                 (j=1,n). (called by cdvda.)

    Here b(j) is the jth element of vector b, and a(i,j) is the
    (i,j)th coefficient of the matrix A corresponding to the
    ith constraint and the jth dimension.

    The two faster versions cvolumef and cdvdaf do not continue down
    the recursive tree if b(j) = 0 for any j at any time. This avoids
    extra work but restricts the applicability of the routines to
    cases where the origin does not pass through any inconsistent
    constraints.
     
				Malcolm Sambridge, April 1995.

  --------------------------------------------------------------*/

/*--------------------------------------------------------------

			ROUTINE: cvolume

    This routine calculates the `volume' in dimension n of the region
    bounded by a set of m linear inequality constraints of the form
    A x <= b, where a has m rows and n columns and is given by a(m,n),
    b is the n-vector and is contained in b(m). The recursive formula
    of Lasserre (1983) is used. Redundant constraints are allowed 
    If the inequality constraints are inconsistent then the volume 
    is returned as zero.  If the original polyhedron is unbounded 
    then a warning is issued and the volume is return as -1.0 
    (even though it is undefined). 

			Jean Braun and Malcolm Sambridge, Jan 1995.

    Lasserre, J. B., 1983. "An analytical expression and an Algorithm
    for the Volume of a Convex Polyhedron in R^n.", JOTA, vol. 39, 
    no. 3, 363-377.

  --------------------------------------------------------------*/

float cvolume (a,b,m,n,mmax,nmax)

int   *n, *m, *mmax, *nmax;
float *a, *b; 

{

float v,amax,pivot;
int   i,j,t,k,l;
int   jj,kk;
float   *ai, *aj, *ajt, *apjj, *bi;
int   kmm,tmm;
int   nn,mm,nn_max,mm_max;
int   nm1,mm1;
float  *ap, *bp;
int   firstmin,firstmax;
float bmin,bmax,bb;
float partialv;

nn= *n;
mm= *m;
nn_max= *nmax;
mm_max= *mmax;

/* one-dimensional case (full reduction) */

if (nn == 1) 
  {
  firstmin=0;
  firstmax=0;
  for (l=0;l<mm;l++)
    {
    if ( *(a+l) > 0.) 
      {
      bb= *(b+l)/ *(a+l);
      if (firstmin==0) {firstmin=1;bmin=bb;}
      else if (bb<bmin) bmin=bb;
      }
    else if ( *(a+l) < 0.)
      {
      bb= *(b+l)/ *(a+l);
      if (firstmax==0) {firstmax=1;bmax=bb;}
      else if (bb>bmax) bmax=bb;
      }
    else if ( *(b+l) < 0.)         /* Constraints are inconsistent */
      { 
       printf("Inconsistent constraints found after reduction to n = 1 \n");
       return(0.); 
      }
    }
  v=0.;
  if (firstmin*firstmax == 1) v=bmin-bmax;
  else 
    {
/*     printf("Volume is unbounded at 1-D; volume returned as -1\n");*/
     return(-1.0);
    }

  if (v<0.) {v=0.;} 

  return(v);
  }

nm1=nn-1;
mm1=mm-1;
v=0.;

for (i=0;i<mm;i++)
  {
   ai=a+i;
   bi=b+i;

/* find largest pivot */

  amax=0.;
  for (j=0;j<nn;j++) 
    if (fabs( *(ai+j*mm_max)) >= amax) {amax= fabs( *(ai+j*mm_max)); t=j;}
  tmm=t*mm_max;
  pivot=*(ai+tmm);

/* finds contribution to v from this pivot (if not nil) */

  if (amax == 0.)
  {
                                 /* Constraint is inconsistent */

    if ( *(bi) < 0.) 
      { printf("Constraint %d is inconsistent\n",i+1); return(0.); }

                                 /* otherwise constraint is redundant */

    printf("Constraint %d is redundant\n",i+1); 
  }
  else
  {

/* allocate memory */

  ap = (float *) malloc((sizeof (float))*nm1*mm1);
  bp = (float *) malloc((sizeof (float))*mm1);

/* reduce a and b into ap and bp eliminating variable t and constraint i */

  jj=-1;
    for (j=0;j<mm;j++)
      if (j != i)
      {
      jj=jj+1;
      aj=a+j;
      ajt=aj+tmm;
      *(bp+jj)= *(b+j) - *(bi) * *(ajt) / pivot;
      apjj=ap+jj;
      kk=-1;
      for (k=0;k<nn;k++)
        if (k != t)
        {
        kk=kk+1;
        kmm=k*mm_max;
        *(apjj+kk*mm1)= *(aj+kmm)- *(ajt) * *(ai+kmm)/ pivot;
        }
      }
  
/* add contribution to volume from volume calculated in smaller dimension */

  partialv=cvolume(ap,bp, &mm1, &nm1, &mm1, &nm1);
  if(partialv == -1.0)return(-1.0);
  v=v+ *(bi)/amax*partialv/nn; 

  free(ap);
  free(bp);
  }
  }

return(v);

}

/*--------------------------------------------------------------
			ROUTINE: volume

   A dummy routine used to call cvolume from a fortran routine 


			Jean Braun and Malcolm Sambridge, Jan 1995.

----------------------------------------------------------------*/

void volume_();
void volume();

void volume_(a,b,m,n,mmax,nmax,result)
     int   *n, *m, *mmax, *nmax;
     float *a, *b;
     float *result; 
{
  volume (a,b,m,n,mmax,nmax,result);
}

void volume (a,b,m,n,mmax,nmax,result)
     int   *n, *m, *mmax, *nmax;
     float *a, *b;
     float *result; 
{
  *result=cvolume(a,b,m,n,mmax,nmax);
}

/*--------------------------------------------------------------

			ROUTINE: cvolumeb

    This routine calculates the `volume' in dimension n of the region
    bounded by a set of m linear inequality constraints of the form
    A x <= b, where a has m rows and n columns and is given by a(m,n),
    b is the n-vector and is contained in b(m). The recursive formula
    of Lasserre (1983) is used. Redundant constraints are allowed and
    a warning is issued if any are encountered. If the inequality 
    constraints are inconsistent then the volume is returned as zero.
    If the original polyhedron is unbounded then a warning is issued
    and the volume is return as zero (even though it is undefined). 

    This version also calculates the derivative of the volume with
    respect to the parameter b(0) using the simple formula of
    Lasserre (1983). If *opt == 2 then only the derivative is 
    calculated and not the volume.

    This routine is a variation from the routine `cvolume'.

    Calls are made to routine cvolume.

				Malcolm Sambridge, March 1995.


  --------------------------------------------------------------*/

float cvolumeb (a,b,m,n,mmax,nmax,opt,dvdb)

int   *n, *m, *opt, *mmax, *nmax;
float *a, *b; 
float *dvdb; 

{

float v,amax,pivot;
int   i,j,t,k,l;
int   jj,kk;
float   *ai, *aj, *ajt, *apjj, *bi;
int   kmm,tmm;
int   nn,mm,nn_max,mm_max;
int   nm1,mm1;
int   lmin,lmax;
float  *ap, *bp;
int   firstmin,firstmax;
float bmin,bmax,bb;
float vol;

nn= *n;
mm= *m;
nn_max= *nmax;
mm_max= *mmax;

/* one-dimensional case (full reduction) */

if (nn == 1) 
  {
  firstmin=0;
  firstmax=0;
  lmax=0;
  lmin=0;
  for (l=0;l<mm;l++)
    {
    if ( *(a+l) > 0.) 
      {
      bb= *(b+l)/ *(a+l);
      if (firstmin==0) {firstmin=1;bmin=bb;lmin=l;}
      else if (bb<bmin) {bmin=bb;lmin=l;}
      }
    else if ( *(a+l) < 0.)
      {
      bb= *(b+l)/ *(a+l);
      if (firstmax==0) {firstmax=1;bmax=bb;lmax=l;}
      else if (bb>bmax) {bmax=bb;lmax=l;}
      }
    else if ( *(b+l) < 0.) 
      { 
                              /* Constraints are inconsistent.  
                                 Set volume and derivative to zero. */

       printf("Inconsistent constraints found after reduction to n = 1 \n");
      *dvdb = 0.; 
      return(0.);
      }
    }
  v=0.;
  *dvdb = 0.; 
  if (firstmin*firstmax == 1) v=bmin-bmax;
  else 
    {
     printf("Volume is unbounded; volume returned as -1\n derivatives returned as zero\n");
     return(-1.0);
    }

  if (v<0.) {v=0.;*dvdb=0.;} 
  else if (v>0. && lmin == 0) *dvdb = 1. / *a;
  else if (v>0. && lmax == 0) *dvdb = -1. / *a;
  return(v);
  }

nm1=nn-1;
mm1=mm-1;
v=0.;

/*  perform main loop over constraints */

for (i=0;i<mm;i++)
  {
   ai=a+i;
   bi=b+i;
/* find largest pivot */

  amax=0.;
  for (j=0;j<nn;j++) 
    if (fabs( *(ai+j*mm_max)) >= amax) {amax= fabs( *(ai+j*mm_max)); t=j;}
  tmm=t*mm_max;
  pivot=*(ai+tmm);

/* finds contribution to v from this pivot (if not nil) */

  if (amax == 0.)
  {
                                 /* Constraint is inconsistent */

    if ( *(bi) < 0.) 
       {
        printf("Constraint %d is inconsistent\n",i+1); 
        return(0.);
       } 

                                 /* otherwise constraint is redundant */

    printf("Constraint %d is redundant\n",i+1); 
  }
  else
  {

/* allocate memory */

  ap = (float *) malloc((sizeof (float))*nm1*mm1);
  bp = (float *) malloc((sizeof (float))*mm1);

/* reduce a and b into ap and bp eliminating variable t and constraint i */

  jj=-1;
    for (j=0;j<mm;j++)
      if (j != i)
      {
      jj=jj+1;
      aj=a+j;
      ajt=aj+tmm;
      *(bp+jj)= *(b+j) - *(bi) * *(ajt) / pivot;
      apjj=ap+jj;
      kk=-1;
      for (k=0;k<nn;k++)
        if (k != t)
        {
        kk=kk+1;
        kmm=k*mm_max;
        *(apjj+kk*mm1)= *(aj+kmm)- *(ajt) * *(ai+kmm)/ pivot;
        }
      }
  
/* add contribution to volume from volume calculated in smaller dimension */

  vol=cvolume(ap,bp, &mm1, &nm1, &mm1, &nm1);
  if(vol == -1.0)
     {
      *dvdb = 0.;
      return(-1.0);
     }
  v=v+ *(bi)/amax*vol/nn;

  free(ap);
  free(bp);

/* calculate derivatives for first constraint only */

                                    /* calculate volume and derivative 
                                       with respect to b_0 */
  if (i == 0) *dvdb = vol/amax; 
                                    /* calculate derivative with respect 
                                       to b_0 but not volume */
  if (*opt == 2) return (0.); 
  }
  }

return(v);

}

/*--------------------------------------------------------------

			ROUTINE: volumeb

   A dummy routine used to call cvolumeb from a fortran routine 

----------------------------------------------------------------*/

void volumeb_();
void volumeb();

void volumeb_(a,b,m,n,mmax,nmax,opt,volume,dvdb) 
     int   *n, *m, *mmax, *nmax, *opt;
     float *a, *b;
     float *volume; 
     float *dvdb; 
{
  volumeb(a,b,m,n,mmax,nmax,opt,volume,dvdb);
}


void volumeb (a,b,m,n,mmax,nmax,opt,volume,dvdb)

int   *n, *m, *mmax, *nmax, *opt;
float *a, *b;
float *volume; 
float *dvdb; 

{

if(*opt == 1)                      /* calculate volume and derivative with
                                       respect to b(0) */
  {
   *volume=cvolumeb(a,b,m,n,mmax,nmax,opt,dvdb);
  }
else if(*opt == 2)                /* calculate derivative with respect to b(0) 
                                       but not volume */
  {
   *volume=cvolumeb(a,b,m,n,mmax,nmax,opt,dvdb);
  }
else 
  {
   printf(" Warning: routine volumeb called with an invalid option parameter\n");
   printf("          valid options are 1 and 2, option given = %d \n",*opt);
  } 

}

/*--------------------------------------------------------------

			ROUTINE: cvolumebj

    This routine only calculates the j-th outer loop of the recursive
    routine cvolumeb. It returns the partial volume for projection 
    onto the j-th constraint and the derivative of the total volume 
    with respect to parameter b(j) using the simple formula of 
    Lasserre(1983). (See cvolumeb for more details.)
    
    The reason for this routine is so that the derivatives
    with respect to parameter b(j) can be calculated and passed back
    to a fortran routine without creating and an extra array of size
    m (because only one derivative is calculated per call). In
    this way it also avoids recalculating the total volume m times
    (which would be the case if we used a simple variation of routine
     cvolumeb).

    To calculate the total volume this routine must be called m times
    and the partial volume summed

    Constraint j is determined by the value of *con.

    Calls are made to routine cvolume.

				Malcolm Sambridge, March 1995.

  --------------------------------------------------------------*/

float cvolumebj (a,b,m,n,mmax,nmax,con,dvdb)

int   *n, *m, *mmax, *nmax, con;
float *a, *b; 
float *dvdb; 

{

float v,amax,pivot;
int   i,j,t,k,l;
int   jj,kk;
float   *ai, *aj, *ajt, *apjj, *bi;
int   kmm,tmm;
int   nn,mm,nn_max,mm_max;
int   nm1,mm1;
int   lmin,lmax;
float  *ap, *bp;
int   firstmin,firstmax;
float bmin,bmax,bb;
float vol;

nn= *n;
mm= *m;
nn_max= *nmax;
mm_max= *mmax;

/* one-dimensional case (full reduction) */

if (nn == 1) 
  {
  firstmin=0;
  firstmax=0;
  lmax=0;
  lmin=0;
  for (l=0;l<mm;l++) 
    {
    if ( *(a+l) > 0.) 
      {
      bb= *(b+l)/ *(a+l);
      if (firstmin==0) {firstmin=1;bmin=bb;lmin=l;}
      else if (bb<bmin) {bmin=bb;lmin=l;}
      }
    else if ( *(a+l) < 0.)
      {
      bb= *(b+l)/ *(a+l);
      if (firstmax==0) {firstmax=1;bmax=bb;lmax=l;}
      else if (bb>bmax) {bmax=bb;lmax=l;}
      }
    else if ( *(b+l) < 0.) 
      { 
                              /* Constraints are inconsistent.  
                                 Set volume and derivative to zero. */

       printf("Inconsistent constraints found after reduction to n = 1 \n");
      *dvdb = 0.; 
      return(0.);
      }
    }
  v=0.;
  *dvdb = 0.; 
  if (firstmin*firstmax == 1) v=bmin-bmax;
  else 
    {
     printf("Volume is unbounded; volume returned as -1\n derivatives returned as zero\n");
     return(-1.0);
    }

  if (v<0.) {v=0.;*dvdb=0.;} 
  else if (v>0. && lmin == con) *dvdb = 1. / *(a+lmin);
  else if (v>0. && lmax == con) *dvdb = -1. / *(a+lmax);
  return(v);
  }

nm1=nn-1;
mm1=mm-1;
v=0.;

/*  perform main loop over constraints */

/* for (i=0;i<mm;i++) */

  i = con;

   ai=a+i;
   bi=b+i;

/* find largest pivot */

  amax=0.;
  for (j=0;j<nn;j++) 
    if (fabs( *(ai+j*mm_max)) >= amax) {amax= fabs( *(ai+j*mm_max)); t=j;}
  tmm=t*mm_max;
  pivot=*(ai+tmm);

/* finds contribution to v from this pivot (if not nil) */

  if (amax == 0.)
  {
                                 /* Constraint is inconsistent */

    if ( *(bi) < 0.) 
       {
        printf("Constraint %d is inconsistent\n",i+1); 
        *dvdb = 0.; 
        return(0.);
       } 

                                 /* otherwise constraint is redundant */

    printf("Constraint %d is redundant\n",i+1); 
    *dvdb = 0.; 
  }
  else
  {

/* allocate memory */

  ap = (float *) malloc((sizeof (float))*nm1*mm1);
  bp = (float *) malloc((sizeof (float))*mm1);

/* reduce a and b into ap and bp eliminating variable t and constraint i */
  jj=-1;
    for (j=0;j<mm;j++)
      if (j != i)
      {
      jj=jj+1;
      aj=a+j;
      ajt=aj+tmm;
      *(bp+jj)= *(b+j) - *(bi) * *(ajt) / pivot;
      apjj=ap+jj;
      kk=-1;
      for (k=0;k<nn;k++)
        if (k != t)
        {
        kk=kk+1;
        kmm=k*mm_max;
        *(apjj+kk*mm1)= *(aj+kmm)- *(ajt) * *(ai+kmm)/ pivot;
        }
      }
  
                                    /* calculate partial volume */ 

  vol=cvolume(ap,bp, &mm1, &nm1, &mm1, &nm1);
  if(vol == -1.0)
     {
      *dvdb = 0.;
      return(-1.0);
     }
  v=*(bi)/amax*vol/nn;

                                    /* calculate derivative of total volume
                                       with respect to current constraint */
  *dvdb = vol/amax; 

  free(ap);
  free(bp);
  }

return(v);

}

/*--------------------------------------------------------------

			ROUTINE: volumebj

   A dummy routine used to call cvolumebj from a fortran routine

----------------------------------------------------------------*/

void volumebj_();
void volumebj();

void volumebj_ (a,b,m,n,mmax,nmax,con,volume,dvdb) 
     int   *n, *m, *mmax, *nmax,*con;
     float *a, *b;
     float *volume; 
     float *dvdb; 
{
  volumebj(a,b,m,n,mmax,nmax,con,volume,dvdb);
}


void volumebj (a,b,m,n,mmax,nmax,con,volume,dvdb)

int   *n, *m, *mmax, *nmax,*con;
float *a, *b;
float *volume; 
float *dvdb; 

{

int tcon;
tcon = *con - 1;
                                    /* calculate partial volume and 
                                       derivative with respect to b(con) */

   *volume=cvolumebj(a,b,m,n,mmax,nmax,tcon,dvdb);

}
/*--------------------------------------------------------------

			ROUTINE: cdvda

    This routine calculates the derivative with respect to a(0,tdim)
    of the `volume' in dimension n of the region bounded by a set 
    of m linear inequality constraints of the form A x <= b, where 
    a has m rows and n columns and is given by a(m,n), b is the 
    n-vector and is contained in b(m). The derivative expression
    is recursive and derived from the formula of Lasserre (1983). 

    Redundant constraints are allowed and a warning is issued if any are 
    encountered. If the inequality constraints are inconsistent then the 
    derivative is returned as zero.  If any constraint is orthogonal to 
    the component a(0,idim) then the reduction can only take place onto 
    variable idim. A special case is used to handle this which involves
    no further recursive calls.

    If the original polyhedron is unbounded then a warning is issued
    and the derivative is return as zero. 

    Note: This code takes advantage of the fact that during recursive calls
    constraint 0 does not change its position in the list of remaining 
    constraints (if it has not been eliminated), i.e. it is always the 
    first constraint.  This would not be the case if the algorithm were 
    adapated to deal with other constraints, i.e. evaluate dvda_i,j 
    where i .ne. 0.

    Calls itself cvolumeb, and cvolumebj.
 
				Malcolm Sambridge, March 1995.

  --------------------------------------------------------------*/

float cdvda (a,b,m,n,mmax,nmax,tdim,temp,jval,code)

int   *n, *m, *nmax, *mmax, *tdim, *jval, *code;
float *a, *b, *temp; 

{

float v,amax,pivot;
int   i,j,t,k,l;
int   jj,kk;
float   *ai, *aj, *ajt, *apjj, *bi;
int   kmm,tmm;
int   nn,mm,nn_max,mm_max,ttdim;
int   nm1,mm1;
int   lmin,lmax, jjval, kval;
float  *ap, *bp, *ttemp;
int   firstmin,firstmax;
float bmin,bmax,bb;
float deriv, junk, vol, dvdb, dbda;
int   special, opt;

nn= *n;
mm= *m;
nn_max= *nmax;
mm_max= *mmax;

/* one-dimensional case (full reduction) */

*code = 0;

if (nn == 1) 
  {
  firstmin=0;
  firstmax=0;
  lmax=0;
  lmin=0;
  for (l=0;l<mm;l++)
    {
    if ( *(a+l) > 0.) 
      {
      bb= *(b+l)/ *(a+l);
      if (firstmin==0) {firstmin=1;bmin=bb;lmin=l;}
      else if (bb<bmin) {bmin=bb;lmin=l;}
      }
    else if ( *(a+l) < 0.)
      {
      bb= *(b+l)/ *(a+l);
      if (firstmax==0) {firstmax=1;bmax=bb;lmax=l;}
      else if (bb>bmax) {bmax=bb;lmax=l;}
      }
    else if ( *(b+l) < 0.) 
      {
                                   /* Constraint is inconsistent.
                                      Set derivative to zero. */

       printf("Inconsistent constraints found after reduction to n = 1 \n");
       *code = 1;
       return(0.);
      }
    }
  v=0.;
  if (firstmin*firstmax == 1) v=bmin-bmax;
  else 
    {
     printf("Volume is unbounded; derivative returned is zero\n");
     *code = -1;
     return(0.);
    }

  if (v<0.) return(0.);       

  if(*jval == 1)           /* Constraint 0 has not yet been encountered */
    {
     if (lmin == 0) deriv = -bmin/ *a;
     else if (lmax == 0) deriv = bmax/ *a;
     else deriv = 0.;
     return(deriv); 
    }
  else if(*jval == 0)     /* Constraint 0  has already been encountered */
    {
     deriv =  ( *(temp+lmax) * (bmax/ *(a+lmax)) ) -
              ( *(temp+lmin) * (bmin/ *(a+lmin)) );
     return(deriv); 
    }
  }
nm1=nn-1;
mm1=mm-1;
v=0.;
 
                                 /*  perform main loop over constraints */

for (i=0;i<mm;i++)
  {
   ai=a+i;
   bi=b+i;
   ttdim = *tdim;
   special = 0;

/* find largest pivot */

  amax=0.;
  t = 0;
  for (j=0;j<nn;j++) 
    if (fabs( *(ai+j*mm_max)) >= amax && j != ttdim) 
        {amax= fabs( *(ai+j*mm_max)); t=j;}

                                 /* finds contribution to v from 
                                    this pivot (if not nil) */

  if (amax == 0.)
  {
   if(*(ai + ttdim * mm_max) == 0.0) 
     { 
                                 /* Constraint is inconsistent */
       if ( *(bi) < 0.)
         {
          printf("Constraint %d is inconsistent\n",i+1);
          *code = 1;
          return(0.);
         }

                                 /* otherwise constraint is redundant */

       printf("Constraint %d is redundant\n",i+1); 
     }
   else
     {
                                 /* if projection can only be peformed
                                    on dimension tdim then activate 
                                    special case */ 

     special = 1;
     t = ttdim;
     amax = fabs(*(ai+t * mm_max));

     }
  }

  tmm=t*mm_max;
  pivot=*(ai+tmm);

  if(t < ttdim) ttdim = ttdim -1;


  if (amax != 0)
  {

                 /* determine if constraint 0 has been encountered */
 
   kval = 0;
   if ( i == 0 && *jval == 1)
      {
                                     /* This is the first encounter of
                                        constraint 0 on this path so we 
                                        allocate memory and store parameters 
                                        to be used when n = 1 */

       if (special == 0) 
          {
           ttemp = (float *) malloc((sizeof (float))*mm1);
           for (j=0;j<mm1;j++) *(ttemp+j) = - *(a+j+1+tmm)/pivot;
           kval = 1;
          }
       jjval = 0;
      }
   else if (*jval == 0)             /* Constraint 0 has already been
                                        encountered */
      {
        jjval = 0;  
                                    /* perform recursive update of component
                                       derivative array temp. This eliminates 
                                       row i and copies into a new vector */

        if(special == 0)
          {
           ttemp = (float *) malloc((sizeof (float))*mm1);
           for (j=0;j<i;j++) *(ttemp+j) = *(temp+j) 
                                          -(*(temp+i) * *(a+j+tmm)/pivot);
           for (j=i;j<mm1;j++) *(ttemp+j) = *(temp+j+1)
                                          -(*(temp+i) * *(a+j+1+tmm)/pivot);
          }
      }
   else 
      {                             /* Constraint 0 has not yet been 
                                        encountered */
      jjval = 1;                
      }


/* allocate memory */

  ap = (float *) malloc((sizeof (float))*nm1*mm1);
  bp = (float *) malloc((sizeof (float))*mm1);

/* reduce a and b into ap and bp eliminating variable t and constraint i */

  jj=-1;
    for (j=0;j<mm;j++)
      if (j != i)
      {
      jj=jj+1;
      aj=a+j;
      ajt=aj+tmm;
      *(bp+jj)= *(b+j) - *(bi) * *(ajt) / pivot;
      apjj=ap+jj;
      kk=-1;
      for (k=0;k<nn;k++)
        if (k != t)
        {
        kk=kk+1;
        kmm=k*mm_max;
        *(apjj+kk*mm1)= *(aj+kmm)- *(ajt) * *(ai+kmm)/ pivot;
        }
      }
  
/* add contribution to derivative from that calculated in smaller dimension */

  					/* Normal case method */
  if(special == 0)
    {
     deriv=cdvda(ap,bp, &mm1, &nm1, &mm1, &nm1, &ttdim, ttemp, &jjval,code);
     v=v+ *(bi)/amax*deriv/nn;
     if (kval == 1 || *jval == 0) free(ttemp);
     if(*code != 0)return (0.);

    }
  else					/* Use special case method */
    {
     if( *jval == 1)                    
       {                     
        if(i == 0)                      /* This is constraint 0 */
          {
           deriv = 0.; 
           vol = 0.; 
           dvdb = 0.;
           for (j=1;j<mm;j++) 
              {
               k = j - 1;
               junk=cvolumebj(ap,bp,&mm1,&nm1,&mm1,&nm1,k,&dvdb);
               if(junk == -1.)
                 {
                  *code = -1;
                  return(0.);
                 }
               deriv = deriv + dvdb * *(a + j + tmm) ;
               vol = vol + junk;
              }
           if(nm1 == 1)vol = junk;
           deriv = *(bi) * deriv/pivot;
           deriv = (deriv - vol) /pivot; 
           v=v+ *(bi)/amax*deriv/nn;

          }
        else				/* Constraint 0 not yet encountered */
          {
           opt = 2;
           junk=cvolumeb(ap,bp,&mm1,&nm1,&mm1,&nm1,&opt,&deriv);
           if(junk == -1.)
             {
              *code = -1;
              return(0.);
             }
           deriv= -(deriv *  *(bi)/pivot);
           v=v+ *(bi)/amax*deriv/nn;
          }
       }
     else if( *jval == 0)               /* Constraint 0 already encountered */
       {
        vol = 0.; 
        deriv = 0.; 
        for (j=0;j<i;j++) 
           {
            junk=cvolumebj(ap,bp,&mm1,&nm1,&mm1,&nm1,j,&dvdb);
            if(junk == -1.)
              {
               *code = -1;
               return(0.);
              }
            dbda = (*(a+j+tmm) * *(temp+i)/pivot) - *(temp+j);
            deriv = deriv + dvdb*dbda;
            vol = vol + junk;
           }
        for (j=i+1;j<mm;j++) 
           {
            k = j - 1;
            junk=cvolumebj(ap,bp,&mm1,&nm1,&mm1,&nm1,k,&dvdb);
            if(junk == -1.)
              {
               *code = -1;
               return(0.);
              }
            dbda = (*(a+j+tmm) * *(temp+i)/pivot) - *(temp+j);
            deriv = deriv + dvdb*dbda;
            vol = vol + junk;
           }
           if(nm1 == 1)vol = junk;
           deriv = (*(bi) * deriv - *(temp+i)*vol)/pivot;
           v=v+ *(bi)/amax*deriv/nn;
       }
    }

  free(ap);
  free(bp);
  }
  }

return(v);

}

/*--------------------------------------------------------------

			ROUTINE: dvda

   A dummy routine used to call cdvda from a fortran routine 

----------------------------------------------------------------*/
/*  Not used...won't compile...function name and variable name (were) identical */

void dvda_();
void dvda();

void dvda_ (a,b,m,n,mmax,nmax,idim,result,code) 
     int   *n, *m, *mmax, *nmax, *idim, *code;
     float *a, *b;
     float *result; 
{
  dvda(a,b,m,n,mmax,nmax,idim,result,code);
}

void dvda (a,b,m,n,mmax,nmax,idim,result,code)

int   *n, *m, *mmax, *nmax, *idim, *code;
float *a, *b;
float *result; 

{

int    j;
int    jval, tdim;
float *temp;

jval = 1;
tdim = *idim - 1;

*result=cdvda(a,b,m,n,mmax,nmax,&tdim,temp,&jval,code);

free(temp);
}


/*--------------------------------------------------------------

			ROUTINE: cvolumef

    This routine calculates the `volume' in dimension n of the region
    bounded by a set of m linear inequality constraints of the form
    A x <= b, where a has m rows and n columns and is given by a(m,n),
    b is the n-vector and is contained in b(m). The recursive formula
    of Lasserre (1983) is used. Redundant constraints are allowed 
    If the inequality constraints are inconsistent then the volume 
    is returned as zero.  If the original polyhedron is unbounded 
    then a warning is issued and the volume is return as -1.0 
    (even though it is undefined). 

    This is a faster version which does not continue down the
    recursive tree if if encounters b(j) = 0 for any j. This
    restricts its use to cases where the origin does not
    pass through any inconsistent constraints. Also redundant
    constraints that pass through the origin will not be detected.
 
			Jean Braun and Malcolm Sambridge, Jan 1995.


    Lasserre, J. B., 1983. "An analytical expression and an Algorithm
    for the Volume of a Convex Polyhedron in R^n.", JOTA, vol. 39, 
    no. 3, 363-377.

  --------------------------------------------------------------*/

float cvolumef (a,b,m,n,mmax,nmax)

int   *n, *m, *mmax, *nmax;
float *a, *b; 

{

float v,amax,pivot;
int   i,j,t,k,l;
int   jj,kk;
float   *ai, *aj, *ajt, *apjj, *bi;
int   kmm,tmm;
int   nn,mm,nn_max,mm_max;
int   nm1,mm1;
float  *ap, *bp;
int   firstmin,firstmax;
float bmin,bmax,bb;
float partialv;

nn= *n;
mm= *m;
nn_max= *nmax;
mm_max= *mmax;

/* one-dimensional case (full reduction) */

if (nn == 1) 
  {
  firstmin=0;
  firstmax=0;
  for (l=0;l<mm;l++)
    {
    if ( *(a+l) > 0.) 
      {
      bb= *(b+l)/ *(a+l);
      if (firstmin==0) {firstmin=1;bmin=bb;}
      else if (bb<bmin) bmin=bb;
      }
    else if ( *(a+l) < 0.)
      {
      bb= *(b+l)/ *(a+l);
      if (firstmax==0) {firstmax=1;bmax=bb;}
      else if (bb>bmax) bmax=bb;
      }
    else if ( *(b+l) < 0.)         /* Constraints are inconsistent */
      { 
       printf("Inconsistent constraints found after reduction to n = 1 \n");
       return(0.); 
      }
    }
  v=0.;
  if (firstmin*firstmax == 1) v=bmin-bmax;
  else 
    {
     printf("Volume is unbounded at 1-D; volume returned as -1\n");
     return(-1.0);
    }

  if (v<0.) {v=0.;} 

  return(v);
  }

nm1=nn-1;
mm1=mm-1;
v=0.;
for (i=0;i<mm;i++)
  {
   ai=a+i;
   bi=b+i;

/* find largest pivot */

  amax=0.;
  for (j=0;j<nn;j++) 
    if (fabs( *(ai+j*mm_max)) >= amax) {amax= fabs( *(ai+j*mm_max)); t=j;}
  tmm=t*mm_max;
  pivot=*(ai+tmm);

/* finds contribution to v from this pivot (if not nil) */

  if (amax == 0.)
  {
                                 /* Constraint is inconsistent */

    if ( *(bi) < 0.) 
      { printf("Constraint %d is inconsistent\n",i+1); return(0.); }

                                 /* otherwise constraint is redundant */

    printf("Constraint %d is redundant\n",i+1); 
  }
  else
  {

/* allocate memory */

  ap = (float *) malloc((sizeof (float))*nm1*mm1);
  bp = (float *) malloc((sizeof (float))*mm1);

/* reduce a and b into ap and bp eliminating variable t and constraint i */

  jj=-1;
    for (j=0;j<mm;j++)
      if (j != i)
      {
      jj=jj+1;
      aj=a+j;
      ajt=aj+tmm;
      *(bp+jj)= *(b+j) - *(bi) * *(ajt) / pivot;
      apjj=ap+jj;
      kk=-1;
      for (k=0;k<nn;k++)
        if (k != t)
        {
        kk=kk+1;
        kmm=k*mm_max;
        *(apjj+kk*mm1)= *(aj+kmm)- *(ajt) * *(ai+kmm)/ pivot;
        }
      }
  
/* add contribution to volume from volume calculated in smaller dimension */

  partialv = 0.;
  if (*(bi) != 0.) partialv=cvolumef(ap,bp, &mm1, &nm1, &mm1, &nm1);
  if(partialv == -1.0)return(-1.0);
  v=v+ *(bi)/amax*partialv/nn; 

  free(ap);
  free(bp);
  }
  }

return(v);

}
/*--------------------------------------------------------------

			ROUTINE: volume

   A dummy routine used to call cvolume from a fortran routine 

----------------------------------------------------------------*/

void volumef_();
void volumef();

void volumef_ (a,b,m,n,mmax,nmax,volume) 
     int   *n, *m, *mmax, *nmax;
     float *a, *b;
     float *volume; 
{
  volumef(a,b,m,n,mmax,nmax,volume);
}


void volumef (a,b,m,n,mmax,nmax,volume)

int   *n, *m, *mmax, *nmax;
float *a, *b;
float *volume; 

{

*volume=cvolumef(a,b,m,n,mmax,nmax);

}
/*--------------------------------------------------------------

			ROUTINE: cdvdaf

    This routine calculates the derivative with respect to a(0,tdim)
    of the `volume' in dimension n of the region bounded by a set 
    of m linear inequality constraints of the form A x <= b, where 
    a has m rows and n columns and is given by a(m,n), b is the 
    n-vector and is contained in b(m). The derivative expression
    is recursive and derived from the formula of Lasserre (1983). 

    Redundant constraints are allowed and a warning is issued if any are 
    encountered. If the inequality constraints are inconsistent then the 
    derivative is returned as zero.  If any constraint is orthogonal to 
    the component a(0,idim) then the reduction can only take place onto 
    variable idim. A special case is used to handle this which involves
    no further recursive calls.

    If the original polyhedron is unbounded then a warning is issued
    and the derivative is return as zero. 

    Note: This code takes advantage of the fact that during recursive calls
    constraint 0 does not change its position in the list of remaining 
    constraints (if it has not been eliminated), i.e. it is always the 
    first constraint.  This would not be the case if the algorithm were 
    adapated to deal with other constraints, i.e. evaluate dvda_i,j 
    where i .ne. 0.

    This is a faster version which does not continue down the
    recursive tree if if encounters b(j) = 0 for any j. This
    restricts its use to cases where the origin does not
    pass through any inconsistent constraints. Also redundant
    constraints that pass through the origin will not be detected.
 
    Calls itself cvolumeb, and cvolumebj.
 
				Malcolm Sambridge, March 1995.

  --------------------------------------------------------------*/

float cdvdaf (a,b,m,n,mmax,nmax,tdim,temp,jval,code)

int   *n, *m, *nmax, *mmax, *tdim, *jval, *code;
float *a, *b, *temp; 

{

float v,amax,pivot;
int   i,j,t,k,l;
int   jj,kk;
float   *ai, *aj, *ajt, *apjj, *bi;
int   kmm,tmm;
int   nn,mm,nn_max,mm_max,ttdim;
int   nm1,mm1;
int   lmin,lmax, jjval, kval;
float  *ap, *bp, *ttemp;
int   firstmin,firstmax;
float bmin,bmax,bb;
float deriv, junk, vol, dvdb, dbda;
int   special, opt;

nn= *n;
mm= *m;
nn_max= *nmax;
mm_max= *mmax;

/* one-dimensional case (full reduction) */

*code = 0;

if (nn == 1) 
  {
  firstmin=0;
  firstmax=0;
  lmax=0;
  lmin=0;
  for (l=0;l<mm;l++)
    {
    if ( *(a+l) > 0.) 
      {
      bb= *(b+l)/ *(a+l);
      if (firstmin==0) {firstmin=1;bmin=bb;lmin=l;}
      else if (bb<bmin) {bmin=bb;lmin=l;}
      }
    else if ( *(a+l) < 0.)
      {
      bb= *(b+l)/ *(a+l);
      if (firstmax==0) {firstmax=1;bmax=bb;lmax=l;}
      else if (bb>bmax) {bmax=bb;lmax=l;}
      }
    else if ( *(b+l) < 0.) 
      {
                                   /* Constraint is inconsistent.
                                      Set derivative to zero. */

       printf("Inconsistent constraints found after reduction to n = 1 \n");
       *code = 1;
       return(0.);
      }
    }
  v=0.;
  if (firstmin*firstmax == 1) v=bmin-bmax;
  else 
    {
     printf("Volume is unbounded; derivative returned is zero\n");
     *code = -1;
     return(0.);
    }
  if (v<0.) return(0.);       

  if(*jval == 1)           /* Constraint 0 has not yet been encountered */
    {
     if (lmin == 0) deriv = -bmin/ *a;
     else if (lmax == 0) deriv = bmax/ *a;
     else deriv = 0.;
     return(deriv); 
    }
  else if(*jval == 0)     /* Constraint 0  has already been encountered */
    {
     deriv =  ( *(temp+lmax) * (bmax/ *(a+lmax)) ) -
              ( *(temp+lmin) * (bmin/ *(a+lmin)) );
     return(deriv); 
    }
  }
nm1=nn-1;
mm1=mm-1;
v=0.;
 
                                 /*  perform main loop over constraints */

for (i=0;i<mm;i++)
  {
   ai=a+i;
   bi=b+i;
   ttdim = *tdim;
   special = 0;

/* find largest pivot */

  amax=0.;
  t = 0;
  for (j=0;j<nn;j++) 
    if (fabs( *(ai+j*mm_max)) >= amax && j != ttdim) 
        {amax= fabs( *(ai+j*mm_max)); t=j;}

                                 /* finds contribution to v from 
                                    this pivot (if not nil) */

  if (amax == 0.)
  {
   if(*(ai + ttdim * mm_max) == 0.0) 
     { 
                                 /* Constraint is inconsistent */
       if ( *(bi) < 0.)
         {
          printf("Constraint %d is inconsistent\n",i+1);
          *code = 1;
          return(0.);
         }

                                 /* otherwise constraint is redundant */

       printf("Constraint %d is redundant\n",i+1); 
     }
   else
     {
                                 /* if projection can only be peformed
                                    on dimension tdim then activate 
                                    special case */ 

     special = 1;
     t = ttdim;
     amax = fabs(*(ai+t * mm_max));

     }
  }

  tmm=t*mm_max;
  pivot=*(ai+tmm);

  if(t < ttdim) ttdim = ttdim -1;


  if (amax != 0)
  {

                 /* determine if constraint 0 has been encountered */
 
   kval = 0;
   if ( i == 0 && *jval == 1)
      {
                                     /* This is the first encounter of
                                        constraint 0 on this path so we 
                                        allocate memory and store parameters 
                                        to be used when n = 1 */

       if (special == 0) 
          {
           ttemp = (float *) malloc((sizeof (float))*mm1);
           for (j=0;j<mm1;j++) *(ttemp+j) = - *(a+j+1+tmm)/pivot;
           kval = 1;
          }
       jjval = 0;
      }
   else if (*jval == 0)             /* Constraint 0 has already been
                                        encountered */
      {
        jjval = 0;  
                                    /* perform recursive update of component
                                       derivative array temp. This eliminates 
                                       row i and copies into a new vector */

        if(special == 0)
          {
           ttemp = (float *) malloc((sizeof (float))*mm1);
           for (j=0;j<i;j++) *(ttemp+j) = *(temp+j) 
                                          -(*(temp+i) * *(a+j+tmm)/pivot);
           for (j=i;j<mm1;j++) *(ttemp+j) = *(temp+j+1)
                                          -(*(temp+i) * *(a+j+1+tmm)/pivot);
          }
      }
   else 
      {                             /* Constraint 0 has not yet been 
                                        encountered */
      jjval = 1;                
      }


/* allocate memory */

  ap = (float *) malloc((sizeof (float))*nm1*mm1);
  bp = (float *) malloc((sizeof (float))*mm1);

/* reduce a and b into ap and bp eliminating variable t and constraint i */

  jj=-1;
    for (j=0;j<mm;j++)
      if (j != i)
      {
      jj=jj+1;
      aj=a+j;
      ajt=aj+tmm;
      *(bp+jj)= *(b+j) - *(bi) * *(ajt) / pivot;
      apjj=ap+jj;
      kk=-1;
      for (k=0;k<nn;k++)
        if (k != t)
        {
        kk=kk+1;
        kmm=k*mm_max;
        *(apjj+kk*mm1)= *(aj+kmm)- *(ajt) * *(ai+kmm)/ pivot;
        }
      }
  
/* add contribution to derivative from that calculated in smaller dimension */

  					/* Normal case method */
  if(special == 0)
    {
     deriv = 0.;
     if (*(bi) != 0.) 
     {deriv=cdvdaf(ap,bp, &mm1, &nm1, &mm1, &nm1, &ttdim, ttemp, &jjval,code);}
     v=v+ *(bi)/amax*deriv/nn;
     if (kval == 1 || *jval == 0) free(ttemp);
     if(*code != 0)return (0.);

    }
  else					/* Use special case method */
    {
     if( *jval == 1)                    
       {                     
        if(i == 0)                      /* This is constraint 0 */
          {
           deriv = 0.; 
           vol = 0.; 
           dvdb = 0.;
           for (j=1;j<mm;j++) 
              {
               k = j - 1;
               junk=cvolumebj(ap,bp,&mm1,&nm1,&mm1,&nm1,k,&dvdb);
               if(junk == -1.)
                 {
                  *code = -1;
                  return(0.);
                 }
               deriv = deriv + dvdb * *(a + j + tmm) ;
               vol = vol + junk;
              }
           if(nm1 == 1)vol = junk;
           deriv = *(bi) * deriv/pivot;
           deriv = (deriv - vol) /pivot; 
           v=v+ *(bi)/amax*deriv/nn;

          }
        else				/* Constraint 0 not yet encountered */
          {
           opt = 2;
           junk=cvolumeb(ap,bp,&mm1,&nm1,&mm1,&nm1,&opt,&deriv);
           if(junk == -1.)
             {
              *code = -1;
              return(0.);
             }
           deriv= -(deriv *  *(bi)/pivot);
           v=v+ *(bi)/amax*deriv/nn;
          }
       }
     else if( *jval == 0)               /* Constraint 0 already encountered */
       {
        vol = 0.; 
        deriv = 0.; 
        for (j=0;j<i;j++) 
           {
            junk=cvolumebj(ap,bp,&mm1,&nm1,&mm1,&nm1,j,&dvdb);
            if(junk == -1.)
              {
               *code = -1;
               return(0.);
              }
            dbda = (*(a+j+tmm) * *(temp+i)/pivot) - *(temp+j);
            deriv = deriv + dvdb*dbda;
            vol = vol + junk;
           }
        for (j=i+1;j<mm;j++) 
           {
            k = j - 1;
            junk=cvolumebj(ap,bp,&mm1,&nm1,&mm1,&nm1,k,&dvdb);
            if(junk == -1.)
              {
               *code = -1;
               return(0.);
              }
            dbda = (*(a+j+tmm) * *(temp+i)/pivot) - *(temp+j);
            deriv = deriv + dvdb*dbda;
            vol = vol + junk;
           }
           if(nm1 == 1)vol = junk;
           deriv = (*(bi) * deriv - *(temp+i)*vol)/pivot;
           v=v+ *(bi)/amax*deriv/nn;
       }
    }

  free(ap);
  free(bp);
  }
  }

return(v);

}

/*--------------------------------------------------------------

			ROUTINE: dvda

   A dummy routine used to call cdvda from a fortran routine 

----------------------------------------------------------------*/

void dvdaf_();
void dvdaf();

void dvdaf_ (a,b,m,n,mmax,nmax,idim,dvda,code) 
     int   *n, *m, *mmax, *nmax, *idim, *code;
     float *a, *b;
     float *dvda; 
{
  dvdaf(a,b,m,n,mmax,nmax,idim,dvda,code);
}


void dvdaf (a,b,m,n,mmax,nmax,idim,dvda,code)

int   *n, *m, *mmax, *nmax, *idim, *code;
float *a, *b;
float *dvda; 

{

int    j;
int    jval, tdim;
float *temp;

jval = 1;
tdim = *idim - 1;

*dvda=cdvdaf(a,b,m,n,mmax,nmax,&tdim,temp,&jval,code);
free(temp);
}


/*--------------------------------------------------------------

			ROUTINE: cdvda_debug

    This routine calculates the derivative with respect to a(0,tdim)
    of the `volume' in dimension n of the region bounded by a set 
    of m linear inequality constraints of the form A x <= b, where 
    a has m rows and n columns and is given by a(m,n), b is the 
    n-vector and is contained in b(m). The derivative expression
    is recursive and derived from the formula of Lasserre (1983). 

    Redundant constraints are allowed and a warning is issued if any are 
    encountered. If the inequality constraints are inconsistent then the 
    derivative is returned as zero.  If any constraint is orthogonal to 
    the component a(0,idim) then the reduction can only take place onto 
    variable idim. A special case is used to handle this which involves
    no further recursive calls.

    If the original polyhedron is unbounded then a warning is issued
    and the derivative is return as zero. 

    Note: This code takes advantage of the fact that during recursive calls
    constraint 0 does not change its position in the list of remaining 
    constraints (if it has not been eliminated), i.e. it is always the 
    first constraint.  This would not be the case if the algorithm were 
    adapated to deal with other constraints, i.e. evaluate dvda_i,j 
    where i .ne. 0.

    Calls itself cvolumeb, and cvolumebj.

    This is a version of cdvda used for debugging and contains extra
    code and print statements.
 
				Malcolm Sambridge, March 1995.

  --------------------------------------------------------------*/

float cdvda_debug (a,b,m,n,tdim,temp,jval,code)

int   *n, *m, *tdim, *jval, *code;
float *a, *b, *temp; 

{

float v,amax,pivot;
int   i,j,t,k,l;
int   jj,kk;
float   *ai, *aj, *ajt, *apjj, *bi;
int   kmm,tmm;
int   nn,mm, ttdim;
int   nm1,mm1;
int   lmin,lmax, jjval, kval;
float  *ap, *bp, *ttemp;
int   firstmin,firstmax;
float bmin,bmax,bb;
float deriv, junk, vol, dvdb, dbda;
int   special, opt;
float volp, volm, da, FD, FDa;


nn= *n;
mm= *m;

/* write out a and b (debug) */

       printf("\n"); 
       printf(" Current matrix A and vector b \n");
   for (j=0;j<mm;j++)
      {
      aj=a+j;
      for (k=0;k<nn;k++) 
      {ajt=aj+k * mm; printf(" a %d %d = %f",j,k,*(ajt));}
      printf(" : b = %f \n", *(b+j));
      }

/* one-dimensional case (full reduction) */

*code = 0;

if (nn == 1) 
  {
  printf("One dimension left \n");
  firstmin=0;
  firstmax=0;
  lmax=0;
  lmin=0;
  for (l=0;l<mm;l++)
    {
    if ( *(a+l) > 0.) 
      {
      bb= *(b+l)/ *(a+l);
      if (firstmin==0) {firstmin=1;bmin=bb;lmin=l;}
      else if (bb<bmin) {bmin=bb;lmin=l;}
      }
    else if ( *(a+l) < 0.)
      {
      bb= *(b+l)/ *(a+l);
      if (firstmax==0) {firstmax=1;bmax=bb;lmax=l;}
      else if (bb>bmax) {bmax=bb;lmax=l;}
      }
    else if ( *(b+l) < 0.) 
      {
                                   /* Constraint is inconsistent.
                                      Set derivative to zero. */

       printf("Inconsistent constraints found after reduction to n = 1 \n");
       *code = 1;
       return(0.);
      }
    }
  v=0.;
  if (firstmin*firstmax == 1) v=bmin-bmax;
  else 
    {
     printf("Volume is unbounded; derivative returned is zero\n");
     *code = -1;
     return(0.);
    }

  if (v<0.) return(0.);       

  if(*jval == 1)           /* Constraint 0 has not yet been encountered */
    {
     if (lmin == 0) deriv = -bmin/ *a;
     else if (lmax == 0) deriv = bmax/ *a;
     else deriv = 0.;
     printf(" No projection onto constraint 0 \n");
     printf(" lmin = %d lmax = %d bmin = %f bmax = %f alpha = %f \n",
            lmin,lmax,bmin,bmax,*a);
     printf(" deriv contribution = %f \n",deriv);
     return(deriv); 
    }
  else if(*jval == 0)     /* Constraint 0  has already been encountered */
    {
     deriv =  ( *(temp+lmax) * (bmax/ *(a+lmax)) ) -
              ( *(temp+lmin) * (bmin/ *(a+lmin)) );
     printf(" Projection onto constraint 0 has occurred \n");
     printf(" lmin = %d bmin = %f alpha = %f temp = %f\n",
            lmin,bmin,*(a+lmin),*(temp+lmin));
     printf(" lmax = %d bmax = %f alpha = %f temp = %f\n",
            lmax,bmax,*(a+lmax),*(temp+lmax));
     printf(" deriv contribution = %f \n",deriv);
     return(deriv); 
    }
  }
nm1=nn-1;
mm1=mm-1;
v=0.;
 
printf(" About to start main loop n = %d m = %d \n",nn,mm);

                                 /*  perform main loop over constraints */

for (i=0;i<mm;i++)
  {
   ai=a+i;
   bi=b+i;
   ttdim = *tdim;
   special = 0;

/* find largest pivot */

  amax=0.;
  t = 0;
  for (j=0;j<nn;j++) 
    if (fabs( *(ai+j*mm)) >= amax && j != ttdim) 
        {amax= fabs( *(ai+j*mm)); t=j;}

                                 /* finds contribution to v from 
                                    this pivot (if not nil) */

  if (amax == 0.)
  {
   if(*(ai + ttdim * mm) == 0.0) 
     { 
                                 /* Constraint is inconsistent */
       if ( *(bi) < 0.)
         {
          printf("Constraint %d is inconsistent\n",i+1);
          *code = 1;
          return(0.);
         }

                                 /* otherwise constraint is redundant */

       printf("Constraint %d is redundant\n",i+1); 
     }
   else
     {
                                 /* if projection can only be peformed
                                    on dimension tdim then activate 
                                    special case */ 

     printf("Constraint %d can only be projected onto dimension %d\n",i+1,*tdim);
     printf("using special case method \n");
     special = 1;
     t = ttdim;
     amax = fabs(*(ai+t * mm));

     }
  }

  tmm=t*mm;
  pivot=*(ai+tmm);

  printf("\n Projection onto constraint %d variable %d k = %d\n",i,t,ttdim);

  if(t < ttdim) ttdim = ttdim -1;


  if (amax != 0)
  {

                 /* determine if constraint 0 has been encountered */
 
   kval = 0;
   if ( i == 0 && *jval == 1)
      {
                                     /* This is the first encounter of
                                        constraint 0 on this path so we 
                                        allocate memory and store parameters 
                                        to be used when n = 1 */

       if (special == 0) 
          {
           ttemp = (float *) malloc((sizeof (float))*mm);
           for (j=0;j<mm1;j++) *(ttemp+j) = - *(a+j+1+tmm)/pivot;
           kval = 1;
           printf("\n Generating temp n = %d m = %d i = %d \n",nn,mm,i); 
           printf(" ttemp : \n"); 
           for (j=0;j<mm1;j++) printf(" %f ",*(ttemp+j));
           printf("\n"); 
          }
       jjval = 0;
      }
   else if (*jval == 0)             /* Constraint 0 has already been
                                        encountered */
      {
        jjval = 0;  
                                    /* perform recursive update of component
                                       derivative array temp. This eliminates 
                                       row i and copies into a new vector */

        if(special == 0)
          {
           ttemp = (float *) malloc((sizeof (float))*mm1);
           for (j=0;j<i;j++) *(ttemp+j) = *(temp+j) 
                                          -(*(temp+i) * *(a+j+tmm)/pivot);
           for (j=i;j<mm1;j++) *(ttemp+j) = *(temp+j+1)
                                          -(*(temp+i) * *(a+j+1+tmm)/pivot);
           printf(" Reduced ttemp : \n"); 
           for (j=0;j<mm1;j++) printf(" %f ",*(ttemp+j));
           printf("\n"); 
          }
      }
   else 
      {                             /* Constraint 0 has not yet been 
                                        encountered */
      jjval = 1;                
      }


/* allocate memory */

  ap = (float *) malloc((sizeof (float))*nm1*mm1);
  bp = (float *) malloc((sizeof (float))*mm1);

/* reduce a and b into ap and bp eliminating variable t and constraint i */

  jj=-1;
    for (j=0;j<mm;j++)
      if (j != i)
      {
      jj=jj+1;
      aj=a+j;
      ajt=aj+tmm;
      *(bp+jj)= *(b+j) - *(bi) * *(ajt) / pivot;
      apjj=ap+jj;
      kk=-1;
      for (k=0;k<nn;k++)
        if (k != t)
        {
        kk=kk+1;
        kmm=k*mm;
        *(apjj+kk*mm1)= *(aj+kmm)- *(ajt) * *(ai+kmm)/ pivot;
        }
      }
  
/* add contribution to derivative from that calculated in smaller dimension */

  					/* Normal case method */
  if(special == 0)
    {
/*
     deriv = 0.;
     if (*(bi) != 0.) 
     {deriv=cdvda(ap,bp, &mm1, &nm1, &mm1, &nm1, &ttdim, ttemp, &jjval,code);}
*/
     deriv=cdvda(ap,bp, &mm1, &nm1, &mm1, &nm1, &ttdim, ttemp, &jjval,code);
     v=v+ *(bi)/amax*deriv/nn;
     if (kval == 1 || *jval == 0) free(ttemp);
     if(*code != 0)return (0.);

    }
  else					/* Use special case method */
    {
     if( *jval == 1)                    
       {                     
        if(i == 0)                      /* This is constraint 0 */
          {
           deriv = 0.; 
           vol = 0.; 
           dvdb = 0.;
           printf("\n special case 2: reduction by 0 and variable k\n"); 
           for (j=1;j<mm;j++) 
              {
               k = j - 1;
               junk=cvolumebj(ap,bp,&mm1,&nm1,&mm1,&nm1,k,&dvdb);
               if(junk == -1.)
                 {
                  *code = -1;
                  return(0.);
                 }
               printf("\n j %d k %d dvdb %f vol %f",j,k,dvdb,junk); 
               deriv = deriv + dvdb * *(a + j + tmm) ;
               vol = vol + junk;
              }
           if(nm1 == 1)vol = junk;
           deriv = *(bi) * deriv/pivot;
           deriv = (deriv - vol) /pivot; 
           v=v+ *(bi)/amax*deriv/nn;
           printf("dcont %f",deriv); 
           printf("\n total volume of face = %f",vol); 

/* start debug section */

           FDa = *(bi)/amax*deriv/nn;
           da = 0.01* *(a + *tdim * mm);
           if(da == 0.0)da = 0.01;
           *(a + *tdim * mm) = *(a + *tdim * mm) + da;

  jj=-1;
    for (j=0;j<mm;j++)
      if (j != i)
      {
      jj=jj+1;
      aj=a+j;
      ajt=aj+tmm;
      *(bp+jj)= *(b+j) - *(bi) * *(ajt) / pivot;
      apjj=ap+jj;
      kk=-1;
      for (k=0;k<nn;k++)
        if (k != t)
        {
        kk=kk+1;
        kmm=k*mm;
        *(apjj+kk*mm1)= *(aj+kmm)- *(ajt) * *(ai+kmm)/ pivot;
        }
      }
          volp = cvolume(ap,bp,&mm1,&nm1); 
          amax = fabs(pivot+da);
          volp = (*(bi)/(amax*nn)) * volp;
           *(a + *tdim * mm) = *(a + *tdim * mm) - 2. * da;
  jj=-1;
    for (j=0;j<mm;j++)
      if (j != i)
      {
      jj=jj+1;
      aj=a+j;
      ajt=aj+tmm;
      *(bp+jj)= *(b+j) - *(bi) * *(ajt) / pivot;
      apjj=ap+jj;
      kk=-1;
      for (k=0;k<nn;k++)
        if (k != t)
        {
        kk=kk+1;
        kmm=k*mm;
        *(apjj+kk*mm1)= *(aj+kmm)- *(ajt) * *(ai+kmm)/ pivot;
        }
      }
          volm = cvolume(ap,bp,&mm1,&nm1); 
          amax = fabs(pivot-da);
           *(a + *tdim * mm) = *(a + *tdim * mm) + da;
          volm = (*(bi)/(amax*nn)) * volm;
          FD = (volp-volm)/(2. * da);
          printf("\n k  %d a = %f da = %f",*tdim,*(a + *tdim * mm),da); 
          printf("\n pivot = %f",pivot); 
          printf("\n volp = %f",volp); 
          printf("\n volm = %f",volm); 
          printf("\n FD estimate = %f",FD); 
          printf("\n analytical estimate = %f\n",FDa); 

/* end debug section */

          }
        else				/* Constraint 0 not yet encountered */
          {
           printf("\n special case 1: constraint 0 not yet reached\n"); 
           opt = 2;
           junk=cvolumeb(ap,bp,&mm1,&nm1,&mm1,&nm1,&opt,&deriv);
           if(junk == -1.)
             {
              *code = -1;
              return(0.);
             }
           deriv= -(deriv *  *(bi)/pivot);
           v=v+ *(bi)/amax*deriv/nn;
           printf("\n spec: 0 not yet reached i %d dcont %f",i,deriv); 
 
/* debug section: reduce system and repeat calculation with finite difference */

           FDa = *(bi)/amax*deriv/nn;
           da = 0.01* *(a + *tdim * mm);
           if(da == 0.0)da = 0.01;
           *(a + *tdim * mm) = *(a + *tdim * mm) + da;

/* reduce system */

  jj=-1;
    for (j=0;j<mm;j++)
      if (j != i)
      {
      jj=jj+1;
      aj=a+j;
      ajt=aj+tmm;
      *(bp+jj)= *(b+j) - *(bi) * *(ajt) / pivot;
      apjj=ap+jj;
      kk=-1;
      for (k=0;k<nn;k++)
        if (k != t)
        {
        kk=kk+1;
        kmm=k*mm;
        *(apjj+kk*mm1)= *(aj+kmm)- *(ajt) * *(ai+kmm)/ pivot;
        }
      }
          volp = cvolume(ap,bp,&mm1,&nm1); 
           *(a + *tdim * mm) = *(a + *tdim * mm) - 2. * da;

/* reduce system */

  jj=-1;
    for (j=0;j<mm;j++)
      if (j != i)
      {
      jj=jj+1;
      aj=a+j;
      ajt=aj+tmm;
      *(bp+jj)= *(b+j) - *(bi) * *(ajt) / pivot;
      apjj=ap+jj;
      kk=-1;
      for (k=0;k<nn;k++)
        if (k != t)
        {
        kk=kk+1;
        kmm=k*mm;
        *(apjj+kk*mm1)= *(aj+kmm)- *(ajt) * *(ai+kmm)/ pivot;
        }
      }
          volm = cvolume(ap,bp,&mm1,&nm1); 
           *(a + *tdim * mm) = *(a + *tdim * mm) + da;
          FD = (*(bi)/(amax*nn)) * (volp-volm)/(2. * da);
          printf("\n k  %d a = %f da = %f",*tdim,*(a + *tdim * mm),da); 
          printf("\n volp = %f",volp); 
          printf("\n volm = %f",volm); 
          printf("\n FD estimate = %f",FD); 
          printf("\n analytical estimate = %f\n",FDa); 

/* end debug section */

          }
       }
     else if( *jval == 0)               /* Constraint 0 already encountered */
       {
        printf("\n special case 3: constraint 0 already reduced\n"); 
        vol = 0.; 
        deriv = 0.; 
        for (j=0;j<i;j++) 
           {
            junk=cvolumebj(ap,bp,&mm1,&nm1,&mm1,&nm1,j,&dvdb);
            if(junk == -1.)
              {
               *code = -1;
               return(0.);
              }
            dbda = (*(a+j+tmm) * *(temp+i)/pivot) - *(temp+j);
            deriv = deriv + dvdb*dbda;
            vol = vol + junk;
           }
        for (j=i+1;j<mm;j++) 
           {
            k = j - 1;
            junk=cvolumebj(ap,bp,&mm1,&nm1,&mm1,&nm1,k,&dvdb);
            if(junk == -1.)
              {
               *code = -1;
               return(0.);
              }
            dbda = (*(a+j+tmm) * *(temp+i)/pivot) - *(temp+j);
            deriv = deriv + dvdb*dbda;
            vol = vol + junk;
           }
           if(nm1 == 1)vol = junk;
           deriv = (*(bi) * deriv - *(temp+i)*vol)/pivot;
           v=v+ *(bi)/amax*deriv/nn;
           printf("\n spec: 0 already encountered i = %d dcont %f",i,deriv); 
       }
    }

  free(ap);
  free(bp);
  }
  }

return(v);

}