package org.opensha2.data;
import static java.lang.Math.exp;
import static java.lang.Math.log;
import java.util.Arrays;
import java.util.Collections;
import java.util.List;
/**
* Utility class to perform linear interpolations. Methods are also provided to
* perform interpolations in log space. The methods of this class are designed
* to be fast and, as such perform almost no argument checking.
*
* <p>NOTE: This class is designed to be used primarily with the OpenSHA
* function classes and should probably be relocated to that package and given
* default visibility due to the lack of error-checking. We could write public
* methods that do thorough error checking.
*
* <p><strong>Warning:</strong> These methods do no error checking for
* {@code null} , empty, or single valued arrays; arrays of different lengths;
* nor does it check that the supplied x-values are monotonically increasing
* (sorted). Internally the method uses binary search and it is up to the user
* to supply valid data.
*
* @author Peter Powers
*/
@Deprecated
public final class Interpolate {
// TODO refactor all methods to take extrapolate flag
// TODO support Lists??
// TODO high priority
// TODO unchecked versions?
// x-values always assumed to be monotonically increasing
// y-values must be reversed (for hazard curves)
private Interpolate() {}
/**
* Returns the interpolated or extrapolated x-value corresponding to the
* supplied y-value. If any supplied value is {@code NaN}, returned value will
* also be {@code NaN}. Method does not do any input validation such that if
* the supplied points are coincident or define a horizontal line, the method
* may return {@code Infinity}, {@code -Infinity}, or {@code NaN} .
* @param x1 x-value of first point
* @param y1 y-value of first point
* @param x2 x-value of second point
* @param y2 y-value of second point
* @param y value at which to find x
* @return the interpolated x-value
*/
public static double findX(double x1, double y1, double x2, double y2,
double y) {
/*
* pass through to findY with rearranged args, instead of:
*
* findX() = x1 + (y - y1) * (x2 - x1) / (y2 - y1)
*/
return findY(y1, x1, y2, x2, y);
}
/**
* Returns the interpolated or extrapolated y-value corresponding to the
* supplied x-value. If any supplied value is {@code NaN}, returned value will
* also be {@code NaN}. Method does not do any input validation such that if
* the supplied points are coincident or define a vertical line, the method
* may return {@code Infinity}, {@code -Infinity}, or {@code NaN}.
*
* @param x1 x-value of first point
* @param y1 y-value of first point
* @param x2 x-value of second point
* @param y2 y-value of second point
* @param x value at which to find y
* @return the interpolated y-value
*/
public static double findY(double x1, double y1, double x2, double y2,
double x) {
return y1 + (x - x1) * (y2 - y1) / (x2 - x1);
}
// /**
// * Returns the interpolated or extrapolated y-value using the supplied x-
// * and y-value arrays.
// *
// * @param xs x-values of some function
// * @param ys y-values of some function
// * @param x value at which to find y
// * @return the interpolated y-value
// */
// public static double findX(double[] xs, double[] ys, double y) {
// int i = dataIndex(xs, x);
// return findX(xs[i], ys[i], xs[i + 1], ys[i + 1], x);
// }
/**
* Returns the interpolated or extrapolated y-value using the supplied x- and
* y-value arrays.
*
* @param xs x-values of some function
* @param ys y-values of some function
* @param x value at which to find y
* @return the interpolated y-value
*/
public static double findY(double[] xs, double[] ys, double x) {
int i = dataIndex(xs, x);
return findY(xs[i], ys[i], xs[i + 1], ys[i + 1], x);
}
public static double findY(List<Double> xs, List<Double> ys, double x) {
int i = dataIndex(xs, x);
return findY(xs.get(i), ys.get(i), xs.get(i + 1), ys.get(i + 1), x);
}
// /**
// * Returns the log interpolated or extrapolated y-value using the
// * supplied x- and y-value arrays.
// *
// * TODO needs unit test
// *
// * @param xs x-values of some function
// * @param ys y-values of some function
// * @param x value at which to find y
// * @return the interpolated y-value
// */
// public static double findLogX(double[] xs, double[] ys, double y) {
// int i = dataIndex(xs, x);
// return exp(findY(xs[i], log(ys[i]), xs[i + 1], log(ys[i + 1]), x));
// }
/**
* Returns the log interpolated or extrapolated y-value using the supplied x-
* and y-value arrays.
*
* TODO needs unit test
*
* @param xs x-values of some function
* @param ys y-values of some function
* @param x value at which to find y
* @return the interpolated y-value
*/
public static double findLogY(double[] xs, double[] ys, double x) {
int i = dataIndex(xs, x);
return exp(findY(xs[i], log(ys[i]), xs[i + 1], log(ys[i + 1]), x));
}
/**
* Returns the log-log interpolated or extrapolated y-value using the supplied
* x- and y-value arrays.
*
* @param xs x-values of some function
* @param ys y-values of some function
* @param x value at which to find y
* @return the log-log interpolated y-value
*/
public static double findLogLogY(double[] xs, double[] ys, double x) {
int i = dataIndex(xs, x);
return exp(findY(log(xs[i]), log(ys[i]), log(xs[i + 1]), log(ys[i + 1]), log(x)));
}
/**
* Returns interpolated or extrapolated y-values using the supplied x- and
* y-value arrays.
*
* @param xs x-values of some function
* @param ys y-values of some function
* @param x value at which to find y
* @return the interpolated y-values
*/
public static double[] findY(double[] xs, double[] ys, double[] x) {
double[] y = new double[x.length];
int i = 0;
for (double xVal : x) {
y[i++] = findY(xs, ys, xVal);
}
return y;
}
public static double[] findY(List<Double> xs, List<Double> ys, double[] x) {
double[] y = new double[x.length];
int i = 0;
for (double xVal : x) {
y[i++] = findY(xs, ys, xVal);
}
return y;
}
/**
* Returns the log interpolated or extrapolated y-values using the supplied x-
* and y-value arrays.
*
* @param xs x-values of some function
* @param ys y-values of some function
* @param x value at which to find y
* @return the log interpolated y-values
*/
public static double[] findLogY(double[] xs, double[] ys, double[] x) {
double[] y = new double[x.length];
int i = 0;
for (double xVal : x) {
y[i++] = findLogY(xs, ys, xVal);
}
return y;
}
/**
* Returns the log-log interpolated or extrapolated y-values using the
* supplied x- and y-value arrays.
*
* @param xs x-values of some function
* @param ys y-values of some function
* @param x value at which to find y
* @return the log-log interpolated y-values
*/
public static double[] findLogLogY(double[] xs, double[] ys, double[] x) {
double[] y = new double[x.length];
int i = 0;
for (double xVal : x) {
y[i++] = findLogLogY(xs, ys, xVal);
}
return y;
}
// TODO clean
// TODO its highly likely that given the average (small) size of things
// like hazard curves, simply walking up an array or list is faster than
// binary searching.
// TODO move to DataUtils as some 'unchecked' flavor
private static int dataIndex(double[] data, double value) {
int i = Arrays.binarySearch(data, value);
return binarySearchResultToIndex(i, data.length);
// // adjust index for low value (-1) and in-sequence insertion pt
// i = (i == -1) ? 0 : (i < 0) ? -i - 2 : i;
// // adjust hi index to next to last index
// return (i >= data.length - 1) ? --i : i;
}
private static int dataIndex(List<Double> data, double value) {
int i = Collections.binarySearch(data, value);
return binarySearchResultToIndex(i, data.size());
// // adjust index for low value (-1) and in-sequence insertion pt
// i = (i == -1) ? 0 : (i < 0) ? -i - 2 : i;
// // adjust hi index to next to last index
// return (i >= data.size() - 1) ? --i : i;
}
private static int binarySearchResultToIndex(int i, int size) {
// adjust index for low value (-1) and in-sequence insertion pt
i = (i == -1) ? 0 : (i < 0) ? -i - 2 : i;
// adjust hi index to next to last index
return (i >= size - 1) ? --i : i;
}
}