Added accurate linear combinations for DerivativeStructure instances.

git-svn-id: https://svn.apache.org/repos/asf/commons/proper/math/trunk@1446210 13f79535-47bb-0310-9956-ffa450edef68
This commit is contained in:
Luc Maisonobe 2013-02-14 14:43:15 +00:00
parent 81eddba084
commit ef76ef299e
3 changed files with 502 additions and 0 deletions

View File

@ -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.
">
<action dev="luc" type="add" >
Added accurate linear combination of DerivativeStructure instances,
avoiding cancellation.
</action>
<action dev="erans" type="update" issue="MATH-933">
Throw "MathUnsupportedOperationException" from optimizers that do
not support constraints (previous behaviour was to silently ignore

View File

@ -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
* <code>a<sub>i</sub> b<sub>i</sub></code> to high accuracy.
* It does so by using specific multiplication and addition algorithms to
* preserve accuracy and reduce cancellation effects.
* <br/>
* It is based on the 2005 paper
* <a href="http://citeseerx.ist.psu.edu/viewdoc/summary?doi=10.1.1.2.1547">
* Accurate Sum and Dot Product</a> by Takeshi Ogita, Siegfried M. Rump,
* and Shin'ichi Oishi published in SIAM J. Sci. Comput.
*
* @param a Factors.
* @param b Factors.
* @return <code>&Sigma;<sub>i</sub> a<sub>i</sub> b<sub>i</sub></code>.
* @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
* <code>a<sub>i</sub> b<sub>i</sub></code> to high accuracy.
* It does so by using specific multiplication and addition algorithms to
* preserve accuracy and reduce cancellation effects.
* <br/>
* It is based on the 2005 paper
* <a href="http://citeseerx.ist.psu.edu/viewdoc/summary?doi=10.1.1.2.1547">
* Accurate Sum and Dot Product</a> by Takeshi Ogita, Siegfried M. Rump,
* and Shin'ichi Oishi published in SIAM J. Sci. Comput.
*
* @param a Factors.
* @param b Factors.
* @return <code>&Sigma;<sub>i</sub> a<sub>i</sub> b<sub>i</sub></code>.
* @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.
* <p>
* This method computes a<sub>1</sub>&times;b<sub>1</sub> +
* a<sub>2</sub>&times;b<sub>2</sub>
* 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 <a
* href="http://citeseerx.ist.psu.edu/viewdoc/summary?doi=10.1.1.2.1547">
* Accurate Sum and Dot Product</a> by Takeshi Ogita,
* Siegfried M. Rump, and Shin'ichi Oishi published in SIAM J. Sci. Comput.
* </p>
* @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 a<sub>1</sub>&times;b<sub>1</sub> +
* a<sub>2</sub>&times;b<sub>2</sub>
* @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.
* <p>
* This method computes a<sub>1</sub>&times;b<sub>1</sub> +
* a<sub>2</sub>&times;b<sub>2</sub>
* 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 <a
* href="http://citeseerx.ist.psu.edu/viewdoc/summary?doi=10.1.1.2.1547">
* Accurate Sum and Dot Product</a> by Takeshi Ogita,
* Siegfried M. Rump, and Shin'ichi Oishi published in SIAM J. Sci. Comput.
* </p>
* @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 a<sub>1</sub>&times;b<sub>1</sub> +
* a<sub>2</sub>&times;b<sub>2</sub>
* @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.
* <p>
* This method computes a<sub>1</sub>&times;b<sub>1</sub> +
* a<sub>2</sub>&times;b<sub>2</sub> + a<sub>3</sub>&times;b<sub>3</sub>
* 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 <a
* href="http://citeseerx.ist.psu.edu/viewdoc/summary?doi=10.1.1.2.1547">
* Accurate Sum and Dot Product</a> by Takeshi Ogita,
* Siegfried M. Rump, and Shin'ichi Oishi published in SIAM J. Sci. Comput.
* </p>
* @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 a<sub>1</sub>&times;b<sub>1</sub> +
* a<sub>2</sub>&times;b<sub>2</sub> + a<sub>3</sub>&times;b<sub>3</sub>
* @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.
* <p>
* This method computes a<sub>1</sub>&times;b<sub>1</sub> +
* a<sub>2</sub>&times;b<sub>2</sub> + a<sub>3</sub>&times;b<sub>3</sub>
* 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 <a
* href="http://citeseerx.ist.psu.edu/viewdoc/summary?doi=10.1.1.2.1547">
* Accurate Sum and Dot Product</a> by Takeshi Ogita,
* Siegfried M. Rump, and Shin'ichi Oishi published in SIAM J. Sci. Comput.
* </p>
* @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 a<sub>1</sub>&times;b<sub>1</sub> +
* a<sub>2</sub>&times;b<sub>2</sub> + a<sub>3</sub>&times;b<sub>3</sub>
* @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.
* <p>
* This method computes a<sub>1</sub>&times;b<sub>1</sub> +
* a<sub>2</sub>&times;b<sub>2</sub> + a<sub>3</sub>&times;b<sub>3</sub> +
* a<sub>4</sub>&times;b<sub>4</sub>
* 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 <a
* href="http://citeseerx.ist.psu.edu/viewdoc/summary?doi=10.1.1.2.1547">
* Accurate Sum and Dot Product</a> by Takeshi Ogita,
* Siegfried M. Rump, and Shin'ichi Oishi published in SIAM J. Sci. Comput.
* </p>
* @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 a<sub>1</sub>&times;b<sub>1</sub> +
* a<sub>2</sub>&times;b<sub>2</sub> + a<sub>3</sub>&times;b<sub>3</sub> +
* a<sub>4</sub>&times;b<sub>4</sub>
* @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.
* <p>
* This method computes a<sub>1</sub>&times;b<sub>1</sub> +
* a<sub>2</sub>&times;b<sub>2</sub> + a<sub>3</sub>&times;b<sub>3</sub> +
* a<sub>4</sub>&times;b<sub>4</sub>
* 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 <a
* href="http://citeseerx.ist.psu.edu/viewdoc/summary?doi=10.1.1.2.1547">
* Accurate Sum and Dot Product</a> by Takeshi Ogita,
* Siegfried M. Rump, and Shin'ichi Oishi published in SIAM J. Sci. Comput.
* </p>
* @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 a<sub>1</sub>&times;b<sub>1</sub> +
* a<sub>2</sub>&times;b<sub>2</sub> + a<sub>3</sub>&times;b<sub>3</sub> +
* a<sub>4</sub>&times;b<sub>4</sub>
* @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

View File

@ -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));