diff --git a/src/main/java/org/apache/commons/math/linear/AbstractRealVector.java b/src/main/java/org/apache/commons/math/linear/AbstractRealVector.java new file mode 100644 index 000000000..ac16932c9 --- /dev/null +++ b/src/main/java/org/apache/commons/math/linear/AbstractRealVector.java @@ -0,0 +1,818 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package org.apache.commons.math.linear; + +import java.util.Iterator; + +import org.apache.commons.math.FunctionEvaluationException; +import org.apache.commons.math.MathRuntimeException; +import org.apache.commons.math.analysis.UnivariateRealFunction; +import org.apache.commons.math.analysis.UnivariateRealFunctions; + +/** + * This class provides default basic implementations for many methods in the + * {@link RealVector} interface with. + * @version $Revision$ $Date$ + * @since 2.1 + */ +public abstract class AbstractRealVector implements RealVector { + + /** + * Check if instance and specified vectors have the same dimension. + * @param v vector to compare instance with + * @exception IllegalArgumentException if the vectors do not + * have the same dimension + */ + protected void checkVectorDimensions(RealVector v) { + checkVectorDimensions(v.getDimension()); + } + + /** + * Check if instance dimension is equal to some expected value. + * + * @param n expected dimension. + * @exception IllegalArgumentException if the dimension is + * inconsistent with vector size + */ + protected void checkVectorDimensions(int n) + throws IllegalArgumentException { + double d = getDimension(); + if (d != n) { + throw MathRuntimeException.createIllegalArgumentException( + "vector length mismatch: got {0} but expected {1}", + d, n); + } + } + + /** + * Check if an index is valid. + * @param index index to check + * @exception MatrixIndexException if index is not valid + */ + protected void checkIndex(final int index) + throws MatrixIndexException { + if (index < 0 || index >= getDimension()) { + throw new MatrixIndexException( + "index {0} out of allowed range [{1}, {2}]", + index, 0, getDimension() - 1); + } + } + + /** {@inheritDoc} */ + public void setSubVector(int index, RealVector v) throws MatrixIndexException { + checkIndex(index); + checkIndex(index + v.getDimension() - 1); + setSubVector(index, v.getData()); + } + + /** {@inheritDoc} */ + public void setSubVector(int index, double[] v) throws MatrixIndexException { + checkIndex(index); + checkIndex(index + v.length - 1); + for (int i = 0; i < v.length; i++) { + setEntry(i + index, v[i]); + } + } + + /** {@inheritDoc} */ + public RealVector add(double[] v) throws IllegalArgumentException { + double[] result = v.clone(); + Iterator it = sparseIterator(); + Entry e; + while (it.hasNext() && (e = it.next()) != null) { + result[e.getIndex()] += e.getValue(); + } + return new ArrayRealVector(result, false); + } + + /** {@inheritDoc} */ + public RealVector add(RealVector v) throws IllegalArgumentException { + if (v instanceof ArrayRealVector) { + double[] values = ((ArrayRealVector)v).getDataRef(); + return add(values); + } + RealVector result = v.copy(); + Iterator it = sparseIterator(); + Entry e; + while (it.hasNext() && (e = it.next()) != null) { + final int index = e.getIndex(); + result.setEntry(index, e.getValue() + result.getEntry(index)); + } + return result; + } + + /** {@inheritDoc} */ + public RealVector subtract(double[] v) throws IllegalArgumentException { + double[] result = v.clone(); + Iterator it = sparseIterator(); + Entry e; + while (it.hasNext() && (e = it.next()) != null) { + final int index = e.getIndex(); + result[index] = e.getValue() - result[index]; + } + return new ArrayRealVector(result, false); + } + + /** {@inheritDoc} */ + public RealVector subtract(RealVector v) throws IllegalArgumentException { + if (v instanceof ArrayRealVector) { + double[] values = ((ArrayRealVector)v).getDataRef(); + return add(values); + } + RealVector result = v.copy(); + Iterator it = sparseIterator(); + Entry e; + while (it.hasNext() && (e = it.next()) != null) { + final int index = e.getIndex(); + v.setEntry(index, e.getValue() - result.getEntry(index)); + } + return result; + } + + /** {@inheritDoc} */ + public RealVector mapAdd(double d) { + return copy().mapAddToSelf(d); + } + + /** {@inheritDoc} */ + public RealVector mapAddToSelf(double d) { + if (d != 0) { + Iterator it = iterator(); + Entry e; + while (it.hasNext() && (e = it.next()) != null) { + e.setValue(e.getValue() + d); + } + } + return this; + } + + /** {@inheritDoc} */ + public abstract AbstractRealVector copy(); + + /** {@inheritDoc} */ + public double dotProduct(double[] v) throws IllegalArgumentException { + return dotProduct(new ArrayRealVector(v, false)); + } + + /** {@inheritDoc} */ + public double dotProduct(RealVector v) throws IllegalArgumentException { + checkVectorDimensions(v); + double d = 0; + Iterator it = sparseIterator(); + Entry e; + while (it.hasNext() && (e = it.next()) != null) { + d += e.getValue() * v.getEntry(e.getIndex()); + } + return d; + } + + /** {@inheritDoc} */ + public RealVector ebeDivide(double[] v) throws IllegalArgumentException { + return ebeDivide(new ArrayRealVector(v, false)); + } + + /** {@inheritDoc} */ + public RealVector ebeMultiply(double[] v) throws IllegalArgumentException { + return ebeMultiply(new ArrayRealVector(v, false)); + } + + /** {@inheritDoc} */ + public double getDistance(RealVector v) throws IllegalArgumentException { + checkVectorDimensions(v); + double d = 0; + Iterator it = sparseIterator(); + Entry e; + while (it.hasNext() && (e = it.next()) != null) { + final double diff = e.getValue() - v.getEntry(e.getIndex()); + d += diff * diff; + } + return Math.sqrt(d); + } + + /** {@inheritDoc} */ + public double getDistance(double[] v) throws IllegalArgumentException { + checkVectorDimensions(v.length); + double d = 0; + Iterator it = iterator(); + Entry e; + while (it.hasNext() && (e = it.next()) != null) { + final double diff = e.getValue() - v[e.getIndex()]; + d += diff * diff; + } + return Math.sqrt(d); + } + + /** {@inheritDoc} */ + public double getL1Distance(RealVector v) throws IllegalArgumentException { + checkVectorDimensions(v); + double d = 0; + Iterator it = iterator(); + Entry e; + while (it.hasNext() && (e = it.next()) != null) { + d += Math.abs(e.getValue() - v.getEntry(e.getIndex())); + } + return d; + } + + /** {@inheritDoc} */ + public double getL1Distance(double[] v) throws IllegalArgumentException { + checkVectorDimensions(v.length); + double d = 0; + Iterator it = iterator(); + Entry e; + while (it.hasNext() && (e = it.next()) != null) { + d += Math.abs(e.getValue() - v[e.getIndex()]); + } + return d; + } + + /** {@inheritDoc} */ + public double getLInfDistance(RealVector v) throws IllegalArgumentException { + checkVectorDimensions(v); + double d = 0; + Iterator it = iterator(); + Entry e; + while (it.hasNext() && (e = it.next()) != null) { + d = Math.max(Math.abs(e.getValue() - v.getEntry(e.getIndex())), d); + } + return d; + } + + /** {@inheritDoc} */ + public double getLInfDistance(double[] v) throws IllegalArgumentException { + checkVectorDimensions(v.length); + double d = 0; + Iterator it = iterator(); + Entry e; + while (it.hasNext() && (e = it.next()) != null) { + d = Math.max(Math.abs(e.getValue() - v[e.getIndex()]), d); + } + return d; + } + + /** {@inheritDoc} */ + public RealVector mapAbs() { + return copy().mapAbsToSelf(); + } + + /** {@inheritDoc} */ + public RealVector mapAbsToSelf() { + try { + return mapToSelf(UnivariateRealFunctions.ABS); + } catch (FunctionEvaluationException e) { + throw new IllegalArgumentException(e); + } + } + + /** {@inheritDoc} */ + public RealVector mapAcos() { + return copy().mapAcosToSelf(); + } + + /** {@inheritDoc} */ + public RealVector mapAcosToSelf() { + try { + return mapToSelf(UnivariateRealFunctions.ACOS); + } catch (FunctionEvaluationException e) { + throw new IllegalArgumentException(e); + } + } + + /** {@inheritDoc} */ + public RealVector mapAsin() { + return copy().mapAsinToSelf(); + } + + /** {@inheritDoc} */ + public RealVector mapAsinToSelf() { + try { + return mapToSelf(UnivariateRealFunctions.ASIN); + } catch (FunctionEvaluationException e) { + throw new IllegalArgumentException(e); + } + } + + /** {@inheritDoc} */ + public RealVector mapAtan() { + return copy().mapAtanToSelf(); + } + + /** {@inheritDoc} */ + public RealVector mapAtanToSelf() { + try { + return mapToSelf(UnivariateRealFunctions.ATAN); + } catch (FunctionEvaluationException e) { + throw new IllegalArgumentException(e); + } + } + + /** {@inheritDoc} */ + public RealVector mapCbrt() { + return copy().mapCbrtToSelf(); + } + + /** {@inheritDoc} */ + public RealVector mapCbrtToSelf() { + try { + return mapToSelf(UnivariateRealFunctions.CBRT); + } catch (FunctionEvaluationException e) { + throw new IllegalArgumentException(e); + } + } + + /** {@inheritDoc} */ + public RealVector mapCeil() { + return copy().mapCeilToSelf(); + } + + /** {@inheritDoc} */ + public RealVector mapCeilToSelf() { + try { + return mapToSelf(UnivariateRealFunctions.CEIL); + } catch (FunctionEvaluationException e) { + throw new IllegalArgumentException(e); + } + } + + /** {@inheritDoc} */ + public RealVector mapCos() { + return copy().mapCosToSelf(); + } + + /** {@inheritDoc} */ + public RealVector mapCosToSelf() { + try { + return mapToSelf(UnivariateRealFunctions.COS); + } catch (FunctionEvaluationException e) { + throw new IllegalArgumentException(e); + } + } + + /** {@inheritDoc} */ + public RealVector mapCosh() { + return copy().mapCoshToSelf(); + } + + /** {@inheritDoc} */ + public RealVector mapCoshToSelf() { + try { + return mapToSelf(UnivariateRealFunctions.COSH); + } catch (FunctionEvaluationException e) { + throw new IllegalArgumentException(e); + } + } + + /** {@inheritDoc} */ + public RealVector mapDivide(double d) { + return copy().mapDivideToSelf(d); + } + + /** {@inheritDoc} */ + public RealVector mapExp() { + return copy().mapExpToSelf(); + } + + /** {@inheritDoc} */ + public RealVector mapExpToSelf() { + try { + return mapToSelf(UnivariateRealFunctions.EXP); + } catch (FunctionEvaluationException e) { + throw new IllegalArgumentException(e); + } + } + + /** {@inheritDoc} */ + public RealVector mapExpm1() { + return copy().mapExpm1ToSelf(); + } + + /** {@inheritDoc} */ + public RealVector mapExpm1ToSelf() { + try { + return mapToSelf(UnivariateRealFunctions.EXP1M); + } catch (FunctionEvaluationException e) { + throw new IllegalArgumentException(e); + } + } + + /** {@inheritDoc} */ + public RealVector mapFloor() { + return copy().mapFloorToSelf(); + } + + /** {@inheritDoc} */ + public RealVector mapFloorToSelf() { + try { + return mapToSelf(UnivariateRealFunctions.FLOOR); + } catch (FunctionEvaluationException e) { + throw new IllegalArgumentException(e); + } + } + + /** {@inheritDoc} */ + public RealVector mapInv() { + return copy().mapInvToSelf(); + } + + /** {@inheritDoc} */ + public RealVector mapLog() { + return copy().mapLogToSelf(); + } + + /** {@inheritDoc} */ + public RealVector mapLogToSelf() { + try { + return mapToSelf(UnivariateRealFunctions.LOG); + } catch (FunctionEvaluationException e) { + throw new IllegalArgumentException(e); + } + } + + /** {@inheritDoc} */ + public RealVector mapLog10() { + return copy().mapLog10ToSelf(); + } + + /** {@inheritDoc} */ + public RealVector mapLog10ToSelf() { + try { + return mapToSelf(UnivariateRealFunctions.LOG10); + } catch (FunctionEvaluationException e) { + throw new IllegalArgumentException(e); + } + } + + /** {@inheritDoc} */ + public RealVector mapLog1p() { + return copy().mapLog1pToSelf(); + } + + /** {@inheritDoc} */ + public RealVector mapLog1pToSelf() { + try { + return mapToSelf(UnivariateRealFunctions.ASIN); + } catch (FunctionEvaluationException e) { + throw new IllegalArgumentException(e); + } + } + + /** {@inheritDoc} */ + public RealVector mapMultiply(double d) { + return copy().mapMultiplyToSelf(d); + } + + /** {@inheritDoc} */ + public RealVector mapPow(double d) { + return copy().mapPowToSelf(d); + } + + /** {@inheritDoc} */ + public RealVector mapRint() { + return copy().mapRintToSelf(); + } + + /** {@inheritDoc} */ + public RealVector mapRintToSelf() { + try { + return mapToSelf(UnivariateRealFunctions.RINT); + } catch (FunctionEvaluationException e) { + throw new IllegalArgumentException(e); + } + } + + /** {@inheritDoc} */ + public RealVector mapSignum() { + return copy().mapSignumToSelf(); + } + + /** {@inheritDoc} */ + public RealVector mapSignumToSelf() { + try { + return mapToSelf(UnivariateRealFunctions.SIGNUM); + } catch (FunctionEvaluationException e) { + throw new IllegalArgumentException(e); + } + } + + /** {@inheritDoc} */ + public RealVector mapSin() { + return copy().mapSinToSelf(); + } + + /** {@inheritDoc} */ + public RealVector mapSinToSelf() { + try { + return mapToSelf(UnivariateRealFunctions.SIN); + } catch (FunctionEvaluationException e) { + throw new IllegalArgumentException(e); + } + } + + /** {@inheritDoc} */ + public RealVector mapSinh() { + return copy().mapSinhToSelf(); + } + + /** {@inheritDoc} */ + public RealVector mapSinhToSelf() { + try { + return mapToSelf(UnivariateRealFunctions.SINH); + } catch (FunctionEvaluationException e) { + throw new IllegalArgumentException(e); + } + } + + /** {@inheritDoc} */ + public RealVector mapSqrt() { + return copy().mapSqrtToSelf(); + } + + /** {@inheritDoc} */ + public RealVector mapSqrtToSelf() { + try { + return mapToSelf(UnivariateRealFunctions.SQRT); + } catch (FunctionEvaluationException e) { + throw new IllegalArgumentException(e); + } + } + + /** {@inheritDoc} */ + public RealVector mapSubtract(double d) { + return copy().mapSubtractToSelf(d); + } + + /** {@inheritDoc} */ + public RealVector mapTan() { + return copy().mapTanToSelf(); + } + + /** {@inheritDoc} */ + public RealVector mapTanToSelf() { + try { + return mapToSelf(UnivariateRealFunctions.TAN); + } catch (FunctionEvaluationException e) { + throw new IllegalArgumentException(e); + } + } + + /** {@inheritDoc} */ + public RealVector mapTanh() { + return copy().mapTanhToSelf(); + } + + /** {@inheritDoc} */ + public RealVector mapTanhToSelf() { + try { + return mapToSelf(UnivariateRealFunctions.TANH); + } catch (FunctionEvaluationException e) { + throw new IllegalArgumentException(e); + } + } + + /** {@inheritDoc} */ + public RealVector mapUlp() { + return copy().mapUlpToSelf(); + } + + /** {@inheritDoc} */ + public RealVector mapUlpToSelf() { + try { + return mapToSelf(UnivariateRealFunctions.ULP); + } catch (FunctionEvaluationException e) { + throw new IllegalArgumentException(e); + } + } + + /** {@inheritDoc} */ + public RealMatrix outerProduct(RealVector v) throws IllegalArgumentException { + RealMatrix product; + if (v instanceof SparseRealVector || this instanceof SparseRealVector) { + product = new OpenMapRealMatrix(this.getDimension(), v.getDimension()); + } else { + product = new Array2DRowRealMatrix(this.getDimension(), v.getDimension()); + } + Iterator thisIt = sparseIterator(); + Entry thisE = null; + while (thisIt.hasNext() && (thisE = thisIt.next()) != null) { + Iterator otherIt = v.sparseIterator(); + Entry otherE = null; + while (otherIt.hasNext() && (otherE = otherIt.next()) != null) { + product.setEntry(thisE.getIndex(), otherE.getIndex(), + thisE.getValue() * otherE.getValue()); + } + } + + return product; + + } + + /** {@inheritDoc} */ + public RealMatrix outerProduct(double[] v) throws IllegalArgumentException { + return outerProduct(new ArrayRealVector(v, false)); + } + + /** {@inheritDoc} */ + public RealVector projection(double[] v) throws IllegalArgumentException { + return projection(new ArrayRealVector(v, false)); + } + + /** {@inheritDoc} */ + public void set(double value) { + Iterator it = iterator(); + Entry e = null; + while (it.hasNext() && (e = it.next()) != null) { + e.setValue(value); + } + } + + /** {@inheritDoc} */ + public double[] toArray() { + int dim = getDimension(); + double[] values = new double[dim]; + for (int i = 0; i < dim; i++) { + values[i] = getEntry(i); + } + return values; + } + + /** {@inheritDoc} */ + public double[] getData() { + return toArray(); + } + + /** {@inheritDoc} */ + public RealVector unitVector() { + RealVector copy = copy(); + copy.unitize(); + return copy; + } + + /** {@inheritDoc} */ + public void unitize() { + mapDivideToSelf(getNorm()); + } + + /** {@inheritDoc} */ + public Iterator sparseIterator() { + return new SparseEntryIterator(); + } + + /** {@inheritDoc} */ + public Iterator iterator() { + final int dim = getDimension(); + return new Iterator() { + + /** Current index. */ + private int i = 0; + + /** Current entry. */ + private EntryImpl e = new EntryImpl(); + + /** {@inheritDoc} */ + public boolean hasNext() { + return i < dim; + } + + /** {@inheritDoc} */ + public Entry next() { + e.setIndex(i++); + return e; + } + + /** {@inheritDoc} */ + public void remove() { + throw new UnsupportedOperationException("Not supported"); + } + }; + } + + /** {@inheritDoc} */ + public RealVector map(UnivariateRealFunction function) throws FunctionEvaluationException { + return copy().mapToSelf(function); + } + + /** {@inheritDoc} */ + public RealVector mapToSelf(UnivariateRealFunction function) throws FunctionEvaluationException { + Iterator it = (function.value(0) == 0) ? sparseIterator() : iterator(); + Entry e; + while (it.hasNext() && (e = it.next()) != null) { + e.setValue(function.value(e.getValue())); + } + return this; + } + + /** An entry in the vector. */ + protected class EntryImpl extends Entry { + + /** Simple constructor. */ + public EntryImpl() { + setIndex(0); + } + + /** {@inheritDoc} */ + public double getValue() { + return getEntry(getIndex()); + } + + /** {@inheritDoc} */ + public void setValue(double newValue) { + setEntry(getIndex(), newValue); + } + } + + /** + * This class should rare be used, but is here to provide + * a default implementation of sparseIterator(), which is implemented + * by walking over the entries, skipping those whose values are the default one. + * + * Concrete subclasses which are SparseVector implementations should + * make their own sparse iterator, not use this one. + * + * This implementation might be useful for ArrayRealVector, when expensive + * operations which preserve the default value are to be done on the entries, + * and the fraction of non-default values is small (i.e. someone took a + * SparseVector, and passed it into the copy-constructor of ArrayRealVector) + */ + protected class SparseEntryIterator implements Iterator { + + /** Dimension of the vector. */ + private final int dim; + + /** Temporary entry (reused on each call to {@link #next()}. */ + private EntryImpl tmp = new EntryImpl(); + + /** Current entry. */ + private EntryImpl current; + + /** Next entry. */ + private EntryImpl next; + + /** Simple constructor. */ + protected SparseEntryIterator() { + dim = getDimension(); + current = new EntryImpl(); + if (current.getValue() == 0) { + advance(current); + } + next = new EntryImpl(); + next.setIndex(current.getIndex()); + advance(next); + } + + /** Advance an entry up to the next non null one. + * @param e entry to advance + */ + protected void advance(EntryImpl e) { + if (e == null) { + return; + } + do { + e.setIndex(e.getIndex() + 1); + } while (e.getIndex() < dim && e.getValue() == 0); + if (e.getIndex() >= dim) { + e.setIndex(-1); + } + } + + /** {@inheritDoc} */ + public boolean hasNext() { + return current != null; + } + + /** {@inheritDoc} */ + public Entry next() { + tmp.setIndex(current.getIndex()); + if (next != null) { + current.setIndex(next.getIndex()); + advance(next); + if (next.getIndex() < 0) { + next = null; + } + } else { + current = null; + } + return tmp; + } + + /** {@inheritDoc} */ + public void remove() { + throw new UnsupportedOperationException("Not supported"); + } + } + +} diff --git a/src/main/java/org/apache/commons/math/linear/ArrayRealVector.java b/src/main/java/org/apache/commons/math/linear/ArrayRealVector.java index cd4fb68a0..14b0f393d 100644 --- a/src/main/java/org/apache/commons/math/linear/ArrayRealVector.java +++ b/src/main/java/org/apache/commons/math/linear/ArrayRealVector.java @@ -18,6 +18,7 @@ package org.apache.commons.math.linear; import java.io.Serializable; import java.util.Arrays; +import java.util.Iterator; import org.apache.commons.math.MathRuntimeException; import org.apache.commons.math.util.MathUtils; @@ -27,7 +28,7 @@ import org.apache.commons.math.util.MathUtils; * @version $Revision$ $Date$ * @since 2.0 */ -public class ArrayRealVector implements RealVector, Serializable { +public class ArrayRealVector extends AbstractRealVector implements Serializable { /** Message for non fitting position and size. */ private static final String NON_FITTING_POSITION_AND_SIZE_MESSAGE = @@ -166,7 +167,7 @@ public class ArrayRealVector implements RealVector, Serializable { * @param v vector to copy */ public ArrayRealVector(ArrayRealVector v) { - data = v.data.clone(); + this(v, true); } /** @@ -223,20 +224,22 @@ public class ArrayRealVector implements RealVector, Serializable { } /** {@inheritDoc} */ - public RealVector copy() { + public AbstractRealVector copy() { return new ArrayRealVector(this, true); } /** {@inheritDoc} */ public RealVector add(RealVector v) throws IllegalArgumentException { - try { + if(v instanceof ArrayRealVector) { return add((ArrayRealVector) v); - } catch (ClassCastException cce) { + } else { checkVectorDimensions(v); - double[] out = new double[data.length]; - for (int i = 0; i < data.length; i++) { - out[i] = data[i] + v.getEntry(i); + double[] out = data.clone(); + Iterator it = v.sparseIterator(); + Entry e; + while(it.hasNext() && (e = it.next()) != null) { + out[e.getIndex()] += e.getValue(); } return new ArrayRealVector(out); } @@ -246,9 +249,9 @@ public class ArrayRealVector implements RealVector, Serializable { public RealVector add(double[] v) throws IllegalArgumentException { checkVectorDimensions(v.length); - double[] out = new double[data.length]; + double[] out = data.clone(); for (int i = 0; i < data.length; i++) { - out[i] = data[i] + v[i]; + out[i] += v[i]; } return new ArrayRealVector(out); } @@ -267,13 +270,15 @@ public class ArrayRealVector implements RealVector, Serializable { /** {@inheritDoc} */ public RealVector subtract(RealVector v) throws IllegalArgumentException { - try { + if(v instanceof ArrayRealVector) { return subtract((ArrayRealVector) v); - } catch (ClassCastException cce) { + } else { checkVectorDimensions(v); - double[] out = new double[data.length]; - for (int i = 0; i < data.length; i++) { - out[i] = data[i] - v.getEntry(i); + double[] out = data.clone(); + Iterator it = v.sparseIterator(); + Entry e; + while(it.hasNext() && (e = it.next()) != null) { + out[e.getIndex()] -= e.getValue(); } return new ArrayRealVector(out); } @@ -283,9 +288,9 @@ public class ArrayRealVector implements RealVector, Serializable { public RealVector subtract(double[] v) throws IllegalArgumentException { checkVectorDimensions(v.length); - double[] out = new double[data.length]; + double[] out = data.clone(); for (int i = 0; i < data.length; i++) { - out[i] = data[i] - v[i]; + out[i] -= v[i]; } return new ArrayRealVector(out); } @@ -301,15 +306,6 @@ public class ArrayRealVector implements RealVector, Serializable { return (ArrayRealVector) subtract(v.data); } - /** {@inheritDoc} */ - public RealVector mapAdd(double d) { - double[] out = new double[data.length]; - for (int i = 0; i < data.length; i++) { - out[i] = data[i] + d; - } - return new ArrayRealVector(out); - } - /** {@inheritDoc} */ public RealVector mapAddToSelf(double d) { for (int i = 0; i < data.length; i++) { @@ -318,15 +314,6 @@ public class ArrayRealVector implements RealVector, Serializable { return this; } - /** {@inheritDoc} */ - public RealVector mapSubtract(double d) { - double[] out = new double[data.length]; - for (int i = 0; i < data.length; i++) { - out[i] = data[i] - d; - } - return new ArrayRealVector(out); - } - /** {@inheritDoc} */ public RealVector mapSubtractToSelf(double d) { for (int i = 0; i < data.length; i++) { @@ -335,15 +322,6 @@ public class ArrayRealVector implements RealVector, Serializable { return this; } - /** {@inheritDoc} */ - public RealVector mapMultiply(double d) { - double[] out = new double[data.length]; - for (int i = 0; i < data.length; i++) { - out[i] = data[i] * d; - } - return new ArrayRealVector(out); - } - /** {@inheritDoc} */ public RealVector mapMultiplyToSelf(double d) { for (int i = 0; i < data.length; i++) { @@ -352,15 +330,6 @@ public class ArrayRealVector implements RealVector, Serializable { return this; } - /** {@inheritDoc} */ - public RealVector mapDivide(double d) { - double[] out = new double[data.length]; - for (int i = 0; i < data.length; i++) { - out[i] = data[i] / d; - } - return new ArrayRealVector(out); - } - /** {@inheritDoc} */ public RealVector mapDivideToSelf(double d) { for (int i = 0; i < data.length; i++) { @@ -369,15 +338,6 @@ public class ArrayRealVector implements RealVector, Serializable { return this; } - /** {@inheritDoc} */ - public RealVector mapPow(double d) { - double[] out = new double[data.length]; - for (int i = 0; i < data.length; i++) { - out[i] = Math.pow(data[i], d); - } - return new ArrayRealVector(out); - } - /** {@inheritDoc} */ public RealVector mapPowToSelf(double d) { for (int i = 0; i < data.length; i++) { @@ -386,15 +346,6 @@ public class ArrayRealVector implements RealVector, Serializable { return this; } - /** {@inheritDoc} */ - public RealVector mapExp() { - double[] out = new double[data.length]; - for (int i = 0; i < data.length; i++) { - out[i] = Math.exp(data[i]); - } - return new ArrayRealVector(out); - } - /** {@inheritDoc} */ public RealVector mapExpToSelf() { for (int i = 0; i < data.length; i++) { @@ -403,15 +354,6 @@ public class ArrayRealVector implements RealVector, Serializable { return this; } - /** {@inheritDoc} */ - public RealVector mapExpm1() { - double[] out = new double[data.length]; - for (int i = 0; i < data.length; i++) { - out[i] = Math.expm1(data[i]); - } - return new ArrayRealVector(out); - } - /** {@inheritDoc} */ public RealVector mapExpm1ToSelf() { for (int i = 0; i < data.length; i++) { @@ -420,15 +362,6 @@ public class ArrayRealVector implements RealVector, Serializable { return this; } - /** {@inheritDoc} */ - public RealVector mapLog() { - double[] out = new double[data.length]; - for (int i = 0; i < data.length; i++) { - out[i] = Math.log(data[i]); - } - return new ArrayRealVector(out); - } - /** {@inheritDoc} */ public RealVector mapLogToSelf() { for (int i = 0; i < data.length; i++) { @@ -437,15 +370,6 @@ public class ArrayRealVector implements RealVector, Serializable { return this; } - /** {@inheritDoc} */ - public RealVector mapLog10() { - double[] out = new double[data.length]; - for (int i = 0; i < data.length; i++) { - out[i] = Math.log10(data[i]); - } - return new ArrayRealVector(out); - } - /** {@inheritDoc} */ public RealVector mapLog10ToSelf() { for (int i = 0; i < data.length; i++) { @@ -454,15 +378,6 @@ public class ArrayRealVector implements RealVector, Serializable { return this; } - /** {@inheritDoc} */ - public RealVector mapLog1p() { - double[] out = new double[data.length]; - for (int i = 0; i < data.length; i++) { - out[i] = Math.log1p(data[i]); - } - return new ArrayRealVector(out); - } - /** {@inheritDoc} */ public RealVector mapLog1pToSelf() { for (int i = 0; i < data.length; i++) { @@ -471,15 +386,6 @@ public class ArrayRealVector implements RealVector, Serializable { return this; } - /** {@inheritDoc} */ - public RealVector mapCosh() { - double[] out = new double[data.length]; - for (int i = 0; i < data.length; i++) { - out[i] = Math.cosh(data[i]); - } - return new ArrayRealVector(out); - } - /** {@inheritDoc} */ public RealVector mapCoshToSelf() { for (int i = 0; i < data.length; i++) { @@ -488,15 +394,6 @@ public class ArrayRealVector implements RealVector, Serializable { return this; } - /** {@inheritDoc} */ - public RealVector mapSinh() { - double[] out = new double[data.length]; - for (int i = 0; i < data.length; i++) { - out[i] = Math.sinh(data[i]); - } - return new ArrayRealVector(out); - } - /** {@inheritDoc} */ public RealVector mapSinhToSelf() { for (int i = 0; i < data.length; i++) { @@ -505,15 +402,6 @@ public class ArrayRealVector implements RealVector, Serializable { return this; } - /** {@inheritDoc} */ - public RealVector mapTanh() { - double[] out = new double[data.length]; - for (int i = 0; i < data.length; i++) { - out[i] = Math.tanh(data[i]); - } - return new ArrayRealVector(out); - } - /** {@inheritDoc} */ public RealVector mapTanhToSelf() { for (int i = 0; i < data.length; i++) { @@ -522,15 +410,6 @@ public class ArrayRealVector implements RealVector, Serializable { return this; } - /** {@inheritDoc} */ - public RealVector mapCos() { - double[] out = new double[data.length]; - for (int i = 0; i < data.length; i++) { - out[i] = Math.cos(data[i]); - } - return new ArrayRealVector(out); - } - /** {@inheritDoc} */ public RealVector mapCosToSelf() { for (int i = 0; i < data.length; i++) { @@ -539,15 +418,6 @@ public class ArrayRealVector implements RealVector, Serializable { return this; } - /** {@inheritDoc} */ - public RealVector mapSin() { - double[] out = new double[data.length]; - for (int i = 0; i < data.length; i++) { - out[i] = Math.sin(data[i]); - } - return new ArrayRealVector(out); - } - /** {@inheritDoc} */ public RealVector mapSinToSelf() { for (int i = 0; i < data.length; i++) { @@ -556,15 +426,6 @@ public class ArrayRealVector implements RealVector, Serializable { return this; } - /** {@inheritDoc} */ - public RealVector mapTan() { - double[] out = new double[data.length]; - for (int i = 0; i < data.length; i++) { - out[i] = Math.tan(data[i]); - } - return new ArrayRealVector(out); - } - /** {@inheritDoc} */ public RealVector mapTanToSelf() { for (int i = 0; i < data.length; i++) { @@ -573,15 +434,6 @@ public class ArrayRealVector implements RealVector, Serializable { return this; } - /** {@inheritDoc} */ - public RealVector mapAcos() { - double[] out = new double[data.length]; - for (int i = 0; i < data.length; i++) { - out[i] = Math.acos(data[i]); - } - return new ArrayRealVector(out); - } - /** {@inheritDoc} */ public RealVector mapAcosToSelf() { for (int i = 0; i < data.length; i++) { @@ -590,15 +442,6 @@ public class ArrayRealVector implements RealVector, Serializable { return this; } - /** {@inheritDoc} */ - public RealVector mapAsin() { - double[] out = new double[data.length]; - for (int i = 0; i < data.length; i++) { - out[i] = Math.asin(data[i]); - } - return new ArrayRealVector(out); - } - /** {@inheritDoc} */ public RealVector mapAsinToSelf() { for (int i = 0; i < data.length; i++) { @@ -607,15 +450,6 @@ public class ArrayRealVector implements RealVector, Serializable { return this; } - /** {@inheritDoc} */ - public RealVector mapAtan() { - double[] out = new double[data.length]; - for (int i = 0; i < data.length; i++) { - out[i] = Math.atan(data[i]); - } - return new ArrayRealVector(out); - } - /** {@inheritDoc} */ public RealVector mapAtanToSelf() { for (int i = 0; i < data.length; i++) { @@ -624,15 +458,6 @@ public class ArrayRealVector implements RealVector, Serializable { return this; } - /** {@inheritDoc} */ - public RealVector mapInv() { - double[] out = new double[data.length]; - for (int i = 0; i < data.length; i++) { - out[i] = 1.0 / data[i]; - } - return new ArrayRealVector(out); - } - /** {@inheritDoc} */ public RealVector mapInvToSelf() { for (int i = 0; i < data.length; i++) { @@ -641,15 +466,6 @@ public class ArrayRealVector implements RealVector, Serializable { return this; } - /** {@inheritDoc} */ - public RealVector mapAbs() { - double[] out = new double[data.length]; - for (int i = 0; i < data.length; i++) { - out[i] = Math.abs(data[i]); - } - return new ArrayRealVector(out); - } - /** {@inheritDoc} */ public RealVector mapAbsToSelf() { for (int i = 0; i < data.length; i++) { @@ -658,15 +474,6 @@ public class ArrayRealVector implements RealVector, Serializable { return this; } - /** {@inheritDoc} */ - public RealVector mapSqrt() { - double[] out = new double[data.length]; - for (int i = 0; i < data.length; i++) { - out[i] = Math.sqrt(data[i]); - } - return new ArrayRealVector(out); - } - /** {@inheritDoc} */ public RealVector mapSqrtToSelf() { for (int i = 0; i < data.length; i++) { @@ -675,15 +482,6 @@ public class ArrayRealVector implements RealVector, Serializable { return this; } - /** {@inheritDoc} */ - public RealVector mapCbrt() { - double[] out = new double[data.length]; - for (int i = 0; i < data.length; i++) { - out[i] = Math.cbrt(data[i]); - } - return new ArrayRealVector(out); - } - /** {@inheritDoc} */ public RealVector mapCbrtToSelf() { for (int i = 0; i < data.length; i++) { @@ -692,15 +490,6 @@ public class ArrayRealVector implements RealVector, Serializable { return this; } - /** {@inheritDoc} */ - public RealVector mapCeil() { - double[] out = new double[data.length]; - for (int i = 0; i < data.length; i++) { - out[i] = Math.ceil(data[i]); - } - return new ArrayRealVector(out); - } - /** {@inheritDoc} */ public RealVector mapCeilToSelf() { for (int i = 0; i < data.length; i++) { @@ -709,15 +498,6 @@ public class ArrayRealVector implements RealVector, Serializable { return this; } - /** {@inheritDoc} */ - public RealVector mapFloor() { - double[] out = new double[data.length]; - for (int i = 0; i < data.length; i++) { - out[i] = Math.floor(data[i]); - } - return new ArrayRealVector(out); - } - /** {@inheritDoc} */ public RealVector mapFloorToSelf() { for (int i = 0; i < data.length; i++) { @@ -726,15 +506,6 @@ public class ArrayRealVector implements RealVector, Serializable { return this; } - /** {@inheritDoc} */ - public RealVector mapRint() { - double[] out = new double[data.length]; - for (int i = 0; i < data.length; i++) { - out[i] = Math.rint(data[i]); - } - return new ArrayRealVector(out); - } - /** {@inheritDoc} */ public RealVector mapRintToSelf() { for (int i = 0; i < data.length; i++) { @@ -743,15 +514,6 @@ public class ArrayRealVector implements RealVector, Serializable { return this; } - /** {@inheritDoc} */ - public RealVector mapSignum() { - double[] out = new double[data.length]; - for (int i = 0; i < data.length; i++) { - out[i] = Math.signum(data[i]); - } - return new ArrayRealVector(out); - } - /** {@inheritDoc} */ public RealVector mapSignumToSelf() { for (int i = 0; i < data.length; i++) { @@ -760,15 +522,6 @@ public class ArrayRealVector implements RealVector, Serializable { return this; } - /** {@inheritDoc} */ - public RealVector mapUlp() { - double[] out = new double[data.length]; - for (int i = 0; i < data.length; i++) { - out[i] = Math.ulp(data[i]); - } - return new ArrayRealVector(out); - } - /** {@inheritDoc} */ public RealVector mapUlpToSelf() { for (int i = 0; i < data.length; i++) { @@ -780,15 +533,15 @@ public class ArrayRealVector implements RealVector, Serializable { /** {@inheritDoc} */ public RealVector ebeMultiply(RealVector v) throws IllegalArgumentException { - try { + if(v instanceof ArrayRealVector) { return ebeMultiply((ArrayRealVector) v); - } catch (ClassCastException cce) { + } else { checkVectorDimensions(v); - double[] out = new double[data.length]; + double[] out = data.clone(); for (int i = 0; i < data.length; i++) { - out[i] = data[i] * v.getEntry(i); + out[i] *= v.getEntry(i); } - return new ArrayRealVector(out); + return new ArrayRealVector(out, false); } } @@ -796,11 +549,11 @@ public class ArrayRealVector implements RealVector, Serializable { public RealVector ebeMultiply(double[] v) throws IllegalArgumentException { checkVectorDimensions(v.length); - double[] out = new double[data.length]; + double[] out = data.clone(); for (int i = 0; i < data.length; i++) { - out[i] = data[i] * v[i]; + out[i] *= v[i]; } - return new ArrayRealVector(out); + return new ArrayRealVector(out, false); } /** @@ -817,15 +570,15 @@ public class ArrayRealVector implements RealVector, Serializable { /** {@inheritDoc} */ public RealVector ebeDivide(RealVector v) throws IllegalArgumentException { - try { + if(v instanceof ArrayRealVector) { return ebeDivide((ArrayRealVector) v); - } catch (ClassCastException cce) { + } else { checkVectorDimensions(v); - double[] out = new double[data.length]; + double[] out = data.clone(); for (int i = 0; i < data.length; i++) { - out[i] = data[i] / v.getEntry(i); + out[i] /= v.getEntry(i); } - return new ArrayRealVector(out); + return new ArrayRealVector(out, false); } } @@ -833,11 +586,11 @@ public class ArrayRealVector implements RealVector, Serializable { public RealVector ebeDivide(double[] v) throws IllegalArgumentException { checkVectorDimensions(v.length); - double[] out = new double[data.length]; + double[] out = data.clone(); for (int i = 0; i < data.length; i++) { - out[i] = data[i] / v[i]; + out[i] /= v[i]; } - return new ArrayRealVector(out); + return new ArrayRealVector(out, false); } /** @@ -868,13 +621,15 @@ public class ArrayRealVector implements RealVector, Serializable { /** {@inheritDoc} */ public double dotProduct(RealVector v) throws IllegalArgumentException { - try { + if(v instanceof ArrayRealVector) { return dotProduct((ArrayRealVector) v); - } catch (ClassCastException cce) { + } else { checkVectorDimensions(v); double dot = 0; - for (int i = 0; i < data.length; i++) { - dot += data[i] * v.getEntry(i); + Iterator it = v.sparseIterator(); + Entry e; + while(it.hasNext() && (e = it.next()) != null) { + dot += data[e.getIndex()] * e.getValue(); } return dot; } @@ -932,9 +687,9 @@ public class ArrayRealVector implements RealVector, Serializable { /** {@inheritDoc} */ public double getDistance(RealVector v) throws IllegalArgumentException { - try { + if(v instanceof ArrayRealVector) { return getDistance((ArrayRealVector) v); - } catch (ClassCastException cce) { + } else { checkVectorDimensions(v); double sum = 0; for (int i = 0; i < data.length; ++i) { @@ -978,9 +733,9 @@ public class ArrayRealVector implements RealVector, Serializable { /** {@inheritDoc} */ public double getL1Distance(RealVector v) throws IllegalArgumentException { - try { + if(v instanceof ArrayRealVector) { return getL1Distance((ArrayRealVector) v); - } catch (ClassCastException cce) { + } else { checkVectorDimensions(v); double sum = 0; for (int i = 0; i < data.length; ++i) { @@ -1024,9 +779,9 @@ public class ArrayRealVector implements RealVector, Serializable { /** {@inheritDoc} */ public double getLInfDistance(RealVector v) throws IllegalArgumentException { - try { + if(v instanceof ArrayRealVector) { return getLInfDistance((ArrayRealVector) v); - } catch (ClassCastException cce) { + } else { checkVectorDimensions(v); double max = 0; for (int i = 0; i < data.length; ++i) { @@ -1073,7 +828,7 @@ public class ArrayRealVector implements RealVector, Serializable { if (norm == 0) { throw MathRuntimeException.createArithmeticException("zero norm"); } - return mapDivide(getNorm()); + return mapDivide(norm); } /** {@inheritDoc} */ @@ -1082,9 +837,7 @@ public class ArrayRealVector implements RealVector, Serializable { if (norm == 0) { throw MathRuntimeException.createArithmeticException("cannot normalize a zero norm vector"); } - for (int i = 0; i < data.length; i++) { - data[i] /= norm; - } + mapDivideToSelf(norm); } /** {@inheritDoc} */ @@ -1109,9 +862,9 @@ public class ArrayRealVector implements RealVector, Serializable { /** {@inheritDoc} */ public RealMatrix outerProduct(RealVector v) throws IllegalArgumentException { - try { + if(v instanceof ArrayRealVector) { return outerProduct((ArrayRealVector) v); - } catch (ClassCastException cce) { + } else { checkVectorDimensions(v); final int m = data.length; final RealMatrix out = MatrixUtils.createRealMatrix(m, m); @@ -1354,33 +1107,26 @@ public class ArrayRealVector implements RealVector, Serializable { return true; } - if (other == null) { + if (other == null || !(other instanceof RealVector)) { return false; } - try { - RealVector rhs = (RealVector) other; - if (data.length != rhs.getDimension()) { - return false; - } - - if (rhs.isNaN()) { - return this.isNaN(); - } - - for (int i = 0; i < data.length; ++i) { - if (data[i] != rhs.getEntry(i)) { - return false; - } - } - return true; - - } catch (ClassCastException ex) { - // ignore exception - return false; + RealVector rhs = (RealVector) other; + if (data.length != rhs.getDimension()) { + return false; } + if (rhs.isNaN()) { + return this.isNaN(); + } + + for (int i = 0; i < data.length; ++i) { + if (data[i] != rhs.getEntry(i)) { + return false; + } + } + return true; } /** @@ -1396,18 +1142,4 @@ public class ArrayRealVector implements RealVector, Serializable { return MathUtils.hash(data); } - /** - * Check if an index is valid. - * @param index index to check - * @exception MatrixIndexException if index is not valid - */ - private void checkIndex(final int index) - throws MatrixIndexException { - if (index < 0 || index >= getDimension()) { - throw new MatrixIndexException( - "index {0} out of allowed range [{1}, {2}]", - index, 0, getDimension() - 1); - } - } - } diff --git a/src/main/java/org/apache/commons/math/linear/OpenMapRealVector.java b/src/main/java/org/apache/commons/math/linear/OpenMapRealVector.java index c404aafda..6052675de 100644 --- a/src/main/java/org/apache/commons/math/linear/OpenMapRealVector.java +++ b/src/main/java/org/apache/commons/math/linear/OpenMapRealVector.java @@ -27,7 +27,7 @@ import org.apache.commons.math.util.OpenIntToDoubleHashMap.Iterator; * @version $Revision$ $Date$ * @since 2.0 */ -public class OpenMapRealVector implements SparseRealVector, Serializable { +public class OpenMapRealVector extends AbstractRealVector implements SparseRealVector, Serializable { /** Default Tolerance for having a value considered zero. */ public static final double DEFAULT_ZERO_TOLERANCE = 1.0e-12; @@ -41,8 +41,11 @@ public class OpenMapRealVector implements SparseRealVector, Serializable { /** Dimension of the vector. */ private final int virtualSize; - /** Tolerance for having a value considered zero. */ - private double epsilon; + /** Negative tolerance for having a value considered zero. */ + private double minusEpsilon; + + /** Positive tolerance for having a value considered zero. */ + private double plusEpsilon; /** * Build a 0-length vector. @@ -54,7 +57,7 @@ public class OpenMapRealVector implements SparseRealVector, Serializable { * into this vector.

*/ public OpenMapRealVector() { - this(0, DEFAULT_ZERO_TOLERANCE); + this(0, DEFAULT_ZERO_TOLERANCE, 0); } /** @@ -62,18 +65,19 @@ public class OpenMapRealVector implements SparseRealVector, Serializable { * @param dimension size of the vector */ public OpenMapRealVector(int dimension) { - this(dimension, DEFAULT_ZERO_TOLERANCE); + this(dimension, DEFAULT_ZERO_TOLERANCE, 0); } /** * Construct a (dimension)-length vector of zeros, specifying zero tolerance. * @param dimension Size of the vector * @param epsilon The tolerance for having a value considered zero + * @param defaultValue value for non-specified entries */ - public OpenMapRealVector(int dimension, double epsilon) { + public OpenMapRealVector(int dimension, double epsilon, double defaultValue) { virtualSize = dimension; - entries = new OpenIntToDoubleHashMap(0.0); - this.epsilon = epsilon; + entries = new OpenIntToDoubleHashMap(defaultValue); + setDefault(defaultValue, epsilon); } /** @@ -84,7 +88,8 @@ public class OpenMapRealVector implements SparseRealVector, Serializable { protected OpenMapRealVector(OpenMapRealVector v, int resize) { virtualSize = v.getDimension() + resize; entries = new OpenIntToDoubleHashMap(v.entries); - epsilon = v.getEpsilon(); + minusEpsilon = v.minusEpsilon; + plusEpsilon = v.plusEpsilon; } /** @@ -101,11 +106,12 @@ public class OpenMapRealVector implements SparseRealVector, Serializable { * @param dimension The size of the vector * @param expectedSize The expected number of non-zero entries * @param epsilon The tolerance for having a value considered zero + * @param defaultValue value for non-specified entries */ - public OpenMapRealVector(int dimension, int expectedSize, double epsilon) { + public OpenMapRealVector(int dimension, int expectedSize, double epsilon, double defaultValue) { virtualSize = dimension; - entries = new OpenIntToDoubleHashMap(expectedSize, 0.0); - this.epsilon = epsilon; + entries = new OpenIntToDoubleHashMap(expectedSize, defaultValue); + setDefault(defaultValue, epsilon); } /** @@ -126,10 +132,10 @@ public class OpenMapRealVector implements SparseRealVector, Serializable { public OpenMapRealVector(double[] values, double epsilon) { virtualSize = values.length; entries = new OpenIntToDoubleHashMap(0.0); - this.epsilon = epsilon; + setDefault(0, epsilon); for (int key = 0; key < values.length; key++) { double value = values[key]; - if (!isZero(value)) { + if (!isDefaultValue(value)) { entries.put(key, value); } } @@ -141,7 +147,7 @@ public class OpenMapRealVector implements SparseRealVector, Serializable { * @param values The set of values to create from */ public OpenMapRealVector(Double[] values) { - this(values, DEFAULT_ZERO_TOLERANCE); + this(values, DEFAULT_ZERO_TOLERANCE, 0); } /** @@ -149,14 +155,15 @@ public class OpenMapRealVector implements SparseRealVector, Serializable { * Only non-zero entries will be stored * @param values The set of values to create from * @param epsilon The tolerance for having a value considered zero + * @param defaultValue value for non-specified entries */ - public OpenMapRealVector(Double[] values, double epsilon) { + public OpenMapRealVector(Double[] values, double epsilon, double defaultValue) { virtualSize = values.length; - entries = new OpenIntToDoubleHashMap(0.0); - this.epsilon = epsilon; + entries = new OpenIntToDoubleHashMap(defaultValue); + setDefault(defaultValue, epsilon); for (int key = 0; key < values.length; key++) { double value = values[key].doubleValue(); - if (!isZero(value)) { + if (!isDefaultValue(value)) { entries.put(key, value); } } @@ -169,7 +176,8 @@ public class OpenMapRealVector implements SparseRealVector, Serializable { public OpenMapRealVector(OpenMapRealVector v) { virtualSize = v.getDimension(); entries = new OpenIntToDoubleHashMap(v.getEntries()); - epsilon = v.getEpsilon(); + plusEpsilon = v.plusEpsilon; + minusEpsilon = v.minusEpsilon; } /** @@ -179,15 +187,27 @@ public class OpenMapRealVector implements SparseRealVector, Serializable { public OpenMapRealVector(RealVector v) { virtualSize = v.getDimension(); entries = new OpenIntToDoubleHashMap(0.0); - epsilon = DEFAULT_ZERO_TOLERANCE; + setDefault(0, DEFAULT_ZERO_TOLERANCE); for (int key = 0; key < virtualSize; key++) { double value = v.getEntry(key); - if (!isZero(value)) { + if (!isDefaultValue(value)) { entries.put(key, value); } } } + /** Set defaults. + * @param defaultValue value for non-specified entries + * @param epsilon tolerance to check for equality with default value + */ + private void setDefault(double defaultValue, double epsilon) { + if (epsilon < 0) { + throw new IllegalArgumentException("default tolerance must be > 0 :" + epsilon); + } + plusEpsilon = defaultValue + epsilon; + minusEpsilon = defaultValue - epsilon; + } + /** * Get the entries of this instance. * @return entries of this instance @@ -197,54 +217,41 @@ public class OpenMapRealVector implements SparseRealVector, Serializable { } /** - * Determine if this value is zero. + * Determine if this value is within epsilon of the defaultValue (currently always zero). * @param value The value to test - * @return true if this value is zero, false otherwise + * @return true if this value is within epsilon to the defaultValue, false otherwise */ - protected boolean isZero(double value) { - return value > -epsilon && value < epsilon; - } - - /** - * Get the tolerance for having a value considered zero. - * @return The test range for testing if a value is zero - */ - public double getEpsilon() { - return epsilon; - } - - /** - * Set the tolerance for having a value considered zero. - * @param epsilon The test range for testing if a value is zero - */ - public void setEpsilon(double epsilon) { - this.epsilon = epsilon; + protected boolean isDefaultValue(double value) { + return value < plusEpsilon && value > minusEpsilon; } /** {@inheritDoc} */ - public OpenMapRealVector add(RealVector v) throws IllegalArgumentException { + public RealVector add(RealVector v) throws IllegalArgumentException { checkVectorDimensions(v.getDimension()); if (v instanceof OpenMapRealVector) { return add((OpenMapRealVector) v); + } else { + return super.add(v); } - return add(v.getData()); } /** - * Optimized method to add two OpenMapRealVectors. + * Optimized method to add two OpenMapRealVectors. Copies the larger vector, iterates over the smaller. * @param v Vector to add with * @return The sum of this with v * @throws IllegalArgumentException If the dimensions don't match */ public OpenMapRealVector add(OpenMapRealVector v) throws IllegalArgumentException{ checkVectorDimensions(v.getDimension()); - OpenMapRealVector res = copy(); - Iterator iter = v.getEntries().iterator(); + boolean copyThis = entries.size() > v.entries.size(); + OpenMapRealVector res = copyThis ? this.copy() : v.copy(); + Iterator iter = copyThis ? v.entries.iterator() : entries.iterator(); + OpenIntToDoubleHashMap randomAccess = copyThis ? entries : v.entries; while (iter.hasNext()) { iter.advance(); int key = iter.key(); - if (entries.containsKey(key)) { - res.setEntry(key, entries.get(key) + iter.value()); + if (randomAccess.containsKey(key)) { + res.setEntry(key, randomAccess.get(key) + iter.value()); } else { res.setEntry(key, iter.value()); } @@ -252,16 +259,6 @@ public class OpenMapRealVector implements SparseRealVector, Serializable { return res; } - /** {@inheritDoc} */ - public OpenMapRealVector add(double[] v) throws IllegalArgumentException { - checkVectorDimensions(v.length); - OpenMapRealVector res = new OpenMapRealVector(getDimension()); - for (int i = 0; i < v.length; i++) { - res.setEntry(i, v[i] + getEntry(i)); - } - return res; - } - /** * Optimized method to append a OpenMapRealVector. * @param v vector to append @@ -306,33 +303,6 @@ public class OpenMapRealVector implements SparseRealVector, Serializable { return new OpenMapRealVector(this); } - /** {@inheritDoc} */ - public double dotProduct(RealVector v) throws IllegalArgumentException { - checkVectorDimensions(v.getDimension()); - double res = 0; - Iterator iter = entries.iterator(); - while (iter.hasNext()) { - iter.advance(); - res += v.getEntry(iter.key()) * iter.value(); - } - return res; - } - - /** {@inheritDoc} */ - public double dotProduct(double[] v) throws IllegalArgumentException { - checkVectorDimensions(v.length); - double res = 0; - Iterator iter = entries.iterator(); - while (iter.hasNext()) { - int idx = iter.key(); - double value = 0; - if (idx < v.length) { - value = v[idx]; - } - res += value * iter.value(); - } - return res; - } /** {@inheritDoc} */ public OpenMapRealVector ebeDivide(RealVector v) throws IllegalArgumentException { @@ -1099,7 +1069,7 @@ public class OpenMapRealVector implements SparseRealVector, Serializable { /** {@inheritDoc} */ public void setEntry(int index, double value) throws MatrixIndexException { checkIndex(index); - if (!isZero(value)) { + if (!isDefaultValue(value)) { entries.put(index, value); } else if (entries.containsKey(index)) { entries.remove(index); @@ -1185,7 +1155,7 @@ public class OpenMapRealVector implements SparseRealVector, Serializable { /** {@inheritDoc} */ public void unitize() { double norm = getNorm(); - if (isZero(norm)) { + if (isDefaultValue(norm)) { throw MathRuntimeException.createArithmeticException("cannot normalize a zero norm vector"); } Iterator iter = entries.iterator(); @@ -1196,37 +1166,6 @@ public class OpenMapRealVector implements SparseRealVector, Serializable { } - /** - * Check if an index is valid. - * - * @param index - * index to check - * @exception MatrixIndexException - * if index is not valid - */ - private void checkIndex(final int index) throws MatrixIndexException { - if (index < 0 || index >= getDimension()) { - throw new MatrixIndexException( - "index {0} out of allowed range [{1}, {2}]", - index, 0, getDimension() - 1); - } - } - - /** - * Check if instance dimension is equal to some expected value. - * - * @param n - * expected dimension. - * @exception IllegalArgumentException - * if the dimension is inconsistent with vector size - */ - protected void checkVectorDimensions(int n) throws IllegalArgumentException { - if (getDimension() != n) { - throw MathRuntimeException.createIllegalArgumentException( - "vector length mismatch: got {0} but expected {1}", - getDimension(), n); - } - } /** {@inheritDoc} */ public double[] toArray() { @@ -1243,7 +1182,7 @@ public class OpenMapRealVector implements SparseRealVector, Serializable { final int prime = 31; int result = 1; long temp; - temp = Double.doubleToLongBits(epsilon); + temp = Double.doubleToLongBits(plusEpsilon) + Double.doubleToLongBits(minusEpsilon); result = prime * result + (int) (temp ^ (temp >>> 32)); result = prime * result + virtualSize; Iterator iter = entries.iterator(); @@ -1276,8 +1215,12 @@ public class OpenMapRealVector implements SparseRealVector, Serializable { if (virtualSize != other.virtualSize) { return false; } - if (Double.doubleToLongBits(epsilon) != - Double.doubleToLongBits(other.epsilon)) { + if (Double.doubleToLongBits(minusEpsilon) != + Double.doubleToLongBits(other.minusEpsilon)) { + return false; + } + if (Double.doubleToLongBits(plusEpsilon) != + Double.doubleToLongBits(other.plusEpsilon)) { return false; } Iterator iter = entries.iterator(); diff --git a/src/main/java/org/apache/commons/math/linear/RealVector.java b/src/main/java/org/apache/commons/math/linear/RealVector.java index 559c788a9..d7145a36c 100644 --- a/src/main/java/org/apache/commons/math/linear/RealVector.java +++ b/src/main/java/org/apache/commons/math/linear/RealVector.java @@ -16,6 +16,12 @@ */ package org.apache.commons.math.linear; +import java.util.Iterator; + +import org.apache.commons.math.FunctionEvaluationException; +import org.apache.commons.math.analysis.UnivariateRealFunction; + + /** * Interface defining a real-valued vector with basic algebraic operations. *

@@ -41,6 +47,74 @@ package org.apache.commons.math.linear; */ public interface RealVector { + /** + * Acts as if it is implemented as: + * Entry e = null; + * for(Iterator it = iterator(); it.hasNext(); e = it.next()) { + * e.setValue(function.value(e.getValue())); + * } + * @param function to apply to each successive entry + * @return this vector + * @throws FunctionEvaluationException if function throws it on application to any entry + */ + RealVector mapToSelf(UnivariateRealFunction function) throws FunctionEvaluationException; + + /** + * Acts as if implemented as: + * return copy().map(function); + * @param function to apply to each successive entry + * @return a new vector + * @throws FunctionEvaluationException if function throws it on application to any entry + */ + RealVector map(UnivariateRealFunction function) throws FunctionEvaluationException; + + /** Class representing a modifiable entry in the vector. */ + public abstract class Entry { + + /** Index of the entry. */ + private int index; + + /** Get the value of the entry. + * @return value of the entry + */ + public abstract double getValue(); + + /** Set the value of the entry. + * @param value new value for the entry + */ + public abstract void setValue(double value); + + /** Get the index of the entry. + * @return index of the entry + */ + public int getIndex() { + return index; + } + + /** Set the index of the entry. + * @param index new index for the entry + */ + public void setIndex(int index) { + this.index = index; + } + + } + + /** + * Generic dense iterator - starts with index == zero, and hasNext() == true until index == getDimension(); + * @return a dense iterator + */ + Iterator iterator(); + + /** + * Specialized implementations may choose to not iterate over all dimensions, either because those values are + * unset, or are equal to defaultValue(), or are small enough to be ignored for the purposes of iteration. + * No guarantees are made about order of iteration. + * In dense implementations, this method will often delegate to {@see #iterator() } + * @return a sparse iterator + */ + Iterator sparseIterator(); + /** * Returns a (deep) copy of this. * @return vector copy diff --git a/src/site/xdoc/changes.xml b/src/site/xdoc/changes.xml index ca18f07c4..f64cb18e2 100644 --- a/src/site/xdoc/changes.xml +++ b/src/site/xdoc/changes.xml @@ -39,6 +39,10 @@ The type attribute can be add,update,fix,remove. + + Added mapping and iteration methods to vectors. Provided a default implementation + for the numerous simple methods in the RealVectorInterface. + Fixed an error in handling very close events in ODE integration. diff --git a/src/test/java/org/apache/commons/math/linear/AbstractRealVectorTest.java b/src/test/java/org/apache/commons/math/linear/AbstractRealVectorTest.java new file mode 100644 index 000000000..f5acc9d13 --- /dev/null +++ b/src/test/java/org/apache/commons/math/linear/AbstractRealVectorTest.java @@ -0,0 +1,208 @@ +package org.apache.commons.math.linear; + +import junit.framework.TestCase; +import org.apache.commons.math.analysis.UnivariateRealFunction; +import org.apache.commons.math.linear.RealVector.Entry; + +import java.util.Iterator; +import java.util.Random; + +/** + * + */ +public class AbstractRealVectorTest extends TestCase { + private double[] vec1 = { 1d, 2d, 3d, 4d, 5d }; + private double[] vec2 = { -3d, 0d, 0d, 2d, 1d }; + + private static class TestVectorImpl extends AbstractRealVector { + private double[] values; + + TestVectorImpl(double[] values) { + this.values = values; + } + + @Override + public double[] getData() { return values; } + + @Override + public AbstractRealVector copy() { + return new TestVectorImpl(values.clone()); + } + + + UnsupportedOperationException unsupported() { + return new UnsupportedOperationException("Test implementation only supports methods necessary for testing"); + } + + public RealVector add(RealVector v) throws IllegalArgumentException { + RealVector result = new ArrayRealVector(v); + return result.add(this); + } + + public RealVector subtract(RealVector v) throws IllegalArgumentException { + RealVector result = new ArrayRealVector(v); + return result.subtract(this).mapMultiplyToSelf(-1); + } + + public RealVector mapAddToSelf(double d) { + for(int i=0; i it = v.iterator(); it.hasNext() && (e = it.next()) != null; i++) { + assertEquals(vec2[i], e.getValue()); + } + } + + public void testSparseIterator() throws Exception { + RealVector v = new TestVectorImpl(vec2.clone()); + Entry e; + int i = 0; + double[] nonDefaultV2 = { -3d, 2d, 1d }; + for(Iterator it = v.sparseIterator(); it.hasNext() && (e = it.next()) != null; i++) { + assertEquals(nonDefaultV2[i], e.getValue()); + } + } + + public void testClone() throws Exception { + double[] d = new double[1000000]; + Random r = new Random(1234); + for(int i=0;i 0); + double[] c = d.clone(); + c[0] = 1; + assertNotSame(c[0], d[0]); + d[0] = 1; + assertEquals(new ArrayRealVector(d).getNorm(), new ArrayRealVector(c).getNorm()); + long cloneTime = 0; + long setAndAddTime = 0; + for(int i=0; i<10; i++) { + long start = System.nanoTime(); + double[] v = d.clone(); + for(int j=0; j 4) cloneTime += System.nanoTime() - start; + start = System.nanoTime(); + v = new double[d.length]; + for(int j=0; j 4) setAndAddTime += System.nanoTime() - start; + } + } +} diff --git a/src/test/java/org/apache/commons/math/linear/ArrayRealVectorTest.java b/src/test/java/org/apache/commons/math/linear/ArrayRealVectorTest.java index 10ffbff83..27ce2591a 100644 --- a/src/test/java/org/apache/commons/math/linear/ArrayRealVectorTest.java +++ b/src/test/java/org/apache/commons/math/linear/ArrayRealVectorTest.java @@ -17,12 +17,15 @@ package org.apache.commons.math.linear; import java.io.Serializable; +import java.util.Iterator; import junit.framework.Test; import junit.framework.TestCase; import junit.framework.TestSuite; +import org.apache.commons.math.FunctionEvaluationException; import org.apache.commons.math.TestUtils; +import org.apache.commons.math.analysis.UnivariateRealFunction; /** * Test cases for the {@link ArrayRealVector} class. @@ -63,6 +66,41 @@ public class ArrayRealVectorTest extends TestCase { return new UnsupportedOperationException("Not supported, unneeded for test purposes"); } + public RealVector map(UnivariateRealFunction function) throws FunctionEvaluationException { + throw unsupported(); + } + + public RealVector mapToSelf(UnivariateRealFunction function) throws FunctionEvaluationException { + throw unsupported(); + } + + public Iterator iterator() { + return new Iterator() { + int i = 0; + public boolean hasNext() { + return i sparseIterator() { + return iterator(); + } + public RealVector copy() { throw unsupported(); } diff --git a/src/test/java/org/apache/commons/math/linear/SparseRealVectorTest.java b/src/test/java/org/apache/commons/math/linear/SparseRealVectorTest.java index b0609d344..1adf25c54 100644 --- a/src/test/java/org/apache/commons/math/linear/SparseRealVectorTest.java +++ b/src/test/java/org/apache/commons/math/linear/SparseRealVectorTest.java @@ -17,12 +17,15 @@ package org.apache.commons.math.linear; import java.io.Serializable; +import java.util.Iterator; import junit.framework.Test; import junit.framework.TestCase; import junit.framework.TestSuite; +import org.apache.commons.math.FunctionEvaluationException; import org.apache.commons.math.TestUtils; +import org.apache.commons.math.analysis.UnivariateRealFunction; /** * Test cases for the {@link OpenMapRealVector} class. @@ -63,10 +66,26 @@ public class SparseRealVectorTest extends TestCase { return new UnsupportedOperationException("Not supported, unneeded for test purposes"); } - public RealVector copy() { + public RealVector map(UnivariateRealFunction function) throws FunctionEvaluationException { throw unsupported(); } + public RealVector mapToSelf(UnivariateRealFunction function) throws FunctionEvaluationException { + throw unsupported(); + } + + public Iterator iterator() { + throw unsupported(); + } + + public Iterator sparseIterator() { + throw unsupported(); + } + + public RealVector copy() { + return new SparseRealVectorTestImpl(data); + } + public RealVector add(RealVector v) throws IllegalArgumentException { throw unsupported(); } @@ -432,7 +451,7 @@ public class SparseRealVectorTest extends TestCase { } public void setEntry(int index, double value) throws MatrixIndexException { - throw unsupported(); + data[index] = value; } public void setSubVector(int index, RealVector v) throws MatrixIndexException {