001/*
002 * Licensed to the Apache Software Foundation (ASF) under one or more
003 * contributor license agreements.  See the NOTICE file distributed with
004 * this work for additional information regarding copyright ownership.
005 * The ASF licenses this file to You under the Apache License, Version 2.0
006 * (the "License"); you may not use this file except in compliance with
007 * the License.  You may obtain a copy of the License at
008 *
009 *      http://www.apache.org/licenses/LICENSE-2.0
010 *
011 * Unless required by applicable law or agreed to in writing, software
012 * distributed under the License is distributed on an "AS IS" BASIS,
013 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
014 * See the License for the specific language governing permissions and
015 * limitations under the License.
016 */
017package org.apache.commons.geometry.euclidean.internal;
018
019/** This class consists exclusively of static matrix utility methods.
020 */
021public final class Matrices {
022
023    /** Private constructor. */
024    private Matrices() {}
025
026    /** Compute the determinant of the 2x2 matrix represented by the given values.
027     * The values are listed in row-major order.
028     * @param a00 matrix entry <code>a<sub>0,0</sub></code>
029     * @param a01 matrix entry <code>a<sub>0,1</sub></code>
030     * @param a10 matrix entry <code>a<sub>1,0</sub></code>
031     * @param a11 matrix entry <code>a<sub>1,1</sub></code>
032     * @return computed 2x2 matrix determinant
033     */
034    public static double determinant(
035            final double a00, final double a01,
036            final double a10, final double a11) {
037
038        return (a00 * a11) - (a01 * a10);
039    }
040
041    /** Compute the determinant of the 3x3 matrix represented by the given values.
042     * The values are listed in row-major order.
043     * @param a00 matrix entry <code>a<sub>0,0</sub></code>
044     * @param a01 matrix entry <code>a<sub>0,1</sub></code>
045     * @param a02 matrix entry <code>a<sub>0,2</sub></code>
046     * @param a10 matrix entry <code>a<sub>1,0</sub></code>
047     * @param a11 matrix entry <code>a<sub>1,1</sub></code>
048     * @param a12 matrix entry <code>a<sub>1,2</sub></code>
049     * @param a20 matrix entry <code>a<sub>2,0</sub></code>
050     * @param a21 matrix entry <code>a<sub>2,1</sub></code>
051     * @param a22 matrix entry <code>a<sub>2,2</sub></code>
052     * @return computed 3x3 matrix determinant
053     */
054    public static double determinant(
055            final double a00, final double a01, final double a02,
056            final double a10, final double a11, final double a12,
057            final double a20, final double a21, final double a22) {
058
059        return ((a00 * a11 * a22) + (a01 * a12 * a20) + (a02 * a10 * a21)) -
060                ((a00 * a12 * a21) + (a01 * a10 * a22) + (a02 * a11 * a20));
061    }
062
063    /** Check that the given determinant is valid for use in calculating a matrix
064     * inverse. An {@link IllegalStateException} is thrown if the determinant is
065     * NaN, infinite, or zero.
066     * @param det the determinant to check
067     * @return the checked determinant
068     * @throws IllegalStateException if the matrix determinant value is NaN, infinite,
069     *      or zero
070     */
071    public static double checkDeterminantForInverse(final double det) {
072        if (!Vectors.isRealNonZero(det)) {
073            throw nonInvertibleTransform("matrix determinant is " + det);
074        }
075        return det;
076    }
077
078    /** Check that the given matrix element is valid for use in calculation of
079     * a matrix inverse, throwing an {@link IllegalStateException} if not.
080     * @param element matrix entry to check
081     * @return the checked element
082     * @throws IllegalStateException if the element is not valid for use
083     *      in calculating a matrix inverse, ie if it is NaN or infinite.
084     */
085    public static double checkElementForInverse(final double element) {
086        if (!Double.isFinite(element)) {
087            throw nonInvertibleTransform("invalid matrix element: " + element);
088        }
089
090        return element;
091    }
092
093    /** Create an exception indicating that a matrix is not able to be inverted.
094     * @param msg message containing the specific reason that the matrix cannot
095     *      be inverted
096     * @return IllegalStateException containing the given error message
097     */
098    private static IllegalStateException nonInvertibleTransform(final String msg) {
099        return new IllegalStateException("Matrix is not invertible; " + msg);
100    }
101}