HermesCommon 1.0
matrix.h
Go to the documentation of this file.
00001 // This file is part of HermesCommon
00002 //
00003 // Copyright (c) 2009 hp-FEM group at the University of Nevada, Reno (UNR).
00004 // Email: hpfem-group@unr.edu, home page: http://hpfem.org/.
00005 //
00006 // Hermes2D is free software; you can redistribute it and/or modify
00007 // it under the terms of the GNU General Public License as published
00008 // by the Free Software Foundation; either version 2 of the License,
00009 // or (at your option) any later version.
00010 //
00011 // Hermes2D is distributed in the hope that it will be useful,
00012 // but WITHOUT ANY WARRANTY; without even the implied warranty of
00013 // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
00014 // GNU General Public License for more details.
00015 //
00016 // You should have received a copy of the GNU General Public License
00017 // along with Hermes2D; if not, write to the Free Software
00018 // Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301, USA.
00022 #ifndef __HERMES_COMMON_MATRIX_H
00023 #define __HERMES_COMMON_MATRIX_H
00024 
00025 #include "common.h"
00026 #include "vector.h"
00027 #include "exceptions.h"
00028 #include "mixins.h"
00029 
00030 namespace Hermes
00031 {
00032   enum MatrixSolverType
00033   {
00034     SOLVER_UMFPACK = 0,
00035     SOLVER_PETSC,
00036     SOLVER_MUMPS,
00037     SOLVER_SUPERLU,
00038     SOLVER_AMESOS,
00039     SOLVER_AZTECOO
00040   };
00041 
00043   namespace Algebra
00044   {
00046     namespace DenseMatrixOperations
00047     {
00051       template<typename T>
00052       T **new_matrix(unsigned int m, unsigned int n = 0)
00053       {
00054         if(!n) n = m;
00055         T **vec = (T **) new char[sizeof(T *) * m + sizeof(T) * m * n];
00056         memset(vec, 0, sizeof(T *) * m + sizeof(T) * m * n);
00057         T *row = (T *) (vec + m);
00058         for (unsigned int i = 0; i < m; i++, row += n) vec[i] = row;
00059         return vec;
00060       }
00061 
00062       template<typename T>
00063       T **new_matrix_malloc(unsigned int m, unsigned int n = 0)
00064       {
00065         if(!n) n = m;
00066         T **vec = (T **) malloc(sizeof(T *) * m + sizeof(T) * m * n);
00067         memset(vec, 0, sizeof(T *) * m + sizeof(T) * m * n);
00068         T *row = (T *) (vec + m);
00069         for (unsigned int i = 0; i < m; i++, row += n) vec[i] = row;
00070         return vec;
00071       }
00072 
00075       template<typename T>
00076       void copy_matrix(T** dest, T** src, unsigned int m, unsigned int n = 0)
00077       {
00078         if(n == 0) n = m;
00079         for(unsigned int i = 0; i < m; i++)
00080         {
00081           memcpy(dest[i], src[i], n*sizeof(T));
00082         }
00083       }
00084 
00091       template<typename T>
00092       void save_matrix_octave(const std::string& matrix_name, T** matrix, unsigned int m, unsigned int n = 0, const std::string& filename = std::string())
00093       {
00094         if(n == 0) n = m;
00095 
00096         //create filename
00097         std::string fname = filename;
00098         if(fname.empty())
00099           fname = matrix_name + ".mat";
00100 
00101         //open file
00102         std::ofstream fout(fname.c_str());
00103         if(!fout.is_open())
00104         {
00105           throw Hermes::Exceptions::Exception("Unable to save a matrix to a file \"%s\"", fname.c_str());
00106           return;
00107         }
00108 
00109         //write header
00110         fout << std::string("# name: ") << matrix_name << std::endl;
00111         fout << std::string("# type: matrix") << std::endl;
00112         fout << std::string("# rows: ") << m << std::endl;
00113         fout << std::string("# columns: ") << n << std::endl;
00114 
00115         //write contents
00116         for(unsigned int i = 0; i < m; i++)
00117         {
00118           for(unsigned int k = 0; k < n; k++)
00119             fout << ' ' << matrix[i][k];
00120           fout << std::endl;
00121         }
00122 
00123         //finish
00124         fout.close();
00125       }
00126 
00128       template<typename T>
00129       void save_sparse_matrix_octave(const std::string& matrix_name, const T* Ax, const int* Ap, const int* Ai,
00130         unsigned int m, const std::string& filename = std::string())
00131       {
00132         // create filename
00133         std::string fname = filename;
00134         if(fname.empty())
00135           fname = matrix_name + ".mat";
00136 
00137         // open file
00138         std::ofstream fout(fname.c_str());
00139         if(!fout.is_open())
00140         {
00141           throw Hermes::Exceptions::Exception("Unable to save a matrix to a file \"%s\"", fname.c_str());
00142           return;
00143         }
00144 
00145         // write header
00146         fout << std::string("# name: ") << matrix_name << std::endl;
00147         fout << std::string("# type: sparse matrix") << std::endl;
00148         fout << std::string("# nnz: ") << Ap[m] << std::endl;
00149         fout << std::string("# rows: ") << m << std::endl;
00150         fout << std::string("# columns: ") << m << std::endl;
00151 
00152         // write contents
00153         for (int j = 0; j < m; j++)
00154           for (int i = Ap[j]; i < Ap[j + 1]; i++)
00155             fout << j + 1 << " " << Ai[i] + 1 << " " << Ax[i] << std::endl;
00156 
00157         // finish
00158         fout.close();
00159       }
00160 
00163       template<typename T>
00164       void transpose(T **matrix, unsigned int m, unsigned int n)
00165       {
00166         unsigned int min = std::min(m, n);
00167         for (unsigned int i = 0; i < min; i++)
00168           for (unsigned int j = i + 1; j < min; j++)
00169             std::swap(matrix[i][j], matrix[j][i]);
00170 
00171         if(m < n)
00172           for (unsigned int i = 0; i < m; i++)
00173             for (unsigned int j = m; j < n; j++)
00174               matrix[j][i] = matrix[i][j];
00175         else if(n < m)
00176           for (unsigned int i = n; i < m; i++)
00177             for (unsigned int j = 0; j < n; j++)
00178               matrix[j][i] = matrix[i][j];
00179       }
00180 
00182       template<typename T>
00183       void chsgn(T **matrix, unsigned int m, unsigned int n)
00184       {
00185         for (unsigned int i = 0; i < m; i++)
00186           for (unsigned int j = 0; j < n; j++)
00187             matrix[i][j] = -matrix[i][j];
00188       }
00189 
00196       HERMES_API void ludcmp(double **a, int n, int *indx, double *d);
00197 
00205       template<typename T>
00206       void lubksb(double **a, int n, int *indx, T *b)
00207       {
00208         int i, ip, j;
00209         T sum;
00210 
00211         for (i = 0; i < n; i++)
00212         {
00213           ip = indx[i];
00214           sum = b[ip];
00215           b[ip] = b[i];
00216           for (j = 0; j < i; j++) sum -= a[i][j]*b[j];
00217           b[i] = sum;
00218         }
00219         for (i = n-1; i >= 0; i--)
00220         {
00221           sum = b[i];
00222           for (j = i + 1; j < n; j++) sum -= a[i][j]*b[j];
00223           b[i] = sum / a[i][i];
00224         }
00225       }
00226 
00231       HERMES_API void choldc(double **a, int n, double p[]);
00232 
00240       template<typename T>
00241       void cholsl(double **a, int n, double p[], T b[], T x[])
00242       {
00243         int i, k;
00244         T sum;
00245 
00246         for (i = 0; i < n; i++)
00247         {
00248           sum = b[i];
00249           k = i;
00250           while (--k >= 0) sum -= a[i][k] * x[k];
00251           x[i] = sum / p[i];
00252         }
00253 
00254         for (i = n-1; i >= 0; i--)
00255         {
00256           sum = x[i];
00257           k = i;
00258           while (++k < n) sum -= a[k][i] * x[k];
00259           x[i] = sum / p[i];
00260         }
00261       }
00262     }
00263 
00265     enum EMatrixDumpFormat
00266     {
00267       DF_MATLAB_SPARSE, 
00268 
00269 
00270 
00271 
00272       DF_PLAIN_ASCII,
00275       DF_HERMES_BIN,
00276       DF_MATRIX_MARKET 
00277     };
00278 
00280     template<typename Scalar>
00281     class HERMES_API Matrix : public Hermes::Mixins::Loggable
00282     {
00283     public:
00286       unsigned int get_size() { return this->size;};
00287 
00290       Matrix(unsigned int size) { this->size = size;};
00291 
00292       virtual ~Matrix() {};
00293 
00294       Matrix() { this->size = 0;};
00295 
00297       virtual void alloc() = 0;
00298 
00300       virtual void free() = 0;
00301 
00306       virtual Scalar get(unsigned int m, unsigned int n) = 0;
00307 
00309       virtual void zero() = 0;
00310 
00312       virtual void add_to_diagonal(Scalar v) = 0;
00313 
00319       virtual void add(unsigned int m, unsigned int n, Scalar v) = 0;
00320 
00328       virtual void add(unsigned int m, unsigned int n, Scalar **mat, int *rows, int *cols) = 0;
00329 
00335       virtual bool dump(FILE *file, const char *var_name, EMatrixDumpFormat fmt = DF_MATLAB_SPARSE, char* number_format = "%lf") = 0;
00336 
00339       virtual unsigned int get_matrix_size() const = 0;
00340 
00341     protected:
00342 
00343       unsigned int size;  
00344     };
00345 
00347     template<typename Scalar>
00348     class HERMES_API SparseMatrix : public Matrix<Scalar> {
00349     public:
00350       SparseMatrix();
00353       SparseMatrix(unsigned int size);
00354       virtual ~SparseMatrix();
00355 
00359       virtual void prealloc(unsigned int n);
00360 
00365       virtual void pre_add_ij(unsigned int row, unsigned int col);
00366 
00368       virtual void finish() { }
00369 
00370       virtual unsigned int get_size() { return this->size; }
00371 
00374       virtual void add_sparse_matrix(SparseMatrix* mat)
00375       {
00376         throw Hermes::Exceptions::Exception("add_sparse_matrix() undefined.");
00377       };
00378 
00383       virtual void add_sparse_to_diagonal_blocks(int num_stages, SparseMatrix<Scalar>* mat)
00384       {
00385         throw Hermes::Exceptions::Exception("add_sparse_to_diagonal_blocks() undefined.");
00386       };
00387 
00392       virtual int get_num_row_entries(unsigned int row) { return -1; }
00393 
00401       virtual void extract_row_copy(unsigned int row, unsigned int len,
00402         unsigned int &n_entries, double *vals,
00403         unsigned int *idxs) { }
00404 
00409       virtual int get_num_col_entries(unsigned int col) { return -1; }
00410 
00418       virtual void extract_col_copy(unsigned int col, unsigned int len,
00419         unsigned int &n_entries, double *vals,
00420         unsigned int *idxs) { }
00421 
00423       virtual void multiply_with_vector(Scalar* vector_in, Scalar* vector_out) {
00424         throw Hermes::Exceptions::Exception("multiply_with_vector() undefined.");
00425       };
00426 
00428       virtual void multiply_with_Scalar(Scalar value) {
00429         throw Hermes::Exceptions::Exception("multiply_with_Scalar() undefined.");
00430       };
00431 
00433       virtual SparseMatrix* duplicate() { return (SparseMatrix*)NULL;};
00434 
00436       virtual double get_fill_in() const = 0;
00437 
00438       unsigned row_storage:1; 
00439       unsigned col_storage:1; 
00440 
00443       virtual unsigned int get_nnz() const {
00444         throw Hermes::Exceptions::Exception("get_nnz() undefined.");
00445         return 0;
00446       }
00447 
00448     protected:
00450       static const int PAGE_SIZE = 62;
00451 
00453       struct Page {
00455         int count;
00457         int idx[PAGE_SIZE];
00459         Page *next;
00460       };
00461 
00463       Page **pages;
00464 
00471       int sort_and_store_indices(Page *page, int *buffer, int *max);
00474       int get_num_indices();
00475 
00477       int mem_size;
00478     };
00479 
00481     template<typename Scalar>
00482     class HERMES_API Vector : public Hermes::Mixins::Loggable
00483     {
00484     public:
00485       virtual ~Vector() { }
00486 
00490       virtual void alloc(unsigned int ndofs) = 0;
00492       virtual void free() = 0;
00494       virtual void finish() { }
00495 
00499       virtual Scalar get(unsigned int idx) = 0;
00500 
00503       virtual void extract(Scalar *v) const = 0;
00504 
00506       virtual void zero() = 0;
00507 
00509       virtual void change_sign() = 0;
00510 
00515       virtual void set(unsigned int idx, Scalar y) = 0;
00516 
00521       virtual void add(unsigned int idx, Scalar y) = 0;
00522 
00524       virtual void add_vector(Vector<Scalar>* vec) = 0;
00526       virtual void add_vector(Scalar* vec) = 0;
00527 
00533       virtual void add(unsigned int n, unsigned int *idx, Scalar *y) = 0;
00534 
00536       unsigned int length() const {return this->size;}
00537 
00543       virtual bool dump(FILE *file, const char *var_name,
00544         EMatrixDumpFormat fmt = DF_MATLAB_SPARSE, char* number_format = "%lf") = 0;
00545 
00546     protected:
00548       unsigned int size;
00549     };
00550 
00553     template<typename Scalar> HERMES_API
00554       Vector<Scalar>* create_vector();
00555 
00558     template<typename Scalar> HERMES_API
00559       SparseMatrix<Scalar>*  create_matrix();
00560   }
00561 }
00562 #endif