GammaLib  2.1.0.dev
 All Classes Namespaces Files Functions Variables Typedefs Enumerations Enumerator Friends Macros Pages
GMatrix.cpp
Go to the documentation of this file.
1 /***************************************************************************
2  * GMatrix.cpp - General matrix class *
3  * ----------------------------------------------------------------------- *
4  * copyright (C) 2006-2021 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 GMatrix.cpp
23  * @brief General matrix class implementation
24  * @author Juergen Knoedlseder
25  */
26 
27 /* __ Includes ___________________________________________________________ */
28 #ifdef HAVE_CONFIG_H
29 #include <config.h>
30 #endif
31 #include <cmath>
32 #include "GException.hpp"
33 #include "GTools.hpp"
34 #include "GMath.hpp"
35 #include "GVector.hpp"
36 #include "GMatrix.hpp"
37 #include "GMatrixSparse.hpp"
38 #include "GMatrixSymmetric.hpp"
39 
40 /* __ Method name definitions ____________________________________________ */
41 #define G_CONSTRUCTOR "GMatrix::GMatrix(int&, int&)"
42 #define G_OP_MUL_VEC "GMatrix::operator*(GVector&)"
43 #define G_OP_ADD "GMatrix::operator+=(GMatrix&)"
44 #define G_OP_SUB "GMatrix::operator-=(GMatrix&)"
45 #define G_OP_MAT_MUL "GMatrix::operator*=(GMatrix&)"
46 #define G_AT "GMatrix::at(int&, int&)"
47 #define G_EXTRACT_ROW "GMatrix::row(int&)"
48 #define G_SET_ROW "GMatrix::row(int&, GVector&)"
49 #define G_EXTRACT_COLUMN "GMatrix::column(int&)"
50 #define G_SET_COLUMN "GMatrix::column(int&, GVector&)"
51 #define G_ADD_TO_ROW "GMatrix::add_to_row(int&, GVector&)"
52 #define G_ADD_TO_COLUMN "GMatrix::add_to_column(int&, GVector&)"
53 #define G_INVERT "GMatrix::invert()"
54 #define G_SOLVE "GMatrix::solve(GVector&)"
55 #define G_EXTRACT_LOWER "GMatrix::extract_lower_triangle()"
56 #define G_EXTRACT_UPPER "GMatrix::extract_upper_triangle()"
57 
58 
59 /*==========================================================================
60  = =
61  = Constructors/destructors =
62  = =
63  ==========================================================================*/
64 
65 /***********************************************************************//**
66  * @brief Void matrix constructor
67  *
68  * Constructs an empty matrix. An empty matrix has zero rows and columns.
69  ***************************************************************************/
71 {
72  // Initialise class members
73  init_members();
74 
75  // Return
76  return;
77 }
78 
79 
80 /***********************************************************************//**
81  * @brief Matrix constructor
82  *
83  * @param[in] rows Number of rows [>=0].
84  * @param[in] columns Number of columns [>=0].
85  *
86  * @exception GException::invalid_argument
87  * Number of rows or columns is negative.
88  *
89  * Constructs a matrix with the specified number of @p rows and @p columns.
90  * The memory for all matrix elements will be allocated and all matrix
91  * elements will be initialized to 0.
92  ***************************************************************************/
93 GMatrix::GMatrix(const int& rows, const int& columns) : GMatrixBase()
94 {
95  // Throw exception if number of rows or columns is negative
96  #if defined(G_RANGE_CHECK)
97  if (rows < 0) {
98  std::string msg = "Number of rows "+gammalib::str(rows)+" is negative. "
99  "Please specify a non-negative number of rows.";
101  }
102  if (columns < 0) {
103  std::string msg = "Number of columns "+gammalib::str(columns)+" is "
104  "negative. Please specify a non-negative number of "
105  "columns.";
107  }
108  #endif
109 
110  // Initialise class members for clean destruction
111  init_members();
112 
113  // Allocate matrix memory
114  alloc_members(rows, columns);
115 
116  // Return
117  return;
118 }
119 
120 
121 /***********************************************************************//**
122  * @brief Copy constructor
123  *
124  * @param[in] matrix Matrix.
125  ***************************************************************************/
126 GMatrix::GMatrix(const GMatrix& matrix) : GMatrixBase(matrix)
127 {
128  // Initialise class members for clean destruction
129  init_members();
130 
131  // Copy members
132  copy_members(matrix);
133 
134  // Return
135  return;
136 }
137 
138 
139 /***********************************************************************//**
140  * @brief GMatrixSymmetric to GMatrix storage class convertor
141  *
142  * @param[in] matrix Symmetric matrix (GMatrixSymmetric).
143  *
144  * Constructs a GMatrix object from a symmetric matrix object of type
145  * GMatrixSymmetric. Since the result is a generic matrix, the constructor
146  * will succeed in all cases.
147  ***************************************************************************/
149 {
150  // Initialise class members for clean destruction
151  init_members();
152 
153  // Allocate matrix memory
154  alloc_members(matrix.rows(), matrix.columns());
155 
156  // Fill matrix. We benefit here from the symmetry of the matrix and
157  // loop only over the lower triangle of the symmetric matrix to perform
158  // the fill.
159  for (int col = 0; col < m_cols; ++col) {
160  for (int row = col; row < m_rows; ++row) {
161  double value = matrix(row, col);
162  (*this)(row, col) = value;
163  (*this)(col, row) = value;
164  }
165  }
166 
167  // Return
168  return;
169 }
170 
171 
172 /***********************************************************************//**
173  * @brief GMatrixSparse to GMatrix storage class convertor
174  *
175  * @param[in] matrix Sparse matrix (GMatrixSparse).
176  *
177  * Constructs a GMatrix object from a sparse matrix object of type
178  * GMatrixSparse. Since the result is a generic matrix, the constructor
179  * will succeed in all cases.
180  ***************************************************************************/
182 {
183  // Initialise class members for clean destruction
184  init_members();
185 
186  // Construct matrix
187  alloc_members(matrix.rows(), matrix.columns());
188 
189  // Fill matrix
190  for (int col = 0; col < m_cols; ++col) {
191  for (int row = 0; row < m_rows; ++row) {
192  (*this)(row, col) = matrix(row, col);
193  }
194  }
195 
196  // Return
197  return;
198 }
199 
200 
201 /***********************************************************************//**
202  * @brief Destructor
203  ***************************************************************************/
205 {
206  // Free members
207  free_members();
208 
209  // Return
210  return;
211 }
212 
213 
214 /*==========================================================================
215  = =
216  = Operators =
217  = =
218  ==========================================================================*/
219 
220 /***********************************************************************//**
221  * @brief Matrix assignment operator
222  *
223  * @param[in] matrix Matrix.
224  * @return Matrix.
225  *
226  * Assigns the content of another matrix to the actual matrix instance.
227  ***************************************************************************/
229 {
230  // Execute only if object is not identical
231  if (this != &matrix) {
232 
233  // Assign base class members. Note that this method will also perform
234  // the allocation of the matrix memory and the copy of the matrix
235  // attributes.
236  this->GMatrixBase::operator=(matrix);
237 
238  // Free derived class members
239  free_members();
240 
241  // Initialise derived class members
242  init_members();
243 
244  // Copy derived class members
245  copy_members(matrix);
246 
247  } // endif: object was not identical
248 
249  // Return this object
250  return *this;
251 }
252 
253 
254 /***********************************************************************//**
255  * @brief Value assignment operator
256  *
257  * @param[in] value Value.
258  * @return Matrix.
259  *
260  * Assigns the specified @p value to all elements of the matrix.
261  ***************************************************************************/
262 GMatrix& GMatrix::operator=(const double& value)
263 {
264  // Assign value
265  double* ptr = m_data;
266  for (int i = 0; i < m_elements; ++i) {
267  *ptr++ = value;
268  }
269 
270  // Return this object
271  return *this;
272 }
273 
274 
275 /***********************************************************************//**
276  * @brief Vector multiplication
277  *
278  * @param[in] vector Vector.
279  *
280  * @exception GException::invalid_argument
281  * Vector size differs from number of columns in matrix.
282  *
283  * This method performs a vector multiplication of a matrix. The vector
284  * multiplication will produce a vector. The multiplication can only be
285  * performed when the number of matrix columns is identical to the size
286  * of the vector. If the size of the vector differs an exception will be
287  * thrown.
288  ***************************************************************************/
289 GVector GMatrix::operator*(const GVector& vector) const
290 {
291  // Raise an exception if the matrix and vector dimensions are not compatible
292  if (m_cols != vector.size()) {
293  std::string msg = "Vector size "+gammalib::str(vector.size())+" does "
294  "not match "+gammalib::str(m_cols)+" matrix columns. "
295  "Please specify a vector of size "+
296  gammalib::str(m_cols)+".";
298  }
299 
300  // Perform vector multiplication
301  GVector result(m_rows);
302  for (int row = 0; row < m_rows; ++row) {
303  double sum = 0.0;
304  const double* src = m_data + row;
305  for (int col = 0; col < m_cols; ++col, src += m_rows) {
306  sum += *src * vector[col];
307  }
308  result[row] = sum;
309  }
310 
311  // Return result
312  return result;
313 }
314 
315 
316 /***********************************************************************//**
317  * @brief Negate matrix elements
318  *
319  * @return Matrix with negated elements.
320  *
321  * Returns a matrix where each element has been replaced by its negative
322  * element.
323  ***************************************************************************/
325 {
326  // Copy matrix
327  GMatrix matrix = *this;
328 
329  // Take the absolute value of all matrix elements
330  double* ptr = matrix.m_data;
331  for (int i = 0; i < matrix.m_elements; ++i, ++ptr) {
332  *ptr = -(*ptr);
333  }
334 
335  // Return matrix
336  return matrix;
337 }
338 
339 
340 /***********************************************************************//**
341  * @brief Unary matrix addition operator
342  *
343  * @param[in] matrix Matrix.
344  *
345  * @exception GException::invalid_argument
346  * Incompatible number of matrix rows or columns.
347  *
348  * This method performs a matrix addition. The method throws an exception if
349  * the number of matrix rows or columns are not identical.
350  ***************************************************************************/
352 {
353  // Throw an exception if the matrix dimensions are not compatible
354  if (m_rows != matrix.m_rows) {
355  std::string msg = "Number of matrix rows "+gammalib::str(matrix.m_rows)+
356  " differs from the expected number of "+
357  gammalib::str(m_rows)+" rows. Please specify a "
358  "matrix with "+gammalib::str(m_rows)+" rows.";
360  }
361  if (m_cols != matrix.m_cols) {
362  std::string msg = "Number of matrix columns "+gammalib::str(matrix.m_cols)+
363  " differs from the expected number of "+
364  gammalib::str(m_cols)+" columns. Please specify a "
365  "matrix with "+gammalib::str(m_cols)+" columns.";
367  }
368 
369  // Add all matrix elements
370  const double* src = matrix.m_data;
371  double* dst = m_data;
372  for (int i = 0; i < m_elements; ++i) {
373  *dst++ += *src++;
374  }
375 
376  // Return result
377  return *this;
378 }
379 
380 
381 /***********************************************************************//**
382  * @brief Unary matrix scalar addition operator
383  *
384  * @param[in] scalar Scalar.
385  *
386  * Adds a @p scalar to each matrix element.
387  ***************************************************************************/
388 GMatrix& GMatrix::operator+=(const double& scalar)
389 {
390  // Add all matrix elements
391  double* dst = m_data;
392  for (int i = 0; i < m_elements; ++i) {
393  *dst++ += scalar;
394  }
395 
396  // Return result
397  return *this;
398 }
399 
400 
401 /***********************************************************************//**
402  * @brief Unary matrix subtraction operator
403  *
404  * @param[in] matrix Matrix.
405  *
406  * @exception GException::invalid_argument
407  * Incompatible number of matrix rows or columns.
408  *
409  * This method performs a matrix addition. The method throws an exception if
410  * the number of matrix rows or columns are not identical.
411  ***************************************************************************/
413 {
414  // Throw an exception if the matrix dimensions are not compatible
415  if (m_rows != matrix.m_rows) {
416  std::string msg = "Number of matrix rows "+gammalib::str(matrix.m_rows)+
417  " differs from the expected number of "+
418  gammalib::str(m_rows)+" rows. Please specify a "
419  "matrix with "+gammalib::str(m_rows)+" rows.";
421  }
422  if (m_cols != matrix.m_cols) {
423  std::string msg = "Number of matrix columns "+gammalib::str(matrix.m_cols)+
424  " differs from the expected number of "+
425  gammalib::str(m_cols)+" columns. Please specify a "
426  "matrix with "+gammalib::str(m_cols)+" columns.";
428  }
429 
430  // Subtract all matrix elements
431  const double* src = matrix.m_data;
432  double* dst = m_data;
433  for (int i = 0; i < m_elements; ++i) {
434  *dst++ -= *src++;
435  }
436 
437  // Return result
438  return *this;
439 }
440 
441 
442 /***********************************************************************//**
443  * @brief Unary matrix scalar subtraction operator
444  *
445  * @param[in] scalar Scalar.
446  *
447  * Subtracts a @p scalar from each matrix element.
448  ***************************************************************************/
449 GMatrix& GMatrix::operator-=(const double& scalar)
450 {
451  // Add all matrix elements
452  double* dst = m_data;
453  for (int i = 0; i < m_elements; ++i) {
454  *dst++ -= scalar;
455  }
456 
457  // Return result
458  return *this;
459 }
460 
461 
462 /***********************************************************************//**
463  * @brief Unary matrix multiplication operator
464  *
465  * @param[in] matrix Matrix.
466  *
467  * @exception GException::invalid_argument
468  * Number of rows in @p matrix is different from number of
469  * matrix columns.
470  *
471  * This method performs a matrix multiplication. The operation can only
472  * succeed when the dimensions of both matrices are compatible.
473  *
474  * In case of rectangular matrices the result matrix does not change and
475  * the operation is performed inplace. For the general case the result
476  * matrix changes in size and for simplicity a new matrix is allocated to
477  * hold the result.
478  ***************************************************************************/
480 {
481  // Throw exception if the matrix dimensions are not compatible
482  if (m_cols != matrix.m_rows) {
483  std::string msg = "Number of "+gammalib::str(m_cols)+" columns in "
484  "the first matrix differs from number of "+
485  gammalib::str(matrix.m_rows)+" rows in the second "
486  "matrix. Please specify a second matrix with "+
487  gammalib::str(m_cols)+" rows.";
489  }
490 
491  // Case A: Matrices are rectangular, so perform 'inplace' multiplication
492  if (m_rows == m_cols) {
493  for (int row = 0; row < m_rows; ++row) {
494  GVector v_row = this->row(row);
495  for (int col = 0; col < m_cols; ++col) {
496  double sum = 0.0;
497  for (int i = 0; i < m_cols; ++i) {
498  sum += v_row[i] * matrix(i,col);
499  }
500  (*this)(row,col) = sum;
501  }
502  }
503  }
504 
505  // Case B: Matrices are not rectangular, so we cannot work inplace
506  else {
507 
508  // Allocate result matrix
509  GMatrix result(m_rows, matrix.m_cols);
510 
511  // Loop over all elements of result matrix
512  for (int row = 0; row < m_rows; ++row) {
513  for (int col = 0; col < matrix.m_cols; ++col) {
514  double sum = 0.0;
515  for (int i = 0; i < m_cols; ++i) {
516  sum += (*this)(row,i) * matrix(i,col);
517  }
518  result(row,col) = sum;
519  }
520  }
521 
522  // Assign result
523  *this = result;
524 
525  } // endelse: matrices were not rectangular
526 
527  // Return result
528  return *this;
529 }
530 
531 
532 /*==========================================================================
533  = =
534  = Public methods =
535  = =
536  ==========================================================================*/
537 
538 /***********************************************************************//**
539  * @brief Clear matrix
540  ***************************************************************************/
541 void GMatrix::clear(void)
542 {
543  // Free members
544  free_members();
545 
546  // Initialise private members
547  init_members();
548 
549  // Return
550  return;
551 }
552 
553 
554 /***********************************************************************//**
555  * @brief Clone matrix
556  *
557  * @return Pointer to deep copy of matrix.
558  ***************************************************************************/
560 {
561  // Clone matrix
562  return new GMatrix(*this);
563 }
564 
565 
566 /***********************************************************************//**
567  * @brief Return reference to matrix element
568  *
569  * @param[in] row Matrix row [0,...,rows()[.
570  * @param[in] column Matrix column [0,...,columns()[.
571  * @return Reference to matrix element.
572  *
573  * @exception GException::out_of_range
574  * Matrix row or column out of range.
575  *
576  * Returns a reference to the matrix element at @p row and @p column.
577  *
578  * This method verifies the validity of the @p row and @p column argument.
579  ***************************************************************************/
580 double& GMatrix::at(const int& row, const int& column)
581 {
582  // Throw exception if row or column is out of range
583  if (row < 0 || row >= m_rows) {
584  throw GException::out_of_range(G_AT, "Matrix row", row, m_rows);
585  }
586  if (column < 0 || column >= m_cols) {
587  throw GException::out_of_range(G_AT, "Matrix column", column, m_cols);
588  }
589 
590  // Return element
591  return (m_data[m_colstart[column]+row]);
592 }
593 
594 
595 /***********************************************************************//**
596  * @brief Return reference to matrix element (const version)
597  *
598  * @param[in] row Matrix row [0,...,rows()[.
599  * @param[in] column Matrix column [0,...,columns()[.
600  * @return Const reference to matrix element.
601  *
602  * @exception GException::out_of_range
603  * Matrix row or column out of range.
604  *
605  * Returns a const reference to the matrix element at @p row and @p column.
606  *
607  * This method verifies the validity of the @p row and @p column argument.
608  ***************************************************************************/
609 const double& GMatrix::at(const int& row, const int& column) const
610 {
611  // Throw exception if row or column is out of range
612  if (row < 0 || row >= m_rows) {
613  throw GException::out_of_range(G_AT, "Matrix row", row, m_rows);
614  }
615  if (column < 0 || column >= m_cols) {
616  throw GException::out_of_range(G_AT, "Matrix column", column, m_cols);
617  }
618 
619  // Return element
620  return (m_data[m_colstart[column]+row]);
621 }
622 
623 
624 
625 /***********************************************************************//**
626  * @brief Extract row as vector from matrix
627  *
628  * @param[in] row Matrix row [0,...,rows()[.
629  * @return Vector of matrix row elements (columns() elements).
630  *
631  * @exception GException::out_of_range
632  * Invalid matrix row specified.
633  *
634  * Extracts one @p row of the matrix into a vector. The vector will contain
635  * columns() elements.
636  ***************************************************************************/
637 GVector GMatrix::row(const int& row) const
638 {
639  // Throw exception if the row is invalid
640  #if defined(G_RANGE_CHECK)
641  if (row < 0 || row >= m_rows) {
642  throw GException::out_of_range(G_EXTRACT_ROW, "Matrix row", row, m_rows);
643  }
644  #endif
645 
646  // Create result vector
647  GVector result(m_cols);
648 
649  // Extract row into vector. Recall that the matrix elements are stored
650  // column wise, hence we have to increment the element counter i by
651  // the number of rows to go into the next matrix column.
652  for (int col = 0, i = row; col < m_cols; ++col, i += m_rows) {
653  result[col] = m_data[i];
654  }
655 
656  // Return vector
657  return result;
658 }
659 
660 
661 /***********************************************************************//**
662  * @brief Set row in matrix
663  *
664  * @param[in] row Matrix row [0,...,rows()[.
665  * @param[in] vector Vector of matrix row elements (columns() elements).
666  *
667  * @exception GException::out_of_range
668  * Invalid matrix row specified.
669  * @exception GException::invalid_argument
670  * Vector size does not match number of matrix columns.
671  *
672  * Sets the elements from a vector as the elements of a matrix row. The
673  * size of the vector must be identical to the number of columns in the
674  * matrix.
675  ***************************************************************************/
676 void GMatrix::row(const int& row, const GVector& vector)
677 {
678  // Throw an exception if the row is invalid
679  #if defined(G_RANGE_CHECK)
680  if (row < 0 || row >= m_rows) {
681  throw GException::out_of_range(G_SET_ROW, "Matrix row", row, m_rows);
682  }
683  #endif
684 
685  // Throw an exception if the matrix and vector dimensions are not
686  // compatible
687  if (m_cols != vector.size()) {
688  std::string msg = "Vector size "+gammalib::str(vector.size())+
689  " does not match "+gammalib::str(m_cols)+" matrix "
690  "columns. Please specify a vector of size "+
691  gammalib::str(m_cols)+".";
693  }
694 
695  // Set row from vector. Recall that the matrix elements are stored
696  // column wise, hence we have to increment the element counter i by
697  // the number of rows to go into the next matrix column.
698  for (int col = 0, i = row; col < m_cols; ++col, i += m_rows) {
699  m_data[i] = vector[col];
700  }
701 
702  // Return
703  return;
704 }
705 
706 
707 /***********************************************************************//**
708  * @brief Extract column as vector from matrix
709  *
710  * @param[in] column Matrix column [0,...,columns()[.
711  * @return Vector of matrix column elements (rows() elements).
712  *
713  * @exception GException::out_of_range
714  * Invalid matrix column specified.
715  *
716  * This method extracts a matrix column into a vector.
717  ***************************************************************************/
718 GVector GMatrix::column(const int& column) const
719 {
720  // Throw exception if the column is invalid
721  #if defined(G_RANGE_CHECK)
722  if (column < 0 || column >= m_cols) {
723  throw GException::out_of_range(G_EXTRACT_COLUMN, "Matrix column",
724  column, m_cols);
725  }
726  #endif
727 
728  // Create result vector
729  GVector result(m_rows);
730 
731  // Continue only if we have elements
732  if (m_elements > 0) {
733 
734  // Get start of data in matrix
735  int i = m_colstart[column];
736 
737  // Extract column into vector
738  for (int row = 0; row < m_rows; ++row) {
739  result[row] = m_data[i++];
740  }
741 
742  } // endif: matrix had elements
743 
744  // Return vector
745  return result;
746 }
747 
748 
749 /***********************************************************************//**
750  * @brief Set matrix column from vector
751  *
752  * @param[in] column Matrix column [0,...,columns()[.
753  * @param[in] vector Vector.
754  *
755  * @exception GException::out_of_range
756  * Invalid matrix column specified.
757  * @exception GException::invalid_argument
758  * Vector size does not match number of matrix rows.
759  *
760  * Inserts the content of a vector into a matrix column. Any previous
761  * content in the matrix column will be overwritted.
762  ***************************************************************************/
763 void GMatrix::column(const int& column, const GVector& vector)
764 {
765  // Throw exception if the column is invalid
766  #if defined(G_RANGE_CHECK)
767  if (column < 0 || column >= m_cols) {
768  throw GException::out_of_range(G_SET_COLUMN, "Matrix column",
769  column, m_cols);
770  }
771  #endif
772 
773  // Throw exception if the vector size does not match the number of rows
774  // in the matrix
775  if (m_rows != vector.size()) {
776  std::string msg = "Vector size "+gammalib::str(vector.size())+
777  " does not match "+gammalib::str(m_rows)+" matrix "
778  "rows. Please specify a vector of size "+
779  gammalib::str(m_rows)+".";
781  }
782 
783  // Continue only if we have elements
784  if (m_elements > 0) {
785 
786  // Get start index of data in matrix
787  int i = m_colstart[column];
788 
789  // Insert column into vector
790  for (int row = 0; row < m_rows; ++row) {
791  m_data[i++] = vector[row];
792  }
793 
794  } // endif: matrix had elements
795 
796  // Return
797  return;
798 }
799 
800 
801 /***********************************************************************//**
802  * @brief Add row to matrix elements
803  *
804  * @param[in] row Matrix row [0,...,rows()[.
805  * @param[in] vector Vector of matrix row elements (columns() elements).
806  *
807  * @exception GException::out_of_range
808  * Invalid matrix row specified.
809  * @exception GException::matrix_vector_mismatch
810  * Vector does not match the matrix dimensions.
811  ***************************************************************************/
812 void GMatrix::add_to_row(const int& row, const GVector& vector)
813 {
814  // Throw exception if the row is invalid
815  #if defined(G_RANGE_CHECK)
816  if (row < 0 || row >= m_rows) {
817  throw GException::out_of_range(G_ADD_TO_ROW, "Matrix row", row, m_rows);
818 
819  }
820  #endif
821 
822  // Throw exception if the matrix and vector dimensions are not
823  // compatible
824  if (m_cols != vector.size()) {
825  std::string msg = "Vector size "+gammalib::str(vector.size())+
826  " does not match "+gammalib::str(m_cols)+" matrix "
827  "columns. Please specify a vector of size "+
828  gammalib::str(m_cols)+".";
830  }
831 
832  // Add row from vector. Recall that the matrix elements are stored
833  // column wise, hence we have to increment the element counter i by
834  // the number of rows to go into the next matrix column.
835  for (int col = 0, i = row; col < m_cols; ++col, i += m_rows) {
836  m_data[i] += vector[col];
837  }
838 
839  // Return
840  return;
841 }
842 
843 
844 /***********************************************************************//**
845  * @brief Add vector column into matrix
846  *
847  * @param[in] column Matrix column [0,...,columns()[.
848  * @param[in] vector Vector.
849  *
850  * @exception GException::out_of_range
851  * Invalid matrix column specified.
852  * @exception GException::matrix_vector_mismatch
853  * Vector size does not match number of matrix rows.
854  *
855  * Adds the content of a vector to a matrix column.
856  ***************************************************************************/
857 void GMatrix::add_to_column(const int& column, const GVector& vector)
858 {
859  // Raise an exception if the column is invalid
860  #if defined(G_RANGE_CHECK)
861  if (column < 0 || column >= m_cols) {
862  throw GException::out_of_range(G_ADD_TO_COLUMN, "Matrix column",
863  column, m_cols);
864 
865  }
866  #endif
867 
868  // Raise an exception if the matrix and vector dimensions are not
869  // compatible
870  if (m_rows != vector.size()) {
871  std::string msg = "Vector size "+gammalib::str(vector.size())+
872  " does not match "+gammalib::str(m_rows)+" matrix "
873  "rows. Please specify a vector of size "+
874  gammalib::str(m_rows)+".";
876  }
877 
878  // Continue only if we have elements
879  if (m_elements > 0) {
880 
881  // Get start index of data in matrix
882  int i = m_colstart[column];
883 
884  // Add column into vector
885  for (int row = 0; row < m_rows; ++row) {
886  m_data[i++] += vector[row];
887  }
888 
889  } // endif: matrix had elements
890 
891  // Return
892  return;
893 }
894 
895 
896 /***********************************************************************//**
897  * @brief Return transposed matrix
898  *
899  * @return Transposed matrix.
900  *
901  * Returns transposed matrix of the matrix.
902  ***************************************************************************/
904 {
905  // Allocate result matrix
906  GMatrix matrix(m_cols, m_rows);
907 
908  // Transpose matrix
909  for (int row = 0; row < m_rows; ++row) {
910  for (int col = 0; col < m_cols; ++col) {
911  matrix(col, row) = (*this)(row, col);
912  }
913  }
914 
915  // Return matrix
916  return matrix;
917 }
918 
919 
920 /***********************************************************************//**
921  * @brief Return inverted matrix
922  *
923  * @return Inverted matrix.
924  *
925  * @exception GException::feature_not_implemented
926  * Feature not yet implemented.
927  *
928  * Returns inverse of matrix.
929  *
930  * @todo Needs to be implemented.
931  ***************************************************************************/
933 {
934  // Allocate result matrix
935  GMatrix matrix(m_cols, m_rows);
936 
937  // Throw exception
939 
940  // Return matrix
941  return matrix;
942 }
943 
944 
945 /***********************************************************************//**
946  * @brief Solves linear matrix equation
947  *
948  * @param[in] vector Solution vector.
949  *
950  * @exception GException::feature_not_implemented
951  * Feature not yet implemented.
952  *
953  * Solves the linear equation
954  *
955  * \f[M \times {\tt solution} = {\tt vector} \f]
956  *
957  * where \f$M\f$ is the matrix, \f${\tt vector}\f$ is the result, and
958  * \f${\tt solution}\f$ is the solution.
959  *
960  * @todo Needs to be implemented.
961  ***************************************************************************/
962 GVector GMatrix::solve(const GVector& vector) const
963 {
964  // Allocate result vector
965  GVector result;
966 
967  // Throw exception
969 
970  // Return vector
971  return result;
972 }
973 
974 
975 /***********************************************************************//**
976  * @brief Return absolute of matrix
977  *
978  * @return Absolute of matrix
979  *
980  * Returns matrix where all elements of the matrix have been replaced by
981  * their absolute values.
982  ***************************************************************************/
984 {
985  // Allocate result matrix
986  GMatrix matrix(m_rows, m_cols);
987 
988  // Take the absolute value of all matrix elements
989  double* src = m_data;
990  double* dst = matrix.m_data;
991  for (int i = 0; i < m_elements; ++i) {
992  *dst++ = std::abs(*src++);
993  }
994 
995  // Return matrix
996  return matrix;
997 }
998 
999 
1000 /***********************************************************************//**
1001  * @brief Return fill of matrix
1002  *
1003  * @return Matrix fill (between 0 and 1).
1004  *
1005  * Returns the fill of the matrix. The fill of a matrix is defined as the
1006  * number non-zero elements devided by the number of total elements. By
1007  * definition, the fill is comprised in the interval [0,..,1].
1008  *
1009  * The fill of a matrix with zero elements will be set to 0.
1010  ***************************************************************************/
1011 double GMatrix::fill(void) const
1012 {
1013  // Initialise result
1014  double result = 0.0;
1015 
1016  // Continue only if matrix has elements
1017  if (m_elements > 0) {
1018 
1019  // Determine the number of zero elements
1020  int zero = 0;
1021  for (int i = 0; i < m_elements; ++i) {
1022  if (m_data[i] == 0.0) {
1023  zero++;
1024  }
1025  }
1026 
1027  // Compute fill
1028  result = 1.0-double(zero)/double(m_elements);
1029 
1030  } // endif: there were elements in the matrix
1031 
1032  // Return result
1033  return result;
1034 }
1035 
1036 
1037 /***********************************************************************//**
1038  * @brief Extract lower triangle of matrix
1039  *
1040  * @exception GException::invalid_argument
1041  * Matrix is not a square matrix.
1042  *
1043  * This method extracts the lower triangle of a matrix into another matrix.
1044  * (including the diagonal elements).
1045  * All remaining matrix elements will be zero.
1046  *
1047  * Triangular extraction only works for square matrixes.
1048  ***************************************************************************/
1050 {
1051  // Throw exception if matrix is not square
1052  if (m_rows != m_cols) {
1053  std::string msg = "Number of matrix rows "+gammalib::str(m_rows)+
1054  " differs from number of matrix columns "+
1055  gammalib::str(m_cols)+". This method only works "
1056  "on square matrices.";
1058  }
1059 
1060  // Define result matrix
1061  GMatrix result(m_rows, m_cols);
1062 
1063  // Extract all elements
1064  for (int col = 0; col < m_cols; ++col) {
1065  int i = m_colstart[col] + col;
1066  for (int row = col; row < m_rows; ++row, ++i) {
1067  result.m_data[i] = m_data[i];
1068  }
1069  }
1070 
1071  // Return result
1072  return result;
1073 }
1074 
1075 
1076 /***********************************************************************//**
1077  * @brief Extract upper triangle of matrix
1078  *
1079  * @exception GException::invalid_argument
1080  * Matrix is not a square matrix.
1081  *
1082  * This method extracts the upper triangle of a matrix into another matrix.
1083  * (including the diagonal elements).
1084  * All remaining matrix elements will be zero.
1085  *
1086  * Triangular extraction only works for square matrixes.
1087  ***************************************************************************/
1089 {
1090  // Throw exception if matrix is not squared
1091  if (m_rows != m_cols) {
1092  std::string msg = "Number of matrix rows "+gammalib::str(m_rows)+
1093  " differs from number of matrix columns "+
1094  gammalib::str(m_cols)+". This method only works "
1095  "on square matrices.";
1097  }
1098 
1099  // Define result matrix
1100  GMatrix result(m_rows, m_cols);
1101 
1102  // Extract all elements
1103  for (int col = 0; col < m_cols; ++col) {
1104  int i = m_colstart[col];
1105  for (int row = 0; row <= col; ++row, ++i) {
1106  result.m_data[i] = m_data[i];
1107  }
1108  }
1109 
1110  // Return result
1111  return result;
1112 }
1113 
1114 
1115 /***********************************************************************//**
1116  * @brief Set Euler rotation matrix around x axis
1117  *
1118  * @param[in] angle Rotation angle (degrees)
1119  ***************************************************************************/
1120 void GMatrix::eulerx(const double& angle)
1121 {
1122  // Free members
1124 
1125  // Initialise members
1127 
1128  // Construct 3*3 matrix
1129  alloc_members(3,3);
1130 
1131  // Compute angles
1132  double arg = angle * gammalib::deg2rad;
1133  double cosangle = std::cos(arg);
1134  double sinangle = std::sin(arg);
1135 
1136  // Set matrix elements
1137  (*this)(0,0) = 1.0;
1138  (*this)(0,1) = 0.0;
1139  (*this)(0,2) = 0.0;
1140  (*this)(1,0) = 0.0;
1141  (*this)(1,1) = cosangle;
1142  (*this)(1,2) = -sinangle;
1143  (*this)(2,0) = 0.0;
1144  (*this)(2,1) = sinangle;
1145  (*this)(2,2) = cosangle;
1146 
1147  // Return
1148  return;
1149 }
1150 
1151 
1152 /***********************************************************************//**
1153  * @brief Set Euler rotation matrix around y axis
1154  *
1155  * @param[in] angle Rotation angle (degrees)
1156  ***************************************************************************/
1157 void GMatrix::eulery(const double& angle)
1158 {
1159  // Free members
1161 
1162  // Initialise members
1164 
1165  // Construct 3*3 matrix
1166  alloc_members(3,3);
1167 
1168  // Compute angles
1169  double arg = angle * gammalib::deg2rad;
1170  double cosangle = std::cos(arg);
1171  double sinangle = std::sin(arg);
1172 
1173  // Set matrix elements
1174  (*this)(0,0) = cosangle;
1175  (*this)(0,1) = 0.0;
1176  (*this)(0,2) = sinangle;
1177  (*this)(1,0) = 0.0;
1178  (*this)(1,1) = 1.0;
1179  (*this)(1,2) = 0.0;
1180  (*this)(2,0) = -sinangle;
1181  (*this)(2,1) = 0.0;
1182  (*this)(2,2) = cosangle;
1183 
1184  // Return
1185  return;
1186 }
1187 
1188 
1189 /***********************************************************************//**
1190  * @brief Set Euler rotation matrix around z axis
1191  *
1192  * @param[in] angle Rotation angle (degrees)
1193  ***************************************************************************/
1194 void GMatrix::eulerz(const double& angle)
1195 {
1196  // Free members
1198 
1199  // Initialise members
1201 
1202  // Construct 3*3 matrix
1203  alloc_members(3,3);
1204 
1205  // Compute angles
1206  double arg = angle * gammalib::deg2rad;
1207  double cosangle = std::cos(arg);
1208  double sinangle = std::sin(arg);
1209 
1210  // Set matrix elements
1211  (*this)(0,0) = cosangle;
1212  (*this)(0,1) = -sinangle;
1213  (*this)(0,2) = 0.0;
1214  (*this)(1,0) = sinangle;
1215  (*this)(1,1) = cosangle;
1216  (*this)(1,2) = 0.0;
1217  (*this)(2,0) = 0.0;
1218  (*this)(2,1) = 0.0;
1219  (*this)(2,2) = 1.0;
1220 
1221  // Return
1222  return;
1223 }
1224 
1225 
1226 /***********************************************************************//**
1227  * @brief Print matrix
1228  *
1229  * @param[in] chatter Chattiness.
1230  * @return String containing matrix information.
1231  ***************************************************************************/
1232 std::string GMatrix::print(const GChatter& chatter) const
1233 {
1234  // Initialise result string
1235  std::string result;
1236 
1237  // Continue only if chatter is not silent
1238  if (chatter != SILENT) {
1239 
1240  // Append header
1241  result.append("=== GMatrix ===");
1242 
1243  // Append information
1244  result.append("\n"+gammalib::parformat("Number of rows"));
1245  result.append(gammalib::str(m_rows));
1246  if (m_rowsel != NULL) {
1247  result.append(" (compressed "+gammalib::str(m_num_rowsel)+")");
1248  }
1249  result.append("\n"+gammalib::parformat("Number of columns"));
1250  result.append(gammalib::str(m_cols));
1251  if (m_colsel != NULL) {
1252  result.append(" (compressed "+gammalib::str(m_num_colsel)+")");
1253  }
1254  result.append("\n"+gammalib::parformat("Number of elements"));
1255  result.append(gammalib::str(m_elements));
1256  result.append("\n"+gammalib::parformat("Number of allocated cells"));
1257  result.append(gammalib::str(m_alloc));
1258 
1259  // Append elements and compression schemes
1260  result.append(print_elements(chatter));
1261  result.append(print_row_compression(chatter));
1262  result.append(print_col_compression(chatter));
1263 
1264  } // endif: chatter was not silent
1265 
1266  // Return result
1267  return result;
1268 }
1269 
1270 
1271 /*==========================================================================
1272  = =
1273  = Private methods =
1274  = =
1275  ==========================================================================*/
1276 
1277 /***********************************************************************//**
1278  * @brief Initialise class members
1279  ***************************************************************************/
1281 {
1282  // Return
1283  return;
1284 }
1285 
1286 
1287 /***********************************************************************//**
1288  * @brief Copy class members
1289  *
1290  * @param[in] matrix Matrix.
1291  ***************************************************************************/
1292 void GMatrix::copy_members(const GMatrix& matrix)
1293 {
1294  // Return
1295  return;
1296 }
1297 
1298 
1299 /***********************************************************************//**
1300  * @brief Delete class members
1301  ***************************************************************************/
1303 {
1304  // Return
1305  return;
1306 }
1307 
1308 
1309 /***********************************************************************//**
1310  * @brief Allocate matrix memory
1311  *
1312  * @param[in] rows Number of matrix rows.
1313  * @param[in] columns Number of matrix columns.
1314  *
1315  * Allocates memory for the matrix elements. The method assumes that no
1316  * memory has been allocated for the matrix elements and the column start
1317  * index array. The method allocates the memory for matrix elements and the
1318  * column start indices, sets all matrix elements to 0, and sets the column
1319  * start indices.
1320  *
1321  * If either the number of rows or the number of columns is non-positive, the
1322  * method does nothing.
1323  ***************************************************************************/
1324 void GMatrix::alloc_members(const int& rows, const int& columns)
1325 {
1326  // Determine number of elements to store in matrix
1327  int elements = rows * columns;
1328 
1329  // Continue only if number of elements is positive
1330  if (elements > 0) {
1331 
1332  // Free any existing memory
1333  if (m_data != NULL) delete [] m_data;
1334  if (m_colstart != NULL) delete [] m_colstart;
1335 
1336  // Allocate matrix array and column start index array.
1337  m_data = new double[elements];
1338  m_colstart = new int[columns+1];
1339 
1340  // Store matrix size (logical, storage, allocated)
1341  m_rows = rows;
1342  m_cols = columns;
1343  m_elements = elements;
1344  m_alloc = elements;
1345 
1346  // Set-up column start indices
1347  m_colstart[0] = 0;
1348  for (int col = 1; col <= m_cols; ++col) {
1349  m_colstart[col] = m_colstart[col-1] + m_rows;
1350  }
1351 
1352  // Initialise matrix elements to 0
1353  for (int i = 0; i < m_elements; ++i) {
1354  m_data[i] = 0.0;
1355  }
1356 
1357  } // endif: number of elements was positive
1358 
1359  // Return
1360  return;
1361 }
#define G_AT
Definition: GMatrix.cpp:46
Abstract matrix base class interface definition.
virtual std::string print(const GChatter &chatter=NORMAL) const
Print matrix.
Definition: GMatrix.cpp:1232
std::string print_row_compression(const GChatter &chatter=NORMAL) const
Print row compression scheme if it exists.
void init_members(void)
Initialise class members.
Sparse matrix class interface definition.
GMatrix invert(void) const
Return inverted matrix.
Definition: GMatrix.cpp:932
GVector abs(const GVector &vector)
Computes absolute of vector elements.
Definition: GVector.cpp:1253
#define G_SET_COLUMN
Definition: GMatrix.cpp:50
virtual double & at(const int &row, const int &column)
Return reference to matrix element.
Definition: GMatrix.cpp:580
#define G_OP_ADD
Definition: GMatrix.cpp:43
GVector cos(const GVector &vector)
Computes cosine of vector elements.
Definition: GVector.cpp:1190
Generic matrix class definition.
#define G_OP_SUB
Definition: GMatrix.cpp:44
virtual void add_to_row(const int &row, const GVector &vector)
Add row to matrix elements.
Definition: GMatrix.cpp:812
int m_rows
Number of rows.
virtual GMatrix operator-(void) const
Negate matrix elements.
Definition: GMatrix.cpp:324
#define G_ADD_TO_COLUMN
Definition: GMatrix.cpp:52
virtual GVector column(const int &column) const
Extract column as vector from matrix.
Definition: GMatrix.cpp:718
Symmetric matrix class interface definition.
Gammalib tools definition.
#define G_EXTRACT_COLUMN
Definition: GMatrix.cpp:49
#define G_SET_ROW
Definition: GMatrix.cpp:48
int m_num_colsel
Number of selected columns (for compressed decomposition)
void copy_members(const GMatrix &matrix)
Copy class members.
Definition: GMatrix.cpp:1292
virtual void add_to_column(const int &column, const GVector &vector)
Add vector column into matrix.
Definition: GMatrix.cpp:857
#define G_INVERT
Definition: GMatrix.cpp:53
virtual GVector row(const int &row) const
Extract row as vector from matrix.
Definition: GMatrix.cpp:637
void eulery(const double &angle)
Set Euler rotation matrix around y axis.
Definition: GMatrix.cpp:1157
virtual void clear(void)
Clear matrix.
Definition: GMatrix.cpp:541
void init_members(void)
Initialise class members.
Definition: GMatrix.cpp:1280
virtual GMatrix & operator=(const GMatrix &matrix)
Matrix assignment operator.
Definition: GMatrix.cpp:228
#define G_ADD_TO_ROW
Definition: GMatrix.cpp:51
const double deg2rad
Definition: GMath.hpp:43
#define G_EXTRACT_LOWER
Definition: GMatrix.cpp:55
#define G_OP_MUL_VEC
Definition: GMatrix.cpp:42
std::string print_elements(const GChatter &chatter=NORMAL, const int &num=15) const
Print all matrix elements.
#define G_SOLVE
Definition: GMatrix.cpp:54
void eulerx(const double &angle)
Set Euler rotation matrix around x axis.
Definition: GMatrix.cpp:1120
double * m_data
Matrix data.
const int & rows(void) const
Return number of matrix rows.
GMatrix transpose(void) const
Return transposed matrix.
Definition: GMatrix.cpp:903
GVector solve(const GVector &vector) const
Solves linear matrix equation.
Definition: GMatrix.cpp:962
void eulerz(const double &angle)
Set Euler rotation matrix around z axis.
Definition: GMatrix.cpp:1194
#define G_EXTRACT_UPPER
Definition: GMatrix.cpp:56
virtual GVector operator*(const GVector &vector) const
Vector multiplication.
Definition: GMatrix.cpp:289
int m_cols
Number of columns.
virtual GMatrix & operator-=(const GMatrix &matrix)
Unary matrix subtraction operator.
Definition: GMatrix.cpp:412
GChatter
Definition: GTypemaps.hpp:33
double angle(const GVector &a, const GVector &b)
Computes angle between vectors.
Definition: GVector.cpp:974
int m_alloc
Size of allocated matrix memory.
std::string print_col_compression(const GChatter &chatter=NORMAL) const
Print column compression scheme if it exists.
Vector class interface definition.
virtual double fill(void) const
Return fill of matrix.
Definition: GMatrix.cpp:1011
virtual GMatrix & operator*=(const GMatrix &matrix)
Unary matrix multiplication operator.
Definition: GMatrix.cpp:479
#define G_OP_MAT_MUL
Definition: GMatrix.cpp:45
virtual GMatrix * clone(void) const
Clone matrix.
Definition: GMatrix.cpp:559
Symmetric matrix class definition.
void free_members(void)
Delete class members.
Definition: GMatrix.cpp:1302
int m_elements
Number of elements stored in matrix.
GMatrix(void)
Void matrix constructor.
Definition: GMatrix.cpp:70
virtual ~GMatrix(void)
Destructor.
Definition: GMatrix.cpp:204
virtual double sum(void) const
Return matrix element sum.
Definition: GMatrix.hpp:353
#define G_EXTRACT_ROW
Definition: GMatrix.cpp:47
GMatrix extract_lower_triangle(void) const
Extract lower triangle of matrix.
Definition: GMatrix.cpp:1049
Sparse matrix class definition.
GVector sin(const GVector &vector)
Computes sine of vector elements.
Definition: GVector.cpp:1316
GMatrix abs(void) const
Return absolute of matrix.
Definition: GMatrix.cpp:983
Exception handler interface definition.
virtual GMatrixBase & operator=(const GMatrixBase &matrix)
Assignment operator.
const int & size(void) const
Return size of vector.
Definition: GVector.hpp:178
void free_members(void)
Delete class members.
Generic matrix class definition.
Definition: GMatrix.hpp:79
Vector class.
Definition: GVector.hpp:46
int m_num_rowsel
Number of selected rows (for compressed decomposition)
std::string parformat(const std::string &s, const int &indent=0)
Convert string in parameter format.
Definition: GTools.cpp:1143
int * m_colstart
Column start indices (m_cols+1)
int * m_rowsel
Row selection (for compressed decomposition)
const int & columns(void) const
Return number of matrix columns.
virtual GMatrix & operator+=(const GMatrix &matrix)
Unary matrix addition operator.
Definition: GMatrix.cpp:351
#define G_CONSTRUCTOR
Definition: GMatrix.cpp:41
int * m_colsel
Column selection (for compressed decomposition)
GMatrix extract_upper_triangle(void) const
Extract upper triangle of matrix.
Definition: GMatrix.cpp:1088
void alloc_members(const int &rows, const int &columns)
Allocate matrix memory.
Definition: GMatrix.cpp:1324
Mathematical function definitions.
std::string str(const unsigned short int &value)
Convert unsigned short integer value into string.
Definition: GTools.cpp:489