#include #include #include #include #ifndef _UNDERSCORE float cvolume(float *a, float *b, int *m, int *n, int *mmax, int *nmax); void volume(float *a, float *b, int *m, int *n, int *mmax, int *nmax, float *volume); float cvolumeb(float *a, float *b, int *m, int *n, int *mmax, int *nmax, int *opt, float *dvdb); void volumeb(float *a, float *b, int *m, int *n, int *mmax, int *nmax, int *opt, float *volume, float *dvdb); float cvolumebj(float *a, float *b, int *m, int *n, int *mmax, int *nmax, int con, float *dvdb); void volumebj(float *a, float *b, int *m, int *n, int *mmax, int *nmax, int *con, float *volume, float *dvdb); float cdvda(float *a, float *b, int *m, int *n, int *mmax, int *nmax, int *tdim, float *temp, int *jval, int *code); void dvda(float *a, float *b, int *m, int *n, int *mmax, int *nmax, int *idim, float *dvda, int *code); float cvolumef(float *a, float *b, int *m, int *n, int *mmax, int *nmax); void volumef(float *a, float *b, int *m, int *n, int *mmax, int *nmax, float *volume); float cdvdaf(float *a, float *b, int *m, int *n, int *mmax, int *nmax, int *tdim, float *temp, int *jval, int *code); void dvdaf(float *a, float *b, int *m, int *n, int *mmax, int *nmax, int *idim, float *dvda, int *code); float cdvda_debug(float *a, float *b, int *m, int *n, int *tdim, float *temp, int *jval, int *code); #else float cvolume_ (float *a, float *b, int *m, int *n, int *mmax, int *nmax); void volume_ (float *a, float *b, int *m, int *n, int *mmax, int *nmax, float *volume); float cvolumeb_ (float *a, float *b, int *m, int *n, int *mmax, int *nmax, int *opt, float *dvdb); void volumeb_ (float *a, float *b, int *m, int *n, int *mmax, int *nmax, int *opt, float *volume, float *dvdb); float cvolumebj_ (float *a, float *b, int *m, int *n, int *mmax, int *nmax, int con, float *dvdb); void volumebj_ (float *a, float *b, int *m, int *n, int *mmax, int *nmax, int *con, float *volume, float *dvdb); float cdvda_ (float *a, float *b, int *m, int *n, int *mmax, int *nmax, int *tdim, float *temp, int *jval, int *code); void dvda_ (float *a, float *b, int *m, int *n, int *mmax, int *nmax, int *idim, float *dvda, int *code); float cvolumef_ (float *a, float *b, int *m, int *n, int *mmax, int *nmax); void volumef_ (float *a, float *b, int *m, int *n, int *mmax, int *nmax, float *volume); float cdvdaf_ (float *a, float *b, int *m, int *n, int *mmax, int *nmax, int *tdim, float *temp, int *jval, int *code); void dvdaf_ (float *a, float *b, int *m, int *n, int *mmax, int *nmax, int *idim, float *dvda, int *code); float cdvda_debug_ (float *a, float *b, int *m, int *n, int *tdim, float *temp, int *jval, int *code); #endif /*-------------------------------------------------------------- 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. --------------------------------------------------------------*/ #ifndef _UNDERSCORE float cvolume(a,b,m,n,mmax,nmax) #else float cvolume_ (a,b,m,n,mmax,nmax) #endif 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 = *n,mm = *m, mm_max = *mmax; int nm1,mm1; float *ap, *bp; int firstmin,firstmax; float bmin,bmax,bb; float partialv; /* one-dimensional case (full reduction) */ if (nn == 1) { firstmin=0; firstmax=0; for (l=0;l 0.) { bb= *(b+l)/ *(a+l); if (firstmin==0) {firstmin=1;bmin=bb;} else if (bbbmax) 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"); */ 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= 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(4*nm1*mm1); bp = (float *) malloc(4*mm1); /* reduce a and b into ap and bp eliminating variable t and constraint i */ jj=-1; for (j=0;j 0.) { bb= *(b+l)/ *(a+l); if (firstmin==0) {firstmin=1;bmin=bb;lmin=l;} else if (bbbmax) {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= 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(4*nm1*mm1); bp = (float *) malloc(4*mm1); /* reduce a and b into ap and bp eliminating variable t and constraint i */ jj=-1; for (j=0;j 0.) { bb= *(b+l)/ *(a+l); if (firstmin==0) {firstmin=1;bmin=bb;lmin=l;} else if (bbbmax) {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= 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(4*nm1*mm1); bp = (float *) malloc(4*mm1); /* reduce a and b into ap and bp eliminating variable t and constraint i */ jj=-1; for (j=0;j 0.) { bb= *(b+l)/ *(a+l); if (firstmin==0) {firstmin=1;bmin=bb;lmin=l;} else if (bbbmax) {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= 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(4*mm1); for (j=0;j 0.) { bb= *(b+l)/ *(a+l); if (firstmin==0) {firstmin=1;bmin=bb;} else if (bbbmax) 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= 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(4*nm1*mm1); bp = (float *) malloc(4*mm1); /* reduce a and b into ap and bp eliminating variable t and constraint i */ jj=-1; for (j=0;j 0.) { bb= *(b+l)/ *(a+l); if (firstmin==0) {firstmin=1;bmin=bb;lmin=l;} else if (bbbmax) {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= 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(4*mm1); for (j=0;j 0.) { bb= *(b+l)/ *(a+l); if (firstmin==0) {firstmin=1;bmin=bb;lmin=l;} else if (bbbmax) {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= 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(4*mm); for (j=0;j