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