/**
* Copyright (C) 2009 - present by OpenGamma Inc. and the OpenGamma group of companies
*
* Please see distribution for license.
*/
package com.opengamma.analytics.math.interpolation.data;
import java.io.Serializable;
import java.util.Arrays;
import com.opengamma.util.ArgumentChecker;
import com.opengamma.util.ParallelArrayBinarySort;
/**
* An implementation of {@link Interpolator1DDataBundle} which holds all data in two
* parallel-sorted double arrays.
*/
public class ArrayInterpolator1DDataBundle implements Interpolator1DDataBundle, Serializable {
private static final long serialVersionUID = 1L;
private final double[] _keys;
private final double[] _values;
private final int _n;
public ArrayInterpolator1DDataBundle(final double[] keys, final double[] values) {
this(keys, values, false);
}
public ArrayInterpolator1DDataBundle(final double[] keys, final double[] values, final boolean inputsSorted) {
this(keys, values, inputsSorted, true);
}
public ArrayInterpolator1DDataBundle(final double[] keys, final double[] values, final boolean inputsSorted, final boolean copy) {
ArgumentChecker.notNull(keys, "Keys must not be null.");
ArgumentChecker.notNull(values, "Values must not be null.");
ArgumentChecker.isTrue((keys.length == values.length), "keys and values must be same length.");
ArgumentChecker.isTrue((keys.length > 0), "Must have at least two data points.");
_keys = copy ? Arrays.copyOf(keys, keys.length) : keys;
_values = copy ? Arrays.copyOf(values, values.length) : values;
_n = keys.length;
if (!inputsSorted) {
ParallelArrayBinarySort.parallelBinarySort(_keys, _values);
}
checkSameKeys();
}
private void checkSameKeys() {
for (int i = 1; i < _n; i++) {
ArgumentChecker.isTrue(Double.doubleToLongBits(_keys[i - 1]) != Double.doubleToLongBits(_keys[i]), "Equal nodes in interpolator {}", _keys[i - 1]);
}
}
@Override
public boolean containsKey(final Double key) {
if (key == null) {
return false;
}
return Arrays.binarySearch(_keys, key) >= 0;
}
@Override
public Double firstKey() {
return _keys[0];
}
@Override
public Double firstValue() {
return _values[0];
}
@Override
public Double get(final Double key) {
final int index = Arrays.binarySearch(_keys, key);
if (index < 0) {
return null;
}
return _values[index];
}
@Override
public InterpolationBoundedValues getBoundedValues(final Double key) {
final int index = getLowerBoundIndex(key);
if (index == _n - 1) {
return new InterpolationBoundedValues(index, _keys[index], _values[index], null, null);
}
return new InterpolationBoundedValues(index, _keys[index], _values[index], _keys[index + 1], _values[index + 1]);
}
@Override
public double[] getKeys() {
return _keys;
}
@Override
public int getLowerBoundIndex(final Double value) {
if (value < _keys[0]) {
throw new IllegalArgumentException("Could not get lower bound index for " + value + ": lowest x-value is "
+ _keys[0]);
}
if (value > _keys[_n - 1]) {
throw new IllegalArgumentException("Could not get lower bound index for " + value + ": highest x-value is "
+ _keys[_keys.length - 1]);
}
int index = Arrays.binarySearch(_keys, value);
if (index >= 0) {
// Fast break out if it's an exact match.
return index;
}
if (index < 0) {
index = -(index + 1);
index--;
}
if (value == -0. && index < _n - 1 && _keys[index + 1] == 0.) {
++index;
}
return index;
}
@Override
public Double getLowerBoundKey(final Double value) {
final int index = getLowerBoundIndex(value);
return _keys[index];
}
@Override
public double[] getValues() {
return _values;
}
@Override
public Double higherKey(final Double key) {
final int index = getHigherIndex(key);
if (index >= _n) {
return null;
}
return _keys[index];
}
@Override
public Double higherValue(final Double key) {
final int index = getHigherIndex(key);
if (index >= _n) {
return null;
}
return _values[index];
}
protected int getHigherIndex(final Double key) {
return getLowerBoundIndex(key) + 1;
}
@Override
public Double lastKey() {
return _keys[_n - 1];
}
@Override
public Double lastValue() {
return _values[_n - 1];
}
@Override
public int size() {
return _keys.length;
}
@Override
public int hashCode() {
final int prime = 31;
int result = 1;
result = prime * result + Arrays.hashCode(_keys);
result = prime * result + Arrays.hashCode(_values);
return result;
}
@Override
public boolean equals(final Object obj) {
if (this == obj) {
return true;
}
if (obj == null) {
return false;
}
if (getClass() != obj.getClass()) {
return false;
}
final ArrayInterpolator1DDataBundle other = (ArrayInterpolator1DDataBundle) obj;
if (!Arrays.equals(_keys, other._keys)) {
return false;
}
if (!Arrays.equals(_values, other._values)) {
return false;
}
return true;
}
@Override
public void setYValueAtIndex(final int index, final double y) {
ArgumentChecker.notNegative(index, "index");
if (index >= _n) {
throw new IllegalArgumentException("Index was greater than number of data points");
}
_values[index] = y;
}
}