Linear combination of vectors.


git-svn-id: https://svn.apache.org/repos/asf/commons/proper/math/trunk@1151665 13f79535-47bb-0310-9956-ffa450edef68
This commit is contained in:
Gilles Sadowski 2011-07-27 23:26:45 +00:00
parent 86835c1471
commit 4f7b6d2d75
6 changed files with 510 additions and 18 deletions

View File

@ -514,6 +514,32 @@ public abstract class AbstractRealVector implements RealVector {
return this;
}
/** {@inheritDoc} */
public RealVector combine(double a, double b, double[] y) {
return copy().combineToSelf(a, b, y);
}
/** {@inheritDoc} */
public RealVector combine(double a, double b, RealVector y) {
return copy().combineToSelf(a, b, y);
}
/** {@inheritDoc} */
public RealVector combineToSelf(double a, double b, double[] y) {
return combineToSelf(a, b, new ArrayRealVector(y, false));
}
/** {@inheritDoc} */
public RealVector combineToSelf(double a, double b, RealVector y) {
checkVectorDimensions(y);
for (int i = 0; i < getDimension(); i++) {
final double xi = getEntry(i);
final double yi = y.getEntry(i);
setEntry(i, a * xi + b * yi);
}
return this;
}
/** An entry in the vector. */
protected class EntryImpl extends Entry {

View File

@ -1045,4 +1045,60 @@ public class ArrayRealVector extends AbstractRealVector implements Serializable
}
return MathUtils.hash(data);
}
/**
* Returns the linear combination of {@code this} and {@code y}.
*
* @param a Weight of {@code this}.
* @param b Weight of {@code y}.
* @param y Vector with which {@code this} is linearly combined.
* @return a vector containing {@code a * this[i] + b * y[i]} for all
* {@code i}.
* @throws org.apache.commons.math.exception.DimensionMismatchException
* if {@code y} is not the same size as this vector.
*/
public ArrayRealVector combine(double a, double b, ArrayRealVector y) {
return (ArrayRealVector) copy().combineToSelf(a, b, y.data);
}
/** {@inheritDoc} */
@Override
public RealVector combineToSelf(double a, double b, double[] y) {
checkVectorDimensions(y.length);
for (int i = 0; i < this.data.length; i++) {
data[i] = a * data[i] + b * y[i];
}
return this;
}
/**
* Updates {@code this} with the linear combination of {@code this} and
* {@code y}.
*
* @param a Weight of {@code this}.
* @param b Weight of {@code y}.
* @param y Vector with which {@code this} is linearly combined.
* @return {@code this}, with components equal to
* {@code a * this[i] + b * y[i]} for all {@code i}.
* @throws org.apache.commons.math.exception.DimensionMismatchException
* if {@code y} is not the same size as this vector.
*/
public ArrayRealVector combineToSelf(double a, double b, ArrayRealVector y) {
combineToSelf(a, b, y.data);
return this;
}
/** {@inheritDoc} */
@Override
public RealVector combineToSelf(double a, double b, RealVector y) {
if (y instanceof ArrayRealVector) {
return combineToSelf(a, b, ((ArrayRealVector) y).data);
} else {
checkVectorDimensions(y);
for (int i = 0; i < this.data.length; i++) {
data[i] = a * data[i] + b * y.getEntry(i);
}
return this;
}
}
}

View File

@ -597,4 +597,58 @@ public interface RealVector {
* none are {@code NaN}, {@code false} otherwise.
*/
boolean isInfinite();
/**
* Returns the linear combination of {@code this} and {@code y}.
*
* @param a Weight of {@code this}.
* @param b Weight of {@code y}.
* @param y Vector with which {@code this} is linearly combined.
* @return a vector containing {@code a * this[i] + b * y[i]} for all
* {@code i}.
* @throws org.apache.commons.math.exception.DimensionMismatchException
* if {@code y} is not the same size as this vector.
*/
RealVector combine(double a, double b, double[] y);
/**
* Returns the linear combination of {@code this} and {@code y}.
*
* @param a Weight of {@code this}.
* @param b Weight of {@code y}.
* @param y Vector with which {@code this} is linearly combined.
* @return a vector containing {@code a * this[i] + b * y[i]} for all
* {@code i}.
* @throws org.apache.commons.math.exception.DimensionMismatchException
* if {@code y} is not the same size as this vector.
*/
RealVector combine(double a, double b, RealVector y);
/**
* Updates {@code this} with the linear combination of {@code this} and
* {@code y}.
*
* @param a Weight of {@code this}.
* @param b Weight of {@code y}.
* @param y Vector with which {@code this} is linearly combined.
* @return {@code this}, with components equal to
* {@code a * this[i] + b * y[i]} for all {@code i}.
* @throws org.apache.commons.math.exception.DimensionMismatchException
* if {@code y} is not the same size as this vector.
*/
RealVector combineToSelf(double a, double b, double[] y);
/**
* Updates {@code this} with the linear combination of {@code this} and
* {@code y}.
*
* @param a Weight of {@code this}.
* @param b Weight of {@code y}.
* @param y Vector with which {@code this} is linearly combined.
* @return {@code this}, with components equal to
* {@code a * this[i] + b * y[i]} for all {@code i}.
* @throws org.apache.commons.math.exception.DimensionMismatchException
* if {@code y} is not the same size as this vector.
*/
RealVector combineToSelf(double a, double b, RealVector y);
}

View File

@ -52,6 +52,10 @@ The <action> type attribute can be add,update,fix,remove.
If the output is not quite correct, check for invisible trailing spaces!
-->
<release version="3.0" date="TBD" description="TBD">
<action dev="erans" type="add" issue="MATH-613" due-to="Sébastien Brisard">
Linear combination of vectors: "RealVector" interface updated, implemented
in "AbstractRealVector" and "ArrayRealVector".
</action>
<action dev="erans" type="update" issue="MATH-623" due-to="Arne Plöse">
Slightly more efficient implementation of basic operations in
"ArrayRealVector".

View File

@ -20,6 +20,7 @@ package org.apache.commons.math.linear;
import org.junit.Test;
import org.junit.Assert;
import org.apache.commons.math.analysis.UnivariateRealFunction;
import org.apache.commons.math.exception.DimensionMismatchException;
import org.apache.commons.math.linear.RealVector.Entry;
import java.util.Iterator;
import java.util.Random;
@ -200,7 +201,7 @@ public class AbstractRealVectorTest {
for(Iterator<Entry> it = v.sparseIterator(); it.hasNext() && (e = it.next()) != null; ) {
Assert.assertEquals(onlyOne[1], e.getValue(), 0);
}
}
@Test
@ -216,4 +217,86 @@ public class AbstractRealVectorTest {
Assert.assertEquals(new ArrayRealVector(d).getNorm(), new ArrayRealVector(c).getNorm(), 0);
}
@Test(expected=DimensionMismatchException.class)
public void testCombinePrecondition() {
final double a = 1d;
final double b = 2d;
double[] aux = new double[] { 3d, 4d, 5d };
final TestVectorImpl x = new TestVectorImpl(aux);
aux = new double[] { 6d, 7d };
final TestVectorImpl y = new TestVectorImpl(aux);
x.combine(a, b, y);
}
@Test
public void testCombine() {
final Random random = new Random(20110726);
final int dim = 10;
final double a = (2 * random.nextDouble() - 1);
final double b = (2 * random.nextDouble() - 1);
final RealVector x = new TestVectorImpl(new double[dim]);
final RealVector y = new TestVectorImpl(new double[dim]);
final double[] expected = new double[dim];
for (int i = 0; i < dim; i++) {
final double xi = 2 * random.nextDouble() - 1;
final double yi = 2 * random.nextDouble() - 1;
x.setEntry(i, xi);
y.setEntry(i, yi);
expected[i] = a * xi + b * yi;
}
final RealVector z = x.combine(a, b, y);
Assert.assertTrue(z != x);
final double[] actual = z.getData();
for (int i = 0; i < dim; i++) {
final double delta;
if (expected[i] == 0d) {
delta = Math.ulp(1d);
} else {
delta = Math.ulp(expected[i]);
}
Assert.assertEquals("elements [" + i + "] differ", expected[i],
actual[i], delta);
}
}
@Test(expected=DimensionMismatchException.class)
public void testCombineToSelfPrecondition() {
final double a = 1d;
final double b = 2d;
double[] aux = new double[] { 3d, 4d, 5d };
final TestVectorImpl x = new TestVectorImpl(aux);
aux = new double[] { 6d, 7d };
final TestVectorImpl y = new TestVectorImpl(aux);
x.combineToSelf(a, b, y);
}
@Test
public void testCombineToSelf() {
final Random random = new Random(20110726);
final int dim = 10;
final double a = (2 * random.nextDouble() - 1);
final double b = (2 * random.nextDouble() - 1);
final RealVector x = new TestVectorImpl(new double[dim]);
final RealVector y = new TestVectorImpl(new double[dim]);
final double[] expected = new double[dim];
for (int i = 0; i < dim; i++) {
final double xi = 2 * random.nextDouble() - 1;
final double yi = 2 * random.nextDouble() - 1;
x.setEntry(i, xi);
y.setEntry(i, yi);
expected[i] = a * xi + b * yi;
}
Assert.assertSame(x, x.combineToSelf(a, b, y));
final double[] actual = x.getData();
for (int i = 0; i < dim; i++) {
final double delta;
if (expected[i] == 0d) {
delta = Math.ulp(1d);
} else {
delta = Math.ulp(expected[i]);
}
Assert.assertEquals("elements [" + i + "] differ", expected[i],
actual[i], delta);
}
}
}

View File

@ -18,40 +18,41 @@ package org.apache.commons.math.linear;
import java.io.Serializable;
import java.util.Iterator;
import org.junit.Assert;
import org.junit.Test;
import java.util.Random;
import org.apache.commons.math.TestUtils;
import org.apache.commons.math.analysis.UnivariateRealFunction;
import org.apache.commons.math.util.FastMath;
import org.apache.commons.math.exception.OutOfRangeException;
import org.apache.commons.math.exception.MathIllegalArgumentException;
import org.apache.commons.math.exception.MathArithmeticException;
import org.apache.commons.math.exception.DimensionMismatchException;
import org.apache.commons.math.analysis.function.Abs;
import org.apache.commons.math.analysis.function.Acos;
import org.apache.commons.math.analysis.function.Asin;
import org.apache.commons.math.analysis.function.Atan;
import org.apache.commons.math.analysis.function.Cbrt;
import org.apache.commons.math.analysis.function.Cosh;
import org.apache.commons.math.analysis.function.Ceil;
import org.apache.commons.math.analysis.function.Cos;
import org.apache.commons.math.analysis.function.Cosh;
import org.apache.commons.math.analysis.function.Exp;
import org.apache.commons.math.analysis.function.Expm1;
import org.apache.commons.math.analysis.function.Floor;
import org.apache.commons.math.analysis.function.Inverse;
import org.apache.commons.math.analysis.function.Log;
import org.apache.commons.math.analysis.function.Log10;
import org.apache.commons.math.analysis.function.Log1p;
import org.apache.commons.math.analysis.function.Log;
import org.apache.commons.math.analysis.function.Sinh;
import org.apache.commons.math.analysis.function.Sin;
import org.apache.commons.math.analysis.function.Sqrt;
import org.apache.commons.math.analysis.function.Tanh;
import org.apache.commons.math.analysis.function.Tan;
import org.apache.commons.math.analysis.function.Floor;
import org.apache.commons.math.analysis.function.Ceil;
import org.apache.commons.math.analysis.function.Power;
import org.apache.commons.math.analysis.function.Rint;
import org.apache.commons.math.analysis.function.Signum;
import org.apache.commons.math.analysis.function.Sin;
import org.apache.commons.math.analysis.function.Sinh;
import org.apache.commons.math.analysis.function.Sqrt;
import org.apache.commons.math.analysis.function.Tan;
import org.apache.commons.math.analysis.function.Tanh;
import org.apache.commons.math.analysis.function.Ulp;
import org.apache.commons.math.analysis.function.Power;
import org.apache.commons.math.exception.DimensionMismatchException;
import org.apache.commons.math.exception.MathArithmeticException;
import org.apache.commons.math.exception.MathIllegalArgumentException;
import org.apache.commons.math.exception.OutOfRangeException;
import org.apache.commons.math.util.FastMath;
import org.junit.Assert;
import org.junit.Test;
/**
* Test cases for the {@link ArrayRealVector} class.
@ -342,6 +343,21 @@ public class ArrayRealVectorTest {
throw unsupported();
}
public RealVector combine(double a, double b, double[] y) {
throw unsupported();
}
public RealVector combine(double a, double b, RealVector y) {
throw unsupported();
}
public RealVector combineToSelf(double a, double b, double[] y) {
throw unsupported();
}
public RealVector combineToSelf(double a, double b, RealVector y) {
throw unsupported();
}
}
@Test
@ -1206,6 +1222,259 @@ public class ArrayRealVectorTest {
Assert.assertEquals(6, uv.getEntry(2, 1), tol);
}
@Test(expected=DimensionMismatchException.class)
public void testCombinePreconditionArray() {
final double a = 1d;
final double b = 2d;
double[] aux = new double[] { 3d, 4d, 5d };
final RealVector x = new ArrayRealVector(aux, false);
final double[] y = new double[] { 6d, 7d };
x.combine(a, b, y);
}
@Test
public void testCombineArray() {
final Random random = new Random(20110726);
final int dim = 10;
final double a = (2 * random.nextDouble() - 1);
final double b = (2 * random.nextDouble() - 1);
final RealVector x = new ArrayRealVector(dim);
final double[] y = new double[dim];
final double[] expected = new double[dim];
for (int i = 0; i < dim; i++) {
final double xi = 2 * random.nextDouble() - 1;
final double yi = 2 * random.nextDouble() - 1;
x.setEntry(i, xi);
y[i] = yi;
expected[i] = a * xi + b * yi;
}
final double[] actual = x.combine(a, b, y).getData();
for (int i = 0; i < dim; i++) {
final double delta;
if (expected[i] == 0d) {
delta = Math.ulp(1d);
} else {
delta = Math.ulp(expected[i]);
}
Assert.assertEquals("elements [" + i + "] differ",
expected[i],
actual[i],
delta);
}
}
@Test(expected=DimensionMismatchException.class)
public void testCombinePreconditionSameType() {
final double a = 1d;
final double b = 2d;
double[] aux = new double[] { 3d, 4d, 5d };
final RealVector x = new ArrayRealVector(aux, false);
aux = new double[] { 6d, 7d };
final RealVector y = new ArrayRealVector(aux, false);
x.combine(a, b, y);
}
@Test
public void testCombineSameType() {
final Random random = new Random(20110726);
final int dim = 10;
final double a = (2 * random.nextDouble() - 1);
final double b = (2 * random.nextDouble() - 1);
final RealVector x = new ArrayRealVector(dim);
final RealVector y = new ArrayRealVector(dim);
final double[] expected = new double[dim];
for (int i = 0; i < dim; i++) {
final double xi = 2 * random.nextDouble() - 1;
final double yi = 2 * random.nextDouble() - 1;
x.setEntry(i, xi);
y.setEntry(i, yi);
expected[i] = a * xi + b * yi;
}
final double[] actual = x.combine(a, b, y).getData();
for (int i = 0; i < dim; i++) {
final double delta;
if (expected[i] == 0d) {
delta = Math.ulp(1d);
} else {
delta = Math.ulp(expected[i]);
}
Assert.assertEquals("elements [" + i + "] differ",
expected[i],
actual[i],
delta);
}
}
@Test(expected=DimensionMismatchException.class)
public void testCombinePreconditionMixedType() {
final double a = 1d;
final double b = 2d;
double[] aux = new double[] { 3d, 4d, 5d };
final RealVector x = new ArrayRealVector(aux, false);
aux = new double[] { 6d, 7d };
final RealVector y = new OpenMapRealVector(aux);
x.combine(a, b, y);
}
@Test
public void testCombineMixedTypes() {
final Random random = new Random(20110726);
final int dim = 10;
final double a = (2 * random.nextDouble() - 1);
final double b = (2 * random.nextDouble() - 1);
final RealVector x = new ArrayRealVector(dim);
final RealVector y = new OpenMapRealVector(dim, 0d);
final double[] expected = new double[dim];
for (int i = 0; i < dim; i++) {
final double xi = 2 * random.nextDouble() - 1;
final double yi = 2 * random.nextDouble() - 1;
x.setEntry(i, xi);
y.setEntry(i, yi);
expected[i] = a * xi + b * yi;
}
final double[] actual = x.combine(a, b, y).getData();
for (int i = 0; i < dim; i++) {
final double delta;
if (expected[i] == 0d) {
delta = Math.ulp(1d);
} else {
delta = Math.ulp(expected[i]);
}
Assert.assertEquals("elements [" + i + "] differ",
expected[i],
actual[i],
delta);
}
}
@Test(expected=DimensionMismatchException.class)
public void testCombineToSelfPreconditionArray() {
final double a = 1d;
final double b = 2d;
double[] aux = new double[] { 3d, 4d, 5d };
final RealVector x = new ArrayRealVector(aux, false);
final double[] y = new double[] { 6d, 7d };
x.combineToSelf(a, b, y);
}
@Test
public void testCombineToSelfArray() {
final Random random = new Random(20110726);
final int dim = 10;
final double a = (2 * random.nextDouble() - 1);
final double b = (2 * random.nextDouble() - 1);
final RealVector x = new ArrayRealVector(dim);
final double[] y = new double[dim];
final double[] expected = new double[dim];
for (int i = 0; i < dim; i++) {
final double xi = 2 * random.nextDouble() - 1;
final double yi = 2 * random.nextDouble() - 1;
x.setEntry(i, xi);
y[i] = yi;
expected[i] = a * xi + b * yi;
}
Assert.assertSame(x, x.combineToSelf(a, b, y));
final double[] actual = x.getData();
for (int i = 0; i < dim; i++) {
final double delta;
if (expected[i] == 0d) {
delta = Math.ulp(1d);
} else {
delta = Math.ulp(expected[i]);
}
Assert.assertEquals("elements [" + i + "] differ",
expected[i],
actual[i],
delta);
}
}
@Test(expected=DimensionMismatchException.class)
public void testCombineToSelfPreconditionSameType() {
final double a = 1d;
final double b = 2d;
double[] aux = new double[] { 3d, 4d, 5d };
final RealVector x = new ArrayRealVector(aux, false);
aux = new double[] { 6d, 7d };
final RealVector y = new ArrayRealVector(aux, false);
x.combineToSelf(a, b, y);
}
@Test
public void testCombineToSelfSameType() {
final Random random = new Random(20110726);
final int dim = 10;
final double a = (2 * random.nextDouble() - 1);
final double b = (2 * random.nextDouble() - 1);
final RealVector x = new ArrayRealVector(dim);
final RealVector y = new ArrayRealVector(dim);
final double[] expected = new double[dim];
for (int i = 0; i < dim; i++) {
final double xi = 2 * random.nextDouble() - 1;
final double yi = 2 * random.nextDouble() - 1;
x.setEntry(i, xi);
y.setEntry(i, yi);
expected[i] = a * xi + b * yi;
}
Assert.assertSame(x, x.combineToSelf(a, b, y));
final double[] actual = x.getData();
for (int i = 0; i < dim; i++) {
final double delta;
if (expected[i] == 0d) {
delta = Math.ulp(1d);
} else {
delta = Math.ulp(expected[i]);
}
Assert.assertEquals("elements [" + i + "] differ",
expected[i],
actual[i],
delta);
}
}
@Test(expected=DimensionMismatchException.class)
public void testCombineToSelfPreconditionMixedType() {
final double a = 1d;
final double b = 2d;
double[] aux = new double[] { 3d, 4d, 5d };
final RealVector x = new ArrayRealVector(aux, false);
aux = new double[] { 6d, 7d };
final RealVector y = new OpenMapRealVector(aux);
x.combineToSelf(a, b, y);
}
@Test
public void testCombineToSelfMixedTypes() {
final Random random = new Random(20110726);
final int dim = 10;
final double a = (2 * random.nextDouble() - 1);
final double b = (2 * random.nextDouble() - 1);
final RealVector x = new ArrayRealVector(dim);
final RealVector y = new OpenMapRealVector(dim, 0d);
final double[] expected = new double[dim];
for (int i = 0; i < dim; i++) {
final double xi = 2 * random.nextDouble() - 1;
final double yi = 2 * random.nextDouble() - 1;
x.setEntry(i, xi);
y.setEntry(i, yi);
expected[i] = a * xi + b * yi;
}
Assert.assertSame(x, x.combineToSelf(a, b, y));
final double[] actual = x.getData();
for (int i = 0; i < dim; i++) {
final double delta;
if (expected[i] == 0d) {
delta = Math.ulp(1d);
} else {
delta = Math.ulp(expected[i]);
}
Assert.assertEquals("elements [" + i + "] differ",
expected[i],
actual[i],
delta);
}
}
/** verifies that two vectors are close (sup norm) */
protected void assertClose(String msg, double[] m, double[] n,
double tolerance) {