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