View Javadoc
1   // ******************************************************************************
2   //
3   // Title:       Force Field X.
4   // Description: Force Field X - Software for Molecular Biophysics.
5   // Copyright:   Copyright (c) Michael J. Schnieders 2001-2026.
6   //
7   // This file is part of Force Field X.
8   //
9   // Force Field X is free software; you can redistribute it and/or modify it
10  // under the terms of the GNU General Public License version 3 as published by
11  // the Free Software Foundation.
12  //
13  // Force Field X is distributed in the hope that it will be useful, but WITHOUT
14  // ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
15  // FOR A PARTICULAR PURPOSE. See the GNU General Public License for more
16  // details.
17  //
18  // You should have received a copy of the GNU General Public License along with
19  // Force Field X; if not, write to the Free Software Foundation, Inc., 59 Temple
20  // Place, Suite 330, Boston, MA 02111-1307 USA
21  //
22  // Linking this library statically or dynamically with other modules is making a
23  // combined work based on this library. Thus, the terms and conditions of the
24  // GNU General Public License cover the whole combination.
25  //
26  // As a special exception, the copyright holders of this library give you
27  // permission to link this library with independent modules to produce an
28  // executable, regardless of the license terms of these independent modules, and
29  // to copy and distribute the resulting executable under terms of your choice,
30  // provided that you also meet, for each linked independent module, the terms
31  // and conditions of the license of that module. An independent module is a
32  // module which is not derived from or based on this library. If you modify this
33  // library, you may extend this exception to your version of the library, but
34  // you are not obligated to do so. If you do not wish to do so, delete this
35  // exception statement from your version.
36  //
37  // ******************************************************************************
38  package ffx.numerics.math;
39  
40  /**
41   * The MatrixMath class is a simple matrix math library used mainly by the X-ray package.
42   * <p>
43   * All methods are thread-safe and static.
44   *
45   * @author Michael J. Schnieders
46   * @since 1.0
47   */
48  public final class MatrixMath {
49  
50      private MatrixMath() {
51          // Prevent instantiation.
52      }
53  
54      /**
55       * Calculated the determinant for a 3x3 matrix.
56       *
57       * @param m input matrix.
58       * @return The determinant.
59       */
60      public static double mat3Determinant(double[][] m) {
61          return m[0][0] * m[1][1] * m[2][2] - m[0][0] * m[1][2] * m[2][1]
62                  + m[0][1] * m[1][2] * m[2][0] - m[0][1] * m[1][0] * m[2][2]
63                  + m[0][2] * m[1][0] * m[2][1] - m[0][2] * m[1][1] * m[2][0];
64      }
65  
66      /**
67       * Returns the determinant of a symmetric 3x3 matrix stored
68       * in vector form as 11, 22, 33, 12, 13, 23.
69       *
70       * @param m symmetric input matrix in vector format.
71       * @return The determinant.
72       */
73      public static double mat3Determinant(double[] m) {
74          return m[0] * m[1] * m[2] - m[0] * m[5] * m[5]
75                  + m[3] * m[5] * m[4] - m[3] * m[3] * m[2]
76                  + m[4] * m[3] * m[5] - m[4] * m[1] * m[4];
77      }
78  
79      /**
80       * Compute the inverse of 3x3 matrix. The result is returned in a newly
81       * allocated matrix.
82       *
83       * @param m The input 3x3 matrix.
84       * @return Returns the inverse of the input matrix m.
85       */
86      public static double[][] mat3Inverse(double[][] m) {
87          return mat3Inverse(m, new double[3][3]);
88      }
89  
90      /**
91       * Compute the inverse of 3x3 matrix. If the input matrix m can be specified
92       * for the output matrix to store the result in place.
93       *
94       * @param m      The input 3x3 matrix.
95       * @param output The output 3x3 matrix.
96       * @return Returns the inverse of the input matrix m.
97       */
98      public static double[][] mat3Inverse(double[][] m, double[][] output) {
99          double inverseDet = 1.0 / mat3Determinant(m);
100         double r00 = (m[1][1] * m[2][2] - m[1][2] * m[2][1]) * inverseDet;
101         double r01 = (m[0][2] * m[2][1] - m[0][1] * m[2][2]) * inverseDet;
102         double r02 = (m[0][1] * m[1][2] - m[0][2] * m[1][1]) * inverseDet;
103         double r10 = (m[1][2] * m[2][0] - m[1][0] * m[2][2]) * inverseDet;
104         double r11 = (m[0][0] * m[2][2] - m[0][2] * m[2][0]) * inverseDet;
105         double r12 = (m[0][2] * m[1][0] - m[0][0] * m[1][2]) * inverseDet;
106         double r20 = (m[1][0] * m[2][1] - m[1][1] * m[2][0]) * inverseDet;
107         double r21 = (m[0][1] * m[2][0] - m[0][0] * m[2][1]) * inverseDet;
108         double r22 = (m[0][0] * m[1][1] - m[0][1] * m[1][0]) * inverseDet;
109         output[0][0] = r00;
110         output[0][1] = r01;
111         output[0][2] = r02;
112         output[1][0] = r10;
113         output[1][1] = r11;
114         output[1][2] = r12;
115         output[2][0] = r20;
116         output[2][1] = r21;
117         output[2][2] = r22;
118         return output;
119     }
120 
121     /**
122      * Multiple a 3x3 matrix m and a 3x3 matrix n. The output is returned in a newly allocated
123      * 3x3 matrix.
124      *
125      * @param m an input 3x3 matrix.
126      * @param n an input 3x3 matrix
127      * @return Returns the 3x3 matrix result.
128      */
129     public static double[][] mat3Mat3Multiply(double[][] m, double[][] n) {
130         return mat3Mat3Multiply(m, n, new double[3][3]);
131     }
132 
133     /**
134      * Multiple a 3x3 matrix m and a 3x3 matrix n. The output is stored in result. The matrix m or n
135      * can be used for the result matrix.
136      *
137      * @param m      an input 3x3 matrix.
138      * @param n      an input 3x3 matrix
139      * @param result a 3x3 matrix to store the result.
140      * @return Returns the matrix result.
141      */
142     public static double[][] mat3Mat3Multiply(double[][] m, double[][] n, double[][] result) {
143         double r00 = m[0][0] * n[0][0] + m[0][1] * n[1][0] + m[0][2] * n[2][0];
144         double r01 = m[0][0] * n[0][1] + m[0][1] * n[1][1] + m[0][2] * n[2][1];
145         double r02 = m[0][0] * n[0][2] + m[0][1] * n[1][2] + m[0][2] * n[2][2];
146         double r10 = m[1][0] * n[0][0] + m[1][1] * n[1][0] + m[1][2] * n[2][0];
147         double r11 = m[1][0] * n[0][1] + m[1][1] * n[1][1] + m[1][2] * n[2][1];
148         double r12 = m[1][0] * n[0][2] + m[1][1] * n[1][2] + m[1][2] * n[2][2];
149         double r20 = m[2][0] * n[0][0] + m[2][1] * n[1][0] + m[2][2] * n[2][0];
150         double r21 = m[2][0] * n[0][1] + m[2][1] * n[1][1] + m[2][2] * n[2][1];
151         double r22 = m[2][0] * n[0][2] + m[2][1] * n[1][2] + m[2][2] * n[2][2];
152         result[0][0] = r00;
153         result[0][1] = r01;
154         result[0][2] = r02;
155         result[1][0] = r10;
156         result[1][1] = r11;
157         result[1][2] = r12;
158         result[2][0] = r20;
159         result[2][1] = r21;
160         result[2][2] = r22;
161         return result;
162     }
163 
164     /**
165      * Matrix times a matrix (both 4x4).
166      *
167      * @param m1 First input matrix.
168      * @param m2 Second input matrix.
169      * @return Returns the matrix product.
170      */
171     public static double[][] mat4Mat4(double[][] m1, double[][] m2) {
172         return mat4Mat4(m1, m2, new double[4][4]);
173     }
174 
175     /**
176      * Multiply two 4x4 matrices.
177      *
178      * @param m1  an array of double (first matrix).
179      * @param m2  an array of double (second matrix).
180      * @param res Resultant matrix.
181      * @return Returns the matrix res.
182      */
183     public static double[][] mat4Mat4(double[][] m1, double[][] m2, double[][] res) {
184         double r00 = m1[0][0] * m2[0][0] + m1[0][1] * m2[1][0] + m1[0][2] * m2[2][0] + m1[0][3] * m2[3][0];
185         double r01 = m1[0][0] * m2[0][1] + m1[0][1] * m2[1][1] + m1[0][2] * m2[2][1] + m1[0][3] * m2[3][1];
186         double r02 = m1[0][0] * m2[0][2] + m1[0][1] * m2[1][2] + m1[0][2] * m2[2][2] + m1[0][3] * m2[3][2];
187         double r03 = m1[0][0] * m2[0][3] + m1[0][1] * m2[1][3] + m1[0][2] * m2[2][3] + m1[0][3] * m2[3][3];
188         double r10 = m1[1][0] * m2[0][0] + m1[1][1] * m2[1][0] + m1[1][2] * m2[2][0] + m1[1][3] * m2[3][0];
189         double r11 = m1[1][0] * m2[0][1] + m1[1][1] * m2[1][1] + m1[1][2] * m2[2][1] + m1[1][3] * m2[3][1];
190         double r12 = m1[1][0] * m2[0][2] + m1[1][1] * m2[1][2] + m1[1][2] * m2[2][2] + m1[1][3] * m2[3][2];
191         double r13 = m1[1][0] * m2[0][3] + m1[1][1] * m2[1][3] + m1[1][2] * m2[2][3] + m1[1][3] * m2[3][3];
192         double r20 = m1[2][0] * m2[0][0] + m1[2][1] * m2[1][0] + m1[2][2] * m2[2][0] + m1[2][3] * m2[3][0];
193         double r21 = m1[2][0] * m2[0][1] + m1[2][1] * m2[1][1] + m1[2][2] * m2[2][1] + m1[2][3] * m2[3][1];
194         double r22 = m1[2][0] * m2[0][2] + m1[2][1] * m2[1][2] + m1[2][2] * m2[2][2] + m1[2][3] * m2[3][2];
195         double r23 = m1[2][0] * m2[0][3] + m1[2][1] * m2[1][3] + m1[2][2] * m2[2][3] + m1[2][3] * m2[3][3];
196         double r30 = m1[3][0] * m2[0][0] + m1[3][1] * m2[1][0] + m1[3][2] * m2[2][0] + m1[3][3] * m2[3][0];
197         double r31 = m1[3][0] * m2[0][1] + m1[3][1] * m2[1][1] + m1[3][2] * m2[2][1] + m1[3][3] * m2[3][1];
198         double r32 = m1[3][0] * m2[0][2] + m1[3][1] * m2[1][2] + m1[3][2] * m2[2][2] + m1[3][3] * m2[3][2];
199         double r33 = m1[3][0] * m2[0][3] + m1[3][1] * m2[1][3] + m1[3][2] * m2[2][3] + m1[3][3] * m2[3][3];
200         res[0][0] = r00;
201         res[0][1] = r01;
202         res[0][2] = r02;
203         res[0][3] = r03;
204         res[1][0] = r10;
205         res[1][1] = r11;
206         res[1][2] = r12;
207         res[1][3] = r13;
208         res[2][0] = r20;
209         res[2][1] = r21;
210         res[2][2] = r22;
211         res[2][3] = r23;
212         res[3][0] = r30;
213         res[3][1] = r31;
214         res[3][2] = r32;
215         res[3][3] = r33;
216         return res;
217     }
218 
219     /**
220      * Matrix times a vector representation of a symmetric 3x3 matrix
221      *
222      * @param m input 3x3 matrix.
223      * @param v input vector of the form 11, 22, 33, 12, 13, 23
224      * @return matrix product in newly allocated space.
225      */
226     public static double[][] mat3SymVec6(double[][] m, double[] v) {
227         return mat3SymVec6(m, v, new double[3][3]);
228     }
229 
230     /**
231      * Matrix times a vector representation of a symmetric 3x3 matrix. The input matrix m
232      * can also be used for the output, which overwrites m with the output.
233      *
234      * @param m      input 3x3 matrix.
235      * @param v      input vector of the form 11, 22, 33, 12, 13, 23
236      * @param output output 3x3 matrix.
237      * @return matrix product in newly allocated space.
238      */
239     public static double[][] mat3SymVec6(double[][] m, double[] v, double[][] output) {
240         double r00 = m[0][0] * v[0] + m[0][1] * v[3] + m[0][2] * v[4];
241         double r01 = m[0][0] * v[3] + m[0][1] * v[1] + m[0][2] * v[5];
242         double r02 = m[0][0] * v[4] + m[0][1] * v[5] + m[0][2] * v[2];
243         double r10 = m[1][0] * v[0] + m[1][1] * v[3] + m[1][2] * v[4];
244         double r11 = m[1][0] * v[3] + m[1][1] * v[1] + m[1][2] * v[5];
245         double r12 = m[1][0] * v[4] + m[1][1] * v[5] + m[1][2] * v[2];
246         double r20 = m[2][0] * v[0] + m[2][1] * v[3] + m[2][2] * v[4];
247         double r21 = m[2][0] * v[3] + m[2][1] * v[1] + m[2][2] * v[5];
248         double r22 = m[2][0] * v[4] + m[2][1] * v[5] + m[2][2] * v[2];
249         output[0][0] = r00;
250         output[0][1] = r01;
251         output[0][2] = r02;
252         output[1][0] = r10;
253         output[1][1] = r11;
254         output[1][2] = r12;
255         output[2][0] = r20;
256         output[2][1] = r21;
257         output[2][2] = r22;
258         return output;
259     }
260 
261     /**
262      * Returns the transpose of a 3x3 Matrix m in newly allocated memory.
263      *
264      * @param m The input matrix.
265      * @return An allocated a 3x3 matrix with transpose of m.
266      */
267     public static double[][] mat3Transpose(double[][] m) {
268         return mat3Transpose(m, new double[3][3]);
269     }
270 
271     /**
272      * Transpose a 3x3 Matrix m and store the result in output. The input matrix m and
273      * output matrix output can be the same variable to store the transpose in-place.
274      *
275      * @param m      The input matrix.
276      * @param output The output transposed matrix.
277      * @return Returns the transposed matrix output.
278      */
279     public static double[][] mat3Transpose(double[][] m, double[][] output) {
280         double m00 = m[0][0];
281         double m01 = m[1][0];
282         double m02 = m[2][0];
283         double m10 = m[0][1];
284         double m11 = m[1][1];
285         double m12 = m[2][1];
286         double m20 = m[0][2];
287         double m21 = m[1][2];
288         double m22 = m[2][2];
289         output[0][0] = m00;
290         output[0][1] = m10;
291         output[0][2] = m20;
292         output[1][0] = m01;
293         output[1][1] = m11;
294         output[1][2] = m21;
295         output[2][0] = m02;
296         output[2][1] = m12;
297         output[2][2] = m22;
298         return output;
299     }
300 
301     /**
302      * Multiply a 1x3 vector and 3x3 matrix. The output is returned in a newly allocated 1x3 vector.
303      *
304      * @param v input 1x3 vector.
305      * @param m input 3x3 matrix.
306      * @return Returns the output vector.
307      */
308     public static double[] vec3Mat3(double[] v, double[][] m) {
309         return vec3Mat3(v, m, new double[3]);
310     }
311 
312     /**
313      * Multiply a 1x3 vector and 3x3 matrix. If the vector v is also used for the output, the
314      * output result will overwrite the input values of v.
315      *
316      * @param v      input 1x3 vector.
317      * @param m      input 3x3 matrix.
318      * @param output output 1x3 vector.
319      * @return Returns the output vector.
320      */
321     public static double[] vec3Mat3(double[] v, double[][] m, double[] output) {
322         double r0 = v[0] * m[0][0] + v[1] * m[1][0] + v[2] * m[2][0];
323         double r1 = v[0] * m[0][1] + v[1] * m[1][1] + v[2] * m[2][1];
324         double r2 = v[0] * m[0][2] + v[1] * m[1][2] + v[2] * m[2][2];
325         output[0] = r0;
326         output[1] = r1;
327         output[2] = r2;
328         return output;
329     }
330 
331 }