View Javadoc
1   package org.djunits.value.vfloat.matrix.data;
2   
3   import java.util.stream.IntStream;
4   
5   import org.djunits.value.ValueRuntimeException;
6   import org.djunits.value.storage.StorageType;
7   import org.djunits.value.vfloat.function.FloatFunction;
8   import org.djunits.value.vfloat.function.FloatFunction2;
9   import org.djutils.exceptions.Throw;
10  
11  /**
12   * Stores dense data for a FloatMatrix and carries out basic operations.
13   * <p>
14   * Copyright (c) 2013-2024 Delft University of Technology, PO Box 5, 2600 AA, Delft, the Netherlands. All rights reserved. <br>
15   * BSD-style license. See <a href="https://djunits.org/docs/license.html">DJUNITS License</a>.
16   * </p>
17   * @author <a href="https://www.tudelft.nl/averbraeck">Alexander Verbraeck</a>
18   * @author <a href="https://www.tudelft.nl/staff/p.knoppers/">Peter Knoppers</a>
19   */
20  public class FloatMatrixDataDense extends FloatMatrixData
21  {
22      /** */
23      private static final long serialVersionUID = 1L;
24  
25      /**
26       * Create a matrix with dense data.
27       * @param matrixSI float[]; the data to store
28       * @param rows int; the number of rows
29       * @param cols int; the number of columns
30       * @throws ValueRuntimeException in case <code>rows * cols != matrixSI.length</code>
31       */
32      public FloatMatrixDataDense(final float[] matrixSI, final int rows, final int cols) throws ValueRuntimeException
33      {
34          super(StorageType.DENSE);
35          if (rows * cols != matrixSI.length)
36          {
37              throw new ValueRuntimeException("FloatMatrixDataDense constructor, rows * cols != matrixSI.length");
38          }
39          this.matrixSI = new float[matrixSI.length];
40          System.arraycopy(matrixSI, 0, this.matrixSI, 0, matrixSI.length);
41          this.rows = rows;
42          this.cols = cols;
43      }
44  
45      /**
46       * Create a matrix with dense data. The float array is of the form d[rows][columns] so each value can be found with
47       * f[row][column].
48       * @param matrixSI float[][]; the data to store
49       * @throws NullPointerException when matrixSI is null
50       * @throws ValueRuntimeException in case matrix is ragged
51       */
52      public FloatMatrixDataDense(final float[][] matrixSI) throws ValueRuntimeException
53      {
54          super(StorageType.DENSE);
55          Throw.whenNull(matrixSI, "DoubleMatrixDataDense constructor, matrixSI == null");
56          this.rows = matrixSI.length;
57          this.cols = this.rows == 0 ? 0 : matrixSI[0].length;
58          this.matrixSI = new float[this.rows * this.cols];
59          for (int r = 0; r < this.rows; r++)
60          {
61              float[] row = matrixSI[r];
62              if (row.length != this.cols)
63              {
64                  throw new ValueRuntimeException("FloatMatrixDataDense constructor, ragged matrix");
65              }
66              System.arraycopy(row, 0, this.matrixSI, r * this.cols, row.length);
67          }
68      }
69  
70      @Override
71      public final int cardinality()
72      {
73          // this does not copy the data. See http://stackoverflow.com/questions/23106093/how-to-get-a-stream-from-a-float
74          return (int) IntStream.range(0, this.matrixSI.length).parallel().mapToDouble(i -> this.matrixSI[i])
75                  .filter(d -> d != 0.0).count();
76      }
77  
78      @Override
79      public final FloatMatrixDataDense assign(final FloatFunction floatFunction)
80      {
81          IntStream.range(0, this.rows() * this.cols()).parallel()
82                  .forEach(i -> this.matrixSI[i] = floatFunction.apply(this.matrixSI[i]));
83          return this;
84      }
85  
86      @Override
87      public final FloatMatrixDataDense assign(final FloatFunction2 floatFunction, final FloatMatrixData right)
88      {
89          if (right.isDense())
90          {
91              FloatMatrixDataDense rightDense = (FloatMatrixDataDense) right;
92              IntStream.range(0, this.rows() * this.cols()).parallel()
93                      .forEach(i -> this.matrixSI[i] = floatFunction.apply(this.matrixSI[i], rightDense.matrixSI[i]));
94          }
95          else
96          {
97              IntStream.range(0, this.rows() * this.cols()).parallel().forEach(
98                      i -> this.matrixSI[i] = floatFunction.apply(this.matrixSI[i], right.getSI(i / this.cols, i % this.cols)));
99          }
100         return this;
101     }
102 
103     @Override
104     public final FloatMatrixDataDense toDense()
105     {
106         return this;
107     }
108 
109     @Override
110     public final FloatMatrixDataSparse toSparse()
111     {
112         int length = cardinality();
113         float[] sparseSI = new float[length];
114         long[] indices = new long[length];
115         int count = 0;
116         for (int r = 0; r < this.rows; r++)
117         {
118             for (int c = 0; c < this.cols; c++)
119             {
120                 int index = r * this.cols + c;
121                 if (this.matrixSI[index] != 0.0)
122                 {
123                     sparseSI[count] = this.matrixSI[index];
124                     indices[count] = index;
125                     count++;
126                 }
127             }
128         }
129         return new FloatMatrixDataSparse(sparseSI, indices, this.rows, this.cols);
130     }
131 
132     @Override
133     public final float getSI(final int row, final int col)
134     {
135         return this.matrixSI[row * this.cols + col];
136     }
137 
138     @Override
139     public final void setSI(final int row, final int col, final float valueSI)
140     {
141         this.matrixSI[row * this.cols + col] = valueSI;
142     }
143 
144     @Override
145     public final float[][] getDenseMatrixSI()
146     {
147         float[][] matrix = new float[this.rows][];
148         for (int r = 0; r < this.rows; r++)
149         {
150             float[] row = new float[this.cols];
151             System.arraycopy(this.matrixSI, r * this.cols, row, 0, row.length);
152             matrix[r] = row;
153         }
154         return matrix;
155     }
156 
157     @Override
158     public final double[][] getDoubleDenseMatrixSI()
159     {
160         double[][] matrix = new double[this.rows][];
161         for (int r = 0; r < this.rows; r++)
162         {
163             double[] row = new double[this.cols];
164             int offset = r * this.cols;
165             for (int c = 0; c < this.cols; c++)
166             {
167                 row[c] = this.matrixSI[offset++];
168             }
169             matrix[r] = row;
170         }
171         return matrix;
172     }
173 
174     @Override
175     public final FloatMatrixDataDense copy()
176     {
177         try
178         {
179             return new FloatMatrixDataDense(getDenseMatrixSI());
180         }
181         catch (ValueRuntimeException exception)
182         {
183             throw new RuntimeException(exception); // should not happen -- original is not ragged...
184         }
185     }
186 
187     @Override
188     public FloatMatrixData plus(final FloatMatrixData right) throws ValueRuntimeException
189     {
190         checkSizes(right);
191         float[] fm = new float[this.rows * this.cols];
192         if (right.isDense())
193         {
194             IntStream.range(0, this.rows).parallel().forEach(r -> IntStream.range(0, this.cols).forEach(
195                     c -> fm[r * this.cols + c] = this.matrixSI[r * this.cols + c] + right.matrixSI[r * this.cols + c]));
196         }
197         else
198         { // right is sparse
199             IntStream.range(0, this.rows).parallel().forEach(r -> IntStream.range(0, this.cols)
200                     .forEach(c -> fm[r * this.cols + c] = this.matrixSI[r * this.cols + c] + right.getSI(r, c)));
201         }
202         return new FloatMatrixDataDense(fm, this.rows, this.cols);
203     }
204 
205     @Override
206     public final FloatMatrixDataDense minus(final FloatMatrixData right)
207     {
208         checkSizes(right);
209         float[] fm = new float[this.rows * this.cols];
210         if (right.isDense())
211         {
212             IntStream.range(0, this.rows).parallel().forEach(r -> IntStream.range(0, this.cols).forEach(
213                     c -> fm[r * this.cols + c] = this.matrixSI[r * this.cols + c] - right.matrixSI[r * this.cols + c]));
214         }
215         else
216         { // right is sparse
217             IntStream.range(0, this.rows).parallel().forEach(r -> IntStream.range(0, this.cols)
218                     .forEach(c -> fm[r * this.cols + c] = this.matrixSI[r * this.cols + c] - right.getSI(r, c)));
219         }
220         return new FloatMatrixDataDense(fm, this.rows, this.cols);
221     }
222 
223     @Override
224     public FloatMatrixData times(final FloatMatrixData right) throws ValueRuntimeException
225     {
226         if (right.isSparse())
227         {
228             // result shall be sparse
229             return right.times(this);
230         }
231         // Both are dense
232         checkSizes(right);
233         return this.copy().multiplyBy(right);
234     }
235 
236     @Override
237     public FloatMatrixData divide(final FloatMatrixData right) throws ValueRuntimeException
238     {
239         checkSizes(right);
240         return this.copy().divideBy(right);
241     }
242 
243 }