高斯牛顿迭代法的原理及实现(经典例子,附C和C++代码,含运行结果)

可帮助理解的一些文章:

梯度,雅克比矩阵和海森矩阵

海森矩阵和牛顿法

如何通俗易懂地讲解牛顿迭代法?

最优化方法:牛顿迭代法和拟牛顿迭代法

经典举例:

#include <stdio.h>
#include <math.h>
#include <stdlib.h>

#define MAXN 7
typedef struct {							//n*m矩阵
	int m,n;
	double data[MAXN][MAXN];
}mat;

mat CreateMatrix(int p,int q);
double arry2matrix(mat *a,mat *b,mat *r,double *x,double *y,double *beta,int m,int n);
mat trans(mat a);
mat mul(mat a,mat b);
double *SolveMatrix(mat c,mat d);
void arryans(double *beta,mat c,mat d);

int main(){
	double x[]={0.038, 0.194, 0.425, 0.626, 1.253, 2.500, 3.740};
	double y[]={0.050, 0.127, 0.094, 0.2122, 0.2729, 0.2665, 0.3317};
	mat r = {0,0,0};
	mat a = {0,0,0};
	mat b = {0,0,0};
	mat c = {0,0,0};
	mat d = {0,0,0};
	double beta[2] = {0.9,0.2};
	double rss = 0;
	int T;

	for(T=0;T<10;++T){
		rss = arry2matrix(&a,&b,&r,x,y,beta,7,2);
		printf("%d %f %f %f\n",T,beta[0],beta[1],rss);
		c = mul(b,a);
		d = mul(b,r);
		arryans(beta,c,d);
	}
	system("pause");
}


// Input x[],y[],m,n
// Output a,b,r[]
double arry2matrix(mat *a,mat *b,mat *r,double *x,double *y,double *beta,int m,int n){
	int i;
	double rss = 0;
	(*a).m = m;		// 雅克比矩阵a
	(*a).n = n;
	(*b).m = n;		// a的转置矩阵b
	(*b).n = m;
	(*r).m = m;
	(*r).n = 1;
	
	for(i=0;i<m;++i){
		(*a).data[i][0] = -x[i]/(beta[1]+x[i]);
		(*a).data[i][1] = beta[0]*x[i]/(beta[1]+x[i])/(beta[1]+x[i]);
		(*b).data[0][i] = (*a).data[i][0];
		(*b).data[1][i] = (*a).data[i][1];
		(*r).data[i][0] = y[i]-beta[0]*x[i]/(beta[1]+x[i]);
		rss += (*r).data[i][0]*(*r).data[i][0];  
	}
	return rss;
}

/********************************************************************
*Fuction: 
*Input:  a,b
*Output:  c
********************************************************************/
mat mul(mat a,mat b){
	int i,j,k;
	mat c = {0,0,0};
	c.m = a.m;
	c.n = b.n;
	for(i=0;i<c.m;++i){
		for(j=0;j<c.n;++j){
			c.data[i][j] = 0;
			for(k=0;k<a.n;k++){
				c.data[i][j] += a.data[i][k]*b.data[k][j];
			}
		}
	}
	return c;
}

/********************************************************************
*Fuction: 
*Input:  c,d,beta
*Output:  new_beta
********************************************************************/
void arryans(double *beta,mat c,mat d){					//解一个n阶的线性方程组
    int i, j, k, mi;
    double mx, tmp;
	double beta_tmp[2];
	beta_tmp[0] = beta[0];
	beta_tmp[1] = beta[1];
    for (i = 0; i < c.m-1; i++) {
		mi = i;
		mx = fabs(c.data[i][i]);
        for (j = i + 1; j < c.m; j++)			//找主元素
            if (fabs(c.data[j][i]) > mx) {
                mi = j;							//记录矩阵下三角一列中绝对值最大值的行号 
                mx = fabs(c.data[j][i]);		//记录矩阵下三角一列中绝对值最大值 
            }
        if (i < mi) {							//交换两行
            tmp = d.data[i][0];
            d.data[i][0] = d.data[mi][0];
            d.data[mi][0] = tmp;
            for (j = i; j < c.m; j++) {
                tmp = c.data[i][j];
                c.data[i][j] = c.data[mi][j];
                c.data[mi][j] = tmp;
            }
        }
		//---高斯消元---//
        for (j = i + 1; j < c.m; j++) {				//第i行,第i+1、i+2、…、n-1、n列
            tmp = -c.data[j][i] / c.data[i][i];		//第j行除以第i行
            d.data[j][0] += d.data[i][0] * tmp;
            for (k = i; k < c.m; k++)				//将第i行的tmp倍加到第j行
                c.data[j][k] += c.data[i][k] * tmp;		
        }
    }
    beta[c.m - 1] = d.data[c.m - 1][0] / c.data[c.m - 1][c.m - 1];		//求解方程
    for (i = c.m - 2; i >= 0; i--) {
        beta[i] = d.data[i][0];
        for (j = i + 1; j < c.m; j++)
            beta[i] -= c.data[i][j] * beta[j];
        beta[i] /= c.data[i][i];
    }
	beta[0] = beta_tmp[0]-beta[0];			
	beta[1] = beta_tmp[1]-beta[1];
}


#include <cstdio>
#include <cstring>
#include <cmath>
#include <iostream>
using namespace std;

int n;
double x[10],y[10],beta[10];

struct matrix{
	double a[10][10],tmp[10][10];
	int n,m;
	void clear(){							// 清零
		memset(a,0,sizeof(a));
		memset(tmp,0,sizeof(tmp));
	} 
	void cpy(matrix &b){					// 复制矩阵
		n=b.n;
		m=b.m;
		for (int i=1;i<=n;i++)    
			for (int j=1;j<=m;j++)
				a[i][j]=b.a[i][j];
	}

	void mul(matrix &b){
		for (int i=0;i<=n;i++) 
			for (int j=0;j<=b.m;j++) 
				tmp[i][j]=0;

		for (int i=0;i<=n;i++)
			for (int k=0;k<=m;k++)
				if (a[i][k]){
					for (int j=0;j<=b.m;j++)
						tmp[i][j]+=a[i][k]*b.a[k][j];
					a[i][k]=0;
				}

				for (int i=0;i<=n;i++)
					for (int j=0;j<=b.m;j++)
						a[i][j]=tmp[i][j];
				m=b.m;
	}

	void getinv(){
		for (int i=1;i<=n;i++) for (int j=1;j<=n;j++) a[i][n+j]=0;
		for (int i=1;i<=n;i++) a[i][n+i]=1;
		for (int i=1;i<=n;i++){
			int po;double maxi=0;
			for (int j=i;j<=n;j++){
				if (fabs(a[j][i])>maxi){
					maxi=fabs(a[j][i]);po=j;
				}
			}
			for (int j=1;j<=2*n;j++){
				double t=a[i][j];a[i][j]=a[po][j];a[po][j]=t;
			}
			if (fabs(maxi)==0) continue;

			for (int j=i+1;j<=n;j++){
				double tim=a[j][i]/a[i][i];
				for (int k=i;k<=2*n;k++) a[j][k]-=a[i][k]*tim;
			}
		}

		for (int i=n;i>=1;i--){
			for (int j=i+1;j<=n;j++){
				for (int k=n+1;k<=2*n;k++)
					a[i][k]-=a[i][j]*a[j][k];
				a[i][j]=0;          
			}
			for (int j=n+1;j<=2*n;j++)
				a[i][j]/=a[i][i];
			a[i][i]=1;  
		}

		for (int i=1;i<=n;i++)
			for (int j=1;j<=n;j++)
				a[i][j]=a[i][j+n];
		for (int i=1;i<=n;i++) for (int j=1;j<=n;j++) a[i][j+n]=0;
	}

	void trav(){
		for (int i=1;i<=m;i++)
			for (int j=1;j<=n;j++)
				tmp[i][j]=a[j][i],a[j][i]=0;
		for (int i=1;i<=m;i++)
			for (int j=1;j<=n;j++)
				a[i][j]=tmp[i][j];
		swap(n,m);
	}
}a,b,c,d;

int main(){      
	n = 7;
	double x[]={0,0.038, 0.194, 0.425, 0.626, 1.253, 2.500, 3.740};
	double y[]={0,0.050, 0.127, 0.094, 0.2122, 0.2729, 0.2665, 0.3317};
	double r = 0;
	double rss = 0;
	beta[1]=0.9;beta[2]=0.2;

	for (int i=1;i<=n;i++){
		r = y[i]-beta[1]*x[i]/(beta[2]+x[i]);
		rss += r*r;
	}
	printf("0 %f %f %f\n",beta[1],beta[2],rss);

	for (int T=1;T<=9;T++){

		a.clear();b.clear();c.clear();d.clear();    
		a.n=n;a.m=2;
		for (int i=1;i<=n;i++){
			a.a[i][1]=-x[i]/(beta[2]+x[i]);
			a.a[i][2]=beta[1]*x[i]/(beta[2]+x[i])/(beta[2]+x[i]);
		}
		b.cpy(a);c.cpy(a);
		// 残差矩阵
		d.n=n;d.m=1;
		for (int i=1;i<=n;i++){
			d.a[i][1]=y[i]-beta[1]*x[i]/(beta[2]+x[i]);
		}
		a.trav();			// a转置
		a.mul(b);			// 
		a.getinv();
		c.trav();			// 
		a.mul(c);
		a.mul(d);			//
		beta[1]=beta[1]-a.a[1][1];beta[2]=beta[2]-a.a[2][1];

		double rss=0;
		for (int i=1;i<=n;i++)
			rss+=(y[i]-beta[1]*x[i]/(beta[2]+x[i]))*(y[i]-beta[1]*x[i]/(beta[2]+x[i]));
		printf("%d %f %f %f\n",T,beta[1],beta[2],rss);
	}
	system("pause");
}

运行结果与C语言运行结果一致。

可参考博客:

高斯-牛顿迭代

详解高斯牛顿迭代法原理和代码

 

 

 

 

 

 

 

### 高斯牛顿迭代 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]。 ---
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值