/** * Copyright (C) 2009 - present by OpenGamma Inc. and the OpenGamma group of companies * * Please see distribution for license. */ package com.opengamma.analytics.math.interpolation; import java.util.ArrayList; import java.util.Arrays; import java.util.List; import org.apache.commons.lang.Validate; import org.testng.annotations.Test; import cern.jet.random.engine.MersenneTwister; import cern.jet.random.engine.MersenneTwister64; import cern.jet.random.engine.RandomEngine; import com.opengamma.analytics.math.function.Function1D; import com.opengamma.analytics.math.matrix.DoubleMatrix1D; import com.opengamma.analytics.math.minimization.BrentMinimizer1D; import com.opengamma.analytics.math.minimization.ConjugateGradientVectorMinimizer; import com.opengamma.analytics.math.minimization.ScalarMinimizer; import com.opengamma.analytics.math.statistics.distribution.NormalDistribution; import com.opengamma.analytics.math.statistics.distribution.ProbabilityDistribution; import com.opengamma.util.test.TestGroup; import com.opengamma.util.tuple.Pair; import com.opengamma.util.tuple.Pairs; /** * Test. */ @Test(groups = TestGroup.UNIT) public class SmoothSurfaceTest { //FIXME this test does nothing - either delete or add some real tests protected static final RandomEngine RANDOM = new MersenneTwister64(MersenneTwister.DEFAULT_SEED); private static final ProbabilityDistribution<Double> NORMAL = new NormalDistribution(0, 1, RANDOM); private static final double EPS = 1e-5; private static final RadialBasisFunction SMOOTHER = new RadialBasisFunction(); protected static final List<Pair<double[], Double>> FLAT_DATA = new ArrayList<>(); protected static final List<Pair<double[], Double>> NOISY_DATA = new ArrayList<>(); protected static final List<double[]> NODE_POS = new ArrayList<>(); protected static final double VALUE = 0.3; static { double x, y; for (int i = 0; i < 20; i++) { x = 10 * RANDOM.nextDouble(); y = 10 * RANDOM.nextDouble(); NODE_POS.add(new double[] {x, y}); FLAT_DATA.add(Pairs.of(new double[] {x, y}, VALUE)); NOISY_DATA.add(Pairs.of(new double[] {x, y}, VALUE + 0.1 * NORMAL.nextRandom())); } } @Test(enabled = false) public void test() { final Function1D<Double, Double> basisFunction = new MultiquadraticRadialBasisFunction(0.5); fit(FLAT_DATA, basisFunction, true, NODE_POS); } @Test(enabled = false) public void testNoisy() { final Function1D<Double, Double> basisFunction = new MultiquadraticRadialBasisFunction(0.5); fit(NOISY_DATA, basisFunction, true, NODE_POS); } public void fit(final List<Pair<double[], Double>> data, final Function1D<Double, Double> basisFunction, final boolean isNormalized, final List<double[]> nodePos) { final Function1D<DoubleMatrix1D, Double> fom = new Function1D<DoubleMatrix1D, Double>() { @SuppressWarnings("synthetic-access") @Override public Double evaluate(final DoubleMatrix1D weights) { final List<Pair<double[], Double>> weightsAndPos = combineWeightsAndPos(nodePos, weights); final double chi2 = getChiSquared(data, basisFunction, weightsAndPos, isNormalized); final double plenty = getPlenty(data, basisFunction, weightsAndPos, isNormalized); return chi2 + 0.0 * plenty; // TODO This is not working with a plenty!!!! } }; final ScalarMinimizer lineMinimizer = new BrentMinimizer1D(); final ConjugateGradientVectorMinimizer minimizer = new ConjugateGradientVectorMinimizer(lineMinimizer, 1e-3, 1000); final double[] start = new double[nodePos.size()]; for (int i = 0; i < start.length; i++) { start[i] = VALUE; } final DoubleMatrix1D res = minimizer.minimize(fom, new DoubleMatrix1D(start)); final double chiSquare = fom.evaluate(res); System.out.println(res); System.out.println("chi2: " + chiSquare); final List<Pair<double[], Double>> weights = combineWeightsAndPos(nodePos, res); System.out.println("Pelenty: " + getPlenty(data, basisFunction, weights, isNormalized)); printSurface(basisFunction, weights, isNormalized); } private static List<Pair<double[], Double>> combineWeightsAndPos(final List<double[]> nodePos, final DoubleMatrix1D weights) { final int n = nodePos.size(); Validate.isTrue(n == weights.getNumberOfElements()); final List<Pair<double[], Double>> weightsAndPos = new ArrayList<>(n); for (int i = 0; i < n; i++) { weightsAndPos.add(Pairs.of(nodePos.get(i), weights.getEntry(i))); } return weightsAndPos; } private void printSurface(final Function1D<Double, Double> basisFunction, final List<Pair<double[], Double>> weights, final boolean isNormalized) { // printout final double[] x = new double[2]; System.out.print("\t"); for (int j = 0; j < 99; j++) { System.out.print(j / 10.0 + "\t"); } System.out.print(99 / 10.0 + "\n"); for (int i = 0; i < 100; i++) { System.out.print(i / 10.0 + "\t"); x[0] = i / 10.0; for (int j = 0; j < 100; j++) { x[1] = j / 10.0; final double fit = SMOOTHER.evaluate(basisFunction, weights, x, isNormalized); System.out.print(fit + "\t"); } System.out.print("\n"); } } private double getChiSquared(final List<Pair<double[], Double>> data, final Function1D<Double, Double> basisFunction, final List<Pair<double[], Double>> weights, final boolean isNormalized) { final int n = data.size(); double sum = 0; double[] x; for (int i = 0; i < n; i++) { final Pair<double[], Double> dPair = data.get(i); x = dPair.getFirst(); final double diff = (dPair.getSecond() - SMOOTHER.evaluate(basisFunction, weights, x, isNormalized)) / 0.1; sum += diff * diff; } return sum; } private double getPlenty(final List<Pair<double[], Double>> data, final Function1D<Double, Double> basisFunction, final List<Pair<double[], Double>> weights, final boolean isNormalized) { double sum = 0; for (final Pair<double[], Double> pair : data) { final double[] x = pair.getFirst(); final double[][] hessian = getHessian(basisFunction, weights, x, isNormalized); final double temp = getMatrixMaxValue(hessian); sum += temp * temp; } return sum; } double getMatrixMaxValue(final double[][] matrix) { double res = 0; final int n = matrix.length; for (int i = 0; i < n; i++) { for (int j = 0; j < matrix[i].length; j++) { res += matrix[i][j] * matrix[i][j]; } } return Math.sqrt(res); } private double[][] getHessian(final Function1D<Double, Double> basisFunction, final List<Pair<double[], Double>> weights, final double[] x, final boolean isNormalized) { final int n = x.length; final double[][] res = new double[n][n]; for (int i = 0; i < n; i++) { for (int j = i; j < n; j++) { res[i][j] = getSecondDev(basisFunction, weights, x, isNormalized, i, j); } for (int j = i + 1; j < n; j++) { res[j][i] = res[i][j]; } } return res; } private double getSecondDev(final Function1D<Double, Double> basisFunction, final List<Pair<double[], Double>> weights, final double[] x, final boolean isNormalized, final int i, final int j) { if (i == j) { final double f_x = SMOOTHER.evaluate(basisFunction, weights, x, isNormalized); final double[] temp = Arrays.copyOf(x, x.length); temp[i] += EPS; final double f_p = SMOOTHER.evaluate(basisFunction, weights, temp, isNormalized); temp[i] -= 2 * EPS; final double f_m = SMOOTHER.evaluate(basisFunction, weights, temp, isNormalized); return (f_p + f_m - 2 * f_x) / EPS / EPS; } return 0; } }