/** * Copyright (C) 2012 - present by OpenGamma Inc. and the OpenGamma group of companies * * Please see distribution for license. */ package com.opengamma.strata.math.impl.minimization; import static org.testng.AssertJUnit.assertEquals; import java.util.function.Function; import org.apache.commons.math3.random.Well44497b; import org.testng.annotations.Test; import com.opengamma.strata.collect.array.DoubleArray; import com.opengamma.strata.collect.array.DoubleMatrix; import com.opengamma.strata.math.impl.differentiation.VectorFieldFirstOrderDifferentiator; import com.opengamma.strata.math.impl.linearalgebra.DecompositionFactory; import com.opengamma.strata.math.impl.matrix.MatrixAlgebra; import com.opengamma.strata.math.impl.matrix.OGMatrixAlgebra; import com.opengamma.strata.math.impl.statistics.leastsquare.LeastSquareResults; import com.opengamma.strata.math.impl.statistics.leastsquare.NonLinearLeastSquare; /** * Test. */ @Test public class SumToOneTest { private static final MatrixAlgebra MA = new OGMatrixAlgebra(); private static final NonLinearLeastSquare SOLVER = new NonLinearLeastSquare(DecompositionFactory.SV_COMMONS, MA, 1e-9); private static final VectorFieldFirstOrderDifferentiator DIFFER = new VectorFieldFirstOrderDifferentiator(); private static final Well44497b RANDOM = new Well44497b(0L); @Test public void setTest() { int n = 7; int[][] sets = SumToOne.getSet(n); assertEquals(n, sets.length); } @Test public void setTest2() { int n = 13; int[][] sets = SumToOne.getSet(n); assertEquals(n, sets.length); } @Test public void transformTest() { for (int n = 2; n < 13; n++) { double[] from = new double[n - 1]; for (int j = 0; j < n - 1; j++) { from[j] = RANDOM.nextDouble() * Math.PI / 2; } SumToOne trans = new SumToOne(n); DoubleArray to = trans.transform(DoubleArray.copyOf(from)); assertEquals(n, to.size()); double sum = 0; for (int i = 0; i < n; i++) { sum += to.get(i); } assertEquals("vector length " + n, 1.0, sum, 1e-9); } } @Test public void inverseTransformTest() { for (int n = 2; n < 13; n++) { double[] theta = new double[n - 1]; for (int j = 0; j < n - 1; j++) { theta[j] = RANDOM.nextDouble() * Math.PI / 2; } SumToOne trans = new SumToOne(n); DoubleArray w = trans.transform(DoubleArray.copyOf(theta)); DoubleArray theta2 = trans.inverseTransform(w); for (int j = 0; j < n - 1; j++) { assertEquals("element " + j + ", of vector length " + n, theta[j], theta2.get(j), 1e-9); } } } @Test public void solverTest() { double[] w = new double[] {0.01, 0.5, 0.3, 0.19 }; final int n = w.length; final SumToOne trans = new SumToOne(n); Function<DoubleArray, DoubleArray> func = new Function<DoubleArray, DoubleArray>() { @Override public DoubleArray apply(DoubleArray theta) { return trans.transform(theta); } }; DoubleArray sigma = DoubleArray.filled(n, 1e-4); DoubleArray start = DoubleArray.filled(n - 1, 0.8); LeastSquareResults res = SOLVER.solve(DoubleArray.copyOf(w), sigma, func, start/*, maxJump*/); assertEquals("chi sqr", 0.0, res.getChiSq(), 1e-9); double[] fit = res.getFitParameters().toArray(); double[] expected = trans.inverseTransform(w); for (int i = 0; i < n - 1; i++) { //put the fit result back in the range 0 - pi/2 double x = fit[i]; if (x < 0) { x = -x; } if (x > Math.PI / 2) { int p = (int) (x / Math.PI); x -= p * Math.PI; if (x > Math.PI / 2) { x = -x + Math.PI; } } assertEquals(expected[i], x, 1e-9); } } @Test public void solverTest2() { double[] w = new double[] {3.0, 4.0 }; final int n = w.length; Function<DoubleArray, DoubleArray> func = new Function<DoubleArray, DoubleArray>() { @Override public DoubleArray apply(DoubleArray x) { double a = x.get(0); double theta = x.get(1); double c1 = Math.cos(theta); return DoubleArray.of( a * c1 * c1, a * (1 - c1 * c1)); } }; DoubleArray sigma = DoubleArray.filled(n, 1e-4); DoubleArray start = DoubleArray.of(0.0, 0.8); LeastSquareResults res = SOLVER.solve(DoubleArray.copyOf(w), sigma, func, start/*, maxJump*/); assertEquals("chi sqr", 0.0, res.getChiSq(), 1e-9); double[] fit = res.getFitParameters().toArray(); assertEquals(7.0, fit[0], 1e-9); assertEquals(Math.atan(Math.sqrt(4 / 3.)), fit[1], 1e-9); } @Test public void jacobianTest() { final int n = 5; final SumToOne trans = new SumToOne(n); Function<DoubleArray, DoubleArray> func = new Function<DoubleArray, DoubleArray>() { @Override public DoubleArray apply(DoubleArray theta) { return trans.transform(theta); } }; Function<DoubleArray, DoubleMatrix> jacFunc = new Function<DoubleArray, DoubleMatrix>() { @Override public DoubleMatrix apply(DoubleArray theta) { return trans.jacobian(theta); } }; Function<DoubleArray, DoubleMatrix> fdJacFunc = DIFFER.differentiate(func); for (int tries = 0; tries < 10; tries++) { DoubleArray vTheta = DoubleArray.of(n - 1, i -> RANDOM.nextDouble()); DoubleMatrix jac = jacFunc.apply(vTheta); DoubleMatrix fdJac = fdJacFunc.apply(vTheta); for (int j = 0; j < n - 1; j++) { double sum = 0.0; for (int i = 0; i < n; i++) { sum += jac.get(i, j); assertEquals("element " + i + " " + j, fdJac.get(i, j), jac.get(i, j), 1e-6); } assertEquals("wrong sum of sensitivities", 0.0, sum, 1e-15); } } } }