Thread: implementation of routines from numerical recipes

  1. #1
    Registered User
    Join Date
    Nov 2008
    Posts
    45

    implementation of routines from numerical recipes

    hi,

    i have some specific questions to ask about implementing this downhill simplex routine called amoeba.c, from the book Numerical Recipes, 2nd ed. the questions may be rather straightforward...as my background in c is rather basic, and am totally new to numerical recipes.

    basically, this routine goes as
    Code:
    #include <math.h>
    #define NRANSI
    #include "nrutil.h"
    #define NMAX 5000
    #define GET_PSUM \
    					for (j=1;j<=ndim;j++) {\
    					for (sum=0.0,i=1;i<=mpts;i++) sum += p[i][j];\
    					psum[j]=sum;}
    #define SWAP(a,b) {swap=(a);(a)=(b);(b)=swap;}
    
    void amoeba(float **p, float y[], int ndim, float ftol,
    	float (*funk)(float []), int *nfunk)
    {
    	float amotry(float **p, float y[], float psum[], int ndim,
    		float (*funk)(float []), int ihi, float fac);
    	int i,ihi,ilo,inhi,j,mpts=ndim+1;
    	float rtol,sum,swap,ysave,ytry,*psum;
    
    	psum=vector(1,ndim);
    	*nfunk=0;
    	GET_PSUM
    	for (;;) {
    		ilo=1;
    		ihi = y[1]>y[2] ? (inhi=2,1) : (inhi=1,2);
    		for (i=1;i<=mpts;i++) {
    			if (y[i] <= y[ilo]) ilo=i;
    			if (y[i] > y[ihi]) {
    				inhi=ihi;
    				ihi=i;
    			} else if (y[i] > y[inhi] && i != ihi) inhi=i;
    		}
    		rtol=2.0*fabs(y[ihi]-y[ilo])/(fabs(y[ihi])+fabs(y[ilo]));
    		if (rtol < ftol) {
    			SWAP(y[1],y[ilo])
    			for (i=1;i<=ndim;i++) SWAP(p[1][i],p[ilo][i])
    			break;
    		}
    		if (*nfunk >= NMAX) nrerror("NMAX exceeded");
    		*nfunk += 2;
    		ytry=amotry(p,y,psum,ndim,funk,ihi,-1.0);
    		if (ytry <= y[ilo])
    			ytry=amotry(p,y,psum,ndim,funk,ihi,2.0);
    		else if (ytry >= y[inhi]) {
    			ysave=y[ihi];
    			ytry=amotry(p,y,psum,ndim,funk,ihi,0.5);
    			if (ytry >= ysave) {
    				for (i=1;i<=mpts;i++) {
    					if (i != ilo) {
    						for (j=1;j<=ndim;j++)
    							p[i][j]=psum[j]=0.5*(p[i][j]+p[ilo][j]);
    						y[i]=(*funk)(psum);
    					}
    				}
    				*nfunk += ndim;
    				GET_PSUM
    			}
    		} else --(*nfunk);
    	}
    	free_vector(psum,1,ndim);
    }
    #undef SWAP
    #undef GET_PSUM
    #undef NMAX
    #undef NRANSI
    to run this routine, another routine also has to be compiled and executed. its called amotry.c :

    Code:
    #define NRANSI
    #include "nrutil.h"
    
    float amotry(float **p, float y[], float psum[], int ndim,
    	float (*funk)(float []), int ihi, float fac)
    {
    	int j;
    	float fac1,fac2,ytry,*ptry;
    
    	ptry=vector(1,ndim);
    	fac1=(1.0-fac)/ndim;
    	fac2=fac1-fac;
    	for (j=1;j<=ndim;j++) ptry[j]=psum[j]*fac1-p[ihi][j]*fac2;
    	ytry=(*funk)(ptry);
    	if (ytry < y[ihi]) {
    		y[ihi]=ytry;
    		for (j=1;j<=ndim;j++) {
    			psum[j] += ptry[j]-p[ihi][j];
    			p[ihi][j]=ptry[j];
    		}
    	}
    	free_vector(ptry,1,ndim);
    	return ytry;
    }
    #undef NRANSI
    an example on how to use amoeba.c is also provided, called xamoeba.c:

    Code:
    /* Driver for routine amoeba */
    
    #include <stdio.h>
    #include <math.h>
    #define NRANSI
    #include "nr.h"
    #include "nrutil.h"
    
    #define MP 4
    #define NP 3
    #define FTOL 1.0e-6
    
    float func(float x[])
    {
    	return 0.6-bessj0(SQR(x[1]-0.5)+SQR(x[2]-0.6)+SQR(x[3]-0.7));
    }
    
    int main(void)
    {
    	int i,nfunc,j,ndim=NP;
    	float *x,*y,**p;
    
    	x=vector(1,NP);
    	y=vector(1,MP);
    	p=matrix(1,MP,1,NP);
    	for (i=1;i<=MP;i++) {
    		for (j=1;j<=NP;j++)
    			x[j]=p[i][j]=(i == (j+1) ? 1.0 : 0.0);
    		y[i]=func(x);
    	}
    	amoeba(p,y,ndim,FTOL,func,&nfunc);
    	printf("\nNumber of function evaluations: %3d\n",nfunc);
    	printf("Vertices of final 3-d simplex and\n");
    	printf("function values at the vertices:\n\n");
    	printf("%3s %10s %12s %12s %14s\n\n",
    		"i","x[i]","y[i]","z[i]","function");
    	for (i=1;i<=MP;i++) {
    		printf("%3d ",i);
    		for (j=1;j<=NP;j++) printf("%12.6f ",p[i][j]);
    		printf("%12.6f\n",y[i]);
    	}
    	printf("\nTrue minimum is at (0.5,0.6,0.7)\n");
    	free_matrix(p,1,MP,1,NP);
    	free_vector(y,1,MP);
    	free_vector(x,1,NP);
    	return 0;
    }
    #undef NRANSI
    my question is, how do i modify xamoeba.c to insert my own model function? also, how do i feed the data values (to optimize the model against) during runtime, as i need to do this iteratively for a few million times (i am running it for every pixel of a 15million pixel image)?

    thanks in advance!

  2. #2
    Registered User
    Join Date
    Sep 2006
    Posts
    8,868
    Oh hell yes!


    I understood the first three words of this algorithm - perfectly!

  3. #3
    Registered User
    Join Date
    Nov 2008
    Posts
    45
    hi adak, i am sorry i catch no ball..

  4. #4
    Woof, woof! zacs7's Avatar
    Join Date
    Mar 2007
    Location
    Australia
    Posts
    3,459
    No one has a hope of understanding that, it lacks comments and a good naming scheme. What are you asking for specifically?

  5. #5
    Registered User
    Join Date
    Nov 2008
    Posts
    45
    i see.

    there are these 2 c routines in numerical recipes, named amoeba.c and amotry.c, that i wish to implement in my program. the amoeba.c is a nonlinear regression routine that calls on amotry.c, so both of these have to be compiled and executed together. the xamoeba.c is an example of how to use these 2 routines for a nonlinear regression.

    my question is, how do i modify xamoeba.c to insert my own equation? and which segment of xamoeba.c has to be edited so as to allow data values to be fed to the program during runtime? i do not understand the codes well enough to know how to modify them. for my first question, though, i think i have to edit the chunk "float func(float x[])", although exactly how i am not sure.

    there is actually another example in the text, with comments this time. its as follows:

    Code:
    #include <math.h>
    #include "nrutil.h"
    #define TINY 1.0e-10                                     //A small number.
    #define NMAX 5000 									//Maximum allowed number of function evalua-
    #define GET_PSUM \ tions.
    		for (j=1;j<=ndim;j++) {\
    		for (sum=0.0,i=1;i<=mpts;i++) sum += p[i][j];\
    		psum[j]=sum;}
    #define SWAP(a,b) {swap=(a);(a)=(b);(b)=swap;}
    void amoeba(float **p, float y[], int ndim, float ftol,
    float (*funk)(float []), int *nfunk)
    /*
    Multidimensional minimization of the function funk(x) where x[1..ndim] is a vector in ndim
    dimensions, by the downhill simplex method of Nelder and Mead. The matrix p[1..ndim+1]
    [1..ndim] is input. Its ndim+1 rows are ndim-dimensional vectors which are the vertices of
    the starting simplex. Also input is the vector y[1..ndim+1], whose components must be preinitialized
    to the values of funk evaluated at the ndim+1 vertices (rows) of p; and ftol the
    fractional convergence tolerance to be achieved in the function value (n.b.!). On output, p and
    y will have been reset to ndim+1 new points all within ftol of a minimum function value, and
    nfunk gives the number of function evaluations taken.
    */
    {
    	float amotry(float **p, float y[], float psum[], int ndim,
    		float (*funk)(float []), int ihi, float fac);
    	int i,ihi,ilo,inhi,j,mpts=ndim+1;
    	float rtol,sum,swap,ysave,ytry,*psum;
    	psum=vector(1,ndim);
    	*nfunk=0;
    	GET_PSUM
    	for (;;) {
    	ilo=1;
    	First we must determine which point is the highest (worst), next-highest, and lowest
    	(best), by looping over the points in the simplex.
    	ihi = y[1]>y[2] ? (inhi=2,1) : (inhi=1,2);
    	for (i=1;i<=mpts;i++) {
    		if (y[i] <= y[ilo]) ilo=i;
    		if (y[i] > y[ihi]) {
    			inhi=ihi;
    			ihi=i;
    	} else if (y[i] > y[inhi] && i != ihi) inhi=i;
    	}
    	rtol=2.0*fabs(y[ihi]-y[ilo])/(fabs(y[ihi])+fabs(y[ilo])+TINY);
    	Compute the fractional range from highest to lowest and return if satisfactory.
    	if (rtol < ftol) { If returning, put best point and value in slot 1.
    	SWAP(y[1],y[ilo])
    	for (i=1;i<=ndim;i++) SWAP(p[1][i],p[ilo][i])
    	break;
    	}
    	if (*nfunk >= NMAX) nrerror("NMAX exceeded");
    	*nfunk += 2;
    	Begin a new iteration. First extrapolate by a factor −1 through the face of the simplex
    	across from the high point, i.e., reflect the simplex from the high point.
    	ytry=amotry(p,y,psum,ndim,funk,ihi,-1.0);
    	if (ytry <= y[ilo])
    		Gives a result better than the best point, so try an additional extrapolation by a
    		factor 2.
    		ytry=amotry(p,y,psum,ndim,funk,ihi,2.0);
    	else if (ytry >= y[inhi]) {
    		The reflected point is worse than the second-highest, so look for an intermediate
    		lower point, i.e., do a one-dimensional contraction.
    		ysave=y[ihi];
    		ytry=amotry(p,y,psum,ndim,funk,ihi,0.5);
    		if (ytry >= ysave) { Can't seem to get rid of that high point. Better
    			for (i=1;i<=mpts;i++) { contract around the lowest (best) point.
    
    				if (i != ilo) {
    			for (j=1;j<=ndim;j++)
    				p[i][j]=psum[j]=0.5*(p[i][j]+p[ilo][j]);
    			y[i]=(*funk)(psum);
    		}
    	}
    		*nfunk += ndim; Keep track of function evaluations.
    		GET_PSUM Recompute psum.
    }
    } else --(*nfunk); Correct the evaluation count.
    } Go back for the test of doneness and the next
    free_vector(psum,1,ndim); iteration.
    }
    
    #include "nrutil.h"
    float amotry(float **p, float y[], float psum[], int ndim,
    float (*funk)(float []), int ihi, float fac)
    Extrapolates by a factor fac through the face of the simplex across from the high point, tries
    it, and replaces the high point if the new point is better.
    {
    int j;
    float fac1,fac2,ytry,*ptry;
    ptry=vector(1,ndim);
    fac1=(1.0-fac)/ndim;
    fac2=fac1-fac;
    for (j=1;j<=ndim;j++) ptry[j]=psum[j]*fac1-p[ihi][j]*fac2;
    ytry=(*funk)(ptry); Evaluate the function at the trial point.
    if (ytry < y[ihi]) { If it's better than the highest, then replace the highest.
    y[ihi]=ytry;
    for (j=1;j<=ndim;j++) {
    psum[j] += ptry[j]-p[ihi][j];
    p[ihi][j]=ptry[j];
    }
    }
    free_vector(ptry,1,ndim);
    return ytry;
    }
    sorry for the lack of indentation.

Popular pages Recent additions subscribe to a feed

Similar Threads

  1. Replies: 3
    Last Post: 06-21-2010, 04:16 AM
  2. rand() implementation
    By habert79 in forum C Programming
    Replies: 4
    Last Post: 02-07-2009, 01:18 PM
  3. For the numerical recipes in C types!
    By Smattacus in forum C Programming
    Replies: 5
    Last Post: 10-28-2008, 07:57 PM
  4. Special Allegro Information
    By TechWins in forum Game Programming
    Replies: 12
    Last Post: 08-20-2002, 11:35 PM
  5. rom/bios routines
    By ALLRIGHT in forum C Programming
    Replies: 1
    Last Post: 05-12-2002, 11:38 AM