/** * Copyright (C) 2011 - 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.Assert.assertEquals; import java.util.BitSet; import java.util.function.Function; import org.testng.annotations.Test; import com.opengamma.strata.collect.ArgChecker; 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.minimization.ParameterLimitsTransform.LimitType; /** * Test. */ @Test public class NonLinearTransformFunctionTest { private static final ParameterLimitsTransform[] NULL_TRANSFORMS; private static final ParameterLimitsTransform[] TRANSFORMS; private static final Function<DoubleArray, DoubleArray> FUNCTION = new Function<DoubleArray, DoubleArray>() { @Override public DoubleArray apply(DoubleArray x) { ArgChecker.isTrue(x.size() == 2); double x1 = x.get(0); double x2 = x.get(1); return DoubleArray.of( Math.sin(x1) * Math.cos(x2), Math.sin(x1) * Math.sin(x2), Math.cos(x1)); } }; private static final Function<DoubleArray, DoubleMatrix> JACOBIAN = new Function<DoubleArray, DoubleMatrix>() { @Override public DoubleMatrix apply(DoubleArray x) { ArgChecker.isTrue(x.size() == 2); double x1 = x.get(0); double x2 = x.get(1); double[][] y = new double[3][2]; y[0][0] = Math.cos(x1) * Math.cos(x2); y[0][1] = -Math.sin(x1) * Math.sin(x2); y[1][0] = Math.cos(x1) * Math.sin(x2); y[1][1] = Math.sin(x1) * Math.cos(x2); y[2][0] = -Math.sin(x1); y[2][1] = 0; return DoubleMatrix.copyOf(y); } }; static { NULL_TRANSFORMS = new ParameterLimitsTransform[2]; NULL_TRANSFORMS[0] = new NullTransform(); NULL_TRANSFORMS[1] = new NullTransform(); TRANSFORMS = new ParameterLimitsTransform[2]; TRANSFORMS[0] = new DoubleRangeLimitTransform(0, Math.PI); TRANSFORMS[1] = new SingleRangeLimitTransform(0, LimitType.GREATER_THAN); } @Test public void testNullTransform() { BitSet fixed = new BitSet(); fixed.set(0); DoubleArray start = DoubleArray.of(Math.PI / 4, 1); UncoupledParameterTransforms transforms = new UncoupledParameterTransforms(start, NULL_TRANSFORMS, fixed); NonLinearTransformFunction transFunc = new NonLinearTransformFunction(FUNCTION, JACOBIAN, transforms); Function<DoubleArray, DoubleArray> func = transFunc.getFittingFunction(); Function<DoubleArray, DoubleMatrix> jacFunc = transFunc.getFittingJacobian(); DoubleArray x = DoubleArray.of(0.5); final double rootHalf = Math.sqrt(0.5); DoubleArray y = func.apply(x); assertEquals(3, y.size()); assertEquals(rootHalf * Math.cos(0.5), y.get(0), 1e-9); assertEquals(rootHalf * Math.sin(0.5), y.get(1), 1e-9); assertEquals(rootHalf, y.get(2), 1e-9); DoubleMatrix jac = jacFunc.apply(x); assertEquals(3, jac.rowCount()); assertEquals(1, jac.columnCount()); assertEquals(-rootHalf * Math.sin(0.5), jac.get(0, 0), 1e-9); assertEquals(rootHalf * Math.cos(0.5), jac.get(1, 0), 1e-9); assertEquals(0, jac.get(2, 0), 1e-9); } @Test public void testNonLinearTransform() { BitSet fixed = new BitSet(); DoubleArray start = DoubleArray.filled(2); UncoupledParameterTransforms transforms = new UncoupledParameterTransforms(start, TRANSFORMS, fixed); NonLinearTransformFunction transFunc = new NonLinearTransformFunction(FUNCTION, JACOBIAN, transforms); Function<DoubleArray, DoubleArray> func = transFunc.getFittingFunction(); Function<DoubleArray, DoubleMatrix> jacFunc = transFunc.getFittingJacobian(); VectorFieldFirstOrderDifferentiator diff = new VectorFieldFirstOrderDifferentiator(); Function<DoubleArray, DoubleMatrix> jacFuncFD = diff.differentiate(func); DoubleArray testPoint = DoubleArray.of(4.5, -2.1); DoubleMatrix jac = jacFunc.apply(testPoint); DoubleMatrix jacFD = jacFuncFD.apply(testPoint); assertEquals(3, jac.rowCount()); assertEquals(2, jac.columnCount()); for (int i = 0; i < 3; i++) { for (int j = 0; j < 2; j++) { assertEquals(jacFD.get(i, j), jac.get(i, j), 1e-6); } } } }