📄 misc_core.c
字号:
temp=eps*FABS((fvecp[i]-fvec[i])/eps - err[i])/(FABS(fvec[i])+FABS(fvecp[i])); err[i]=one; if(temp>epsmch && temp<eps) err[i]=((LM_REAL)log10(temp) - epslog)/epslog; if(temp>=eps) err[i]=zero; } free(buf); return;}#ifdef HAVE_LAPACK/* * This function computes the pseudoinverse of a square matrix A * into B using SVD. A and B can coincide * * The function returns 0 in case of error (e.g. A is singular), * the rank of A if successfull * * A, B are mxm * */static int LEVMAR_PSEUDOINVERSE(LM_REAL *A, LM_REAL *B, int m){LM_REAL *buf=NULL;int buf_sz=0;static LM_REAL eps=CNST(-1.0);register int i, j;LM_REAL *a, *u, *s, *vt, *work;int a_sz, u_sz, s_sz, vt_sz, tot_sz;LM_REAL thresh, one_over_denom;int info, rank, worksz, *iwork, iworksz; /* calculate required memory size */ worksz=16*m; /* more than needed */ iworksz=8*m; a_sz=m*m; u_sz=m*m; s_sz=m; vt_sz=m*m; tot_sz=iworksz*sizeof(int) + (a_sz + u_sz + s_sz + vt_sz + worksz)*sizeof(LM_REAL); buf_sz=tot_sz; buf=(LM_REAL *)malloc(buf_sz); if(!buf){ fprintf(stderr, RCAT("memory allocation in ", LEVMAR_PSEUDOINVERSE) "() failed!\n"); exit(1); } iwork=(int *)buf; a=(LM_REAL *)(iwork+iworksz); /* store A (column major!) into a */ for(i=0; i<m; i++) for(j=0; j<m; j++) a[i+j*m]=A[i*m+j]; u=a + a_sz; s=u+u_sz; vt=s+s_sz; work=vt+vt_sz; /* SVD decomposition of A */ GESVD("A", "A", (int *)&m, (int *)&m, a, (int *)&m, s, u, (int *)&m, vt, (int *)&m, work, (int *)&worksz, &info); //GESDD("A", (int *)&m, (int *)&m, a, (int *)&m, s, u, (int *)&m, vt, (int *)&m, work, (int *)&worksz, iwork, &info); /* error treatment */ if(info!=0){ if(info<0){ fprintf(stderr, RCAT(RCAT(RCAT("LAPACK error: illegal value for argument %d of ", GESVD), "/" GESDD) " in ", LEVMAR_PSEUDOINVERSE) "()\n", -info); exit(1); } else{ fprintf(stderr, RCAT("LAPACK error: dgesdd (dbdsdc)/dgesvd (dbdsqr) failed to converge in ", LEVMAR_PSEUDOINVERSE) "() [info=%d]\n", info); free(buf); return 0; } } if(eps<0.0){ LM_REAL aux; /* compute machine epsilon */ for(eps=CNST(1.0); aux=eps+CNST(1.0), aux-CNST(1.0)>0.0; eps*=CNST(0.5)) ; eps*=CNST(2.0); } /* compute the pseudoinverse in B */ for(i=0; i<a_sz; i++) B[i]=0.0; /* initialize to zero */ for(rank=0, thresh=eps*s[0]; rank<m && s[rank]>thresh; rank++){ one_over_denom=CNST(1.0)/s[rank]; for(j=0; j<m; j++) for(i=0; i<m; i++) B[i*m+j]+=vt[rank+i*m]*u[j+rank*m]*one_over_denom; } free(buf); return rank;}#else // no LAPACK/* * This function computes the inverse of A in B. A and B can coincide * * The function employs LAPACK-free LU decomposition of A to solve m linear * systems A*B_i=I_i, where B_i and I_i are the i-th columns of B and I. * * A and B are mxm * * The function returns 0 in case of error, * 1 if successfull * */static int LEVMAR_LUINVERSE(LM_REAL *A, LM_REAL *B, int m){void *buf=NULL;int buf_sz=0;register int i, j, k, l;int *idx, maxi=-1, idx_sz, a_sz, x_sz, work_sz, tot_sz;LM_REAL *a, *x, *work, max, sum, tmp; /* calculate required memory size */ idx_sz=m; a_sz=m*m; x_sz=m; work_sz=m; tot_sz=idx_sz*sizeof(int) + (a_sz+x_sz+work_sz)*sizeof(LM_REAL); buf_sz=tot_sz; buf=(void *)malloc(tot_sz); if(!buf){ fprintf(stderr, RCAT("memory allocation in ", LEVMAR_LUINVERSE) "() failed!\n"); exit(1); } idx=(int *)buf; a=(LM_REAL *)(idx + idx_sz); x=a + a_sz; work=x + x_sz; /* avoid destroying A by copying it to a */ for(i=0; i<a_sz; ++i) a[i]=A[i]; /* compute the LU decomposition of a row permutation of matrix a; the permutation itself is saved in idx[] */ for(i=0; i<m; ++i){ max=0.0; for(j=0; j<m; ++j) if((tmp=FABS(a[i*m+j]))>max) max=tmp; if(max==0.0){ fprintf(stderr, RCAT("Singular matrix A in ", LEVMAR_LUINVERSE) "()!\n"); free(buf); return 0; } work[i]=CNST(1.0)/max; } for(j=0; j<m; ++j){ for(i=0; i<j; ++i){ sum=a[i*m+j]; for(k=0; k<i; ++k) sum-=a[i*m+k]*a[k*m+j]; a[i*m+j]=sum; } max=0.0; for(i=j; i<m; ++i){ sum=a[i*m+j]; for(k=0; k<j; ++k) sum-=a[i*m+k]*a[k*m+j]; a[i*m+j]=sum; if((tmp=work[i]*FABS(sum))>=max){ max=tmp; maxi=i; } } if(j!=maxi){ for(k=0; k<m; ++k){ tmp=a[maxi*m+k]; a[maxi*m+k]=a[j*m+k]; a[j*m+k]=tmp; } work[maxi]=work[j]; } idx[j]=maxi; if(a[j*m+j]==0.0) a[j*m+j]=LM_REAL_EPSILON; if(j!=m-1){ tmp=CNST(1.0)/(a[j*m+j]); for(i=j+1; i<m; ++i) a[i*m+j]*=tmp; } } /* The decomposition has now replaced a. Solve the m linear systems using * forward and back substitution */ for(l=0; l<m; ++l){ for(i=0; i<m; ++i) x[i]=0.0; x[l]=CNST(1.0); for(i=k=0; i<m; ++i){ j=idx[i]; sum=x[j]; x[j]=x[i]; if(k!=0) for(j=k-1; j<i; ++j) sum-=a[i*m+j]*x[j]; else if(sum!=0.0) k=i+1; x[i]=sum; } for(i=m-1; i>=0; --i){ sum=x[i]; for(j=i+1; j<m; ++j) sum-=a[i*m+j]*x[j]; x[i]=sum/a[i*m+i]; } for(i=0; i<m; ++i) B[i*m+l]=x[i]; } free(buf); return 1;}#endif /* HAVE_LAPACK *//* * This function computes in C the covariance matrix corresponding to a least * squares fit. JtJ is the approximate Hessian at the solution (i.e. J^T*J, where * J is the jacobian at the solution), sumsq is the sum of squared residuals * (i.e. goodnes of fit) at the solution, m is the number of parameters (variables) * and n the number of observations. JtJ can coincide with C. * * if JtJ is of full rank, C is computed as sumsq/(n-m)*(JtJ)^-1 * otherwise and if LAPACK is available, C=sumsq/(n-r)*(JtJ)^+ * where r is JtJ's rank and ^+ denotes the pseudoinverse * The diagonal of C is made up from the estimates of the variances * of the estimated regression coefficients. * See the documentation of routine E04YCF from the NAG fortran lib * * The function returns the rank of JtJ if successful, 0 on error * * A and C are mxm * */int LEVMAR_COVAR(LM_REAL *JtJ, LM_REAL *C, LM_REAL sumsq, int m, int n){register int i;int rnk;LM_REAL fact;#ifdef HAVE_LAPACK rnk=LEVMAR_PSEUDOINVERSE(JtJ, C, m); if(!rnk) return 0;#else#ifdef _MSC_VER#pragma message("LAPACK not available, LU will be used for matrix inversion when computing the covariance; this might be unstable at times")#else#warning LAPACK not available, LU will be used for matrix inversion when computing the covariance; this might be unstable at times#endif // _MSC_VER rnk=LEVMAR_LUINVERSE(JtJ, C, m); if(!rnk) return 0; rnk=m; /* assume full rank */#endif /* HAVE_LAPACK */ fact=sumsq/(LM_REAL)(n-rnk); for(i=0; i<m*m; ++i) C[i]*=fact; return rnk;}/* undefine everything. THIS MUST REMAIN AT THE END OF THE FILE */#undef LEVMAR_PSEUDOINVERSE#undef LEVMAR_LUINVERSE#undef LEVMAR_COVAR#undef LEVMAR_CHKJAC#undef FDIF_FORW_JAC_APPROX#undef FDIF_CENT_JAC_APPROX#undef TRANS_MAT_MAT_MULT
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -