All Downloads are FREE. Search and download functionalities are using the official Maven repository.

com.bbn.bue.common.primitives.DoubleUtils Maven / Gradle / Ivy

The newest version!
package com.bbn.bue.common.primitives;

import com.google.common.base.Function;
import com.google.common.base.Predicate;
import com.google.common.primitives.Doubles;

import static com.google.common.base.Preconditions.checkArgument;

public final class DoubleUtils {

  private DoubleUtils() {
    throw new UnsupportedOperationException();
  }

  public static double dotProduct(final double[] a, final double[] b) {
    checkArgument(a.length == b.length);
    double ret = 0.0;
    for (int i = 0; i < a.length; ++i) {
      ret += a[i] * b[i];
    }
    return ret;
  }

  public static final Predicate IsFinite = new Predicate() {
    @Override
    public boolean apply(final Double x) {
      return Doubles.isFinite(x);
    }
  };

  public static final Predicate IsNonNegative = new Predicate() {
    @Override
    public boolean apply(final Double x) {
      return x >= 0.0;
    }
  };


  public static final Function ParseDouble = new Function() {
    @Override
    public Double apply(final String x) {
      return Double.parseDouble(x);
    }
  };


  /**
   * Sum an array of doubles
   */
  public static double sum(final double[] data) {
    double ret = 0.0;
    for (final double x : data) {
      ret += x;
    }
    return ret;
  }

  public static double sum(final double[] data, final int startInclusive, final int endExclusive) {
    checkArgument(startInclusive >= 0);
    checkArgument(endExclusive <= data.length);
    checkArgument(endExclusive >= startInclusive);

    double ret = 0.0;
    for (int i = startInclusive; i < endExclusive; ++i) {
      ret += data[i];
    }
    return ret;
  }


  /**
   * Avoid division by zero.
   */
  public static double XOverYOrZero(final double x, final double y) {
    if (y != 0.0) {
      return x / y;
    } else {
      return 0.0;
    }
  }

  /**
   * Returns the index of the first minimal element of the array. That is, if there is a unique
   * minimum, its index is returned. If there are multiple values tied for smallest, the index of
   * the first is returned. If the supplied array is empty, an {@link IllegalArgumentException} is
   * thrown.
   */
  public static int argMin(final double[] x) {
    checkArgument(x.length > 0);
    double minValue = Double.MAX_VALUE;
    int minIndex = 0;

    for (int i = 0; i < x.length; ++i) {
      final double val = x[i];
      if (val < minValue) {
        minIndex = i;
        minValue = val;
      }
    }
    return minIndex;
  }

  /**
   * Returns the index of the first minimal element of the array within the specified bounds. That
   * is, if there is a unique minimum, its index is returned. If there are multiple values tied for
   * smallest, the index of the first is returned. If the supplied array is empty, an {@link
   * IllegalArgumentException} is thrown.
   */
  public static int argMin(final double[] x, final int startInclusive, final int endExclusive) {
    checkArgument(endExclusive > startInclusive);
    checkArgument(startInclusive >= 0);
    checkArgument(endExclusive <= x.length);
    double minValue = Double.MAX_VALUE;
    int minIndex = 0;

    for (int i = startInclusive; i < endExclusive; ++i) {
      final double val = x[i];
      if (val < minValue) {
        minIndex = i;
        minValue = val;
      }
    }
    return minIndex;
  }


  /**
   * Returns the index of the first maximal element of the array. That is, if there is a unique
   * maximum, its index is returned. If there are multiple values tied for largest, the index of the
   * first is returned. If the supplied array is empty, an {@link IllegalArgumentException} is
   * thrown.
   */
  public static int argMax(final double[] x) {
    checkArgument(x.length > 0);
    double maxValue = Double.MIN_VALUE;
    int maxIndex = 0;

    for (int i = 0; i < x.length; ++i) {
      final double val = x[i];
      if (val > maxValue) {
        maxIndex = i;
        maxValue = val;
      }
    }
    return maxIndex;
  }


  /**
   * Returns the index of the first maximal element of the array within the specified bounds. That
   * is, if there is a unique maximum, its index is returned. If there are multiple values tied for
   * largest, the index of the first is returned. If the supplied array is empty, an {@link
   * IllegalArgumentException} is thrown.
   */
  public static int argMax(final double[] x, final int startInclusive, final int endExclusive) {
    checkArgument(endExclusive > startInclusive);
    checkArgument(startInclusive >= 0);
    checkArgument(endExclusive <= x.length);

    double maxValue = Double.MIN_VALUE;
    int maxIndex = 0;

    for (int i = startInclusive; i < endExclusive; ++i) {
      final double val = x[i];
      if (val > maxValue) {
        maxIndex = i;
        maxValue = val;
      }
    }
    return maxIndex;
  }

  /**
   * Returns the maximum value in the array within the specified bounds. If the supplied range is
   * empty or invalid, an {@link IllegalArgumentException} is thrown.
   */
  public static double max(final double[] data, final int startInclusive, final int endExclusive) {
    checkArgument(endExclusive > startInclusive);
    checkArgument(startInclusive >= 0);
    checkArgument(endExclusive <= data.length);

    double maxValue = Double.NEGATIVE_INFINITY;
    for (int i = startInclusive; i < endExclusive; ++i) {
      maxValue = Math.max(maxValue, data[i]);
    }
    return maxValue;
  }

  /**
   * Returns the maximum value in the array within the specified bounds. If the supplied range is
   * empty or invalid, an {@link IllegalArgumentException} is thrown.
   */
  public static double min(final double[] data, final int startInclusive, final int endExclusive) {
    checkArgument(endExclusive > startInclusive);
    checkArgument(startInclusive >= 0);
    checkArgument(endExclusive <= data.length);

    double minValue = Double.POSITIVE_INFINITY;
    for (int i = startInclusive; i < endExclusive; ++i) {
      minValue = Math.min(minValue, data[i]);
    }
    return minValue;
  }


  public static boolean isCloseToIntegral(final double value, final double tolerance) {
    return Math.abs(value - Math.round(value)) <= tolerance;
  }

  /**
   * Returns true if the two provided values are within {@code tolerance} of one another.
   */
  public static boolean withinEpsilonOf(final double value1, final double value2,
      final double tolerance) {
    return Math.abs(value1 - value2) < tolerance;
  }

  /**
   * Sums an iterable of non-null {@code Doubles}.
   */
  public static double sum(final Iterable values) {
    double ret = 0.0;
    for (final double d : values) {
      ret += d;
    }
    return ret;
  }

  /**
   * Calculates {@code log(sum_i(exp(x_i)))} in a more numerically stable way than the naive
   * implementation.  Such sums commonly arise in machine learning algorithms (e.g. calculating
   * expectations in conditional random fields). If the input array is empty, {@link
   * Double#NEGATIVE_INFINITY} is returned.
   */
  public static double logSumOfExponentials(double[] arr) {
    if (arr.length == 0) {
      return Double.NEGATIVE_INFINITY;
    }

    final double maxVal = Doubles.max(arr);
    double ret = 0.0;
    for (int i = 0; i < arr.length; ++i) {
      // ensures biggest value we ever exp is 0.
      ret += Math.exp(arr[i] - maxVal);
    }
    return maxVal + Math.log(ret);
  }


  /**
   * Shifts the provided {@code val} towards but not past zero.  If the absolute value of
   * {@code val} is less than or equal to shift, zero will be returned. Otherwise, negative {@code val}s
   * will have {@code shift} added and positive vals will have {@code shift} subtracted.
   *
   * {@code shift} must be non-negative
   *
   * Inspired by AdaGradRDA.ISTAHelper from FACTORIE.
   */
  public static double shiftTowardsZeroWithClipping(double val, double shift) {
    checkArgument(shift>=0.0);
    if (val > shift) {
      return val - shift;
    } else if (val < -shift) {
      return val + shift;
    } else {
      return 0.0;
    }
  }

  /**
   * Shifts the provided {@code val} towards but not past zero.  If the absolute value of {@code
   * val} is less than or equal to shift, zero will be returned. Otherwise, negative {@code val}s
   * will have {@code shift} added and positive vals will have {@code shift} subtracted.
   *
   * If {@code shift} is negative, the result is undefined.  This method is the same as {@link
   * #shiftTowardsZeroWithClipping(double, double)} except that it eliminates the check on {@code
   * shift} for speed in deep-inner loops. This is a profile/jitwatch-guided optimization.
   *
   * Inspired by AdaGradRDA.ISTAHelper from FACTORIE.
   */
  public static double shiftTowardsZeroWithClippingRecklessly(double val, double shift) {
    if (val > shift) {
      return val - shift;
    } else if (val < -shift) {
      return val + shift;
    } else {
      return 0.0;
    }
  }

  /**
   * Clips the given value within the given bounds.  If {@code -bounds <=  val <= bounds}, {@code
   * val} is returned unchanged. Otherwise, {@code -bounds} is returned if {@code valbounds}. If {@code bounds} is negative, an {@link
   * IllegalArgumentException} will be thrown.  In inner loops, consider using {@link
   * #clipRecklessly(double, double)}.
   *
   * {@code NaN} values will be left unchanged, but positive and negative infinity will be clipped.
   */
  public static double clip(double val, double bounds) {
    checkArgument(bounds >= 0.0);
    return clipRecklessly(val, bounds);
  }

  /**
   * Clips the given value within the given bounds.  If {@code -bounds <=  val <= bounds}, {@code
   * val} is returned unchanged. Otherwise, {@code -bounds} is returned if {@code valbounds}. {@code bounds} must be non-negative, but this
   * is not enforced, so prefer using {@link #clip(double, double)} except in inner-loops.
   *
   * {@code NaN} values will be left unchanged, but positive and negative infinity will be clipped.
   */
  public static double clipRecklessly(double val, double bounds) {
    if (val > bounds) {
      return bounds;
    } else if (val < -bounds) {
      return -bounds;
    } else {
      return val;
    }
  }
}




© 2015 - 2024 Weber Informatics LLC | Privacy Policy