SparseFieldVector.java

  1. /*
  2.  * Licensed to the Apache Software Foundation (ASF) under one or more
  3.  * contributor license agreements.  See the NOTICE file distributed with
  4.  * this work for additional information regarding copyright ownership.
  5.  * The ASF licenses this file to You under the Apache License, Version 2.0
  6.  * (the "License"); you may not use this file except in compliance with
  7.  * the License.  You may obtain a copy of the License at
  8.  *
  9.  *      http://www.apache.org/licenses/LICENSE-2.0
  10.  *
  11.  * Unless required by applicable law or agreed to in writing, software
  12.  * distributed under the License is distributed on an "AS IS" BASIS,
  13.  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
  14.  * See the License for the specific language governing permissions and
  15.  * limitations under the License.
  16.  */
  17. package org.apache.commons.math4.legacy.linear;

  18. import java.io.Serializable;

  19. import org.apache.commons.math4.legacy.core.Field;
  20. import org.apache.commons.math4.legacy.core.FieldElement;
  21. import org.apache.commons.math4.legacy.exception.DimensionMismatchException;
  22. import org.apache.commons.math4.legacy.exception.MathArithmeticException;
  23. import org.apache.commons.math4.legacy.exception.NotPositiveException;
  24. import org.apache.commons.math4.legacy.exception.NullArgumentException;
  25. import org.apache.commons.math4.legacy.exception.NumberIsTooSmallException;
  26. import org.apache.commons.math4.legacy.exception.OutOfRangeException;
  27. import org.apache.commons.math4.legacy.exception.util.LocalizedFormats;
  28. import org.apache.commons.math4.legacy.core.MathArrays;

  29. /**
  30.  * This class implements the {@link FieldVector} interface with a {@link OpenIntToFieldHashMap} backing store.
  31.  * <p>
  32.  *  Caveat: This implementation assumes that, for any {@code x},
  33.  *  the equality {@code x * 0d == 0d} holds. But it is is not true for
  34.  *  {@code NaN}. Moreover, zero entries will lose their sign.
  35.  *  Some operations (that involve {@code NaN} and/or infinities) may
  36.  *  thus give incorrect results.
  37.  * </p>
  38.  * @param <T> the type of the field elements
  39.  * @since 2.0
  40.  */
  41. public class SparseFieldVector<T extends FieldElement<T>> implements FieldVector<T>, Serializable {
  42.     /**  Serialization identifier. */
  43.     private static final long serialVersionUID = 7841233292190413362L;
  44.     /** Field to which the elements belong. */
  45.     private final Field<T> field;
  46.     /** Entries of the vector. */
  47.     private final OpenIntToFieldHashMap<T> entries;
  48.     /** Dimension of the vector. */
  49.     private final int virtualSize;

  50.     /**
  51.      * Build a 0-length vector.
  52.      * Zero-length vectors may be used to initialize construction of vectors
  53.      * by data gathering. We start with zero-length and use either the {@link
  54.      * #SparseFieldVector(SparseFieldVector, int)} constructor
  55.      * or one of the {@code append} method ({@link #append(FieldVector)} or
  56.      * {@link #append(SparseFieldVector)}) to gather data into this vector.
  57.      *
  58.      * @param field Field to which the elements belong.
  59.      */
  60.     public SparseFieldVector(Field<T> field) {
  61.         this(field, 0);
  62.     }


  63.     /**
  64.      * Construct a vector of zeroes.
  65.      *
  66.      * @param field Field to which the elements belong.
  67.      * @param dimension Size of the vector.
  68.      */
  69.     public SparseFieldVector(Field<T> field, int dimension) {
  70.         this.field = field;
  71.         virtualSize = dimension;
  72.         entries = new OpenIntToFieldHashMap<>(field);
  73.     }

  74.     /**
  75.      * Build a resized vector, for use with append.
  76.      *
  77.      * @param v Original vector
  78.      * @param resize Amount to add.
  79.      */
  80.     protected SparseFieldVector(SparseFieldVector<T> v, int resize) {
  81.         field = v.field;
  82.         virtualSize = v.getDimension() + resize;
  83.         entries = new OpenIntToFieldHashMap<>(v.entries);
  84.     }


  85.     /**
  86.      * Build a vector with known the sparseness (for advanced use only).
  87.      *
  88.      * @param field Field to which the elements belong.
  89.      * @param dimension Size of the vector.
  90.      * @param expectedSize Expected number of non-zero entries.
  91.      */
  92.     public SparseFieldVector(Field<T> field, int dimension, int expectedSize) {
  93.         this.field = field;
  94.         virtualSize = dimension;
  95.         entries = new OpenIntToFieldHashMap<>(field,expectedSize);
  96.     }

  97.     /**
  98.      * Create from a Field array.
  99.      * Only non-zero entries will be stored.
  100.      *
  101.      * @param field Field to which the elements belong.
  102.      * @param values Set of values to create from.
  103.      * @exception NullArgumentException if values is null
  104.      */
  105.     public SparseFieldVector(Field<T> field, T[] values) throws NullArgumentException {
  106.         NullArgumentException.check(values);
  107.         this.field = field;
  108.         virtualSize = values.length;
  109.         entries = new OpenIntToFieldHashMap<>(field);
  110.         for (int key = 0; key < values.length; key++) {
  111.             T value = values[key];
  112.             entries.put(key, value);
  113.         }
  114.     }

  115.     /**
  116.      * Copy constructor.
  117.      *
  118.      * @param v Instance to copy.
  119.      */
  120.     public SparseFieldVector(SparseFieldVector<T> v) {
  121.         field = v.field;
  122.         virtualSize = v.getDimension();
  123.         entries = new OpenIntToFieldHashMap<>(v.getEntries());
  124.     }

  125.     /**
  126.      * Get the entries of this instance.
  127.      *
  128.      * @return the entries of this instance
  129.      */
  130.     private OpenIntToFieldHashMap<T> getEntries() {
  131.         return entries;
  132.     }

  133.     /**
  134.      * Optimized method to add sparse vectors.
  135.      *
  136.      * @param v Vector to add.
  137.      * @return {@code this + v}.
  138.      * @throws DimensionMismatchException if {@code v} is not the same size as
  139.      * {@code this}.
  140.      */
  141.     public FieldVector<T> add(SparseFieldVector<T> v)
  142.         throws DimensionMismatchException {
  143.         checkVectorDimensions(v.getDimension());
  144.         SparseFieldVector<T> res = (SparseFieldVector<T>)copy();
  145.         OpenIntToFieldHashMap<T>.Iterator iter = v.getEntries().iterator();
  146.         while (iter.hasNext()) {
  147.             iter.advance();
  148.             int key = iter.key();
  149.             T value = iter.value();
  150.             if (entries.containsKey(key)) {
  151.                 res.setEntry(key, entries.get(key).add(value));
  152.             } else {
  153.                 res.setEntry(key, value);
  154.             }
  155.         }
  156.         return res;
  157.     }

  158.     /**
  159.      * Construct a vector by appending a vector to this vector.
  160.      *
  161.      * @param v Vector to append to this one.
  162.      * @return a new vector.
  163.      */
  164.     public FieldVector<T> append(SparseFieldVector<T> v) {
  165.         SparseFieldVector<T> res = new SparseFieldVector<>(this, v.getDimension());
  166.         OpenIntToFieldHashMap<T>.Iterator iter = v.entries.iterator();
  167.         while (iter.hasNext()) {
  168.             iter.advance();
  169.             res.setEntry(iter.key() + virtualSize, iter.value());
  170.         }
  171.         return res;
  172.     }

  173.     /** {@inheritDoc} */
  174.     @Override
  175.     public FieldVector<T> append(FieldVector<T> v) {
  176.         if (v instanceof SparseFieldVector<?>) {
  177.             return append((SparseFieldVector<T>) v);
  178.         } else {
  179.             final int n = v.getDimension();
  180.             FieldVector<T> res = new SparseFieldVector<>(this, n);
  181.             for (int i = 0; i < n; i++) {
  182.                 res.setEntry(i + virtualSize, v.getEntry(i));
  183.             }
  184.             return res;
  185.         }
  186.     }

  187.     /** {@inheritDoc}
  188.      * @exception NullArgumentException if d is null
  189.      */
  190.     @Override
  191.     public FieldVector<T> append(T d) throws NullArgumentException {
  192.         NullArgumentException.check(d);
  193.         FieldVector<T> res = new SparseFieldVector<>(this, 1);
  194.         res.setEntry(virtualSize, d);
  195.         return res;
  196.      }

  197.     /** {@inheritDoc} */
  198.     @Override
  199.     public FieldVector<T> copy() {
  200.         return new SparseFieldVector<>(this);
  201.     }

  202.     /** {@inheritDoc} */
  203.     @Override
  204.     public T dotProduct(FieldVector<T> v) throws DimensionMismatchException {
  205.         checkVectorDimensions(v.getDimension());
  206.         T res = field.getZero();
  207.         OpenIntToFieldHashMap<T>.Iterator iter = entries.iterator();
  208.         while (iter.hasNext()) {
  209.             iter.advance();
  210.             res = res.add(v.getEntry(iter.key()).multiply(iter.value()));
  211.         }
  212.         return res;
  213.     }

  214.     /** {@inheritDoc} */
  215.     @Override
  216.     public FieldVector<T> ebeDivide(FieldVector<T> v)
  217.         throws DimensionMismatchException, MathArithmeticException {
  218.         checkVectorDimensions(v.getDimension());
  219.         SparseFieldVector<T> res = new SparseFieldVector<>(this);
  220.         OpenIntToFieldHashMap<T>.Iterator iter = res.entries.iterator();
  221.         while (iter.hasNext()) {
  222.             iter.advance();
  223.             res.setEntry(iter.key(), iter.value().divide(v.getEntry(iter.key())));
  224.         }
  225.         return res;
  226.     }

  227.     /** {@inheritDoc} */
  228.     @Override
  229.     public FieldVector<T> ebeMultiply(FieldVector<T> v)
  230.         throws DimensionMismatchException {
  231.         checkVectorDimensions(v.getDimension());
  232.         SparseFieldVector<T> res = new SparseFieldVector<>(this);
  233.         OpenIntToFieldHashMap<T>.Iterator iter = res.entries.iterator();
  234.         while (iter.hasNext()) {
  235.             iter.advance();
  236.             res.setEntry(iter.key(), iter.value().multiply(v.getEntry(iter.key())));
  237.         }
  238.         return res;
  239.     }

  240.     /** {@inheritDoc} */
  241.     @Override
  242.     public int getDimension() {
  243.         return virtualSize;
  244.     }

  245.     /** {@inheritDoc} */
  246.     @Override
  247.     public T getEntry(int index) throws OutOfRangeException {
  248.         checkIndex(index);
  249.         return entries.get(index);
  250.    }

  251.     /** {@inheritDoc} */
  252.     @Override
  253.     public Field<T> getField() {
  254.         return field;
  255.     }

  256.     /** {@inheritDoc} */
  257.     @Override
  258.     public FieldVector<T> getSubVector(int index, int n)
  259.         throws OutOfRangeException, NotPositiveException {
  260.         if (n < 0) {
  261.             throw new NotPositiveException(LocalizedFormats.NUMBER_OF_ELEMENTS_SHOULD_BE_POSITIVE, n);
  262.         }
  263.         checkIndex(index);
  264.         checkIndex(index + n - 1);
  265.         SparseFieldVector<T> res = new SparseFieldVector<>(field,n);
  266.         int end = index + n;
  267.         OpenIntToFieldHashMap<T>.Iterator iter = entries.iterator();
  268.         while (iter.hasNext()) {
  269.             iter.advance();
  270.             int key = iter.key();
  271.             if (key >= index && key < end) {
  272.                 res.setEntry(key - index, iter.value());
  273.             }
  274.         }
  275.         return res;
  276.     }

  277.     /** {@inheritDoc} */
  278.     @Override
  279.     public FieldVector<T> mapAdd(T d) throws NullArgumentException {
  280.         return copy().mapAddToSelf(d);
  281.     }

  282.     /** {@inheritDoc} */
  283.     @Override
  284.     public FieldVector<T> mapAddToSelf(T d) throws NullArgumentException {
  285.         for (int i = 0; i < virtualSize; i++) {
  286.             setEntry(i, getEntry(i).add(d));
  287.         }
  288.         return this;
  289.     }

  290.     /** {@inheritDoc} */
  291.     @Override
  292.     public FieldVector<T> mapDivide(T d)
  293.         throws NullArgumentException, MathArithmeticException {
  294.         return copy().mapDivideToSelf(d);
  295.     }

  296.     /** {@inheritDoc} */
  297.     @Override
  298.     public FieldVector<T> mapDivideToSelf(T d)
  299.         throws NullArgumentException, MathArithmeticException {
  300.         OpenIntToFieldHashMap<T>.Iterator iter = entries.iterator();
  301.         while (iter.hasNext()) {
  302.             iter.advance();
  303.             entries.put(iter.key(), iter.value().divide(d));
  304.         }
  305.         return this;
  306.     }

  307.     /** {@inheritDoc} */
  308.     @Override
  309.     public FieldVector<T> mapInv() throws MathArithmeticException {
  310.         return copy().mapInvToSelf();
  311.     }

  312.     /** {@inheritDoc} */
  313.     @Override
  314.     public FieldVector<T> mapInvToSelf() throws MathArithmeticException {
  315.         for (int i = 0; i < virtualSize; i++) {
  316.             setEntry(i, field.getOne().divide(getEntry(i)));
  317.         }
  318.         return this;
  319.     }

  320.     /** {@inheritDoc} */
  321.     @Override
  322.     public FieldVector<T> mapMultiply(T d) throws NullArgumentException {
  323.         return copy().mapMultiplyToSelf(d);
  324.     }

  325.     /** {@inheritDoc} */
  326.     @Override
  327.     public FieldVector<T> mapMultiplyToSelf(T d) throws NullArgumentException {
  328.         OpenIntToFieldHashMap<T>.Iterator iter = entries.iterator();
  329.         while (iter.hasNext()) {
  330.             iter.advance();
  331.             entries.put(iter.key(), iter.value().multiply(d));
  332.         }
  333.         return this;
  334.     }

  335.     /** {@inheritDoc} */
  336.     @Override
  337.     public FieldVector<T> mapSubtract(T d) throws NullArgumentException {
  338.         return copy().mapSubtractToSelf(d);
  339.     }

  340.     /** {@inheritDoc} */
  341.     @Override
  342.     public FieldVector<T> mapSubtractToSelf(T d) throws NullArgumentException {
  343.         return mapAddToSelf(field.getZero().subtract(d));
  344.     }

  345.     /**
  346.      * Optimized method to compute outer product when both vectors are sparse.
  347.      * @param v vector with which outer product should be computed
  348.      * @return the matrix outer product between instance and v
  349.      */
  350.     public FieldMatrix<T> outerProduct(SparseFieldVector<T> v) {
  351.         final int n = v.getDimension();
  352.         SparseFieldMatrix<T> res = new SparseFieldMatrix<>(field, virtualSize, n);
  353.         OpenIntToFieldHashMap<T>.Iterator iter = entries.iterator();
  354.         while (iter.hasNext()) {
  355.             iter.advance();
  356.             OpenIntToFieldHashMap<T>.Iterator iter2 = v.entries.iterator();
  357.             while (iter2.hasNext()) {
  358.                 iter2.advance();
  359.                 res.setEntry(iter.key(), iter2.key(), iter.value().multiply(iter2.value()));
  360.             }
  361.         }
  362.         return res;
  363.     }

  364.     /** {@inheritDoc} */
  365.     @Override
  366.     public FieldMatrix<T> outerProduct(FieldVector<T> v) {
  367.         if (v instanceof SparseFieldVector<?>) {
  368.             return outerProduct((SparseFieldVector<T>)v);
  369.         } else {
  370.             final int n = v.getDimension();
  371.             FieldMatrix<T> res = new SparseFieldMatrix<>(field, virtualSize, n);
  372.             OpenIntToFieldHashMap<T>.Iterator iter = entries.iterator();
  373.             while (iter.hasNext()) {
  374.                 iter.advance();
  375.                 int row = iter.key();
  376.                 FieldElement<T> value = iter.value();
  377.                 for (int col = 0; col < n; col++) {
  378.                     res.setEntry(row, col, value.multiply(v.getEntry(col)));
  379.                 }
  380.             }
  381.             return res;
  382.         }
  383.     }

  384.     /** {@inheritDoc} */
  385.     @Override
  386.     public FieldVector<T> projection(FieldVector<T> v)
  387.         throws DimensionMismatchException, MathArithmeticException {
  388.         checkVectorDimensions(v.getDimension());
  389.         return v.mapMultiply(dotProduct(v).divide(v.dotProduct(v)));
  390.     }

  391.     /** {@inheritDoc}
  392.      * @exception NullArgumentException if value is null
  393.      */
  394.     @Override
  395.     public void set(T value) {
  396.         NullArgumentException.check(value);
  397.         for (int i = 0; i < virtualSize; i++) {
  398.             setEntry(i, value);
  399.         }
  400.     }

  401.     /** {@inheritDoc}
  402.      * @exception NullArgumentException if value is null
  403.      */
  404.     @Override
  405.     public void setEntry(int index, T value) throws NullArgumentException, OutOfRangeException {
  406.         NullArgumentException.check(value);
  407.         checkIndex(index);
  408.         entries.put(index, value);
  409.     }

  410.     /** {@inheritDoc} */
  411.     @Override
  412.     public void setSubVector(int index, FieldVector<T> v)
  413.         throws OutOfRangeException {
  414.         checkIndex(index);
  415.         checkIndex(index + v.getDimension() - 1);
  416.         final int n = v.getDimension();
  417.         for (int i = 0; i < n; i++) {
  418.             setEntry(i + index, v.getEntry(i));
  419.         }
  420.     }

  421.     /**
  422.      * Optimized method to compute {@code this} minus {@code v}.
  423.      * @param v vector to be subtracted
  424.      * @return {@code this - v}
  425.      * @throws DimensionMismatchException if {@code v} is not the same size as
  426.      * {@code this}.
  427.      */
  428.     public SparseFieldVector<T> subtract(SparseFieldVector<T> v)
  429.         throws DimensionMismatchException {
  430.         checkVectorDimensions(v.getDimension());
  431.         SparseFieldVector<T> res = (SparseFieldVector<T>)copy();
  432.         OpenIntToFieldHashMap<T>.Iterator iter = v.getEntries().iterator();
  433.         while (iter.hasNext()) {
  434.             iter.advance();
  435.             int key = iter.key();
  436.             if (entries.containsKey(key)) {
  437.                 res.setEntry(key, entries.get(key).subtract(iter.value()));
  438.             } else {
  439.                 res.setEntry(key, field.getZero().subtract(iter.value()));
  440.             }
  441.         }
  442.         return res;
  443.     }

  444.     /** {@inheritDoc} */
  445.     @Override
  446.     public FieldVector<T> subtract(FieldVector<T> v)
  447.         throws DimensionMismatchException {
  448.         if (v instanceof SparseFieldVector<?>) {
  449.             return subtract((SparseFieldVector<T>)v);
  450.         } else {
  451.             final int n = v.getDimension();
  452.             checkVectorDimensions(n);
  453.             SparseFieldVector<T> res = new SparseFieldVector<>(this);
  454.             for (int i = 0; i < n; i++) {
  455.                 if (entries.containsKey(i)) {
  456.                     res.setEntry(i, entries.get(i).subtract(v.getEntry(i)));
  457.                 } else {
  458.                     res.setEntry(i, field.getZero().subtract(v.getEntry(i)));
  459.                 }
  460.             }
  461.             return res;
  462.         }
  463.     }

  464.     /** {@inheritDoc} */
  465.     @Override
  466.     public T[] toArray() {
  467.         T[] res = MathArrays.buildArray(field, virtualSize);
  468.         OpenIntToFieldHashMap<T>.Iterator iter = entries.iterator();
  469.         while (iter.hasNext()) {
  470.             iter.advance();
  471.             res[iter.key()] = iter.value();
  472.         }
  473.         return res;
  474.     }

  475.     /**
  476.      * Check whether an index is valid.
  477.      *
  478.      * @param index Index to check.
  479.      * @throws OutOfRangeException if the index is not valid.
  480.      */
  481.     private void checkIndex(final int index) throws OutOfRangeException {
  482.         if (index < 0 || index >= getDimension()) {
  483.             throw new OutOfRangeException(index, 0, getDimension() - 1);
  484.         }
  485.     }

  486.     /**
  487.      * Checks that the indices of a subvector are valid.
  488.      *
  489.      * @param start the index of the first entry of the subvector
  490.      * @param end the index of the last entry of the subvector (inclusive)
  491.      * @throws OutOfRangeException if {@code start} of {@code end} are not valid
  492.      * @throws NumberIsTooSmallException if {@code end < start}
  493.      * @since 3.3
  494.      */
  495.     private void checkIndices(final int start, final int end)
  496.         throws NumberIsTooSmallException, OutOfRangeException {
  497.         final int dim = getDimension();
  498.         if (start < 0 || start >= dim) {
  499.             throw new OutOfRangeException(LocalizedFormats.INDEX, start, 0,
  500.                                           dim - 1);
  501.         }
  502.         if (end < 0 || end >= dim) {
  503.             throw new OutOfRangeException(LocalizedFormats.INDEX, end, 0,
  504.                                           dim - 1);
  505.         }
  506.         if (end < start) {
  507.             throw new NumberIsTooSmallException(LocalizedFormats.INITIAL_ROW_AFTER_FINAL_ROW,
  508.                                                 end, start, false);
  509.         }
  510.     }

  511.     /**
  512.      * Check if instance dimension is equal to some expected value.
  513.      *
  514.      * @param n Expected dimension.
  515.      * @throws DimensionMismatchException if the dimensions do not match.
  516.      */
  517.     protected void checkVectorDimensions(int n)
  518.         throws DimensionMismatchException {
  519.         if (getDimension() != n) {
  520.             throw new DimensionMismatchException(getDimension(), n);
  521.         }
  522.     }

  523.     /** {@inheritDoc} */
  524.     @Override
  525.     public FieldVector<T> add(FieldVector<T> v) throws DimensionMismatchException {
  526.         if (v instanceof SparseFieldVector<?>) {
  527.             return add((SparseFieldVector<T>) v);
  528.         } else {
  529.             final int n = v.getDimension();
  530.             checkVectorDimensions(n);
  531.             SparseFieldVector<T> res = new SparseFieldVector<>(field,
  532.                                                                 getDimension());
  533.             for (int i = 0; i < n; i++) {
  534.                 res.setEntry(i, v.getEntry(i).add(getEntry(i)));
  535.             }
  536.             return res;
  537.         }
  538.     }

  539.     /**
  540.      * Visits (but does not alter) all entries of this vector in default order
  541.      * (increasing index).
  542.      *
  543.      * @param visitor the visitor to be used to process the entries of this
  544.      * vector
  545.      * @return the value returned by {@link FieldVectorPreservingVisitor#end()}
  546.      * at the end of the walk
  547.      * @since 3.3
  548.      */
  549.     public T walkInDefaultOrder(final FieldVectorPreservingVisitor<T> visitor) {
  550.         final int dim = getDimension();
  551.         visitor.start(dim, 0, dim - 1);
  552.         for (int i = 0; i < dim; i++) {
  553.             visitor.visit(i, getEntry(i));
  554.         }
  555.         return visitor.end();
  556.     }

  557.     /**
  558.      * Visits (but does not alter) some entries of this vector in default order
  559.      * (increasing index).
  560.      *
  561.      * @param visitor visitor to be used to process the entries of this vector
  562.      * @param start the index of the first entry to be visited
  563.      * @param end the index of the last entry to be visited (inclusive)
  564.      * @return the value returned by {@link FieldVectorPreservingVisitor#end()}
  565.      * at the end of the walk
  566.      * @throws NumberIsTooSmallException if {@code end < start}.
  567.      * @throws OutOfRangeException if the indices are not valid.
  568.      * @since 3.3
  569.      */
  570.     public T walkInDefaultOrder(final FieldVectorPreservingVisitor<T> visitor,
  571.                                 final int start, final int end)
  572.         throws NumberIsTooSmallException, OutOfRangeException {
  573.         checkIndices(start, end);
  574.         visitor.start(getDimension(), start, end);
  575.         for (int i = start; i <= end; i++) {
  576.             visitor.visit(i, getEntry(i));
  577.         }
  578.         return visitor.end();
  579.     }

  580.     /**
  581.      * Visits (but does not alter) all entries of this vector in optimized
  582.      * order. The order in which the entries are visited is selected so as to
  583.      * lead to the most efficient implementation; it might depend on the
  584.      * concrete implementation of this abstract class.
  585.      *
  586.      * @param visitor the visitor to be used to process the entries of this
  587.      * vector
  588.      * @return the value returned by {@link FieldVectorPreservingVisitor#end()}
  589.      * at the end of the walk
  590.      * @since 3.3
  591.      */
  592.     public T walkInOptimizedOrder(final FieldVectorPreservingVisitor<T> visitor) {
  593.         return walkInDefaultOrder(visitor);
  594.     }

  595.     /**
  596.      * Visits (but does not alter) some entries of this vector in optimized
  597.      * order. The order in which the entries are visited is selected so as to
  598.      * lead to the most efficient implementation; it might depend on the
  599.      * concrete implementation of this abstract class.
  600.      *
  601.      * @param visitor visitor to be used to process the entries of this vector
  602.      * @param start the index of the first entry to be visited
  603.      * @param end the index of the last entry to be visited (inclusive)
  604.      * @return the value returned by {@link FieldVectorPreservingVisitor#end()}
  605.      * at the end of the walk
  606.      * @throws NumberIsTooSmallException if {@code end < start}.
  607.      * @throws OutOfRangeException if the indices are not valid.
  608.      * @since 3.3
  609.      */
  610.     public T walkInOptimizedOrder(final FieldVectorPreservingVisitor<T> visitor,
  611.                                   final int start, final int end)
  612.         throws NumberIsTooSmallException, OutOfRangeException {
  613.         return walkInDefaultOrder(visitor, start, end);
  614.     }

  615.     /**
  616.      * Visits (and possibly alters) all entries of this vector in default order
  617.      * (increasing index).
  618.      *
  619.      * @param visitor the visitor to be used to process and modify the entries
  620.      * of this vector
  621.      * @return the value returned by {@link FieldVectorChangingVisitor#end()}
  622.      * at the end of the walk
  623.      * @since 3.3
  624.      */
  625.     public T walkInDefaultOrder(final FieldVectorChangingVisitor<T> visitor) {
  626.         final int dim = getDimension();
  627.         visitor.start(dim, 0, dim - 1);
  628.         for (int i = 0; i < dim; i++) {
  629.             setEntry(i, visitor.visit(i, getEntry(i)));
  630.         }
  631.         return visitor.end();
  632.     }

  633.     /**
  634.      * Visits (and possibly alters) some entries of this vector in default order
  635.      * (increasing index).
  636.      *
  637.      * @param visitor visitor to be used to process the entries of this vector
  638.      * @param start the index of the first entry to be visited
  639.      * @param end the index of the last entry to be visited (inclusive)
  640.      * @return the value returned by {@link FieldVectorChangingVisitor#end()}
  641.      * at the end of the walk
  642.      * @throws NumberIsTooSmallException if {@code end < start}.
  643.      * @throws OutOfRangeException if the indices are not valid.
  644.      * @since 3.3
  645.      */
  646.     public T walkInDefaultOrder(final FieldVectorChangingVisitor<T> visitor,
  647.                                 final int start, final int end)
  648.         throws NumberIsTooSmallException, OutOfRangeException {
  649.         checkIndices(start, end);
  650.         visitor.start(getDimension(), start, end);
  651.         for (int i = start; i <= end; i++) {
  652.             setEntry(i, visitor.visit(i, getEntry(i)));
  653.         }
  654.         return visitor.end();
  655.     }

  656.     /**
  657.      * Visits (and possibly alters) all entries of this vector in optimized
  658.      * order. The order in which the entries are visited is selected so as to
  659.      * lead to the most efficient implementation; it might depend on the
  660.      * concrete implementation of this abstract class.
  661.      *
  662.      * @param visitor the visitor to be used to process the entries of this
  663.      * vector
  664.      * @return the value returned by {@link FieldVectorChangingVisitor#end()}
  665.      * at the end of the walk
  666.      * @since 3.3
  667.      */
  668.     public T walkInOptimizedOrder(final FieldVectorChangingVisitor<T> visitor) {
  669.         return walkInDefaultOrder(visitor);
  670.     }

  671.     /**
  672.      * Visits (and possibly change) some entries of this vector in optimized
  673.      * order. The order in which the entries are visited is selected so as to
  674.      * lead to the most efficient implementation; it might depend on the
  675.      * concrete implementation of this abstract class.
  676.      *
  677.      * @param visitor visitor to be used to process the entries of this vector
  678.      * @param start the index of the first entry to be visited
  679.      * @param end the index of the last entry to be visited (inclusive)
  680.      * @return the value returned by {@link FieldVectorChangingVisitor#end()}
  681.      * at the end of the walk
  682.      * @throws NumberIsTooSmallException if {@code end < start}.
  683.      * @throws OutOfRangeException if the indices are not valid.
  684.      * @since 3.3
  685.      */
  686.     public T walkInOptimizedOrder(final FieldVectorChangingVisitor<T> visitor,
  687.                                   final int start, final int end)
  688.         throws NumberIsTooSmallException, OutOfRangeException {
  689.         return walkInDefaultOrder(visitor, start, end);
  690.     }

  691.     /** {@inheritDoc} */
  692.     @Override
  693.     public int hashCode() {
  694.         final int prime = 31;
  695.         int result = 1;
  696.         result = prime * result + ((field == null) ? 0 : field.hashCode());
  697.         result = prime * result + virtualSize;
  698.         OpenIntToFieldHashMap<T>.Iterator iter = entries.iterator();
  699.         while (iter.hasNext()) {
  700.             iter.advance();
  701.             int temp = iter.value().hashCode();
  702.             result = prime * result + temp;
  703.         }
  704.         return result;
  705.     }


  706.     /** {@inheritDoc} */
  707.     @Override
  708.     public boolean equals(Object obj) {

  709.         if (this == obj) {
  710.             return true;
  711.         }

  712.         if (!(obj instanceof SparseFieldVector<?>)) {
  713.             return false;
  714.         }

  715.         @SuppressWarnings("unchecked") // OK, because "else if" check below ensures that
  716.                                        // other must be the same type as this
  717.         SparseFieldVector<T> other = (SparseFieldVector<T>) obj;
  718.         if (field == null) {
  719.             if (other.field != null) {
  720.                 return false;
  721.             }
  722.         } else if (!field.equals(other.field)) {
  723.             return false;
  724.         }
  725.         if (virtualSize != other.virtualSize) {
  726.             return false;
  727.         }

  728.         OpenIntToFieldHashMap<T>.Iterator iter = entries.iterator();
  729.         while (iter.hasNext()) {
  730.             iter.advance();
  731.             T test = other.getEntry(iter.key());
  732.             if (!test.equals(iter.value())) {
  733.                 return false;
  734.             }
  735.         }
  736.         iter = other.getEntries().iterator();
  737.         while (iter.hasNext()) {
  738.             iter.advance();
  739.             T test = iter.value();
  740.             if (!test.equals(getEntry(iter.key()))) {
  741.                 return false;
  742.             }
  743.         }
  744.         return true;
  745.     }
  746. }