diff --git a/src/changes/changes.xml b/src/changes/changes.xml index 1b563d3e7..f9ac147ac 100644 --- a/src/changes/changes.xml +++ b/src/changes/changes.xml @@ -55,6 +55,10 @@ This is a minor release: It combines bug fixes and new features. Changes to existing features were made in a backwards-compatible way such as to allow drop-in replacement of the v3.1[.1] JAR file. "> + + Added accurate linear combination of DerivativeStructure instances, + avoiding cancellation. + Throw "MathUnsupportedOperationException" from optimizers that do not support constraints (previous behaviour was to silently ignore diff --git a/src/main/java/org/apache/commons/math3/util/MathArrays.java b/src/main/java/org/apache/commons/math3/util/MathArrays.java index 3c981e8bd..8eccae460 100644 --- a/src/main/java/org/apache/commons/math3/util/MathArrays.java +++ b/src/main/java/org/apache/commons/math3/util/MathArrays.java @@ -22,6 +22,7 @@ import java.util.ArrayList; import java.util.Comparator; import java.util.Collections; +import org.apache.commons.math3.analysis.differentiation.DerivativeStructure; import org.apache.commons.math3.exception.DimensionMismatchException; import org.apache.commons.math3.exception.MathInternalError; import org.apache.commons.math3.exception.NonMonotonicSequenceException; @@ -1117,6 +1118,353 @@ public class MathArrays { return result; } + /** + * Compute a linear combination accurately. + * This method computes the sum of the products + * ai bi to high accuracy. + * It does so by using specific multiplication and addition algorithms to + * preserve accuracy and reduce cancellation effects. + *
+ * It is based on the 2005 paper + * + * Accurate Sum and Dot Product by Takeshi Ogita, Siegfried M. Rump, + * and Shin'ichi Oishi published in SIAM J. Sci. Comput. + * + * @param a Factors. + * @param b Factors. + * @return Σi ai bi. + * @throws DimensionMismatchException if arrays dimensions don't match + * @since 3.2 + */ + public static DerivativeStructure linearCombination(final DerivativeStructure[] a, final DerivativeStructure[] b) + throws DimensionMismatchException { + + // compute an accurate value, taking care of cancellations + final double[] aDouble = new double[a.length]; + for (int i = 0; i < a.length; ++i) { + aDouble[i] = a[i].getValue(); + } + final double[] bDouble = new double[b.length]; + for (int i = 0; i < b.length; ++i) { + bDouble[i] = b[i].getValue(); + } + final double accurateValue = MathArrays.linearCombination(aDouble, bDouble); + + // compute a simple value, with all partial derivatives + DerivativeStructure simpleValue = a[0].getField().getZero(); + for (int i = 0; i < a.length; ++i) { + simpleValue = simpleValue.add(a[i].multiply(b[i])); + } + + // create a result with accurate value and all derivatives (not necessarily as accurate as the value) + final double[] data = simpleValue.getAllDerivatives(); + data[0] = accurateValue; + return new DerivativeStructure(simpleValue.getFreeParameters(), simpleValue.getOrder(), data); + + } + + /** + * Compute a linear combination accurately. + * This method computes the sum of the products + * ai bi to high accuracy. + * It does so by using specific multiplication and addition algorithms to + * preserve accuracy and reduce cancellation effects. + *
+ * It is based on the 2005 paper + * + * Accurate Sum and Dot Product by Takeshi Ogita, Siegfried M. Rump, + * and Shin'ichi Oishi published in SIAM J. Sci. Comput. + * + * @param a Factors. + * @param b Factors. + * @return Σi ai bi. + * @throws DimensionMismatchException if arrays dimensions don't match + */ + public static DerivativeStructure linearCombination(final double[] a, final DerivativeStructure[] b) + throws DimensionMismatchException { + + // compute an accurate value, taking care of cancellations + final double[] bDouble = new double[b.length]; + for (int i = 0; i < b.length; ++i) { + bDouble[i] = b[i].getValue(); + } + final double accurateValue = MathArrays.linearCombination(a, bDouble); + + // compute a simple value, with all partial derivatives + DerivativeStructure simpleValue = b[0].getField().getZero(); + for (int i = 0; i < a.length; ++i) { + simpleValue = simpleValue.add(b[i].multiply(a[i])); + } + + // create a result with accurate value and all derivatives (not necessarily as accurate as the value) + final double[] data = simpleValue.getAllDerivatives(); + data[0] = accurateValue; + return new DerivativeStructure(simpleValue.getFreeParameters(), simpleValue.getOrder(), data); + + } + + /** + * Compute a linear combination accurately. + *

+ * This method computes a1×b1 + + * a2×b2 + * to high accuracy. It does so by using specific multiplication and + * addition algorithms to preserve accuracy and reduce cancellation effects. + * It is based on the 2005 paper + * Accurate Sum and Dot Product by Takeshi Ogita, + * Siegfried M. Rump, and Shin'ichi Oishi published in SIAM J. Sci. Comput. + *

+ * @param a1 first factor of the first term + * @param b1 second factor of the first term + * @param a2 first factor of the second term + * @param b2 second factor of the second term + * @return a1×b1 + + * a2×b2 + * @see #linearCombination(DerivativeStructure, DerivativeStructure, DerivativeStructure, DerivativeStructure, DerivativeStructure, DerivativeStructure) + * @see #linearCombination(DerivativeStructure, DerivativeStructure, DerivativeStructure, DerivativeStructure, DerivativeStructure, DerivativeStructure, DerivativeStructure, DerivativeStructure) + * @since 3.2 + */ + public static DerivativeStructure linearCombination(final DerivativeStructure a1, final DerivativeStructure b1, + final DerivativeStructure a2, final DerivativeStructure b2) { + + // compute an accurate value, taking care of cancellations + final double accurateValue = MathArrays.linearCombination(a1.getValue(), b1.getValue(), + a2.getValue(), b2.getValue()); + + // compute a simple value, with all partial derivatives + final DerivativeStructure simpleValue = a1.multiply(b1).add(a2.multiply(b2)); + + // create a result with accurate value and all derivatives (not necessarily as accurate as the value) + final double[] data = simpleValue.getAllDerivatives(); + data[0] = accurateValue; + return new DerivativeStructure(simpleValue.getFreeParameters(), simpleValue.getOrder(), data); + + } + + /** + * Compute a linear combination accurately. + *

+ * This method computes a1×b1 + + * a2×b2 + * to high accuracy. It does so by using specific multiplication and + * addition algorithms to preserve accuracy and reduce cancellation effects. + * It is based on the 2005 paper + * Accurate Sum and Dot Product by Takeshi Ogita, + * Siegfried M. Rump, and Shin'ichi Oishi published in SIAM J. Sci. Comput. + *

+ * @param a1 first factor of the first term + * @param b1 second factor of the first term + * @param a2 first factor of the second term + * @param b2 second factor of the second term + * @return a1×b1 + + * a2×b2 + * @see #linearCombination(double, DerivativeStructure, double, DerivativeStructure, double, DerivativeStructure) + * @see #linearCombination(double, DerivativeStructure, double, DerivativeStructure, double, DerivativeStructure, double, DerivativeStructure) + * @since 3.2 + */ + public static DerivativeStructure linearCombination(final double a1, final DerivativeStructure b1, + final double a2, final DerivativeStructure b2) { + + // compute an accurate value, taking care of cancellations + final double accurateValue = MathArrays.linearCombination(a1, b1.getValue(), + a2, b2.getValue()); + + // compute a simple value, with all partial derivatives + final DerivativeStructure simpleValue = b1.multiply(a1).add(b2.multiply(a2)); + + // create a result with accurate value and all derivatives (not necessarily as accurate as the value) + final double[] data = simpleValue.getAllDerivatives(); + data[0] = accurateValue; + return new DerivativeStructure(simpleValue.getFreeParameters(), simpleValue.getOrder(), data); + + } + + /** + * Compute a linear combination accurately. + *

+ * This method computes a1×b1 + + * a2×b2 + a3×b3 + * to high accuracy. It does so by using specific multiplication and + * addition algorithms to preserve accuracy and reduce cancellation effects. + * It is based on the 2005 paper + * Accurate Sum and Dot Product by Takeshi Ogita, + * Siegfried M. Rump, and Shin'ichi Oishi published in SIAM J. Sci. Comput. + *

+ * @param a1 first factor of the first term + * @param b1 second factor of the first term + * @param a2 first factor of the second term + * @param b2 second factor of the second term + * @param a3 first factor of the third term + * @param b3 second factor of the third term + * @return a1×b1 + + * a2×b2 + a3×b3 + * @see #linearCombination(DerivativeStructure, DerivativeStructure, DerivativeStructure, DerivativeStructure) + * @see #linearCombination(DerivativeStructure, DerivativeStructure, DerivativeStructure, DerivativeStructure, DerivativeStructure, DerivativeStructure, DerivativeStructure, DerivativeStructure) + * @since 3.2 + */ + public static DerivativeStructure linearCombination(final DerivativeStructure a1, final DerivativeStructure b1, + final DerivativeStructure a2, final DerivativeStructure b2, + final DerivativeStructure a3, final DerivativeStructure b3) { + + // compute an accurate value, taking care of cancellations + final double accurateValue = MathArrays.linearCombination(a1.getValue(), b1.getValue(), + a2.getValue(), b2.getValue(), + a3.getValue(), b3.getValue()); + + // compute a simple value, with all partial derivatives + final DerivativeStructure simpleValue = a1.multiply(b1).add(a2.multiply(b2)).add(a3.multiply(b3)); + + // create a result with accurate value and all derivatives (not necessarily as accurate as the value) + final double[] data = simpleValue.getAllDerivatives(); + data[0] = accurateValue; + return new DerivativeStructure(simpleValue.getFreeParameters(), simpleValue.getOrder(), data); + + } + + /** + * Compute a linear combination accurately. + *

+ * This method computes a1×b1 + + * a2×b2 + a3×b3 + * to high accuracy. It does so by using specific multiplication and + * addition algorithms to preserve accuracy and reduce cancellation effects. + * It is based on the 2005 paper + * Accurate Sum and Dot Product by Takeshi Ogita, + * Siegfried M. Rump, and Shin'ichi Oishi published in SIAM J. Sci. Comput. + *

+ * @param a1 first factor of the first term + * @param b1 second factor of the first term + * @param a2 first factor of the second term + * @param b2 second factor of the second term + * @param a3 first factor of the third term + * @param b3 second factor of the third term + * @return a1×b1 + + * a2×b2 + a3×b3 + * @see #linearCombination(double, DerivativeStructure, double, DerivativeStructure) + * @see #linearCombination(double, DerivativeStructure, double, DerivativeStructure, double, DerivativeStructure, double, DerivativeStructure) + * @since 3.2 + */ + public static DerivativeStructure linearCombination(final double a1, final DerivativeStructure b1, + final double a2, final DerivativeStructure b2, + final double a3, final DerivativeStructure b3) { + + // compute an accurate value, taking care of cancellations + final double accurateValue = MathArrays.linearCombination(a1, b1.getValue(), + a2, b2.getValue(), + a3, b3.getValue()); + + // compute a simple value, with all partial derivatives + final DerivativeStructure simpleValue = b1.multiply(a1).add(b2.multiply(a2)).add(b3.multiply(a3)); + + // create a result with accurate value and all derivatives (not necessarily as accurate as the value) + final double[] data = simpleValue.getAllDerivatives(); + data[0] = accurateValue; + return new DerivativeStructure(simpleValue.getFreeParameters(), simpleValue.getOrder(), data); + + } + + /** + * Compute a linear combination accurately. + *

+ * This method computes a1×b1 + + * a2×b2 + a3×b3 + + * a4×b4 + * to high accuracy. It does so by using specific multiplication and + * addition algorithms to preserve accuracy and reduce cancellation effects. + * It is based on the 2005 paper + * Accurate Sum and Dot Product by Takeshi Ogita, + * Siegfried M. Rump, and Shin'ichi Oishi published in SIAM J. Sci. Comput. + *

+ * @param a1 first factor of the first term + * @param b1 second factor of the first term + * @param a2 first factor of the second term + * @param b2 second factor of the second term + * @param a3 first factor of the third term + * @param b3 second factor of the third term + * @param a4 first factor of the third term + * @param b4 second factor of the third term + * @return a1×b1 + + * a2×b2 + a3×b3 + + * a4×b4 + * @see #linearCombination(DerivativeStructure, DerivativeStructure, DerivativeStructure, DerivativeStructure) + * @see #linearCombination(DerivativeStructure, DerivativeStructure, DerivativeStructure, DerivativeStructure, DerivativeStructure, DerivativeStructure) + * @since 3.2 + */ + public static DerivativeStructure linearCombination(final DerivativeStructure a1, final DerivativeStructure b1, + final DerivativeStructure a2, final DerivativeStructure b2, + final DerivativeStructure a3, final DerivativeStructure b3, + final DerivativeStructure a4, final DerivativeStructure b4) { + + // compute an accurate value, taking care of cancellations + final double accurateValue = MathArrays.linearCombination(a1.getValue(), b1.getValue(), + a2.getValue(), b2.getValue(), + a3.getValue(), b3.getValue(), + a4.getValue(), b4.getValue()); + + // compute a simple value, with all partial derivatives + final DerivativeStructure simpleValue = a1.multiply(b1).add(a2.multiply(b2)).add(a3.multiply(b3)).add(a4.multiply(b4)); + + // create a result with accurate value and all derivatives (not necessarily as accurate as the value) + final double[] data = simpleValue.getAllDerivatives(); + data[0] = accurateValue; + return new DerivativeStructure(simpleValue.getFreeParameters(), simpleValue.getOrder(), data); + + } + + /** + * Compute a linear combination accurately. + *

+ * This method computes a1×b1 + + * a2×b2 + a3×b3 + + * a4×b4 + * to high accuracy. It does so by using specific multiplication and + * addition algorithms to preserve accuracy and reduce cancellation effects. + * It is based on the 2005 paper + * Accurate Sum and Dot Product by Takeshi Ogita, + * Siegfried M. Rump, and Shin'ichi Oishi published in SIAM J. Sci. Comput. + *

+ * @param a1 first factor of the first term + * @param b1 second factor of the first term + * @param a2 first factor of the second term + * @param b2 second factor of the second term + * @param a3 first factor of the third term + * @param b3 second factor of the third term + * @param a4 first factor of the third term + * @param b4 second factor of the third term + * @return a1×b1 + + * a2×b2 + a3×b3 + + * a4×b4 + * @see #linearCombination(double, DerivativeStructure, double, DerivativeStructure) + * @see #linearCombination(double, DerivativeStructure, double, DerivativeStructure, double, DerivativeStructure) + * @since 3.2 + */ + public static DerivativeStructure linearCombination(final double a1, final DerivativeStructure b1, + final double a2, final DerivativeStructure b2, + final double a3, final DerivativeStructure b3, + final double a4, final DerivativeStructure b4) { + + // compute an accurate value, taking care of cancellations + final double accurateValue = MathArrays.linearCombination(a1, b1.getValue(), + a2, b2.getValue(), + a3, b3.getValue(), + a4, b4.getValue()); + + // compute a simple value, with all partial derivatives + final DerivativeStructure simpleValue = b1.multiply(a1).add(b2.multiply(a2)).add(b3.multiply(a3)).add(b4.multiply(a4)); + + // create a result with accurate value and all derivatives (not necessarily as accurate as the value) + final double[] data = simpleValue.getAllDerivatives(); + data[0] = accurateValue; + return new DerivativeStructure(simpleValue.getFreeParameters(), simpleValue.getOrder(), data); + + } + /** * Returns true iff both arguments are null or have same dimensions and all * their elements are equal as defined by diff --git a/src/test/java/org/apache/commons/math3/util/MathArraysTest.java b/src/test/java/org/apache/commons/math3/util/MathArraysTest.java index 214a4cbf1..dcb5a8b96 100644 --- a/src/test/java/org/apache/commons/math3/util/MathArraysTest.java +++ b/src/test/java/org/apache/commons/math3/util/MathArraysTest.java @@ -14,6 +14,8 @@ package org.apache.commons.math3.util; import java.util.Arrays; + +import org.apache.commons.math3.analysis.differentiation.DerivativeStructure; import org.apache.commons.math3.exception.NonMonotonicSequenceException; import org.apache.commons.math3.exception.DimensionMismatchException; import org.apache.commons.math3.exception.NotPositiveException; @@ -537,6 +539,11 @@ public class MathArraysTest { final double abSumArray = MathArrays.linearCombination(a, b); Assert.assertEquals(abSumInline, abSumArray, 0); + Assert.assertEquals(-1.8551294182586248737720779899, abSumInline, 1.0e-15); + + final double naive = a[0] * b[0] + a[1] * b[1] + a[2] * b[2]; + Assert.assertTrue(FastMath.abs(naive - abSumInline) > 1.5); + } @Test @@ -713,6 +720,149 @@ public class MathArraysTest { Assert.assertTrue(Double.isNaN(MathArrays.linearCombination(a[7], b[7]))); } + @Test + public void testLinearCombination1DSDS() { + final DerivativeStructure[] a = new DerivativeStructure[] { + new DerivativeStructure(6, 1, 0, -1321008684645961.0 / 268435456.0), + new DerivativeStructure(6, 1, 1, -5774608829631843.0 / 268435456.0), + new DerivativeStructure(6, 1, 2, -7645843051051357.0 / 8589934592.0) + }; + final DerivativeStructure[] b = new DerivativeStructure[] { + new DerivativeStructure(6, 1, 3, -5712344449280879.0 / 2097152.0), + new DerivativeStructure(6, 1, 4, -4550117129121957.0 / 2097152.0), + new DerivativeStructure(6, 1, 5, 8846951984510141.0 / 131072.0) + }; + + final DerivativeStructure abSumInline = MathArrays.linearCombination(a[0], b[0], + a[1], b[1], + a[2], b[2]); + final DerivativeStructure abSumArray = MathArrays.linearCombination(a, b); + + Assert.assertEquals(abSumInline.getValue(), abSumArray.getValue(), 0); + Assert.assertEquals(-1.8551294182586248737720779899, abSumInline.getValue(), 1.0e-15); + Assert.assertEquals(b[0].getValue(), abSumInline.getPartialDerivative(1, 0, 0, 0, 0, 0), 1.0e-15); + Assert.assertEquals(b[1].getValue(), abSumInline.getPartialDerivative(0, 1, 0, 0, 0, 0), 1.0e-15); + Assert.assertEquals(b[2].getValue(), abSumInline.getPartialDerivative(0, 0, 1, 0, 0, 0), 1.0e-15); + Assert.assertEquals(a[0].getValue(), abSumInline.getPartialDerivative(0, 0, 0, 1, 0, 0), 1.0e-15); + Assert.assertEquals(a[1].getValue(), abSumInline.getPartialDerivative(0, 0, 0, 0, 1, 0), 1.0e-15); + Assert.assertEquals(a[2].getValue(), abSumInline.getPartialDerivative(0, 0, 0, 0, 0, 1), 1.0e-15); + + } + + @Test + public void testLinearCombination1DoubleDS() { + final double[] a = new double[] { + -1321008684645961.0 / 268435456.0, + -5774608829631843.0 / 268435456.0, + -7645843051051357.0 / 8589934592.0 + }; + final DerivativeStructure[] b = new DerivativeStructure[] { + new DerivativeStructure(3, 1, 0, -5712344449280879.0 / 2097152.0), + new DerivativeStructure(3, 1, 1, -4550117129121957.0 / 2097152.0), + new DerivativeStructure(3, 1, 2, 8846951984510141.0 / 131072.0) + }; + + final DerivativeStructure abSumInline = MathArrays.linearCombination(a[0], b[0], + a[1], b[1], + a[2], b[2]); + final DerivativeStructure abSumArray = MathArrays.linearCombination(a, b); + + Assert.assertEquals(abSumInline.getValue(), abSumArray.getValue(), 0); + Assert.assertEquals(-1.8551294182586248737720779899, abSumInline.getValue(), 1.0e-15); + Assert.assertEquals(a[0], abSumInline.getPartialDerivative(1, 0, 0), 1.0e-15); + Assert.assertEquals(a[1], abSumInline.getPartialDerivative(0, 1, 0), 1.0e-15); + Assert.assertEquals(a[2], abSumInline.getPartialDerivative(0, 0, 1), 1.0e-15); + + } + + @Test + public void testLinearCombination2DSDS() { + // we compare accurate versus naive dot product implementations + // on regular vectors (i.e. not extreme cases like in the previous test) + Well1024a random = new Well1024a(0xc6af886975069f11l); + + for (int i = 0; i < 10000; ++i) { + final DerivativeStructure[] u = new DerivativeStructure[4]; + final DerivativeStructure[] v = new DerivativeStructure[4]; + for (int j = 0; j < u.length; ++j) { + u[j] = new DerivativeStructure(u.length, 1, j, 1e17 * random.nextDouble()); + v[j] = new DerivativeStructure(u.length, 1, 1e17 * random.nextDouble()); + } + + DerivativeStructure lin = MathArrays.linearCombination(u[0], v[0], u[1], v[1]); + double ref = u[0].getValue() * v[0].getValue() + + u[1].getValue() * v[1].getValue(); + Assert.assertEquals(ref, lin.getValue(), 1.0e-15 * FastMath.abs(ref)); + Assert.assertEquals(v[0].getValue(), lin.getPartialDerivative(1, 0, 0, 0), 1.0e-15 * FastMath.abs(v[0].getValue())); + Assert.assertEquals(v[1].getValue(), lin.getPartialDerivative(0, 1, 0, 0), 1.0e-15 * FastMath.abs(v[1].getValue())); + + lin = MathArrays.linearCombination(u[0], v[0], u[1], v[1], u[2], v[2]); + ref = u[0].getValue() * v[0].getValue() + + u[1].getValue() * v[1].getValue() + + u[2].getValue() * v[2].getValue(); + Assert.assertEquals(ref, lin.getValue(), 1.0e-15 * FastMath.abs(ref)); + Assert.assertEquals(v[0].getValue(), lin.getPartialDerivative(1, 0, 0, 0), 1.0e-15 * FastMath.abs(v[0].getValue())); + Assert.assertEquals(v[1].getValue(), lin.getPartialDerivative(0, 1, 0, 0), 1.0e-15 * FastMath.abs(v[1].getValue())); + Assert.assertEquals(v[2].getValue(), lin.getPartialDerivative(0, 0, 1, 0), 1.0e-15 * FastMath.abs(v[2].getValue())); + + lin = MathArrays.linearCombination(u[0], v[0], u[1], v[1], u[2], v[2], u[3], v[3]); + ref = u[0].getValue() * v[0].getValue() + + u[1].getValue() * v[1].getValue() + + u[2].getValue() * v[2].getValue() + + u[3].getValue() * v[3].getValue(); + Assert.assertEquals(ref, lin.getValue(), 1.0e-15 * FastMath.abs(ref)); + Assert.assertEquals(v[0].getValue(), lin.getPartialDerivative(1, 0, 0, 0), 1.0e-15 * FastMath.abs(v[0].getValue())); + Assert.assertEquals(v[1].getValue(), lin.getPartialDerivative(0, 1, 0, 0), 1.0e-15 * FastMath.abs(v[1].getValue())); + Assert.assertEquals(v[2].getValue(), lin.getPartialDerivative(0, 0, 1, 0), 1.0e-15 * FastMath.abs(v[2].getValue())); + Assert.assertEquals(v[3].getValue(), lin.getPartialDerivative(0, 0, 0, 1), 1.0e-15 * FastMath.abs(v[3].getValue())); + + } + } + + @Test + public void testLinearCombination2DoubleDS() { + // we compare accurate versus naive dot product implementations + // on regular vectors (i.e. not extreme cases like in the previous test) + Well1024a random = new Well1024a(0xc6af886975069f11l); + + for (int i = 0; i < 10000; ++i) { + final double[] u = new double[4]; + final DerivativeStructure[] v = new DerivativeStructure[4]; + for (int j = 0; j < u.length; ++j) { + u[j] = 1e17 * random.nextDouble(); + v[j] = new DerivativeStructure(u.length, 1, j, 1e17 * random.nextDouble()); + } + + DerivativeStructure lin = MathArrays.linearCombination(u[0], v[0], u[1], v[1]); + double ref = u[0] * v[0].getValue() + + u[1] * v[1].getValue(); + Assert.assertEquals(ref, lin.getValue(), 1.0e-15 * FastMath.abs(ref)); + Assert.assertEquals(u[0], lin.getPartialDerivative(1, 0, 0, 0), 1.0e-15 * FastMath.abs(v[0].getValue())); + Assert.assertEquals(u[1], lin.getPartialDerivative(0, 1, 0, 0), 1.0e-15 * FastMath.abs(v[1].getValue())); + + lin = MathArrays.linearCombination(u[0], v[0], u[1], v[1], u[2], v[2]); + ref = u[0] * v[0].getValue() + + u[1] * v[1].getValue() + + u[2] * v[2].getValue(); + Assert.assertEquals(ref, lin.getValue(), 1.0e-15 * FastMath.abs(ref)); + Assert.assertEquals(u[0], lin.getPartialDerivative(1, 0, 0, 0), 1.0e-15 * FastMath.abs(v[0].getValue())); + Assert.assertEquals(u[1], lin.getPartialDerivative(0, 1, 0, 0), 1.0e-15 * FastMath.abs(v[1].getValue())); + Assert.assertEquals(u[2], lin.getPartialDerivative(0, 0, 1, 0), 1.0e-15 * FastMath.abs(v[2].getValue())); + + lin = MathArrays.linearCombination(u[0], v[0], u[1], v[1], u[2], v[2], u[3], v[3]); + ref = u[0] * v[0].getValue() + + u[1] * v[1].getValue() + + u[2] * v[2].getValue() + + u[3] * v[3].getValue(); + Assert.assertEquals(ref, lin.getValue(), 1.0e-15 * FastMath.abs(ref)); + Assert.assertEquals(u[0], lin.getPartialDerivative(1, 0, 0, 0), 1.0e-15 * FastMath.abs(v[0].getValue())); + Assert.assertEquals(u[1], lin.getPartialDerivative(0, 1, 0, 0), 1.0e-15 * FastMath.abs(v[1].getValue())); + Assert.assertEquals(u[2], lin.getPartialDerivative(0, 0, 1, 0), 1.0e-15 * FastMath.abs(v[2].getValue())); + Assert.assertEquals(u[3], lin.getPartialDerivative(0, 0, 0, 1), 1.0e-15 * FastMath.abs(v[3].getValue())); + + } + } + @Test public void testArrayEquals() { Assert.assertFalse(MathArrays.equals(new double[] { 1d }, null));