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
019import org.apache.commons.geometry.core.Vector;
020import org.apache.commons.numbers.core.Norm;
021import org.apache.commons.numbers.core.Sum;
022
023/** This class consists exclusively of static vector utility methods.
024 */
025public final class Vectors {
026
027    /** Private constructor. */
028    private Vectors() {}
029
030    /** Returns true if the given value is real (ie, not NaN or infinite)
031     * and not equal to zero.
032     * @param value the value to test
033     * @return true if {@code value} is not NaN, infinite, or zero; otherwise
034     *      false
035     */
036    public static boolean isRealNonZero(final double value) {
037        return Double.isFinite(value) && value != 0.0;
038    }
039
040    /** Throws an {@link IllegalArgumentException} if the given norm value
041     * is not real (ie, not NaN or infinite) or zero. The argument is returned
042     * to allow this method to be called inline.
043     * @param norm vector norm value
044     * @return the validated norm value
045     * @throws IllegalArgumentException if the given norm value is NaN, infinite,
046     *      or zero
047     */
048    public static double checkedNorm(final double norm) {
049        if (!isRealNonZero(norm)) {
050            throw illegalNorm(norm);
051        }
052
053        return norm;
054    }
055
056    /** Returns the vector's norm value, throwing an {@link IllegalArgumentException} if the value
057     * is not real (ie, not NaN or infinite) or zero.
058     * @param vec vector to obtain the real, non-zero norm of
059     * @return the validated norm value
060     * @throws IllegalArgumentException if the vector norm value is NaN, infinite,
061     *      or zero
062     */
063    public static double checkedNorm(final Vector<?> vec) {
064        return checkedNorm(vec.norm());
065    }
066
067    /** Return an exception indicating an illegal norm value.
068     * @param norm illegal norm value
069     * @return exception indicating an illegal norm value
070     */
071    public static IllegalArgumentException illegalNorm(final double norm) {
072        return new IllegalArgumentException("Illegal norm: " + norm);
073    }
074
075    /** Get the L<sub>2</sub> norm (commonly known as the Euclidean norm) for the vector
076     * with the given components. This corresponds to the common notion of vector magnitude
077     * or length and is defined as the square root of the sum of the squares of all vector components.
078     * @param x vector component
079     * @return L<sub>2</sub> norm for the vector with the given components
080     * @see <a href="http://mathworld.wolfram.com/L2-Norm.html">L2 Norm</a>
081     */
082    public static double norm(final double x) {
083        return Math.abs(x);
084    }
085
086    /** Get the L<sub>2</sub> norm (commonly known as the Euclidean norm) for the vector
087     * with the given components. This corresponds to the common notion of vector magnitude
088     * or length and is defined as the square root of the sum of the squares of all vector components.
089     * @param x1 first vector component
090     * @param x2 second vector component
091     * @return L<sub>2</sub> norm for the vector with the given components
092     * @see <a href="http://mathworld.wolfram.com/L2-Norm.html">L2 Norm</a>
093     */
094    public static double norm(final double x1, final double x2) {
095        return Math.hypot(x1, x2);
096    }
097
098    /** Get the L<sub>2</sub> norm (commonly known as the Euclidean norm) for the vector
099     * with the given components. This corresponds to the common notion of vector magnitude
100     * or length and is defined as the square root of the sum of the squares of all vector components.
101     * @param x1 first vector component
102     * @param x2 second vector component
103     * @param x3 third vector component
104     * @return L<sub>2</sub> norm for the vector with the given components
105     * @see <a href="http://mathworld.wolfram.com/L2-Norm.html">L2 Norm</a>
106     */
107    public static double norm(final double x1, final double x2, final double x3) {
108        return Norm.EUCLIDEAN.of(x1, x2, x3);
109    }
110
111    /** Get the square of the L<sub>2</sub> norm (also known as the Euclidean norm)
112     * for the vector with the given components. This is equal to the sum of the squares of
113     * all vector components.
114     * @param x vector component
115     * @return square of the L<sub>2</sub> norm for the vector with the given components
116     * @see #norm(double)
117     */
118    public static double normSq(final double x) {
119        return x * x;
120    }
121
122    /** Get the square of the L<sub>2</sub> norm (also known as the Euclidean norm)
123     * for the vector with the given components. This is equal to the sum of the squares of
124     * all vector components.
125     * @param x1 first vector component
126     * @param x2 second vector component
127     * @return square of the L<sub>2</sub> norm for the vector with the given components
128     * @see #norm(double, double)
129     */
130    public static double normSq(final double x1, final double x2) {
131        return (x1 * x1) + (x2 * x2);
132    }
133
134    /** Get the square of the L<sub>2</sub> norm (also known as the Euclidean norm)
135     * for the vector with the given components. This is equal to the sum of the squares of
136     * all vector components.
137     * @param x1 first vector component
138     * @param x2 second vector component
139     * @param x3 third vector component
140     * @return square of the L<sub>2</sub> norm for the vector with the given components
141     * @see #norm(double, double, double)
142     */
143    public static double normSq(final double x1, final double x2, final double x3) {
144        return (x1 * x1) + (x2 * x2) + (x3 * x3);
145    }
146
147    /** Compute the linear combination \(a_1 b_1 + a_2 b_2 \) with high accuracy.
148     * @param a1 first factor of the first term
149     * @param b1 second factor of the first term
150     * @param a2 first factor of the second term
151     * @param b2 second factor of the seconf term
152     * @return linear combination.
153     * @see Sum
154     */
155    public static double linearCombination(final double a1, final double b1,
156                                           final double a2, final double b2) {
157        return Sum.create()
158                .addProduct(a1, b1)
159                .addProduct(a2, b2).getAsDouble();
160    }
161
162    /** Compute the linear combination \(a_1 b_1 + a_2 b_2 + a_3 b_3 \) with high accuracy.
163     * @param a1 first factor of the first term
164     * @param b1 second factor of the first term
165     * @param a2 first factor of the second term
166     * @param b2 second factor of the seconf term
167     * @param a3 first factor of the third term
168     * @param b3 second factor of the third term
169     * @return linear combination.
170     * @see Sum
171     */
172    public static double linearCombination(final double a1, final double b1,
173                                           final double a2, final double b2,
174                                           final double a3, final double b3) {
175        return Sum.create()
176                .addProduct(a1, b1)
177                .addProduct(a2, b2)
178                .addProduct(a3, b3).getAsDouble();
179    }
180}