@Test
 public void test() {
   assertEquals(
       Math.log(INTERPOLATOR.interpolate(MODEL, 3.4)),
       LINEAR.interpolate(TRANSFORMED_MODEL, 3.4),
       EPS);
 }
  @Test
  public void firstDerivativeTest() {
    double a = 1.0;
    double b = 1.5;
    double c = -0.5;
    double[] x = new double[] {0., 2., 5.};
    int n = x.length;
    double[] y = new double[n];
    for (int i = 0; i < n; i++) {
      y[i] = a + b * x[i] + c * x[i] * x[i];
    }
    Interpolator1D interpolator = new NaturalCubicSplineInterpolator1D();
    Interpolator1DDataBundle db = interpolator.getDataBundle(x, y);
    Double grad = interpolator.firstDerivative(db, x[n - 1]);
    Function1D<Double, Double> func = interpolator.getFunction(db);
    ScalarFirstOrderDifferentiator diff = new ScalarFirstOrderDifferentiator();
    Function1D<Double, Boolean> domain =
        new Function1D<Double, Boolean>() {
          @Override
          public Boolean evaluate(Double x) {
            return x <= 5.0;
          }
        };
    Function1D<Double, Double> gradFunc = diff.differentiate(func, domain);

    assertEquals(gradFunc.evaluate(x[n - 1]), grad, 1e-8);
  }
 private Map<Double, Interpolator1DDataBundle> testData(final Map<DoublesPair, Double> data) {
   final Map<Double, Interpolator1DDataBundle> result = new TreeMap<>();
   final TreeMap<DoublesPair, Double> sorted = new TreeMap<>(_comparator);
   sorted.putAll(data);
   final Iterator<Map.Entry<DoublesPair, Double>> iterator = sorted.entrySet().iterator();
   final Map.Entry<DoublesPair, Double> firstEntry = iterator.next();
   double x = firstEntry.getKey().first;
   Map<Double, Double> yzValues = new TreeMap<>();
   yzValues.put(firstEntry.getKey().second, firstEntry.getValue());
   while (iterator.hasNext()) {
     final Map.Entry<DoublesPair, Double> nextEntry = iterator.next();
     final double newX = nextEntry.getKey().first;
     if (Double.doubleToLongBits(newX) != Double.doubleToLongBits(x)) {
       final Interpolator1DDataBundle interpolatorData = _yInterpolator.getDataBundle(yzValues);
       result.put(x, interpolatorData);
       yzValues = new TreeMap<>();
       yzValues.put(nextEntry.getKey().second, nextEntry.getValue());
       x = newX;
     } else {
       yzValues.put(nextEntry.getKey().second, nextEntry.getValue());
     }
     if (!iterator.hasNext()) {
       yzValues.put(nextEntry.getKey().second, nextEntry.getValue());
       final Interpolator1DDataBundle interpolatorData = _yInterpolator.getDataBundle(yzValues);
       result.put(x, interpolatorData);
     }
   }
   return result;
 }
 @Test(expectedExceptions = IllegalArgumentException.class)
 public void samexNodesTest() {
   final double[] xData = new double[] {0.4, 0.7, 0.9, 0.9, 1.3, 1.8};
   final double[] yData = new double[] {0.4, 0.5, 0.6, 0.7, 0.8, 1.0};
   final Interpolator1DDataBundle data = INTERPOLATOR.getDataBundle(xData, yData);
   double y = INTERPOLATOR.interpolate(data, 1.0);
   assertTrue("y: " + y, !Double.isNaN(y));
 }
 static {
   int n = Y_DATA.length;
   YSTAR_DATA = new double[n];
   for (int i = 0; i < n; i++) {
     YSTAR_DATA[i] = TRANSFORM.transform(Y_DATA[i]);
   }
   DATA_BUNDLE = INTERPOLATOR_BASE.getDataBundleFromSortedArrays(X_DATA, Y_DATA);
   TRANS_DATA_BUNDLE = INTERPOLATOR.getDataBundleFromSortedArrays(X_DATA, YSTAR_DATA);
 }
 @Override
 public Double interpolate(
     final Map<Double, Interpolator1DDataBundle> dataBundle, final DoublesPair value) {
   ArgumentChecker.notNull(value, "value");
   ArgumentChecker.notNull(dataBundle, "data bundle");
   final Map<Double, Double> xData = new HashMap<>();
   for (final Map.Entry<Double, Interpolator1DDataBundle> entry : dataBundle.entrySet()) {
     xData.put(entry.getKey(), _yInterpolator.interpolate(entry.getValue(), value.getSecond()));
   }
   return _xInterpolator.interpolate(_xInterpolator.getDataBundle(xData), value.getFirst());
 }
 @Test
 public void testSensitivity() {
   for (int i = 0; i < 20; i++) {
     double x = 5.0 * i / 19.0;
     double[] fdSense = INTERPOLATOR.getFiniteDifferenceSensitivities(TRANS_DATA_BUNDLE, x);
     double[] analSense = INTERPOLATOR.getNodeSensitivitiesForValue(TRANS_DATA_BUNDLE, x);
     for (int j = 0; j < fdSense.length; j++) {
       assertEquals(analSense[j], fdSense[j], 1e-8);
     }
   }
 }
 static {
   final TreeMap<Double, Double> data = new TreeMap<>();
   final TreeMap<Double, Double> transformedData = new TreeMap<>();
   double x;
   for (int i = 0; i < 10; i++) {
     x = Double.valueOf(i);
     data.put(x, FUNCTION.evaluate(x));
     transformedData.put(x, Math.log(FUNCTION.evaluate(x)));
   }
   MODEL = LINEAR.getDataBundle(data);
   TRANSFORMED_MODEL = INTERPOLATOR.getDataBundle(transformedData);
 }
  @Override
  public double[] getNodeSensitivitiesForValue(
      final Interpolator1DDataBundle data, final Double value) {

    final double yStar = _base.interpolate(data, value);
    final double grad = _transform.inverseTransformGradient(yStar);
    final double[] temp = _base.getNodeSensitivitiesForValue(data, value);

    final int n = temp.length;
    for (int i = 0; i < n; i++) {
      temp[i] *= grad;
    }
    return temp;
  }
 @Test(enabled = false)
 public void test() {
   System.out.println("TransformedInterpolator1DTest");
   for (int i = 0; i < 200; i++) {
     double x = 5.0 * i / 199.0;
     System.out.println(
         x
             + "\t"
             + INTERPOLATOR_BASE.interpolate(DATA_BUNDLE, x)
             + "\t"
             + INTERPOLATOR.interpolate(TRANS_DATA_BUNDLE, x)
             + "\t"
             + INTERPOLATOR.interpolate(DATA_BUNDLE, x));
   }
 }
 @Test
 public void testCorrectAtNodes() {
   final int n = Y_DATA.length;
   for (int i = 0; i < n; i++) {
     double y = INTERPOLATOR.interpolate(TRANS_DATA_BUNDLE, X_DATA[i]);
     assertEquals(Y_DATA[i], y, 1e-12);
   }
 }
 @Test
 public void testInRange() {
   for (int i = 0; i < 200; i++) {
     double x = 5.0 * i / 199.0;
     double y = INTERPOLATOR.interpolate(TRANS_DATA_BUNDLE, x);
     assertTrue(y >= 0 && y <= 1);
   }
 }
 @Test
 public void testDataBundleType2() {
   assertEquals(
       INTERPOLATOR
           .getDataBundleFromSortedArrays(new double[] {1, 2, 3}, new double[] {1, 2, 3})
           .getClass(),
       ArrayInterpolator1DDataBundle.class);
 }
  @Test
  public void montonicTest() {
    final boolean print = false;
    if (print) {
      System.out.println("MonotonicCubicInterpolator1DTest");
    }

    final int n = 100;
    final double low = X_DATA[0];
    final double range = X_DATA[X_DATA.length - 1] - X_DATA[0];
    double value = INTERPOLATOR.interpolate(DATA, low);
    for (int i = 1; i < n; i++) {
      double x = low + i * range / (n - 1);
      double y = INTERPOLATOR.interpolate(DATA, x);
      assertTrue(y > value);
      value = y;
      if (print) {
        System.out.println(x + "\t" + y);
      }
    }
  }
 @Test
 public void dataBundleTest() {
   Interpolator1DDataBundle db = INTERPOLATOR.getDataBundle(X_DATA, Y_DATA);
   double[] keys = db.getKeys();
   double[] values = db.getValues();
   final int n = X_DATA.length;
   assertEquals("keys length", n, keys.length);
   assertEquals("values length", n, values.length);
   for (int i = 0; i < n; i++) {
     assertEquals("keys " + i, X_DATA[i], keys[i]);
     assertEquals("values " + i, Y_DATA[i], values[i]);
   }
 }
  @Override
  public Map<DoublesPair, Double> getNodeSensitivitiesForValue(
      final Map<Double, Interpolator1DDataBundle> dataBundle, final DoublesPair value) {
    ArgumentChecker.notNull(value, "value");
    ArgumentChecker.notNull(dataBundle, "data bundle");
    final Map<Double, Double> xData = new HashMap<>();
    final double[][] temp = new double[dataBundle.size()][];
    int i = 0;
    for (final Map.Entry<Double, Interpolator1DDataBundle> entry : dataBundle.entrySet()) {
      // this is the sensitivity of the point projected onto a column of y-points to those points
      temp[i++] = _yInterpolator.getNodeSensitivitiesForValue(entry.getValue(), value.getSecond());
      xData.put(entry.getKey(), _yInterpolator.interpolate(entry.getValue(), value.getSecond()));
    }
    // this is the sensitivity of the point to the points projected onto y columns
    final double[] xSense =
        _xInterpolator.getNodeSensitivitiesForValue(
            _xInterpolator.getDataBundle(xData), value.getFirst());
    ArgumentChecker.isTrue(
        xSense.length == dataBundle.size(),
        "Number of x sensitivities {} must be equal to the data bundle size {}",
        xSense.length,
        dataBundle.size());
    final Map<DoublesPair, Double> res = new HashMap<>();

    double sense;
    i = 0;
    int j = 0;
    for (final Map.Entry<Double, Interpolator1DDataBundle> entry : dataBundle.entrySet()) {
      final double[] yValues = entry.getValue().getKeys();
      for (j = 0; j < yValues.length; j++) {
        sense = xSense[i] * temp[i][j];
        res.put(DoublesPair.of(entry.getKey().doubleValue(), yValues[j]), sense);
      }
      i++;
    }

    return res;
  }
 @Test(expectedExceptions = IllegalArgumentException.class)
 public void testHighValue() {
   INTERPOLATOR.interpolate(MODEL, 12.);
 }
 @Test(expectedExceptions = IllegalArgumentException.class)
 public void testNullData() {
   INTERPOLATOR.interpolate(MODEL, null);
 }
 @Test(expectedExceptions = IllegalArgumentException.class)
 public void testNullDataBundle() {
   INTERPOLATOR.interpolate(null, 3.4);
 }
public class PCHIPInterpolator1DTest {

  private static final Interpolator1D INTERPOLATOR =
      Interpolator1DFactory.getInterpolator(Interpolator1DFactory.PCHIP);

  private static final double[] X_DATA = new double[] {0, 0.4, 1.0, 1.8, 2.8, 5};
  private static final double[] Y_DATA = new double[] {3., 4., 4.1, 4.5, 7.2, 8.0};

  private static final Interpolator1DDataBundle DATA = INTERPOLATOR.getDataBundle(X_DATA, Y_DATA);

  @Test(expectedExceptions = IllegalArgumentException.class)
  public void testNullData() {
    INTERPOLATOR.interpolate(null, 2.3);
  }

  @Test(expectedExceptions = IllegalArgumentException.class)
  public void testNullValue() {
    INTERPOLATOR.interpolate(DATA, null);
  }

  @Test
  public void testDataBundleType1() {
    assertEquals(
        INTERPOLATOR.getDataBundle(X_DATA, Y_DATA).getClass(),
        Interpolator1DPiecewisePoynomialDataBundle.class);
  }

  @Test
  public void testDataBundleType2() {
    assertEquals(
        INTERPOLATOR.getDataBundleFromSortedArrays(X_DATA, Y_DATA).getClass(),
        Interpolator1DPiecewisePoynomialDataBundle.class);
  }

  @Test
  public void dataBundleTest() {
    Interpolator1DDataBundle db = INTERPOLATOR.getDataBundle(X_DATA, Y_DATA);
    double[] keys = db.getKeys();
    double[] values = db.getValues();
    final int n = X_DATA.length;
    assertEquals("keys length", n, keys.length);
    assertEquals("values length", n, values.length);
    for (int i = 0; i < n; i++) {
      assertEquals("keys " + i, X_DATA[i], keys[i]);
      assertEquals("values " + i, Y_DATA[i], values[i]);
    }
  }

  @Test
  public void montonicTest() {
    final boolean print = false;
    if (print) {
      System.out.println("MonotonicCubicInterpolator1DTest");
    }

    final int n = 100;
    final double low = X_DATA[0];
    final double range = X_DATA[X_DATA.length - 1] - X_DATA[0];
    double value = INTERPOLATOR.interpolate(DATA, low);
    for (int i = 1; i < n; i++) {
      double x = low + i * range / (n - 1);
      double y = INTERPOLATOR.interpolate(DATA, x);
      assertTrue(y > value);
      value = y;
      if (print) {
        System.out.println(x + "\t" + y);
      }
    }
  }

  @Test(expectedExceptions = IllegalArgumentException.class)
  public void samexNodesTest() {
    final double[] xData = new double[] {0.4, 0.7, 0.9, 0.9, 1.3, 1.8};
    final double[] yData = new double[] {0.4, 0.5, 0.6, 0.7, 0.8, 1.0};
    final Interpolator1DDataBundle data = INTERPOLATOR.getDataBundle(xData, yData);
    double y = INTERPOLATOR.interpolate(data, 1.0);
    assertTrue("y: " + y, !Double.isNaN(y));
  }
}
 @Test(expectedExceptions = IllegalArgumentException.class)
 public void testNullValue() {
   INTERPOLATOR.interpolate(DATA, null);
 }
 @Test
 public void testDataBundleType2() {
   assertEquals(
       INTERPOLATOR.getDataBundleFromSortedArrays(X_DATA, Y_DATA).getClass(),
       Interpolator1DPiecewisePoynomialDataBundle.class);
 }
 /**
  * The node values must be in the transformed space
  *
  * @param x The positions of the nodes. <b>These must be in ascending order</b>
  * @param y The values of the nodes - these must be in the transformed space
  * @return a data bundle
  */
 @Override
 public Interpolator1DDataBundle getDataBundleFromSortedArrays(
     final double[] x, final double[] y) {
   return _base.getDataBundleFromSortedArrays(x, y);
 }
 /**
  * The node values must be in the transformed space
  *
  * @param x The positions of the nodes (not necessarily in order)
  * @param y The values of the nodes - these must be in the transformed space
  * @return a data bundle
  */
 @Override
 public Interpolator1DDataBundle getDataBundle(final double[] x, final double[] y) {
   return _base.getDataBundle(x, y);
 }
 @Override
 public double firstDerivative(final Interpolator1DDataBundle data, final Double value) {
   return _transform.inverseTransformGradient(_base.interpolate(data, value))
       * _base.firstDerivative(data, value);
 }
 @Override
 public double firstDerivative(
     Interpolator1DDataBundle data, Double value, Interpolator1D interpolator) {
   JodaBeanUtils.notNull(data, "data");
   return interpolator.firstDerivative(data, value);
 }
 @Override
 public Double extrapolate(
     Interpolator1DDataBundle data, Double value, Interpolator1D interpolator) {
   JodaBeanUtils.notNull(data, "data");
   return interpolator.interpolate(data, value);
 }
 @Override
 public double[] getNodeSensitivitiesForValue(
     Interpolator1DDataBundle data, Double value, Interpolator1D interpolator) {
   JodaBeanUtils.notNull(data, "data");
   return interpolator.getNodeSensitivitiesForValue(data, value);
 }
 @Override
 public Double interpolate(final Interpolator1DDataBundle data, final Double value) {
   return _transform.inverseTransform(_base.interpolate(data, value));
 }