summaryrefslogtreecommitdiff
path: root/src/main/java/org/apache/commons/math3/analysis/interpolation/BicubicSplineInterpolatingFunction.java
diff options
context:
space:
mode:
Diffstat (limited to 'src/main/java/org/apache/commons/math3/analysis/interpolation/BicubicSplineInterpolatingFunction.java')
-rw-r--r--src/main/java/org/apache/commons/math3/analysis/interpolation/BicubicSplineInterpolatingFunction.java641
1 files changed, 641 insertions, 0 deletions
diff --git a/src/main/java/org/apache/commons/math3/analysis/interpolation/BicubicSplineInterpolatingFunction.java b/src/main/java/org/apache/commons/math3/analysis/interpolation/BicubicSplineInterpolatingFunction.java
new file mode 100644
index 0000000..8f1771a
--- /dev/null
+++ b/src/main/java/org/apache/commons/math3/analysis/interpolation/BicubicSplineInterpolatingFunction.java
@@ -0,0 +1,641 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package org.apache.commons.math3.analysis.interpolation;
+
+import java.util.Arrays;
+import org.apache.commons.math3.analysis.BivariateFunction;
+import org.apache.commons.math3.exception.DimensionMismatchException;
+import org.apache.commons.math3.exception.NoDataException;
+import org.apache.commons.math3.exception.OutOfRangeException;
+import org.apache.commons.math3.exception.NonMonotonicSequenceException;
+import org.apache.commons.math3.util.MathArrays;
+
+/**
+ * Function that implements the
+ * <a href="http://en.wikipedia.org/wiki/Bicubic_interpolation">
+ * bicubic spline interpolation</a>. Due to numerical accuracy issues this should not
+ * be used.
+ *
+ * @since 2.1
+ * @deprecated as of 3.4 replaced by
+ * {@link org.apache.commons.math3.analysis.interpolation.PiecewiseBicubicSplineInterpolatingFunction}
+ */
+@Deprecated
+public class BicubicSplineInterpolatingFunction
+ implements BivariateFunction {
+ /** Number of coefficients. */
+ private static final int NUM_COEFF = 16;
+ /**
+ * Matrix to compute the spline coefficients from the function values
+ * and function derivatives values
+ */
+ private static final double[][] AINV = {
+ { 1,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0 },
+ { 0,0,0,0,1,0,0,0,0,0,0,0,0,0,0,0 },
+ { -3,3,0,0,-2,-1,0,0,0,0,0,0,0,0,0,0 },
+ { 2,-2,0,0,1,1,0,0,0,0,0,0,0,0,0,0 },
+ { 0,0,0,0,0,0,0,0,1,0,0,0,0,0,0,0 },
+ { 0,0,0,0,0,0,0,0,0,0,0,0,1,0,0,0 },
+ { 0,0,0,0,0,0,0,0,-3,3,0,0,-2,-1,0,0 },
+ { 0,0,0,0,0,0,0,0,2,-2,0,0,1,1,0,0 },
+ { -3,0,3,0,0,0,0,0,-2,0,-1,0,0,0,0,0 },
+ { 0,0,0,0,-3,0,3,0,0,0,0,0,-2,0,-1,0 },
+ { 9,-9,-9,9,6,3,-6,-3,6,-6,3,-3,4,2,2,1 },
+ { -6,6,6,-6,-3,-3,3,3,-4,4,-2,2,-2,-2,-1,-1 },
+ { 2,0,-2,0,0,0,0,0,1,0,1,0,0,0,0,0 },
+ { 0,0,0,0,2,0,-2,0,0,0,0,0,1,0,1,0 },
+ { -6,6,6,-6,-4,-2,4,2,-3,3,-3,3,-2,-1,-2,-1 },
+ { 4,-4,-4,4,2,2,-2,-2,2,-2,2,-2,1,1,1,1 }
+ };
+
+ /** Samples x-coordinates */
+ private final double[] xval;
+ /** Samples y-coordinates */
+ private final double[] yval;
+ /** Set of cubic splines patching the whole data grid */
+ private final BicubicSplineFunction[][] splines;
+ /**
+ * Partial derivatives.
+ * The value of the first index determines the kind of derivatives:
+ * 0 = first partial derivatives wrt x
+ * 1 = first partial derivatives wrt y
+ * 2 = second partial derivatives wrt x
+ * 3 = second partial derivatives wrt y
+ * 4 = cross partial derivatives
+ */
+ private final BivariateFunction[][][] partialDerivatives;
+
+ /**
+ * @param x Sample values of the x-coordinate, in increasing order.
+ * @param y Sample values of the y-coordinate, in increasing order.
+ * @param f Values of the function on every grid point.
+ * @param dFdX Values of the partial derivative of function with respect
+ * to x on every grid point.
+ * @param dFdY Values of the partial derivative of function with respect
+ * to y on every grid point.
+ * @param d2FdXdY Values of the cross partial derivative of function on
+ * every grid point.
+ * @throws DimensionMismatchException if the various arrays do not contain
+ * the expected number of elements.
+ * @throws NonMonotonicSequenceException if {@code x} or {@code y} are
+ * not strictly increasing.
+ * @throws NoDataException if any of the arrays has zero length.
+ */
+ public BicubicSplineInterpolatingFunction(double[] x,
+ double[] y,
+ double[][] f,
+ double[][] dFdX,
+ double[][] dFdY,
+ double[][] d2FdXdY)
+ throws DimensionMismatchException,
+ NoDataException,
+ NonMonotonicSequenceException {
+ this(x, y, f, dFdX, dFdY, d2FdXdY, false);
+ }
+
+ /**
+ * @param x Sample values of the x-coordinate, in increasing order.
+ * @param y Sample values of the y-coordinate, in increasing order.
+ * @param f Values of the function on every grid point.
+ * @param dFdX Values of the partial derivative of function with respect
+ * to x on every grid point.
+ * @param dFdY Values of the partial derivative of function with respect
+ * to y on every grid point.
+ * @param d2FdXdY Values of the cross partial derivative of function on
+ * every grid point.
+ * @param initializeDerivatives Whether to initialize the internal data
+ * needed for calling any of the methods that compute the partial derivatives
+ * this function.
+ * @throws DimensionMismatchException if the various arrays do not contain
+ * the expected number of elements.
+ * @throws NonMonotonicSequenceException if {@code x} or {@code y} are
+ * not strictly increasing.
+ * @throws NoDataException if any of the arrays has zero length.
+ *
+ * @see #partialDerivativeX(double,double)
+ * @see #partialDerivativeY(double,double)
+ * @see #partialDerivativeXX(double,double)
+ * @see #partialDerivativeYY(double,double)
+ * @see #partialDerivativeXY(double,double)
+ */
+ public BicubicSplineInterpolatingFunction(double[] x,
+ double[] y,
+ double[][] f,
+ double[][] dFdX,
+ double[][] dFdY,
+ double[][] d2FdXdY,
+ boolean initializeDerivatives)
+ throws DimensionMismatchException,
+ NoDataException,
+ NonMonotonicSequenceException {
+ final int xLen = x.length;
+ final int yLen = y.length;
+
+ if (xLen == 0 || yLen == 0 || f.length == 0 || f[0].length == 0) {
+ throw new NoDataException();
+ }
+ if (xLen != f.length) {
+ throw new DimensionMismatchException(xLen, f.length);
+ }
+ if (xLen != dFdX.length) {
+ throw new DimensionMismatchException(xLen, dFdX.length);
+ }
+ if (xLen != dFdY.length) {
+ throw new DimensionMismatchException(xLen, dFdY.length);
+ }
+ if (xLen != d2FdXdY.length) {
+ throw new DimensionMismatchException(xLen, d2FdXdY.length);
+ }
+
+ MathArrays.checkOrder(x);
+ MathArrays.checkOrder(y);
+
+ xval = x.clone();
+ yval = y.clone();
+
+ final int lastI = xLen - 1;
+ final int lastJ = yLen - 1;
+ splines = new BicubicSplineFunction[lastI][lastJ];
+
+ for (int i = 0; i < lastI; i++) {
+ if (f[i].length != yLen) {
+ throw new DimensionMismatchException(f[i].length, yLen);
+ }
+ if (dFdX[i].length != yLen) {
+ throw new DimensionMismatchException(dFdX[i].length, yLen);
+ }
+ if (dFdY[i].length != yLen) {
+ throw new DimensionMismatchException(dFdY[i].length, yLen);
+ }
+ if (d2FdXdY[i].length != yLen) {
+ throw new DimensionMismatchException(d2FdXdY[i].length, yLen);
+ }
+ final int ip1 = i + 1;
+ for (int j = 0; j < lastJ; j++) {
+ final int jp1 = j + 1;
+ final double[] beta = new double[] {
+ f[i][j], f[ip1][j], f[i][jp1], f[ip1][jp1],
+ dFdX[i][j], dFdX[ip1][j], dFdX[i][jp1], dFdX[ip1][jp1],
+ dFdY[i][j], dFdY[ip1][j], dFdY[i][jp1], dFdY[ip1][jp1],
+ d2FdXdY[i][j], d2FdXdY[ip1][j], d2FdXdY[i][jp1], d2FdXdY[ip1][jp1]
+ };
+
+ splines[i][j] = new BicubicSplineFunction(computeSplineCoefficients(beta),
+ initializeDerivatives);
+ }
+ }
+
+ if (initializeDerivatives) {
+ // Compute all partial derivatives.
+ partialDerivatives = new BivariateFunction[5][lastI][lastJ];
+
+ for (int i = 0; i < lastI; i++) {
+ for (int j = 0; j < lastJ; j++) {
+ final BicubicSplineFunction bcs = splines[i][j];
+ partialDerivatives[0][i][j] = bcs.partialDerivativeX();
+ partialDerivatives[1][i][j] = bcs.partialDerivativeY();
+ partialDerivatives[2][i][j] = bcs.partialDerivativeXX();
+ partialDerivatives[3][i][j] = bcs.partialDerivativeYY();
+ partialDerivatives[4][i][j] = bcs.partialDerivativeXY();
+ }
+ }
+ } else {
+ // Partial derivative methods cannot be used.
+ partialDerivatives = null;
+ }
+ }
+
+ /**
+ * {@inheritDoc}
+ */
+ public double value(double x, double y)
+ throws OutOfRangeException {
+ final int i = searchIndex(x, xval);
+ final int j = searchIndex(y, yval);
+
+ final double xN = (x - xval[i]) / (xval[i + 1] - xval[i]);
+ final double yN = (y - yval[j]) / (yval[j + 1] - yval[j]);
+
+ return splines[i][j].value(xN, yN);
+ }
+
+ /**
+ * Indicates whether a point is within the interpolation range.
+ *
+ * @param x First coordinate.
+ * @param y Second coordinate.
+ * @return {@code true} if (x, y) is a valid point.
+ * @since 3.3
+ */
+ public boolean isValidPoint(double x, double y) {
+ if (x < xval[0] ||
+ x > xval[xval.length - 1] ||
+ y < yval[0] ||
+ y > yval[yval.length - 1]) {
+ return false;
+ } else {
+ return true;
+ }
+ }
+
+ /**
+ * @param x x-coordinate.
+ * @param y y-coordinate.
+ * @return the value at point (x, y) of the first partial derivative with
+ * respect to x.
+ * @throws OutOfRangeException if {@code x} (resp. {@code y}) is outside
+ * the range defined by the boundary values of {@code xval} (resp.
+ * {@code yval}).
+ * @throws NullPointerException if the internal data were not initialized
+ * (cf. {@link #BicubicSplineInterpolatingFunction(double[],double[],double[][],
+ * double[][],double[][],double[][],boolean) constructor}).
+ */
+ public double partialDerivativeX(double x, double y)
+ throws OutOfRangeException {
+ return partialDerivative(0, x, y);
+ }
+ /**
+ * @param x x-coordinate.
+ * @param y y-coordinate.
+ * @return the value at point (x, y) of the first partial derivative with
+ * respect to y.
+ * @throws OutOfRangeException if {@code x} (resp. {@code y}) is outside
+ * the range defined by the boundary values of {@code xval} (resp.
+ * {@code yval}).
+ * @throws NullPointerException if the internal data were not initialized
+ * (cf. {@link #BicubicSplineInterpolatingFunction(double[],double[],double[][],
+ * double[][],double[][],double[][],boolean) constructor}).
+ */
+ public double partialDerivativeY(double x, double y)
+ throws OutOfRangeException {
+ return partialDerivative(1, x, y);
+ }
+ /**
+ * @param x x-coordinate.
+ * @param y y-coordinate.
+ * @return the value at point (x, y) of the second partial derivative with
+ * respect to x.
+ * @throws OutOfRangeException if {@code x} (resp. {@code y}) is outside
+ * the range defined by the boundary values of {@code xval} (resp.
+ * {@code yval}).
+ * @throws NullPointerException if the internal data were not initialized
+ * (cf. {@link #BicubicSplineInterpolatingFunction(double[],double[],double[][],
+ * double[][],double[][],double[][],boolean) constructor}).
+ */
+ public double partialDerivativeXX(double x, double y)
+ throws OutOfRangeException {
+ return partialDerivative(2, x, y);
+ }
+ /**
+ * @param x x-coordinate.
+ * @param y y-coordinate.
+ * @return the value at point (x, y) of the second partial derivative with
+ * respect to y.
+ * @throws OutOfRangeException if {@code x} (resp. {@code y}) is outside
+ * the range defined by the boundary values of {@code xval} (resp.
+ * {@code yval}).
+ * @throws NullPointerException if the internal data were not initialized
+ * (cf. {@link #BicubicSplineInterpolatingFunction(double[],double[],double[][],
+ * double[][],double[][],double[][],boolean) constructor}).
+ */
+ public double partialDerivativeYY(double x, double y)
+ throws OutOfRangeException {
+ return partialDerivative(3, x, y);
+ }
+ /**
+ * @param x x-coordinate.
+ * @param y y-coordinate.
+ * @return the value at point (x, y) of the second partial cross-derivative.
+ * @throws OutOfRangeException if {@code x} (resp. {@code y}) is outside
+ * the range defined by the boundary values of {@code xval} (resp.
+ * {@code yval}).
+ * @throws NullPointerException if the internal data were not initialized
+ * (cf. {@link #BicubicSplineInterpolatingFunction(double[],double[],double[][],
+ * double[][],double[][],double[][],boolean) constructor}).
+ */
+ public double partialDerivativeXY(double x, double y)
+ throws OutOfRangeException {
+ return partialDerivative(4, x, y);
+ }
+
+ /**
+ * @param which First index in {@link #partialDerivatives}.
+ * @param x x-coordinate.
+ * @param y y-coordinate.
+ * @return the value at point (x, y) of the selected partial derivative.
+ * @throws OutOfRangeException if {@code x} (resp. {@code y}) is outside
+ * the range defined by the boundary values of {@code xval} (resp.
+ * {@code yval}).
+ * @throws NullPointerException if the internal data were not initialized
+ * (cf. {@link #BicubicSplineInterpolatingFunction(double[],double[],double[][],
+ * double[][],double[][],double[][],boolean) constructor}).
+ */
+ private double partialDerivative(int which, double x, double y)
+ throws OutOfRangeException {
+ final int i = searchIndex(x, xval);
+ final int j = searchIndex(y, yval);
+
+ final double xN = (x - xval[i]) / (xval[i + 1] - xval[i]);
+ final double yN = (y - yval[j]) / (yval[j + 1] - yval[j]);
+
+ return partialDerivatives[which][i][j].value(xN, yN);
+ }
+
+ /**
+ * @param c Coordinate.
+ * @param val Coordinate samples.
+ * @return the index in {@code val} corresponding to the interval
+ * containing {@code c}.
+ * @throws OutOfRangeException if {@code c} is out of the
+ * range defined by the boundary values of {@code val}.
+ */
+ private int searchIndex(double c, double[] val) {
+ final int r = Arrays.binarySearch(val, c);
+
+ if (r == -1 ||
+ r == -val.length - 1) {
+ throw new OutOfRangeException(c, val[0], val[val.length - 1]);
+ }
+
+ if (r < 0) {
+ // "c" in within an interpolation sub-interval: Return the
+ // index of the sample at the lower end of the sub-interval.
+ return -r - 2;
+ }
+ final int last = val.length - 1;
+ if (r == last) {
+ // "c" is the last sample of the range: Return the index
+ // of the sample at the lower end of the last sub-interval.
+ return last - 1;
+ }
+
+ // "c" is another sample point.
+ return r;
+ }
+
+ /**
+ * Compute the spline coefficients from the list of function values and
+ * function partial derivatives values at the four corners of a grid
+ * element. They must be specified in the following order:
+ * <ul>
+ * <li>f(0,0)</li>
+ * <li>f(1,0)</li>
+ * <li>f(0,1)</li>
+ * <li>f(1,1)</li>
+ * <li>f<sub>x</sub>(0,0)</li>
+ * <li>f<sub>x</sub>(1,0)</li>
+ * <li>f<sub>x</sub>(0,1)</li>
+ * <li>f<sub>x</sub>(1,1)</li>
+ * <li>f<sub>y</sub>(0,0)</li>
+ * <li>f<sub>y</sub>(1,0)</li>
+ * <li>f<sub>y</sub>(0,1)</li>
+ * <li>f<sub>y</sub>(1,1)</li>
+ * <li>f<sub>xy</sub>(0,0)</li>
+ * <li>f<sub>xy</sub>(1,0)</li>
+ * <li>f<sub>xy</sub>(0,1)</li>
+ * <li>f<sub>xy</sub>(1,1)</li>
+ * </ul>
+ * where the subscripts indicate the partial derivative with respect to
+ * the corresponding variable(s).
+ *
+ * @param beta List of function values and function partial derivatives
+ * values.
+ * @return the spline coefficients.
+ */
+ private double[] computeSplineCoefficients(double[] beta) {
+ final double[] a = new double[NUM_COEFF];
+
+ for (int i = 0; i < NUM_COEFF; i++) {
+ double result = 0;
+ final double[] row = AINV[i];
+ for (int j = 0; j < NUM_COEFF; j++) {
+ result += row[j] * beta[j];
+ }
+ a[i] = result;
+ }
+
+ return a;
+ }
+}
+
+/**
+ * 2D-spline function.
+ *
+ */
+class BicubicSplineFunction implements BivariateFunction {
+ /** Number of points. */
+ private static final short N = 4;
+ /** Coefficients */
+ private final double[][] a;
+ /** First partial derivative along x. */
+ private final BivariateFunction partialDerivativeX;
+ /** First partial derivative along y. */
+ private final BivariateFunction partialDerivativeY;
+ /** Second partial derivative along x. */
+ private final BivariateFunction partialDerivativeXX;
+ /** Second partial derivative along y. */
+ private final BivariateFunction partialDerivativeYY;
+ /** Second crossed partial derivative. */
+ private final BivariateFunction partialDerivativeXY;
+
+ /**
+ * Simple constructor.
+ *
+ * @param coeff Spline coefficients.
+ */
+ BicubicSplineFunction(double[] coeff) {
+ this(coeff, false);
+ }
+
+ /**
+ * Simple constructor.
+ *
+ * @param coeff Spline coefficients.
+ * @param initializeDerivatives Whether to initialize the internal data
+ * needed for calling any of the methods that compute the partial derivatives
+ * this function.
+ */
+ BicubicSplineFunction(double[] coeff, boolean initializeDerivatives) {
+ a = new double[N][N];
+ for (int i = 0; i < N; i++) {
+ for (int j = 0; j < N; j++) {
+ a[i][j] = coeff[i * N + j];
+ }
+ }
+
+ if (initializeDerivatives) {
+ // Compute all partial derivatives functions.
+ final double[][] aX = new double[N][N];
+ final double[][] aY = new double[N][N];
+ final double[][] aXX = new double[N][N];
+ final double[][] aYY = new double[N][N];
+ final double[][] aXY = new double[N][N];
+
+ for (int i = 0; i < N; i++) {
+ for (int j = 0; j < N; j++) {
+ final double c = a[i][j];
+ aX[i][j] = i * c;
+ aY[i][j] = j * c;
+ aXX[i][j] = (i - 1) * aX[i][j];
+ aYY[i][j] = (j - 1) * aY[i][j];
+ aXY[i][j] = j * aX[i][j];
+ }
+ }
+
+ partialDerivativeX = new BivariateFunction() {
+ /** {@inheritDoc} */
+ public double value(double x, double y) {
+ final double x2 = x * x;
+ final double[] pX = {0, 1, x, x2};
+
+ final double y2 = y * y;
+ final double y3 = y2 * y;
+ final double[] pY = {1, y, y2, y3};
+
+ return apply(pX, pY, aX);
+ }
+ };
+ partialDerivativeY = new BivariateFunction() {
+ /** {@inheritDoc} */
+ public double value(double x, double y) {
+ final double x2 = x * x;
+ final double x3 = x2 * x;
+ final double[] pX = {1, x, x2, x3};
+
+ final double y2 = y * y;
+ final double[] pY = {0, 1, y, y2};
+
+ return apply(pX, pY, aY);
+ }
+ };
+ partialDerivativeXX = new BivariateFunction() {
+ /** {@inheritDoc} */
+ public double value(double x, double y) {
+ final double[] pX = {0, 0, 1, x};
+
+ final double y2 = y * y;
+ final double y3 = y2 * y;
+ final double[] pY = {1, y, y2, y3};
+
+ return apply(pX, pY, aXX);
+ }
+ };
+ partialDerivativeYY = new BivariateFunction() {
+ /** {@inheritDoc} */
+ public double value(double x, double y) {
+ final double x2 = x * x;
+ final double x3 = x2 * x;
+ final double[] pX = {1, x, x2, x3};
+
+ final double[] pY = {0, 0, 1, y};
+
+ return apply(pX, pY, aYY);
+ }
+ };
+ partialDerivativeXY = new BivariateFunction() {
+ /** {@inheritDoc} */
+ public double value(double x, double y) {
+ final double x2 = x * x;
+ final double[] pX = {0, 1, x, x2};
+
+ final double y2 = y * y;
+ final double[] pY = {0, 1, y, y2};
+
+ return apply(pX, pY, aXY);
+ }
+ };
+ } else {
+ partialDerivativeX = null;
+ partialDerivativeY = null;
+ partialDerivativeXX = null;
+ partialDerivativeYY = null;
+ partialDerivativeXY = null;
+ }
+ }
+
+ /**
+ * {@inheritDoc}
+ */
+ public double value(double x, double y) {
+ if (x < 0 || x > 1) {
+ throw new OutOfRangeException(x, 0, 1);
+ }
+ if (y < 0 || y > 1) {
+ throw new OutOfRangeException(y, 0, 1);
+ }
+
+ final double x2 = x * x;
+ final double x3 = x2 * x;
+ final double[] pX = {1, x, x2, x3};
+
+ final double y2 = y * y;
+ final double y3 = y2 * y;
+ final double[] pY = {1, y, y2, y3};
+
+ return apply(pX, pY, a);
+ }
+
+ /**
+ * Compute the value of the bicubic polynomial.
+ *
+ * @param pX Powers of the x-coordinate.
+ * @param pY Powers of the y-coordinate.
+ * @param coeff Spline coefficients.
+ * @return the interpolated value.
+ */
+ private double apply(double[] pX, double[] pY, double[][] coeff) {
+ double result = 0;
+ for (int i = 0; i < N; i++) {
+ for (int j = 0; j < N; j++) {
+ result += coeff[i][j] * pX[i] * pY[j];
+ }
+ }
+
+ return result;
+ }
+
+ /**
+ * @return the partial derivative wrt {@code x}.
+ */
+ public BivariateFunction partialDerivativeX() {
+ return partialDerivativeX;
+ }
+ /**
+ * @return the partial derivative wrt {@code y}.
+ */
+ public BivariateFunction partialDerivativeY() {
+ return partialDerivativeY;
+ }
+ /**
+ * @return the second partial derivative wrt {@code x}.
+ */
+ public BivariateFunction partialDerivativeXX() {
+ return partialDerivativeXX;
+ }
+ /**
+ * @return the second partial derivative wrt {@code y}.
+ */
+ public BivariateFunction partialDerivativeYY() {
+ return partialDerivativeYY;
+ }
+ /**
+ * @return the second partial cross-derivative.
+ */
+ public BivariateFunction partialDerivativeXY() {
+ return partialDerivativeXY;
+ }
+}