Bug Summary

File:src/linalg/GMatrixSymmetric.cpp
Location:line 1447, column 32
Description:Array access (via field 'm_inx') results in a null pointer dereference

Annotated Source Code

1/***************************************************************************
2 * GMatrixSymmetric.cpp - Symmetric matrix class *
3 * ----------------------------------------------------------------------- *
4 * copyright (C) 2006-2013 by Juergen Knoedlseder *
5 * ----------------------------------------------------------------------- *
6 * *
7 * This program is free software: you can redistribute it and/or modify *
8 * it under the terms of the GNU General Public License as published by *
9 * the Free Software Foundation, either version 3 of the License, or *
10 * (at your option) any later version. *
11 * *
12 * This program is distributed in the hope that it will be useful, *
13 * but WITHOUT ANY WARRANTY; without even the implied warranty of *
14 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the *
15 * GNU General Public License for more details. *
16 * *
17 * You should have received a copy of the GNU General Public License *
18 * along with this program. If not, see <http://www.gnu.org/licenses/>. *
19 * *
20 ***************************************************************************/
21/**
22 * @file GMatrixSymmetric.cpp
23 * @brief Symmetric matrix class implementation
24 * @author Juergen Knoedlseder
25 */
26
27/* __ Includes ___________________________________________________________ */
28#ifdef HAVE_CONFIG_H1
29#include <config.h>
30#endif
31#include <cmath>
32#include "GTools.hpp"
33#include "GException.hpp"
34#include "GVector.hpp"
35#include "GMatrix.hpp"
36#include "GMatrixSparse.hpp"
37#include "GMatrixSymmetric.hpp"
38
39/* __ Method name definitions ____________________________________________ */
40#define G_CONSTRUCTOR"GMatrixSymmetric::GMatrixSymmetric(int&, int&)" "GMatrixSymmetric::GMatrixSymmetric(int&, int&)"
41#define G_MATRIX"GMatrixSymmetric::GMatrixSymmetric(GMatrix&)" "GMatrixSymmetric::GMatrixSymmetric(GMatrix&)"
42#define G_SPARSEMATRIX"GMatrixSymmetric::GMatrixSymmetric(GSparseMatrix&)" "GMatrixSymmetric::GMatrixSymmetric(GSparseMatrix&)"
43#define G_OP_ADD"GMatrixSymmetric::operator+=(GMatrixSymmetric&)" "GMatrixSymmetric::operator+=(GMatrixSymmetric&)"
44#define G_OP_SUB"GMatrixSymmetric::operator-=(GMatrixSymmetric&)" "GMatrixSymmetric::operator-=(GMatrixSymmetric&)"
45#define G_OP_MUL_VEC"GMatrixSymmetric::operator*(GVector&)" "GMatrixSymmetric::operator*(GVector&)"
46#define G_OP_MAT_MUL"GMatrixSymmetric::operator*=(GMatrixSymmetric&)" "GMatrixSymmetric::operator*=(GMatrixSymmetric&)"
47#define G_AT"GMatrixSymmetric::at(int&, int&)" "GMatrixSymmetric::at(int&, int&)"
48#define G_EXTRACT_ROW"GMatrixSymmetric::row(int&)" "GMatrixSymmetric::row(int&)"
49#define G_SET_ROW"GMatrixSymmetric::row(int&, GVector&)" "GMatrixSymmetric::row(int&, GVector&)"
50#define G_EXTRACT_COLUMN"GMatrixSymmetric::column(int&)" "GMatrixSymmetric::column(int&)"
51#define G_SET_COLUMN"GMatrixSymmetric::column(int&, GVector&)" "GMatrixSymmetric::column(int&, GVector&)"
52#define G_ADD_TO_ROW"GMatrixSymmetric::add_to_row(int&, GVector&)" "GMatrixSymmetric::add_to_row(int&, GVector&)"
53#define G_ADD_TO_COLUMN"GMatrixSymmetric::add_to_column(int&, GVector&)" "GMatrixSymmetric::add_to_column(int&, GVector&)"
54#define G_CHOL_DECOMP"GMatrixSymmetric::cholesky_decompose(int&)" "GMatrixSymmetric::cholesky_decompose(int&)"
55#define G_CHOL_SOLVE"GMatrixSymmetric::cholesky_solver(GVector&, int&)" "GMatrixSymmetric::cholesky_solver(GVector&, int&)"
56#define G_CHOL_INVERT"GMatrixSymmetric::cholesky_invert(int&)" "GMatrixSymmetric::cholesky_invert(int&)"
57#define G_COPY_MEMBERS"GMatrixSymmetric::copy_members(GMatrixSymmetric&)" "GMatrixSymmetric::copy_members(GMatrixSymmetric&)"
58#define G_ALLOC_MEMBERS"GMatrixSymmetric::alloc_members(int&, int&)" "GMatrixSymmetric::alloc_members(int&, int&)"
59
60
61/*==========================================================================
62 = =
63 = Constructors/destructors =
64 = =
65 ==========================================================================*/
66
67/***********************************************************************//**
68 * @brief Void constructor
69 *
70 * Constructs an empty matrix (i.e. a matrix without any elements; the number
71 * of rows and columns of the matrix will be zero).
72 *
73 * @todo Check the entire matrix class to see whether handling with an
74 * empty matrix may lead to some conflicts.
75 ***************************************************************************/
76GMatrixSymmetric::GMatrixSymmetric(void) : GMatrixBase()
77{
78 // Initialise class members for clean destruction
79 init_members();
80
81 // Return
82 return;
83}
84
85/***********************************************************************//**
86 * @brief Matrix constructor
87 *
88 * @param[in] rows Number of rows [>0].
89 * @param[in] columns Number of columns [>0].
90 *
91 * @exception GException::empty
92 * Specified number of rows or columns is not valid.
93 ***************************************************************************/
94GMatrixSymmetric::GMatrixSymmetric(const int& rows, const int& columns) :
95 GMatrixBase()
96{
97 // Continue only if matrix is valid
98 if (rows > 0 && columns > 0) {
99
100 // Initialise class members for clean destruction
101 init_members();
102
103 // Allocate matrix memory
104 alloc_members(rows, columns);
105
106 }
107 else {
108 throw GException::empty(G_CONSTRUCTOR"GMatrixSymmetric::GMatrixSymmetric(int&, int&)");
109 }
110
111 // Return
112 return;
113}
114
115
116/***********************************************************************//**
117 * @brief GMatrix to GMatrixSymmetric storage class convertor
118 *
119 * @param[in] matrix General matrix (GMatrix).
120 *
121 * @exception GException::matrix_not_symmetric
122 * Matrix is not symmetric.
123 *
124 * Converts a general matrix into the symmetric storage class. If the input
125 * matrix is not symmetric, an exception is thrown.
126 ***************************************************************************/
127GMatrixSymmetric::GMatrixSymmetric(const GMatrix& matrix)
128{
129 // Initialise class members for clean destruction
130 init_members();
131
132 // Allocate matrix memory
133 alloc_members(matrix.rows(), matrix.columns());
134
135 // Fill matrix
136 for (int col = 0; col < m_cols; ++col) {
137 for (int row = col; row < m_rows; ++row) {
138 double value_ll = matrix(row,col);
139 double value_ur = matrix(col,row);
140 if (value_ll != value_ur) {
141 throw GException::matrix_not_symmetric(G_MATRIX"GMatrixSymmetric::GMatrixSymmetric(GMatrix&)",
142 matrix.rows(),
143 matrix.columns());
144 }
145 (*this)(row, col) = matrix(row, col);
146 }
147 }
148
149 // Return
150 return;
151}
152
153
154/***********************************************************************//**
155 * @brief GMatrixSparse to GMatrixSymmetric storage class convertor
156 *
157 * @param[in] matrix Sparse matrix (GMatrixSparse).
158 *
159 * @exception GException::matrix_not_symmetric
160 * Sparse matrix is not symmetric.
161 *
162 * Converts a sparse matrix into the symmetric storage class. If the input
163 * matrix is not symmetric, an exception is thrown.
164 ***************************************************************************/
165GMatrixSymmetric::GMatrixSymmetric(const GMatrixSparse& matrix)
166{
167 // Initialise class members for clean destruction
168 init_members();
169
170 // Allocate matrix memory
171 alloc_members(matrix.rows(), matrix.columns());
172
173 // Fill matrix
174 for (int col = 0; col < m_cols; ++col) {
175 for (int row = col; row < m_rows; ++row) {
176 double value_ll = matrix(row,col);
177 double value_ur = matrix(col,row);
178 if (value_ll != value_ur) {
179 throw GException::matrix_not_symmetric(G_SPARSEMATRIX"GMatrixSymmetric::GMatrixSymmetric(GSparseMatrix&)",
180 matrix.rows(),
181 matrix.columns());
182 }
183 (*this)(row, col) = matrix(row, col);
184 }
185 }
186
187 // Return
188 return;
189}
190
191
192/***********************************************************************//**
193 * @brief Copy constructor
194 *
195 * @param[in] matrix Matrix.
196 ***************************************************************************/
197GMatrixSymmetric::GMatrixSymmetric(const GMatrixSymmetric& matrix) :
198 GMatrixBase(matrix)
199{
200 // Initialise private members for clean destruction
201 init_members();
3
Calling 'GMatrixSymmetric::init_members'
5
Returning from 'GMatrixSymmetric::init_members'
202
203 // Copy members
204 copy_members(matrix);
205
206 // Return
207 return;
208}
209
210
211/***********************************************************************//**
212 * @brief Destructor
213 ***************************************************************************/
214GMatrixSymmetric::~GMatrixSymmetric(void)
215{
216 // Free members
217 free_members();
218
219 // Return
220 return;
221}
222
223
224/*==========================================================================
225 = =
226 = Operators =
227 = =
228 ==========================================================================*/
229
230/***********************************************************************//**
231 * @brief Matrix assignment operator
232 *
233 * @param[in] matrix Matrix.
234 * @return Matrix.
235 *
236 * Assigns the content of another matrix to the actual matrix instance.
237 ***************************************************************************/
238GMatrixSymmetric& GMatrixSymmetric::operator=(const GMatrixSymmetric& matrix)
239{
240 // Execute only if object is not identical
241 if (this != &matrix) {
242
243 // Assign base class members. Note that this method will also perform
244 // the allocation of the matrix memory and the copy of the matrix
245 // attributes.
246 this->GMatrixBase::operator=(matrix);
247
248 // Free members
249 free_members();
250
251 // Initialise members
252 init_members();
253
254 // Copy members
255 copy_members(matrix);
256
257 } // endif: object was not identical
258
259 // Return this object
260 return *this;
261}
262
263
264/***********************************************************************//**
265 * @brief Value assignment operator
266 *
267 * @param[in] value Value.
268 * @return Matrix.
269 *
270 * Assigns the specified @p value to all elements of the matrix.
271 ***************************************************************************/
272GMatrixSymmetric& GMatrixSymmetric::operator=(const double& value)
273{
274 // Assign value
275 double* ptr = m_data;
276 for (int i = 0; i < m_elements; ++i) {
277 *ptr++ = value;
278 }
279
280 // Return this object
281 return *this;
282}
283
284
285/***********************************************************************//**
286 * @brief Return reference to matrix element
287 *
288 * @param[in] row Matrix row [0,...,rows()-1].
289 * @param[in] column Matrix column [0,...,columns()-1].
290 * @return Reference to matrix element.
291 ***************************************************************************/
292double& GMatrixSymmetric::operator()(const int& row, const int& column)
293{
294 // Get element index
295 int inx = (row >= column) ? m_colstart[column]+(row-column)
296 : m_colstart[row]+(column-row);
297
298 // Return element
299 return m_data[inx];
300}
301
302
303/***********************************************************************//**
304 * @brief Return reference to matrix element (const version)
305 *
306 * @param[in] row Matrix row [0,...,rows()-1].
307 * @param[in] column Matrix column [0,...,columns()-1].
308 * @return Reference to matrix element.
309 ***************************************************************************/
310const double& GMatrixSymmetric::operator()(const int& row,
311 const int& column) const
312{
313 // Get element index
314 int inx = (row >= column) ? m_colstart[column]+(row-column)
315 : m_colstart[row]+(column-row);
316
317 // Return element
318 return m_data[inx];
319}
320
321
322/***********************************************************************//**
323 * @brief Vector multiplication
324 *
325 * @param[in] vector Vector.
326 *
327 * @exception GException::matrix_vector_mismatch
328 * Vector length differs from number of columns in matrix.
329 *
330 * This method performs a vector multiplication of a matrix. The vector
331 * multiplication will produce a vector. The matrix multiplication can only
332 * be performed when the number of matrix columns is equal to the length of
333 * the vector.
334 ***************************************************************************/
335GVector GMatrixSymmetric::operator*(const GVector& vector) const
336{
337 // Raise an exception if the matrix and vector dimensions are not compatible
338 if (m_cols != vector.size()) {
339 throw GException::matrix_vector_mismatch(G_OP_MUL_VEC"GMatrixSymmetric::operator*(GVector&)", vector.size(),
340 m_rows, m_cols);
341 }
342
343 // Perform vector multiplication
344 GVector result(m_rows);
345 for (int row = 0; row < m_rows; ++row) {
346 double sum = 0.0;
347 for (int col = 0; col < m_cols; ++col) {
348 sum += (*this)(row,col) * vector[col];
349 }
350 result[row] = sum;
351 }
352
353 // Return result
354 return result;
355}
356
357
358/***********************************************************************//**
359 * @brief Negate matrix elements
360 *
361 * @return Matrix with negated elements.
362 *
363 * Returns a matrix where each element has been replaced by its negative
364 * element.
365 ***************************************************************************/
366GMatrixSymmetric GMatrixSymmetric::operator-(void) const
367{
368 // Copy matrix
369 GMatrixSymmetric matrix = *this;
370
371 // Take the absolute value of all matrix elements
372 double* ptr = matrix.m_data;
373 for (int i = 0; i < matrix.m_elements; ++i, ++ptr) {
374 *ptr = -(*ptr);
375 }
376
377 // Return matrix
378 return matrix;
379}
380
381
382/***********************************************************************//**
383 * @brief Unary matrix addition operator
384 *
385 * @param[in] matrix Matrix.
386 *
387 * @exception GException::matrix_mismatch
388 * Incompatible matrix size.
389 *
390 * This method performs a matrix addition. The operation can only succeed
391 * when the dimensions of both matrices are identical.
392 ***************************************************************************/
393GMatrixSymmetric& GMatrixSymmetric::operator+=(const GMatrixSymmetric& matrix)
394{
395 // Raise an exception if the matrix dimensions are not compatible
396 if (m_rows != matrix.m_rows || m_cols != matrix.m_cols) {
397 throw GException::matrix_mismatch(G_OP_ADD"GMatrixSymmetric::operator+=(GMatrixSymmetric&)",
398 m_rows, m_cols,
399 matrix.m_rows, matrix.m_cols);
400 }
401
402 // Add all matrix elements
403 const double* src = matrix.m_data;
404 double* dst = m_data;
405 for (int i = 0; i < m_elements; ++i) {
406 *dst++ += *src++;
407 }
408
409 // Return result
410 return *this;
411}
412
413
414/***********************************************************************//**
415 * @brief Unary matrix subtraction operator
416 *
417 * @param[in] matrix Matrix.
418 *
419 * @exception GException::matrix_mismatch
420 * Incompatible matrix size.
421 *
422 * This method performs a matrix addition. The operation can only succeed
423 * when the dimensions of both matrices are identical.
424 ***************************************************************************/
425GMatrixSymmetric& GMatrixSymmetric::operator-=(const GMatrixSymmetric& matrix)
426{
427 // Raise an exception if the matrix dimensions are not compatible
428 if (m_rows != matrix.m_rows || m_cols != matrix.m_cols) {
429 throw GException::matrix_mismatch(G_OP_SUB"GMatrixSymmetric::operator-=(GMatrixSymmetric&)",
430 m_rows, m_cols,
431 matrix.m_rows, matrix.m_cols);
432 }
433
434 // Subtract all matrix elements
435 const double* src = matrix.m_data;
436 double* dst = m_data;
437 for (int i = 0; i < m_elements; ++i) {
438 *dst++ -= *src++;
439 }
440
441 // Return result
442 return *this;
443}
444
445
446/*==========================================================================
447 = =
448 = Public methods =
449 = =
450 ==========================================================================*/
451
452/***********************************************************************//**
453 * @brief Clear matrix
454 ***************************************************************************/
455void GMatrixSymmetric::clear(void)
456{
457 // Free members
458 free_members();
459
460 // Initialise private members
461 init_members();
462
463 // Return
464 return;
465}
466
467
468/***********************************************************************//**
469 * @brief Clone matrix
470 *
471 * @return Pointer to deep copy of matrix.
472 ***************************************************************************/
473GMatrixSymmetric* GMatrixSymmetric::clone(void) const
474{
475 // Clone matrix
476 return new GMatrixSymmetric(*this);
477}
478
479
480/***********************************************************************//**
481 * @brief Return reference to matrix element
482 *
483 * @param[in] row Matrix row [0,...,rows()-1].
484 * @param[in] column Matrix column [0,...,columns()-1].
485 * @return Reference to matrix element.
486 *
487 * @exception GException::out_of_range
488 * Row or column index out of range.
489 ***************************************************************************/
490double& GMatrixSymmetric::at(const int& row, const int& column)
491{
492 // Raise exception if row or column index is out of range
493 if (row < 0 || row >= m_rows || column < 0 || column >= m_cols) {
494 throw GException::out_of_range(G_AT"GMatrixSymmetric::at(int&, int&)", row, column, m_rows, m_cols);
495 }
496
497 // Get element index
498 int inx = (row >= column) ? m_colstart[column]+(row-column)
499 : m_colstart[row]+(column-row);
500
501 // Return element
502 return m_data[inx];
503}
504
505
506/***********************************************************************//**
507 * @brief Return reference to matrix element (const version)
508 *
509 * @param[in] row Matrix row [0,...,rows()-1].
510 * @param[in] column Matrix column [0,...,columns()-1].
511 * @return Reference to matrix element.
512 *
513 * @exception GException::out_of_range
514 * Row or column index out of range.
515 ***************************************************************************/
516const double& GMatrixSymmetric::at(const int& row, const int& column) const
517{
518 // Raise exception if row or column index is out of range
519 if (row < 0 || row >= m_rows || column < 0 || column >= m_cols) {
520 throw GException::out_of_range(G_AT"GMatrixSymmetric::at(int&, int&)", row, column, m_rows, m_cols);
521 }
522
523 // Get element index
524 int inx = (row >= column) ? m_colstart[column]+(row-column)
525 : m_colstart[row]+(column-row);
526
527 // Return element
528 return m_data[inx];
529}
530
531
532/***********************************************************************//**
533 * @brief Extract row as vector from matrix
534 *
535 * @param[in] row Row to be extracted (starting from 0).
536 *
537 * @exception GException::out_of_range
538 * Invalid row index specified.
539 *
540 * This method extracts a matrix row into a vector.
541 ***************************************************************************/
542GVector GMatrixSymmetric::row(const int& row) const
543{
544 // Raise an exception if the row index is invalid
545 #if defined(G_RANGE_CHECK1)
546 if (row < 0 || row >= m_rows) {
547 throw GException::out_of_range(G_EXTRACT_ROW"GMatrixSymmetric::row(int&)", row, 0, m_rows-1);
548 }
549 #endif
550
551 // Create result vector
552 GVector result(m_cols);
553
554 // Extract row into vector
555 for (int col = 0; col < m_cols; ++col) {
556 result[col] = (*this)(row,col);
557 }
558
559 // Return vector
560 return result;
561}
562
563
564/***********************************************************************//**
565 * @brief Set row in matrix
566 *
567 * @todo To be implemented.
568 ***************************************************************************/
569void GMatrixSymmetric::row(const int& row, const GVector& vector)
570{
571 // Raise an exception if the row index is invalid
572 #if defined(G_RANGE_CHECK1)
573 if (row < 0 || row >= m_rows) {
574 throw GException::out_of_range(G_SET_ROW"GMatrixSymmetric::row(int&, GVector&)", row, 0, m_rows-1);
575 }
576 #endif
577
578 // Return
579 return;
580}
581
582
583/***********************************************************************//**
584 * @brief Extract column as vector from matrix
585 *
586 * @param[in] column Column index [0,...,columns()-1].
587 *
588 * @exception GException::out_of_range
589 * Invalid row index specified.
590 *
591 * This method extracts a matrix column into a vector.
592 ***************************************************************************/
593GVector GMatrixSymmetric::column(const int& column) const
594{
595 // Raise an exception if the column index is invalid
596 #if defined(G_RANGE_CHECK1)
597 if (column < 0 || column >= m_cols) {
598 throw GException::out_of_range(G_EXTRACT_COLUMN"GMatrixSymmetric::column(int&)", column, 0, m_cols-1);
599 }
600 #endif
601
602 // Create result vector
603 GVector result(m_rows);
604
605 // Extract column into vector
606 for (int row = 0; row < m_rows; ++row) {
607 result[row] = (*this)(row, column);
608 }
609
610 // Return vector
611 return result;
612}
613
614
615/***********************************************************************//**
616 * @brief Set matrix column from vector
617 *
618 * @param[in] column Column index [0,...,columns()-1].
619 * @param[in] vector Vector.
620 *
621 * @exception GException::out_of_range
622 * Invalid column index specified.
623 * @exception GException::matrix_vector_mismatch
624 * Matrix dimension mismatches the vector size.
625 *
626 * Inserts the content of a vector into a matrix column. Any previous
627 * content in the matrix column will be overwritted.
628 ***************************************************************************/
629void GMatrixSymmetric::column(const int& column, const GVector& vector)
630{
631 // Raise an exception if the column index is invalid
632 #if defined(G_RANGE_CHECK1)
633 if (column < 0 || column >= m_cols) {
634 throw GException::out_of_range(G_SET_COLUMN"GMatrixSymmetric::column(int&, GVector&)", column, 0, m_cols-1);
635 }
636 #endif
637
638 // Raise an exception if the matrix and vector dimensions are not
639 // compatible
640 if (m_rows != vector.size()) {
641 throw GException::matrix_vector_mismatch(G_SET_COLUMN"GMatrixSymmetric::column(int&, GVector&)", vector.size(),
642 m_rows, m_cols);
643 }
644
645 // Insert column into vector
646 for (int row = 0; row < m_rows; ++row) {
647 (*this)(row, column) = vector[row];
648 }
649
650 // Return
651 return;
652}
653
654
655/***********************************************************************//**
656 * @brief Add row to matrix elements
657 *
658 * @todo To be implemented.
659 ***************************************************************************/
660void GMatrixSymmetric::add_to_row(const int& row, const GVector& vector)
661{
662 // Raise an exception if the row index is invalid
663 #if defined(G_RANGE_CHECK1)
664 if (row < 0 || row >= m_rows) {
665 throw GException::out_of_range(G_ADD_TO_ROW"GMatrixSymmetric::add_to_row(int&, GVector&)", row, 0, m_rows-1);
666 }
667 #endif
668
669 // Return
670 return;
671}
672
673
674/***********************************************************************//**
675 * @brief Add vector column into matrix
676 *
677 * @param[in] column Column index [0,...,columns()-1].
678 * @param[in] vector Vector.
679 *
680 * @exception GException::out_of_range
681 * Invalid column index specified.
682 * @exception GException::matrix_vector_mismatch
683 * Matrix dimension mismatches the vector size.
684 *
685 * Adds the content of a vector to a matrix column.
686 ***************************************************************************/
687void GMatrixSymmetric::add_to_column(const int& column, const GVector& vector)
688{
689 // Raise an exception if the column index is invalid
690 #if defined(G_RANGE_CHECK1)
691 if (column < 0 || column >= m_cols) {
692 throw GException::out_of_range(G_ADD_TO_COLUMN"GMatrixSymmetric::add_to_column(int&, GVector&)", column, 0, m_cols-1);
693 }
694 #endif
695
696 // Raise an exception if the matrix and vector dimensions are not
697 // compatible
698 if (m_rows != vector.size()) {
699 throw GException::matrix_vector_mismatch(G_ADD_TO_COLUMN"GMatrixSymmetric::add_to_column(int&, GVector&)", vector.size(),
700 m_rows, m_cols);
701 }
702
703 // Insert column into vector
704 for (int row = 0; row < m_rows; ++row) {
705 (*this)(row, column) += vector[row];
706 }
707
708 // Return
709 return;
710}
711
712
713/***********************************************************************//**
714 * @brief Return inverted matrix
715 *
716 * @return Inverted matrix.
717 *
718 * Returns inverse of matrix. Inversion is done for the moment using Cholesky
719 * decomposition. This does not work on any kind of matrix.
720 *
721 * @todo Specify in documentation for which kind of matrix the method works.
722 ***************************************************************************/
723GMatrixSymmetric GMatrixSymmetric::invert(void) const
724{
725 // Allocate result matrix
726 GMatrixSymmetric matrix(m_cols, m_rows);
727
728 // Invert matrix
729 matrix.cholesky_invert(true);
730
731 // Return matrix
732 return matrix;
733}
734
735
736/***********************************************************************//**
737 * @brief Solves linear matrix equation
738 *
739 * @param[in] vector Solution vector.
740 *
741 * Solves the linear equation
742 *
743 * \f[M \times {\tt solution} = {\tt vector} \f]
744 *
745 * where \f$M\f$ is the matrix, \f${\tt vector}\f$ is the result, and
746 * \f${\tt solution}\f$ is the solution. Solving is done using Cholesky
747 * decomposition. This does not work on any kind of matrix.
748 *
749 * @todo Specify in documentation for which kind of matrix the method works.
750 ***************************************************************************/
751GVector GMatrixSymmetric::solve(const GVector& vector) const
752{
753 // Get Cholesky decomposition of matrix
754 GMatrixSymmetric decomposition = cholesky_decompose(true);
755
756 // Solve linear equation
757 GVector result = decomposition.cholesky_solver(vector);
758
759 // Return result
760 return result;
761}
762
763
764/***********************************************************************//**
765 * @brief Return absolute of matrix
766 *
767 * @return Absolute of matrix
768 *
769 * Returns matrix where all elements of the matrix have been replaced by
770 * their absolute values.
771 ***************************************************************************/
772GMatrixSymmetric GMatrixSymmetric::abs(void) const
773{
774 // Allocate result matrix
775 GMatrixSymmetric matrix(m_rows, m_cols);
776
777 // Take the absolute value of all matrix elements
778 double* src = m_data;
779 double* dst = matrix.m_data;
780 for (int i = 0; i < m_elements; ++i) {
781 *dst++ = std::abs(*src++);
782 }
783
784 // Return matrix
785 return matrix;
786}
787
788
789/***********************************************************************//**
790 * @brief Determine fill of matrix
791 *
792 * @return Matrix fill (between 0 and 1).
793 *
794 * The fill of a matrix is defined as the number of non-zero elements
795 * devided by the total number of matrix elements.
796 ***************************************************************************/
797double GMatrixSymmetric::fill(void) const
798{
799 // Determine the number of zero elements
800 int zero = 0;
801 for (int col = 0, i = 0; col < m_cols; ++col) {
802 if (m_data[i++] == 0.0) { // Count diag. once
803 zero++;
804 }
805 for (int row = col+1; row < m_rows; ++row) {
806 if (m_data[i++] == 0.0) { // Count off-diag. twice
807 zero +=2;
808 }
809 }
810 }
811
812 // Return the fill
813 return (1.0-double(zero)/double(m_elements));
814}
815
816
817/***********************************************************************//**
818 * @brief Sum matrix elements
819 *
820 * @return Sum of all matrix elements.
821 ***************************************************************************/
822double GMatrixSymmetric::sum(void) const
823{
824 // Initialise matrix sums (diagonal and off-diagonal)
825 double diag = 0.0;
826 double off_diag = 0.0;
827
828 // Calulate sum over diagonal elements
829 for (int row = 0; row < m_rows; ++row) {
830 diag += m_data[m_colstart[row]];
831 }
832
833 // Calulate sum over off-diagonal elements
834 for (int row = 0; row < m_rows; ++row) {
835 for (int col = row+1; col < m_cols; ++col) {
836 off_diag += m_data[m_colstart[row]+(col-row)];
837 }
838 }
839
840 // Calculate total
841 double result = diag + 2.0 * off_diag;
842
843 // Return result
844 return result;
845}
846
847
848/***********************************************************************//**
849 * @brief Extract lower triangle of matrix
850 *
851 * This method extracts the lower triangle of a matrix into another matrix.
852 * (including the diagonal elements).
853 * All remaining matrix elements will be zero.
854 ***************************************************************************/
855GMatrix GMatrixSymmetric::extract_lower_triangle(void) const
856{
857 // Define result matrix
858 GMatrix result(m_rows, m_cols);
859
860 // Extract all elements
861 for (int row = 0; row < m_rows; ++row) {
862 for (int col = 0; col <= row; ++col) {
863 result(row,col) = m_data[m_colstart[col]+(row-col)];
864 }
865 }
866
867 // Return result
868 return result;
869}
870
871
872/***********************************************************************//**
873 * @brief Extract upper triangle of matrix
874 *
875 * This method extracts the upper triangle of a matrix into another matrix.
876 * (including the diagonal elements).
877 * All remaining matrix elements will be zero.
878 ***************************************************************************/
879GMatrix GMatrixSymmetric::extract_upper_triangle(void) const
880{
881 // Define result matrix
882 GMatrix result(m_rows, m_cols);
883
884 // Extract all elements
885 for (int row = 0; row < m_rows; ++row) {
886 for (int col = row; col < m_cols; ++col) {
887 result(row,col) = m_data[m_colstart[row]+(col-row)];
888 }
889 }
890
891 // Return result
892 return result;
893}
894
895
896/***********************************************************************//**
897 * @brief Return Cholesky decomposition
898 *
899 * @param[in] compress Use zero-row/column compression (defaults to true).
900 * @return Cholesky decomposition of matrix
901 *
902 * @exception GException::matrix_not_pos_definite
903 * Matrix is not positive definite.
904 * @exception GException::matrix_zero
905 * All matrix elements are zero.
906 *
907 * Returns the Cholesky decomposition of a sparse matrix. The decomposition
908 * is stored within a GMatrixSymmetric object.
909 *
910 * The method is inspired by the algorithm found in Numerical Recipes.
911 * The decomposition, which is a matrix occupying only the lower triange,
912 * is stored in the elements of the symmetric matrix. To visualise the
913 * matrix one has to use 'lower_triangle()' to extract the relevant part.
914 * Case A operates on a full matrix, Case B operates on a (logically)
915 * compressed matrix where zero rows/columns have been removed.
916 ***************************************************************************/
917GMatrixSymmetric GMatrixSymmetric::cholesky_decompose(const bool& compress) const
918{
919 // Create copy of matrix
920 GMatrixSymmetric matrix = *this;
2
Calling copy constructor for 'GMatrixSymmetric'
6
Returning from copy constructor for 'GMatrixSymmetric'
921
922 // Set-up incides of non zero rows if matrix compression is requested
923 if (compress) {
7
Taking true branch
924 matrix.set_inx();
8
Calling 'GMatrixSymmetric::set_inx'
925 }
926
927 // Check if zero-row/col compression is needed
928 int no_zeros = ((compress && (matrix.m_num_inx == matrix.m_rows)) || !compress);
929
930 // Case A: no zero-row/col compression needed
931 if (no_zeros) {
932
933 // Loop over upper triangle (col >= row)
934 double diag = 0.0;
935 for (int row = 0; row < matrix.m_rows; ++row) {
936 double* ptr = matrix.m_data + matrix.m_colstart[row];
937 for (int col = row; col < matrix.m_cols; ++col, ++ptr) {
938 // sum = M(row,col)
939 double sum = *ptr;
940 for (int k = 0; k < row; ++k) {
941 int offset = matrix.m_colstart[k] - k; // is always positive
942 sum -= matrix.m_data[offset+row] * matrix.m_data[offset+col]; // sum -= M(row,k)*M(col,k)
943 }
944 if (row == col) {
945 if (sum <= 0.0) {
946 throw GException::matrix_not_pos_definite(G_CHOL_DECOMP"GMatrixSymmetric::cholesky_decompose(int&)", row, sum);
947 }
948 *ptr = std::sqrt(sum); // M(row,row) = sqrt(sum)
949 diag = 1.0/(*ptr);
950 }
951 else {
952 *ptr = sum*diag; // M(row,col) = sum/M(row,row)
953 }
954 }
955 }
956 } // endif: there were no zero rows/cols in matrix
957
958 // Case B: zero-row/col compression needed
959 else if (matrix.m_num_inx > 0) {
960
961 // Allocate loop variables and pointers
962 int row;
963 int col;
964 int k;
965 int* row_ptr;
966 int* col_ptr;
967 int* k_ptr;
968
969 // Loop over upper triangle (col >= row)
970 double diag = 0.0;
971 for (row = 0, row_ptr = matrix.m_inx; row < matrix.m_num_inx; ++row, ++row_ptr) {
972 double* ptr_0 = matrix.m_data + matrix.m_colstart[*row_ptr] - *row_ptr;
973 for (col = row, col_ptr = matrix.m_inx + row; col < matrix.m_num_inx; ++col, ++col_ptr) {
974 double* ptr = ptr_0 + *col_ptr;
975 double sum = *ptr; // sum = M(row,col)
976 for (k = 0, k_ptr = matrix.m_inx; k < row; ++k, ++k_ptr) {
977 int offset = matrix.m_colstart[*k_ptr] - *k_ptr; // is always positive
978 sum -= matrix.m_data[offset+*row_ptr] *
979 matrix.m_data[offset+*col_ptr];
980 // sum -= M(row,k)*M(col,k)
981 }
982 if (*row_ptr == *col_ptr) {
983 if (sum <= 0.0) {
984 throw GException::matrix_not_pos_definite(G_CHOL_DECOMP"GMatrixSymmetric::cholesky_decompose(int&)", *row_ptr, sum);
985 }
986 *ptr = std::sqrt(sum); // M(row,row) = sqrt(sum)
987 diag = 1.0/(*ptr);
988 }
989 else {
990 *ptr = sum*diag; // M(row,col) = sum/M(row,row)
991 }
992 }
993 }
994 } // endelse: zero-row/col compression needed
995
996 // Case C: all matrix elements are zero
997 else {
998 throw GException::matrix_zero(G_CHOL_DECOMP"GMatrixSymmetric::cholesky_decompose(int&)");
999 }
1000
1001 // Return matrix
1002 return matrix;
1003}
1004
1005
1006/***********************************************************************//**
1007 * @brief Cholesky solver
1008 *
1009 * @param[in] vector Vector for which should be solved.
1010 * @param[in] compress Use zero-row/column compression (default: true).
1011 *
1012 * @exception GException::matrix_vector_mismatch
1013 * Matrix and vector do not match.
1014 * @exception GException::matrix_zero
1015 * All matrix elements are zero.
1016 *
1017 * Solves the linear equation A*x=b using a Cholesky decomposition of A.
1018 * This function is to be applied on a decomposition GMatrixSymmetric matrix
1019 * that is produced by 'cholesky_decompose'. Case A operates on a full
1020 * matrix, Case B on a zero rows/columns (logically) compressed matrix.
1021 ***************************************************************************/
1022GVector GMatrixSymmetric::cholesky_solver(const GVector& vector,
1023 const bool& compress) const
1024{
1025 // Raise an exception if the matrix and vector dimensions are not compatible
1026 if (m_rows != vector.size()) {
1027 throw GException::matrix_vector_mismatch(G_CHOL_SOLVE"GMatrixSymmetric::cholesky_solver(GVector&, int&)", vector.size(),
1028 m_rows, m_cols);
1029 }
1030
1031 // Allocate result vector
1032 GVector x(m_rows);
1033
1034 // Check if zero-row/col compression is needed
1035 int no_zeros = ((compress && (m_num_inx == m_rows)) || !compress);
1036
1037 // Case A: no zero-row/col compression needed
1038 if (no_zeros) {
1039
1040 // Solve L*y=b, storing y in x (row>k)
1041 for (int row = 0; row < m_rows; ++row) {
1042 double sum = vector[row];
1043 for (int k = 0; k < row; ++k) {
1044 sum -= m_data[m_colstart[k]+(row-k)] * x[k]; // sum -= M(row,k) * x(k)
1045 }
1046 x[row] = sum/m_data[m_colstart[row]]; // x(row) = sum/M(row,row)
1047 }
1048
1049 // Solve trans(L)*x=y (k>row)
1050 for (int row = m_rows-1; row >= 0; --row) {
1051 double sum = x[row];
1052 double* ptr = m_data + m_colstart[row] + 1;
1053 for (int k = row+1; k < m_rows; ++k) {
1054 sum -= *ptr++ * x[k]; // sum -= M(k,row) * x(k)
1055 }
1056 x[row] = sum/m_data[m_colstart[row]]; // x(row) = sum/M(row,row)
1057 }
1058 } // endif: no zero-row/col compression needed
1059
1060 // Case B: zero-row/col compression needed
1061 else if (m_num_inx > 0) {
1062
1063 // Allocate loop variables and pointers
1064 int row;
1065 int k;
1066 int* row_ptr;
1067 int* k_ptr;
1068
1069 // Solve L*y=b, storing y in x (row>k)
1070 for (row = 0, row_ptr = m_inx; row < m_num_inx; ++row, ++row_ptr) {
1071 double sum = vector[*row_ptr];
1072 double* ptr = m_data + *row_ptr;
1073 for (k = 0, k_ptr = m_inx; k < row; ++k, ++k_ptr) {
1074 sum -= *(ptr + m_colstart[*k_ptr] - *k_ptr) * x[*k_ptr]; // sum -= M(row,k) * x(k)
1075 }
1076 x[*row_ptr] = sum/m_data[m_colstart[*row_ptr]]; // x(row) = sum/M(row,row)
1077 }
1078
1079 // Solve trans(L)*x=y (k>row)
1080 for (row = m_num_inx-1, row_ptr = m_inx+m_num_inx-1; row >= 0; --row, --row_ptr) {
1081 double sum = x[*row_ptr];
1082 double* ptr_diag = m_data + m_colstart[*row_ptr];
1083 double* ptr = ptr_diag - *row_ptr;
1084 for (k = row+1, k_ptr = m_inx+row+1; k < m_num_inx; ++k, ++k_ptr) {
1085 sum -= *(ptr + *k_ptr) * x[*k_ptr]; // sum -= M(k,row) * x(k)
1086 }
1087 x[*row_ptr] = sum/(*ptr_diag); // x(row) = sum/M(row,row)
1088 }
1089 } // endelse: zero-row/col compression needed
1090
1091 // Case C: all matrix elements are zero
1092 else {
1093 throw GException::matrix_zero(G_CHOL_SOLVE"GMatrixSymmetric::cholesky_solver(GVector&, int&)");
1094 }
1095
1096 // Return result vector
1097 return x;
1098}
1099
1100
1101/***********************************************************************//**
1102 * @brief Invert matrix using a Cholesky decomposition
1103 *
1104 * @param[in] compress Use zero-row/column compression (defaults to true).
1105 * @return Inverted matrix.
1106 *
1107 * @exception GException::matrix_zero
1108 * All matrix elements are zero.
1109 *
1110 * Inverts the matrix using a Cholesky decomposition.
1111 *
1112 * The method distinguish two cases. Case A operates on a full matrix while
1113 * Case B operates on a (logically) compressed matrix where all zero
1114 * rows/columns are skipped.
1115 ***************************************************************************/
1116GMatrixSymmetric GMatrixSymmetric::cholesky_invert(const bool& compress) const
1117{
1118 // Generate Cholesky decomposition of matrix
1119 GMatrixSymmetric matrix = cholesky_decompose(compress);
1
Calling 'GMatrixSymmetric::cholesky_decompose'
1120
1121 // Check if zero-row/col compression is needed
1122 int no_zeros = ((compress && (matrix.m_num_inx == matrix.m_rows)) || !compress);
1123
1124 // Case A: no zero-row/col compression needed
1125 if (no_zeros) {
1126
1127 // Generate inverse of Cholesky decomposition (col>row)
1128 for (int row = 0; row < matrix.m_rows; ++row) {
1129
1130 // M(row,row) = 1/M(row,row)
1131 double* ptr = matrix.m_data + matrix.m_colstart[row];
1132 *ptr = 1.0/(*ptr);
1133
1134 for (int col = row+1; col < matrix.m_cols; ++col) {
1135
1136 // sum -= M(col,k)*M(k,row)
1137 double sum = 0.0;
1138 double* ptr1 = matrix.m_data + col - row;
1139 double* ptr2 = ptr;
1140 for (int k = row; k < col; ++k) {
1141 sum -= *(ptr1-- + matrix.m_colstart[k]) * *ptr2++;
1142 }
1143
1144 // M(col,row) = sum/M(col,col)
1145 *(ptr+col-row) = sum/matrix.m_data[matrix.m_colstart[col]];
1146 }
1147 }
1148
1149 // Matrix multiplication (col>=row)
1150 for (int row = 0; row < matrix.m_rows; ++row) {
1151 double* ptr = matrix.m_data + matrix.m_colstart[row];
1152 for (int col = row; col < matrix.m_cols; ++col) {
1153 // sum += M(row,k)*M(k,col)
1154 double sum = 0.0;
1155 double* ptr1 = ptr + col - row;
1156 double* ptr2 = matrix.m_data + matrix.m_colstart[col];
1157 for (int k = col; k < matrix.m_cols; ++k) {
1158 sum += *ptr1++ * *ptr2++;
1159 }
1160 // M(row,col) = sum
1161 *(ptr+col-row) = sum;
1162 }
1163 }
1164 } // endif: no zero-row/col compression needed
1165
1166 // Case B: zero-row/col compression needed
1167 else if (matrix.m_num_inx > 0) {
1168
1169 // Allocate loop variables and pointers
1170 int row;
1171 int col;
1172 int k;
1173 int* row_ptr;
1174 int* col_ptr;
1175 int* k_ptr;
1176
1177 // Generate inverse of Cholesky decomposition (col>row)
1178 for (row = 0, row_ptr = matrix.m_inx;
1179 row < matrix.m_num_inx; ++row, ++row_ptr) {
1180
1181 // M(row,row) = 1/M(row,row)
1182 double* ptr_diag = matrix.m_data + matrix.m_colstart[*row_ptr];
1183 double* ptr_2 = ptr_diag - *row_ptr;
1184 *ptr_diag = 1.0/(*ptr_diag);
1185
1186 for (col = row+1, col_ptr = matrix.m_inx+row+1;
1187 col < matrix.m_num_inx; ++col, ++col_ptr) {
1188
1189 // sum -= M(col,k)*M(k,row)
1190 double sum = 0.0;
1191 double* ptr_1 = matrix.m_data + *col_ptr;
1192 for (k = row, k_ptr = matrix.m_inx+row;
1193 k < col; ++k, ++k_ptr) {
1194 sum -= *(ptr_1 + matrix.m_colstart[*k_ptr] - *k_ptr) *
1195 *(ptr_2 + *k_ptr);
1196 }
1197
1198 // M(col,row) = sum/M(col,col)
1199 *(ptr_2 + *col_ptr) =
1200 sum/matrix.m_data[matrix.m_colstart[*col_ptr]];
1201 }
1202 }
1203
1204 // Matrix multiplication (col>=row)
1205 for (row = 0, row_ptr = matrix.m_inx;
1206 row < matrix.m_num_inx; ++row, ++row_ptr) {
1207 double* ptr_diag = matrix.m_data + matrix.m_colstart[*row_ptr];
1208 double* ptr_1 = ptr_diag - *row_ptr;
1209
1210 for (col = row, col_ptr = matrix.m_inx+row;
1211 col < matrix.m_num_inx; ++col, ++col_ptr) {
1212
1213 // sum += M(row,k)*M(k,col)
1214 double sum = 0.0;
1215 double* ptr_2 = matrix.m_data + matrix.m_colstart[*col_ptr] - *col_ptr;
1216 for (k = col, k_ptr = matrix.m_inx+col;
1217 k < matrix.m_num_inx; ++k, ++k_ptr) {
1218 sum += *(ptr_1 + *k_ptr) * *(ptr_2 + *k_ptr);
1219 }
1220
1221 // M(row,col) = sum
1222 *(ptr_1 + *col_ptr) = sum;
1223 }
1224 }
1225 } // endelse: zero-row/col compression needed
1226
1227 // Case C: all matrix elements are zero
1228 else {
1229 throw GException::matrix_zero(G_CHOL_INVERT"GMatrixSymmetric::cholesky_invert(int&)");
1230 }
1231
1232 // Return matrix
1233 return matrix;
1234}
1235
1236
1237/***********************************************************************//**
1238 * @brief Print matrix
1239 *
1240 * @param[in] chatter Chattiness (defaults to NORMAL).
1241 * @return String containing matrix information
1242 ***************************************************************************/
1243std::string GMatrixSymmetric::print(const GChatter& chatter) const
1244{
1245 // Initialise result string
1246 std::string result;
1247
1248 // Append header
1249 result.append("=== GMatrixSymmetric ===");
1250
1251 // Continue only if chatter is not silent
1252 if (chatter != SILENT) {
1253
1254 // Append information
1255 result.append("\n"+gammalib::parformat("Number of rows"));
1256 result.append(gammalib::str(m_rows));
1257 if (m_rowsel != NULL__null) {
1258 result.append(" (compressed "+gammalib::str(m_num_rowsel)+")");
1259 }
1260 result.append("\n"+gammalib::parformat("Number of columns"));
1261 result.append(gammalib::str(m_cols));
1262 if (m_colsel != NULL__null) {
1263 result.append(" (compressed "+gammalib::str(m_num_colsel)+")");
1264 }
1265 result.append("\n"+gammalib::parformat("Number of elements"));
1266 result.append(gammalib::str(m_elements));
1267 result.append("\n"+gammalib::parformat("Number of allocated cells"));
1268 result.append(gammalib::str(m_alloc));
1269
1270 // Append elements and compression schemes
1271 result.append(print_elements(chatter));
1272 result.append(print_row_compression(chatter));
1273 result.append(print_col_compression(chatter));
1274
1275 } // endif: chatter was not silent
1276
1277 // Return result
1278 return result;
1279}
1280
1281
1282/*==========================================================================
1283 = =
1284 = Private methods =
1285 = =
1286 ==========================================================================*/
1287
1288/***********************************************************************//**
1289 * @brief Initialise class mambers
1290 ***************************************************************************/
1291void GMatrixSymmetric::init_members(void)
1292{
1293 // Initialise members
1294 m_num_inx = 0;
1295 m_inx = NULL__null;
4
Null pointer value stored to 'matrix.m_inx'
1296
1297 // Return
1298 return;
1299}
1300
1301
1302/***********************************************************************//**
1303 * @brief Copy class members
1304 *
1305 * @param[in] matrix Matrix.
1306 ***************************************************************************/
1307void GMatrixSymmetric::copy_members(const GMatrixSymmetric& matrix)
1308{
1309 // Copy attributes
1310 m_num_inx = matrix.m_num_inx;
1311
1312 // Copy index selection
1313 if (m_cols > 0) {
1314 m_inx = new int[m_cols];
1315 for (int i = 0; i < m_cols; ++i) {
1316 m_inx[i] = matrix.m_inx[i];
1317 }
1318 }
1319
1320 // Return
1321 return;
1322}
1323
1324
1325/***********************************************************************//**
1326 * @brief Delete class members
1327 ***************************************************************************/
1328void GMatrixSymmetric::free_members(void)
1329{
1330 // De-allocate only if memory has indeed been allocated by derived class
1331 if (m_inx != NULL__null) delete [] m_inx;
1332
1333 // Return
1334 return;
1335}
1336
1337
1338/***********************************************************************//**
1339 * @brief Allocates matrix memory
1340 *
1341 * @param[in] rows Number of rows.
1342 * @param[in] columns Number of columns.
1343 *
1344 * @exception GException::matrix_not_symmetric
1345 * Matrix is not symmetric.
1346 *
1347 * This method is the main constructor code that allocates and initialises
1348 * memory for matrix elements. The method assumes that no memory has been
1349 * allocated for the matrix elements, the column start index array and the
1350 * index array.
1351 * The method allocates the memory for matrix elements, the column start
1352 * indices and the index array, sets all matrix elements to 0.0, and sets
1353 * the column start indices. The content of the index array is undefined.
1354 *
1355 * @todo Verify if the index array m_inx should be initialized.
1356 ***************************************************************************/
1357void GMatrixSymmetric::alloc_members(const int& rows, const int& columns)
1358{
1359 // Determine number of physical elements in matrix
1360 int elements = rows*(rows+1)/2;
1361
1362 // Throw exception if number of rows and columns is not identical
1363 if (rows != columns) {
1364 throw GException::matrix_not_symmetric(G_ALLOC_MEMBERS"GMatrixSymmetric::alloc_members(int&, int&)", rows, columns);
1365 }
1366
1367 // Continue only if number of elements is positive
1368 if (elements > 0) {
1369
1370 // Free any existing memory
1371 if (m_data != NULL__null) delete [] m_data;
1372 if (m_colstart != NULL__null) delete [] m_colstart;
1373 if (m_inx != NULL__null) delete [] m_inx;
1374
1375 // Allocate matrix array and column start index array.
1376 m_data = new double[elements];
1377 m_colstart = new int[columns+1];
1378 m_inx = new int[columns];
1379
1380 // Store matrix size (logical and physical)
1381 m_rows = rows;
1382 m_cols = columns;
1383 m_elements = elements;
1384 m_alloc = elements;
1385
1386 // Set-up column start indices
1387 m_colstart[0] = 0;
1388 int offset = rows;
1389 for (int col = 1; col <= m_cols; ++col) {
1390 m_colstart[col] = m_colstart[col-1] + offset--;
1391 }
1392
1393 // Initialise matrix elements to 0.0
1394 for (int i = 0; i < m_elements; ++i) {
1395 m_data[i] = 0.0;
1396 }
1397
1398 } // endif: number of elements was positive
1399
1400 // Return
1401 return;
1402}
1403
1404
1405/***********************************************************************//**
1406 * @brief Set index selection
1407 *
1408 * Determines the non-zero rows/columns in matrix and set up index array
1409 * that points to these rows/columns. This array is used for compressed
1410 * matrix calculations (Case B in the above routines).
1411 ***************************************************************************/
1412void GMatrixSymmetric::set_inx(void)
1413{
1414 // Allocate loop variables and pointers
1415 int row;
1416 int col;
1417
1418 // Find all nonzero rows/cols
1419 m_num_inx = 0;
1420 for (row = 0; row < m_rows; ++row) {
9
Loop condition is true. Entering loop body
1421
1422 // Check first for zero diagonal. If we have one then check the rest of
1423 // the row
1424 if (m_data[m_colstart[row]] == 0.0) {
10
Taking false branch
1425 for (col = 0; col < row; ++col) {
1426 if (m_data[m_colstart[col]+(row-col)] != 0.0) {
1427 break;
1428 }
1429 }
1430 // Found a non-zero element
1431 if (col < row) {
1432 m_inx[m_num_inx++] = row;
1433 }
1434 else {
1435 for (col = row+1; col < m_cols; ++col) {
1436 if (m_data[m_colstart[row]+(col-row)] != 0.0) {
1437 break;
1438 }
1439 }
1440 // Found a non-zero element
1441 if (col < m_cols) {
1442 m_inx[m_num_inx++] = row;
1443 }
1444 }
1445 }
1446 else {
1447 m_inx[m_num_inx++] = row;
11
Array access (via field 'm_inx') results in a null pointer dereference
1448 }
1449 }
1450
1451 // Return
1452 return;
1453}
1454
1455
1456/*==========================================================================
1457 = =
1458 = Friend functions =
1459 = =
1460 ==========================================================================*/
1461
1462/***********************************************************************//**
1463 * @brief Binary matrix multiplication operator
1464 *
1465 * @param[in] matrix Matrix to be multiplied.
1466 *
1467 * @exception GException::matrix_mismatch
1468 * Incompatible matrix size.
1469 *
1470 * This method performs a matrix multiplication. Since the product of two
1471 * symmetric matrices is not necessarily symmetric, this method returns a
1472 * GMatrix object.
1473 *
1474 * The operation can only succeed when the dimensions of both matrices are
1475 * compatible.
1476 ***************************************************************************/
1477GMatrix GMatrixSymmetric::operator*(const GMatrixSymmetric& matrix) const
1478{
1479 // Raise an exception if the matrix dimensions are not compatible
1480 if (m_cols != matrix.m_rows) {
1481 throw GException::matrix_mismatch(G_OP_MAT_MUL"GMatrixSymmetric::operator*=(GMatrixSymmetric&)",
1482 m_rows, m_cols,
1483 matrix.m_rows, matrix.m_cols);
1484 }
1485
1486 // Allocate result matrix
1487 GMatrix result(m_rows, matrix.m_cols);
1488
1489 // Loop over all elements of result matrix
1490 for (int row = 0; row < m_rows; ++row) {
1491 for (int col = 0; col < matrix.m_cols; ++col) {
1492 double sum = 0.0;
1493 for (int i = 0; i < m_cols; ++i) {
1494 sum += (*this)(row,i) * matrix(i,col);
1495 }
1496 result(row,col) = sum;
1497 }
1498 }
1499
1500 // Return result
1501 return result;
1502}