1 package org.djunits.value.vfloat.matrix.data;
2
3 import java.util.Arrays;
4 import java.util.Collection;
5 import java.util.concurrent.atomic.AtomicInteger;
6 import java.util.stream.IntStream;
7
8 import org.djunits.Throw;
9 import org.djunits.unit.Unit;
10 import org.djunits.unit.scale.Scale;
11 import org.djunits.value.ValueRuntimeException;
12 import org.djunits.value.storage.StorageType;
13 import org.djunits.value.vfloat.function.FloatFunction;
14 import org.djunits.value.vfloat.function.FloatFunction2;
15 import org.djunits.value.vfloat.matrix.base.FloatSparseValue;
16 import org.djunits.value.vfloat.scalar.base.FloatScalarInterface;
17
18
19
20
21
22
23
24
25
26
27
28 public class FloatMatrixDataSparse extends FloatMatrixData
29 {
30
31 private static final long serialVersionUID = 1L;
32
33
34 private long[] indices;
35
36
37
38
39
40
41
42
43 public FloatMatrixDataSparse(final float[] matrixSI, final long[] indices, final int rows, final int cols)
44 {
45 super(StorageType.SPARSE);
46 this.matrixSI = matrixSI;
47 this.indices = indices;
48 this.rows = rows;
49 this.cols = cols;
50 }
51
52
53
54
55
56
57
58
59
60
61 public <U extends Unit<U>, S extends FloatScalarInterface<U, S>> FloatMatrixDataSparse(
62 final Collection<FloatSparseValue<U, S>> dataSI, final int rows, final int cols) throws NullPointerException
63 {
64 super(StorageType.SPARSE);
65 Throw.whenNull(dataSI, "matrixSI is null");
66
67 int length = (int) dataSI.stream().parallel().filter(d -> d.getValueSI() != 0.0).count();
68 this.rows = rows;
69 this.cols = cols;
70 this.matrixSI = new float[length];
71 this.indices = new long[length];
72 int index = 0;
73 for (FloatSparseValue<U, S> data : dataSI)
74 {
75 if (data.getValueSI() != 0.0)
76 {
77 this.indices[index] = data.getRow() * this.cols + data.getColumn();
78 this.matrixSI[index] = data.getValueSI();
79 index++;
80 }
81 }
82 }
83
84
85 @Override
86 public final int cardinality()
87 {
88 return this.indices.length;
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 ValueRuntimeException
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
109 for (int c = 0; c < cols; c++)
110 {
111 int index = r * cols + c;
112 if (row[c] != 0.0)
113 {
114 matrixSI[count] = row[c];
115 indices[count] = index;
116 count++;
117 }
118 }
119 }
120 }
121
122
123
124
125
126
127
128
129
130
131 @SuppressWarnings("checkstyle:finalparameters")
132 private static void fill(final float[][] data, float[] matrixSI, long[] indices, final Scale scale)
133 throws ValueRuntimeException
134 {
135 int rows = data.length;
136 int cols = data[0].length;
137 int count = 0;
138 for (int r = 0; r < rows; r++)
139 {
140 float[] row = data[r];
141
142 for (int c = 0; c < cols; c++)
143 {
144 int index = r * cols + c;
145 float value = (float) scale.toStandardUnit(row[c]);
146 if (value != 0.0)
147 {
148 matrixSI[count] = value;
149 indices[count] = index;
150 count++;
151 }
152 }
153 }
154 }
155
156
157 @Override
158 public FloatMatrixData assign(final FloatFunction floatFunction)
159 {
160 if (floatFunction.apply(0f) != 0f)
161 {
162
163 FloatMatrixDataSparse result = toDense().assign(floatFunction).toSparse();
164 this.indices = result.indices;
165 this.matrixSI = result.matrixSI;
166 return this;
167 }
168
169 int currentSize = rows() * cols();
170 if (currentSize > 16)
171 {
172 currentSize = 16;
173 }
174 long[] newIndices = new long[currentSize];
175 float[] newValues = new float[currentSize];
176 int nonZeroValues = 0;
177 int ownIndex = 0;
178 while (ownIndex < this.indices.length)
179 {
180 long index = this.indices[ownIndex];
181 float value = floatFunction.apply(this.matrixSI[ownIndex]);
182 ownIndex++;
183 if (value != 0f)
184 {
185 if (nonZeroValues >= currentSize)
186 {
187
188 currentSize *= 2;
189 if (currentSize > rows() * cols())
190 {
191 currentSize = rows() * cols();
192 }
193 long[] newNewIndices = new long[currentSize];
194 System.arraycopy(newIndices, 0, newNewIndices, 0, newIndices.length);
195 newIndices = newNewIndices;
196 float[] newNewValues = new float[currentSize];
197 System.arraycopy(newValues, 0, newNewValues, 0, newValues.length);
198 newValues = newNewValues;
199 }
200 newIndices[nonZeroValues] = index;
201 newValues[nonZeroValues] = value;
202 nonZeroValues++;
203 }
204 }
205 if (nonZeroValues < currentSize)
206 {
207
208 long[] newNewIndices = new long[nonZeroValues];
209 System.arraycopy(newIndices, 0, newNewIndices, 0, nonZeroValues);
210 newIndices = newNewIndices;
211 float[] newNewValues = new float[nonZeroValues];
212 System.arraycopy(newValues, 0, newNewValues, 0, nonZeroValues);
213 newValues = newNewValues;
214 }
215 this.indices = newIndices;
216 this.matrixSI = newValues;
217 return this;
218 }
219
220
221 @Override
222 public final FloatMatrixDataSparse assign(final FloatFunction2 floatFunction, final FloatMatrixData right)
223 {
224 checkSizes(right);
225 int currentSize = rows() * cols();
226 if (currentSize > 16)
227 {
228 currentSize = 16;
229 }
230 long[] newIndices = new long[currentSize];
231 float[] newValues = new float[currentSize];
232 int nonZeroValues = 0;
233 int ownIndex = 0;
234 int otherIndex = 0;
235 if (right.isSparse())
236 {
237 FloatMatrixDataSparse/../org/djunits/value/vfloat/matrix/data/FloatMatrixDataSparse.html#FloatMatrixDataSparse">FloatMatrixDataSparse other = (FloatMatrixDataSparse) right;
238 while (ownIndex < this.indices.length || otherIndex < other.indices.length)
239 {
240 float value;
241 long index;
242 if (ownIndex < this.indices.length && otherIndex < other.indices.length)
243 {
244 if (this.indices[ownIndex] == other.indices[otherIndex])
245 {
246 value = floatFunction.apply(this.matrixSI[ownIndex], other.matrixSI[otherIndex]);
247 index = this.indices[ownIndex];
248 ownIndex++;
249 otherIndex++;
250 }
251 else if (this.indices[ownIndex] < other.indices[otherIndex])
252 {
253
254 value = floatFunction.apply(this.matrixSI[ownIndex], 0.0f);
255 index = this.indices[ownIndex];
256 ownIndex++;
257 }
258 else
259 {
260
261 value = floatFunction.apply(0.0f, other.matrixSI[otherIndex]);
262 index = other.indices[otherIndex];
263 otherIndex++;
264 }
265 }
266 else if (ownIndex < this.indices.length)
267 {
268 value = floatFunction.apply(this.matrixSI[ownIndex], 0f);
269 index = this.indices[ownIndex];
270 ownIndex++;
271 }
272 else
273 {
274 value = floatFunction.apply(0.0f, other.matrixSI[otherIndex]);
275 index = other.indices[otherIndex];
276 otherIndex++;
277 }
278 if (value != 0f)
279 {
280 if (nonZeroValues >= currentSize)
281 {
282
283 currentSize *= 2;
284 if (currentSize > rows() * cols())
285 {
286 currentSize = rows() * cols();
287 }
288 long[] newNewIndices = new long[currentSize];
289 System.arraycopy(newIndices, 0, newNewIndices, 0, newIndices.length);
290 newIndices = newNewIndices;
291 float[] newNewValues = new float[currentSize];
292 System.arraycopy(newValues, 0, newNewValues, 0, newValues.length);
293 newValues = newNewValues;
294 }
295 newIndices[nonZeroValues] = index;
296 newValues[nonZeroValues] = value;
297 nonZeroValues++;
298 }
299 }
300 }
301 else
302 {
303 FloatMatrixDataDense./../org/djunits/value/vfloat/matrix/data/FloatMatrixDataDense.html#FloatMatrixDataDense">FloatMatrixDataDense other = (FloatMatrixDataDense) right;
304 while (otherIndex < right.matrixSI.length)
305 {
306 float value;
307 int index = otherIndex;
308 if (ownIndex < this.indices.length)
309 {
310 if (this.indices[ownIndex] == otherIndex)
311 {
312 value = floatFunction.apply(this.matrixSI[ownIndex], other.matrixSI[otherIndex]);
313 ownIndex++;
314 }
315 else
316 {
317
318 value = floatFunction.apply(0.0f, other.matrixSI[otherIndex]);
319 }
320 otherIndex++;
321 }
322 else
323 {
324 value = floatFunction.apply(0.0f, other.matrixSI[otherIndex]);
325 otherIndex++;
326 }
327 if (value != 0f)
328 {
329 if (nonZeroValues >= currentSize)
330 {
331
332 currentSize *= 2;
333 if (currentSize > rows() * cols())
334 {
335 currentSize = rows() * cols();
336 }
337 long[] newNewIndices = new long[currentSize];
338 System.arraycopy(newIndices, 0, newNewIndices, 0, newIndices.length);
339 newIndices = newNewIndices;
340 float[] newNewValues = new float[currentSize];
341 System.arraycopy(newValues, 0, newNewValues, 0, newValues.length);
342 newValues = newNewValues;
343 }
344 newIndices[nonZeroValues] = index;
345 newValues[nonZeroValues] = value;
346 nonZeroValues++;
347 }
348 }
349 }
350 if (nonZeroValues < currentSize)
351 {
352
353 long[] newNewIndices = new long[nonZeroValues];
354 System.arraycopy(newIndices, 0, newNewIndices, 0, nonZeroValues);
355 newIndices = newNewIndices;
356 float[] newNewValues = new float[nonZeroValues];
357 System.arraycopy(newValues, 0, newNewValues, 0, nonZeroValues);
358 newValues = newNewValues;
359 }
360 this.indices = newIndices;
361 this.matrixSI = newValues;
362 return this;
363 }
364
365
366 @Override
367 public final FloatMatrixDataDense toDense()
368 {
369 float[] denseSI = new float[this.rows * this.cols];
370 for (int index = 0; index < this.matrixSI.length; index++)
371 {
372 denseSI[(int) this.indices[index]] = this.matrixSI[index];
373 }
374 try
375 {
376 return new FloatMatrixDataDense(denseSI, this.rows, this.cols);
377 }
378 catch (ValueRuntimeException exception)
379 {
380 throw new RuntimeException(exception);
381 }
382 }
383
384
385 @Override
386 public final FloatMatrixDataSparse toSparse()
387 {
388 return this;
389 }
390
391
392 @Override
393 public final float getSI(final int row, final int col)
394 {
395 long index = row * this.cols + col;
396 int internalIndex = Arrays.binarySearch(this.indices, index);
397 return internalIndex < 0 ? 0.0f : this.matrixSI[internalIndex];
398 }
399
400
401 @Override
402 public final void setSI(final int row, final int col, final float valueSI)
403 {
404 long index = row * this.cols + col;
405 int internalIndex = Arrays.binarySearch(this.indices, index);
406 if (internalIndex >= 0)
407 {
408 this.matrixSI[internalIndex] = valueSI;
409 return;
410 }
411
412
413 internalIndex = -internalIndex - 1;
414 long[] indicesNew = new long[this.indices.length + 1];
415 float[] matrixSINew = new float[this.matrixSI.length + 1];
416 System.arraycopy(this.indices, 0, indicesNew, 0, internalIndex);
417 System.arraycopy(this.matrixSI, 0, matrixSINew, 0, internalIndex);
418 System.arraycopy(this.indices, internalIndex, indicesNew, internalIndex + 1, this.indices.length - internalIndex);
419 System.arraycopy(this.matrixSI, internalIndex, matrixSINew, internalIndex + 1, this.indices.length - internalIndex);
420 indicesNew[internalIndex] = index;
421 matrixSINew[internalIndex] = valueSI;
422 this.indices = indicesNew;
423 this.matrixSI = matrixSINew;
424 }
425
426
427 @Override
428 public final float[][] getDenseMatrixSI()
429 {
430 return toDense().getDenseMatrixSI();
431 }
432
433
434 @Override
435 public final double[][] getDoubleDenseMatrixSI()
436 {
437 return toDense().getDoubleDenseMatrixSI();
438 }
439
440
441 @Override
442 public final FloatMatrixDataSparse copy()
443 {
444 float[] vCopy = new float[this.matrixSI.length];
445 System.arraycopy(this.matrixSI, 0, vCopy, 0, this.matrixSI.length);
446 long[] iCopy = new long[this.indices.length];
447 System.arraycopy(this.indices, 0, iCopy, 0, this.indices.length);
448 return new FloatMatrixDataSparse(vCopy, iCopy, this.rows, this.cols);
449 }
450
451
452
453
454
455
456
457 public static FloatMatrixDataSparse instantiate(final float[][] valuesSI) throws ValueRuntimeException
458 {
459 checkRectangularAndNonEmpty(valuesSI);
460 int length = nonZero(valuesSI);
461 final int rows = valuesSI.length;
462 final int cols = valuesSI[0].length;
463 float[] sparseSI = new float[length];
464 long[] indices = new long[length];
465 fill(valuesSI, sparseSI, indices);
466 return new FloatMatrixDataSparse(sparseSI, indices, rows, cols);
467 }
468
469
470
471
472
473
474
475
476 public static FloatMatrixDataSparse instantiate(final float[][] values, final Scale scale) throws ValueRuntimeException
477 {
478 checkRectangularAndNonEmpty(values);
479 int length = nonZero(values);
480 final int rows = values.length;
481 final int cols = values[0].length;
482 float[] sparseSI = new float[length];
483 long[] indices = new long[length];
484 fill(values, sparseSI, indices, scale);
485 return new FloatMatrixDataSparse(sparseSI, indices, rows, cols);
486 }
487
488
489
490
491
492
493 private static int nonZero(final float[][] valuesSI)
494 {
495
496 AtomicInteger atomicLength = new AtomicInteger(0);
497 IntStream.range(0, valuesSI.length).parallel().forEach(r -> IntStream.range(0, valuesSI[0].length).forEach(c ->
498 {
499 if (valuesSI[r][c] != 0.0f)
500 {
501 atomicLength.incrementAndGet();
502 }
503 }));
504
505 return atomicLength.get();
506 }
507
508
509 @Override
510 public FloatMatrixDataix/data/FloatMatrixData.html#FloatMatrixData">FloatMatrixData plus(final FloatMatrixData right) throws ValueRuntimeException
511 {
512 if (right.isDense())
513 {
514 return right.copy().incrementBy(this);
515 }
516 return this.copy().incrementBy(right);
517 }
518
519
520 @Override
521 public final FloatMatrixDatax/data/FloatMatrixData.html#FloatMatrixData">FloatMatrixData minus(final FloatMatrixData right)
522 {
523 if (right.isDense())
524 {
525 return this.toDense().decrementBy(right);
526 }
527 return this.copy().decrementBy(right);
528 }
529
530
531 @Override
532 public FloatMatrixDatax/data/FloatMatrixData.html#FloatMatrixData">FloatMatrixData times(final FloatMatrixData right) throws ValueRuntimeException
533 {
534 return this.copy().multiplyBy(right);
535 }
536
537
538 @Override
539 public FloatMatrixData/data/FloatMatrixData.html#FloatMatrixData">FloatMatrixData divide(final FloatMatrixData right) throws ValueRuntimeException
540 {
541 if (right.isSparse())
542 {
543
544 return this.toDense().divide(right);
545 }
546
547 return this.copy().divideBy(right);
548 }
549
550
551 @Override
552 public int hashCode()
553 {
554 return super.hashCode();
555 }
556
557
558 @Override
559 @SuppressWarnings({"checkstyle:needbraces", "checkstyle:designforextension"})
560 public boolean equals(final Object obj)
561 {
562 if (this == obj)
563 return true;
564 if (obj == null)
565 return false;
566 if (!(obj instanceof FloatMatrixData))
567 return false;
568 FloatMatrixData/../../../org/djunits/value/vfloat/matrix/data/FloatMatrixData.html#FloatMatrixData">FloatMatrixData other = (FloatMatrixData) obj;
569 if (this.rows != other.rows)
570 return false;
571 if (this.cols != other.cols)
572 return false;
573 if (other instanceof FloatMatrixDataDense)
574 return super.equals(other);
575 if (getClass() != obj.getClass())
576 return false;
577
578 if (!Arrays.equals(this.indices, ((FloatMatrixDataSparse) other).indices))
579 return false;
580 return Arrays.equals(this.matrixSI, ((FloatMatrixDataSparse) other).matrixSI);
581 }
582
583 }