Gauss-Newton算法是一個(gè)古老的處理非線性最小二乘問題的方法。該方法在迭代過程中要求矩陣J(x)滿秩。為了克服這個(gè)困難,Levenberg(1944)提出了一種新的方法,但未受到重視。后來Marquardt(1963)又重新提出,并在理論上進(jìn)行了控討,得到Levenberg-Marquardt方法,簡稱LM方法。在此基礎(chǔ)上,F(xiàn)letcher(1971)對(duì)其實(shí)現(xiàn)策略進(jìn)行了改進(jìn),得到了Levenberg-Marquardt-Fletcher方法(LMF)。再后來,More(1978)將LM方法與信賴域方法結(jié)合,建立了帶信賴域的LM方法。
下載源碼levmar-2.6解壓,在其README.txt中對(duì)levmar的授權(quán)GPL、編譯等進(jìn)行了說明。在Windows操作系統(tǒng)中,可以使用nmake /f Makefile.vc來編譯levmar和一個(gè)示例程序。
從官網(wǎng)介紹可知,levmar有些算法依賴LAPACK庫,一個(gè)線性代數(shù)計(jì)算開源庫。所以如果要使用那些算法,編譯的時(shí)候必須包含這個(gè)庫。從示例程序的源文件lmdemo.c中可以看出,有些問題的求解是需要LAPACK庫的,相關(guān)源碼列出如下:
#ifdef LM_DBL_PREC
/* double precision LM, with & without Jacobian */
/* unconstrained minimization */
extern int dlevmar_der(
void (*func)(double *p, double *hx, int m, int n, void *adata),
void (*jacf)(double *p, double *j, int m, int n, void *adata),
double *p, double *x, int m, int n, int itmax, double *opts,
double *info, double *work, double *covar, void *adata);
extern int dlevmar_dif(
void (*func)(double *p, double *hx, int m, int n, void *adata),
double *p, double *x, int m, int n, int itmax, double *opts,
double *info, double *work, double *covar, void *adata);
/* box-constrained minimization */
extern int dlevmar_bc_der(
void (*func)(double *p, double *hx, int m, int n, void *adata),
void (*jacf)(double *p, double *j, int m, int n, void *adata),
double *p, double *x, int m, int n, double *lb, double *ub, double *dscl,
int itmax, double *opts, double *info, double *work, double *covar, void *adata);
extern int dlevmar_bc_dif(
void (*func)(double *p, double *hx, int m, int n, void *adata),
double *p, double *x, int m, int n, double *lb, double *ub, double *dscl,
int itmax, double *opts, double *info, double *work, double *covar, void *adata);
#ifdef HAVE_LAPACK
/* linear equation constrained minimization */
extern int dlevmar_lec_der(
void (*func)(double *p, double *hx, int m, int n, void *adata),
void (*jacf)(double *p, double *j, int m, int n, void *adata),
double *p, double *x, int m, int n, double *A, double *b, int k,
int itmax, double *opts, double *info, double *work, double *covar, void *adata);
extern int dlevmar_lec_dif(
void (*func)(double *p, double *hx, int m, int n, void *adata),
double *p, double *x, int m, int n, double *A, double *b, int k,
int itmax, double *opts, double *info, double *work, double *covar, void *adata);
/* box & linear equation constrained minimization */
extern int dlevmar_blec_der(
void (*func)(double *p, double *hx, int m, int n, void *adata),
void (*jacf)(double *p, double *j, int m, int n, void *adata),
double *p, double *x, int m, int n, double *lb, double *ub, double *A, double *b, int k, double *wghts,
int itmax, double *opts, double *info, double *work, double *covar, void *adata);
extern int dlevmar_blec_dif(
void (*func)(double *p, double *hx, int m, int n, void *adata),
double *p, double *x, int m, int n, double *lb, double *ub, double *A, double *b, int k, double *wghts,
int itmax, double *opts, double *info, double *work, double *covar, void *adata);
/* box, linear equations & inequalities constrained minimization */
extern int dlevmar_bleic_der(
void (*func)(double *p, double *hx, int m, int n, void *adata),
void (*jacf)(double *p, double *j, int m, int n, void *adata),
double *p, double *x, int m, int n, double *lb, double *ub,
double *A, double *b, int k1, double *C, double *d, int k2,
int itmax, double *opts, double *info, double *work, double *covar, void *adata);
extern int dlevmar_bleic_dif(
void (*func)(double *p, double *hx, int m, int n, void *adata),
double *p, double *x, int m, int n, double *lb, double *ub,
double *A, double *b, int k1, double *C, double *d, int k2,
int itmax, double *opts, double *info, double *work, double *covar, void *adata);
/* box & linear inequality constraints */
extern int dlevmar_blic_der(
void (*func)(double *p, double *hx, int m, int n, void *adata),
void (*jacf)(double *p, double *j, int m, int n, void *adata),
double *p, double *x, int m, int n, double *lb, double *ub, double *C, double *d, int k2,
int itmax, double opts[4], double info[LM_INFO_SZ], double *work, double *covar, void *adata);
extern int dlevmar_blic_dif(
void (*func)(double *p, double *hx, int m, int n, void *adata),
double *p, double *x, int m, int n, double *lb, double *ub, double *C, double *d, int k2,
int itmax, double opts[5], double info[LM_INFO_SZ], double *work, double *covar, void *adata);
/* linear equation & inequality constraints */
extern int dlevmar_leic_der(
void (*func)(double *p, double *hx, int m, int n, void *adata),
void (*jacf)(double *p, double *j, int m, int n, void *adata),
double *p, double *x, int m, int n, double *A, double *b, int k1, double *C, double *d, int k2,
int itmax, double opts[4], double info[LM_INFO_SZ], double *work, double *covar, void *adata);
extern int dlevmar_leic_dif(
void (*func)(double *p, double *hx, int m, int n, void *adata),
double *p, double *x, int m, int n, double *A, double *b, int k1, double *C, double *d, int k2,
int itmax, double opts[5], double info[LM_INFO_SZ], double *work, double *covar, void *adata);
/* linear inequality constraints */
extern int dlevmar_lic_der(
void (*func)(double *p, double *hx, int m, int n, void *adata),
void (*jacf)(double *p, double *j, int m, int n, void *adata),
double *p, double *x, int m, int n, double *C, double *d, int k2,
int itmax, double opts[4], double info[LM_INFO_SZ], double *work, double *covar, void *adata);
extern int dlevmar_lic_dif(
void (*func)(double *p, double *hx, int m, int n, void *adata),
double *p, double *x, int m, int n, double *C, double *d, int k2,
int itmax, double opts[5], double info[LM_INFO_SZ], double *work, double *covar, void *adata);
#endif /* HAVE_LAPACK */
#endif /* LM_DBL_PREC */
從頭文件levmar.h中的代碼可以看出,在#ifdef HAVE_LAPACK和#endif /* HAVE_LAPACK */之間的函數(shù)都是不可用的。除此之外的函數(shù)是可用的,如基本的dlevmar_der和dlevmar_dif等函數(shù)是不依賴LAPACK庫的。如果只使用這幾個(gè)函數(shù),則可以不用配置LAPACK庫,編譯levmar就很簡單了。
這時(shí)就可以啟動(dòng)Visual Studio的編譯器CL來編譯levmar庫了。配置好編譯環(huán)境的命令工具從Visual Studio的菜單來啟動(dòng):
要編譯32位的levmar庫,可以使用x86的命令工具,要編譯64位的levmar,可以使用x64的命令工具。啟動(dòng)命令工具后,切換到levmar源碼文件夾,并輸入命令
接著在命令窗口中運(yùn)行l(wèi)mdemo.exe,測試levmar例子程序。如果lmdemo正常運(yùn)行,說明levmar已經(jīng)成功編譯。