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