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