/* Copyright (c) 1997 Lucent Technologies */ /* All Rights Reserved */ /* THIS IS UNPUBLISHED PROPRIETARY SOURCE CODE OF LUCENT. */ /* The copyright notice above does not evidence any */ /* actual or intended publication of such source code. */ /* sample funcadd */ #include "stdlib.h" /* for atoi */ #include "math.h" #include "funcadd.h" /* includes "stdio1.h" */ #include "myalloc.h" /* Sample function kth optionally prints its arguments using * a variant of stdio.h supplied by funcadd.h. */ #ifdef __cplusplus /* The #ifdef __cplusplus lines allow this to be compiled * either by an ANSI C compiler or by a C++ compiler. */ extern "C" { #endif static void showvec( real *x, int n, AmplExports *ae); static void showmat( real **A, int n, AmplExports *ae); static void showmat2( real **A, int n, AmplExports *ae); static void mx( real **A, real *x, real *y, int n); static double dotprod( double *x, double *y, int n); static int argmax( real *x, int n); static real erf (real x); static real gammp (real a, real x); static void gser(real *gamser, real a, real x, real *gln); static void gcf( real *gammcf, real a, real x, real *gln); static real ginv(arglist *al) /* generalized inverse of a single argument */ { real x = al->ra[0]; x = x ? 1./x : 0.; if (al->derivs) { *al->derivs = -x*x; if (al->hes) *al->hes = -2.*x * *al->derivs; } return x; } static char * sginv(arglist *al) /* character-valued version of ginv */ { static char buf[32]; AmplExports *ae = al->AE; /* for sprintf */ real x = al->ra[0]; sprintf(buf, "x%.g", x ? 1./x : 0); return buf; } static real myhypot(arglist *al) /* myhypot(x,y) = sqrt(x*x + y*y) */ { real *d, *h, rv, x, x0, y, y0; x = x0 = al->ra[0]; y = y0 = al->ra[1]; if (x < 0.) x = -x; if (y < 0.) y = -y; rv = x; if (x < y) { rv = y; y = x; x = rv; } if (rv) { y /= x; rv = x * sqrt(1. + y*y); if (d = (real *)al->derivs) { d[0] = x0 / rv; d[1] = y0 / rv; if (h = al->hes) { h[0] = d[1]*d[1] / rv; h[1] = -d[0]*d[1] / rv; h[2] = d[0]*d[0] / rv; } } } else if (d = (real *)al->derivs) { d[0] = d[1] = 0; if (h = al->hes) h[0] = h[1] = h[2] = 0; } return rv; } static real ncall(void) /* returns it's invocation count */ { static real x; return ++x; } static real mean(register arglist *al) /* mean of arbitrarily many arguments */ { real x, z; real *d, *de, *ra; int *at, i, j, n, nreal; char *se, *sym; AmplExports *ae = al->AE; n = al->n; if (n <= 0) return 0; at = al->at; ra = al->ra; d = (real *)al->derivs; x = 0.0; nreal = 0; for(i=0; i= 0) { x += ra[j]; ++nreal; } else { x += z = strtod(sym = al->sa[-(j+1)], &se); if (*se) { fprintf(Stderr, "mean treating arg %d = \"%s\" as %.g\n", i+1, sym, z); fflush(Stderr); } } } if (d) { z = 1.0/n; for (i=0; iAE; static real **A=NULL, **E=NULL; static real *lambda=NULL, *x=NULL, *y=NULL, *y0=NULL; /* srand48(0); */ narg = al->n; if (narg <= 0) return 0; n = (int)(sqrt(1+8*narg)-1)/2; if (n*(n+1)/2 != narg) { fprintf(Stderr, "should be mineig({i in 1..n, j in 1..n: j>=i} A[i,j])\n"); fflush(Stderr); } at = al->at; ra = al->ra; d = (real *)al->derivs; h = al->hes; /* if (A == NULL) { CALLOC( A, n, real * ); } else { REALLOC( A, n, real * ); } for (i=0; i= 0) { A[i][j] = ra[jj]; } else { A[i][j] = z = strtod(sym = al->sa[-(jj+1)], &se); if (*se) { fprintf(Stderr, "mineig treating arg %d = \"%s\" as %.g\n", i+1, sym, z); fflush(Stderr); } } k++; } } /* showmat(A,n,ae); */ for (i=0; i= 0) {shift = lambda[0]/2 + y[0];} else {shift = y[0];} */ shift = y0[0]; fprintf(Stderr, "shift = %f \n", shift); for (i=0; ira[0]; if (al->derivs) { *al->derivs = 1; if (al->hes) *al->hes = 0; } return x; } static real R_real, R_imag; static real lx, ly, lz, qx, qy, qz, zmin, zmax; static void R(arglist *al) /* inverse of 3D spectral density on a spherical shell */ { int j, n=1000; /* int j, n=20; */ real pi = 4*atan(1); real lx, ly, lz, qx, qy, qz, zmin, zmax, z; real z_perp, lq, /* component of l in direction of q */ lox, loy, loz, /* component of l orthogonal to q */ l_mag, q_mag; lx = al->ra[0]; ly = al->ra[1]; lz = al->ra[2]; qx = al->ra[3]; qy = al->ra[4]; qz = al->ra[5]; zmin = al->ra[6]; zmax = al->ra[7]; q_mag = sqrt(qx*qx + qy*qy + qz*qz); qx /= q_mag; qy /= q_mag; qz /= q_mag; R_real=0; R_imag=0; for (j=0; jderivs) { *al->derivs = 1; if (al->hes) *al->hes = 0; } */ } static real C(arglist *al) /* inverse of 3D spectral density on a spherical shell */ { if (lx != al->ra[0] || ly != al->ra[1] || lz != al->ra[2] || qx != al->ra[3] || qy != al->ra[4] || qz != al->ra[5] || zmin != al->ra[6] || zmax != al->ra[7] ) { R(al); } return R_real; } static real S(arglist *al) /* inverse of 3D spectral density on a spherical shell */ { if (lx != al->ra[0] || ly != al->ra[1] || lz != al->ra[2] || qx != al->ra[3] || qy != al->ra[4] || qz != al->ra[5] || zmin != al->ra[6] || zmax != al->ra[7] ) { R(al); } return R_imag; } static real kth_eig(register arglist *al) /* minimum kth of a symmetric matrix */ { real z, lambdak, normx, normy, shift=0, cosine, ydotEkk, lambda0=HUGE_VAL, hm, num; real *e0, *ek, *d, *h, *ra; int *at, i, ii, j, jj, k, kk, m, n, N, cnt=0, i0; char *se, *sym; AmplExports *ae = al->AE; static real **A=NULL, **E=NULL; static real *lambda=NULL, *x=NULL, *y=NULL, *y0=NULL; /* srand48(0); */ N = al->n - 1; if (N <= 0) return 0; n = (int)(sqrt(1+8*N)-1)/2; if (n*(n+1)/2 != N) { fprintf(Stderr, "should be kth_eig(k, {i in 1..n, j in 1..n: j>=i} A[i,j])\n"); fflush(Stderr); } at = al->at; ra = al->ra; d = (real *)al->derivs; h = al->hes; i0 = (int)al->ra[0]; /* if (A == NULL) { CALLOC( A, n, real * ); } else { REALLOC( A, n, real * ); } for (i=0; i= 0) { A[i][j] = ra[jj]; } else { A[i][j] = z = strtod(sym = al->sa[-(jj+1)], &se); if (*se) { fprintf(Stderr, "kth_eig treating arg %d = \"%s\" as %.g\n", i+1, sym, z); fflush(Stderr); } } k++; } } /* showmat(A,n,ae); */ for (i=0; iAE; static real **A=NULL, Ident, **A0=NULL; static int convex_flag=1; N = al->n; if (N <= 0) return 0; n = (int)(sqrt(1+8*N)-1)/2; if (n*(n+1)/2 != N) { fprintf(Stderr, "should be kth_diag({i in 1..n, j in 1..n: j>=i} A[i,j])\n"); fflush(Stderr); } at = al->at; ra = al->ra; d = (real *)al->derivs; h = al->hes; k0++; if (k0==n) k0 = 0; /* printf("IN KTH_DIAG \n"); printf("k0 = %3d \n", k0); */ if (A == NULL) { REALLOC( A, n, real *); A[0] = NULL; } else { REALLOC( A, n, real *); } REALLOC( A[0], 2*n*n, real); for (i=0, k=0; i= 0) { A[i][j] = ra[jj]; } else { A[i][j] = z = strtod(sym = al->sa[-(jj+1)], &se); if (*se) { fprintf(Stderr, "kth_diag treating arg %d = \"%s\" as %.g\n", i+1, sym, z); fflush(Stderr); } } A[j][i] = A[i][j]; k++; } for(j=n; j<2*n; j++) { A[i][j] = 0; } A[i][n+i] = 1; } for (i=0; i 0.001) ||(i!=j && fabs(Ident) > 0.001) ) { fprintf(stdout,"error in Gaussian elimination \n"); } } } } if (diagval < -1.0e-12) {convex_flag = 0;} if (k0 == n-1) { if (convex_flag == 0) { fprintf(stdout,"matrix X not positive semidefinite \n"); } convex_flag = 1; } return diagval; } static real kth_diag_eps(register arglist *al) /* kth diagonal element of D in LDL^T */ /* must be called in order: 1,2,...,n */ { real z, diagval; real *d, *h, *ra; int *at, i, ii, j, jj, k, m, n, N; static int k0=-1; char *se, *sym; AmplExports *ae = al->AE; static real **A=NULL, Ident, **A0=NULL; N = al->n; if (N <= 0) return 0; n = (int)(sqrt(1+8*N)-1)/2; if (n*(n+1)/2 != N) { fprintf(Stderr, "should be kth_diag({i in 1..n, j in 1..n: j>=i} A[i,j])\n"); fflush(Stderr); } at = al->at; ra = al->ra; d = (real *)al->derivs; h = al->hes; k0++; if (k0==n) k0 = 0; /* printf("IN KTH_DIAG \n"); printf("k0 = %3d \n", k0); */ if (A == NULL) { REALLOC( A, n, real *); A[0] = NULL; } else { REALLOC( A, n, real *); } REALLOC( A[0], 2*n*n, real); for (i=0, k=0; i= 0) { A[i][j] = ra[jj]; } else { A[i][j] = z = strtod(sym = al->sa[-(jj+1)], &se); if (*se) { fprintf(Stderr, "kth_diag treating arg %d = \"%s\" as %.g\n", i+1, sym, z); fflush(Stderr); } } A[j][i] = A[i][j]; k++; } for(j=n; j<2*n; j++) { A[i][j] = 0; } A[i][n+i] = 1; A[i][i] += 1.0e-6; } for (i=0; i 0.001) ||(i!=j && fabs(Ident) > 0.001) ) { fprintf(stdout,"error in Gaussian elimination \n"); } } } } return diagval; } static real kth_diag2(register arglist *al) /* kth diagonal element of D in LDL^T */ /* must be called in order: 1,2,...,n */ { real z, diagval; real *d, *h, *ra; int *at, i, ii, j, jj, k, m, n, N; static int k0=-1; char *se, *sym; AmplExports *ae = al->AE; static real **A=NULL, Ident, **A0=NULL; N = al->n - 1; if (N <= 0) return 0; n = (int)(sqrt(N)); if (n*n != N) { fprintf(Stderr, "should be kth_diag2(k, {i in 1..n, j in 1..n} A[i,j])\n"); fflush(Stderr); } at = al->at; ra = al->ra; d = (real *)al->derivs; h = al->hes; k = (int)al->ra[0]; k--; /* convert from 1..n to 0..n-1 */ if (k != k0+1 && k != 0) { fprintf(Stderr, "k in kth_diag2 not in increasing order \n"); fflush(Stderr); } k0 = k; if (A == NULL) { REALLOC( A, n, real *); A[0] = NULL; } else { REALLOC( A, n, real *); } REALLOC( A[0], 2*n*n, real); for (i=0, k=0; i= 0) { A[i][j] = ra[jj]; } else { A[i][j] = z = strtod(sym = al->sa[-(jj+1)], &se); if (*se) { fprintf(Stderr, "kth_diag2 treating arg %d = \"%s\" as %.g\n", i+1, sym, z); fflush(Stderr); } } k++; } for(j=n; j<2*n; j++) { A[i][j] = 0; } A[i][n+i] = 1; } for (i=0; i 0.00001) ||(i!=j && fabs(Ident) > 0.00001) ) { fprintf(stdout,"error in Gaussian elimination \n"); } } } } return diagval; } static real myerf(arglist *al) /* 1/sqrt(2 pi) int_-infty^x e^{-t^2/2} dt */ { int j; double h = 1.0/128.0, x0 = -10; double h2 = h/2; double myerf=0; double pi = 4*atan(1); double rtp = sqrt(2*pi); double rt = sqrt(2); double deriv; real x = al->ra[0]; myerf = (erf(x/rt) + 1)/2; if (al->derivs) { deriv = exp(-x*x/2)/rtp; *al->derivs = deriv; if (al->hes) *al->hes = -x * deriv; } return myerf; } static real stderf(arglist *al) /* 2/sqrt(pi) int_0^x e^{-t^2} dt */ { int j; double h = 1.0/128.0, x0 = -10; double h2 = h/2; double stderf=0; double pi = 4*atan(1); double rp = sqrt(pi); double rt = sqrt(2); double deriv; real x = al->ra[0]; stderf = erf(x); if (al->derivs) { deriv = 2*exp(-x*x)/rp; *al->derivs = deriv; if (al->hes) *al->hes = -2*x * deriv; } return stderf; } static void showvec( real *x, int n, AmplExports *ae) { int i, j; for(i=0; i=i) { fprintf(stderr, "%10.4f ", A[i][j]); } else { fprintf(stderr, " "); } } fprintf(Stderr, "\n"); fflush(Stderr); } } static void showmat2( real **A, int n, AmplExports *ae) { int i, j; for(i=0; i max) {ii=i; max=fabs(x[i]);} return ii; } static real mymin(register arglist *al) /* minimum eigenvalue of a symmetric matrix */ { real z, x0=HUGE_VAL; real *d, *h, *ra; int *at, i, j, jj, k, m, n, i0; char *se, *sym; AmplExports *ae = al->AE; static real *x=NULL; n = al->n; if (n <= 0) return 0; at = al->at; ra = al->ra; d = (real *)al->derivs; h = al->hes; REALLOC( x, n, real ); for(i=0; i= 0) { x[i] = ra[jj]; } else { x[i] = z = strtod(sym = al->sa[-(jj+1)], &se); if (*se) { fprintf(Stderr, "mymin treating arg %d = \"%s\" as %.g\n", i+1, sym, z); fflush(Stderr); } } } for (k=0; kAE; static real *x=NULL; n = al->n - 1; if (n <= 0) return 0; at = al->at; ra = al->ra; d = (real *)al->derivs; h = al->hes; REALLOC( x, n+1, real ); i0 = (int)al->ra[0]; for(i=1; i<=n; i++) { jj = at[i]; if (jj >= 0) { x[i] = ra[jj]; } else { x[i] = z = strtod(sym = al->sa[-(jj+1)], &se); if (*se) { fprintf(Stderr, "nonneg treating arg %d = \"%s\" as %.g\n", i+1, sym, z); fflush(Stderr); } } } if (d) { for (i=0; iAE; k = al->at[0] ? atoi(al->sa[0]) : (int)al->ra[0]; n = al->n; if (k < 0) { fprintf(Stderr, "kth("); comma = ""; for(i = 0; i < n; i++, comma = ", ") if ((j = al->at[i]) >= 0) fprintf(Stderr, "%s%.g", comma, al->ra[j]); else fprintf(Stderr, "%s%s", comma, al->sa[-(j+1)]); fprintf(Stderr, ")\n"); fflush(Stderr); k = -k; } if (n <= 1 || k <= 0 || k >= n) return ""; if ((j = al->at[k]) >= 0) { sprintf(buf, "%.g", al->ra[j]); return buf; } return al->sa[-(j+1)]; } void funcadd(AmplExports *ae){ /* Insert calls on addfunc here... */ /* Arg 3, called type, must satisfy 0 <= type <= 6: * type&1 == 0: 0,2,4,6 ==> force all arguments to be numeric. * type&1 == 1: 1,3,5 ==> pass both symbolic and numeric arguments. * type&6 == 0: 0,1 ==> the function is real valued. * type&6 == 2: 2,3 ==> the function is char * valued; static storage suffices: AMPL copies the return value. * type&6 == 4: 4,5 ==> the function is random (real valued). * type&6 == 6: 6 ==> random, real valued, pass nargs real args, * 0 <= nargs <= 2. * * Arg 4, called nargs, is interpretted as follows: * >= 0 ==> the function has exactly nargs arguments * <= -1 ==> the function has >= -(nargs+1) arguments. */ addfunc("ginv", (rfunc)ginv, 0, 1, 0); addfunc("sginv", (rfunc)sginv, 2, 1, 0); addfunc("hypot", (rfunc)myhypot, 0, 2, 0); addfunc("ncall", (rfunc)ncall, 0, 0, 0); addfunc("rncall", (rfunc)ncall, 4, 0, 0); /*could change 4 to 6*/ addfunc("mean0", (rfunc)mean, 0, -1, 0); addfunc("mean", (rfunc)mean, 1, -1, 0); addfunc("mineig", (rfunc)mineig, 1, -1, 0); addfunc("kth_eig", (rfunc)kth_eig, 1, -1, 0); addfunc("linear", (rfunc)linear, 1, -1, 0); addfunc("C", (rfunc)C, 0, 8, 0); addfunc("S", (rfunc)S, 0, 8, 0); addfunc("kth_diag", (rfunc)kth_diag, 1, -1, 0); addfunc("kth_diag_eps",(rfunc)kth_diag_eps,1, -1, 0); addfunc("kth_diag2",(rfunc)kth_diag2,1, -1, 0); addfunc("myerf", (rfunc)myerf, 0, 1, 0); addfunc("stderf", (rfunc)stderf, 0, 1, 0); addfunc("mymin", (rfunc)mymin, 1, -1, 0); addfunc("nonneg", (rfunc)nonneg, 1, -1, 0); addfunc("kth", (rfunc)kth, 3, -2, 0); } static double erf (double x) { return x < 0.0 ? -gammp(0.5, x*x) : gammp(0.5, x*x); } static double gammln(double xx) { double x, tmp, ser; static double cof[6]={76.18009173, -86.50532033, 24.01409822, -1.231739516, 0.120858003e-2, -0.536382e-5}; int j; x = xx-1.0; tmp = x+5.5; tmp -= (x+0.5)*log(tmp); ser=1.0; for (j=0; j<=5;j++) { x += 1.0; ser += cof[j]/x; } return -tmp+log(2.50662827465*ser); } static double gammp (double a, double x) { double gamser, gammcf, gln; if (x < 0.0 || a <= 0.0) { /* fprintf(stderr,"invalid arguments in gammp\n"); exit(0); */ } if (x < (a+1.0)) { gser(&gamser,a,x,&gln); return gamser; } else { gcf(&gammcf,a,x,&gln); return 1.0-gammcf; } } #define ITMAX 100 #define EPS 3.0e-7 static void gser(double *gamser, double a, double x, double *gln) { int n; double sum, del, ap; *gln=gammln(a); if (x <= 0.0) { /* if (x < 0.0) {fprintf(stderr,"x < 0 in gser\n"); exit(0);} */ *gamser=0.0; return; } else { ap = a; del = sum = 1.0/a; for (n=1; n<= ITMAX; n++) { ap += 1.0; del *= x/ap; sum += del; if (fabs(del) < fabs(sum)*EPS) { *gamser=sum*exp(-x+a*log(x)-(*gln)); return; } } /* fprintf(stderr,"a too large or ITMAX too small in gser\n"); exit(0); */ } } static void gcf( double *gammcf, double a, double x, double *gln) { int n; double gold=0.0,g,fac=1.0, b1=1.0; double b0=0.0, anf, ana, an, a1, a0=1.0; *gln = gammln(a); a1 = x; for (n=1; n<=ITMAX; n++) { an= (double) n; ana = an - a; a0 = (a1+a0*ana)*fac; b0 = (b1+b0*ana)*fac; anf = an*fac; a1 = x*a0+anf*a1; b1 = x*b0+anf*b1; if (a1) { fac = 1.0/a1; g = b1*fac; if (fabs((g-gold)/g) < EPS) { *gammcf = exp(-x+a*log(x)-(*gln))*g; return; } gold = g; } } /* fprintf(stderr,"a too large or ITMAX too small in gcf\n"); exit(0); */ } #ifdef __cplusplus } #endif