MathArrays.java
- /*
- * Licensed to the Apache Software Foundation (ASF) under one or more
- * contributor license agreements. See the NOTICE file distributed with
- * this work for additional information regarding copyright ownership.
- * The ASF licenses this file to You under the Apache License, Version 2.0
- * (the "License"); you may not use this file except in compliance with
- * the License. You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
- package org.apache.commons.math4.legacy.core;
- import java.lang.reflect.Array;
- import java.util.Arrays;
- import java.util.Iterator;
- import java.util.TreeSet;
- import org.apache.commons.numbers.core.Precision;
- import org.apache.commons.math4.legacy.exception.DimensionMismatchException;
- import org.apache.commons.math4.legacy.exception.MathArithmeticException;
- import org.apache.commons.math4.legacy.exception.MathIllegalArgumentException;
- import org.apache.commons.math4.legacy.exception.MathInternalError;
- import org.apache.commons.math4.legacy.exception.NoDataException;
- import org.apache.commons.math4.legacy.exception.NonMonotonicSequenceException;
- import org.apache.commons.math4.legacy.exception.NotANumberException;
- import org.apache.commons.math4.legacy.exception.NotPositiveException;
- import org.apache.commons.math4.legacy.exception.NotStrictlyPositiveException;
- import org.apache.commons.math4.legacy.exception.NullArgumentException;
- import org.apache.commons.math4.legacy.exception.NumberIsTooLargeException;
- import org.apache.commons.math4.legacy.exception.NotFiniteNumberException;
- import org.apache.commons.math4.legacy.exception.util.LocalizedFormats;
- import org.apache.commons.math4.core.jdkmath.JdkMath;
- /**
- * Arrays utilities.
- *
- * @since 3.0
- */
- public final class MathArrays {
- /**
- * Private constructor.
- */
- private MathArrays() {}
- /**
- * Real-valued function that operate on an array or a part of it.
- * @since 3.1
- */
- public interface Function {
- /**
- * Operates on an entire array.
- *
- * @param array Array to operate on.
- * @return the result of the operation.
- */
- double evaluate(double[] array);
- /**
- * @param array Array to operate on.
- * @param startIndex Index of the first element to take into account.
- * @param numElements Number of elements to take into account.
- * @return the result of the operation.
- */
- double evaluate(double[] array,
- int startIndex,
- int numElements);
- }
- /**
- * Create a copy of an array scaled by a value.
- *
- * @param arr Array to scale.
- * @param val Scalar.
- * @return scaled copy of array with each entry multiplied by val.
- * @since 3.2
- */
- public static double[] scale(double val, final double[] arr) {
- double[] newArr = new double[arr.length];
- for (int i = 0; i < arr.length; i++) {
- newArr[i] = arr[i] * val;
- }
- return newArr;
- }
- /**
- * <p>Multiply each element of an array by a value.</p>
- *
- * <p>The array is modified in place (no copy is created).</p>
- *
- * @param arr Array to scale
- * @param val Scalar
- * @since 3.2
- */
- public static void scaleInPlace(double val, final double[] arr) {
- for (int i = 0; i < arr.length; i++) {
- arr[i] *= val;
- }
- }
- /**
- * Creates an array whose contents will be the element-by-element
- * addition of the arguments.
- *
- * @param a First term of the addition.
- * @param b Second term of the addition.
- * @return a new array {@code r} where {@code r[i] = a[i] + b[i]}.
- * @throws DimensionMismatchException if the array lengths differ.
- * @since 3.1
- */
- public static double[] ebeAdd(double[] a, double[] b) {
- checkEqualLength(a, b);
- final double[] result = a.clone();
- for (int i = 0; i < a.length; i++) {
- result[i] += b[i];
- }
- return result;
- }
- /**
- * Creates an array whose contents will be the element-by-element
- * subtraction of the second argument from the first.
- *
- * @param a First term.
- * @param b Element to be subtracted.
- * @return a new array {@code r} where {@code r[i] = a[i] - b[i]}.
- * @throws DimensionMismatchException if the array lengths differ.
- * @since 3.1
- */
- public static double[] ebeSubtract(double[] a, double[] b) {
- checkEqualLength(a, b);
- final double[] result = a.clone();
- for (int i = 0; i < a.length; i++) {
- result[i] -= b[i];
- }
- return result;
- }
- /**
- * Creates an array whose contents will be the element-by-element
- * multiplication of the arguments.
- *
- * @param a First factor of the multiplication.
- * @param b Second factor of the multiplication.
- * @return a new array {@code r} where {@code r[i] = a[i] * b[i]}.
- * @throws DimensionMismatchException if the array lengths differ.
- * @since 3.1
- */
- public static double[] ebeMultiply(double[] a, double[] b) {
- checkEqualLength(a, b);
- final double[] result = a.clone();
- for (int i = 0; i < a.length; i++) {
- result[i] *= b[i];
- }
- return result;
- }
- /**
- * Creates an array whose contents will be the element-by-element
- * division of the first argument by the second.
- *
- * @param a Numerator of the division.
- * @param b Denominator of the division.
- * @return a new array {@code r} where {@code r[i] = a[i] / b[i]}.
- * @throws DimensionMismatchException if the array lengths differ.
- * @since 3.1
- */
- public static double[] ebeDivide(double[] a, double[] b) {
- checkEqualLength(a, b);
- final double[] result = a.clone();
- for (int i = 0; i < a.length; i++) {
- result[i] /= b[i];
- }
- return result;
- }
- /**
- * Calculates the L<sub>1</sub> (sum of abs) distance between two points.
- *
- * @param p1 the first point
- * @param p2 the second point
- * @return the L<sub>1</sub> distance between the two points
- * @throws DimensionMismatchException if the array lengths differ.
- */
- public static double distance1(double[] p1, double[] p2) {
- checkEqualLength(p1, p2);
- double sum = 0;
- for (int i = 0; i < p1.length; i++) {
- sum += JdkMath.abs(p1[i] - p2[i]);
- }
- return sum;
- }
- /**
- * Calculates the L<sub>1</sub> (sum of abs) distance between two points.
- *
- * @param p1 the first point
- * @param p2 the second point
- * @return the L<sub>1</sub> distance between the two points
- * @throws DimensionMismatchException if the array lengths differ.
- */
- public static int distance1(int[] p1, int[] p2) {
- checkEqualLength(p1, p2);
- int sum = 0;
- for (int i = 0; i < p1.length; i++) {
- sum += JdkMath.abs(p1[i] - p2[i]);
- }
- return sum;
- }
- /**
- * Calculates the L<sub>2</sub> (Euclidean) distance between two points.
- *
- * @param p1 the first point
- * @param p2 the second point
- * @return the L<sub>2</sub> distance between the two points
- * @throws DimensionMismatchException if the array lengths differ.
- */
- public static double distance(double[] p1, double[] p2) {
- checkEqualLength(p1, p2);
- double sum = 0;
- for (int i = 0; i < p1.length; i++) {
- final double dp = p1[i] - p2[i];
- sum += dp * dp;
- }
- return JdkMath.sqrt(sum);
- }
- /**
- * Calculates the L<sub>2</sub> (Euclidean) distance between two points.
- *
- * @param p1 the first point
- * @param p2 the second point
- * @return the L<sub>2</sub> distance between the two points
- * @throws DimensionMismatchException if the array lengths differ.
- */
- public static double distance(int[] p1, int[] p2) {
- checkEqualLength(p1, p2);
- double sum = 0;
- for (int i = 0; i < p1.length; i++) {
- final double dp = (double) p1[i] - p2[i];
- sum += dp * dp;
- }
- return JdkMath.sqrt(sum);
- }
- /**
- * Calculates the L<sub>∞</sub> (max of abs) distance between two points.
- *
- * @param p1 the first point
- * @param p2 the second point
- * @return the L<sub>∞</sub> distance between the two points
- * @throws DimensionMismatchException if the array lengths differ.
- */
- public static double distanceInf(double[] p1, double[] p2) {
- checkEqualLength(p1, p2);
- double max = 0;
- for (int i = 0; i < p1.length; i++) {
- max = JdkMath.max(max, JdkMath.abs(p1[i] - p2[i]));
- }
- return max;
- }
- /**
- * Calculates the L<sub>∞</sub> (max of abs) distance between two points.
- *
- * @param p1 the first point
- * @param p2 the second point
- * @return the L<sub>∞</sub> distance between the two points
- * @throws DimensionMismatchException if the array lengths differ.
- */
- public static int distanceInf(int[] p1, int[] p2) {
- checkEqualLength(p1, p2);
- int max = 0;
- for (int i = 0; i < p1.length; i++) {
- max = JdkMath.max(max, JdkMath.abs(p1[i] - p2[i]));
- }
- return max;
- }
- /**
- * Specification of ordering direction.
- */
- public enum OrderDirection {
- /** Constant for increasing direction. */
- INCREASING,
- /** Constant for decreasing direction. */
- DECREASING
- }
- /**
- * Check that an array is monotonically increasing or decreasing.
- *
- * @param <T> the type of the elements in the specified array
- * @param val Values.
- * @param dir Ordering direction.
- * @param strict Whether the order should be strict.
- * @return {@code true} if sorted, {@code false} otherwise.
- */
- public static <T extends Comparable<? super T>> boolean isMonotonic(T[] val,
- OrderDirection dir,
- boolean strict) {
- T previous = val[0];
- final int max = val.length;
- for (int i = 1; i < max; i++) {
- final int comp;
- switch (dir) {
- case INCREASING:
- comp = previous.compareTo(val[i]);
- if (strict) {
- if (comp >= 0) {
- return false;
- }
- } else {
- if (comp > 0) {
- return false;
- }
- }
- break;
- case DECREASING:
- comp = val[i].compareTo(previous);
- if (strict) {
- if (comp >= 0) {
- return false;
- }
- } else {
- if (comp > 0) {
- return false;
- }
- }
- break;
- default:
- // Should never happen.
- throw new MathInternalError();
- }
- previous = val[i];
- }
- return true;
- }
- /**
- * Check that an array is monotonically increasing or decreasing.
- *
- * @param val Values.
- * @param dir Ordering direction.
- * @param strict Whether the order should be strict.
- * @return {@code true} if sorted, {@code false} otherwise.
- */
- public static boolean isMonotonic(double[] val, OrderDirection dir, boolean strict) {
- return checkOrder(val, dir, strict, false);
- }
- /**
- * Check that both arrays have the same length.
- *
- * @param a Array.
- * @param b Array.
- * @param abort Whether to throw an exception if the check fails.
- * @return {@code true} if the arrays have the same length.
- * @throws DimensionMismatchException if the lengths differ and
- * {@code abort} is {@code true}.
- * @since 3.6
- */
- public static boolean checkEqualLength(double[] a,
- double[] b,
- boolean abort) {
- if (a.length == b.length) {
- return true;
- } else {
- if (abort) {
- throw new DimensionMismatchException(a.length, b.length);
- }
- return false;
- }
- }
- /**
- * Check that both arrays have the same length.
- *
- * @param a Array.
- * @param b Array.
- * @throws DimensionMismatchException if the lengths differ.
- * @since 3.6
- */
- public static void checkEqualLength(double[] a,
- double[] b) {
- checkEqualLength(a, b, true);
- }
- /**
- * Check that both arrays have the same length.
- *
- * @param a Array.
- * @param b Array.
- * @param abort Whether to throw an exception if the check fails.
- * @return {@code true} if the arrays have the same length.
- * @throws DimensionMismatchException if the lengths differ and
- * {@code abort} is {@code true}.
- * @since 3.6
- */
- public static boolean checkEqualLength(int[] a,
- int[] b,
- boolean abort) {
- if (a.length == b.length) {
- return true;
- } else {
- if (abort) {
- throw new DimensionMismatchException(a.length, b.length);
- }
- return false;
- }
- }
- /**
- * Check that both arrays have the same length.
- *
- * @param a Array.
- * @param b Array.
- * @throws DimensionMismatchException if the lengths differ.
- * @since 3.6
- */
- public static void checkEqualLength(int[] a,
- int[] b) {
- checkEqualLength(a, b, true);
- }
- /**
- * Check that the given array is sorted.
- *
- * @param val Values.
- * @param dir Ordering direction.
- * @param strict Whether the order should be strict.
- * @param abort Whether to throw an exception if the check fails.
- * @return {@code true} if the array is sorted.
- * @throws NonMonotonicSequenceException if the array is not sorted
- * and {@code abort} is {@code true}.
- */
- public static boolean checkOrder(double[] val, OrderDirection dir,
- boolean strict, boolean abort) {
- double previous = val[0];
- final int max = val.length;
- int index;
- ITEM:
- for (index = 1; index < max; index++) {
- switch (dir) {
- case INCREASING:
- if (strict) {
- if (val[index] <= previous) {
- break ITEM;
- }
- } else {
- if (val[index] < previous) {
- break ITEM;
- }
- }
- break;
- case DECREASING:
- if (strict) {
- if (val[index] >= previous) {
- break ITEM;
- }
- } else {
- if (val[index] > previous) {
- break ITEM;
- }
- }
- break;
- default:
- // Should never happen.
- throw new MathInternalError();
- }
- previous = val[index];
- }
- if (index == max) {
- // Loop completed.
- return true;
- }
- // Loop early exit means wrong ordering.
- if (abort) {
- throw new NonMonotonicSequenceException(val[index],
- previous,
- index,
- dir == OrderDirection.INCREASING,
- strict);
- } else {
- return false;
- }
- }
- /**
- * Check that the given array is sorted.
- *
- * @param val Values.
- * @param dir Ordering direction.
- * @param strict Whether the order should be strict.
- * @throws NonMonotonicSequenceException if the array is not sorted.
- * @since 2.2
- */
- public static void checkOrder(double[] val, OrderDirection dir, boolean strict) {
- checkOrder(val, dir, strict, true);
- }
- /**
- * Check that the given array is sorted in strictly increasing order.
- *
- * @param val Values.
- * @throws NonMonotonicSequenceException if the array is not sorted.
- * @since 2.2
- */
- public static void checkOrder(double[] val) {
- checkOrder(val, OrderDirection.INCREASING, true);
- }
- /**
- * Throws DimensionMismatchException if the input array is not rectangular.
- *
- * @param in array to be tested
- * @throws NullArgumentException if input array is null
- * @throws DimensionMismatchException if input array is not rectangular
- * @since 3.1
- */
- public static void checkRectangular(final long[][] in) {
- NullArgumentException.check(in);
- for (int i = 1; i < in.length; i++) {
- if (in[i].length != in[0].length) {
- throw new DimensionMismatchException(
- LocalizedFormats.DIFFERENT_ROWS_LENGTHS,
- in[i].length, in[0].length);
- }
- }
- }
- /**
- * Check that all entries of the input array are strictly positive.
- *
- * @param in Array to be tested
- * @throws NotStrictlyPositiveException if any entries of the array are not
- * strictly positive.
- * @since 3.1
- */
- public static void checkPositive(final double[] in) {
- for (double x : in) {
- if (x <= 0) {
- throw new NotStrictlyPositiveException(x);
- }
- }
- }
- /**
- * Check that no entry of the input array is {@code NaN}.
- *
- * @param in Array to be tested.
- * @throws NotANumberException if an entry is {@code NaN}.
- * @since 3.4
- */
- public static void checkNotNaN(final double[] in) {
- for (double x : in) {
- if (Double.isNaN(x)) {
- throw new NotANumberException();
- }
- }
- }
- /**
- * Check that all the elements are real numbers.
- *
- * @param val Arguments.
- * @throws NotFiniteNumberException if any values of the array is not a
- * finite real number.
- */
- public static void checkFinite(final double[] val) {
- for (double x : val) {
- if (!Double.isFinite(x)) {
- throw new NotFiniteNumberException(x);
- }
- }
- }
- /**
- * Check that all entries of the input array are >= 0.
- *
- * @param in Array to be tested
- * @throws NotPositiveException if any array entries are less than 0.
- * @since 3.1
- */
- public static void checkNonNegative(final long[] in) {
- for (long i : in) {
- if (i < 0) {
- throw new NotPositiveException(i);
- }
- }
- }
- /**
- * Check all entries of the input array are >= 0.
- *
- * @param in Array to be tested
- * @throws NotPositiveException if any array entries are less than 0.
- * @since 3.1
- */
- public static void checkNonNegative(final long[][] in) {
- for (int i = 0; i < in.length; i++) {
- for (int j = 0; j < in[i].length; j++) {
- if (in[i][j] < 0) {
- throw new NotPositiveException(in[i][j]);
- }
- }
- }
- }
- /**
- * Returns true iff both arguments are null or have same dimensions and all
- * their elements are equal as defined by
- * {@link Precision#equals(float,float)}.
- *
- * @param x first array
- * @param y second array
- * @return true if the values are both null or have same dimension
- * and equal elements.
- */
- public static boolean equals(float[] x, float[] y) {
- if (x == null || y == null) {
- return (x == null) == (y == null);
- }
- if (x.length != y.length) {
- return false;
- }
- for (int i = 0; i < x.length; ++i) {
- if (!Precision.equals(x[i], y[i])) {
- return false;
- }
- }
- return true;
- }
- /**
- * Returns true iff both arguments are null or have same dimensions and all
- * their elements are equal as defined by
- * {@link Precision#equalsIncludingNaN(double,double) this method}.
- *
- * @param x first array
- * @param y second array
- * @return true if the values are both null or have same dimension and
- * equal elements
- * @since 2.2
- */
- public static boolean equalsIncludingNaN(float[] x, float[] y) {
- if (x == null || y == null) {
- return (x == null) == (y == null);
- }
- if (x.length != y.length) {
- return false;
- }
- for (int i = 0; i < x.length; ++i) {
- if (!Precision.equalsIncludingNaN(x[i], y[i])) {
- return false;
- }
- }
- return true;
- }
- /**
- * Returns {@code true} iff both arguments are {@code null} or have same
- * dimensions and all their elements are equal as defined by
- * {@link Precision#equals(double,double)}.
- *
- * @param x First array.
- * @param y Second array.
- * @return {@code true} if the values are both {@code null} or have same
- * dimension and equal elements.
- */
- public static boolean equals(double[] x, double[] y) {
- if (x == null || y == null) {
- return (x == null) == (y == null);
- }
- if (x.length != y.length) {
- return false;
- }
- for (int i = 0; i < x.length; ++i) {
- if (!Precision.equals(x[i], y[i])) {
- return false;
- }
- }
- return true;
- }
- /**
- * Returns {@code true} iff both arguments are {@code null} or have same
- * dimensions and all their elements are equal as defined by
- * {@link Precision#equalsIncludingNaN(double,double) this method}.
- *
- * @param x First array.
- * @param y Second array.
- * @return {@code true} if the values are both {@code null} or have same
- * dimension and equal elements.
- * @since 2.2
- */
- public static boolean equalsIncludingNaN(double[] x, double[] y) {
- if (x == null || y == null) {
- return (x == null) == (y == null);
- }
- if (x.length != y.length) {
- return false;
- }
- for (int i = 0; i < x.length; ++i) {
- if (!Precision.equalsIncludingNaN(x[i], y[i])) {
- return false;
- }
- }
- return true;
- }
- /**
- * Normalizes an array to make it sum to a specified value.
- * Returns the result of the transformation
- * <pre>
- * x |-> x * normalizedSum / sum
- * </pre>
- * applied to each non-NaN element x of the input array, where sum is the
- * sum of the non-NaN entries in the input array.
- * <p>
- * Throws IllegalArgumentException if {@code normalizedSum} is infinite
- * or NaN and ArithmeticException if the input array contains any infinite elements
- * or sums to 0.
- * <p>
- * Ignores (i.e., copies unchanged to the output array) NaNs in the input array.
- *
- * @param values Input array to be normalized
- * @param normalizedSum Target sum for the normalized array
- * @return the normalized array.
- * @throws MathArithmeticException if the input array contains infinite
- * elements or sums to zero.
- * @throws MathIllegalArgumentException if the target sum is infinite or {@code NaN}.
- * @since 2.1
- */
- public static double[] normalizeArray(double[] values, double normalizedSum) {
- if (Double.isInfinite(normalizedSum)) {
- throw new MathIllegalArgumentException(LocalizedFormats.NORMALIZE_INFINITE);
- }
- if (Double.isNaN(normalizedSum)) {
- throw new MathIllegalArgumentException(LocalizedFormats.NORMALIZE_NAN);
- }
- double sum = 0d;
- final int len = values.length;
- double[] out = new double[len];
- for (int i = 0; i < len; i++) {
- if (Double.isInfinite(values[i])) {
- throw new MathIllegalArgumentException(LocalizedFormats.INFINITE_ARRAY_ELEMENT, values[i], i);
- }
- if (!Double.isNaN(values[i])) {
- sum += values[i];
- }
- }
- if (sum == 0) {
- throw new MathArithmeticException(LocalizedFormats.ARRAY_SUMS_TO_ZERO);
- }
- final double scale = normalizedSum / sum;
- for (int i = 0; i < len; i++) {
- if (Double.isNaN(values[i])) {
- out[i] = Double.NaN;
- } else {
- out[i] = values[i] * scale;
- }
- }
- return out;
- }
- /** Build an array of elements.
- * <p>
- * Arrays are filled with field.getZero()
- *
- * @param <T> the type of the field elements
- * @param field field to which array elements belong
- * @param length of the array
- * @return a new array
- * @since 3.2
- */
- public static <T> T[] buildArray(final Field<T> field, final int length) {
- @SuppressWarnings("unchecked") // OK because field must be correct class
- T[] array = (T[]) Array.newInstance(field.getRuntimeClass(), length);
- Arrays.fill(array, field.getZero());
- return array;
- }
- /** Build a double dimension array of elements.
- * <p>
- * Arrays are filled with field.getZero()
- *
- * @param <T> the type of the field elements
- * @param field field to which array elements belong
- * @param rows number of rows in the array
- * @param columns number of columns (may be negative to build partial
- * arrays in the same way <code>new Field[rows][]</code> works)
- * @return a new array
- * @since 3.2
- */
- @SuppressWarnings("unchecked")
- public static <T> T[][] buildArray(final Field<T> field, final int rows, final int columns) {
- final T[][] array;
- if (columns < 0) {
- T[] dummyRow = buildArray(field, 0);
- array = (T[][]) Array.newInstance(dummyRow.getClass(), rows);
- } else {
- array = (T[][]) Array.newInstance(field.getRuntimeClass(),
- rows, columns);
- for (int i = 0; i < rows; ++i) {
- Arrays.fill(array[i], field.getZero());
- }
- }
- return array;
- }
- /**
- * Calculates the <a href="http://en.wikipedia.org/wiki/Convolution">
- * convolution</a> between two sequences.
- * <p>
- * The solution is obtained via straightforward computation of the
- * convolution sum (and not via FFT). Whenever the computation needs
- * an element that would be located at an index outside the input arrays,
- * the value is assumed to be zero.
- *
- * @param x First sequence.
- * Typically, this sequence will represent an input signal to a system.
- * @param h Second sequence.
- * Typically, this sequence will represent the impulse response of the system.
- * @return the convolution of {@code x} and {@code h}.
- * This array's length will be {@code x.length + h.length - 1}.
- * @throws NullArgumentException if either {@code x} or {@code h} is {@code null}.
- * @throws NoDataException if either {@code x} or {@code h} is empty.
- *
- * @since 3.3
- */
- public static double[] convolve(double[] x, double[] h) {
- NullArgumentException.check(x);
- NullArgumentException.check(h);
- final int xLen = x.length;
- final int hLen = h.length;
- if (xLen == 0 || hLen == 0) {
- throw new NoDataException();
- }
- // initialize the output array
- final int totalLength = xLen + hLen - 1;
- final double[] y = new double[totalLength];
- // straightforward implementation of the convolution sum
- for (int n = 0; n < totalLength; n++) {
- double yn = 0;
- int k = JdkMath.max(0, n + 1 - xLen);
- int j = n - k;
- while (k < hLen && j >= 0) {
- yn += x[j--] * h[k++];
- }
- y[n] = yn;
- }
- return y;
- }
- /**
- * Returns an array representing the natural number {@code n}.
- *
- * @param n Natural number.
- * @return an array whose entries are the numbers 0, 1, ..., {@code n}-1.
- * If {@code n == 0}, the returned array is empty.
- */
- public static int[] natural(int n) {
- return sequence(n, 0, 1);
- }
- /**
- * Returns an array of {@code size} integers starting at {@code start},
- * skipping {@code stride} numbers.
- *
- * @param size Natural number.
- * @param start Natural number.
- * @param stride Natural number.
- * @return an array whose entries are the numbers
- * {@code start, start + stride, ..., start + (size - 1) * stride}.
- * If {@code size == 0}, the returned array is empty.
- *
- * @since 3.4
- */
- public static int[] sequence(int size,
- int start,
- int stride) {
- final int[] a = new int[size];
- for (int i = 0; i < size; i++) {
- a[i] = start + i * stride;
- }
- return a;
- }
- /**
- * This method is used
- * to verify that the input parameters designate a subarray of positive length.
- * <ul>
- * <li>returns <code>true</code> iff the parameters designate a subarray of
- * positive length</li>
- * <li>throws <code>MathIllegalArgumentException</code> if the array is null or
- * or the indices are invalid</li>
- * <li>returns <code>false</code> if the array is non-null, but
- * <code>length</code> is 0.</li>
- * </ul>
- *
- * @param values the input array
- * @param begin index of the first array element to include
- * @param length the number of elements to include
- * @return true if the parameters are valid and designate a subarray of positive length
- * @throws MathIllegalArgumentException if the indices are invalid or the array is null
- * @since 3.3
- */
- public static boolean verifyValues(final double[] values, final int begin, final int length) {
- return verifyValues(values, begin, length, false);
- }
- /**
- * This method is used
- * to verify that the input parameters designate a subarray of positive length.
- * <ul>
- * <li>returns <code>true</code> iff the parameters designate a subarray of
- * non-negative length</li>
- * <li>throws <code>IllegalArgumentException</code> if the array is null or
- * or the indices are invalid</li>
- * <li>returns <code>false</code> if the array is non-null, but
- * <code>length</code> is 0 unless <code>allowEmpty</code> is <code>true</code></li>
- * </ul>
- *
- * @param values the input array
- * @param begin index of the first array element to include
- * @param length the number of elements to include
- * @param allowEmpty if <code>true</code> then zero length arrays are allowed
- * @return true if the parameters are valid
- * @throws MathIllegalArgumentException if the indices are invalid or the array is null
- * @since 3.3
- */
- public static boolean verifyValues(final double[] values, final int begin,
- final int length, final boolean allowEmpty) {
- if (values == null) {
- throw new NullArgumentException(LocalizedFormats.INPUT_ARRAY);
- }
- if (begin < 0) {
- throw new NotPositiveException(LocalizedFormats.START_POSITION, Integer.valueOf(begin));
- }
- if (length < 0) {
- throw new NotPositiveException(LocalizedFormats.LENGTH, Integer.valueOf(length));
- }
- if (begin + length > values.length) {
- throw new NumberIsTooLargeException(LocalizedFormats.SUBARRAY_ENDS_AFTER_ARRAY_END,
- Integer.valueOf(begin + length), Integer.valueOf(values.length), true);
- }
- return !(length == 0 && !allowEmpty);
- }
- /**
- * This method is used
- * to verify that the begin and length parameters designate a subarray of positive length
- * and the weights are all non-negative, non-NaN, finite, and not all zero.
- * <ul>
- * <li>returns <code>true</code> iff the parameters designate a subarray of
- * positive length and the weights array contains legitimate values.</li>
- * <li>throws <code>IllegalArgumentException</code> if any of the following are true:
- * <ul><li>the values array is null</li>
- * <li>the weights array is null</li>
- * <li>the weights array does not have the same length as the values array</li>
- * <li>the weights array contains one or more infinite values</li>
- * <li>the weights array contains one or more NaN values</li>
- * <li>the weights array contains negative values</li>
- * <li>the weights array does not contain at least one non-zero value (applies when length is non zero)</li>
- * <li>the start and length arguments do not determine a valid array</li></ul>
- * </li>
- * <li>returns <code>false</code> if the array is non-null, but
- * <code>length</code> is 0.</li>
- * </ul>
- *
- * @param values the input array
- * @param weights the weights array
- * @param begin index of the first array element to include
- * @param length the number of elements to include
- * @return true if the parameters are valid and designate a subarray of positive length
- * @throws MathIllegalArgumentException if the indices are invalid or the array is null
- * @since 3.3
- */
- public static boolean verifyValues(
- final double[] values,
- final double[] weights,
- final int begin,
- final int length) {
- return verifyValues(values, weights, begin, length, false);
- }
- /**
- * This method is used
- * to verify that the begin and length parameters designate a subarray of positive length
- * and the weights are all non-negative, non-NaN, finite, and not all zero.
- * <ul>
- * <li>returns <code>true</code> iff the parameters designate a subarray of
- * non-negative length and the weights array contains legitimate values.</li>
- * <li>throws <code>MathIllegalArgumentException</code> if any of the following are true:
- * <ul><li>the values array is null</li>
- * <li>the weights array is null</li>
- * <li>the weights array does not have the same length as the values array</li>
- * <li>the weights array contains one or more infinite values</li>
- * <li>the weights array contains one or more NaN values</li>
- * <li>the weights array contains negative values</li>
- * <li>the weights array does not contain at least one non-zero value (applies when length is non zero)</li>
- * <li>the start and length arguments do not determine a valid array</li></ul>
- * </li>
- * <li>returns <code>false</code> if the array is non-null, but
- * <code>length</code> is 0 unless <code>allowEmpty</code> is <code>true</code>.</li>
- * </ul>
- *
- * @param values the input array.
- * @param weights the weights array.
- * @param begin index of the first array element to include.
- * @param length the number of elements to include.
- * @param allowEmpty if {@code true} than allow zero length arrays to pass.
- * @return {@code true} if the parameters are valid.
- * @throws NullArgumentException if either of the arrays are null
- * @throws MathIllegalArgumentException if the array indices are not valid,
- * the weights array contains NaN, infinite or negative elements, or there
- * are no positive weights.
- * @since 3.3
- */
- public static boolean verifyValues(final double[] values, final double[] weights,
- final int begin, final int length, final boolean allowEmpty) {
- if (weights == null || values == null) {
- throw new NullArgumentException(LocalizedFormats.INPUT_ARRAY);
- }
- checkEqualLength(weights, values);
- if (length != 0) {
- boolean containsPositiveWeight = false;
- for (int i = begin; i < begin + length; i++) {
- final double weight = weights[i];
- if (Double.isNaN(weight)) {
- throw new MathIllegalArgumentException(LocalizedFormats.NAN_ELEMENT_AT_INDEX, Integer.valueOf(i));
- }
- if (Double.isInfinite(weight)) {
- throw new MathIllegalArgumentException(LocalizedFormats.INFINITE_ARRAY_ELEMENT,
- Double.valueOf(weight), Integer.valueOf(i));
- }
- if (weight < 0) {
- throw new MathIllegalArgumentException(LocalizedFormats.NEGATIVE_ELEMENT_AT_INDEX,
- Integer.valueOf(i), Double.valueOf(weight));
- }
- if (!containsPositiveWeight && weight > 0.0) {
- containsPositiveWeight = true;
- }
- }
- if (!containsPositiveWeight) {
- throw new MathIllegalArgumentException(LocalizedFormats.WEIGHT_AT_LEAST_ONE_NON_ZERO);
- }
- }
- return verifyValues(values, begin, length, allowEmpty);
- }
- /**
- * Concatenates a sequence of arrays. The return array consists of the
- * entries of the input arrays concatenated in the order they appear in
- * the argument list. Null arrays cause NullPointerExceptions; zero
- * length arrays are allowed (contributing nothing to the output array).
- *
- * @param x list of double[] arrays to concatenate
- * @return a new array consisting of the entries of the argument arrays
- * @throws NullPointerException if any of the arrays are null
- * @since 3.6
- */
- public static double[] concatenate(double[]... x) {
- int combinedLength = 0;
- for (double[] a : x) {
- combinedLength += a.length;
- }
- int offset = 0;
- int curLength = 0;
- final double[] combined = new double[combinedLength];
- for (int i = 0; i < x.length; i++) {
- curLength = x[i].length;
- System.arraycopy(x[i], 0, combined, offset, curLength);
- offset += curLength;
- }
- return combined;
- }
- /**
- * Returns an array consisting of the unique values in {@code data}.
- * The return array is sorted in descending order. Empty arrays
- * are allowed, but null arrays result in NullPointerException.
- * Infinities are allowed. NaN values are allowed with maximum
- * sort order - i.e., if there are NaN values in {@code data},
- * {@code Double.NaN} will be the first element of the output array,
- * even if the array also contains {@code Double.POSITIVE_INFINITY}.
- *
- * @param data array to scan
- * @return descending list of values included in the input array
- * @throws NullPointerException if data is null
- * @since 3.6
- */
- public static double[] unique(double[] data) {
- TreeSet<Double> values = new TreeSet<>();
- for (int i = 0; i < data.length; i++) {
- values.add(data[i]);
- }
- final int count = values.size();
- final double[] out = new double[count];
- Iterator<Double> iterator = values.descendingIterator();
- int i = 0;
- while (iterator.hasNext()) {
- out[i++] = iterator.next();
- }
- return out;
- }
- }