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.  *      https://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. /*
  18.  * This is not the original file distributed by the Apache Software Foundation
  19.  * It has been modified by the Hipparchus project
  20.  */
  21. package org.hipparchus.linear;

  22. import java.io.Serializable;

  23. import org.hipparchus.Field;
  24. import org.hipparchus.FieldElement;
  25. import org.hipparchus.exception.LocalizedCoreFormats;
  26. import org.hipparchus.exception.MathIllegalArgumentException;
  27. import org.hipparchus.exception.MathRuntimeException;
  28. import org.hipparchus.exception.NullArgumentException;
  29. import org.hipparchus.util.MathArrays;
  30. import org.hipparchus.util.MathUtils;
  31. import org.hipparchus.util.OpenIntToFieldHashMap;

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

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


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

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


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

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

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

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

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

  159.     }

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

  386.     /** {@inheritDoc} */
  387.     @Override
  388.     public FieldVector<T> projection(FieldVector<T> v)
  389.         throws MathRuntimeException {
  390.         checkVectorDimensions(v.getDimension());
  391.         return v.mapMultiply(dotProduct(v).divide(v.dotProduct(v)));
  392.     }

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

  403.     /** {@inheritDoc}
  404.      * @exception NullArgumentException if value is null
  405.      */
  406.     @Override
  407.     public void setEntry(int index, T value) throws MathIllegalArgumentException, NullArgumentException {
  408.         MathUtils.checkNotNull(value);
  409.         checkIndex(index);
  410.         entries.put(index, value);
  411.     }

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

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

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

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

  477.     /**
  478.      * Check whether an index is valid.
  479.      *
  480.      * @param index Index to check.
  481.      * @throws MathIllegalArgumentException if the index is not valid.
  482.      */
  483.     private void checkIndex(final int index) throws MathIllegalArgumentException {
  484.         MathUtils.checkRangeInclusive(index, 0, getDimension() - 1);
  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 MathIllegalArgumentException if {@code start} of {@code end} are not valid
  492.      * @throws MathIllegalArgumentException if {@code end < start}
  493.      */
  494.     private void checkIndices(final int start, final int end)
  495.         throws MathIllegalArgumentException {
  496.         final int dim = getDimension();
  497.         if ((start < 0) || (start >= dim)) {
  498.             throw new MathIllegalArgumentException(LocalizedCoreFormats.INDEX, start, 0,
  499.                                           dim - 1);
  500.         }
  501.         if ((end < 0) || (end >= dim)) {
  502.             throw new MathIllegalArgumentException(LocalizedCoreFormats.INDEX, end, 0,
  503.                                           dim - 1);
  504.         }
  505.         if (end < start) {
  506.             throw new MathIllegalArgumentException(LocalizedCoreFormats.INITIAL_ROW_AFTER_FINAL_ROW,
  507.                                                 end, start, false);
  508.         }
  509.     }

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

  523.     /** {@inheritDoc} */
  524.     @Override
  525.     public FieldVector<T> add(FieldVector<T> v) throws MathIllegalArgumentException {
  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, getDimension());
  532.             for (int i = 0; i < n; i++) {
  533.                 res.setEntry(i, v.getEntry(i).add(getEntry(i)));
  534.             }
  535.             return res;
  536.         }
  537.     }

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

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

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

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

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

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

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

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

  682.     /** {@inheritDoc} */
  683.     @Override
  684.     public int hashCode() {
  685.         final int prime = 31;
  686.         int result = 1;
  687.         result = prime * result + ((field == null) ? 0 : field.hashCode());
  688.         result = prime * result + virtualSize;
  689.         OpenIntToFieldHashMap<T>.Iterator iter = entries.iterator();
  690.         while (iter.hasNext()) {
  691.             iter.advance();
  692.             int temp = iter.value().hashCode();
  693.             result = prime * result + temp;
  694.         }
  695.         return result;
  696.     }


  697.     /** {@inheritDoc} */
  698.     @Override
  699.     public boolean equals(Object obj) {

  700.         if (this == obj) {
  701.             return true;
  702.         }

  703.         if (!(obj instanceof SparseFieldVector<?>)) {
  704.             return false;
  705.         }

  706.         @SuppressWarnings("unchecked") // OK, because "else if" check below ensures that
  707.                                        // other must be the same type as this
  708.         SparseFieldVector<T> other = (SparseFieldVector<T>) obj;
  709.         if (field == null) {
  710.             if (other.field != null) {
  711.                 return false;
  712.             }
  713.         } else if (!field.equals(other.field)) {
  714.             return false;
  715.         }
  716.         if (virtualSize != other.virtualSize) {
  717.             return false;
  718.         }

  719.         OpenIntToFieldHashMap<T>.Iterator iter = entries.iterator();
  720.         while (iter.hasNext()) {
  721.             iter.advance();
  722.             T test = other.getEntry(iter.key());
  723.             if (!test.equals(iter.value())) {
  724.                 return false;
  725.             }
  726.         }
  727.         iter = other.getEntries().iterator();
  728.         while (iter.hasNext()) {
  729.             iter.advance();
  730.             T test = iter.value();
  731.             if (!test.equals(getEntry(iter.key()))) {
  732.                 return false;
  733.             }
  734.         }
  735.         return true;
  736.     }
  737. }