View Javadoc
1   package org.djunits.value.vfloat.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 FloatVector 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 FloatVectorDataSparse extends FloatVectorData
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 float[]; 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 FloatVectorDataSparse(final float[] 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 FloatVectorDataDense toDense()
48      {
49          float[] denseSI = new float[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 FloatVectorDataDense(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 float getSI(final int index)
67      {
68          int internalIndex = Arrays.binarySearch(this.indices, index);
69          return internalIndex < 0 ? 0.0f : this.vectorSI[internalIndex];
70      }
71  
72      /** {@inheritDoc} */
73      @Override
74      public final void setSI(final int index, final float 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          float[] vectorSINew = new float[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          indicesNew[internalIndex] = index;
95          vectorSINew[internalIndex] = valueSI;
96          this.indices = indicesNew;
97          this.vectorSI = vectorSINew;
98      }
99  
100     /** {@inheritDoc} */
101     @Override
102     public final float[] getDenseVectorSI()
103     {
104         return toDense().vectorSI;
105     }
106 
107     /** {@inheritDoc} */
108     @Override
109     public final FloatVectorDataSparse copy()
110     {
111         float[] vCopy = new float[this.vectorSI.length];
112         System.arraycopy(this.vectorSI, 0, vCopy, 0, this.vectorSI.length);
113         int[] iCopy = new int[this.indices.length];
114         System.arraycopy(this.indices, 0, iCopy, 0, this.indices.length);
115         return new FloatVectorDataSparse(vCopy, iCopy, this.size);
116     }
117 
118     /**
119      * Instantiate a FloatVectorDataSparse from an array.
120      * @param valuesSI float[]; the (SI) values to store
121      * @return the FloatVectorDataSparse
122      */
123     public static FloatVectorDataSparse instantiate(final float[] valuesSI)
124     {
125         // determine number of non-null cells
126         int length = (int) IntStream.range(0, valuesSI.length).parallel().mapToDouble(i -> valuesSI[i]).filter(f -> f != 0.0f)
127                 .count();
128         float[] sparseSI = new float[length];
129         int[] indices = new int[length];
130 
131         // fill the sparse data structures. Cannot be parallelized because of stateful and sequence-sensitive count
132         int count = 0;
133         for (int i = 0; i < valuesSI.length; i++)
134         {
135             if (valuesSI[i] != 0.0)
136             {
137                 sparseSI[count] = valuesSI[i];
138                 indices[count] = i;
139                 count++;
140             }
141         }
142         return new FloatVectorDataSparse(sparseSI, indices, valuesSI.length);
143     }
144 
145     /** {@inheritDoc} */
146     @Override
147     public final void incrementBy(final FloatVectorData right) throws ValueException
148     {
149         int newLength =
150                 (int) IntStream.range(0, size()).parallel().filter(i -> this.getSI(i) != 0.0 || right.getSI(i) != 0.0).count();
151         float[] newVectorSI = new float[newLength];
152         int[] newIndices = new int[newLength];
153 
154         // fill the sparse data structures. Cannot be parallelized because of stateful and sequence-sensitive count
155         // note: if adding -2 and +2, a 0-value will be part of the new sparse matrix.
156         int count = 0;
157         for (int i = 0; i < size(); i++)
158         {
159             if (this.getSI(i) != 0.0 || right.getSI(i) != 0.0)
160             {
161                 newVectorSI[count] = getSI(i) + right.getSI(i);
162                 newIndices[count] = i;
163                 count++;
164             }
165         }
166 
167         this.indices = newIndices;
168         this.vectorSI = newVectorSI;
169     }
170 
171     /** {@inheritDoc} */
172     @Override
173     public final void decrementBy(final FloatVectorData right) throws ValueException
174     {
175         int newLength =
176                 (int) IntStream.range(0, size()).parallel().filter(i -> this.getSI(i) != 0.0 || right.getSI(i) != 0.0).count();
177         float[] newVectorSI = new float[newLength];
178         int[] newIndices = new int[newLength];
179 
180         // fill the sparse data structures. Cannot be parallelized because of stateful and sequence-sensitive count
181         // note: if subtracting 2 from 2, a 0-value will be part of the new sparse matrix.
182         int count = 0;
183         for (int i = 0; i < size(); i++)
184         {
185             if (this.getSI(i) != 0.0 || right.getSI(i) != 0.0)
186             {
187                 newVectorSI[count] = getSI(i) - right.getSI(i);
188                 newIndices[count] = i;
189                 count++;
190             }
191         }
192 
193         this.indices = newIndices;
194         this.vectorSI = newVectorSI;
195     }
196 
197     /** {@inheritDoc} */
198     @Override
199     public final void multiplyBy(final FloatVectorData right) throws ValueException
200     {
201         int newLength =
202                 (int) IntStream.range(0, size()).parallel().filter(i -> this.getSI(i) != 0.0 && right.getSI(i) != 0.0).count();
203         float[] newVectorSI = new float[newLength];
204         int[] newIndices = new int[newLength];
205 
206         // fill the sparse data structures. Cannot be parallelized because of stateful and sequence-sensitive count
207         int count = 0;
208         for (int i = 0; i < size(); i++)
209         {
210             if (this.getSI(i) != 0.0 && right.getSI(i) != 0.0)
211             {
212                 newVectorSI[count] = getSI(i) * right.getSI(i);
213                 newIndices[count] = i;
214                 count++;
215             }
216         }
217 
218         this.indices = newIndices;
219         this.vectorSI = newVectorSI;
220     }
221 
222     /** {@inheritDoc} */
223     @Override
224     public final void divideBy(final FloatVectorData right) throws ValueException
225     {
226         int newLength =
227                 (int) IntStream.range(0, size()).parallel().filter(i -> this.getSI(i) != 0.0 && right.getSI(i) != 0.0).count();
228         float[] newVectorSI = new float[newLength];
229         int[] newIndices = new int[newLength];
230 
231         // fill the sparse data structures. Cannot be parallelized because of stateful and sequence-sensitive count
232         int count = 0;
233         for (int i = 0; i < size(); i++)
234         {
235             if (this.getSI(i) != 0.0 && right.getSI(i) != 0.0)
236             {
237                 newVectorSI[count] = getSI(i) / right.getSI(i);
238                 newIndices[count] = i;
239                 count++;
240             }
241         }
242 
243         this.indices = newIndices;
244         this.vectorSI = newVectorSI;
245     }
246 
247     /** {@inheritDoc} */
248     @Override
249     @SuppressWarnings("checkstyle:designforextension")
250     public int hashCode()
251     {
252         final int prime = 31;
253         int result = super.hashCode();
254         result = prime * result + Arrays.hashCode(this.indices);
255         result = prime * result + this.size;
256         return result;
257     }
258 
259     /** {@inheritDoc} */
260     @SuppressWarnings({ "checkstyle:needbraces", "checkstyle:designforextension" })
261     @Override
262     public boolean equals(final Object obj)
263     {
264         if (this == obj)
265             return true;
266         if (!super.equals(obj))
267             return false;
268         if (getClass() != obj.getClass())
269             return false;
270         FloatVectorDataSparse other = (FloatVectorDataSparse) obj;
271         if (!Arrays.equals(this.indices, other.indices))
272             return false;
273         if (this.size != other.size)
274             return false;
275         return true;
276     }
277 }