高斯牛顿法(C++实现)

#include <iostream>
#include <cmath>
#include <Eigen/Eigen>

using namespace Eigen;

#define ITER_STEP   (1e-5)
#define ITER_CNT    (100)

typedef void (*func_ptr)(const VectorXd &input, const VectorXd ¶ms, VectorXd &output);

void people_func(const VectorXd &input, const VectorXd ¶ms, VectorXd &output)
{
    double A = params(0, 0);
    double B = params(1, 0);

    for (int i = 0; i < input.rows(); i++) {
        output(i, 0) = A * exp(input(i, 0) * B);
    }
}

void get_jacobian(func_ptr func,
        const VectorXd &input,
        const VectorXd ¶ms,
        MatrixXd &output
        )
{
    int m = input.rows();
    int n = params.rows();

    VectorXd out0(m, 1);
    VectorXd out1(m, 1);
    VectorXd param0(n, 1); 
    VectorXd param1(n, 1); 

    //output.resize(m, n);

    for (int j = 0; j < n; j++) {
        param0 = params;
        param1 = params;
        param0(j, 0) -= ITER_STEP;
        param1(j, 0) += ITER_STEP;
        func(input, param0, out0);
        func(input, param1, out1);
        output.block(0, j, m, 1) = (out1 - out0) / (2 * ITER_STEP);
    }
}

void gauss_newton(func_ptr func,
        const VectorXd &inputs,
        const VectorXd &output,
        VectorXd ¶ms
        )
{
    int m = inputs.rows();
    int n = params.rows();

    // jacobian 
    MatrixXd jmat(m, n);
    VectorXd r(m, 1);
    VectorXd tmp(m, 1);

    double pre_mse = 0.0;
    double mse;

    for (int i = 0; i < ITER_CNT; i++) {
        mse = 0.0;
        func(inputs, params, tmp);
        r = output - tmp;
        get_jacobian(func, inputs, params, jmat);
        mse = r.transpose() * r;
        mse /= m;
        if (fabs(mse - pre_mse) < 1e-8) {
            break;
        }
        pre_mse = mse;
        VectorXd delta = (jmat.transpose() * jmat).inverse() * jmat.transpose() * r;
        printf ("i = %d, mse %lf.\n", i, mse);
        params += delta;
    }

    std::cout << "params:" << params.transpose() << std::endl;
}


int people_fit()
{
    // A * exp(B * x)
    VectorXd inputs(8, 1);
    inputs << 1, 2, 3, 4, 5, 6, 7, 8;
    VectorXd output(8, 1);
    output << 8.3, 11.0, 14.7, 19.7, 26.7, 35.2, 44.4, 55.9;

    VectorXd params(2, 1);
    params << 8, 0.7;
    gauss_newton(people_func, inputs, output, params);
    return 0;
}

void tri_func(const VectorXd &input, const VectorXd ¶ms, VectorXd &output)
{
    double A = params(0, 0);
    double B = params(1, 0);
    double C = params(2, 0);
    double D = params(3, 0);

    for (int i = 0; i < input.rows(); i++) {
        output(i, 0) = A*sin(B*input(i, 0)) + C*cos(D*input(i, 0));
    }
}

int tri_func_fit()
{
    // A * sin(Bx) + C * cos(Dx)
    double A = 5;
    double B = 1;
    double C = 10;
    double D = 2;

    const int smp_cnt = 100;
    VectorXd input(smp_cnt, 1);
    VectorXd output(smp_cnt, 1);
    VectorXd params(4, 1);

    params << 1, 1, 9, 1;

    for (int i = 0; i < smp_cnt; i++) {
        input(i, 0) = i;
        output(i, 0) = A*sin(B*input(i, 0))+C*cos(D*input(i, 0)) + (rand() % 255) / 255.0;
    }
    gauss_newton(tri_func, input, output, params);
    return 0;
}

int main()
{
    people_fit();
    //tri_func_fit();
}


### 高斯牛顿迭代 C++ 实现 以下是基于高斯牛顿迭代C++ 示例代码实现,用于解决非线性最小二乘问题。此方通过不断更新参数估计值来逼近最优解。 #### 示例代码 ```cpp #include <iostream> #include <cmath> #include <vector> using namespace std; // 定义残差函数及其雅可比矩阵计算 double residual(double x, double a, double b) { return exp(a * x + b) - (a * x + b); // 假设的目标函数形式 } void jacobian(vector<double>& J, double x, double a, double b) { J[0] = x * exp(a * x + b) - x; J[1] = exp(a * x + b) - 1; } int main() { const int max_iter = 100; // 最大迭代次数 const double tol = 1e-6; // 收敛精度 vector<double> data_x = {0.0, 0.5, 1.0}; // 输入数据点 vector<double> params(2, 0.0); // 初始参数猜测 [a, b] for (int iter = 0; iter < max_iter; ++iter) { vector<vector<double>> J(data_x.size(), vector<double>(params.size())); vector<double> r(data_x.size()), delta_params(params.size()); // 构建雅可比矩阵和残差向量 for (size_t i = 0; i < data_x.size(); ++i) { r[i] = residual(data_x[i], params[0], params[1]); jacobian(J[i], data_x[i], params[0], params[1]); } // 解正规方程 JTJΔp = -JT*r vector<vector<double>> JTJ(params.size(), vector<double>(params.size(), 0)); vector<double> JTr(params.size(), 0); for (size_t p = 0; p < params.size(); ++p) { for (size_t q = 0; q <= p; ++q) { for (size_t i = 0; i < data_x.size(); ++i) { JTJ[p][q] += J[i][p] * J[i][q]; } JTJ[q][p] = JTJ[p][q]; // 对称性质 } for (size_t i = 0; i < data_x.size(); ++i) { JTr[p] -= J[i][p] * r[i]; } } // 使用高斯消元或其他数值方求解 Δp for (size_t k = 0; k < params.size(); ++k) { for (size_t i = k + 1; i < params.size(); ++i) { double factor = JTJ[i][k] / JTJ[k][k]; for (size_t j = k; j < params.size(); ++j) { JTJ[i][j] -= factor * JTJ[k][j]; } JTr[i] -= factor * JTr[k]; } } for (int i = static_cast<int>(params.size()) - 1; i >= 0; --i) { delta_params[i] = JTr[i]; for (size_t j = i + 1; j < params.size(); ++j) { delta_params[i] -= JTJ[i][j] * delta_params[j]; } delta_params[i] /= JTJ[i][i]; } bool converged = true; for (size_t i = 0; i < params.size(); ++i) { params[i] += delta_params[i]; if (fabs(delta_params[i]) > tol) { converged = false; } } cout << "Iteration " << iter + 1 << ": "; for (auto param : params) { cout << param << " "; } cout << endl; if (converged) break; } cout << "Final parameters: "; for (auto param : params) { cout << param << " "; } cout << endl; return 0; } ``` 上述代码实现高斯牛顿算的核心逻辑[^3],包括构建雅可比矩阵、计算残差以及通过正规方程求解参数增量的过程。 --- ### 相关理论说明 高斯牛顿法是一种优化技术,适用于非线性最小二乘问题。其基本思想是利用泰勒展开近似目标函数,并通过迭代逐步改进参数估计值。每次迭代过程中,需要计算当前点处的雅可比矩阵并求解正规方程 \( \mathbf{J}^\top\mathbf{J}\Delta\mathbf{p} = -\mathbf{J}^\top\mathbf{r} \)[^1]。 ---
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值