View Javadoc
1   package org.djunits.value.vfloat.matrix.base;
2   
3   import java.lang.reflect.Array;
4   
5   import org.djunits.Throw;
6   import org.djunits.unit.Unit;
7   import org.djunits.value.Absolute;
8   import org.djunits.value.AbstractIndexedValue;
9   import org.djunits.value.ValueRuntimeException;
10  import org.djunits.value.formatter.Format;
11  import org.djunits.value.storage.StorageType;
12  import org.djunits.value.util.ValueUtil;
13  import org.djunits.value.vfloat.function.FloatFunction;
14  import org.djunits.value.vfloat.function.FloatMathFunctions;
15  import org.djunits.value.vfloat.matrix.data.FloatMatrixData;
16  import org.djunits.value.vfloat.scalar.base.AbstractFloatScalar;
17  import org.djunits.value.vfloat.scalar.base.FloatScalar;
18  import org.djunits.value.vfloat.vector.base.AbstractFloatVector;
19  import org.djunits.value.vfloat.vector.data.FloatVectorData;
20  import org.ojalgo.matrix.PrimitiveMatrix;
21  
22  /**
23   * The most basic abstract class for the FloatMatrix.
24   * <p>
25   * Copyright (c) 2013-2019 Delft University of Technology, PO Box 5, 2600 AA, Delft, the Netherlands. All rights reserved. <br>
26   * BSD-style license. See <a href="https://djunits.org/docs/license.html">DJUNITS License</a>.
27   * </p>
28   * @author <a href="https://www.tudelft.nl/averbraeck">Alexander Verbraeck</a>
29   * @author <a href="https://www.tudelft.nl/staff/p.knoppers/">Peter Knoppers</a>
30   * @author <a href="https://www.transport.citg.tudelft.nl">Wouter Schakel</a>
31   * @param <U> the unit
32   * @param <S> the scalar with unit U
33   * @param <V> the vector type belonging to the matrix type
34   * @param <M> the generic matrix type
35   */
36  public abstract class AbstractFloatMatrix<U extends Unit<U>, S extends AbstractFloatScalar<U, S>,
37          V extends AbstractFloatVector<U, S, V>, M extends AbstractFloatMatrix<U, S, V, M>>
38          extends AbstractIndexedValue<U, S, M, FloatMatrixData> implements FloatMatrixInterface<U, S, V, M>
39  {
40      /** */
41      private static final long serialVersionUID = 20161015L;
42  
43      /** The stored data as an object, can be sparse or dense. */
44      @SuppressWarnings("checkstyle:visibilitymodifier")
45      protected FloatMatrixData data;
46  
47      /**
48       * Construct a new FloatMatrix.
49       * @param data FloatMatrixData; an internal data object
50       * @param unit U; the unit
51       */
52      AbstractFloatMatrix(final FloatMatrixData data, final U unit)
53      {
54          super(unit);
55          Throw.whenNull(data, "data cannot be null");
56          this.data = data;
57      }
58  
59      /** {@inheritDoc} */
60      @Override
61      protected final FloatMatrixData getData()
62      {
63          return this.data;
64      }
65  
66      /** {@inheritDoc} */
67      @Override
68      protected void setData(final FloatMatrixData data)
69      {
70          this.data = data;
71      }
72  
73      /** {@inheritDoc} */
74      @Override
75      public float getSI(final int row, final int column) throws ValueRuntimeException
76      {
77          checkIndex(row, column);
78          return this.data.getSI(row, column);
79      }
80  
81      /** {@inheritDoc} */
82      @Override
83      public float getInUnit(final int row, final int column) throws ValueRuntimeException
84      {
85          checkIndex(row, column);
86          return (float) ValueUtil.expressAsUnit(this.data.getSI(row, column), getDisplayUnit());
87      }
88  
89      /** {@inheritDoc} */
90      @Override
91      public float getInUnit(final int row, final int column, final U targetUnit) throws ValueRuntimeException
92      {
93          checkIndex(row, column);
94          return (float) ValueUtil.expressAsUnit(this.data.getSI(row, column), targetUnit);
95      }
96  
97      /** {@inheritDoc} */
98      @Override
99      public void setSI(final int row, final int column, final float valueSI) throws ValueRuntimeException
100     {
101         checkIndex(row, column);
102         checkCopyOnWrite();
103         this.data.setSI(row, column, valueSI);
104     }
105 
106     /** {@inheritDoc} */
107     @Override
108     public void setInUnit(final int row, final int column, final float valueInUnit) throws ValueRuntimeException
109     {
110         setSI(row, column, (float) ValueUtil.expressAsSIUnit(valueInUnit, getDisplayUnit()));
111     }
112 
113     /** {@inheritDoc} */
114     @Override
115     public void setInUnit(final int row, final int column, final float valueInUnit, final U valueUnit)
116             throws ValueRuntimeException
117     {
118         setSI(row, column, (float) ValueUtil.expressAsSIUnit(valueInUnit, valueUnit));
119     }
120 
121     /** {@inheritDoc} */
122     @Override
123     public void set(final int row, final int column, final S value) throws ValueRuntimeException
124     {
125         setSI(row, column, value.si);
126     }
127 
128     /** {@inheritDoc} */
129     @Override
130     public float[] getRowSI(final int row) throws ValueRuntimeException
131     {
132         checkRowIndex(row);
133         float[] result = new float[this.data.cols()];
134         for (int col = 0; col < result.length; col++)
135         {
136             result[col] = this.data.getSI(row, col);
137         }
138         return result;
139     }
140 
141     /** {@inheritDoc} */
142     @Override
143     public float[] getColumnSI(final int column) throws ValueRuntimeException
144     {
145         checkColumnIndex(column);
146         float[] result = new float[this.data.rows()];
147         for (int row = 0; row < result.length; row++)
148         {
149             result[row] = this.data.getSI(row, column);
150         }
151         return result;
152     }
153 
154     /** {@inheritDoc} */
155     @Override
156     public float[] getDiagonalSI() throws ValueRuntimeException
157     {
158         checkSquare();
159         float[] result = new float[this.data.rows()];
160         for (int row = 0; row < result.length; row++)
161         {
162             result[row] = this.data.getSI(row, row);
163         }
164         return result;
165     }
166 
167     /** {@inheritDoc} */
168     @Override
169     public final float[][] getValuesSI()
170     {
171         return this.data.getDenseMatrixSI();
172     }
173 
174     /** {@inheritDoc} */
175     @Override
176     public final float[][] getValuesInUnit()
177     {
178         return getValuesInUnit(getDisplayUnit());
179     }
180 
181     /** {@inheritDoc} */
182     @Override
183     public final float[][] getValuesInUnit(final U targetUnit)
184     {
185         float[][] values = getValuesSI();
186         for (int i = values.length; --i >= 0;)
187         {
188             for (int j = values[i].length; --j >= 0;)
189             {
190                 values[i][j] = (float) ValueUtil.expressAsUnit(values[i][j], targetUnit);
191             }
192         }
193         return values;
194     }
195 
196     /** {@inheritDoc} */
197     @Override
198     public int rows()
199     {
200         return this.data.rows();
201     }
202 
203     /** {@inheritDoc} */
204     @Override
205     public int cols()
206     {
207         return this.data.cols();
208     }
209 
210     /** {@inheritDoc} */
211     @SuppressWarnings("unchecked")
212     @Override
213     public S[][] getScalars()
214     {
215         S[][] array = (S[][]) Array.newInstance(getScalarClass(), rows(), cols());
216         for (int i = 0; i < rows(); i++)
217         {
218             S[] row = (S[]) Array.newInstance(getScalarClass(), cols());
219             array[i] = row;
220             for (int j = 0; j < cols(); j++)
221             {
222                 row[j] = get(i, j);
223             }
224         }
225         return array;
226     }
227 
228     /** {@inheritDoc} */
229     @Override
230     public S get(final int row, final int column) throws ValueRuntimeException
231     {
232         checkIndex(row, column);
233         return FloatScalar.instantiateSI(getSI(row, column), getDisplayUnit());
234     }
235 
236     /** {@inheritDoc} */
237     @Override
238     public V getRow(final int row) throws ValueRuntimeException
239     {
240         checkRowIndex(row);
241         FloatVectorData dvd =
242                 FloatVectorData.instantiate(getRowSI(row), getDisplayUnit().getStandardUnit().getScale(), getStorageType());
243         return instantiateVector(dvd, getDisplayUnit());
244     }
245 
246     /** {@inheritDoc} */
247     @Override
248     public V getColumn(final int column) throws ValueRuntimeException
249     {
250         checkColumnIndex(column);
251         FloatVectorData dvd = FloatVectorData.instantiate(getColumnSI(column), getDisplayUnit().getStandardUnit().getScale(),
252                 getStorageType());
253         return instantiateVector(dvd, getDisplayUnit());
254     }
255 
256     /** {@inheritDoc} */
257     @Override
258     public V getDiagonal() throws ValueRuntimeException
259     {
260         checkSquare();
261         FloatVectorData dvd =
262                 FloatVectorData.instantiate(getDiagonalSI(), getDisplayUnit().getStandardUnit().getScale(), getStorageType());
263         return instantiateVector(dvd, getDisplayUnit());
264 
265     }
266 
267     /** {@inheritDoc} */
268     @SuppressWarnings("unchecked")
269     @Override
270     public S[] getRowScalars(final int row) throws ValueRuntimeException
271     {
272         checkRowIndex(row);
273         S[] array = (S[]) Array.newInstance(getScalarClass(), cols());
274         for (int col = 0; col < cols(); col++)
275         {
276             array[col] = get(row, col);
277         }
278         return array;
279     }
280 
281     /** {@inheritDoc} */
282     @SuppressWarnings("unchecked")
283     @Override
284     public S[] getColumnScalars(final int col) throws ValueRuntimeException
285     {
286         checkColumnIndex(col);
287         S[] array = (S[]) Array.newInstance(getScalarClass(), rows());
288         for (int row = 0; row < rows(); row++)
289         {
290             array[row] = get(row, col);
291         }
292         return array;
293     }
294 
295     /** {@inheritDoc} */
296     @SuppressWarnings("unchecked")
297     @Override
298     public S[] getDiagonalScalars() throws ValueRuntimeException
299     {
300         checkSquare();
301         S[] array = (S[]) Array.newInstance(getScalarClass(), rows());
302         for (int row = 0; row < rows(); row++)
303         {
304             array[row] = get(row, row);
305         }
306         return array;
307     }
308 
309     /** {@inheritDoc} */
310     @SuppressWarnings("unchecked")
311     @Override
312     public M toSparse()
313     {
314         M result;
315         if (getStorageType().equals(StorageType.SPARSE))
316         {
317             result = (M) this;
318             result.setDisplayUnit(getDisplayUnit());
319         }
320         else
321         {
322             result = instantiateMatrix(this.data.toSparse(), getDisplayUnit());
323         }
324         result.setDisplayUnit(getDisplayUnit());
325         return result;
326     }
327 
328     /** {@inheritDoc} */
329     @SuppressWarnings("unchecked")
330     @Override
331     public M toDense()
332     {
333         M result;
334         if (getStorageType().equals(StorageType.DENSE))
335         {
336             result = (M) this;
337             result.setDisplayUnit(getDisplayUnit());
338         }
339         else
340         {
341             result = instantiateMatrix(this.data.toDense(), getDisplayUnit());
342         }
343         return result;
344     }
345 
346     /** {@inheritDoc} */
347     @SuppressWarnings("unchecked")
348     @Override
349     public final M assign(final FloatFunction floatFunction)
350     {
351         checkCopyOnWrite();
352         this.data.assign(floatFunction);
353         return (M) this;
354     }
355 
356     /** {@inheritDoc} */
357     @Override
358     public final M abs()
359     {
360         return assign(FloatMathFunctions.ABS);
361     }
362 
363     /** {@inheritDoc} */
364     @Override
365     public final M ceil()
366     {
367         return assign(FloatMathFunctions.CEIL);
368     }
369 
370     /** {@inheritDoc} */
371     @Override
372     public final M floor()
373     {
374         return assign(FloatMathFunctions.FLOOR);
375     }
376 
377     /** {@inheritDoc} */
378     @Override
379     public final M neg()
380     {
381         return assign(FloatMathFunctions.NEG);
382     }
383 
384     /** {@inheritDoc} */
385     @Override
386     public final M rint()
387     {
388         return assign(FloatMathFunctions.RINT);
389     }
390 
391     /** {@inheritDoc} */
392     @Override
393     public String toString()
394     {
395         return toString(getDisplayUnit(), false, true);
396     }
397 
398     /** {@inheritDoc} */
399     @Override
400     public String toString(final U displayUnit)
401     {
402         return toString(displayUnit, false, true);
403     }
404 
405     /** {@inheritDoc} */
406     @Override
407     public String toString(final boolean verbose, final boolean withUnit)
408     {
409         return toString(getDisplayUnit(), verbose, withUnit);
410     }
411 
412     /** {@inheritDoc} */
413     @Override
414     public String toString(final U displayUnit, final boolean verbose, final boolean withUnit)
415     {
416         StringBuffer buf = new StringBuffer();
417         if (verbose)
418         {
419             String ab = this instanceof Absolute ? "Abs " : "Rel ";
420             String ds = this.data.isDense() ? "Dense  " : this.data.isSparse() ? "Sparse " : "?????? ";
421             if (isMutable())
422             {
423                 buf.append("Mutable   " + ab + ds);
424             }
425             else
426             {
427                 buf.append("Immutable " + ab + ds);
428             }
429         }
430         for (int row = 0; row < rows(); row++)
431         {
432             buf.append("\r\n\t");
433             for (int col = 0; col < cols(); col++)
434             {
435                 try
436                 {
437                     float d = (float) ValueUtil.expressAsUnit(getSI(row, col), displayUnit);
438                     buf.append(" " + Format.format(d));
439                 }
440                 catch (ValueRuntimeException ve)
441                 {
442                     buf.append(" " + "********************".substring(0, Format.DEFAULTSIZE));
443                 }
444             }
445         }
446         buf.append("\n");
447         if (withUnit)
448         {
449             buf.append(displayUnit.getDefaultDisplayAbbreviation());
450         }
451         return buf.toString();
452     }
453 
454     /**
455      * Check that provided row and column indices are valid.
456      * @param row int; the row value to check
457      * @param col int; the column value to check
458      * @throws ValueRuntimeException when row or column is invalid
459      */
460     protected final void checkIndex(final int row, final int col) throws ValueRuntimeException
461     {
462         if (row < 0 || row >= rows() || col < 0 || col >= cols())
463         {
464             throw new ValueRuntimeException("index out of range (valid range is 0.." + (rows() - 1) + ", 0.." + (cols() - 1)
465                     + ", got " + row + ", " + col + ")");
466         }
467     }
468 
469     /**
470      * Check that provided row index is valid.
471      * @param row int; the row value to check
472      * @throws ValueRuntimeException when row is invalid
473      */
474     protected final void checkRowIndex(final int row) throws ValueRuntimeException
475     {
476         if (row < 0 || row >= rows())
477         {
478             throw new ValueRuntimeException("row index out of range (valid range is 0.." + (rows() - 1) + ", got " + row + ")");
479         }
480     }
481 
482     /**
483      * Check that provided column index is valid.
484      * @param col int; the column value to check
485      * @throws ValueRuntimeException when row is invalid
486      */
487     protected final void checkColumnIndex(final int col) throws ValueRuntimeException
488     {
489         if (col < 0 || col >= cols())
490         {
491             throw new ValueRuntimeException(
492                     "column index out of range (valid range is 0.." + (cols() - 1) + ", got " + col + ")");
493         }
494     }
495 
496     /**
497      * Check that the matrix is square.
498      * @throws ValueRuntimeException when matrix is not square
499      */
500     protected final void checkSquare() throws ValueRuntimeException
501     {
502         Throw.when(rows() != cols(), ValueRuntimeException.class, "Matrix is not square, rows=%d, cols=%d", rows(), cols());
503     }
504 
505     /** {@inheritDoc} */
506     @Override
507     public final float determinant() throws ValueRuntimeException
508     {
509         try
510         {
511             final PrimitiveMatrix.Factory matrixFactory = PrimitiveMatrix.FACTORY;
512             final PrimitiveMatrix m = matrixFactory.rows(this.data.getDoubleDenseMatrixSI());
513             if (!m.isSquare())
514             {
515                 throw new IllegalArgumentException("Matrix is not square -- determinant cannot be calculated.");
516             }
517             return m.getDeterminant().floatValue();
518         }
519         catch (IllegalArgumentException exception)
520         {
521             throw new ValueRuntimeException(exception); // Matrix must be square
522         }
523     }
524 
525     /** {@inheritDoc} */
526     @Override
527     @SuppressWarnings("checkstyle:designforextension")
528     public int hashCode()
529     {
530         final int prime = 31;
531         int result = getDisplayUnit().getStandardUnit().hashCode();
532         result = prime * result + ((this.data == null) ? 0 : this.data.hashCode());
533         return result;
534     }
535 
536     /** {@inheritDoc} */
537     @Override
538     @SuppressWarnings({"checkstyle:designforextension", "checkstyle:needbraces"})
539     public boolean equals(final Object obj)
540     {
541         if (this == obj)
542             return true;
543         if (obj == null)
544             return false;
545         if (getClass() != obj.getClass())
546             return false;
547         AbstractFloatMatrix<?, ?, ?, ?> other = (AbstractFloatMatrix<?, ?, ?, ?>) obj;
548         if (!getDisplayUnit().getStandardUnit().equals(other.getDisplayUnit().getStandardUnit()))
549             return false;
550         if (this.data == null)
551         {
552             if (other.data != null)
553                 return false;
554         }
555         else if (!this.data.equals(other.data))
556             return false;
557         return true;
558     }
559 }