public static IDataset interpolate(IDataset oldx, IDataset oldy, IDataset newx) {

    // TODO more sanity checks on inputs

    DoubleDataset dx = (DoubleDataset) DatasetUtils.cast(oldx, Dataset.FLOAT64);
    DoubleDataset dy = (DoubleDataset) DatasetUtils.cast(oldy, Dataset.FLOAT64);

    boolean sorted = true;
    double maxtest = oldx.getDouble(0);
    for (int i = 1; i < ((Dataset) oldx).count(); i++) {
      if (maxtest > oldx.getDouble(i)) {
        sorted = false;
        break;
      }
      maxtest = dx.getDouble(i);
    }

    double[] sortedx = null;
    double[] sortedy = null;

    if (!sorted) {
      IntegerDataset sIdx = getIndiciesOfSorted(dx);
      sortedx = new double[dx.getData().length];
      sortedy = new double[dy.getData().length];

      for (int i = 0; i < sIdx.getSize(); i++) {
        sortedx[i] = dx.getDouble(sIdx.get(i));
        sortedy[i] = dy.getDouble(sIdx.get(i));
      }
    } else {
      sortedx = dx.getData();
      sortedy = dy.getData();
    }

    SplineInterpolator si = new SplineInterpolator();
    PolynomialSplineFunction poly = si.interpolate(sortedx, sortedy);

    IDataset newy = newx.clone();
    newy.setName(oldy.getName() + "_interpolated");

    for (int i = 0; i < ((Dataset) newx).count(); i++) {
      newy.set(poly.value(newx.getDouble(i)), i);
    }

    return newy;
  }