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