您的位置:首页 > 其它

Levenberg–Marquardt算法

2016-11-24 14:43 274 查看
算法描述及示例引用自“Machine Learning An Algorithm Perspective 2nd Edition”





使用C++进行浮点数的比较时,一定要注意容差问题。

#include <iostream>
#include <math.h>
#include <Eigen/Core>
#include <Eigen/Dense>
using namespace std;

double rx(const Eigen::MatrixXd &x,int i)
{
switch(i)
{
case 0: return 10*(x(1,0) - x(0,0) * x(0,0));
case 1: return 1-x(0,0);
}

return INT_MAX;
}

double fx(const Eigen::MatrixXd &x)
{
return 100 *(x(1,0) - x(0,0) * x(0,0)) * (x(1,0) - x(0,0) * x(0,0)) + (1-x(0,0)) * (1-x(0,0));
}

double Jac(const Eigen::MatrixXd &x,int i,int j)
{
int index = 2*i+j;
switch(index)
{
case 0: return -20 * x(0,0);
case 1: return 10.0;
case 2: return -1.0;
case 3: return 0.0;
}
}

void computeRelatedValues(const Eigen::MatrixXd& x,double &fval,Eigen::MatrixXd &r,Eigen::MatrixXd &J,Eigen::MatrixXd &grad)
{
fval = fx(x);

for (int i = 0;i<2;++i)
{
r(i,0) = rx(x,i);
}

for(int i = 0;i<2;++i)
for(int j = 0;j<2;++j)
{
J(i,j) = Jac(x,i,j);
}

grad = J.transpose() * r;
}
void LM()
{
Eigen::MatrixXd x(2,1);
x(0,0) = -1.92;
x(1,0) = 2.0;

int max_iter = 100;
double func_tol = pow(10.0,-5);

int iter = 0;

double fval = INT_MAX;
Eigen::MatrixXd r(2,1);
Eigen::MatrixXd J(2,2);
Eigen::MatrixXd grad;

computeRelatedValues(x,fval,r,J,grad);

double nu = 0.01;

cout<<fval<<" ["<<x(0,0)<<" "<<x(1,0)<<"] "<<grad.norm()<<" "<<nu<<endl;

while(iter < max_iter && grad.norm() > func_tol)
{
++iter;

computeRelatedValues(x,fval,r,J,grad);

Eigen::MatrixXd I = Eigen::MatrixXd::Identity(2,2);
Eigen::MatrixXd H = J.transpose() *J + nu*I;

Eigen::MatrixXd x_new = Eigen::MatrixXd::Zero(2,1);

int iter1 = 0;

double diff = (x-x_new).norm();
//注意如何比较两个向量是否相等
while(diff > pow(10.0,-5) && iter1 < max_iter)
{
++iter1;
Eigen::MatrixXd delta_x = H.colPivHouseholderQr().solve(grad);
cout<<delta_x<<endl;
Eigen::MatrixXd x_new = x - delta_x;
cout<<x_new<<endl;
double fval_new = INT_MAX;
Eigen::MatrixXd r_new(2,1);
Eigen::MatrixXd J_new(2,2);
Eigen::MatrixXd grad_new;
computeRelatedValues(x_new,fval_new,r_new,J_new,grad_new);

double rho = abs(fval - fval_new) / (grad.transpose() * (x_new - x)).norm();

if (rho > 0)
{
x = x_new;
diff = (x - x_new).norm();
cout<<diff<<endl;
if (rho > 0.25)
{
nu = nu /10;
}
}
else
{
nu = nu *10;
}

}

cout<<fval<<" ["<<x(0,0)<<" "<<x(1,0)<<"] "<<grad.norm()<<" "<<nu<<endl;

}

}
int main()
{
LM();

return 0;
}
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: