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