1 package org.djunits.vecmat.dn;
2
3 import java.lang.reflect.Array;
4 import java.util.Arrays;
5 import java.util.Iterator;
6 import java.util.List;
7 import java.util.Objects;
8
9 import org.djunits.quantity.SIQuantity;
10 import org.djunits.quantity.def.Quantity;
11 import org.djunits.unit.UnitInterface;
12 import org.djunits.unit.si.SIUnit;
13 import org.djunits.util.ArrayMath;
14 import org.djunits.vecmat.def.Vector;
15 import org.djunits.vecmat.storage.DataGridSi;
16 import org.djunits.vecmat.storage.DenseDoubleDataSi;
17 import org.djutils.exceptions.Throw;
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32 public abstract class VectorN<Q extends Quantity<Q>, V extends VectorN<Q, V, SI, H, VT>,
33 SI extends VectorN<SIQuantity, SI, ?, ?, ?>, H extends VectorN<?, ?, ?, ?, ?>, VT extends VectorN<Q, VT, ?, ?, V>>
34 extends Vector<Q, V, SI, H, VT>
35 {
36
37 private static final long serialVersionUID = 600L;
38
39
40 @SuppressWarnings("checkstyle:visibilitymodifier")
41 protected final DataGridSi<?> dataSi;
42
43
44
45
46
47
48
49 protected VectorN(final DataGridSi<?> dataSi, final UnitInterface<Q> displayUnit)
50 {
51 super(displayUnit);
52 Throw.whenNull(dataSi, "dataSi");
53 this.dataSi = dataSi;
54 }
55
56 @Override
57 public Iterator<Q> iterator()
58 {
59 final double[] si = this.dataSi.unsafeSiArray();
60 final UnitInterface<Q> frozenDisplayUnit = getDisplayUnit();
61 return Arrays.stream(si).mapToObj(v -> frozenDisplayUnit.ofSi(v, frozenDisplayUnit)).iterator();
62 }
63
64 @Override
65 public Q[] getScalarArray()
66 {
67 final double[] siArray = this.dataSi.unsafeSiArray();
68 final UnitInterface<Q> frozenDisplayUnit = getDisplayUnit();
69 final Q first = frozenDisplayUnit.ofSi(siArray[0], frozenDisplayUnit);
70 final Class<?> qClass = first.getClass();
71 @SuppressWarnings("unchecked")
72 final Q[] out = (Q[]) Array.newInstance(qClass, siArray.length);
73 out[0] = first;
74 for (int i = 1; i < siArray.length; i++)
75 {
76 out[i] = frozenDisplayUnit.ofSi(siArray[i], frozenDisplayUnit);
77 }
78 return out;
79 }
80
81 @Override
82 public Q normL1()
83 {
84 double n = 0.0;
85 for (var d : unsafeSiArray())
86 {
87 n += Math.abs(d);
88 }
89 return getDisplayUnit().ofSi(n, getDisplayUnit());
90 }
91
92 @Override
93 public Q normL2()
94 {
95 double n = 0.0;
96 for (var d : unsafeSiArray())
97 {
98 n += d * d;
99 }
100 return getDisplayUnit().ofSi(Math.sqrt(n), getDisplayUnit());
101 }
102
103 @Override
104 public Q normLp(final int p)
105 {
106 double n = 0.0;
107 for (var d : unsafeSiArray())
108 {
109 n += Math.pow(Math.abs(d), p);
110 }
111 return getDisplayUnit().ofSi(Math.pow(n, 1.0 / p), getDisplayUnit());
112 }
113
114 @Override
115 public Q normLinf()
116 {
117 double max = Double.NEGATIVE_INFINITY;
118 for (var d : unsafeSiArray())
119 {
120 max = Math.max(Math.abs(d), max);
121 }
122 return getDisplayUnit().ofSi(max, getDisplayUnit());
123 }
124
125 @Override
126 public int rows()
127 {
128 return this.dataSi.rows();
129 }
130
131 @Override
132 public int cols()
133 {
134 return this.dataSi.cols();
135 }
136
137 @Override
138 public double[] getSiArray()
139 {
140 return this.dataSi.getSiArray();
141 }
142
143 @Override
144 public double[] unsafeSiArray()
145 {
146 return this.dataSi.unsafeSiArray();
147 }
148
149 @Override
150 public int nonZeroCount()
151 {
152 return this.dataSi.nonZeroCount();
153 }
154
155 @Override
156 public int hashCode()
157 {
158 return Objects.hash(this.dataSi, rows(), cols());
159 }
160
161 @SuppressWarnings("checkstyle:needbraces")
162 @Override
163 public boolean equals(final Object obj)
164 {
165 if (this == obj)
166 return true;
167 if (obj == null)
168 return false;
169 if (getClass() != obj.getClass())
170 return false;
171 VectorN<?, ?, ?, ?, ?> other = (VectorN<?, ?, ?, ?, ?>) obj;
172 return Objects.equals(this.dataSi, other.dataSi) && rows() == other.rows() && cols() == other.cols();
173 }
174
175
176
177
178
179
180
181
182
183
184
185 public static class Col<Q extends Quantity<Q>> extends
186 VectorN<Q, Col<Q>, VectorN.Col<SIQuantity>, VectorN.Col<?>, VectorN.Row<Q>> implements Vector.Col<VectorN.Col<Q>, Q>
187 {
188
189 private static final long serialVersionUID = 600L;
190
191
192
193
194
195
196
197
198 public Col(final DataGridSi<?> dataSi, final UnitInterface<Q> displayUnit)
199 {
200 super(dataSi, displayUnit);
201 Throw.when(dataSi.cols() != 1, IllegalArgumentException.class,
202 "Column vector initialized with more than one column");
203 }
204
205 @Override
206 public VectorN.Col<Q> instantiateSi(final double[] data, final UnitInterface<Q> displayUnit)
207 {
208 return new VectorN.Col<Q>(this.dataSi.instantiateNew(data), displayUnit);
209 }
210
211 @Override
212 public Col<SIQuantity> instantiateSi(final double[] siNew, final SIUnit siUnit)
213 {
214 return new VectorN.Col<SIQuantity>(this.dataSi.instantiateNew(siNew), siUnit);
215 }
216
217 @Override
218 public boolean isColumnVector()
219 {
220 return true;
221 }
222
223 @Override
224 public int size()
225 {
226 return this.dataSi.rows();
227 }
228
229 @Override
230 public double si(final int index) throws IndexOutOfBoundsException
231 {
232 return this.dataSi.get(index, 0);
233 }
234
235 @Override
236 public VectorN.Row<Q> transpose()
237 {
238 var newSi = this.dataSi.instantiateNew(unsafeSiArray(), cols(), rows());
239 return new VectorN.Row<Q>(newSi, getDisplayUnit());
240 }
241
242 @Override
243 public VectorN.Col<SIQuantity> invertEntries()
244 {
245 SIUnit siUnit = getDisplayUnit().siUnit().invert();
246 return new VectorN.Col<SIQuantity>(this.dataSi.instantiateNew(ArrayMath.reciprocal(unsafeSiArray())), siUnit);
247 }
248
249 @Override
250 public VectorN.Col<SIQuantity> multiplyEntries(final VectorN.Col<?> other)
251 {
252 SIUnit siUnit = SIUnit.add(getDisplayUnit().siUnit(), other.getDisplayUnit().siUnit());
253 return new VectorN.Col<SIQuantity>(
254 this.dataSi.instantiateNew(ArrayMath.multiply(unsafeSiArray(), other.unsafeSiArray())), siUnit);
255 }
256
257 @Override
258 public VectorN.Col<SIQuantity> divideEntries(final VectorN.Col<?> other)
259 {
260 SIUnit siUnit = SIUnit.subtract(getDisplayUnit().siUnit(), other.getDisplayUnit().siUnit());
261 return new VectorN.Col<SIQuantity>(
262 this.dataSi.instantiateNew(ArrayMath.divide(unsafeSiArray(), other.unsafeSiArray())), siUnit);
263 }
264
265 @Override
266 public VectorN.Col<SIQuantity> multiplyEntries(final Quantity<?> quantity)
267 {
268 SIUnit siUnit = SIUnit.add(getDisplayUnit().siUnit(), quantity.getDisplayUnit().siUnit());
269 return new VectorN.Col<SIQuantity>(this.dataSi.instantiateNew(ArrayMath.scaleBy(unsafeSiArray(), quantity.si())),
270 siUnit);
271 }
272
273
274
275
276
277
278
279
280
281
282 public static <Q extends Quantity<Q>> VectorN.Col<Q> of(final double[] dataInUnit, final UnitInterface<Q> unit)
283 {
284 double[] dataSi = new double[dataInUnit.length];
285 for (int i = 0; i < dataInUnit.length; i++)
286 {
287 dataSi[i] = unit.toBaseValue(dataInUnit[i]);
288 }
289 return ofSi(dataSi, unit);
290 }
291
292
293
294
295
296
297
298
299 public static <Q extends Quantity<Q>> VectorN.Col<Q> ofSi(final double[] dataSi, final UnitInterface<Q> displayUnit)
300 {
301 return new VectorN.Col<Q>(new DenseDoubleDataSi(dataSi.clone(), dataSi.length, 1), displayUnit);
302 }
303
304
305
306
307
308
309
310
311
312 public static <Q extends Quantity<Q>> VectorN.Col<Q> of(final Q[] data)
313 {
314 Throw.when(data.length < 1, IllegalArgumentException.class, "data array length < 1");
315 double[] dataSi = new double[data.length];
316 for (int i = 0; i < data.length; i++)
317 {
318 dataSi[i] = data[i].si();
319 }
320 return ofSi(dataSi, data[0].getDisplayUnit());
321 }
322
323
324
325
326
327
328
329
330
331
332 public static <Q extends Quantity<Q>> VectorN.Col<Q> ofSi(final DataGridSi<?> dataSi,
333 final UnitInterface<Q> displayUnit)
334 {
335 return new VectorN.Col<Q>(dataSi, displayUnit);
336 }
337
338
339
340
341
342
343
344
345
346 public static <Q extends Quantity<Q>> VectorN.Col<Q> of(final List<Q> data)
347 {
348 Throw.when(data.size() < 1, IllegalArgumentException.class, "data.size < 1");
349 double[] dataSi = new double[data.size()];
350 for (int i = 0; i < data.size(); i++)
351 {
352 dataSi[i] = data.get(i).si();
353 }
354 return ofSi(dataSi, data.get(0).getDisplayUnit());
355 }
356
357
358
359
360
361
362
363
364
365
366
367
368 public <TQ extends Quantity<TQ>> VectorN.Col<TQ> as(final UnitInterface<TQ> targetUnit) throws IllegalArgumentException
369 {
370 Throw.when(!getDisplayUnit().siUnit().equals(targetUnit.siUnit()), IllegalArgumentException.class,
371 "Quantity.as(%s) called, but units do not match: %s <> %s", targetUnit,
372 getDisplayUnit().siUnit().getDisplayAbbreviation(), targetUnit.siUnit().getDisplayAbbreviation());
373 return new VectorN.Col<TQ>(this.dataSi, targetUnit);
374 }
375
376 }
377
378
379
380
381
382
383
384
385
386
387
388 public static class Row<Q extends Quantity<Q>> extends
389 VectorN<Q, Row<Q>, VectorN.Row<SIQuantity>, VectorN.Row<?>, VectorN.Col<Q>> implements Vector.Row<VectorN.Row<Q>, Q>
390 {
391
392 private static final long serialVersionUID = 600L;
393
394
395
396
397
398
399
400
401 public Row(final DataGridSi<?> dataSi, final UnitInterface<Q> displayUnit)
402 {
403 super(dataSi, displayUnit);
404 Throw.when(dataSi.rows() != 1, IllegalArgumentException.class, "Row vector initialized with more than one row");
405 }
406
407 @Override
408 public boolean isColumnVector()
409 {
410 return false;
411 }
412
413 @Override
414 public VectorN.Row<Q> instantiateSi(final double[] data, final UnitInterface<Q> displayUnit)
415 {
416 return new VectorN.Row<>(this.dataSi.instantiateNew(data), displayUnit);
417 }
418
419 @Override
420 public VectorN.Row<SIQuantity> instantiateSi(final double[] siNew, final SIUnit siUnit)
421 {
422 return new VectorN.Row<SIQuantity>(this.dataSi.instantiateNew(siNew), siUnit);
423 }
424
425 @Override
426 public int size()
427 {
428 return this.dataSi.cols();
429 }
430
431 @Override
432 public double si(final int index) throws IndexOutOfBoundsException
433 {
434 return this.dataSi.get(0, index);
435 }
436
437 @Override
438 public VectorN.Col<Q> transpose()
439 {
440 var newSi = this.dataSi.instantiateNew(unsafeSiArray(), cols(), rows());
441 return new VectorN.Col<Q>(newSi, getDisplayUnit());
442 }
443
444 @Override
445 public VectorN.Row<SIQuantity> invertEntries()
446 {
447 SIUnit siUnit = getDisplayUnit().siUnit().invert();
448 return new VectorN.Row<SIQuantity>(this.dataSi.instantiateNew(ArrayMath.reciprocal(unsafeSiArray())), siUnit);
449 }
450
451 @Override
452 public VectorN.Row<SIQuantity> multiplyEntries(final VectorN.Row<?> other)
453 {
454 SIUnit siUnit = SIUnit.add(getDisplayUnit().siUnit(), other.getDisplayUnit().siUnit());
455 return new VectorN.Row<SIQuantity>(
456 this.dataSi.instantiateNew(ArrayMath.multiply(unsafeSiArray(), other.unsafeSiArray())), siUnit);
457 }
458
459 @Override
460 public VectorN.Row<SIQuantity> divideEntries(final VectorN.Row<?> other)
461 {
462 SIUnit siUnit = SIUnit.subtract(getDisplayUnit().siUnit(), other.getDisplayUnit().siUnit());
463 return new VectorN.Row<SIQuantity>(
464 this.dataSi.instantiateNew(ArrayMath.divide(unsafeSiArray(), other.unsafeSiArray())), siUnit);
465 }
466
467 @Override
468 public VectorN.Row<SIQuantity> multiplyEntries(final Quantity<?> quantity)
469 {
470 SIUnit siUnit = SIUnit.add(getDisplayUnit().siUnit(), quantity.getDisplayUnit().siUnit());
471 return new VectorN.Row<SIQuantity>(this.dataSi.instantiateNew(ArrayMath.scaleBy(unsafeSiArray(), quantity.si())),
472 siUnit);
473 }
474
475
476
477
478
479
480
481
482
483
484 public static <Q extends Quantity<Q>> VectorN.Row<Q> of(final double[] dataInUnit, final UnitInterface<Q> unit)
485 {
486 double[] dataSi = new double[dataInUnit.length];
487 for (int i = 0; i < dataInUnit.length; i++)
488 {
489 dataSi[i] = unit.toBaseValue(dataInUnit[i]);
490 }
491 return ofSi(dataSi, unit);
492 }
493
494
495
496
497
498
499
500
501 public static <Q extends Quantity<Q>> VectorN.Row<Q> ofSi(final double[] dataSi, final UnitInterface<Q> displayUnit)
502 {
503 return new VectorN.Row<Q>(new DenseDoubleDataSi(dataSi.clone(), 1, dataSi.length), displayUnit);
504 }
505
506
507
508
509
510
511
512
513
514 public static <Q extends Quantity<Q>> VectorN.Row<Q> of(final Q[] data)
515 {
516 Throw.when(data.length < 1, IllegalArgumentException.class, "data array length < 1");
517 double[] dataSi = new double[data.length];
518 for (int i = 0; i < data.length; i++)
519 {
520 dataSi[i] = data[i].si();
521 }
522 return ofSi(dataSi, data[0].getDisplayUnit());
523 }
524
525
526
527
528
529
530
531
532
533
534 public static <Q extends Quantity<Q>> VectorN.Row<Q> ofSi(final DataGridSi<?> dataSi,
535 final UnitInterface<Q> displayUnit)
536 {
537 return new VectorN.Row<Q>(dataSi, displayUnit);
538 }
539
540
541
542
543
544
545
546
547
548 public static <Q extends Quantity<Q>> VectorN.Row<Q> of(final List<Q> data)
549 {
550 Throw.when(data.size() < 1, IllegalArgumentException.class, "data.size < 1");
551 double[] dataSi = new double[data.size()];
552 for (int i = 0; i < data.size(); i++)
553 {
554 dataSi[i] = data.get(i).si();
555 }
556 return ofSi(dataSi, data.get(0).getDisplayUnit());
557 }
558
559
560
561
562
563
564
565
566
567
568
569
570 public <TQ extends Quantity<TQ>> VectorN.Row<TQ> as(final UnitInterface<TQ> targetUnit) throws IllegalArgumentException
571 {
572 Throw.when(!getDisplayUnit().siUnit().equals(targetUnit.siUnit()), IllegalArgumentException.class,
573 "Quantity.as(%s) called, but units do not match: %s <> %s", targetUnit,
574 getDisplayUnit().siUnit().getDisplayAbbreviation(), targetUnit.siUnit().getDisplayAbbreviation());
575 return new VectorN.Row<TQ>(this.dataSi, targetUnit);
576 }
577
578 }
579
580 }