Levenberg–Marquardt算法

算法描述及示例引用自“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;
}
  • 2
    点赞
  • 7
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值