View Javadoc
1   package org.djunits.value.vdouble.vector;
2   
3   import java.util.Arrays;
4   import java.util.stream.IntStream;
5   
6   import org.djunits.value.StorageType;
7   import org.djunits.value.ValueException;
8   
9   /**
10   * Stores sparse data for a DoubleVector and carries out basic operations.
11   * <p>
12   * Copyright (c) 2013-2018 Delft University of Technology, PO Box 5, 2600 AA, Delft, the Netherlands. All rights reserved. <br>
13   * BSD-style license. See <a href="http://opentrafficsim.org/docs/license.html">OpenTrafficSim License</a>.
14   * </p>
15   * $LastChangedDate: 2015-07-24 02:58:59 +0200 (Fri, 24 Jul 2015) $, @version $Revision: 1147 $, by $Author: averbraeck $,
16   * initial version Oct 3, 2015 <br>
17   * @author <a href="http://www.tbm.tudelft.nl/averbraeck">Alexander Verbraeck</a>
18   * @author <a href="http://www.tudelft.nl/pknoppers">Peter Knoppers</a>
19   */
20  public class DoubleVectorDataSparse extends DoubleVectorData
21  {
22      /** the index values of the Vector. */
23      private int[] indices;
24  
25      /** the length of the vector (padded with 0 after highest index in indices). */
26      private final int size;
27  
28      /**
29       * Create a vector with sparse data.
30       * @param vectorSI the data to store
31       * @param indices the index values of the Vector
32       * @param size the length of the vector (padded with 0 after highest index in indices)
33       */
34      public DoubleVectorDataSparse(final double[] vectorSI, final int[] indices, final int size)
35      {
36          super(StorageType.SPARSE);
37          this.vectorSI = vectorSI;
38          this.indices = indices;
39          this.size = size;
40      }
41  
42      /** {@inheritDoc} */
43      @Override
44      public final DoubleVectorDataDense toDense()
45      {
46          double[] denseSI = new double[this.size];
47          for (int index = 0; index < this.vectorSI.length; index++)
48          {
49              denseSI[this.indices[index]] = this.vectorSI[index];
50          }
51          return new DoubleVectorDataDense(denseSI);
52      }
53  
54      /** {@inheritDoc} */
55      @Override
56      public final int size()
57      {
58          return this.size;
59      }
60  
61      /** {@inheritDoc} */
62      @Override
63      public final double getSI(final int index)
64      {
65          int internalIndex = Arrays.binarySearch(this.indices, index);
66          return internalIndex < 0 ? 0.0 : this.vectorSI[internalIndex];
67      }
68  
69      /** {@inheritDoc} */
70      @Override
71      public final void setSI(final int index, final double valueSI)
72      {
73          int internalIndex = Arrays.binarySearch(this.indices, index);
74          if (internalIndex >= 0)
75          {
76              this.vectorSI[internalIndex] = valueSI;
77              return;
78          }
79  
80          // make room. TODO increase size in chunks
81          internalIndex = -internalIndex - 1;
82          int[] indicesNew = new int[this.indices.length + 1];
83          double[] vectorSINew = new double[this.vectorSI.length + 1];
84          System.arraycopy(this.indices, 0, indicesNew, 0, internalIndex);
85          System.arraycopy(this.vectorSI, 0, vectorSINew, 0, internalIndex);
86          // System.out.println("arraycopy1 current size is " + this.indices.length + " srcPos=" + internalIndex +
87          // ", new size is "
88          // + indicesNew.length + " dstPos=" + (internalIndex + 1) + " length=" + (this.indices.length - internalIndex));
89          System.arraycopy(this.indices, internalIndex, indicesNew, internalIndex + 1, this.indices.length - internalIndex);
90          System.arraycopy(this.vectorSI, internalIndex, vectorSINew, internalIndex + 1, this.indices.length - internalIndex);
91          // System.arraycopy(this.indices, internalIndex, indicesNew, internalIndex - 1, this.indices.length - internalIndex);
92          // System.arraycopy(this.vectorSI, internalIndex, vectorSINew, internalIndex - 1, this.indices.length - internalIndex);
93          indicesNew[internalIndex] = index;
94          vectorSINew[internalIndex] = valueSI;
95          this.indices = indicesNew;
96          this.vectorSI = vectorSINew;
97      }
98  
99      /** {@inheritDoc} */
100     @Override
101     public final double[] getDenseVectorSI()
102     {
103         return toDense().vectorSI;
104     }
105 
106     /** {@inheritDoc} */
107     @Override
108     public final DoubleVectorDataSparse copy()
109     {
110         double[] vCopy = new double[this.vectorSI.length];
111         System.arraycopy(this.vectorSI, 0, vCopy, 0, this.vectorSI.length);
112         int[] iCopy = new int[this.indices.length];
113         System.arraycopy(this.indices, 0, iCopy, 0, this.indices.length);
114         return new DoubleVectorDataSparse(vCopy, iCopy, this.size);
115     }
116 
117     /**
118      * Instantiate a DoubleVectorDataSparse from an array.
119      * @param valuesSI the (SI) values to store
120      * @return the DoubleVectorDataSparse
121      */
122     public static DoubleVectorDataSparse instantiate(final double[] valuesSI)
123     {
124         // determine number of non-null cells
125         int length = (int) Arrays.stream(valuesSI).parallel().filter(d -> d != 0.0).count();
126         double[] sparseSI = new double[length];
127         int[] indices = new int[length];
128 
129         // fill the sparse data structures. Cannot be parallelized because of stateful and sequence-sensitive count
130         int count = 0;
131         for (int i = 0; i < valuesSI.length; i++)
132         {
133             if (valuesSI[i] != 0.0)
134             {
135                 sparseSI[count] = valuesSI[i];
136                 indices[count] = i;
137                 count++;
138             }
139         }
140         return new DoubleVectorDataSparse(sparseSI, indices, valuesSI.length);
141     }
142 
143     /** {@inheritDoc} */
144     @Override
145     public final void incrementBy(final DoubleVectorData right) throws ValueException
146     {
147         int newLength =
148                 (int) IntStream.range(0, size()).parallel().filter(i -> this.getSI(i) != 0.0 || right.getSI(i) != 0.0).count();
149         double[] newVectorSI = new double[newLength];
150         int[] newIndices = new int[newLength];
151 
152         // fill the sparse data structures. Cannot be parallelized because of stateful and sequence-sensitive count
153         // note: if adding -2 and +2, a 0-value will be part of the new sparse vector.
154         int count = 0;
155         for (int i = 0; i < size(); i++)
156         {
157             if (this.getSI(i) != 0.0 || right.getSI(i) != 0.0)
158             {
159                 newVectorSI[count] = getSI(i) + right.getSI(i);
160                 newIndices[count] = i;
161                 count++;
162             }
163         }
164 
165         this.indices = newIndices;
166         this.vectorSI = newVectorSI;
167     }
168 
169     /** {@inheritDoc} */
170     @Override
171     public final void decrementBy(final DoubleVectorData right) throws ValueException
172     {
173         int newLength =
174                 (int) IntStream.range(0, size()).parallel().filter(i -> this.getSI(i) != 0.0 || right.getSI(i) != 0.0).count();
175         double[] newVectorSI = new double[newLength];
176         int[] newIndices = new int[newLength];
177 
178         // fill the sparse data structures. Cannot be parallelized because of stateful and sequence-sensitive count
179         // note: if subtracting 2 from 2, a 0-value will be part of the new sparse vector.
180         int count = 0;
181         for (int i = 0; i < size(); i++)
182         {
183             if (this.getSI(i) != 0.0 || right.getSI(i) != 0.0)
184             {
185                 newVectorSI[count] = getSI(i) - right.getSI(i);
186                 newIndices[count] = i;
187                 count++;
188             }
189         }
190 
191         this.indices = newIndices;
192         this.vectorSI = newVectorSI;
193     }
194 
195     /** {@inheritDoc} */
196     @Override
197     public final void multiplyBy(final DoubleVectorData right) throws ValueException
198     {
199         int newLength =
200                 (int) IntStream.range(0, size()).parallel().filter(i -> this.getSI(i) != 0.0 && right.getSI(i) != 0.0).count();
201         double[] newVectorSI = new double[newLength];
202         int[] newIndices = new int[newLength];
203 
204         // fill the sparse data structures. Cannot be parallelized because of stateful and sequence-sensitive count
205         int count = 0;
206         for (int i = 0; i < size(); i++)
207         {
208             if (this.getSI(i) != 0.0 && right.getSI(i) != 0.0)
209             {
210                 newVectorSI[count] = getSI(i) * right.getSI(i);
211                 newIndices[count] = i;
212                 count++;
213             }
214         }
215 
216         this.indices = newIndices;
217         this.vectorSI = newVectorSI;
218     }
219 
220     /** {@inheritDoc} */
221     @Override
222     public final void divideBy(final DoubleVectorData right) throws ValueException
223     {
224         int newLength =
225                 (int) IntStream.range(0, size()).parallel().filter(i -> this.getSI(i) != 0.0 && right.getSI(i) != 0.0).count();
226         double[] newVectorSI = new double[newLength];
227         int[] newIndices = new int[newLength];
228 
229         // fill the sparse data structures. Cannot be parallelized because of stateful and sequence-sensitive count
230         int count = 0;
231         for (int i = 0; i < size(); i++)
232         {
233             if (this.getSI(i) != 0.0 && right.getSI(i) != 0.0)
234             {
235                 newVectorSI[count] = getSI(i) / right.getSI(i);
236                 newIndices[count] = i;
237                 count++;
238             }
239         }
240 
241         this.indices = newIndices;
242         this.vectorSI = newVectorSI;
243     }
244 
245     /** {@inheritDoc} */
246     @Override
247     @SuppressWarnings("checkstyle:designforextension")
248     public int hashCode()
249     {
250         final int prime = 31;
251         int result = super.hashCode();
252         result = prime * result + Arrays.hashCode(this.indices);
253         result = prime * result + this.size;
254         return result;
255     }
256 
257     /** {@inheritDoc} */
258     @SuppressWarnings({ "checkstyle:needbraces", "checkstyle:designforextension" })
259     @Override
260     public boolean equals(final Object obj)
261     {
262         if (this == obj)
263             return true;
264         if (!super.equals(obj))
265             return false;
266         if (getClass() != obj.getClass())
267             return false;
268         DoubleVectorDataSparse other = (DoubleVectorDataSparse) obj;
269         if (!Arrays.equals(this.indices, other.indices))
270             return false;
271         if (this.size != other.size)
272             return false;
273         return true;
274     }
275 }