allow zero length vectors

JIRA: MATH-391

git-svn-id: https://svn.apache.org/repos/asf/commons/proper/math/branches/MATH_2_X@1003993 13f79535-47bb-0310-9956-ffa450edef68
This commit is contained in:
Luc Maisonobe 2010-10-03 16:39:16 +00:00
parent 6793b921a0
commit 1b9e8dd09f
5 changed files with 112 additions and 29 deletions

View File

@ -79,8 +79,15 @@ public class ArrayFieldVector<T extends FieldElement<T>> implements FieldVector<
/** /**
* Construct a vector from an array, copying the input array. * Construct a vector from an array, copying the input array.
* <p>
* This constructor need a non-empty {@code d} array to retrieve
* the field from its first element. This implies it cannot build
* 0 length vectors. To build vectors from any size, one should
* use the {@link #ArrayFieldVector(Field, FieldElement[])} constructor.
* </p>
* @param d array of Ts. * @param d array of Ts.
* @throws IllegalArgumentException if <code>d</code> is empty * @throws IllegalArgumentException if <code>d</code> is empty
* @see #ArrayFieldVector(Field, FieldElement[])
*/ */
public ArrayFieldVector(T[] d) public ArrayFieldVector(T[] d)
throws IllegalArgumentException { throws IllegalArgumentException {
@ -93,6 +100,17 @@ public class ArrayFieldVector<T extends FieldElement<T>> implements FieldVector<
} }
} }
/**
* Construct a vector from an array, copying the input array.
* @param field field to which the elements belong
* @param d array of Ts.
* @see #ArrayFieldVector(FieldElement[])
*/
public ArrayFieldVector(Field<T> field, T[] d) {
this.field = field;
data = d.clone();
}
/** /**
* Create a new ArrayFieldVector using the input array as the underlying * Create a new ArrayFieldVector using the input array as the underlying
* data array. * data array.
@ -100,22 +118,46 @@ public class ArrayFieldVector<T extends FieldElement<T>> implements FieldVector<
* ArrayFieldVector and not used directly, the <code>copyArray</code> may be * ArrayFieldVector and not used directly, the <code>copyArray</code> may be
* set to <code>false</code. This will prevent the copying and improve * set to <code>false</code. This will prevent the copying and improve
* performance as no new array will be built and no data will be copied.</p> * performance as no new array will be built and no data will be copied.</p>
* <p>
* This constructor need a non-empty {@code d} array to retrieve
* the field from its first element. This implies it cannot build
* 0 length vectors. To build vectors from any size, one should
* use the {@link #ArrayFieldVector(Field, FieldElement[], boolean)} constructor.
* </p>
* @param d data for new vector * @param d data for new vector
* @param copyArray if true, the input array will be copied, otherwise * @param copyArray if true, the input array will be copied, otherwise
* it will be referenced * it will be referenced
* @throws IllegalArgumentException if <code>d</code> is empty * @throws IllegalArgumentException if <code>d</code> is empty
* @throws NullPointerException if <code>d</code> is null * @throws NullPointerException if <code>d</code> is null
* @see #ArrayFieldVector(FieldElement[]) * @see #ArrayFieldVector(FieldElement[])
* @see #ArrayFieldVector(Field, FieldElement[], boolean)
*/ */
public ArrayFieldVector(T[] d, boolean copyArray) public ArrayFieldVector(T[] d, boolean copyArray)
throws NullPointerException, IllegalArgumentException { throws NullPointerException, IllegalArgumentException {
try { if (d.length == 0) {
field = d[0].getField();
data = copyArray ? d.clone() : d;
} catch (ArrayIndexOutOfBoundsException e) {
throw MathRuntimeException.createIllegalArgumentException( throw MathRuntimeException.createIllegalArgumentException(
LocalizedFormats.VECTOR_MUST_HAVE_AT_LEAST_ONE_ELEMENT); LocalizedFormats.VECTOR_MUST_HAVE_AT_LEAST_ONE_ELEMENT);
} }
field = d[0].getField();
data = copyArray ? d.clone() : d;
}
/**
* Create a new ArrayFieldVector using the input array as the underlying
* data array.
* <p>If an array is built specially in order to be embedded in a
* ArrayFieldVector and not used directly, the <code>copyArray</code> may be
* set to <code>false</code. This will prevent the copying and improve
* performance as no new array will be built and no data will be copied.</p>
* @param field field to which the elements belong
* @param d data for new vector
* @param copyArray if true, the input array will be copied, otherwise
* it will be referenced
* @see #ArrayFieldVector(FieldElement[], boolean)
*/
public ArrayFieldVector(Field<T> field, T[] d, boolean copyArray) {
this.field = field;
data = copyArray ? d.clone() : d;
} }
/** /**
@ -204,9 +246,16 @@ public class ArrayFieldVector<T extends FieldElement<T>> implements FieldVector<
/** /**
* Construct a vector by appending one vector to another vector. * Construct a vector by appending one vector to another vector.
* <p>
* This constructor need at least one non-empty array to retrieve
* the field from its first element. This implies it cannot build
* 0 length vectors. To build vectors from any size, one should
* use the {@link #ArrayFieldVector(Field, FieldElement[], FieldElement[])} constructor.
* </p>
* @param v1 first vector (will be put in front of the new vector) * @param v1 first vector (will be put in front of the new vector)
* @param v2 second vector (will be put at back of the new vector) * @param v2 second vector (will be put at back of the new vector)
* @exception IllegalArgumentException if both vectors are empty * @exception IllegalArgumentException if both vectors are empty
* @see #ArrayFieldVector(Field, FieldElement[], FieldElement[])
*/ */
public ArrayFieldVector(T[] v1, T[] v2) { public ArrayFieldVector(T[] v1, T[] v2) {
try { try {
@ -220,6 +269,24 @@ public class ArrayFieldVector<T extends FieldElement<T>> implements FieldVector<
} }
} }
/**
* Construct a vector by appending one vector to another vector.
* @param field field to which the elements belong
* @param v1 first vector (will be put in front of the new vector)
* @param v2 second vector (will be put at back of the new vector)
* @see #ArrayFieldVector(FieldElement[], FieldElement[])
*/
public ArrayFieldVector(Field<T> field, T[] v1, T[] v2) {
if (v1.length + v2.length == 0) {
throw MathRuntimeException.createIllegalArgumentException(
LocalizedFormats.VECTOR_MUST_HAVE_AT_LEAST_ONE_ELEMENT);
}
data = buildArray(v1.length + v2.length);
System.arraycopy(v1, 0, data, 0, v1.length);
System.arraycopy(v2, 0, data, v1.length, v2.length);
this.field = data[0].getField();
}
/** Build an array of elements. /** Build an array of elements.
* @param length size of the array to build * @param length size of the array to build
* @return a new array * @return a new array

View File

@ -91,18 +91,9 @@ public class ArrayRealVector extends AbstractRealVector implements Serializable
* @param d data for new vector * @param d data for new vector
* @param copyArray if true, the input array will be copied, otherwise * @param copyArray if true, the input array will be copied, otherwise
* it will be referenced * it will be referenced
* @throws IllegalArgumentException if <code>d</code> is empty
* @throws NullPointerException if <code>d</code> is null
* @see #ArrayRealVector(double[]) * @see #ArrayRealVector(double[])
*/ */
public ArrayRealVector(double[] d, boolean copyArray) public ArrayRealVector(double[] d, boolean copyArray) {
throws NullPointerException, IllegalArgumentException {
if (d == null) {
throw new NullPointerException();
}
if (d.length == 0) {
throw MathRuntimeException.createIllegalArgumentException(LocalizedFormats.VECTOR_MUST_HAVE_AT_LEAST_ONE_ELEMENT);
}
data = copyArray ? d.clone() : d; data = copyArray ? d.clone() : d;
} }

View File

@ -52,6 +52,9 @@ The <action> type attribute can be add,update,fix,remove.
If the output is not quite correct, check for invisible trailing spaces! If the output is not quite correct, check for invisible trailing spaces!
--> -->
<release version="2.2" date="TBD" description="TBD"> <release version="2.2" date="TBD" description="TBD">
<action dev="luc" type="fix" issue="MATH-391">
Fixed an error preventing zero length vectors to be built by some constructors
</action>
<action dev="luc" type="fix" issue="MATH-421"> <action dev="luc" type="fix" issue="MATH-421">
Fixed an error preventing ODE solvers to be restarted after they have been stopped by a discrete event Fixed an error preventing ODE solvers to be restarted after they have been stopped by a discrete event
</action> </action>

View File

@ -590,6 +590,35 @@ public class ArrayFieldVectorTest extends TestCase {
assertEquals(v,TestUtils.serializeAndRecover(v)); assertEquals(v,TestUtils.serializeAndRecover(v));
} }
public void testZeroVectors() {
// when the field is not specified, array cannot be empty
try {
new ArrayFieldVector<Fraction>(new Fraction[0]);
fail("IllegalArgumentException expected");
} catch (IllegalArgumentException ex) {
// expected behavior
}
try {
new ArrayFieldVector<Fraction>(new Fraction[0], true);
fail("IllegalArgumentException expected");
} catch (IllegalArgumentException ex) {
// expected behavior
}
try {
new ArrayFieldVector<Fraction>(new Fraction[0], false);
fail("IllegalArgumentException expected");
} catch (IllegalArgumentException ex) {
// expected behavior
}
// when the field is specified, array can be empty
assertEquals(0, new ArrayFieldVector<Fraction>(FractionField.getInstance(), new Fraction[0]).getDimension());
assertEquals(0, new ArrayFieldVector<Fraction>(FractionField.getInstance(), new Fraction[0], true).getDimension());
assertEquals(0, new ArrayFieldVector<Fraction>(FractionField.getInstance(), new Fraction[0], false).getDimension());
}
/** verifies that two vectors are equals */ /** verifies that two vectors are equals */
protected void checkArray(String msg, Fraction[] m, Fraction[] n) { protected void checkArray(String msg, Fraction[] m, Fraction[] n) {
if (m.length != n.length) { if (m.length != n.length) {

View File

@ -24,6 +24,8 @@ import junit.framework.TestCase;
import org.apache.commons.math.FunctionEvaluationException; import org.apache.commons.math.FunctionEvaluationException;
import org.apache.commons.math.TestUtils; import org.apache.commons.math.TestUtils;
import org.apache.commons.math.analysis.UnivariateRealFunction; import org.apache.commons.math.analysis.UnivariateRealFunction;
import org.apache.commons.math.fraction.Fraction;
import org.apache.commons.math.fraction.FractionField;
import org.apache.commons.math.util.FastMath; import org.apache.commons.math.util.FastMath;
/** /**
@ -607,20 +609,6 @@ public class ArrayRealVectorTest extends TestCase {
assertEquals("testData is 9.0 ", 9.0, v14.getEntry(2)); assertEquals("testData is 9.0 ", 9.0, v14.getEntry(2));
assertEquals("testData is 1.0 ", 1.0, v14.getEntry(3)); assertEquals("testData is 1.0 ", 1.0, v14.getEntry(3));
try {
new ArrayRealVector((double[]) null, false);
fail("expected exception");
} catch (NullPointerException npe) {
// expected
}
try {
new ArrayRealVector(new double[0], false);
fail("expected exception");
} catch (IllegalArgumentException iae) {
// expected
}
} }
public void testDataInOut() { public void testDataInOut() {
@ -1280,6 +1268,11 @@ public class ArrayRealVectorTest extends TestCase {
assertEquals(v,TestUtils.serializeAndRecover(v)); assertEquals(v,TestUtils.serializeAndRecover(v));
} }
public void testZeroVectors() {
assertEquals(0, new ArrayRealVector(new double[0]).getDimension());
assertEquals(0, new ArrayRealVector(new double[0], true).getDimension());
assertEquals(0, new ArrayRealVector(new double[0], false).getDimension());
}
public void testMinMax() { public void testMinMax() {
ArrayRealVector v1 = new ArrayRealVector(new double[] { 0, -6, 4, 12, 7 }); ArrayRealVector v1 = new ArrayRealVector(new double[] { 0, -6, 4, 12, 7 });