computation/interfaces/direct/Cholmod.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_CHOLMOD_CXX
00021 
00022 #include "Cholmod.hxx"
00023 
00024 namespace Seldon
00025 {
00026 
00027   MatrixCholmod::MatrixCholmod()
00028   {
00029     // Sets default parameters.
00030     cholmod_start(&param_chol);
00031     Lsparse = NULL;
00032     n = 0;
00033   }
00034 
00035 
00036 
00037   MatrixCholmod::~MatrixCholmod()
00038   {
00039     if (n > 0)
00040       {
00041         Clear();
00042         cholmod_finish(&param_chol);
00043       }
00044   }
00045 
00046 
00047   void MatrixCholmod::HideMessages()
00048   {
00049   }
00050 
00051 
00052   void MatrixCholmod::ShowMessages()
00053   {
00054   }
00055 
00056 
00057   void MatrixCholmod::ShowFullHistory()
00058   {
00059   }
00060 
00061 
00062   void MatrixCholmod::Clear()
00063   {
00064     if (n > 0)
00065       {
00066         n = 0;
00067         cholmod_free_factor(&L, &param_chol);
00068         if (Lsparse != NULL)
00069           cholmod_free_sparse(&Lsparse, &param_chol);
00070 
00071         Lsparse = NULL;
00072       }
00073   }
00074 
00075 
00076   template<class Prop, class Storage, class Allocator>
00077   void MatrixCholmod::
00078   FactorizeMatrix(Matrix<double, Prop, Storage, Allocator> & mat,
00079                   bool keep_matrix)
00080   {
00081     Clear();
00082 
00083     n = mat.GetM();
00084     Matrix<double, Symmetric, RowSymSparse, MallocAlloc<double> > Acsc;
00085     Copy(mat, Acsc);
00086     if (!keep_matrix)
00087       mat.Clear();
00088 
00089     // Initialization of sparse matrix.
00090     cholmod_sparse A;
00091 
00092     A.nrow = n;
00093     A.ncol = n;
00094     A.nzmax = Acsc.GetDataSize();
00095     A.nz = NULL;
00096     A.p = Acsc.GetPtr();
00097     A.i = Acsc.GetInd();
00098     A.x = Acsc.GetData();
00099     A.z = NULL;
00100     A.stype = -1;
00101     A.xtype = CHOLMOD_REAL;
00102     A.dtype = CHOLMOD_DOUBLE;
00103     A.sorted = true;
00104     A.packed = true;
00105     L = cholmod_analyze(&A, &param_chol);
00106 
00107     // Cholesky factorization.
00108     cholmod_factorize(&A, L, &param_chol);
00109 
00110     cholmod_change_factor(CHOLMOD_REAL, true, L->is_super,
00111                           true, L->is_monotonic, L, &param_chol);
00112 
00113     // We convert the factorization to column sparse row format.
00114     cholmod_factor* B = cholmod_copy_factor(L, &param_chol);
00115     Lsparse = cholmod_factor_to_sparse(B, &param_chol);
00116 
00117     cholmod_free_factor(&B, &param_chol);
00118   }
00119 
00120 
00122   template<class Transpose_status, class Allocator>
00123   void MatrixCholmod::Solve(const Transpose_status& TransA,
00124                             Vector<double, VectFull, Allocator>& x)
00125   {
00126     // Dense right hand side.
00127     cholmod_dense b_rhs;
00128     b_rhs.nrow = x.GetM();
00129     b_rhs.ncol = 1;
00130     b_rhs.nzmax = b_rhs.nrow;
00131     b_rhs.d = b_rhs.nrow;
00132     b_rhs.x = x.GetData();
00133     b_rhs.z = NULL;
00134     b_rhs.xtype = CHOLMOD_REAL;
00135     b_rhs.dtype = CHOLMOD_DOUBLE;
00136 
00137     cholmod_dense* x_sol, *y;
00138     if (TransA.Trans())
00139       {
00140         y = cholmod_solve(CHOLMOD_Lt, L, &b_rhs, &param_chol);
00141         x_sol = cholmod_solve(CHOLMOD_Pt, L, y, &param_chol);
00142       }
00143     else
00144       {
00145         y = cholmod_solve(CHOLMOD_P, L, &b_rhs, &param_chol);
00146         x_sol = cholmod_solve(CHOLMOD_L, L, y, &param_chol);
00147       }
00148 
00149     double* data = reinterpret_cast<double*>(x_sol->x);
00150     for (int i = 0; i < x.GetM(); i++)
00151       x(i) = data[i];
00152 
00153     cholmod_free_dense(&x_sol, &param_chol);
00154     cholmod_free_dense(&y, &param_chol);
00155   }
00156 
00157 
00159   template<class Transpose_status, class Allocator>
00160   void MatrixCholmod::Mlt(const Transpose_status& TransA,
00161                           Vector<double, VectFull, Allocator>& X)
00162   {
00163     int trans = 1;
00164     if(TransA.Trans())
00165       trans = 0;
00166 
00167     Vector<double, VectFull, Allocator> Y = X;
00168 
00169     cholmod_dense Xchol,Ychol;
00170 
00171     Xchol.nrow = X.GetM();
00172     Xchol.ncol = 1;
00173     Xchol.nzmax = Xchol.nrow;
00174     Xchol.d = Xchol.nrow;
00175     Xchol.x = X.GetData();
00176     Xchol.z = NULL;
00177     Xchol.xtype = CHOLMOD_REAL;
00178     Xchol.dtype = CHOLMOD_DOUBLE;
00179 
00180     Ychol.nrow = X.GetM();
00181     Ychol.ncol = 1;
00182     Ychol.nzmax = Ychol.nrow;
00183     Ychol.d = Ychol.nrow;
00184     Ychol.x = Y.GetData();
00185     Ychol.z = NULL;
00186     Ychol.xtype = CHOLMOD_REAL;
00187     Ychol.dtype = CHOLMOD_DOUBLE;
00188 
00189     // Conversion from Lsparse to Seldon structure.
00190     Matrix<double, General, RowSparse, MallocAlloc<double> > Lcsr;
00191     Lcsr.SetData(n, n, Lsparse->nzmax, reinterpret_cast<double*>(Lsparse->x),
00192                  reinterpret_cast<int*>(Lsparse->p),
00193                  reinterpret_cast<int*>(Lsparse->i));
00194 
00195     if (TransA.Trans())
00196       {
00197         // Computing L^T P^T x.
00198         cholmod_dense* x_sol;
00199         x_sol = cholmod_solve(CHOLMOD_P, L, &Xchol, &param_chol);
00200 
00201         double* data = reinterpret_cast<double*>(x_sol->x);
00202         for (int i = 0; i < n; i++)
00203           Y(i) = data[i];
00204 
00205         Seldon::Mlt(Lcsr, Y, X);
00206 
00207         cholmod_free_dense(&x_sol, &param_chol);
00208       }
00209     else
00210       {
00211         // Computing P L x.
00212         Seldon::MltAdd(1.0, SeldonTrans, Lcsr, X, 0.0, Y);
00213 
00214         cholmod_dense* x_sol;
00215         x_sol = cholmod_solve(CHOLMOD_Pt, L, &Ychol, &param_chol);
00216 
00217         double* data = reinterpret_cast<double*>(x_sol->x);
00218         for (int i = 0; i < X.GetM(); i++)
00219           X(i) = data[i];
00220 
00221         cholmod_free_dense(&x_sol, &param_chol);
00222       }
00223 
00224     Lcsr.Nullify();
00225   }
00226 
00227 
00228   template<class T, class Prop, class Storage, class Allocator>
00229   void GetCholesky(Matrix<T, Prop, Storage, Allocator>& A,
00230                    MatrixCholmod& mat_chol, bool keep_matrix = false)
00231   {
00232     mat_chol.FactorizeMatrix(A, keep_matrix);
00233   }
00234 
00235 
00236   template<class T, class Allocator, class Transpose_status>
00237   void
00238   SolveCholesky(const Transpose_status& TransA,
00239                 MatrixCholmod& mat_chol, Vector<T, VectFull, Allocator>& x)
00240   {
00241     mat_chol.Solve(TransA, x);
00242   }
00243 
00244 
00245   template<class T, class Allocator, class Transpose_status>
00246   void
00247   MltCholesky(const Transpose_status& TransA,
00248               MatrixCholmod& mat_chol, Vector<T, VectFull, Allocator>& x)
00249   {
00250     mat_chol.Mlt(TransA, x);
00251   }
00252 
00253 }
00254 
00255 #define SELDON_FILE_CHOLMOD_CXX
00256 #endif