/** * @param pp * @param xKeys * @return Second derivatives of piecewise polynomial functions at xKeys When _dim in * PiecewisePolynomialResult is greater than 1, i.e., the struct contains multiple piecewise * polynomials, a row vector of return value corresponds to each piecewise polynomial */ public DoubleMatrix2D differentiateTwice( final PiecewisePolynomialResult pp, final double[] xKeys) { ArgumentChecker.notNull(pp, "pp"); ArgumentChecker.isFalse(pp.getOrder() < 3, "polynomial degree < 2"); final double[][] coefs = pp.getCoefMatrix().getData(); final double[] knots = pp.getKnots().getData(); final int nKnots = pp.getNumberOfIntervals() + 1; final int nCoefs = pp.getOrder(); final int dim = pp.getDimensions(); double[][] res = new double[dim * (nKnots - 1)][nCoefs - 2]; for (int i = 0; i < dim * (nKnots - 1); ++i) { Arrays.fill(res[i], 0.); } for (int i = 0; i < dim * (nKnots - 1); ++i) { for (int j = 0; j < nCoefs - 2; ++j) { res[i][j] = coefs[i][j] * (nCoefs - j - 1) * (nCoefs - j - 2); } } PiecewisePolynomialResult ppDiff = new PiecewisePolynomialResult( new DoubleMatrix1D(knots), DoubleMatrix2D.noCopy(res), nCoefs - 1, pp.getDimensions()); return evaluate(ppDiff, xKeys); }
/** * @param pp PiecewisePolynomialResult * @param initialKey * @param xKeys * @return Integral of piecewise polynomial between initialKey and xKeys */ public DoubleMatrix1D integrate( final PiecewisePolynomialResult pp, final double initialKey, final double[] xKeys) { ArgumentChecker.notNull(pp, "pp"); ArgumentChecker.notNull(xKeys, "xKeys"); ArgumentChecker.isFalse(Double.isNaN(initialKey), "initialKey containing NaN"); ArgumentChecker.isFalse(Double.isInfinite(initialKey), "initialKey containing Infinity"); ArgumentChecker.isTrue(pp.getDimensions() == 1, "Dimension should be 1"); final double[] knots = pp.getKnots().getData(); final int nCoefs = pp.getOrder(); final int nKnots = pp.getNumberOfIntervals() + 1; final double[][] coefMatrix = pp.getCoefMatrix().getData(); double[][] res = new double[nKnots - 1][nCoefs + 1]; for (int i = 0; i < nKnots - 1; ++i) { Arrays.fill(res[i], 0.); } for (int i = 0; i < nKnots - 1; ++i) { for (int j = 0; j < nCoefs; ++j) { res[i][j] = coefMatrix[i][j] / (nCoefs - j); } } double[] constTerms = new double[nKnots - 1]; Arrays.fill(constTerms, 0.); int indicator = 0; if (initialKey <= knots[1]) { indicator = 0; } else { for (int i = 1; i < nKnots - 1; ++i) { if (knots[i] < initialKey) { indicator = i; } } } double sum = getValue(res[indicator], initialKey, knots[indicator]); for (int i = indicator; i < nKnots - 2; ++i) { constTerms[i + 1] = constTerms[i] + getValue(res[i], knots[i + 1], knots[i]) - sum; sum = 0.; } constTerms[indicator] = -getValue(res[indicator], initialKey, knots[indicator]); for (int i = indicator - 1; i > -1; --i) { constTerms[i] = constTerms[i + 1] - getValue(res[i], knots[i + 1], knots[i]); } for (int i = 0; i < nKnots - 1; ++i) { res[i][nCoefs] = constTerms[i]; } final PiecewisePolynomialResult ppInt = new PiecewisePolynomialResult( new DoubleMatrix1D(knots), DoubleMatrix2D.noCopy(res), nCoefs + 1, 1); return new DoubleMatrix1D(evaluate(ppInt, xKeys).getData()[0]); }
/** * @param pp PiecewisePolynomialResult * @param xKeys * @return Values of piecewise polynomial functions at xKeys When _dim in * PiecewisePolynomialResult is greater than 1, i.e., the struct contains multiple piecewise * polynomials, one element of return vector of DoubleMatrix2D corresponds to each piecewise * polynomial */ public DoubleMatrix2D[] evaluate(final PiecewisePolynomialResult pp, final double[][] xKeys) { ArgumentChecker.notNull(pp, "pp"); ArgumentChecker.notNull(xKeys, "xKeys"); final int keyLength = xKeys[0].length; final int keyDim = xKeys.length; for (int j = 0; j < keyDim; ++j) { for (int i = 0; i < keyLength; ++i) { ArgumentChecker.isFalse(Double.isNaN(xKeys[j][i]), "xKeys containing NaN"); ArgumentChecker.isFalse(Double.isInfinite(xKeys[j][i]), "xKeys containing Infinity"); } } final double[] knots = pp.getKnots().getData(); final int nKnots = knots.length; final DoubleMatrix2D coefMatrix = pp.getCoefMatrix(); final int dim = pp.getDimensions(); double[][][] res = new double[dim][keyDim][keyLength]; for (int k = 0; k < dim; ++k) { for (int l = 0; l < keyDim; ++l) { for (int j = 0; j < keyLength; ++j) { int indicator = 0; if (xKeys[l][j] < knots[1]) { indicator = 0; } else { for (int i = 1; i < nKnots - 1; ++i) { if (knots[i] <= xKeys[l][j]) { indicator = i; } } } final double[] coefs = coefMatrix.getRowVector(dim * indicator + k, false).getData(); res[k][l][j] = getValue(coefs, xKeys[l][j], knots[indicator]); ArgumentChecker.isFalse(Double.isInfinite(res[k][l][j]), "Too large input"); ArgumentChecker.isFalse(Double.isNaN(res[k][l][j]), "Too large input"); } } } DoubleMatrix2D[] resMat = new DoubleMatrix2D[dim]; for (int i = 0; i < dim; ++i) { resMat[i] = DoubleMatrix2D.noCopy(res[i]); } return resMat; }
@Override public PiecewisePolynomialResult interpolate( final double[] xValues, final double[][] yValuesMatrix) { ArgumentChecker.notNull(xValues, "xValues"); ArgumentChecker.notNull(yValuesMatrix, "yValuesMatrix"); ArgumentChecker.isTrue( xValues.length == yValuesMatrix[0].length | xValues.length + 2 == yValuesMatrix[0].length, "(xValues length = yValuesMatrix's row vector length) or (xValues length + 2 = yValuesMatrix's row vector length)"); ArgumentChecker.isTrue(xValues.length > 2, "Data points should be more than 2"); final int nDataPts = xValues.length; final int yValuesLen = yValuesMatrix[0].length; final int dim = yValuesMatrix.length; for (int i = 0; i < nDataPts; ++i) { ArgumentChecker.isFalse(Double.isNaN(xValues[i]), "xValues containing NaN"); ArgumentChecker.isFalse(Double.isInfinite(xValues[i]), "xValues containing Infinity"); } for (int i = 0; i < yValuesLen; ++i) { for (int j = 0; j < dim; ++j) { ArgumentChecker.isFalse(Double.isNaN(yValuesMatrix[j][i]), "yValuesMatrix containing NaN"); ArgumentChecker.isFalse( Double.isInfinite(yValuesMatrix[j][i]), "yValuesMatrix containing Infinity"); } } for (int i = 0; i < nDataPts; ++i) { for (int j = i + 1; j < nDataPts; ++j) { ArgumentChecker.isFalse(xValues[i] == xValues[j], "xValues should be distinct"); } } double[] xValuesSrt = new double[nDataPts]; DoubleMatrix2D[] coefMatrix = new DoubleMatrix2D[dim]; for (int i = 0; i < dim; ++i) { xValuesSrt = Arrays.copyOf(xValues, nDataPts); double[] yValuesSrt = new double[nDataPts]; if (nDataPts == yValuesLen) { yValuesSrt = Arrays.copyOf(yValuesMatrix[i], nDataPts); } else { yValuesSrt = Arrays.copyOfRange(yValuesMatrix[i], 1, nDataPts + 1); } ParallelArrayBinarySort.parallelBinarySort(xValuesSrt, yValuesSrt); final double[] intervals = _solver.intervalsCalculator(xValuesSrt); final double[] slopes = _solver.slopesCalculator(yValuesSrt, intervals); final PiecewisePolynomialResult result = _method.interpolate(xValues, yValuesMatrix[i]); ArgumentChecker.isTrue(result.getOrder() >= 3, "Primary interpolant should be degree >= 2"); final double[] initialFirst = _function.differentiate(result, xValuesSrt).getData()[0]; final double[] initialSecond = _function.differentiateTwice(result, xValuesSrt).getData()[0]; final double[] first = firstDerivativeCalculator(yValuesSrt, intervals, slopes, initialFirst); boolean modFirst = false; int k; double[] aValues = aValuesCalculator(slopes, first); double[] bValues = bValuesCalculator(slopes, first); double[][] intervalsA = getIntervalsA(intervals, slopes, first, bValues); double[][] intervalsB = getIntervalsB(intervals, slopes, first, aValues); while (modFirst == false) { k = 0; for (int j = 0; j < nDataPts - 2; ++j) { if (first[j + 1] > 0.) { if (intervalsA[j + 1][1] + Math.abs(intervalsA[j + 1][1]) * ERROR < intervalsB[j][0] - Math.abs(intervalsB[j][0]) * ERROR | intervalsA[j + 1][0] - Math.abs(intervalsA[j + 1][0]) * ERROR > intervalsB[j][1] + Math.abs(intervalsB[j][1]) * ERROR) { ++k; first[j + 1] = firstDerivativesRecalculator(intervals, slopes, aValues, bValues, j + 1); } } } if (k == 0) { modFirst = true; } aValues = aValuesCalculator(slopes, first); bValues = bValuesCalculator(slopes, first); intervalsA = getIntervalsA(intervals, slopes, first, bValues); intervalsB = getIntervalsB(intervals, slopes, first, aValues); } final double[] second = secondDerivativeCalculator(initialSecond, intervalsA, intervalsB); coefMatrix[i] = new DoubleMatrix2D(_solver.solve(yValuesSrt, intervals, slopes, first, second)); } final int nIntervals = coefMatrix[0].getNumberOfRows(); final int nCoefs = coefMatrix[0].getNumberOfColumns(); double[][] resMatrix = new double[dim * nIntervals][nCoefs]; for (int i = 0; i < nIntervals; ++i) { for (int j = 0; j < dim; ++j) { resMatrix[dim * i + j] = coefMatrix[j].getRowVector(i, false).getData(); } } for (int i = 0; i < (nIntervals * dim); ++i) { for (int j = 0; j < nCoefs; ++j) { ArgumentChecker.isFalse(Double.isNaN(resMatrix[i][j]), "Too large input"); ArgumentChecker.isFalse(Double.isInfinite(resMatrix[i][j]), "Too large input"); } } return new PiecewisePolynomialResult( new DoubleMatrix1D(xValuesSrt, false), DoubleMatrix2D.noCopy(resMatrix), nCoefs, dim); }