1 package org.djunits.value.vfloat.matrix;
2
3 import java.util.Arrays;
4 import java.util.concurrent.atomic.AtomicInteger;
5 import java.util.stream.IntStream;
6
7 import org.djunits.value.StorageType;
8 import org.djunits.value.ValueException;
9
10
11
12
13
14
15
16
17
18
19
20
21 public class FloatMatrixDataSparse extends FloatMatrixData
22 {
23
24 private long[] indices;
25
26
27 private final int length;
28
29
30
31
32
33
34
35
36
37 public FloatMatrixDataSparse(final float[] matrixSI, final long[] indices, final int length, final int rows, final int cols)
38 {
39 super(StorageType.SPARSE);
40 this.matrixSI = matrixSI;
41 this.indices = indices;
42 this.length = length;
43 this.rows = rows;
44 this.cols = cols;
45 }
46
47
48
49
50
51
52
53
54 public FloatMatrixDataSparse(final float[] denseSI, final int rows, final int cols) throws ValueException
55 {
56 super(StorageType.SPARSE);
57 if (denseSI == null || denseSI.length == 0)
58 {
59 throw new ValueException("FloatMatrixDataSparse constructor, denseSI == null || denseSI.length == 0");
60 }
61
62 this.length = nonZero(denseSI);
63 this.rows = rows;
64 this.cols = cols;
65 this.matrixSI = new float[this.length];
66 this.indices = new long[this.length];
67 fill(denseSI, this.matrixSI, this.indices);
68 }
69
70
71
72
73
74
75 public FloatMatrixDataSparse(final float[][] dataSI) throws ValueException
76 {
77 super(StorageType.SPARSE);
78 if (dataSI == null || dataSI.length == 0)
79 {
80 throw new ValueException("FloatMatrixDataSparse constructor, matrixSI == null || matrixSI.length == 0");
81 }
82
83 this.length = nonZero(dataSI);
84 this.rows = dataSI.length;
85 this.cols = dataSI[0].length;
86 this.matrixSI = new float[this.length];
87 this.indices = new long[this.length];
88 fill(dataSI, this.matrixSI, this.indices);
89 }
90
91
92
93
94
95
96
97
98
99 @SuppressWarnings("checkstyle:finalparameters")
100 private static void fill(final float[][] data, float[] matrixSI, long[] indices) throws ValueException
101 {
102 int rows = data.length;
103 int cols = data[0].length;
104 int count = 0;
105 for (int r = 0; r < rows; r++)
106 {
107 float[] row = data[r];
108 if (row.length != cols)
109 {
110 throw new ValueException("Matrix is ragged");
111 }
112 for (int c = 0; c < cols; c++)
113 {
114 int index = r * cols + c;
115 if (row[c] != 0.0)
116 {
117 matrixSI[count] = row[c];
118 indices[count] = index;
119 count++;
120 }
121 }
122 }
123 }
124
125
126
127
128
129
130
131
132 @SuppressWarnings("checkstyle:finalparameters")
133 private static void fill(final float[] data, float[] matrixSI, long[] indices)
134 {
135 int count = 0;
136 for (int i = 0; i < data.length; i++)
137 {
138 if (data[i] != 0.0)
139 {
140 matrixSI[count] = data[i];
141 indices[count] = i;
142 count++;
143 }
144 }
145 }
146
147
148 @Override
149 public final FloatMatrixDataDense toDense()
150 {
151 float[] denseSI = new float[this.rows * this.cols];
152 for (int index = 0; index < this.matrixSI.length; index++)
153 {
154 denseSI[(int) this.indices[index]] = this.matrixSI[index];
155 }
156 try
157 {
158 return new FloatMatrixDataDense(denseSI, this.rows, this.cols);
159 }
160 catch (ValueException exception)
161 {
162 throw new RuntimeException(exception);
163 }
164 }
165
166
167 @Override
168 public final float getSI(final int row, final int col)
169 {
170 long index = row * this.cols + col;
171 int internalIndex = Arrays.binarySearch(this.indices, index);
172 return internalIndex < 0 ? 0.0f : this.matrixSI[internalIndex];
173 }
174
175
176 @Override
177 public final void setSI(final int row, final int col, final float valueSI)
178 {
179 long index = row * this.cols + col;
180 int internalIndex = Arrays.binarySearch(this.indices, index);
181 if (internalIndex >= 0)
182 {
183 this.matrixSI[internalIndex] = valueSI;
184 return;
185 }
186
187
188 internalIndex = -internalIndex - 1;
189 long[] indicesNew = new long[this.indices.length + 1];
190 float[] matrixSINew = new float[this.matrixSI.length + 1];
191 System.arraycopy(this.indices, 0, indicesNew, 0, internalIndex);
192 System.arraycopy(this.matrixSI, 0, matrixSINew, 0, internalIndex);
193 System.arraycopy(this.indices, internalIndex, indicesNew, internalIndex - 1, this.indices.length - internalIndex);
194 System.arraycopy(this.matrixSI, internalIndex, matrixSINew, internalIndex - 1, this.indices.length - internalIndex);
195 indicesNew[internalIndex] = index;
196 matrixSINew[internalIndex] = valueSI;
197 this.indices = indicesNew;
198 this.matrixSI = matrixSINew;
199 }
200
201
202 @Override
203 public final float[][] getDenseMatrixSI()
204 {
205 return toDense().getDenseMatrixSI();
206 }
207
208
209 @Override
210 public final double[][] getDoubleDenseMatrixSI()
211 {
212 return toDense().getDoubleDenseMatrixSI();
213 }
214
215
216 @Override
217 public final FloatMatrixDataSparse copy()
218 {
219 float[] vCopy = new float[this.matrixSI.length];
220 System.arraycopy(this.matrixSI, 0, vCopy, 0, this.matrixSI.length);
221 long[] iCopy = new long[this.indices.length];
222 System.arraycopy(this.indices, 0, iCopy, 0, this.indices.length);
223 return new FloatMatrixDataSparse(vCopy, iCopy, this.length, this.rows, this.cols);
224 }
225
226
227
228
229
230
231
232 public static FloatMatrixDataSparse instantiate(final float[][] valuesSI) throws ValueException
233 {
234 int length = nonZero(valuesSI);
235 final int rows = valuesSI.length;
236 final int cols = valuesSI[0].length;
237 float[] sparseSI = new float[length];
238 long[] indices = new long[length];
239 fill(valuesSI, sparseSI, indices);
240 return new FloatMatrixDataSparse(sparseSI, indices, length, rows, cols);
241 }
242
243
244
245
246
247
248 private static int nonZero(final float[][] valuesSI)
249 {
250
251 AtomicInteger atomicLength = new AtomicInteger(0);
252 IntStream.range(0, valuesSI.length).parallel().forEach(r -> IntStream.range(0, valuesSI[0].length).forEach(c -> {
253 if (valuesSI[r][c] != 0.0)
254 {
255 atomicLength.incrementAndGet();
256 }
257 }));
258
259 return atomicLength.get();
260 }
261
262
263
264
265
266
267 private static int nonZero(final float[] valuesSI)
268 {
269 return (int) IntStream.range(0, valuesSI.length).parallel().mapToDouble(i -> valuesSI[i]).filter(d -> d != 0.0).count();
270 }
271
272
273 @Override
274 public final void incrementBy(final FloatMatrixData right) throws ValueException
275 {
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290 int newLength = 0;
291 for (int r = 0; r < rows(); r++)
292 {
293 for (int c = 0; c < cols(); c++)
294 {
295 if (this.getSI(r, c) + right.getSI(r, c) != 0.0)
296 {
297 newLength++;
298 }
299 }
300 }
301 float[] newMatrixSI = new float[newLength];
302 long[] newIndices = new long[newLength];
303
304
305 int count = 0;
306 for (int r = 0; r < rows(); r++)
307 {
308 for (int c = 0; c < cols(); c++)
309 {
310 float value = this.getSI(r, c) + right.getSI(r, c);
311 if (value != 0.0)
312 {
313 int index = r * cols() + c;
314 newMatrixSI[count] = value;
315 newIndices[count] = index;
316 count++;
317 }
318 }
319 }
320
321 this.indices = newIndices;
322 this.matrixSI = newMatrixSI;
323 }
324
325
326 @Override
327 public final void decrementBy(final FloatMatrixData right) throws ValueException
328 {
329 int newLength = 0;
330 for (int r = 0; r < rows(); r++)
331 {
332 for (int c = 0; c < cols(); c++)
333 {
334 if (this.getSI(r, c) - right.getSI(r, c) != 0.0)
335 {
336 newLength++;
337 }
338 }
339 }
340 float[] newMatrixSI = new float[newLength];
341 long[] newIndices = new long[newLength];
342
343
344 int count = 0;
345 for (int r = 0; r < rows(); r++)
346 {
347 for (int c = 0; c < cols(); c++)
348 {
349 float value = this.getSI(r, c) - right.getSI(r, c);
350 if (value != 0.0)
351 {
352 int index = r * cols() + c;
353 newMatrixSI[count] = value;
354 newIndices[count] = index;
355 count++;
356 }
357 }
358 }
359
360 this.indices = newIndices;
361 this.matrixSI = newMatrixSI;
362 }
363
364
365 @Override
366 public final void multiplyBy(final FloatMatrixData right) throws ValueException
367 {
368 int newLength = 0;
369 for (int r = 0; r < rows(); r++)
370 {
371 for (int c = 0; c < cols(); c++)
372 {
373 if (this.getSI(r, c) * right.getSI(r, c) != 0.0)
374 {
375 newLength++;
376 }
377 }
378 }
379 float[] newMatrixSI = new float[newLength];
380 long[] newIndices = new long[newLength];
381
382
383 int count = 0;
384 for (int r = 0; r < rows(); r++)
385 {
386 for (int c = 0; c < cols(); c++)
387 {
388 float value = this.getSI(r, c) * right.getSI(r, c);
389 if (value != 0.0)
390 {
391 int index = r * cols() + c;
392 newMatrixSI[count] = value;
393 newIndices[count] = index;
394 count++;
395 }
396 }
397 }
398
399 this.indices = newIndices;
400 this.matrixSI = newMatrixSI;
401 }
402
403
404 @Override
405 public final void divideBy(final FloatMatrixData right) throws ValueException
406 {
407 int newLength = 0;
408 for (int r = 0; r < rows(); r++)
409 {
410 for (int c = 0; c < cols(); c++)
411 {
412 if (this.getSI(r, c) / right.getSI(r, c) != 0.0)
413 {
414 newLength++;
415 }
416 }
417 }
418 float[] newMatrixSI = new float[newLength];
419 long[] newIndices = new long[newLength];
420
421
422 int count = 0;
423 for (int r = 0; r < rows(); r++)
424 {
425 for (int c = 0; c < cols(); c++)
426 {
427 float value = this.getSI(r, c) / right.getSI(r, c);
428 if (value != 0.0)
429 {
430 int index = r * cols() + c;
431 newMatrixSI[count] = value;
432 newIndices[count] = index;
433 count++;
434 }
435 }
436 }
437
438 this.indices = newIndices;
439 this.matrixSI = newMatrixSI;
440 }
441
442
443 @Override
444 @SuppressWarnings("checkstyle:designforextension")
445 public int hashCode()
446 {
447 final int prime = 31;
448 int result = super.hashCode();
449 result = prime * result + Arrays.hashCode(this.indices);
450 result = prime * result + this.length;
451 return result;
452 }
453
454
455 @Override
456 @SuppressWarnings({ "checkstyle:needbraces", "checkstyle:designforextension" })
457 public boolean equals(final Object obj)
458 {
459 if (this == obj)
460 return true;
461 if (!super.equals(obj))
462 return false;
463 if (getClass() != obj.getClass())
464 return false;
465 FloatMatrixDataSparse other = (FloatMatrixDataSparse) obj;
466 if (!Arrays.equals(this.indices, other.indices))
467 return false;
468 if (this.length != other.length)
469 return false;
470 return true;
471 }
472 }