00001
00002
00003
00004
00005
00006
00007
00008
00009
00010
00011
00012
00013
00014
00015
00016
00017
00018
00019
00020
00024
00025 #include <limits>
00026 #include <iostream>
00027
00028 #include <qvmath.h>
00029 #include <qvdefines.h>
00030 #include <qvmath/qvmatrixalgebra.h>
00031
00032
00033
00034
00035
00036
00037
00038
00039
00040 #ifdef MKL_AVAILABLE
00041
00042
00043
00044
00045
00046
00047 #define CHECK_MKL_DSS_ERROR \
00048 if (error != MKL_DSS_SUCCESS) { \
00049 std::cout << "Solver returned error code " << error << std::endl; \
00050 exit(1); \
00051 }
00052
00053 #elif LAPACK_AVAILABLE // Only with non-MKL LAPACK
00054 #define dgesvd dgesvd_
00055 #define dgesdd dgesdd_
00056 #define dpotrf dpotrf_
00057 #define dgeqrf dgeqrf_
00058 #define dgetrf dgetrf_
00059 #define dorgqr dorgqr_
00060 #define dsyev dsyev_
00061 extern "C" {
00062 void dgesvd(char *jobu,char *jobvt, int *m, int *n, double *a, int *lda, double *s, double *u, int *ldu,
00063 double *vt, int *ldvt, double *work, int *lwork, int *info );
00064 void dgesdd(char *jobz, int *m, int *n, double *a, int *lda, double *s, double *u, int *ldu, double *vt,
00065 int *ldvt, double *work, int *lwork, int *iwork, int *info );
00066 void dpotrf(char *uplo, int *n, double *a, int *lda, int *info );
00067 void dgeqrf(int *m, int *n, double *a, int *lda, double *tau, double *work, int *lwork, int *info );
00068 void dgetrf(int *m, int *n, double *a, int *lda, int *ipiv, int *info );
00069 void dorgqr(int *m, int *n, int *k, double *a, int *lda, double *tau, double *work, int *lwork, int *info );
00070 void dsyev(char *jobz, char *uplo, int *n, double *a, int *lda, double *w, double *work, int *lwork, int *info );
00071 }
00072 #endif
00073
00074 #ifdef QVCHOLMOD
00075 #include <QVCholmodSolver>
00076 #endif
00077
00078 #include <QVPermutation>
00079
00080 void singularValueDecomposition_internal(const QVMatrix &M, QVMatrix &U, QVVector &s, QVMatrix &V,
00081 const TQVSVD_Method method, bool only_singular_values = false)
00082 {
00083 int m = M.getRows(), n = M.getCols();
00084 if(method == GSL_THIN_DECOMP_MOD or method == GSL_THIN_DECOMP or method == GSL_THIN_DECOMP_JACOBI) {
00085 #ifdef GSL_AVAILABLE
00086 bool transposed = FALSE;
00087 gsl_matrix *u, *v;
00088 gsl_vector *ss;
00089
00090 if(M.getCols() > M.getRows())
00091 transposed = TRUE;
00092 const int dim2 = (transposed ? M.getRows():M.getCols());
00093
00094
00095 u = (transposed ? M.transpose() : M);
00096 ss = gsl_vector_alloc (dim2);
00097 v = gsl_matrix_alloc (dim2, dim2);
00098
00099 if(method == GSL_THIN_DECOMP_MOD) {
00100 gsl_vector *work = gsl_vector_alloc (dim2);
00101 gsl_matrix *XX = gsl_matrix_alloc (dim2,dim2);
00102
00103 gsl_linalg_SV_decomp_mod(u, XX, v, ss, work);
00104
00105 gsl_vector_free(work);
00106 gsl_matrix_free(XX);
00107 } else if(method == GSL_THIN_DECOMP) {
00108 gsl_vector *work = gsl_vector_alloc (dim2);
00109
00110 gsl_linalg_SV_decomp(u, v, ss, work);
00111
00112 gsl_vector_free(work);
00113 } else {
00114 gsl_linalg_SV_decomp_jacobi(u, v, ss);
00115 }
00116
00117
00118 if (not only_singular_values) U = u;
00119 s = ss;
00120 if (not only_singular_values) V = v;
00121
00122 if(not only_singular_values and transposed) {
00123 QVMatrix inter = U;
00124 U = V;
00125 V = inter;
00126 }
00127
00128
00129 gsl_matrix_free(u);
00130 gsl_vector_free(ss);
00131 gsl_matrix_free(v);
00132 #else
00133 qFatal("SVD decomposition: cannot use GSL methods if GSL library is not available.");
00134 #endif
00135 } else if (method == LAPACK_FULL_DGESVD or method == LAPACK_FULL_DGESDD or
00136 method == LAPACK_THIN_DGESVD or method == LAPACK_THIN_DGESDD) {
00137 #ifdef LAPACK_AVAILABLE
00138
00139 const char *jobu = "A",*jobvt = "A";
00140
00141
00142 QVMatrix MM = M.transpose();
00143 int ldu, ldvt, lwork, res;
00144 QVector<int> iwork(8*qMin(m,n));
00145 double *mptr = MM.getWriteData();
00146 int *iworkptr = iwork.data();
00147
00148 if (only_singular_values) {
00149 jobu = "N";
00150 jobvt = "N";
00151 U = QVMatrix(1,1);
00152 V = QVMatrix(1,1);
00153 ldu = 1;
00154 ldvt = 1;
00155 } else if(method == LAPACK_FULL_DGESVD or method == LAPACK_FULL_DGESDD) {
00156 jobu = "A";
00157 jobvt = "A";
00158 U = QVMatrix(m,m);
00159 V = QVMatrix(n,n);
00160 ldu = m;
00161 ldvt = n;
00162 } else if (method == LAPACK_THIN_DGESVD or method == LAPACK_THIN_DGESDD) {
00163 jobu = "S";
00164 jobvt = "S";
00165
00166 U = QVMatrix(qMin(m,n),m);
00167 V = QVMatrix(n,qMin(m,n));
00168 ldu = m ;
00169 ldvt = qMin(m,n);
00170 }
00171
00172 s = QVVector(qMin(m,n));
00173 double *sptr=s.data(), *uptr=U.getWriteData(), *vptr=V.getWriteData(), *workptr, ans;
00174
00175
00176 lwork = -1;
00177 if (method == LAPACK_FULL_DGESVD or method == LAPACK_THIN_DGESVD)
00178 dgesvd(const_cast<char*>(jobu),const_cast<char*>(jobvt),
00179 &m,&n,mptr,&m,sptr,uptr,&ldu,vptr,&ldvt,&ans,&lwork,&res);
00180 else if (method == LAPACK_FULL_DGESDD or method == LAPACK_THIN_DGESDD)
00181 dgesdd(const_cast<char*>(jobu),
00182 &m,&n,mptr,&m,sptr,uptr,&ldu,vptr,&ldvt,&ans,&lwork,iworkptr,&res);
00183 lwork = static_cast<int>(ceil(ans));
00184 QVVector work(lwork);
00185 workptr = work.data();
00186
00187
00188 if (method == LAPACK_FULL_DGESVD or method == LAPACK_THIN_DGESVD)
00189 dgesvd(const_cast<char*>(jobu),const_cast<char*>(jobvt),
00190 &m,&n,mptr,&m,sptr,uptr,&ldu,vptr,&ldvt,workptr,&lwork,&res);
00191 else if (method == LAPACK_FULL_DGESDD or method == LAPACK_THIN_DGESDD)
00192 dgesdd(const_cast<char*>(jobu),
00193 &m,&n,mptr,&m,sptr,uptr,&ldu,vptr,&ldvt,workptr,&lwork,iworkptr,&res);
00194
00195
00196 if(not only_singular_values)
00197 U = U.transpose();
00198 #else
00199 qFatal("SVD decomposition: cannot use LAPACK methods if MKL, ATLAS or LAPACK BASE are not available.");
00200 #endif
00201 }
00202 }
00203
00204 void singularValueDecomposition(const QVMatrix &M, QVMatrix &U, QVVector &s, QVMatrix &V, const TQVSVD_Method method)
00205 {
00206 singularValueDecomposition_internal(M, U, s, V, method);
00207 }
00208
00209 void SingularValueDecomposition(const QVMatrix &M, QVMatrix &U, QVMatrix &S, QVMatrix &V, const TQVSVD_Method method)
00210 {
00211 QVVector s;
00212
00213 std::cout << "WARNING: 'SingularValueDecomposition' DEPRECATED, use 'singularValueDecomposition' instead\n";
00214
00215 singularValueDecomposition_internal(M, U, s, V, method);
00216 S = QVMatrix::diagonal(s);
00217 const int m = U.getCols(), n = V.getCols();
00218 if (m>n)
00219 S = S & QVMatrix(m-n,n,0.0);
00220 else if (m<n)
00221 S = S | QVMatrix(m,n-m,0.0);
00222 }
00223
00224 void solveFromSingularValueDecomposition(const QVMatrix &U, const QVVector &s, const QVMatrix &V, QVMatrix &X, const QVMatrix &B)
00225 {
00226 X = U.dotProduct(B,true,false);
00227 for(int i=0;i<s.size();i++)
00228 for(int j=0;j<X.getCols();j++)
00229 X(i,j) /= s[i];
00230
00231 const int m = U.getRows(), n = V.getRows();
00232 if (U.getRows() == U.getCols() and U.getRows() == U.getCols())
00233 if (m>n)
00234 X = V.dotProduct(X.getRows(0,n-1),false,false);
00235 else
00236 X = V.getCols(0,m-1).dotProduct(X,false,false);
00237 else
00238 X = V.dotProduct(X,false,false);
00239 }
00240
00241 void solveFromSingularValueDecomposition(const QVMatrix &U, const QVVector &s, const QVMatrix &V, QVVector &x, const QVVector &b)
00242 {
00243 QVMatrix X , B = b.toColumnMatrix();
00244
00245 solveFromSingularValueDecomposition(U, s, V, X, B);
00246
00247 x = X;
00248 }
00249
00250 void solveBySingularValueDecomposition(const QVMatrix &M, QVVector &x, const QVVector &b, const TQVSVD_Method method)
00251 {
00252 QVMatrix U_dummy, V_dummy, X, B = b.toColumnMatrix();
00253 QVVector s_dummy;
00254
00255 singularValueDecomposition_internal(M, U_dummy, s_dummy, V_dummy, method);
00256 solveFromSingularValueDecomposition(U_dummy, s_dummy, V_dummy, X, B);
00257 x = X;
00258 }
00259
00260 void solveBySingularValueDecomposition(const QVMatrix &M, QVMatrix &X, const QVMatrix &B, const TQVSVD_Method method)
00261 {
00262 QVMatrix U_dummy, V_dummy;
00263 QVVector s_dummy;
00264
00265 singularValueDecomposition_internal(M, U_dummy, s_dummy, V_dummy, method);
00266 solveFromSingularValueDecomposition(U_dummy, s_dummy, V_dummy, X, B);
00267 }
00268
00269 void solveBySingularValueDecomposition(const QVMatrix &M, QVVector &x, const QVVector &b,
00270 QVMatrix &U, QVVector &s, QVMatrix &V, const TQVSVD_Method method)
00271 {
00272 QVMatrix X, B = b.toColumnMatrix();
00273
00274 singularValueDecomposition_internal(M, U, s, V, method);
00275 solveFromSingularValueDecomposition(U, s, V, X, B);
00276
00277 x = X;
00278 }
00279
00280 void solveBySingularValueDecomposition(const QVMatrix &M, QVMatrix &X, const QVMatrix &B,
00281 QVMatrix &U, QVVector &s, QVMatrix &V, const TQVSVD_Method method)
00282 {
00283 singularValueDecomposition_internal(M, U, s, V, method);
00284 solveFromSingularValueDecomposition(U, s, V, X, B);
00285 }
00286
00287 double singularValueDecompositionResidual(const QVMatrix &M, const QVMatrix &U, const QVVector &s, const QVMatrix &V)
00288 {
00289
00290 QVMatrix S = QVMatrix::diagonal(s);
00291 int m = U.getCols(), n = V.getCols();
00292 if (m>n)
00293 S = S & QVMatrix(m-n,n,0.0);
00294 else if (m<n)
00295 S = S | QVMatrix(m,n-m,0.0);
00296
00297 double res1 = (U*S*V.transpose()-M).norm2();
00298 double res2 = (U.transpose()*U - QVMatrix::identity(U.getCols())).norm2();
00299 double res3 = (V.transpose()*V - QVMatrix::identity(V.getCols())).norm2();
00300
00301 return res1 + res2 + res3;
00302 }
00303
00304 void singularValues(const QVMatrix &M, QVVector &s, const TQVSV_Method method)
00305 {
00306 QVMatrix U_dummy, V_dummy;
00307
00308 if(method == GSL_ONLY_DECOMP_MOD)
00309 singularValueDecomposition_internal(M, U_dummy, s, V_dummy,
00310 GSL_THIN_DECOMP_MOD, true);
00311 else if(method == GSL_ONLY_DECOMP)
00312 singularValueDecomposition_internal(M, U_dummy, s, V_dummy, GSL_THIN_DECOMP, true);
00313 else if(method == GSL_ONLY_DECOMP_JACOBI)
00314 singularValueDecomposition_internal(M, U_dummy, s, V_dummy, GSL_THIN_DECOMP_JACOBI, true);
00315 else if(method == LAPACK_ONLY_DGESVD)
00316 singularValueDecomposition_internal(M, U_dummy, s, V_dummy, LAPACK_THIN_DGESVD, true);
00317 else if(method == LAPACK_ONLY_DGESDD)
00318 singularValueDecomposition_internal(M, U_dummy, s, V_dummy, LAPACK_THIN_DGESDD, true);
00319 }
00320
00321 double singularValuesResidual(const QVMatrix &M, const QVVector &s)
00322 {
00323 double acum1 = 0.0, acum2 = 0.0;
00324
00325
00326
00327 for(int i=0;i<M.getRows();i++)
00328 for(int j=0;j<M.getCols();j++)
00329 acum1 += M(i,j)*M(i,j);
00330
00331 for(int i=0;i<s.size();i++)
00332 acum2 += s[i]*s[i];
00333
00334 return qAbs(acum1-acum2);
00335 }
00336
00337
00338 void CholeskyDecomposition_internal(const QVMatrix &M, QVMatrix &L, const TQVCholesky_Method method)
00339 {
00340 Q_ASSERT(M.getCols() == M.getRows());
00341
00342 if(method == GSL_CHOLESKY) {
00343 #ifdef GSL_AVAILABLE
00344 const int n = M.getRows();
00345
00346 gsl_matrix *a = M;
00347
00348 gsl_linalg_cholesky_decomp(a);
00349
00350 L = QVMatrix(n,n);
00351 double *dataL = L.getWriteData();
00352
00353 for (int i = 0; i < n; i++)
00354 for (int j = 0; j < n; j++)
00355 if (j <= i)
00356 dataL[i*n+j] = a->data[i*n+j];
00357 else
00358 dataL[i*n+j] = 0;
00359
00360 gsl_matrix_free(a);
00361 #else
00362 qFatal("Cholesky decomposition: cannot use GSL methods if GSL library is not available.");
00363 #endif
00364 } else if(method == LAPACK_CHOLESKY_DPOTRF) {
00365 #ifdef LAPACK_AVAILABLE
00366 const char *uplo = "L";
00367 int n = M.getRows(), lda = n, res;
00368 L = M;
00369 double *lptr = L.getWriteData();
00370 dpotrf(const_cast<char*>(uplo),&n,lptr,&lda,&res);
00371 for(int i=1;i<n;i++)
00372 for(int j=0;j<i;j++)
00373 L(i,j) = 0.0;
00374 L = L.transpose();
00375 #else
00376 qFatal("Cholesky decomposition: cannot use LAPACK methods if MKL, ATLAS of LAPACK BASE not available.");
00377 #endif
00378 }
00379 L.setType(QVMatrix::LowerTriangular);
00380 }
00381
00382 void CholeskyDecomposition(const QVMatrix &M, QVMatrix &L, const TQVCholesky_Method method)
00383 {
00384 CholeskyDecomposition_internal(M, L, method);
00385 }
00386
00387 void solveFromCholeskyDecomposition(const QVMatrix &L, QVMatrix &X, const QVMatrix &B)
00388 {
00389 QVMatrix X_inter;
00390 L.triangularSolve(B,X_inter,false);
00391 L.triangularSolve(X_inter,X,true);
00392 }
00393
00394 void solveFromCholeskyDecomposition(const QVMatrix &L, QVVector &x, const QVVector &b)
00395 {
00396 QVMatrix X , B = b.toColumnMatrix();
00397
00398 solveFromCholeskyDecomposition(L, X, B);
00399
00400 x = X;
00401 }
00402
00403 void solveByCholeskyDecomposition(const QVMatrix &M, QVMatrix &X, const QVMatrix &B, const TQVCholesky_Method method)
00404 {
00405 QVMatrix L_dummy;
00406
00407 CholeskyDecomposition_internal(M, L_dummy, method);
00408 solveFromCholeskyDecomposition(L_dummy, X, B);
00409
00410 }
00411
00412 void solveByCholeskyDecomposition(const QVMatrix &M, QVVector &x, const QVVector &b, const TQVCholesky_Method method)
00413 {
00414 QVMatrix L_dummy, X, B = b.toColumnMatrix();
00415
00416 CholeskyDecomposition_internal(M, L_dummy, method);
00417 solveFromCholeskyDecomposition(L_dummy, X, B);
00418
00419 x = X;
00420 }
00421
00422 void solveByCholeskyDecomposition(const QVMatrix &M, QVMatrix &X, const QVMatrix &B,
00423 QVMatrix &L, const TQVCholesky_Method method)
00424 {
00425 CholeskyDecomposition_internal(M, L, method);
00426 solveFromCholeskyDecomposition(L, X, B);
00427
00428 }
00429
00430 void solveByCholeskyDecomposition(const QVMatrix &M, QVVector &x, const QVVector &b,
00431 QVMatrix &L, const TQVCholesky_Method method)
00432 {
00433 QVMatrix X, B = b.toColumnMatrix();
00434
00435 CholeskyDecomposition_internal(M, L, method);
00436 solveFromCholeskyDecomposition(L, X, B);
00437
00438 x = X;
00439 }
00440
00441 double CholeskyDecompositionResidual(const QVMatrix &M, const QVMatrix &L)
00442 {
00443 Q_ASSERT(M.getCols() == M.getRows());
00444 Q_ASSERT(L.getCols() == L.getRows());
00445 Q_ASSERT(M.getRows() == L.getRows());
00446
00447 return (L * L.transpose() - M).norm2();
00448 }
00449
00450
00451 void LUDecomposition_internal(const QVMatrix &M, QVMatrix &P, QVMatrix &L, QVMatrix &U, const TQVLU_Method method)
00452 {
00453 int m = M.getRows(), n = M.getCols();
00454
00455 if(method == GSL_LU) {
00456 #ifdef GSL_AVAILABLE
00457 if(m != n)
00458 qFatal("LU decomposition: GSL_LU method works only on square matrices.");
00459
00460 gsl_matrix *a = M;
00461 gsl_permutation *p = gsl_permutation_alloc(m);
00462
00463 int signum;
00464
00465 gsl_linalg_LU_decomp(a, p, &signum);
00466
00467 P = QVMatrix(m, m, 0.0);
00468 L = QVMatrix(m, m);
00469 U = QVMatrix(m, m);
00470
00471 double *dataL = L.getWriteData(),
00472 *dataU = U.getWriteData(),
00473 *dataP = P.getWriteData();
00474
00475 for (int i = 0; i < m; i++)
00476 for (int j = 0; j < m; j++)
00477 if (j > i) {
00478 dataU[i*m + j] = a->data[i*m+j];
00479 dataL[i*m + j] = 0;
00480 } else if (j < i) {
00481 dataU[i*m + j] = 0;
00482 dataL[i*m + j] = a->data[i*m+j];
00483 } else {
00484 dataU[i*m + j] = a->data[i*m+j];
00485 dataL[i*m + j] = 1;
00486 }
00487
00488 for (int j = 0; j < m; j++)
00489 dataP[(p->data[j])*m + j] = 1;
00490
00491 gsl_matrix_free(a);
00492 gsl_permutation_free(p);
00493 #else
00494 qFatal("LU decomposition: cannot use GSL methods if GSL library is not available.");
00495 #endif
00496 } else if(method == LAPACK_DGETRF) {
00497 #ifdef LAPACK_AVAILABLE
00498 int lda = m, res;
00499 QVMatrix MT = M.transpose();
00500 double *mtptr = MT.getWriteData();
00501 QVector<int> ipiv(m);
00502 int *ipivptr = ipiv.data();
00503
00504 dgetrf(&m,&n,mtptr,&lda,ipivptr,&res);
00505
00506 P = QVMatrix(m, m, 0.0);
00507 L = QVMatrix(m, m>n?n:m, 0.0);
00508 U = QVMatrix(m>n?n:m, n, 0.0);
00509 const int lm = L.getRows(), ln = L.getCols(), um = U.getRows(), un=U.getCols();
00510
00511 double *dataL = L.getWriteData(),
00512 *dataU = U.getWriteData();
00513
00514
00515 for(int i = 0; i < lm; i++)
00516 for (int j = 0; j < ln; j++)
00517 if (j < i)
00518 dataL[i*ln + j] = mtptr[j*m+i];
00519 else if (j==i)
00520 dataL[i*ln + j] = 1;
00521
00522
00523 for(int i = 0; i < um; i++)
00524 for (int j = 0; j < un; j++)
00525 if (j > i)
00526 dataU[i*un + j] = mtptr[j*m+i];
00527 else if (j==i)
00528 dataU[i*un + j] = mtptr[j*m+i];
00529
00530
00531 QVector<int> perm(m);
00532 for (int i = 0; i < m; i++)
00533 perm[i] = i;
00534 for (int i = 0; i < m; i++)
00535 if(ipivptr[i] != 0) {
00536 int inter = perm[i];
00537 perm[i] = perm[ipivptr[i]-1];
00538 perm[ipivptr[i]-1] = inter;
00539 }
00540 for (int i = 0; i < m; i++)
00541 P(perm[i],i) = 1;
00542 #else
00543 qFatal("LU decomposition: cannot use LAPACK methods if MKL, ATLAS of LAPACK BASE not available.");
00544 #endif
00545 }
00546
00547 L.setType(QVMatrix::LowerTriangular);
00548 U.setType(QVMatrix::UpperTriangular);
00549 P.setType(QVMatrix::PermutationMatrix);
00550 }
00551
00552 void LUDecomposition(const QVMatrix &M, QVMatrix &P, QVMatrix &L, QVMatrix &U, const TQVLU_Method method)
00553 {
00554 LUDecomposition_internal(M, P, L, U, method);
00555 }
00556
00557 void solveFromLUDecomposition(const QVMatrix &P, const QVMatrix &L, const QVMatrix &U, QVMatrix &X, const QVMatrix &B)
00558 {
00559 const int m = L.getRows(), n = U.getCols();
00560 if(m>n)
00561 qFatal("LU decomposition: cannot be used to solve overdetermined (m>n) systems of equations.");
00562
00563 QVMatrix X_inter, B_inter;
00564 B_inter = P.transpose() * B;
00565 L.triangularSolve(B_inter,X_inter,false,true);
00566
00567
00568 if(m==n) {
00569 U.triangularSolve(X_inter,X,false);
00570 } else if (m < n) {
00571 QVMatrix U_inter = U.getCols(0,m-1);
00572 U_inter.setType(QVMatrix::UpperTriangular);
00573 U_inter.triangularSolve(X_inter,X,false);
00574 X = X & QVMatrix(n-m,X.getCols(),0.0);
00575 }
00576 }
00577
00578 void solveFromLUDecomposition(const QVMatrix &P, const QVMatrix &L, const QVMatrix &U, QVVector &x, const QVVector &b)
00579 {
00580 QVMatrix X , B = b.toColumnMatrix();
00581
00582 solveFromLUDecomposition(P, L, U, X, B);
00583
00584 x = X;
00585 }
00586
00587 void solveByLUDecomposition(const QVMatrix &M, QVMatrix &X, const QVMatrix &B, const TQVLU_Method method)
00588 {
00589 QVMatrix P_dummy, L_dummy, U_dummy;
00590
00591 LUDecomposition_internal(M, P_dummy, L_dummy, U_dummy, method);
00592 solveFromLUDecomposition(P_dummy, L_dummy, U_dummy, X, B);
00593 }
00594
00595 void solveByLUDecomposition(const QVMatrix &M, QVVector &x, const QVVector &b, const TQVLU_Method method)
00596 {
00597 QVMatrix P_dummy, L_dummy, U_dummy, X, B = b.toColumnMatrix();
00598
00599 LUDecomposition_internal(M, P_dummy, L_dummy, U_dummy, method);
00600 solveFromLUDecomposition(P_dummy, L_dummy, U_dummy, X, B);
00601
00602 x = X;
00603 }
00604
00605 void solveByLUDecomposition(const QVMatrix &M, QVMatrix &X, const QVMatrix &B,
00606 QVMatrix &P, QVMatrix &L, QVMatrix &U, const TQVLU_Method method)
00607 {
00608 LUDecomposition_internal(M, P, L, U, method);
00609 solveFromLUDecomposition(P, L, U, X, B);
00610 }
00611
00612
00613 void solveByLUDecomposition(const QVMatrix &M, QVVector &x, const QVVector &b,
00614 QVMatrix &P, QVMatrix &L, QVMatrix &U, const TQVLU_Method method)
00615 {
00616 QVMatrix X, B = b.toColumnMatrix();
00617
00618 LUDecomposition_internal(M, P, L, U, method);
00619 solveFromLUDecomposition(P, L, U, X, B);
00620
00621 x = X;
00622 }
00623
00624 double LUDecompositionResidual(const QVMatrix &M, const QVMatrix &P, const QVMatrix &L, const QVMatrix &U)
00625 {
00626 return (P*L*U - M).norm2();
00627 }
00628
00629
00630 void QRDecomposition_internal(const QVMatrix &M, QVMatrix &Q, QVMatrix &R, const TQVQR_Method method)
00631 {
00632 int m = M.getRows(), n = M.getCols();
00633
00634 if(method == GSL_HOUSEHOLDER_THIN_QR or method == GSL_HOUSEHOLDER_FULL_QR) {
00635 #ifdef GSL_AVAILABLE
00636 const int min = (m<n ? m:n);
00637
00638 gsl_matrix *a = M;
00639 gsl_matrix *q, *r;
00640 if(m<n or method == GSL_HOUSEHOLDER_FULL_QR) {
00641 q = gsl_matrix_alloc(m, m);
00642 r = gsl_matrix_alloc(m, n);
00643 } else {
00644 q = gsl_matrix_alloc(m, n);
00645 r = gsl_matrix_alloc(n, n);
00646 }
00647 gsl_vector *tau = gsl_vector_alloc(min);
00648
00649 gsl_linalg_QR_decomp(a, tau);
00650
00651 if(m<n or method == GSL_HOUSEHOLDER_FULL_QR) {
00652 gsl_linalg_QR_unpack (a, tau, q, r);
00653 } else {
00654 for(int i=0; i<m; i++)
00655 for(int j=0; j<n; j++)
00656 if(i == j)
00657 q->data[i*n+j] = 1.0;
00658 else
00659 q->data[i*n+j] = 0.0;
00660 gsl_vector *v = gsl_vector_alloc(m);
00661 for(int j=0; j<n; j++) {
00662 gsl_matrix_get_col(v, q, j);
00663 gsl_linalg_QR_Qvec(a, tau, v);
00664 gsl_matrix_set_col(q, j, v);
00665 }
00666 gsl_vector_free(v);
00667 for(int i = 0; i < n; i++)
00668 for(int j = 0; j < n; j++)
00669 if(j>=i)
00670 r->data[i*n+j] = gsl_matrix_get(a, i, j);
00671 else
00672 r->data[i*n+j] = 0.0;
00673 }
00674
00675 Q = q;
00676 R = r;
00677
00678 gsl_matrix_free(a);
00679 gsl_matrix_free(q);
00680 gsl_matrix_free(r);
00681 gsl_vector_free(tau);
00682 #else
00683 qFatal("QR decomposition: cannot use GSL methods if GSL library is not available.");
00684 #endif
00685 } else if(method == LAPACK_THIN_DGEQR2 or method == LAPACK_FULL_DGEQR2) {
00686 #ifdef LAPACK_AVAILABLE
00687 int lda = m, res, lwork = -1;
00688 QVMatrix MT = M.transpose();
00689 QVVector tau(qMax(m,n));
00690 double *mtptr = MT.getWriteData(), *workptr, *tauptr = tau.data(), ans;
00691
00692
00693
00694
00695 if(m>=n and method == LAPACK_FULL_DGEQR2)
00696 dgeqrf(&m,&m,mtptr,&lda,tauptr,&ans,&lwork,&res);
00697 else
00698 dgeqrf(&m,&n,mtptr,&lda,tauptr,&ans,&lwork,&res);
00699 lwork = static_cast<int>(ceil(ans));
00700 QVVector work(lwork);
00701 workptr = work.data();
00702
00703
00704 dgeqrf(&m,&n,mtptr,&lda,tauptr,workptr,&lwork,&res);
00705
00706
00707 if(m<n or method == LAPACK_FULL_DGEQR2)
00708 R = MT.transpose();
00709 else
00710 R = MT.transpose().getRows(0,n-1);
00711
00712
00713 for(int i=1;i<R.getRows();i++)
00714 for(int j=0;j<qMin(i,R.getCols());j++)
00715 R(i,j) = 0.0;
00716
00717
00718
00719
00720
00721
00722
00723
00724
00725
00726
00727
00728
00729
00730
00731
00732
00733
00734
00735
00736
00737
00738 if(m<n and method == LAPACK_FULL_DGEQR2) {
00739 dorgqr(&m,&m,&m,mtptr,&lda,tauptr,workptr,&lwork,&res);
00740 MT = MT.getRows(0,m-1);
00741 } else if(m<n and method == LAPACK_THIN_DGEQR2) {
00742 dorgqr(&m,&m,&m,mtptr,&lda,tauptr,workptr,&lwork,&res);
00743 MT = MT.getRows(0,m-1);
00744 } else if(m>=n and method == LAPACK_FULL_DGEQR2) {
00745 MT = MT & QVMatrix(m-n,m,0.0);
00746 mtptr = MT.getWriteData();
00747 dorgqr(&m,&m,&n,mtptr,&lda,tauptr,workptr,&lwork,&res);
00748 } else if(m>=n and method == LAPACK_THIN_DGEQR2) {
00749 dorgqr(&m,&n,&n,mtptr,&lda,tauptr,workptr,&lwork,&res);
00750 }
00751
00752 Q = MT.transpose();
00753 #else
00754 qFatal("QR decomposition: cannot use LAPACK methods if MKL, ATLAS of LAPACK BASE not available.");
00755 #endif
00756 }
00757
00758 R.setType(QVMatrix::UpperTriangular);
00759 }
00760
00761 void QRDecomposition(const QVMatrix &M, QVMatrix &Q, QVMatrix &R, const TQVQR_Method method)
00762 {
00763 QRDecomposition_internal(M, Q, R, method);
00764 }
00765
00766 double QRDecompositionResidual(const QVMatrix &M, const QVMatrix &Q, const QVMatrix &R)
00767 {
00768 return (Q*R - M).norm2() + (Q.transpose()*Q - QVMatrix::identity(Q.getCols())).norm2();
00769 }
00770
00771 void QLDecomposition(const QVMatrix &M, QVMatrix &Q, QVMatrix &L, const TQVQR_Method method)
00772 {
00773 QVMatrix M_inter,Q_inter,R_inter;
00774
00775 M_inter = M.transpose().reversedRows().transpose();
00776
00777 QRDecomposition_internal(M_inter, Q_inter, R_inter, method);
00778
00779 Q = Q_inter.transpose().reversedRows().transpose();
00780 L = R_inter.transpose().reversedRows().reversedCols().transpose();
00781 L.setType(QVMatrix::LowerTriangular);
00782 }
00783
00784 double QLDecompositionResidual(const QVMatrix &M, const QVMatrix &Q, const QVMatrix &L)
00785 {
00786 return (Q*L - M).norm2() + (Q.transpose()*Q - QVMatrix::identity(Q.getCols())).norm2();
00787 }
00788
00789 void RQDecomposition(const QVMatrix &M, QVMatrix &R, QVMatrix &Q, const TQVQR_Method method)
00790 {
00791 QVMatrix M_inter,Q_inter,R_inter;
00792
00793 M_inter = M.reversedRows().transpose();
00794
00795 QRDecomposition_internal(M_inter, Q_inter, R_inter, method);
00796
00797 Q = Q_inter.transpose().reversedRows();
00798 R = R_inter.transpose().reversedRows().reversedCols();
00799 R.setType(QVMatrix::UpperTriangular);
00800 }
00801
00802 double RQDecompositionResidual(const QVMatrix &M, const QVMatrix &R, const QVMatrix &Q)
00803 {
00804 return (R*Q - M).norm2() + (Q*Q.transpose() - QVMatrix::identity(Q.getRows())).norm2();
00805 }
00806
00807 void LQDecomposition(const QVMatrix &M, QVMatrix &L, QVMatrix &Q, const TQVQR_Method method)
00808 {
00809 QVMatrix M_inter,Q_inter,R_inter;
00810
00811 M_inter = M.transpose();
00812
00813 QRDecomposition_internal(M_inter, Q_inter, R_inter, method);
00814
00815 Q = Q_inter.transpose();
00816 L = R_inter.transpose();
00817 L.setType(QVMatrix::LowerTriangular);
00818 }
00819
00820 double LQDecompositionResidual(const QVMatrix &M, const QVMatrix &L, const QVMatrix &Q)
00821 {
00822 return (L*Q - M).norm2() + (Q*Q.transpose() - QVMatrix::identity(Q.getRows())).norm2();
00823 }
00824
00825 void solveFromQRDecomposition(const QVMatrix &Q, const QVMatrix &R, QVMatrix &X, const QVMatrix &B)
00826 {
00827 const int m = Q.getRows(), n = R.getCols();
00828
00829 QVMatrix X_inter = Q.dotProduct(B,true,false);
00830
00831 if(m == n)
00832 R.triangularSolve(X_inter,X,false);
00833 else if(m > n) {
00834 QVMatrix R_inter = R.getRows(0,n-1);
00835 R_inter.setType(QVMatrix::UpperTriangular);
00836 R_inter.triangularSolve(X_inter.getRows(0,n-1),X,false);
00837
00838 } else {
00839 QVMatrix R_inter = R.getCols(0,m-1);
00840 R_inter.setType(QVMatrix::UpperTriangular);
00841 R_inter.triangularSolve(X_inter,X,false);
00842 X = X & QVMatrix(n-m,X.getCols(),0.0);
00843 }
00844 }
00845
00846 void solveFromQRDecomposition(const QVMatrix &Q, const QVMatrix &R, QVVector &x, const QVVector &b)
00847 {
00848 QVMatrix X , B = b.toColumnMatrix();
00849
00850 solveFromQRDecomposition(Q, R, X, B);
00851
00852 x = X;
00853 }
00854
00855 void solveByQRDecomposition(const QVMatrix &M, QVVector &x, const QVVector &b, const TQVQR_Method method)
00856 {
00857 QVMatrix Q_dummy, R_dummy, X, B = b.toColumnMatrix();
00858
00859 QRDecomposition_internal(M, Q_dummy, R_dummy, method);
00860 solveFromQRDecomposition(Q_dummy, R_dummy, X, B);
00861 x = X;
00862 }
00863
00864 void solveByQRDecomposition(const QVMatrix &M, QVMatrix &X, const QVMatrix &B, const TQVQR_Method method)
00865 {
00866 QVMatrix Q_dummy, R_dummy;
00867
00868 QRDecomposition_internal(M, Q_dummy, R_dummy, method);
00869 solveFromQRDecomposition(Q_dummy, R_dummy, X, B);
00870 }
00871
00872 void solveByQRDecomposition(const QVMatrix &M, QVVector &x, const QVVector &b, QVMatrix &Q, QVMatrix &R, const TQVQR_Method method)
00873 {
00874 QVMatrix X, B = b.toColumnMatrix();
00875
00876 QRDecomposition_internal(M, Q, R, method);
00877 solveFromQRDecomposition(Q, R, X, B);
00878
00879 x = X;
00880 }
00881
00882 void solveByQRDecomposition(const QVMatrix &M, QVMatrix &X, const QVMatrix &B, QVMatrix &Q, QVMatrix &R, const TQVQR_Method method)
00883 {
00884 QRDecomposition_internal(M, Q, R, method);
00885 solveFromQRDecomposition(Q, R, X, B);
00886 }
00887
00888
00889 void eigenDecomposition_internal(const QVMatrix &M, QVVector &eigVals, QVMatrix &eigVecs, const TQVEigenDecomposition_Method method, bool only_ev = false)
00890
00891 {
00892
00893 Q_ASSERT(M.getCols() == M.getRows());
00894
00895 if(method == GSL_EIGENSYMM) {
00896 #ifdef GSL_AVAILABLE
00897
00898 const int n = M.getCols();
00899 gsl_matrix *m = M;
00900 gsl_vector *eval = gsl_vector_alloc (n);
00901 gsl_matrix *evec = gsl_matrix_alloc (n, n);
00902
00903 if(only_ev) {
00904 gsl_eigen_symm_workspace *w = gsl_eigen_symm_alloc (n);
00905
00906 gsl_eigen_symm (m, eval, w);
00907
00908 gsl_eigen_symmv_sort (eval, evec, GSL_EIGEN_SORT_VAL_DESC);
00909
00910 gsl_eigen_symm_free (w);
00911 } else {
00912 gsl_eigen_symmv_workspace *w = gsl_eigen_symmv_alloc (n);
00913
00914 gsl_eigen_symmv (m, eval, evec, w);
00915 gsl_eigen_symmv_sort (eval, evec, GSL_EIGEN_SORT_VAL_DESC);
00916
00917 eigVecs = evec;
00918
00919
00920 gsl_eigen_symmv_free (w);
00921 }
00922 eigVals = eval;
00923
00924 gsl_matrix_free (m);
00925 gsl_vector_free (eval);
00926 gsl_matrix_free (evec);
00927 #else
00928 qFatal("EigenDecomposition: cannot use GSL methods if GSL library is not available.");
00929 #endif
00930 } else if(method == LAPACK_DSYEV) {
00931 #ifdef LAPACK_AVAILABLE
00932
00933 int n = M.getCols(), lda = n, lwork = -1, res;
00934 const char *jobz, *uplo = "L";
00935 QVMatrix oldEigVecs;
00936 if(only_ev) {
00937 jobz = "N";
00938 oldEigVecs = eigVecs;
00939 } else {
00940 jobz = "V";
00941 }
00942
00943 eigVecs = M;
00944 eigVals = QVVector(n, 0.0);
00945 double *eigvecsptr = eigVecs.getWriteData(), *w = eigVals.data(), *workptr, ans;
00946
00947
00948 dsyev(const_cast<char*>(jobz),const_cast<char*>(uplo),
00949 &n, eigvecsptr, &lda, w, &ans, &lwork, &res);
00950 lwork = static_cast<int>(ceil(ans));
00951 QVVector work(lwork, 0.0);
00952 workptr = work.data();
00953
00954 dsyev(const_cast<char*>(jobz),const_cast<char*>(uplo),
00955 &n, eigvecsptr, &lda, w, workptr, &lwork, &res);
00956
00957
00958 for(int i=0;i<n/2;i++) {
00959 double inter;
00960 inter = eigVals[i];
00961 eigVals[i] = eigVals[n-i-1];
00962 eigVals[n-i-1] = inter;
00963 for(int j=0;j<n;j++) {
00964 inter = eigVecs(i,j);
00965 eigVecs(i,j) = eigVecs(n-i-1,j);
00966 eigVecs(n-i-1,j) = inter;
00967 }
00968 }
00969
00970
00971 if(only_ev)
00972 eigVecs = oldEigVecs;
00973 else
00974
00975 eigVecs = eigVecs.transpose();
00976 #else
00977 qFatal("EigenDecomposition: cannot use LAPACK methods if LAPACK, ATLAS or MKL libraries are not available.");
00978 #endif
00979 }
00980
00981
00982
00983
00984
00985
00986
00987
00988 }
00989
00990 void eigenDecomposition(const QVMatrix &M, QVVector &lambda, QVMatrix &Q, const TQVEigenDecomposition_Method method)
00991 {
00992 eigenDecomposition_internal(M, lambda, Q, method);
00993 }
00994
00995 double eigenDecompositionResidual(const QVMatrix &M, const QVVector &lambda, const QVMatrix &Q)
00996 {
00997 Q_ASSERT(M.getCols() == M.getRows());
00998 Q_ASSERT(M.getCols() == lambda.size());
00999 Q_ASSERT(Q.getCols() == Q.getRows());
01000 Q_ASSERT(Q.getCols() == lambda.size());
01001
01002 double res1 = (Q*QVMatrix::diagonal(lambda)*Q.transpose()-M).norm2();
01003 double res2 = (Q.transpose()*Q - QVMatrix::identity(Q.getCols())).norm2();
01004
01005 return res1 + res2;
01006 }
01007
01008 void eigenValues(const QVMatrix &M, QVVector &lambda, const TQVEigenValues_Method method)
01009 {
01010 QVMatrix Q_dummy;
01011
01012 Q_ASSERT(M.getCols() == M.getRows());
01013
01014 if(method == GSL_EIGENSYMM_ONLY)
01015 eigenDecomposition_internal(M, lambda, Q_dummy, GSL_EIGENSYMM, true);
01016 else if(method == LAPACK_DSYEV_ONLY)
01017 eigenDecomposition_internal(M, lambda, Q_dummy, LAPACK_DSYEV, true);
01018 }
01019
01020 double eigenValuesResidual(const QVMatrix &M, const QVVector &lambda)
01021 {
01022 double acum = 0.0;
01023
01024 Q_ASSERT(M.getCols() == M.getRows());
01025 Q_ASSERT(M.getCols() == lambda.size());
01026
01027
01028 for(int i=0;i<M.getRows();i++)
01029 acum += M(i,i);
01030 for(int i=0;i<lambda.size();i++)
01031 acum -= lambda[i];
01032
01033 return qAbs(acum);
01034 }
01035
01036
01037 QVMatrix pseudoInverse(const QVMatrix &M, const TQVSVD_Method method, double epsilon)
01038 {
01039 QVMatrix U, V;
01040 QVVector s;
01041
01042 singularValueDecomposition(M, U, s, V, method);
01043
01044
01045
01046 const int m = M.getRows(), n = M.getCols();
01047 QVMatrix result(n,m,0.0);
01048 if(s[0] > 0.0)
01049 for(int i=0;i<s.size();i++)
01050 if(s[i]/s[0] > epsilon)
01051 result += (1/s[i]) * (V.getCol(i).outerProduct(U.getCol(i)));
01052
01053 return result;
01054 }
01055
01056
01057 double determinant(const QVMatrix &M, const TQVLU_Method method)
01058 {
01059 Q_ASSERT(M.getRows() == M.getCols());
01060 const int n = M.getRows();
01061
01062
01063
01064
01065
01066
01067
01068
01069
01070
01071
01072
01073 if(n == 1)
01074 return M(0,0);
01075
01076 double det=1.0;
01077
01078 QVMatrix P,L,U;
01079
01080 LUDecomposition(M,P,L,U,method);
01081
01082 for(int i=0;i<n;i++)
01083 det *= U(i,i);
01084
01085 QVPermutation perm = QVPermutation::fromMatrix(P);
01086
01087 det *= perm.signature();
01088
01089 return det;
01090 }
01091
01092 void solveHomogeneous(const QVMatrix &A, QVector<double> &x, const TQVSVD_Method method)
01093 {
01094 QVMatrix U, V;
01095 QVVector s;
01096 singularValueDecomposition(A, U, s, V, method);
01097
01098 x = V.getCol(V.getCols()-1);
01099 }
01100
01101 double solveResidual(const QVMatrix &M, const QVMatrix &X, const QVMatrix &B)
01102 {
01103 double res = (M*X-B).norm2();
01104
01105 return res;
01106 }
01107
01108 double solveResidual(const QVMatrix &M, const QVVector &x, const QVVector &b)
01109 {
01110 double res = (M*x-b).norm2();
01111
01112 return res;
01113 }
01114
01115 #ifndef DOXYGEN_IGNORE_THIS
01116 double solveConjugateGradient(const QVSparseBlockMatrix &A, QVVector &x, const QVVector &b, const int maxIters, const int minIters, const double minAbsoluteError)
01117 {
01118 QVVector r = b - A.dotProduct(x),
01119 p = r;
01120 double rsold = r.dotProduct(r);
01121
01122 int i;
01123 for (i = 0; i < maxIters; i++)
01124 {
01125 const QVVector Ap = A * p;
01126 const double alpha = rsold / p.dotProduct(Ap);
01127 x = x + alpha * p;
01128 r = r - alpha * Ap;
01129
01130
01131
01132
01133 const double rsnew = r.dotProduct(r);
01134 if ( (rsnew < minAbsoluteError) and (i > minIters) )
01135 break;
01136
01137 p = r + (rsnew / rsold )* p;
01138 rsold = rsnew;
01139 }
01140
01141
01142 return sqrt(rsold);
01143 }
01144
01145
01146 double solvePreconditionedConjugateGradient(const QVSparseBlockMatrix &A, const QVSparseBlockMatrix &invM, QVVector &x, const QVVector &b, const int maxIters, const int minIters, const double minAbsoluteError)
01147 {
01148 QVVector r = b - A.dotProduct(x),
01149 z = invM*r,
01150 p = z;
01151
01152 int i;
01153 for (i = 0; i < maxIters; i++)
01154 {
01155 const double rk_zk = r.dotProduct(z);
01156 Q_ASSERT(rk_zk == z.dotProduct(r));
01157
01158 const double alpha = rk_zk / (p.dotProduct(A*p));
01159 x = x + alpha * p;
01160 r = r - alpha * A*p;
01161 z = invM * r;
01162
01163 const double rsnew = r.dotProduct(r);
01164 if ( (rsnew < minAbsoluteError) and (i > minIters) )
01165 break;
01166
01167
01168
01169
01170
01171 const double beta = r.dotProduct(z) / rk_zk;
01172 p = z + beta * p;
01173 }
01174
01175
01176 return 1.0;
01177 }
01178 #endif
01179
01180 bool blockJacobiPreconditionMatrix(const QVSparseBlockMatrix &A, const QVVector &b, QVSparseBlockMatrix &invM)
01181 {
01182 const int majorRows = A.getMajorRows(), majorCols = A.getMajorCols(),
01183 minorRows = A.getMinorRows(), minorCols = A.getMinorCols();
01184
01185 if ( (majorRows != majorCols) or (minorRows != minorCols) )
01186 return false;
01187
01188 invM = QVSparseBlockMatrix(majorRows, majorRows, minorRows, minorRows);
01189
01190 for(int i = 0; i < majorRows; i++)
01191 invM.setBlock(i, i, A[i][i].inverse());
01192
01193 return true;
01194 }
01195
01196 bool blockJacobiPreconditioning(QVSparseBlockMatrix &A, QVVector &b)
01197 {
01198 const int majorRows = A.getMajorRows(), majorCols = A.getMajorCols(),
01199 minorRows = A.getMinorRows(), minorCols = A.getMinorCols();
01200
01201 if ( (majorRows != majorCols) or (minorRows != minorCols) )
01202 return false;
01203
01204 QVSparseBlockMatrix precond(majorRows, majorRows, minorRows, minorRows);
01205 for(int i = 0; i < majorRows; i++)
01206 precond.setBlock(i, i, A[i][i].inverse());
01207
01208 A = precond * A;
01209 b = precond * b;
01210
01211 return true;
01212 }
01213
01214 int dummy;
01215
01216 double sparseSolve(const QVSparseBlockMatrix &qvspmatrixPre, QVVector &x, const QVVector &bPre,
01217 const bool isSymmetric, const bool isPosDefinite, const TQVSparseSolve_Method method,
01218 const bool start_from_x, const bool iters_or_resid,
01219 const int iters, const double resid, int &final_iter_count)
01220 {
01221 QVSparseBlockMatrix qvspmatrix = qvspmatrixPre;
01222 QVVector b = bPre;
01223
01224 if (b.size() != qvspmatrix.getMajorRows()*qvspmatrix.getMinorRows())
01225 {
01226 std::cout << "[sparseSolve] Error: tried to solve sparse linear system with incompatible sizes of rhs vector and "
01227 << "coefficient matrix." << std::endl
01228 << "\tSparse matrix number of blocks:\t"
01229 << qvspmatrix.getMajorRows() << "x" << qvspmatrix.getMajorCols() << std::endl
01230 << "\tSparse matrix size of each block:\t"
01231 << qvspmatrix.getMinorRows() << "x" << qvspmatrix.getMinorCols() << std::endl
01232 << "\tRight hand side vector size:\t" << b.size() << std::endl;
01233 exit(1);
01234 }
01235
01236 const bool isSquare = (qvspmatrix.getMajorRows() == qvspmatrix.getMajorCols()) and
01237 (qvspmatrix.getMinorRows() == qvspmatrix.getMinorCols());
01238
01239 switch (method)
01240 {
01241 case QVCHOLMOD_DSS:
01242 {
01243 #ifdef QVCHOLMOD
01244 if ( not isSymmetric )
01245 qFatal("[sparseSolve] Cannot use CHOLMOD method to solve a non-symmetric matrix.");
01246
01247 QVVector mutableB = b;
01248 QVCholmodSolver solver(qvspmatrix);
01249 solver.init();
01250 solver.solve(x, mutableB);
01251 #else
01252 qFatal("[sparseSolve] Cannot use CHOLMOD methods if CHOLMOD is not available.");
01253 #endif
01254 break;
01255 }
01256
01257 case QVMKL_DSS:
01258 {
01259 #ifdef MKL_AVAILABLE
01260
01261 x = QVVector(qvspmatrix.getMajorCols()*qvspmatrix.getMinorCols());
01262
01263
01264 MKLPardisoSparseFormat pardisomatrix;
01265 if (isSquare and isSymmetric)
01266 squareSymmetricSparseMatrixToPardisoFormat(qvspmatrix, pardisomatrix);
01267 else
01268 pardisomatrix = MKLPardisoSparseFormat(qvspmatrix,isSymmetric);
01269
01270
01271 _MKL_DSS_HANDLE_t handle;
01272 _INTEGER_t error;
01273 int opt = MKL_DSS_DEFAULTS;
01274 int sym = isSymmetric ? MKL_DSS_SYMMETRIC : MKL_DSS_NON_SYMMETRIC;
01275 int type = isPosDefinite ? MKL_DSS_POSITIVE_DEFINITE : MKL_DSS_INDEFINITE;
01276
01277
01278 error = dss_create(handle,opt);
01279 CHECK_MKL_DSS_ERROR
01280
01281
01282 error = dss_define_structure(handle,sym,pardisomatrix.rowIndex,pardisomatrix.nRows,pardisomatrix.nCols, pardisomatrix.columns,pardisomatrix.nNonZeros);
01283 CHECK_MKL_DSS_ERROR
01284
01285
01286 error = dss_reorder(handle,opt,0);
01287 CHECK_MKL_DSS_ERROR
01288
01289
01290 error = dss_factor_real(handle,type,pardisomatrix.values);
01291 CHECK_MKL_DSS_ERROR
01292
01293
01294 int nrhs = 1;
01295 error = dss_solve_real(handle,opt,b.data(),nrhs,x.data());
01296 CHECK_MKL_DSS_ERROR
01297
01298
01299 error = dss_delete(handle,opt);
01300 CHECK_MKL_DSS_ERROR
01301
01302
01303 return 0.0;
01304 #else
01305 qFatal("[sparseSolve] Cannot use MKL methods if MKL is not available.");
01306 #endif
01307 break;
01308 }
01309
01310 case QVMKL_ISS:
01311 {
01312 #ifdef MKL_AVAILABLE
01313
01314
01315 if(not isSymmetric or not isPosDefinite)
01316 qFatal("[sparseSolve] QVMKL_ISS method only admits a symmetric and positive definite coefficient matrix.");
01317
01318
01319 MKL_INT n=b.size(), rci_request, itercount, i;
01320 MKL_INT ipar[128];
01321 double dpar[128],*tmp;
01322 QVVector temp(4*n);
01323 tmp = temp.data();
01324 char tr='u';
01325
01326
01327 MKLPardisoSparseFormat pardisomatrix;
01328 if (isSquare and isSymmetric)
01329 squareSymmetricSparseMatrixToPardisoFormat(qvspmatrix, pardisomatrix);
01330 else
01331 pardisomatrix = MKLPardisoSparseFormat(qvspmatrix,isSymmetric);
01332
01333
01334
01335 if(start_from_x)
01336 {
01337 if(x.size() != qvspmatrix.getMajorCols()*qvspmatrix.getMinorCols())
01338 {
01339 std::cout << "[sparseSolve] (QVMKL_ISS): error, tried to reuse unknowns x vector with incompatible size with "
01340 << "coefficient matrix." << std::endl
01341 << "\tSparse matrix number of blocks:\t"
01342 << qvspmatrix.getMajorRows() << "x" << qvspmatrix.getMajorCols() << std::endl
01343 << "\tSparse matrix size of each block:\t"
01344 << qvspmatrix.getMinorRows() << "x" << qvspmatrix.getMinorCols() << std::endl
01345 << "\tunknowns x vector size:\t" << x.size() << std::endl;
01346 exit(1);
01347 }
01348 }
01349 else {
01350
01351 x = QVVector(qvspmatrix.getMajorCols()*qvspmatrix.getMinorCols());
01352 for(i=0;i<n;i++) x[i]=1.E0;
01353 }
01354
01355
01356 dcg_init(&n,x.data(),const_cast<double*>(b.data()),&rci_request,ipar,dpar,tmp);
01357 if (rci_request!=0) goto failure;
01358
01359
01360 if(iters_or_resid)
01361 {
01362
01363 if(iters > qvspmatrix.getMajorCols()*qvspmatrix.getMinorCols())
01364 {
01365 std::cout << "[sparseSolve] (QVMKL_ISS): error, iters must be less than or equal to the dimension of the problem.\n"
01366 << "\tSparse matrix number of blocks:\t"
01367 << qvspmatrix.getMajorRows() << "x" << qvspmatrix.getMajorCols() << std::endl
01368 << "\tSparse matrix size of each block: "
01369 << qvspmatrix.getMinorRows() << "x" << qvspmatrix.getMinorCols() << std::endl
01370 << "\tdimension: " << qvspmatrix.getMajorCols()*qvspmatrix.getMinorCols() << std::endl
01371 << "\titers requested: " << iters << std::endl;
01372 exit(1);
01373 }
01374
01375 ipar[4]=iters;
01376 ipar[7]=1;
01377 ipar[8]=0;
01378 ipar[9]=0;
01379 }
01380 else {
01381
01382 ipar[8]=1;
01383 ipar[9]=0;
01384 dpar[0]=0.0;
01385 dpar[1]=resid;
01386 }
01387
01388
01389 dcg_check(&n,x.data(),const_cast<double*>(b.data()),&rci_request,ipar,dpar,tmp);
01390 if (rci_request!=0) goto failure;
01391
01392
01393
01394 rci:
01395 dcg(&n,x.data(),const_cast<double*>(b.data()),&rci_request,ipar,dpar,tmp);
01396
01397 if (rci_request==0) goto getsln;
01398
01399 if (rci_request==1)
01400 {
01401 mkl_dcsrsymv(&tr, &n, pardisomatrix.values, pardisomatrix.rowIndex, pardisomatrix.columns, tmp, &tmp[n]);
01402 goto rci;
01403 }
01404
01405
01406 std::cerr << "[sparseSolve] WARNING: failed to complete requested convergence\n";
01407
01408
01409
01410 getsln:
01411 dcg_get(&n,x.data(),const_cast<double*>(b.data()),&rci_request,ipar,dpar,tmp,&itercount);
01412
01413 final_iter_count = itercount;
01414
01415 goto end;
01416 failure:
01417 std::cout << "RCI CG solver failed to complete computations. Error code " << rci_request << std::endl;
01418 qFatal("[sparseSolve] QVMKL_ISS method failed.");
01419 end:
01420 return dpar[4];
01421 #else
01422 qFatal("[sparseSolve] cannot use MKL methods if MKL not available.");
01423 #endif
01424 break;
01425 }
01426
01427 case QV_BJPCG:
01428 {
01429 if ( not isSymmetric )
01430 qFatal("[sparseSolve] Cannot use block Jacobi preconditioner on a non-symmetric coefficient matrix.");
01431
01432 QVSparseBlockMatrix invM;
01433 if (not blockJacobiPreconditionMatrix(qvspmatrix, b, invM))
01434 return false;
01435
01436 return solvePreconditionedConjugateGradient(qvspmatrix, invM, x, b, iters, 0, resid);
01437 break;
01438 }
01439
01440 case QV_SCG:
01441 {
01442 foreach(int ib, qvspmatrix.keys())
01443 {
01444 const QMap<int, QVMatrix> &majorRow = qvspmatrix[ib];
01445 foreach(int jb, majorRow.keys())
01446 if (ib != jb)
01447 qvspmatrix[jb][ib] = majorRow[jb].transpose();
01448 }
01449
01450 return solveConjugateGradient(qvspmatrix, x, b, iters, 0, resid);
01451 break;
01452 }
01453
01454 case QV_DENSE:
01455 {
01456 solveByCholeskyDecomposition(QVMatrix(qvspmatrix), x, b);
01457 return true;
01458 break;
01459 }
01460
01461 default:
01462 {
01463 return 0.0;
01464 break;
01465 }
01466 }
01467 return -1.0;
01468 }
01469
01470
01471 #ifdef MKL_AVAILABLE
01472 double sparseSolve(const MKLPardisoSparseFormat &pardisomatrix, QVVector &x, const QVVector &b,
01473 const bool isSymmetric, const bool isPosDefinite, const TQVSparseSolve_Method method,
01474 const bool start_from_x, const bool iters_or_resid,
01475 const int iters, const double resid, int &final_iter_count)
01476 {
01477
01478
01479 if(b.size() != pardisomatrix.getMajorRows()*pardisomatrix.getMinorRows()) {
01480 std::cout << "[sparseSolve] Error: tried to solve sparse linear system with incompatible sizes of rhs vector and "
01481 << "coefficient matrix." << std::endl
01482 << "\tSparse matrix number of blocks:\t"
01483 << pardisomatrix.getMajorRows() << "x" << pardisomatrix.getMajorCols() << std::endl
01484 << "\tSparse matrix size of each block:\t"
01485 << pardisomatrix.getMinorRows() << "x" << pardisomatrix.getMinorCols() << std::endl
01486 << "\tRight hand side vector size:\t" << b.size() << std::endl;
01487 exit(1);
01488 }
01489
01490 if(method == QVMKL_DSS) {
01491
01492 x = QVVector(pardisomatrix.getMajorCols()*pardisomatrix.getMinorCols());
01493
01494
01495 _MKL_DSS_HANDLE_t handle;
01496 _INTEGER_t error;
01497 int opt = MKL_DSS_DEFAULTS;
01498 int sym = isSymmetric ? MKL_DSS_SYMMETRIC : MKL_DSS_NON_SYMMETRIC;
01499 int type = isPosDefinite ? MKL_DSS_POSITIVE_DEFINITE : MKL_DSS_INDEFINITE;
01500
01501
01502 error = dss_create(handle,opt);
01503 CHECK_MKL_DSS_ERROR
01504
01505
01506 error = dss_define_structure(handle,sym,pardisomatrix.rowIndex,pardisomatrix.nRows,pardisomatrix.nCols,
01507 pardisomatrix.columns,pardisomatrix.nNonZeros);
01508 CHECK_MKL_DSS_ERROR
01509
01510
01511 error = dss_reorder(handle,opt,0);
01512 CHECK_MKL_DSS_ERROR
01513
01514
01515 error = dss_factor_real(handle,type,pardisomatrix.values);
01516 CHECK_MKL_DSS_ERROR
01517
01518
01519 int nrhs = 1;
01520 error = dss_solve_real(handle,opt,b.data(),nrhs,x.data());
01521 CHECK_MKL_DSS_ERROR
01522
01523
01524 error = dss_delete(handle,opt);
01525 CHECK_MKL_DSS_ERROR
01526
01527
01528 return 0.0;
01529 } else if(method == QVMKL_ISS) {
01530
01531
01532 if(not isSymmetric or not isPosDefinite) {
01533 qFatal("[sparseSolve] QVMKL_ISS method only admits a symmetric and positive definite coefficient matrix.");
01534 }
01535
01536 MKL_INT n=b.size(), rci_request, itercount, i;
01537 MKL_INT ipar[128];
01538 double dpar[128],*tmp;
01539 QVVector temp(4*n);
01540 tmp = temp.data();
01541 char tr='u';
01542
01543
01544 if(start_from_x) {
01545 if(x.size() != pardisomatrix.getMajorCols()*pardisomatrix.getMinorCols()) {
01546 std::cout << "[sparseSolve] (QVMKL_ISS): error, tried to reuse unknowns x vector with incompatible size with "
01547 << "coefficient matrix." << std::endl
01548 << "\tSparse matrix number of blocks:\t"
01549 << pardisomatrix.getMajorRows() << "x" << pardisomatrix.getMajorCols() << std::endl
01550 << "\tSparse matrix size of each block:\t"
01551 << pardisomatrix.getMinorRows() << "x" << pardisomatrix.getMinorCols() << std::endl
01552 << "\tunknowns x vector size:\t" << x.size() << std::endl;
01553 exit(1);
01554 }
01555 } else {
01556
01557 x = QVVector(pardisomatrix.getMajorCols()*pardisomatrix.getMinorCols());
01558 for(i=0;i<n;i++)
01559 x[i]=1.E0;
01560 }
01561
01562
01563 dcg_init(&n,x.data(),const_cast<double*>(b.data()),&rci_request,ipar,dpar,tmp);
01564 if (rci_request!=0) goto failure;
01565
01566
01567 if(iters_or_resid) {
01568
01569 if(iters > pardisomatrix.getMajorCols()*pardisomatrix.getMinorCols()) {
01570 std::cout << "[sparseSolve] (QVMKL_ISS): error, iters must be less than or equal to the dimension of the problem.\n"
01571 << "\tSparse matrix number of blocks:\t"
01572 << pardisomatrix.getMajorRows() << "x" << pardisomatrix.getMajorCols() << std::endl
01573 << "\tSparse matrix size of each block: "
01574 << pardisomatrix.getMinorRows() << "x" << pardisomatrix.getMinorCols() << std::endl
01575 << "\tdimension: " << pardisomatrix.getMajorCols()*pardisomatrix.getMinorCols() << std::endl
01576 << "\titers requested: " << iters << std::endl;
01577 exit(1);
01578 }
01579 ipar[4]=iters;
01580 ipar[7]=1;
01581 ipar[8]=0;
01582 ipar[9]=0;
01583 } else {
01584
01585 ipar[8]=1;
01586 ipar[9]=0;
01587 dpar[0]=0.0;
01588 dpar[1]=resid;
01589 }
01590
01591
01592 dcg_check(&n,x.data(),const_cast<double*>(b.data()),&rci_request,ipar,dpar,tmp);
01593 if (rci_request!=0) goto failure;
01594
01595
01596
01597 rci:
01598 dcg(&n,x.data(),const_cast<double*>(b.data()),&rci_request,ipar,dpar,tmp);
01599
01600 if (rci_request==0) goto getsln;
01601
01602 if (rci_request==1) {
01603 mkl_dcsrsymv(&tr, &n, pardisomatrix.values, pardisomatrix.rowIndex, pardisomatrix.columns, tmp, &tmp[n]);
01604 goto rci;
01605 }
01606
01607
01608 std::cerr << "[sparseSolve] WARNING: failed to complete requested convergence\n";
01609
01610
01611
01612 getsln:
01613 dcg_get(&n,x.data(),const_cast<double*>(b.data()),&rci_request,ipar,dpar,tmp,&itercount);
01614
01615 final_iter_count = itercount;
01616
01617 goto end;
01618 failure:
01619 std::cout << "RCI CG solver failed to complete computations. Error code " << rci_request << std::endl;
01620 qFatal("[sparseSolve] QVMKL_ISS method failed.");
01621 end:
01622 return dpar[4];
01623 }
01624 return 0.0;
01625 }
01626 #endif
01627
01628
01629 bool solveHomogeneous(const QVSparseBlockMatrix &A, QVVector &x, const int maxIterations, const double minRelativeError, const TQVSparseSolve_Method method)
01630 {
01631 #ifdef MKL_AVAILABLE
01632 if(method != QVMKL_DSS) {
01633 std::cerr << "[solveHomogeneous] Warning: this function for sparse matrices only supports QVMKL_DSS method." << std::endl;
01634 }
01635
01636 const QVSparseBlockMatrix AtA = A.transpose() * A;
01637
01638
01639 const int totalCols = AtA.getMajorCols() * AtA.getMinorCols();
01640
01641 if (x.count() != totalCols)
01642 x = QVVector::random(totalCols);
01643
01644
01645
01646 const int opt = MKL_DSS_DEFAULTS,
01647 sym = MKL_DSS_SYMMETRIC,
01648 type = MKL_DSS_POSITIVE_DEFINITE;
01649
01650 MKLPardisoSparseFormat pardisomatrix(AtA, true);
01651
01652
01653 _MKL_DSS_HANDLE_t handle;
01654 _INTEGER_t error = dss_create(handle,opt);
01655 CHECK_MKL_DSS_ERROR;
01656
01657
01658 error = dss_define_structure(handle, sym, pardisomatrix.rowIndex, pardisomatrix.nRows, pardisomatrix.nCols, pardisomatrix.columns, pardisomatrix.nNonZeros);
01659 CHECK_MKL_DSS_ERROR;
01660
01661
01662 error = dss_reorder(handle,opt,0);
01663 CHECK_MKL_DSS_ERROR;
01664
01665
01666 error = dss_factor_real(handle, type, pardisomatrix.values);
01667 CHECK_MKL_DSS_ERROR;
01668
01669
01670 bool success = false;
01671
01672 for(int i = 0; i < maxIterations; i++)
01673 {
01674 QVVector xNew = x;
01675
01676
01677
01678 int nrhs = 1;
01679 error = dss_solve_real(handle, opt, x.data(), nrhs, xNew.data());
01680 CHECK_MKL_DSS_ERROR;
01681
01682 xNew = xNew / xNew.norm2();
01683 const double relativeError = (x-xNew).norm2();
01684
01685 x = xNew;
01686
01687 if (relativeError <= minRelativeError)
01688 {
01689 success = true;
01690 break;
01691 }
01692 }
01693
01694
01695
01696 error = dss_delete(handle,opt);
01697 CHECK_MKL_DSS_ERROR;
01698
01699 return success;
01700
01701 #else
01702 std::cerr << "[solveHomogeneous] Warning: this function requires the MKL library." << std::endl;
01703 #endif
01704 }
01705
01706
01707
01708 void solveLinear(const QVMatrix &A, QVVector &x, const QVVector &b)
01709 {
01710 std::cout << "solveLinear DEPRECATED, use any of the following functions instead, depending on your needs:\n"
01711 "solveBySingularValueDecomposition\n"
01712 "solveByCholeskyDecomposition\n"
01713 "solveByLUDecomposition\n"
01714 "solveByQRDecomposition\n"
01715 "(see QVision documentation for details):\n";
01716
01717 Q_ASSERT(A.getCols() == A.getRows());
01718 Q_ASSERT(A.getCols() == x.size());
01719 Q_ASSERT(A.getCols() == b.size());
01720
01721 #ifdef GSL_AVAILABLE
01722 gsl_matrix *gA = A;
01723 gsl_vector *gB = b;
01724
01725 gsl_linalg_HH_svx(gA, gB);
01726 x = gB;
01727
01728 gsl_matrix_free(gA);
01729 gsl_vector_free(gB);
01730 #else
01731 qFatal("solveLinear: cannot use GSL methods if GSL library is not available.");
01732 #endif
01733 }
01734
01735 void solveLinear(const QVMatrix &A, QVMatrix &X, const QVMatrix &B)
01736 {
01737 std::cout << "solveLinear DEPRECATED, use any of the following functions instead, depending on your needs:\n"
01738 "solveBySingularValueDecomposition\n"
01739 "solveByCholeskyDecomposition\n"
01740 "solveByLUDecomposition\n"
01741 "solveByQRDecomposition\n"
01742 "(see QVision documentation for details):\n";
01743
01744 Q_ASSERT(A.getCols() == A.getRows());
01745 Q_ASSERT(A.getCols() == X.getRows());
01746 Q_ASSERT(A.getCols() == B.getRows());
01747
01748 #ifdef GSL_AVAILABLE
01749 const int dimN = A.getRows();
01750 const int numS = X.getCols();
01751 int signum;
01752
01753 double *dataX = X.getWriteData();
01754 const double *dataB = B.getReadData();
01755
01756 gsl_matrix *a = A;
01757 gsl_permutation *p = gsl_permutation_alloc(dimN);
01758 gsl_vector *b = gsl_vector_alloc(dimN);
01759 gsl_vector *x = gsl_vector_alloc(dimN);
01760
01761 gsl_linalg_LU_decomp(a, p, &signum);
01762
01763 for(int sist = 0; sist < numS; sist++)
01764 {
01765 for(int i = 0; i < dimN; i++)
01766 b->data[i] = dataB[i*numS + sist];
01767
01768 gsl_linalg_LU_solve(a, p, b, x);
01769
01770 for(int i = 0; i < dimN; i++)
01771 dataX[i*numS + sist] = x->data[i];
01772 }
01773
01774 gsl_matrix_free(a);
01775 gsl_permutation_free(p);
01776 gsl_vector_free(b);
01777 gsl_vector_free(x);
01778 #else
01779 qFatal("solveLinear: cannot use GSL methods if GSL library is not available.");
01780 #endif
01781 }
01782
01783 void solveOverDetermined(const QVMatrix &A, QVMatrix &X, const QVMatrix &B)
01784 {
01785 std::cout << "solveOverDetermined DEPRECATED, use any of the following functions instead:\n"
01786 "solveBySingularValueDecomposition\n"
01787 "solveByQRDecomposition\n"
01788 "(see QVision documentation for details):\n";
01789
01790 Q_ASSERT(A.getCols() <= A.getRows());
01791 Q_ASSERT(A.getCols() == X.getRows());
01792 Q_ASSERT(A.getRows() == B.getRows());
01793
01794 #ifdef GSL_AVAILABLE
01795 const int dim1 = A.getRows();
01796 const int dim2 = A.getCols();
01797 const int numS = X.getCols();
01798
01799 double *dataX = X.getWriteData();
01800 const double *dataB = B.getReadData();
01801
01802 gsl_matrix *u = A;
01803 gsl_vector *s = gsl_vector_alloc(dim2);
01804 gsl_matrix *v = gsl_matrix_alloc(dim2, dim2);
01805 gsl_vector *workV = gsl_vector_alloc(dim2);
01806 gsl_matrix *workM = gsl_matrix_alloc(dim2,dim2);
01807 gsl_vector *b = gsl_vector_alloc(dim1);
01808 gsl_vector *x = gsl_vector_alloc(dim2);
01809
01810 gsl_linalg_SV_decomp_mod(u, workM, v, s, workV);
01811
01812 for(int sist = 0; sist < numS; sist++)
01813 {
01814 for(int i = 0; i < dim1; i++)
01815 b->data[i] = dataB[i*numS + sist];
01816
01817 gsl_linalg_SV_solve(u, v, s, b, x);
01818
01819 for(int i = 0; i < dim2; i++)
01820 dataX[i*numS + sist] = x->data[i];
01821 }
01822
01823 gsl_matrix_free(u);
01824 gsl_vector_free(s);
01825 gsl_matrix_free(v);
01826 gsl_vector_free(workV);
01827 gsl_matrix_free(workM);
01828 gsl_vector_free(b);
01829 gsl_vector_free(x);
01830 #else
01831 qFatal("solveLinear: cannot use GSL methods if GSL library is not available.");
01832 #endif
01833 }
01834
01835 void solveHomogeneousLinear(const QVMatrix &A, QVector<double> &x)
01836 {
01837 std::cout << "solveHomogeneousLinear DEPRECATED, use solveHomogeneous function instead (see QVision documentation)."
01838 << std::endl;
01839
01840 QVMatrix U, V, S;
01841 SingularValueDecomposition(A, U, S, V);
01842
01843
01844 x = V.getCol(V.getCols()-1);
01845 }
01846
01847
01848 double homogLineFromMoments(double x,double y,double xx,double xy,double yy,double &a,double &b,double &c)
01849 {
01850 double a11=xx-x*x, a12=xy-x*y, a22=yy-y*y, temp, e1, e2, angle, cosangle, sinangle;
01851
01852
01853 temp = sqrt(a11*a11+4*a12*a12-2*a11*a22+a22*a22);
01854 e1 = a11+a22-temp;
01855 e2 = a11+a22+temp;
01856 if(e2<EPSILON)
01857 {
01858
01859
01860
01861 return 1.0;
01862 }
01863 if(fabs(e1)/e2 > 0.9)
01864 {
01865
01866
01867 return fabs(e1)/e2;
01868 }
01869
01870 if(fabs(a12)>EPSILON)
01871 angle = atan2(2*a12,a11-a22+temp);
01872 else
01873 if(a11>=a22)
01874 angle = 0;
01875 else
01876 angle = PI/2;
01877 if(angle < 0)
01878 angle += PI;
01879 cosangle = cos(angle); sinangle = sin(angle);
01880
01881
01882
01883 a = -sinangle; b = cosangle; c = x*sinangle-y*cosangle;
01884 return fabs(e1)/e2;
01885 }
01886
01887 QVVector regressionLine(const QVMatrix &points)
01888 {
01890 double x = 0, y = 0, xx = 0, yy = 0, xy = 0;
01891 const int rows = points.getRows();
01892
01893 for (int i = 0; i < rows; i++)
01894 {
01895 double xActual = points(i,0), yActual = points(i,1);
01896 x += xActual;
01897 y += yActual;
01898 xx += xActual*xActual;
01899 xy += xActual*yActual;
01900 yy += yActual*yActual;
01901 }
01902
01903 x /= rows; y /= rows; xx /= rows; xy /= rows; yy /= rows;
01904
01905 double a, b, c;
01906 if (homogLineFromMoments(x,y,xx,xy,yy,a,b,c))
01907 {
01908 QVVector result(3);
01909 result[0] = a; result[1] = b; result[2] = c;
01910 return result;
01911 }
01912 else
01913 return QVVector();
01914 }
01915
01916
01917
01918 void cold_start_mkl_initialization(const int size)
01919 {
01920
01921 #define COLD_START_MATRIX_SIZE size
01922 QVMatrix A = QVMatrix::random(COLD_START_MATRIX_SIZE,COLD_START_MATRIX_SIZE);
01923 QVSparseBlockMatrix sparseM(1, 1, COLD_START_MATRIX_SIZE, COLD_START_MATRIX_SIZE);
01924 sparseM.setBlock(0, 0, A.transpose() * A);
01925 QVVector xInc(COLD_START_MATRIX_SIZE, 0.0), b = QVVector::random(COLD_START_MATRIX_SIZE);
01926 sparseSolve(sparseM, xInc, b, true, true, QVMKL_DSS, true, true, 10);
01927 }
01928
01929
01930
01931
01932 void SingularValueDecomposition(const QVMatrix &M, QVMatrix &U, QVVector &s, QVMatrix &V, const TQVSVD_Method method)
01933 {
01934 std::cout << "WARNING: 'SingularValueDecomposition' deprecated. Use 'singularValueDecomposition' instead." << std::endl;
01935 singularValueDecomposition(M, U, s, V, method);
01936 }
01937
01938 void SolveFromSingularValueDecomposition(const QVMatrix &U, const QVVector &s, const QVMatrix &V, QVMatrix &X, const QVMatrix &B)
01939 {
01940 std::cout << "WARNING: 'SolveFromSingularValueDecomposition' deprecated. Use 'solveFromSingularValueDecomposition' instead." << std::endl;
01941 solveFromSingularValueDecomposition(U, s, V, X, B);
01942 }
01943
01944 void SolveFromSingularValueDecomposition(const QVMatrix &U, const QVVector &s, const QVMatrix &V, QVVector &x, const QVVector &b)
01945 {
01946 std::cout << "WARNING: 'SolveFromSingularValueDecomposition' deprecated. Use 'solveFromSingularValueDecomposition' instead." << std::endl;
01947 solveFromSingularValueDecomposition(U, s, V, x, b);
01948 }
01949
01950 void SolveBySingularValueDecomposition(const QVMatrix &M, QVMatrix &X, const QVMatrix &B, const TQVSVD_Method method )
01951 {
01952 std::cout << "WARNING: 'SolveBySingularValueDecomposition' deprecated. Use 'solveBySingularValueDecomposition' instead." << std::endl;
01953 solveBySingularValueDecomposition(M, X, B, method);
01954 }
01955
01956 void SolveBySingularValueDecomposition(const QVMatrix &M, QVVector &x, const QVVector &b, const TQVSVD_Method method )
01957 {
01958 std::cout << "WARNING: 'SolveBySingularValueDecomposition' deprecated. Use 'solveBySingularValueDecomposition' instead." << std::endl;
01959 solveBySingularValueDecomposition(M, x, b, method);
01960 }
01961
01962 void SolveBySingularValueDecomposition(const QVMatrix &M, QVMatrix &X, const QVMatrix &B, QVMatrix &U, QVVector &s, QVMatrix &V, const TQVSVD_Method method)
01963 {
01964 std::cout << "WARNING: 'SolveBySingularValueDecomposition' deprecated. Use 'solveBySingularValueDecomposition' instead." << std::endl;
01965 solveBySingularValueDecomposition(M, X, B, U, s, V, method);
01966 }
01967
01968 void SolveBySingularValueDecomposition(const QVMatrix &M, QVVector &x, const QVVector &b, QVMatrix &U, QVVector &s, QVMatrix &V, const TQVSVD_Method method)
01969 {
01970 std::cout << "WARNING: 'SolveBySingularValueDecomposition' deprecated. Use 'solveBySingularValueDecomposition' instead." << std::endl;
01971 solveBySingularValueDecomposition(M, x, b, U, s, V, method);
01972 }
01973
01974 double SingularValueDecompositionResidual(const QVMatrix &M, const QVMatrix &U, const QVVector &s, const QVMatrix &V)
01975 {
01976 std::cout << "WARNING: 'SingularValueDecompositionResidual' deprecated. Use 'singularValueDecompositionResidual' instead." << std::endl;
01977 return singularValueDecompositionResidual(M, U, s, V);
01978 }
01979
01980 void SingularValues(const QVMatrix &M, QVVector &s, const TQVSV_Method method)
01981 {
01982 std::cout << "WARNING: 'SingularValues' deprecated. Use 'singularValues' instead." << std::endl;
01983 singularValues(M, s, method);
01984 }
01985
01986 double SingularValuesResidual(const QVMatrix &M, const QVVector &s)
01987 {
01988 std::cout << "WARNING: 'SingularValuesResidual' deprecated. Use 'singularValuesResidual' instead." << std::endl;
01989 return singularValuesResidual(M, s);
01990 }
01991
01992 void SolveFromCholeskyDecomposition(const QVMatrix &L, QVMatrix &X, const QVMatrix &B)
01993 {
01994 std::cout << "WARNING: 'SolveFromCholeskyDecomposition' deprecated. Use 'solveFromCholeskyDecomposition' instead." << std::endl;
01995 solveFromCholeskyDecomposition(L, X, B);
01996 }
01997
01998 void SolveFromCholeskyDecomposition(const QVMatrix &L, QVVector &x, const QVVector &b)
01999 {
02000 std::cout << "WARNING: 'SolveFromCholeskyDecomposition' deprecated. Use 'solveFromCholeskyDecomposition' instead." << std::endl;
02001 solveFromCholeskyDecomposition(L, x, b);
02002 }
02003
02004 void SolveByCholeskyDecomposition(const QVMatrix &M, QVMatrix &X, const QVMatrix &B, const TQVCholesky_Method method)
02005 {
02006 std::cout << "WARNING: 'SolveByCholeskyDecomposition' deprecated. Use 'solveByCholeskyDecomposition' instead." << std::endl;
02007 solveByCholeskyDecomposition(M, X, B, method);
02008 }
02009
02010 void SolveByCholeskyDecomposition(const QVMatrix &M, QVVector &x, const QVVector &b, const TQVCholesky_Method method)
02011 {
02012 std::cout << "WARNING: 'SolveByCholeskyDecomposition' deprecated. Use 'solveByCholeskyDecomposition' instead." << std::endl;
02013 solveByCholeskyDecomposition(M, x, b, method);
02014 }
02015
02016 void SolveByCholeskyDecomposition(const QVMatrix &M, QVMatrix &X, const QVMatrix &B, QVMatrix &L, const TQVCholesky_Method method)
02017 {
02018 std::cout << "WARNING: 'SolveByCholeskyDecomposition' deprecated. Use 'solveByCholeskyDecomposition' instead." << std::endl;
02019 solveByCholeskyDecomposition(M, X, B, L, method);
02020 }
02021
02022 void SolveByCholeskyDecomposition(const QVMatrix &M, QVVector &x, const QVVector &b, QVMatrix &L, const TQVCholesky_Method method)
02023 {
02024 std::cout << "WARNING: 'SolveByCholeskyDecomposition' deprecated. Use 'solveByCholeskyDecomposition' instead." << std::endl;
02025 solveByCholeskyDecomposition(M, x, b, L, method);
02026 }
02027
02028 void SolveFromLUDecomposition(const QVMatrix &P, const QVMatrix &L, const QVMatrix &U, QVMatrix &X, const QVMatrix &B)
02029 {
02030 std::cout << "WARNING: 'SolveFromLUDecomposition' deprecated. Use 'solveFromLUDecomposition' instead." << std::endl;
02031 solveFromLUDecomposition(P, L, U, X, B);
02032 }
02033
02034 void SolveFromLUDecomposition(const QVMatrix &P, const QVMatrix &L, const QVMatrix &U, QVVector &x, const QVVector &b)
02035 {
02036 std::cout << "WARNING: 'SolveFromLUDecomposition' deprecated. Use 'solveFromLUDecomposition' instead." << std::endl;
02037 solveFromLUDecomposition(P, L, U, x, b);
02038 }
02039
02040 void SolveByLUDecomposition(const QVMatrix &M, QVMatrix &X, const QVMatrix &B, const TQVLU_Method method)
02041 {
02042 std::cout << "WARNING: 'SolveByLUDecomposition' deprecated. Use 'solveByLUDecomposition' instead." << std::endl;
02043 solveByLUDecomposition(M, X, B, method);
02044 }
02045
02046 void SolveByLUDecomposition(const QVMatrix &M, QVVector &x, const QVVector &b, const TQVLU_Method method)
02047 {
02048 std::cout << "WARNING: 'SolveByLUDecomposition' deprecated. Use 'solveByLUDecomposition' instead." << std::endl;
02049 solveByLUDecomposition(M, x, b, method);
02050 }
02051
02052 void SolveByLUDecomposition(const QVMatrix &M, QVMatrix &X, const QVMatrix &B, QVMatrix &P, QVMatrix &L, QVMatrix &U, const TQVLU_Method method)
02053 {
02054 std::cout << "WARNING: 'SolveByLUDecomposition' deprecated. Use 'solveByLUDecomposition' instead." << std::endl;
02055 solveByLUDecomposition(M, X, B, P, L, U, method);
02056 }
02057
02058 void SolveByLUDecomposition(const QVMatrix &M, QVVector &x, const QVVector &b,QVMatrix &P, QVMatrix &L, QVMatrix &U, const TQVLU_Method method)
02059 {
02060 std::cout << "WARNING: 'SolveByLUDecomposition' deprecated. Use 'solveByLUDecomposition' instead." << std::endl;
02061 solveByLUDecomposition(M, x, b, P, L, U, method);
02062 }
02063
02064 void SolveFromQRDecomposition(const QVMatrix &Q, const QVMatrix &R, QVMatrix &X, const QVMatrix &B)
02065 {
02066 std::cout << "WARNING: 'SolveFromQRDecomposition' deprecated. Use 'solveFromQRDecomposition' instead." << std::endl;
02067 solveFromQRDecomposition(Q, R, X, B);
02068 }
02069
02070 void SolveFromQRDecomposition(const QVMatrix &Q, const QVMatrix &R, QVVector &x, const QVVector &b)
02071 {
02072 std::cout << "WARNING: 'SolveFromQRDecomposition' deprecated. Use 'solveFromQRDecomposition' instead." << std::endl;
02073 solveFromQRDecomposition(Q, R, x, b);
02074 }
02075
02076 void SolveByQRDecomposition(const QVMatrix &M, QVMatrix &X, const QVMatrix &B, const TQVQR_Method method)
02077 {
02078 std::cout << "WARNING: 'SolveByQRDecomposition' deprecated. Use 'solveByQRDecomposition' instead." << std::endl;
02079 solveByQRDecomposition(M, X, B, method);
02080 }
02081
02082 void SolveByQRDecomposition(const QVMatrix &M, QVVector &x, const QVVector &b, const TQVQR_Method method)
02083 {
02084 std::cout << "WARNING: 'SolveByQRDecomposition' deprecated. Use 'solveByQRDecomposition' instead." << std::endl;
02085 solveByQRDecomposition(M, x, b, method);
02086 }
02087
02088 void SolveByQRDecomposition(const QVMatrix &M, QVMatrix &X, const QVMatrix &B, QVMatrix &Q, QVMatrix &R, const TQVQR_Method method)
02089 {
02090 std::cout << "WARNING: 'SolveByQRDecomposition' deprecated. Use 'solveByQRDecomposition' instead." << std::endl;
02091 solveByQRDecomposition(M, X, B, Q, R, method);
02092 }
02093
02094 void SolveByQRDecomposition(const QVMatrix &M, QVVector &x, const QVVector &b, QVMatrix &Q, QVMatrix &R, const TQVQR_Method method)
02095 {
02096 std::cout << "WARNING: 'SolveByQRDecomposition' deprecated. Use 'solveByQRDecomposition' instead." << std::endl;
02097 solveByQRDecomposition(M, x, b, Q, R, method);
02098 }
02099
02100 void EigenDecomposition(const QVMatrix &M, QVVector &lambda, QVMatrix &Q, const TQVEigenDecomposition_Method method)
02101 {
02102 std::cout << "WARNING: 'EigenDecomposition' deprecated. Use 'eigenDecomposition' instead." << std::endl;
02103 eigenDecomposition(M, lambda, Q, method);
02104 }
02105
02106 double EigenDecompositionResidual(const QVMatrix &M, const QVVector &lambda, const QVMatrix &Q)
02107 {
02108 std::cout << "WARNING: 'EigenDecompositionResidual' deprecated. Use 'eigenDecompositionResidual' instead." << std::endl;
02109 return eigenDecompositionResidual(M, lambda, Q);
02110 }
02111
02112 void EigenValues(const QVMatrix &M, QVVector &lambda, const TQVEigenValues_Method method)
02113 {
02114 std::cout << "WARNING: 'EigenValues' deprecated. Use 'eigenValues' instead." << std::endl;
02115 eigenValues(M, lambda, method);
02116 }
02117
02118 double EigenValuesResidual(const QVMatrix &M, const QVVector &lambda)
02119 {
02120 std::cout << "WARNING: 'EigenValuesResidual' deprecated. Use 'eigenValuesResidual' instead." << std::endl;
02121 return eigenValuesResidual(M, lambda);
02122 }
02123
02124 void SolveHomogeneous(const QVMatrix &A, QVector<double> &x, const TQVSVD_Method method)
02125 {
02126 std::cout << "WARNING: 'SolveHomogeneous' deprecated. Use 'solveHomogeneous' instead." << std::endl;
02127 solveHomogeneous(A, x, method);
02128 }
02129
02130 double SolveResidual(const QVMatrix &M, const QVMatrix &X, const QVMatrix &B)
02131 {
02132 std::cout << "WARNING: 'SolveResidual' deprecated. Use 'solveResidual' instead." << std::endl;
02133 return solveResidual(M, X, B);
02134 }
02135
02136 double SolveResidual(const QVMatrix &M, const QVVector &x, const QVVector &b)
02137 {
02138 std::cout << "WARNING: 'SolveResidual' deprecated. Use 'solveResidual' instead." << std::endl;
02139 return solveResidual(M, x, b);
02140 }
02141
02142 double SparseSolve( const QVSparseBlockMatrix M, QVVector &x, const QVVector b, const bool isSymmetric, const bool isPosDefinite, const TQVSparseSolve_Method method,
02143 const bool start_from_x, const bool iters_or_resid, const int iters, const double resid, int &final_iter_count)
02144 {
02145 std::cout << "WARNING: 'SparseSolve' deprecated. Use 'sparseSolve' instead." << std::endl;
02146 return sparseSolve(M, x, b, isSymmetric, isPosDefinite, method, start_from_x, iters_or_resid, iters, resid, final_iter_count);
02147 }
02148
02149 void SolveHomogeneous(const QVSparseBlockMatrix &A, QVVector &x, const int maxIterations, const double minRelativeError, const TQVSparseSolve_Method method)
02150 {
02151 std::cout << "WARNING: 'SolveHomogeneous' deprecated. Use 'solveHomogeneous' instead." << std::endl;
02152 solveHomogeneous(A, x, maxIterations, minRelativeError, method);
02153 }
02154
02155 #ifdef GSL_AVAILABLE
02156
02157 void solveHomogeneousEig(const QVMatrix &M, QVVector &result)
02158 {
02159 QVMatrix A = M.dotProduct(M,true,false);
02160 const int n = A.getCols();
02161 gsl_matrix m;
02162 m.size1 = m.size2 = m.tda = n;
02163 m.data = A.getWriteData();
02164 m.block = NULL;
02165 m.owner = 1;
02166
02167 gsl_vector *eval = gsl_vector_alloc (n);
02168 gsl_matrix *evec = gsl_matrix_alloc (n, n);
02169 gsl_eigen_symmv_workspace *w = gsl_eigen_symmv_alloc (n);
02170 gsl_eigen_symmv (&m, eval, evec, w);
02171 gsl_eigen_symmv_sort (eval, evec, GSL_EIGEN_SORT_VAL_DESC);
02172 gsl_eigen_symmv_free (w);
02173 gsl_vector_free (eval);
02174
02175 result = QVVector(n);
02176 for(int i = 0; i < n; i++)
02177 result[i] = gsl_matrix_get(evec,i,n-1);
02178
02179 gsl_matrix_free (evec);
02180 }
02181 #endif
02182