L—M算法 C++源代码

// Term.cpp : 定义控制台应用程序的入口点。
//
#include "stdafx.h"
#include <cmath>
#include <iostream>
using namespace std;

double GetF(double *p,int N)
{
 if(N!=5)
 {
 return 0.0;
 }
 double A = p[0];
 double B = p[1];
 double C = p[2];
 double D = p[3];
 double X = p[4];
 return A-(A-B)/(pow((C/X),D) + 1);
}

int GetA(double *p,int N,double *out)
{
 if(N!=5)
 {
  *out = 0;
  return 1;
 }

 double A = p[0];
 double B = p[1];
 double C = p[2];
 double D = p[3];
 double X = p[4];

 out[0] = pow(C/X,D)/(pow(C/X,D)+1);
 out[1] = 1/pow(C/X,D);
 out[2] = D*(A-B)*pow(C/X,D)/(C*pow(pow(C/X,D)+1,2));
 out[3] = log(C/X)*(A-B)*pow(C/X,D)/pow(pow(C/X,D)+1,2);
 out[4] = 0;

 return 0;
}

//解法方程A*X = B
int Solve_Equation(double *A,double *B,int size,int row,double *X)
{
 int i,j;int T = 0;
 double Large = -1e10;
 int s_index = 0;
 double Temp = 0.0;
 for (i = 0;i<row;i++)
 {
  Large = -1e10;
  for (j = i;j<size;j++)
  {
   if(A[j*row+i]>Large)
   {
    Large = A[j*row+i];
    s_index = j;
   }
  }  
  //如果最大列主元不在子块的第一行,那么进行交换
  if(i!=s_index)
  {
   for (int m = 0;m<row;m++)
   {
    Temp = A[i*size+m];
    A[i*row+m] = A[s_index*size+m];
    A[s_index*size+m] = Temp;
   }
   Temp = B[i];
   B[i] = B[s_index];
   B[s_index] = Temp;
  }
  //进行消元
  double M = 1.0;
  for (j = i+1;j<size;j++)
  {
   M = A[j*row+i]/A[i*row+i];
   for (int k = i;k<size;k++)
   {
    A[j*size+k] = A[j*row+k]-M*A[i*row+k];
   }
   B[j] = B[j]-M*B[i];
  }
 }
 //计算方程组的系数的
 for (i = 0;i<size;i++)
 {
  int Flag = 1;
  for (j = i;j<row && Flag;j++)
  {
   if(B[i]!=0 && A[i*row+j] ==0)
   {
    T = -1;
    break;
   }
   if(A[i*row+j]!=0)
   {
    T++;
    Flag = 0;
   }
  }
 }
 //求取方程组的解
 if(T == row)
 {
  X[size-1] = B[size-1]/A[(size-1)*row+(size-1)];
  for (int m = size-2;m>=0;m--)
  {
   Temp = B[m]-X[m+1]*A[m*row+m+1];
   for (int n = m+2;n<size;n++)
   {
    Temp = Temp-X[n]*A[m*row+n];
   }
   X[m] = Temp/A[m*row+m];
  }
  return 0;
 }
 else
  return 1;
}

//计算Q+U的值     
void ADD_M(double *D_Q,double U_K,double *D_d,int L)
{
 for (int i =0;i<L;i++)
 {
  for (int j = 0;j<L;j++)
  {
   if(i == j)   *(D_d+i*L+j) = *(D_Q+i*L+j)+U_K;
   else         *(D_d+i*L+j) = *(D_Q+i*L+j);
  }
 }
}


//G矩阵取反
//I_G矩阵为G矩阵取反以后的矩阵
void Invert_G(double G[],double I_G[],int l)
{
 for (int i = 0;i<l;i++)
  I_G[i] = -G[i];
}

//H—收敛准则
bool X_Compare(double *FK_1,double *FK,double E,double k)
{
 double s = 0;
 for (int i = 0;i<k;i++)
 {
  s+=pow(FK_1[i]-FK[i],2);
 }

 if(sqrt(s)<E)   return true;
 else            return false;
}

//保存上一次的X值
void X_Save(double *Des,double *Source,double n)
{
 for (int i = 0;i<n;i++)
 {
  Des[i] = Source[i];
 }
}

typedef double (*Tpf)(double *,int);
typedef int (*TpA)(double *,int ,double *);


void ColMutRow(double *l,int M,double *r,int N,double *out)
{

 for(int i =0 ; i < M  ; ++i)
 {
  for( int j = 0 ; j< N; ++j)
  {
   *(out + i*N + j) = l[i] * r[j];
  }
 }
}

void RowMutCol(double *l,double *r,int N,double *out)
{
 *out = 0;
 for(int i =0 ; i < N  ; ++i)
 {
  for( int j = 0 ; j< N; ++j)
  {
   *(out) += l[i] * r[j];
  }
 }
}


void VecMutNum(double *l,double r,int N,double *out)
{
 for(int i =0 ; i < N  ; ++i)
 {
  *(out + i ) = l[i] * r;
 }
}

void VecAddVec(double *l,double *r,int N,double *out)
{
 for(int i =0 ; i < N  ; ++i)
 {
  *(out + i ) = l[i] + r[i];
 }
}


void VecAssignment(double *dsc,double *src,int n)
{
 memcpy(dsc,src,n*sizeof(double)); //x = x0 ;
}

//getf-目标函数
//getA-目标函数的雅克布矩阵
//beta0,u0,v0 迭代参数
//x0 初始值
//N x0的维数
//e 迭代精度
//KMAX 最大迭代次数
int LMA(Tpf getf,TpA getA,double beta0,double u0,double v0,double *x0,int N,double e ,int KMax , double * out,double * Sout )
{
 double *x = new double[N];
 double f  = 0.0 ;
 double S  = 0.0;
 double *A = new double[N];
 double *Q = new double[N*N];
 double *Q_I = new double[N*N];
 double *G = new double[N];
 double *P = new double[N];
 double *I_G = new double[N];
 double fk_1 = 0.0;
 double Sk_1 = 0.0;
 int KMAX = KMax;
 int k;

 //第一步:初始参数
 double beta = beta0;
 double u = u0;
 double v = v0;

 //第二步:给定初始点X0,置K=0
 VecAssignment(x,x0,N); // X = X0
 k = 0;

 //零时变量
 double gp,s_bgp;
 bool Finished  = false;
 double *xk_1 = new double[N];

 //迭代开始
 do
 {

  //第三步:计算F,S
  f = getf(x,N); //fk=f(xk)
  S= f * f;
  //ColMutRow(f,1,f,1,S); //Sk=f*f

  //第四步:计算A,Q
  getA(x,N,A);
  ColMutRow(A,N,A,N,Q);

  //第五步:计算G
  ColMutRow(A,N,&f,1,G);

  do
  {
   //第六步:解法方程
   ADD_M(Q,u,Q_I,N);
   Invert_G(G,I_G,N);
   Solve_Equation(Q_I,I_G,N,N,P);

   //第七步:计算XK_1
   VecAddVec(x,P,N,xk_1);  //xk+1 = x + P;
   fk_1 = getf(xk_1,N);  //fk=f(xk)
   Sk_1= fk_1 *fk_1;

   //第八步:H—收敛准则
   Finished = X_Compare(&fk_1,&f,e,1);
   if(Finished)
   {
    VecAssignment(out,xk_1,N); //x = xk+1;
    *Sout = S;
    break;
   }

   //第九步:检验S
   RowMutCol(G,P,N,&gp);
   s_bgp = S + beta * gp ;
   if(Sk_1 < s_bgp)
   {
    u = u/v;
    break;
   }
   else
   {
    u = v*u;
   }

  }while(true);
  //第十步:置K=K+1
  k = k + 1; 
  VecAssignment(x,xk_1,N); //xk = xk+1;
 }while( k<KMAX && !Finished );

 VecAssignment(out,xk_1,N); //x = xk+1;
 *Sout = S;

 delete []G;
 delete []I_G;
 delete []P;
 delete []Q;
 delete []Q_I;
 delete []A;
 delete []x;
 return 1;
}

int _tmain(int argc, _TCHAR* argv[])
{
 double u0,v0,e,Beta;
 int N,Max;
/*
 cout<<"请输入初始u0的值:";
 cin>>u0;
 cout<<endl;
 cout<<"请输入初始v0的值:";
 cin>>v0;
 cout<<endl;
 //cout<<"请输入初始N的值:";
 //cin>>N;
 //cout<<endl;
 cout<<"请输入初始e的值:";
 cin>>e;
 cout<<endl;
 cout<<"请输入最大循环次数:";
 cin>>Max;
 cout<<endl;
 cout<<"请输入初始Beta的值:";
 cin>>Beta;
 cout<<endl;
 for (int i = 0;i<N;i++)
 {
  cout<<"请输入X【"<<i<<"】的初始值:";
  cin>>I_X[i];
  cout<<endl;
 }
*/
 N = 5;

 double *I_X = new double[N];
 double *Xout =  new double [N];

 u0 = 0.3;
 Beta = 0.5;
 v0 = 2;
 I_X[0] = 2.3;
 I_X[1] = 4.4;
 I_X[2] = 3.7;
 I_X[3] = 1.6;
 I_X[4] = 5.1;

 e= 0.0000001;
 Max = 100;
 double sout;

 cout <<GetF(I_X,N) << endl;
 LMA(GetF,GetA,Beta,u0,v0,I_X,N,e ,Max, Xout,&sout);
 for (int i = 0;i<N;i++)
 {
    cout << Xout[i] << "      ";
 }
 cout<<sout<<endl;
 cout <<GetF(Xout,N) << endl;

 delete []Xout;
 delete []I_X;

 system("pause");
 return 0;
}

 

  • 0
    点赞
  • 2
    收藏
    觉得还不错? 一键收藏
  • 1
    评论
LM算法,全称为Levenberg-Marquard算法,它可用于解决非线性最小二乘问题,多用于曲线拟合等场合。 LM算法的实现并不算难,它的关键是用模型函数 f 对待估参数向量 p 在其邻域内做线性近似,忽略掉二阶以上的导数项,从而转化为线性最小二乘问题,它具有收敛速度快等优点。LM算法属于一种“信赖域法”——所谓的信赖域法,此处稍微解释一下:在最优化算法中,都是要求一个函数的极小值,每一步迭代中,都要求目标函数值是下降的,而信赖域法,顾名思义,就是从初始点开始,先假设一个可以信赖的最大位移 s ,然后在以当前点为中心,以 s 为半径的区域内,通过寻找目标函数的一个近似函数(二次的)的最优点,来求解得到真正的位移。在得到了位移之后,再计算目标函数值,如果其使目标函数值的下降满足了一定条件,那么就说明这个位移是可靠的,则继续按此规则迭代计算下去;如果其不能使目标函数值的下降满足一定的条件,则应减小信赖域的范围,再重新求解。 事实上,你从所有可以找到的资料里看到的LM算法的说明,都可以找到类似于“如果目标函数值增大,则调整某系数再继续求解;如果目标函数值减小,则调整某系数再继续求解”的迭代过程,这种过程与上面所说的信赖域法是非常相似的,所以说LM算法是一种信赖域法。
### 回答1: Delaunay三角剖分算法是一个将给定点集进行连边分割成不相交三角形的算法,其分割结果是基于三角形的最小内角,以此来保证分割结果的质量。在计算机图形学、离散数学和计算机视觉等领域中,Delaunay三角剖分算法都有广泛的应用。 C语言是一种常用的编程语言,在许多计算领域中都有着重要的应用。为了实现Delaunay三角剖分算法,我们可以使用C语言编写相关的源代码。该算法代码可分为以下几个步骤: 1. 首先确定点集的边界,以确定整个区域的边界。我们可以使用任意一个叶子点作为三角网格的起点。 2. 将所有的点按照x坐标排序,以方便后续计算。 3. 选取一个凸包三角形,它应该包含所有的点。根据这个凸包三角形来初始化我们的三角形列表。 4. 顺次遍历点集中的每一个点,判断其是否属于当前三角形网格中的某个三角形。如果不属于,则根据Delaunay的定义找到该点能加入的新三角形,以及需要翻转的旧三角形。 5. 将每个新的三角形加入三角形网格中,并将旧的三角形从网格中删去。 6. 重复以上步骤,直到所有点都被处理完毕。 7. 由于边缘的三角形可能不属于需要的结果,因此需要将这些边缘的三角形删除,从而得到最终的Delaunay三角剖分结果。 总的来说,实现Delaunay三角剖分算法需要进行多次计算和遍历,涉及到数据结构、算法设计等方面。在C语言中,我们可以使用数组、堆栈等数据结构来支持算法的实现。最终代码的实现需要根据具体的应用需求而定,可以根据相关的算法描述和设计思路来进行编写和调试。 ### 回答2: Delaunay三角剖分算法是一种广泛应用于计算机图形学和计算几何领域的算法。其主要作用是将一个点集按照一定的规则进行三角剖分,得到无重叠的三角形组合。这些三角形通常用于计算复杂的几何形状线段、点和区域之间的关系。 C语言是一种广泛应用于计算机程序设计和开发的高级编程语言。在Delaunay三角剖分算法的实现过程中,C语言是一种传统的编程语言选择。下面给出一个简单的Delaunay三角剖分算法C语言的实现,以供参考。 首先,我们需要定义一个包含点坐标值的结构体: typedef struct { double x; double y; } Point; 接着,我们需要定义一个包含边线信息的结构体: typedef struct { Point p1; Point p2; } Line; 定义一个检查是否为Delaunay三角形的函数: int isDelaunay(Point p1, Point p2, Point p3, Point test) { double edge1 = (p1.x - p2.x) * (test.y - p2.y) - (p1.y - p2.y) * (test.x - p2.x); double edge2 = (p2.x - p3.x) * (test.y - p3.y) - (p2.y - p3.y) * (test.x - p3.x); double edge3 = (p3.x - p1.x) * (test.y - p1.y) - (p3.y - p1.y) * (test.x - p1.x); if (edge1 > 0 && edge2 > 0 && edge3 > 0) { return 1; } else if (edge1 < 0 && edge2 < 0 && edge3 < 0) { return 1; } else { return 0; } } 定义一个进行三角剖分的函数: void DelaunayTriangulation(Point *points, int numPoints) { Line *lines = malloc(3 * (numPoints - 2) * sizeof(Line)); int numLines = 0; int i, j, k; for (i = 0; i < numPoints - 2; i++) { for (j = i + 1; j < numPoints - 1; j++) { for (k = j + 1; k < numPoints; k++) { int isTri = 1; int l; for (l = 0; l < numPoints; l++) { if (l != i && l != j && l != k) { if(isDelaunay(points[i], points[j], points[k], points[l])) { isTri = 0; break; } } } if (isTri) { lines[numLines].p1 = points[i]; lines[numLines].p2 = points[j]; numLines++; lines[numLines].p1 = points[j]; lines[numLines].p2 = points[k]; numLines++; lines[numLines].p1 = points[k]; lines[numLines].p2 = points[i]; numLines++; } } } } /* perform edge flipping to get a Delaunay triangulation */ int label = 0; for (i = 0; i < numLines; ) { int j; for (j = i+1; j < numLines; j++){ if ((lines[i].p1.x == lines[j].p2.x && lines[i].p1.y == lines[j].p2.y && lines[i].p2.x == lines[j].p1.x && lines[i].p2.y == lines[j].p1.y) || (lines[i].p1.x == lines[j].p1.x && lines[i].p1.y == lines[j].p1.y && lines[i].p2.x == lines[j].p2.x && lines[i].p2.y == lines[j].p2.y) || (lines[i].p1.x == lines[j].p2.x && lines[i].p1.y == lines[j].p2.y && lines[i].p2.x == lines[j].p1.x && lines[i].p2.y == lines[j].p1.y) || (lines[i].p1.x == lines[j].p1.x && lines[i].p1.y == lines[j].p2.y && lines[i].p2.x == lines[j].p2.x && lines[i].p2.y == lines[j].p1.y)){ Point newPt1, newPt2; newPt1 = lines[i].p1 == lines[j].p1 ? lines[i].p2 : lines[i].p1; newPt2 = lines[j].p1 == lines[i].p1 ? lines[j].p2 : lines[j].p1; lines[i].p2 = newPt1; lines[j].p2 = newPt2; i = 0; j = 0; continue; } } i++; } /* print out the completed Delaunay triangulation */ for (i = 0; i < numLines; i++) { printf(" %f,%f - %f,%f\n", lines[i].p1.x, lines[i].p1.y, lines[i].p2.x,lines[i].p2.y); } free(lines); } 最后,我们可以通过编写主函数(main)来测试该算法: int main(int argc, char *argv[]) { /* can be adapted to take in command line args */ Point points[] = {{0,0}, {1,0}, {0,1}, {1,1}, {0.5,0.5}}; int numPoints = sizeof(points) / sizeof(Point); DelaunayTriangulation(points, numPoints); return 0; } 通过以上的代码,我们实现了一个简单的Delaunay三角剖分算法,并通过一个包含5个点的点集进行了测试。在实际应用中,可以根据具体需求进行算法优化和性能调整。

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值