/* This file is part of MAUS: http:// micewww.pp.rl.ac.uk:8080/projects/maus * * MAUS is free software: you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation, either version 3 of the License, or * (at your option) any later version. * * MAUS is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with MAUS. If not, see . */ /* Author: Peter Lane */ #include "Maths/SymmetricMatrix.hh" #include #include "CLHEP/Matrix/Matrix.h" #include "CLHEP/Matrix/SymMatrix.h" #include "gsl/gsl_linalg.h" #include "gsl/gsl_eigen.h" #include "Utils/Exception.hh" #include "Maths/Matrix.hh" #include "Maths/Vector.hh" namespace MAUS { // ************************* // Constructors // ************************* SymmetricMatrix::SymmetricMatrix() : Matrix() {} SymmetricMatrix::SymmetricMatrix( const SymmetricMatrix& original_instance) : Matrix(original_instance) {} SymmetricMatrix::SymmetricMatrix( const Matrix& matrix) : Matrix() { size_t size = matrix.number_of_rows(); build_matrix(size, false); double element; for (size_t row = 1; row <= size; ++row) { for (size_t column = 1; column <= row; ++column) { element = matrix(row, column); Matrix::operator()(row, column) = element; if (row != column) { Matrix::operator()(column, row) = element; } } } } SymmetricMatrix::SymmetricMatrix( const ::CLHEP::HepSymMatrix& hep_matrix) : Matrix() { size_t size = hep_matrix.num_row(); build_matrix(size, false); double element; for (size_t row = 1; row <= size; ++row) { for (size_t column = 1; column <= row; ++column) { element = hep_matrix(row, column); Matrix::operator()(row, column) = element; if (row != column) { Matrix::operator()(column, row) = element; } } } } SymmetricMatrix::SymmetricMatrix(const TMatrixDSym& root_sym_matrix) : Matrix() { const double * data = root_sym_matrix.GetMatrixArray(); build_matrix(root_sym_matrix.GetNrows(), data); } SymmetricMatrix::SymmetricMatrix(const size_t size) : Matrix(size, size) {} SymmetricMatrix::SymmetricMatrix(const size_t size, const double& value) : Matrix() { build_matrix(size); for (size_t row = 1; row <= size; row++) { for (size_t column = 1; column <= row; column++) { Matrix::operator()(row, column) = value; if (row != column) { Matrix::operator()(column, row) = value; } } } } SymmetricMatrix::SymmetricMatrix(const size_t size, double const * const data) : Matrix() { build_matrix(size, data); } // ************************* // Indexing Operators // ************************* double SymmetricMatrix::operator()(const size_t row, const size_t column) const { return Matrix::operator()(row, column); } // ************************* // Size Functions // ************************* const size_t SymmetricMatrix::size() const { return number_of_rows(); } // ************************* // Element Set Functions // ************************* void SymmetricMatrix::set(size_t row, size_t column, double value) { Matrix::operator()(row, column) = value; Matrix::operator()(column, row) = value; } // ************************* // Assignment Operators // ************************* SymmetricMatrix& SymmetricMatrix::operator=(const SymmetricMatrix& rhs) { Matrix::operator=(rhs); return *this; } SymmetricMatrix& SymmetricMatrix::operator+=(const SymmetricMatrix& rhs) { Matrix::operator+=(rhs); return *this; } SymmetricMatrix& SymmetricMatrix::operator-=(const SymmetricMatrix& rhs) { Matrix::operator-=(rhs); return *this; } SymmetricMatrix& SymmetricMatrix::operator*=(const double& rhs) { Matrix::operator*=(rhs); return *this; } SymmetricMatrix& SymmetricMatrix::operator/=(const double& rhs) { Matrix::operator/=(rhs); return *this; } // ************************* // Algebraic Operators // ************************* const SymmetricMatrix SymmetricMatrix::operator+( const SymmetricMatrix& rhs) const { return SymmetricMatrix(*this) += rhs; } const SymmetricMatrix SymmetricMatrix::operator-( const SymmetricMatrix& rhs) const { return SymmetricMatrix(*this) -= rhs; } const SymmetricMatrix SymmetricMatrix::operator*(const double& rhs) const { return SymmetricMatrix(*this) *= rhs; } const SymmetricMatrix SymmetricMatrix::operator/(const double& rhs) const { return SymmetricMatrix(*this) /= rhs; } // ############################ // SymmetricMatrix (protected) // ############################ void SymmetricMatrix::build_matrix(const size_t size, const bool initialize) { Matrix::build_matrix(size, size, initialize); } void SymmetricMatrix::build_matrix(const size_t size, double const * const data) { build_matrix(size, false); double element; for (size_t row = 0; row < size; ++row) { for (size_t column = 0; column <= row; ++column) { element = data[row*size + column]; Matrix::operator()(row+1, column+1) = element; if (row != column) { Matrix::operator()(column+1, row+1) = element; } } } } // ############################ // Free Functions // ############################ // **************************** // Conversion Functions // **************************** SymmetricMatrix inverse(const SymmetricMatrix& matrix) { return SymmetricMatrix(inverse((Matrix) matrix)); } namespace CLHEP { ::CLHEP::HepSymMatrix HepSymMatrix(const SymmetricMatrix& matrix) { size_t size = matrix.size(); ::CLHEP::HepSymMatrix hep_matrix(size); double element; for (size_t row = 1; row <= size; ++row) { for (size_t column = 1; column <= row; ++column) { element = matrix(row, column); hep_matrix(row, column) = element; if (row != column) { hep_matrix(column, row) = element; } } } return hep_matrix; } } // namespace MAUS::CLHEP // ************************* // Eigensystem Functions // ************************* Vector eigenvalues(const SymmetricMatrix& matrix) { size_t rows = matrix.number_of_rows(); size_t columns = matrix.number_of_columns(); if (rows != columns) { throw(Exception(Exception::recoverable, "Attempt to get eigenvalues of non-square matrix", "MAUS::eigenvalues") ); } SymmetricMatrix temp_matrix(matrix); gsl_vector * eigenvalues = gsl_vector_alloc(rows); gsl_eigen_symm_workspace * workspace = gsl_eigen_symm_alloc(rows); int ierr = gsl_eigen_symm(temp_matrix.matrix_, eigenvalues, workspace); gsl_eigen_symm_free(workspace); if (ierr != 0) { gsl_vector_free(eigenvalues); throw(Exception(Exception::recoverable, "Failed to calculate eigenvalue", "MAUS::eigenvalues")); } Vector eigenvalue_vector(eigenvalues->data, rows); gsl_vector_free(eigenvalues); return eigenvalue_vector; } std::pair, Matrix > eigensystem( const SymmetricMatrix& matrix) { size_t rows = matrix.number_of_rows(); size_t columns = matrix.number_of_columns(); if (rows != columns) { throw(Exception(Exception::recoverable, "Attempt to get eigensystem of non-square matrix", "MAUS::eigensystem") ); } SymmetricMatrix temp_matrix(matrix); gsl_vector * eigenvalues = gsl_vector_alloc(rows); gsl_matrix * eigenvectors = gsl_matrix_calloc(rows, columns); gsl_eigen_symmv_workspace * workspace = gsl_eigen_symmv_alloc(rows); int ierr = gsl_eigen_symmv(temp_matrix.matrix_, eigenvalues, eigenvectors, workspace); gsl_eigen_symmv_free(workspace); if (ierr != 0) { gsl_vector_free(eigenvalues); gsl_matrix_free(eigenvectors); throw(Exception(Exception::recoverable, "Failed to calculate eigenvalue", "MAUS::eigenvectors")); } Vector eigenvalue_vector(eigenvalues->data, rows); gsl_vector_free(eigenvalues); Matrix eigenvector_matrix(rows, columns, eigenvectors->data); gsl_matrix_free(eigenvectors); return std::pair, Matrix >( eigenvalue_vector, eigenvector_matrix); } // ************************* // Unitary Operators // ************************* SymmetricMatrix operator-(const SymmetricMatrix& matrix) { return SymmetricMatrix(-((Matrix) matrix)); } // ************************* // Scalar Operators // ************************* SymmetricMatrix operator*(const double& lhs, const SymmetricMatrix& rhs) { return SymmetricMatrix(lhs * (Matrix) rhs); } } // namespace MAUS