FloatMatrixDataDense.java

  1. package org.djunits.value.vfloat.matrix.data;

  2. import java.util.stream.IntStream;

  3. import org.djunits.value.ValueRuntimeException;
  4. import org.djunits.value.storage.StorageType;
  5. import org.djunits.value.vfloat.function.FloatFunction;
  6. import org.djunits.value.vfloat.function.FloatFunction2;
  7. import org.djutils.exceptions.Throw;

  8. /**
  9.  * Stores dense data for a FloatMatrix and carries out basic operations.
  10.  * <p>
  11.  * Copyright (c) 2013-2025 Delft University of Technology, PO Box 5, 2600 AA, Delft, the Netherlands. All rights reserved. <br>
  12.  * BSD-style license. See <a href="https://djunits.org/docs/license.html">DJUNITS License</a>.
  13.  * </p>
  14.  * @author <a href="https://www.tudelft.nl/averbraeck">Alexander Verbraeck</a>
  15.  * @author <a href="https://www.tudelft.nl/staff/p.knoppers/">Peter Knoppers</a>
  16.  */
  17. public class FloatMatrixDataDense extends FloatMatrixData
  18. {
  19.     /** */
  20.     private static final long serialVersionUID = 1L;

  21.     /**
  22.      * Create a matrix with dense data.
  23.      * @param matrixSI the data to store
  24.      * @param rows the number of rows
  25.      * @param cols the number of columns
  26.      * @throws ValueRuntimeException in case <code>rows * cols != matrixSI.length</code>
  27.      */
  28.     public FloatMatrixDataDense(final float[] matrixSI, final int rows, final int cols) throws ValueRuntimeException
  29.     {
  30.         super(StorageType.DENSE);
  31.         if (rows * cols != matrixSI.length)
  32.         {
  33.             throw new ValueRuntimeException("FloatMatrixDataDense constructor, rows * cols != matrixSI.length");
  34.         }
  35.         this.matrixSI = new float[matrixSI.length];
  36.         System.arraycopy(matrixSI, 0, this.matrixSI, 0, matrixSI.length);
  37.         this.rows = rows;
  38.         this.cols = cols;
  39.     }

  40.     /**
  41.      * Create a matrix with dense data. The float array is of the form d[rows][columns] so each value can be found with
  42.      * f[row][column].
  43.      * @param matrixSI the data to store
  44.      * @throws NullPointerException when matrixSI is null
  45.      * @throws ValueRuntimeException in case matrix is ragged
  46.      */
  47.     public FloatMatrixDataDense(final float[][] matrixSI) throws ValueRuntimeException
  48.     {
  49.         super(StorageType.DENSE);
  50.         Throw.whenNull(matrixSI, "DoubleMatrixDataDense constructor, matrixSI == null");
  51.         this.rows = matrixSI.length;
  52.         this.cols = this.rows == 0 ? 0 : matrixSI[0].length;
  53.         this.matrixSI = new float[this.rows * this.cols];
  54.         for (int r = 0; r < this.rows; r++)
  55.         {
  56.             float[] row = matrixSI[r];
  57.             if (row.length != this.cols)
  58.             {
  59.                 throw new ValueRuntimeException("FloatMatrixDataDense constructor, ragged matrix");
  60.             }
  61.             System.arraycopy(row, 0, this.matrixSI, r * this.cols, row.length);
  62.         }
  63.     }

  64.     @Override
  65.     public final int cardinality()
  66.     {
  67.         // this does not copy the data. See http://stackoverflow.com/questions/23106093/how-to-get-a-stream-from-a-float
  68.         return (int) IntStream.range(0, this.matrixSI.length).parallel().mapToDouble(i -> this.matrixSI[i])
  69.                 .filter(d -> d != 0.0).count();
  70.     }

  71.     @Override
  72.     public final FloatMatrixDataDense assign(final FloatFunction floatFunction)
  73.     {
  74.         IntStream.range(0, this.rows() * this.cols()).parallel()
  75.                 .forEach(i -> this.matrixSI[i] = floatFunction.apply(this.matrixSI[i]));
  76.         return this;
  77.     }

  78.     @Override
  79.     public final FloatMatrixDataDense assign(final FloatFunction2 floatFunction, final FloatMatrixData right)
  80.     {
  81.         if (right.isDense())
  82.         {
  83.             FloatMatrixDataDense rightDense = (FloatMatrixDataDense) right;
  84.             IntStream.range(0, this.rows() * this.cols()).parallel()
  85.                     .forEach(i -> this.matrixSI[i] = floatFunction.apply(this.matrixSI[i], rightDense.matrixSI[i]));
  86.         }
  87.         else
  88.         {
  89.             IntStream.range(0, this.rows() * this.cols()).parallel().forEach(
  90.                     i -> this.matrixSI[i] = floatFunction.apply(this.matrixSI[i], right.getSI(i / this.cols, i % this.cols)));
  91.         }
  92.         return this;
  93.     }

  94.     @Override
  95.     public final FloatMatrixDataDense toDense()
  96.     {
  97.         return this;
  98.     }

  99.     @Override
  100.     public final FloatMatrixDataSparse toSparse()
  101.     {
  102.         int length = cardinality();
  103.         float[] sparseSI = new float[length];
  104.         long[] indices = new long[length];
  105.         int count = 0;
  106.         for (int r = 0; r < this.rows; r++)
  107.         {
  108.             for (int c = 0; c < this.cols; c++)
  109.             {
  110.                 int index = r * this.cols + c;
  111.                 if (this.matrixSI[index] != 0.0)
  112.                 {
  113.                     sparseSI[count] = this.matrixSI[index];
  114.                     indices[count] = index;
  115.                     count++;
  116.                 }
  117.             }
  118.         }
  119.         return new FloatMatrixDataSparse(sparseSI, indices, this.rows, this.cols);
  120.     }

  121.     @Override
  122.     public final float getSI(final int row, final int col)
  123.     {
  124.         return this.matrixSI[row * this.cols + col];
  125.     }

  126.     @Override
  127.     public final void setSI(final int row, final int col, final float valueSI)
  128.     {
  129.         this.matrixSI[row * this.cols + col] = valueSI;
  130.     }

  131.     @Override
  132.     public final float[][] getDenseMatrixSI()
  133.     {
  134.         float[][] matrix = new float[this.rows][];
  135.         for (int r = 0; r < this.rows; r++)
  136.         {
  137.             float[] row = new float[this.cols];
  138.             System.arraycopy(this.matrixSI, r * this.cols, row, 0, row.length);
  139.             matrix[r] = row;
  140.         }
  141.         return matrix;
  142.     }

  143.     @Override
  144.     public final double[][] getDoubleDenseMatrixSI()
  145.     {
  146.         double[][] matrix = new double[this.rows][];
  147.         for (int r = 0; r < this.rows; r++)
  148.         {
  149.             double[] row = new double[this.cols];
  150.             int offset = r * this.cols;
  151.             for (int c = 0; c < this.cols; c++)
  152.             {
  153.                 row[c] = this.matrixSI[offset++];
  154.             }
  155.             matrix[r] = row;
  156.         }
  157.         return matrix;
  158.     }

  159.     @Override
  160.     public final FloatMatrixDataDense copy()
  161.     {
  162.         try
  163.         {
  164.             return new FloatMatrixDataDense(getDenseMatrixSI());
  165.         }
  166.         catch (ValueRuntimeException exception)
  167.         {
  168.             throw new RuntimeException(exception); // should not happen -- original is not ragged...
  169.         }
  170.     }

  171.     @Override
  172.     public FloatMatrixData plus(final FloatMatrixData right) throws ValueRuntimeException
  173.     {
  174.         checkSizes(right);
  175.         float[] fm = new float[this.rows * this.cols];
  176.         if (right.isDense())
  177.         {
  178.             IntStream.range(0, this.rows).parallel().forEach(r -> IntStream.range(0, this.cols).forEach(
  179.                     c -> fm[r * this.cols + c] = this.matrixSI[r * this.cols + c] + right.matrixSI[r * this.cols + c]));
  180.         }
  181.         else
  182.         { // right is sparse
  183.             IntStream.range(0, this.rows).parallel().forEach(r -> IntStream.range(0, this.cols)
  184.                     .forEach(c -> fm[r * this.cols + c] = this.matrixSI[r * this.cols + c] + right.getSI(r, c)));
  185.         }
  186.         return new FloatMatrixDataDense(fm, this.rows, this.cols);
  187.     }

  188.     @Override
  189.     public final FloatMatrixDataDense minus(final FloatMatrixData right)
  190.     {
  191.         checkSizes(right);
  192.         float[] fm = new float[this.rows * this.cols];
  193.         if (right.isDense())
  194.         {
  195.             IntStream.range(0, this.rows).parallel().forEach(r -> IntStream.range(0, this.cols).forEach(
  196.                     c -> fm[r * this.cols + c] = this.matrixSI[r * this.cols + c] - right.matrixSI[r * this.cols + c]));
  197.         }
  198.         else
  199.         { // right is sparse
  200.             IntStream.range(0, this.rows).parallel().forEach(r -> IntStream.range(0, this.cols)
  201.                     .forEach(c -> fm[r * this.cols + c] = this.matrixSI[r * this.cols + c] - right.getSI(r, c)));
  202.         }
  203.         return new FloatMatrixDataDense(fm, this.rows, this.cols);
  204.     }

  205.     @Override
  206.     public FloatMatrixData times(final FloatMatrixData right) throws ValueRuntimeException
  207.     {
  208.         if (right.isSparse())
  209.         {
  210.             // result shall be sparse
  211.             return right.times(this);
  212.         }
  213.         // Both are dense
  214.         checkSizes(right);
  215.         return this.copy().multiplyBy(right);
  216.     }

  217.     @Override
  218.     public FloatMatrixData divide(final FloatMatrixData right) throws ValueRuntimeException
  219.     {
  220.         checkSizes(right);
  221.         return this.copy().divideBy(right);
  222.     }

  223. }