📄 axb_core.c
字号:
} } /* solve using the computed Cholesky in one lapack call */ POTRS("U", (int *)&m, (int *)&nrhs, a, (int *)&m, b, (int *)&m, &info); if(info<0){ fprintf(stderr, RCAT(RCAT("LAPACK error: illegal value for argument %d of ", POTRS) " in ", AX_EQ_B_CHOL) "()\n", -info); exit(1); }#if 0 /* alternative: solve the linear system U^T y = b ... */ TRTRS("U", "T", "N", (int *)&m, (int *)&nrhs, a, (int *)&m, b, (int *)&m, &info); /* error treatment */ if(info!=0){ if(info<0){ fprintf(stderr, RCAT(RCAT("LAPACK error: illegal value for argument %d of ", TRTRS) " in ", AX_EQ_B_CHOL) "()\n", -info); exit(1); } else{ fprintf(stderr, RCAT("LAPACK error: the %d-th diagonal element of A is zero (singular matrix) in ", AX_EQ_B_CHOL) "()\n", info);#ifndef LINSOLVERS_RETAIN_MEMORY free(buf);#endif return 0; } } /* ... solve the linear system U x = y */ TRTRS("U", "N", "N", (int *)&m, (int *)&nrhs, a, (int *)&m, b, (int *)&m, &info); /* error treatment */ if(info!=0){ if(info<0){ fprintf(stderr, RCAT(RCAT("LAPACK error: illegal value for argument %d of ", TRTRS) "in ", AX_EQ_B_CHOL) "()\n", -info); exit(1); } else{ fprintf(stderr, RCAT("LAPACK error: the %d-th diagonal element of A is zero (singular matrix) in ", AX_EQ_B_CHOL) "()\n", info);#ifndef LINSOLVERS_RETAIN_MEMORY free(buf);#endif return 0; } }#endif /* 0 */ /* copy the result in x */ for(i=0; i<m; i++) x[i]=b[i];#ifndef LINSOLVERS_RETAIN_MEMORY free(buf);#endif return 1;}/* * This function returns the solution of Ax = b * * The function employs LU decomposition: * If A=L U with L lower and U upper triangular, then the original system * amounts to solving * L y = b, U x = y * * A is mxm, b is mx1 * * The function returns 0 in case of error, 1 if successful * * This function is often called repetitively to solve problems of identical * dimensions. To avoid repetitive malloc's and free's, allocated memory is * retained between calls and free'd-malloc'ed when not of the appropriate size. * A call with NULL as the first argument forces this memory to be released. */int AX_EQ_B_LU(LM_REAL *A, LM_REAL *B, LM_REAL *x, int m){__STATIC__ LM_REAL *buf=NULL;__STATIC__ int buf_sz=0;int a_sz, ipiv_sz, b_sz, tot_sz;register int i, j;int info, *ipiv, nrhs=1;LM_REAL *a, *b; if(!A)#ifdef LINSOLVERS_RETAIN_MEMORY { if(buf) free(buf); buf=NULL; buf_sz=0; return 1; }#else return 1; /* NOP */#endif /* LINSOLVERS_RETAIN_MEMORY */ /* calculate required memory size */ ipiv_sz=m; a_sz=m*m; b_sz=m; tot_sz=(a_sz + b_sz)*sizeof(LM_REAL) + ipiv_sz*sizeof(int); /* should be arranged in that order for proper doubles alignment */#ifdef LINSOLVERS_RETAIN_MEMORY if(tot_sz>buf_sz){ /* insufficient memory, allocate a "big" memory chunk at once */ if(buf) free(buf); /* free previously allocated memory */ buf_sz=tot_sz; buf=(LM_REAL *)malloc(buf_sz); if(!buf){ fprintf(stderr, RCAT("memory allocation in ", AX_EQ_B_LU) "() failed!\n"); exit(1); } }#else buf_sz=tot_sz; buf=(LM_REAL *)malloc(buf_sz); if(!buf){ fprintf(stderr, RCAT("memory allocation in ", AX_EQ_B_LU) "() failed!\n"); exit(1); }#endif /* LINSOLVERS_RETAIN_MEMORY */ a=buf; b=a+a_sz; ipiv=(int *)(b+b_sz); /* store A (column major!) into a and B into b */ for(i=0; i<m; i++){ for(j=0; j<m; j++) a[i+j*m]=A[i*m+j]; b[i]=B[i]; } /* LU decomposition for A */ GETRF((int *)&m, (int *)&m, a, (int *)&m, ipiv, (int *)&info); if(info!=0){ if(info<0){ fprintf(stderr, RCAT(RCAT("argument %d of ", GETRF) " illegal in ", AX_EQ_B_LU) "()\n", -info); exit(1); } else{ fprintf(stderr, RCAT(RCAT("singular matrix A for ", GETRF) " in ", AX_EQ_B_LU) "()\n");#ifndef LINSOLVERS_RETAIN_MEMORY free(buf);#endif return 0; } } /* solve the system with the computed LU */ GETRS("N", (int *)&m, (int *)&nrhs, a, (int *)&m, ipiv, b, (int *)&m, (int *)&info); if(info!=0){ if(info<0){ fprintf(stderr, RCAT(RCAT("argument %d of ", GETRS) " illegal in ", AX_EQ_B_LU) "()\n", -info); exit(1); } else{ fprintf(stderr, RCAT(RCAT("unknown error for ", GETRS) " in ", AX_EQ_B_LU) "()\n");#ifndef LINSOLVERS_RETAIN_MEMORY free(buf);#endif return 0; } } /* copy the result in x */ for(i=0; i<m; i++){ x[i]=b[i]; }#ifndef LINSOLVERS_RETAIN_MEMORY free(buf);#endif return 1;}/* * This function returns the solution of Ax = b * * The function is based on SVD decomposition: * If A=U D V^T with U, V orthogonal and D diagonal, the linear system becomes * (U D V^T) x = b or x=V D^{-1} U^T b * Note that V D^{-1} U^T is the pseudoinverse A^+ * * A is mxm, b is mx1. * * The function returns 0 in case of error, 1 if successful * * This function is often called repetitively to solve problems of identical * dimensions. To avoid repetitive malloc's and free's, allocated memory is * retained between calls and free'd-malloc'ed when not of the appropriate size. * A call with NULL as the first argument forces this memory to be released. */int AX_EQ_B_SVD(LM_REAL *A, LM_REAL *B, LM_REAL *x, int m){__STATIC__ LM_REAL *buf=NULL;__STATIC__ int buf_sz=0;static LM_REAL eps=LM_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;register LM_REAL sum;int info, rank, worksz, *iwork, iworksz; if(!A)#ifdef LINSOLVERS_RETAIN_MEMORY { if(buf) free(buf); buf=NULL; buf_sz=0; return 1; }#else return 1; /* NOP */#endif /* LINSOLVERS_RETAIN_MEMORY */ /* calculate required memory size */#if 1 /* use optimal size */ worksz=-1; // workspace query. Keep in mind that GESDD requires more memory than GESVD /* note that optimal work size is returned in thresh */ GESVD("A", "A", (int *)&m, (int *)&m, NULL, (int *)&m, NULL, NULL, (int *)&m, NULL, (int *)&m, (LM_REAL *)&thresh, (int *)&worksz, &info); //GESDD("A", (int *)&m, (int *)&m, NULL, (int *)&m, NULL, NULL, (int *)&m, NULL, (int *)&m, (LM_REAL *)&thresh, (int *)&worksz, NULL, &info); worksz=(int)thresh;#else /* use minimum size */ worksz=5*m; // min worksize for GESVD //worksz=m*(7*m+4); // min worksize for GESDD#endif iworksz=8*m; a_sz=m*m; u_sz=m*m; s_sz=m; vt_sz=m*m; tot_sz=(a_sz + u_sz + s_sz + vt_sz + worksz)*sizeof(LM_REAL) + iworksz*sizeof(int); /* should be arranged in that order for proper doubles alignment */#ifdef LINSOLVERS_RETAIN_MEMORY if(tot_sz>buf_sz){ /* insufficient memory, allocate a "big" memory chunk at once */ if(buf) free(buf); /* free previously allocated memory */ buf_sz=tot_sz; buf=(LM_REAL *)malloc(buf_sz); if(!buf){ fprintf(stderr, RCAT("memory allocation in ", AX_EQ_B_SVD) "() failed!\n"); exit(1); } }#else buf_sz=tot_sz; buf=(LM_REAL *)malloc(buf_sz); if(!buf){ fprintf(stderr, RCAT("memory allocation in ", AX_EQ_B_SVD) "() failed!\n"); exit(1); }#endif /* LINSOLVERS_RETAIN_MEMORY */ a=buf; u=a+a_sz; s=u+u_sz; vt=s+s_sz; work=vt+vt_sz; iwork=(int *)(work+worksz); /* 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]; /* 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 ", AX_EQ_B_SVD) "()\n", -info); exit(1); } else{ fprintf(stderr, RCAT("LAPACK error: dgesdd (dbdsdc)/dgesvd (dbdsqr) failed to converge in ", AX_EQ_B_SVD) "() [info=%d]\n", info);#ifndef LINSOLVERS_RETAIN_MEMORY free(buf);#endif return 0; } } if(eps<0.0){ LM_REAL aux; /* compute machine epsilon */ for(eps=LM_CNST(1.0); aux=eps+LM_CNST(1.0), aux-LM_CNST(1.0)>0.0; eps*=LM_CNST(0.5)) ; eps*=LM_CNST(2.0); } /* compute the pseudoinverse in a */ for(i=0; i<a_sz; i++) a[i]=0.0; /* initialize to zero */ for(rank=0, thresh=eps*s[0]; rank<m && s[rank]>thresh; rank++){ one_over_denom=LM_CNST(1.0)/s[rank]; for(j=0; j<m; j++) for(i=0; i<m; i++) a[i*m+j]+=vt[rank+i*m]*u[j+rank*m]*one_over_denom; } /* compute A^+ b in x */ for(i=0; i<m; i++){ for(j=0, sum=0.0; j<m; j++) sum+=a[i*m+j]*B[j]; x[i]=sum; }#ifndef LINSOLVERS_RETAIN_MEMORY free(buf);#endif return 1;}/* undefine all. IT MUST REMAIN IN THIS POSITION IN FILE */#undef AX_EQ_B_QR#undef AX_EQ_B_QRLS#undef AX_EQ_B_CHOL#undef AX_EQ_B_LU#undef AX_EQ_B_SVD#undef GEQRF#undef ORGQR#undef TRTRS#undef POTF2#undef POTRF#undef POTRS#undef GETRF#undef GETRS#undef GESVD#undef GESDD#else // no LAPACK/* precision-specific definitions */#define AX_EQ_B_LU LM_ADD_PREFIX(Ax_eq_b_LU_noLapack)/* * This function returns the solution of Ax = b * * The function employs LU decomposition followed by forward/back substitution (see * also the LAPACK-based LU solver above) * * A is mxm, b is mx1 * * The function returns 0 in case of error, 1 if successful * * This function is often called repetitively to solve problems of identical * dimensions. To avoid repetitive malloc's and free's, allocated memory is * retained between calls and free'd-malloc'ed when not of the appropriate size. * A call with NULL as the first argument forces this memory to be released. */int AX_EQ_B_LU(LM_REAL *A, LM_REAL *B, LM_REAL *x, int m){__STATIC__ void *buf=NULL;__STATIC__ int buf_sz=0;register int i, j, k;int *idx, maxi=-1, idx_sz, a_sz, work_sz, tot_sz;LM_REAL *a, *work, max, sum, tmp; if(!A)#ifdef LINSOLVERS_RETAIN_MEMORY { if(buf) free(buf); buf=NULL; buf_sz=0; return 1; }#else return 1; /* NOP */#endif /* LINSOLVERS_RETAIN_MEMORY */ /* calculate required memory size */ idx_sz=m; a_sz=m*m; work_sz=m; tot_sz=(a_sz+work_sz)*sizeof(LM_REAL) + idx_sz*sizeof(int); /* should be arranged in that order for proper doubles alignment */#ifdef LINSOLVERS_RETAIN_MEMORY if(tot_sz>buf_sz){ /* insufficient memory, allocate a "big" memory chunk at once */ if(buf) free(buf); /* free previously allocated memory */ buf_sz=tot_sz; buf=(void *)malloc(tot_sz); if(!buf){ fprintf(stderr, RCAT("memory allocation in ", AX_EQ_B_LU) "() failed!\n"); exit(1); } }#else buf_sz=tot_sz; buf=(void *)malloc(tot_sz); if(!buf){ fprintf(stderr, RCAT("memory allocation in ", AX_EQ_B_LU) "() failed!\n"); exit(1); }#endif /* LINSOLVERS_RETAIN_MEMORY */ a=buf; work=a+a_sz; idx=(int *)(work+work_sz); /* avoid destroying A, B by copying them to a, x resp. */ for(i=0; i<m; ++i){ // B & 1st row of A a[i]=A[i]; x[i]=B[i]; } for( ; i<a_sz; ++i) a[i]=A[i]; // copy A's remaining rows /**** for(i=0; i<m; ++i){ for(j=0; j<m; ++j) a[i*m+j]=A[i*m+j]; x[i]=B[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 ", AX_EQ_B_LU) "()!\n");#ifndef LINSOLVERS_RETAIN_MEMORY free(buf);#endif return 0; } work[i]=LM_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=LM_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 linear system using * forward and back substitution */ 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]; }#ifndef LINSOLVERS_RETAIN_MEMORY free(buf);#endif return 1;}/* undefine all. IT MUST REMAIN IN THIS POSITION IN FILE */#undef AX_EQ_B_LU#endif /* HAVE_LAPACK */
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -