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