package nl.wldelft.util; import nl.wldelft.fews.system.plugin.transformationmodule.function.implementation.stagedischarge.LookupTableOffset; import java.util.Arrays; public class FloatArrayUtils { // ******* DoubleArrayUtils and FloatArrayUtils should BE THE SAME ********* // use Intellij replace float, double with preserve case for easy conversion public static final float[] EMPTY_ARRAY = new float[0]; private FloatArrayUtils() { } public static boolean equals(float[] a, int aPos, int aLength, float[] b, int bPos, int bLength) { if (a == null && b == null) return true; if (a == null || b == null) return false; checkArg("a", a, aPos, aLength); checkArg("b", b, bPos, bLength); if (aLength != bLength) return false; if (a == b && aPos == bPos) return true; for (int i = aPos, j = bPos, n = aPos + aLength; i < n; i++, j++) { if (a[i] != b[j] && Float.floatToIntBits(a[i]) != Float.floatToIntBits(b[j])) return false; } return true; } public static boolean contains(float[] array, float value) { return indexOf(array, value) != -1; } public static boolean containsNaN(float[] array) { return indexOfNaN(array) != -1; } public static boolean containsNonNaN(float[] array) { return indexOfNonNaN(array) != -1; } public static boolean containsInfinite(float[] array) { if (array == null) return false; for (int i = 0; i < array.length; i++) { if (Float.isInfinite(array[i])) return true; } return false; } public static int indexOf(float[] array, float value) { return indexOf(array, 0, array.length, value); } public static int indexOf(float[] array, int pos, int length, float value) { checkArg("array", array, pos, length); if (Float.isNaN(value)) { for (int i = pos, n = pos + length; i < n; i++) { if (Float.isNaN(array[i])) return i; } } else { for (int i = pos, n = pos + length; i < n; i++) { if (array[i] == value) return i; } } return -1; } public static int indexOfNaN(float[] array) { return indexOfNaN(array, 0, array.length); } public static int indexOfNaN(float[] array, int pos, int length) { checkArg("array", array, pos, length); for (int i = pos, n = pos + length; i < n; i++) { if (Float.isNaN(array[i])) return i; } return -1; } public static int indexOfNonNaN(float[] array) { return indexOfNonNaN(array, 0, array.length); } public static int indexOfNonNaN(float[] array, int pos, int length) { checkArg("array", array, pos, length); for (int i = pos, n = pos + length; i < n; i++) { if (!Float.isNaN(array[i])) return i; } return -1; } public static int binarySearchClosest(float[] sortedArray, float value) { if (sortedArray.length == 0) return -1; if (sortedArray.length == 1) return 0; int res = Arrays.binarySearch(sortedArray, value); if (res >= 0) return res; res = -(res + 1); if (res == sortedArray.length) return sortedArray.length - 1; if (res == 0) return 0; float low = sortedArray[res - 1]; float high = sortedArray[res]; if (value - low < high - value) return res - 1; return res; } public static int count(float[] array, float value) { int res = 0; if (Float.isNaN(value)) { for (int i = 0; i < array.length; i++) { if (Float.isNaN(array[i])) res++; } } else { for (int i = 0; i < array.length; i++) { if (array[i] == value) res++; } } return res; } /** * Reverse the order of the values in the array. * <p/> * [0,1,2,3] -> [3,2,1,0] * * @param array */ public static void reverseOrder(float[] array) { if (array == null) throw new IllegalArgumentException("array == null"); if (array.length == 1) return; int halfLength = array.length / 2; int lastIndex = array.length - 1; for (int i = 0; i < halfLength; i++) { float f1 = array[i]; array[i] = array[lastIndex - i]; array[lastIndex - i] = f1; } } public static void replace(float[] array, float oldValue, float newValue) { if (array == null) throw new IllegalArgumentException("array == null"); if (Float.isNaN(oldValue)) { replaceNaN(array, newValue); return; } if (oldValue == newValue) return; for (int i = 0; i < array.length; i++) { if (array[i] != oldValue) continue; array[i] = newValue; } } public static void replaceNaN(float[] array, float newValue) { if (array == null) throw new IllegalArgumentException("array == null"); if (Float.floatToRawIntBits(newValue) == Float.floatToIntBits(Float.NaN)) return; for (int i = 0; i < array.length; i++) { if (!Float.isNaN(array[i])) continue; array[i] = newValue; } } public static void replace(float[] array, float[] oldValues, float newValue) { if (array == null) throw new IllegalArgumentException("array == null"); if (oldValues == null) throw new IllegalArgumentException("oldValues == null"); for (int i = 0; i < array.length; i++) { if (contains(oldValues, array[i])) { array[i] = newValue; } } } public static void replace(float[] array, float minValue, float maxValue, float newValue) { for (int i = 0; i < array.length; i++) { if (minValue <= array[i] && array[i] <= maxValue) { array[i] = newValue; } } } public static float min(float[] array) { return min(array, 0, array.length); } public static float min(float[] array, int pos, int length) { float res = Float.POSITIVE_INFINITY; for (int i = pos, n = pos + length; i < n; i++) { float v = array[i]; if (v < res) res = v; } if (res == Float.POSITIVE_INFINITY) return Float.NaN; return res; } public static float max(float[] array) { return max(array, 0, array.length); } public static float max(float[] array, int pos, int length) { checkArg("array", array, pos, length); float res = Float.NEGATIVE_INFINITY; for (int i = pos, n = pos + length; i < n; i++) { float v = array[i]; if (v > res) res = v; } if (res == Float.NEGATIVE_INFINITY) return Float.NaN; return res; } public static float maxSkipNaN(float[] array) { return maxSkipNaN(array, 0, array.length); } public static float maxSkipNaN(float[] array, int pos, int length) { checkArg("array", array, pos, length); float res = Float.NEGATIVE_INFINITY; for (int i = pos, n = pos + length; i < n; i++) { float v = array[i]; if (Float.isNaN(v)) continue; if (v > res) res = v; } if (res == Float.NEGATIVE_INFINITY) return Float.NaN; return res; } public static float sum(float[] array) { return sum(array, 0, array.length); } public static float sum(float[] array, int pos, int length) { checkArg("array", array, pos, length); if (length == 0) return 0f; float res = array[pos]; for (int i = pos + 1, n = pos + length; i < n; i++) { res += array[i]; } return res; } public static float sumSkipNaN(float[] array) { return sumSkipNaN(array, 0, array.length); } public static float sumSkipNaN(float[] array, int pos, int length) { checkArg("array", array, pos, length); if (length == 0) return 0f; float res = 0; for (int i = pos, n = pos + length; i < n; i++) { float v = array[i]; if (Float.isNaN(v)) continue; res += array[i]; } return res; } public static float mean(float[] array) { return mean(array, 0, array.length); } public static float mean(float[] array, int beginIndex, int length) { if (length == 0) return Float.NaN; return sum(array, beginIndex, length) / length; } public static float meanSkipNaN(float[] array) { return meanSkipNaN(array, 0, array.length); } public static float meanSkipNaN(float[] array, int pos, int length) { checkArg("array", array, pos, length); float res = 0; int count = 0; for (int i = pos, n = pos + length; i < n; i++) { float v = array[i]; if (Float.isNaN(v)) continue; res += v; count++; } if (count == 0) return Float.NaN; return res / count; } public static boolean isAscending(float[] array) { return getFirstNonAscendingIndex(array) == -1; } public static int getFirstNonAscendingIndex(float[] array) { if (array.length <= 1) return -1; float lastValue = array[0]; for (int i = 1; i < array.length; i++) { float v = array[i]; if (v <= lastValue) return i; lastValue = v; } return -1; } public static float[] select(float[] array, int[] indices) { if (indices.length == 0) return FloatArrayUtils.EMPTY_ARRAY; float[] res = new float[indices.length]; for (int i = 0; i < res.length; i++) { res[i] = array[indices[i]]; } return res; } public static long getInterpolatedValueY(float[] xs, long[] ys, float x) { if (xs == null) throw new IllegalArgumentException("xs == null"); if (ys == null) throw new IllegalArgumentException("ys == null"); if (xs.length != ys.length) throw new IllegalArgumentException("xs.length != ys.length"); assert isAscending(xs); int i = Arrays.binarySearch(xs, x); if (i >= 0) return ys[i]; int insertionPoint = -(i + 1); if (insertionPoint == 0) return ys[0]; if (insertionPoint == xs.length) return ys[ys.length - 1]; float x1 = xs[insertionPoint - 1]; float x2 = xs[insertionPoint]; float y1 = ys[insertionPoint - 1]; float y2 = ys[insertionPoint]; return (long) (y1 + (x - x1) / (x2 - x1) * (y2 - y1)); } public static float getInterpolatedValueY(float[] xs, float[] ys, float x) { return getInterpolatedValueY(xs, ys, x, true); } /** * Lookup x value in array xs and find corresponding y value in ys. Use linear interpolation * for calculation of y. * * @param xs X lookup array * @param ys Y lookup array * @param x X lookup value * @param allowExtrapolation Option to allow conversion of values outside the xs array. When true then values * are mapped to either the minimum or maximum values in the ys array. When false the values outside the * xs range are mapped to NAN. * @return */ public static float getInterpolatedValueY(float[] xs, float[] ys, float x, boolean allowExtrapolation) { if (xs == null) throw new IllegalArgumentException("xs == null"); if (ys == null) throw new IllegalArgumentException("ys == null"); if (xs.length != ys.length) throw new IllegalArgumentException("xs.length != ys.length"); assert isAscending(xs); int i = Arrays.binarySearch(xs, x); if (i >= 0) return ys[i]; int insertionPoint = -(i + 1); if (insertionPoint == 0) { if (allowExtrapolation) return ys[0]; else return Float.NaN; } if (insertionPoint == xs.length) { if (allowExtrapolation) return ys[ys.length - 1]; else return Float.NaN; } float x1 = xs[insertionPoint - 1]; float x2 = xs[insertionPoint]; float y1 = ys[insertionPoint - 1]; float y2 = ys[insertionPoint]; return y1 + (x - x1) / (x2 - x1) * (y2 - y1); } public static float interpolate(float[] hs, float[] qs, float h, boolean allowExtrapolation, boolean useLogarithmicInterpolation, boolean searchClosestPoint) { return interpolate(hs, qs, h, allowExtrapolation, useLogarithmicInterpolation, searchClosestPoint, LookupTableOffset.getEmptyLookupOffset(), LookupTableOffset.getEmptyLookupOffset()); } /** * Looks up the given input value h in the given array hs and returns the corresponding value from the given array qs. * The values in the lookup array hs must be in ascending order. Each value hs[n] must have a corresponding value qs[n]. * If h is between two consecutive values in the lookup array hs, then the corresponding qs values will be interpolated * to get a q value for the given h value. * * Options for interpolation/extrapolation: * If useLogarithmicInterpolation is true, then interpolation and extrapolation is logarithmic. Otherwise interpolation * and extrapolation is linear. * If searchClosestPoint is true, then returns the qs value that corresponds to the hs value that is closest to the input h. * If allowExtrapolation is false, then does not extrapolate, but returns the qs value that corresponds to the hs value * that is closest to the input h (either the minimum hs value or the maximum hs value). * * @param hs * @param qs * @param h * @param allowExtrapolation * @param useLogarithmicInterpolation * @param searchClosestPoint * @param hOffset to use this method without offsets, pass in LookupTableOffset.getDummyLookupOffset(). * @param qOffset to use this method without offsets, pass in LookupTableOffset.getDummyLookupOffset(). * @return interpolated value. */ public static float interpolate(float[] hs, float[] qs, float h, boolean allowExtrapolation, boolean useLogarithmicInterpolation, boolean searchClosestPoint, LookupTableOffset hOffset, LookupTableOffset qOffset) { if (hs == null) throw new IllegalArgumentException("hs == null"); if (qs == null) throw new IllegalArgumentException("qs == null"); if (hs.length != qs.length) throw new IllegalArgumentException("hs.length != qs.length"); int i = Arrays.binarySearch(hs, h); if (i >= 0) return qs[i];//h value in hs array, return corresponding qs value. //h value not in hs array, so either interpolate or extrapolate to get q value. int insertionPoint = -(i + 1); double qu = 0; double ql = 0; double hu = 0; double hl = 0; double a; if (insertionPoint == 0) { if (allowExtrapolation) { qu = qs[1]; ql = qs[0]; hu = hs[1]; hl = hs[0]; } else { return returnWithOffset(qs[0], qOffset); } } else if (insertionPoint == hs.length) { if (allowExtrapolation) { qu = qs[qs.length - 1]; ql = qs[qs.length - 2]; hu = hs[qs.length - 1]; hl = hs[qs.length - 2]; } else { return returnWithOffset(qs[qs.length - 1], qOffset); } } else { //interpolate. qu = qs[insertionPoint]; ql = qs[insertionPoint - 1]; hu = hs[insertionPoint]; hl = hs[insertionPoint - 1]; } double h1 = h; //aply offsets float hoffset = hOffset.getOffset((float) h1); float qoffset = qOffset.getOffset((float) hl); h1 -= hoffset; qu -= qoffset; ql -= qoffset; hu -= hoffset; hl -= hoffset; if (useLogarithmicInterpolation) { if (hu == 0) hu = 0.0001; if (hl == 0) hl = 0.0001; if (qu == 0) qu = 0.0001; if (ql == 0) ql = 0.0001; qu = Math.log(qu); ql = Math.log(ql); hu = Math.log(hu); hl = Math.log(hl); h1 = Math.log(h1); } if (searchClosestPoint) { if (Math.abs(h - hu) > Math.abs(h - hl)) { return returnWithOffset((float) ql, qOffset); } else { return returnWithOffset((float) qu, qOffset); } } a = (qu - ql) / (hu - hl); double result = ql + a * (h1 - hl); result = useLogarithmicInterpolation ? Math.exp(result) : result; return returnWithOffset((float) result,qOffset); } private static float returnWithOffset(float value,LookupTableOffset lookupTableOffset) { return value + lookupTableOffset.getOffset(value); } public static ArraySegmentIterator createRangeSegmentIterator(final float[] array, final int pos, final int length, final FloatRange range) { checkArg("array", array, pos, length); final int startPos = range.indexOfInRange(array, pos, length); if (startPos == -1) return ArraySegmentIterator.EMPTY; return new ArraySegmentIterator() { private int currentPos = startPos; private int currentLength = 0; @Override public int next() { if (currentPos == -1) return -1; if (currentLength != 0) { currentPos = range.indexOfInRange(array, currentPos + currentLength, pos + length - currentPos - currentLength); if (currentPos == -1) return -1; } int outOfRangePos = range.indexOfOutOfRange(array, currentPos, pos + length - currentPos); if (outOfRangePos == -1) { currentLength = pos + length - currentPos; int res = currentPos; currentPos = -1; return res; } currentLength = outOfRangePos - currentPos; return currentPos; } @Override public int length() { return currentLength; } }; } public static Float[] box(float[] array) { if (array == null) throw new IllegalArgumentException("array == null"); Float[] res = new Float[array.length]; for (int i = 0; i < array.length; i++) { res[i] = new Float(array[i]); } return res; } public static float[] unbox(Float[] array) { if (array == null) throw new IllegalArgumentException("array == null"); float[] res = new float[array.length]; for (int i = 0; i < array.length; i++) { res[i] = array[i].floatValue(); } return res; } public static float[] unbox(Float[] array, float nullValue) { if (array == null) throw new IllegalArgumentException("array == null"); float[] res = new float[array.length]; for (int i = 0; i < array.length; i++) { Float value = array[i]; res[i] = value == null ? nullValue : value.floatValue(); } return res; } public static void checkArg(String arrayName, float[] array, int pos, int length) { if (array == null) throw new IllegalArgumentException(arrayName + " == null"); if (pos < 0) throw new IllegalArgumentException(arrayName + "pos < 0 " + pos + " < 0"); if (length < 0) throw new IllegalArgumentException(arrayName + "length < 0 " + length + " < 0"); if (pos + length > array.length) throw new IllegalArgumentException(arrayName + "pos + " + arrayName + "length > " + arrayName + ".length " + pos + " + " + length + " > " + array.length); } public static float[] resize(float[] array, int size) { if (array == null) throw new IllegalArgumentException("array == null"); if (size < 0) throw new IllegalArgumentException("size < 0"); if (size == 0) return EMPTY_ARRAY; int oldSize = array.length; if (oldSize == size) return array; float[] res = new float[size]; int preservedSize = size < oldSize ? size : oldSize; if (preservedSize > 0) System.arraycopy(array, 0, res, 0, preservedSize); return res; } public static void copy(float[] src, float[] dest) { if (src == null) throw new IllegalArgumentException("src == null"); if (dest == null) throw new IllegalArgumentException("dest == null"); int srcLength = src.length; int dstLength = dest.length; if (srcLength != dstLength) throw new IllegalArgumentException("src.length != dst.length"); System.arraycopy(src, 0, dest, 0, srcLength); } public static float[] subArray(float[] array, int beginIndex) { return subArray(array, beginIndex, array.length); } public static float[] subArray(float[] array, int beginIndex, int endIndex) { if (array == null) { throw new IllegalArgumentException("anArray == null"); } int length = endIndex - beginIndex; float[] res = new float[length]; System.arraycopy(array, beginIndex, res, 0, length); return res; } public static float[] join(float[] array1, float[] array2) { if (array1 == null && array2 == null) return null; if (array1 == null) return array2.clone(); if (array2 == null) return array1.clone(); float[] res = new float[array1.length + array2.length]; System.arraycopy(array1, 0, res, 0, array1.length); System.arraycopy(array2, 0, res, array1.length, array2.length); return res; } public static float[] join(float[][] arrays) { if (arrays == null) throw new IllegalArgumentException("arrays == null"); float[] res = new float[countElements(arrays)]; int j = 0; for (int i = 0; i < arrays.length; i++) { float[] array = arrays[i]; if (array == null) continue; System.arraycopy(array, 0, res, j, array.length); j += array.length; } return res; } public static float[][] split(float[] array, int maxArrayLength) { if (array == null) throw new IllegalArgumentException("array == null"); if (array.length <= maxArrayLength) return new float[][]{array}; int arrayCount = array.length / maxArrayLength; int restArrayLength = array.length % maxArrayLength; if (restArrayLength != 0) arrayCount++; float[][] res = new float[arrayCount][]; for (int i = 0, n = array.length / maxArrayLength; i < n; i++) { float[] subArray = new float[maxArrayLength]; System.arraycopy(array, i * maxArrayLength, subArray, 0, maxArrayLength); res[i] = subArray; } if (restArrayLength != 0) { float[] subArray = new float[restArrayLength]; System.arraycopy(array, (arrayCount - 1) * maxArrayLength, subArray, 0, restArrayLength); res[arrayCount - 1] = subArray; } return res; } public static float[] ensureCapacity(float[] array, int minCapacity) { if (array == null) throw new IllegalArgumentException("array == null"); if (array.length >= minCapacity) return array; int newCapacity = minCapacity * 3 / 2 + 1; if (newCapacity < minCapacity) newCapacity = minCapacity; float[] res = new float[newCapacity]; System.arraycopy(array, 0, res, 0, array.length); return res; } public static int countElements(float[][] arrays) { if (arrays == null) throw new IllegalArgumentException("arrays == null"); int res = 0; for (int i = 0; i < arrays.length; i++) { float[] array = arrays[i]; if (array == null) continue; res += array.length; } return res; } /** * The java array.clone is very slow */ public static float[] copyOf(float[] array) { return copyOfRange(array, 0, array.length); } public static float[] copyOfRange(float[] array, int pos, int length) { return copyOfRange(array, pos, length, length); } public static float[] copyOfRange(float[] array, int pos, int length, int newCapacity) { if (newCapacity == 0) return EMPTY_ARRAY; float[] res = new float[newCapacity]; arraycopy(array, pos, res, 0, length); return res; } /** * 4 times faster than java 6 {@link System#arraycopy(Object, int, Object, int, int)} for small arrays */ public static void arraycopy(float[] src, int srcPos, float[] dest, int destPos, int length) { if (length < 10) { for (int i = srcPos, j = destPos, n = srcPos + length; i < n; i++, j++) { dest[j] = src[i]; } } else { System.arraycopy(src, srcPos, dest, destPos, length); } } }