View Javadoc
1   /*
2    * Licensed to the Apache Software Foundation (ASF) under one or more
3    * contributor license agreements.  See the NOTICE file distributed with
4    * this work for additional information regarding copyright ownership.
5    * The ASF licenses this file to You under the Apache License, Version 2.0
6    * (the "License"); you may not use this file except in compliance with
7    * the License.  You may obtain a copy of the License at
8    *
9    *      https://www.apache.org/licenses/LICENSE-2.0
10   *
11   * Unless required by applicable law or agreed to in writing, software
12   * distributed under the License is distributed on an "AS IS" BASIS,
13   * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
14   * See the License for the specific language governing permissions and
15   * limitations under the License.
16   */
17  
18  /*
19   * This is not the original file distributed by the Apache Software Foundation
20   * It has been modified by the Hipparchus project
21   */
22  
23  package org.hipparchus.linear;
24  
25  import java.io.Serializable;
26  import org.hipparchus.exception.LocalizedCoreFormats;
27  import org.hipparchus.exception.MathIllegalArgumentException;
28  import org.hipparchus.exception.MathIllegalStateException;
29  import org.hipparchus.exception.NullArgumentException;
30  import org.hipparchus.util.FastMath;
31  import org.hipparchus.util.MathUtils;
32  
33  /**
34   * Implementation of {@link RealMatrix} using a {@code double[][]} array to
35   * store entries.
36   *
37   */
38  public class Array2DRowRealMatrix extends AbstractRealMatrix implements Serializable {
39      /** Serializable version identifier. */
40      private static final long serialVersionUID = -1067294169172445528L;
41  
42      /** Entries of the matrix. */
43      private double[][] data;
44  
45      /**
46       * Creates a matrix with no data
47       */
48      public Array2DRowRealMatrix() {
49          // This constructor is intentionally empty. Nothing special is needed here.
50      }
51  
52      /**
53       * Create a new RealMatrix with the supplied row and column dimensions.
54       *
55       * @param rowDimension Number of rows in the new matrix.
56       * @param columnDimension Number of columns in the new matrix.
57       * @throws MathIllegalArgumentException if the row or column dimension is
58       * not positive.
59       */
60      public Array2DRowRealMatrix(final int rowDimension,
61                                  final int columnDimension)
62          throws MathIllegalArgumentException {
63          super(rowDimension, columnDimension);
64          data = new double[rowDimension][columnDimension];
65      }
66  
67      /**
68       * Create a new {@code RealMatrix} using the input array as the underlying
69       * data array.
70       * <p>The input array is copied, not referenced. This constructor has
71       * the same effect as calling {@link #Array2DRowRealMatrix(double[][], boolean)}
72       * with the second argument set to {@code true}.</p>
73       *
74       * @param d Data for the new matrix.
75       * @throws MathIllegalArgumentException if {@code d} is not rectangular.
76       * @throws MathIllegalArgumentException if {@code d} row or column dimension is zero.
77       * @throws NullArgumentException if {@code d} is {@code null}.
78       * @see #Array2DRowRealMatrix(double[][], boolean)
79       */
80      public Array2DRowRealMatrix(final double[][] d)
81          throws MathIllegalArgumentException, NullArgumentException {
82          copyIn(d);
83      }
84  
85      /**
86       * Create a new RealMatrix using the input array as the underlying
87       * data array.
88       * If an array is built specially in order to be embedded in a
89       * RealMatrix and not used directly, the {@code copyArray} may be
90       * set to {@code false}. This will prevent the copying and improve
91       * performance as no new array will be built and no data will be copied.
92       *
93       * @param d Data for new matrix.
94       * @param copyArray if {@code true}, the input array will be copied,
95       * otherwise it will be referenced.
96       * @throws MathIllegalArgumentException if {@code d} is not rectangular.
97       * @throws MathIllegalArgumentException if {@code d} row or column dimension is zero.
98       * @throws NullArgumentException if {@code d} is {@code null}.
99       * @see #Array2DRowRealMatrix(double[][])
100      */
101     public Array2DRowRealMatrix(final double[][] d, final boolean copyArray)
102         throws MathIllegalArgumentException,
103         NullArgumentException {
104         if (copyArray) {
105             copyIn(d);
106         } else {
107             if (d == null) {
108                 throw new NullArgumentException();
109             }
110             final int nRows = d.length;
111             if (nRows == 0) {
112                 throw new MathIllegalArgumentException(LocalizedCoreFormats.AT_LEAST_ONE_ROW);
113             }
114             final int nCols = d[0].length;
115             if (nCols == 0) {
116                 throw new MathIllegalArgumentException(LocalizedCoreFormats.AT_LEAST_ONE_COLUMN);
117             }
118             for (int r = 1; r < nRows; r++) {
119                 if (d[r].length != nCols) {
120                     throw new MathIllegalArgumentException(LocalizedCoreFormats.DIMENSIONS_MISMATCH,
121                                                            d[r].length, nCols);
122                 }
123             }
124             data = d; // NOPMD - array copy is taken care of by parameter
125         }
126     }
127 
128     /**
129      * Create a new (column) RealMatrix using {@code v} as the
130      * data for the unique column of the created matrix.
131      * The input array is copied.
132      *
133      * @param v Column vector holding data for new matrix.
134      */
135     public Array2DRowRealMatrix(final double[] v) {
136         final int nRows = v.length;
137         data = new double[nRows][1];
138         for (int row = 0; row < nRows; row++) {
139             data[row][0] = v[row];
140         }
141     }
142 
143     /** {@inheritDoc} */
144     @Override
145     public RealMatrix createMatrix(final int rowDimension,
146                                    final int columnDimension)
147         throws MathIllegalArgumentException {
148         return new Array2DRowRealMatrix(rowDimension, columnDimension);
149     }
150 
151     /** {@inheritDoc} */
152     @Override
153     public RealMatrix copy() {
154         return new Array2DRowRealMatrix(copyOut(), false);
155     }
156 
157     /**
158      * Compute the sum of {@code this} and {@code m}.
159      *
160      * @param m Matrix to be added.
161      * @return {@code this + m}.
162      * @throws MathIllegalArgumentException if {@code m} is not the same
163      * size as {@code this}.
164      */
165     public Array2DRowRealMatrix add(final Array2DRowRealMatrix m)
166         throws MathIllegalArgumentException {
167         // Safety check.
168         MatrixUtils.checkAdditionCompatible(this, m);
169 
170         final int rowCount    = getRowDimension();
171         final int columnCount = getColumnDimension();
172         final double[][] outData = new double[rowCount][columnCount];
173         for (int row = 0; row < rowCount; row++) {
174             final double[] dataRow    = data[row];
175             final double[] mRow       = m.data[row];
176             final double[] outDataRow = outData[row];
177             for (int col = 0; col < columnCount; col++) {
178                 outDataRow[col] = dataRow[col] + mRow[col];
179             }
180         }
181 
182         return new Array2DRowRealMatrix(outData, false);
183     }
184 
185     /**
186      * Returns {@code this} minus {@code m}.
187      *
188      * @param m Matrix to be subtracted.
189      * @return {@code this - m}
190      * @throws MathIllegalArgumentException if {@code m} is not the same
191      * size as {@code this}.
192      */
193     public Array2DRowRealMatrix subtract(final Array2DRowRealMatrix m)
194         throws MathIllegalArgumentException {
195         MatrixUtils.checkSubtractionCompatible(this, m);
196 
197         final int rowCount    = getRowDimension();
198         final int columnCount = getColumnDimension();
199         final double[][] outData = new double[rowCount][columnCount];
200         for (int row = 0; row < rowCount; row++) {
201             final double[] dataRow    = data[row];
202             final double[] mRow       = m.data[row];
203             final double[] outDataRow = outData[row];
204             for (int col = 0; col < columnCount; col++) {
205                 outDataRow[col] = dataRow[col] - mRow[col];
206             }
207         }
208 
209         return new Array2DRowRealMatrix(outData, false);
210     }
211 
212     /**
213      * Returns the result of postmultiplying {@code this} by {@code m}.
214      *
215      * @param m matrix to postmultiply by
216      * @return {@code this * m}
217      * @throws MathIllegalArgumentException if
218      * {@code columnDimension(this) != rowDimension(m)}
219      */
220     public Array2DRowRealMatrix multiply(final Array2DRowRealMatrix m)
221         throws MathIllegalArgumentException {
222         MatrixUtils.checkMultiplicationCompatible(this, m);
223 
224         final int nRows = this.getRowDimension();
225         final int nCols = m.getColumnDimension();
226         final int nSum = this.getColumnDimension();
227 
228         final double[][] outData = new double[nRows][nCols];
229         // Will hold a column of "m".
230         final double[] mCol = new double[nSum];
231         final double[][] mData = m.data;
232 
233         // Multiply.
234         for (int col = 0; col < nCols; col++) {
235             // Copy all elements of column "col" of "m" so that
236             // will be in contiguous memory.
237             for (int mRow = 0; mRow < nSum; mRow++) {
238                 mCol[mRow] = mData[mRow][col];
239             }
240 
241             for (int row = 0; row < nRows; row++) {
242                 final double[] dataRow = data[row];
243                 double sum = 0;
244                 for (int i = 0; i < nSum; i++) {
245                     sum += dataRow[i] * mCol[i];
246                 }
247                 outData[row][col] = sum;
248             }
249         }
250 
251         return new Array2DRowRealMatrix(outData, false);
252     }
253 
254     /**
255      * Returns the result of postmultiplying {@code this} by {@code m^T}.
256      * @param m matrix to first transpose and second postmultiply by
257      * @return {@code this * m^T}
258      * @throws MathIllegalArgumentException if
259      * {@code columnDimension(this) != columnDimension(m)}
260      * @since 1.3
261      */
262     public RealMatrix multiplyTransposed(final Array2DRowRealMatrix m)
263         throws MathIllegalArgumentException {
264         MatrixUtils.checkSameColumnDimension(this, m);
265 
266         final int nRows = this.getRowDimension();
267         final int nCols = m.getRowDimension();
268         final int nSum  = this.getColumnDimension();
269 
270         final RealMatrix out = MatrixUtils.createRealMatrix(nRows, nCols);
271         final double[][] mData   = m.data;
272 
273         // Multiply.
274         for (int col = 0; col < nCols; col++) {
275             for (int row = 0; row < nRows; row++) {
276                 final double[] dataRow = data[row];
277                 final double[] mRow    = mData[col];
278                 double sum = 0;
279                 for (int i = 0; i < nSum; i++) {
280                     sum += dataRow[i] * mRow[i];
281                 }
282                 out.setEntry(row, col, sum);
283             }
284         }
285 
286         return out;
287 
288     }
289 
290     /** {@inheritDoc} */
291     @Override
292     public RealMatrix multiplyTransposed(final RealMatrix m) {
293         if (m instanceof Array2DRowRealMatrix) {
294             return multiplyTransposed((Array2DRowRealMatrix) m);
295         } else {
296             MatrixUtils.checkSameColumnDimension(this, m);
297 
298             final int nRows = this.getRowDimension();
299             final int nCols = m.getRowDimension();
300             final int nSum  = this.getColumnDimension();
301 
302             final RealMatrix out = MatrixUtils.createRealMatrix(nRows, nCols);
303 
304             // Multiply.
305             for (int col = 0; col < nCols; col++) {
306                 for (int row = 0; row < nRows; row++) {
307                     final double[] dataRow = data[row];
308                     double sum = 0;
309                     for (int i = 0; i < nSum; i++) {
310                         sum += dataRow[i] * m.getEntry(col, i);
311                     }
312                     out.setEntry(row, col, sum);
313                 }
314             }
315 
316             return out;
317 
318         }
319     }
320 
321     /**
322      * Returns the result of postmultiplying {@code this^T} by {@code m}.
323      * @param m matrix to postmultiply by
324      * @return {@code this^T * m}
325      * @throws MathIllegalArgumentException if
326      * {@code columnDimension(this) != columnDimension(m)}
327      * @since 1.3
328      */
329     public RealMatrix transposeMultiply(final Array2DRowRealMatrix m)
330         throws MathIllegalArgumentException {
331         MatrixUtils.checkSameRowDimension(this, m);
332 
333         final int nRows = this.getColumnDimension();
334         final int nCols = m.getColumnDimension();
335         final int nSum  = this.getRowDimension();
336 
337         final RealMatrix out = MatrixUtils.createRealMatrix(nRows, nCols);
338         final double[][] mData   = m.data;
339 
340         // Multiply.
341         for (int k = 0; k < nSum; k++) {
342             final double[] dataK = data[k];
343             final double[] mK    = mData[k];
344             for (int row = 0; row < nRows; row++) {
345                 final double dataIRow = dataK[row];
346                 for (int col = 0; col < nCols; col++) {
347                     out.addToEntry(row, col, dataIRow * mK[col]);
348                 }
349             }
350         }
351 
352         return out;
353 
354     }
355 
356     /** {@inheritDoc} */
357     @Override
358     public RealMatrix transposeMultiply(final RealMatrix m) {
359         if (m instanceof Array2DRowRealMatrix) {
360             return transposeMultiply((Array2DRowRealMatrix) m);
361         } else {
362             MatrixUtils.checkSameRowDimension(this, m);
363 
364             final int nRows = this.getColumnDimension();
365             final int nCols = m.getColumnDimension();
366             final int nSum  = this.getRowDimension();
367 
368             final RealMatrix out = MatrixUtils.createRealMatrix(nRows, nCols);
369 
370             // Multiply.
371             for (int k = 0; k < nSum; k++) {
372                 final double[] dataK = data[k];
373                 for (int row = 0; row < nRows; row++) {
374                     final double dataIRow = dataK[row];
375                     for (int col = 0; col < nCols; col++) {
376                         out.addToEntry(row, col, dataIRow * m.getEntry(k, col));
377                     }
378                 }
379             }
380 
381             return out;
382 
383         }
384     }
385 
386     /** {@inheritDoc} */
387     @Override
388     public double[][] getData() {
389         return copyOut();
390     }
391 
392     /**
393      * Get a reference to the underlying data array.
394      *
395      * @return 2-dimensional array of entries.
396      */
397     public double[][] getDataRef() {
398         return data; // NOPMD - returning an internal array is intentional and documented here
399     }
400 
401     /** {@inheritDoc} */
402     @Override
403     public void setSubMatrix(final double[][] subMatrix, final int row,
404                              final int column)
405         throws MathIllegalArgumentException, NullArgumentException {
406         if (data == null) {
407             if (row > 0) {
408                 throw new MathIllegalStateException(LocalizedCoreFormats.FIRST_ROWS_NOT_INITIALIZED_YET, row);
409             }
410             if (column > 0) {
411                 throw new MathIllegalStateException(LocalizedCoreFormats.FIRST_COLUMNS_NOT_INITIALIZED_YET, column);
412             }
413             MathUtils.checkNotNull(subMatrix);
414             final int nRows = subMatrix.length;
415             if (nRows == 0) {
416                 throw new MathIllegalArgumentException(LocalizedCoreFormats.AT_LEAST_ONE_ROW);
417             }
418 
419             final int nCols = subMatrix[0].length;
420             if (nCols == 0) {
421                 throw new MathIllegalArgumentException(LocalizedCoreFormats.AT_LEAST_ONE_COLUMN);
422             }
423             data = new double[subMatrix.length][nCols];
424             for (int i = 0; i < data.length; ++i) {
425                 if (subMatrix[i].length != nCols) {
426                     throw new MathIllegalArgumentException(LocalizedCoreFormats.DIMENSIONS_MISMATCH,
427                                                            subMatrix[i].length, nCols);
428                 }
429                 System.arraycopy(subMatrix[i], 0, data[i + row], column, nCols);
430             }
431         } else {
432             super.setSubMatrix(subMatrix, row, column);
433         }
434 
435     }
436 
437     /** {@inheritDoc} */
438     @Override
439     public double getEntry(final int row, final int column)
440         throws MathIllegalArgumentException {
441       try {
442         return data[row][column];
443       } catch (IndexOutOfBoundsException e) {
444         // throw the exact cause of the exception
445         MatrixUtils.checkMatrixIndex(this, row, column);
446         // should never happen
447         throw e;
448       }
449     }
450 
451     /** {@inheritDoc} */
452     @Override
453     public void setEntry(final int row, final int column, final double value)
454         throws MathIllegalArgumentException {
455         MatrixUtils.checkMatrixIndex(this, row, column);
456         data[row][column] = value;
457     }
458 
459     /** {@inheritDoc} */
460     @Override
461     public void addToEntry(final int row, final int column,
462                            final double increment)
463         throws MathIllegalArgumentException {
464         MatrixUtils.checkMatrixIndex(this, row, column);
465         data[row][column] += increment;
466     }
467 
468     /** {@inheritDoc} */
469     @Override
470     public void multiplyEntry(final int row, final int column,
471                               final double factor)
472         throws MathIllegalArgumentException {
473         MatrixUtils.checkMatrixIndex(this, row, column);
474         data[row][column] *= factor;
475     }
476 
477     /** {@inheritDoc} */
478     @Override
479     public int getRowDimension() {
480         return (data == null) ? 0 : data.length;
481     }
482 
483     /** {@inheritDoc} */
484     @Override
485     public int getColumnDimension() {
486         return ((data == null) || (data[0] == null)) ? 0 : data[0].length;
487     }
488 
489     /** {@inheritDoc} */
490     @Override
491     public double[] operate(final double[] v)
492         throws MathIllegalArgumentException {
493         final int nRows = this.getRowDimension();
494         final int nCols = this.getColumnDimension();
495         if (v.length != nCols) {
496             throw new MathIllegalArgumentException(LocalizedCoreFormats.DIMENSIONS_MISMATCH,
497                                                    v.length, nCols);
498         }
499         final double[] out = new double[nRows];
500         for (int row = 0; row < nRows; row++) {
501             final double[] dataRow = data[row];
502             double sum = 0;
503             for (int i = 0; i < nCols; i++) {
504                 sum += dataRow[i] * v[i];
505             }
506             out[row] = sum;
507         }
508         return out;
509     }
510 
511     /** {@inheritDoc} */
512     @Override
513     public double[] preMultiply(final double[] v)
514         throws MathIllegalArgumentException {
515         final int nRows = getRowDimension();
516         final int nCols = getColumnDimension();
517         if (v.length != nRows) {
518             throw new MathIllegalArgumentException(LocalizedCoreFormats.DIMENSIONS_MISMATCH,
519                                                    v.length, nRows);
520         }
521 
522         final double[] out = new double[nCols];
523         for (int col = 0; col < nCols; ++col) {
524             double sum = 0;
525             for (int i = 0; i < nRows; ++i) {
526                 sum += data[i][col] * v[i];
527             }
528             out[col] = sum;
529         }
530 
531         return out;
532 
533     }
534 
535     /** {@inheritDoc} */
536     @Override
537     public RealMatrix getSubMatrix(final int startRow, final int endRow,
538                                    final int startColumn, final int endColumn)
539         throws MathIllegalArgumentException {
540         MatrixUtils.checkSubMatrixIndex(this, startRow, endRow, startColumn, endColumn);
541         final int rowCount = endRow - startRow + 1;
542         final int columnCount = endColumn - startColumn + 1;
543         final double[][] outData = new double[rowCount][columnCount];
544         for (int i = 0; i < rowCount; ++i) {
545             System.arraycopy(data[startRow + i], startColumn, outData[i], 0, columnCount);
546         }
547 
548         Array2DRowRealMatrix subMatrix = new Array2DRowRealMatrix();
549         subMatrix.data = outData;
550         return subMatrix;
551     }
552 
553     /** {@inheritDoc} */
554     @Override
555     public double walkInRowOrder(final RealMatrixChangingVisitor visitor) {
556         final int rows    = getRowDimension();
557         final int columns = getColumnDimension();
558         visitor.start(rows, columns, 0, rows - 1, 0, columns - 1);
559         for (int i = 0; i < rows; ++i) {
560             final double[] rowI = data[i];
561             for (int j = 0; j < columns; ++j) {
562                 rowI[j] = visitor.visit(i, j, rowI[j]);
563             }
564         }
565         return visitor.end();
566     }
567 
568     /** {@inheritDoc} */
569     @Override
570     public double walkInRowOrder(final RealMatrixPreservingVisitor visitor) {
571         final int rows    = getRowDimension();
572         final int columns = getColumnDimension();
573         visitor.start(rows, columns, 0, rows - 1, 0, columns - 1);
574         for (int i = 0; i < rows; ++i) {
575             final double[] rowI = data[i];
576             for (int j = 0; j < columns; ++j) {
577                 visitor.visit(i, j, rowI[j]);
578             }
579         }
580         return visitor.end();
581     }
582 
583     /** {@inheritDoc} */
584     @Override
585     public double walkInRowOrder(final RealMatrixChangingVisitor visitor,
586                                  final int startRow, final int endRow,
587                                  final int startColumn, final int endColumn)
588         throws MathIllegalArgumentException {
589         MatrixUtils.checkSubMatrixIndex(this, startRow, endRow, startColumn, endColumn);
590         visitor.start(getRowDimension(), getColumnDimension(),
591                       startRow, endRow, startColumn, endColumn);
592         for (int i = startRow; i <= endRow; ++i) {
593             final double[] rowI = data[i];
594             for (int j = startColumn; j <= endColumn; ++j) {
595                 rowI[j] = visitor.visit(i, j, rowI[j]);
596             }
597         }
598         return visitor.end();
599     }
600 
601     /** {@inheritDoc} */
602     @Override
603     public double walkInRowOrder(final RealMatrixPreservingVisitor visitor,
604                                  final int startRow, final int endRow,
605                                  final int startColumn, final int endColumn)
606         throws MathIllegalArgumentException {
607         MatrixUtils.checkSubMatrixIndex(this, startRow, endRow, startColumn, endColumn);
608         visitor.start(getRowDimension(), getColumnDimension(),
609                       startRow, endRow, startColumn, endColumn);
610         for (int i = startRow; i <= endRow; ++i) {
611             final double[] rowI = data[i];
612             for (int j = startColumn; j <= endColumn; ++j) {
613                 visitor.visit(i, j, rowI[j]);
614             }
615         }
616         return visitor.end();
617     }
618 
619     /** {@inheritDoc} */
620     @Override
621     public double walkInColumnOrder(final RealMatrixChangingVisitor visitor) {
622         final int rows    = getRowDimension();
623         final int columns = getColumnDimension();
624         visitor.start(rows, columns, 0, rows - 1, 0, columns - 1);
625         for (int j = 0; j < columns; ++j) {
626             for (int i = 0; i < rows; ++i) {
627                 final double[] rowI = data[i];
628                 rowI[j] = visitor.visit(i, j, rowI[j]);
629             }
630         }
631         return visitor.end();
632     }
633 
634     /** {@inheritDoc} */
635     @Override
636     public double walkInColumnOrder(final RealMatrixPreservingVisitor visitor) {
637         final int rows    = getRowDimension();
638         final int columns = getColumnDimension();
639         visitor.start(rows, columns, 0, rows - 1, 0, columns - 1);
640         for (int j = 0; j < columns; ++j) {
641             for (int i = 0; i < rows; ++i) {
642                 visitor.visit(i, j, data[i][j]);
643             }
644         }
645         return visitor.end();
646     }
647 
648     /** {@inheritDoc} */
649     @Override
650     public double walkInColumnOrder(final RealMatrixChangingVisitor visitor,
651                                     final int startRow, final int endRow,
652                                     final int startColumn, final int endColumn)
653         throws MathIllegalArgumentException {
654         MatrixUtils.checkSubMatrixIndex(this, startRow, endRow, startColumn, endColumn);
655         visitor.start(getRowDimension(), getColumnDimension(),
656                       startRow, endRow, startColumn, endColumn);
657         for (int j = startColumn; j <= endColumn; ++j) {
658             for (int i = startRow; i <= endRow; ++i) {
659                 final double[] rowI = data[i];
660                 rowI[j] = visitor.visit(i, j, rowI[j]);
661             }
662         }
663         return visitor.end();
664     }
665 
666     /** {@inheritDoc} */
667     @Override
668     public double walkInColumnOrder(final RealMatrixPreservingVisitor visitor,
669                                     final int startRow, final int endRow,
670                                     final int startColumn, final int endColumn)
671         throws MathIllegalArgumentException {
672         MatrixUtils.checkSubMatrixIndex(this, startRow, endRow, startColumn, endColumn);
673         visitor.start(getRowDimension(), getColumnDimension(),
674                       startRow, endRow, startColumn, endColumn);
675         for (int j = startColumn; j <= endColumn; ++j) {
676             for (int i = startRow; i <= endRow; ++i) {
677                 visitor.visit(i, j, data[i][j]);
678             }
679         }
680         return visitor.end();
681     }
682 
683     /**
684      * Get a fresh copy of the underlying data array.
685      *
686      * @return a copy of the underlying data array.
687      */
688     private double[][] copyOut() {
689         final int nRows = this.getRowDimension();
690         final double[][] out = new double[nRows][this.getColumnDimension()];
691         // can't copy 2-d array in one shot, otherwise get row references
692         for (int i = 0; i < nRows; i++) {
693             System.arraycopy(data[i], 0, out[i], 0, data[i].length);
694         }
695         return out;
696     }
697 
698     /**
699      * Replace data with a fresh copy of the input array.
700      *
701      * @param in Data to copy.
702      * @throws MathIllegalArgumentException if the input array is empty.
703      * @throws MathIllegalArgumentException if the input array is not rectangular.
704      * @throws NullArgumentException if the input array is {@code null}.
705      */
706     private void copyIn(final double[][] in)
707         throws MathIllegalArgumentException, NullArgumentException {
708         setSubMatrix(in, 0, 0);
709     }
710 
711     /** {@inheritDoc} */
712     @Override
713     public double[] getRow(final int row) throws MathIllegalArgumentException {
714         MatrixUtils.checkRowIndex(this, row);
715         final int nCols = getColumnDimension();
716         final double[] out = new double[nCols];
717         System.arraycopy(data[row], 0, out, 0, nCols);
718         return out;
719     }
720 
721     /** {@inheritDoc} */
722     @Override
723     public void setRow(final int row, final double[] array)
724         throws MathIllegalArgumentException {
725         MatrixUtils.checkRowIndex(this, row);
726         final int nCols = getColumnDimension();
727         if (array.length != nCols) {
728             throw new MathIllegalArgumentException(LocalizedCoreFormats.DIMENSIONS_MISMATCH_2x2,
729                                                    1, array.length, 1, nCols);
730         }
731         System.arraycopy(array, 0, data[row], 0, nCols);
732     }
733 
734     /**
735      * Kronecker product of the current matrix and the parameter matrix.
736      *
737      * @param b matrix to post Kronecker-multiply by
738      * @return this ⨂ b
739      */
740     public RealMatrix kroneckerProduct(final RealMatrix b) {
741         final int m = getRowDimension();
742         final int n = getColumnDimension();
743 
744         final int p = b.getRowDimension();
745         final int q = b.getColumnDimension();
746 
747         final RealMatrix kroneckerProduct = MatrixUtils.createRealMatrix(m * p, n * q);
748 
749         for (int i = 0; i < m; i++) {
750             for (int j = 0; j < n; j++) {
751                 kroneckerProduct.setSubMatrix(b.scalarMultiply(getEntry(i, j)) .getData(), i * p, j * q);
752             }
753         }
754 
755         return kroneckerProduct;
756     }
757 
758     /**
759      * Transforms a matrix in a vector (Vectorization).
760      * @return a one column matrix
761      */
762     public RealMatrix stack() {
763         final int m = getRowDimension();
764         final int n = getColumnDimension();
765 
766         final RealMatrix stacked = MatrixUtils.createRealMatrix(m * n, 1);
767 
768         for (int i = 0; i < m; i++) {
769             stacked.setSubMatrix(getColumnMatrix(i).getData(), i * n, 0);
770         }
771 
772         return stacked;
773     }
774 
775     /**
776      * Transforms a one-column stacked matrix into a squared matrix (devectorization).
777      * @return square matrix
778      */
779     public RealMatrix unstackSquare() {
780         final int m = getRowDimension();
781         final int n = getColumnDimension();
782         final int s = (int) FastMath.round(FastMath.sqrt(m));
783 
784         if (n != 1) {
785             throw new MathIllegalArgumentException(LocalizedCoreFormats.DIMENSIONS_MISMATCH, n, 1);
786         }
787         if (s * s != m) {
788             throw new MathIllegalArgumentException(LocalizedCoreFormats.NON_SQUARE_MATRIX, s, ((double) m) / s);
789         }
790 
791         final RealMatrix unstacked = MatrixUtils.createRealMatrix(s, s);
792 
793         for (int i = 0; i < s; i++) {
794             unstacked.setColumnMatrix(i, getSubMatrix(i * s, i * s + s - 1, 0, 0));
795         }
796 
797         return unstacked;
798     }
799 
800 }