/*************************************************************************** * GMatrixBase.cpp - Abstract matrix base class * * ----------------------------------------------------------------------- * * copyright (C) 2006-2013 by Juergen Knoedlseder * * ----------------------------------------------------------------------- * * * * This program is free software: you can redistribute it and/or modify * * it under the terms of the GNU General Public License as published by * * the Free Software Foundation, either version 3 of the License, or * * (at your option) any later version. * * * * This program is distributed in the hope that it will be useful, * * but WITHOUT ANY WARRANTY; without even the implied warranty of * * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * * GNU General Public License for more details. * * * * You should have received a copy of the GNU General Public License * * along with this program. If not, see . * * * ***************************************************************************/ /** * @file GMatrixBase.cpp * @brief Abstract matrix base class implementation * @author Juergen Knoedlseder */ /* __ Includes ___________________________________________________________ */ #include #include "GTools.hpp" #include "GException.hpp" #include "GVector.hpp" #include "GMatrixBase.hpp" /* __ Method name definitions ____________________________________________ */ #define G_COPY_MEMBERS "GMatrixBase::copy_members(GMatrixBase)" #define G_SELECT_NON_ZERO "GMatrixBase::select_non_zero()" /* __ Debugging definitions ______________________________________________ */ //#define G_DEBUG_COPY_MEMBERS // Dump copy_members info /*========================================================================== = = = Constructors/destructors = = = ==========================================================================*/ /***********************************************************************//** * @brief Void constructor ***************************************************************************/ GMatrixBase::GMatrixBase(void) { // Initialise members init_members(); // Return return; } /***********************************************************************//** * @brief Copy constructor * * @param[in] matrix Matrix. * * Constructs matrix by copying information from another matrix. The * constructor is sufficiently generic to provide the base constructor for * all derived classes, including sparse matrices. ***************************************************************************/ GMatrixBase::GMatrixBase(const GMatrixBase& matrix) { // Initialise class members for clean destruction init_members(); // Copy members copy_members(matrix); // Return return; } /***********************************************************************//** * @brief Destructor ***************************************************************************/ GMatrixBase::~GMatrixBase(void) { // Free class members free_members(); // Return return; } /*========================================================================== = = = Operators = = = ==========================================================================*/ /***********************************************************************//** * @brief Assignment operator * * @param[in] matrix Matrix. * @return Matrix. ***************************************************************************/ GMatrixBase& GMatrixBase::operator=(const GMatrixBase& matrix) { // Execute only if object is not identical if (this != &matrix) { // Free members free_members(); // Initialise members init_members(); // Copy members copy_members(matrix); } // endif: object was not identical // Return this object return *this; } /***********************************************************************//** * @brief Equalty operator * * @param[in] matrix Matrix. * @return True if both matrices are identical. * * Checks if two matrices are identical. Two matrices are considered * identical if they have the same dimensions and identical elements. ***************************************************************************/ bool GMatrixBase::operator==(const GMatrixBase& matrix) const { // Initalise result to true (are identical) bool result = true; // Test for difference. The loop will stop once then first difference // is encountered. if (m_rows == matrix.m_rows && m_cols == matrix.m_cols && m_elements == matrix.m_elements) { for (int i = 0; i < m_elements; ++i) { if (m_data[i] != matrix.m_data[i]) { result = false; break; } } } else { result = false; } // Return result return result; } /***********************************************************************//** * @brief Non-equality operator * * @param[in] matrix Matrix. * @return True if both matrices are different. * * Checks if two matrices are different. Two matrices are considered * different if they either have different dimensions or at least one element * that differs. ***************************************************************************/ bool GMatrixBase::operator!=(const GMatrixBase& matrix) const { // Get negated result of equality operation bool result = !(this->operator==(matrix)); // Return result return result; } /*========================================================================== = = = Protected methods = = = ==========================================================================*/ /***********************************************************************//** * @brief Initialise class members ***************************************************************************/ void GMatrixBase::init_members(void) { // Initialise members m_rows = 0; // Number of rows m_cols = 0; // Number of columns m_elements = 0; // Logically used number of elements m_alloc = 0; // Allocated # of elements (>= m_elements) m_num_rowsel = 0; // Number of selected rows (for comp. decomp.) m_num_colsel = 0; // Number of selected columns (for comp. decomp.) m_data = NULL; // Matrix data m_colstart = NULL; // Column start indices (m_cols+1) m_rowsel = NULL; // Row selection (for compressed decomposition) m_colsel = NULL; // Column selection (for compressed decomposition) // Return return; } /***********************************************************************//** * @brief Copy class members * * @param[in] matrix Matrix. ***************************************************************************/ void GMatrixBase::copy_members(const GMatrixBase& matrix) { // Copy matrix attributes m_rows = matrix.m_rows; m_cols = matrix.m_cols; m_elements = matrix.m_elements; m_alloc = matrix.m_alloc; m_num_rowsel = matrix.m_num_rowsel; m_num_colsel = matrix.m_num_colsel; // Allocate only memory if we have rows and columns and data to copy if (m_rows > 0 && m_cols > 0) { // Allocate memory for column start array and copy content if (matrix.m_colstart != NULL) { m_colstart = new int[m_cols+1]; for (int i = 0; i <= m_cols; ++i) { m_colstart[i] = matrix.m_colstart[i]; } } // Allocate memory for elements and copy them if (matrix.m_data != NULL && m_alloc > 0) { m_data = new double[m_alloc]; for (int i = 0; i < m_elements; ++i) { m_data[i] = matrix.m_data[i]; } } // If there is a row selection then copy it if (matrix.m_rowsel != NULL && m_num_rowsel > 0) { m_rowsel = new int[m_num_rowsel]; for (int i = 0; i < m_num_rowsel; ++i) { m_rowsel[i] = matrix.m_rowsel[i]; } } // If there is a column selection then copy it if (matrix.m_colsel != NULL && m_num_colsel > 0) { m_colsel = new int[m_num_colsel]; for (int i = 0; i < m_num_colsel; ++i) { m_colsel[i] = matrix.m_colsel[i]; } } } // endif: there were data to copy // Optionally show debug information #if defined(G_DEBUG_COPY_MEMBERS) std::cout << "GMatrixBase::copy_members:" << " m_colstart=" << matrix.m_colstart << "->" << m_colstart << " m_data=" << matrix.m_data << "->" << m_data << " m_rowsel=" << matrix.m_rowsel << "->" << m_rowsel << " m_colsel=" << matrix.m_colsel << "->" << m_colsel << std::endl; #endif // Return return; } /***********************************************************************//** * @brief Delete class members ***************************************************************************/ void GMatrixBase::free_members(void) { // De-allocate only if memory has indeed been allocated if (m_colsel != NULL) delete [] m_colsel; if (m_rowsel != NULL) delete [] m_rowsel; if (m_data != NULL) delete [] m_data; if (m_colstart != NULL) delete [] m_colstart; // Properly mark members as free m_colstart = NULL; m_data = NULL; m_rowsel = NULL; m_colsel = NULL; // Return return; } /***********************************************************************//** * @brief Setup compressed matrix factorisation * * Determines the non-zero rows and columns in matrix and set up index * arrays that point to these rows/columns. These arrays are used for * compressed matrix factorisations. ***************************************************************************/ void GMatrixBase::select_non_zero(void) { // Free existing selection arrays if (m_rowsel != NULL) delete [] m_rowsel; if (m_colsel != NULL) delete [] m_colsel; // Allocate selection arrays m_rowsel = new int[m_rows]; m_colsel = new int[m_cols]; // Initialise non-zero row and column counters m_num_rowsel = 0; m_num_colsel = 0; // Declare loop variables int row; int col; // Find all non-zero rows for (row = 0; row < m_rows; ++row) { for (col = 0; col < m_cols; ++col) { if ((*this)(row,col) != 0.0) { break; } } // Found a non-zero element in row if (col < m_cols) { m_rowsel[m_num_rowsel++] = row; } } // Find all non-zero columns for (col = 0; col < m_cols; ++col) { for (row = 0; row < m_rows; ++row) { if ((*this)(row,col) != 0.0) break; } // Found a non-zero element in column if (row < m_rows) { m_colsel[m_num_colsel++] = col; } } // Return return; } /***********************************************************************//** * @brief Scale all matrix elements with a scalar * * @param[in] scalar Scalar. * * Multiply all matrix elements with a scalar. There are three cases: * - the multiplier is 0, then reset all elements to 0, * - the multiplier is +/-1, then do nothing or negate, * - in any other case, multiply by multiplier. ***************************************************************************/ void GMatrixBase::scale_elements(const double& scalar) { // Case 1: If multiplicator is 0 then set entire matrix to 0 if (scalar == 0.0) { for (int i = 0; i < m_elements; ++i) { m_data[i] = 0.0; } } // Case 3: If multiplicator is not +/- 1 then perform multiplication else if (std::abs(scalar) != 1.0) { for (int i = 0; i < m_elements; ++i) { m_data[i] *= scalar; } } // Case 2: If multiplication is -1 then negate else if (scalar == -1.0) { for (int i = 0; i < m_elements; ++i) { m_data[i] = -m_data[i]; } } // Return return; } /***********************************************************************//** * @brief Set all elements to a specific value * * @param[in] value Value. * * Sets all matrix elements to a specific value. ***************************************************************************/ void GMatrixBase::set_all_elements(const double& value) { // Set all matrix elements for (int i = 0; i < m_elements; ++i) { m_data[i] = value; } // Return return; } /***********************************************************************//** * @brief Return minimum matrix element * * @return Minimum element in matrix. * * Returns the minimum matrix element. If the matrix is empty, returns 0. ***************************************************************************/ double GMatrixBase::get_min_element(void) const { // Initialise result double result = 0.0; // Continue only if there are elements if (m_elements > 0) { // Set actual minimum to first elements result = m_data[0]; // Search all elements for the smallest one for (int i = 1; i < m_elements; ++i) { if (m_data[i] < result) { result = m_data[i]; } } } // endif: there were elements // Return result return result; } /***********************************************************************//** * @brief Returns maximum matrix element * * @return Maximum element in matrix. * * Returns the maximum matrix element. If the matrix is empty, returns 0. ***************************************************************************/ double GMatrixBase::get_max_element(void) const { // Initialise result double result = 0.0; // Continue only if there are elements if (m_elements > 0) { // Set actual maximum to first elements result = m_data[0]; // Search all elements for the largest one for (int i = 1; i < m_elements; ++i) { if (m_data[i] > result) { result = m_data[i]; } } } // endif: there were elements // Return result return result; } /***********************************************************************//** * @brief Returns sum over all matrix elements ***************************************************************************/ double GMatrixBase::get_element_sum(void) const { // Initialise matrix sum double result = 0.0; // Add all elements for (int i = 0; i < m_elements; ++i) { result += m_data[i]; } // Return result return result; } /***********************************************************************//** * @brief Print all matrix elements * * @param[in] chatter Chattiness (defaults to NORMAL). * @param[in] num Maximum number of rows and columns to print (default: 10) * * Prints all matrix elements into a string. The parameter max_elements * allows to control the maximum number of matrix elements that should be * printed. If set to 0, all elements will be printed. Otherwise, the number * of rows and columns will be limited by ommitting the central values. ***************************************************************************/ std::string GMatrixBase::print_elements(const GChatter& chatter, const int& num) const { // Initialise result string std::string result; // Set row and column limits int row_stop = 0; int row_start = 0; int col_stop = 0; int col_start = 0; if (num > 0) { if (m_rows > num) { row_stop = num/2; row_start = m_rows - row_stop; } if (m_cols > num) { col_stop = num/2; col_start = m_cols - col_stop; } } // Print matrix elements row by row using the access function for (int row = 0; row < row_stop; ++row) { result += "\n "; for (int col = 0; col < col_stop; ++col) { result += gammalib::str((*this)(row,col)); if (col != m_cols-1) { result += ", "; } } if (col_start > col_stop) { result += "... "; } for (int col = col_start; col < m_cols; ++col) { result += gammalib::str((*this)(row,col)); if (col != m_cols-1) { result += ", "; } } } if (row_start > row_stop) { result += "\n "; for (int col = 0; col < col_stop; ++col) { result += "... "; } if (col_start > col_stop) { result += "... "; } for (int col = col_start; col < m_cols; ++col) { result += "... "; } } for (int row = row_start; row < m_rows; ++row) { result += "\n "; for (int col = 0; col < col_stop; ++col) { result += gammalib::str((*this)(row,col)); if (col != m_cols-1) { result += ", "; } } if (col_start > col_stop) { result += "... "; } for (int col = col_start; col < m_cols; ++col) { result += gammalib::str((*this)(row,col)); if (col != m_cols-1) { result += ", "; } } } // Return result return result; } /***********************************************************************//** * @brief Print row compression scheme if it exists * * @param[in] chatter Chattiness (defaults to NORMAL). ***************************************************************************/ std::string GMatrixBase::print_row_compression(const GChatter& chatter) const { // Initialise result string std::string result; // If there is a row compression the print the scheme if (m_rowsel != NULL) { result.append("\n"+gammalib::parformat("Row selection")); for (int row = 0; row < m_num_rowsel; ++row) { result.append(" "); result.append(gammalib::str(m_rowsel[row])); } } // Return result return result; } /***********************************************************************//** * @brief Print column compression scheme if it exists * * @param[in] chatter Chattiness (defaults to NORMAL). ***************************************************************************/ std::string GMatrixBase::print_col_compression(const GChatter& chatter) const { // Initialise result string std::string result; // If there is a row compression the print the scheme if (m_colsel != NULL) { result.append("\n"+gammalib::parformat("Column selection")); for (int col = 0; col < m_num_colsel; ++col) { result.append(" "); result.append(gammalib::str(m_colsel[col])); } } // Return result return result; }