nr_conjgrad.c

来自「LastWave」· C语言 代码 · 共 317 行

C
317
字号
#include "lastwave.h"#include "signals.h"static LWFLOAT *vector(int nl, int nh){	LWFLOAT *v;	v=(LWFLOAT *) Malloc((unsigned) (nh-nl+1)*sizeof(LWFLOAT));	if (!v) Errorf("allocation failure in vector()");	return v-nl;}static void free_vector(LWFLOAT *v,int nl,int nh){	Free((char*) (v+nl));}#define ITMAX 100#define CGOLD 0.3819660#define ZEPS 1.0e-10#define SIGN1(a,b) ((b) > 0.0 ? fabs(a) : -fabs(a))#define SHFT(a,b,c,d) (a)=(b);(b)=(c);(c)=(d);static LWFLOAT brent(LWFLOAT ax,LWFLOAT bx,LWFLOAT cx,LWFLOAT (*f)(LWFLOAT),LWFLOAT tol,LWFLOAT *xmin){	int iter;	LWFLOAT a,b,d,etemp,fu,fv,fw,fx,p,q,r,tol1,tol2,u,v,w,x,xm;	LWFLOAT e=0.0;	a=((ax < cx) ? ax : cx);	b=((ax > cx) ? ax : cx);	x=w=v=bx;	fw=fv=fx=(*f)(x);	for (iter=1;iter<=ITMAX;iter++) {		xm=0.5*(a+b);		tol2=2.0*(tol1=tol*fabs(x)+ZEPS);		if (fabs(x-xm) <= (tol2-0.5*(b-a))) {			*xmin=x;			return fx;		}		if (fabs(e) > tol1) {			r=(x-w)*(fx-fv);			q=(x-v)*(fx-fw);			p=(x-v)*q-(x-w)*r;			q=2.0*(q-r);			if (q > 0.0) p = -p;			q=fabs(q);			etemp=e;			e=d;			if (fabs(p) >= fabs(0.5*q*etemp) || p <= q*(a-x) || p >= q*(b-x))				d=CGOLD*(e=(x >= xm ? a-x : b-x));			else {				d=p/q;				u=x+d;				if (u-a < tol2 || b-u < tol2)					d=SIGN1(tol1,xm-x);			}		} else {			d=CGOLD*(e=(x >= xm ? a-x : b-x));		}		u=(fabs(d) >= tol1 ? x+d : x+SIGN1(tol1,d));		fu=(*f)(u);		if (fu <= fx) {			if (u >= x) a=x; else b=x;			SHFT(v,w,x,u)			SHFT(fv,fw,fx,fu)		} else {			if (u < x) a=u; else b=u;			if (fu <= fw || w == x) {				v=w;				w=u;				fv=fw;				fw=fu;			} else if (fu <= fv || v == x || v == w) {				v=u;				fv=fu;			}		}	}	Errorf("Too many iterations in BRENT");	*xmin=x;	return fx;}#undef ITMAX#undef CGOLD#undef ZEPS#undef SIGN1#define GOLD 1.618034#define GLIMIT 100.0#define TINY 1.0e-20#define SIGN1(a,b) ((b) > 0.0 ? fabs(a) : -fabs(a))static void mnbrak(LWFLOAT *ax,LWFLOAT *bx,LWFLOAT *cx,LWFLOAT *fa,LWFLOAT *fb,LWFLOAT *fc,LWFLOAT (*func)(LWFLOAT)){	LWFLOAT ulim,u,r,q,fu,dum;	*fa=(*func)(*ax);	*fb=(*func)(*bx);	if (*fb > *fa) {		SHFT(dum,*ax,*bx,dum)		SHFT(dum,*fb,*fa,dum)	}	*cx=(*bx)+GOLD*(*bx-*ax);	*fc=(*func)(*cx);	while (*fb > *fc) {		r=(*bx-*ax)*(*fb-*fc);		q=(*bx-*cx)*(*fb-*fa);		u=(*bx)-((*bx-*cx)*q-(*bx-*ax)*r)/			(2.0*SIGN1(MAX(fabs(q-r),TINY),q-r));		ulim=(*bx)+GLIMIT*(*cx-*bx);		if ((*bx-u)*(u-*cx) > 0.0) {			fu=(*func)(u);			if (fu < *fc) {				*ax=(*bx);				*bx=u;				*fa=(*fb);				*fb=fu;				return;			} else if (fu > *fb) {				*cx=u;				*fc=fu;				return;			}			u=(*cx)+GOLD*(*cx-*bx);			fu=(*func)(u);		} else if ((*cx-u)*(u-ulim) > 0.0) {			fu=(*func)(u);			if (fu < *fc) {				SHFT(*bx,*cx,u,*cx+GOLD*(*cx-*bx))				SHFT(*fb,*fc,fu,(*func)(u))			}		} else if ((u-ulim)*(ulim-*cx) >= 0.0) {			u=ulim;			fu=(*func)(u);		} else {			u=(*cx)+GOLD*(*cx-*bx);			fu=(*func)(u);		}		SHFT(*ax,*bx,*cx,u)		SHFT(*fa,*fb,*fc,fu)	}}#undef GOLD#undef GLIMIT#undef TINY#undef SIGN1#undef SHFT/* * Minimization along a direction */  #define TOL 2.0e-4 static int ncom=0;	/* defining declarations */static LWFLOAT *pcom=0,*xicom=0,(*nrfunc)();static LWFLOAT f1dim(LWFLOAT x){	int j;	LWFLOAT f,*xt;	xt=vector(1,ncom);	for (j=1;j<=ncom;j++) xt[j]=pcom[j]+x*xicom[j];	f=(*nrfunc)(xt);	free_vector(xt,1,ncom);	return f;}static void linmin(LWFLOAT p[],LWFLOAT xi[],int n,LWFLOAT *fret,LWFLOAT (*func)(LWFLOAT p[])){	int j;	LWFLOAT xx,xmin,fx,fb,fa,bx,ax;	ncom=n;	pcom=vector(1,n);	xicom=vector(1,n);	nrfunc=func;	for (j=1;j<=n;j++) {		pcom[j]=p[j];		xicom[j]=xi[j];	}	ax=0.0;	xx=1.0;	bx=2.0;	mnbrak(&ax,&xx,&bx,&fa,&fx,&fb,f1dim);	*fret=brent(ax,xx,bx,f1dim,TOL,&xmin);	for (j=1;j<=n;j++) {		xi[j] *= xmin;		p[j] += xi[j];	}	free_vector(xicom,1,n);	free_vector(pcom,1,n);}#undef TOL/* * Conjugate gradient method */ #define ITMAX 2000         // Maximum number of iterations#define EPS 1.0e-10       // Precision#define FREEALL free_vector(xi,1,n);free_vector(h,1,n);free_vector(g,1,n);static void frprmn(LWFLOAT p[], int n, LWFLOAT ftol, int *iter, LWFLOAT *fret, LWFLOAT (*func)(LWFLOAT p[]),void (*dfunc)(LWFLOAT p[], LWFLOAT xi[]), char flagPrint){	int j,its,i;	LWFLOAT gg,gam,fp,dgg;	LWFLOAT *g,*h,*xi;	void linmin();	g=vector(1,n);	h=vector(1,n);	xi=vector(1,n);	fp=(*func)(p);	(*dfunc)(p,xi);	for (j=1;j<=n;j++) {		g[j] = -xi[j];		xi[j]=h[j]=g[j];	}	for (its=1;its<=ITMAX;its++) {		*iter=its;		linmin(p,xi,n,fret,func);		if (flagPrint) {		  Printf("##Iteration %d : val = %f\n",its,*fret);		  for (i=0;i<n;i++) Printf("%g ",p[i+1]);		  Printf("\n");		}		if (2.0*fabs(*fret-fp) <= ftol*(fabs(*fret)+fabs(fp)+EPS)) {			FREEALL			return;		}		fp=(*func)(p);		(*dfunc)(p,xi);		dgg=gg=0.0;		for (j=1;j<=n;j++) {			gg += g[j]*g[j];/*		  dgg += xi[j]*xi[j];	*/			dgg += (xi[j]+g[j])*xi[j];		}		if (gg == 0.0) {			FREEALL			return;		}		gam=dgg/gg;		for (j=1;j<=n;j++) {			g[j] = -xi[j];			xi[j]=h[j]=g[j]+gam*h[j];		}	}	Errorf("Too many iterations in FRPRMN");}#undef ITMAX#undef EPS#undef FREEALLstatic SIGNAL theSig = NULL;static SIGNAL theGrad = NULL;static int theN;static LWFLOAT (*theF)(SIGNAL p);static void  (*theDF)(SIGNAL p, SIGNAL grad);static LWFLOAT theFunc(LWFLOAT p[]){  LWFLOAT f;    theSig->Y = p+1;  theSig->size = theN;  f = (*theF)(theSig);  theSig->size = 0;  theSig->Y = NULL;      return(f);}static void theDFunc(LWFLOAT p[], LWFLOAT g[]){  theSig->Y = p+1;  theSig->size = theN;  theGrad->Y = g+1;  theGrad->size = theN;  (*theDF)(theSig,theGrad);  theSig->size = 0;  theSig->Y = NULL;  theGrad->size = 0;    theGrad->Y = NULL;}void ConjGrad(SIGNAL startPoint, LWFLOAT tolerance, LWFLOAT (*f)(SIGNAL point),void (*df)(SIGNAL point,SIGNAL grad), int *nIter, LWFLOAT *minVal, char flagPrint){  if (theSig == NULL) {    theSig = NewSignal();    theGrad = NewSignal();  }  theN = startPoint->size;  theF = f;  theDF = df;    frprmn(startPoint->Y-1,startPoint->size,tolerance,nIter,minVal,theFunc,theDFunc,flagPrint);    DeleteSignal(theSig);  DeleteSignal(theGrad);  theSig = theGrad = NULL;}

⌨️ 快捷键说明

复制代码Ctrl + C
搜索代码Ctrl + F
全屏模式F11
增大字号Ctrl + =
减小字号Ctrl + -
显示快捷键?