00001
00002
00003
00004
00005
00006
00007
00008
00009
00010
00011
00012
00013
00014
00015
00016
00017
00018
00019
00020 #ifndef SELDON_FILE_SPARSE_CHOLESKY_FACTORISATION_CXX
00021
00022 #include "Ordering.cxx"
00023 #include "SparseCholeskyFactorisation.hxx"
00024
00025 namespace Seldon
00026 {
00027
00029
00034 template<class T, class Prop, class Allocator>
00035 void GetCholesky(Matrix<T, Prop, ArrayRowSymSparse, Allocator>& A,
00036 int print_level = 0)
00037 {
00038 int n = A.GetN();
00039 T t, s, fact;
00040 int j_col, jrow, index_lu, jpos;
00041 Vector<T> Row_Val(n);
00042 IVect Index(n), Row_Ind(n);
00043 Row_Val.Fill(0);
00044 Row_Ind.Fill(-1);
00045
00046 Index.Fill(-1);
00047
00048
00049 Matrix<T, General, ArrayRowSparse, Allocator> B;
00050 Copy(A, B);
00051
00052
00053 A.Clear();
00054 A.Reallocate(n, n);
00055
00056
00057 int new_percent = 0, old_percent = 0;
00058 for (int i_row = 0; i_row < n; i_row++)
00059 {
00060
00061 if (print_level > 0)
00062 {
00063 new_percent = int(double(i_row) / double(n-1) * 78.);
00064 for (int percent = old_percent; percent < new_percent; percent++)
00065 {
00066 cout << "#";
00067 cout.flush();
00068 }
00069 old_percent = new_percent;
00070 }
00071
00072 int size_row = B.GetRowSize(i_row);
00073
00074
00075 int length_lower = 0, length_upper = 1;
00076 Row_Ind(i_row) = i_row;
00077 Row_Val(i_row) = 0.0;
00078 Index(i_row) = i_row;
00079
00080 for (int j = 0; j < size_row; j++)
00081 {
00082 int k = B.Index(i_row, j);
00083 t = B.Value(i_row, j);
00084 if (k < i_row)
00085 {
00086 Row_Ind(length_lower) = k;
00087 Row_Val(length_lower) = t;
00088 Index(k) = length_lower;
00089 length_lower++;
00090 }
00091 else if (k == i_row)
00092 Row_Val(i_row) = t;
00093 else
00094 {
00095 jpos = i_row + length_upper;
00096 Row_Ind(jpos) = k;
00097 Row_Val(jpos) = t;
00098 Index(k) = jpos;
00099 length_upper++;
00100 }
00101 }
00102
00103 B.ClearRow(i_row);
00104
00105 j_col = 0;
00106 int length = 0;
00107
00108
00109 while (j_col < length_lower)
00110 {
00111 jrow = Row_Ind(j_col);
00112
00113
00114 int k = j_col;
00115 for (int j = (j_col+1) ; j < length_lower; j++)
00116 {
00117 if (Row_Ind(j) < jrow)
00118 {
00119 jrow = Row_Ind(j);
00120 k = j;
00121 }
00122 }
00123
00124
00125 if (k != j_col)
00126 {
00127
00128 int j = Row_Ind(j_col);
00129 Row_Ind(j_col) = Row_Ind(k);
00130 Row_Ind(k) = j;
00131
00132 Index(jrow) = j_col;
00133 Index(j) = k;
00134
00135 s = Row_Val(j_col);
00136 Row_Val(j_col) = Row_Val(k);
00137 Row_Val(k) = s;
00138 }
00139
00140
00141 Index(jrow) = -1;
00142 fact = Row_Val(j_col) * A.Value(jrow, 0);
00143
00144
00145 for (int k = 1; k < A.GetRowSize(jrow); k++)
00146 {
00147 s = fact * A.Value(jrow, k);
00148 int j = A.Index(jrow, k);
00149
00150 jpos = Index(j);
00151 if (j >= i_row)
00152 {
00153
00154 if (jpos == -1)
00155 {
00156
00157 int i = i_row + length_upper;
00158 Row_Ind(i) = j;
00159 Index(j) = i;
00160 Row_Val(i) = -s;
00161 length_upper++;
00162 }
00163 else
00164 {
00165
00166 Row_Val(jpos) -= s;
00167 }
00168 }
00169 else
00170 {
00171
00172 if (jpos == -1)
00173 {
00174
00175 Row_Ind(length_lower) = j;
00176 Index(j) = length_lower;
00177 Row_Val(length_lower) = -s;
00178 length_lower++;
00179 }
00180 else
00181 {
00182
00183 Row_Val(jpos) -= s;
00184 }
00185 }
00186 }
00187
00188
00189
00190
00191 Row_Val(length) = fact;
00192 Row_Ind(length) = jrow;
00193 ++length;
00194 j_col++;
00195 }
00196
00197 for (int k = 0; k < length_upper; k++)
00198 Index(Row_Ind(i_row + k)) = -1;
00199
00200
00201 size_row = length_upper;
00202 A.ReallocateRow(i_row, length_upper);
00203
00204
00205 if (Row_Val(i_row) <= 0)
00206 {
00207 cout << "Error during Cholesky factorization " << endl;
00208 cout << "Matrix must be definite positive " << endl;
00209 cout << "but diagonal element of row " << i_row
00210 << "is equal to " << Row_Val(i_row) << endl;
00211
00212 #ifdef SELDON_WITH_ABORT
00213 abort();
00214 #endif
00215 }
00216
00217 A.Value(i_row, 0) = 1.0 / Row_Val(i_row);
00218 A.Index(i_row, 0) = i_row;
00219 index_lu = 1;
00220
00221
00222 for (int k = i_row + 1; k < i_row + length_upper; k++)
00223 {
00224 A.Index(i_row, index_lu) = Row_Ind(k);
00225 A.Value(i_row, index_lu) = Row_Val(k);
00226 index_lu++;
00227 }
00228 }
00229
00230 if (print_level > 0)
00231 {
00232 cout << endl;
00233 cout << "The matrix takes " <<
00234 int((A.GetDataSize() * (sizeof(T)+4)) / (1024*1024)) << " MB" << endl;
00235 }
00236
00237
00238 for (int i = 0; i < n; i++)
00239 {
00240 A.Value(i, 0) = sqrt(A.Value(i,0));
00241
00242 for (int k = 1; k < A.GetRowSize(i); k++)
00243 A.Value(i, k) *= A.Value(i, 0);
00244
00245 A.Value(i, 0) = 1.0 / A.Value(i, 0);
00246 }
00247 }
00248
00249
00251
00256 template<class classTrans,
00257 class T0, class T1, class Prop, class Storage,
00258 class Allocator1, class Allocator2>
00259 void SolveCholesky(const classTrans& TransA,
00260 const Matrix<T0, Prop, ArrayRowSymSparse, Allocator1>& A,
00261 Vector<T1, Storage, Allocator2>& x)
00262 {
00263 int n = A.GetM();
00264 if (n <= 0)
00265 return;
00266
00267 if (TransA.Trans())
00268 {
00269
00270 int j;
00271 for (int i = n - 1; i >= 0; i--)
00272 {
00273 T1 val = x(i);
00274 for (int k = 1; k < A.GetRowSize(i) ; k++)
00275 {
00276 j = A.Index(i, k);
00277 val -= A.Value(i, k) * x(j);
00278 }
00279
00280 x(i) = val / A.Value(i, 0);
00281 }
00282 }
00283 else
00284 {
00285
00286 int j;
00287 for (int i = 0; i < n; i++)
00288 {
00289 x(i) /= A.Value(i, 0);
00290 for (int k = 1; k < A.GetRowSize(i) ; k++)
00291 {
00292 j = A.Index(i, k);
00293 x(j) -= A.Value(i, k) * x(i);
00294 }
00295 }
00296 }
00297 }
00298
00299
00301
00306 template<class classTrans,
00307 class T, class Prop, class Allocator>
00308 void SolveCholesky(const classTrans& TransA,
00309 const Matrix<T, Prop, RowSymSparse>& A,
00310 Vector<T, VectFull, Allocator>& X)
00311 {
00312 int n = A.GetM();
00313 if (n <= 0)
00314 return;
00315
00316 int* ind = A.GetInd();
00317 int* ptr = A.GetPtr();
00318 T* data = A.GetData();
00319 T val = 0;
00320
00321 if (TransA.Trans())
00322
00323 for (int i = n - 1; i >= 0; i--)
00324 {
00325 val = X(i);
00326 for (int j = ptr[i] + 1; j < ptr[i+1]; j++)
00327 val -= data[j] * X(ind[j]);
00328
00329 X(i) = val / data[ptr[i]];
00330 }
00331 else
00332
00333 for (int i = 0; i < n; i++)
00334 {
00335 X(i) /= data[ptr[i]];
00336 for (int j = ptr[i] + 1; j < ptr[i+1]; j++)
00337 X(ind[j]) -= data[j] * X(i);
00338 }
00339 }
00340
00341
00343
00348 template<class classTrans,
00349 class T0, class T1, class Prop, class Storage,
00350 class Allocator1, class Allocator2>
00351 void MltCholesky(const classTrans& TransA,
00352 const Matrix<T0, Prop, ArrayRowSymSparse, Allocator1>& A,
00353 Vector<T1, Storage, Allocator2>& x)
00354 {
00355 int n = A.GetM();
00356 if (n <= 0)
00357 return;
00358
00359 if (TransA.Trans())
00360 {
00361
00362 int j;
00363 for (int i = 0; i < n; i++)
00364 {
00365 T1 val = x(i) * A.Value(i, 0);
00366 for (int k = 1; k < A.GetRowSize(i) ; k++)
00367 {
00368 j = A.Index(i, k);
00369 val += A.Value(i, k)*x(j);
00370 }
00371
00372 x(i) = val;
00373 }
00374 }
00375 else
00376 {
00377
00378 int j;
00379 for (int i = n - 1; i >= 0; i--)
00380 {
00381 for (int k = 1; k < A.GetRowSize(i) ; k++)
00382 {
00383 j = A.Index(i, k);
00384 x(j) += A.Value(i, k)*x(i);
00385 }
00386
00387 x(i) *= A.Value(i, 0);
00388 }
00389 }
00390 }
00391
00392
00394
00399 template<class classTrans,
00400 class T0, class T1, class Prop, class Storage,
00401 class Allocator1, class Allocator2>
00402 void MltCholesky(const classTrans& TransA,
00403 const Matrix<T0, Prop, RowSymSparse, Allocator1>& A,
00404 Vector<T1, Storage, Allocator2>& x)
00405 {
00406 int n = A.GetM();
00407 if (n <= 0)
00408 return;
00409
00410 int* ind = A.GetInd();
00411 int* ptr = A.GetPtr();
00412 T1* data = A.GetData();
00413 T1 val = 0;
00414
00415 if (TransA.Trans())
00416
00417 for (int i = 0; i < n; i++)
00418 {
00419 val = x(i) * data[ptr[i]];
00420 for (int k = ptr[i] + 1; k < ptr[i+1]; k++)
00421 val += data[k] * x(ind[k]);
00422
00423 x(i) = val;
00424 }
00425 else
00426
00427 for (int i = n - 1; i >= 0; i--)
00428 {
00429 for (int k = ptr[i] + 1; k < ptr[i+1]; k++)
00430 x(ind[k]) += data[k] * x(i);
00431
00432 x(i) *= data[ptr[i]];
00433 }
00434 }
00435
00436
00438
00440
00441
00443 template<class T>
00444 SparseCholeskySolver<T>::SparseCholeskySolver()
00445 {
00446 n = 0;
00447 print_level = -1;
00448 type_ordering = SparseMatrixOrdering::IDENTITY;
00449
00450 type_solver = SELDON_SOLVER;
00451 #ifdef SELDON_WITH_CHOLMOD
00452 type_solver = CHOLMOD;
00453 #endif
00454 }
00455
00456
00458 template<class T>
00459 void SparseCholeskySolver<T>::HideMessages()
00460 {
00461 print_level = -1;
00462
00463 #ifdef SELDON_WITH_CHOLMOD
00464 mat_chol.HideMessages();
00465 #endif
00466
00467 }
00468
00469
00471 template<class T>
00472 void SparseCholeskySolver<T>::ShowMessages()
00473 {
00474 print_level = 1;
00475
00476 #ifdef SELDON_WITH_CHOLMOD
00477 mat_chol.ShowMessages();
00478 #endif
00479
00480 }
00481
00482
00484 template<class T>
00485 void SparseCholeskySolver<T>::ShowFullHistory()
00486 {
00487 print_level = 3;
00488
00489 #ifdef SELDON_WITH_CHOLMOD
00490 mat_chol.ShowMessages();
00491 #endif
00492
00493 }
00494
00495
00497 template<class T>
00498 void SparseCholeskySolver<T>::Clear()
00499 {
00500 if (n > 0)
00501 {
00502 n = 0;
00503
00504 #ifdef SELDON_WITH_CHOLMOD
00505 mat_chol.Clear();
00506 #endif
00507
00508 mat_sym.Clear();
00509 }
00510 }
00511
00512
00514 template<class T>
00515 int SparseCholeskySolver<T>::GetM() const
00516 {
00517 return n;
00518 }
00519
00520
00522 template<class T>
00523 int SparseCholeskySolver<T>::GetN() const
00524 {
00525 return n;
00526 }
00527
00528
00530 template<class T>
00531 int SparseCholeskySolver<T>::GetTypeOrdering() const
00532 {
00533 return type_ordering;
00534 }
00535
00536
00538 template<class T>
00539 void SparseCholeskySolver<T>::SetOrdering(const IVect& num)
00540 {
00541 type_ordering = SparseMatrixOrdering::USER;
00542 permutation = num;
00543 }
00544
00545
00547 template<class T>
00548 void SparseCholeskySolver<T>::SelectOrdering(int type)
00549 {
00550 type_ordering = type;
00551 }
00552
00553
00555 template<class T>
00556 void SparseCholeskySolver<T>::SelectDirectSolver(int type)
00557 {
00558 type_solver = type;
00559 }
00560
00561
00563 template<class T>
00564 int SparseCholeskySolver<T>::GetDirectSolver()
00565 {
00566 return type_solver;
00567 }
00568
00569
00571 template<class T> template<class MatrixSparse>
00572 void SparseCholeskySolver<T>::Factorize(MatrixSparse& A, bool keep_matrix)
00573 {
00574 n = A.GetM();
00575 if (type_solver == CHOLMOD)
00576 {
00577 #ifdef SELDON_WITH_CHOLMOD
00578 mat_chol.FactorizeMatrix(A, keep_matrix);
00579 #else
00580 throw Error("SparseCholeskySolver::Factorize",
00581 "Recompile with Cholmod or change solver type.");
00582 #endif
00583 }
00584 else
00585 {
00586 FindSparseOrdering(A, permutation, type_ordering);
00587 Copy(A, mat_sym);
00588 if (!keep_matrix)
00589 A.Clear();
00590
00591 ApplyInversePermutation(mat_sym, permutation, permutation);
00592
00593 GetCholesky(mat_sym, print_level);
00594 xtmp.Reallocate(n);
00595 }
00596 }
00597
00598
00600 template<class T> template<class TransStatus, class Vector1>
00601 void SparseCholeskySolver<T>
00602 ::Solve(const TransStatus& TransA, Vector1& x_solution)
00603 {
00604 if (type_solver == CHOLMOD)
00605 {
00606 #ifdef SELDON_WITH_CHOLMOD
00607 mat_chol.Solve(TransA, x_solution);
00608 #else
00609 throw Error("SparseCholeskySolver::Factorize",
00610 "Recompile with Cholmod or change solver type.");
00611 #endif
00612 }
00613 else
00614 if (TransA.NoTrans())
00615 {
00616 for (int i = 0; i < x_solution.GetM(); i++)
00617 xtmp(permutation(i)) = x_solution(i);
00618
00619 SolveCholesky(TransA, mat_sym, xtmp);
00620 Copy(xtmp, x_solution);
00621 }
00622 else
00623 {
00624 Copy(x_solution, xtmp);
00625 SolveCholesky(TransA, mat_sym, xtmp);
00626
00627 for (int i = 0; i < x_solution.GetM(); i++)
00628 x_solution(i) = xtmp(permutation(i));
00629 }
00630 }
00631
00632
00634 template<class T> template<class TransStatus, class Vector1>
00635 void SparseCholeskySolver<T>
00636 ::Mlt(const TransStatus& TransA, Vector1& x_solution)
00637 {
00638 if (type_solver == CHOLMOD)
00639 {
00640 #ifdef SELDON_WITH_CHOLMOD
00641 mat_chol.Mlt(TransA, x_solution);
00642 #else
00643 throw Error("SparseCholeskySolver::Factorize",
00644 "Recompile with Cholmod or change solver type.");
00645 #endif
00646 }
00647 else
00648 if (TransA.NoTrans())
00649 {
00650 Copy(x_solution, xtmp);
00651 MltCholesky(TransA, mat_sym, xtmp);
00652
00653 for (int i = 0; i < x_solution.GetM(); i++)
00654 x_solution(i) = xtmp(permutation(i));
00655 }
00656 else
00657 {
00658 for (int i = 0; i < x_solution.GetM(); i++)
00659 xtmp(permutation(i)) = x_solution(i);
00660
00661 MltCholesky(TransA, mat_sym, xtmp);
00662 Copy(xtmp, x_solution);
00663 }
00664 }
00665
00666 }
00667
00668
00669 #define SELDON_FILE_SPARSE_CHOLESKY_FACTORISATION_CXX
00670 #endif