You are viewing an old version of this page. View the current version.

Compare with Current View Page History

« Previous Version 2 Next »

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);
        }
    }
}
  • No labels