From 4c56e614974c73f17e3d6b3badc8ca4cb416fa74 Mon Sep 17 00:00:00 2001 From: Luc Maisonobe Date: Thu, 16 Aug 2012 10:07:08 +0000 Subject: [PATCH] Added expm1 and log1p to DSCompiler and DerivativeStructure. git-svn-id: https://svn.apache.org/repos/asf/commons/proper/math/trunk@1373778 13f79535-47bb-0310-9956-ffa450edef68 --- .../analysis/differentiation/DSCompiler.java | 49 +++++++++++++++++++ .../differentiation/DerivativeStructure.java | 18 +++++++ .../DerivativeStructureTest.java | 47 ++++++++++++++++++ 3 files changed, 114 insertions(+) diff --git a/src/main/java/org/apache/commons/math3/analysis/differentiation/DSCompiler.java b/src/main/java/org/apache/commons/math3/analysis/differentiation/DSCompiler.java index cc350f0e1..de9516bc8 100644 --- a/src/main/java/org/apache/commons/math3/analysis/differentiation/DSCompiler.java +++ b/src/main/java/org/apache/commons/math3/analysis/differentiation/DSCompiler.java @@ -974,6 +974,27 @@ public class DSCompiler { } + /** Compute exp(x) - 1 of a derivative structure. + * @param operand array holding the operand + * @param operandOffset offset of the operand in its array + * @param result array where result must be stored (for + * exponential the result array cannot be the input + * array) + * @param resultOffset offset of the result in its array + */ + public void expm1(final double[] operand, final int operandOffset, + final double[] result, final int resultOffset) { + + // create the function value and derivatives + double[] function = new double[1 + order]; + function[0] = FastMath.expm1(operand[operandOffset]); + Arrays.fill(function, 1, 1 + order, FastMath.exp(operand[operandOffset])); + + // apply function composition + compose(operand, operandOffset, function, result, resultOffset); + + } + /** Compute natural logarithm of a derivative structure. * @param operand array holding the operand * @param operandOffset offset of the operand in its array @@ -1002,6 +1023,34 @@ public class DSCompiler { } + /** Computes of a derivative structure. + * @param operand array holding the operand + * @param operandOffset offset of the operand in its array + * @param result array where result must be stored (for + * logarithm the result array cannot be the input + * array) + */ + public void log1p(final double[] operand, final int operandOffset, + final double[] result, final int resultOffset) { + + + // create the function value and derivatives + double[] function = new double[1 + order]; + function[0] = FastMath.log1p(operand[operandOffset]); + if (order > 0) { + double inv = 1.0 / (1.0 + operand[operandOffset]); + double xk = inv; + for (int i = 1; i <= order; ++i) { + function[i] = xk; + xk *= -i * inv; + } + } + + // apply function composition + compose(operand, operandOffset, function, result, resultOffset); + + } + /** Compute cosine of a derivative structure. * @param operand array holding the operand * @param operandOffset offset of the operand in its array diff --git a/src/main/java/org/apache/commons/math3/analysis/differentiation/DerivativeStructure.java b/src/main/java/org/apache/commons/math3/analysis/differentiation/DerivativeStructure.java index 1e5b6db11..d707c8871 100644 --- a/src/main/java/org/apache/commons/math3/analysis/differentiation/DerivativeStructure.java +++ b/src/main/java/org/apache/commons/math3/analysis/differentiation/DerivativeStructure.java @@ -497,6 +497,15 @@ public class DerivativeStructure implements FieldElement, S return result; } + /** Exponential minus 1. + * @return exponential minus one of the instance + */ + public DerivativeStructure expm1() { + final DerivativeStructure result = new DerivativeStructure(compiler); + compiler.expm1(data, 0, result.data, 0); + return result; + } + /** Natural logarithm. * @return logarithm of the instance */ @@ -506,6 +515,15 @@ public class DerivativeStructure implements FieldElement, S return result; } + /** Shifted natural logarithm. + * @return logarithm of one plus the instance + */ + public DerivativeStructure log1p() { + final DerivativeStructure result = new DerivativeStructure(compiler); + compiler.log1p(data, 0, result.data, 0); + return result; + } + /** Cosine operation. * @return cos(this) */ diff --git a/src/test/java/org/apache/commons/math3/analysis/differentiation/DerivativeStructureTest.java b/src/test/java/org/apache/commons/math3/analysis/differentiation/DerivativeStructureTest.java index 7057a2112..92b208cab 100644 --- a/src/test/java/org/apache/commons/math3/analysis/differentiation/DerivativeStructureTest.java +++ b/src/test/java/org/apache/commons/math3/analysis/differentiation/DerivativeStructureTest.java @@ -417,6 +417,22 @@ public class DerivativeStructureTest { } } + @Test + public void testExpm1Definition() { + double epsilon = 3.0e-16; + for (int maxOrder = 0; maxOrder < 5; ++maxOrder) { + for (double x = 0.1; x < 1.2; x += 0.001) { + DerivativeStructure dsX = new DerivativeStructure(1, maxOrder, 0, x); + DerivativeStructure expm11 = dsX.expm1(); + DerivativeStructure expm12 = dsX.exp().subtract(dsX.getField().getOne()); + DerivativeStructure zero = expm11.subtract(expm12); + for (int n = 0; n <= maxOrder; ++n) { + Assert.assertEquals(0, zero.getPartialDerivative(n), epsilon); + } + } + } + } + @Test public void testLog() { double[] epsilon = new double[] { 1.0e-16, 1.0e-16, 3.0e-14, 7.0e-13, 3.0e-11 }; @@ -432,6 +448,22 @@ public class DerivativeStructureTest { } } + @Test + public void testLog1pDefinition() { + double epsilon = 3.0e-16; + for (int maxOrder = 0; maxOrder < 5; ++maxOrder) { + for (double x = 0.1; x < 1.2; x += 0.001) { + DerivativeStructure dsX = new DerivativeStructure(1, maxOrder, 0, x); + DerivativeStructure log1p1 = dsX.log1p(); + DerivativeStructure log1p2 = dsX.add(dsX.getField().getOne()).log(); + DerivativeStructure zero = log1p1.subtract(log1p2); + for (int n = 0; n <= maxOrder; ++n) { + Assert.assertEquals(0, zero.getPartialDerivative(n), epsilon); + } + } + } + } + @Test public void testLogExp() { double[] epsilon = new double[] { 2.0e-16, 2.0e-16, 3.0e-16, 2.0e-15, 6.0e-15 }; @@ -447,6 +479,21 @@ public class DerivativeStructureTest { } } + @Test + public void testLog1pExpm1() { + double[] epsilon = new double[] { 6.0e-17, 3.0e-16, 5.0e-16, 9.0e-16, 6.0e-15 }; + for (int maxOrder = 0; maxOrder < 5; ++maxOrder) { + for (double x = 0.1; x < 1.2; x += 0.001) { + DerivativeStructure dsX = new DerivativeStructure(1, maxOrder, 0, x); + DerivativeStructure rebuiltX = dsX.expm1().log1p(); + DerivativeStructure zero = rebuiltX.subtract(dsX); + for (int n = 0; n <= maxOrder; ++n) { + Assert.assertEquals(0.0, zero.getPartialDerivative(n), epsilon[n]); + } + } + } + } + @Test public void testSinCos() { double epsilon = 5.0e-16;