1 package org.djunits.vecmat.dn;
2
3 import java.util.Objects;
4
5 import org.djunits.quantity.SIQuantity;
6 import org.djunits.quantity.def.Quantity;
7 import org.djunits.unit.UnitInterface;
8 import org.djunits.unit.si.SIUnit;
9 import org.djunits.util.ArrayMath;
10 import org.djunits.util.MatrixMath;
11 import org.djunits.vecmat.NonInvertibleMatrixException;
12 import org.djunits.vecmat.d1.Matrix1x1;
13 import org.djunits.vecmat.d2.Matrix2x2;
14 import org.djunits.vecmat.d3.Matrix3x3;
15 import org.djunits.vecmat.def.SquareMatrix;
16 import org.djunits.vecmat.storage.DataGridSi;
17 import org.djunits.vecmat.storage.DenseDoubleDataSi;
18 import org.djutils.exceptions.Throw;
19
20
21
22
23
24
25
26
27
28
29
30
31 public class MatrixNxN<Q extends Quantity<Q, U>, U extends UnitInterface<U, Q>>
32 extends SquareMatrix<Q, U, MatrixNxN<Q, U>, MatrixNxN<SIQuantity, SIUnit>, MatrixNxN<?, ?>>
33 {
34
35 private static final long serialVersionUID = 600L;
36
37
38 private final DataGridSi<?> dataSi;
39
40
41
42
43
44
45
46 public MatrixNxN(final DataGridSi<?> dataSi, final U displayUnit)
47 {
48 super(displayUnit);
49 Throw.whenNull(dataSi, "dataSi");
50 Throw.when(dataSi.rows() != dataSi.cols(), IllegalArgumentException.class, "Data for the NxN matrix is not square");
51 this.dataSi = dataSi;
52 }
53
54
55
56
57
58
59
60
61
62
63 @SuppressWarnings("checkstyle:needbraces")
64 public static <Q extends Quantity<Q, U>, U extends UnitInterface<U, Q>> MatrixNxN<Q, U> of(final double[] valueArrayInUnit,
65 final U displayUnit)
66 {
67 Throw.whenNull(valueArrayInUnit, "valueArrayInUnit");
68 Throw.whenNull(displayUnit, "displayUnit");
69 int len = valueArrayInUnit.length;
70
71
72
73
74
75 int n = (int) Math.sqrt(len);
76 Throw.when(len != n * n, IllegalArgumentException.class,
77 "valueArrayInUnit does not contain a square number of entries (%d)", len);
78 double[] aSi = new double[valueArrayInUnit.length];
79 for (int i = 0; i < valueArrayInUnit.length; i++)
80 aSi[i] = displayUnit.toBaseValue(valueArrayInUnit[i]);
81 return new MatrixNxN<Q, U>(new DenseDoubleDataSi(aSi, n, n), displayUnit);
82 }
83
84
85
86
87
88
89
90
91
92
93
94 @SuppressWarnings("checkstyle:needbraces")
95 public static <Q extends Quantity<Q, U>, U extends UnitInterface<U, Q>> MatrixNxN<Q, U> of(final double[][] valueGridInUnit,
96 final U displayUnit)
97 {
98 Throw.whenNull(valueGridInUnit, "valueGridInUnit");
99 Throw.whenNull(displayUnit, "displayUnit");
100 int n = valueGridInUnit.length;
101 Throw.when(n == 0, IllegalArgumentException.class, "valueGridInUnit has 0 rows");
102 double[] aSi = new double[n * n];
103 for (int r = 0; r < valueGridInUnit.length; r++)
104 {
105 Throw.when(valueGridInUnit[r].length != n, IllegalArgumentException.class,
106 "valueGridInUnit is not a NxN array; row %d has a length of %d, not %d", r, valueGridInUnit[r].length, n);
107 for (int c = 0; c < n; c++)
108 aSi[n * r + c] = displayUnit.toBaseValue(valueGridInUnit[r][c]);
109 }
110 return new MatrixNxN<Q, U>(new DenseDoubleDataSi(aSi, n, n), displayUnit);
111 }
112
113 @Override
114 public MatrixNxN<Q, U> instantiateSi(final double[] siNew)
115 {
116 return new MatrixNxN<Q, U>(this.dataSi.instantiateNew(siNew), getDisplayUnit().getBaseUnit())
117 .setDisplayUnit(getDisplayUnit());
118 }
119
120 @Override
121 public double[] si()
122 {
123 return this.dataSi.getDataArray();
124 }
125
126 @Override
127 public double si(final int row, final int col)
128 {
129 return this.dataSi.get(row, col);
130 }
131
132 @Override
133 public int rows()
134 {
135 return this.dataSi.rows();
136 }
137
138 @Override
139 public int cols()
140 {
141 return this.dataSi.cols();
142 }
143
144
145
146
147
148 public DataGridSi<?> getDataGrid()
149 {
150 return this.dataSi;
151 }
152
153 @Override
154 public MatrixNxN<SIQuantity, SIUnit> instantiateSi(final double[] siNew, final SIUnit siUnit)
155 {
156 return new MatrixNxN<SIQuantity, SIUnit>(this.dataSi.instantiateNew(siNew), siUnit);
157 }
158
159 @Override
160 public VectorN.Row<Q, U> getRowVector(final int row)
161 {
162 checkRow(row);
163 return VectorN.Row.ofSi(this.dataSi.getRowArray(row), getDisplayUnit());
164 }
165
166 @Override
167 public VectorN.Row<Q, U> mgetRowVector(final int mRow)
168 {
169 mcheckRow(mRow);
170 return VectorN.Row.ofSi(this.dataSi.getRowArray(mRow - 1), getDisplayUnit());
171 }
172
173 @Override
174 public VectorN.Col<Q, U> getColumnVector(final int col)
175 {
176 checkCol(col);
177 return VectorN.Col.ofSi(this.dataSi.getColArray(col), getDisplayUnit());
178 }
179
180 @Override
181 public VectorN.Col<Q, U> mgetColumnVector(final int mCol)
182 {
183 mcheckCol(mCol);
184 return VectorN.Col.ofSi(this.dataSi.getColArray(mCol - 1), getDisplayUnit());
185 }
186
187 @Override
188 public VectorN.Col<Q, U> getDiagonalVector() throws IllegalStateException
189 {
190 final int n = rows();
191 final double[] data = new double[n];
192 for (int i = 0; i < n; i++)
193 {
194 data[i] = si(i, i);
195 }
196
197 return VectorN.Col.ofSi(data, getDisplayUnit());
198 }
199
200 @Override
201 public double[] getRowSi(final int row)
202 {
203 checkRow(row);
204 return this.dataSi.getRowArray(row);
205 }
206
207 @Override
208 public double[] getColumnSi(final int col)
209 {
210 checkCol(col);
211 return this.dataSi.getColArray(col);
212 }
213
214 @Override
215 public MatrixNxN<SIQuantity, SIUnit> inverse() throws NonInvertibleMatrixException
216 {
217 double[] invData = MatrixMath.inverse(si(), order());
218 return new MatrixNxN<SIQuantity, SIUnit>(this.dataSi.instantiateNew(invData), getDisplayUnit().siUnit().invert());
219 }
220
221 @Override
222 public MatrixNxN<SIQuantity, SIUnit> adjugate()
223 {
224 double[] invData = MatrixMath.adjugate(si(), order());
225 return new MatrixNxN<SIQuantity, SIUnit>(this.dataSi.instantiateNew(invData),
226 getDisplayUnit().siUnit().pow(order() - 1));
227 }
228
229 @Override
230 public MatrixNxN<SIQuantity, SIUnit> invertElements()
231 {
232 SIUnit siUnit = getDisplayUnit().siUnit().invert();
233 return new MatrixNxN<SIQuantity, SIUnit>(this.dataSi.instantiateNew(ArrayMath.reciprocal(si())), siUnit);
234 }
235
236 @Override
237 public MatrixNxN<SIQuantity, SIUnit> multiplyElements(final MatrixNxN<?, ?> other)
238 {
239 SIUnit siUnit = SIUnit.add(getDisplayUnit().siUnit(), other.getDisplayUnit().siUnit());
240 return new MatrixNxN<SIQuantity, SIUnit>(this.dataSi.instantiateNew(ArrayMath.multiply(si(), other.si())), siUnit);
241 }
242
243 @Override
244 public MatrixNxN<SIQuantity, SIUnit> divideElements(final MatrixNxN<?, ?> other)
245 {
246 SIUnit siUnit = SIUnit.subtract(getDisplayUnit().siUnit(), other.getDisplayUnit().siUnit());
247 return new MatrixNxN<SIQuantity, SIUnit>(this.dataSi.instantiateNew(ArrayMath.divide(si(), other.si())), siUnit);
248 }
249
250 @Override
251 public MatrixNxN<SIQuantity, SIUnit> multiplyElements(final Quantity<?, ?> quantity)
252 {
253 SIUnit siUnit = SIUnit.add(getDisplayUnit().siUnit(), quantity.getDisplayUnit().siUnit());
254 return new MatrixNxN<SIQuantity, SIUnit>(this.dataSi.instantiateNew(ArrayMath.scaleBy(si(), quantity.si())), siUnit);
255 }
256
257 @Override
258 public int hashCode()
259 {
260 return Objects.hash(this.dataSi);
261 }
262
263 @SuppressWarnings("checkstyle:needbraces")
264 @Override
265 public boolean equals(final Object obj)
266 {
267 if (this == obj)
268 return true;
269 if (obj == null)
270 return false;
271 if (getClass() != obj.getClass())
272 return false;
273 MatrixNxN<?, ?> other = (MatrixNxN<?, ?>) obj;
274 return Objects.equals(this.dataSi, other.dataSi);
275 }
276
277
278
279
280
281
282
283
284
285
286
287 public MatrixNxN<SIQuantity, SIUnit> multiply(final MatrixNxN<?, ?> otherMat)
288 {
289 checkMultiply(otherMat);
290 final int n = order();
291 final double[] resultData = MatrixMath.multiply(si(), otherMat.si(), n, n, n);
292 final SIUnit resultUnit = getDisplayUnit().siUnit().plus(otherMat.getDisplayUnit().siUnit());
293 return new MatrixNxN<SIQuantity, SIUnit>(this.dataSi.instantiateNew(resultData), resultUnit);
294 }
295
296
297
298
299
300
301
302
303
304
305 public VectorN.Col<SIQuantity, SIUnit> multiply(final VectorN.Col<?, ?> otherVec)
306 {
307 checkMultiply(otherVec);
308 final int n = order();
309 final double[] resultData = MatrixMath.multiply(si(), otherVec.si(), n, n, 1);
310 final SIUnit resultUnit = getDisplayUnit().siUnit().plus(otherVec.getDisplayUnit().siUnit());
311 return VectorN.Col.ofSi(resultData, resultUnit);
312 }
313
314
315
316
317
318
319
320
321
322
323
324
325 public <TQ extends Quantity<TQ, TU>, TU extends UnitInterface<TU, TQ>> MatrixNxN<TQ, TU> as(final TU targetUnit)
326 {
327 Throw.when(!getDisplayUnit().siUnit().equals(targetUnit.siUnit()), IllegalArgumentException.class,
328 "MatrixNxN.as(%s) called, but units do not match: %s <> %s", targetUnit,
329 getDisplayUnit().siUnit().getDisplayAbbreviation(), targetUnit.siUnit().getDisplayAbbreviation());
330 return new MatrixNxN<TQ, TU>(this.dataSi.instantiateNew(si()), targetUnit.getBaseUnit()).setDisplayUnit(targetUnit);
331 }
332
333
334
335
336
337
338 public Matrix1x1<Q, U> asMatrix1x1()
339 {
340 Throw.when(order() != 1, IllegalStateException.class, "asMatrix1x1() called, but matrix is no 1x1 but %dx%d", rows(),
341 cols());
342 return Matrix1x1.of(si(), getDisplayUnit().getBaseUnit()).setDisplayUnit(getDisplayUnit());
343 }
344
345
346
347
348
349
350 public Matrix2x2<Q, U> asMatrix2x2()
351 {
352 Throw.when(order() != 2, IllegalStateException.class, "asMatrix2x2() called, but matrix is no 2x2 but %dx%d", rows(),
353 cols());
354 return Matrix2x2.of(si(), getDisplayUnit().getBaseUnit()).setDisplayUnit(getDisplayUnit());
355 }
356
357
358
359
360
361
362 public Matrix3x3<Q, U> asMatrix3x3()
363 {
364 Throw.when(order() != 3, IllegalStateException.class, "asMatrix3x3() called, but matrix is no 3x3 but %dx%d", rows(),
365 cols());
366 return Matrix3x3.of(si(), getDisplayUnit().getBaseUnit()).setDisplayUnit(getDisplayUnit());
367 }
368
369 }