Commit 305067486e2cf831fc2edfa05960a4ed28936f07
1 parent
92d08c9c
Improve Doxygen documentation, add at() methods and value assignment operator.
Showing
5 changed files
with
389 additions
and
121 deletions
include/GMatrixBase.hpp
| ... | ... | @@ -38,9 +38,110 @@ |
| 38 | 38 | * |
| 39 | 39 | * @brief Abstract matrix base class interface defintion |
| 40 | 40 | * |
| 41 | - * This class is an abstract base class from which all matrix classes will | |
| 42 | - * be derived. It defines the common interface for all matrix classes and | |
| 43 | - * implements common methods and data members. | |
| 41 | + * This class provides the abstract interface for all matrix classes. A | |
| 42 | + * GammaLib matrix is a two dimensional array of double precision values | |
| 43 | + * that is commonly used for linear algebra computations. | |
| 44 | + * | |
| 45 | + * The matrix classes were designed in a manner so that matrices can be used | |
| 46 | + * in a natural syntax that is comparable to the syntax used for scalar | |
| 47 | + * values. In particular, the following matrix operations are available: | |
| 48 | + * | |
| 49 | + * assigned_matrix = matrix; | |
| 50 | + * assigned_matrix = value; | |
| 51 | + * added_matrix = matrix1 + matrix2; | |
| 52 | + * added_matrix += matrix; | |
| 53 | + * subtracted_matrix = matrix1 - matrix2; | |
| 54 | + * subtracted_matrix -= matrix; | |
| 55 | + * multiplied_matrix = matrix1 * matrix2; | |
| 56 | + * multiplied_matrix *= matrix; | |
| 57 | + * scaled_matrix = matrix * scale; | |
| 58 | + * scaled_matrix = scale * matrix; | |
| 59 | + * scaled_matrix *= scale; | |
| 60 | + * divided_matrix = matrix / factor; | |
| 61 | + * divided_matrix /= factor; | |
| 62 | + * negated_matrix = -matrix; | |
| 63 | + * | |
| 64 | + * where @p matrix, @p matrix1 and @p matrix2 are matrices, and | |
| 65 | + * @p value, @p scale and @p factor are double precision values. For the | |
| 66 | + * value assignment operator, each matrix element is assigned the specified | |
| 67 | + * value. For the scaling and division operators, every matrix element is | |
| 68 | + * multiplied or divided by the specified value. | |
| 69 | + * | |
| 70 | + * Matrices can also be compared using | |
| 71 | + * | |
| 72 | + * if (matrix == another_matrix) ... | |
| 73 | + * if (matrix != another_matrix) ... | |
| 74 | + * | |
| 75 | + * where identify is defined as having the same number of rows and columns | |
| 76 | + * and every element having the same value. | |
| 77 | + * | |
| 78 | + * Matrix elements are accessed using the access operators or the at() methods | |
| 79 | + * | |
| 80 | + * double element = matrix(row, column); | |
| 81 | + * double element = matrix.at(row, column); | |
| 82 | + * | |
| 83 | + * the difference being that the access operators do NOT but the at() | |
| 84 | + * methods do perform validity checking of the @p row and @p column | |
| 85 | + * arguments. Access operators and at() methods exist for non-const and | |
| 86 | + * const references. | |
| 87 | + * | |
| 88 | + * For more efficient matrix access, methods operating on matrix rows and | |
| 89 | + * columns are available. The | |
| 90 | + * | |
| 91 | + * GVector row = matrix.row(index); | |
| 92 | + * GVector column = matrix.column(index); | |
| 93 | + * | |
| 94 | + * methods return a row or a column in a GVector object, while the | |
| 95 | + * | |
| 96 | + * GVector row; | |
| 97 | + * GVector column; | |
| 98 | + * ... | |
| 99 | + * matrix.row(index, row); | |
| 100 | + * matrix.column(index, column); | |
| 101 | + * | |
| 102 | + * store a row or a column provided by a GVector object into the matrix. | |
| 103 | + * Obviously, the vector needs to be of the same size as the number of rows | |
| 104 | + * or columns available in the matrix. Adding of matrix elements row-by-row | |
| 105 | + * or column-by-column is done using the | |
| 106 | + * | |
| 107 | + * matrix.add_to_row(index, row); | |
| 108 | + * matrix.add_to_column(index, column); | |
| 109 | + * | |
| 110 | + * methods. | |
| 111 | + * | |
| 112 | + * Matrix multiplication with a vector is done using | |
| 113 | + * | |
| 114 | + * GVector vector; | |
| 115 | + * ... | |
| 116 | + * GVector product = matrix * vector; | |
| 117 | + * | |
| 118 | + * where the size of @p vector needs to be identical to the number of | |
| 119 | + * columns in the matrix. | |
| 120 | + * | |
| 121 | + * Furthermore, the following methods exist for matrix operations: | |
| 122 | + * | |
| 123 | + * matrix.transpose(); // Transposes matrix | |
| 124 | + * matrix.invert(); // Inverts matrix | |
| 125 | + * matrix.negate(); // Negates all matrix elements | |
| 126 | + * matrix.abs(); // Sets all matrix elements to their absolute values | |
| 127 | + * | |
| 128 | + * Friend functions are implemented to perform the same operations also in a | |
| 129 | + * more natural syntax that will generate a new matrix | |
| 130 | + * | |
| 131 | + * transposed_matrix = transpose(matrix); | |
| 132 | + * inverted_matrix = invert(matrix); | |
| 133 | + * negated_matrix = -matrix; | |
| 134 | + * absolute_matrix = abs(matrix); | |
| 135 | + * | |
| 136 | + * The following methods allow to access matrix attributes: | |
| 137 | + * | |
| 138 | + * matrix.fill(); // Percentage of non-zero elements in matrix [0,1] | |
| 139 | + * matrix.min(); // Minimum matrix element | |
| 140 | + * matrix.max(); // Maximum matrix element | |
| 141 | + * matrix.sum(); // Sum of all matrix elements | |
| 142 | + * matrix.rows(); // Number of rows in matrix | |
| 143 | + * matrix.columns(); // Number of columns in matrix | |
| 144 | + * matrix.size(); // Number of elements in matrix | |
| 44 | 145 | ***************************************************************************/ |
| 45 | 146 | class GMatrixBase : public GBase { |
| 46 | 147 | |
| ... | ... | @@ -61,23 +162,25 @@ public: |
| 61 | 162 | virtual bool operator!=(const GMatrixBase& matrix) const; |
| 62 | 163 | |
| 63 | 164 | // Pure virtual methods |
| 64 | - virtual void clear(void) = 0; | |
| 65 | - virtual GMatrixBase* clone(void) const = 0; | |
| 66 | - virtual GVector row(const int& row) const = 0; | |
| 67 | - virtual void row(const int& row, const GVector& vector) = 0; | |
| 68 | - virtual GVector column(const int& column) const = 0; | |
| 69 | - virtual void column(const int& column, const GVector& vector) = 0; | |
| 70 | - virtual void add_to_row(const int& row, const GVector& vector) = 0; | |
| 71 | - virtual void add_to_column(const int& column, const GVector& vector) = 0; | |
| 72 | - virtual void transpose(void) = 0; | |
| 73 | - virtual void invert(void) = 0; | |
| 74 | - virtual void negate(void) = 0; | |
| 75 | - virtual void abs(void) = 0; | |
| 76 | - virtual double fill(void) const = 0; | |
| 77 | - virtual double min(void) const = 0; | |
| 78 | - virtual double max(void) const = 0; | |
| 79 | - virtual double sum(void) const = 0; | |
| 80 | - virtual std::string print(const GChatter& chatter = NORMAL) const = 0; | |
| 165 | + virtual void clear(void) = 0; | |
| 166 | + virtual GMatrixBase* clone(void) const = 0; | |
| 167 | + virtual double& at(const int& row, const int& column) = 0; | |
| 168 | + virtual const double& at(const int& row, const int& column) const = 0; | |
| 169 | + virtual GVector row(const int& row) const = 0; | |
| 170 | + virtual void row(const int& row, const GVector& vector) = 0; | |
| 171 | + virtual GVector column(const int& column) const = 0; | |
| 172 | + virtual void column(const int& column, const GVector& vector) = 0; | |
| 173 | + virtual void add_to_row(const int& row, const GVector& vector) = 0; | |
| 174 | + virtual void add_to_column(const int& column, const GVector& vector) = 0; | |
| 175 | + virtual void transpose(void) = 0; | |
| 176 | + virtual void invert(void) = 0; | |
| 177 | + virtual void negate(void) = 0; | |
| 178 | + virtual void abs(void) = 0; | |
| 179 | + virtual double fill(void) const = 0; | |
| 180 | + virtual double min(void) const = 0; | |
| 181 | + virtual double max(void) const = 0; | |
| 182 | + virtual double sum(void) const = 0; | |
| 183 | + virtual std::string print(const GChatter& chatter = NORMAL) const = 0; | |
| 81 | 184 | |
| 82 | 185 | // Base class methods |
| 83 | 186 | const int& size(void) const; | ... | ... |
include/GMatrixSparse.hpp
| ... | ... | @@ -49,16 +49,20 @@ class GSparseNumeric; |
| 49 | 49 | * |
| 50 | 50 | * @brief Sparse matrix class interface defintion |
| 51 | 51 | * |
| 52 | - * This class implements a sparse matrix class. The class only stores | |
| 53 | - * non-zero elements, which can considerably reduce the memory requirements | |
| 54 | - * for large systems that are sparsly filled. | |
| 52 | + * This class implements a sparse matrix. The class only stores non-zero | |
| 53 | + * elements, which can considerably reduce the memory requirements for large | |
| 54 | + * systems that are sparsely filled. Also the computations will be faster | |
| 55 | + * because only non-zero elements will be used in the operations. | |
| 56 | + * | |
| 57 | + * For a description of the common matrix methods, please refer to the | |
| 58 | + * GMatrixBase class. | |
| 55 | 59 | * |
| 56 | 60 | * The class has been inspired from the code CSparse that can be downloaded |
| 57 | - * from http://www.cise.ufl.edu/research/sparse/CSparse/ | |
| 58 | - * CSparse has been written by Timothy A. Davis to accompany his book | |
| 59 | - * "Direct Methods for Sparse Linear Systems". In the CSparse code, a sparse | |
| 60 | - * matrix is implemented by the structure cs_sparse. The members of this | |
| 61 | - * structure map as follows to the member of the GMatrixSparse class: | |
| 61 | + * from http://www.cise.ufl.edu/research/sparse/CSparse/ which has been | |
| 62 | + * written by Timothy A. Davis to accompany his book "Direct Methods for | |
| 63 | + * Sparse Linear Systems". In the CSparse code, a sparse matrix is | |
| 64 | + * implemented by the structure cs_sparse. The members of this | |
| 65 | + * structure map as follows to the members of the GMatrixSparse class: | |
| 62 | 66 | * |
| 63 | 67 | * <table border> |
| 64 | 68 | * <tr> |
| ... | ... | @@ -106,6 +110,76 @@ class GSparseNumeric; |
| 106 | 110 | * </tr> |
| 107 | 111 | * </table> |
| 108 | 112 | * |
| 113 | + * Matrix allocation is done using the constructors | |
| 114 | + * | |
| 115 | + * GMatrixSparse sparsematrix(rows, columns); | |
| 116 | + * GMatrixSparse sparsematrix(rows, columns, elements); | |
| 117 | + * GMatrixSparse sparsematrix(matrix); | |
| 118 | + * GMatrixSparse sparsematrix(sparsematrix); | |
| 119 | + * GMatrixSparse sparsematrix(symmetricmatrix); | |
| 120 | + * | |
| 121 | + * where @p rows and @p columns specify the number of rows and columns of | |
| 122 | + * the matrix and @p elements is the size of the memory that should be | |
| 123 | + * pre-allocated for matrix storage (optional). Storage conversion | |
| 124 | + * constructors exist that allow allocating a sparse matrix by copying from | |
| 125 | + * a general matrix of type GMatrix and a symmetrix matrix of type | |
| 126 | + * GMatrixSymmetric. | |
| 127 | + * | |
| 128 | + * Because the location of a specific matrix element is not necessarily known | |
| 129 | + * in advance, the class implements a so called pending element for matrix | |
| 130 | + * element setting. A pending element is an element that is scheduled for | |
| 131 | + * insertion in the matrix, but which has not yet been inserted. The matrix | |
| 132 | + * element access operators () and at() return the reference to this pending | |
| 133 | + * element if a memory location for a given row and column does not yet | |
| 134 | + * exist. The protected method fill_pending() is then called before all | |
| 135 | + * operations that are done on the matrix to insert the element before the | |
| 136 | + * operation is executed. | |
| 137 | + * | |
| 138 | + * Another mechanism that has been implemented to speed up the fill of the | |
| 139 | + * sparse matrix is a "fill stack" that is used for insertion or addition | |
| 140 | + * of matrix columns by the | |
| 141 | + * | |
| 142 | + * matrix.column(index, vector); | |
| 143 | + * matrix.column(index, values, rows, number); | |
| 144 | + * matrix.add_to_column(index, vector); | |
| 145 | + * matrix.add_to_column(index, values, rows, number); | |
| 146 | + * | |
| 147 | + * methods. The fill stack is a buffer that implements a queue for columns | |
| 148 | + * that are to be inserted into the matrix. This is more efficient than | |
| 149 | + * insertion of elements one by one, as every insertion of an element may | |
| 150 | + * require to shift all elements back by one memory location. | |
| 151 | + * | |
| 152 | + * The fill stack is used as follows: | |
| 153 | + * | |
| 154 | + * matrix.stack_init(size, entries); | |
| 155 | + * ... | |
| 156 | + * matrix.column(index, vector); // (or one of the other column methods) | |
| 157 | + * ... | |
| 158 | + * matrix.stack_flush(); | |
| 159 | + * ... | |
| 160 | + * matrix.stack_destroy(); | |
| 161 | + * | |
| 162 | + * The stack_init(size, entries) method initialises the fill stack, where | |
| 163 | + * @p size is the size of the allocated memory buffer and @p entries is the | |
| 164 | + * maximum number of entries (i.e. columns) that will be held by the buffer. | |
| 165 | + * If @p size is set to 0 (the default value), a default @p size value of | |
| 166 | + * 512 is used. If @p entries is set to 0 (the default value), the number of | |
| 167 | + * matrix columns is taken as default @p entries value. Note that a too large | |
| 168 | + * number of elements will produce some overhead due to fill stack | |
| 169 | + * management, hence @p entries should not exceeed a value of the order of | |
| 170 | + * 10-100. | |
| 171 | + * | |
| 172 | + * The stack_flush() method flushes the stack, which is mandatory before any | |
| 173 | + * usage of the matrix. Note that the fill stack IS NOT INSERTED AUTOMATICALLY | |
| 174 | + * before any matrix operation, hence manual stack flushing is needed to make | |
| 175 | + * all filled matrix elements available for usage. The stack_destroy() method | |
| 176 | + * will flush the stack and free all stack elements. This method | |
| 177 | + * should be called once no filling is required anymore. If stack_destroy() | |
| 178 | + * is called immediately after filling, no call to stack_flush() is needed as | |
| 179 | + * the stack_destroy() method flushes the stack before destroying it. The | |
| 180 | + * matrix stack is also destroyed by the sparse matrix destructor, hence | |
| 181 | + * manual stack destruction is not mandatory. | |
| 182 | + * | |
| 109 | 183 | * Except for *m_rowinx which is implemented on the level of GMatrixSparse, |
| 110 | 184 | * all other members are implemented by the base class GMatrixBase. |
| 111 | 185 | ***************************************************************************/ |
| ... | ... | @@ -144,6 +218,7 @@ public: |
| 144 | 218 | |
| 145 | 219 | // Other operators |
| 146 | 220 | virtual GMatrixSparse& operator=(const GMatrixSparse& matrix); |
| 221 | + virtual GMatrixSparse& operator=(const double& value); | |
| 147 | 222 | virtual GMatrixSparse operator+(const GMatrixSparse& matrix) const; |
| 148 | 223 | virtual GMatrixSparse operator-(const GMatrixSparse& matrix) const; |
| 149 | 224 | virtual GMatrixSparse operator*(const GMatrixSparse& matrix) const; |
| ... | ... | @@ -157,6 +232,8 @@ public: |
| 157 | 232 | // Implemented pure virtual base class methods |
| 158 | 233 | virtual void clear(void); |
| 159 | 234 | virtual GMatrixSparse* clone(void) const; |
| 235 | + virtual double& at(const int& row, const int& column); | |
| 236 | + virtual const double& at(const int& row, const int& column) const; | |
| 160 | 237 | virtual GVector row(const int& row) const; |
| 161 | 238 | virtual void row(const int& row, const GVector& vector); |
| 162 | 239 | virtual GVector column(const int& column) const; |
| ... | ... | @@ -174,10 +251,10 @@ public: |
| 174 | 251 | virtual std::string print(const GChatter& chatter = NORMAL) const; |
| 175 | 252 | |
| 176 | 253 | // Other methods |
| 177 | - void column(const double* values, const int* rows, | |
| 178 | - int number, const int& col); | |
| 179 | - void add_to_column(const double* values, const int* rows, | |
| 180 | - int number, const int& col); | |
| 254 | + void column(const int& column, const double* values, | |
| 255 | + const int* rows, int number); | |
| 256 | + void add_to_column(const int& column, const double* values, | |
| 257 | + const int* rows, int number); | |
| 181 | 258 | void cholesky_decompose(bool compress = true); |
| 182 | 259 | GVector cholesky_solver(const GVector& vector, bool compress = true); |
| 183 | 260 | void cholesky_invert(bool compress = true); | ... | ... |
pyext/GMatrixBase.i
| ... | ... | @@ -42,29 +42,31 @@ public: |
| 42 | 42 | virtual ~GMatrixBase(void); |
| 43 | 43 | |
| 44 | 44 | // Pure virtual operators |
| 45 | - virtual GVector operator*(const GVector& vector) const = 0; | |
| 45 | + virtual GVector operator*(const GVector& vector) const = 0; | |
| 46 | 46 | |
| 47 | 47 | // Implemented base class operators |
| 48 | - virtual bool operator==(const GMatrixBase& matrix) const; | |
| 49 | - virtual bool operator!=(const GMatrixBase& matrix) const; | |
| 48 | + virtual bool operator==(const GMatrixBase& matrix) const; | |
| 49 | + virtual bool operator!=(const GMatrixBase& matrix) const; | |
| 50 | 50 | |
| 51 | 51 | // Pure virtual methods |
| 52 | - virtual void clear(void) = 0; | |
| 53 | - virtual GMatrixBase* clone(void) const = 0; | |
| 54 | - virtual GVector row(const int& row) const = 0; | |
| 55 | - virtual void row(const int& row, const GVector& vector) = 0; | |
| 56 | - virtual GVector column(const int& column) const = 0; | |
| 57 | - virtual void column(const int& column, const GVector& vector) = 0; | |
| 58 | - virtual void add_to_row(const int& row, const GVector& vector) = 0; | |
| 59 | - virtual void add_to_column(const int& column, const GVector& vector) = 0; | |
| 60 | - virtual void transpose(void) = 0; | |
| 61 | - virtual void invert(void) = 0; | |
| 62 | - virtual void negate(void) = 0; | |
| 63 | - virtual void abs(void) = 0; | |
| 64 | - virtual double fill(void) const = 0; | |
| 65 | - virtual double min(void) const = 0; | |
| 66 | - virtual double max(void) const = 0; | |
| 67 | - virtual double sum(void) const = 0; | |
| 52 | + virtual void clear(void) = 0; | |
| 53 | + virtual GMatrixBase* clone(void) const = 0; | |
| 54 | + virtual double& at(const int& row, const int& column) = 0; | |
| 55 | + virtual const double& at(const int& row, const int& column) const = 0; | |
| 56 | + virtual GVector row(const int& row) const = 0; | |
| 57 | + virtual void row(const int& row, const GVector& vector) = 0; | |
| 58 | + virtual GVector column(const int& column) const = 0; | |
| 59 | + virtual void column(const int& column, const GVector& vector) = 0; | |
| 60 | + virtual void add_to_row(const int& row, const GVector& vector) = 0; | |
| 61 | + virtual void add_to_column(const int& column, const GVector& vector) = 0; | |
| 62 | + virtual void transpose(void) = 0; | |
| 63 | + virtual void invert(void) = 0; | |
| 64 | + virtual void negate(void) = 0; | |
| 65 | + virtual void abs(void) = 0; | |
| 66 | + virtual double fill(void) const = 0; | |
| 67 | + virtual double min(void) const = 0; | |
| 68 | + virtual double max(void) const = 0; | |
| 69 | + virtual double sum(void) const = 0; | |
| 68 | 70 | |
| 69 | 71 | // Base class methods |
| 70 | 72 | const int& size(void) const; | ... | ... |
pyext/GMatrixSparse.i
| ... | ... | @@ -73,6 +73,8 @@ public: |
| 73 | 73 | // Implemented pure virtual base class methods |
| 74 | 74 | virtual void clear(void); |
| 75 | 75 | virtual GMatrixSparse* clone(void) const; |
| 76 | + virtual double& at(const int& row, const int& column); | |
| 77 | + virtual const double& at(const int& row, const int& column) const; | |
| 76 | 78 | virtual GVector row(const int& row) const; |
| 77 | 79 | virtual void row(const int& row, const GVector& vector); |
| 78 | 80 | virtual GVector column(const int& column) const; |
| ... | ... | @@ -89,10 +91,10 @@ public: |
| 89 | 91 | virtual double sum(void) const; |
| 90 | 92 | |
| 91 | 93 | // Other methods |
| 92 | - void add_to_column(const double* values, const int* rows, | |
| 93 | - int number, const int& column); | |
| 94 | - void column(const double* values, const int* rows, | |
| 95 | - int number, const int& column); | |
| 94 | + void column(const int& column, const double* values, | |
| 95 | + const int* rows, int number); | |
| 96 | + void add_to_column(const int& column, const double* values, | |
| 97 | + const int* rows, int number); | |
| 96 | 98 | void cholesky_decompose(bool compress = true); |
| 97 | 99 | GVector cholesky_solver(const GVector& vector, bool compress = true); |
| 98 | 100 | void cholesky_invert(bool compress = true); |
| ... | ... | @@ -125,4 +127,8 @@ public: |
| 125 | 127 | GMatrixSparse copy() { |
| 126 | 128 | return (*self); |
| 127 | 129 | } |
| 130 | + GMatrixSparse set(const double& value) { | |
| 131 | + (*self) = value; | |
| 132 | + return (*self); | |
| 133 | + } | |
| 128 | 134 | }; | ... | ... |
src/linalg/GMatrixSparse.cpp
| ... | ... | @@ -17,19 +17,6 @@ |
| 17 | 17 | * You should have received a copy of the GNU General Public License * |
| 18 | 18 | * along with this program. If not, see <http://www.gnu.org/licenses/>. * |
| 19 | 19 | * * |
| 20 | - * ----------------------------------------------------------------------- * | |
| 21 | - * This class implements the compressed sparse column format. The * | |
| 22 | - * following arrays are allocated: * | |
| 23 | - * * | |
| 24 | - * m_rows (n) Number of rows * | |
| 25 | - * m_cols (m) Number of columns * | |
| 26 | - * m_data (Ax) Holds all 'elements' non-zero values, in column order * | |
| 27 | - * m_colstart (Ap) Holds the index of the first element of each column * | |
| 28 | - * m_rowinx (Ai) Holds the row indices for all elements * | |
| 29 | - * * | |
| 30 | - * Column 'col' covers therefore [m_colstart[j], ..., m_colstart[j+1]-1] * | |
| 31 | - * Note that 'm_colstart' has m_cols+1 elements. * | |
| 32 | - * * | |
| 33 | 20 | ***************************************************************************/ |
| 34 | 21 | /** |
| 35 | 22 | * @file GMatrixSparse.cpp |
| ... | ... | @@ -53,20 +40,20 @@ |
| 53 | 40 | |
| 54 | 41 | /* __ Method name definitions ____________________________________________ */ |
| 55 | 42 | #define G_CONSTRUCTOR "GMatrixSparse::GMatrixSparse(int&, int&, int&)" |
| 56 | -#define G_ACCESS "GMatrixSparse::operator(int&, int&)" | |
| 57 | 43 | #define G_OP_MUL_VEC "GMatrixSparse::operator*(GVector&)" |
| 58 | 44 | #define G_OP_ADD "GMatrixSparse::operator+=(GMatrixSparse&)" |
| 59 | 45 | #define G_OP_SUB "GMatrixSparse::operator-=(GMatrixSparse&)" |
| 60 | 46 | #define G_OP_MAT_MUL "GMatrixSparse::operator*=(GMatrixSparse&)" |
| 47 | +#define G_AT "GMatrixSparse::at(int&, int&)" | |
| 61 | 48 | #define G_EXTRACT_ROW "GMatrixSymmetric::row(int&)" |
| 62 | 49 | #define G_SET_ROW "GMatrixSymmetric::row(int&, GVector&)" |
| 63 | 50 | #define G_EXTRACT_COLUMN "GMatrixSymmetric::column(int&)" |
| 64 | 51 | #define G_SET_COLUMN "GMatrixSymmetric::column(int&, GVector&)" |
| 65 | -#define G_SET_COLUMN2 "GMatrixSymmetric::column(double*, int*, int, int&)" | |
| 52 | +#define G_SET_COLUMN2 "GMatrixSymmetric::column(int&, double*, int*, int)" | |
| 66 | 53 | #define G_ADD_TO_ROW "GMatrixSymmetric::add_to_row(int&, GVector&)" |
| 67 | 54 | #define G_ADD_TO_COLUMN "GMatrixSymmetric::add_to_column(int&, GVector&)" |
| 68 | -#define G_ADD_TO_COLUMN2 "GMatrixSymmetric::add_to_column(double*, int*,"\ | |
| 69 | - " int, int&)" | |
| 55 | +#define G_ADD_TO_COLUMN2 "GMatrixSymmetric::add_to_column(int&, double*," | |
| 56 | + " int*, int)" | |
| 70 | 57 | #define G_INVERT "GMatrixSparse::invert(void)" |
| 71 | 58 | #define G_CHOL_DECOMP "GMatrixSparse::cholesky_decompose(bool)" |
| 72 | 59 | #define G_CHOL_SOLVE "GMatrixSparse::cholesky_solver(GVector&, bool)" |
| ... | ... | @@ -137,6 +124,9 @@ GMatrixSparse::GMatrixSparse(void) : GMatrixBase() |
| 137 | 124 | * of rows and columns. The elements parameter allows to specify how much |
| 138 | 125 | * physical memory should be allocated initially. By default, no memory |
| 139 | 126 | * will be allocated. |
| 127 | + * | |
| 128 | + * @todo Is there a real need to throw an empty exception? The class should | |
| 129 | + * be able to operate on empty matrices. | |
| 140 | 130 | ***************************************************************************/ |
| 141 | 131 | GMatrixSparse::GMatrixSparse(const int& rows, |
| 142 | 132 | const int& columns, |
| ... | ... | @@ -257,9 +247,12 @@ GMatrixSparse::~GMatrixSparse(void) |
| 257 | 247 | ==========================================================================*/ |
| 258 | 248 | |
| 259 | 249 | /***********************************************************************//** |
| 260 | - * @brief Assignment operator | |
| 250 | + * @brief Matrix assignment operator | |
| 261 | 251 | * |
| 262 | 252 | * @param[in] matrix Matrix. |
| 253 | + * @return Matrix. | |
| 254 | + * | |
| 255 | + * Assigns the content of another matrix to the actual matrix instance. | |
| 263 | 256 | ***************************************************************************/ |
| 264 | 257 | GMatrixSparse& GMatrixSparse::operator=(const GMatrixSparse& matrix) |
| 265 | 258 | { |
| ... | ... | @@ -288,25 +281,65 @@ GMatrixSparse& GMatrixSparse::operator=(const GMatrixSparse& matrix) |
| 288 | 281 | |
| 289 | 282 | |
| 290 | 283 | /***********************************************************************//** |
| 291 | - * @brief Access operator | |
| 284 | + * @brief Value assignment operator | |
| 285 | + * | |
| 286 | + * @param[in] value Value. | |
| 287 | + * @return Matrix. | |
| 288 | + * | |
| 289 | + * Assigns the specified @p value to all elements of the matrix. | |
| 290 | + ***************************************************************************/ | |
| 291 | +GMatrixSparse& GMatrixSparse::operator=(const double& value) | |
| 292 | +{ | |
| 293 | + // Fill any pending element to have a non-pending state | |
| 294 | + fill_pending(); | |
| 295 | + | |
| 296 | + // If value is 0 then simply reinitialize column start indices | |
| 297 | + if (value == 0) { | |
| 298 | + | |
| 299 | + // Initialise column start indices to 0 | |
| 300 | + for (int col = 0; col <= m_cols; ++col) { | |
| 301 | + m_colstart[col] = 0; | |
| 302 | + } | |
| 303 | + | |
| 304 | + } | |
| 305 | + | |
| 306 | + // ... otherwise fill column-wise | |
| 307 | + else { | |
| 308 | + | |
| 309 | + // Set column vector | |
| 310 | + GVector column(m_rows); | |
| 311 | + column = value; | |
| 312 | + | |
| 313 | + // Column-wise setting | |
| 314 | + for (int col = 0; col < m_cols; ++col) { | |
| 315 | + this->column(col, column); | |
| 316 | + } | |
| 317 | + | |
| 318 | + } | |
| 319 | + | |
| 320 | + // Return this object | |
| 321 | + return *this; | |
| 322 | +} | |
| 323 | + | |
| 324 | + | |
| 325 | +/***********************************************************************//** | |
| 326 | + * @brief Return reference to matrix element | |
| 292 | 327 | * |
| 293 | 328 | * @param[in] row Matrix row [0,...,rows()-1]. |
| 294 | 329 | * @param[in] column Matrix column [0,...,columns()-1]. |
| 330 | + * @return Reference to matrix element. | |
| 295 | 331 | * |
| 296 | - * @exception GException::out_of_range | |
| 297 | - * Row or column index out of range. | |
| 332 | + * Returns the reference to the matrix element at @p row and @p column. If | |
| 333 | + * the matrix element does not yet exist, a reference to the pending element | |
| 334 | + * with a value of 0.0 is returned. | |
| 298 | 335 | ***************************************************************************/ |
| 299 | 336 | double& GMatrixSparse::operator()(const int& row, const int& column) |
| 300 | 337 | { |
| 301 | - // Compile option: perform range check | |
| 302 | - #if defined(G_RANGE_CHECK) | |
| 303 | - if (row < 0 || row >= m_rows || column < 0 || column >= m_cols) { | |
| 304 | - throw GException::out_of_range(G_ACCESS, row, column, m_rows, m_cols); | |
| 305 | - } | |
| 306 | - #endif | |
| 338 | + // Fill pending element. This will set the value of the pending element | |
| 339 | + // to 0.0. | |
| 340 | + fill_pending(); | |
| 307 | 341 | |
| 308 | 342 | // Get element |
| 309 | - fill_pending(); | |
| 310 | 343 | int inx = get_index(row, column); |
| 311 | 344 | double* value; |
| 312 | 345 | if (inx < 0) { |
| ... | ... | @@ -324,29 +357,24 @@ double& GMatrixSparse::operator()(const int& row, const int& column) |
| 324 | 357 | |
| 325 | 358 | |
| 326 | 359 | /***********************************************************************//** |
| 327 | - * @brief Access operator (const version) | |
| 360 | + * @brief Return reference to matrix element (const version) | |
| 328 | 361 | * |
| 329 | 362 | * @param[in] row Matrix row [0,...,rows()-1]. |
| 330 | 363 | * @param[in] column Matrix column [0,...,columns()-1]. |
| 364 | + * @return Const reference to matrix element. | |
| 331 | 365 | * |
| 332 | - * @exception GException::out_of_range | |
| 333 | - * Row or column index out of range. | |
| 334 | - * | |
| 335 | - * We need here the zero element to return also a pointer for 0.0 entry that | |
| 336 | - * is not stored. Since we have the const version we don't have to care about | |
| 337 | - * modification of this zero value. | |
| 366 | + * Returns a const reference to the matrix element at @p row and @p column. | |
| 367 | + * If the matrix element does not yet exist, a reference to the zero element | |
| 368 | + * is returned. If the matrix element corresponds to the pending element, | |
| 369 | + * a reference to the pending element is returned. Otherwise, a reference | |
| 370 | + * to the matrix elements is returned. | |
| 338 | 371 | ***************************************************************************/ |
| 339 | 372 | const double& GMatrixSparse::operator()(const int& row, |
| 340 | 373 | const int& column) const |
| 341 | 374 | { |
| 342 | - // Compile option: perform range check | |
| 343 | - #if defined(G_RANGE_CHECK) | |
| 344 | - if (row < 0 || row >= m_rows || column < 0 || column >= m_cols) { | |
| 345 | - throw GException::out_of_range(G_ACCESS, row, column, m_rows, m_cols); | |
| 346 | - } | |
| 347 | - #endif | |
| 348 | - | |
| 349 | - // Get element | |
| 375 | + // Get element. We need here the zero element to return also a pointer | |
| 376 | + // for 0.0 entry that is not stored. Since we have the const version we | |
| 377 | + // don't have to care about modification of this zero value. | |
| 350 | 378 | int inx = get_index(row, column); |
| 351 | 379 | double* value; |
| 352 | 380 | if (inx < 0) { |
| ... | ... | @@ -635,6 +663,50 @@ GMatrixSparse* GMatrixSparse::clone(void) const |
| 635 | 663 | |
| 636 | 664 | |
| 637 | 665 | /***********************************************************************//** |
| 666 | + * @brief Return reference to matrix element | |
| 667 | + * | |
| 668 | + * @param[in] row Matrix row [0,...,rows()-1]. | |
| 669 | + * @param[in] column Matrix column [0,...,columns()-1]. | |
| 670 | + * @return Reference to matrix element. | |
| 671 | + * | |
| 672 | + * @exception GException::out_of_range | |
| 673 | + * Row or column index out of range. | |
| 674 | + ***************************************************************************/ | |
| 675 | +double& GMatrixSparse::at(const int& row, const int& column) | |
| 676 | +{ | |
| 677 | + // Raise exception if row or column index is out of range | |
| 678 | + if (row < 0 || row >= m_rows || column < 0 || column >= m_cols) { | |
| 679 | + throw GException::out_of_range(G_AT, row, column, m_rows, m_cols); | |
| 680 | + } | |
| 681 | + | |
| 682 | + // Return element | |
| 683 | + return ((*this)(row, column)); | |
| 684 | +} | |
| 685 | + | |
| 686 | + | |
| 687 | +/***********************************************************************//** | |
| 688 | + * @brief Return reference to matrix element (const version) | |
| 689 | + * | |
| 690 | + * @param[in] row Matrix row [0,...,rows()-1]. | |
| 691 | + * @param[in] column Matrix column [0,...,columns()-1]. | |
| 692 | + * @return Reference to matrix element. | |
| 693 | + * | |
| 694 | + * @exception GException::out_of_range | |
| 695 | + * Row or column index out of range. | |
| 696 | + ***************************************************************************/ | |
| 697 | +const double& GMatrixSparse::at(const int& row, const int& column) const | |
| 698 | +{ | |
| 699 | + // Raise exception if row or column index is out of range | |
| 700 | + if (row < 0 || row >= m_rows || column < 0 || column >= m_cols) { | |
| 701 | + throw GException::out_of_range(G_AT, row, column, m_rows, m_cols); | |
| 702 | + } | |
| 703 | + | |
| 704 | + // Return element | |
| 705 | + return ((*this)(row, column)); | |
| 706 | +} | |
| 707 | + | |
| 708 | + | |
| 709 | +/***********************************************************************//** | |
| 638 | 710 | * @brief Extract row as vector from matrix |
| 639 | 711 | * |
| 640 | 712 | * @param[in] row Row to be extracted (starting from 0). |
| ... | ... | @@ -888,10 +960,10 @@ void GMatrixSparse::column(const int& column, const GVector& vector) |
| 888 | 960 | /***********************************************************************//** |
| 889 | 961 | * @brief Insert compressed array into matrix column |
| 890 | 962 | * |
| 963 | + * @param[in] column Column index [0,...,columns()-1]. | |
| 891 | 964 | * @param[in] values Compressed array. |
| 892 | 965 | * @param[in] rows Row indices of array. |
| 893 | 966 | * @param[in] number Number of elements in array. |
| 894 | - * @param[in] column Column index [0,...,columns()-1]. | |
| 895 | 967 | * |
| 896 | 968 | * @exception GException::out_of_range |
| 897 | 969 | * Invalid column index specified. |
| ... | ... | @@ -904,12 +976,13 @@ void GMatrixSparse::column(const int& column, const GVector& vector) |
| 904 | 976 | * This is the main driver routine to insert data into a matrix. Note that |
| 905 | 977 | * there is another instance of this function that takes a vector. |
| 906 | 978 | ***************************************************************************/ |
| 907 | -void GMatrixSparse::column(const double* values, const int* rows, | |
| 908 | - int number, const int& column) | |
| 979 | +void GMatrixSparse::column(const int& column, const double* values, | |
| 980 | + const int* rows, int number) | |
| 909 | 981 | { |
| 910 | 982 | // Debug header |
| 911 | 983 | #if defined(G_DEBUG_SPARSE_INSERTION) |
| 912 | - std::cout << "GMatrixSparse::insert_col(v, i, n, " << column << "):" << std::endl; | |
| 984 | + std::cout << "GMatrixSparse::column("; | |
| 985 | + std::cout << column << ", values, rows, " << number << "):" << std::endl; | |
| 913 | 986 | std::cout << " Matrix Data : "; |
| 914 | 987 | for (int i = 0; i < m_elements; ++i) { |
| 915 | 988 | std::cout << m_data[i] << " "; |
| ... | ... | @@ -1166,10 +1239,10 @@ void GMatrixSparse::add_to_column(const int& column, const GVector& vector) |
| 1166 | 1239 | /***********************************************************************//** |
| 1167 | 1240 | * @brief Add compressed array into matrix column |
| 1168 | 1241 | * |
| 1242 | + * @param[in] column Column index [0,...,columns()-1]. | |
| 1169 | 1243 | * @param[in] values Compressed array. |
| 1170 | 1244 | * @param[in] rows Row indices of array. |
| 1171 | 1245 | * @param[in] number Number of elements in array. |
| 1172 | - * @param[in] col Column index (starting from 0). | |
| 1173 | 1246 | * |
| 1174 | 1247 | * @exception GException::out_of_range |
| 1175 | 1248 | * Invalid column index specified. |
| ... | ... | @@ -1182,12 +1255,13 @@ void GMatrixSparse::add_to_column(const int& column, const GVector& vector) |
| 1182 | 1255 | * normal and stack-based filled. Note that there is another instance of this |
| 1183 | 1256 | * method that takes a vector. |
| 1184 | 1257 | ***************************************************************************/ |
| 1185 | -void GMatrixSparse::add_to_column(const double* values, const int* rows, | |
| 1186 | - int number, const int& col) | |
| 1258 | +void GMatrixSparse::add_to_column(const int& column, const double* values, | |
| 1259 | + const int* rows, int number) | |
| 1187 | 1260 | { |
| 1188 | 1261 | // Debug header |
| 1189 | 1262 | #if defined(G_DEBUG_SPARSE_ADDITION) |
| 1190 | - std::cout << "GMatrixSparse::add_col(v, i, n, " << col << "):" << std::endl; | |
| 1263 | + std::cout << "GMatrixSparse::add_col("; | |
| 1264 | + std::cout << column << ", values, rows, " << number << "):" << std::endl; | |
| 1191 | 1265 | std::cout << " Matrix Data : "; |
| 1192 | 1266 | for (int i = 0; i < m_elements; ++i) { |
| 1193 | 1267 | std::cout << m_data[i] << " "; |
| ... | ... | @@ -1216,7 +1290,7 @@ void GMatrixSparse::add_to_column(const double* values, const int* rows, |
| 1216 | 1290 | // stack_push_column does its own argument verifications, so to avoid |
| 1217 | 1291 | // double checking we don't do anything before this call ... |
| 1218 | 1292 | if (m_stack_data != NULL) { |
| 1219 | - number = stack_push_column(values, rows, number, col); | |
| 1293 | + number = stack_push_column(values, rows, number, column); | |
| 1220 | 1294 | if (number == 0) { |
| 1221 | 1295 | return; |
| 1222 | 1296 | } |
| ... | ... | @@ -1231,8 +1305,8 @@ void GMatrixSparse::add_to_column(const double* values, const int* rows, |
| 1231 | 1305 | |
| 1232 | 1306 | // Raise an exception if the column index is invalid |
| 1233 | 1307 | #if defined(G_RANGE_CHECK) |
| 1234 | - if (col < 0 || col >= m_cols) { | |
| 1235 | - throw GException::out_of_range(G_ADD_TO_COLUMN2, col, 0, m_cols-1); | |
| 1308 | + if (column < 0 || column >= m_cols) { | |
| 1309 | + throw GException::out_of_range(G_ADD_TO_COLUMN2, column, 0, m_cols-1); | |
| 1236 | 1310 | } |
| 1237 | 1311 | #endif |
| 1238 | 1312 | |
| ... | ... | @@ -1245,8 +1319,8 @@ void GMatrixSparse::add_to_column(const double* values, const int* rows, |
| 1245 | 1319 | } // endelse: there was no stack |
| 1246 | 1320 | |
| 1247 | 1321 | // Get indices of column in matrix |
| 1248 | - int i_start = m_colstart[col]; | |
| 1249 | - int i_stop = m_colstart[col+1]; | |
| 1322 | + int i_start = m_colstart[column]; | |
| 1323 | + int i_stop = m_colstart[column+1]; | |
| 1250 | 1324 | |
| 1251 | 1325 | // Case A: the column exists in the matrix, so mix new elements with existing |
| 1252 | 1326 | // data |
| ... | ... | @@ -1267,7 +1341,7 @@ void GMatrixSparse::add_to_column(const double* values, const int* rows, |
| 1267 | 1341 | wrk_double, wrk_int, &num_mix); |
| 1268 | 1342 | |
| 1269 | 1343 | // Insert mixed column |
| 1270 | - this->column(wrk_double, wrk_int, num_mix, col); | |
| 1344 | + this->column(column, wrk_double, wrk_int, num_mix); | |
| 1271 | 1345 | |
| 1272 | 1346 | // Free workspace |
| 1273 | 1347 | delete [] wrk_int; |
| ... | ... | @@ -1277,20 +1351,23 @@ void GMatrixSparse::add_to_column(const double* values, const int* rows, |
| 1277 | 1351 | |
| 1278 | 1352 | // Case B: the column does not yet exist in the matrix, so just insert it |
| 1279 | 1353 | else { |
| 1280 | - this->column(values, rows, number, col); | |
| 1354 | + this->column(column, values, rows, number); | |
| 1281 | 1355 | } |
| 1282 | 1356 | |
| 1283 | 1357 | // Debugging: show sparse matrix after insertion |
| 1284 | 1358 | #if defined(G_DEBUG_SPARSE_ADDITION) |
| 1285 | 1359 | std::cout << " Out Data: "; |
| 1286 | - for (int i = 0; i < m_elements; ++i) | |
| 1360 | + for (int i = 0; i < m_elements; ++i) { | |
| 1287 | 1361 | std::cout << m_data[i] << " "; |
| 1362 | + } | |
| 1288 | 1363 | std::cout << std::endl << " Out Row : "; |
| 1289 | - for (int i = 0; i < m_elements; ++i) | |
| 1364 | + for (int i = 0; i < m_elements; ++i) { | |
| 1290 | 1365 | std::cout << m_rowinx[i] << " "; |
| 1366 | + } | |
| 1291 | 1367 | std::cout << std::endl << " Out Col : "; |
| 1292 | - for (int i = 0; i < m_cols+1; ++i) | |
| 1368 | + for (int i = 0; i < m_cols+1; ++i) { | |
| 1293 | 1369 | std::cout << m_colstart[i] << " "; |
| 1370 | + } | |
| 1294 | 1371 | std::cout << std::endl; |
| 1295 | 1372 | #endif |
| 1296 | 1373 | |
| ... | ... | @@ -1321,15 +1398,18 @@ void GMatrixSparse::transpose(void) |
| 1321 | 1398 | /***********************************************************************//** |
| 1322 | 1399 | * @brief Invert matrix |
| 1323 | 1400 | * |
| 1324 | - * @exception GException::feature_not_implemented | |
| 1325 | - * Feature not yet implemented. | |
| 1401 | + * Inverts the matrix using the Cholesky decomposition. This does not work | |
| 1402 | + * on any kind of matrix. | |
| 1326 | 1403 | * |
| 1327 | - * @todo Needs to be implemented. | |
| 1404 | + * @todo Specify in documentation for which kind of matrix the method works. | |
| 1328 | 1405 | ***************************************************************************/ |
| 1329 | 1406 | void GMatrixSparse::invert(void) |
| 1330 | 1407 | { |
| 1331 | - // Throw exception | |
| 1332 | - throw GException::feature_not_implemented(G_INVERT); | |
| 1408 | + // Perform Chloesky decomposition | |
| 1409 | + cholesky_decompose(true); | |
| 1410 | + | |
| 1411 | + // Invert matrix | |
| 1412 | + cholesky_invert(true); | |
| 1333 | 1413 | |
| 1334 | 1414 | // Return |
| 1335 | 1415 | return; | ... | ... |