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: <l...@apache.org>
To: <comm...@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-unsubscr...@commons.apache.org
For additional commands, e-mail: dev-h...@commons.apache.org

Reply via email to