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 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. 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"> <action dev="erans" type="update" issue="MATH-933">
Throw "MathUnsupportedOperationException" from optimizers that do Throw "MathUnsupportedOperationException" from optimizers that do
not support constraints (previous behaviour was to silently ignore 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.Comparator;
import java.util.Collections; 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.DimensionMismatchException;
import org.apache.commons.math3.exception.MathInternalError; import org.apache.commons.math3.exception.MathInternalError;
import org.apache.commons.math3.exception.NonMonotonicSequenceException; import org.apache.commons.math3.exception.NonMonotonicSequenceException;
@ -1117,6 +1118,353 @@ public class MathArrays {
return result; 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 * Returns true iff both arguments are null or have same dimensions and all
* their elements are equal as defined by * their elements are equal as defined by

View File

@ -14,6 +14,8 @@
package org.apache.commons.math3.util; package org.apache.commons.math3.util;
import java.util.Arrays; 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.NonMonotonicSequenceException;
import org.apache.commons.math3.exception.DimensionMismatchException; import org.apache.commons.math3.exception.DimensionMismatchException;
import org.apache.commons.math3.exception.NotPositiveException; import org.apache.commons.math3.exception.NotPositiveException;
@ -537,6 +539,11 @@ public class MathArraysTest {
final double abSumArray = MathArrays.linearCombination(a, b); final double abSumArray = MathArrays.linearCombination(a, b);
Assert.assertEquals(abSumInline, abSumArray, 0); 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 @Test
@ -713,6 +720,149 @@ public class MathArraysTest {
Assert.assertTrue(Double.isNaN(MathArrays.linearCombination(a[7], b[7]))); 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 @Test
public void testArrayEquals() { public void testArrayEquals() {
Assert.assertFalse(MathArrays.equals(new double[] { 1d }, null)); Assert.assertFalse(MathArrays.equals(new double[] { 1d }, null));