diff options
Diffstat (limited to 'src/main/java/org/apache/commons/math3/linear/SparseFieldVector.java')
-rw-r--r-- | src/main/java/org/apache/commons/math3/linear/SparseFieldVector.java | 771 |
1 files changed, 771 insertions, 0 deletions
diff --git a/src/main/java/org/apache/commons/math3/linear/SparseFieldVector.java b/src/main/java/org/apache/commons/math3/linear/SparseFieldVector.java new file mode 100644 index 0000000..a86ea50 --- /dev/null +++ b/src/main/java/org/apache/commons/math3/linear/SparseFieldVector.java @@ -0,0 +1,771 @@ +/* + * 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.math3.linear; + +import org.apache.commons.math3.Field; +import org.apache.commons.math3.FieldElement; +import org.apache.commons.math3.exception.DimensionMismatchException; +import org.apache.commons.math3.exception.MathArithmeticException; +import org.apache.commons.math3.exception.NotPositiveException; +import org.apache.commons.math3.exception.NullArgumentException; +import org.apache.commons.math3.exception.NumberIsTooSmallException; +import org.apache.commons.math3.exception.OutOfRangeException; +import org.apache.commons.math3.exception.util.LocalizedFormats; +import org.apache.commons.math3.util.MathArrays; +import org.apache.commons.math3.util.MathUtils; +import org.apache.commons.math3.util.OpenIntToFieldHashMap; + +import java.io.Serializable; + +/** + * This class implements the {@link FieldVector} interface with a {@link OpenIntToFieldHashMap} + * backing store. + * + * <p>Caveat: This implementation assumes that, for any {@code x}, the equality {@code x * 0d == 0d} + * holds. But it is is not true for {@code NaN}. Moreover, zero entries will lose their sign. Some + * operations (that involve {@code NaN} and/or infinities) may thus give incorrect results. + * + * @param <T> the type of the field elements + * @since 2.0 + */ +public class SparseFieldVector<T extends FieldElement<T>> implements FieldVector<T>, Serializable { + /** Serialization identifier. */ + private static final long serialVersionUID = 7841233292190413362L; + + /** Field to which the elements belong. */ + private final Field<T> field; + + /** Entries of the vector. */ + private final OpenIntToFieldHashMap<T> entries; + + /** Dimension of the vector. */ + private final int virtualSize; + + /** + * Build a 0-length vector. Zero-length vectors may be used to initialize construction of + * vectors by data gathering. We start with zero-length and use either the {@link + * #SparseFieldVector(SparseFieldVector, int)} constructor or one of the {@code append} method + * ({@link #append(FieldVector)} or {@link #append(SparseFieldVector)}) to gather data into this + * vector. + * + * @param field Field to which the elements belong. + */ + public SparseFieldVector(Field<T> field) { + this(field, 0); + } + + /** + * Construct a vector of zeroes. + * + * @param field Field to which the elements belong. + * @param dimension Size of the vector. + */ + public SparseFieldVector(Field<T> field, int dimension) { + this.field = field; + virtualSize = dimension; + entries = new OpenIntToFieldHashMap<T>(field); + } + + /** + * Build a resized vector, for use with append. + * + * @param v Original vector + * @param resize Amount to add. + */ + protected SparseFieldVector(SparseFieldVector<T> v, int resize) { + field = v.field; + virtualSize = v.getDimension() + resize; + entries = new OpenIntToFieldHashMap<T>(v.entries); + } + + /** + * Build a vector with known the sparseness (for advanced use only). + * + * @param field Field to which the elements belong. + * @param dimension Size of the vector. + * @param expectedSize Expected number of non-zero entries. + */ + public SparseFieldVector(Field<T> field, int dimension, int expectedSize) { + this.field = field; + virtualSize = dimension; + entries = new OpenIntToFieldHashMap<T>(field, expectedSize); + } + + /** + * Create from a Field array. Only non-zero entries will be stored. + * + * @param field Field to which the elements belong. + * @param values Set of values to create from. + * @exception NullArgumentException if values is null + */ + public SparseFieldVector(Field<T> field, T[] values) throws NullArgumentException { + MathUtils.checkNotNull(values); + this.field = field; + virtualSize = values.length; + entries = new OpenIntToFieldHashMap<T>(field); + for (int key = 0; key < values.length; key++) { + T value = values[key]; + entries.put(key, value); + } + } + + /** + * Copy constructor. + * + * @param v Instance to copy. + */ + public SparseFieldVector(SparseFieldVector<T> v) { + field = v.field; + virtualSize = v.getDimension(); + entries = new OpenIntToFieldHashMap<T>(v.getEntries()); + } + + /** + * Get the entries of this instance. + * + * @return the entries of this instance + */ + private OpenIntToFieldHashMap<T> getEntries() { + return entries; + } + + /** + * Optimized method to add sparse vectors. + * + * @param v Vector to add. + * @return {@code this + v}. + * @throws DimensionMismatchException if {@code v} is not the same size as {@code this}. + */ + public FieldVector<T> add(SparseFieldVector<T> v) throws DimensionMismatchException { + checkVectorDimensions(v.getDimension()); + SparseFieldVector<T> res = (SparseFieldVector<T>) copy(); + OpenIntToFieldHashMap<T>.Iterator iter = v.getEntries().iterator(); + while (iter.hasNext()) { + iter.advance(); + int key = iter.key(); + T value = iter.value(); + if (entries.containsKey(key)) { + res.setEntry(key, entries.get(key).add(value)); + } else { + res.setEntry(key, value); + } + } + return res; + } + + /** + * Construct a vector by appending a vector to this vector. + * + * @param v Vector to append to this one. + * @return a new vector. + */ + public FieldVector<T> append(SparseFieldVector<T> v) { + SparseFieldVector<T> res = new SparseFieldVector<T>(this, v.getDimension()); + OpenIntToFieldHashMap<T>.Iterator iter = v.entries.iterator(); + while (iter.hasNext()) { + iter.advance(); + res.setEntry(iter.key() + virtualSize, iter.value()); + } + return res; + } + + /** {@inheritDoc} */ + public FieldVector<T> append(FieldVector<T> v) { + if (v instanceof SparseFieldVector<?>) { + return append((SparseFieldVector<T>) v); + } else { + final int n = v.getDimension(); + FieldVector<T> res = new SparseFieldVector<T>(this, n); + for (int i = 0; i < n; i++) { + res.setEntry(i + virtualSize, v.getEntry(i)); + } + return res; + } + } + + /** + * {@inheritDoc} + * + * @exception NullArgumentException if d is null + */ + public FieldVector<T> append(T d) throws NullArgumentException { + MathUtils.checkNotNull(d); + FieldVector<T> res = new SparseFieldVector<T>(this, 1); + res.setEntry(virtualSize, d); + return res; + } + + /** {@inheritDoc} */ + public FieldVector<T> copy() { + return new SparseFieldVector<T>(this); + } + + /** {@inheritDoc} */ + public T dotProduct(FieldVector<T> v) throws DimensionMismatchException { + checkVectorDimensions(v.getDimension()); + T res = field.getZero(); + OpenIntToFieldHashMap<T>.Iterator iter = entries.iterator(); + while (iter.hasNext()) { + iter.advance(); + res = res.add(v.getEntry(iter.key()).multiply(iter.value())); + } + return res; + } + + /** {@inheritDoc} */ + public FieldVector<T> ebeDivide(FieldVector<T> v) + throws DimensionMismatchException, MathArithmeticException { + checkVectorDimensions(v.getDimension()); + SparseFieldVector<T> res = new SparseFieldVector<T>(this); + OpenIntToFieldHashMap<T>.Iterator iter = res.entries.iterator(); + while (iter.hasNext()) { + iter.advance(); + res.setEntry(iter.key(), iter.value().divide(v.getEntry(iter.key()))); + } + return res; + } + + /** {@inheritDoc} */ + public FieldVector<T> ebeMultiply(FieldVector<T> v) throws DimensionMismatchException { + checkVectorDimensions(v.getDimension()); + SparseFieldVector<T> res = new SparseFieldVector<T>(this); + OpenIntToFieldHashMap<T>.Iterator iter = res.entries.iterator(); + while (iter.hasNext()) { + iter.advance(); + res.setEntry(iter.key(), iter.value().multiply(v.getEntry(iter.key()))); + } + return res; + } + + /** + * {@inheritDoc} + * + * @deprecated as of 3.1, to be removed in 4.0. Please use the {@link #toArray()} method + * instead. + */ + @Deprecated + public T[] getData() { + return toArray(); + } + + /** {@inheritDoc} */ + public int getDimension() { + return virtualSize; + } + + /** {@inheritDoc} */ + public T getEntry(int index) throws OutOfRangeException { + checkIndex(index); + return entries.get(index); + } + + /** {@inheritDoc} */ + public Field<T> getField() { + return field; + } + + /** {@inheritDoc} */ + public FieldVector<T> getSubVector(int index, int n) + throws OutOfRangeException, NotPositiveException { + if (n < 0) { + throw new NotPositiveException( + LocalizedFormats.NUMBER_OF_ELEMENTS_SHOULD_BE_POSITIVE, n); + } + checkIndex(index); + checkIndex(index + n - 1); + SparseFieldVector<T> res = new SparseFieldVector<T>(field, n); + int end = index + n; + OpenIntToFieldHashMap<T>.Iterator iter = entries.iterator(); + while (iter.hasNext()) { + iter.advance(); + int key = iter.key(); + if (key >= index && key < end) { + res.setEntry(key - index, iter.value()); + } + } + return res; + } + + /** {@inheritDoc} */ + public FieldVector<T> mapAdd(T d) throws NullArgumentException { + return copy().mapAddToSelf(d); + } + + /** {@inheritDoc} */ + public FieldVector<T> mapAddToSelf(T d) throws NullArgumentException { + for (int i = 0; i < virtualSize; i++) { + setEntry(i, getEntry(i).add(d)); + } + return this; + } + + /** {@inheritDoc} */ + public FieldVector<T> mapDivide(T d) throws NullArgumentException, MathArithmeticException { + return copy().mapDivideToSelf(d); + } + + /** {@inheritDoc} */ + public FieldVector<T> mapDivideToSelf(T d) + throws NullArgumentException, MathArithmeticException { + OpenIntToFieldHashMap<T>.Iterator iter = entries.iterator(); + while (iter.hasNext()) { + iter.advance(); + entries.put(iter.key(), iter.value().divide(d)); + } + return this; + } + + /** {@inheritDoc} */ + public FieldVector<T> mapInv() throws MathArithmeticException { + return copy().mapInvToSelf(); + } + + /** {@inheritDoc} */ + public FieldVector<T> mapInvToSelf() throws MathArithmeticException { + for (int i = 0; i < virtualSize; i++) { + setEntry(i, field.getOne().divide(getEntry(i))); + } + return this; + } + + /** {@inheritDoc} */ + public FieldVector<T> mapMultiply(T d) throws NullArgumentException { + return copy().mapMultiplyToSelf(d); + } + + /** {@inheritDoc} */ + public FieldVector<T> mapMultiplyToSelf(T d) throws NullArgumentException { + OpenIntToFieldHashMap<T>.Iterator iter = entries.iterator(); + while (iter.hasNext()) { + iter.advance(); + entries.put(iter.key(), iter.value().multiply(d)); + } + return this; + } + + /** {@inheritDoc} */ + public FieldVector<T> mapSubtract(T d) throws NullArgumentException { + return copy().mapSubtractToSelf(d); + } + + /** {@inheritDoc} */ + public FieldVector<T> mapSubtractToSelf(T d) throws NullArgumentException { + return mapAddToSelf(field.getZero().subtract(d)); + } + + /** + * Optimized method to compute outer product when both vectors are sparse. + * + * @param v vector with which outer product should be computed + * @return the matrix outer product between instance and v + */ + public FieldMatrix<T> outerProduct(SparseFieldVector<T> v) { + final int n = v.getDimension(); + SparseFieldMatrix<T> res = new SparseFieldMatrix<T>(field, virtualSize, n); + OpenIntToFieldHashMap<T>.Iterator iter = entries.iterator(); + while (iter.hasNext()) { + iter.advance(); + OpenIntToFieldHashMap<T>.Iterator iter2 = v.entries.iterator(); + while (iter2.hasNext()) { + iter2.advance(); + res.setEntry(iter.key(), iter2.key(), iter.value().multiply(iter2.value())); + } + } + return res; + } + + /** {@inheritDoc} */ + public FieldMatrix<T> outerProduct(FieldVector<T> v) { + if (v instanceof SparseFieldVector<?>) { + return outerProduct((SparseFieldVector<T>) v); + } else { + final int n = v.getDimension(); + FieldMatrix<T> res = new SparseFieldMatrix<T>(field, virtualSize, n); + OpenIntToFieldHashMap<T>.Iterator iter = entries.iterator(); + while (iter.hasNext()) { + iter.advance(); + int row = iter.key(); + FieldElement<T> value = iter.value(); + for (int col = 0; col < n; col++) { + res.setEntry(row, col, value.multiply(v.getEntry(col))); + } + } + return res; + } + } + + /** {@inheritDoc} */ + public FieldVector<T> projection(FieldVector<T> v) + throws DimensionMismatchException, MathArithmeticException { + checkVectorDimensions(v.getDimension()); + return v.mapMultiply(dotProduct(v).divide(v.dotProduct(v))); + } + + /** + * {@inheritDoc} + * + * @exception NullArgumentException if value is null + */ + public void set(T value) { + MathUtils.checkNotNull(value); + for (int i = 0; i < virtualSize; i++) { + setEntry(i, value); + } + } + + /** + * {@inheritDoc} + * + * @exception NullArgumentException if value is null + */ + public void setEntry(int index, T value) throws NullArgumentException, OutOfRangeException { + MathUtils.checkNotNull(value); + checkIndex(index); + entries.put(index, value); + } + + /** {@inheritDoc} */ + public void setSubVector(int index, FieldVector<T> v) throws OutOfRangeException { + checkIndex(index); + checkIndex(index + v.getDimension() - 1); + final int n = v.getDimension(); + for (int i = 0; i < n; i++) { + setEntry(i + index, v.getEntry(i)); + } + } + + /** + * Optimized method to compute {@code this} minus {@code v}. + * + * @param v vector to be subtracted + * @return {@code this - v} + * @throws DimensionMismatchException if {@code v} is not the same size as {@code this}. + */ + public SparseFieldVector<T> subtract(SparseFieldVector<T> v) throws DimensionMismatchException { + checkVectorDimensions(v.getDimension()); + SparseFieldVector<T> res = (SparseFieldVector<T>) copy(); + OpenIntToFieldHashMap<T>.Iterator iter = v.getEntries().iterator(); + while (iter.hasNext()) { + iter.advance(); + int key = iter.key(); + if (entries.containsKey(key)) { + res.setEntry(key, entries.get(key).subtract(iter.value())); + } else { + res.setEntry(key, field.getZero().subtract(iter.value())); + } + } + return res; + } + + /** {@inheritDoc} */ + public FieldVector<T> subtract(FieldVector<T> v) throws DimensionMismatchException { + if (v instanceof SparseFieldVector<?>) { + return subtract((SparseFieldVector<T>) v); + } else { + final int n = v.getDimension(); + checkVectorDimensions(n); + SparseFieldVector<T> res = new SparseFieldVector<T>(this); + for (int i = 0; i < n; i++) { + if (entries.containsKey(i)) { + res.setEntry(i, entries.get(i).subtract(v.getEntry(i))); + } else { + res.setEntry(i, field.getZero().subtract(v.getEntry(i))); + } + } + return res; + } + } + + /** {@inheritDoc} */ + public T[] toArray() { + T[] res = MathArrays.buildArray(field, virtualSize); + OpenIntToFieldHashMap<T>.Iterator iter = entries.iterator(); + while (iter.hasNext()) { + iter.advance(); + res[iter.key()] = iter.value(); + } + return res; + } + + /** + * Check whether an index is valid. + * + * @param index Index to check. + * @throws OutOfRangeException if the index is not valid. + */ + private void checkIndex(final int index) throws OutOfRangeException { + if (index < 0 || index >= getDimension()) { + throw new OutOfRangeException(index, 0, getDimension() - 1); + } + } + + /** + * Checks that the indices of a subvector are valid. + * + * @param start the index of the first entry of the subvector + * @param end the index of the last entry of the subvector (inclusive) + * @throws OutOfRangeException if {@code start} of {@code end} are not valid + * @throws NumberIsTooSmallException if {@code end < start} + * @since 3.3 + */ + private void checkIndices(final int start, final int end) + throws NumberIsTooSmallException, OutOfRangeException { + final int dim = getDimension(); + if ((start < 0) || (start >= dim)) { + throw new OutOfRangeException(LocalizedFormats.INDEX, start, 0, dim - 1); + } + if ((end < 0) || (end >= dim)) { + throw new OutOfRangeException(LocalizedFormats.INDEX, end, 0, dim - 1); + } + if (end < start) { + throw new NumberIsTooSmallException( + LocalizedFormats.INITIAL_ROW_AFTER_FINAL_ROW, end, start, false); + } + } + + /** + * Check if instance dimension is equal to some expected value. + * + * @param n Expected dimension. + * @throws DimensionMismatchException if the dimensions do not match. + */ + protected void checkVectorDimensions(int n) throws DimensionMismatchException { + if (getDimension() != n) { + throw new DimensionMismatchException(getDimension(), n); + } + } + + /** {@inheritDoc} */ + public FieldVector<T> add(FieldVector<T> v) throws DimensionMismatchException { + if (v instanceof SparseFieldVector<?>) { + return add((SparseFieldVector<T>) v); + } else { + final int n = v.getDimension(); + checkVectorDimensions(n); + SparseFieldVector<T> res = new SparseFieldVector<T>(field, getDimension()); + for (int i = 0; i < n; i++) { + res.setEntry(i, v.getEntry(i).add(getEntry(i))); + } + return res; + } + } + + /** + * Visits (but does not alter) all entries of this vector in default order (increasing index). + * + * @param visitor the visitor to be used to process the entries of this vector + * @return the value returned by {@link FieldVectorPreservingVisitor#end()} at the end of the + * walk + * @since 3.3 + */ + public T walkInDefaultOrder(final FieldVectorPreservingVisitor<T> visitor) { + final int dim = getDimension(); + visitor.start(dim, 0, dim - 1); + for (int i = 0; i < dim; i++) { + visitor.visit(i, getEntry(i)); + } + return visitor.end(); + } + + /** + * Visits (but does not alter) some entries of this vector in default order (increasing index). + * + * @param visitor visitor to be used to process the entries of this vector + * @param start the index of the first entry to be visited + * @param end the index of the last entry to be visited (inclusive) + * @return the value returned by {@link FieldVectorPreservingVisitor#end()} at the end of the + * walk + * @throws NumberIsTooSmallException if {@code end < start}. + * @throws OutOfRangeException if the indices are not valid. + * @since 3.3 + */ + public T walkInDefaultOrder( + final FieldVectorPreservingVisitor<T> visitor, final int start, final int end) + throws NumberIsTooSmallException, OutOfRangeException { + checkIndices(start, end); + visitor.start(getDimension(), start, end); + for (int i = start; i <= end; i++) { + visitor.visit(i, getEntry(i)); + } + return visitor.end(); + } + + /** + * Visits (but does not alter) all entries of this vector in optimized order. The order in which + * the entries are visited is selected so as to lead to the most efficient implementation; it + * might depend on the concrete implementation of this abstract class. + * + * @param visitor the visitor to be used to process the entries of this vector + * @return the value returned by {@link FieldVectorPreservingVisitor#end()} at the end of the + * walk + * @since 3.3 + */ + public T walkInOptimizedOrder(final FieldVectorPreservingVisitor<T> visitor) { + return walkInDefaultOrder(visitor); + } + + /** + * Visits (but does not alter) some entries of this vector in optimized order. The order in + * which the entries are visited is selected so as to lead to the most efficient implementation; + * it might depend on the concrete implementation of this abstract class. + * + * @param visitor visitor to be used to process the entries of this vector + * @param start the index of the first entry to be visited + * @param end the index of the last entry to be visited (inclusive) + * @return the value returned by {@link FieldVectorPreservingVisitor#end()} at the end of the + * walk + * @throws NumberIsTooSmallException if {@code end < start}. + * @throws OutOfRangeException if the indices are not valid. + * @since 3.3 + */ + public T walkInOptimizedOrder( + final FieldVectorPreservingVisitor<T> visitor, final int start, final int end) + throws NumberIsTooSmallException, OutOfRangeException { + return walkInDefaultOrder(visitor, start, end); + } + + /** + * Visits (and possibly alters) all entries of this vector in default order (increasing index). + * + * @param visitor the visitor to be used to process and modify the entries of this vector + * @return the value returned by {@link FieldVectorChangingVisitor#end()} at the end of the walk + * @since 3.3 + */ + public T walkInDefaultOrder(final FieldVectorChangingVisitor<T> visitor) { + final int dim = getDimension(); + visitor.start(dim, 0, dim - 1); + for (int i = 0; i < dim; i++) { + setEntry(i, visitor.visit(i, getEntry(i))); + } + return visitor.end(); + } + + /** + * Visits (and possibly alters) some entries of this vector in default order (increasing index). + * + * @param visitor visitor to be used to process the entries of this vector + * @param start the index of the first entry to be visited + * @param end the index of the last entry to be visited (inclusive) + * @return the value returned by {@link FieldVectorChangingVisitor#end()} at the end of the walk + * @throws NumberIsTooSmallException if {@code end < start}. + * @throws OutOfRangeException if the indices are not valid. + * @since 3.3 + */ + public T walkInDefaultOrder( + final FieldVectorChangingVisitor<T> visitor, final int start, final int end) + throws NumberIsTooSmallException, OutOfRangeException { + checkIndices(start, end); + visitor.start(getDimension(), start, end); + for (int i = start; i <= end; i++) { + setEntry(i, visitor.visit(i, getEntry(i))); + } + return visitor.end(); + } + + /** + * Visits (and possibly alters) all entries of this vector in optimized order. The order in + * which the entries are visited is selected so as to lead to the most efficient implementation; + * it might depend on the concrete implementation of this abstract class. + * + * @param visitor the visitor to be used to process the entries of this vector + * @return the value returned by {@link FieldVectorChangingVisitor#end()} at the end of the walk + * @since 3.3 + */ + public T walkInOptimizedOrder(final FieldVectorChangingVisitor<T> visitor) { + return walkInDefaultOrder(visitor); + } + + /** + * Visits (and possibly change) some entries of this vector in optimized order. The order in + * which the entries are visited is selected so as to lead to the most efficient implementation; + * it might depend on the concrete implementation of this abstract class. + * + * @param visitor visitor to be used to process the entries of this vector + * @param start the index of the first entry to be visited + * @param end the index of the last entry to be visited (inclusive) + * @return the value returned by {@link FieldVectorChangingVisitor#end()} at the end of the walk + * @throws NumberIsTooSmallException if {@code end < start}. + * @throws OutOfRangeException if the indices are not valid. + * @since 3.3 + */ + public T walkInOptimizedOrder( + final FieldVectorChangingVisitor<T> visitor, final int start, final int end) + throws NumberIsTooSmallException, OutOfRangeException { + return walkInDefaultOrder(visitor, start, end); + } + + /** {@inheritDoc} */ + @Override + public int hashCode() { + final int prime = 31; + int result = 1; + result = prime * result + ((field == null) ? 0 : field.hashCode()); + result = prime * result + virtualSize; + OpenIntToFieldHashMap<T>.Iterator iter = entries.iterator(); + while (iter.hasNext()) { + iter.advance(); + int temp = iter.value().hashCode(); + result = prime * result + temp; + } + return result; + } + + /** {@inheritDoc} */ + @Override + public boolean equals(Object obj) { + + if (this == obj) { + return true; + } + + if (!(obj instanceof SparseFieldVector<?>)) { + return false; + } + + @SuppressWarnings("unchecked") // OK, because "else if" check below ensures that + // other must be the same type as this + SparseFieldVector<T> other = (SparseFieldVector<T>) obj; + if (field == null) { + if (other.field != null) { + return false; + } + } else if (!field.equals(other.field)) { + return false; + } + if (virtualSize != other.virtualSize) { + return false; + } + + OpenIntToFieldHashMap<T>.Iterator iter = entries.iterator(); + while (iter.hasNext()) { + iter.advance(); + T test = other.getEntry(iter.key()); + if (!test.equals(iter.value())) { + return false; + } + } + iter = other.getEntries().iterator(); + while (iter.hasNext()) { + iter.advance(); + T test = iter.value(); + if (!test.equals(getEntry(iter.key()))) { + return false; + } + } + return true; + } +} |