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-2025.
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   *
43   * <p>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     * Returns the determinant for a 3x3 matrix.
56     *
57     * @param m input matrix.
58     * @return Returns the determinant.
59     */
60    public static double determinant3(double[][] m) {
61      return m[0][0] * m[1][1] * m[2][2]
62          - m[0][0] * m[1][2] * m[2][1]
63          + m[0][1] * m[1][2] * m[2][0]
64          - m[0][1] * m[1][0] * m[2][2]
65          + m[0][2] * m[1][0] * m[2][1]
66          - m[0][2] * m[1][1] * m[2][0];
67    }
68  
69    /**
70     * determinant3
71     *
72     * @param m an array of double.
73     * @return Returns the determinant.
74     */
75    public static double determinant3(double[] m) {
76      return m[0] * m[1] * m[2]
77          - m[0] * m[5] * m[5]
78          + m[3] * m[5] * m[4]
79          - m[3] * m[3] * m[2]
80          + m[4] * m[3] * m[5]
81          - m[4] * m[1] * m[4];
82    }
83  
84    /**
85     * inverse of a 3x3 matrix.
86     *
87     * @param m input matrix.
88     * @return Returns the matrix inverse.
89     */
90    public static double[][] mat3Inverse(double[][] m) {
91      return mat3Inverse(m, new double[3][3]);
92    }
93  
94    /**
95     * mat3inverse
96     *
97     * @param m   an array of double.
98     * @param res an array of double.
99     * @return Returns the matrix res.
100    */
101   public static double[][] mat3Inverse(double[][] m, double[][] res) {
102     double det = determinant3(m);
103     res[0][0] = (m[1][1] * m[2][2] - m[1][2] * m[2][1]) / det;
104     res[0][1] = (m[0][2] * m[2][1] - m[0][1] * m[2][2]) / det;
105     res[0][2] = (m[0][1] * m[1][2] - m[0][2] * m[1][1]) / det;
106     res[1][0] = (m[1][2] * m[2][0] - m[1][0] * m[2][2]) / det;
107     res[1][1] = (m[0][0] * m[2][2] - m[0][2] * m[2][0]) / det;
108     res[1][2] = (m[0][2] * m[1][0] - m[0][0] * m[1][2]) / det;
109     res[2][0] = (m[1][0] * m[2][1] - m[1][1] * m[2][0]) / det;
110     res[2][1] = (m[0][1] * m[2][0] - m[0][0] * m[2][1]) / det;
111     res[2][2] = (m[0][0] * m[1][1] - m[0][1] * m[1][0]) / det;
112     return res;
113   }
114 
115   /**
116    * Matrix times a matrix.
117    *
118    * @param m1 First input matrix.
119    * @param m2 Second input matrix.
120    * @return Returns the matrix product.
121    */
122   public static double[][] mat3Mat3(double[][] m1, double[][] m2) {
123     return mat3Mat3(m1, m2, new double[3][3]);
124   }
125 
126   /**
127    * mat3mat3
128    *
129    * @param m1  an array of double.
130    * @param m2  an array of double.
131    * @param res an array of double.
132    * @return Returns the matrix res.
133    */
134   public static double[][] mat3Mat3(double[][] m1, double[][] m2, double[][] res) {
135     res[0][0] = m1[0][0] * m2[0][0] + m1[0][1] * m2[1][0] + m1[0][2] * m2[2][0];
136     res[0][1] = m1[0][0] * m2[0][1] + m1[0][1] * m2[1][1] + m1[0][2] * m2[2][1];
137     res[0][2] = m1[0][0] * m2[0][2] + m1[0][1] * m2[1][2] + m1[0][2] * m2[2][2];
138     res[1][0] = m1[1][0] * m2[0][0] + m1[1][1] * m2[1][0] + m1[1][2] * m2[2][0];
139     res[1][1] = m1[1][0] * m2[0][1] + m1[1][1] * m2[1][1] + m1[1][2] * m2[2][1];
140     res[1][2] = m1[1][0] * m2[0][2] + m1[1][1] * m2[1][2] + m1[1][2] * m2[2][2];
141     res[2][0] = m1[2][0] * m2[0][0] + m1[2][1] * m2[1][0] + m1[2][2] * m2[2][0];
142     res[2][1] = m1[2][0] * m2[0][1] + m1[2][1] * m2[1][1] + m1[2][2] * m2[2][1];
143     res[2][2] = m1[2][0] * m2[0][2] + m1[2][1] * m2[1][2] + m1[2][2] * m2[2][2];
144     return res;
145   }
146 
147   /**
148    * Matrix times a matrix (both 4x4).
149    *
150    * @param m1 First input matrix.
151    * @param m2 Second input matrix.
152    * @return Returns the matrix product.
153    */
154   public static double[][] mat4Mat4(double[][] m1, double[][] m2) {
155     return mat4Mat4(m1, m2, new double[4][4]);
156   }
157 
158   /**
159    * Multiply two 4x4 matrices.
160    *
161    * @param m1  an array of double (first matrix).
162    * @param m2  an array of double (second matrix).
163    * @param res Resultant matrix.
164    * @return Returns the matrix res.
165    */
166   public static double[][] mat4Mat4(double[][] m1, double[][] m2, double[][] res) {
167     assert (m1.length == 4);
168     assert (m1[0].length == 4);
169     assert (m2.length == 4);
170     assert (m2[0].length == 4);
171     assert (res.length == 4);
172     assert (res[0].length == 4);
173     res[0][0] =
174         m1[0][0] * m2[0][0] + m1[0][1] * m2[1][0] + m1[0][2] * m2[2][0] + m1[0][3] * m2[3][0];
175     res[0][1] =
176         m1[0][0] * m2[0][1] + m1[0][1] * m2[1][1] + m1[0][2] * m2[2][1] + m1[0][3] * m2[3][1];
177     res[0][2] =
178         m1[0][0] * m2[0][2] + m1[0][1] * m2[1][2] + m1[0][2] * m2[2][2] + m1[0][3] * m2[3][2];
179     res[0][3] =
180         m1[0][0] * m2[0][3] + m1[0][1] * m2[1][3] + m1[0][2] * m2[2][3] + m1[0][3] * m2[3][3];
181     res[1][0] =
182         m1[1][0] * m2[0][0] + m1[1][1] * m2[1][0] + m1[1][2] * m2[2][0] + m1[1][3] * m2[3][0];
183     res[1][1] =
184         m1[1][0] * m2[0][1] + m1[1][1] * m2[1][1] + m1[1][2] * m2[2][1] + m1[1][3] * m2[3][1];
185     res[1][2] =
186         m1[1][0] * m2[0][2] + m1[1][1] * m2[1][2] + m1[1][2] * m2[2][2] + m1[1][3] * m2[3][2];
187     res[1][3] =
188         m1[1][0] * m2[0][3] + m1[1][1] * m2[1][3] + m1[1][2] * m2[2][3] + m1[1][3] * m2[3][3];
189     res[2][0] =
190         m1[2][0] * m2[0][0] + m1[2][1] * m2[1][0] + m1[2][2] * m2[2][0] + m1[2][3] * m2[3][0];
191     res[2][1] =
192         m1[2][0] * m2[0][1] + m1[2][1] * m2[1][1] + m1[2][2] * m2[2][1] + m1[2][3] * m2[3][1];
193     res[2][2] =
194         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     res[2][3] =
196         m1[2][0] * m2[0][3] + m1[2][1] * m2[1][3] + m1[2][2] * m2[2][3] + m1[2][3] * m2[3][3];
197     res[3][0] =
198         m1[3][0] * m2[0][0] + m1[3][1] * m2[1][0] + m1[3][2] * m2[2][0] + m1[3][3] * m2[3][0];
199     res[3][1] =
200         m1[3][0] * m2[0][1] + m1[3][1] * m2[1][1] + m1[3][2] * m2[2][1] + m1[3][3] * m2[3][1];
201     res[3][2] =
202         m1[3][0] * m2[0][2] + m1[3][1] * m2[1][2] + m1[3][2] * m2[2][2] + m1[3][3] * m2[3][2];
203     res[3][3] =
204         m1[3][0] * m2[0][3] + m1[3][1] * m2[1][3] + m1[3][2] * m2[2][3] + m1[3][3] * m2[3][3];
205     return res;
206   }
207 
208   /**
209    * matrix times a vector representation of a symmetric 3x3 matrix
210    *
211    * @param m input matrix
212    * @param v input vector of the form 11, 22, 33, 12, 13, 23
213    * @return matrix product
214    */
215   public static double[][] mat3SymVec6(double[][] m, double[] v) {
216     return mat3SymVec6(m, v, new double[3][3]);
217   }
218 
219   /**
220    * mat3SymVec6
221    *
222    * @param m   an array of double.
223    * @param v   an array of double.
224    * @param res an array of double.
225    * @return Returns the matrix res.
226    */
227   public static double[][] mat3SymVec6(double[][] m, double[] v, double[][] res) {
228     res[0][0] = m[0][0] * v[0] + m[0][1] * v[3] + m[0][2] * v[4];
229     res[0][1] = m[0][0] * v[3] + m[0][1] * v[1] + m[0][2] * v[5];
230     res[0][2] = m[0][0] * v[4] + m[0][1] * v[5] + m[0][2] * v[2];
231     res[1][0] = m[1][0] * v[0] + m[1][1] * v[3] + m[1][2] * v[4];
232     res[1][1] = m[1][0] * v[3] + m[1][1] * v[1] + m[1][2] * v[5];
233     res[1][2] = m[1][0] * v[4] + m[1][1] * v[5] + m[1][2] * v[2];
234     res[2][0] = m[2][0] * v[0] + m[2][1] * v[3] + m[2][2] * v[4];
235     res[2][1] = m[2][0] * v[3] + m[2][1] * v[1] + m[2][2] * v[5];
236     res[2][2] = m[2][0] * v[4] + m[2][1] * v[5] + m[2][2] * v[2];
237     return res;
238   }
239 
240   /**
241    * matrix times a vector
242    *
243    * @param m input matrix.
244    * @param v input vector.
245    * @return Returns the vector product.
246    */
247   public static double[] mat3Vec3(double[] v, double[][] m) {
248     return mat3Vec3(v, m, new double[3]);
249   }
250 
251   /**
252    * mat3vec3
253    *
254    * @param v   an array of double.
255    * @param m   an array of double.
256    * @param res an array of double.
257    * @return Returns the matrix res.
258    */
259   public static double[] mat3Vec3(double[] v, double[][] m, double[] res) {
260     res[0] = m[0][0] * v[0] + m[0][1] * v[1] + m[0][2] * v[2];
261     res[1] = m[1][0] * v[0] + m[1][1] * v[1] + m[1][2] * v[2];
262     res[2] = m[2][0] * v[0] + m[2][1] * v[1] + m[2][2] * v[2];
263     return res;
264   }
265 
266   /**
267    * scalar times a matrix times a matrix.
268    *
269    * @param scalar Input scalar.
270    * @param m1     First input matrix.
271    * @param m2     Second input matrix.
272    * @return Returns the matrix product.
273    */
274   public static double[][] scalarMat3Mat3(double scalar, double[][] m1, double[][] m2) {
275     return scalarMat3Mat3(scalar, m1, m2, new double[3][3]);
276   }
277 
278   /**
279    * scalarMat3mat3
280    *
281    * @param scalar a double.
282    * @param m1     an array of double.
283    * @param m2     an array of double.
284    * @param res    an array of double.
285    * @return Returns the matrix res.
286    */
287   public static double[][] scalarMat3Mat3(
288       double scalar, double[][] m1, double[][] m2, double[][] res) {
289     res[0][0] =
290         (scalar * m1[0][0]) * m2[0][0]
291             + (scalar * m1[0][1]) * m2[1][0]
292             + (scalar * m1[0][2]) * m2[2][0];
293     res[0][1] =
294         (scalar * m1[0][0]) * m2[0][1]
295             + (scalar * m1[0][1]) * m2[1][1]
296             + (scalar * m1[0][2]) * m2[2][1];
297     res[0][2] =
298         (scalar * m1[0][0]) * m2[0][2]
299             + (scalar * m1[0][1]) * m2[1][2]
300             + (scalar * m1[0][2]) * m2[2][2];
301     res[1][0] =
302         (scalar * m1[1][0]) * m2[0][0]
303             + (scalar * m1[1][1]) * m2[1][0]
304             + (scalar * m1[1][2]) * m2[2][0];
305     res[1][1] =
306         (scalar * m1[1][0]) * m2[0][1]
307             + (scalar * m1[1][1]) * m2[1][1]
308             + (scalar * m1[1][2]) * m2[2][1];
309     res[1][2] =
310         (scalar * m1[1][0]) * m2[0][2]
311             + (scalar * m1[1][1]) * m2[1][2]
312             + (scalar * m1[1][2]) * m2[2][2];
313     res[2][0] =
314         (scalar * m1[2][0]) * m2[0][0]
315             + (scalar * m1[2][1]) * m2[1][0]
316             + (scalar * m1[2][2]) * m2[2][0];
317     res[2][1] =
318         (scalar * m1[2][0]) * m2[0][1]
319             + (scalar * m1[2][1]) * m2[1][1]
320             + (scalar * m1[2][2]) * m2[2][1];
321     res[2][2] =
322         (scalar * m1[2][0]) * m2[0][2]
323             + (scalar * m1[2][1]) * m2[1][2]
324             + (scalar * m1[2][2]) * m2[2][2];
325     return res;
326   }
327 
328   /**
329    * vector representation of a symmetric 3x3 matrix times a matrix
330    *
331    * @param v input vector of the form 11, 22, 33, 12, 13, 23.
332    * @param m input matrix.
333    * @return Returns matrix product.
334    */
335   public static double[][] symVec6Mat3(double[] v, double[][] m) {
336     double[][] res = new double[3][3];
337     symVec6Mat3(v, m, res);
338     return res;
339   }
340 
341   /**
342    * symVec6mat3
343    *
344    * @param v   an array of double.
345    * @param m   an array of double.
346    * @param res an array of double.
347    * @return Returns the matrix res.
348    */
349   public static double[][] symVec6Mat3(double[] v, double[][] m, double[][] res) {
350     res[0][0] = v[0] * m[0][0] + v[3] * m[1][0] + v[4] * m[2][0];
351     res[0][1] = v[0] * m[0][1] + v[3] * m[1][1] + v[4] * m[2][1];
352     res[0][2] = v[0] * m[0][2] + v[3] * m[1][2] + v[4] * m[2][2];
353     res[1][0] = v[3] * m[0][0] + v[1] * m[1][0] + v[5] * m[2][0];
354     res[1][1] = v[3] * m[0][1] + v[1] * m[1][1] + v[5] * m[2][1];
355     res[1][2] = v[3] * m[0][2] + v[1] * m[1][2] + v[5] * m[2][2];
356     res[2][0] = v[4] * m[0][0] + v[5] * m[1][0] + v[2] * m[2][0];
357     res[2][1] = v[4] * m[0][1] + v[5] * m[1][1] + v[2] * m[2][1];
358     res[2][2] = v[4] * m[0][2] + v[5] * m[1][2] + v[2] * m[2][2];
359     return res;
360   }
361 
362   /**
363    * transpose3
364    *
365    * @param m Matrix m.
366    * @return Returns the transposed matrix in a new array.
367    */
368   public static double[][] transpose3(double[][] m) {
369     return transpose3(m, new double[3][3]);
370   }
371 
372   /**
373    * transpose3
374    *
375    * @param m Matrix m.
376    * @param t Matrix t.
377    * @return Returns the matrix t.
378    */
379   public static double[][] transpose3(double[][] m, double[][] t) {
380     t[0][0] = m[0][0];
381     t[0][1] = m[1][0];
382     t[0][2] = m[2][0];
383     t[1][0] = m[0][1];
384     t[1][1] = m[1][1];
385     t[1][2] = m[2][1];
386     t[2][0] = m[0][2];
387     t[2][1] = m[1][2];
388     t[2][2] = m[2][2];
389     return t;
390   }
391 
392   /**
393    * Vector times a matrix.
394    *
395    * @param v input vector.
396    * @param m input matrix.
397    * @return Returns the vector product.
398    */
399   public static double[] vec3Mat3(double[] v, double[][] m) {
400     return vec3Mat3(v, m, new double[3]);
401   }
402 
403   /**
404    * vec3mat3
405    *
406    * @param v   an array of double.
407    * @param m   an array of double.
408    * @param res an array of double.
409    * @return Returns the array res.
410    */
411   public static double[] vec3Mat3(double[] v, double[][] m, double[] res) {
412     res[0] = v[0] * m[0][0] + v[1] * m[1][0] + v[2] * m[2][0];
413     res[1] = v[0] * m[0][1] + v[1] * m[1][1] + v[2] * m[2][1];
414     res[2] = v[0] * m[0][2] + v[1] * m[1][2] + v[2] * m[2][2];
415     return res;
416   }
417 
418   /**
419    * Multiply coordinates by the transpose of a matrix.
420    *
421    * @param in     input coordinates.
422    * @param out    output coordinates.
423    * @param matrix multiply by the transpose of this matrix.
424    */
425   public static void applyMatrixTranspose(double[] in, double[] out, double[][] matrix) {
426     double xc = in[0];
427     double yc = in[1];
428     double zc = in[2];
429     out[0] = xc * matrix[0][0] + yc * matrix[1][0] + zc * matrix[2][0];
430     out[1] = xc * matrix[0][1] + yc * matrix[1][1] + zc * matrix[2][1];
431     out[2] = xc * matrix[0][2] + yc * matrix[1][2] + zc * matrix[2][2];
432   }
433 }