You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@commons.apache.org by lu...@apache.org on 2009/12/09 23:56:12 UTC

svn commit: r889008 - in /commons/proper/math/trunk/src: main/java/org/apache/commons/math/linear/ site/xdoc/ test/java/org/apache/commons/math/linear/

Author: luc
Date: Wed Dec  9 22:56:11 2009
New Revision: 889008

URL: http://svn.apache.org/viewvc?rev=889008&view=rev
Log:
Added mapping and iteration methods to vectors.
Provided a default implementation for the numerous simple methods in the RealVectorInterface.

Added:
    commons/proper/math/trunk/src/main/java/org/apache/commons/math/linear/AbstractRealVector.java   (with props)
    commons/proper/math/trunk/src/test/java/org/apache/commons/math/linear/AbstractRealVectorTest.java   (with props)
Modified:
    commons/proper/math/trunk/src/main/java/org/apache/commons/math/linear/ArrayRealVector.java
    commons/proper/math/trunk/src/main/java/org/apache/commons/math/linear/OpenMapRealVector.java
    commons/proper/math/trunk/src/main/java/org/apache/commons/math/linear/RealVector.java
    commons/proper/math/trunk/src/site/xdoc/changes.xml
    commons/proper/math/trunk/src/test/java/org/apache/commons/math/linear/ArrayRealVectorTest.java
    commons/proper/math/trunk/src/test/java/org/apache/commons/math/linear/SparseRealVectorTest.java

Added: commons/proper/math/trunk/src/main/java/org/apache/commons/math/linear/AbstractRealVector.java
URL: http://svn.apache.org/viewvc/commons/proper/math/trunk/src/main/java/org/apache/commons/math/linear/AbstractRealVector.java?rev=889008&view=auto
==============================================================================
--- commons/proper/math/trunk/src/main/java/org/apache/commons/math/linear/AbstractRealVector.java (added)
+++ commons/proper/math/trunk/src/main/java/org/apache/commons/math/linear/AbstractRealVector.java Wed Dec  9 22:56:11 2009
@@ -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<Entry> 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<Entry> 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<Entry> 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<Entry> 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<Entry> 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<Entry> 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<Entry> 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<Entry> 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<Entry> 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<Entry> 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<Entry> 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<Entry> 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<Entry> thisIt = sparseIterator();
+        Entry thisE = null;
+        while (thisIt.hasNext() && (thisE = thisIt.next()) != null) {
+            Iterator<Entry> 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<Entry> 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<Entry> sparseIterator() {
+        return new SparseEntryIterator();
+    }
+
+    /** {@inheritDoc} */
+    public Iterator<Entry> iterator() {
+        final int dim = getDimension();
+        return new Iterator<Entry>() {
+
+            /** 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<Entry> 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<Entry> {
+
+        /** 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");
+        }
+    }
+
+}

Propchange: commons/proper/math/trunk/src/main/java/org/apache/commons/math/linear/AbstractRealVector.java
------------------------------------------------------------------------------
    svn:eol-style = native

Propchange: commons/proper/math/trunk/src/main/java/org/apache/commons/math/linear/AbstractRealVector.java
------------------------------------------------------------------------------
    svn:keywords = Author Date Id Revision

Modified: commons/proper/math/trunk/src/main/java/org/apache/commons/math/linear/ArrayRealVector.java
URL: http://svn.apache.org/viewvc/commons/proper/math/trunk/src/main/java/org/apache/commons/math/linear/ArrayRealVector.java?rev=889008&r1=889007&r2=889008&view=diff
==============================================================================
--- commons/proper/math/trunk/src/main/java/org/apache/commons/math/linear/ArrayRealVector.java (original)
+++ commons/proper/math/trunk/src/main/java/org/apache/commons/math/linear/ArrayRealVector.java Wed Dec  9 22:56:11 2009
@@ -18,6 +18,7 @@
 
 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 @@
  * @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 @@
      * @param v vector to copy
      */
     public ArrayRealVector(ArrayRealVector v) {
-        data = v.data.clone();
+        this(v, true);
     }
 
     /**
@@ -223,20 +224,22 @@
     }
 
     /** {@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<Entry> 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 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 @@
     /** {@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<Entry> 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 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);
     }
@@ -302,15 +307,6 @@
     }
 
     /** {@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++) {
             data[i] = data[i] + d;
@@ -319,15 +315,6 @@
     }
 
     /** {@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++) {
             data[i] = data[i] - d;
@@ -336,15 +323,6 @@
     }
 
     /** {@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++) {
             data[i] = data[i] * d;
@@ -353,15 +331,6 @@
     }
 
     /** {@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++) {
             data[i] = data[i] / d;
@@ -370,15 +339,6 @@
     }
 
     /** {@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++) {
             data[i] = Math.pow(data[i], d);
@@ -387,15 +347,6 @@
     }
 
     /** {@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++) {
             data[i] = Math.exp(data[i]);
@@ -404,15 +355,6 @@
     }
 
     /** {@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++) {
             data[i] = Math.expm1(data[i]);
@@ -421,15 +363,6 @@
     }
 
     /** {@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++) {
             data[i] = Math.log(data[i]);
@@ -438,15 +371,6 @@
     }
 
     /** {@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++) {
             data[i] = Math.log10(data[i]);
@@ -455,15 +379,6 @@
     }
 
     /** {@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++) {
             data[i] = Math.log1p(data[i]);
@@ -472,15 +387,6 @@
     }
 
     /** {@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++) {
             data[i] = Math.cosh(data[i]);
@@ -489,15 +395,6 @@
     }
 
     /** {@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++) {
             data[i] = Math.sinh(data[i]);
@@ -506,15 +403,6 @@
     }
 
     /** {@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++) {
             data[i] = Math.tanh(data[i]);
@@ -523,15 +411,6 @@
     }
 
     /** {@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++) {
             data[i] = Math.cos(data[i]);
@@ -540,15 +419,6 @@
     }
 
     /** {@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++) {
             data[i] = Math.sin(data[i]);
@@ -557,15 +427,6 @@
     }
 
     /** {@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++) {
             data[i] = Math.tan(data[i]);
@@ -574,15 +435,6 @@
     }
 
     /** {@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++) {
             data[i] = Math.acos(data[i]);
@@ -591,15 +443,6 @@
     }
 
     /** {@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++) {
             data[i] = Math.asin(data[i]);
@@ -608,15 +451,6 @@
     }
 
     /** {@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++) {
             data[i] = Math.atan(data[i]);
@@ -625,15 +459,6 @@
     }
 
     /** {@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++) {
             data[i] = 1.0 / data[i];
@@ -642,15 +467,6 @@
     }
 
     /** {@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++) {
             data[i] = Math.abs(data[i]);
@@ -659,15 +475,6 @@
     }
 
     /** {@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++) {
             data[i] = Math.sqrt(data[i]);
@@ -676,15 +483,6 @@
     }
 
     /** {@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++) {
             data[i] = Math.cbrt(data[i]);
@@ -693,15 +491,6 @@
     }
 
     /** {@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++) {
             data[i] = Math.ceil(data[i]);
@@ -710,15 +499,6 @@
     }
 
     /** {@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++) {
             data[i] = Math.floor(data[i]);
@@ -727,15 +507,6 @@
     }
 
     /** {@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++) {
             data[i] = Math.rint(data[i]);
@@ -744,15 +515,6 @@
     }
 
     /** {@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++) {
             data[i] = Math.signum(data[i]);
@@ -761,15 +523,6 @@
     }
 
     /** {@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++) {
             data[i] = Math.ulp(data[i]);
@@ -780,15 +533,15 @@
     /** {@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 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 @@
     /** {@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 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 @@
     /** {@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<Entry> it = v.sparseIterator();
+            Entry e;
+            while(it.hasNext() && (e = it.next()) != null) {
+                dot += data[e.getIndex()] * e.getValue();
             }
             return dot;
         }
@@ -932,9 +687,9 @@
     /** {@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 @@
     /** {@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 @@
     /** {@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 @@
         if (norm == 0) {
             throw MathRuntimeException.createArithmeticException("zero norm");
         }
-        return mapDivide(getNorm());
+        return mapDivide(norm);
     }
 
     /** {@inheritDoc} */
@@ -1082,9 +837,7 @@
         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 @@
     /** {@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 @@
         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;
+      RealVector rhs = (RealVector) other;
+      if (data.length != rhs.getDimension()) {
+        return false;
+      }
 
-      } catch (ClassCastException ex) {
-          // ignore exception
-          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 @@
         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);
-        }
-    }
-
 }

Modified: commons/proper/math/trunk/src/main/java/org/apache/commons/math/linear/OpenMapRealVector.java
URL: http://svn.apache.org/viewvc/commons/proper/math/trunk/src/main/java/org/apache/commons/math/linear/OpenMapRealVector.java?rev=889008&r1=889007&r2=889008&view=diff
==============================================================================
--- commons/proper/math/trunk/src/main/java/org/apache/commons/math/linear/OpenMapRealVector.java (original)
+++ commons/proper/math/trunk/src/main/java/org/apache/commons/math/linear/OpenMapRealVector.java Wed Dec  9 22:56:11 2009
@@ -27,7 +27,7 @@
  * @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 @@
     /** 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 @@
      * into this vector.</p>
      */
     public OpenMapRealVector() {
-        this(0, DEFAULT_ZERO_TOLERANCE);
+        this(0, DEFAULT_ZERO_TOLERANCE, 0);
     }
 
     /**
@@ -62,18 +65,19 @@
      * @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 @@
     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 @@
      * @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 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 @@
      * @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 @@
      * 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 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 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 @@
     }
 
     /**
-     * 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 <code>true</code> if this value is zero, <code>false</code> 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
+     * @return <code>true</code> if this value is within epsilon to the defaultValue, <code>false</code> otherwise
      */
-    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 <code>this</code> with <code>v</code>
      * @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 @@
         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 @@
         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 @@
     /** {@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 @@
     /** {@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 @@
 
     }
 
-    /**
-     * 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 @@
         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 @@
         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();

Modified: commons/proper/math/trunk/src/main/java/org/apache/commons/math/linear/RealVector.java
URL: http://svn.apache.org/viewvc/commons/proper/math/trunk/src/main/java/org/apache/commons/math/linear/RealVector.java?rev=889008&r1=889007&r2=889008&view=diff
==============================================================================
--- commons/proper/math/trunk/src/main/java/org/apache/commons/math/linear/RealVector.java (original)
+++ commons/proper/math/trunk/src/main/java/org/apache/commons/math/linear/RealVector.java Wed Dec  9 22:56:11 2009
@@ -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.
  * <p>
@@ -42,6 +48,74 @@
 public interface RealVector {
 
     /**
+     * Acts as if it is implemented as:
+     * Entry e = null;
+     * for(Iterator<Entry> 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<Entry> 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<Entry> sparseIterator();
+
+    /**
      * Returns a (deep) copy of this.
      * @return vector copy
      */

Modified: commons/proper/math/trunk/src/site/xdoc/changes.xml
URL: http://svn.apache.org/viewvc/commons/proper/math/trunk/src/site/xdoc/changes.xml?rev=889008&r1=889007&r2=889008&view=diff
==============================================================================
--- commons/proper/math/trunk/src/site/xdoc/changes.xml (original)
+++ commons/proper/math/trunk/src/site/xdoc/changes.xml Wed Dec  9 22:56:11 2009
@@ -39,6 +39,10 @@
   </properties>
   <body>
     <release version="2.1" date="TBD" description="TBD">
+      <action dev="luc" type="fix" issue="MATH-312" due-to="Jake Mannix">
+        Added mapping and iteration methods to vectors. Provided a default implementation
+        for the numerous simple methods in the RealVectorInterface.
+      </action>
       <action dev="luc" type="fix" issue="MATH-322" >
         Fixed an error in handling very close events in ODE integration.
       </action>

Added: commons/proper/math/trunk/src/test/java/org/apache/commons/math/linear/AbstractRealVectorTest.java
URL: http://svn.apache.org/viewvc/commons/proper/math/trunk/src/test/java/org/apache/commons/math/linear/AbstractRealVectorTest.java?rev=889008&view=auto
==============================================================================
--- commons/proper/math/trunk/src/test/java/org/apache/commons/math/linear/AbstractRealVectorTest.java (added)
+++ commons/proper/math/trunk/src/test/java/org/apache/commons/math/linear/AbstractRealVectorTest.java Wed Dec  9 22:56:11 2009
@@ -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<values.length; i++) {
+                values[i] += d;
+            }
+            return this;
+        }
+
+        public RealVector mapSubtractToSelf(double d) {
+            for(int i=0; i<values.length; i++) {
+                values[i] -= d;
+            }
+            return this;
+        }
+
+        public RealVector mapMultiplyToSelf(double d) {
+            for(int i=0; i<values.length; i++) {
+                values[i] *= d;
+            }
+            return this;
+        }
+
+        public RealVector mapDivideToSelf(double d) {
+            for(int i=0; i<values.length; i++) {
+                values[i] /= d;
+            }
+            return this;
+        }
+
+        public RealVector mapPowToSelf(double d) {
+            for(int i=0; i<values.length; i++) {
+                values[i] = Math.pow(values[i], d);
+            }
+            return this;
+        }
+
+        public RealVector mapInvToSelf() {
+            for(int i=0; i<values.length; i++) {
+                values[i] = 1/values[i];
+            }
+            return this;
+        }
+
+        public RealVector ebeMultiply(RealVector v) throws IllegalArgumentException {
+            throw unsupported();
+        }
+
+        public RealVector ebeDivide(RealVector v) throws IllegalArgumentException {
+            throw unsupported();
+        }
+
+        public double dotProduct(RealVector v) throws IllegalArgumentException {
+            throw unsupported();
+        }
+
+        public double getNorm() {
+            throw unsupported();
+        }
+
+        public double getL1Norm() {
+            throw unsupported();
+        }
+
+        public double getLInfNorm() {
+            throw unsupported();
+        }
+
+        public RealVector projection(RealVector v) throws IllegalArgumentException {
+            throw unsupported();
+        }
+
+        public double getEntry(int index) throws MatrixIndexException {
+            return values[index];
+        }
+
+        public void setEntry(int index, double value) throws MatrixIndexException {
+            values[index] = value;
+        }
+
+        public int getDimension() {
+            return values.length;
+        }
+
+        public RealVector append(RealVector v) {
+            throw unsupported();
+        }
+
+        public RealVector append(double d) {
+            throw unsupported();
+        }
+
+        public RealVector append(double[] a) {
+            throw unsupported();
+        }
+
+        public RealVector getSubVector(int index, int n) throws MatrixIndexException {
+            throw unsupported();
+        }
+
+        public boolean isNaN() {
+            throw unsupported();
+        }
+
+        public boolean isInfinite() {
+            throw unsupported();
+        }
+    }
+
+    private static void assertEquals(double[] d1, double[] d2) {
+        assertEquals(d1.length, d2.length);
+        for(int i=0; i<d1.length; i++) assertEquals(d1[i], d2[i]);
+    }
+
+    public void testMap() throws Exception {
+        double[] vec1Squared = { 1d, 4d, 9d, 16d, 25d };
+        RealVector v = new TestVectorImpl(vec1.clone());
+        RealVector w = v.map(new UnivariateRealFunction() { public double value(double x) { return x * x; } });
+        assertEquals(vec1Squared, w.getData());
+    }
+
+    public void testIterator() throws Exception {
+        RealVector v = new TestVectorImpl(vec2.clone());
+        Entry e;
+        int i = 0;
+        for(Iterator<Entry> 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<Entry> 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<d.length; i++) d[i] = r.nextDouble();
+        assertTrue(new ArrayRealVector(d).getNorm() > 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<v.length; j++) v[j] += 1234.5678;
+          if(i > 4) cloneTime += System.nanoTime() - start;
+          start = System.nanoTime();
+          v = new double[d.length];
+          for(int j=0; j<v.length; j++) v[j] = d[j] + 1234.5678;
+          if(i > 4) setAndAddTime += System.nanoTime() - start;
+        }
+    }
+}

Propchange: commons/proper/math/trunk/src/test/java/org/apache/commons/math/linear/AbstractRealVectorTest.java
------------------------------------------------------------------------------
    svn:eol-style = native

Propchange: commons/proper/math/trunk/src/test/java/org/apache/commons/math/linear/AbstractRealVectorTest.java
------------------------------------------------------------------------------
    svn:keywords = Author Date Id Revision

Modified: commons/proper/math/trunk/src/test/java/org/apache/commons/math/linear/ArrayRealVectorTest.java
URL: http://svn.apache.org/viewvc/commons/proper/math/trunk/src/test/java/org/apache/commons/math/linear/ArrayRealVectorTest.java?rev=889008&r1=889007&r2=889008&view=diff
==============================================================================
--- commons/proper/math/trunk/src/test/java/org/apache/commons/math/linear/ArrayRealVectorTest.java (original)
+++ commons/proper/math/trunk/src/test/java/org/apache/commons/math/linear/ArrayRealVectorTest.java Wed Dec  9 22:56:11 2009
@@ -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 @@
             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<Entry> iterator() {
+            return new Iterator<Entry>() {
+                int i = 0;
+                public boolean hasNext() {
+                    return i<data.length;
+                }
+                public Entry next() {
+                    final int j = i++;
+                    Entry e = new Entry() {
+                        public double getValue() {
+                            return data[j];
+                        }
+                        public void setValue(double newValue) {
+                            data[j] = newValue;
+                        }
+                    };
+                    e.setIndex(j);
+                    return e;
+                }
+                public void remove() { }
+            };
+        }
+
+        public Iterator<Entry> sparseIterator() {
+            return iterator();
+        }
+
         public RealVector copy() {
             throw unsupported();
         }

Modified: commons/proper/math/trunk/src/test/java/org/apache/commons/math/linear/SparseRealVectorTest.java
URL: http://svn.apache.org/viewvc/commons/proper/math/trunk/src/test/java/org/apache/commons/math/linear/SparseRealVectorTest.java?rev=889008&r1=889007&r2=889008&view=diff
==============================================================================
--- commons/proper/math/trunk/src/test/java/org/apache/commons/math/linear/SparseRealVectorTest.java (original)
+++ commons/proper/math/trunk/src/test/java/org/apache/commons/math/linear/SparseRealVectorTest.java Wed Dec  9 22:56:11 2009
@@ -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 @@
             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<Entry> iterator() {
             throw unsupported();
         }
 
+        public Iterator<Entry> sparseIterator() {
+            throw unsupported();
+        }
+
+        public RealVector copy() {
+            return new SparseRealVectorTestImpl(data);
+        }
+
         public RealVector add(RealVector v) throws IllegalArgumentException {
             throw unsupported();
         }
@@ -432,7 +451,7 @@
         }
 
         public void setEntry(int index, double value) throws MatrixIndexException {
-            throw unsupported();
+            data[index] = value;
         }
 
         public void setSubVector(int index, RealVector v) throws MatrixIndexException {



Re: svn commit: r889008 - in /commons/proper/math/trunk/src: main/java/org/apache/commons/math/linear/ site/xdoc/ test/java/org/apache/commons/math/linear/

Posted by Jake Mannix <ja...@gmail.com>.
Hey Bill,

  I'm glad you looked at this!  You point out something which is really
weird - as my comment in the JIRA ticket indicates, I believe I removed any
allowing of nonzero default values, for exactly the reasons you brought up
(in short, they're a total pain to deal with), and many more:

"New patch. This one has no reference to the "nonzero default values" for
sparse vectors, which can be addressed in another JIRA ticket. This patch
now only deals with the following files: "

At least I *thought* I'd reverted that change in the patch, and that's what
I was trying to submit.  I have to look at the set of patches which were on
that ticket, and if neither of them were what I thought, then mea culpa,
that should have been removed (and I wish you'd responded to my comment in
the JIRA implying that I had already fixed it, and asking you if you were
using the most recent patch - had you replied saying 'yes I am, actually!',
I could have caught this and fixed it ages ago)!

On Wed, Dec 9, 2009 at 9:28 PM, Bill Barker <bi...@verizon.net> wrote:

> There are some things I don't like about this, but will try to find the
> time to fix them myself .  Comments inline (and I can't veto anything in
> [math], so these are just suggestions).
>
> +        /** Simple constructor. */
>> +        protected SparseEntryIterator() {
>> +            dim = getDimension();
>> +            current = new EntryImpl();
>> +            if (current.getValue() == 0) {
>> +                advance(current);
>> +            }
>>
>
> This totally doesn't work if the vector consists of all zero elements.  The
> 'hasNext' method (below) will return true, and you will get an exception
> trying to get the first element.


Yes, this is a great unit test case, should have been checked for (and is a
special case, which should possibly be dealt with separately).

And actually, as I mention in the javadocs for this SparseIterator class,
this class has limited usefulness: when would *not* writing a specialized
implementation of iterateNonZero() be done in particular implementations of
RealVector?  In Mahout's version of this class, the contract is a little
looser: iterateNonZero() doesn't try to gaurantee that it only iterates over
nonzero elements, it is really just the "sparseIterator" - default behavior
in the abstract base class is to delegate iterateNonZero() to iterate(), and
let subclasses decide whether there is something more sparse that can be
done.  I think that's a lot cleaner, and avoids the dancing you have to do
to walk the AbstractRealVector sparsely without knowing what your
implementation is.


  -jake

Re: svn commit: r889008 - in /commons/proper/math/trunk/src: main/java/org/apache/commons/math/linear/ site/xdoc/ test/java/org/apache/commons/math/linear/

Posted by Bill Barker <bi...@verizon.net>.
There are some things I don't like about this, but will try to find the time 
to fix them myself .  Comments inline (and I can't veto anything in [math], 
so these are just suggestions).

----- Original Message ----- 
From: <lu...@apache.org>
To: <co...@commons.apache.org>
Sent: Wednesday, December 09, 2009 2:56 PM
Subject: svn commit: r889008 - in /commons/proper/math/trunk/src: 
main/java/org/apache/commons/math/linear/ site/xdoc/ 
test/java/org/apache/commons/math/linear/


> Author: luc
> Date: Wed Dec  9 22:56:11 2009
> New Revision: 889008
>
> URL: http://svn.apache.org/viewvc?rev=889008&view=rev
> Log:
> Added mapping and iteration methods to vectors.
> Provided a default implementation for the numerous simple methods in the 
> RealVectorInterface.
>
> +    protected class SparseEntryIterator implements Iterator<Entry> {
> +
> +        /** 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);
> +            }

This totally doesn't work if the vector consists of all zero elements.  The 
'hasNext' method (below) will return true, and you will get an exeption 
trying to get the first element.

> +            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);
> +            }
> +        }

This is fragile, since it relies on e.getIndex() == -1 when invalid (and 
then you scan the vector once more).

> +
> +        /** {@inheritDoc} */
> +        public boolean hasNext() {
> +            return current != null;
> +        }
> +

quick fix is to check that current.getIndex() >= 0

> +        /** {@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");
> +        }
> +    }
> +
> +}
>
> Modified: 
> commons/proper/math/trunk/src/main/java/org/apache/commons/math/linear/OpenMapRealVector.java
> URL: 
> http://svn.apache.org/viewvc/commons/proper/math/trunk/src/main/java/org/apache/commons/math/linear/OpenMapRealVector.java?rev=889008&r1=889007&r2=889008&view=diff
> ==============================================================================
> ---  
> commons/proper/math/trunk/src/main/java/org/apache/commons/math/linear/OpenMapRealVector.java 
> (original)
> +++ 
> commons/proper/math/trunk/src/main/java/org/apache/commons/math/linear/OpenMapRealVector.java 
> Wed Dec  9 22:56:11 2009
> @@ -27,7 +27,7 @@
>  * @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 @@
>     /** 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;
>

If non-zero defaultValues are allowed, then we need to store the 
defaultValue, to avoid floating point precision issues where (plusEpsilon + 
minusEpsilon)/2 != defaultValue.

>     /**
>      * Build a 0-length vector.
> @@ -54,7 +57,7 @@
>      * into this vector.</p>
>      */
>     public OpenMapRealVector() {
> -        this(0, DEFAULT_ZERO_TOLERANCE);
> +        this(0, DEFAULT_ZERO_TOLERANCE, 0);
>     }
>
>     /**
> @@ -62,18 +65,19 @@
>      * @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);
>     }
>

As I stated in the Jira issue, I really dislike supporting non-zero 
defaultValues here.  It causes too many things to just produce nonsensical 
results:

   RealVector v = new OpenMapRealVector(1000, 1.0e-12, 1);
   assertEquals(v.getEntry(0), 0); // passes

   RealVector v = new OpenMapRealVector(1000, 1.0e-12, 1);
   RealVector w = new OpenMapRealVector(1000, 1.0e-12, 2);
   assertEquals(v.add(w).getEntry(0), 0); // passes



>     /** {@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 <code>this</code> with <code>v</code>
>      * @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());
>             }

This only works (in a wonderland sense of working) when both sides have the 
same defaultValue.

> @@ -252,16 +259,6 @@
>         return res;
>     }
>
> -    /** {@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;
> -    }
> -

For this class to be useful, it needs it's own sparseIterator() method to 
cover delegating this method to the base class.

> @@ -1185,7 +1155,7 @@
>     /** {@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 @@
>
>     }

This one is just silly.  This results in:
     RealVector v = new OpenMapRealVector(1000, 1.0e-12, 1);
     v.setEntry(0,1);
     v.unitize();
throwing an execption.



---------------------------------------------------------------------
To unsubscribe, e-mail: dev-unsubscribe@commons.apache.org
For additional commands, e-mail: dev-help@commons.apache.org