#ifndef__FILE_READ_SAVE_H#define__FILE_READ_SAVE_H#include<string>classUFileReadSave{public:UFileReadSave(void){};//inline~UFileReadSave(void){};public:/**********************************************************
Description: Get the bytes of file.
Arguments:
{
strFilePath: File path.
fileByteNum: The Bytes will be read.
}
Return: Status.
**********************************************************/staticboolGetFileBytes(std::string& strFilePath, size_t& fileByteNum);// 20200810Updated/**********************************************************
Description: Read the binary file to an memory.
Arguments:
{
pDst: The destination memory.
strFilePath: File path.
fileByteNum: The Bytes will be read.
}
Return: Status.
**********************************************************/staticboolReadFile(char* pSrc, std::string& strFilePath, size_t fileByteNum);/**********************************************************
Description: Read the binary file to an memory with multi-processor.
Arguments:
{
pDst: The destination memory.
strFilePath: File path.
fileByteNum: The Bytes will be read.
}
Return: Status.
**********************************************************/staticboolReadFileMultiPrcs(void* pSrc, std::string& strFilePath, size_t fileByteNum,int threadNum =0);/**********************************************************
Description: Write the binary file to the disk.
Arguments:
{
pSrc: The source data.
strFilePath: File path.
fileByteNum: The Bytes will be saved.
}
Return: Status.
**********************************************************/staticboolSaveFile(char* pSrc, std::string& strFilePath, size_t fileByteNum);};#endif
2.2 UFileReadSave.cpp
#include"UFileReadSave.h"#include<fstream>#include<iostream>#include<string>#include<stdio.h>#include<thread>#include<vector>usingnamespace std;boolUFileReadSave::GetFileBytes(std::string& strFilePath, size_t& fileByteNum){
ifstream projFile(strFilePath.c_str(), ios::binary);if(!projFile.is_open()){
cout << strFilePath <<" is losted!"<< endl;// file lostedreturnfalse;}
projFile.seekg(0, ios::end);
fileByteNum = projFile.tellg();
projFile.close();returntrue;}boolUFileReadSave::ReadFile(char* pDst, std::string& strFilePath, size_t fileByteNum){
ifstream projFile(strFilePath.c_str(), ios::binary);if(!projFile.is_open()){
cout << strFilePath <<" is losted!"<< endl;// file lostedreturnfalse;}
projFile.seekg(0, ios::end);
size_t fileLen = projFile.tellg();if(fileLen < fileByteNum)//file too small{
cout << strFilePath <<" only has "<< fileLen <<" bytes which is less than required "<< fileByteNum <<" bytes."<< endl;returnfalse;// 20200908Updated}
projFile.seekg(0, ios::beg);
projFile.read(pDst, fileByteNum);
projFile.close();returntrue;}boolUFileReadSave::SaveFile(char* pSrc, std::string& strFilePath, size_t fileByteNum){
ofstream projFile(strFilePath.c_str(), ios::binary);if(!projFile.is_open()){
cout << strFilePath <<" open failed! Please select another path"<< endl;//file lostedreturnfalse;}
projFile.write(pSrc, fileByteNum);
projFile.close();returntrue;}
#ifndefLMFIT_H#defineLMFIT_H#include<math.h>#include<string>#include"maqr.h"#include<iostream>#include"lmstruct.h"#defineDERIV_STEP1e-5#definenum_params4//参数个数#definetotal_data8#defineMAX_ITER500#defineMIN_SETP1e-12#defineGTOL1e-12doubleFunc(double* x,double* par,int n){return par[0]*exp(par[1]* x[n])+ par[2]*exp(par[3]* x[n]);}doubleDeriv(double(*Func)(double* x,double* par,int n),double* x,double* par,int j,int k){double par1[num_params];double par2[num_params];for(unsigned i =0; i < num_params;++i){
par1[i]= par2[i]= par[i];}
par1[k]-= DERIV_STEP;
par2[k]+= DERIV_STEP;double p1 =Func(x, par1, j);double p2 =Func(x, par2, j);return(p2 - p1)/(2* DERIV_STEP);}doublecalBottom(double* hlm,float u,double* c){double b[num_params]={0};double sum =0;for(unsigned i =0; i < num_params;++i){
b[i]= u * hlm[i];
sum += hlm[i]*(b[i]- c[i]);}return sum;}//求取方程左边方程voidCalLeft(double* Jf,float u,double* a){for(unsigned i =0; i < num_params;++i){for(unsigned j =0; j < num_params;++j){for(unsigned k =0; k < total_data;++k){
a[i * num_params + j]+= Jf[k * num_params + i]* Jf[k * num_params + j];}
a[i * num_params + j]+= u;}}}voidCalRight(double* q,double* Jf,double* r,double* c,double* d){//double c[num_params] = { 0 };for(unsigned i =0; i < num_params;++i){for(unsigned k =0; k < total_data;++k){
c[i]+= Jf[k * num_params + i]* r[k];}}for(unsigned i =0; i < num_params;++i){for(unsigned j =0; j < num_params;++j){
d[i]+= q[j * num_params + i]* c[j];}}}doublenorm(double* r,unsigned m){double sum =0;for(unsigned i =0; i < m;++i){
sum += r[i]* r[i];}returnsqrt(sum);}/*利用L - M方法求解 原方程(J^(T)*J + u * I) * hlm = J ^ (T)*r
对(J^(T)*J + u * I)做QR分解,并作运算变换得到
R * hlm = Q^(T) * J^(T) * r 根据此方程求解hlm
利用实际下降量和预测下降量的比值来判断拟合效果
*/voidLM(double(*Func)(double* x,double* par,int n),double* x,double* y,double* par, lm_status_struct* s){int m =8;//数据个数double* r =newdouble[m];//存放阈值与拟合值的误差double* r_temp =newdouble[m];double* par_temp =newdouble[num_params];double* Jf =newdouble[m * num_params];// 雅各比矩阵double last_mse =0;float u =1, v =2;double mse =0;
s->outcome =1;// 迭代100次退出int i =0;for(i =0; i < MAX_ITER;++i){
mse =0;double mse_temp =0;//计算雅各比行列式 同时得到误差for(unsigned j =0; j < m;++j){//计算y与拟合的值之间的误差
r[j]= y[j]-Func(x, par, j);
mse += r[j]* r[j];for(unsigned k =0; k < num_params;++k){
Jf[j * num_params + k]=Deriv(Func, x, par, j, k);}}
mse /= m;//求取平均误差//std::cout << "mse: " << mse << std::endl;//for (unsigned j = 0; j < total_data; ++j) {// for (unsigned k = 0; k < num_params; ++k) {// std::cout << Jf[j * num_params + k] << " ";// }// std::cout << std::endl;//}//std::cout << std::endl;double hlm[num_params]={0};double a[num_params * num_params]={0};// 用来存放(J^(T) * J + u * I)的结果double q[num_params * num_params]={0};//a矩阵QR分解后的Q矩阵double d[num_params]={0};CalLeft(Jf, u, a);//计算转换方程的等式左边的值 结果存放在a中//QR分解 分解完以后a = R, q = Qmaqr(a, num_params, num_params, q, s);//计算右边Q^(T) * J^(T) * rdouble c[num_params]={0};CalRight(q, Jf, r, c, d);//计算方程右边的值,用d来存放//检测退化if(norm(c, num_params)< GTOL){//std::cout << "norm(c, num_params) < GTOL" << std::endl;
s->outcome =3;// 矩阵退化退出break;}for(int i = num_params -1; i >=0;--i){for(int j = i +1; j < num_params;++j){
d[i]-= a[i * num_params + j]* hlm[j];}
hlm[i]= d[i]/ a[i * num_params + i];//求解步长
par_temp[i]= par[i]+ hlm[i];//更新参数}for(unsigned j =0; j < total_data;++j){
r_temp[j]= y[j]-Func(x, par_temp, j);
mse_temp += r_temp[j]* r_temp[j];//计算更新参数后的总误差}
mse_temp /= total_data;//std::cout << "mse_temp: " << mse_temp << std::endl;double bottom =calBottom(hlm, u, c);//计算判断拟合效果式子的分母double qqq =(mse - mse_temp)/(0.5* bottom);// 这里是一个矩阵运算,判断拟合效果的依据//std::cout << "qqq: " << qqq << std::endl;if(qqq >0){double s =1.0/3.0;
v =2;
mse = mse_temp;// 更新误差for(unsigned j =0; j < num_params;++j){
par[j]= par_temp[j];}double temp =1-pow(2* qqq -1,3);if(s > temp){
u = u * s;}else{
u = u * temp;}}else{
u = u * v;
v =2* v;}double setp =norm(hlm, num_params);// The difference in mse is very small, so quit// 退出条件:步长收敛if(setp <= MIN_SETP){//std::cout << "setp <= MIN_SETP" << std::endl;
s->outcome =4;// 步长很小退出break;}//退出条件:两次更新后的误差差值很小,已经收敛if(qqq >0&&fabs(mse - last_mse)<1e-3){//std::cout << "qqq > 0 && fabs(mse - last_mse) < 1e-3" << std::endl;
s->outcome =5;// 两次误差很小退出break;}//printf("%d %lf\n", i, mse);
last_mse = mse;}delete[] r;delete[] r_temp;delete[] par_temp;delete[] Jf;
s->fnorm =sqrt(mse * m);
s->nfev = i;}//int main() {// //a*exp^(b*x) + c*exp^(d*x)//// int totoal_data = 8;//// //double x[8] = { 0,0.740742,1.2037,1.85185,30.2778,45.3704,59.6296,80.9259 };// //double x[8] = { 0,1.18182,1.54546,2.45455,33.5455,48.0909,57.3636,84.3636 };// //double x[8] = { 0,0.545454,0.81818,1.36364,40.0909,47.8182,63.5455, 87.1818 };// //double x[8] = { 0,0.545456,0.818182,1.18182,49.2727,60.6364,77.1818,99.4545 };// //double x[8] = { 0,0.545454,0.454544,1.72727,49.7273,62,76.8182,110.455 };// double x[8] = { 0,0.545454,1,1.54545,34.8182,45.277,57.8182,86.9091 };//// double y[8] = { 20,90,160,230,230,160,90,20 };// double par[4] = { 1873, -0.0448, -1847, -0.1429 };//// LM(Func, x, y, par);//// std::cout << "拟合值: ";// for (int i = 0; i < 8; ++i) {// std::cout << Func(x, par, i) << " ";// }// std::cout << std::endl;//}//#endif// !LMFIT_H
3.2 QR分解
#pragmaonce#ifndefMAQR_H#defineMAQR_H#include"math.h"#include"stdio.h"
__device__ intmaqr(double* a,unsigned m,unsigned n,double* q, lm_status_struct& s){int i, j, k, l, nn, p, jj;double u, alpha, w, t;if(m < n){printf("fail\n");return(0);}for(i =0; i <= m -1; i++)for(j =0; j <= m -1; j++){
l = i * m + j; q[l]=0.0;if(i == j) q[l]=1.0;}
nn = n;if(m == n) nn = m -1;for(k =0; k <= nn -1; k++){
u =0.0; l = k * n + k;for(i = k; i <= m -1; i++){
w =fabs(a[i * n + k]);if(w > u) u = w;}
alpha =0.0;for(i = k; i <= m -1; i++){
t = a[i * n + k]/ u; alpha = alpha + t * t;}if(a[l]>0.0) u =-u;
alpha = u *sqrt(alpha);if(fabs(alpha)+1.0==1.0){//printf("fail\n");
s.outcome =2;// qr分解失败退出return(0);}
u =sqrt(2.0* alpha *(alpha - a[l]));if((u +1.0)!=1.0){
a[l]=(a[l]- alpha)/ u;for(i = k +1; i <= m -1; i++){
p = i * n + k; a[p]= a[p]/ u;}for(j =0; j <= m -1; j++){
t =0.0;for(jj = k; jj <= m -1; jj++)
t = t + a[jj * n + k]* q[jj * m + j];for(i = k; i <= m -1; i++){
p = i * m + j; q[p]= q[p]-2.0* t * a[i * n + k];}}for(j = k +1; j <= n -1; j++){
t =0.0;for(jj = k; jj <= m -1; jj++)
t = t + a[jj * n + k]* a[jj * n + j];for(i = k; i <= m -1; i++){
p = i * n + j; a[p]= a[p]-2.0* t * a[i * n + k];}}
a[l]= alpha;for(i = k +1; i <= m -1; i++)
a[i * n + k]=0.0;}}for(i =0; i <= m -2; i++)for(j = i +1; j <= m -1; j++){
p = i * m + j; l = j * m + i;
t = q[p]; q[p]= q[l]; q[l]= t;}return(1);}#endif// !MAQR_H