computation/solver/SparseCholeskyFactorisation.cxx

00001 // Copyright (C) 2010 Marc Duruflé
00002 //
00003 // This file is part of the linear-algebra library Seldon,
00004 // http://seldon.sourceforge.net/.
00005 //
00006 // Seldon is free software; you can redistribute it and/or modify it under the
00007 // terms of the GNU Lesser General Public License as published by the Free
00008 // Software Foundation; either version 2.1 of the License, or (at your option)
00009 // any later version.
00010 //
00011 // Seldon is distributed in the hope that it will be useful, but WITHOUT ANY
00012 // WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
00013 // FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License for
00014 // more details.
00015 //
00016 // You should have received a copy of the GNU Lesser General Public License
00017 // along with Seldon. If not, see http://www.gnu.org/licenses/.
00018 
00019 
00020 #ifndef SELDON_FILE_SPARSE_CHOLESKY_FACTORIZATION_CXX
00021 
00022 namespace Seldon
00023 {
00024 
00026 
00031   template<class T, class Prop, class Allocator>
00032   void GetCholesky(Matrix<T, Prop, ArrayRowSymSparse, Allocator>& A)
00033   {
00034     int n = A.GetN();
00035     T t, s, fact;
00036     int j_col, jrow, index_lu, jpos;
00037     Vector<T> Row_Val(n);
00038     IVect Index(n), Row_Ind(n);
00039     Row_Val.Fill(0);
00040     Row_Ind.Fill(-1);
00041 
00042     Index.Fill(-1);
00043 
00044     // Conversion to unsymmetric matrix.
00045     Matrix<T, General, ArrayRowSparse, Allocator> B;
00046     Copy(A, B);
00047 
00048     // A is cleared.
00049     A.Clear();
00050     A.Reallocate(n, n);
00051 
00052     // Main loop over rows.
00053     for (int i_row = 0; i_row < n; i_row++)
00054       {
00055         int size_row = B.GetRowSize(i_row);
00056 
00057         // we are separating lower from upper part
00058         int length_lower = 0, length_upper = 1;
00059         Row_Ind(i_row) = i_row;
00060         Row_Val(i_row) = 0.0;
00061         Index(i_row) = i_row;
00062 
00063         for (int j = 0; j < size_row; j++)
00064           {
00065             int k = B.Index(i_row, j);
00066             t = B.Value(i_row, j);
00067             if (k < i_row)
00068               {
00069                 Row_Ind(length_lower) = k;
00070                 Row_Val(length_lower) = t;
00071                 Index(k) = length_lower;
00072                 length_lower++;
00073               }
00074             else if (k == i_row)
00075               Row_Val(i_row) = t;
00076             else
00077               {
00078                 jpos = i_row + length_upper;
00079                 Row_Ind(jpos) = k;
00080                 Row_Val(jpos) = t;
00081                 Index(k) = jpos;
00082                 length_upper++;
00083               }
00084           }
00085 
00086         B.ClearRow(i_row);
00087 
00088         j_col = 0;
00089         int length = 0;
00090 
00091         // Previous rows are eliminated.
00092         while (j_col < length_lower)
00093           {
00094             jrow = Row_Ind(j_col);
00095 
00096             // We search first element in lower part.
00097             int k = j_col;
00098             for (int j = (j_col+1) ; j < length_lower; j++)
00099               {
00100                 if (Row_Ind(j) < jrow)
00101                   {
00102                     jrow = Row_Ind(j);
00103                     k = j;
00104                   }
00105               }
00106 
00107 
00108             if (k != j_col)
00109               {
00110                 // If k different from j_col, we are exchanging positions.
00111                 int j = Row_Ind(j_col);
00112                 Row_Ind(j_col) = Row_Ind(k);
00113                 Row_Ind(k) = j;
00114 
00115                 Index(jrow) = j_col;
00116                 Index(j) = k;
00117 
00118                 s = Row_Val(j_col);
00119                 Row_Val(j_col) = Row_Val(k);
00120                 Row_Val(k) = s;
00121               }
00122 
00123             // Zero out element in row.
00124             Index(jrow) = -1;
00125             fact = Row_Val(j_col) * A.Value(jrow, 0);
00126 
00127             // Combines current row and row jrow.
00128             for (int k = 1; k < A.GetRowSize(jrow); k++)
00129               {
00130                 s = fact * A.Value(jrow, k);
00131                 int j = A.Index(jrow, k);
00132 
00133                 jpos = Index(j);
00134                 if (j >= i_row)
00135                   {
00136                     // Dealing with upper part.
00137                     if (jpos == -1)
00138                       {
00139                         // This is a fill-in element.
00140                         int i = i_row + length_upper;
00141                         Row_Ind(i) = j;
00142                         Index(j) = i;
00143                         Row_Val(i) = -s;
00144                         length_upper++;
00145                       }
00146                     else
00147                       {
00148                         // This is not a fill-in element.
00149                         Row_Val(jpos) -= s;
00150                       }
00151                   }
00152                 else
00153                   {
00154                     // Dealing  with lower part.
00155                     if (jpos == -1)
00156                       {
00157                         // This is a fill-in element.
00158                         Row_Ind(length_lower) = j;
00159                         Index(j) = length_lower;
00160                         Row_Val(length_lower) = -s;
00161                         length_lower++;
00162                       }
00163                     else
00164                       {
00165                         // This is not a fill-in element.
00166                         Row_Val(jpos) -= s;
00167                       }
00168                   }
00169               }
00170 
00171             // Stores this pivot element
00172             // (from left to right -- no danger of overlap
00173             // with the working elements in L (pivots).
00174             Row_Val(length) = fact;
00175             Row_Ind(length) = jrow;
00176             ++length;
00177             j_col++;
00178           }
00179 
00180         for (int k = 0; k < length_upper; k++)
00181           Index(Row_Ind(i_row + k)) = -1;
00182 
00183         // Now we can store the uppert part of row.
00184         size_row = length_upper;
00185         A.ReallocateRow(i_row, length_upper);
00186 
00187         // We store inverse of square root of diagonal element of u.
00188         if (Row_Val(i_row) < 0)
00189           {
00190             cout << "Error during Cholesky factorization " << endl;
00191             cout << "Matrix must be definite positive " << endl;
00192             cout << "but diagonal element of row " << i_row
00193                  << "is equal to " << Row_Val(i_row) << endl;
00194 
00195 #ifdef SELDON_WITH_ABORT
00196             abort();
00197 #endif
00198           }
00199 
00200         A.Value(i_row, 0) = 1.0 / Row_Val(i_row);
00201         A.Index(i_row, 0) = i_row;
00202         index_lu = 1;
00203 
00204         // and extra-diagonal terms
00205         for (int k = i_row + 1; k < i_row + length_upper; k++)
00206           {
00207             A.Index(i_row, index_lu) = Row_Ind(k);
00208             A.Value(i_row, index_lu) = Row_Val(k);
00209             index_lu++;
00210           }
00211       }
00212 
00213     // Diagonal of A is replaced by its square root.
00214     for (int i = 0; i < n; i++)
00215       {
00216         A.Value(i, 0) = sqrt(A.Value(i,0));
00217         // and other elements multiplied by this value.
00218         for (int k = 1; k < A.GetRowSize(i); k++)
00219           A.Value(i, k) *= A.Value(i, 0);
00220       }
00221   }
00222 
00223 
00224   // Resolution of L x = y.
00225   template<class classTrans,
00226            class T0, class T1, class Prop, class Storage,
00227            class Allocator1, class Allocator2>
00228   void SolveCholesky(const classTrans& TransA,
00229                      const Matrix<T0, Prop, ArrayRowSymSparse, Allocator1>& A,
00230                      Vector<T1, Storage, Allocator2>& x)
00231   {
00232     int n = A.GetM();
00233     if (n <= 0)
00234       return;
00235 
00236     if (TransA.Trans())
00237       {
00238         // We solve L^T x = x
00239         int j;
00240         for (int i = n - 1; i >= 0; i--)
00241           {
00242             T1 val = x(i);
00243             for (int k = 1; k < A.GetRowSize(i) ; k++)
00244               {
00245                 j = A.Index(i, k);
00246                 val -= A.Value(i, k) * x(j);
00247               }
00248 
00249             x(i) = val * A.Value(i, 0);
00250           }
00251       }
00252     else
00253       {
00254         // We solve L x = x
00255         int j;
00256         for (int i = 0; i < n; i++)
00257           {
00258             x(i) *= A.Value(i, 0);
00259             for (int k = 1; k < A.GetRowSize(i) ; k++)
00260               {
00261                 j = A.Index(i, k);
00262                 x(j) -= A.Value(i, k) * x(i);
00263               }
00264           }
00265       }
00266   }
00267 
00268 
00269   // Computation of y = L x.
00270   template<class classTrans,
00271            class T0, class T1, class Prop, class Storage,
00272            class Allocator1, class Allocator2>
00273   void MltCholesky(const classTrans& TransA,
00274                    const Matrix<T0, Prop, ArrayRowSymSparse, Allocator1>& A,
00275                    Vector<T1, Storage, Allocator2>& x)
00276   {
00277     int n = A.GetM();
00278     if (n <= 0)
00279       return;
00280 
00281     if (TransA.Trans())
00282       {
00283         // We overwrite x by L^T x
00284         int j;
00285         for (int i = 0; i < n; i++)
00286           {
00287             T1 val = x(i) / A.Value(i, 0);
00288             for (int k = 1; k < A.GetRowSize(i) ; k++)
00289               {
00290                 j = A.Index(i, k);
00291                 val += A.Value(i, k)*x(j);
00292               }
00293 
00294             x(i) = val;
00295           }
00296       }
00297     else
00298       {
00299         // We overwrite x with L x
00300         int j;
00301         for (int i = n - 1; i >= 0; i--)
00302           {
00303             for (int k = 1; k < A.GetRowSize(i) ; k++)
00304               {
00305                 j = A.Index(i, k);
00306                 x(j) += A.Value(i, k)*x(i);
00307               }
00308 
00309             x(i) /= A.Value(i, 0);
00310           }
00311       }
00312   }
00313 
00314 }
00315 
00316 #define SELDON_FILE_SPARSE_CHOLESKY_FACTORIZATION_CXX
00317 #endif