--- trunk/src/math/SquareMatrix.hpp 2004/10/13 06:51:09 70 +++ trunk/src/math/SquareMatrix.hpp 2006/05/17 21:51:42 963 @@ -1,28 +1,44 @@ /* - * Copyright (C) 2000-2004 Object Oriented Parallel Simulation Engine (OOPSE) project - * - * Contact: oopse@oopse.org - * - * This program is free software; you can redistribute it and/or - * modify it under the terms of the GNU Lesser General Public License - * as published by the Free Software Foundation; either version 2.1 - * of the License, or (at your option) any later version. - * All we ask is that proper credit is given for our work, which includes - * - but is not limited to - adding the above copyright notice to the beginning - * of your source code files, and to any copyright notice that you may distribute - * with programs based on this work. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU Lesser General Public License for more details. - * - * You should have received a copy of the GNU Lesser General Public License - * along with this program; if not, write to the Free Software - * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. + * Copyright (c) 2005 The University of Notre Dame. All Rights Reserved. * + * The University of Notre Dame grants you ("Licensee") a + * non-exclusive, royalty free, license to use, modify and + * redistribute this software in source and binary code form, provided + * that the following conditions are met: + * + * 1. Acknowledgement of the program authors must be made in any + * publication of scientific results based in part on use of the + * program. An acceptable form of acknowledgement is citation of + * the article in which the program was described (Matthew + * A. Meineke, Charles F. Vardeman II, Teng Lin, Christopher + * J. Fennell and J. Daniel Gezelter, "OOPSE: An Object-Oriented + * Parallel Simulation Engine for Molecular Dynamics," + * J. Comput. Chem. 26, pp. 252-271 (2005)) + * + * 2. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * + * 3. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the + * distribution. + * + * This software is provided "AS IS," without a warranty of any + * kind. All express or implied conditions, representations and + * warranties, including any implied warranty of merchantability, + * fitness for a particular purpose or non-infringement, are hereby + * excluded. The University of Notre Dame and its licensors shall not + * be liable for any damages suffered by licensee as a result of + * using, modifying or distributing the software or its + * derivatives. In no event will the University of Notre Dame or its + * licensors be liable for any lost revenue, profit or data, or for + * direct, indirect, special, consequential, incidental or punitive + * damages, however caused and regardless of the theory of liability, + * arising out of the use of or inability to use software, even if the + * University of Notre Dame has been advised of the possibility of + * such damages. */ - + /** * @file SquareMatrix.hpp * @author Teng Lin @@ -32,499 +48,347 @@ #ifndef MATH_SQUAREMATRIX_HPP #define MATH_SQUAREMATRIX_HPP -#include "Vector3d.hpp" +#include "math/RectMatrix.hpp" +#include "utils/NumericConstant.hpp" namespace oopse { - /** - * @class SquareMatrix SquareMatrix.hpp "math/SquareMatrix.hpp" - * @brief A square matrix class - * @template Real the element type - * @template Dim the dimension of the square matrix - */ - template - class SquareMatrix{ - public: + /** + * @class SquareMatrix SquareMatrix.hpp "math/SquareMatrix.hpp" + * @brief A square matrix class + * @template Real the element type + * @template Dim the dimension of the square matrix + */ + template + class SquareMatrix : public RectMatrix { + public: + typedef Real ElemType; + typedef Real* ElemPoinerType; - /** default constructor */ - SquareMatrix() { - for (unsigned int i = 0; i < Dim; i++) - for (unsigned int j = 0; j < Dim; j++) - data_[i][j] = 0.0; - } + /** default constructor */ + SquareMatrix() { + for (unsigned int i = 0; i < Dim; i++) + for (unsigned int j = 0; j < Dim; j++) + this->data_[i][j] = 0.0; + } - /** Constructs and initializes every element of this matrix to a scalar */ - SquareMatrix(double s) { - for (unsigned int i = 0; i < Dim; i++) - for (unsigned int j = 0; j < Dim; j++) - data_[i][j] = s; - } + /** Constructs and initializes every element of this matrix to a scalar */ + SquareMatrix(Real s) : RectMatrix(s){ + } - /** copy constructor */ - SquareMatrix(const SquareMatrix& m) { - *this = m; - } - - /** destructor*/ - ~SquareMatrix() {} + /** Constructs and initializes from an array */ + SquareMatrix(Real* array) : RectMatrix(array){ + } - /** copy assignment operator */ - SquareMatrix& operator =(const SquareMatrix& m) { - for (unsigned int i = 0; i < Dim; i++) - for (unsigned int j = 0; j < Dim; j++) - data_[i][j] = m.data_[i][j]; - } - - /** - * Return the reference of a single element of this matrix. - * @return the reference of a single element of this matrix - * @param i row index - * @param j colum index - */ - double& operator()(unsigned int i, unsigned int j) { - return data_[i][j]; - } - /** - * Return the value of a single element of this matrix. - * @return the value of a single element of this matrix - * @param i row index - * @param j colum index - */ - double operator()(unsigned int i, unsigned int j) const { - return data_[i][j]; - } + /** copy constructor */ + SquareMatrix(const RectMatrix& m) : RectMatrix(m) { + } + + /** copy assignment operator */ + SquareMatrix& operator =(const RectMatrix& m) { + RectMatrix::operator=(m); + return *this; + } + + /** Retunrs an identity matrix*/ - /** - * Returns a row of this matrix as a vector. - * @return a row of this matrix as a vector - * @param row the row index - */ - Vector getRow(unsigned int row) { - Vector v; + static SquareMatrix identity() { + SquareMatrix m; + + for (unsigned int i = 0; i < Dim; i++) + for (unsigned int j = 0; j < Dim; j++) + if (i == j) + m(i, j) = 1.0; + else + m(i, j) = 0.0; - for (unsigned int i = 0; i < Dim; i++) - v[i] = data_[row][i]; + return m; + } - return v; - } + /** + * Retunrs the inversion of this matrix. + * @todo need implementation + */ + SquareMatrix inverse() { + SquareMatrix result; - /** - * Sets a row of this matrix - * @param row the row index - * @param v the vector to be set - */ - void setRow(unsigned int row, const Vector& v) { - Vector v; + return result; + } - for (unsigned int i = 0; i < Dim; i++) - data_[row][i] = v[i]; - } + /** + * Returns the determinant of this matrix. + * @todo need implementation + */ + Real determinant() const { + Real det; + return det; + } - /** - * Returns a column of this matrix as a vector. - * @return a column of this matrix as a vector - * @param col the column index - */ - Vector getColum(unsigned int col) { - Vector v; + /** Returns the trace of this matrix. */ + Real trace() const { + Real tmp = 0; + + for (unsigned int i = 0; i < Dim ; i++) + tmp += this->data_[i][i]; - for (unsigned int i = 0; i < Dim; i++) - v[i] = data_[i][col]; + return tmp; + } - return v; - } + /** Tests if this matrix is symmetrix. */ + bool isSymmetric() const { + for (unsigned int i = 0; i < Dim - 1; i++) + for (unsigned int j = i; j < Dim; j++) + if (fabs(this->data_[i][j] - this->data_[j][i]) > epsilon) + return false; + + return true; + } - /** - * Sets a column of this matrix - * @param col the column index - * @param v the vector to be set - */ - void setColum(unsigned int col, const Vector& v){ - Vector v; + /** Tests if this matrix is orthogonal. */ + bool isOrthogonal() { + SquareMatrix tmp; - for (unsigned int i = 0; i < Dim; i++) - data_[i][col] = v[i]; - } + tmp = *this * transpose(); - /** Negates the value of this matrix in place. */ - inline void negate() { - for (unsigned int i = 0; i < Dim; i++) - for (unsigned int j = 0; j < Dim; j++) - data_[i][j] = -data_[i][j]; - } - - /** - * Sets the value of this matrix to the negation of matrix m. - * @param m the source matrix - */ - inline void negate(const SquareMatrix& m) { - for (unsigned int i = 0; i < Dim; i++) - for (unsigned int j = 0; j < Dim; j++) - data_[i][j] = -m.data_[i][j]; - } - - /** - * Sets the value of this matrix to the sum of itself and m (*this += m). - * @param m the other matrix - */ - inline void add( const SquareMatrix& m ) { - for (unsigned int i = 0; i < Dim; i++) - for (unsigned int j = 0; j < Dim; j++) - data_[i][j] += m.data_[i][j]; - } - - /** - * Sets the value of this matrix to the sum of m1 and m2 (*this = m1 + m2). - * @param m1 the first matrix - * @param m2 the second matrix - */ - inline void add( const SquareMatrix& m1, const SquareMatrix& m2 ) { - for (unsigned int i = 0; i < Dim; i++) - for (unsigned int j = 0; j < Dim; j++) - data_[i][j] = m1.data_[i][j] + m2.data_[i][j]; - } - - /** - * Sets the value of this matrix to the difference of itself and m (*this -= m). - * @param m the other matrix - */ - inline void sub( const SquareMatrix& m ) { - for (unsigned int i = 0; i < Dim; i++) - for (unsigned int j = 0; j < Dim; j++) - data_[i][j] -= m.data_[i][j]; - } - - /** - * Sets the value of this matrix to the difference of matrix m1 and m2 (*this = m1 - m2). - * @param m1 the first matrix - * @param m2 the second matrix - */ - inline void sub( const SquareMatrix& m1, const Vector &m2){ - for (unsigned int i = 0; i < Dim; i++) - for (unsigned int j = 0; j < Dim; j++) - data_[i][j] = m1.data_[i][j] - m2.data_[i][j]; - } - - /** - * Sets the value of this matrix to the scalar multiplication of itself (*this *= s). - * @param s the scalar value - */ - inline void mul( double s ) { - for (unsigned int i = 0; i < Dim; i++) - for (unsigned int j = 0; j < Dim; j++) - data_[i][j] *= s; - } + return tmp.isDiagonal(); + } - /** - * Sets the value of this matrix to the scalar multiplication of matrix m (*this = s * m). - * @param s the scalar value - * @param m the matrix - */ - inline void mul( double s, const SquareMatrix& m ) { - for (unsigned int i = 0; i < Dim; i++) - for (unsigned int j = 0; j < Dim; j++) - data_[i][j] = s * m.data_[i][j]; - } + /** Tests if this matrix is diagonal. */ + bool isDiagonal() const { + for (unsigned int i = 0; i < Dim ; i++) + for (unsigned int j = 0; j < Dim; j++) + if (i !=j && fabs(this->data_[i][j]) > epsilon) + return false; + + return true; + } - /** - * Sets the value of this matrix to the multiplication of this matrix and matrix m - * (*this = *this * m). - * @param m the matrix - */ - inline void mul(const SquareMatrix& m ) { - SquareMatrix tmp(*this); - - for (unsigned int i = 0; i < Dim; i++) - for (unsigned int j = 0; j < Dim; j++) { + /** Tests if this matrix is the unit matrix. */ + bool isUnitMatrix() const { + if (!isDiagonal()) + return false; + + for (unsigned int i = 0; i < Dim ; i++) + if (fabs(this->data_[i][i] - 1) > epsilon) + return false; - data_[i][j] = 0.0; - for (unsigned int k = 0; k < Dim; k++) - data_[i][j] = tmp.data_[i][k] * m.data_[k][j] - } - } - - /** - * Sets the value of this matrix to the left multiplication of matrix m into itself - * (*this = m * *this). - * @param m the matrix - */ - inline void leftmul(const SquareMatrix& m ) { - SquareMatrix tmp(*this); - - for (unsigned int i = 0; i < Dim; i++) - for (unsigned int j = 0; j < Dim; j++) { - - data_[i][j] = 0.0; - for (unsigned int k = 0; k < Dim; k++) - data_[i][j] = m.data_[i][k] * tmp.data_[k][j] - } - } + return true; + } - /** - * Sets the value of this matrix to the multiplication of matrix m1 and matrix m2 - * (*this = m1 * m2). - * @param m1 the first matrix - * @param m2 the second matrix - */ - inline void mul(const SquareMatrix& m1, - const SquareMatrix& m2 ) { - for (unsigned int i = 0; i < Dim; i++) - for (unsigned int j = 0; j < Dim; j++) { - - data_[i][j] = 0.0; - for (unsigned int k = 0; k < Dim; k++) - data_[i][j] = m1.data_[i][k] * m2.data_[k][j] - } + /** Return the transpose of this matrix */ + SquareMatrix transpose() const{ + SquareMatrix result; + + for (unsigned int i = 0; i < Dim; i++) + for (unsigned int j = 0; j < Dim; j++) + result(j, i) = this->data_[i][j]; - } - - /** - * Sets the value of this matrix to the scalar division of itself (*this /= s ). - * @param s the scalar value - */ - inline void div( double s) { - for (unsigned int i = 0; i < Dim; i++) - for (unsigned int j = 0; j < Dim; j++) - data_[i][j] /= s; - } - - inline SquareMatrix& operator=(const SquareMatrix& v) { - if (this == &v) - return *this; - - for (unsigned int i = 0; i < Dim; i++) - data_[i] = v[i]; - - return *this; - } - - /** - * Sets the value of this matrix to the scalar division of matrix v1 (*this = v1 / s ). - * @paran v1 the source matrix - * @param s the scalar value - */ - inline void div( const SquareMatrix& v1, double s ) { - for (unsigned int i = 0; i < Dim; i++) - data_[i] = v1.data_[i] / s; - } + return result; + } + + /** @todo need implementation */ + void diagonalize() { + //jacobi(m, eigenValues, ortMat); + } - /** - * Multiples a scalar into every element of this matrix. - * @param s the scalar value - */ - SquareMatrix& operator *=(const double s) { - this->mul(s); - return *this; - } + /** + * Jacobi iteration routines for computing eigenvalues/eigenvectors of + * real symmetric matrix + * + * @return true if success, otherwise return false + * @param a symmetric matrix whose eigenvectors are to be computed. On return, the matrix is + * overwritten + * @param w will contain the eigenvalues of the matrix On return of this function + * @param v the columns of this matrix will contain the eigenvectors. The eigenvectors are + * normalized and mutually orthogonal. + */ + + static int jacobi(SquareMatrix& a, Vector& d, + SquareMatrix& v); + };//end SquareMatrix - /** - * Divides every element of this matrix by a scalar. - * @param s the scalar value - */ - SquareMatrix& operator /=(const double s) { - this->div(s); - return *this; - } - /** - * Sets the value of this matrix to the sum of the other matrix and itself (*this += m). - * @param m the other matrix - */ - SquareMatrix& operator += (const SquareMatrix& m) { - add(m); - return *this; - } + /*========================================================================= - /** - * Sets the value of this matrix to the differerence of itself and the other matrix (*this -= m) - * @param m the other matrix - */ - SquareMatrix& operator -= (const SquareMatrix& m){ - sub(m); - return *this; - } + Program: Visualization Toolkit + Module: $RCSfile: SquareMatrix.hpp,v $ - /** set this matrix to an identity matrix*/ + Copyright (c) Ken Martin, Will Schroeder, Bill Lorensen + All rights reserved. + See Copyright.txt or http://www.kitware.com/Copyright.htm for details. - void identity() { - for (unsigned int i = 0; i < Dim; i++) - for (unsigned int i = 0; i < Dim; i++) - if (i == j) - data_[i][j] = 1.0; - else - data_[i][j] = 0.0; - } + This software is distributed WITHOUT ANY WARRANTY; without even + the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR + PURPOSE. See the above copyright notice for more information. - /** Sets the value of this matrix to the inversion of itself. */ - void inverse() { - inverse(*this); - } + =========================================================================*/ - /** - * Sets the value of this matrix to the inversion of other matrix. - * @ param m the source matrix - */ - void inverse(const SquareMatrix& m); - - /** Sets the value of this matrix to the transpose of itself. */ - void transpose() { - for (unsigned int i = 0; i < Dim - 1; i++) - for (unsigned int j = i; j < Dim; j++) - std::swap(data_[i][j], data_[j][i]); - } +#define VTK_ROTATE(a,i,j,k,l) g=a(i, j);h=a(k, l);a(i, j)=g-s*(h+g*tau); \ + a(k, l)=h+s*(g-h*tau) - /** - * Sets the value of this matrix to the transpose of other matrix. - * @ param m the source matrix - */ - void transpose(const SquareMatrix& m) { - - if (this == &m) { - transpose(); - } else { - for (unsigned int i = 0; i < Dim; i++) - for (unsigned int j =0; j < Dim; j++) - data_[i][j] = m.data_[i][j]; - } - } +#define VTK_MAX_ROTATIONS 20 - /** Returns the determinant of this matrix. */ - double determinant() const { + // Jacobi iteration for the solution of eigenvectors/eigenvalues of a nxn + // real symmetric matrix. Square nxn matrix a; size of matrix in n; + // output eigenvalues in w; and output eigenvectors in v. Resulting + // eigenvalues/vectors are sorted in decreasing order; eigenvectors are + // normalized. + template + int SquareMatrix::jacobi(SquareMatrix& a, Vector& w, + SquareMatrix& v) { + const int n = Dim; + int i, j, k, iq, ip, numPos; + Real tresh, theta, tau, t, sm, s, h, g, c, tmp; + Real bspace[4], zspace[4]; + Real *b = bspace; + Real *z = zspace; - } + // only allocate memory if the matrix is large + if (n > 4) { + b = new Real[n]; + z = new Real[n]; + } - /** Returns the trace of this matrix. */ - double trace() const { - double tmp = 0; - - for (unsigned int i = 0; i < Dim ; i++) - tmp += data_[i][i]; + // initialize + for (ip=0; ip epsilon) - return false; - - return true; - } + if (i < 3) { // first 3 sweeps + tresh = 0.2*sm/(n*n); + } else { + tresh = 0.0; + } - /** Tests if this matrix is orthogona. */ - bool isOrthogonal() const { - SquareMatrix t(*this); + for (ip=0; ip 3 && (fabs(w[ip])+g) == fabs(w[ip]) + && (fabs(w[iq])+g) == fabs(w[iq])) { + a(ip, iq) = 0.0; + } else if (fabs(a(ip, iq)) > tresh) { + h = w[iq] - w[ip]; + if ( (fabs(h)+g) == fabs(h)) { + t = (a(ip, iq)) / h; + } else { + theta = 0.5*h / (a(ip, iq)); + t = 1.0 / (fabs(theta)+sqrt(1.0+theta*theta)); + if (theta < 0.0) { + t = -t; + } + } + c = 1.0 / sqrt(1+t*t); + s = t*c; + tau = s/(1.0+c); + h = t*a(ip, iq); + z[ip] -= h; + z[iq] += h; + w[ip] -= h; + w[iq] += h; + a(ip, iq)=0.0; - return isUnitMatrix(*this * t); - } + // ip already shifted left by 1 unit + for (j = 0;j <= ip-1;j++) { + VTK_ROTATE(a,j,ip,j,iq); + } + // ip and iq already shifted left by 1 unit + for (j = ip+1;j <= iq-1;j++) { + VTK_ROTATE(a,ip,j,j,iq); + } + // iq already shifted left by 1 unit + for (j=iq+1; j epsilon) - return false; - - return true; - } - - /** Tests if this matrix is the unit matrix. */ - bool isUnitMatrix() const { - if (!isDiagonal()) - return false; - - for (unsigned int i = 0; i < Dim ; i++) - if (fabs(data_[i][i] - 1) > epsilon) - return false; - - return true; - } - - protected: - double data_[Dim][Dim]; /**< matrix element */ - - };//end SquareMatrix - - - /** Negate the value of every element of this matrix. */ - template - inline SquareMatrix operator -(const SquareMatrix& m) { - SquareMatrix result(m); - - result.negate(); - - return result; + for (ip=0; ip - inline SquareMatrix operator + (const SquareMatrix& m1, - const SquareMatrix& m2) { - SquareMatrixresult; - result.add(m1, m2); - - return result; + //// this is NEVER called + if ( i >= VTK_MAX_ROTATIONS ) { + std::cout << "vtkMath::Jacobi: Error extracting eigenfunctions" << std::endl; + return 0; } - - /** - * Return the difference of two matrixes (m1 - m2). - * @return the sum of two matrixes - * @param m1 the first matrix - * @param m2 the second matrix - */ - template - inline SquareMatrix operator - (const SquareMatrix& m1, - const SquareMatrix& m2) { - SquareMatrixresult; - result.sub(m1, m2); - - return result; + // sort eigenfunctions these changes do not affect accuracy + for (j=0; j= tmp) { // why exchage if same? + k = i; + tmp = w[k]; + } + } + if (k != j) { + w[k] = w[j]; + w[j] = tmp; + for (i=0; i - inline SquareMatrix operator *(const SquareMatrix& m1, - const SquareMatrix& m2) { - SquareMatrix result; - - result.mul(m1, m2); - - return result; + // insure eigenvector consistency (i.e., Jacobi can compute vectors that + // are negative of one another (.707,.707,0) and (-.707,-.707,0). This can + // reek havoc in hyperstreamline/other stuff. We will select the most + // positive eigenvector. + int ceil_half_n = (n >> 1) + (n & 1); + for (j=0; j= 0.0 ) { + numPos++; + } + } + // if ( numPos < ceil(RealType(n)/RealType(2.0)) ) + if ( numPos < ceil_half_n) { + for (i=0; i - inline Vector operator *(const SquareMatrix& m, - const SquareMatrix& v) { - Vector result; - for (unsigned int i = 0; i < Dim ; i++) - for (unsigned int j = 0; j < Dim ; j++) - result[i] += m(i, j) * v[j]; - - return result; + if (n > 4) { + delete [] b; + delete [] z; } + return 1; + } + + + typedef SquareMatrix Mat6x6d; } #endif //MATH_SQUAREMATRIX_HPP +