📄 misc_core.c
字号:
/////////////////////////////////////////////////////////////////////////////////// // Levenberg - Marquardt non-linear minimization algorithm// Copyright (C) 2004-05 Manolis Lourakis (lourakis@ics.forth.gr)// Institute of Computer Science, Foundation for Research & Technology - Hellas// Heraklion, Crete, Greece.//// This program is free software; you can redistribute it and/or modify// it under the terms of the GNU General Public License as published by// the Free Software Foundation; either version 2 of the License, or// (at your option) any later version.//// This program is distributed in the hope that it will be useful,// but WITHOUT ANY WARRANTY; without even the implied warranty of// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the// GNU General Public License for more details.///////////////////////////////////////////////////////////////////////////////////#ifndef LM_REAL // not included by misc.c#error This file should not be compiled directly!#endif/* precision-specific definitions */#define LEVMAR_CHKJAC LM_ADD_PREFIX(levmar_chkjac)#define FDIF_FORW_JAC_APPROX LM_ADD_PREFIX(fdif_forw_jac_approx)#define FDIF_CENT_JAC_APPROX LM_ADD_PREFIX(fdif_cent_jac_approx)#define TRANS_MAT_MAT_MULT LM_ADD_PREFIX(trans_mat_mat_mult)#define LEVMAR_COVAR LM_ADD_PREFIX(levmar_covar)#ifdef HAVE_LAPACK#define LEVMAR_PSEUDOINVERSE LM_ADD_PREFIX(levmar_pseudoinverse)static int LEVMAR_PSEUDOINVERSE(LM_REAL *A, LM_REAL *B, int m);/* BLAS matrix multiplication & LAPACK SVD routines */#define GEMM LM_CAT_(LM_BLAS_PREFIX, LM_ADD_PREFIX(gemm_))/* C := alpha*op( A )*op( B ) + beta*C */extern void GEMM(char *transa, char *transb, int *m, int *n, int *k, LM_REAL *alpha, LM_REAL *a, int *lda, LM_REAL *b, int *ldb, LM_REAL *beta, LM_REAL *c, int *ldc);#define GESVD LM_ADD_PREFIX(gesvd_)#define GESDD LM_ADD_PREFIX(gesdd_)extern int GESVD(char *jobu, char *jobvt, int *m, int *n, LM_REAL *a, int *lda, LM_REAL *s, LM_REAL *u, int *ldu, LM_REAL *vt, int *ldvt, LM_REAL *work, int *lwork, int *info);/* lapack 3.0 new SVD routine, faster than xgesvd() */extern int GESDD(char *jobz, int *m, int *n, LM_REAL *a, int *lda, LM_REAL *s, LM_REAL *u, int *ldu, LM_REAL *vt, int *ldvt, LM_REAL *work, int *lwork, int *iwork, int *info);#else#define LEVMAR_LUINVERSE LM_ADD_PREFIX(levmar_LUinverse_noLapack)static int LEVMAR_LUINVERSE(LM_REAL *A, LM_REAL *B, int m);#endif /* HAVE_LAPACK *//* blocked multiplication of the transpose of the nxm matrix a with itself (i.e. a^T a) * using a block size of bsize. The product is returned in b. * Since a^T a is symmetric, its computation can be speeded up by computing only its * upper triangular part and copying it to the lower part. * * More details on blocking can be found at * http://www-2.cs.cmu.edu/afs/cs/academic/class/15213-f02/www/R07/section_a/Recitation07-SectionA.pdf */void TRANS_MAT_MAT_MULT(LM_REAL *a, LM_REAL *b, int n, int m){#ifdef HAVE_LAPACK /* use BLAS matrix multiply */LM_REAL alpha=CNST(1.0), beta=CNST(0.0); /* Fool BLAS to compute a^T*a avoiding transposing a: a is equivalent to a^T in column major, * therefore BLAS computes a*a^T with a and a*a^T in column major, which is equivalent to * computing a^T*a in row major! */ GEMM("N", "T", &m, &m, &n, &alpha, a, &m, a, &m, &beta, b, &m);#else /* no LAPACK, use blocking-based multiply */register int i, j, k, jj, kk;register LM_REAL sum, *bim, *akm;const int bsize=__BLOCKSZ__;#define __MIN__(x, y) (((x)<=(y))? (x) : (y))#define __MAX__(x, y) (((x)>=(y))? (x) : (y)) /* compute upper triangular part using blocking */ for(jj=0; jj<m; jj+=bsize){ for(i=0; i<m; ++i){ bim=b+i*m; for(j=__MAX__(jj, i); j<__MIN__(jj+bsize, m); ++j) bim[j]=0.0; //b[i*m+j]=0.0; } for(kk=0; kk<n; kk+=bsize){ for(i=0; i<m; ++i){ bim=b+i*m; for(j=__MAX__(jj, i); j<__MIN__(jj+bsize, m); ++j){ sum=0.0; for(k=kk; k<__MIN__(kk+bsize, n); ++k){ akm=a+k*m; sum+=akm[i]*akm[j]; //a[k*m+i]*a[k*m+j]; } bim[j]+=sum; //b[i*m+j]+=sum; } } } } /* copy upper triangular part to the lower one */ for(i=0; i<m; ++i) for(j=0; j<i; ++j) b[i*m+j]=b[j*m+i];#undef __MIN__#undef __MAX__#endif /* HAVE_LAPACK */}/* forward finite difference approximation to the jacobian of func */void FDIF_FORW_JAC_APPROX( void (*func)(LM_REAL *p, LM_REAL *hx, int m, int n, void *adata), /* function to differentiate */ LM_REAL *p, /* I: current parameter estimate, mx1 */ LM_REAL *hx, /* I: func evaluated at p, i.e. hx=func(p), nx1 */ LM_REAL *hxx, /* W/O: work array for evaluating func(p+delta), nx1 */ LM_REAL delta, /* increment for computing the jacobian */ LM_REAL *jac, /* O: array for storing approximated jacobian, nxm */ int m, int n, void *adata){register int i, j;LM_REAL tmp;register LM_REAL d; for(j=0; j<m; ++j){ /* determine d=max(1E-04*|p[j]|, delta), see HZ */ d=CNST(1E-04)*p[j]; // force evaluation d=FABS(d); if(d<delta) d=delta; tmp=p[j]; p[j]+=d; (*func)(p, hxx, m, n, adata); p[j]=tmp; /* restore */ d=CNST(1.0)/d; /* invert so that divisions can be carried out faster as multiplications */ for(i=0; i<n; ++i){ jac[i*m+j]=(hxx[i]-hx[i])*d; } }}/* central finite difference approximation to the jacobian of func */void FDIF_CENT_JAC_APPROX( void (*func)(LM_REAL *p, LM_REAL *hx, int m, int n, void *adata), /* function to differentiate */ LM_REAL *p, /* I: current parameter estimate, mx1 */ LM_REAL *hxm, /* W/O: work array for evaluating func(p-delta), nx1 */ LM_REAL *hxp, /* W/O: work array for evaluating func(p+delta), nx1 */ LM_REAL delta, /* increment for computing the jacobian */ LM_REAL *jac, /* O: array for storing approximated jacobian, nxm */ int m, int n, void *adata){register int i, j;LM_REAL tmp;register LM_REAL d; for(j=0; j<m; ++j){ /* determine d=max(1E-04*|p[j]|, delta), see HZ */ d=CNST(1E-04)*p[j]; // force evaluation d=FABS(d); if(d<delta) d=delta; tmp=p[j]; p[j]-=d; (*func)(p, hxm, m, n, adata); p[j]=tmp+d; (*func)(p, hxp, m, n, adata); p[j]=tmp; /* restore */ d=CNST(0.5)/d; /* invert so that divisions can be carried out faster as multiplications */ for(i=0; i<n; ++i){ jac[i*m+j]=(hxp[i]-hxm[i])*d; } }}/* * Check the jacobian of a n-valued nonlinear function in m variables * evaluated at a point p, for consistency with the function itself. * * Based on fortran77 subroutine CHKDER by * Burton S. Garbow, Kenneth E. Hillstrom, Jorge J. More * Argonne National Laboratory. MINPACK project. March 1980. * * * func points to a function from R^m --> R^n: Given a p in R^m it yields hx in R^n * jacf points to a function implementing the jacobian of func, whose correctness * is to be tested. Given a p in R^m, jacf computes into the nxm matrix j the * jacobian of func at p. Note that row i of j corresponds to the gradient of * the i-th component of func, evaluated at p. * p is an input array of length m containing the point of evaluation. * m is the number of variables * n is the number of functions * adata points to possible additional data and is passed uninterpreted * to func, jacf. * err is an array of length n. On output, err contains measures * of correctness of the respective gradients. if there is * no severe loss of significance, then if err[i] is 1.0 the * i-th gradient is correct, while if err[i] is 0.0 the i-th * gradient is incorrect. For values of err between 0.0 and 1.0, * the categorization is less certain. In general, a value of * err[i] greater than 0.5 indicates that the i-th gradient is * probably correct, while a value of err[i] less than 0.5 * indicates that the i-th gradient is probably incorrect. * * * The function does not perform reliably if cancellation or * rounding errors cause a severe loss of significance in the * evaluation of a function. therefore, none of the components * of p should be unusually small (in particular, zero) or any * other value which may cause loss of significance. */void LEVMAR_CHKJAC( void (*func)(LM_REAL *p, LM_REAL *hx, int m, int n, void *adata), void (*jacf)(LM_REAL *p, LM_REAL *j, int m, int n, void *adata), LM_REAL *p, int m, int n, void *adata, LM_REAL *err){LM_REAL factor=CNST(100.0);LM_REAL one=CNST(1.0);LM_REAL zero=CNST(0.0);LM_REAL *fvec, *fjac, *pp, *fvecp, *buf;register int i, j;LM_REAL eps, epsf, temp, epsmch;LM_REAL epslog;int fvec_sz=n, fjac_sz=n*m, pp_sz=m, fvecp_sz=n; epsmch=LM_REAL_EPSILON; eps=(LM_REAL)sqrt(epsmch); buf=(LM_REAL *)malloc((fvec_sz + fjac_sz + pp_sz + fvecp_sz)*sizeof(LM_REAL)); if(!buf){ fprintf(stderr, LCAT(LEVMAR_CHKJAC, "(): memory allocation request failed\n")); exit(1); } fvec=buf; fjac=fvec+fvec_sz; pp=fjac+fjac_sz; fvecp=pp+pp_sz; /* compute fvec=func(p) */ (*func)(p, fvec, m, n, adata); /* compute the jacobian at p */ (*jacf)(p, fjac, m, n, adata); /* compute pp */ for(j=0; j<m; ++j){ temp=eps*FABS(p[j]); if(temp==zero) temp=eps; pp[j]=p[j]+temp; } /* compute fvecp=func(pp) */ (*func)(pp, fvecp, m, n, adata); epsf=factor*epsmch; epslog=(LM_REAL)log10(eps); for(i=0; i<n; ++i) err[i]=zero; for(j=0; j<m; ++j){ temp=FABS(p[j]); if(temp==zero) temp=one; for(i=0; i<n; ++i) err[i]+=temp*fjac[i*m+j]; } for(i=0; i<n; ++i){ temp=one; if(fvec[i]!=zero && fvecp[i]!=zero && FABS(fvecp[i]-fvec[i])>=epsf*FABS(fvec[i]))
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -