diff --git a/src/GMatrix.cpp b/src/GMatrix.cpp index 7430af9..a092062 100644 --- a/src/GMatrix.cpp +++ b/src/GMatrix.cpp @@ -18,20 +18,51 @@ using namespace std; +/*========================================================================== + = = + = GMatrix constructors/destructors = + = = + ==========================================================================*/ + +/*************************************************************************** + * GMatrix private constructor (used for derived class initialization) * + ***************************************************************************/ +GMatrix::GMatrix(void) +{ + // Initialise private members for clean destruction + m_rows = 0; + m_cols = 0; + m_elements = 0; + m_num_rowsel = 0; + m_num_colsel = 0; + m_data = NULL; + m_colstart = NULL; + m_rowsel = NULL; + m_colsel = NULL; + + // Return + return; +} + + /*************************************************************************** * GMatrix constructor * ***************************************************************************/ -GMatrix::GMatrix(unsigned rows, unsigned cols) +GMatrix::GMatrix(int rows, int cols) { // Initialise private members for clean destruction - m_rows = 0; - m_cols = 0; - m_elements = 0; - m_data = NULL; - m_colstart = NULL; + m_rows = 0; + m_cols = 0; + m_elements = 0; + m_num_rowsel = 0; + m_num_colsel = 0; + m_data = NULL; + m_colstart = NULL; + m_rowsel = NULL; + m_colsel = NULL; // Determine number of physical elements in matrix - unsigned elements = rows*cols; + int elements = rows*cols; // Throw exception if requested matrix size is zero if (elements == 0) @@ -40,7 +71,7 @@ GMatrix::GMatrix(unsigned rows, unsigned cols) // Allocate matrix array and column start index array. Throw an exception // if allocation failed m_data = new double[elements]; - m_colstart = new unsigned[cols+1]; + m_colstart = new int[cols+1]; if (m_data == NULL || m_colstart == NULL) throw mem_alloc("GMatrix constructor", elements); @@ -51,36 +82,80 @@ GMatrix::GMatrix(unsigned rows, unsigned cols) // Set-up column start indices m_colstart[0] = 0; - for (unsigned col = 1; col <= m_cols; ++col) + for (int col = 1; col <= m_cols; ++col) m_colstart[col] = m_colstart[col-1] + m_rows; // Initialise matrix elements to 0.0 - for (unsigned i = 0; i < m_elements; ++i) + for (int i = 0; i < m_elements; ++i) m_data[i] = 0.0; + + // Return + return; } /*************************************************************************** - * GMatrix copy constructor * + * GMatrix copy constructor * + * ----------------------------------------------------------------------- * + * The copy constructor is sufficiently general to provide the base * + * constructor for all derived classes, including sparse matrices. * ***************************************************************************/ GMatrix::GMatrix(const GMatrix& m) { - m_rows = 0; - m_cols = 0; - m_elements = 0; - m_data = NULL; - m_colstart = NULL; - m_data = new double[m.m_elements]; - m_colstart = new unsigned[m.m_cols+1]; - if (m_data == NULL || m_colstart == NULL) - throw mem_alloc("GMatrix copy constructor", m.m_elements); + // Initialise private members for clean destruction + m_rows = 0; + m_cols = 0; + m_elements = 0; + m_num_rowsel = 0; + m_num_colsel = 0; + m_data = NULL; + m_colstart = NULL; + m_rowsel = NULL; + m_colsel = NULL; + + // Allocate memory for column start array and copy content + m_colstart = new int[m.m_cols+1]; + if (m_colstart == NULL) + throw mem_alloc("GMatrix copy constructor", m.m_cols+1); + for (int i = 0; i <= m.m_cols; ++i) + m_colstart[i] = m.m_colstart[i]; + + // Allocate memory for elements and copy them (only if there are elements) + if (m.m_elements > 0) { + m_data = new double[m.m_elements]; + if (m_data == NULL) + throw mem_alloc("GMatrix copy constructor", m.m_elements); + for (int i = 0; i < m.m_elements; ++i) + m_data[i] = m.m_data[i]; + } + + // If there is a row selection then copy it + if (m.m_rowsel != NULL && m.m_num_rowsel > 0) { + m_rowsel = new int[m.m_num_rowsel]; + if (m_rowsel == NULL) + throw mem_alloc("GMatrix copy constructor", m.m_num_rowsel); + for (int i = 0; i < m.m_num_rowsel; ++i) + m_rowsel[i] = m.m_rowsel[i]; + m_num_rowsel = m.m_num_rowsel; + } + + // If there is a column selection then copy it + if (m.m_colsel != NULL && m.m_num_colsel > 0) { + m_colsel = new int[m.m_num_colsel]; + if (m_colsel == NULL) + throw mem_alloc("GMatrix copy constructor", m.m_num_colsel); + for (int i = 0; i < m.m_num_colsel; ++i) + m_colsel[i] = m.m_colsel[i]; + m_num_colsel = m.m_num_colsel; + } + + // Copy matrix attributes m_rows = m.m_rows; m_cols = m.m_cols; m_elements = m.m_elements; - for (unsigned i = 0; i <= m_cols; ++i) - m_colstart[i] = m.m_colstart[i]; - for (unsigned i = 0; i < m_elements; ++i) - m_data[i] = m.m_data[i]; + + // Return + return; } @@ -90,104 +165,591 @@ GMatrix::GMatrix(const GMatrix& m) GMatrix::~GMatrix() { // De-allocate only if memory has indeed been allocated - if (m_colstart != NULL) delete[] m_colstart; - if (m_data != NULL) delete[] m_data; + if (m_colstart != NULL) delete [] m_colstart; + if (m_rowsel != NULL) delete [] m_rowsel; + if (m_colsel != NULL) delete [] m_colsel; + if (m_data != NULL) delete [] m_data; + + // Return + return; } +/*========================================================================== + = = + = GMatrix operators = + = = + ==========================================================================*/ + /*************************************************************************** * GMatrix assignment operator * ***************************************************************************/ GMatrix& GMatrix::operator= (const GMatrix& m) { - m_rows = 0; - m_cols = 0; - m_elements = 0; - m_data = NULL; - m_colstart = NULL; - m_data = new double[m.m_elements]; - m_colstart = new unsigned[m.m_cols+1]; - if (m_data == NULL || m_colstart == NULL) - throw mem_alloc("GMatrix assignment operator", m.m_elements); - m_rows = m.m_rows; - m_cols = m.m_cols; - m_elements = m.m_elements; - for (unsigned i = 0; i <= m_cols; ++i) - m_colstart[i] = m.m_colstart[i]; - for (unsigned i = 0; i < m_elements; ++i) - m_data[i] = m.m_data[i]; - return *this; -} + // Execute only if object is not identical + if (this != &m) { + + // De-allocate memory if it has indeed been allocated + if (m_colstart != NULL) delete [] m_colstart; + if (m_rowsel != NULL) delete [] m_rowsel; + if (m_colsel != NULL) delete [] m_colsel; + if (m_data != NULL) delete [] m_data; + + // Initialise private members for clean destruction + m_rows = 0; + m_cols = 0; + m_elements = 0; + m_num_rowsel = 0; + m_num_colsel = 0; + m_data = NULL; + m_colstart = NULL; + m_rowsel = NULL; + m_colsel = NULL; + + // Allocate memory for column start array and copy content + m_colstart = new int[m.m_cols+1]; + if (m_colstart == NULL) + throw mem_alloc("GMatrix::operator= (const GMatrix&)", m.m_cols+1); + for (int i = 0; i <= m.m_cols; ++i) + m_colstart[i] = m.m_colstart[i]; + + // Allocate memory for elements and copy them (only if there are elements) + if (m.m_elements > 0) { + m_data = new double[m.m_elements]; + if (m_data == NULL) + throw mem_alloc("GMatrix::operator= (const GMatrix&)", m.m_elements); + for (int i = 0; i < m.m_elements; ++i) + m_data[i] = m.m_data[i]; + } + // If there is a row selection then copy it + if (m.m_rowsel != NULL && m.m_num_rowsel > 0) { + m_rowsel = new int[m.m_num_rowsel]; + if (m_rowsel == NULL) + throw mem_alloc("GMatrix::operator= (const GMatrix&)", m.m_num_rowsel); + for (int i = 0; i < m.m_num_rowsel; ++i) + m_rowsel[i] = m.m_rowsel[i]; + m_num_rowsel = m.m_num_rowsel; + } -/*************************************************************************** - * GMatrix output operator * - ***************************************************************************/ -ostream& operator<< (ostream& os, const GMatrix& m) -{ - for (unsigned row = 0; row < m.m_rows; ++row) { - for (unsigned col = 0; col < m.m_cols; ++col) { - os << m(row,col); - if (col != m.m_cols-1) - os << ", "; - } - if (row != m.m_rows-1) - os << endl; - } - return os; + // If there is a column selection then copy it + if (m.m_colsel != NULL && m.m_num_colsel > 0) { + m_colsel = new int[m.m_num_colsel]; + if (m_colsel == NULL) + throw mem_alloc("GMatrix::operator= (const GMatrix&)", m.m_num_colsel); + for (int i = 0; i < m.m_num_colsel; ++i) + m_colsel[i] = m.m_colsel[i]; + m_num_colsel = m.m_num_colsel; + } + + // Copy matrix attributes + m_rows = m.m_rows; + m_cols = m.m_cols; + m_elements = m.m_elements; + } // endif: object was not identical + + // Return this object + return *this; } /*************************************************************************** - * GMatrix * Gvector multiplication * + * Vector multiplication * ***************************************************************************/ GVector GMatrix::operator* (const GVector& v) const { // Raise an exception if the matrix and vector dimensions are not compatible if (m_cols != v.m_num) - throw vec_mat_mismatch("GMatrix*GVector operator", v.m_num, m_rows, m_cols); + throw matrix_vector_mismatch("GMatrix::operator* (const GVector&)", + v.m_num, m_rows, m_cols); // Perform vector multiplication GVector result(m_rows); - for (unsigned row = 0; row < m_rows; ++row) { + for (int row = 0; row < m_rows; ++row) { double sum = 0.0; - for (unsigned col = 0; col < m_cols; ++col) + for (int col = 0; col < m_cols; ++col) sum += (*this)(row,col) * v(col); result(row) = sum; } + + // Return result + return result; +} + + +/*************************************************************************** + * GMatrix comparison (equality operator) * + ***************************************************************************/ +int GMatrix::operator== (const GMatrix &m) const +{ + // Initalise the result to 'equal matrices' + int result = 1; + + // Perform comparison (only if matrix dimensions and number of physical + // elements are identical; otherwise set result to 'false') + if (m_rows == m.m_rows && m_cols == m.m_cols && m_elements == m.m_elements) { + for (int i = 0; i < m_elements; ++i) { + if (m_data[i] != m.m_data[i]) { + result = 0; + break; + } + } + } + else + result = 0; + + // Return result + return result; +} + + +/*************************************************************************** + * GMatrix comparison (non-equality operator) * + ***************************************************************************/ +int GMatrix::operator!= (const GMatrix &m) const +{ + // Initalise the result to 'equal matrices' + int result = 0; + + // Perform comparison (only if matrix dimensions and number of physical + // elements are identical; otherwise set result to 'true') + if (m_rows == m.m_rows && m_cols == m.m_cols && m_elements == m.m_elements) { + for (int i = 0; i < m_elements; ++i) { + if (m_data[i] != m.m_data[i]) { + result = 1; + break; + } + } + } + else + result = 1; + + // Return result return result; } /*************************************************************************** - * GMatrix * GMatrix multiplication * + * GMatrix negation (unary minus operator) * ***************************************************************************/ -GMatrix GMatrix::operator* (const GMatrix& m) const +GMatrix GMatrix::operator- ( ) const +{ + // Copy argument into result + GMatrix result = *this; + + // Negate result + for (int i = 0; i < m_elements; ++i) + result.m_data[i] = -result.m_data[i]; + + // Return result + return result; +} + + +/*************************************************************************** + * GMatrix addition (unary addition operator) * + ***************************************************************************/ +GMatrix& GMatrix::operator+= (const GMatrix& m) +{ + // Raise an exception if the matrix dimensions are not compatible + if (m_rows != m.m_rows || m_cols != m.m_cols) + throw matrix_mismatch("GMatrix::operator+= (const GMatrix&)", + m_rows, m_cols, m.m_rows, m.m_cols); + + // Add matrices + for (int i = 0; i < m_elements; ++i) + m_data[i] += m.m_data[i]; + + // Return result + return *this; +} + + +/*************************************************************************** + * GMatrix subtraction (unary subtraction operator) * + ***************************************************************************/ +GMatrix& GMatrix::operator-= (const GMatrix& m) +{ + // Raise an exception if the matrix dimensions are not compatible + if (m_rows != m.m_rows || m_cols != m.m_cols) + throw matrix_mismatch("GMatrix::operator-= (const GMatrix&)", + m_rows, m_cols, m.m_rows, m.m_cols); + + // Subtract matrices + for (int i = 0; i < m_elements; ++i) + m_data[i] -= m.m_data[i]; + + // Return result + return *this; +} + + +/*************************************************************************** + * Matrix multiplication (unary multiplication operator) * + * ----------------------------------------------------------------------- * + * In case of rectangular matrices the result matrix does not change and * + * the operations can be performed 'quasi' inplace (except of a vector). * + * For the general case the result matrix changes the size so for * + * simplicity a new matrix is allocated to hold the results. * + ***************************************************************************/ +GMatrix& GMatrix::operator*= (const GMatrix& m) { // Raise an exception if the matrix dimensions are not compatible if (m_cols != m.m_rows) - throw GMatrix::dim_mult_mismatch("GMatrix multiplication", m_cols, m.m_rows); - - // Perform matrix multiplication - GMatrix result(m_rows,m.m_cols); - for (unsigned row = 0; row < m_rows; ++row) { - for (unsigned col = 0; col < m.m_cols; ++col) { - double sum = 0.0; - for (unsigned i = 0; i < m_cols; ++i) - sum += (*this)(row,i)*m(i,col); - result(row,col) = sum; + throw matrix_mismatch("GMatrix::operator*= (const GMatrix&)", + m_rows, m_cols, m.m_rows, m.m_cols); + + // Case A: Matrices are rectangular, so perform 'inplace' multiplication + if (m_rows == m_cols) { + for (int row = 0; row < m_rows; ++row) { + GVector v_row = extract_row(row); + for (int col = 0; col < m_cols; ++col) { + double sum = 0.0; + for (int i = 0; i < m_cols; ++i) + sum += v_row(i) * m(i,col); + (*this)(row,col) = sum; + } } } + + // Case B: Matrices are not rectangular, so we cannot work inplace + else { + + // Allocate result matrix + GMatrix result(m_rows, m.m_cols); + + // Loop over all elements of result matrix + for (int row = 0; row < m_rows; ++row) { + for (int col = 0; col < m.m_cols; ++col) { + double sum = 0.0; + for (int i = 0; i < m_cols; ++i) + sum += (*this)(row,i) * m(i,col); + result(row,col) = sum; + } + } + + // Assign result + *this = result; + + } // endelse: matrices were not rectangular + + // Return result + return *this; +} + + +/*************************************************************************** + * GMatrix scalar multiplication (unary scalar multiplication operator) * + ***************************************************************************/ +GMatrix& GMatrix::operator*= (const double& d) +{ + // Case A: If multiplicator is 0.0 then set entire matrix to 0.0 + if (d == 0.0) { + for (int i = 0; i < m_elements; ++i) + m_data[i] = 0.0; + } + + // Case B: If multiplicator is not +/- 1.0 then perform multiplication + else if (fabs(d) != 1.0) { + for (int i = 0; i < m_elements; ++i) + m_data[i] *= d; + } + + // Case C: If multiplication is -1.0 then negate + else if (d == -1.0) { + for (int i = 0; i < m_elements; ++i) + m_data[i] = -m_data[i]; + } + + // Return result + return *this; +} + + +/*************************************************************************** + * Matrix scalar division (unary scalar division operator) * + ***************************************************************************/ +GMatrix& GMatrix::operator/= (const double& d) +{ + // Case A: If divider is not +/- 1.0 then perform division + if (fabs(d) != 1.0) { + for (int i = 0; i < m_elements; ++i) + m_data[i] /= d; + } + + // Case B: If divider is -1.0 then negate + else if (d == -1.0) { + for (int i = 0; i < m_elements; ++i) + m_data[i] = -m_data[i]; + } + + // Return result + return *this; +} + + +/*========================================================================== + = = + = GMatrix member functions = + = = + ==========================================================================*/ + +/*************************************************************************** + * Get minimum physical matrix element * + ***************************************************************************/ +double GMatrix::min() const +{ + // Initialise minimum with first element + double 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]; + } + + // Return result + return result; +} + + +/*************************************************************************** + * Get maximum physical matrix element * + ***************************************************************************/ +double GMatrix::max() const +{ + // Initialise minimum with first element + double 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]; + } + + // Return result + return result; +} + + +/*************************************************************************** + * Get matrix sum * + ***************************************************************************/ +double GMatrix::sum() 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; +} + + +/*************************************************************************** + * Inplace transpose of matrix * + * ----------------------------------------------------------------------- * + * The transpose operation exchanges the number of rows against the number * + * of columns. The element transformation is done inplace. * + ***************************************************************************/ +void GMatrix::transpose() +{ + // Case A: matrix is rectangular then simply swap the elements + if (m_rows == m_cols) { + double swap; + double* ptr_dst; + double* ptr_src; + for (int row = 0; row < m_rows; ++row) { + for (int col = row; col < m_cols; ++col) { + ptr_dst = m_data + m_cols*row + col; + ptr_src = m_data + m_rows*col + row; + swap = *ptr_dst; + *ptr_dst = *ptr_src; + *ptr_src = swap; + } + } + } + + // Case B: Dummy for non-rectangular transpose + else { + GMatrix result(m_cols, m_rows); + for (int row = 0; row < m_rows; ++row) { + for (int col = 0; col < m_cols; ++col) + result(col, row) = (*this)(row, col); + } + *this = result; + } + +} + + +/*************************************************************************** + * Extract row from matrix into vector * + ***************************************************************************/ +GVector GMatrix::extract_row(int row) const +{ + // Raise an exception if the row index is invalid + #if defined(G_RANGE_CHECK) + if (row >= m_rows) + throw out_of_range("GMatrix::extract_row(int)", + row, 0, m_rows, m_cols); + #endif + + // Create result vector + GVector result(m_cols); + + // Extract row into vector + for (int col = 0; col < m_cols; ++col) + result(col) = (*this)(row,col); + + // Return vector return result; + } /*************************************************************************** - * Class exception handlers * + * Extract column from matrix into vector * ***************************************************************************/ -// Matrix row or column out of range -GMatrix::out_of_range::out_of_range(string origin, unsigned row, unsigned col, - unsigned rows, unsigned cols) +GVector GMatrix::extract_col(int col) const +{ + // Raise an exception if the column index is invalid + #if defined(G_RANGE_CHECK) + if (col >= m_cols) + throw out_of_range("GMatrix::extract_col(int)", + 0, col, m_rows, m_cols); + #endif + + // Create result vector + GVector result(m_rows); + + // Extract column into vector + for (int row = 0; row < m_rows; ++row) + result(row) = (*this)(row,col); + + // Return vector + return result; + +} + + +/*========================================================================== + = = + = GMatrix private member functions = + = = + ==========================================================================*/ + +/*************************************************************************** + * select_non_zero * + * ----------------------------------------------------------------------- * + * Determines the non-zero rows and columns in matrix and set up index * + * arrays that points to these rows/columns. These arraya are used for * + * compressed matrix factorisations. * + ***************************************************************************/ +void GMatrix::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]; + if (m_rowsel == NULL) + throw mem_alloc("GMatrix::select_non_zero()", m_rows); + m_colsel = new int[m_cols]; + if (m_colsel == NULL) + throw mem_alloc("GMatrix::select_non_zero()", 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; + } + if (col < m_cols) // found a non-zero element in row + 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; + } + if (row < m_rows) // found a non-zero element in column + m_colsel[m_num_colsel++] = col; + } + + // Return + return; +} + +/*========================================================================== + = = + = GMatrix friends = + = = + ==========================================================================*/ + +/*************************************************************************** + * Output operator * + ***************************************************************************/ +ostream& operator<< (ostream& os, const GMatrix& m) +{ + // Loop over all matrix elements + for (int row = 0; row < m.m_rows; ++row) { + for (int col = 0; col < m.m_cols; ++col) { + os << m(row,col); + if (col != m.m_cols-1) + os << ", "; + } + if (row != m.m_rows-1) + os << endl; + } + + // Return output stream + return os; +} + + +/*************************************************************************** + * Matrix absolute values * + ***************************************************************************/ +GMatrix fabs(const GMatrix& m) +{ + // Define result matrix + GMatrix result = m; + + // Convert all elements to absolute values + for (int i = 0; i < result.m_elements; ++i) + result.m_data[i] = fabs(result.m_data[i]); + + // Return result + return result; +} + + +/*========================================================================== + = = + = GMatrix exception classes = + = = + ==========================================================================*/ + +/*************************************************************************** + * Matrix row or column out of range * + ***************************************************************************/ +GMatrix::out_of_range::out_of_range(string origin, int row, int col, + int rows, int cols) { m_origin = origin; ostringstream s_row; @@ -203,9 +765,12 @@ GMatrix::out_of_range::out_of_range(string origin, unsigned row, unsigned col, s_cols.str() + "])"; } -// Matrix - Vector mismatch -GMatrix::vec_mat_mismatch::vec_mat_mismatch(string origin, unsigned num, - unsigned rows, unsigned cols) + +/*************************************************************************** + * Mismatch between matrix and vector * + ***************************************************************************/ +GMatrix::matrix_vector_mismatch::matrix_vector_mismatch(string origin, + int num, int rows, int cols) { m_origin = origin; ostringstream s_num; @@ -219,9 +784,12 @@ GMatrix::vec_mat_mismatch::vec_mat_mismatch(string origin, unsigned num, s_rows.str() + "," + s_cols.str() + "]"; } -// Matrix mismatch (additional etc.) -GMatrix::dim_add_mismatch::dim_add_mismatch(string origin, unsigned rows1, unsigned rows2, - unsigned cols1, unsigned cols2) + +/*************************************************************************** + * Matrix mismatch in operation * + ***************************************************************************/ +GMatrix::matrix_mismatch::matrix_mismatch(string origin, int rows1, + int cols1, int rows2, int cols2) { m_origin = origin; ostringstream s_rows1; @@ -229,24 +797,84 @@ GMatrix::dim_add_mismatch::dim_add_mismatch(string origin, unsigned rows1, unsig ostringstream s_cols1; ostringstream s_cols2; s_rows1 << rows1; + s_cols1 << cols1; s_rows2 << rows2; + s_cols2 << cols2; + m_message = "Matrix mismatch: M1(" + s_rows1.str() + "," + s_cols1.str() + + ") incompatible with M2(" + s_rows2.str() + "," + + s_cols2.str() + ")"; +} + + +/*************************************************************************** + * Matrix not rectangular * + ***************************************************************************/ +GMatrix::matrix_not_rect::matrix_not_rect(string origin, int rows1, + int cols1, int rows2, int cols2) +{ + m_origin = origin; + ostringstream s_rows1; + ostringstream s_rows2; + ostringstream s_cols1; + ostringstream s_cols2; + s_rows1 << rows1; s_cols1 << cols1; + s_rows2 << rows2; s_cols2 << cols2; - m_message = "Size [" + s_rows1.str() + "," + s_cols1.str() + - "] of first matrix is incompatible with size [" + - s_rows2.str() + "," + s_cols2.str() + - "] of second matrix"; + m_message = "Operation only valid for rectangular matrices: M[" + + s_rows1.str() + "," + s_cols1.str() + + "] *= M[" + s_rows2.str() + "," + s_cols2.str() + + "] not allowed"; +} + + +/*************************************************************************** + * Matrix is not positive definite * + ***************************************************************************/ +GMatrix::matrix_not_pos_definite::matrix_not_pos_definite(string origin, + int row, double sum) +{ + m_origin = origin; + ostringstream s_rows; + ostringstream s_sum; + s_rows << row; + s_sum << scientific << sum; + m_message = "Matrix is not positive definite (sum " + s_sum.str() + + " occured in row/column " + s_rows.str() + ")"; } -// Matrix mismatch (multiplication) -GMatrix::dim_mult_mismatch::dim_mult_mismatch(string origin, unsigned cols, unsigned rows) + +/*************************************************************************** + * Matrix is not symmetric * + ***************************************************************************/ +GMatrix::matrix_not_symmetric::matrix_not_symmetric(string origin, int cols, + int rows) { m_origin = origin; ostringstream s_rows; ostringstream s_cols; s_rows << rows; s_cols << cols; - m_message = "Number of columns [" + s_cols.str() + - "] in first matrix is incompatible with number of rows [" + - s_rows.str() + "] in second matrix"; + m_message = "Matrix is not symmetric [" + s_rows.str() + "," + + s_cols.str() + "]"; +} + + +/*************************************************************************** + * Matrix has not been factorised * + ***************************************************************************/ +GMatrix::matrix_not_factorised::matrix_not_factorised(string origin, string type) +{ + m_origin = origin; + m_message = "Matrix has not been factorised using " + type; +} + + +/*************************************************************************** + * All matrix elements are zero * + ***************************************************************************/ +GMatrix::matrix_zero::matrix_zero(string origin) +{ + m_origin = origin; + m_message = "All matrix elements are zero"; } diff --git a/src/GMatrix.hpp b/src/GMatrix.hpp index 078957f..e308811 100644 --- a/src/GMatrix.hpp +++ b/src/GMatrix.hpp @@ -32,264 +32,131 @@ using namespace std; * GMatrix class definition * ***************************************************************************/ class GMatrix { - // Operator friends - friend GMatrix operator+ (const double& a, const GMatrix& b); - friend GMatrix operator- (const double& a, const GMatrix& b); - friend GMatrix operator* (const double& a, const GMatrix& b); + // Binary operator friends + friend GMatrix operator* (const double& a, const GMatrix& b); + friend GMatrix operator* (const GMatrix& a, const double& b); + friend GMatrix operator/ (const GMatrix& a, const double& b); // I/O friends - friend ostream& operator<< (ostream& os, const GMatrix& m); + friend ostream& operator<< (ostream& os, const GMatrix& m); // Friend functions friend GMatrix transpose(const GMatrix& m); friend GMatrix fabs(const GMatrix& m); + public: // Constructors and destructors - GMatrix(unsigned rows, unsigned cols); + GMatrix(int rows, int cols); GMatrix(const GMatrix& m); virtual ~GMatrix(); // Matrix element access operators - virtual double& operator() (unsigned row, unsigned col); - virtual const double& operator() (unsigned row, unsigned col) const; + virtual double& operator() (int row, int col); + virtual const double& operator() (int row, int col) const; // Matrix assignment operators - GMatrix& operator= (const GMatrix& m); - GMatrix& operator= (const double& d); + virtual GMatrix& operator= (const GMatrix& m); + + // Binary operators + virtual GMatrix operator+ (const GMatrix& m) const; + virtual GMatrix operator- (const GMatrix& m) const; + virtual GMatrix operator* (const GMatrix& m) const; + virtual GVector operator* (const GVector& v) const; + virtual int operator== (const GMatrix& m) const; + virtual int operator!= (const GMatrix& m) const; - // Generic matrix operators (structure independent) + // Unary operators + GMatrix operator- () const; virtual GMatrix& operator+= (const GMatrix& m); virtual GMatrix& operator-= (const GMatrix& m); - virtual GMatrix& operator+= (const double& d); - virtual GMatrix& operator-= (const double& d); + virtual GMatrix& operator*= (const GMatrix& m); virtual GMatrix& operator*= (const double& d); virtual GMatrix& operator/= (const double& d); - virtual int operator== (const GMatrix& m) const; - virtual int operator!= (const GMatrix& m) const; - - // Specific matrix operators (structure dependent) - GMatrix operator+ (const GMatrix& m) const; - GMatrix operator- (const GMatrix& m) const; - GMatrix operator* (const GMatrix& m) const; - virtual GVector operator* (const GVector& v) const; - GMatrix operator+ (const double& d) const; - GMatrix operator- (const double& d) const; - GMatrix operator* (const double& d) const; - GMatrix operator/ (const double& d) const; - GMatrix operator- () const; - - // Generic matrix functions (structure independent) - virtual double min() const; // Minimum physical element - virtual double max() const; // Maximum physical element - virtual double sum() const; // Sum of matrix elements - virtual unsigned rows() const; // Return number of rows - virtual unsigned cols() const; // Return number of columns - // Specific matrix functions (structure dependent) - virtual void transpose(); // Inplace transpose of matrix + // Matrix functions + virtual int rows() const { return m_rows; } + virtual int cols() const { return m_cols; } + virtual double min() const; + virtual double max() const; + virtual double sum() const; + virtual void transpose(); + virtual GVector extract_row(int row) const; + virtual GVector extract_col(int col) const; // Exception: Matrix indices out of range class out_of_range : public GException { public: - out_of_range(string origin, unsigned row, unsigned col, - unsigned rows, unsigned cols); + out_of_range(string origin, int row, int col, int rows, int cols); }; // Exception: Vector - Matrix mismatch - class vec_mat_mismatch : public GException { + class matrix_vector_mismatch : public GException { public: - vec_mat_mismatch(string origin, unsigned num, unsigned rows, unsigned cols); + matrix_vector_mismatch(string origin, int num, int rows, int cols); }; - // Exception: Matrix dimensions mismatch (addition, etc.) - class dim_add_mismatch : public GException { + // Exception: Matrix dimensions mismatch + class matrix_mismatch : public GException { public: - dim_add_mismatch(string origin, unsigned rows1, unsigned rows2, - unsigned cols1, unsigned cols2); + matrix_mismatch(string origin, int rows1, int cols1, int cols1, int cols2); }; - // Exception: Matrix dimensions mismatch (multiplication) - class dim_mult_mismatch : public GException { + // Exception: Matrix not rectangular + class matrix_not_rect : public GException { public: - dim_mult_mismatch(string origin, unsigned cols, unsigned rows); + matrix_not_rect(string origin, int rows1, int cols1, int cols1, int cols2); }; -protected: - // Void constructor to be used by derived classes which have own constructor - GMatrix() { } - - // Private data area - unsigned m_rows; // Number of rows - unsigned m_cols; // Number of columns - unsigned m_elements; // Number of (physical) elements in matrix - unsigned* m_colstart; // Column start indices (m_cols+1) - double* m_data; // Matrix data -}; - - -/*************************************************************************** - * Generic inline members (to be inherited) * - ***************************************************************************/ -// Matrix unary addition operator: GMatrix += GMatrix -inline -GMatrix& GMatrix::operator+= (const GMatrix& m) -{ - if (m_rows != m.m_rows || m_cols != m.m_cols) - throw dim_add_mismatch("GMatrix += operator", m_rows, m.m_rows, m_cols, m.m_cols); - for (unsigned i = 0; i < m_elements; ++i) - m_data[i] += m.m_data[i]; - return *this; -} - -// Matrix unary subtraction operator: GMatrix -= GMatrix -inline -GMatrix& GMatrix::operator-= (const GMatrix& m) -{ - if (m_rows != m.m_rows || m_cols != m.m_cols) - throw dim_add_mismatch("GMatrix -= operator", m_rows, m.m_rows, m_cols, m.m_cols); - for (unsigned i = 0; i < m_elements; ++i) - m_data[i] -= m.m_data[i]; - return *this; -} - -// Scalar unary addition operator: GMatrix += double -inline -GMatrix& GMatrix::operator+= (const double& d) -{ - for (unsigned i = 0; i < m_elements; ++i) - m_data[i] += d; - return *this; -} - -// Scalar unary subtraction operator: GMatrix -= double -inline -GMatrix& GMatrix::operator-= (const double& d) -{ - for (unsigned i = 0; i < m_elements; ++i) - m_data[i] -= d; - return *this; -} - -// Scalar unary multiplication operator: GMatrix *= double -inline -GMatrix& GMatrix::operator*= (const double& d) -{ - for (unsigned i = 0; i < m_elements; ++i) - m_data[i] *= d; - return *this; -} - -// Scalar unary division operator: GMatrix /= double -inline -GMatrix& GMatrix::operator/= (const double& d) -{ - for (unsigned i = 0; i < m_elements; ++i) - m_data[i] /= d; - return *this; -} - -// Equality operator: GMatrix == GMatrix -inline -int GMatrix::operator== (const GMatrix &m) const -{ - int result = 1; - if (m_rows == m.m_rows && m_cols == m.m_cols && m_elements == m.m_elements) { - for (unsigned i = 0; i < m_elements; ++i) { - if (m_data[i] != m.m_data[i]) { - result = 0; - break; - } - } - } - else - result = 0; - return result; -} + // Exception: Matrix not positive definite + class matrix_not_pos_definite : public GException { + public: + matrix_not_pos_definite(string origin, int row, double sum); + }; -// Non equality operator: GMatrix != GMatrix -inline -int GMatrix::operator!= (const GMatrix &m) const -{ - int result = 0; - if (m_rows == m.m_rows && m_cols == m.m_cols && m_elements == m.m_elements) { - for (unsigned i = 0; i < m_elements; ++i) { - if (m_data[i] != m.m_data[i]) { - result = 1; - break; - } - } - } - else - result = 1; - return result; -} + // Exception: Matrix not symmetric + class matrix_not_symmetric : public GException { + public: + matrix_not_symmetric(string origin, int cols, int rows); + }; -// Matrix minimum: GMatrix.min() -inline -double GMatrix::min() const -{ - double result = m_data[0]; - for (unsigned i = 1; i < m_elements; ++i) { - if (m_data[i] < result) - result = m_data[i]; - } - return result; -} + // Exception: Matrix not factorised + class matrix_not_factorised : public GException { + public: + matrix_not_factorised(string origin, string type); + }; -// Matrix maximum: GMatrix.max() -inline -double GMatrix::max() const -{ - double result = m_data[0]; - for (unsigned i = 1; i < m_elements; ++i) { - if (m_data[i] > result) - result = m_data[i]; - } - return result; -} + // Exception: All matrix elements are zero + class matrix_zero : public GException { + public: + matrix_zero(string origin); + }; -// Matrix sum: GMatrix.sum() -inline -double GMatrix::sum() const -{ - double result = 0.0; - for (unsigned row = 0; row < m_rows; ++row) { - for (unsigned col = 0; col < m_cols; ++col) - result += (*this)(row,col); - } - return result; -} +protected: + // Void constructor to be used by derived classes which have own constructor + GMatrix(); -// Return number of rows: GMatrix.rows() -inline -unsigned GMatrix::rows() const -{ - return m_rows; -} + // Private member functions + void select_non_zero(void); -// Return number of columns: GMatrix.cols() -inline -unsigned GMatrix::cols() const -{ - return m_cols; -} + // Private data area + int m_rows; // Number of rows + int m_cols; // Number of columns + int m_elements; // Number of (physical) elements in matrix + int m_num_rowsel; // Number of selected rows (for compressed decomposition) + int m_num_colsel; // Number of selected columns (for compressed decomposition) + int* m_colstart; // Column start indices (m_cols+1) + int* m_rowsel; // Row selection (for compressed decomposition) + int* m_colsel; // Column selection (for compressed decomposition) + double* m_data; // Matrix data +}; /*************************************************************************** - * Specific inline members (may need specific function for derived class) * + * Inline member functions * ***************************************************************************/ -// Scalar assignment operator: GMatrix = double -inline -GMatrix& GMatrix::operator= (const double& d) -{ - for (unsigned i = 0; i < m_elements; ++i) - m_data[i] = d; - return *this; -} - -// Matrix element access operator: GMatrix(row,col) +// Matrix element access operator inline -double& GMatrix::operator() (unsigned row, unsigned col) +double& GMatrix::operator() (int row, int col) { #if defined(G_RANGE_CHECK) if (row >= m_rows || col >= m_cols) @@ -298,9 +165,9 @@ double& GMatrix::operator() (unsigned row, unsigned col) return m_data[m_colstart[col]+row]; } -// Matrix element access operator (const version): GMatrix(row,col) +// Matrix element access operator (const version) inline -const double& GMatrix::operator() (unsigned row, unsigned col) const +const double& GMatrix::operator() (int row, int col) const { #if defined(G_RANGE_CHECK) if (row >= m_rows || col >= m_cols) @@ -309,7 +176,7 @@ const double& GMatrix::operator() (unsigned row, unsigned col) const return m_data[m_colstart[col]+row]; } -// Matrix addition: GMatrix + GMatrix +// Binary matrix addition inline GMatrix GMatrix::operator+ (const GMatrix& m) const { @@ -318,7 +185,7 @@ GMatrix GMatrix::operator+ (const GMatrix& m) const return result; } -// Matrix subtraction: GMatrix - GMatrix +// Binary matrix subtraction inline GMatrix GMatrix::operator- (const GMatrix& m) const { @@ -327,91 +194,29 @@ GMatrix GMatrix::operator- (const GMatrix& m) const return result; } -// Matrix scaling: GMatrix + double -inline -GMatrix GMatrix::operator+ (const double& d) const -{ - GMatrix result = (*this); - result += d; - return result; -} - -// Matrix scaling: GMatrix - double -inline -GMatrix GMatrix::operator- (const double& d) const -{ - GMatrix result = (*this); - result -= d; - return result; -} - -// Matrix scaling: GMatrix * double -inline -GMatrix GMatrix::operator* (const double& d) const -{ - GMatrix result = (*this); - result *= d; - return result; -} - -// Matrix inverse scaling: GMatrix * double -inline -GMatrix GMatrix::operator/ (const double& d) const -{ - GMatrix result = (*this); - result /= d; - return result; -} - -// Unary minus operator: -GMatrix +// Binary matrix multiplication inline -GMatrix GMatrix::operator- ( ) const +GMatrix GMatrix::operator* (const GMatrix& m) const { GMatrix result = *this; - for (unsigned i = 0; i < m_elements; ++i) - result.m_data[i] = -result.m_data[i]; + result *= m; return result; } -// Matrix transpose: GMatrix.transpose() -inline -void GMatrix::transpose() -{ - for (unsigned row = 0; row < m_rows; ++row) { - double* ptr0 = m_data + row; - double* ptr2 = m_data + m_colstart[row]+row+1; - for (unsigned col = row+1; col < m_cols; ++col) { - double* ptr1 = ptr0 + m_colstart[col]; - double swap = *ptr1; - *ptr1 = *ptr2; - *ptr2++ = swap; - } - } -} - /*************************************************************************** * Inline friends * ***************************************************************************/ -// Matrix addition: double + GMatrix -inline -GMatrix operator+ (const double& a, const GMatrix& b) -{ - GMatrix result = b; - result += a; - return result; -} - -// Matrix subtraction: double - GMatrix -inline -GMatrix operator- (const double& a, const GMatrix& b) +// Binary matrix scaling (matrix is left operand) +inline +GMatrix operator* (const GMatrix& a, const double& b) { - GMatrix result = b; - result -= a; + GMatrix result = a; + result *= b; return result; } -// Matrix scaling: double * GMatrix +// Binary matrix scaling (matrix is right operand) inline GMatrix operator* (const double& a, const GMatrix& b) { @@ -420,22 +225,21 @@ GMatrix operator* (const double& a, const GMatrix& b) return result; } -// Matrix transpose: transpose(GMatrix) -inline -GMatrix transpose(const GMatrix& m) +// Binary matrix division (matrix is left operand) +inline +GMatrix operator/ (const GMatrix& a, const double& b) { - GMatrix result = m; - result.transpose(); + GMatrix result = a; + result /= b; return result; } -// Matrix absolute: fabs(GMatrix) +// Matrix transpose function inline -GMatrix fabs(const GMatrix& m) +GMatrix transpose(const GMatrix& m) { GMatrix result = m; - for (unsigned i = 0; i < result.m_elements; ++i) - result.m_data[i] = fabs(result.m_data[i]); + result.transpose(); return result; } diff --git a/src/GSparseMatrix.cpp b/src/GSparseMatrix.cpp new file mode 100644 index 0000000..52df670 --- /dev/null +++ b/src/GSparseMatrix.cpp @@ -0,0 +1,1691 @@ +/*************************************************************************** + * GSparseMatrix.cpp - sparse matrix class * + * ----------------------------------------------------------------------- * + * copyright : (C) 2006 by Jurgen Knodlseder * + * ----------------------------------------------------------------------- * + * * + * 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 2 of the License, or * + * (at your option) any later version. * + * * + * ----------------------------------------------------------------------- * + * This class implements the compressed sparse column format. The * + * following arrays are allocated: * + * m_data : holds all 'elements' non-zero values, in column order (Ax) * + * m_colstart : holds the index of the first element of each column (Ap) * + * m_rowinx : holds the row indices for all elements (Ai) * + * Column 'col' covers therefore [m_colstart[j], ..., m_colstart[j+1]-1] * + * Note that 'm_colstart' has m_cols+1 elements. * +/*************************************************************************** + +/* __ Includes ___________________________________________________________ */ +#include "GSparseMatrix.hpp" +#include "GSparseSymbolic.hpp" +#include "GSparseNumeric.hpp" + +/* __ Namespaces _________________________________________________________ */ +using namespace std; + +/* __ Definitions ________________________________________________________ */ +//#define G_DEBUG_SPARSE_PENDING // Analyse pending values +//#define G_DEBUG_SPARSE_INSERTION // Analyse value insertion +//#define G_DEBUG_SPARSE_COMPRESSION // Analyse zero row/column compression + + +/*========================================================================== + = = + = GSparseMatrix constructors/destructors = + = = + ==========================================================================*/ + +/*************************************************************************** + * GSparseMatrix constructor * + ***************************************************************************/ +GSparseMatrix::GSparseMatrix(int rows, int cols, int elements) : GMatrix() +{ + // Initialise private members for clean destruction + m_rows = 0; + m_cols = 0; + m_elements = 0; + m_data = NULL; + m_colstart = NULL; + m_rowinx = NULL; + m_zero = 0.0; + m_fill_val = 0.0; + m_fill_row = 0; + m_fill_col = 0; + m_symbolic = NULL; + m_numeric = NULL; + + // Allocate column start array. This is the only array that we can + // allocate at this time. The other arrays can only be allocated during + // filling of the matrix + m_colstart = new int[cols+1]; + if (m_colstart == NULL) + throw mem_alloc("GSparseMatrix constructor", cols+1); + + // Store (logical) matrix size + m_rows = rows; + m_cols = cols; + + // Initialise column start indices to 0 + for (int col = 0; col <= m_cols; ++col) + m_colstart[col] = 0; + + // Optionally allocate elements + if (elements > 0) + alloc_elements(0, elements); + + // Return + return; +} + + +/*************************************************************************** + * GSparseMatrix copy constructor * + * ----------------------------------------------------------------------- * + * First invoques GMatrix copy constructor (which sets the logical matrix * + * dimensions and copies the elements and the column start array). It * + * remains then to this constructor to copy the row indices. * + * NOTE: The copy constructor does NOT fill a pending element. * + ***************************************************************************/ +GSparseMatrix::GSparseMatrix(const GSparseMatrix& m) : GMatrix(m) +{ + // Initialise private members for clean destruction + m_rowinx = NULL; + m_symbolic = NULL; + m_numeric = NULL; + + // Copy data members + m_zero = m.m_zero; + m_fill_val = m.m_fill_val; + m_fill_row = m.m_fill_row; + m_fill_col = m.m_fill_col; + + // Allocate memory for row indices and copy them (only if there are elements) + if (m_elements > 0) { + m_rowinx = new int[m_elements]; + if (m_rowinx == NULL) + throw mem_alloc("GSparseMatrix copy constructor", m_elements); + for (int i = 0; i < m_elements; ++i) + m_rowinx[i] = m.m_rowinx[i]; + } + + // If there is a symbolic decomposition then copy it + if (m.m_symbolic != NULL) { + GSparseSymbolic* symbolic = new GSparseSymbolic(); + if (symbolic == NULL) + throw mem_alloc("GSparseMatrix copy constructor", 1); + *symbolic = *((GSparseSymbolic*)m.m_symbolic); + m_symbolic = (void*)symbolic; + } + + // If there is a numeric decomposition then copy it + if (m.m_numeric != NULL) { + GSparseNumeric* numeric = new GSparseNumeric(); + if (numeric == NULL) + throw mem_alloc("GSparseMatrix copy constructor", 1); + *numeric = *((GSparseNumeric*)m.m_numeric); + m_numeric = (void*)numeric; + } + + // Return + return; +} + + +/*************************************************************************** + * GSparseMatrix destructor * + * ----------------------------------------------------------------------- * + * First invoques this destructor to de-allocate row indices, then invoque * + * ~GMatrix destructor to de-allocate the other arrays. * + ***************************************************************************/ +GSparseMatrix::~GSparseMatrix() +{ + // De-allocate only if memory has indeed been allocated by derived class + if (m_rowinx != NULL) delete [] m_rowinx; + if (m_symbolic != NULL) delete (GSparseSymbolic*)m_symbolic; + if (m_numeric != NULL) delete (GSparseNumeric*)m_numeric; + + // Return + return; +} + + +/*========================================================================== + = = + = GSparseMatrix operators = + = = + ==========================================================================*/ + +/*************************************************************************** + * GSparseMatrix assignment operator * + ***************************************************************************/ +GSparseMatrix& GSparseMatrix::operator= (const GSparseMatrix& m) +{ + // Execute only if object is not identical + if (this != &m) { + + // Invoque base class assignment operator + this->GMatrix::operator=(m); + + // De-allocate memory if it has indeed been allocated + if (m_rowinx != NULL) delete [] m_rowinx; + if (m_symbolic != NULL) delete (GSparseSymbolic*)m_symbolic; + if (m_numeric != NULL) delete (GSparseNumeric*)m_numeric; + + // Initialise private members for clean destruction + m_rowinx = NULL; + m_symbolic = NULL; + m_numeric = NULL; + + // Copy data members + m_zero = m.m_zero; + m_fill_val = m.m_fill_val; + m_fill_row = m.m_fill_row; + m_fill_col = m.m_fill_col; + + // Allocate memory for row indices and copy them (only if there are elements) + if (m_elements > 0) { + m_rowinx = new int[m_elements]; + if (m_rowinx == NULL) + throw mem_alloc("GSparseMatrix::operator= (const GSparseMatrix&)", + m_elements); + for (int i = 0; i < m_elements; ++i) + m_rowinx[i] = m.m_rowinx[i]; + } + + // If there is a symbolic decomposition then copy it + if (m.m_symbolic != NULL) { + GSparseSymbolic* symbolic = new GSparseSymbolic(); + if (symbolic == NULL) + throw mem_alloc("GSparseMatrix copy constructor", 1); + *symbolic = *((GSparseSymbolic*)m.m_symbolic); + m_symbolic = (void*)symbolic; + } + + // If there is a numeric decomposition then copy it + if (m.m_numeric != NULL) { + GSparseNumeric* numeric = new GSparseNumeric(); + if (numeric == NULL) + throw mem_alloc("GSparseMatrix copy constructor", 1); + *numeric = *((GSparseNumeric*)m.m_numeric); + m_numeric = (void*)numeric; + } + + } // endif: object was not identical + + // Return + return *this; +} + + +/*************************************************************************** + * Vector multiplication * + * ----------------------------------------------------------------------- * + * Performs sparse matrix*vector multiplication including an eventually * + * pending fill. * + ***************************************************************************/ +GVector GSparseMatrix::operator* (const GVector& v) const +{ + // Raise an exception if the matrix and vector dimensions are not compatible + if (m_cols != v.m_num) + throw matrix_vector_mismatch("GSparseMatrix::operator* (const GVector&)", + v.m_num, m_rows, m_cols); + + // Initialise result vector + GVector result(m_rows); + + // Multiply only if there are elements in matrix + if (m_elements > 0) { + + // Perform vector multiplication + for (int col = 0; col < m_cols; ++col) { + int i_start = m_colstart[col]; + int i_stop = m_colstart[col+1]; + double* ptr_data = m_data + i_start; + int* ptr_rowinx = m_rowinx + i_start; + for (int i = i_start; i < i_stop; ++i) + result(*ptr_rowinx++) += *ptr_data++ * v(col); + } + + // If fill is pending then add-in also this element into the product + if (m_fill_val != 0.0) { + result(m_fill_row) += m_fill_val * v(m_fill_col); + #if defined(G_DEBUG_SPARSE_PENDING) + cout << "GSparseMatrix::operator* (const GVector&) const: pending value " << + m_fill_val << " for location (" << m_fill_row << "," << m_fill_col << + ") has been used." << endl; + #endif + } + + } // endif: there were elements in matrix + + // Return result + return result; +} + + +/*************************************************************************** + * GSparseMatrix comparison (equality operator) * + ***************************************************************************/ +int GSparseMatrix::operator== (const GSparseMatrix &m) const +{ + // Initalise the result to 'equal matrices' + int result = 1; + + // Perform comparison (only if matrix dimensions are identical) + if (m_rows == m.m_rows && m_cols == m.m_cols) { + + // Loop over all matrix elements + for (int row = 0; row < m_rows; ++row) { + for (int col = 0; col < m_cols; ++col) { + if ((*this)(row,col) != m(row,col)) { + result = 0; + break; + } + } + if (!result) + break; + } + } + else + result = 0; + + // Return result + return result; +} + + +/*************************************************************************** + * GSparseMatrix comparison (non-equality operator) * + ***************************************************************************/ +int GSparseMatrix::operator!= (const GSparseMatrix &m) const +{ + // Initalise the result to 'equal matrices' + int result = 0; + + // Perform comparison (only if matrix dimensions are identical) + if (m_rows == m.m_rows && m_cols == m.m_cols) { + + // Loop over all matrix elements + for (int row = 0; row < m_rows; ++row) { + for (int col = 0; col < m_cols; ++col) { + if ((*this)(row,col) != m(row,col)) { + result = 1; + break; + } + } + if (!result) + break; + } + } + else + result = 1; + + // Return result + return result; +} + + +/*************************************************************************** + * GSparseMatrix negation (unary minus operator) * + ***************************************************************************/ +GSparseMatrix GSparseMatrix::operator- ( ) const +{ + // Copy argument into result + GSparseMatrix result = *this; + + // Fill pending matrix element + result.fill_pending(); + + // Negate result + for (int i = 0; i < result.m_elements; ++i) + result.m_data[i] = -result.m_data[i]; + + // Return result + return result; +} + + +/*************************************************************************** + * GSparseMatrix addition (unary addition operator) * + * ----------------------------------------------------------------------- * + * NOT YET IN PURE NATIVE CODE !!!!!! * + ***************************************************************************/ +GSparseMatrix& GSparseMatrix::operator+= (const GSparseMatrix& m) +{ + // Raise an exception if the matrix dimensions are not compatible + if (m_rows != m.m_rows || m_cols != m.m_cols) + throw matrix_mismatch("GSparseMatrix::operator+= (const GSparseMatrix&)", + m_rows, m_cols, m.m_rows, m.m_cols); + + // Perform inplace matrix addition + for (int col = 0; col < m_cols; ++col) { + GVector v_result = extract_col(col); + GVector v_operand = m.extract_col(col); + v_result += v_operand; + insert_col(v_result, col); + } + + // Return result + return *this; +} + + +/*************************************************************************** + * GSparseMatrix subtraction (unary addition operator) * + * ----------------------------------------------------------------------- * + * NOT YET IN PURE NATIVE CODE !!!!!! * + ***************************************************************************/ +GSparseMatrix& GSparseMatrix::operator-= (const GSparseMatrix& m) +{ + // Raise an exception if the matrix dimensions are not compatible + if (m_rows != m.m_rows || m_cols != m.m_cols) + throw matrix_mismatch("GSparseMatrix::operator-= (const GSparseMatrix&)", + m_rows, m_cols, m.m_rows, m.m_cols); + + // Perform inplace matrix subtraction + for (int col = 0; col < m_cols; ++col) { + GVector v_result = extract_col(col); + GVector v_operand = m.extract_col(col); + v_result -= v_operand; + insert_col(v_result, col); + } + + // Return result + return *this; +} + + +/*************************************************************************** + * Matrix multiplication (unary multiplication operator) * + * ----------------------------------------------------------------------- * + * NOT YET IN PURE NATIVE CODE !!!!!! * + ***************************************************************************/ +GSparseMatrix& GSparseMatrix::operator*= (const GSparseMatrix& m) +{ + // Raise an exception if the matrix dimensions are not compatible + if (m_cols != m.m_rows || m_rows != m.m_cols) + throw matrix_mismatch("GSparseMatrix::operator*= (const GSparseMatrix&)", + m_rows, m_cols, m.m_rows, m.m_cols); + + // Allocate result matrix + GSparseMatrix result(m_rows, m.m_cols); + + // Multiply only if there are elements in both matrices + if (m_elements > 0 && m.m_elements > 0) { + + // Loop over all elements of result matrix + for (int row = 0; row < m_rows; ++row) { + for (int col = 0; col < m.m_cols; ++col) { + double sum = 0.0; + for (int i = 0; i < m_cols; ++i) + sum += (*this)(row,i) * m(i,col); + result(row,col) = sum; + } + } + + } + + // Assign result + *this = result; + + // Return result + return *this; +} + + +/*========================================================================== + = = + = GSparseMatrix member functions = + = = + ==========================================================================*/ + +/*************************************************************************** + * Get minimum matrix element * + ***************************************************************************/ +double GSparseMatrix::min() const +{ + // Initialise minimum with fill value + double result = m_fill_val; + + // Search all elements for the smallest one + for (int i = 0; i < m_elements; ++i) { + if (m_data[i] < result) + result = m_data[i]; + } + + // If minimum is > 0.0 and there are zero elements then set the minimum + // to 0.0 + if ((result > 0.0) && (m_elements < (m_rows*m_cols))) + result = 0.0; + + // Return result + return result; +} + + +/*************************************************************************** + * Get maximum matrix element * + ***************************************************************************/ +double GSparseMatrix::max() const +{ + // Initialise maximum with fill value + double result = m_fill_val; + + // Search all elements for the largest one + for (int i = 0; i < m_elements; ++i) { + if (m_data[i] > result) + result = m_data[i]; + } + + // If maximum is < 0.0 and there are zero elements then set the maximum + // to 0.0 + if ((result < 0.0) && (m_elements < (m_rows*m_cols))) + result = 0.0; + + // Return result + return result; +} + + +/*************************************************************************** + * Compute sum of non-zero elements * + ***************************************************************************/ +double GSparseMatrix::sum() const +{ + // Initialise matrix sum with fill value + double result = m_fill_val; + + // Add all elements + for (int i = 0; i < m_elements; ++i) + result += m_data[i]; + + // Return result + return result; +} + + +/*************************************************************************** + * Inplace transpose of matrix * + * ----------------------------------------------------------------------- * + * Call cs function * + ***************************************************************************/ +void GSparseMatrix::transpose() +{ + *this = cs_transpose(this, 1); +} + + +/*************************************************************************** + * Extract row from matrix into vector * + ***************************************************************************/ +GVector GSparseMatrix::extract_row(int row) const +{ + // Raise an exception if the row index is invalid + #if defined(G_RANGE_CHECK) + if (row >= m_rows) + throw out_of_range("GSparseMatrix::extract_row(int)", + row, 0, m_rows, m_cols); + #endif + + // Create result vector + GVector result(m_cols); + + // Loop over all columns to extract data + for (int col = 0; col < m_cols; ++col) { + + // Get the start and stop of the elements + int i_start = m_colstart[col]; + int i_stop = m_colstart[col+1]; + + // Search requested row in elements + int i; + for (i = i_start; i < i_stop; ++i) { + if (m_rowinx[i] == row) + break; + } + + // Copy element if we found one + if (i < i_stop) + result(col) = m_data[i]; + + } // endfor: looped over all columns + + // If there is a pending element then put it in the vector + if (m_fill_val != 0.0 && m_fill_row == row) + result(m_fill_col) = m_fill_val; + + // Return vector + return result; + +} + + +/*************************************************************************** + * Extract column from matrix into vector * + ***************************************************************************/ +GVector GSparseMatrix::extract_col(int col) const +{ + // Raise an exception if the column index is invalid + #if defined(G_RANGE_CHECK) + if (col >= m_cols) + throw out_of_range("GSparseMatrix::extract_col(int)", + 0, col, m_rows, m_cols); + #endif + + // Create result vector + GVector result(m_rows); + + // Get the start and stop of the elements + int i_start = m_colstart[col]; + int i_stop = m_colstart[col+1]; + + // Extract elements into vector + for (int i = i_start; i < i_stop; ++i) + result(m_rowinx[i]) = m_data[i]; + + // If there is a pending element then put it in the vector + if (m_fill_val != 0.0 && m_fill_col == col) + result(m_fill_row) = m_fill_val; + + // Return vector + return result; + +} + + +/*************************************************************************** + * Insert vector column into matrix * + ***************************************************************************/ +void GSparseMatrix::insert_col(const GVector& v, int col) +{ + // Debug header + #if defined(G_DEBUG_SPARSE_INSERTION) + cout << "GSparseMatrix::insert_col([" << v << "], " << col << "):" << endl; + cout << " In Data : "; + for (int i = 0; i < m_elements; ++i) + cout << m_data[i] << " "; + cout << endl << " In Row .: "; + for (int i = 0; i < m_elements; ++i) + cout << m_rowinx[i] << " "; + cout << endl << " In Col .: "; + for (int i = 0; i < m_cols+1; ++i) + cout << m_colstart[i] << " "; + cout << endl; + #endif + + // Raise an exception if the column index is invalid + #if defined(G_RANGE_CHECK) + if (col >= m_cols) + throw out_of_range("GSparseMatrix::insert_col(const GVector&, int)", + 0, col, m_rows, m_cols); + #endif + + // Raise an exception if the matrix and vector dimensions are not compatible + if (m_rows != v.m_num) + throw matrix_vector_mismatch("GSparseMatrix::insert_col(const GVector&, int)", + v.m_num, m_rows, m_cols); + + // If there is a pending element for this column then delete it since + // the vector overwrites this element + if (m_fill_val != 0.0 && m_fill_col == col) { + #if defined(G_DEBUG_SPARSE_PENDING) + cout << "GSparseMatrix::insert_col(const GVector, int): pending value " << + m_fill_val << " for location (" << m_fill_row << "," << m_fill_col << + ") became obsolete" << endl; + #endif + m_fill_val = 0.0; + m_fill_row = 0; + m_fill_col = 0; + } + + // Determine the number of non-zero elements in the vector + int n_vector = 0; + for (int row = 0; row < m_rows; ++row) { + if (v(row) != 0.0) + n_vector++; + } + + // Get the start and stop indices of the actual column and compute + // the number of exisiting elements in the column + int i_start = m_colstart[col]; + int i_stop = m_colstart[col+1]; + int n_exist = i_stop - i_start; + + // Compute the size difference for the new matrix. It is positive if + // the number of non-zero entries in the vector is larger than the + // number of non-zero entries in the matrix (in this case we have to + // increase the matrix size). + int n_diff = n_vector - n_exist; + + // If we need space then allocate it, if we have to much space the free it + if (n_diff > 0) { + alloc_elements(i_start, n_diff); + #if defined(G_DEBUG_SPARSE_INSERTION) + cout << " Insert .: " << n_diff << " elements at index " << i_start << endl; + #endif + } + else if (n_diff < 0) { + free_elements(i_start, -n_diff); + #if defined(G_DEBUG_SPARSE_INSERTION) + cout << " Remove .: " << -n_diff << " elements at index " << i_start << endl; + #endif + } + + // Insert the vector elements in the matrix + if (n_vector > 0) { + for (int row = 0, i = i_start; row < m_rows; ++row) { + if (v(row) != 0.0) { + m_data[i] = v(row); + m_rowinx[i] = row; + i++; + } + } + } + + // Update column start indices + for (int i = col+1; i <= m_cols; ++i) + m_colstart[i] += n_diff; + + // Debugging: show sparse matrix after insertion + #if defined(G_DEBUG_SPARSE_INSERTION) + cout << " Out Data: "; + for (int i = 0; i < m_elements; ++i) + cout << m_data[i] << " "; + cout << endl << " Out Row : "; + for (int i = 0; i < m_elements; ++i) + cout << m_rowinx[i] << " "; + cout << endl << " Out Col : "; + for (int i = 0; i < m_cols+1; ++i) + cout << m_colstart[i] << " "; + cout << endl; + #endif + + // Return + return; +} + + +/*************************************************************************** + * Add vector to matrix column * + ***************************************************************************/ +void GSparseMatrix::add_col(const GVector& v, int col) +{ + // Raise an exception if the column index is invalid + #if defined(G_RANGE_CHECK) + if (col >= m_cols) + throw out_of_range("GSparseMatrix::add_col(const GVector&, int)", + 0, col, m_rows, m_cols); + #endif + + // Raise an exception if the matrix and vector dimensions are incompatible + if (m_rows != v.m_num) + throw matrix_vector_mismatch("GSparseMatrix::add_col(const GVector&, int)", + v.m_num, m_rows, m_cols); + + // Extract vector for column, add elements, and re-insert vector + GVector column = extract_col(col); + column += v; + insert_col(column, col); + + // Return + return; +} + + +/*************************************************************************** + * Convert matrix into full matrix * + ***************************************************************************/ +GMatrix GSparseMatrix::convert_to_full() const +{ + // Define result matrix + GMatrix result(m_rows, m_cols); + + // Extract all elements + for (int row = 0; row < m_rows; ++row) { + for (int col = 0; col < m_cols; ++col) + result(row,col) = (*this)(row,col); + } + + // Return result + return result; +} + + +/*************************************************************************** + * GSparseMatrix Cholesky decomposition * + * ----------------------------------------------------------------------- * + * Cholesky decomposition of a sparse matrix. The decomposition is stored * + * within the GSparseMatrix without destroying the original matrix. * +***************************************************************************/ +void GSparseMatrix::cholesky_decompose(int compress) +{ + // Save original matrix size + int matrix_rows = m_rows; + int matrix_cols = m_cols; + + // Delete any existing symbolic analysis object + if (m_symbolic != NULL) delete (GSparseSymbolic*)m_symbolic; + + // Allocate symbolic analysis object + GSparseSymbolic* symbolic = new GSparseSymbolic(); + if (symbolic == NULL) + throw mem_alloc("GSparseMatrix::cholesky_decompose(int)", 1); + + // Declare numeric analysis object. We don't allocate one since we'll + // throw it away at the end of the function (the L matrix will be copied + // in this object) + GSparseNumeric numeric; + + // Fill pending element into matrix + fill_pending(); + + // Remove rows and columns containing only zeros if matrix compression + // has been selected + if (compress) + remove_zero_row_col(); + + // Ordering an symbolic analysis of matrix. This sets up an array 'pinv' + // which contains the fill-in reducing permutations + symbolic->cholesky_symbolic_analysis(1, *this); + + // Perform numeric Cholesky decomposition + numeric.cholesky_numeric_analysis(*this, *symbolic); + + // Insert zero rows and columns if they have been removed previously. + // Since no selection information is present in numeric.m_L we have to + // copy it from this in order to allow for insertion. + if (compress) { + + // If there is a row selection then copy it + if (m_rowsel != NULL && m_num_rowsel > 0) { + numeric.m_L->m_rowsel = new int[m_num_rowsel]; + if (numeric.m_L->m_rowsel == NULL) + throw mem_alloc("GSparseMatrix::cholesky_decompose(int)", m_num_rowsel); + for (int i = 0; i < m_num_rowsel; ++i) + numeric.m_L->m_rowsel[i] = m_rowsel[i]; + numeric.m_L->m_num_rowsel = m_num_rowsel; + } + + // If there is a column selection then copy it + if (m_colsel != NULL && m_num_colsel > 0) { + numeric.m_L->m_colsel = new int[m_num_colsel]; + if (numeric.m_L->m_colsel == NULL) + throw mem_alloc("GSparseMatrix::cholesky_decompose(int)", m_num_colsel); + for (int i = 0; i < m_num_colsel; ++i) + numeric.m_L->m_colsel[i] = m_colsel[i]; + numeric.m_L->m_num_colsel = m_num_colsel; + } + + // Now we can insert zero rows and columns + numeric.m_L->insert_zero_row_col(matrix_rows, matrix_cols); + } + + // Store Cholesky decomposition in matrix + *this = *(numeric.m_L); + + // Store symbolic pointer in sparse matrix object + m_symbolic = (void*)symbolic; + + // Return + return; +} + + +/*************************************************************************** + * GSparseMatrix Cholesky solver * + * ----------------------------------------------------------------------- * + * Solves the linear equation A*x=b using a Cholesky decomposition of A. * + * This function is to be applied on a GSparseMatrix matrix for which a * + * Choleksy factorization has been produced using 'cholesky_decompose'. * + ***************************************************************************/ +GVector GSparseMatrix::cholesky_solver(const GVector& v, int compress) +{ + // Declare loop variables + int row; + int col; + int c_row; + int c_col; + + // Dump header + #if defined(G_DEBUG_SPARSE_COMPRESSION) + cout << "GSparseMatrix::cholesky_solver" << endl; + cout << " Input vector .....: " << v << endl; + #endif + + // Raise an exception if the matrix and vector dimensions are incompatible + if (m_rows != v.m_num) + throw matrix_vector_mismatch( + "GSparseMatrix::cholesky_solver(const GVector&, int)", + v.m_num, m_rows, m_cols); + + // Raise an exception if there is no symbolic pointer + if (!m_symbolic) + throw matrix_not_factorised( + "GSparseMatrix::cholesky_solver(const GVector&, int)", + "Cholesky decomposition"); + + // Get symbolic pointer + GSparseSymbolic* symbolic = (GSparseSymbolic*)m_symbolic; + + // Raise an exception if there is no permutation + if (!symbolic->m_pinv) + throw matrix_not_factorised( + "GSparseMatrix::cholesky_solver(const GVector&, int)", + "Cholesky decomposition"); + + // Flag row and column compression + int row_compressed = (m_rowsel != NULL && m_num_rowsel < m_rows); + int col_compressed = (m_colsel != NULL && m_num_colsel < m_cols); + + // Decide if we need a compression algorithm or not + int no_zero = !(compress && (row_compressed || col_compressed)); + + // Allocate vector for permutation and result vector + GVector result(m_cols); + + // Setup pointers to L matrix and x vector + int* Lp = m_colstart; + int* Li = m_rowinx; + double* Lx = m_data; + + // Case A: no zero-row/col compression needed + if (no_zero) { + + // Declare working vector + GVector x(m_rows); + + // Perform inverse vector permutation + for (int i = 0; i < v.m_num; ++i) + x.m_data[symbolic->m_pinv[i]] = v.m_data[i]; + + // Inplace solve L\x=x + for (col = 0; col < m_cols; ++col) { // loop over columns + x.m_data[col] /= Lx[Lp[col]]; // divide by diag. + for (int p = Lp[col]+1; p < Lp[col+1]; p++) // loop over elements + x.m_data[Li[p]] -= Lx[p] * x.m_data[col]; + } + + // Inplace solve L'\x=x + for (col = m_cols-1; col >= 0; --col) { // loop over columns + for (int p = Lp[col]+1; p < Lp[col+1]; p++) // loop over elements + x.m_data[col] -= Lx[p] * x.m_data[Li[p]]; + x.m_data[col] /= Lx[Lp[col]]; + } + + // Perform vector permutation + for (int i = 0; i < m_cols; ++i) + result.m_data[i] = x.m_data[symbolic->m_pinv[i]]; + + } // endif: Case A + + // Case B: zero-row/column compression requested + else { + + // Allocate row and column mapping arrays + int* row_map = new int[m_rows]; + if (row_map == NULL) + throw mem_alloc("GSparseMatrix::cholesky_solver(const GVector&, int)", m_rows); + int* col_map = new int[m_cols]; + if (col_map == NULL) + throw mem_alloc("GSparseMatrix::cholesky_solver(const GVector&, int)", m_cols); + + // Setup row mapping array that maps original matrix rows into compressed + // matrix rows. An entry of -1 indicates that the row should be dropped. + // If no selection exists then setup an identity map. + if (row_compressed) { + for (row = 0; row < m_rows; ++row) + row_map[row] = -1; + for (c_row = 0; c_row < m_num_rowsel; ++c_row) + row_map[m_rowsel[c_row]] = c_row; + } + else { + for (row = 0; row < m_rows; ++row) + row_map[row] = row; + } + #if defined(G_DEBUG_SPARSE_COMPRESSION) + cout << " Row mapping ......:"; + for (row = 0; row < m_rows; ++row) + cout << " " << row_map[row]; + cout << endl; + #endif + + // Setup column mapping array that maps original matrix column into compressed + // matrix columns. An entry of -1 indicates that the column should be dropped + // If no selection exists then setup an identity map. + if (col_compressed) { + for (col = 0; col < m_cols; ++col) + col_map[col] = -1; + for (c_col = 0; c_col < m_num_colsel; ++c_col) + col_map[m_colsel[c_col]] = c_col; + } + else { + for (col = 0; col < m_cols; ++col) + col_map[col] = col; + } + #if defined(G_DEBUG_SPARSE_COMPRESSION) + cout << " Column mapping ...:"; + for (col = 0; col < m_cols; ++col) + cout << " " << col_map[col]; + cout << endl; + #endif + + // Declare working vector + GVector x(row_compressed ? m_num_rowsel : m_rows); + + // Compress input vector v -> c_v if required + if (m_rowsel != NULL && m_num_rowsel < m_rows) { + for (c_row = 0; c_row < m_num_rowsel; ++c_row) + x.m_data[c_row] = v.m_data[m_rowsel[c_row]]; + } + else + x = v; + #if defined(G_DEBUG_SPARSE_COMPRESSION) + cout << " Compressed vector : " << x << endl; + #endif + + // Perform inverse permutation + x = iperm(x, symbolic->m_pinv); + #if defined(G_DEBUG_SPARSE_COMPRESSION) + cout << " Permutated vector : " << x << endl; + #endif + + // Inplace solve L\x=x. The column and row maps are just use to see which + // columns or rows should be skipped in the calculations. + for (col = 0; col < m_cols; ++col) { // loop over columns + if ((c_col = col_map[col]) >= 0) { // use only non-zero cols + x.m_data[c_col] /= Lx[Lp[col]]; // divide by diag. + for (int p = Lp[col]+1; p < Lp[col+1]; p++) { // loop over elements + if ((c_row = row_map[Li[p]]) >= 0) // use only non-zero rows + x.m_data[c_row] -= Lx[p] * x.m_data[c_col]; + } + } + } + #if defined(G_DEBUG_SPARSE_COMPRESSION) + cout << " Solve Lx=x .......: " << x << endl; + #endif + + // Inplace solve L'\x=x. The column and row maps are just use to see which + // columns or rows should be skipped in the calculations. + for (col = m_cols-1; col >= 0; --col) { // loop over columns + if ((c_col = col_map[col]) >= 0) { // use only non-zero cols + for (int p = Lp[col]+1; p < Lp[col+1]; p++) { // loop over elements + if ((c_row = row_map[Li[p]]) >= 0) // use only non-zero rows + x.m_data[c_col] -= Lx[p] * x.m_data[c_row]; + } + x.m_data[c_col] /= Lx[Lp[col]]; + } + } + #if defined(G_DEBUG_SPARSE_COMPRESSION) + cout << " Solve L'x=x ......: " << x << endl; + #endif + + // Perform vector permutation + x = perm(x, symbolic->m_pinv); + #if defined(G_DEBUG_SPARSE_COMPRESSION) + cout << " Permutated vector : " << x << endl; + #endif + + // If column compression has been performed the expand the result vector + // accordingly + if (m_colsel != NULL && m_num_colsel < m_cols) { + for (c_col = 0; c_col < m_num_colsel; ++c_col) + result.m_data[m_colsel[c_col]] = x.m_data[c_col]; + } + else + result = x; + #if defined(G_DEBUG_SPARSE_COMPRESSION) + cout << " Restored vector ..: " << result << endl; + #endif + + // Free mapping arrays + delete [] row_map; + delete [] col_map; + + } // endelse: Case B + + // Return result vector + return result; +} + + +/*************************************************************************** + * GSparseMatrix Cholesky invert * + * ----------------------------------------------------------------------- * + * Inplace matrix inversion using the Cholesky decomposition. * + ***************************************************************************/ +void GSparseMatrix::cholesky_invert(int compress) +{ + // Generate Cholesky decomposition of matrix + cholesky_decompose(compress); + + // Allocate result matrix and unit vector + GSparseMatrix result(m_rows, m_cols); + GVector unit(m_rows); + + // Column-wise solving of the problem + for (int col = 0; col < m_cols; ++col) { + + // Set unit vector + unit.m_data[col] = 1.0; + + // Solve for column + GVector x = cholesky_solver(unit, compress); + + // Insert column in matrix + result.insert_col(x, col); + + // Clear unit vector for next round + unit.m_data[col] = 0.0; + + } + + *this = result; + + // Return + return; +} + + +/*========================================================================== + = = + = GSparseMatrix private functions = + = = + ==========================================================================*/ + +/*************************************************************************** + * Determines element index for (row,col) * + * ----------------------------------------------------------------------- * + * Returns the index in the compressed array for (row,col). The following * + * special results exist: * + * -1: Requested index does not exist in the matrix * + * m_elements: Requested index is the pending element * + ***************************************************************************/ +int GSparseMatrix::get_index(int row, int col) const +{ + // Initialise element to 'not found' + int index = -1; + + // If we have a pending element then check if this element is requested + if (m_fill_val != 0.0) { + if (row == m_fill_row && col == m_fill_col) + return m_elements; + } + + // If requested element is not the pending element then check if it exists + // in the matrix. Only if it is found its index is returned. Otherwise + // the default index is -1, signalling that the element is absent. + if (m_elements > 0) { + int* ptr_colstart = m_colstart + col; + int i_start = *ptr_colstart++; + int i_stop = *ptr_colstart; + int* ptr_rowinx = m_rowinx + i_start; + for (int i = i_start; i < i_stop; ++i) { + int row_test = *ptr_rowinx++; + if (row_test == row) { + index = i; + break; + } + } + } + + // Return index + return index; +} + + +/*************************************************************************** + * Fills pending matrix element * + * ----------------------------------------------------------------------- * + * If 'm_fill_val' is non-zero a pending matrix element exists that should * + * be filled into (row,col)=(m_fill_row,m_fill_col). This routine performs * + * the filling of the matrix with this element and resets 'm_fill_val' to * + * zero. This routine allows for element-by-element filling of a sparse * + * matrix. This is, of course, very time consuming and should in general * + * be avoided. However, it allows to design a sparse matrix class that * + * hides the matrix sparsity completely to the user. * + ***************************************************************************/ +void GSparseMatrix::fill_pending(void) +{ + // If we have a pending element then fill it into the matrix + if (m_fill_val != 0.0) { + + // Debugging + #if defined(G_DEBUG_SPARSE_PENDING) || defined(G_DEBUG_SPARSE_INSERTION) + cout << "GSparseMatrix::fill_pending(): pending value " << + m_fill_val << " will be filled in location (" << + m_fill_row << "," << m_fill_col << ")" << endl; + #endif + + // If there are so far no elements in the matrix then append element ... + int inx_insert; + if (m_elements == 0) + inx_insert = 0; + + // ... otherwise search for index to insert + else { + int* ptr_colstart = m_colstart + m_fill_col; + int i_start = *ptr_colstart++; + int i_stop = *ptr_colstart; + int* ptr_rowinx = m_rowinx + i_start; + for (inx_insert = i_start; inx_insert < i_stop; ++inx_insert) { + int row_test = *ptr_rowinx++; + if (row_test > m_fill_row) { + break; + } + } + } + + // Allocate memory for new element + alloc_elements(inx_insert, 1); + + // Insert element + m_data[inx_insert] = m_fill_val; + m_rowinx[inx_insert] = m_fill_row; + + // Update column start indices + for (int col = m_fill_col+1; col <= m_cols; ++col) + m_colstart[col] += 1; + + // Reset fill value + m_fill_val = 0.0; + m_fill_row = 0; + m_fill_col = 0; + + // Debugging: show sparse matrix after filling + #if defined(G_DEBUG_SPARSE_PENDING) || defined(G_DEBUG_SPARSE_INSERTION) + cout << " Data: "; + for (int i = 0; i < m_elements; ++i) + cout << m_data[i] << " "; + cout << endl << " Row.: "; + for (int i = 0; i < m_elements; ++i) + cout << m_rowinx[i] << " "; + cout << endl << " Col.: "; + for (int i = 0; i < m_cols+1; ++i) + cout << m_colstart[i] << " "; + cout << endl; + #endif + + } // endif: a pending matrix element was found + +} + + +/*************************************************************************** + * Allocate memory for new matrix elements * + * ----------------------------------------------------------------------- * + * Inserts a memory allocation for 'num' elements at the index 'start'. * + * The new elements are filled with 0.0 and the corresponding row indices * + * are set to 0. * + * NOTE: This routine does not take care of updating 'm_colstart'. This * + * has to be done by the client. * + ***************************************************************************/ +void GSparseMatrix::alloc_elements(int start, int num) +{ + // Continue only if we need memory + if (num > 0) { + + // If start is after the end the append memory + if (start > m_elements) + start = m_elements; + + // Allocate memory for new elements + double* new_data = new double[m_elements+num]; + int* new_rowinx = new int[m_elements+num]; + if (new_data == NULL || new_rowinx == NULL) + throw mem_alloc("GSparseMatrix::alloc_elements(int, int)", + m_elements+num); + + // Copy all elements before index to insert + for (int i = 0; i < start; ++i) { + new_data[i] = m_data[i]; + new_rowinx[i] = m_rowinx[i]; + } + + // Clear new elements (zero content for row 0) + for (int i = start; i < start+num; ++i) { + new_data[i] = 0.0; + new_rowinx[i] = 0; + } + + // Copy all elements after index to insert + for (int i = start; i < m_elements; ++i) { + new_data[i+num] = m_data[i]; + new_rowinx[i+num] = m_rowinx[i]; + } + + // Delete old memory + if (m_data != NULL) delete [] m_data; + if (m_rowinx != NULL) delete [] m_rowinx; + + // Update pointers to new memory and update element counter + m_data = new_data; + m_rowinx = new_rowinx; + m_elements += num; + + } // endif: needed new memory + +} + + +/*************************************************************************** + * Free memory for obsolete matrix elements * + * ----------------------------------------------------------------------- * + * Free memory for 'num' elements starting from index 'start'. * + * NOTE: This routine does not take care of updating 'm_colstart'. This * + * has to be done by the client. * + ***************************************************************************/ +void GSparseMatrix::free_elements(int start, int num) +{ + // Continue only if we need to free memory and if start is within the + // range + if (num > 0 && start < m_elements) { + + // Determine the new size of the matrix. If there are no elements then + // simply delete all matrix elements ... + int new_size = m_elements - num; + if (new_size < 1) { + if (m_data != NULL) delete [] m_data; + if (m_rowinx != NULL) delete [] m_rowinx; + m_data = NULL; + m_rowinx = NULL; + m_elements = 0; + } + + // ... otherwise shrink the array + else { + + // Allocate new memory + double* new_data = new double[new_size]; + int* new_rowinx = new int[new_size]; + if (new_data == NULL || new_rowinx == NULL) + throw mem_alloc("GSparseMatrix::free_elements(int, int)", + new_size); + + // Copy all elements before the starting index + for (int i = 0; i < start; ++i) { + new_data[i] = m_data[i]; + new_rowinx[i] = m_rowinx[i]; + } + + // Copy all elements after the starting index + for (int i = start; i < new_size; ++i) { + new_data[i] = m_data[i+num]; + new_rowinx[i] = m_rowinx[i+num]; + } + + // Delete old memory + if (m_data != NULL) delete [] m_data; + if (m_rowinx != NULL) delete [] m_rowinx; + + // Update pointers to new memory and update element counter + m_data = new_data; + m_rowinx = new_rowinx; + m_elements = new_size; + + } // endif: array shrinkage needed + } // endif: needed new memory + +} + + +/*************************************************************************** + * remove_zero_row_col * + * ----------------------------------------------------------------------- * + * Remove all rows and columns that contain only zeros from matrix. This * + * function is needed for compressed matrix factorisation. The resulting * + * matrix has reduced size (# of rows and columns) and dimensions (# of * + * elements). Note that the physical memory is not reduced by the routine. * + ***************************************************************************/ +void GSparseMatrix::remove_zero_row_col(void) +{ + // Dump header + #if defined(G_DEBUG_SPARSE_COMPRESSION) + cout << "GSparseMatrix::remove_zero_row_col" << endl; + #endif + + // Fill pending value in matrix + fill_pending(); + + // Select non-zero rows and columns of matrix + select_non_zero(); + + // Stop if there is no compression + if (m_rows == m_num_rowsel && m_cols == m_num_colsel) + return; + + // Raise exception if all matrix elements are zero + if (m_num_rowsel < 1 || m_num_colsel < 1) + throw matrix_zero("GSparseMatrix::remove_zero_row_col()"); + + // Allocate row mapping array + int* row_map = new int[m_rows]; + if (row_map == NULL) + throw mem_alloc("GSparseMatrix::remove_zero_row_col()", m_rows); + + // Setup row mapping array that maps original matrix rows into compressed + // matrix rows. An entry of -1 indicates that the row should be dropped + for (int row = 0; row < m_rows; ++row) + row_map[row] = -1; + for (int c_row = 0; c_row < m_num_rowsel; ++c_row) + row_map[m_rowsel[c_row]] = c_row; + + // Initialise pointers to compressed array + double* d_data = m_data; + int* d_rowinx = m_rowinx; + + // Initialise column start of first column to zero + m_colstart[0] = 0; + + // Dump column start array + #if defined(G_DEBUG_SPARSE_COMPRESSION) + cout << " before compression:"; + for (int col = 0; col <= m_cols; ++col) + cout << " " << m_colstart[col]; + cout << endl; + #endif + + // Loop over all columns of compressed matrix + for (int c_col = 0; c_col < m_num_colsel; ++c_col) { + + // Get index range for elements in original matrix + int i_start = m_colstart[m_colsel[c_col]]; + int i_stop = m_colstart[m_colsel[c_col]+1]; + + // Initialise number of element counter for the compressed column + int num = 0; + + // Loop over all elements in original column + int c_row; + for (int i = i_start; i < i_stop; ++i) { + if ((c_row = row_map[m_rowinx[i]]) >= 0) { + *d_data++ = m_data[i]; + *d_rowinx++ = c_row; + num++; + } + } + + // Update column stop + m_colstart[c_col+1] = m_colstart[c_col] + num; + + } // endfor: looped over all columns of compressed matrix + + // Dump column start array + #if defined(G_DEBUG_SPARSE_COMPRESSION) + cout << " after compression :"; + for (int c_col = 0; c_col <= m_num_colsel; ++c_col) + cout << " " << m_colstart[c_col]; + cout << endl; + #endif + + // Free row mapping array + delete [] row_map; + + // Update matrix attributes + m_rows = m_num_rowsel; + m_cols = m_num_colsel; + m_elements = m_colstart[m_num_colsel]; + + // Return + return; +} + + +/*************************************************************************** + * insert_zero_row_col * + * ----------------------------------------------------------------------- * + * Insert zero rows and columns into matrix. Since for a sparse matrix * + * this does not require any allocation of additional memory, the data are * + * not moved by this function, but the pointers are re-arranged. * + ***************************************************************************/ +void GSparseMatrix::insert_zero_row_col(int rows, int cols) +{ + // Dump header + #if defined(G_DEBUG_SPARSE_COMPRESSION) + cout << "GSparseMatrix::insert_zero_row_col(" << rows << "," << cols << + ")" << endl; + #endif + + // Fill pending value in matrix + fill_pending(); + + // Stop if there is no insertion + if (m_rows == rows && m_cols == cols) + return; + + // If row selection exists then restore row indices + if (m_rowsel != NULL) { + for (int i = 0; i < m_elements; ++i) + m_rowinx[i] = m_rowsel[m_rowinx[i]]; + } + + // Dump column start array + #if defined(G_DEBUG_SPARSE_COMPRESSION) + cout << " before restoration:"; + for (int c_col = 0; c_col <= m_num_colsel; ++c_col) + cout << " " << m_colstart[c_col]; + cout << endl; + #endif + + // If column selection exists then restore column counters + if (m_colsel != NULL) { + int col_stop = cols - 1; + for (int c_col = m_num_colsel-1; c_col > 0; --c_col) { + int col_start = m_colsel[c_col-1] + 1; + int col_value = m_colstart[c_col]; + for (int col = col_start; col <= col_stop; ++col) + m_colstart[col] = col_value; + col_stop = col_start - 1; + } + m_colstart[cols] = m_elements; + } + + // Dump column start array + #if defined(G_DEBUG_SPARSE_COMPRESSION) + cout << " after restoration :"; + for (int col = 0; col <= cols; ++col) + cout << " " << m_colstart[col]; + cout << endl; + #endif + + // Update matrix attributes + m_rows = rows; + m_cols = cols; + + // Return + return; +} + + +/*************************************************************************** + * cs_transpose * + * ----------------------------------------------------------------------- * + * Transpose matrix. The flag 'values' allows to avoid copying the actual * + * data values. This allows to perform a logical matrix transposition, as * + * needed by the symbolic matrix analysis class. * + ***************************************************************************/ +GSparseMatrix GSparseMatrix::cs_transpose(GSparseMatrix* m, int values) +{ + // Fill pending value in input matrix + m->fill_pending(); + + // Declare and allocate result matrix + GSparseMatrix result(m->m_cols, m->m_rows, m->m_elements); + + // Allocate and initialise workspace + int wrk_size = m->m_rows; + int* wrk_int = new int[wrk_size]; + if (wrk_int == NULL) + throw mem_alloc("GSparseMatrix::cs_transpose(GSparseMatrix*, int)", + wrk_size); + for (int i = 0; i < wrk_size; i++) + wrk_int[i] = 0; + + // Setup the number of non-zero elements in each row + for (int p = 0; p < m->m_elements; p++) + wrk_int[m->m_rowinx[p]]++; + + // Set row pointers. To use a GSparseSymbolic function we have to + // allocate and object (but this does not take memory) + cs_cumsum(result.m_colstart, wrk_int, m->m_rows); + + // Case A: Normal transponse, including assignment of values + if (values) { + for (int col = 0; col < m->m_cols; col++) { + for (int p = m->m_colstart[col] ; p < m->m_colstart[col+1] ; p++) { + int i = wrk_int[m->m_rowinx[p]]++; + result.m_rowinx[i] = col; + result.m_data[i] = m->m_data[p] ; + } + } + } + + // Case B: Logical transponse, no assignment of values is performed + else { + for (int col = 0; col < m->m_cols; col++) { + for (int p = m->m_colstart[col] ; p < m->m_colstart[col+1] ; p++) + result.m_rowinx[wrk_int[m->m_rowinx[p]]++] = col; + } + } + + // Return transponse matrix + return result; + +} + + +/*========================================================================== + = = + = GSparseMatrix friends = + = = + ==========================================================================*/ + +/*************************************************************************** + * Output operator * + ***************************************************************************/ +ostream& operator<< (ostream& os, const GSparseMatrix& m) +{ + // Put header in stream + os << "=== GSparseMatrix ===" << endl; + if (m.m_rowsel != NULL) + os << " Number of rows ............: " << m.m_rows << " (compressed " << + m.m_num_rowsel << ")" << endl; + else + os << " Number of rows ............: " << m.m_rows << endl; + if (m.m_colsel != NULL) + os << " Number of columns .........: " << m.m_cols << " (compressed " << + m.m_num_colsel << ")" << endl; + else + os << " Number of columns .........: " << m.m_cols << endl; + os << " Number of non-zero elements: " << m.m_elements << endl; + os << " Sparse matrix fill ........: " << m.fill() << endl; + + // Loop over all matrix elements and put them into the stream + for (int row = 0; row < m.m_rows; ++row) { + os << " "; + for (int col = 0; col < m.m_cols; ++col) { + os << m(row,col); + if (col != m.m_cols-1) + os << ", "; + } + if (row != m.m_rows-1) + os << endl; + } + + // If there is a row compression the show scheme + if (m.m_rowsel != NULL) { + os << endl << " Row selection ..:"; + for (int row = 0; row < m.m_num_rowsel; ++row) + os << " " << m.m_rowsel[row]; + } + + // If there is a column compression the show scheme + if (m.m_colsel != NULL) { + os << endl << " Column selection:"; + for (int col = 0; col < m.m_num_colsel; ++col) + os << " " << m.m_colsel[col]; + } + + // If there is a symbolic decomposition then put it also in the stream + if (m.m_symbolic != NULL) { + os << endl << *((GSparseSymbolic*)m.m_symbolic); + } + + // If there is a numeric decomposition then put it also in the stream + if (m.m_numeric != NULL) { + os << endl << *((GSparseNumeric*)m.m_numeric); + } + + // Return output stream + return os; +} + + +/*************************************************************************** + * Matrix absolute values * + ***************************************************************************/ +GSparseMatrix fabs(const GSparseMatrix& m) +{ + // Define result matrix + GSparseMatrix result = m; + + // Fill pending element + result.fill_pending(); + + // Convert all elements to absolute values + for (int i = 0; i < result.m_elements; ++i) + result.m_data[i] = fabs(result.m_data[i]); + + // Return result + return result; +} + + +/*========================================================================== + = = + = GSparseMatrix exception classes = + = = + ==========================================================================*/ + + +/*========================================================================== + = = + = Other functions used by GSparseMatrix = + = = + ==========================================================================*/ + +/*************************************************************************** + * cs_cumsum * + * ----------------------------------------------------------------------- * + * Evaluate p[0..n] = cumulative sum of c[0..n-1] * + * ----------------------------------------------------------------------- * + * Input: c[0..n-1] integer array of n elements * + * Output: nz2 cumulative sum of c[0..n-1] * + * p[0..n] integer array of n+1 elements * + * c[0..n-1] holds p[0..n-1] on output * + ***************************************************************************/ +double cs_cumsum(int* p, int* c, int n) +{ + // Signal error if one of the input pointers is NULL + if (!p || !c) return (-1); + + // Initialise sums (integer and double) + int nz = 0; + double nz2 = 0.0; + + // Evaluate p[0..n] = cumulative sum of c[0..n-1] + for (int i = 0; i < n; ++i) { + p[i] = nz ; + nz += c[i]; + nz2 += c[i]; // also in double to avoid int overflow + c[i] = p[i]; // also copy p[0..n-1] back into c[0..n-1] + } + p[n] = nz ; + + // Return cumulative sum of c[0..n-1] + return nz2; +} + diff --git a/src/GSparseMatrix.hpp b/src/GSparseMatrix.hpp index 82baece..51ddf50 100644 --- a/src/GSparseMatrix.hpp +++ b/src/GSparseMatrix.hpp @@ -1,5 +1,5 @@ /*************************************************************************** - * GSymMatrix.hpp - symmetric matrix class * + * GSparseMatrix.hpp - sparse matrix class * * ----------------------------------------------------------------------- * * copyright : (C) 2006 by Jurgen Knodlseder * * ----------------------------------------------------------------------- * @@ -11,8 +11,8 @@ * * ***************************************************************************/ -#ifndef GSYMMATRIX_HPP -#define GSYMMATRIX_HPP +#ifndef GSPARSEMATRIX_HPP +#define GSPARSEMATRIX_HPP /* __ Includes ___________________________________________________________ */ #include "GException.hpp" @@ -27,251 +27,248 @@ using namespace std; /* __ Structures _________________________________________________________ */ /* __ Prototypes _________________________________________________________ */ +double cs_cumsum(int* p, int* c, int n); /*************************************************************************** - * GSymMatrix class definition * + * GSparseMatrix class definition * ***************************************************************************/ -class GSymMatrix : public GMatrix { - // Operator friends - friend GSymMatrix operator* (const double &a, const GSymMatrix &b); +class GSparseMatrix : public GMatrix { + // Friend classes + friend class GSparseSymbolic; + friend class GSparseNumeric; + + // Binary operator friends + friend GSparseMatrix operator* (const double& a, const GSparseMatrix& b); + friend GSparseMatrix operator* (const GSparseMatrix& a, const double& b); + friend GSparseMatrix operator/ (const GSparseMatrix& a, const double& b); // I/O friends - // ... - + friend ostream& operator<< (ostream& os, const GSparseMatrix& m); + // Friend functions - friend GSymMatrix transpose(const GSymMatrix &m); - friend GSymMatrix cholesky_decompose(const GSymMatrix &m); - friend GMatrix full(const GSymMatrix &m); - friend GMatrix lower_triangle(const GSymMatrix &m); - friend GMatrix upper_triangle(const GSymMatrix &m); + friend GSparseMatrix transpose(const GSparseMatrix& m); + friend GSparseMatrix fabs(const GSparseMatrix& m); + friend GSparseMatrix cholesky_decompose(const GSparseMatrix& m, int compress = 1); + friend GSparseMatrix cholesky_invert(const GSparseMatrix& m, int compress = 1); + public: // Constructors and destructors (not inherited) - GSymMatrix(unsigned rows, unsigned cols); - ~GSymMatrix() { } + GSparseMatrix(int rows, int cols, int elements = 0); + GSparseMatrix(const GSparseMatrix& m); + virtual ~GSparseMatrix(); // Matrix element access operators - double& operator() (unsigned row, unsigned col); - const double& operator() (unsigned row, unsigned col) const; + virtual double& operator() (int row, int col); + virtual const double& operator() (int row, int col) const; // Matrix assignment operators (not inherited) - GSymMatrix& operator= (const GSymMatrix& m); - GSymMatrix& operator= (const double& d); - - // Specific matrix operators (structure dependent) - GSymMatrix operator+ (const GSymMatrix& m) const; - GSymMatrix operator- (const GSymMatrix& m) const; - GSymMatrix operator* (const GSymMatrix& m) const; - GVector operator* (const GVector& v) const; - GSymMatrix operator* (const double& d) const; - GSymMatrix operator/ (const double& d) const; - GSymMatrix operator- () const; - - // Specific matrix functions - void transpose(); // Inplace transpose of matrix - void cholesky_decompose(); // Inplace Cholesky decomposition - - // Exception: Matrix not symmetric - class not_sym : public GException { - public: - not_sym(string origin, unsigned cols, unsigned rows); - }; - - // Exception: Matrix not positive definite - class not_pos_definite : public GException { - public: - not_pos_definite(string origin, unsigned row, double sum); - }; + virtual GSparseMatrix& operator= (const GSparseMatrix& m); + + // Binary operators + virtual GSparseMatrix operator+ (const GSparseMatrix& m) const; + virtual GSparseMatrix operator- (const GSparseMatrix& m) const; + virtual GSparseMatrix operator* (const GSparseMatrix& m) const; + virtual GVector operator* (const GVector& v) const; + virtual int operator== (const GSparseMatrix& m) const; + virtual int operator!= (const GSparseMatrix& m) const; + + // Unary operators + GSparseMatrix operator- () const; + virtual GSparseMatrix& operator+= (const GSparseMatrix& m); + virtual GSparseMatrix& operator-= (const GSparseMatrix& m); + virtual GSparseMatrix& operator*= (const GSparseMatrix& m); + virtual GSparseMatrix& operator*= (const double& d); + virtual GSparseMatrix& operator/= (const double& d); + + // Matrix functions + // USE_BASE: virtual int rows() const { return m_rows; } + // USE_BASE: virtual int cols() const { return m_cols; } + virtual double fill() const { return (double(m_elements)/double(m_rows*m_cols)); } + virtual double min() const; + virtual double max() const; + virtual double sum() const; + virtual void transpose(); + virtual GVector extract_row(int row) const; + virtual GVector extract_col(int col) const; + virtual void insert_col(const GVector& v, int col); + virtual void add_col(const GVector& v, int col); + virtual GMatrix convert_to_full() const; + //TBD virtual GMatrix extract_lower_triangle() const; + //TBD virtual GMatrix extract_upper_triangle() const; + virtual void cholesky_decompose(int compress = 1); + virtual GVector cholesky_solver(const GVector& v, int compress = 1); + virtual void cholesky_invert(int compress = 1); + private: + // Private functions + int get_index(int row, int col) const; + void fill_pending(void); + void alloc_elements(int start, int num); + void free_elements(int start, int num); + void remove_zero_row_col(void); + void insert_zero_row_col(int rows, int cols); + GSparseMatrix cs_transpose(GSparseMatrix *m, int values); + + // Private data members + int* m_rowinx; // Row-indices of all elements + double m_zero; // The zero element (needed for data access) + double m_fill_val; // Element to be filled + int m_fill_row; // Row into which element needs to be filled + int m_fill_col; // Column into which element needs to be filled + void* m_symbolic; // Holds GSparseSymbolic object after decomposition + void* m_numeric; // Holds GSparseNumeric object after decomposition }; /*************************************************************************** * Inline members that override base class members * ***************************************************************************/ -// Matrix assignment operator: GSymMatrix = GSymMatrix -inline -GSymMatrix& GSymMatrix::operator= (const GSymMatrix& m) -{ - if (this != &m) - this->GMatrix::operator=(m); -} - -// Scalar assignment operator: GSymMatrix = double +// Matrix element access operator inline -GSymMatrix& GSymMatrix::operator= (const double& d) -{ - this->GMatrix::operator=(d); -} - -// Matrix element access operator: GSymMatrix(row,col) -inline -double& GSymMatrix::operator() (unsigned row, unsigned col) +double& GSparseMatrix::operator() (int row, int col) { - #if G_RANGE_CHECK + #if defined(G_RANGE_CHECK) if (row >= m_rows || col >= m_cols) - throw out_of_range("GSymMatrix access", row, col, m_rows, m_cols); + throw out_of_range("GSparseMatrix access", row, col, m_rows, m_cols); #endif - unsigned inx = (row >= col) ? m_colstart[col]+(row-col) : m_colstart[row]+(col-row); - return m_data[inx]; + fill_pending(); + int inx = get_index(row,col); + double* value; + if (inx < 0) { + value = &m_fill_val; + m_fill_row = row; + m_fill_col = col; + } + else + value = &(m_data[inx]); + return *value; } -// Matrix element access operator (const version): GSymMatrix(row,col) +// Matrix element access operator (const version) +// We need here the zero element to return also a pointer for 0.0 entry that is +// not stored. Since we have the const version we don't have to care about +// modification of this zero value. inline -const double& GSymMatrix::operator() (unsigned row, unsigned col) const +const double& GSparseMatrix::operator() (int row, int col) const { - #if G_RANGE_CHECK + #if defined(G_RANGE_CHECK) if (row >= m_rows || col >= m_cols) - throw out_of_range("GSymMatrix access", row, col, m_rows, m_cols); + throw out_of_range("GSparseMatrix access", row, col, m_rows, m_cols); #endif - unsigned inx = (row >= col) ? m_colstart[col]+(row-col) : m_colstart[row]+(col-row); - return m_data[inx]; + int inx = get_index(row,col); + double* value; + if (inx < 0) + value = (double*)&m_zero; + else if (inx == m_elements) + value = (double*)&m_fill_val; + else + value = (double*)&(m_data[inx]); + return *value; } -// Matrix addition: GSymMatrix + GSymMatrix +// Binary matrix addition inline -GSymMatrix GSymMatrix::operator+ (const GSymMatrix& m) const +GSparseMatrix GSparseMatrix::operator+ (const GSparseMatrix& m) const { - GSymMatrix result = *this; + GSparseMatrix result = *this; result += m; return result; } -// Matrix subtraction: GSymMatrix - GSymMatrix +// Binary matrix subtraction inline -GSymMatrix GSymMatrix::operator- (const GSymMatrix& m) const +GSparseMatrix GSparseMatrix::operator- (const GSparseMatrix& m) const { - GSymMatrix result = *this; + GSparseMatrix result = *this; result -= m; return result; } -// Matrix multiplication: GSymMatrix * GSymMatrix -inline -GSymMatrix GSymMatrix::operator* (const GSymMatrix& m) const -{ - #if G_RANGE_CHECK - if (m_cols != m.m_rows) - throw GMatrix::dim_mult_mismatch("GSymMatrix multiplication", m_cols, m.m_rows); - #endif - GSymMatrix result(m_rows,m.m_cols); - for (unsigned row = 0; row < m_rows; ++row) { - for (unsigned col = 0; col < m.m_cols; ++col) { - double sum = 0.0; - for (unsigned i = 0; i < m_cols; ++i) - sum += (*this)(row,i)*m(i,col); - result(row,col) = sum; - } - } - return result; -} - -// Matrix/Vector multiplication: GSymMatrix * GVector +// Binary matrix multiplication inline -GVector GSymMatrix::operator* (const GVector& v) const -{ - return (this->GMatrix::operator*(v)); -} - -// Matrix scaling: GSymMatrix * double -inline -GSymMatrix GSymMatrix::operator* (const double &d) const -{ - GSymMatrix result = (*this); - result *= d; - return result; -} - -// Matrix inverse scaling: GSymMatrix * double -inline -GSymMatrix GSymMatrix::operator/ (const double &d) const +GSparseMatrix GSparseMatrix::operator* (const GSparseMatrix& m) const { - GSymMatrix result = (*this); - result /= d; + GSparseMatrix result = *this; + result *= m; return result; } -// Unary minus operator +// Unary scalar multiplication inline -GSymMatrix GSymMatrix::operator- ( ) const +GSparseMatrix& GSparseMatrix::operator*= (const double& d) { - GSymMatrix result = *this; - for (unsigned i = 0; i < m_elements; ++i) - result.m_data[i] = -result.m_data[i]; - return result; + fill_pending(); + this->GMatrix::operator*=(d); } -// Matrix transpose +// Unary scalar division inline -void GSymMatrix::transpose() +GSparseMatrix& GSparseMatrix::operator/= (const double& d) { - return; + fill_pending(); + this->GMatrix::operator/=(d); } - /*************************************************************************** * Inline friends * ***************************************************************************/ -// Matrix scaling: double * GSymMatrix +// Binary matrix scaling (matrix is left operand) inline -GSymMatrix operator* (const double& a, const GSymMatrix& b) +GSparseMatrix operator* (const GSparseMatrix& a, const double& b) { - GSymMatrix result = b; - result *= a; + GSparseMatrix result = a; + result.fill_pending(); + result *= b; return result; } -// Matrix transpose: transpose(GSymMatrix) +// Binary matrix scaling (matrix is right operand) inline -GSymMatrix transpose(const GSymMatrix &m) +GSparseMatrix operator* (const double& a, const GSparseMatrix& b) { - return m; + GSparseMatrix result = b; + result.fill_pending(); + result *= a; + return result; } -// Cholesky decomposition: cholesky_decompose(GSymMatrix) +// Binary matrix division (matrix is left operand) inline -GSymMatrix cholesky_decompose(const GSymMatrix &m) +GSparseMatrix operator/ (const GSparseMatrix& a, const double& b) { - GSymMatrix result = m; - result.cholesky_decompose(); + GSparseMatrix result = a; + result.fill_pending(); + result /= b; return result; } -// Convert symmetric matrix into full matrix: full(GSymMatrix) +// Matrix transpose function inline -GMatrix full(const GSymMatrix& m) +GSparseMatrix transpose(const GSparseMatrix& m) { - GMatrix result(m.m_rows,m.m_cols); - for (unsigned row = 0; row < m.m_rows; ++row) { - for (unsigned col = 0; col < m.m_cols; ++col) - result(row,col) = m(row,col); - } + GSparseMatrix result = m; + result.transpose(); return result; } -// Convert symmetric matrix into lower triangle full matrix: lower_triangle(GSymMatrix) +// Cholesky decomposition inline -GMatrix lower_triangle(const GSymMatrix &m) +GSparseMatrix cholesky_decompose(const GSparseMatrix& m, int compress) { - GMatrix result(m.m_rows,m.m_cols); - for (unsigned row = 0; row < m.m_rows; ++row) { - for (unsigned col = 0; col <= row; ++col) - result(row,col) = m.m_data[m.m_colstart[col]+(row-col)]; - } + GSparseMatrix result = m; + result.cholesky_decompose(compress); return result; } -// Convert symmetric matrix into upper triangle full matrix: lower_triangle(GSymMatrix) +// Matrix inversion using Cholesky decomposition inline -GMatrix upper_triangle(const GSymMatrix &m) +GSparseMatrix cholesky_invert(const GSparseMatrix& m, int compress) { - GMatrix result(m.m_rows,m.m_cols); - for (unsigned row = 0; row < m.m_rows; ++row) { - for (unsigned col = row; col < m.m_cols; ++col) - result(row,col) = m.m_data[m.m_colstart[row]+(col-row)]; - } + GSparseMatrix result = m; + result.cholesky_invert(compress); return result; } -#endif /* GSYMMATRIX_HPP */ +#endif /* GSPARSEMATRIX_HPP */ diff --git a/src/GSparseNumeric.cpp b/src/GSparseNumeric.cpp new file mode 100644 index 0000000..6710dd9 --- /dev/null +++ b/src/GSparseNumeric.cpp @@ -0,0 +1,382 @@ +/*************************************************************************** + * GSparseNumeric.cpp - sparse matrix numeric analysis class * + * ----------------------------------------------------------------------- * + * copyright : (C) 2006 by Jurgen Knodlseder * + * ----------------------------------------------------------------------- * + * * + * 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 2 of the License, or * + * (at your option) any later version. * + * * + ***************************************************************************/ + +/* __ Includes ___________________________________________________________ */ +#include "GSparseSymbolic.hpp" +#include "GSparseNumeric.hpp" + +/* __ Namespaces _________________________________________________________ */ +using namespace std; + +/* __ Macros _____________________________________________________________ */ +#define CS_FLIP(i) (-(i)-2) +#define CS_MARK(w,j) { w [j] = CS_FLIP (w [j]) ; } +#define CS_MARKED(w,j) (w [j] < 0) + + +/*========================================================================== + = = + = GSparseNumeric constructors/destructors = + = = + ==========================================================================*/ + +/*************************************************************************** + * GSparseNumeric constructor * + ***************************************************************************/ +GSparseNumeric::GSparseNumeric() +{ + // Initialise private members for clean destruction + m_L = NULL; + m_U = NULL; + m_pinv = NULL; + m_B = NULL; + m_n_pinv = 0; + m_n_B = 0; + + // Return + return; +} + + +/*************************************************************************** + * GSparseNumeric destructor * + ***************************************************************************/ +GSparseNumeric::~GSparseNumeric() +{ + // De-allocate only if memory has indeed been allocated + if (m_L != NULL) delete m_L; + if (m_U != NULL) delete m_U; + if (m_pinv != NULL) delete [] m_pinv; + if (m_B != NULL) delete [] m_B; + + // Return + return; +} + + +/*========================================================================== + = = + = GSparseNumeric operators = + = = + ==========================================================================*/ + +/*************************************************************************** + * GSparseNumeric assignment operator * + ***************************************************************************/ +GSparseNumeric& GSparseNumeric::operator= (const GSparseNumeric& n) +{ + // Execute only if object is not identical + if (this != &n) { + + // Initialise private members for clean destruction + m_L = NULL; + m_U = NULL; + m_pinv = NULL; + m_B = NULL; + m_n_pinv = 0; + m_n_B = 0; + + // Copy m_L if it exists + if (n.m_L != NULL) + m_L = new GSparseMatrix(*n.m_L); + + // Copy m_U if it exists + if (n.m_U != NULL) + m_U = new GSparseMatrix(*n.m_U); + + // Copy m_pinv array if it exists + if (n.m_pinv != NULL) { + m_pinv = new int[n.m_n_pinv]; + if (m_pinv == NULL) + throw mem_alloc("GSparseNumeric::operator= (const GSparseNumeric&)", + n.m_n_pinv); + for (int i = 0; i < n.m_n_pinv; ++i) + m_pinv[i] = n.m_pinv[i]; + m_n_pinv = n.m_n_pinv; + } + + // Copy m_B array if it exists + if (n.m_B != NULL) { + m_B = new double[n.m_n_B]; + if (m_B == NULL) + throw mem_alloc("GSparseNumeric::operator= (const GSparseNumeric&)", + n.m_n_B); + for (int i = 0; i < n.m_n_B; ++i) + m_B[i] = n.m_B[i]; + m_n_B = n.m_n_B; + } + + } // endif: object was not identical + + // Return + return *this; +} + + +/*========================================================================== + = = + = GSparseNumeric member functions = + = = + ==========================================================================*/ + +/*************************************************************************** + * cholesky_numeric_analysis * + * ----------------------------------------------------------------------- * + * L = chol (A, [pinv parent cp]), pinv is optional. This function * + * allocates the memory to hold the information. * + * ----------------------------------------------------------------------- * + * Input: A Sparse matrix * + * S Symbolic analysis of sparse matrix * + ***************************************************************************/ +void GSparseNumeric::cholesky_numeric_analysis(GSparseMatrix& A, + const GSparseSymbolic& S) +{ + // Return if arrays in the symbolic analysis have not been allocated + if (!S.m_cp || !S.m_parent) return; + + // Declare + double lki; + int top, i, p, k; + + // Assign input matrix attributes + int n = A.m_cols; + + // Allocate int workspace + int wrk_size = 2*n; + int* wrk_int = new int[wrk_size]; + if (wrk_int == NULL) + throw mem_alloc( + "GSparseNumeric::cholesky_numeric_analysis(GSparseMatrix&, const GSparseSymbolic&)", + wrk_size); + + // Allocate double workspace + wrk_size = n; + double* wrk_double = new double[wrk_size]; + if (wrk_double == NULL) + throw mem_alloc( + "GSparseNumeric::cholesky_numeric_analysis(GSparseMatrix&, const GSparseSymbolic&)", + wrk_size); + + // Assign pointers + int* cp = S.m_cp; + int* pinv = S.m_pinv; + int* parent = S.m_parent; + + // Assign C = A(p,p) where A and C are symmetric and the upper part stored + GSparseMatrix C = (pinv) ? S.cs_symperm(&A, pinv, 1) : (A); + + // Assign workspace pointer + int* c = wrk_int; + int* s = wrk_int + n; + double* x = wrk_double; + + // Assign C matrix pointers + int* Cp = C.m_colstart; + int* Ci = C.m_rowinx; + double* Cx = C.m_data; + + // Allocate L matrix + m_L = new GSparseMatrix(n,n,cp[n]); + if (m_L == NULL) + throw mem_alloc( + "GSparseNumeric::cholesky_numeric_analysis(GSparseMatrix&, const GSparseSymbolic&)", + 1); + + // Assign L matrix pointers + int* Lp = m_L->m_colstart; + int* Li = m_L->m_rowinx; + double* Lx = m_L->m_data; + + // Initialise column pointers of L and c + for (k = 0; k < n; ++k) + Lp[k] = c[k] = cp[k]; + + // Compute L(:,k) for L*L' = C + for (k = 0; k < n; k++) { + + // Nonzero pattern of L(k,:) + top = cs_ereach(&C, k, parent, s, c); // find pattern of L(k,:) + x[k] = 0; // x (0:k) is now zero + + // x = full(triu(C(:,k))) + for (p = Cp[k]; p < Cp[k+1]; p++) { + if (Ci[p] <= k) + x[Ci[p]] = Cx[p]; + } + + // d = C(k,k) + double d = x[k]; + + // Clear x for k+1st iteration + x[k] = 0; + + // Triangular solve: Solve L(0:k-1,0:k-1) * x = C(:,k) + for ( ; top < n; top++) { + i = s[top]; // s [top..n-1] is pattern of L(k,:) + lki = x[i]/Lx[Lp[i]]; // L(k,i) = x (i) / L(i,i) + x[i] = 0; // clear x for k+1st iteration + for (p = Lp[i]+1; p < c[i]; p++) + x[Li[p]] -= Lx[p] * lki; + d -= lki * lki; // d = d - L(k,i)*L(k,i) + p = c [i]++ ; + Li[p] = k; // store L(k,i) in column i + Lx[p] = lki; + } + + // Compute L(k,k) + if (d <= 0) + throw GSparseMatrix::matrix_not_pos_definite( + "GSparseNumeric::cholesky_numeric_analysis(GSparseMatrix&, const GSparseSymbolic&)", + k, d); + + // Store L(k,k) = sqrt (d) in column k + p = c[k]++; + Li[p] = k; + Lx[p] = sqrt(d); + } + + // Finalize L + Lp[n] = cp[n]; + + // Free workspace + delete [] wrk_int; + delete [] wrk_double; + + // Return void + return; +} + + +/*========================================================================== + = = + = GSparseNumeric private functions = + = = + ==========================================================================*/ + +/*************************************************************************** + * cs_ereach * + * ----------------------------------------------------------------------- * + * Find nonzero pattern of Cholesky L(k,1:k-1) using etree and * + * triu(A(:,k)) * + * ----------------------------------------------------------------------- * + * Input: A Sparse matrix * + * k Node * + * parent ... * + * s ... * + * w ... * + * Input: top Index, where s[top..n-1] contains pattern * + * of L(k,:); -1 if arrays have not been * + * allocated * + ***************************************************************************/ +int GSparseNumeric::cs_ereach(const GSparseMatrix* A, int k, + const int* parent, int* s, int* w) +{ + // Return -1 if arrays have not been allocated + if (!parent || !s || !w) return (-1); + + // Assign A matrix attributes and pointers + int n = A->m_cols; + int top = n; + int* Ap = A->m_colstart; + int* Ai = A->m_rowinx; + + // Mark node k as visited + CS_MARK(w, k); + + // Loop over elements of node + int i; + for (int p = Ap[k]; p < Ap[k+1]; ++p) { + i = Ai[p]; // A(i,k) is nonzero + if (i > k) continue; // only use upper triangular part of A + + // Traverse up etree + int len; + for (len = 0; !CS_MARKED(w,i); i = parent[i]) { + s[len++] = i; // L(k,i) is nonzero + CS_MARK(w, i); // mark i as visited + } + + // Push path onto stack + while (len > 0) + s[--top] = s[--len]; + } + + // Unmark all nodes + for (int p = top; p < n; ++p) + CS_MARK(w, s[p]); + + // Unmark node k + CS_MARK(w, k); + + // Return index top, where s[top..n-1] contains pattern of L(k,:) + return (top); +} + + +/*========================================================================== + = = + = GSparseNumeric static member functions = + = = + ==========================================================================*/ + +/*========================================================================== + = = + = GSparseNumeric friends = + = = + ==========================================================================*/ + +/*************************************************************************** + * Output operator * + ***************************************************************************/ +ostream& operator<< (ostream& os, const GSparseNumeric& n) +{ + // Put header is stream + os << "=== GSparseNumeric ==="; + + // Show L or V matrix + if (n.m_L != NULL) { + os << endl << + " === L or V "; + os << *n.m_L << endl; + } + + // Show U or R matrix + if (n.m_U != NULL) { + os << endl << + " === U or R matrix "; + os << *n.m_U << endl; + } + + // Show inverse permutation if it exists + if (n.m_pinv != NULL) { + os << endl << " Inverse permutation (of " << n.m_n_pinv << " elements)" << endl; + for (int i = 0; i < n.m_n_pinv; ++i) + os << " " << n.m_pinv[i]; + } + + // Show beta array if it exists + if (n.m_B != NULL) { + os << endl << " Beta[0.." << n.m_n_B << "]" << endl; + for (int i = 0; i < n.m_n_B; ++i) + os << " " << n.m_B[i]; + } + + // Return output stream + return os; +} + +/*========================================================================== + = = + = GSparseNumeric exception classes = + = = + ==========================================================================*/ diff --git a/src/GSparseNumeric.hpp b/src/GSparseNumeric.hpp new file mode 100644 index 0000000..5b7be6a --- /dev/null +++ b/src/GSparseNumeric.hpp @@ -0,0 +1,79 @@ +/*************************************************************************** + * GSparseNumeric.hpp - sparse matrix numeric analysis class * + * ----------------------------------------------------------------------- * + * copyright : (C) 2006 by Jurgen Knodlseder * + * ----------------------------------------------------------------------- * + * * + * 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 2 of the License, or * + * (at your option) any later version. * + * * + ***************************************************************************/ + +#ifndef GSPARSENUMERIC_HPP +#define GSPARSENUMERIC_HPP + +/* __ Includes ___________________________________________________________ */ +#include "GException.hpp" +#include "GVector.hpp" +#include "GMatrix.hpp" +#include "GSparseMatrix.hpp" + +/* __ Namespaces _________________________________________________________ */ +using namespace std; + +/* __ Definitions ________________________________________________________ */ + +/* __ Enumerators ________________________________________________________ */ + +/* __ Structures _________________________________________________________ */ + +/* __ Prototypes _________________________________________________________ */ + + +/*************************************************************************** + * GSparseNumeric class definition * + ***************************************************************************/ +class GSparseNumeric { + // Friend classes + friend class GSparseMatrix; + + // I/O friends + friend ostream& operator<< (ostream& os, const GSparseNumeric& n); + +public: + // Constructors and destructors + GSparseNumeric(); + ~GSparseNumeric(); + + // Assignment operator + GSparseNumeric& operator= (const GSparseNumeric& n); + + // Functions + void cholesky_numeric_analysis(GSparseMatrix& m, const GSparseSymbolic& s); + +private: + // Functions + int cs_ereach(const GSparseMatrix* A, int k, const int* parent, int* s, int* w); + + // Data + GSparseMatrix* m_L; // L for LU and Cholesky, V for QR + GSparseMatrix* m_U; // U for LU, R for QR, not used for Cholesky + int* m_pinv; // partial pivoting for LU + double* m_B; // beta [0..n-1] for QR + int m_n_pinv; // Number of elements in m_pinv + int m_n_B; // Number of elements in m_B +}; + + +/*************************************************************************** + * Inline members * + ***************************************************************************/ + + +/*************************************************************************** + * Inline friends * + ***************************************************************************/ + +#endif /* GSPARSENUMERIC_HPP */ diff --git a/src/GSparseSymbolic.cpp b/src/GSparseSymbolic.cpp new file mode 100644 index 0000000..79605c6 --- /dev/null +++ b/src/GSparseSymbolic.cpp @@ -0,0 +1,1453 @@ +/*************************************************************************** + * GSparseSymbolic.cpp - sparse matrix symbolic analysis class * + * ----------------------------------------------------------------------- * + * copyright : (C) 2006 by Jurgen Knodlseder * + * ----------------------------------------------------------------------- * + * * + * 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 2 of the License, or * + * (at your option) any later version. * + * * + ***************************************************************************/ + +/* __ Includes ___________________________________________________________ */ +#include "GSparseSymbolic.hpp" + +/* __ Namespaces _________________________________________________________ */ +using namespace std; + +/* __ Macros _____________________________________________________________ */ +#define CS_MIN(a,b) (((a) < (b)) ? (a) : (b)) +#define CS_MAX(a,b) (((a) > (b)) ? (a) : (b)) +#define CS_FLIP(i) (-(i)-2) + +/* __ Definitions ________________________________________________________ */ +//#define G_DEBUG_SPARSE_SYM_AMD_ORDERING // Debug AMD ordering + + +/*========================================================================== + = = + = GSparseSymbolic constructors/destructors = + = = + ==========================================================================*/ + +/*************************************************************************** + * GSparseSymbolic constructor * + ***************************************************************************/ +GSparseSymbolic::GSparseSymbolic() +{ + // Initialise private members for clean destruction + m_n_pinv = 0; + m_n_q = 0; + m_n_parent = 0; + m_n_cp = 0; + m_n_leftmost = 0; + m_pinv = NULL; + m_q = NULL; + m_parent = NULL; + m_cp = NULL; + m_leftmost = NULL; + m_m2 = 0; + m_lnz = 0.0; + m_unz = 0.0; + + // Return + return; +} + + +/*************************************************************************** + * GSparseSymbolic destructor * + ***************************************************************************/ +GSparseSymbolic::~GSparseSymbolic() +{ + // De-allocate only if memory has indeed been allocated + if (m_pinv != NULL) delete[] m_pinv; + if (m_q != NULL) delete[] m_q; + if (m_parent != NULL) delete[] m_parent; + if (m_cp != NULL) delete[] m_cp; + if (m_leftmost != NULL) delete[] m_leftmost; + + // Return + return; +} + + +/*========================================================================== + = = + = GSparseSymbolic operators = + = = + ==========================================================================*/ + +/*************************************************************************** + * GSparseSymbolic assignment operator * + ***************************************************************************/ +GSparseSymbolic& GSparseSymbolic::operator= (const GSparseSymbolic& s) +{ + // Execute only if object is not identical + if (this != &s) { + + // Initialise private members for clean destruction + m_n_pinv = 0; + m_n_q = 0; + m_n_parent = 0; + m_n_cp = 0; + m_n_leftmost = 0; + m_pinv = NULL; + m_q = NULL; + m_parent = NULL; + m_cp = NULL; + m_leftmost = NULL; + m_m2 = 0; + m_lnz = 0.0; + m_unz = 0.0; + + // Copy data members + m_m2 = s.m_m2; + m_lnz = s.m_lnz; + m_unz = s.m_unz; + + // Copy m_pinv array if it exists + if (s.m_pinv != NULL) { + m_pinv = new int[s.m_n_pinv]; + if (m_pinv == NULL) + throw mem_alloc("GSparseSymbolic::operator= (const GSparseSymbolic&)", + s.m_n_pinv); + for (int i = 0; i < s.m_n_pinv; ++i) + m_pinv[i] = s.m_pinv[i]; + m_n_pinv = s.m_n_pinv; + } + + // Copy m_q array if it exists + if (s.m_q != NULL) { + m_q = new int[s.m_n_q]; + if (m_q == NULL) + throw mem_alloc("GSparseSymbolic::operator= (const GSparseSymbolic&)", + s.m_n_q); + for (int i = 0; i < s.m_n_q; ++i) + m_q[i] = s.m_q[i]; + m_n_q = s.m_n_q; + } + + // Copy m_parent array if it exists + if (s.m_parent != NULL) { + m_parent = new int[s.m_n_parent]; + if (m_parent == NULL) + throw mem_alloc("GSparseSymbolic::operator= (const GSparseSymbolic&)", + s.m_n_parent); + for (int i = 0; i < s.m_n_parent; ++i) + m_parent[i] = s.m_parent[i]; + m_n_parent = s.m_n_parent; + } + + // Copy m_cp array if it exists + if (s.m_cp != NULL) { + m_cp = new int[s.m_n_cp]; + if (m_cp == NULL) + throw mem_alloc("GSparseSymbolic::operator= (const GSparseSymbolic&)", + s.m_n_cp); + for (int i = 0; i < s.m_n_cp; ++i) + m_cp[i] = s.m_cp[i]; + m_n_cp = s.m_n_cp; + } + + // Copy m_leftmost array if it exists + if (s.m_leftmost != NULL) { + m_leftmost = new int[s.m_n_leftmost]; + if (m_leftmost == NULL) + throw mem_alloc("GSparseSymbolic::operator= (const GSparseSymbolic&)", + s.m_n_leftmost); + for (int i = 0; i < s.m_n_leftmost; ++i) + m_leftmost[i] = s.m_leftmost[i]; + m_leftmost = s.m_leftmost; + } + + } // endif: object was not identical + + // Return + return (*this); +} + + +/*========================================================================== + = = + = GSparseSymbolic member functions = + = = + ==========================================================================*/ + +/*************************************************************************** + * cholesky_symbolic_analysis * + * ----------------------------------------------------------------------- * + * Ordering and symbolic analysis for a Cholesky factorization. This * + * function allocates the memory to hold the information. * + * ----------------------------------------------------------------------- * + * Input: order 0: natural * + * 1: Cholesky decomposition * + * m Sparse matrix * + ***************************************************************************/ +void GSparseSymbolic::cholesky_symbolic_analysis(int order, GSparseMatrix& m) +{ + // Check if order type is valid + if (order < 0 || order > 1) + throw invalid_order("GSparseSymbolic::cholesky_symbolic_analysis(int, GSparseMatrix*)", + order, 0, 1); + + // Fill pending element + m.fill_pending(); + + // Assign input matrix attributes + int n = m.m_cols; + + // P = amd(A+A'), or natural + int* P = cs_amd(order, &m); + + // Find inverse permutation and store it in class member 'm_pinv' + m_pinv = cs_pinv(P, n); + m_n_pinv = n; + + // Delete workspace + delete [] P; + + // C = spones(triu(A(P,P))) + GSparseMatrix C = cs_symperm(&m, m_pinv, 0); + + // Find etree of C and store it in class member 'm_parent' + m_parent = cs_etree(&C, 0); + m_n_parent = n; + + // Post order the etree + int* post = cs_post(m_parent, n); + + // Find column counts of chol(C) + int* c = cs_counts(&C, m_parent, post, 0); + + // Delete workspace + delete [] post; + + // Allocate column pointers for Cholesky decomposition + m_n_cp = n+1; + m_cp = new int[m_n_cp]; + if (m_cp == NULL) + throw mem_alloc("GSparseSymbolic::cs_schol(int, GSparseMatrix*)", m_n_cp); + + // Find column pointers for L + m_unz = m_lnz = cs_cumsum(m_cp, c, n); + + // Delete workspace + delete [] c; + +// return ((S->lnz >= 0) ? S : cs_sfree (S)) ; +} + + +/*========================================================================== + = = + = GSparseSymbolic private functions = + = = + ==========================================================================*/ + +/*************************************************************************** + * cs_amd * + * ----------------------------------------------------------------------- * + * Applies an approximate minimum degree ordering algorithm to derive the * + * permutations that minimise the fill-in. * + * p = amd(A+A') if symmetric is true, or amd(A'A) otherwise * + * ----------------------------------------------------------------------- * + * Input: order 0: natural * + * 1: Cholesky decomposition * + * 2: LU decomposition * + * 3: QR decomposition * + * A Sparse matrix * + * Output: p[0..n] integer array of n+1 elements * + ***************************************************************************/ +int* GSparseSymbolic::cs_amd(int order, GSparseMatrix* A) +{ + // Throw exception if order is not a decomposition + if (order < 0 || order > 3) + throw invalid_order("GSparseSymbolic::cs_amd(int, GSparseMatrix*)", + order, 0, 3); + + // Debug + #if defined(G_DEBUG_SPARSE_SYM_AMD_ORDERING) + cout << endl << "GSparseSymbolic::cs_amd entered" << endl; + cout << " order ......................: " << order << endl; + cout << " number of rows .............: " << A->m_rows << endl; + cout << " number of columns ..........: " << A->m_cols << endl; + cout << " number of non-zero elements : " << A->m_elements << endl; + #endif + + // Declare + int dense; + int d, dk, dext, lemax = 0, e, elenk, eln, i, j, k, k1, + k2, k3, jlast, ln, mindeg = 0, nvi, nvj, nvk, mark, wnvi, + ok, nel = 0, p, p1, p2, p3, p4, pj, pk, pk1, pk2, pn, q; + unsigned int h ; + + // Assign input matrix attributes + int m = A->m_rows; + int n = A->m_cols; + + + // ====================================================================== + // Step 1: Construct matrix C + // ====================================================================== + + // Debug + #if defined(G_DEBUG_SPARSE_SYM_AMD_ORDERING) + cout << " Step 1: Construct matrix C" << endl; + #endif + + // Initialise matrix C. We do not care at this point about the actual + // dimension since we attribute the matrix later anyways. It's just + // that there is no empty constructor of a matrix, so we have to put + // something by default ... + GSparseMatrix C(m,n); + + // Get (logical) transpose of A: AT = A' + GSparseMatrix AT = A->cs_transpose(A,0); + + // Find dense threshold + dense = (int)CS_MAX(16, 10 * sqrt((double)n)); + dense = CS_MIN(n-2, dense); + + // Case A: Cholesky decomposition of a symmetric matrix: C = A + A' + if (order == 1 && n == m) { +// C = cs_add (A, AT, 0, 0); + C = *A + AT; + } + + // Case B: LU decomposition: C = A' * A with no dense rows + else if (order == 2) { + + // Assign A' matrix attributes + int* ATp = AT.m_colstart; + int* ATi = AT.m_rowinx; + + // Drop dense columns from AT + for (p2 = 0, j = 0; j < m; j++) { + p = ATp[j]; // column j of AT starts here + ATp[j] = p2; // new column j starts here + if (ATp[j+1] - p > dense) continue; // skip dense col j + for ( ; p < ATp[j+1]; p++) + ATi[p2++] = ATi[p] ; + } + + // Finalise AT + ATp[m] = p2; + + // Get (logical) transpose of AT: A2 = AT' + GSparseMatrix A2 = AT.cs_transpose(&AT,0); + + // C = A' * A with no dense rows +// C = A2 ? cs_multiply(AT, A2) : NULL; + C = AT * A2; + } + + // Case C: QR decomposition: C = A' * A + else { +// C = cs_multiply(AT, A); + C = AT * *A; + } + + // Stop in case of an error +// if (!C) return (NULL) ; + + // Drop diagonal entries from C + cs_fkeep(&C, &cs_diag, NULL); + + // Assign C matrix attributes + int* Cp = C.m_colstart; + int cnz = Cp[n]; + + // Allocate result array + int* P = new int[n+1]; + if (P == NULL) + throw mem_alloc("GSparseSymbolic::cs_amd (int, GSparseMatrix*)", n+1); + + // Allocate workspace + int wrk_size = 8*(n+1); + int* wrk_int = new int[wrk_size]; + if (wrk_int == NULL) + throw mem_alloc("GSparseSymbolic::cs_amd (int, GSparseMatrix*)", wrk_size); + + // Add elbow room to C +// t = cnz + cnz/5 + 2*n; +// if (!P || !W || !cs_sprealloc (C, t)) return (cs_idone (P, C, W, 0)) ; + int t = cnz/5 + 2*n; + C.alloc_elements(cnz, t); + + // Set workspace pointers + int* len = wrk_int; + int* nv = wrk_int + (n+1); + int* next = wrk_int + 2*(n+1); + int* head = wrk_int + 3*(n+1); + int* elen = wrk_int + 4*(n+1); + int* degree = wrk_int + 5*(n+1); + int* w = wrk_int + 6*(n+1); + int* hhead = wrk_int + 7*(n+1); + int* last = P; // use P as workspace for last + + + // ====================================================================== + // Step 2: Initialize quotient graph + // ====================================================================== + + // Debug + #if defined(G_DEBUG_SPARSE_SYM_AMD_ORDERING) + cout << " Step 2: Initialize quotient graph" << endl; + #endif + + // (Re-)assign C matrix attributes + int nzmax = C.m_elements; // Maximum number of entries + Cp = C.m_colstart; + int* Ci = C.m_rowinx; + + // Setup array that contains for each column the number of non-zero elements + for (k = 0 ; k < n ; k++) + len[k] = Cp[k+1] - Cp[k]; + len[n] = 0; + + // Loop over all columns + for (i = 0 ; i <= n ; i++) { + head[i] = -1; // degree list i is empty + last[i] = -1; + next[i] = -1; + hhead[i] = -1; // hash list i is empty + nv[i] = 1; // node i is just one node + w[i] = 1; // node i is alive + elen[i] = 0; // Ek of node i is empty + degree[i] = len[i]; // degree of node i + } + + // Clear w + mark = cs_wclear(0, 0, w, n); + + // End-point initialisations + elen[n] = -2; // n is a dead element + Cp[n] = -1; // n is a root of assembly tree + w[n] = 0; // n is a dead element + + + // ====================================================================== + // Step 3: Initialize degree lists + // ====================================================================== + + // Debug + #if defined(G_DEBUG_SPARSE_SYM_AMD_ORDERING) + cout << " Step 3: Initialize degree lists" << endl; + #endif + + // Loop over all columns + for (i = 0 ; i < n ; i++) { + + // Get degree of node + d = degree[i]; + + // Case A: Node i is empty + if (d == 0) { + elen[i] = -2; // element i is dead + nel++ ; + Cp[i] = -1; // i is a root of assembly tree + w[i] = 0; // i is a dead element + } + + // Case B: Node is dense + else if (d > dense) { + nv[i] = 0; // absorb i into element n + elen[i] = -1; // node i is dead + nel++ ; + Cp[i] = CS_FLIP(n); + nv[n]++ ; + } + + // Case C: Node is sparse + else { + if (head[d] != -1) last[head[d]] = i; + next[i] = head[d]; // put node i in degree list d + head[d] = i; + } + } // endfor: looped over all columns + + + // ====================================================================== + // Step 4: Build permutations + // ====================================================================== + + // Debug + #if defined(G_DEBUG_SPARSE_SYM_AMD_ORDERING) + cout << " Step 4: Build permutations" << endl; + #endif + + // While (selecting pivots) do + while (nel < n) { + + // Select node of minimum approximate degree + for (k = -1; mindeg < n && (k = head [mindeg]) == -1; mindeg++) ; + if (next[k] != -1) last [next[k]] = -1; + head[mindeg] = next[k]; // remove k from degree list + elenk = elen[k]; // elenk = |Ek| + nvk = nv[k]; // # of nodes k represents + nel += nvk; // nv[k] nodes of A eliminated + + // Garbage collection + if (elenk > 0 && cnz + mindeg >= nzmax) { + + // Loop over all columns + for (j = 0 ; j < n ; j++) { + // If j is a live node or element, then ... + if ((p = Cp[j]) >= 0) { + Cp[j] = Ci[p]; // save first entry of object + Ci[p] = CS_FLIP(j); // first entry is now CS_FLIP(j) + } + } + + // Scan all memory + for (q = 0, p = 0; p < cnz ; ) { + // If we found object j, then ... + if ((j = CS_FLIP(Ci[p++])) >= 0) { + Ci[q] = Cp[j]; // restore first entry of object + Cp[j] = q++; // new pointer to object j + for (k3 = 0; k3 < len [j]-1; k3++) + Ci[q++] = Ci[p++]; + } + } + cnz = q; // Ci[cnz...nzmax-1] now free + + } // endif: garbage collection done + + // Construct new element ---------------------------------------- */ + dk = 0; + nv[k] = -nvk; // flag k as in Lk + p = Cp[k]; + pk1 = (elenk == 0) ? p : cnz; // do in place if elen[k] == 0 + pk2 = pk1; + for (k1 = 1; k1 <= elenk + 1; k1++) { + + // ... + if (k1 > elenk) { + e = k; // search the nodes in k + pj = p; // list of nodes starts at Ci[pj] + ln = len [k] - elenk; // length of list of nodes in k + } + else { + e = Ci[p++]; // search the nodes in e + pj = Cp[e]; + ln = len[e]; // length of list of nodes in e + } + + // ... + for (k2 = 1 ; k2 <= ln ; k2++) { + i = Ci[pj++]; + if ((nvi = nv [i]) <= 0) // Skip of node i is dead or seen + continue; + dk += nvi; // degree[Lk] += size of node i + nv[i] = -nvi; // negate nv[i] to denote i in Lk + Ci[pk2++] = i; // place i in Lk + if (next[i] != -1) + last[next[i]] = last[i]; + + // remove i from degree list + if (last[i] != -1) + next[last[i]] = next[i]; + else + head[degree[i]] = next[i]; + } // endfor: k2 + + // ... + if (e != k) { + Cp[e] = CS_FLIP (k); // absorb e into k + w[e] = 0; // e is now a dead element + } + } // endfor: k1 + + if (elenk != 0) cnz = pk2; // Ci [cnz...nzmax] is free + degree[k] = dk; // external degree of k - |Lk\i| + Cp[k] = pk1; // element k is in Ci[pk1..pk2-1] + len[k] = pk2 - pk1; + elen[k] = -2; // k is now an element + + // Clear w if necessary + mark = cs_wclear(mark, lemax, w, n); + + // Scan 1: Find set differences |Le\Lk| + for (pk = pk1 ; pk < pk2 ; pk++) { + i = Ci [pk]; + if ((eln = elen [i]) <= 0) // skip if elen[i] empty + continue; + nvi = -nv[i]; // nv [i] was negated + wnvi = mark - nvi; + + // Scan Ei + for (p = Cp[i]; p <= Cp[i] + eln - 1; p++) { + e = Ci [p] ; + if (w[e] >= mark) + w[e] -= nvi; // decrement |Le\Lk| + else if (w[e] != 0) // ensure e is a live element + w[e] = degree[e] + wnvi; // 1st time e seen in scan 1 + } + } // endfor: scan 1 finished + + // Scan 2: Degree update + for (pk = pk1; pk < pk2; pk++) { + i = Ci [pk] ; /* consider node i in Lk */ + p1 = Cp [i] ; + p2 = p1 + elen [i] - 1 ; + pn = p1 ; + + // Scan Ei + for (h = 0, d = 0, p = p1 ; p <= p2 ; p++) { + e = Ci [p] ; + // If e is an unabsorbed element, then ... + if (w [e] != 0) { + dext = w [e] - mark ; /* dext = |Le\Lk| */ + if (dext > 0) { + d += dext ; /* sum up the set differences */ + Ci [pn++] = e ; /* keep e in Ei */ + h += e ; /* compute the hash of node i */ + } + else { + Cp [e] = CS_FLIP (k) ; /* aggressive absorb. e->k */ + w [e] = 0 ; /* e is a dead element */ + } + } + } // endfor: scanned Ei + + // elen[i] = |Ei| + elen [i] = pn - p1 + 1 ; + p3 = pn ; + p4 = p1 + len [i] ; + + // Prune edges in Ai + for (p = p2 + 1 ; p < p4 ; p++) { + j = Ci [p] ; + if ((nvj = nv [j]) <= 0) continue ; /* node j dead or in Lk */ + d += nvj ; /* degree(i) += |j| */ + Ci [pn++] = j ; /* place j in node list of i */ + h += j ; /* compute hash for node i */ + } + + // Check for mass elimination + if (d == 0) { + Cp [i] = CS_FLIP (k) ; /* absorb i into k */ + nvi = -nv [i] ; + dk -= nvi ; /* |Lk| -= |i| */ + nvk += nvi ; /* |k| += nv[i] */ + nel += nvi ; + nv [i] = 0 ; + elen [i] = -1 ; /* node i is dead */ + } + else { + degree [i] = CS_MIN (degree [i], d) ; /* update degree(i) */ + Ci [pn] = Ci [p3] ; /* move first node to end */ + Ci [p3] = Ci [p1] ; /* move 1st el. to end of Ei */ + Ci [p1] = k ; /* add k as 1st element in of Ei */ + len [i] = pn - p1 + 1 ; /* new len of adj. list of node i */ + h %= n ; /* finalize hash of i */ + next [i] = hhead [h] ; /* place i in hash bucket */ + hhead [h] = i ; + last [i] = h ; /* save hash of i in last[i] */ + } + } // endfor: scan 2 is done + + // finalize |Lk| + degree[k] = dk ; + lemax = CS_MAX(lemax, dk); + + // Clear w + mark = cs_wclear(mark+lemax, lemax, w, n); + + // Supernode detection + for (pk = pk1 ; pk < pk2 ; pk++) { + i = Ci [pk] ; + if (nv [i] >= 0) continue ; /* skip if i is dead */ + h = last [i] ; /* scan hash bucket of node i */ + i = hhead [h] ; + hhead [h] = -1 ; /* hash bucket will be empty */ + + // ... + for ( ; i != -1 && next [i] != -1 ; i = next [i], mark++) { + ln = len [i] ; + eln = elen [i] ; + for (p = Cp [i]+1 ; p <= Cp [i] + ln-1 ; p++) w [Ci [p]] = mark; + jlast = i ; + + // Compare i with all j + for (j = next [i] ; j != -1 ; ) { + ok = (len [j] == ln) && (elen [j] == eln) ; + for (p = Cp [j] + 1 ; ok && p <= Cp [j] + ln - 1 ; p++) { + if (w [Ci [p]] != mark) ok = 0 ; /* compare i and j*/ + } + + // i and j are identical + if (ok) { + Cp[j] = CS_FLIP(i); /* absorb j into i */ + nv[i] += nv[j]; + nv[j] = 0; + elen[j] = -1; /* node j is dead */ + j = next[j]; /* delete j from hash bucket */ + next[jlast] = j; + } + // j and i are different + else { + jlast = j; + j = next[j]; + } + } // endfor: comparison of i with all j + } // + } // endfor: supernode detection + + // Finalize new element + for (p = pk1, pk = pk1 ; pk < pk2 ; pk++) /* finalize Lk */ + { + i = Ci [pk] ; + if ((nvi = -nv [i]) <= 0) continue ;/* skip if i is dead */ + nv [i] = nvi ; /* restore nv[i] */ + d = degree [i] + dk - nvi ; /* compute external degree(i) */ + d = CS_MIN (d, n - nel - nvi) ; + if (head [d] != -1) last [head [d]] = i ; + next [i] = head [d] ; /* put i back in degree list */ + last [i] = -1 ; + head [d] = i ; + mindeg = CS_MIN (mindeg, d) ; /* find new minimum degree */ + degree [i] = d ; + Ci [p++] = i ; /* place i in Lk */ + } + nv [k] = nvk ; /* # nodes absorbed into k */ + if ((len [k] = p-pk1) == 0) /* length of adj list of element k*/ + { + Cp [k] = -1 ; /* k is a root of the tree */ + w [k] = 0 ; /* k is now a dead element */ + } + if (elenk != 0) cnz = p ; /* free unused space in Lk */ + } + + // Postordering + for (i = 0 ; i < n ; i++) Cp [i] = CS_FLIP (Cp [i]) ;/* fix assembly tree */ + for (j = 0 ; j <= n ; j++) head [j] = -1 ; + for (j = n ; j >= 0 ; j--) /* place unordered nodes in lists */ + { + if (nv [j] > 0) continue ; /* skip if j is an element */ + next [j] = head [Cp [j]] ; /* place j in list of its parent */ + head [Cp [j]] = j ; + } + for (e = n ; e >= 0 ; e--) /* place elements in lists */ + { + if (nv [e] <= 0) continue ; /* skip unless e is an element */ + if (Cp [e] != -1) + { + next [e] = head [Cp [e]] ; /* place e in list of its parent */ + head [Cp [e]] = e ; + } + } + + // ====================================================================== + // Step 5: Postorder the assembly tree + // ====================================================================== + + // Debug + #if defined(G_DEBUG_SPARSE_SYM_AMD_ORDERING) + cout << " Step 5: Postorder the assembly tree" << endl; + #endif + + // Postorder the assembly tree + for (k = 0, i = 0 ; i <= n ; i++) { + if (Cp [i] == -1) + k = cs_tdfs(i, k, head, next, P, w); + } + + // Free workspace + delete [] wrk_int; + + // Debug + #if defined(G_DEBUG_SPARSE_SYM_AMD_ORDERING) + cout << " Permutation:" << endl; + for (i = 0; i < n; ++i) + cout << " " << P[i]; + cout << endl; + cout << "GSparseSymbolic::cs_amd finished" << endl; + #endif + + // Return result + return (P); +} + + +/*************************************************************************** + * cs_counts * + * ----------------------------------------------------------------------- * + * Column counts of LL'=A or LL'=A'A, given parent & post ordering * + * ----------------------------------------------------------------------- * + * Input: A Sparse matrix A * + * parent[0..n-1] parent array * + * post[0..n-1] post ordering array * + * ata 0: count LL'=A, 1: count LL'=A'A * + * Output: p[0..n] integer array of n+1 elements * + ***************************************************************************/ +int* GSparseSymbolic::cs_counts(GSparseMatrix* A, const int* parent, + const int* post, int ata) +{ + // Declare loop variables + int i, j, k, J, p, q, jleaf; + + // Return NULL pointer if input arrays are NULL or sparse matrix is + // empty + if (!parent || !post) return (NULL); + + // Assign input matrix attributes + int m = A->m_rows; + int n = A->m_cols; + + // Allocate result + int* colcount = new int[n]; + if (colcount == NULL) + throw mem_alloc("GSparseSymbolic::cs_counts(GSparseMatrix*, const int*, const int*, int)", + n); + int* delta = colcount; + + // Allocate workspace + int wrk_size = 4*n + (ata ? (n+m+1) : 0); + int* wrk_int = new int[wrk_size]; + if (wrk_int == NULL) + throw mem_alloc("GSparseSymbolic::cs_counts(GSparseMatrix*, const int*, const int*, int)", + wrk_size); + + // Get transpose of A: AT = A' + GSparseMatrix AT = A->cs_transpose(A,0); + + // Set-up pointers to workspace + int* ancestor = wrk_int; + int* maxfirst = wrk_int + n; + int* prevleaf = wrk_int + 2*n; + int* first = wrk_int + 3*n; + + // Clear workspace + for (k = 0; k < wrk_size; k++) + wrk_int[k] = -1; + + // Find first j + for (k = 0; k < n; k++) { + j = post[k]; + delta[j] = (first[j] == -1) ? 1 : 0; // delta[j]=1 if j is a leaf + for ( ; j != -1 && first[j] == -1; j = parent[j]) first[j] = k; + } + + // Assign output matrix attributes + int* ATp = AT.m_colstart; + int* ATi = AT.m_rowinx; + + // Initialise + int* head = NULL; + int* next = NULL; + if (ata) init_ata(&AT, post, wrk_int, &head, &next); + + // Each node in its own set + for (i = 0; i < n; i++) ancestor[i] = i; + + // Loop over all columns of matrix A (or rows of matrix AT) + #define HEAD(k,j) (ata ? head [k] : j) + #define NEXT(J) (ata ? next [J] : -1) + for (k = 0; k < n; k++) { + j = post[k]; // j is the kth node in postordered etree + if (parent[j] != -1) delta[parent[j]]--; // j is not a root + for (J = HEAD(k,j); J != -1; J = NEXT(J)) { // J=j for LL'=A case + + // Loop over all non-zero elements in column J + for (p = ATp[J]; p < ATp[J+1]; p++) { + i = ATi [p] ; + q = cs_leaf(i, j, first, maxfirst, prevleaf, ancestor, &jleaf); + if (jleaf >= 1) delta [j]++ ; /* A(i,j) is in skeleton */ + if (jleaf == 2) delta [q]-- ; /* account for overlap in q */ + } + } + if (parent[j] != -1) ancestor[j] = parent[j]; + } + + // Sum up delta's of each child + for (j = 0; j < n; j++) { + if (parent[j] != -1) colcount[parent[j]] += colcount[j]; + } + + // Free workspace + delete [] wrk_int; + + // Return result + return (colcount); +} + + +/*************************************************************************** + * cs_etree * + * ----------------------------------------------------------------------- * + * Compute the etree of A using triu(A), or A'A without forming A'A * + * ----------------------------------------------------------------------- * + * Input: A Sparse matrix A * + * ata flag * + * Output: etree(A) Evaluation tree of matrix A * + ***************************************************************************/ +int* GSparseSymbolic::cs_etree(GSparseMatrix* A, int ata) +{ + // Declare loop variables + int i, k, p; + + // Assign matrix attributes + int m = A->m_rows; + int n = A->m_cols; + + // Allocate result array + int* parent = new int[n]; + if (parent == NULL) + throw mem_alloc("GSparseSymbolic::cs_etree(GSparseMatrix*, int)", n); + + // Allocate workspace + int wrk_size = n + (ata ? m : 0); + int* wrk_int = new int[wrk_size]; + if (wrk_int == NULL) + throw mem_alloc("GSparseSymbolic::cs_etree(GSparseMatrix*, int)", wrk_size); + + // Set-up pointers to workspace. If 'ata=1' then we use also a prev array + int* ancestor = wrk_int; + int* prev = wrk_int + n; + + // If 'prev' is requested, initialise array with -1 + if (ata) for (i = 0; i < m ; ++i) prev[i] = -1; + + // Loop over all nodes (columns) + for (k = 0; k < n; ++k) { + + // Initialise node k to having no parent and no ancestor + parent[k] = -1; // node k has no parent yet + ancestor[k] = -1; // nor does k have an ancestor + + // Loop over all elements in column k + for (p = A->m_colstart[k]; p < A->m_colstart[k+1]; ++p) { + + // Get element index + i = ata ? (prev[A->m_rowinx[p]]) : (A->m_rowinx[p]); + + // Traverse from i to k + int inext; + for ( ; i != -1 && i < k; i = inext) { + inext = ancestor[i]; // inext = ancestor of i + ancestor[i] = k; // path compression + if (inext == -1) parent[i] = k; // no ancestor, parent is k + } + if (ata) prev[A->m_rowinx[p]] = k; + } + } + + // Free workspace + delete [] wrk_int; + + // Return result + return (parent); + +} + + +/*************************************************************************** + * cs_fkeep * + * ----------------------------------------------------------------------- * + * Drop entries for which fkeep(A(i,j)) is false. Return the number of * + * non-zero elements if ok, otherwise return -1. * + * ----------------------------------------------------------------------- * + * Input: A Sparse matrix * + * fkeep Screening function * + * other Other function * + * Output: result 0..n-1 if ok, -1 in case of error * + ***************************************************************************/ +int GSparseSymbolic::cs_fkeep(GSparseMatrix* A, int(*fkeep)(int, int, double, void*), + void* other) +{ + // Return error if some of the input pointers is invalid + if (!A || !fkeep) return (-1); + + // Declare + int j, p, nz = 0; + + // Assign matrix attributes + int n = A->m_cols; + int* Ap = A->m_colstart; + int* Ai = A->m_rowinx; + double* Ax = A->m_data; + + // Loop over all columns + for (j = 0; j < n; j++) { + p = Ap[j]; // get current location of col j + Ap[j] = nz; // record new location of col j + for ( ; p < Ap[j+1] ; p++) { + if (fkeep(Ai[p], j, Ax ? Ax[p] : 1, other)) { + if (Ax) Ax[nz] = Ax[p]; // keep A(i,j) + Ai[nz++] = Ai[p] ; + } + } + } + + // Finalise A + Ap[n] = nz; + + // Remove extra space from A +// cs_sprealloc (A, 0) ; /* remove extra space from A */ + + // Return number of non-zero elements + return (nz) ; +} + + +/*************************************************************************** + * cs_leaf * + * ----------------------------------------------------------------------- * + * Consider A(i,j), node j in ith row subtree and return lca(jprev,j) * + * ----------------------------------------------------------------------- * + * Input: i row to consider * + * j column to consider * + * first[0..n-1] ... * + * maxfirst[0..n-1] ... * + * prevleaf[0..n-1] ... * + * ancestor[0..n-1] ... * + * Output: q ... * + * jleaf ... * + ***************************************************************************/ +int GSparseSymbolic::cs_leaf(int i, int j, const int *first, int *maxfirst, + int *prevleaf, int *ancestor, int *jleaf) +{ + // If one of the input pointers is invalid then return -1 + if (!first || !maxfirst || !prevleaf || !ancestor || !jleaf) return (-1); + + // Declare loop variables + int q, s, sparent; + + // ... + *jleaf = 0 ; + + // If j is not a leaf then return -1 + if (i <= j || first[j] <= maxfirst[i]) return (-1); + + // Update max first[j] seen so far + maxfirst[i] = first[j]; + + // jprev = previous leaf of ith subtree + int jprev = prevleaf[i]; + prevleaf[i] = j; + + // j is first or subsequent leaf + *jleaf = (jprev == -1) ? 1: 2; + + // If j is 1st leaf then q is the root of ith subtree + if (*jleaf == 1) return (i); + + // ... + for (q = jprev; q != ancestor[q]; q = ancestor[q]) ; + + // ... + for (s = jprev; s != q; s = sparent) { + sparent = ancestor[s]; // path compression + ancestor[s] = q; + } + + // Return least common ancester (jprev,j) + return (q); +} + + +/*************************************************************************** + * cs_pinv * + * ----------------------------------------------------------------------- * + * Inverts the permutation p[0..n-1] * + * ----------------------------------------------------------------------- * + * Input: p[0..n-1] integer array of n elements (NULL denotres ID) * + * Output: pinv[0..n-1] pinv[0..n-1] = p[n-1..0] * + ***************************************************************************/ +int* GSparseSymbolic::cs_pinv(int const *p, int n) +{ + // Return NULL pointer if input pointer is NULL. This denotes identity + if (!p || n < 1) return (NULL); + + // Allocate result array + int* pinv = new int[n]; + if (pinv == NULL) + throw mem_alloc("GSparseSymbolic::cs_pinv", n); + + // Invert the permutation + for (int k = 0; k < n; ++k) + pinv[p[k]] = k; + + // Return result + return (pinv); +} + + +/*************************************************************************** + * cs_post * + * ----------------------------------------------------------------------- * + * Post order a forest * + * ----------------------------------------------------------------------- * + * Input: parent[0..n-1] integer array of n elements * + * Output: post[0..n-1] ... * + ***************************************************************************/ +int* GSparseSymbolic::cs_post(const int* parent, int n) +{ + // Return NULL pointer if input pointer is NULL + if (!parent || n < 1) return (NULL); + + // Allocate result array + int* post = new int[n]; + if (post == NULL) + throw mem_alloc("GSparseSymbolic::cs_post(const int*, int)", n); + + // Allocate workspace + int wrk_size = 3 * n; + int* wrk_int = new int[wrk_size]; + if (wrk_int == NULL) + throw mem_alloc("GSparseSymbolic::cs_post(const int*, int)", wrk_size); + + // Set-up pointers to workspace + int* head = wrk_int; + int* next = wrk_int + n; + int* stack = wrk_int + 2*n; // Working array for 'cs_tdfs' function + + // Declare and initialise loop variables + int j, k = 0; + + // Empty linked list + for (j = 0 ; j < n ; j++) head[j] = -1; + + // Traverse nodes in reverse order to build a linked list 'head' + for (j = n-1; j >= 0; j--) { + + // Skip if j is a root + if (parent[j] == -1) continue; + + // Add j to list of its parent + next[j] = head[parent[j]]; + head[parent[j]] = j; + } + + // Traverse nodes + for (j = 0 ; j < n ; j++) { + + // Skip if j is not a root + if (parent[j] != -1) continue; + + // Depth-first search and postorder of a tree rooted at node j + k = cs_tdfs(j, k, head, next, post, stack); + } + + // Free workspace + delete [] wrk_int; + + // Return result + return (post); + +} + + +/*************************************************************************** + * cs_symperm * + * ----------------------------------------------------------------------- * + * C = A(p,p) where A and C are symmetric the upper part stored. * + * pinv not p * + * ----------------------------------------------------------------------- * + * Input: A Sparse matrix * + * pinv pinv[0..n-1] * + * values =1 allocate memory for values (NOT USED) * + * Output: C Sparse matrix * + ***************************************************************************/ +GSparseMatrix GSparseSymbolic::cs_symperm(GSparseMatrix* A, const int* pinv, + int values) const +{ + // Declare loop variables + int i, j, p, q, i2, j2; + + // Assign matrix attributes + int n = A->m_cols; + int* Ap = A->m_colstart; + int* Ai = A->m_rowinx; + double* Ax = A->m_data; + + // Allocate result matrix + GSparseMatrix C(n, n, Ap[n]); + + // Allocate and initialise workspace + int wrk_size = n; + int* wrk_int = new int[wrk_size]; + if (wrk_int == NULL) + throw mem_alloc("GSparseSymbolic::cs_symperm(GSparseMatrix*, const int*, int", + wrk_size); + for (i = 0; i < wrk_size; ++i) + wrk_int[i] = 0; + + // Assign result matriix attributes + int* Cp = C.m_colstart; + int* Ci = C.m_rowinx; + double* Cx = C.m_data; + + // Count entries in each column of C + for (j = 0; j < n; j++) { + + // Column j of A is column j2 of C + j2 = pinv ? pinv[j] : j; + + // Loop over entries in column j + for (p = Ap[j]; p < Ap[j+1]; p++) { + i = Ai [p]; + if (i > j) continue; // skip lower triangular part of A + i2 = pinv ? pinv[i] : i; // row i of A is row i2 of C + wrk_int[CS_MAX(i2, j2)]++; // column count of C + } + } + + // Compute column pointers of C + cs_cumsum(Cp, wrk_int, n); + + // Loop over all columns of A + for (j = 0 ; j < n ; j++) { + + // Column j of A is column j2 of C + j2 = pinv ? pinv[j] : j; + + // Loop over entries in column j + for (p = Ap[j]; p < Ap[j+1]; p++) { + i = Ai [p] ; + if (i > j) continue; // skip lower triangular part of A + i2 = pinv ? pinv[i] : i; // row i of A is row i2 of C + Ci[q = wrk_int[CS_MAX(i2,j2)]++] = CS_MIN(i2,j2); + Cx[q] = Ax[p]; + } + } + + // Free workspace + delete [] wrk_int; + + // Return result + return (C); + +} + + +/*************************************************************************** + * cs_tdfs * + * ----------------------------------------------------------------------- * + * Depth-first search and postorder of a tree rooted at node j * + * ----------------------------------------------------------------------- * + * Input: j Node of tree root * + * k ... * + * head head[0..n-1] linked list (updated) * + * next next[0..n-1] linked list info * + * post post[0..n-1] array (updated) * + * stack stack[0..n-1] working array (updated) * + * Output: k Update of k * + ***************************************************************************/ +int GSparseSymbolic::cs_tdfs(int j, int k, int* head, const int* next, + int* post, int* stack) +{ + // Return -1 if one of the array pointers is NULL + if (!head || !next || !post || !stack) return (-1); + + // Decrare + int i, p; + + // Place j on the first position of the stack + stack[0] = j; + + // Loop while stack is not empty + int top = 0; + while (top >= 0) { + p = stack[top]; // p = top of stack + i = head[p]; // i = youngest child of p + if (i == -1) { + top--; // p has no unordered children left + post[k++] = p; // node p is the kth postordered node + } + else { + head[p] = next[i]; // remove i from children of p + stack[++top] = i; // start depth-first search on child node i + } + } + + // Return result + return (k) ; +} + + +/*========================================================================== + = = + = GSparseSymbolic static member functions = + = = + ==========================================================================*/ + +/*************************************************************************** + * init_ata * + * ----------------------------------------------------------------------- * + * Initialise A'A. * + * Note that the returned pointers 'head' and 'info' point into the * + * 'wrk_int' workspace array. * + * ----------------------------------------------------------------------- * + * Input: AT Sparse matrix A' * + * post ... * + * wrk_int Workspace * + * head pointer to head[0..n-1] linked list * + * next pointer to next[0..n-1] linked list info * + * Output: - - * + ***************************************************************************/ +void GSparseSymbolic::init_ata(GSparseMatrix* AT, const int* post, + int* wrk_int, int** head, int** next) +{ + // Declare loop variables + int i, k, p; + + // Assign matrix attributes + int m = AT->m_cols; + int n = AT->m_rows; + int* ATp = AT->m_colstart; + int* ATi = AT->m_rowinx; + + // Set-up pointers to workspace + *head = wrk_int + 4*n; + *next = wrk_int + 5*n+1; + + // Invert post + for (k = 0 ; k < n ; k++) + wrk_int[post[k]] = k; + + // Loop over columns of AT matrix + for (i = 0 ; i < m ; i++) { + + // Loop over elements in column i of AT matrix + for (k = n, p = ATp[i]; p < ATp[i+1]; p++) + k = CS_MIN(k,wrk_int[ATi[p]]); + + // Place row i in linked list k + (*next)[i] = (*head)[k]; + (*head)[k] = i; + } +} + + +/*************************************************************************** + * cs_diag * + * ----------------------------------------------------------------------- * + * Keep off-diagonal entries and drop diagonal entries. * + * ----------------------------------------------------------------------- * + * Input: i Row index * + * j Column index * + * aij NOT USED * + * other NOT USED * + * Output: diag 0: off-diagonal, 1: diagonal element * + ***************************************************************************/ +int GSparseSymbolic::cs_diag(int i, int j, double aij, void* other) +{ + return (i != j); +} + + +/*************************************************************************** + * cs_wclear * + * ----------------------------------------------------------------------- * + * Clear w array * + * ----------------------------------------------------------------------- * + * Input: mark ... * + * lemax ... * + * w w[0..n-1] working array * + * n Size of the working array * + * Output: mark Update of mark * + * w Cleared w[0..n-1] working array * + ***************************************************************************/ +int GSparseSymbolic::cs_wclear(int mark, int lemax, int* w, int n) +{ + // Declare loop variables + int k; + + // ... + if (mark < 2 || (mark + lemax < 0)) { + for (k = 0; k < n; k++) if (w[k] != 0) w[k] = 1; + mark = 2; + } + + // Return mark. At this point, w[0..n-1] < mark holds + return (mark); +} + + +/*========================================================================== + = = + = GSparseSymbolic friends = + = = + ==========================================================================*/ + +/*************************************************************************** + * Output operator * + ***************************************************************************/ +ostream& operator<< (ostream& os, const GSparseSymbolic& s) +{ + // Put header is stream + os << "=== GSparseSymbolic ==="; + + // Show inverse permutation if it exists + if (s.m_pinv != NULL) { + os << endl << " Inverse permutation (of " << s.m_n_pinv << " elements)" << + endl; + for (int i = 0; i < s.m_n_pinv; ++i) + os << " " << s.m_pinv[i]; + } + + // Show fill reducing column permutation if it exists + if (s.m_q != NULL) { + os << endl << " Fill reducing column permutation (" << s.m_n_cp << + " elements)" << endl; + for (int i = 0; i < s.m_n_cp; ++i) + os << " " << s.m_q[i]; + } + + // Show elimination tree for Cholesky and QR if it exists + if (s.m_parent != NULL) { + os << endl << " Elimination tree (" << s.m_n_parent << " elements)" << + endl; + for (int i = 0; i < s.m_n_parent; ++i) + os << " " << s.m_parent[i]; + } + + // Show column pointers for Cholesky row counts for QR if it exists + if (s.m_cp != NULL) { + os << endl << " Cholesky column pointers/QR row counts (" << s.m_n_cp << + " elements)" << endl; + for (int i = 0; i < s.m_n_cp; ++i) + os << " " << s.m_cp[i]; + } + + // Show leftmost[i] = min(find(A(i,:))) if it exists + if (s.m_leftmost != NULL) { + os << endl << " leftmost[i] = min(find(A(i,:))) (" << s.m_n_leftmost << + " elements)" << endl; + for (int i = 0; i < s.m_n_leftmost; ++i) + os << " " << s.m_leftmost[i]; + } + + // Return output stream + return os; +} + + +/*========================================================================== + = = + = GSparseSymbolic exception classes = + = = + ==========================================================================*/ + +/*************************************************************************** + * Invalid ordering scheme requested * + ***************************************************************************/ +GSparseSymbolic::invalid_order::invalid_order(string origin, int order, + int min_order, int max_order) +{ + m_origin = origin; + ostringstream s_order; + ostringstream s_min_order; + ostringstream s_max_order; + s_order << order; + s_min_order << min_order; + s_max_order << max_order; + m_message = "Invalid ordering type " + s_order.str() + + "requested; must be comprised in [" + s_min_order.str() + + "," + s_max_order.str() + "]"; +} diff --git a/src/GSparseSymbolic.hpp b/src/GSparseSymbolic.hpp new file mode 100644 index 0000000..d83e9c2 --- /dev/null +++ b/src/GSparseSymbolic.hpp @@ -0,0 +1,113 @@ +/*************************************************************************** + * GSparseSymbolic.hpp - sparse matrix symbolic analysis class * + * ----------------------------------------------------------------------- * + * copyright : (C) 2006 by Jurgen Knodlseder * + * ----------------------------------------------------------------------- * + * * + * 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 2 of the License, or * + * (at your option) any later version. * + * * + ***************************************************************************/ + +#ifndef GSPARSESYMBOLIC_HPP +#define GSPARSESYMBOLIC_HPP + +/* __ Includes ___________________________________________________________ */ +#include "GException.hpp" +#include "GVector.hpp" +#include "GMatrix.hpp" +#include "GSparseMatrix.hpp" + +/* __ Namespaces _________________________________________________________ */ +using namespace std; + +/* __ Definitions ________________________________________________________ */ + +/* __ Enumerators ________________________________________________________ */ + +/* __ Structures _________________________________________________________ */ + +/* __ Prototypes _________________________________________________________ */ + + +/*************************************************************************** + * GSparseSymbolic class definition * + ***************************************************************************/ +class GSparseSymbolic { + // Friend classes + friend class GSparseMatrix; + friend class GSparseNumeric; + + // Binary operator friends + + // I/O friends + friend ostream& operator<< (ostream& os, const GSparseSymbolic& s); + + // Friend functions + +public: + // Constructors and destructors + GSparseSymbolic(); +// GSparseSymbolic(const GSparseSymbolic& s) { cout << "would sym to" << endl;} + ~GSparseSymbolic(); + + // Assignment operator + GSparseSymbolic& operator= (const GSparseSymbolic& s); + + // Binary operators + + // Unary operators + + // Functions + void cholesky_symbolic_analysis(int order, GSparseMatrix& m); + + // Exception: Invalid ordering scheme + class invalid_order : public GException { + public: + invalid_order(string origin, int order, int min_order, int max_order); + }; + +private: + // Functions + int* cs_amd (int order, GSparseMatrix* A); + int* cs_counts(GSparseMatrix* A, const int* parent, const int* post, int ata); + int* cs_etree(GSparseMatrix* A, int ata); + int cs_fkeep(GSparseMatrix* A, int(*fkeep)(int, int, double, void*), void* other); + int cs_leaf(int i, int j, const int* first, int* maxfirst, int* prevleaf, int* ancestor, int* jleaf); + int* cs_pinv(int const* p, int n); + int* cs_post(const int* parent, int n); + GSparseMatrix cs_symperm(GSparseMatrix* A, const int* pinv, int values) const; + int cs_tdfs(int j, int k, int* head, const int* next, int* post, int* stack); + static void init_ata(GSparseMatrix* AT, const int* post, int* wrk_int, int** head, int** next); + static int cs_diag(int i, int j, double aij, void* other); + static int cs_wclear(int mark, int lemax, int* w, int n); + + // Data + int* m_pinv; // Inverse row permutation for QR, fill reduce permutation for Cholesky + int* m_q; // Fill-reducing column permutation for LU and QR + int* m_parent; // elimination tree for Cholesky and QR + int* m_cp; // column pointers for Cholesky, row counts for QR + int* m_leftmost; // leftmost[i] = min(find(A(i,:))), for QR + int m_m2; // # of rows for QR, after adding fictitious rows + double m_lnz; // # entries in L for LU or Cholesky; in V for QR + double m_unz; // # entries in U for LU; in R for QR + int m_n_pinv; // Number of elements in m_pinv + int m_n_q; // Number of elements in m_q + int m_n_parent; // Number of elements in m_parent + int m_n_cp; // Number of elements in m_cp + int m_n_leftmost; // Number of elements in m_leftmost +}; + + +/*************************************************************************** + * Inline members * + ***************************************************************************/ + + +/*************************************************************************** + * Inline friends * + ***************************************************************************/ + +#endif /* GSPARSESYMBOLIC_HPP */ diff --git a/src/GSymMatrix.cpp b/src/GSymMatrix.cpp index 63b7d90..d3e6727 100644 --- a/src/GSymMatrix.cpp +++ b/src/GSymMatrix.cpp @@ -18,26 +18,34 @@ using namespace std; +/*========================================================================== + = = + = GSymMatrix constructors/destructors = + = = + ==========================================================================*/ + /*************************************************************************** - * GSymMatrix constructor * + * GSymMatrix constructor * ***************************************************************************/ -GSymMatrix::GSymMatrix(unsigned rows, unsigned cols) : GMatrix() +GSymMatrix::GSymMatrix(int rows, int cols) : GMatrix() { // Initialise private members for clean destruction - m_rows = 0; - m_cols = 0; - m_elements = 0; - m_num_inx = 0; - m_data = NULL; - m_colstart = NULL; - m_inx = NULL; + m_rows = 0; + m_cols = 0; + m_elements = 0; + m_num_rowsel = 0; + m_num_colsel = 0; + m_data = NULL; + m_colstart = NULL; + m_rowsel = NULL; + m_colsel = NULL; // Throw exception if number of rows and columns is not identical if (rows != cols) - throw not_sym("GSymMatrix constructor", rows, cols); + throw matrix_not_symmetric("GSymMatrix constructor", rows, cols); // Determine number of physical elements in matrix - unsigned elements = rows*(rows+1)/2; + int elements = rows*(rows+1)/2; // Throw exception if requested matrix size is zero if (elements == 0) @@ -46,8 +54,8 @@ GSymMatrix::GSymMatrix(unsigned rows, unsigned cols) : GMatrix() // Allocate matrix array and column start index array. Throw an exception // if allocation failed m_data = new double[elements]; - m_colstart = new unsigned[cols+1]; - m_inx = new unsigned[cols]; + m_colstart = new int[cols+1]; + m_inx = new int[cols]; if (m_data == NULL || m_colstart == NULL || m_inx == NULL) throw mem_alloc("GSymMatrix constructor", elements); @@ -58,13 +66,16 @@ GSymMatrix::GSymMatrix(unsigned rows, unsigned cols) : GMatrix() // Set-up column start indices m_colstart[0] = 0; - unsigned offset = rows; - for (unsigned col = 1; col <= m_cols; ++col) + int offset = rows; + for (int col = 1; col <= m_cols; ++col) m_colstart[col] = m_colstart[col-1] + offset--; // Initialise matrix elements to 0.0 - for (unsigned i = 0; i < m_elements; ++i) + for (int i = 0; i < m_elements; ++i) m_data[i] = 0.0; + + // Return + return; } @@ -75,12 +86,16 @@ GSymMatrix::GSymMatrix(unsigned rows, unsigned cols) : GMatrix() ***************************************************************************/ GSymMatrix::GSymMatrix(const GSymMatrix& m) : GMatrix(m) { + // Copy members m_num_inx = m.m_num_inx; - m_inx = new unsigned[m_cols]; + m_inx = new int[m_cols]; if (m_inx == NULL) throw mem_alloc("GSymMatrix copy constructor", m_cols); - for (unsigned i = 0; i < m_cols; ++i) + for (int i = 0; i < m_cols; ++i) m_inx[i] = m.m_inx[i]; + + // Return + return; } @@ -92,46 +107,259 @@ GSymMatrix::GSymMatrix(const GSymMatrix& m) : GMatrix(m) GSymMatrix::~GSymMatrix() { // De-allocate only if memory has indeed been allocated by derived class - if (m_inx != NULL) delete[] m_inx; + if (m_inx != NULL) delete [] m_inx; + + // Return + return; } +/*========================================================================== + = = + = GSymMatrix operators = + = = + ==========================================================================*/ + /*************************************************************************** * GSymMatrix assignment operator * ***************************************************************************/ GSymMatrix& GSymMatrix::operator= (const GSymMatrix& m) { + // Execute only if object is not identical if (this != &m) { + + // Invoque base class assignment operator this->GMatrix::operator=(m); + + // De-allocate memory if it has indeed been allocated + if (m_inx != NULL) delete [] m_inx; + + // Copy data members m_num_inx = m.m_num_inx; - m_inx = new unsigned[m_cols]; + + // Allocate memory for indices and copy them + m_inx = new int[m_cols]; if (m_inx == NULL) throw mem_alloc("GSymMatrix assignment operator", m_cols); - for (unsigned i = 0; i < m_cols; ++i) + for (int i = 0; i < m_cols; ++i) m_inx[i] = m.m_inx[i]; } + + // Return this object + return *this; } /*************************************************************************** - * GSymMatrix * GSymMatrix multiplication * + * Vector multiplication * ***************************************************************************/ -GSymMatrix GSymMatrix::operator* (const GSymMatrix& m) const +GVector GSymMatrix::operator* (const GVector& v) const +{ + // Raise an exception if the matrix and vector dimensions are not compatible + if (m_cols != v.m_num) + throw matrix_vector_mismatch("GSymMatrix::operator* (const GVector&)", + v.m_num, m_rows, m_cols); + + // Perform vector multiplication + GVector result(m_rows); + for (int row = 0; row < m_rows; ++row) { + double sum = 0.0; + for (int col = 0; col < m_cols; ++col) + sum += (*this)(row,col) * v(col); + result(row) = sum; + } + + // Return result + return result; +} + + +/*************************************************************************** + * GSymMatrix negation (unary minus operator) * + ***************************************************************************/ +GSymMatrix GSymMatrix::operator- ( ) const +{ + // Copy argument into result + GSymMatrix result = *this; + + // Negate result + for (int i = 0; i < m_elements; ++i) + result.m_data[i] = -result.m_data[i]; + + // Return result + return result; +} + + +/*************************************************************************** + * Matrix multiplication (unary multiplication operator) * + * ----------------------------------------------------------------------- * + * Symmetric matrices must have the same dimensions to be multiplied. * + ***************************************************************************/ +GSymMatrix& GSymMatrix::operator*= (const GSymMatrix& m) { // Raise an exception if the matrix dimensions are not compatible - if (m_cols != m.m_rows) - throw GMatrix::dim_mult_mismatch("GSymMatrix multiplication", m_cols, m.m_rows); + if (m_cols != m.m_rows || m_rows != m.m_cols) + throw matrix_mismatch("GSymMatrix::operator*= (const GSymMatrix&)", + m_rows, m_cols, m.m_rows, m.m_cols); - // Perform matrix multiplication - GSymMatrix result(m_rows,m.m_cols); - for (unsigned row = 0; row < m_rows; ++row) { - for (unsigned col = 0; col < m.m_cols; ++col) { + // Allocate result matrix + GSymMatrix result(m_rows, m.m_cols); + + // Loop over all elements of result matrix + for (int row = 0; row < m_rows; ++row) { + for (int col = 0; col < m.m_cols; ++col) { double sum = 0.0; - for (unsigned i = 0; i < m_cols; ++i) - sum += (*this)(row,i)*m(i,col); - result(row,col) = sum; - } + for (int i = 0; i < m_cols; ++i) + sum += (*this)(row,i) * m(i,col); + result(row,col) = sum; + } + } + + // Assign result + *this = result; + + // Return result + return *this; +} + + +/*========================================================================== + = = + = GSymMatrix member functions = + = = + ==========================================================================*/ + +/*************************************************************************** + * Sum matrix elements * + ***************************************************************************/ +double GSymMatrix::sum() const +{ + // Initialise matrix sums (diagonal and off-diagonal) + double diag = 0.0; + double off_diag = 0.0; + + // Calulate sum over diagonal elements + for (int row = 0; row < m_rows; ++row) + diag += m_data[m_colstart[row]]; + + // Calulate sum over off-diagonal elements + for (int row = 0; row < m_rows; ++row) { + for (int col = row+1; col < m_cols; ++col) + off_diag += m_data[m_colstart[row]+(col-row)]; + } + + // Calculate total + double result = diag + 2.0 * off_diag; + + // Return result + return result; +} + + +/*************************************************************************** + * Extract row from matrix into vector * + ***************************************************************************/ +GVector GSymMatrix::extract_row(int row) const +{ + // Raise an exception if the row index is invalid + #if defined(G_RANGE_CHECK) + if (row >= m_rows) + throw out_of_range("GSymMatrix::extract_row(int)", + row, 0, m_rows, m_cols); + #endif + + // Create result vector + GVector result(m_cols); + + // Extract row into vector + for (int col = 0; col < m_cols; ++col) + result(col) = (*this)(row,col); + + // Return vector + return result; + +} + + +/*************************************************************************** + * Extract column from matrix into vector * + ***************************************************************************/ +GVector GSymMatrix::extract_col(int col) const +{ + // Raise an exception if the column index is invalid + #if defined(G_RANGE_CHECK) + if (col >= m_cols) + throw out_of_range("GSymMatrix::extract_col(int)", + 0, col, m_rows, m_cols); + #endif + + // Create result vector + GVector result(m_rows); + + // Extract column into vector + for (int row = 0; row < m_rows; ++row) + result(row) = (*this)(row,col); + + // Return vector + return result; + +} + + +/*************************************************************************** + * Convert symmetric matrix into full matrix * + ***************************************************************************/ +GMatrix GSymMatrix::convert_to_full() const +{ + // Define result matrix + GMatrix result(m_rows, m_cols); + + // Extract all elements + for (int row = 0; row < m_rows; ++row) { + for (int col = 0; col < m_cols; ++col) + result(row,col) = (*this)(row,col); } + + // Return result + return result; +} + + +/*************************************************************************** + * Extract lower triangle of symmetric matrix into full matrix * + ***************************************************************************/ +GMatrix GSymMatrix::extract_lower_triangle() const +{ + // Define result matrix + GMatrix result(m_rows, m_cols); + + // Extract all elements + for (int row = 0; row < m_rows; ++row) { + for (int col = 0; col <= row; ++col) + result(row,col) = m_data[m_colstart[col]+(row-col)]; + } + + // Return result + return result; +} + + +/*************************************************************************** + * Extract upper triangle of symmetric matrix into full matrix * + ***************************************************************************/ +GMatrix GSymMatrix::extract_upper_triangle() const +{ + // Define result matrix + GMatrix result(m_rows, m_cols); + + // Extract all elements + for (int row = 0; row < m_rows; ++row) { + for (int col = row; col < m_cols; ++col) + result(row,col) = m_data[m_colstart[row]+(col-row)]; + } + + // Return result return result; } @@ -159,18 +387,19 @@ void GSymMatrix::cholesky_decompose(int compress) if (no_zeros) { // Loop over upper triangle (col >= row) - for (unsigned row = 0; row < m_rows; ++row) { + for (int row = 0; row < m_rows; ++row) { double* ptr = m_data + m_colstart[row]; - for (unsigned col = row; col < m_cols; ++col, ++ptr) { + for (int col = row; col < m_cols; ++col, ++ptr) { double sum = *ptr; // sum = M(row,col) - for (unsigned k = 0; k < row; ++k) { - unsigned offset = m_colstart[k] - k; // is always positive + for (int k = 0; k < row; ++k) { + int offset = m_colstart[k] - k; // is always positive sum -= m_data[offset+row] * m_data[offset+col]; // sum -= M(row,k)*M(col,k) } double diag; if (row == col) { if (sum <= 0.0) - throw not_pos_definite("GSymMatrix cholesky_decompose", row, sum); + throw matrix_not_pos_definite("GSymMatrix::cholesky_decompose(int)", + row, sum); *ptr = sqrt(sum); // M(row,row) = sqrt(sum) diag = 1.0/(*ptr); } @@ -184,12 +413,12 @@ void GSymMatrix::cholesky_decompose(int compress) else if (m_num_inx > 0) { // Allocate loop variables and pointers - unsigned row; - unsigned col; - unsigned k; - unsigned* row_ptr; - unsigned* col_ptr; - unsigned* k_ptr; + int row; + int col; + int k; + int* row_ptr; + int* col_ptr; + int* k_ptr; // Loop over upper triangle (col >= row) for (row = 0, row_ptr = m_inx; row < m_num_inx; ++row, ++row_ptr) { @@ -198,13 +427,14 @@ void GSymMatrix::cholesky_decompose(int compress) double* ptr = ptr_0 + *col_ptr; double sum = *ptr; // sum = M(row,col) for (k = 0, k_ptr = m_inx; k < row; ++k, ++k_ptr) { - unsigned offset = m_colstart[*k_ptr] - *k_ptr; // is always positive + int offset = m_colstart[*k_ptr] - *k_ptr; // is always positive sum -= m_data[offset+*row_ptr] * m_data[offset+*col_ptr]; // sum -= M(row,k)*M(col,k) } double diag; if (*row_ptr == *col_ptr) { if (sum <= 0.0) - throw not_pos_definite("GSymMatrix cholesky_decompose", *row_ptr, sum); + throw matrix_not_pos_definite("GSymMatrix::cholesky_decompose(int)", + *row_ptr, sum); *ptr = sqrt(sum); // M(row,row) = sqrt(sum) diag = 1.0/(*ptr); } @@ -216,7 +446,7 @@ void GSymMatrix::cholesky_decompose(int compress) // Case C: all matrix elements are zero else - throw all_zero("GSymMatrix cholesky_decompose"); + throw matrix_zero("GSymMatrix::cholesky_decompose(int)"); } @@ -231,6 +461,12 @@ void GSymMatrix::cholesky_decompose(int compress) ***************************************************************************/ GVector GSymMatrix::cholesky_solver(const GVector& v, int compress) { + // Raise an exception if the matrix and vector dimensions are not compatible + if (m_rows != v.m_num) + throw matrix_vector_mismatch( + "GSymMatrix::cholesky_solver(const GVector&, int)", + v.m_num, m_rows, m_cols); + // Allocate result vector GVector x(m_rows); @@ -241,9 +477,9 @@ GVector GSymMatrix::cholesky_solver(const GVector& v, int compress) if (no_zeros) { // Solve L*y=b, storing y in x (row>k) - for (unsigned row = 0; row < m_rows; ++row) { + for (int row = 0; row < m_rows; ++row) { double sum = v(row); - for (unsigned k = 0; k < row; ++k) + for (int k = 0; k < row; ++k) sum -= m_data[m_colstart[k]+(row-k)] * x(k); // sum -= M(row,k) * x(k) x(row) = sum/m_data[m_colstart[row]]; // x(row) = sum/M(row,row) } @@ -252,7 +488,7 @@ GVector GSymMatrix::cholesky_solver(const GVector& v, int compress) for (int row = m_rows-1; row >= 0; --row) { double sum = x(row); double* ptr = m_data + m_colstart[row] + 1; - for (unsigned k = row+1; k < m_rows; ++k) + for (int k = row+1; k < m_rows; ++k) sum -= *ptr++ * x(k); // sum -= M(k,row) * x(k) x(row) = sum/m_data[m_colstart[row]]; // x(row) = sum/M(row,row) } @@ -263,9 +499,9 @@ GVector GSymMatrix::cholesky_solver(const GVector& v, int compress) // Allocate loop variables and pointers int row; - unsigned k; - unsigned* row_ptr; - unsigned* k_ptr; + int k; + int* row_ptr; + int* k_ptr; // Solve L*y=b, storing y in x (row>k) for (row = 0, row_ptr = m_inx; row < m_num_inx; ++row, ++row_ptr) { @@ -289,7 +525,7 @@ GVector GSymMatrix::cholesky_solver(const GVector& v, int compress) // Case C: all matrix elements are zero else - throw all_zero("GSymMatrix cholesky_solver"); + throw matrix_zero("GSymMatrix::cholesky_solver(const GVector&, int)"); // Return result vector return x; @@ -315,27 +551,27 @@ void GSymMatrix::cholesky_invert(int compress) if (no_zeros) { // Generate inverse of Cholesky decomposition (col>row) - for (unsigned row = 0; row < m_rows; ++row) { + for (int row = 0; row < m_rows; ++row) { double* ptr = m_data + m_colstart[row]; *ptr = 1.0/(*ptr); // M(row,row) = 1/M(row,row) - for (unsigned col = row+1; col < m_cols; ++col) { + for (int col = row+1; col < m_cols; ++col) { double sum = 0.0; double* ptr1 = m_data + col - row; double* ptr2 = ptr; - for (unsigned k = row; k < col; ++k) + for (int k = row; k < col; ++k) sum -= *(ptr1-- + m_colstart[k]) * *ptr2++; // sum -= M(col,k)*M(k,row) *(ptr+col-row) = sum/m_data[m_colstart[col]]; // M(col,row) = sum/M(col,col) } } // Matrix multiplication (col>=row) - for (unsigned row = 0; row < m_rows; ++row) { + for (int row = 0; row < m_rows; ++row) { double* ptr = m_data + m_colstart[row]; - for (unsigned col = row; col < m_cols; ++col) { + for (int col = row; col < m_cols; ++col) { double sum = 0.0; double* ptr1 = ptr + col - row; double* ptr2 = m_data + m_colstart[col]; - for (unsigned k = col; k < m_cols; ++k) + for (int k = col; k < m_cols; ++k) sum += *ptr1++ * *ptr2++; // sum += M(row,k)*M(k,col) *(ptr+col-row) = sum; // M(row,col) = sum } @@ -346,12 +582,12 @@ void GSymMatrix::cholesky_invert(int compress) else if (m_num_inx > 0) { // Allocate loop variables and pointers - unsigned row; - unsigned col; - unsigned k; - unsigned* row_ptr; - unsigned* col_ptr; - unsigned* k_ptr; + int row; + int col; + int k; + int* row_ptr; + int* col_ptr; + int* k_ptr; // Generate inverse of Cholesky decomposition (col>row) for (row = 0, row_ptr = m_inx; row < m_num_inx; ++row, ++row_ptr) { @@ -384,11 +620,17 @@ void GSymMatrix::cholesky_invert(int compress) // Case C: all matrix elements are zero else - throw all_zero("GSymMatrix cholesky_invert"); + throw matrix_zero("GSymMatrix::cholesky_invert(int)"); } +/*========================================================================== + = = + = GSymMatrix private functions = + = = + ==========================================================================*/ + /*************************************************************************** * GSymMatrix set_inx * * ----------------------------------------------------------------------- * @@ -399,8 +641,8 @@ void GSymMatrix::cholesky_invert(int compress) void GSymMatrix::set_inx(void) { // Allocate loop variables and pointers - unsigned row; - unsigned col; + int row; + int col; // Find all nonzero rows/cols m_num_inx = 0; @@ -430,37 +672,31 @@ void GSymMatrix::set_inx(void) } +/*========================================================================== + = = + = GSymMatrix friends = + = = + ==========================================================================*/ + /*************************************************************************** - * Class exception handlers * + * Matrix absolute values * ***************************************************************************/ -// Matrix not symmetric -GSymMatrix::not_sym::not_sym(string origin, unsigned cols, unsigned rows) +GSymMatrix fabs(const GSymMatrix& m) { - m_origin = origin; - ostringstream s_rows; - ostringstream s_cols; - s_rows << rows; - s_cols << cols; - m_message = "Matrix is not symmetric [" + s_rows.str() + "," + - s_cols.str() + "]"; + // Define result matrix + GSymMatrix result(m.m_rows,m.m_cols); + + // Convert all elements to absolute values + for (int i = 0; i < m.m_elements; ++i) + result.m_data[i] = fabs(m.m_data[i]); + + // Return result + return result; } -// Matrix not positive definite -GSymMatrix::not_pos_definite::not_pos_definite(string origin, unsigned row, - double sum) -{ - m_origin = origin; - ostringstream s_rows; - ostringstream s_sum; - s_rows << row; - s_sum << scientific << sum; - m_message = "Matrix is not positive definite (sum " + s_sum.str() + - " occured in row " + s_rows.str() + ")"; -} -// All matrix elements are zero -GSymMatrix::all_zero::all_zero(string origin) -{ - m_origin = origin; - m_message = "All matrix elements are zero"; -} +/*========================================================================== + = = + = GSymMatrix exception classes = + = = + ==========================================================================*/ diff --git a/src/GSymMatrix.hpp b/src/GSymMatrix.hpp index a47375d..8fcd5ad 100644 --- a/src/GSymMatrix.hpp +++ b/src/GSymMatrix.hpp @@ -33,113 +33,106 @@ using namespace std; * GSymMatrix class definition * ***************************************************************************/ class GSymMatrix : public GMatrix { - // Operator friends - friend GSymMatrix operator+ (const double& a, const GSymMatrix& b); - friend GSymMatrix operator- (const double& a, const GSymMatrix& b); - friend GSymMatrix operator* (const double& a, const GSymMatrix& b); + // Binary operator friends + friend GSymMatrix operator* (const double& a, const GSymMatrix& b); + friend GSymMatrix operator* (const GSymMatrix& a, const double& b); + friend GSymMatrix operator/ (const GSymMatrix& a, const double& b); // I/O friends - // ... - + // USE_BASE: friend ostream& operator<< (ostream& os, const GSymMatrix& m); + // Friend functions friend GSymMatrix transpose(const GSymMatrix& m); friend GSymMatrix fabs(const GSymMatrix& m); friend GSymMatrix cholesky_decompose(const GSymMatrix& m, int compress = 1); friend GSymMatrix cholesky_invert(const GSymMatrix& m, int compress = 1); - friend GMatrix full(const GSymMatrix& m); - friend GMatrix lower_triangle(const GSymMatrix& m); - friend GMatrix upper_triangle(const GSymMatrix& m); + public: // Constructors and destructors (not inherited) - GSymMatrix(unsigned rows, unsigned cols); + GSymMatrix(int rows, int cols); GSymMatrix(const GSymMatrix& m); - ~GSymMatrix(); + virtual ~GSymMatrix(); // Matrix element access operators - double& operator() (unsigned row, unsigned col); - const double& operator() (unsigned row, unsigned col) const; + virtual double& operator() (int row, int col); + virtual const double& operator() (int row, int col) const; // Matrix assignment operators (not inherited) - GSymMatrix& operator= (const GSymMatrix& m); - GSymMatrix& operator= (const double& d); - - // Specific matrix operators (structure dependent) - GSymMatrix operator+ (const GSymMatrix& m) const; - GSymMatrix operator- (const GSymMatrix& m) const; - GSymMatrix operator* (const GSymMatrix& m) const; - GVector operator* (const GVector& v) const; - GSymMatrix operator+ (const double& d) const; - GSymMatrix operator- (const double& d) const; - GSymMatrix operator* (const double& d) const; - GSymMatrix operator/ (const double& d) const; - GSymMatrix operator- () const; - - // Specific matrix functions - void transpose(); // Inplace transpose of matrix - void cholesky_decompose(int compress = 1); // Inplace Cholesky decomposition - GVector cholesky_solver(const GVector& v, int compress = 1); // Cholesky solver - void cholesky_invert(int compress = 1); // Inplace Cholesky matrix inverter - - // Exception: Matrix not symmetric - class not_sym : public GException { - public: - not_sym(string origin, unsigned cols, unsigned rows); - }; + virtual GSymMatrix& operator= (const GSymMatrix& m); - // Exception: Matrix not positive definite - class not_pos_definite : public GException { - public: - not_pos_definite(string origin, unsigned row, double sum); - }; + // Binary operators + virtual GSymMatrix operator+ (const GSymMatrix& m) const; + virtual GSymMatrix operator- (const GSymMatrix& m) const; + virtual GSymMatrix operator* (const GSymMatrix& m) const; + virtual GVector operator* (const GVector& v) const; + // USE_BASE: virtual int operator== (const GSymMatrix& m) const; + // USE_BASE: virtual int operator!= (const GSymMatrix& m) const; + // Unary operators + GSymMatrix operator- () const; + // USE_BASE: virtual GSymMatrix& operator+= (const GSymMatrix& m); + // USE_BASE: virtual GSymMatrix& operator-= (const GSymMatrix& m); + virtual GSymMatrix& operator*= (const GSymMatrix& m); + virtual GSymMatrix& operator*= (const double& d); + virtual GSymMatrix& operator/= (const double& d); + + // Matrix functions + // USE_BASE: virtual int rows() const { return m_rows; } + // USE_BASE: virtual int cols() const { return m_cols; } + // USE_BASE: virtual double min() const; + // USE_BASE: virtual double max() const; + virtual double sum() const; + virtual void transpose() { return; } + virtual GVector extract_row(int row) const; + virtual GVector extract_col(int col) const; + virtual GMatrix convert_to_full() const; + virtual GMatrix extract_lower_triangle() const; + virtual GMatrix extract_upper_triangle() const; + virtual void cholesky_decompose(int compress = 1); + virtual GVector cholesky_solver(const GVector& v, int compress = 1); + virtual void cholesky_invert(int compress = 1); + // Exception: All matrix elements are zero class all_zero : public GException { public: all_zero(string origin); }; + private: - void set_inx(void); // Set indices of non-zero rows/columns - unsigned m_num_inx; // Number of non-zero rows/columns - unsigned* m_inx; // Indices of non-zero rows/columns + void set_inx(void); // Set indices of non-zero rows/columns + int m_num_inx; // Number of non-zero rows/columns + int* m_inx; // Indices of non-zero rows/columns }; /*************************************************************************** - * Inline members that override base class members * + * Inline member functions * ***************************************************************************/ -// Scalar assignment operator: GSymMatrix = double +// Matrix element access operator inline -GSymMatrix& GSymMatrix::operator= (const double& d) -{ - this->GMatrix::operator=(d); - return *this; -} - -// Matrix element access operator: GSymMatrix(row,col) -inline -double& GSymMatrix::operator() (unsigned row, unsigned col) +double& GSymMatrix::operator() (int row, int col) { #if defined(G_RANGE_CHECK) if (row >= m_rows || col >= m_cols) throw out_of_range("GSymMatrix access", row, col, m_rows, m_cols); #endif - unsigned inx = (row >= col) ? m_colstart[col]+(row-col) : m_colstart[row]+(col-row); + int inx = (row >= col) ? m_colstart[col]+(row-col) : m_colstart[row]+(col-row); return m_data[inx]; } -// Matrix element access operator (const version): GSymMatrix(row,col) +// Matrix element access operator (const version) inline -const double& GSymMatrix::operator() (unsigned row, unsigned col) const +const double& GSymMatrix::operator() (int row, int col) const { #if defined(G_RANGE_CHECK) if (row >= m_rows || col >= m_cols) throw out_of_range("GSymMatrix access", row, col, m_rows, m_cols); #endif - unsigned inx = (row >= col) ? m_colstart[col]+(row-col) : m_colstart[row]+(col-row); + int inx = (row >= col) ? m_colstart[col]+(row-col) : m_colstart[row]+(col-row); return m_data[inx]; } -// Matrix addition: GSymMatrix + GSymMatrix +// Binary matrix addition inline GSymMatrix GSymMatrix::operator+ (const GSymMatrix& m) const { @@ -148,7 +141,7 @@ GSymMatrix GSymMatrix::operator+ (const GSymMatrix& m) const return result; } -// Matrix subtraction: GSymMatrix - GSymMatrix +// Binary matrix subtraction inline GSymMatrix GSymMatrix::operator- (const GSymMatrix& m) const { @@ -157,116 +150,68 @@ GSymMatrix GSymMatrix::operator- (const GSymMatrix& m) const return result; } -// Matrix/Vector multiplication: GSymMatrix * GVector +// Binary matrix multiplication inline -GVector GSymMatrix::operator* (const GVector& v) const -{ - return (this->GMatrix::operator*(v)); -} - -// Matrix scaling: GSymMatrix + double -inline -GSymMatrix GSymMatrix::operator+ (const double& d) const +GSymMatrix GSymMatrix::operator* (const GSymMatrix& m) const { - GSymMatrix result = (*this); - result += d; - return result; -} - -// Matrix scaling: GSymMatrix - double -inline -GSymMatrix GSymMatrix::operator- (const double& d) const -{ - GSymMatrix result = (*this); - result -= d; - return result; -} - -// Matrix scaling: GSymMatrix * double -inline -GSymMatrix GSymMatrix::operator* (const double& d) const -{ - GSymMatrix result = (*this); - result *= d; - return result; -} - -// Matrix inverse scaling: GSymMatrix * double -inline -GSymMatrix GSymMatrix::operator/ (const double& d) const -{ - GSymMatrix result = (*this); - result /= d; + GSymMatrix result = *this; + result *= m; return result; } -// Unary minus operator +// Unary scalar multiplication inline -GSymMatrix GSymMatrix::operator- ( ) const +GSymMatrix& GSymMatrix::operator*= (const double& d) { - GSymMatrix result = *this; - for (unsigned i = 0; i < m_elements; ++i) - result.m_data[i] = -result.m_data[i]; - return result; + this->GMatrix::operator*=(d); } -// Matrix transpose +// Unary scalar division inline -void GSymMatrix::transpose() +GSymMatrix& GSymMatrix::operator/= (const double& d) { - return; + this->GMatrix::operator/=(d); } - /*************************************************************************** * Inline friends * ***************************************************************************/ -// Matrix addition: double + GSymMatrix -inline -GSymMatrix operator+ (const double& a, const GSymMatrix& b) +// Binary matrix scaling (matrix is left operand) +inline +GSymMatrix operator* (const GSymMatrix& a, const double& b) { - GSymMatrix result = b; - result += a; + GSymMatrix result = a; + result *= b; return result; } -// Matrix subtracxtion: double * GSymMatrix +// Binary matrix scaling (matrix is right operand) inline -GSymMatrix operator- (const double& a, const GSymMatrix& b) +GSymMatrix operator* (const double& a, const GSymMatrix& b) { GSymMatrix result = b; - result -= a; + result *= a; return result; } -// Matrix scaling: double * GSymMatrix -inline -GSymMatrix operator* (const double& a, const GSymMatrix& b) +// Binary matrix division (matrix is left operand) +inline +GSymMatrix operator/ (const GSymMatrix& a, const double& b) { - GSymMatrix result = b; - result *= a; + GSymMatrix result = a; + result /= b; return result; } -// Matrix transpose: transpose(GSymMatrix) +// Matrix transpose function inline GSymMatrix transpose(const GSymMatrix& m) { return m; } -// Matrix absolute: fabs(GSymMatrix) -inline -GSymMatrix fabs(const GSymMatrix& m) -{ - GSymMatrix result = m; - for (unsigned i = 0; i < result.m_elements; ++i) - result.m_data[i] = fabs(result.m_data[i]); - return result; -} - -// Cholesky decomposition: cholesky_decompose(GSymMatrix) +// Cholesky decomposition inline GSymMatrix cholesky_decompose(const GSymMatrix& m, int compress) { @@ -275,7 +220,7 @@ GSymMatrix cholesky_decompose(const GSymMatrix& m, int compress) return result; } -// Inversion using Cholesky decomposition: cholesky_invert(GSymMatrix) +// Matrix inversion using Cholesky decomposition inline GSymMatrix cholesky_invert(const GSymMatrix& m, int compress) { @@ -284,40 +229,4 @@ GSymMatrix cholesky_invert(const GSymMatrix& m, int compress) return result; } -// Convert symmetric matrix into full matrix: full(GSymMatrix) -inline -GMatrix full(const GSymMatrix& m) -{ - GMatrix result(m.m_rows,m.m_cols); - for (unsigned row = 0; row < m.m_rows; ++row) { - for (unsigned col = 0; col < m.m_cols; ++col) - result(row,col) = m(row,col); - } - return result; -} - -// Convert symmetric matrix into lower triangle full matrix: lower_triangle(GSymMatrix) -inline -GMatrix lower_triangle(const GSymMatrix& m) -{ - GMatrix result(m.m_rows,m.m_cols); - for (unsigned row = 0; row < m.m_rows; ++row) { - for (unsigned col = 0; col <= row; ++col) - result(row,col) = m.m_data[m.m_colstart[col]+(row-col)]; - } - return result; -} - -// Convert symmetric matrix into upper triangle full matrix: lower_triangle(GSymMatrix) -inline -GMatrix upper_triangle(const GSymMatrix& m) -{ - GMatrix result(m.m_rows,m.m_cols); - for (unsigned row = 0; row < m.m_rows; ++row) { - for (unsigned col = row; col < m.m_cols; ++col) - result(row,col) = m.m_data[m.m_colstart[row]+(col-row)]; - } - return result; -} - #endif /* GSYMMATRIX_HPP */ diff --git a/src/GVector.cpp b/src/GVector.cpp index d073b1f..5d574b3 100644 --- a/src/GVector.cpp +++ b/src/GVector.cpp @@ -15,10 +15,16 @@ #include "GVector.hpp" +/*========================================================================== + = = + = GVector constructors/destructors = + = = + ==========================================================================*/ + /*************************************************************************** * GVector constructor * ***************************************************************************/ -GVector::GVector(unsigned num) +GVector::GVector(int num) { // Throw exception if requested vector length is zero if (num == 0) @@ -31,8 +37,11 @@ GVector::GVector(unsigned num) // Store vector size and initialize elements to 0.0 m_num = num; - for (unsigned i = 0; i < m_num; ++i) + for (int i = 0; i < m_num; ++i) m_data[i] = 0.0; + + // Return + return; } @@ -46,15 +55,42 @@ GVector::~GVector() m_num = 0; delete[] m_data; } + + // Return + return; } +/*========================================================================== + = = + = GVector operators = + = = + ==========================================================================*/ + +/*========================================================================== + = = + = GVector member functions = + = = + ==========================================================================*/ + +/*========================================================================== + = = + = GVector private functions = + = = + ==========================================================================*/ + +/*========================================================================== + = = + = GVector friends = + = = + ==========================================================================*/ + /*************************************************************************** * GVector output operator * ***************************************************************************/ ostream& operator<< (ostream& os, const GVector& v) { - for (unsigned i = 0; i < v.m_num; ++i) { + for (int i = 0; i < v.m_num; ++i) { os << v(i); if (i != v.m_num-1) os << ", "; @@ -80,12 +116,17 @@ GVector cross(const GVector &a, const GVector &b) } +/*========================================================================== + = = + = GSparseMatrix exception classes = + = = + ==========================================================================*/ + /*************************************************************************** * Class exception handlers * ***************************************************************************/ // Vector index out of range -GVector::out_of_range::out_of_range(string origin, unsigned inx, - unsigned elements) +GVector::out_of_range::out_of_range(string origin, int inx, int elements) { m_origin = origin; if (elements > 0) { @@ -102,8 +143,7 @@ GVector::out_of_range::out_of_range(string origin, unsigned inx, } // Vector dimensions differ -GVector::dim_mismatch::dim_mismatch(string origin, unsigned size1, - unsigned size2) +GVector::dim_mismatch::dim_mismatch(string origin, int size1, int size2) { m_origin = origin; ostringstream s_size1; @@ -115,7 +155,7 @@ GVector::dim_mismatch::dim_mismatch(string origin, unsigned size1, } // Invalid vector dimension for cross product -GVector::bad_cross_dim::bad_cross_dim(unsigned elements) +GVector::bad_cross_dim::bad_cross_dim(int elements) { ostringstream s_elements; s_elements << elements; diff --git a/src/GVector.hpp b/src/GVector.hpp index c770b21..c95bc90 100644 --- a/src/GVector.hpp +++ b/src/GVector.hpp @@ -36,7 +36,8 @@ using namespace std; class GVector { // Friend classes friend class GMatrix; - friend class GMatrixSym; + friend class GSymMatrix; + friend class GSparseMatrix; // Operator friends friend GVector operator+ (const GVector &a, const GVector &b); @@ -61,6 +62,8 @@ class GVector { friend double min(const GVector &v); friend double max(const GVector &v); friend double sum(const GVector &v); + friend GVector perm(const GVector &v, const int *p); + friend GVector iperm(const GVector &v, const int *p); friend GVector acos(const GVector &v); friend GVector acosh(const GVector &v); friend GVector asin(const GVector &v); @@ -81,13 +84,13 @@ class GVector { public: // Constructors and destructors - explicit GVector(unsigned num); + explicit GVector(int num); GVector(const GVector& v); ~GVector(); // Vector element access operators - double& operator() (unsigned inx); - const double& operator() (unsigned inx) const; + double& operator() (int inx); + const double& operator() (int inx) const; // Vector operators GVector& operator= (const GVector& v); @@ -101,28 +104,28 @@ public: GVector operator- () const; // Vector functions - unsigned size() const; // Return dimension of vector + int size() const; // Return dimension of vector // Exception: Vector index out of range class out_of_range : public GException { public: - out_of_range(string origin, unsigned inx, unsigned elements); + out_of_range(string origin, int inx, int elements); }; // Exception: Vector dimensions mismatch class dim_mismatch : public GException { public: - dim_mismatch(string origin, unsigned size1, unsigned size2); + dim_mismatch(string origin, int size1, int size2); }; // Exception: Invalid vector dimension for cross product class bad_cross_dim : public GException { public: - bad_cross_dim(unsigned elements); + bad_cross_dim(int elements); }; private: - unsigned m_num; - double* m_data; + int m_num; + double* m_data; }; @@ -138,13 +141,13 @@ GVector::GVector(const GVector& v) if (m_data == NULL) throw mem_alloc("GVector copy constructor", v.m_num); m_num = v.m_num; - for (unsigned i = 0; i < m_num; ++i) + for (int i = 0; i < m_num; ++i) m_data[i] = v.m_data[i]; } // Vector element access operator inline -double& GVector::operator() (unsigned inx) +double& GVector::operator() (int inx) { #if defined(G_RANGE_CHECK) if (inx >= m_num) @@ -155,7 +158,7 @@ double& GVector::operator() (unsigned inx) // Vector element access operator (const version) inline -const double& GVector::operator() (unsigned inx) const +const double& GVector::operator() (int inx) const { #if defined(G_RANGE_CHECK) if (inx >= m_num) @@ -168,12 +171,15 @@ const double& GVector::operator() (unsigned inx) const inline GVector& GVector::operator= (const GVector& v) { - m_data = new double[v.m_num]; - if (m_data == NULL) - throw mem_alloc("GVector assignment operator", v.m_num); - m_num = v.m_num; - for (unsigned i = 0; i < m_num; ++i) - m_data[i] = v.m_data[i]; + if (this != &v) { + if (m_data != NULL) delete [] m_data; + m_data = new double[v.m_num]; + if (m_data == NULL) + throw mem_alloc("GVector assignment operator", v.m_num); + m_num = v.m_num; + for (int i = 0; i < m_num; ++i) + m_data[i] = v.m_data[i]; + } return *this; } @@ -183,7 +189,7 @@ GVector& GVector::operator+= (const GVector& v) { if (m_num != v.m_num) throw dim_mismatch("GVector += operator", m_num, v.m_num); - for (unsigned i = 0; i < m_num; ++i) + for (int i = 0; i < m_num; ++i) m_data[i] += v.m_data[i]; return *this; } @@ -194,7 +200,7 @@ GVector& GVector::operator-= (const GVector& v) { if (m_num != v.m_num) throw dim_mismatch("GVector -= operator", m_num, v.m_num); - for (unsigned i = 0; i < m_num; ++i) + for (int i = 0; i < m_num; ++i) m_data[i] -= v.m_data[i]; return *this; } @@ -203,7 +209,7 @@ GVector& GVector::operator-= (const GVector& v) inline GVector& GVector::operator= (const double& v) { - for (unsigned i = 0; i < m_num; ++i) + for (int i = 0; i < m_num; ++i) m_data[i] = v; return *this; } @@ -212,7 +218,7 @@ GVector& GVector::operator= (const double& v) inline GVector& GVector::operator+= (const double& v) { - for (unsigned i = 0; i < m_num; ++i) + for (int i = 0; i < m_num; ++i) m_data[i] += v; return *this; } @@ -221,7 +227,7 @@ GVector& GVector::operator+= (const double& v) inline GVector& GVector::operator-= (const double& v) { - for (unsigned i = 0; i < m_num; ++i) + for (int i = 0; i < m_num; ++i) m_data[i] -= v; return *this; } @@ -230,7 +236,7 @@ GVector& GVector::operator-= (const double& v) inline GVector& GVector::operator*= (const double& v) { - for (unsigned i = 0; i < m_num; ++i) + for (int i = 0; i < m_num; ++i) m_data[i] *= v; return *this; } @@ -239,7 +245,7 @@ GVector& GVector::operator*= (const double& v) inline GVector& GVector::operator/= (const double& v) { - for (unsigned i = 0; i < m_num; ++i) + for (int i = 0; i < m_num; ++i) m_data[i] /= v; return *this; } @@ -249,14 +255,14 @@ inline GVector GVector::operator- ( ) const { GVector result = *this; - for (unsigned i = 0; i < m_num; ++i) + for (int i = 0; i < m_num; ++i) result.m_data[i] = -result.m_data[i]; return result; } // Return size of vector inline -unsigned GVector::size() const +int GVector::size() const { return m_num; } @@ -326,7 +332,7 @@ double operator* (const GVector& a, const GVector& b) if (a.m_num != b.m_num) throw GVector::dim_mismatch("GVector scalar product", a.m_num, b.m_num); double result = 0.0; - for (unsigned i = 0; i < a.m_num; ++i) + for (int i = 0; i < a.m_num; ++i) result += (a.m_data[i] * b.m_data[i]); return result; } @@ -363,7 +369,7 @@ inline double norm(const GVector &v) { double result = 0.0; - for (unsigned i = 0; i < v.m_num; ++i) + for (int i = 0; i < v.m_num; ++i) result += (v.m_data[i] * v.m_data[i]); result = (result > 0.0) ? sqrt(result) : 0.0; return result; @@ -374,7 +380,7 @@ inline double min(const GVector &v) { double result = v.m_data[0]; - for (unsigned i = 1; i < v.m_num; ++i) { + for (int i = 1; i < v.m_num; ++i) { if (v.m_data[i] < result) result = v.m_data[i]; } @@ -386,7 +392,7 @@ inline double max(const GVector &v) { double result = v.m_data[0]; - for (unsigned i = 1; i < v.m_num; ++i) { + for (int i = 1; i < v.m_num; ++i) { if (v.m_data[i] > result) result = v.m_data[i]; } @@ -398,17 +404,45 @@ inline double sum(const GVector &v) { double result = 0.0; - for (unsigned i = 0; i < v.m_num; ++i) + for (int i = 0; i < v.m_num; ++i) result += v.m_data[i]; return result; } +// Vector permutation +inline +GVector perm(const GVector &v, const int *p) +{ + GVector result(v.m_num); + if (p == NULL) + result = v; + else { + for (int i = 0; i < v.m_num; ++i) + result.m_data[i] = v.m_data[p[i]]; + } + return result; +} + +// Inverse vector permutation +inline +GVector iperm(const GVector &v, const int *p) +{ + GVector result(v.m_num); + if (p == NULL) + result = v; + else { + for (int i = 0; i < v.m_num; ++i) + result.m_data[p[i]] = v.m_data[i]; + } + return result; +} + // Vector acos inline GVector acos(const GVector &v) { GVector result(v.m_num); - for (unsigned i = 0; i < v.m_num; ++i) + for (int i = 0; i < v.m_num; ++i) result.m_data[i] = acos(v.m_data[i]); return result; } @@ -418,7 +452,7 @@ inline GVector acosh(const GVector &v) { GVector result(v.m_num); - for (unsigned i = 0; i < v.m_num; ++i) + for (int i = 0; i < v.m_num; ++i) result.m_data[i] = acosh(v.m_data[i]); return result; } @@ -428,7 +462,7 @@ inline GVector asin(const GVector &v) { GVector result(v.m_num); - for (unsigned i = 0; i < v.m_num; ++i) + for (int i = 0; i < v.m_num; ++i) result.m_data[i] = asin(v.m_data[i]); return result; } @@ -438,7 +472,7 @@ inline GVector asinh(const GVector &v) { GVector result(v.m_num); - for (unsigned i = 0; i < v.m_num; ++i) + for (int i = 0; i < v.m_num; ++i) result.m_data[i] = asinh(v.m_data[i]); return result; } @@ -448,7 +482,7 @@ inline GVector atan(const GVector &v) { GVector result(v.m_num); - for (unsigned i = 0; i < v.m_num; ++i) + for (int i = 0; i < v.m_num; ++i) result.m_data[i] = atan(v.m_data[i]); return result; } @@ -458,7 +492,7 @@ inline GVector atanh(const GVector &v) { GVector result(v.m_num); - for (unsigned i = 0; i < v.m_num; ++i) + for (int i = 0; i < v.m_num; ++i) result.m_data[i] = atanh(v.m_data[i]); return result; } @@ -468,7 +502,7 @@ inline GVector cos(const GVector &v) { GVector result(v.m_num); - for (unsigned i = 0; i < v.m_num; ++i) + for (int i = 0; i < v.m_num; ++i) result.m_data[i] = cos(v.m_data[i]); return result; } @@ -478,7 +512,7 @@ inline GVector cosh(const GVector &v) { GVector result(v.m_num); - for (unsigned i = 0; i < v.m_num; ++i) + for (int i = 0; i < v.m_num; ++i) result.m_data[i] = cosh(v.m_data[i]); return result; } @@ -488,7 +522,7 @@ inline GVector exp(const GVector &v) { GVector result(v.m_num); - for (unsigned i = 0; i < v.m_num; ++i) + for (int i = 0; i < v.m_num; ++i) result.m_data[i] = exp(v.m_data[i]); return result; } @@ -498,7 +532,7 @@ inline GVector fabs(const GVector &v) { GVector result(v.m_num); - for (unsigned i = 0; i < v.m_num; ++i) + for (int i = 0; i < v.m_num; ++i) result.m_data[i] = fabs(v.m_data[i]); return result; } @@ -508,7 +542,7 @@ inline GVector log(const GVector &v) { GVector result(v.m_num); - for (unsigned i = 0; i < v.m_num; ++i) + for (int i = 0; i < v.m_num; ++i) result.m_data[i] = log(v.m_data[i]); return result; } @@ -518,7 +552,7 @@ inline GVector log10(const GVector &v) { GVector result(v.m_num); - for (unsigned i = 0; i < v.m_num; ++i) + for (int i = 0; i < v.m_num; ++i) result.m_data[i] = log10(v.m_data[i]); return result; } @@ -528,7 +562,7 @@ inline GVector sin(const GVector &v) { GVector result(v.m_num); - for (unsigned i = 0; i < v.m_num; ++i) + for (int i = 0; i < v.m_num; ++i) result.m_data[i] = sin(v.m_data[i]); return result; } @@ -538,7 +572,7 @@ inline GVector sinh(const GVector &v) { GVector result(v.m_num); - for (unsigned i = 0; i < v.m_num; ++i) + for (int i = 0; i < v.m_num; ++i) result.m_data[i] = sinh(v.m_data[i]); return result; } @@ -548,7 +582,7 @@ inline GVector sqrt(const GVector &v) { GVector result(v.m_num); - for (unsigned i = 0; i < v.m_num; ++i) + for (int i = 0; i < v.m_num; ++i) result.m_data[i] = sqrt(v.m_data[i]); return result; } @@ -558,7 +592,7 @@ inline GVector tan(const GVector &v) { GVector result(v.m_num); - for (unsigned i = 0; i < v.m_num; ++i) + for (int i = 0; i < v.m_num; ++i) result.m_data[i] = tan(v.m_data[i]); return result; } @@ -568,7 +602,7 @@ inline GVector tanh(const GVector &v) { GVector result(v.m_num); - for (unsigned i = 0; i < v.m_num; ++i) + for (int i = 0; i < v.m_num; ++i) result.m_data[i] = tanh(v.m_data[i]); return result; } @@ -579,7 +613,7 @@ int operator== (const GVector &a, const GVector &b) { int result = 1; if (a.m_num == b.m_num) { - for (unsigned i = 0; i < a.m_num; ++i) { + for (int i = 0; i < a.m_num; ++i) { if (a.m_data[i] != b.m_data[i]) { result = 0; break; @@ -597,7 +631,7 @@ int operator!= (const GVector &a, const GVector &b) { int result = 0; if (a.m_num == b.m_num) { - for (unsigned i = 0; i < a.m_num; ++i) { + for (int i = 0; i < a.m_num; ++i) { if (a.m_data[i] != b.m_data[i]) { result = 1; break; diff --git a/src/Makefile.am b/src/Makefile.am index a928862..20481c0 100644 --- a/src/Makefile.am +++ b/src/Makefile.am @@ -3,7 +3,10 @@ files = GException.hpp GException.cpp \ GVector.hpp GVector.cpp \ GMatrix.hpp GMatrix.cpp \ - GSymMatrix.hpp GSymMatrix.cpp + GSymMatrix.hpp GSymMatrix.cpp \ + GSparseMatrix.hpp GSparseMatrix.cpp \ + GSparseSymbolic.hpp GSparseSymbolic.cpp \ + GSparseNumeric.hpp GSparseNumeric.cpp lib_LTLIBRARIES = libgamma.la libgamma_la_SOURCES = $(files) diff --git a/src/Makefile.in b/src/Makefile.in index 20dbd3d..5188229 100644 --- a/src/Makefile.in +++ b/src/Makefile.in @@ -1,8 +1,8 @@ -# Makefile.in generated by automake 1.6.3 from Makefile.am. +# Makefile.in generated by automake 1.9.2 from Makefile.am. # @configure_input@ -# Copyright 1994, 1995, 1996, 1997, 1998, 1999, 2000, 2001, 2002 -# Free Software Foundation, Inc. +# Copyright (C) 1994, 1995, 1996, 1997, 1998, 1999, 2000, 2001, 2002, +# 2003, 2004 Free Software Foundation, Inc. # This Makefile.in is free software; the Free Software Foundation # gives unlimited permission to copy and/or distribute it, # with or without modifications, as long as this notice is preserved. @@ -13,168 +13,234 @@ # PARTICULAR PURPOSE. @SET_MAKE@ -SHELL = @SHELL@ + +SOURCES = $(libgamma_la_SOURCES) srcdir = @srcdir@ top_srcdir = @top_srcdir@ VPATH = @srcdir@ -prefix = @prefix@ -exec_prefix = @exec_prefix@ - -bindir = @bindir@ -sbindir = @sbindir@ -libexecdir = @libexecdir@ -datadir = @datadir@ -sysconfdir = @sysconfdir@ -sharedstatedir = @sharedstatedir@ -localstatedir = @localstatedir@ -libdir = @libdir@ -infodir = @infodir@ -mandir = @mandir@ -includedir = @includedir@ -oldincludedir = /usr/include pkgdatadir = $(datadir)/@PACKAGE@ pkglibdir = $(libdir)/@PACKAGE@ pkgincludedir = $(includedir)/@PACKAGE@ top_builddir = .. - -ACLOCAL = @ACLOCAL@ -AUTOCONF = @AUTOCONF@ -AUTOMAKE = @AUTOMAKE@ -AUTOHEADER = @AUTOHEADER@ - am__cd = CDPATH="$${ZSH_VERSION+.}$(PATH_SEPARATOR)" && cd INSTALL = @INSTALL@ -INSTALL_PROGRAM = @INSTALL_PROGRAM@ -INSTALL_DATA = @INSTALL_DATA@ install_sh_DATA = $(install_sh) -c -m 644 install_sh_PROGRAM = $(install_sh) -c install_sh_SCRIPT = $(install_sh) -c -INSTALL_SCRIPT = @INSTALL_SCRIPT@ INSTALL_HEADER = $(INSTALL_DATA) -transform = @program_transform_name@ +transform = $(program_transform_name) NORMAL_INSTALL = : PRE_INSTALL = : POST_INSTALL = : NORMAL_UNINSTALL = : PRE_UNINSTALL = : POST_UNINSTALL = : -host_alias = @host_alias@ +build_triplet = @build@ host_triplet = @host@ - -EXEEXT = @EXEEXT@ -OBJEXT = @OBJEXT@ -PATH_SEPARATOR = @PATH_SEPARATOR@ +subdir = src +DIST_COMMON = $(srcdir)/Makefile.am $(srcdir)/Makefile.in +ACLOCAL_M4 = $(top_srcdir)/aclocal.m4 +am__aclocal_m4_deps = $(top_srcdir)/configure.ac +am__configure_deps = $(am__aclocal_m4_deps) $(CONFIGURE_DEPENDENCIES) \ + $(ACLOCAL_M4) +mkinstalldirs = $(install_sh) -d +CONFIG_HEADER = $(top_builddir)/config.h +CONFIG_CLEAN_FILES = +am__vpath_adj_setup = srcdirstrip=`echo "$(srcdir)" | sed 's|.|.|g'`; +am__vpath_adj = case $$p in \ + $(srcdir)/*) f=`echo "$$p" | sed "s|^$$srcdirstrip/||"`;; \ + *) f=$$p;; \ + esac; +am__strip_dir = `echo $$p | sed -e 's|^.*/||'`; +am__installdirs = "$(DESTDIR)$(libdir)" +libLTLIBRARIES_INSTALL = $(INSTALL) +LTLIBRARIES = $(lib_LTLIBRARIES) +libgamma_la_LIBADD = +am__objects_1 = GException.lo GVector.lo GMatrix.lo GSymMatrix.lo \ + GSparseMatrix.lo GSparseSymbolic.lo GSparseNumeric.lo +am_libgamma_la_OBJECTS = $(am__objects_1) +libgamma_la_OBJECTS = $(am_libgamma_la_OBJECTS) +DEFAULT_INCLUDES = -I. -I$(srcdir) -I$(top_builddir) +depcomp = +am__depfiles_maybe = +CXXCOMPILE = $(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) \ + $(AM_CPPFLAGS) $(CPPFLAGS) $(AM_CXXFLAGS) $(CXXFLAGS) +LTCXXCOMPILE = $(LIBTOOL) --mode=compile --tag=CXX $(CXX) $(DEFS) \ + $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) \ + $(AM_CXXFLAGS) $(CXXFLAGS) +CXXLD = $(CXX) +CXXLINK = $(LIBTOOL) --mode=link --tag=CXX $(CXXLD) $(AM_CXXFLAGS) \ + $(CXXFLAGS) $(AM_LDFLAGS) $(LDFLAGS) -o $@ +COMPILE = $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) \ + $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) +LTCOMPILE = $(LIBTOOL) --mode=compile --tag=CC $(CC) $(DEFS) \ + $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) \ + $(AM_CFLAGS) $(CFLAGS) +CCLD = $(CC) +LINK = $(LIBTOOL) --mode=link --tag=CC $(CCLD) $(AM_CFLAGS) $(CFLAGS) \ + $(AM_LDFLAGS) $(LDFLAGS) -o $@ +SOURCES = $(libgamma_la_SOURCES) +DIST_SOURCES = $(libgamma_la_SOURCES) +ETAGS = etags +CTAGS = ctags +DISTFILES = $(DIST_COMMON) $(DIST_SOURCES) $(TEXINFOS) $(EXTRA_DIST) +ACLOCAL = @ACLOCAL@ AMTAR = @AMTAR@ AR = @AR@ -AS = @AS@ +AUTOCONF = @AUTOCONF@ +AUTOHEADER = @AUTOHEADER@ +AUTOMAKE = @AUTOMAKE@ AWK = @AWK@ CC = @CC@ +CFLAGS = @CFLAGS@ +CPP = @CPP@ +CPPFLAGS = @CPPFLAGS@ CXX = @CXX@ CXXCPP = @CXXCPP@ -DEPDIR = @DEPDIR@ -DLLTOOL = @DLLTOOL@ +CXXFLAGS = @CXXFLAGS@ +CYGPATH_W = @CYGPATH_W@ +DEFS = @DEFS@ ECHO = @ECHO@ +ECHO_C = @ECHO_C@ +ECHO_N = @ECHO_N@ +ECHO_T = @ECHO_T@ EGREP = @EGREP@ +EXEEXT = @EXEEXT@ F77 = @F77@ -GCJ = @GCJ@ -GCJFLAGS = @GCJFLAGS@ +FFLAGS = @FFLAGS@ +INSTALL_DATA = @INSTALL_DATA@ +INSTALL_PROGRAM = @INSTALL_PROGRAM@ +INSTALL_SCRIPT = @INSTALL_SCRIPT@ INSTALL_STRIP_PROGRAM = @INSTALL_STRIP_PROGRAM@ +LDFLAGS = @LDFLAGS@ +LIBOBJS = @LIBOBJS@ +LIBS = @LIBS@ LIBTOOL = @LIBTOOL@ +LIBTOOL_DEPS = @LIBTOOL_DEPS@ LN_S = @LN_S@ +LTLIBOBJS = @LTLIBOBJS@ MAINT = @MAINT@ -OBJDUMP = @OBJDUMP@ +MAINTAINER_MODE_FALSE = @MAINTAINER_MODE_FALSE@ +MAINTAINER_MODE_TRUE = @MAINTAINER_MODE_TRUE@ +MAKEINFO = @MAKEINFO@ +OBJEXT = @OBJEXT@ PACKAGE = @PACKAGE@ +PACKAGE_BUGREPORT = @PACKAGE_BUGREPORT@ +PACKAGE_NAME = @PACKAGE_NAME@ +PACKAGE_STRING = @PACKAGE_STRING@ +PACKAGE_TARNAME = @PACKAGE_TARNAME@ +PACKAGE_VERSION = @PACKAGE_VERSION@ +PATH_SEPARATOR = @PATH_SEPARATOR@ RANLIB = @RANLIB@ -RC = @RC@ +SET_MAKE = @SET_MAKE@ +SHELL = @SHELL@ STRIP = @STRIP@ VERSION = @VERSION@ -am__include = @am__include@ -am__quote = @am__quote@ +ac_ct_AR = @ac_ct_AR@ +ac_ct_CC = @ac_ct_CC@ +ac_ct_CXX = @ac_ct_CXX@ +ac_ct_F77 = @ac_ct_F77@ +ac_ct_RANLIB = @ac_ct_RANLIB@ +ac_ct_STRIP = @ac_ct_STRIP@ +am__leading_dot = @am__leading_dot@ +am__tar = @am__tar@ +am__untar = @am__untar@ +bindir = @bindir@ +build = @build@ +build_alias = @build_alias@ +build_cpu = @build_cpu@ +build_os = @build_os@ +build_vendor = @build_vendor@ +datadir = @datadir@ +exec_prefix = @exec_prefix@ +host = @host@ +host_alias = @host_alias@ +host_cpu = @host_cpu@ +host_os = @host_os@ +host_vendor = @host_vendor@ +includedir = @includedir@ +infodir = @infodir@ install_sh = @install_sh@ - +libdir = @libdir@ +libexecdir = @libexecdir@ +localstatedir = @localstatedir@ +mandir = @mandir@ +mkdir_p = @mkdir_p@ +oldincludedir = @oldincludedir@ +prefix = @prefix@ +program_transform_name = @program_transform_name@ +sbindir = @sbindir@ +sharedstatedir = @sharedstatedir@ +sysconfdir = @sysconfdir@ +target_alias = @target_alias@ files = GException.hpp GException.cpp \ GVector.hpp GVector.cpp \ GMatrix.hpp GMatrix.cpp \ - GSymMatrix.hpp GSymMatrix.cpp - + GSymMatrix.hpp GSymMatrix.cpp \ + GSparseMatrix.hpp GSparseMatrix.cpp \ + GSparseSymbolic.hpp GSparseSymbolic.cpp \ + GSparseNumeric.hpp GSparseNumeric.cpp lib_LTLIBRARIES = libgamma.la libgamma_la_SOURCES = $(files) -subdir = src -mkinstalldirs = $(SHELL) $(top_srcdir)/mkinstalldirs -CONFIG_HEADER = $(top_builddir)/config.h -CONFIG_CLEAN_FILES = -LTLIBRARIES = $(lib_LTLIBRARIES) - -libgamma_la_LDFLAGS = -libgamma_la_LIBADD = -am__objects_1 = GException.lo GVector.lo GMatrix.lo GSymMatrix.lo -am_libgamma_la_OBJECTS = $(am__objects_1) -libgamma_la_OBJECTS = $(am_libgamma_la_OBJECTS) - -DEFS = @DEFS@ -DEFAULT_INCLUDES = -I. -I$(srcdir) -I$(top_builddir) -CPPFLAGS = @CPPFLAGS@ -LDFLAGS = @LDFLAGS@ -LIBS = @LIBS@ -depcomp = -am__depfiles_maybe = -CXXCOMPILE = $(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) \ - $(AM_CPPFLAGS) $(CPPFLAGS) $(AM_CXXFLAGS) $(CXXFLAGS) -LTCXXCOMPILE = $(LIBTOOL) --mode=compile $(CXX) $(DEFS) \ - $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) \ - $(AM_CXXFLAGS) $(CXXFLAGS) -CXXLD = $(CXX) -CXXLINK = $(LIBTOOL) --mode=link $(CXXLD) $(AM_CXXFLAGS) $(CXXFLAGS) \ - $(AM_LDFLAGS) $(LDFLAGS) -o $@ -CXXFLAGS = @CXXFLAGS@ -CFLAGS = @CFLAGS@ -COMPILE = $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) \ - $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -LTCOMPILE = $(LIBTOOL) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) \ - $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -CCLD = $(CC) -LINK = $(LIBTOOL) --mode=link $(CCLD) $(AM_CFLAGS) $(CFLAGS) \ - $(AM_LDFLAGS) $(LDFLAGS) -o $@ -DIST_SOURCES = $(libgamma_la_SOURCES) -DIST_COMMON = Makefile.am Makefile.in -SOURCES = $(libgamma_la_SOURCES) - all: all-am .SUFFIXES: .SUFFIXES: .cpp .lo .o .obj -$(srcdir)/Makefile.in: @MAINTAINER_MODE_TRUE@ Makefile.am $(top_srcdir)/configure.ac $(ACLOCAL_M4) +$(srcdir)/Makefile.in: @MAINTAINER_MODE_TRUE@ $(srcdir)/Makefile.am $(am__configure_deps) + @for dep in $?; do \ + case '$(am__configure_deps)' in \ + *$$dep*) \ + cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh \ + && exit 0; \ + exit 1;; \ + esac; \ + done; \ + echo ' cd $(top_srcdir) && $(AUTOMAKE) --gnu --ignore-deps src/Makefile'; \ cd $(top_srcdir) && \ - $(AUTOMAKE) --gnu src/Makefile -Makefile: @MAINTAINER_MODE_TRUE@ $(srcdir)/Makefile.in $(top_builddir)/config.status - cd $(top_builddir) && $(SHELL) ./config.status $(subdir)/$@ $(am__depfiles_maybe) -libLTLIBRARIES_INSTALL = $(INSTALL) + $(AUTOMAKE) --gnu --ignore-deps src/Makefile +.PRECIOUS: Makefile +Makefile: $(srcdir)/Makefile.in $(top_builddir)/config.status + @case '$?' in \ + *config.status*) \ + cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh;; \ + *) \ + echo ' cd $(top_builddir) && $(SHELL) ./config.status $(subdir)/$@ $(am__depfiles_maybe)'; \ + cd $(top_builddir) && $(SHELL) ./config.status $(subdir)/$@ $(am__depfiles_maybe);; \ + esac; + +$(top_builddir)/config.status: $(top_srcdir)/configure $(CONFIG_STATUS_DEPENDENCIES) + cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh + +$(top_srcdir)/configure: @MAINTAINER_MODE_TRUE@ $(am__configure_deps) + cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh +$(ACLOCAL_M4): @MAINTAINER_MODE_TRUE@ $(am__aclocal_m4_deps) + cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh install-libLTLIBRARIES: $(lib_LTLIBRARIES) @$(NORMAL_INSTALL) - $(mkinstalldirs) $(DESTDIR)$(libdir) + test -z "$(libdir)" || $(mkdir_p) "$(DESTDIR)$(libdir)" @list='$(lib_LTLIBRARIES)'; for p in $$list; do \ if test -f $$p; then \ - f="`echo $$p | sed -e 's|^.*/||'`"; \ - echo " $(LIBTOOL) --mode=install $(libLTLIBRARIES_INSTALL) $(INSTALL_STRIP_FLAG) $$p $(DESTDIR)$(libdir)/$$f"; \ - $(LIBTOOL) --mode=install $(libLTLIBRARIES_INSTALL) $(INSTALL_STRIP_FLAG) $$p $(DESTDIR)$(libdir)/$$f; \ + f=$(am__strip_dir) \ + echo " $(LIBTOOL) --mode=install $(libLTLIBRARIES_INSTALL) $(INSTALL_STRIP_FLAG) '$$p' '$(DESTDIR)$(libdir)/$$f'"; \ + $(LIBTOOL) --mode=install $(libLTLIBRARIES_INSTALL) $(INSTALL_STRIP_FLAG) "$$p" "$(DESTDIR)$(libdir)/$$f"; \ else :; fi; \ done uninstall-libLTLIBRARIES: @$(NORMAL_UNINSTALL) - @list='$(lib_LTLIBRARIES)'; for p in $$list; do \ - p="`echo $$p | sed -e 's|^.*/||'`"; \ - echo " $(LIBTOOL) --mode=uninstall rm -f $(DESTDIR)$(libdir)/$$p"; \ - $(LIBTOOL) --mode=uninstall rm -f $(DESTDIR)$(libdir)/$$p; \ + @set -x; list='$(lib_LTLIBRARIES)'; for p in $$list; do \ + p=$(am__strip_dir) \ + echo " $(LIBTOOL) --mode=uninstall rm -f '$(DESTDIR)$(libdir)/$$p'"; \ + $(LIBTOOL) --mode=uninstall rm -f "$(DESTDIR)$(libdir)/$$p"; \ done clean-libLTLIBRARIES: -test -z "$(lib_LTLIBRARIES)" || rm -f $(lib_LTLIBRARIES) @list='$(lib_LTLIBRARIES)'; for p in $$list; do \ dir="`echo $$p | sed -e 's|/[^/]*$$||'`"; \ - test -z "$dir" && dir=.; \ + test "$$dir" != "$$p" || dir=.; \ echo "rm -f \"$${dir}/so_locations\""; \ rm -f "$${dir}/so_locations"; \ done @@ -182,19 +248,19 @@ libgamma.la: $(libgamma_la_OBJECTS) $(libgamma_la_DEPENDENCIES) $(CXXLINK) -rpath $(libdir) $(libgamma_la_LDFLAGS) $(libgamma_la_OBJECTS) $(libgamma_la_LIBADD) $(LIBS) mostlyclean-compile: - -rm -f *.$(OBJEXT) core *.core + -rm -f *.$(OBJEXT) distclean-compile: -rm -f *.tab.c .cpp.o: - $(CXXCOMPILE) -c -o $@ `test -f '$<' || echo '$(srcdir)/'`$< + $(CXXCOMPILE) -c -o $@ $< .cpp.obj: - $(CXXCOMPILE) -c -o $@ `cygpath -w $<` + $(CXXCOMPILE) -c -o $@ `$(CYGPATH_W) '$<'` .cpp.lo: - $(LTCXXCOMPILE) -c -o $@ `test -f '$<' || echo '$(srcdir)/'`$< + $(LTCXXCOMPILE) -c -o $@ $< mostlyclean-libtool: -rm -f *.lo @@ -206,11 +272,6 @@ distclean-libtool: -rm -f libtool uninstall-info-am: -ETAGS = etags -ETAGSFLAGS = - -tags: TAGS - ID: $(HEADERS) $(SOURCES) $(LISP) $(TAGS_FILES) list='$(SOURCES) $(HEADERS) $(LISP) $(TAGS_FILES)'; \ unique=`for i in $$list; do \ @@ -219,6 +280,7 @@ ID: $(HEADERS) $(SOURCES) $(LISP) $(TAGS_FILES) $(AWK) ' { files[$$0] = 1; } \ END { for (i in files) print i; }'`; \ mkid -fID $$unique +tags: TAGS TAGS: $(HEADERS) $(SOURCES) $(TAGS_DEPENDENCIES) \ $(TAGS_FILES) $(LISP) @@ -230,8 +292,24 @@ TAGS: $(HEADERS) $(SOURCES) $(TAGS_DEPENDENCIES) \ done | \ $(AWK) ' { files[$$0] = 1; } \ END { for (i in files) print i; }'`; \ - test -z "$(ETAGS_ARGS)$$tags$$unique" \ - || $(ETAGS) $(ETAGSFLAGS) $(AM_ETAGSFLAGS) $(ETAGS_ARGS) \ + if test -z "$(ETAGS_ARGS)$$tags$$unique"; then :; else \ + test -n "$$unique" || unique=$$empty_fix; \ + $(ETAGS) $(ETAGSFLAGS) $(AM_ETAGSFLAGS) $(ETAGS_ARGS) \ + $$tags $$unique; \ + fi +ctags: CTAGS +CTAGS: $(HEADERS) $(SOURCES) $(TAGS_DEPENDENCIES) \ + $(TAGS_FILES) $(LISP) + tags=; \ + here=`pwd`; \ + list='$(SOURCES) $(HEADERS) $(LISP) $(TAGS_FILES)'; \ + unique=`for i in $$list; do \ + if test -f "$$i"; then echo $$i; else echo $(srcdir)/$$i; fi; \ + done | \ + $(AWK) ' { files[$$0] = 1; } \ + END { for (i in files) print i; }'`; \ + test -z "$(CTAGS_ARGS)$$tags$$unique" \ + || $(CTAGS) $(CTAGSFLAGS) $(AM_CTAGSFLAGS) $(CTAGS_ARGS) \ $$tags $$unique GTAGS: @@ -240,19 +318,21 @@ GTAGS: && gtags -i $(GTAGS_ARGS) $$here distclean-tags: - -rm -f TAGS ID GTAGS GRTAGS GSYMS GPATH -DISTFILES = $(DIST_COMMON) $(DIST_SOURCES) $(TEXINFOS) $(EXTRA_DIST) - -top_distdir = .. -distdir = $(top_distdir)/$(PACKAGE)-$(VERSION) + -rm -f TAGS ID GTAGS GRTAGS GSYMS GPATH tags distdir: $(DISTFILES) - @list='$(DISTFILES)'; for file in $$list; do \ + @srcdirstrip=`echo "$(srcdir)" | sed 's|.|.|g'`; \ + topsrcdirstrip=`echo "$(top_srcdir)" | sed 's|.|.|g'`; \ + list='$(DISTFILES)'; for file in $$list; do \ + case $$file in \ + $(srcdir)/*) file=`echo "$$file" | sed "s|^$$srcdirstrip/||"`;; \ + $(top_srcdir)/*) file=`echo "$$file" | sed "s|^$$topsrcdirstrip/|$(top_builddir)/|"`;; \ + esac; \ if test -f $$file || test -d $$file; then d=.; else d=$(srcdir); fi; \ dir=`echo "$$file" | sed -e 's,/[^/]*$$,,'`; \ if test "$$dir" != "$$file" && test "$$dir" != "."; then \ dir="/$$dir"; \ - $(mkinstalldirs) "$(distdir)$$dir"; \ + $(mkdir_p) "$(distdir)$$dir"; \ else \ dir=''; \ fi; \ @@ -270,10 +350,10 @@ distdir: $(DISTFILES) check-am: all-am check: check-am all-am: Makefile $(LTLIBRARIES) - installdirs: - $(mkinstalldirs) $(DESTDIR)$(libdir) - + for dir in "$(DESTDIR)$(libdir)"; do \ + test -z "$$dir" || $(mkdir_p) "$$dir"; \ + done install: install-am install-exec: install-exec-am install-data: install-data-am @@ -285,7 +365,7 @@ install-am: all-am installcheck: installcheck-am install-strip: $(MAKE) $(AM_MAKEFLAGS) INSTALL_PROGRAM="$(INSTALL_STRIP_PROGRAM)" \ - INSTALL_STRIP_FLAG=-s \ + install_sh_PROGRAM="$(INSTALL_STRIP_PROGRAM)" INSTALL_STRIP_FLAG=-s \ `test -z '$(STRIP)' || \ echo "INSTALL_PROGRAM_ENV=STRIPPROG='$(STRIP)'"` install mostlyclean-generic: @@ -293,7 +373,7 @@ mostlyclean-generic: clean-generic: distclean-generic: - -rm -f Makefile $(CONFIG_CLEAN_FILES) + -test -z "$(CONFIG_CLEAN_FILES)" || rm -f $(CONFIG_CLEAN_FILES) maintainer-clean-generic: @echo "This command is intended for maintainers to use" @@ -304,7 +384,7 @@ clean-am: clean-generic clean-libLTLIBRARIES clean-libtool \ mostlyclean-am distclean: distclean-am - + -rm -f Makefile distclean-am: clean-am distclean-compile distclean-generic \ distclean-libtool distclean-tags @@ -312,6 +392,8 @@ dvi: dvi-am dvi-am: +html: html-am + info: info-am info-am: @@ -327,7 +409,7 @@ install-man: installcheck-am: maintainer-clean: maintainer-clean-am - + -rm -f Makefile maintainer-clean-am: distclean-am maintainer-clean-generic mostlyclean: mostlyclean-am @@ -335,17 +417,26 @@ mostlyclean: mostlyclean-am mostlyclean-am: mostlyclean-compile mostlyclean-generic \ mostlyclean-libtool +pdf: pdf-am + +pdf-am: + +ps: ps-am + +ps-am: + uninstall-am: uninstall-info-am uninstall-libLTLIBRARIES -.PHONY: GTAGS all all-am check check-am clean clean-generic \ - clean-libLTLIBRARIES clean-libtool distclean distclean-compile \ - distclean-generic distclean-libtool distclean-tags distdir dvi \ - dvi-am info info-am install install-am install-data \ - install-data-am install-exec install-exec-am install-info \ - install-info-am install-libLTLIBRARIES install-man \ - install-strip installcheck installcheck-am installdirs \ - maintainer-clean maintainer-clean-generic mostlyclean \ - mostlyclean-compile mostlyclean-generic mostlyclean-libtool \ +.PHONY: CTAGS GTAGS all all-am check check-am clean clean-generic \ + clean-libLTLIBRARIES clean-libtool ctags distclean \ + distclean-compile distclean-generic distclean-libtool \ + distclean-tags distdir dvi dvi-am html html-am info info-am \ + install install-am install-data install-data-am install-exec \ + install-exec-am install-info install-info-am \ + install-libLTLIBRARIES install-man install-strip installcheck \ + installcheck-am installdirs maintainer-clean \ + maintainer-clean-generic mostlyclean mostlyclean-compile \ + mostlyclean-generic mostlyclean-libtool pdf pdf-am ps ps-am \ tags uninstall uninstall-am uninstall-info-am \ uninstall-libLTLIBRARIES diff --git a/test/Makefile.am b/test/Makefile.am index 00e66c9..a8b0a4c 100644 --- a/test/Makefile.am +++ b/test/Makefile.am @@ -1,10 +1,18 @@ ## Process this file with automake to produce Makefile.in -check_PROGRAMS = test_GVector test_GMatrix test_GSymMatrix -TESTS = test_GVector test_GMatrix test_GSymMatrix +check_PROGRAMS = test_GVector \ + test_GMatrix \ + test_GSymMatrix \ + test_GSparseMatrix +TESTS = test_GVector \ + test_GMatrix \ + test_GSymMatrix \ + test_GSparseMatrix test_GVector_SOURCES = test_GVector.cpp test_GVector_LDADD = ../src/libgamma.la test_GMatrix_SOURCES = test_GMatrix.cpp test_GMatrix_LDADD = ../src/libgamma.la test_GSymMatrix_SOURCES = test_GSymMatrix.cpp test_GSymMatrix_LDADD = ../src/libgamma.la +test_GSparseMatrix_SOURCES = test_GSparseMatrix.cpp +test_GSparseMatrix_LDADD = ../src/libgamma.la diff --git a/test/Makefile.in b/test/Makefile.in index 2bcd22e..b83e5d0 100644 --- a/test/Makefile.in +++ b/test/Makefile.in @@ -1,8 +1,8 @@ -# Makefile.in generated by automake 1.6.3 from Makefile.am. +# Makefile.in generated by automake 1.9.2 from Makefile.am. # @configure_input@ -# Copyright 1994, 1995, 1996, 1997, 1998, 1999, 2000, 2001, 2002 -# Free Software Foundation, Inc. +# Copyright (C) 1994, 1995, 1996, 1997, 1998, 1999, 2000, 2001, 2002, +# 2003, 2004 Free Software Foundation, Inc. # This Makefile.in is free software; the Free Software Foundation # gives unlimited permission to copy and/or distribute it, # with or without modifications, as long as this notice is preserved. @@ -13,143 +13,206 @@ # PARTICULAR PURPOSE. @SET_MAKE@ -SHELL = @SHELL@ +SOURCES = $(test_GMatrix_SOURCES) $(test_GSparseMatrix_SOURCES) $(test_GSymMatrix_SOURCES) $(test_GVector_SOURCES) srcdir = @srcdir@ top_srcdir = @top_srcdir@ VPATH = @srcdir@ -prefix = @prefix@ -exec_prefix = @exec_prefix@ - -bindir = @bindir@ -sbindir = @sbindir@ -libexecdir = @libexecdir@ -datadir = @datadir@ -sysconfdir = @sysconfdir@ -sharedstatedir = @sharedstatedir@ -localstatedir = @localstatedir@ -libdir = @libdir@ -infodir = @infodir@ -mandir = @mandir@ -includedir = @includedir@ -oldincludedir = /usr/include pkgdatadir = $(datadir)/@PACKAGE@ pkglibdir = $(libdir)/@PACKAGE@ pkgincludedir = $(includedir)/@PACKAGE@ top_builddir = .. - -ACLOCAL = @ACLOCAL@ -AUTOCONF = @AUTOCONF@ -AUTOMAKE = @AUTOMAKE@ -AUTOHEADER = @AUTOHEADER@ - am__cd = CDPATH="$${ZSH_VERSION+.}$(PATH_SEPARATOR)" && cd INSTALL = @INSTALL@ -INSTALL_PROGRAM = @INSTALL_PROGRAM@ -INSTALL_DATA = @INSTALL_DATA@ install_sh_DATA = $(install_sh) -c -m 644 install_sh_PROGRAM = $(install_sh) -c install_sh_SCRIPT = $(install_sh) -c -INSTALL_SCRIPT = @INSTALL_SCRIPT@ INSTALL_HEADER = $(INSTALL_DATA) -transform = @program_transform_name@ +transform = $(program_transform_name) NORMAL_INSTALL = : PRE_INSTALL = : POST_INSTALL = : NORMAL_UNINSTALL = : PRE_UNINSTALL = : POST_UNINSTALL = : -host_alias = @host_alias@ +build_triplet = @build@ host_triplet = @host@ - -EXEEXT = @EXEEXT@ -OBJEXT = @OBJEXT@ -PATH_SEPARATOR = @PATH_SEPARATOR@ +check_PROGRAMS = test_GVector$(EXEEXT) test_GMatrix$(EXEEXT) \ + test_GSymMatrix$(EXEEXT) test_GSparseMatrix$(EXEEXT) +subdir = test +DIST_COMMON = $(srcdir)/Makefile.am $(srcdir)/Makefile.in +ACLOCAL_M4 = $(top_srcdir)/aclocal.m4 +am__aclocal_m4_deps = $(top_srcdir)/configure.ac +am__configure_deps = $(am__aclocal_m4_deps) $(CONFIGURE_DEPENDENCIES) \ + $(ACLOCAL_M4) +mkinstalldirs = $(install_sh) -d +CONFIG_HEADER = $(top_builddir)/config.h +CONFIG_CLEAN_FILES = +am_test_GMatrix_OBJECTS = test_GMatrix.$(OBJEXT) +test_GMatrix_OBJECTS = $(am_test_GMatrix_OBJECTS) +test_GMatrix_DEPENDENCIES = ../src/libgamma.la +am_test_GSparseMatrix_OBJECTS = test_GSparseMatrix.$(OBJEXT) +test_GSparseMatrix_OBJECTS = $(am_test_GSparseMatrix_OBJECTS) +test_GSparseMatrix_DEPENDENCIES = ../src/libgamma.la +am_test_GSymMatrix_OBJECTS = test_GSymMatrix.$(OBJEXT) +test_GSymMatrix_OBJECTS = $(am_test_GSymMatrix_OBJECTS) +test_GSymMatrix_DEPENDENCIES = ../src/libgamma.la +am_test_GVector_OBJECTS = test_GVector.$(OBJEXT) +test_GVector_OBJECTS = $(am_test_GVector_OBJECTS) +test_GVector_DEPENDENCIES = ../src/libgamma.la +DEFAULT_INCLUDES = -I. -I$(srcdir) -I$(top_builddir) +depcomp = +am__depfiles_maybe = +CXXCOMPILE = $(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) \ + $(AM_CPPFLAGS) $(CPPFLAGS) $(AM_CXXFLAGS) $(CXXFLAGS) +LTCXXCOMPILE = $(LIBTOOL) --mode=compile --tag=CXX $(CXX) $(DEFS) \ + $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) \ + $(AM_CXXFLAGS) $(CXXFLAGS) +CXXLD = $(CXX) +CXXLINK = $(LIBTOOL) --mode=link --tag=CXX $(CXXLD) $(AM_CXXFLAGS) \ + $(CXXFLAGS) $(AM_LDFLAGS) $(LDFLAGS) -o $@ +SOURCES = $(test_GMatrix_SOURCES) $(test_GSparseMatrix_SOURCES) \ + $(test_GSymMatrix_SOURCES) $(test_GVector_SOURCES) +DIST_SOURCES = $(test_GMatrix_SOURCES) $(test_GSparseMatrix_SOURCES) \ + $(test_GSymMatrix_SOURCES) $(test_GVector_SOURCES) +ETAGS = etags +CTAGS = ctags +DISTFILES = $(DIST_COMMON) $(DIST_SOURCES) $(TEXINFOS) $(EXTRA_DIST) +ACLOCAL = @ACLOCAL@ AMTAR = @AMTAR@ AR = @AR@ -AS = @AS@ +AUTOCONF = @AUTOCONF@ +AUTOHEADER = @AUTOHEADER@ +AUTOMAKE = @AUTOMAKE@ AWK = @AWK@ CC = @CC@ +CFLAGS = @CFLAGS@ +CPP = @CPP@ +CPPFLAGS = @CPPFLAGS@ CXX = @CXX@ CXXCPP = @CXXCPP@ -DEPDIR = @DEPDIR@ -DLLTOOL = @DLLTOOL@ +CXXFLAGS = @CXXFLAGS@ +CYGPATH_W = @CYGPATH_W@ +DEFS = @DEFS@ ECHO = @ECHO@ +ECHO_C = @ECHO_C@ +ECHO_N = @ECHO_N@ +ECHO_T = @ECHO_T@ EGREP = @EGREP@ +EXEEXT = @EXEEXT@ F77 = @F77@ -GCJ = @GCJ@ -GCJFLAGS = @GCJFLAGS@ +FFLAGS = @FFLAGS@ +INSTALL_DATA = @INSTALL_DATA@ +INSTALL_PROGRAM = @INSTALL_PROGRAM@ +INSTALL_SCRIPT = @INSTALL_SCRIPT@ INSTALL_STRIP_PROGRAM = @INSTALL_STRIP_PROGRAM@ +LDFLAGS = @LDFLAGS@ +LIBOBJS = @LIBOBJS@ +LIBS = @LIBS@ LIBTOOL = @LIBTOOL@ +LIBTOOL_DEPS = @LIBTOOL_DEPS@ LN_S = @LN_S@ +LTLIBOBJS = @LTLIBOBJS@ MAINT = @MAINT@ -OBJDUMP = @OBJDUMP@ +MAINTAINER_MODE_FALSE = @MAINTAINER_MODE_FALSE@ +MAINTAINER_MODE_TRUE = @MAINTAINER_MODE_TRUE@ +MAKEINFO = @MAKEINFO@ +OBJEXT = @OBJEXT@ PACKAGE = @PACKAGE@ +PACKAGE_BUGREPORT = @PACKAGE_BUGREPORT@ +PACKAGE_NAME = @PACKAGE_NAME@ +PACKAGE_STRING = @PACKAGE_STRING@ +PACKAGE_TARNAME = @PACKAGE_TARNAME@ +PACKAGE_VERSION = @PACKAGE_VERSION@ +PATH_SEPARATOR = @PATH_SEPARATOR@ RANLIB = @RANLIB@ -RC = @RC@ +SET_MAKE = @SET_MAKE@ +SHELL = @SHELL@ STRIP = @STRIP@ VERSION = @VERSION@ -am__include = @am__include@ -am__quote = @am__quote@ +ac_ct_AR = @ac_ct_AR@ +ac_ct_CC = @ac_ct_CC@ +ac_ct_CXX = @ac_ct_CXX@ +ac_ct_F77 = @ac_ct_F77@ +ac_ct_RANLIB = @ac_ct_RANLIB@ +ac_ct_STRIP = @ac_ct_STRIP@ +am__leading_dot = @am__leading_dot@ +am__tar = @am__tar@ +am__untar = @am__untar@ +bindir = @bindir@ +build = @build@ +build_alias = @build_alias@ +build_cpu = @build_cpu@ +build_os = @build_os@ +build_vendor = @build_vendor@ +datadir = @datadir@ +exec_prefix = @exec_prefix@ +host = @host@ +host_alias = @host_alias@ +host_cpu = @host_cpu@ +host_os = @host_os@ +host_vendor = @host_vendor@ +includedir = @includedir@ +infodir = @infodir@ install_sh = @install_sh@ +libdir = @libdir@ +libexecdir = @libexecdir@ +localstatedir = @localstatedir@ +mandir = @mandir@ +mkdir_p = @mkdir_p@ +oldincludedir = @oldincludedir@ +prefix = @prefix@ +program_transform_name = @program_transform_name@ +sbindir = @sbindir@ +sharedstatedir = @sharedstatedir@ +sysconfdir = @sysconfdir@ +target_alias = @target_alias@ +TESTS = test_GVector \ + test_GMatrix \ + test_GSymMatrix \ + test_GSparseMatrix -check_PROGRAMS = test_GVector test_GMatrix test_GSymMatrix -TESTS = test_GVector test_GMatrix test_GSymMatrix test_GVector_SOURCES = test_GVector.cpp test_GVector_LDADD = ../src/libgamma.la test_GMatrix_SOURCES = test_GMatrix.cpp test_GMatrix_LDADD = ../src/libgamma.la test_GSymMatrix_SOURCES = test_GSymMatrix.cpp test_GSymMatrix_LDADD = ../src/libgamma.la -subdir = test -mkinstalldirs = $(SHELL) $(top_srcdir)/mkinstalldirs -CONFIG_HEADER = $(top_builddir)/config.h -CONFIG_CLEAN_FILES = -check_PROGRAMS = test_GVector$(EXEEXT) test_GMatrix$(EXEEXT) \ - test_GSymMatrix$(EXEEXT) -am_test_GMatrix_OBJECTS = test_GMatrix.$(OBJEXT) -test_GMatrix_OBJECTS = $(am_test_GMatrix_OBJECTS) -test_GMatrix_DEPENDENCIES = ../src/libgamma.la -test_GMatrix_LDFLAGS = -am_test_GSymMatrix_OBJECTS = test_GSymMatrix.$(OBJEXT) -test_GSymMatrix_OBJECTS = $(am_test_GSymMatrix_OBJECTS) -test_GSymMatrix_DEPENDENCIES = ../src/libgamma.la -test_GSymMatrix_LDFLAGS = -am_test_GVector_OBJECTS = test_GVector.$(OBJEXT) -test_GVector_OBJECTS = $(am_test_GVector_OBJECTS) -test_GVector_DEPENDENCIES = ../src/libgamma.la -test_GVector_LDFLAGS = - -DEFS = @DEFS@ -DEFAULT_INCLUDES = -I. -I$(srcdir) -I$(top_builddir) -CPPFLAGS = @CPPFLAGS@ -LDFLAGS = @LDFLAGS@ -LIBS = @LIBS@ -depcomp = -am__depfiles_maybe = -CXXCOMPILE = $(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) \ - $(AM_CPPFLAGS) $(CPPFLAGS) $(AM_CXXFLAGS) $(CXXFLAGS) -LTCXXCOMPILE = $(LIBTOOL) --mode=compile $(CXX) $(DEFS) \ - $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) \ - $(AM_CXXFLAGS) $(CXXFLAGS) -CXXLD = $(CXX) -CXXLINK = $(LIBTOOL) --mode=link $(CXXLD) $(AM_CXXFLAGS) $(CXXFLAGS) \ - $(AM_LDFLAGS) $(LDFLAGS) -o $@ -CXXFLAGS = @CXXFLAGS@ -DIST_SOURCES = $(test_GMatrix_SOURCES) $(test_GSymMatrix_SOURCES) \ - $(test_GVector_SOURCES) -DIST_COMMON = Makefile.am Makefile.in -SOURCES = $(test_GMatrix_SOURCES) $(test_GSymMatrix_SOURCES) $(test_GVector_SOURCES) - +test_GSparseMatrix_SOURCES = test_GSparseMatrix.cpp +test_GSparseMatrix_LDADD = ../src/libgamma.la all: all-am .SUFFIXES: .SUFFIXES: .cpp .lo .o .obj -$(srcdir)/Makefile.in: @MAINTAINER_MODE_TRUE@ Makefile.am $(top_srcdir)/configure.ac $(ACLOCAL_M4) +$(srcdir)/Makefile.in: @MAINTAINER_MODE_TRUE@ $(srcdir)/Makefile.am $(am__configure_deps) + @for dep in $?; do \ + case '$(am__configure_deps)' in \ + *$$dep*) \ + cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh \ + && exit 0; \ + exit 1;; \ + esac; \ + done; \ + echo ' cd $(top_srcdir) && $(AUTOMAKE) --gnu --ignore-deps test/Makefile'; \ cd $(top_srcdir) && \ - $(AUTOMAKE) --gnu test/Makefile -Makefile: @MAINTAINER_MODE_TRUE@ $(srcdir)/Makefile.in $(top_builddir)/config.status - cd $(top_builddir) && $(SHELL) ./config.status $(subdir)/$@ $(am__depfiles_maybe) + $(AUTOMAKE) --gnu --ignore-deps test/Makefile +.PRECIOUS: Makefile +Makefile: $(srcdir)/Makefile.in $(top_builddir)/config.status + @case '$?' in \ + *config.status*) \ + cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh;; \ + *) \ + echo ' cd $(top_builddir) && $(SHELL) ./config.status $(subdir)/$@ $(am__depfiles_maybe)'; \ + cd $(top_builddir) && $(SHELL) ./config.status $(subdir)/$@ $(am__depfiles_maybe);; \ + esac; + +$(top_builddir)/config.status: $(top_srcdir)/configure $(CONFIG_STATUS_DEPENDENCIES) + cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh + +$(top_srcdir)/configure: @MAINTAINER_MODE_TRUE@ $(am__configure_deps) + cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh +$(ACLOCAL_M4): @MAINTAINER_MODE_TRUE@ $(am__aclocal_m4_deps) + cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh clean-checkPROGRAMS: @list='$(check_PROGRAMS)'; for p in $$list; do \ @@ -160,6 +223,9 @@ clean-checkPROGRAMS: test_GMatrix$(EXEEXT): $(test_GMatrix_OBJECTS) $(test_GMatrix_DEPENDENCIES) @rm -f test_GMatrix$(EXEEXT) $(CXXLINK) $(test_GMatrix_LDFLAGS) $(test_GMatrix_OBJECTS) $(test_GMatrix_LDADD) $(LIBS) +test_GSparseMatrix$(EXEEXT): $(test_GSparseMatrix_OBJECTS) $(test_GSparseMatrix_DEPENDENCIES) + @rm -f test_GSparseMatrix$(EXEEXT) + $(CXXLINK) $(test_GSparseMatrix_LDFLAGS) $(test_GSparseMatrix_OBJECTS) $(test_GSparseMatrix_LDADD) $(LIBS) test_GSymMatrix$(EXEEXT): $(test_GSymMatrix_OBJECTS) $(test_GSymMatrix_DEPENDENCIES) @rm -f test_GSymMatrix$(EXEEXT) $(CXXLINK) $(test_GSymMatrix_LDFLAGS) $(test_GSymMatrix_OBJECTS) $(test_GSymMatrix_LDADD) $(LIBS) @@ -168,19 +234,19 @@ test_GVector$(EXEEXT): $(test_GVector_OBJECTS) $(test_GVector_DEPENDENCIES) $(CXXLINK) $(test_GVector_LDFLAGS) $(test_GVector_OBJECTS) $(test_GVector_LDADD) $(LIBS) mostlyclean-compile: - -rm -f *.$(OBJEXT) core *.core + -rm -f *.$(OBJEXT) distclean-compile: -rm -f *.tab.c .cpp.o: - $(CXXCOMPILE) -c -o $@ `test -f '$<' || echo '$(srcdir)/'`$< + $(CXXCOMPILE) -c -o $@ $< .cpp.obj: - $(CXXCOMPILE) -c -o $@ `cygpath -w $<` + $(CXXCOMPILE) -c -o $@ `$(CYGPATH_W) '$<'` .cpp.lo: - $(LTCXXCOMPILE) -c -o $@ `test -f '$<' || echo '$(srcdir)/'`$< + $(LTCXXCOMPILE) -c -o $@ $< mostlyclean-libtool: -rm -f *.lo @@ -192,11 +258,6 @@ distclean-libtool: -rm -f libtool uninstall-info-am: -ETAGS = etags -ETAGSFLAGS = - -tags: TAGS - ID: $(HEADERS) $(SOURCES) $(LISP) $(TAGS_FILES) list='$(SOURCES) $(HEADERS) $(LISP) $(TAGS_FILES)'; \ unique=`for i in $$list; do \ @@ -205,6 +266,7 @@ ID: $(HEADERS) $(SOURCES) $(LISP) $(TAGS_FILES) $(AWK) ' { files[$$0] = 1; } \ END { for (i in files) print i; }'`; \ mkid -fID $$unique +tags: TAGS TAGS: $(HEADERS) $(SOURCES) $(TAGS_DEPENDENCIES) \ $(TAGS_FILES) $(LISP) @@ -216,8 +278,24 @@ TAGS: $(HEADERS) $(SOURCES) $(TAGS_DEPENDENCIES) \ done | \ $(AWK) ' { files[$$0] = 1; } \ END { for (i in files) print i; }'`; \ - test -z "$(ETAGS_ARGS)$$tags$$unique" \ - || $(ETAGS) $(ETAGSFLAGS) $(AM_ETAGSFLAGS) $(ETAGS_ARGS) \ + if test -z "$(ETAGS_ARGS)$$tags$$unique"; then :; else \ + test -n "$$unique" || unique=$$empty_fix; \ + $(ETAGS) $(ETAGSFLAGS) $(AM_ETAGSFLAGS) $(ETAGS_ARGS) \ + $$tags $$unique; \ + fi +ctags: CTAGS +CTAGS: $(HEADERS) $(SOURCES) $(TAGS_DEPENDENCIES) \ + $(TAGS_FILES) $(LISP) + tags=; \ + here=`pwd`; \ + list='$(SOURCES) $(HEADERS) $(LISP) $(TAGS_FILES)'; \ + unique=`for i in $$list; do \ + if test -f "$$i"; then echo $$i; else echo $(srcdir)/$$i; fi; \ + done | \ + $(AWK) ' { files[$$0] = 1; } \ + END { for (i in files) print i; }'`; \ + test -z "$(CTAGS_ARGS)$$tags$$unique" \ + || $(CTAGS) $(CTAGSFLAGS) $(AM_CTAGSFLAGS) $(CTAGS_ARGS) \ $$tags $$unique GTAGS: @@ -226,10 +304,10 @@ GTAGS: && gtags -i $(GTAGS_ARGS) $$here distclean-tags: - -rm -f TAGS ID GTAGS GRTAGS GSYMS GPATH + -rm -f TAGS ID GTAGS GRTAGS GSYMS GPATH tags check-TESTS: $(TESTS) - @failed=0; all=0; xfail=0; xpass=0; \ + @failed=0; all=0; xfail=0; xpass=0; skip=0; \ srcdir=$(srcdir); export srcdir; \ list='$(TESTS)'; \ if test -n "$$list"; then \ @@ -241,26 +319,29 @@ check-TESTS: $(TESTS) all=`expr $$all + 1`; \ case " $(XFAIL_TESTS) " in \ *" $$tst "*) \ - xpass=`expr $$xpass + 1`; \ - failed=`expr $$failed + 1`; \ - echo "XPASS: $$tst"; \ + xpass=`expr $$xpass + 1`; \ + failed=`expr $$failed + 1`; \ + echo "XPASS: $$tst"; \ ;; \ *) \ - echo "PASS: $$tst"; \ + echo "PASS: $$tst"; \ ;; \ esac; \ elif test $$? -ne 77; then \ all=`expr $$all + 1`; \ case " $(XFAIL_TESTS) " in \ *" $$tst "*) \ - xfail=`expr $$xfail + 1`; \ - echo "XFAIL: $$tst"; \ + xfail=`expr $$xfail + 1`; \ + echo "XFAIL: $$tst"; \ ;; \ *) \ - failed=`expr $$failed + 1`; \ - echo "FAIL: $$tst"; \ + failed=`expr $$failed + 1`; \ + echo "FAIL: $$tst"; \ ;; \ esac; \ + else \ + skip=`expr $$skip + 1`; \ + echo "SKIP: $$tst"; \ fi; \ done; \ if test "$$failed" -eq 0; then \ @@ -276,24 +357,41 @@ check-TESTS: $(TESTS) banner="$$failed of $$all tests did not behave as expected ($$xpass unexpected passes)"; \ fi; \ fi; \ - dashes=`echo "$$banner" | sed s/./=/g`; \ + dashes="$$banner"; \ + skipped=""; \ + if test "$$skip" -ne 0; then \ + skipped="($$skip tests were not run)"; \ + test `echo "$$skipped" | wc -c` -le `echo "$$banner" | wc -c` || \ + dashes="$$skipped"; \ + fi; \ + report=""; \ + if test "$$failed" -ne 0 && test -n "$(PACKAGE_BUGREPORT)"; then \ + report="Please report to $(PACKAGE_BUGREPORT)"; \ + test `echo "$$report" | wc -c` -le `echo "$$banner" | wc -c` || \ + dashes="$$report"; \ + fi; \ + dashes=`echo "$$dashes" | sed s/./=/g`; \ echo "$$dashes"; \ echo "$$banner"; \ + test -z "$$skipped" || echo "$$skipped"; \ + test -z "$$report" || echo "$$report"; \ echo "$$dashes"; \ test "$$failed" -eq 0; \ else :; fi -DISTFILES = $(DIST_COMMON) $(DIST_SOURCES) $(TEXINFOS) $(EXTRA_DIST) - -top_distdir = .. -distdir = $(top_distdir)/$(PACKAGE)-$(VERSION) distdir: $(DISTFILES) - @list='$(DISTFILES)'; for file in $$list; do \ + @srcdirstrip=`echo "$(srcdir)" | sed 's|.|.|g'`; \ + topsrcdirstrip=`echo "$(top_srcdir)" | sed 's|.|.|g'`; \ + list='$(DISTFILES)'; for file in $$list; do \ + case $$file in \ + $(srcdir)/*) file=`echo "$$file" | sed "s|^$$srcdirstrip/||"`;; \ + $(top_srcdir)/*) file=`echo "$$file" | sed "s|^$$topsrcdirstrip/|$(top_builddir)/|"`;; \ + esac; \ if test -f $$file || test -d $$file; then d=.; else d=$(srcdir); fi; \ dir=`echo "$$file" | sed -e 's,/[^/]*$$,,'`; \ if test "$$dir" != "$$file" && test "$$dir" != "."; then \ dir="/$$dir"; \ - $(mkinstalldirs) "$(distdir)$$dir"; \ + $(mkdir_p) "$(distdir)$$dir"; \ else \ dir=''; \ fi; \ @@ -313,9 +411,7 @@ check-am: all-am $(MAKE) $(AM_MAKEFLAGS) check-TESTS check: check-am all-am: Makefile - installdirs: - install: install-am install-exec: install-exec-am install-data: install-data-am @@ -327,7 +423,7 @@ install-am: all-am installcheck: installcheck-am install-strip: $(MAKE) $(AM_MAKEFLAGS) INSTALL_PROGRAM="$(INSTALL_STRIP_PROGRAM)" \ - INSTALL_STRIP_FLAG=-s \ + install_sh_PROGRAM="$(INSTALL_STRIP_PROGRAM)" INSTALL_STRIP_FLAG=-s \ `test -z '$(STRIP)' || \ echo "INSTALL_PROGRAM_ENV=STRIPPROG='$(STRIP)'"` install mostlyclean-generic: @@ -335,17 +431,18 @@ mostlyclean-generic: clean-generic: distclean-generic: - -rm -f Makefile $(CONFIG_CLEAN_FILES) + -test -z "$(CONFIG_CLEAN_FILES)" || rm -f $(CONFIG_CLEAN_FILES) maintainer-clean-generic: @echo "This command is intended for maintainers to use" @echo "it deletes files that may require special tools to rebuild." clean: clean-am -clean-am: clean-checkPROGRAMS clean-generic clean-libtool mostlyclean-am +clean-am: clean-checkPROGRAMS clean-generic clean-libtool \ + mostlyclean-am distclean: distclean-am - + -rm -f Makefile distclean-am: clean-am distclean-compile distclean-generic \ distclean-libtool distclean-tags @@ -353,6 +450,8 @@ dvi: dvi-am dvi-am: +html: html-am + info: info-am info-am: @@ -368,7 +467,7 @@ install-man: installcheck-am: maintainer-clean: maintainer-clean-am - + -rm -f Makefile maintainer-clean-am: distclean-am maintainer-clean-generic mostlyclean: mostlyclean-am @@ -376,17 +475,26 @@ mostlyclean: mostlyclean-am mostlyclean-am: mostlyclean-compile mostlyclean-generic \ mostlyclean-libtool +pdf: pdf-am + +pdf-am: + +ps: ps-am + +ps-am: + uninstall-am: uninstall-info-am -.PHONY: GTAGS all all-am check check-TESTS check-am clean \ - clean-checkPROGRAMS clean-generic clean-libtool distclean \ - distclean-compile distclean-generic distclean-libtool \ - distclean-tags distdir dvi dvi-am info info-am install \ - install-am install-data install-data-am install-exec \ - install-exec-am install-info install-info-am install-man \ - install-strip installcheck installcheck-am installdirs \ - maintainer-clean maintainer-clean-generic mostlyclean \ - mostlyclean-compile mostlyclean-generic mostlyclean-libtool \ +.PHONY: CTAGS GTAGS all all-am check check-TESTS check-am clean \ + clean-checkPROGRAMS clean-generic clean-libtool ctags \ + distclean distclean-compile distclean-generic \ + distclean-libtool distclean-tags distdir dvi dvi-am html \ + html-am info info-am install install-am install-data \ + install-data-am install-exec install-exec-am install-info \ + install-info-am install-man install-strip installcheck \ + installcheck-am installdirs maintainer-clean \ + maintainer-clean-generic mostlyclean mostlyclean-compile \ + mostlyclean-generic mostlyclean-libtool pdf pdf-am ps ps-am \ tags uninstall uninstall-am uninstall-info-am # Tell versions [3.59,3.63) of GNU make to not export all variables. diff --git a/test/test_GMatrix.cpp b/test/test_GMatrix.cpp index 24d2dc0..9ba71b9 100644 --- a/test/test_GMatrix.cpp +++ b/test/test_GMatrix.cpp @@ -18,10 +18,12 @@ using namespace std; /* __ Globals ____________________________________________________________ */ -double g_matrix[] = {1.0, 2.0, 3.0, 4.0, 5.0, 6.0, 7.0, 8.0, 9.0}; -double g_vector[] = {1.0, 2.0, 3.0}; +double g_matrix[] = {1.0, 2.0, 3.0, 4.0, + 5.0, 6.0, 7.0, 8.0, + 9.0, 10., 11., 12.}; +double g_vector[] = {1.0, 2.0, 3.0, 4.0}; unsigned g_rows = 3; -unsigned g_cols = 3; +unsigned g_cols = 4; /*************************************************************************** @@ -72,7 +74,32 @@ int check_matrix(const GMatrix& m, const double scale, const double add) for (unsigned row = 0; row < g_rows; ++row) { for (unsigned col = 0; col < g_cols; ++col) { double value = g_matrix[col+row*g_cols] * scale + add; - if (m(row,col) != value) { + if (fabs(m(row,col)-value) > 1.0e-15) { + result = 0; + break; + } + } + } + } + catch (exception &e) { + cout << "TEST ERROR: Unable to check test matrix." << endl; + throw; + } + return result; +} + + +/*************************************************************************** + * Check transposed test matrix * + ***************************************************************************/ +int check_transpose_matrix(const GMatrix& m, const double scale, const double add) +{ + int result = 1; + try { + for (unsigned row = 0; row < g_rows; ++row) { + for (unsigned col = 0; col < g_cols; ++col) { + double value = g_matrix[col+row*g_cols] * scale + add; + if (m(col,row) != value) { result = 0; break; } @@ -167,15 +194,15 @@ int check_matrix_vector(const GVector& v) ***************************************************************************/ int check_matrix_matrix(const GMatrix& m) { - if (m.rows() != g_rows || m.cols() != g_cols) + if (m.rows() != g_rows || m.cols() != g_rows) return 0; int result = 1; try { - for (unsigned row = 0; row < g_rows; ++row) { - for (unsigned col = 0; col < g_cols; ++col) { + for (unsigned row = 0; row < m.rows(); ++row) { + for (unsigned col = 0; col < m.cols(); ++col) { double value = 0.0; for (unsigned i = 0; i < g_cols; ++i) - value += g_matrix[i+row*g_cols] * g_matrix[row+i*g_cols]; + value += g_matrix[i+row*g_cols] * g_matrix[i+col*g_cols]; if (m(row,col) != value) { result = 0; break; @@ -323,7 +350,7 @@ int main(void) cout << "GMatrix - Test 4: Define matrix using copy constructor: "; // GMatrix test4 = m_test; - if (!check_matrix(test4, 1.0, 0.0) && !check_matrix(m_test, 1.0, 0.0)) { + if (!check_matrix(test4, 1.0, 0.0) || !check_matrix(m_test, 1.0, 0.0)) { cout << endl << "TEST ERROR: Corrupt copy constructor." << endl; cout << test4 << endl; throw; @@ -341,8 +368,8 @@ int main(void) // // GMatrix = GMatrix result = m_test; - if (!check_matrix(result, 1.0, 0.0) && !check_matrix(m_test, 1.0, 0.0)) { - cout << endl << "TEST ERROR: Corrupt copy constructor." << endl; + if (!check_matrix(result, 1.0, 0.0) || !check_matrix(m_test, 1.0, 0.0)) { + cout << endl << "TEST ERROR: Corrupt assignment." << endl; cout << result << endl; throw; } @@ -356,14 +383,41 @@ int main(void) } cout << "ok." << endl; - // Test 6: Matrix*Vector multiplication + // Test 6: Transposition try { - cout << "GMatrix - Test 6: Matrix*Vector multiplication: "; + cout << "GMatrix - Test 6: Transposition: "; // - GVector v_test6 = m_test*v_test; - if (!check_matrix_vector(v_test6) && !check_matrix(m_test, 1.0, 0.0)) { + // transpose(GMatrix) + result = transpose(m_test); + if (!check_transpose_matrix(result, 1.0, 0.0) || !check_matrix(m_test, 1.0, 0.0)) { + cout << endl << "TEST ERROR: Corrupt transpose(GMatrix) function." << endl; + cout << result << endl; + throw; + } + // + // GMatrix.transpose() + result = m_test; + result.transpose(); + if (!check_transpose_matrix(result, 1.0, 0.0) || !check_matrix(m_test, 1.0, 0.0)) { + cout << endl << "TEST ERROR: Corrupt GMatrix.transpose() function." << endl; + cout << result << endl; + throw; + } + } + catch (exception &e) { + cout << e.what() << endl; + throw; + } + cout << "ok." << endl; + + // Test 7: Matrix*Vector multiplication + try { + cout << "GMatrix - Test 7: Matrix*Vector multiplication: "; + // + GVector v_test7 = m_test*v_test; + if (!check_matrix_vector(v_test7) || !check_matrix(m_test, 1.0, 0.0)) { cout << endl << "TEST ERROR: Corrupt Matrix*Vector multiplication." << endl; - cout << v_test6 << endl; + cout << v_test7 << endl; throw; } } @@ -372,9 +426,9 @@ int main(void) throw; } try { - GVector v_test6 = bigger*v_test; + GVector v_test7 = bigger*v_test; } - catch (GMatrix::vec_mat_mismatch &e) { + catch (GMatrix::matrix_vector_mismatch &e) { } catch (exception &e) { cout << e.what() << endl; @@ -382,14 +436,14 @@ int main(void) } cout << "ok." << endl; - // Test 7: Matrix*Matrix multiplication + // Test 8: Matrix*Matrix multiplication try { - cout << "GMatrix - Test 7: Matrix*Matrix multiplication: "; + cout << "GMatrix - Test 8: Matrix*Matrix multiplication: "; // - GMatrix m_test7 = m_test*m_test; - if (!check_matrix_matrix(m_test7) && !check_matrix(m_test, 1.0, 0.0)) { + GMatrix m_test8 = m_test * transpose(m_test); + if (!check_matrix_matrix(m_test8) || !check_matrix(m_test, 1.0, 0.0)) { cout << endl << "TEST ERROR: Corrupt Matrix*Matrix multiplication." << endl; - cout << m_test7 << endl; + cout << m_test8 << endl; throw; } } @@ -398,18 +452,18 @@ int main(void) throw; } try { - GMatrix m_test7 = m_test*bigger; + GMatrix m_test8 = m_test*bigger; } - catch (GMatrix::dim_mult_mismatch &e) { + catch (GMatrix::matrix_mismatch &e) { } catch (exception &e) { cout << e.what() << endl; throw; } try { - GMatrix m_test7 = bigger*m_test; + GMatrix m_test8 = bigger*m_test; } - catch (GMatrix::dim_mult_mismatch &e) { + catch (GMatrix::matrix_mismatch &e) { } catch (exception &e) { cout << e.what() << endl; @@ -417,67 +471,40 @@ int main(void) } cout << "ok." << endl; - // Test 8: Assignment and arithmetics + // Test 9: Assignment and arithmetics try { - cout << "GMatrix - Test 8: Assignment and arithmetics: "; + cout << "GMatrix - Test 9: Assignment and arithmetics: "; // // -GMatrix result = -m_test; - if (!check_matrix(result, -1.0, 0.0) && !check_matrix(m_test, 1.0, 0.0)) { + if (!check_matrix(result, -1.0, 0.0) || !check_matrix(m_test, 1.0, 0.0)) { cout << endl << "TEST ERROR: Corrupt -GMatrix operator." << endl; cout << result << endl; throw; } // - // GMatrix = 3.0 - result = m_test; - result = 3.0; - if (!check_matrix(result, 0.0, 3.0) && !check_matrix(m_test, 1.0, 0.0)) { - cout << endl << "TEST ERROR: Corrupt GMatrix = double operator." << endl; - cout << result << endl; - throw; - } - // // GMatrix += GMatrix result = m_test; result += m_test; - if (!check_matrix(result, 2.0, 0.0) && !check_matrix(m_test, 1.0, 0.0)) { + if (!check_matrix(result, 2.0, 0.0) || !check_matrix(m_test, 1.0, 0.0)) { cout << endl << "TEST ERROR: Corrupt GMatrix += GMatrix operator." << endl; cout << result << endl; throw; } // - // GMatrix += 3.0 - result = m_test; - result += 3.0; - if (!check_matrix(result, 1.0, 3.0) && !check_matrix(m_test, 1.0, 0.0)) { - cout << endl << "TEST ERROR: Corrupt GMatrix += double operator." << endl; - cout << result << endl; - throw; - } - // // GMatrix -= GMatrix result = m_test; result -= m_test; - if (!check_matrix(result, 0.0, 0.0) && !check_matrix(m_test, 1.0, 0.0)) { + if (!check_matrix(result, 0.0, 0.0) || !check_matrix(m_test, 1.0, 0.0)) { cout << endl << "TEST ERROR: Corrupt GMatrix -= GMatrix operator." << endl; cout << result << endl; throw; } // - // GMatrix -= 3.0 - result = m_test; - result -= 3.0; - if (!check_matrix(result, 1.0, -3.0) && !check_matrix(m_test, 1.0, 0.0)) { - cout << endl << "TEST ERROR: Corrupt GMatrix -= double operator." << endl; - cout << result << endl; - throw; - } - // // GMatrix *= 3.0 result = m_test; result *= 3.0; - if (!check_matrix(result, 3.0, 0.0) && !check_matrix(m_test, 1.0, 0.0)) { + if (!check_matrix(result, 3.0, 0.0) || !check_matrix(m_test, 1.0, 0.0)) { cout << endl << "TEST ERROR: Corrupt GMatrix *= double operator." << endl; cout << result << endl; throw; @@ -486,7 +513,7 @@ int main(void) // GMatrix /= 3.0 result = m_test; result /= 3.0; - if (!check_matrix(result, 1.0/3.0, 0.0) && !check_matrix(m_test, 1.0, 0.0)) { + if (!check_matrix(result, 1.0/3.0, 0.0) || !check_matrix(m_test, 1.0, 0.0)) { cout << endl << "TEST ERROR: Corrupt GMatrix /= double operator." << endl; cout << result << endl; throw; @@ -494,7 +521,7 @@ int main(void) // // GMatrix + GMatrix result = m_test + m_test; - if (!check_matrix(result, 2.0, 0.0) && !check_matrix(m_test, 1.0, 0.0)) { + if (!check_matrix(result, 2.0, 0.0) || !check_matrix(m_test, 1.0, 0.0)) { cout << endl << "TEST ERROR: Corrupt GMatrix + GMatrix operator." << endl; cout << result << endl; throw; @@ -502,7 +529,7 @@ int main(void) // // GMatrix - GMatrix result = m_test - m_test; - if (!check_matrix(result, 0.0, 0.0) && !check_matrix(m_test, 1.0, 0.0)) { + if (!check_matrix(result, 0.0, 0.0) || !check_matrix(m_test, 1.0, 0.0)) { cout << endl << "TEST ERROR: Corrupt GMatrix - GMatrix operator." << endl; cout << result << endl; throw; @@ -510,47 +537,15 @@ int main(void) // // GMatrix - GMatrix result = m_test - m_test; - if (!check_matrix(result, 0.0, 0.0) && !check_matrix(m_test, 1.0, 0.0)) { + if (!check_matrix(result, 0.0, 0.0) || !check_matrix(m_test, 1.0, 0.0)) { cout << endl << "TEST ERROR: Corrupt GMatrix - GMatrix operator." << endl; cout << result << endl; throw; } // - // GMatrix + 3.0 - result = m_test + 3.0; - if (!check_matrix(result, 1.0, 3.0) && !check_matrix(m_test, 1.0, 0.0)) { - cout << endl << "TEST ERROR: Corrupt GMatrix + double operator." << endl; - cout << result << endl; - throw; - } - // - // 3.0 + GMatrix - result = 3.0 + m_test; - if (!check_matrix(result, 1.0, 3.0) && !check_matrix(m_test, 1.0, 0.0)) { - cout << endl << "TEST ERROR: Corrupt double + GMatrix operator." << endl; - cout << result << endl; - throw; - } - // - // GMatrix - 3.0 - result = m_test - 3.0; - if (!check_matrix(result, 1.0, -3.0) && !check_matrix(m_test, 1.0, 0.0)) { - cout << endl << "TEST ERROR: Corrupt GMatrix - double operator." << endl; - cout << result << endl; - throw; - } - // - // 3.0 - GMatrix - result = 3.0 - m_test; - if (!check_matrix(result, -1.0, 3.0) && !check_matrix(m_test, 1.0, 0.0)) { - cout << endl << "TEST ERROR: Corrupt double - GMatrix operator." << endl; - cout << result << endl; - throw; - } - // // GMatrix * 3.0 result = m_test * 3.0; - if (!check_matrix(result, 3.0, 0.0) && !check_matrix(m_test, 1.0, 0.0)) { + if (!check_matrix(result, 3.0, 0.0) || !check_matrix(m_test, 1.0, 0.0)) { cout << endl << "TEST ERROR: Corrupt GMatrix * double operator." << endl; cout << result << endl; throw; @@ -558,7 +553,7 @@ int main(void) // // 3.0 * GMatrix result = 3.0 * m_test; - if (!check_matrix(result, 3.0, 0.0) && !check_matrix(m_test, 1.0, 0.0)) { + if (!check_matrix(result, 3.0, 0.0) || !check_matrix(m_test, 1.0, 0.0)) { cout << endl << "TEST ERROR: Corrupt double * GMatrix operator." << endl; cout << result << endl; throw; @@ -566,7 +561,7 @@ int main(void) // // GMatrix / 3.0 result = m_test / 3.0; - if (!check_matrix(result, 1.0/3.0, 0.0) && !check_matrix(m_test, 1.0, 0.0)) { + if (!check_matrix(result, 1.0/3.0, 0.0) || !check_matrix(m_test, 1.0, 0.0)) { cout << endl << "TEST ERROR: Corrupt GMatrix / double operator." << endl; cout << result << endl; throw; @@ -580,7 +575,7 @@ int main(void) result = m_test; result += bigger; } - catch (GMatrix::dim_add_mismatch) { + catch (GMatrix::matrix_mismatch) { } catch (exception &e) { cout << e.what() << endl; @@ -588,9 +583,9 @@ int main(void) } cout << "ok." << endl; - // Test 9: Matrix functions + // Test 10: Matrix functions try { - cout << "GMatrix - Test 9: Matrix functions: "; + cout << "GMatrix - Test 10: Matrix functions: "; // double min = m_test.min(); if (!check_matrix_min(min)) { @@ -618,9 +613,9 @@ int main(void) } cout << "ok." << endl; - // Test 10: Matrix comparison + // Test 11: Matrix comparison try { - cout << "GMatrix - Test 10: Comparison: "; + cout << "GMatrix - Test 11: Comparison: "; // if ((m_test == m_test) != 1) { cout << endl << "TEST ERROR: Corrupt GMatrix == GMatrix operator." << endl; @@ -659,49 +654,4 @@ int main(void) } cout << "ok." << endl; - // Test 11: Transformations - try { - cout << "GMatrix - Test 11: Transformations: "; - // - // transpose(GMatrix) - result = transpose(m_test); - if (!check_matrix(result, 1.0, 0.0) && !check_matrix(m_test, 1.0, 0.0)) { - cout << endl << "TEST ERROR: Corrupt transpose(GMatrix) function." << endl; - cout << result << endl; - throw; - } - // - // GMatrix.transpose() - result = m_test; - result.transpose(); - if (!check_matrix(result, 1.0, 0.0) && !check_matrix(m_test, 1.0, 0.0)) { - cout << endl << "TEST ERROR: Corrupt GMatrix.transpose() function." << endl; - cout << result << endl; - throw; - } -/* - // - // lower_triangle(GMatrix) - m_test11 = lower_triangle(m_test); - if (!check_matrix_lt(m_test11, 1.0, 0.0) && !check_matrix(m_test, 1.0, 0.0)) { - cout << endl << "TEST ERROR: Corrupt lower_triangle(GMatrix) function." << endl; - cout << m_test11 << endl; - throw; - } - // - // upper_triangle(GMatrix) - m_test11 = upper_triangle(m_test); - if (!check_matrix_ut(m_test11, 1.0, 0.0) && !check_matrix(m_test, 1.0, 0.0)) { - cout << endl << "TEST ERROR: Corrupt upper_triangle(GMatrix) function." << endl; - cout << m_test11 << endl; - throw; - } -*/ - } - catch (exception &e) { - cout << e.what() << endl; - throw; - } - cout << "ok." << endl; - -} \ No newline at end of file +} diff --git a/test/test_GSparseMatrix.cpp b/test/test_GSparseMatrix.cpp new file mode 100644 index 0000000..91e4c8b --- /dev/null +++ b/test/test_GSparseMatrix.cpp @@ -0,0 +1,1443 @@ +/*************************************************************************** + * test_GSparseMatrix.cpp - test GSparseMatrix class * + * ----------------------------------------------------------------------- * + * copyright : (C) 2006 by Jurgen Knodlseder * + * ----------------------------------------------------------------------- * + * * + * 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 2 of the License, or * + * (at your option) any later version. * + * * + ***************************************************************************/ + +/* __ Includes ___________________________________________________________ */ +#include "test_GSparseMatrix.hpp" + +/* __ Namespaces _________________________________________________________ */ +using namespace std; + +/* __ Definitions ________________________________________________________ */ +//#define DUMP_RESIDUALS // Dump residuals +#define DUMP_TIMING // Dump timing + +/* __ Globals ____________________________________________________________ */ +double g_matrix[] = {1.0, 7.0, 3.0, 2.0, 4.0, 8.0, 5.0, 6.0, 9.0}; +unsigned g_row[] = { 0, 0, 1, 2, 2, 2, 3, 3, 3}; +unsigned g_col[] = { 0, 4, 1, 0, 2, 4, 2, 3, 4}; +double g_vector[] = {1.0, 2.0, 3.0, 4.0, 5.0}; +unsigned g_elements = 9; +unsigned g_rows = 4; +unsigned g_cols = 5; + + +/*************************************************************************** + * Set test matrix * + ***************************************************************************/ +GSparseMatrix set_matrix(void) +{ + try { + GSparseMatrix matrix(g_rows,g_cols); + for (unsigned i = 0; i < g_elements; ++i) + matrix(g_row[i],g_col[i]) = g_matrix[i]; + return matrix; + } + catch (exception &e) { + cout << "TEST ERROR: Unable to set test matrix." << endl; + throw; + } +} + + +/*************************************************************************** + * Set test vector * + ***************************************************************************/ +GVector set_vector(void) +{ + try { + GVector vector(g_cols); + for (unsigned col = 0; col < g_cols; ++col) + vector(col) = g_vector[col]; + return vector; + } + catch (exception &e) { + cout << "TEST ERROR: Unable to set test vector." << endl; + throw; + } +} + + +/*************************************************************************** + * Check test matrix * + ***************************************************************************/ +int check_matrix(const GSparseMatrix& m, const double scale, const double add) +{ + int result = 1; + try { + for (unsigned row = 0; row < g_rows; ++row) { + for (unsigned col = 0; col < g_cols; ++col) { + unsigned i; + double ref_value = add; + for (i = 0; i < g_elements; ++i) { + if (g_row[i] == row && g_col[i] == col) { + ref_value = g_matrix[i] * scale + add; + break; + } + } + if (fabs(m(row,col)-ref_value) > 1.0e-15) { +//cout << row << "," << col << ": " << fabs(m(row,col)-ref_value) << endl; + result = 0; + break; + } + } + } + } + catch (exception &e) { + cout << "TEST ERROR: Unable to check test matrix." << endl; + throw; + } + return result; +} + + +/*************************************************************************** + * Check matrix*vector * + ***************************************************************************/ +int check_matrix_vector(const GVector& v) +{ + int result = 1; + try { + for (unsigned row = 0; row < v.size(); ++row) { + double value = 0.0; + for (unsigned col = 0; col < g_cols; ++col) { + unsigned i; + double ref_value = 0.0; + for (i = 0; i < g_elements; ++i) { + if (g_row[i] == row && g_col[i] == col) { + ref_value = g_matrix[i]; + break; + } + } + value += ref_value * g_vector[col]; + } + if (v(row) != value) { + result = 0; + break; + } + } + } + catch (exception &e) { + cout << "TEST ERROR: Unable to check matrix*vector product." << endl; + throw; + } + return result; +} + + +/*************************************************************************** + * Check matrix*matrix * + ***************************************************************************/ +int check_matrix_matrix(const GSparseMatrix& m) +{ + if (m.rows() != g_rows || m.cols() != g_rows) + return 0; + int result = 1; + try { + for (unsigned row = 0; row < m.rows(); ++row) { + for (unsigned col = 0; col < m.cols(); ++col) { + double value = 0.0; + for (unsigned i = 0; i < g_cols; ++i) { + unsigned k; + double ref_value_1 = 0.0; + double ref_value_2 = 0.0; + for (k = 0; k < g_elements; ++k) { + if (g_row[k] == row && g_col[k] == i) { + ref_value_1 = g_matrix[k]; + break; + } + } + for (k = 0; k < g_elements; ++k) { + if (g_row[k] == col && g_col[k] == i) { + ref_value_2 = g_matrix[k]; + break; + } + } + value += ref_value_1 * ref_value_2; + } +//cout << row << "," << col << ": " << fabs(m(row,col)-value) << endl; + if (m(row,col) != value) { + result = 0; + break; + } + } + } + } + catch (exception &e) { + cout << "TEST ERROR: Unable to check matrix*matrix product." << endl; + throw; + } + return result; +} + + +/*************************************************************************** + * Check transposed test matrix * + ***************************************************************************/ +int check_transpose_matrix(const GSparseMatrix& m, const double scale, const double add) +{ + int result = 1; + try { + for (unsigned row = 0; row < g_rows; ++row) { + for (unsigned col = 0; col < g_cols; ++col) { + unsigned i; + double ref_value = 0.0; + for (i = 0; i < g_elements; ++i) { + if (g_row[i] == row && g_col[i] == col) { + ref_value = g_matrix[i] * scale + add; + break; + } + } + if (fabs(m(col,row)-ref_value) > 1.0e-15) { + result = 0; + break; + } + } + } + } + catch (exception &e) { + cout << "TEST ERROR: Unable to check test matrix." << endl; + throw; + } + return result; +} + + +/*************************************************************************** + * Check matrix min * + ***************************************************************************/ +int check_matrix_min(const double min) +{ + double value = g_matrix[0]; + for (unsigned i = 0; i < g_elements; ++i) { + if (g_matrix[i] < value) + value = g_matrix[i]; + } +// return (min == value); + return (min == 0.0); +} + + +/*************************************************************************** + * Check matrix max * + ***************************************************************************/ +int check_matrix_max(const double max) +{ + double value = g_matrix[0]; + for (unsigned i = 0; i < g_elements; ++i) { + if (g_matrix[i] > value) + value = g_matrix[i]; + } + return (max == value); +} + + +/*************************************************************************** + * Check matrix sum * + ***************************************************************************/ +int check_matrix_sum(const double sum) +{ + double value = 0.0; + for (unsigned i = 0; i < g_elements; ++i) + value += g_matrix[i]; + return (sum == value); +} + + +/*************************************************************************** + * Test: Output * + ***************************************************************************/ +void test_output(const GSparseMatrix& m_test) +{ + cout << "Test GSparseMatrix: Output test matrix: " << endl; + try { + cout << m_test << endl; + } + catch (exception &e) { + cout << endl << "TEST ERROR: Unable to output matrix." << endl; + cout << e.what() << endl; + throw; + } +} + + +/*************************************************************************** + * Test: Allocate zero matrix * + ***************************************************************************/ +void test_allocate(void) +{ + cout << "Test GSparseMatrix: Allocate zero matrix: "; + try { + GSparseMatrix test(0,0); + } + catch (empty &e) { + cout << ". ok." << endl; + } + catch (exception &e) { + cout << endl << "TEST ERROR: Did not signal zero matrix allocation." << endl; + cout << e.what() << endl; + throw; + } + cout << ". ok." << endl; +} + + +/*************************************************************************** + * Test: Assign values * + ***************************************************************************/ +void test_assign_values(const GSparseMatrix& m_test) +{ + cout << "Test GSparseMatrix: Assign matrix values: "; + try { + // + GSparseMatrix test(3,3); + test(1,1) = 1.0; + if (test(0,0) != 0.0 || test(1,0) != 0.0 || test(2,0) != 0.0 || + test(0,1) != 0.0 || test(1,1) != 1.0 || test(2,1) != 0.0 || + test(0,2) != 0.0 || test(1,2) != 0.0 || test(2,2) != 0.0) { + cout << endl << "TEST ERROR: Unable to set matrix values." << endl; + cout << test << endl; + throw; + } + cout << "."; + // + GSparseMatrix result = m_test; + result(0,0) = 0.0; + result(0,0) = 1.0; + if (!check_matrix(result, 1.0, 0.0) || !check_matrix(m_test, 1.0, 0.0)) { + cout << endl << "TEST ERROR: Bad M(row,col) assignment." << endl; + cout << "result:" << endl << result << endl; + cout << "m_test:" << endl << m_test << endl; + throw; + } + cout << "."; + // + result = m_test; + result(0,0) = 0.0; + result(0,4) = 0.0; + result(0,0) = 1.0; + result(0,4) = 0.0; + result(0,4) = 7.0; + if (!check_matrix(result, 1.0, 0.0) || !check_matrix(m_test, 1.0, 0.0)) { + cout << endl << "TEST ERROR: Bad M(row,col) assignment." << endl; + cout << "result:" << endl << result << endl; + cout << "m_test:" << endl << m_test << endl; + throw; + } + cout << "."; + // + result = m_test; + result(0,1) = 2.0; + result(0,2) = 2.0; + result(0,3) = 2.0; + result(0,1) = 0.0; + result(0,2) = 0.0; + result(0,3) = 0.0; + if (!check_matrix(result, 1.0, 0.0) || !check_matrix(m_test, 1.0, 0.0)) { + cout << endl << "TEST ERROR: Bad M(row,col) assignment." << endl; + cout << "result:" << endl << result << endl; + cout << "m_test:" << endl << m_test << endl; + throw; + } + cout << "."; + } + catch (exception &e) { + cout << e.what() << endl; + throw; + } + #if defined(G_RANGE_CHECK) + try { + GSparseMatrix test(3,3); + test(3,3) = 1.0; + } + catch (GMatrix::out_of_range &e) { + } + catch (exception &e) { + cout << e.what() << endl; + throw; + } + cout << "."; + #endif + cout << " ok." << endl; +} + + +/*************************************************************************** + * Test: Matrix copy constructor * + ***************************************************************************/ +void test_copy_constructor(const GSparseMatrix& m_test) +{ + cout << "Test GSparseMatrix: Define matrix using copy constructor: "; + try { + // + GSparseMatrix test = m_test; + if (!check_matrix(test, 1.0, 0.0) || !check_matrix(m_test, 1.0, 0.0)) { + cout << endl << "TEST ERROR: Corrupt copy constructor." << endl; + cout << test << endl; + throw; + } + } + catch (exception &e) { + cout << e.what() << endl; + throw; + } + cout << ". ok." << endl; +} + + +/*************************************************************************** + * Test: Matrix assignment * + ***************************************************************************/ +void test_assign_matrix(const GSparseMatrix& m_test) +{ + cout << "Test GSparseMatrix: Matrix assignment: "; + try { + // + // GSparseMatrix = GSparseMatrix + GSparseMatrix result(1,1); + result = m_test; + if (!check_matrix(result, 1.0, 0.0) || !check_matrix(m_test, 1.0, 0.0)) { + cout << endl << "TEST ERROR: Corrupt assignment." << endl; + cout << result << endl; + throw; + } + cout << "."; + // + // GSparseMatrix = GSparseMatrix (bigger matrix) + GSparseMatrix bigger(1000,1000); + for (int i = 0; i < 1000; ++i) + bigger(i,i) = (i+1)*1.1; + result = bigger; + cout << "."; + } + catch (exception &e) { + cout << e.what() << endl; + throw; + } + cout << " ok." << endl; +} + + +/*************************************************************************** + * Test: Matrix transpose * + ***************************************************************************/ +void test_transpose(const GSparseMatrix& m_test) +{ + cout << "Test GSparseMatrix: Matrix transpose: "; + try { + // + // transpose(GSparseMatrix) + GSparseMatrix result(1,1); + result = transpose(m_test); + if (!check_transpose_matrix(result, 1.0, 0.0) || !check_matrix(m_test, 1.0, 0.0)) { + cout << endl << "TEST ERROR: Corrupt transpose(GSparseMatrix) function." << endl; + cout << result << endl; + throw; + } + cout << "."; + // + // GSparseMatrix.transpose() + result = m_test; + result.transpose(); + if (!check_transpose_matrix(result, 1.0, 0.0) || !check_matrix(m_test, 1.0, 0.0)) { + cout << endl << "TEST ERROR: Corrupt GSparseMatrix.transpose() function." << endl; + cout << result << endl; + throw; + } + cout << "."; + } + catch (exception &e) { + cout << e.what() << endl; + throw; + } + cout << " ok." << endl; +} + + +/*************************************************************************** + * Test: Matrix*Vector multiplication * + ***************************************************************************/ +void test_matrix_vector(const GSparseMatrix& m_test, const GVector& v_test) +{ + cout << "Test GSparseMatrix: Matrix*Vector multiplication: "; + try { + // + GVector test = m_test*v_test; + if (!check_matrix_vector(test) || !check_matrix(m_test, 1.0, 0.0)) { + cout << endl << "TEST ERROR: Corrupt Matrix*Vector multiplication." << endl; + cout << test << endl; + throw; + } + } + catch (exception &e) { + cout << e.what() << endl; + throw; + } + cout << "."; + try { + GSparseMatrix bigger(1000,1000); + for (int i = 0; i < 1000; ++i) + bigger(i,i) = (i+1)*1.1; + GVector test = bigger*v_test; + } + catch (GMatrix::matrix_vector_mismatch &e) { + } + catch (exception &e) { + cout << e.what() << endl; + throw; + } + cout << ". ok." << endl; +} + + +/*************************************************************************** + * Test: Matrix*Vector multiplication * + ***************************************************************************/ +void test_matrix_matrix(const GSparseMatrix& m_test) +{ + cout << "Test GSparseMatrix: Matrix*Matrix multiplication: "; + try { + // + GSparseMatrix test = m_test * transpose(m_test); + if (!check_matrix_matrix(test) || !check_matrix(m_test, 1.0, 0.0)) { + cout << endl << "TEST ERROR: Corrupt Matrix*Matrix multiplication." << endl; + cout << "test:" << endl << test << endl; + cout << "m_test:" << endl << m_test << endl; + throw; + } + cout << "."; + // + GSparseMatrix bigger(1000,1000); + for (int i = 0; i < 1000; ++i) + bigger(i,i) = (i+1)*1.1; + try { + GSparseMatrix test = m_test * bigger; + } + catch (GMatrix::matrix_mismatch &e) { + cout << "."; + } + catch (exception &e) { + cout << e.what() << endl; + throw; + } + // + try { + GSparseMatrix test7 = bigger * m_test; + } + catch (GMatrix::matrix_mismatch &e) { + cout << "."; + } + catch (exception &e) { + cout << e.what() << endl; + throw; + } + } + catch (exception &e) { + cout << e.what() << endl; + throw; + } + cout << " ok." << endl; +} + + +/*************************************************************************** + * Test: Arithmetics * + ***************************************************************************/ +void test_arithmetics(const GSparseMatrix& m_test) +{ + cout << "Test GSparseMatrix: Arithmetics: "; + try { + // + // -GSparseMatrix + GSparseMatrix result(1,1); + result = -m_test; + if (!check_matrix(result, -1.0, 0.0) || !check_matrix(m_test, 1.0, 0.0)) { + cout << endl << "TEST ERROR: Corrupt -GSparseMatrix operator." << endl; + cout << "result " << result << endl; + cout << "m_test " << m_test << endl; + throw; + } + cout << "."; + // + // fabs(GSparseMatrix) + result = fabs(m_test); + if (!check_matrix(result, 1.0, 0.0) || !check_matrix(m_test, 1.0, 0.0)) { + cout << endl << "TEST ERROR: Corrupt fabs(GSparseMatrix) function." << endl; + cout << "result " << result << endl; + cout << "m_test " << m_test << endl; + throw; + } + cout << "."; + // + // GSparseMatrix += GSparseMatrix + result = m_test; + result += m_test; + if (!check_matrix(result, 2.0, 0.0) || !check_matrix(m_test, 1.0, 0.0)) { + cout << endl << "TEST ERROR: Corrupt GSparseMatrix += GSparseMatrix operator." << endl; + cout << "result " << result << endl; + cout << "m_test " << m_test << endl; + throw; + } + cout << "."; + // + // GSparseMatrix -= GSparseMatrix + result = m_test; + result -= m_test; + if (!check_matrix(result, 0.0, 0.0) || !check_matrix(m_test, 1.0, 0.0)) { + cout << endl << "TEST ERROR: Corrupt GSparseMatrix -= GSparseMatrix operator." << endl; + cout << "result " << result << endl; + cout << "m_test " << m_test << endl; + throw; + } + cout << "."; + // + // GSparseMatrix *= 3.0 + result = m_test; + result *= 3.0; + if (!check_matrix(result, 3.0, 0.0) || !check_matrix(m_test, 1.0, 0.0)) { + cout << endl << "TEST ERROR: Corrupt GSparseMatrix *= double operator." << endl; + cout << "result " << result << endl; + cout << "m_test " << m_test << endl; + throw; + } + cout << "."; + // + // GSparseMatrix /= 3.0 + result = m_test; + result /= 3.0; + if (!check_matrix(result, 1.0/3.0, 0.0) || !check_matrix(m_test, 1.0, 0.0)) { + cout << endl << "TEST ERROR: Corrupt GSparseMatrix /= double operator." << endl; + cout << "result " << result << endl; + cout << "m_test " << m_test << endl; + throw; + } + cout << "."; + // + // GSparseMatrix + GSparseMatrix + result = m_test + m_test; + if (!check_matrix(result, 2.0, 0.0) || !check_matrix(m_test, 1.0, 0.0)) { + cout << endl << "TEST ERROR: Corrupt GSparseMatrix + GSparseMatrix operator." << endl; + cout << "result " << result << endl; + cout << "m_test " << m_test << endl; + throw; + } + cout << "."; + // + // GSparseMatrix - GSparseMatrix + result = m_test - m_test; + if (!check_matrix(result, 0.0, 0.0) || !check_matrix(m_test, 1.0, 0.0)) { + cout << endl << "TEST ERROR: Corrupt GSparseMatrix - GSparseMatrix operator." << endl; + cout << "result " << result << endl; + cout << "m_test " << m_test << endl; + throw; + } + cout << "."; + // + // GSparseMatrix - GSparseMatrix + result = m_test - m_test; + if (!check_matrix(result, 0.0, 0.0) || !check_matrix(m_test, 1.0, 0.0)) { + cout << endl << "TEST ERROR: Corrupt GSparseMatrix - GSparseMatrix operator." << endl; + cout << "result " << result << endl; + cout << "m_test " << m_test << endl; + throw; + } + cout << "."; + // + // GSparseMatrix * 3.0 + result = m_test * 3.0; + if (!check_matrix(result, 3.0, 0.0) || !check_matrix(m_test, 1.0, 0.0)) { + cout << endl << "TEST ERROR: Corrupt GSparseMatrix * double operator." << endl; + cout << "result " << result << endl; + cout << "m_test " << m_test << endl; + throw; + } + cout << "."; + // + // GSparseMatrix * -7.12 + result = m_test * -7.12; + if (!check_matrix(result, -7.12, 0.0) || !check_matrix(m_test, 1.0, 0.0)) { + cout << endl << "TEST ERROR: Corrupt GSparseMatrix * double operator." << endl; + cout << "result " << result << endl; + cout << "m_test " << m_test << endl; + throw; + } + cout << "."; + // + // 3.0 * GSparseMatrix + result = 3.0 * m_test; + if (!check_matrix(result, 3.0, 0.0) || !check_matrix(m_test, 1.0, 0.0)) { + cout << endl << "TEST ERROR: Corrupt double * GSparseMatrix operator." << endl; + cout << "result " << result << endl; + cout << "m_test " << m_test << endl; + throw; + } + cout << "."; + // + // GSparseMatrix / 3.0 + result = m_test / 3.0; + if (!check_matrix(result, 1.0/3.0, 0.0) || !check_matrix(m_test, 1.0, 0.0)) { + cout << endl << "TEST ERROR: Corrupt GSparseMatrix / double operator." << endl; + cout << "result " << result << endl; + cout << "m_test " << m_test << endl; + throw; + } + cout << "."; + // + // GSparseMatrix / 0.0 + double zero = 0.0; + result = m_test / zero; + if (!check_matrix(result, 1.0/zero, 0.0) || !check_matrix(m_test, 1.0, 0.0)) { + cout << endl << "TEST ERROR: Corrupt GSparseMatrix / 0.0." << endl; + cout << "result " << result << endl; + cout << "m_test " << m_test << endl; + throw; + cout << "."; + } + // + // GSparseMatrix.add_col() + result = m_test; + GVector v_add(g_rows); + for (int i = 0; i < g_rows; ++i) + v_add(i) = 7.0; + for (int col = 0; col < g_cols; ++col) + result.add_col(v_add, col); + if (!check_matrix(result, 1.0, 7.0) || !check_matrix(m_test, 1.0, 0.0)) { + cout << endl << "TEST ERROR: Corrupt GSparseMatrix.add_col(+v)." << endl; + cout << "result " << result << endl; + cout << "m_test " << m_test << endl; + throw; + } + cout << "."; + // + // GSparseMatrix.add_col() + for (int col = 0; col < g_cols; ++col) + result.add_col(-v_add, col); + if (!check_matrix(result, 1.0, 0.0) || !check_matrix(m_test, 1.0, 0.0)) { + cout << endl << "TEST ERROR: Corrupt GSparseMatrix.add_col(-v)." << endl; + cout << "result " << result << endl; + cout << "m_test " << m_test << endl; + throw; + } + cout << "."; + } + catch (exception &e) { + cout << e.what() << endl; + throw; + } + try { + GSparseMatrix bigger(1000,1000); + GSparseMatrix result(1,1); + for (int i = 0; i < 1000; ++i) + bigger(i,i) = (i+1)*1.1; + result = m_test; + result += bigger; + } + catch (GMatrix::matrix_mismatch) { + cout << "."; + } + catch (exception &e) { + cout << e.what() << endl; + throw; + } + cout << " ok." << endl; +} + + +/*************************************************************************** + * Test: Matrix functions * + ***************************************************************************/ +void test_functions(const GSparseMatrix& m_test) +{ + cout << "Test GSparseMatrix: Matrix functions: "; + try { + // + double min = m_test.min(); + if (!check_matrix_min(min)) { + cout << endl << "TEST ERROR: Corrupt GSparseMatrix.min() function." << endl; + cout << "min:" << min << endl; + throw; + } + cout << "."; + // + double max = m_test.max(); + if (!check_matrix_max(max)) { + cout << endl << "TEST ERROR: Corrupt GSparseMatrix.max() function." << endl; + cout << "max:" << max << endl; + throw; + } + cout << "."; + // + double sum = m_test.sum(); + if (!check_matrix_sum(sum)) { + cout << endl << "TEST ERROR: Corrupt GSparseMatrix.sum() function." << endl; + cout << "sum:" << sum << endl; + throw; + } + cout << "."; + } + catch (exception &e) { + cout << e.what() << endl; + } + cout << " ok." << endl; +} + + +/*************************************************************************** + * Test: Matrix comparison * + ***************************************************************************/ +void test_comparison(const GSparseMatrix& m_test) +{ + cout << "Test GSparseMatrix: Comparison: "; + try { + GSparseMatrix bigger(1000,1000); + for (int i = 0; i < 1000; ++i) + bigger(i,i) = (i+1)*1.1; + // + if ((m_test == m_test) != 1) { + cout << endl << "TEST ERROR: Corrupt GSparseMatrix == GSparseMatrix operator." << endl; + throw; + } + cout << "."; + // + GSparseMatrix test(g_rows,g_cols); + if ((m_test == test) != 0) { + cout << endl << "TEST ERROR: Corrupt GSparseMatrix == GSparseMatrix operator." << endl; + throw; + } + cout << "."; + // + if ((m_test == bigger) != 0) { + cout << endl << "TEST ERROR: Corrupt GSparseMatrix == GSparseMatrix operator." << endl; + throw; + } + cout << "."; + // + if ((m_test != m_test) != 0) { + cout << endl << "TEST ERROR: Corrupt GSparseMatrix != GSparseMatrix operator." << endl; + throw; + } + cout << "."; + // + if ((m_test != test) != 1) { + cout << endl << "TEST ERROR: Corrupt GSparseMatrix != GSparseMatrix operator." << endl; + throw; + } + cout << "."; + // + if ((m_test != bigger) != 1) { + cout << endl << "TEST ERROR: Corrupt GSparseMatrix != GSparseMatrix operator." << endl; + throw; + } + cout << "."; + } + catch (exception &e) { + cout << e.what() << endl; + throw; + } + cout << " ok." << endl; +} + + +/*************************************************************************** + * Test: Matrix conversions * + ***************************************************************************/ +void test_conversion(const GSparseMatrix& m_test) +{ + cout << "Test GSparseMatrix: Conversions: "; + cout << " ok." << endl; +} + + +/*************************************************************************** + * Test: Cholesky factorisation * + ***************************************************************************/ +void test_cholesky(void) +{ + cout << "Test GSparseMatrix: Cholesky decomposition, solver and inverter: "; + try { + // + // Setup matrix for Cholesky decomposition + GSparseMatrix m_chol_test(5,5); + m_chol_test(0,0) = 1.0; + m_chol_test(0,1) = 0.2; + m_chol_test(0,2) = 0.2; + m_chol_test(0,3) = 0.2; + m_chol_test(0,4) = 0.2; + m_chol_test(1,0) = 0.2; + m_chol_test(2,0) = 0.2; + m_chol_test(3,0) = 0.2; + m_chol_test(4,0) = 0.2; + m_chol_test(1,1) = 1.0; + m_chol_test(2,2) = 1.0; + m_chol_test(3,3) = 1.0; + m_chol_test(4,4) = 1.0; + // + // Try to solve now (should not work) + try { + GVector v_test12(5); + v_test12 = m_chol_test.cholesky_solver(v_test12); + } + catch (GMatrix::matrix_not_factorised) { + cout << "."; + } + catch (exception &e) { + cout << e.what() << endl; + throw; + } + // + // Test Cholesky decomposition + GSparseMatrix cd = cholesky_decompose(m_chol_test); + cout << "."; + // + // Test inplace Cholesky decomposition + cd = m_chol_test; + cd.cholesky_decompose(); + cout << "."; + // + // Test Cholesky solver + GVector e0(5); + GVector a0(5); + e0(0) = 1.0; + a0(0) = 1.0; + a0(1) = 0.2; + a0(2) = 0.2; + a0(3) = 0.2; + a0(4) = 0.2; + GVector s0 = cd.cholesky_solver(a0); + double res = max(fabs(s0-e0)); + if (res < 1.0e-15) + #if defined(DUMP_RESIDUALS) + cout << " Res(S0)=" << res << " "; + #else + cout << "."; + #endif + else { + cout << endl << "TEST ERROR: Corrupt cholesky_solver(GVector) function." << endl; + cout << "Residual vector (all elements should be zero):" << endl; + cout << s0 << endl; + throw; + } + // + e0(0) = 0.0; + e0(1) = 1.0; + a0(0) = 0.2; + a0(1) = 1.0; + a0(2) = 0.0; + a0(3) = 0.0; + a0(4) = 0.0; + s0 = cd.cholesky_solver(a0); + res = max(fabs(s0-e0)); + if (res < 1.0e-15) + #if defined(DUMP_RESIDUALS) + cout << "Res(S1)=" << res << " "; + #else + cout << "."; + #endif + else { + cout << endl << "TEST ERROR: Corrupt cholesky_solver(GVector) function." << endl; + cout << "Residual vector (all elements should be zero):" << endl; + cout << s0 << endl; + throw; + } + // + e0(1) = 0.0; + e0(2) = 1.0; + a0(1) = 0.0; + a0(2) = 1.0; + s0 = cd.cholesky_solver(a0); + res = max(fabs(s0-e0)); + if (res < 1.0e-15) + #if defined(DUMP_RESIDUALS) + cout << "Res(S2)=" << res << " "; + #else + cout << "."; + #endif + else { + cout << endl << "TEST ERROR: Corrupt cholesky_solver(GVector) function." << endl; + cout << "Residual vector (all elements should be zero):" << endl; + cout << s0 << endl; + throw; + } + // + e0(2) = 0.0; + e0(3) = 1.0; + a0(2) = 0.0; + a0(3) = 1.0; + s0 = cd.cholesky_solver(a0); + res = max(fabs(s0-e0)); + if (res < 1.0e-15) + #if defined(DUMP_RESIDUALS) + cout << "Res(S3)=" << res << " "; + #else + cout << "."; + #endif + else { + cout << endl << "TEST ERROR: Corrupt cholesky_solver(GVector) function." << endl; + cout << "Residual vector (all elements should be zero):" << endl; + cout << s0 << endl; + throw; + } + // + e0(3) = 0.0; + e0(4) = 1.0; + a0(3) = 0.0; + a0(4) = 1.0; + s0 = cd.cholesky_solver(a0); + res = max(fabs(s0-e0)); + if (res < 1.0e-15) + #if defined(DUMP_RESIDUALS) + cout << "Res(S4)=" << res << " "; + #else + cout << "."; + #endif + else { + cout << endl << "TEST ERROR: Corrupt cholesky_solver(GVector) function." << endl; + cout << "Residual vector (all elements should be zero):" << endl; + cout << s0 << endl; + throw; + } + // + // Setup matrix for Cholesky decomposition with zero row/col + GSparseMatrix m_chol_test_zero(6,6); + m_chol_test_zero(0,0) = 1.0; + m_chol_test_zero(0,1) = 0.2; + m_chol_test_zero(0,2) = 0.2; + m_chol_test_zero(0,4) = 0.2; + m_chol_test_zero(0,5) = 0.2; + m_chol_test_zero(1,0) = 0.2; + m_chol_test_zero(2,0) = 0.2; + m_chol_test_zero(4,0) = 0.2; + m_chol_test_zero(5,0) = 0.2; + m_chol_test_zero(1,1) = 1.0; + m_chol_test_zero(2,2) = 1.0; + m_chol_test_zero(4,4) = 1.0; + m_chol_test_zero(5,5) = 1.0; + // + // Test compressed Cholesky decomposition + GSparseMatrix cd_zero = m_chol_test_zero; + cd_zero.cholesky_decompose(); + // + // Test compressed Cholesky solver + e0 = GVector(6); + a0 = GVector(6); + e0(0) = 1.0; + a0(0) = 1.0; + a0(1) = 0.2; + a0(2) = 0.2; + a0(4) = 0.2; + a0(5) = 0.2; + s0 = cd_zero.cholesky_solver(a0); + res = max(fabs(s0-e0)); + if (res < 1.0e-15) + #if defined(DUMP_RESIDUALS) + cout << "Res(S0Z)=" << res << " "; + #else + cout << "."; + #endif + else { + cout << endl << "TEST ERROR: Corrupt cholesky_solver(GVector) function." << endl; + cout << "Residual vector (all elements should be zero):" << endl; + cout << s0 << endl; + throw; + } + // + e0(0) = 0.0; + e0(1) = 1.0; + a0(0) = 0.2; + a0(1) = 1.0; + a0(2) = 0.0; + a0(4) = 0.0; + a0(5) = 0.0; + s0 = cd_zero.cholesky_solver(a0); + res = max(fabs(s0-e0)); + if (res < 1.0e-15) + #if defined(DUMP_RESIDUALS) + cout << "Res(S1Z)=" << res << " "; + #else + cout << "."; + #endif + else { + cout << endl << "TEST ERROR: Corrupt cholesky_solver(GVector) function." << endl; + cout << "Residual vector (all elements should be zero):" << endl; + cout << s0 << endl; + throw; + } + // + e0(1) = 0.0; + e0(2) = 1.0; + a0(1) = 0.0; + a0(2) = 1.0; + s0 = cd_zero.cholesky_solver(a0); + res = max(fabs(s0-e0)); + if (res < 1.0e-15) + #if defined(DUMP_RESIDUALS) + cout << "Res(S2Z)=" << res << " "; + #else + cout << "."; + #endif + else { + cout << endl << "TEST ERROR: Corrupt cholesky_solver(GVector) function." << endl; + cout << "Residual vector (all elements should be zero):" << endl; + cout << s0 << endl; + throw; + } + // + e0(2) = 0.0; + e0(4) = 1.0; + a0(2) = 0.0; + a0(4) = 1.0; + s0 = cd_zero.cholesky_solver(a0); + res = max(fabs(s0-e0)); + if (res < 1.0e-15) + #if defined(DUMP_RESIDUALS) + cout << "Res(S3Z)=" << res << " "; + #else + cout << "."; + #endif + else { + cout << endl << "TEST ERROR: Corrupt cholesky_solver(GVector) function." << endl; + cout << "Residual vector (all elements should be zero):" << endl; + cout << s0 << endl; + throw; + } + // + e0(4) = 0.0; + e0(5) = 1.0; + a0(4) = 0.0; + a0(5) = 1.0; + s0 = cd_zero.cholesky_solver(a0); + res = max(fabs(s0-e0)); + if (res < 1.0e-15) + #if defined(DUMP_RESIDUALS) + cout << "Res(S4Z)=" << res << " "; + #else + cout << "."; + #endif + else { + cout << endl << "TEST ERROR: Corrupt cholesky_solver(GVector) function." << endl; + cout << "Residual vector (all elements should be zero):" << endl; + cout << s0 << endl; + throw; + } + // + // Setup matrix for Cholesky decomposition with zero row/col (unsymmetric case) + GSparseMatrix m_chol_test_zero2(6,5); + m_chol_test_zero2(0,0) = 1.0; + m_chol_test_zero2(0,1) = 0.2; + m_chol_test_zero2(0,2) = 0.2; + m_chol_test_zero2(0,3) = 0.2; + m_chol_test_zero2(0,4) = 0.2; + m_chol_test_zero2(1,0) = 0.2; + m_chol_test_zero2(2,0) = 0.2; + m_chol_test_zero2(4,0) = 0.2; + m_chol_test_zero2(5,0) = 0.2; + m_chol_test_zero2(1,1) = 1.0; + m_chol_test_zero2(2,2) = 1.0; + m_chol_test_zero2(4,3) = 1.0; + m_chol_test_zero2(5,4) = 1.0; + // + // Test compressed Cholesky decomposition (unsymmetric case) + GSparseMatrix cd_zero2 = m_chol_test_zero2; + cd_zero2.cholesky_decompose(); + // + // Test compressed Cholesky solver (unsymmetric case) + e0 = GVector(5); + a0 = GVector(6); + e0(0) = 1.0; + a0(0) = 1.0; + a0(1) = 0.2; + a0(2) = 0.2; + a0(4) = 0.2; + a0(5) = 0.2; + s0 = cd_zero2.cholesky_solver(a0); + res = max(fabs(s0-e0)); + if (res < 1.0e-15) + #if defined(DUMP_RESIDUALS) + cout << "Res(S0ZU)=" << res << " "; + #else + cout << "."; + #endif + else { + cout << endl << "TEST ERROR: Corrupt cholesky_solver(GVector) function." << endl; + cout << "Residual vector (all elements should be zero):" << endl; + cout << s0 << endl; + throw; + } + // + e0(0) = 0.0; + e0(1) = 1.0; + a0(0) = 0.2; + a0(1) = 1.0; + a0(2) = 0.0; + a0(4) = 0.0; + a0(5) = 0.0; + s0 = cd_zero2.cholesky_solver(a0); + res = max(fabs(s0-e0)); + if (res < 1.0e-15) + #if defined(DUMP_RESIDUALS) + cout << "Res(S1ZU)=" << res << " "; + #else + cout << "."; + #endif + else { + cout << endl << "TEST ERROR: Corrupt cholesky_solver(GVector) function." << endl; + cout << "Residual vector (all elements should be zero):" << endl; + cout << s0 << endl; + throw; + } + // + e0(1) = 0.0; + e0(2) = 1.0; + a0(1) = 0.0; + a0(2) = 1.0; + s0 = cd_zero2.cholesky_solver(a0); + res = max(fabs(s0-e0)); + if (res < 1.0e-15) + #if defined(DUMP_RESIDUALS) + cout << "Res(S2ZU)=" << res << " "; + #else + cout << "."; + #endif + else { + cout << endl << "TEST ERROR: Corrupt cholesky_solver(GVector) function." << endl; + cout << "Residual vector (all elements should be zero):" << endl; + cout << s0 << endl; + throw; + } + // + e0(2) = 0.0; + e0(3) = 1.0; + a0(2) = 0.0; + a0(4) = 1.0; + s0 = cd_zero2.cholesky_solver(a0); + res = max(fabs(s0-e0)); + if (res < 1.0e-15) + #if defined(DUMP_RESIDUALS) + cout << "Res(S3ZU)=" << res << " "; + #else + cout << "."; + #endif + else { + cout << endl << "TEST ERROR: Corrupt cholesky_solver(GVector) function." << endl; + cout << "Residual vector (all elements should be zero):" << endl; + cout << s0 << endl; + throw; + } + // + e0(3) = 0.0; + e0(4) = 1.0; + a0(4) = 0.0; + a0(5) = 1.0; + s0 = cd_zero2.cholesky_solver(a0); + res = max(fabs(s0-e0)); + if (res < 1.0e-15) + #if defined(DUMP_RESIDUALS) + cout << "Res(S4ZU)=" << res << " "; + #else + cout << "."; + #endif + else { + cout << endl << "TEST ERROR: Corrupt cholesky_solver(GVector) function." << endl; + cout << "Residual vector (all elements should be zero):" << endl; + cout << s0 << endl; + throw; + } + // + // Test Cholesky inverter (inplace) + GSparseMatrix unit(5,5); + unit(0,0) = 1.0; + unit(1,1) = 1.0; + unit(2,2) = 1.0; + unit(3,3) = 1.0; + unit(4,4) = 1.0; + GSparseMatrix m_chol_test_inv = m_chol_test; + m_chol_test_inv.cholesky_invert(); + GSparseMatrix ci_product = m_chol_test * m_chol_test_inv; + GSparseMatrix ci_residuals = ci_product - unit; + res = (fabs(ci_residuals)).max(); + if (res < 1.0e-15) + #if defined(DUMP_RESIDUALS) + cout << "Res(CI)=" << res << " "; + #else + cout << "."; + #endif + else { + cout << endl << "TEST ERROR: Corrupt GSparseMatrix.cholesky_invert() function." << endl; + cout << "Residual matrix (all elements should be zero):" << endl; + cout << ci_residuals << endl; + throw; + } + // + // Test Cholesky inverter + m_chol_test_inv = cholesky_invert(m_chol_test); + ci_product = m_chol_test * m_chol_test_inv; + ci_residuals = ci_product - unit; + res = (fabs(ci_residuals)).max(); + if (res < 1.0e-15) + #if defined(DUMP_RESIDUALS) + cout << "Res(CI2)=" << res << " "; + #else + cout << "."; + #endif + else { + cout << endl << "TEST ERROR: Corrupt cholesky_invert(GSparseMatrix) function." << endl; + cout << "Residual matrix (all elements should be zero):" << endl; + cout << ci_residuals << endl; + throw; + } + // + // Test Cholesky inverter for compressed matrix + unit = GSparseMatrix(6,6); + unit(0,0) = 1.0; + unit(1,1) = 1.0; + unit(2,2) = 1.0; + unit(4,4) = 1.0; + unit(5,5) = 1.0; + GSparseMatrix m_chol_test_zero_inv = m_chol_test_zero; + m_chol_test_zero_inv.cholesky_invert(); + GSparseMatrix ciz_product = m_chol_test_zero * m_chol_test_zero_inv; + GSparseMatrix ciz_residuals = ciz_product - unit; + res = (fabs(ciz_residuals)).max(); + if (res < 1.0e-15) + #if defined(DUMP_RESIDUALS) + cout << "Res(CIZ)=" << res << " "; + #else + cout << "."; + #endif + else { + cout << endl << "TEST ERROR: Corrupt compressed GSparseMatrix.cholesky_invert() function." << endl; + cout << "Residual matrix (all elements should be zero):" << endl; + cout << ciz_residuals << endl; + throw; + } + } + catch (exception &e) { + cout << e.what() << endl; + throw; + } + cout << "ok." << endl; +} + + +/*************************************************************************** + * Test: Heavy calculus * + ***************************************************************************/ +void test_heavy() +{ + // Allocate some variables + clock_t t_start; + double t_elapse; + int number; + + // Perform test + cout << "Test GSparseMatrix: Heavy calculus: "; + try { + // + // Fill 10000 x 10000 matrix with 10000 values + number = 10000; + t_start = clock(); + GSparseMatrix large(number,number); + for (int i = 0; i < number; ++i) + large(i,i) = (i+1)*3.14; + t_elapse = double(clock() - t_start)/double(CLOCKS_PER_SEC); + #if defined(DUMP_TIMING) + cout << endl << " - Fill of 10000 values needed " << t_elapse << + " sec (reference ~ 1.9 sec)"; + #endif + // + // Modify 10000 x 10000 matrix with 10000 (exisiting) values + t_start = clock(); + for (int i = 0; i < number; ++i) + large(i,i) = (i+1)*1.0; + t_elapse = double(clock() - t_start)/double(CLOCKS_PER_SEC); + #if defined(DUMP_TIMING) + cout << endl << " - Modification of 10000 values needed " << t_elapse << + " sec (reference ~ 0 sec)"; + #endif + // + // Subsequent addition and subtractions + number = 300; + t_start = clock(); + GSparseMatrix sum(number,number); + GSparseMatrix add(number,number); + GSparseMatrix sub(number,number); + for (int i = 0; i < number; ++i) { + add(i,number-i-1) = (i*i+1)*0.01; + sum += add; + sub(i,i) = (i+1)*1.0; + sum -= sub; + } + t_elapse = double(clock() - t_start)/double(CLOCKS_PER_SEC); + #if defined(DUMP_TIMING) + cout << endl << " - Matrix adding and subtraction 300 times " << t_elapse << + " sec (reference ~ 1.5 sec)"; + #endif + // + // Subsequent multiplications + t_start = clock(); + GSparseMatrix fac(number,number); + for (int i = 0; i < 1; ++i) { + for (int j = 0; j < number; ++j) + fac(j,j) = (i+1)*1.0; + sum *= fac; + } + t_elapse = double(clock() - t_start)/double(CLOCKS_PER_SEC); + #if defined(DUMP_TIMING) + cout << endl << " - Matrix multiplication 1 times " << t_elapse << + " sec (reference ~ 3.5 sec)"; + #endif + } + catch (exception &e) { + cout << e.what() << endl; + throw; + } + #if defined(DUMP_TIMING) + cout << endl; + #endif + cout << "ok." << endl; +} + + +/*************************************************************************** + * Main test function * + ***************************************************************************/ +int main(void) +{ + // Dump header + cout << endl; + cout << "*******************************" << endl; + cout << "* GSparseMatrix class testing *" << endl; + cout << "*******************************" << endl; + + // Set test matrix and vector + GSparseMatrix m_test = set_matrix(); + GVector v_test = set_vector(); + + // Execute the tests + test_output(m_test); + test_allocate(); + test_assign_values(m_test); + test_copy_constructor(m_test); + test_assign_matrix(m_test); + test_transpose(m_test); + test_matrix_vector(m_test, v_test); + test_matrix_matrix(m_test); + test_arithmetics(m_test); + test_functions(m_test); + test_comparison(m_test); + test_conversion(m_test); + test_cholesky(); + test_heavy(); + + // Return + return 0; +} diff --git a/test/test_GSparseMatrix.hpp b/test/test_GSparseMatrix.hpp new file mode 100644 index 0000000..dcdefba --- /dev/null +++ b/test/test_GSparseMatrix.hpp @@ -0,0 +1,23 @@ +/*************************************************************************** + * test_GSparseMatrix.hpp - test GSparseMatrix class * + * ----------------------------------------------------------------------- * + * copyright : (C) 2006 by Jurgen Knodlseder * + * ----------------------------------------------------------------------- * + * * + * 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 2 of the License, or * + * (at your option) any later version. * + * * + ***************************************************************************/ + +#ifndef TEST_GSPARSEMATRIX_HPP +#define TEST_GSPARSEMATRIX_HPP + +/* __ Includes ___________________________________________________________ */ +#include "../src/GSparseMatrix.hpp" +#include // cout, cerr +#include // std::exception +#include + +#endif /* TEST_GSPARSEMATRIX_HPP */ diff --git a/test/test_GSymMatrix.cpp b/test/test_GSymMatrix.cpp index 9974d9a..507391e 100644 --- a/test/test_GSymMatrix.cpp +++ b/test/test_GSymMatrix.cpp @@ -99,7 +99,7 @@ int check_matrix(const GSymMatrix& m, const double scale, const double add) for (unsigned row = 0; row < g_rows; ++row) { for (unsigned col = 0; col < g_cols; ++col) { double value = g_matrix[col+row*g_cols] * scale + add; - if (m(row,col) != value) { + if (fabs(m(row,col)-value) > 1.0e-15) { result = 0; break; } @@ -219,15 +219,15 @@ int check_matrix_vector(const GVector& v) ***************************************************************************/ int check_matrix_matrix(const GSymMatrix& m) { - if (m.rows() != g_rows || m.cols() != g_cols) + if (m.rows() != g_rows || m.cols() != g_rows) return 0; int result = 1; try { - for (unsigned row = 0; row < g_rows; ++row) { - for (unsigned col = 0; col < g_cols; ++col) { + for (unsigned row = 0; row < m.rows(); ++row) { + for (unsigned col = 0; col < m.cols(); ++col) { double value = 0.0; for (unsigned i = 0; i < g_cols; ++i) - value += g_matrix[i+row*g_cols] * g_matrix[row+i*g_cols]; + value += g_matrix[i+row*g_cols] * g_matrix[i+col*g_cols]; if (m(row,col) != value) { result = 0; break; @@ -375,7 +375,7 @@ int main(void) cout << "GSymMatrix - Test 4: Define matrix using copy constructor: "; // GSymMatrix test4 = m_test; - if (!check_matrix(test4, 1.0, 0.0) && !check_matrix(m_test, 1.0, 0.0)) { + if (!check_matrix(test4, 1.0, 0.0) || !check_matrix(m_test, 1.0, 0.0)) { cout << endl << "TEST ERROR: Corrupt copy constructor." << endl; cout << test4 << endl; throw; @@ -393,8 +393,8 @@ int main(void) // // GSymMatrix = GSymMatrix result = m_test; - if (!check_matrix(result, 1.0, 0.0) && !check_matrix(m_test, 1.0, 0.0)) { - cout << endl << "TEST ERROR: Corrupt copy constructor." << endl; + if (!check_matrix(result, 1.0, 0.0) || !check_matrix(m_test, 1.0, 0.0)) { + cout << endl << "TEST ERROR: Corrupt assignment." << endl; cout << result << endl; throw; } @@ -413,7 +413,7 @@ int main(void) cout << "GSymMatrix - Test 6: Matrix*Vector multiplication: "; // GVector v_test6 = m_test*v_test; - if (!check_matrix_vector(v_test6) && !check_matrix(m_test, 1.0, 0.0)) { + if (!check_matrix_vector(v_test6) || !check_matrix(m_test, 1.0, 0.0)) { cout << endl << "TEST ERROR: Corrupt Matrix*Vector multiplication." << endl; cout << v_test6 << endl; throw; @@ -426,7 +426,7 @@ int main(void) try { GVector v_test6 = bigger*v_test; } - catch (GMatrix::vec_mat_mismatch &e) { + catch (GMatrix::matrix_vector_mismatch &e) { } catch (exception &e) { cout << e.what() << endl; @@ -439,7 +439,7 @@ int main(void) cout << "GSymMatrix - Test 7: Matrix*Matrix multiplication: "; // GSymMatrix m_test7 = m_test*m_test; - if (!check_matrix_matrix(m_test7) && !check_matrix(m_test, 1.0, 0.0)) { + if (!check_matrix_matrix(m_test7) || !check_matrix(m_test, 1.0, 0.0)) { cout << endl << "TEST ERROR: Corrupt Matrix*Matrix multiplication." << endl; cout << m_test7 << endl; throw; @@ -452,7 +452,7 @@ int main(void) try { GSymMatrix m_test7 = m_test*bigger; } - catch (GMatrix::dim_mult_mismatch &e) { + catch (GMatrix::matrix_mismatch &e) { } catch (exception &e) { cout << e.what() << endl; @@ -461,7 +461,7 @@ int main(void) try { GSymMatrix m_test7 = bigger*m_test; } - catch (GMatrix::dim_mult_mismatch &e) { + catch (GMatrix::matrix_mismatch &e) { } catch (exception &e) { cout << e.what() << endl; @@ -475,61 +475,34 @@ int main(void) // // -GSymMatrix result = -m_test; - if (!check_matrix(result, -1.0, 0.0) && !check_matrix(m_test, 1.0, 0.0)) { + if (!check_matrix(result, -1.0, 0.0) || !check_matrix(m_test, 1.0, 0.0)) { cout << endl << "TEST ERROR: Corrupt -GSymMatrix operator." << endl; cout << result << endl; throw; } // - // GSymMatrix = 3.0 - result = m_test; - result = 3.0; - if (!check_matrix(result, 0.0, 3.0) && !check_matrix(m_test, 1.0, 0.0)) { - cout << endl << "TEST ERROR: Corrupt GSymMatrix = double operator." << endl; - cout << result << endl; - throw; - } - // // GSymMatrix += GSymMatrix result = m_test; result += m_test; - if (!check_matrix(result, 2.0, 0.0) && !check_matrix(m_test, 1.0, 0.0)) { + if (!check_matrix(result, 2.0, 0.0) || !check_matrix(m_test, 1.0, 0.0)) { cout << endl << "TEST ERROR: Corrupt GSymMatrix += GSymMatrix operator." << endl; cout << result << endl; throw; } // - // GSymMatrix += 3.0 - result = m_test; - result += 3.0; - if (!check_matrix(result, 1.0, 3.0) && !check_matrix(m_test, 1.0, 0.0)) { - cout << endl << "TEST ERROR: Corrupt GSymMatrix += double operator." << endl; - cout << result << endl; - throw; - } - // // GSymMatrix -= GSymMatrix result = m_test; result -= m_test; - if (!check_matrix(result, 0.0, 0.0) && !check_matrix(m_test, 1.0, 0.0)) { + if (!check_matrix(result, 0.0, 0.0) || !check_matrix(m_test, 1.0, 0.0)) { cout << endl << "TEST ERROR: Corrupt GSymMatrix -= GSymMatrix operator." << endl; cout << result << endl; throw; } // - // GSymMatrix -= 3.0 - result = m_test; - result -= 3.0; - if (!check_matrix(result, 1.0, -3.0) && !check_matrix(m_test, 1.0, 0.0)) { - cout << endl << "TEST ERROR: Corrupt GSymMatrix -= double operator." << endl; - cout << result << endl; - throw; - } - // // GSymMatrix *= 3.0 result = m_test; result *= 3.0; - if (!check_matrix(result, 3.0, 0.0) && !check_matrix(m_test, 1.0, 0.0)) { + if (!check_matrix(result, 3.0, 0.0) || !check_matrix(m_test, 1.0, 0.0)) { cout << endl << "TEST ERROR: Corrupt GSymMatrix *= double operator." << endl; cout << result << endl; throw; @@ -538,7 +511,7 @@ int main(void) // GSymMatrix /= 3.0 result = m_test; result /= 3.0; - if (!check_matrix(result, 1.0/3.0, 0.0) && !check_matrix(m_test, 1.0, 0.0)) { + if (!check_matrix(result, 1.0/3.0, 0.0) || !check_matrix(m_test, 1.0, 0.0)) { cout << endl << "TEST ERROR: Corrupt GSymMatrix /= double operator." << endl; cout << result << endl; throw; @@ -546,7 +519,7 @@ int main(void) // // GSymMatrix + GSymMatrix result = m_test + m_test; - if (!check_matrix(result, 2.0, 0.0) && !check_matrix(m_test, 1.0, 0.0)) { + if (!check_matrix(result, 2.0, 0.0) || !check_matrix(m_test, 1.0, 0.0)) { cout << endl << "TEST ERROR: Corrupt GSymMatrix + GSymMatrix operator." << endl; cout << result << endl; throw; @@ -554,7 +527,7 @@ int main(void) // // GSymMatrix - GSymMatrix result = m_test - m_test; - if (!check_matrix(result, 0.0, 0.0) && !check_matrix(m_test, 1.0, 0.0)) { + if (!check_matrix(result, 0.0, 0.0) || !check_matrix(m_test, 1.0, 0.0)) { cout << endl << "TEST ERROR: Corrupt GSymMatrix - GSymMatrix operator." << endl; cout << result << endl; throw; @@ -562,47 +535,15 @@ int main(void) // // GSymMatrix - GSymMatrix result = m_test - m_test; - if (!check_matrix(result, 0.0, 0.0) && !check_matrix(m_test, 1.0, 0.0)) { + if (!check_matrix(result, 0.0, 0.0) || !check_matrix(m_test, 1.0, 0.0)) { cout << endl << "TEST ERROR: Corrupt GSymMatrix - GSymMatrix operator." << endl; cout << result << endl; throw; } // - // GSymMatrix + 3.0 - result = m_test + 3.0; - if (!check_matrix(result, 1.0, 3.0) && !check_matrix(m_test, 1.0, 0.0)) { - cout << endl << "TEST ERROR: Corrupt GSymMatrix + double operator." << endl; - cout << result << endl; - throw; - } - // - // 3.0 + GSymMatrix - result = 3.0 + m_test; - if (!check_matrix(result, 1.0, 3.0) && !check_matrix(m_test, 1.0, 0.0)) { - cout << endl << "TEST ERROR: Corrupt double + GSymMatrix operator." << endl; - cout << result << endl; - throw; - } - // - // GSymMatrix - 3.0 - result = m_test - 3.0; - if (!check_matrix(result, 1.0, -3.0) && !check_matrix(m_test, 1.0, 0.0)) { - cout << endl << "TEST ERROR: Corrupt GSymMatrix - double operator." << endl; - cout << result << endl; - throw; - } - // - // 3.0 - GSymMatrix - result = 3.0 - m_test; - if (!check_matrix(result, -1.0, 3.0) && !check_matrix(m_test, 1.0, 0.0)) { - cout << endl << "TEST ERROR: Corrupt double - GSymMatrix operator." << endl; - cout << result << endl; - throw; - } - // // GSymMatrix * 3.0 result = m_test * 3.0; - if (!check_matrix(result, 3.0, 0.0) && !check_matrix(m_test, 1.0, 0.0)) { + if (!check_matrix(result, 3.0, 0.0) || !check_matrix(m_test, 1.0, 0.0)) { cout << endl << "TEST ERROR: Corrupt GSymMatrix * double operator." << endl; cout << result << endl; throw; @@ -610,7 +551,7 @@ int main(void) // // 3.0 * GSymMatrix result = 3.0 * m_test; - if (!check_matrix(result, 3.0, 0.0) && !check_matrix(m_test, 1.0, 0.0)) { + if (!check_matrix(result, 3.0, 0.0) || !check_matrix(m_test, 1.0, 0.0)) { cout << endl << "TEST ERROR: Corrupt double * GSymMatrix operator." << endl; cout << result << endl; throw; @@ -618,7 +559,7 @@ int main(void) // // GSymMatrix / 3.0 result = m_test / 3.0; - if (!check_matrix(result, 1.0/3.0, 0.0) && !check_matrix(m_test, 1.0, 0.0)) { + if (!check_matrix(result, 1.0/3.0, 0.0) || !check_matrix(m_test, 1.0, 0.0)) { cout << endl << "TEST ERROR: Corrupt GSymMatrix / double operator." << endl; cout << result << endl; throw; @@ -632,7 +573,7 @@ int main(void) result = m_test; result += bigger; } - catch (GMatrix::dim_add_mismatch) { + catch (GMatrix::matrix_mismatch) { } catch (exception &e) { cout << e.what() << endl; @@ -717,7 +658,7 @@ int main(void) // // transpose(GSymMatrix) result = transpose(m_test); - if (!check_matrix(result, 1.0, 0.0) && !check_matrix(m_test, 1.0, 0.0)) { + if (!check_matrix(result, 1.0, 0.0) || !check_matrix(m_test, 1.0, 0.0)) { cout << endl << "TEST ERROR: Corrupt transpose(GSymMatrix) function." << endl; cout << result << endl; throw; @@ -726,32 +667,32 @@ int main(void) // GSymMatrix.transpose() result = m_test; result.transpose(); - if (!check_matrix(result, 1.0, 0.0) && !check_matrix(m_test, 1.0, 0.0)) { + if (!check_matrix(result, 1.0, 0.0) || !check_matrix(m_test, 1.0, 0.0)) { cout << endl << "TEST ERROR: Corrupt GSymMatrix.transpose() function." << endl; cout << result << endl; throw; } // - // full(GSymMatrix) - GMatrix m_test11 = full(m_test); - if (!check_matrix(m_test11, 1.0, 0.0) && !check_matrix(m_test, 1.0, 0.0)) { - cout << endl << "TEST ERROR: Corrupt full(GSymMatrix) operator." << endl; + // convert_to_full() + GMatrix m_test11 = m_test.convert_to_full(); + if (!check_matrix(m_test11, 1.0, 0.0) || !check_matrix(m_test, 1.0, 0.0)) { + cout << endl << "TEST ERROR: Corrupt convert_to_full() operator." << endl; cout << m_test11 << endl; throw; } // - // lower_triangle(GSymMatrix) - m_test11 = lower_triangle(m_test); - if (!check_matrix_lt(m_test11, 1.0, 0.0) && !check_matrix(m_test, 1.0, 0.0)) { - cout << endl << "TEST ERROR: Corrupt lower_triangle(GSymMatrix) function." << endl; + // extract_lower_triangle() + m_test11 = m_test.extract_lower_triangle(); + if (!check_matrix_lt(m_test11, 1.0, 0.0) || !check_matrix(m_test, 1.0, 0.0)) { + cout << endl << "TEST ERROR: Corrupt extract_lower_triangle() function." << endl; cout << m_test11 << endl; throw; } // - // upper_triangle(GSymMatrix) - m_test11 = upper_triangle(m_test); - if (!check_matrix_ut(m_test11, 1.0, 0.0) && !check_matrix(m_test, 1.0, 0.0)) { - cout << endl << "TEST ERROR: Corrupt upper_triangle(GSymMatrix) function." << endl; + // extract_upper_triangle() + m_test11 = m_test.extract_upper_triangle(); + if (!check_matrix_ut(m_test11, 1.0, 0.0) || !check_matrix(m_test, 1.0, 0.0)) { + cout << endl << "TEST ERROR: Corrupt extract_upper_triangle() function." << endl; cout << m_test11 << endl; throw; } @@ -768,10 +709,10 @@ int main(void) // // Test Cholesky decomposition GSymMatrix cd = cholesky_decompose(m_test); - GMatrix cd_lower = lower_triangle(cd); + GMatrix cd_lower = cd.extract_lower_triangle(); GMatrix cd_upper = transpose(cd_lower); GMatrix cd_product = cd_lower * cd_upper; - GMatrix cd_residuals = full(m_test) - cd_product; + GMatrix cd_residuals = m_test.convert_to_full() - cd_product; // double res = (fabs(cd_residuals)).max(); if (res < 1.0e-15) @@ -786,10 +727,10 @@ int main(void) // Test compressed Cholesky decomposition GSymMatrix m_test_zero = set_matrix_zero(); GSymMatrix cd_zero = cholesky_decompose(m_test_zero); - GMatrix cd_zero_lower = lower_triangle(cd_zero); + GMatrix cd_zero_lower = cd_zero.extract_lower_triangle(); GMatrix cd_zero_upper = transpose(cd_zero_lower); GMatrix cd_zero_product = cd_zero_lower * cd_zero_upper; - GMatrix cd_zero_residuals = full(m_test_zero) - cd_zero_product; + GMatrix cd_zero_residuals = m_test_zero.convert_to_full() - cd_zero_product; // res = (fabs(cd_zero_residuals)).max(); if (res < 1.0e-15) @@ -804,7 +745,7 @@ int main(void) // Test Cholesky inplace decomposition GSymMatrix m_test12 = m_test; m_test12.cholesky_decompose(); - GMatrix cd_lower2 = lower_triangle(m_test12); + GMatrix cd_lower2 = m_test12.extract_lower_triangle(); if (cd_lower2 != cd_lower) { cout << endl << "TEST ERROR: Corrupt GSymMatrix.cholesky_decompose() function." << endl; cout << cd_lower2 << endl; @@ -967,4 +908,4 @@ int main(void) } cout << "ok." << endl; -} \ No newline at end of file +}