OpenMD 3.1
Molecular Dynamics in the Open
Loading...
Searching...
No Matches
SquareMatrix.hpp
Go to the documentation of this file.
1/*
2 * Copyright (c) 2004-present, The University of Notre Dame. All rights
3 * reserved.
4 *
5 * Redistribution and use in source and binary forms, with or without
6 * modification, are permitted provided that the following conditions are met:
7 *
8 * 1. Redistributions of source code must retain the above copyright notice,
9 * this list of conditions and the following disclaimer.
10 *
11 * 2. Redistributions in binary form must reproduce the above copyright notice,
12 * this list of conditions and the following disclaimer in the documentation
13 * and/or other materials provided with the distribution.
14 *
15 * 3. Neither the name of the copyright holder nor the names of its
16 * contributors may be used to endorse or promote products derived from
17 * this software without specific prior written permission.
18 *
19 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
20 * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
21 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
22 * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE
23 * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
24 * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
25 * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
26 * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
27 * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
28 * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
29 * POSSIBILITY OF SUCH DAMAGE.
30 *
31 * SUPPORT OPEN SCIENCE! If you use OpenMD or its source code in your
32 * research, please cite the appropriate papers when you publish your
33 * work. Good starting points are:
34 *
35 * [1] Meineke, et al., J. Comp. Chem. 26, 252-271 (2005).
36 * [2] Fennell & Gezelter, J. Chem. Phys. 124, 234104 (2006).
37 * [3] Sun, Lin & Gezelter, J. Chem. Phys. 128, 234107 (2008).
38 * [4] Vardeman, Stocker & Gezelter, J. Chem. Theory Comput. 7, 834 (2011).
39 * [5] Kuang & Gezelter, Mol. Phys., 110, 691-701 (2012).
40 * [6] Lamichhane, Gezelter & Newman, J. Chem. Phys. 141, 134109 (2014).
41 * [7] Lamichhane, Newman & Gezelter, J. Chem. Phys. 141, 134110 (2014).
42 * [8] Bhattarai, Newman & Gezelter, Phys. Rev. B 99, 094106 (2019).
43 */
44
45/**
46 * @file SquareMatrix.hpp
47 * @author Teng Lin
48 * @date 10/11/2004
49 * @version 1.0
50 */
51#ifndef MATH_SQUAREMATRIX_HPP
52#define MATH_SQUAREMATRIX_HPP
53
54#include "math/LU.hpp"
55#include "math/RectMatrix.hpp"
56
57namespace OpenMD {
58
59 /**
60 * @class SquareMatrix SquareMatrix.hpp "math/SquareMatrix.hpp"
61 * @brief A square matrix class
62 * \tparam Real the element type
63 * \tparam Dim the dimension of the square matrix
64 */
65 template<typename Real, int Dim>
66 class SquareMatrix : public RectMatrix<Real, Dim, Dim> {
67 public:
68 using ElemType = Real;
69 using ElemPoinerType = Real*;
70
71 /** default constructor */
73 for (unsigned int i = 0; i < Dim; i++)
74 for (unsigned int j = 0; j < Dim; j++)
75 this->data_[i][j] = 0.0;
76 }
77
78 /** Constructs and initializes every element of this matrix to a scalar */
79 SquareMatrix(Real s) : RectMatrix<Real, Dim, Dim>(s) {}
80
81 /** Constructs and initializes from an array */
82 SquareMatrix(Real* array) : RectMatrix<Real, Dim, Dim>(array) {}
83
84 /** copy constructor */
86 RectMatrix<Real, Dim, Dim>(m) {}
87
88 /** copy assignment operator */
93
94 /** Returns an identity matrix*/
95
98
99 for (unsigned int i = 0; i < Dim; i++)
100 for (unsigned int j = 0; j < Dim; j++)
101 if (i == j)
102 m(i, j) = 1.0;
103 else
104 m(i, j) = 0.0;
105
106 return m;
107 }
108
109 /**
110 * Returns the inverse of this matrix.
111 */
113 // LU sacrifices the original matrix, so create a copy:
114 SquareMatrix<Real, Dim> tmp(this);
116
117 // Use LU-factorization to invert the matrix:
118 invertMatrix(tmp, m);
119 delete tmp;
120 return m;
121 }
122
123 /**
124 * Returns the determinant of this matrix.
125 */
126 Real determinant() const {
127 Real det;
128 // Base case : if matrix contains single element
129 if (Dim == 1) return this->data_[0][0];
130
131 int sign = 1; // To store sign multiplier
132
133 // Iterate for each element of first row
134 for (int f = 0; f < Dim; f++) {
135 // Getting Cofactor of A[0][f]
136 SquareMatrix<Real, Dim - 1> temp = cofactor(this, 0, f);
137 det += sign * this->data_[0][f] * temp.determinant();
138
139 // terms are to be added with alternate sign
140 sign = -sign;
141 }
142 return det;
143 }
144
145 SquareMatrix<Real, Dim - 1> cofactor(int p, int q) {
146 SquareMatrix<Real, Dim - 1> m;
147
148 int i = 0, j = 0;
149 // Looping for each element of the matrix
150 for (unsigned int row = 0; row < Dim; row++) {
151 for (unsigned int col = 0; col < Dim; col++) {
152 // Copying into temporary matrix only those element
153 // which are not in given row and column
154 if (row != p && col != q) {
155 m(i, j++) = this->data_[row][col];
156
157 // Row is filled, so increase row index and
158 // reset col index
159 if (j == Dim - 1) {
160 j = 0;
161 i++;
162 }
163 }
164 }
165 }
166 return m;
167 }
168
169 /** Returns the trace of this matrix. */
170 Real trace() const {
171 Real tmp = 0;
172
173 for (unsigned int i = 0; i < Dim; i++)
174 tmp += this->data_[i][i];
175
176 return tmp;
177 }
178
179 /** Tests if this matrix is symmetrix. */
180 bool isSymmetric() const {
181 for (unsigned int i = 0; i < Dim - 1; i++)
182 for (unsigned int j = i; j < Dim; j++)
183 if (fabs(this->data_[i][j] - this->data_[j][i]) > epsilon)
184 return false;
185
186 return true;
187 }
188
189 /** Tests if this matrix is orthogonal. */
192
193 tmp = *this * transpose();
194
195 return tmp.isDiagonal();
196 }
197
198 /** Tests if this matrix is diagonal. */
199 bool isDiagonal() const {
200 for (unsigned int i = 0; i < Dim; i++)
201 for (unsigned int j = 0; j < Dim; j++)
202 if (i != j && fabs(this->data_[i][j]) > epsilon) return false;
203
204 return true;
205 }
206
207 /**
208 * Returns a column vector that contains the elements from the
209 * diagonal of m in the order R(0) = m(0,0), R(1) = m(1,1), and so
210 * on.
211 */
213 Vector<Real, Dim> result;
214 for (unsigned int i = 0; i < Dim; i++) {
215 result(i) = this->data_[i][i];
216 }
217 return result;
218 }
219
220 /** Tests if this matrix is the unit matrix. */
221 bool isUnitMatrix() const {
222 if (!isDiagonal()) return false;
223
224 for (unsigned int i = 0; i < Dim; i++)
225 if (fabs(this->data_[i][i] - 1) > epsilon) return false;
226
227 return true;
228 }
229
230 /** Return the transpose of this matrix */
233
234 for (unsigned int i = 0; i < Dim; i++)
235 for (unsigned int j = 0; j < Dim; j++)
236 result(j, i) = this->data_[i][j];
237
238 return result;
239 }
240
241 /** @todo need implementation */
242 void diagonalize() {
243 // jacobi(m, eigenValues, ortMat);
244 }
245
246 /**
247 * Jacobi iteration routines for computing eigenvalues/eigenvectors of
248 * real symmetric matrix
249 *
250 * @return true if success, otherwise return false
251 * @param a symmetric matrix whose eigenvectors are to be computed. On
252 * return, the matrix is overwritten
253 * @param d will contain the eigenvalues of the matrix On return of this
254 * function
255 * @param v the columns of this matrix will contain the eigenvectors. The
256 * eigenvectors are normalized and mutually orthogonal.
257 */
258
261 }; // end SquareMatrix
262
263 /*=========================================================================
264
265 Program: Visualization Toolkit
266 Module: Excerpted from vtkMath.cxx
267
268 Copyright (c) 1993-2015 Ken Martin, Will Schroeder, Bill Lorensen
269 All rights reserved.
270
271 Redistribution and use in source and binary forms, with or without
272 modification, are permitted provided that the following conditions are met:
273
274 * Redistributions of source code must retain the above copyright notice,
275 this list of conditions and the following disclaimer.
276
277 * Redistributions in binary form must reproduce the above copyright notice,
278 this list of conditions and the following disclaimer in the documentation
279 and/or other materials provided with the distribution.
280
281 * Neither name of Ken Martin, Will Schroeder, or Bill Lorensen nor the names
282 of any contributors may be used to endorse or promote products derived
283 from this software without specific prior written permission.
284
285 THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS ``AS IS''
286 AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
287 IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
288 ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHORS OR CONTRIBUTORS BE LIABLE FOR
289 ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
290 DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
291 SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
292 CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
293 OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
294 OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
295
296 =========================================================================*/
297
298#define ROTATE(a, i, j, k, l) \
299 g = a(i, j); \
300 h = a(k, l); \
301 a(i, j) = g - s * (h + g * tau); \
302 a(k, l) = h + s * (g - h * tau)
303
304#define MAX_ROTATIONS 20
305
306 // Note that MAX_SCRATCH_ARRAY_SIZE is defined in LU.hpp
307
308 // Jacobi iteration for the solution of eigenvectors/eigenvalues of a nxn
309 // real symmetric matrix. Square nxn matrix a; size of matrix in n;
310 // output eigenvalues in w; and output eigenvectors in v. Resulting
311 // eigenvalues/vectors are sorted in decreasing order; eigenvectors are
312 // normalized.
313 template<typename Real, int Dim>
317 const int n = Dim;
318 int i, j, k, iq, ip, numPos;
319 Real tresh, theta, tau, t, sm, s, h, g, c, tmp;
320 Real bspace[MAX_SCRATCH_ARRAY_SIZE], zspace[MAX_SCRATCH_ARRAY_SIZE];
321 Real* b = (n <= MAX_SCRATCH_ARRAY_SIZE) ? bspace : new Real[n];
322 Real* z = (n <= MAX_SCRATCH_ARRAY_SIZE) ? zspace : new Real[n];
323
324 // initialize
325 for (ip = 0; ip < n; ip++) {
326 for (iq = 0; iq < n; iq++) {
327 v(ip, iq) = 0.0;
328 }
329 v(ip, ip) = 1.0;
330 }
331 for (ip = 0; ip < n; ip++) {
332 b[ip] = w[ip] = a(ip, ip);
333 z[ip] = 0.0;
334 }
335
336 // begin rotation sequence
337 for (i = 0; i < MAX_ROTATIONS; ++i) {
338 sm = 0.0;
339 for (ip = 0; ip < n - 1; ip++) {
340 for (iq = ip + 1; iq < n; iq++) {
341 sm += std::abs(a(ip, iq));
342 }
343 }
344 if (sm == 0.0) { break; }
345
346 if (i < 3) { // first 3 sweeps
347 tresh = 0.2 * sm / (n * n);
348 } else {
349 tresh = 0.0;
350 }
351
352 for (ip = 0; ip < n - 1; ip++) {
353 for (iq = ip + 1; iq < n; iq++) {
354 g = 100.0 * std::abs(a(ip, iq));
355
356 // after 4 sweeps
357 if (i > 3 && (std::abs(w[ip]) + g) == std::abs(w[ip]) &&
358 (std::abs(w[iq]) + g) == std::abs(w[iq])) {
359 a(ip, iq) = 0.0;
360 } else if (std::abs(a(ip, iq)) > tresh) {
361 h = w[iq] - w[ip];
362 if ((std::abs(h) + g) == std::abs(h)) {
363 t = (a(ip, iq)) / h;
364 } else {
365 theta = 0.5 * h / (a(ip, iq));
366 t = 1.0 / (std::abs(theta) + std::sqrt(1.0 + theta * theta));
367 if (theta < 0.0) { t = -t; }
368 }
369 c = 1.0 / std::sqrt(1 + t * t);
370 s = t * c;
371 tau = s / (1.0 + c);
372 h = t * a(ip, iq);
373 z[ip] -= h;
374 z[iq] += h;
375 w[ip] -= h;
376 w[iq] += h;
377 a(ip, iq) = 0.0;
378
379 // ip already shifted left by 1 unit
380 for (j = 0; j <= ip - 1; ++j) {
381 ROTATE(a, j, ip, j, iq);
382 }
383 // ip and iq already shifted left by 1 unit
384 for (j = ip + 1; j <= iq - 1; ++j) {
385 ROTATE(a, ip, j, j, iq);
386 }
387 // iq already shifted left by 1 unit
388 for (j = iq + 1; j < n; ++j) {
389 ROTATE(a, ip, j, iq, j);
390 }
391 for (j = 0; j < n; ++j) {
392 ROTATE(v, j, ip, j, iq);
393 }
394 }
395 }
396 }
397
398 for (ip = 0; ip < n; ip++) {
399 b[ip] += z[ip];
400 w[ip] = b[ip];
401 z[ip] = 0.0;
402 }
403 }
404
405 //// this is NEVER called
406 if (i >= MAX_ROTATIONS) {
407 std::cout << "SquareMatrix::Jacobi: Error extracting eigenfunctions"
408 << std::endl;
409 if (n > MAX_SCRATCH_ARRAY_SIZE) {
410 delete[] b;
411 delete[] z;
412 }
413 return 0;
414 }
415
416 // sort eigenfunctions these changes do not affect accuracy
417 for (j = 0; j < n - 1; ++j) { // boundary incorrect
418 k = j;
419 tmp = w[k];
420 for (i = j + 1; i < n; ++i) { // boundary incorrect, shifted already
421 if (w[i] >= tmp) { // why exchage if same?
422 k = i;
423 tmp = w[k];
424 }
425 }
426 if (k != j) {
427 w[k] = w[j];
428 w[j] = tmp;
429 for (i = 0; i < n; i++) {
430 tmp = v(i, j);
431 v(i, j) = v(i, k);
432 v(i, k) = tmp;
433 }
434 }
435 }
436 // insure eigenvector consistency (i.e., Jacobi can compute
437 // vectors that are negative of one another (.707,.707,0) and
438 // (-.707,-.707,0). This can wreak havoc in other stuff. We will
439 // select the most positive eigenvector.
440 int ceil_half_n = (n >> 1) + (n & 1);
441 for (j = 0; j < n; ++j) {
442 for (numPos = 0, i = 0; i < n; ++i) {
443 if (v(i, j) >= 0.0) { numPos++; }
444 }
445 if (numPos < ceil_half_n) {
446 for (i = 0; i < n; ++i) {
447 v(i, j) *= -1.0;
448 }
449 }
450 }
451
452 if (n > MAX_SCRATCH_ARRAY_SIZE) {
453 delete[] b;
454 delete[] z;
455 }
456 return 1;
457 }
458#undef ROTATE
459#undef MAX_ROTATIONS
460
462} // namespace OpenMD
463
464#endif // MATH_SQUAREMATRIX_HPP
rectangular matrix class
RectMatrix< Real, Row, Col > & operator=(const RectMatrix< Real, Row, Col > &m)
copy assignment operator
A square matrix class.
SquareMatrix()
default constructor
Vector< Real, Dim > diagonals() const
Returns a column vector that contains the elements from the diagonal of m in the order R(0) = m(0,...
SquareMatrix< Real, Dim > & operator=(const RectMatrix< Real, Dim, Dim > &m)
copy assignment operator
Real trace() const
Returns the trace of this matrix.
bool isOrthogonal()
Tests if this matrix is orthogonal.
static SquareMatrix< Real, Dim > identity()
Returns an identity matrix.
Real determinant() const
Returns the determinant of this matrix.
bool isSymmetric() const
Tests if this matrix is symmetrix.
bool isDiagonal() const
Tests if this matrix is diagonal.
SquareMatrix(const RectMatrix< Real, Dim, Dim > &m)
copy constructor
SquareMatrix< Real, Dim > inverse()
Returns the inverse of this matrix.
SquareMatrix(Real s)
Constructs and initializes every element of this matrix to a scalar.
SquareMatrix(Real *array)
Constructs and initializes from an array.
bool isUnitMatrix() const
Tests if this matrix is the unit matrix.
SquareMatrix< Real, Dim > transpose() const
Return the transpose of this matrix.
static int jacobi(SquareMatrix< Real, Dim > &a, Vector< Real, Dim > &d, SquareMatrix< Real, Dim > &v)
Jacobi iteration routines for computing eigenvalues/eigenvectors of real symmetric matrix.
Fix length vector class.
Definition Vector.hpp:78
This basic Periodic Table class was originally taken from the data.cpp file in OpenBabel.
bool invertMatrix(MatrixType &A, MatrixType &AI)
Invert input square matrix A into matrix AI.
Definition LU.hpp:98