Array2DRowRealMatrix.java

  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.  * This is not the original file distributed by the Apache Software Foundation
  19.  * It has been modified by the Hipparchus project
  20.  */

  21. package org.hipparchus.linear;

  22. import java.io.Serializable;
  23. import org.hipparchus.exception.LocalizedCoreFormats;
  24. import org.hipparchus.exception.MathIllegalArgumentException;
  25. import org.hipparchus.exception.MathIllegalStateException;
  26. import org.hipparchus.exception.NullArgumentException;
  27. import org.hipparchus.util.FastMath;
  28. import org.hipparchus.util.MathUtils;

  29. /**
  30.  * Implementation of {@link RealMatrix} using a {@code double[][]} array to
  31.  * store entries.
  32.  *
  33.  */
  34. public class Array2DRowRealMatrix extends AbstractRealMatrix implements Serializable {
  35.     /** Serializable version identifier. */
  36.     private static final long serialVersionUID = -1067294169172445528L;

  37.     /** Entries of the matrix. */
  38.     private double[][] data;

  39.     /**
  40.      * Creates a matrix with no data
  41.      */
  42.     public Array2DRowRealMatrix() {
  43.         // This constructor is intentionally empty. Nothing special is needed here.
  44.     }

  45.     /**
  46.      * Create a new RealMatrix with the supplied row and column dimensions.
  47.      *
  48.      * @param rowDimension Number of rows in the new matrix.
  49.      * @param columnDimension Number of columns in the new matrix.
  50.      * @throws MathIllegalArgumentException if the row or column dimension is
  51.      * not positive.
  52.      */
  53.     public Array2DRowRealMatrix(final int rowDimension,
  54.                                 final int columnDimension)
  55.         throws MathIllegalArgumentException {
  56.         super(rowDimension, columnDimension);
  57.         data = new double[rowDimension][columnDimension];
  58.     }

  59.     /**
  60.      * Create a new {@code RealMatrix} using the input array as the underlying
  61.      * data array.
  62.      * <p>The input array is copied, not referenced. This constructor has
  63.      * the same effect as calling {@link #Array2DRowRealMatrix(double[][], boolean)}
  64.      * with the second argument set to {@code true}.</p>
  65.      *
  66.      * @param d Data for the new matrix.
  67.      * @throws MathIllegalArgumentException if {@code d} is not rectangular.
  68.      * @throws MathIllegalArgumentException if {@code d} row or column dimension is zero.
  69.      * @throws NullArgumentException if {@code d} is {@code null}.
  70.      * @see #Array2DRowRealMatrix(double[][], boolean)
  71.      */
  72.     public Array2DRowRealMatrix(final double[][] d)
  73.         throws MathIllegalArgumentException, NullArgumentException {
  74.         copyIn(d);
  75.     }

  76.     /**
  77.      * Create a new RealMatrix using the input array as the underlying
  78.      * data array.
  79.      * If an array is built specially in order to be embedded in a
  80.      * RealMatrix and not used directly, the {@code copyArray} may be
  81.      * set to {@code false}. This will prevent the copying and improve
  82.      * performance as no new array will be built and no data will be copied.
  83.      *
  84.      * @param d Data for new matrix.
  85.      * @param copyArray if {@code true}, the input array will be copied,
  86.      * otherwise it will be referenced.
  87.      * @throws MathIllegalArgumentException if {@code d} is not rectangular.
  88.      * @throws MathIllegalArgumentException if {@code d} row or column dimension is zero.
  89.      * @throws NullArgumentException if {@code d} is {@code null}.
  90.      * @see #Array2DRowRealMatrix(double[][])
  91.      */
  92.     public Array2DRowRealMatrix(final double[][] d, final boolean copyArray)
  93.         throws MathIllegalArgumentException,
  94.         NullArgumentException {
  95.         if (copyArray) {
  96.             copyIn(d);
  97.         } else {
  98.             if (d == null) {
  99.                 throw new NullArgumentException();
  100.             }
  101.             final int nRows = d.length;
  102.             if (nRows == 0) {
  103.                 throw new MathIllegalArgumentException(LocalizedCoreFormats.AT_LEAST_ONE_ROW);
  104.             }
  105.             final int nCols = d[0].length;
  106.             if (nCols == 0) {
  107.                 throw new MathIllegalArgumentException(LocalizedCoreFormats.AT_LEAST_ONE_COLUMN);
  108.             }
  109.             for (int r = 1; r < nRows; r++) {
  110.                 if (d[r].length != nCols) {
  111.                     throw new MathIllegalArgumentException(LocalizedCoreFormats.DIMENSIONS_MISMATCH,
  112.                                                            d[r].length, nCols);
  113.                 }
  114.             }
  115.             data = d; // NOPMD - array copy is taken care of by parameter
  116.         }
  117.     }

  118.     /**
  119.      * Create a new (column) RealMatrix using {@code v} as the
  120.      * data for the unique column of the created matrix.
  121.      * The input array is copied.
  122.      *
  123.      * @param v Column vector holding data for new matrix.
  124.      */
  125.     public Array2DRowRealMatrix(final double[] v) {
  126.         final int nRows = v.length;
  127.         data = new double[nRows][1];
  128.         for (int row = 0; row < nRows; row++) {
  129.             data[row][0] = v[row];
  130.         }
  131.     }

  132.     /** {@inheritDoc} */
  133.     @Override
  134.     public RealMatrix createMatrix(final int rowDimension,
  135.                                    final int columnDimension)
  136.         throws MathIllegalArgumentException {
  137.         return new Array2DRowRealMatrix(rowDimension, columnDimension);
  138.     }

  139.     /** {@inheritDoc} */
  140.     @Override
  141.     public RealMatrix copy() {
  142.         return new Array2DRowRealMatrix(copyOut(), false);
  143.     }

  144.     /**
  145.      * Compute the sum of {@code this} and {@code m}.
  146.      *
  147.      * @param m Matrix to be added.
  148.      * @return {@code this + m}.
  149.      * @throws MathIllegalArgumentException if {@code m} is not the same
  150.      * size as {@code this}.
  151.      */
  152.     public Array2DRowRealMatrix add(final Array2DRowRealMatrix m)
  153.         throws MathIllegalArgumentException {
  154.         // Safety check.
  155.         MatrixUtils.checkAdditionCompatible(this, m);

  156.         final int rowCount    = getRowDimension();
  157.         final int columnCount = getColumnDimension();
  158.         final double[][] outData = new double[rowCount][columnCount];
  159.         for (int row = 0; row < rowCount; row++) {
  160.             final double[] dataRow    = data[row];
  161.             final double[] mRow       = m.data[row];
  162.             final double[] outDataRow = outData[row];
  163.             for (int col = 0; col < columnCount; col++) {
  164.                 outDataRow[col] = dataRow[col] + mRow[col];
  165.             }
  166.         }

  167.         return new Array2DRowRealMatrix(outData, false);
  168.     }

  169.     /**
  170.      * Returns {@code this} minus {@code m}.
  171.      *
  172.      * @param m Matrix to be subtracted.
  173.      * @return {@code this - m}
  174.      * @throws MathIllegalArgumentException if {@code m} is not the same
  175.      * size as {@code this}.
  176.      */
  177.     public Array2DRowRealMatrix subtract(final Array2DRowRealMatrix m)
  178.         throws MathIllegalArgumentException {
  179.         MatrixUtils.checkSubtractionCompatible(this, m);

  180.         final int rowCount    = getRowDimension();
  181.         final int columnCount = getColumnDimension();
  182.         final double[][] outData = new double[rowCount][columnCount];
  183.         for (int row = 0; row < rowCount; row++) {
  184.             final double[] dataRow    = data[row];
  185.             final double[] mRow       = m.data[row];
  186.             final double[] outDataRow = outData[row];
  187.             for (int col = 0; col < columnCount; col++) {
  188.                 outDataRow[col] = dataRow[col] - mRow[col];
  189.             }
  190.         }

  191.         return new Array2DRowRealMatrix(outData, false);
  192.     }

  193.     /**
  194.      * Returns the result of postmultiplying {@code this} by {@code m}.
  195.      *
  196.      * @param m matrix to postmultiply by
  197.      * @return {@code this * m}
  198.      * @throws MathIllegalArgumentException if
  199.      * {@code columnDimension(this) != rowDimension(m)}
  200.      */
  201.     public Array2DRowRealMatrix multiply(final Array2DRowRealMatrix m)
  202.         throws MathIllegalArgumentException {
  203.         MatrixUtils.checkMultiplicationCompatible(this, m);

  204.         final int nRows = this.getRowDimension();
  205.         final int nCols = m.getColumnDimension();
  206.         final int nSum = this.getColumnDimension();

  207.         final double[][] outData = new double[nRows][nCols];
  208.         // Will hold a column of "m".
  209.         final double[] mCol = new double[nSum];
  210.         final double[][] mData = m.data;

  211.         // Multiply.
  212.         for (int col = 0; col < nCols; col++) {
  213.             // Copy all elements of column "col" of "m" so that
  214.             // will be in contiguous memory.
  215.             for (int mRow = 0; mRow < nSum; mRow++) {
  216.                 mCol[mRow] = mData[mRow][col];
  217.             }

  218.             for (int row = 0; row < nRows; row++) {
  219.                 final double[] dataRow = data[row];
  220.                 double sum = 0;
  221.                 for (int i = 0; i < nSum; i++) {
  222.                     sum += dataRow[i] * mCol[i];
  223.                 }
  224.                 outData[row][col] = sum;
  225.             }
  226.         }

  227.         return new Array2DRowRealMatrix(outData, false);
  228.     }

  229.     /**
  230.      * Returns the result of postmultiplying {@code this} by {@code m^T}.
  231.      * @param m matrix to first transpose and second postmultiply by
  232.      * @return {@code this * m^T}
  233.      * @throws MathIllegalArgumentException if
  234.      * {@code columnDimension(this) != columnDimension(m)}
  235.      * @since 1.3
  236.      */
  237.     public RealMatrix multiplyTransposed(final Array2DRowRealMatrix m)
  238.         throws MathIllegalArgumentException {
  239.         MatrixUtils.checkSameColumnDimension(this, m);

  240.         final int nRows = this.getRowDimension();
  241.         final int nCols = m.getRowDimension();
  242.         final int nSum  = this.getColumnDimension();

  243.         final RealMatrix out = MatrixUtils.createRealMatrix(nRows, nCols);
  244.         final double[][] mData   = m.data;

  245.         // Multiply.
  246.         for (int col = 0; col < nCols; col++) {
  247.             for (int row = 0; row < nRows; row++) {
  248.                 final double[] dataRow = data[row];
  249.                 final double[] mRow    = mData[col];
  250.                 double sum = 0;
  251.                 for (int i = 0; i < nSum; i++) {
  252.                     sum += dataRow[i] * mRow[i];
  253.                 }
  254.                 out.setEntry(row, col, sum);
  255.             }
  256.         }

  257.         return out;

  258.     }

  259.     /** {@inheritDoc} */
  260.     @Override
  261.     public RealMatrix multiplyTransposed(final RealMatrix m) {
  262.         if (m instanceof Array2DRowRealMatrix) {
  263.             return multiplyTransposed((Array2DRowRealMatrix) m);
  264.         } else {
  265.             MatrixUtils.checkSameColumnDimension(this, m);

  266.             final int nRows = this.getRowDimension();
  267.             final int nCols = m.getRowDimension();
  268.             final int nSum  = this.getColumnDimension();

  269.             final RealMatrix out = MatrixUtils.createRealMatrix(nRows, nCols);

  270.             // Multiply.
  271.             for (int col = 0; col < nCols; col++) {
  272.                 for (int row = 0; row < nRows; row++) {
  273.                     final double[] dataRow = data[row];
  274.                     double sum = 0;
  275.                     for (int i = 0; i < nSum; i++) {
  276.                         sum += dataRow[i] * m.getEntry(col, i);
  277.                     }
  278.                     out.setEntry(row, col, sum);
  279.                 }
  280.             }

  281.             return out;

  282.         }
  283.     }

  284.     /**
  285.      * Returns the result of postmultiplying {@code this^T} by {@code m}.
  286.      * @param m matrix to postmultiply by
  287.      * @return {@code this^T * m}
  288.      * @throws MathIllegalArgumentException if
  289.      * {@code columnDimension(this) != columnDimension(m)}
  290.      * @since 1.3
  291.      */
  292.     public RealMatrix transposeMultiply(final Array2DRowRealMatrix m)
  293.         throws MathIllegalArgumentException {
  294.         MatrixUtils.checkSameRowDimension(this, m);

  295.         final int nRows = this.getColumnDimension();
  296.         final int nCols = m.getColumnDimension();
  297.         final int nSum  = this.getRowDimension();

  298.         final RealMatrix out = MatrixUtils.createRealMatrix(nRows, nCols);
  299.         final double[][] mData   = m.data;

  300.         // Multiply.
  301.         for (int k = 0; k < nSum; k++) {
  302.             final double[] dataK = data[k];
  303.             final double[] mK    = mData[k];
  304.             for (int row = 0; row < nRows; row++) {
  305.                 final double dataIRow = dataK[row];
  306.                 for (int col = 0; col < nCols; col++) {
  307.                     out.addToEntry(row, col, dataIRow * mK[col]);
  308.                 }
  309.             }
  310.         }

  311.         return out;

  312.     }

  313.     /** {@inheritDoc} */
  314.     @Override
  315.     public RealMatrix transposeMultiply(final RealMatrix m) {
  316.         if (m instanceof Array2DRowRealMatrix) {
  317.             return transposeMultiply((Array2DRowRealMatrix) m);
  318.         } else {
  319.             MatrixUtils.checkSameRowDimension(this, m);

  320.             final int nRows = this.getColumnDimension();
  321.             final int nCols = m.getColumnDimension();
  322.             final int nSum  = this.getRowDimension();

  323.             final RealMatrix out = MatrixUtils.createRealMatrix(nRows, nCols);

  324.             // Multiply.
  325.             for (int k = 0; k < nSum; k++) {
  326.                 final double[] dataK = data[k];
  327.                 for (int row = 0; row < nRows; row++) {
  328.                     final double dataIRow = dataK[row];
  329.                     for (int col = 0; col < nCols; col++) {
  330.                         out.addToEntry(row, col, dataIRow * m.getEntry(k, col));
  331.                     }
  332.                 }
  333.             }

  334.             return out;

  335.         }
  336.     }

  337.     /** {@inheritDoc} */
  338.     @Override
  339.     public double[][] getData() {
  340.         return copyOut();
  341.     }

  342.     /**
  343.      * Get a reference to the underlying data array.
  344.      *
  345.      * @return 2-dimensional array of entries.
  346.      */
  347.     public double[][] getDataRef() {
  348.         return data; // NOPMD - returning an internal array is intentional and documented here
  349.     }

  350.     /** {@inheritDoc} */
  351.     @Override
  352.     public void setSubMatrix(final double[][] subMatrix, final int row,
  353.                              final int column)
  354.         throws MathIllegalArgumentException, NullArgumentException {
  355.         if (data == null) {
  356.             if (row > 0) {
  357.                 throw new MathIllegalStateException(LocalizedCoreFormats.FIRST_ROWS_NOT_INITIALIZED_YET, row);
  358.             }
  359.             if (column > 0) {
  360.                 throw new MathIllegalStateException(LocalizedCoreFormats.FIRST_COLUMNS_NOT_INITIALIZED_YET, column);
  361.             }
  362.             MathUtils.checkNotNull(subMatrix);
  363.             final int nRows = subMatrix.length;
  364.             if (nRows == 0) {
  365.                 throw new MathIllegalArgumentException(LocalizedCoreFormats.AT_LEAST_ONE_ROW);
  366.             }

  367.             final int nCols = subMatrix[0].length;
  368.             if (nCols == 0) {
  369.                 throw new MathIllegalArgumentException(LocalizedCoreFormats.AT_LEAST_ONE_COLUMN);
  370.             }
  371.             data = new double[subMatrix.length][nCols];
  372.             for (int i = 0; i < data.length; ++i) {
  373.                 if (subMatrix[i].length != nCols) {
  374.                     throw new MathIllegalArgumentException(LocalizedCoreFormats.DIMENSIONS_MISMATCH,
  375.                                                            subMatrix[i].length, nCols);
  376.                 }
  377.                 System.arraycopy(subMatrix[i], 0, data[i + row], column, nCols);
  378.             }
  379.         } else {
  380.             super.setSubMatrix(subMatrix, row, column);
  381.         }

  382.     }

  383.     /** {@inheritDoc} */
  384.     @Override
  385.     public double getEntry(final int row, final int column)
  386.         throws MathIllegalArgumentException {
  387.       try {
  388.         return data[row][column];
  389.       } catch (IndexOutOfBoundsException e) {
  390.         // throw the exact cause of the exception
  391.         MatrixUtils.checkMatrixIndex(this, row, column);
  392.         // should never happen
  393.         throw e;
  394.       }
  395.     }

  396.     /** {@inheritDoc} */
  397.     @Override
  398.     public void setEntry(final int row, final int column, final double value)
  399.         throws MathIllegalArgumentException {
  400.         MatrixUtils.checkMatrixIndex(this, row, column);
  401.         data[row][column] = value;
  402.     }

  403.     /** {@inheritDoc} */
  404.     @Override
  405.     public void addToEntry(final int row, final int column,
  406.                            final double increment)
  407.         throws MathIllegalArgumentException {
  408.         MatrixUtils.checkMatrixIndex(this, row, column);
  409.         data[row][column] += increment;
  410.     }

  411.     /** {@inheritDoc} */
  412.     @Override
  413.     public void multiplyEntry(final int row, final int column,
  414.                               final double factor)
  415.         throws MathIllegalArgumentException {
  416.         MatrixUtils.checkMatrixIndex(this, row, column);
  417.         data[row][column] *= factor;
  418.     }

  419.     /** {@inheritDoc} */
  420.     @Override
  421.     public int getRowDimension() {
  422.         return (data == null) ? 0 : data.length;
  423.     }

  424.     /** {@inheritDoc} */
  425.     @Override
  426.     public int getColumnDimension() {
  427.         return ((data == null) || (data[0] == null)) ? 0 : data[0].length;
  428.     }

  429.     /** {@inheritDoc} */
  430.     @Override
  431.     public double[] operate(final double[] v)
  432.         throws MathIllegalArgumentException {
  433.         final int nRows = this.getRowDimension();
  434.         final int nCols = this.getColumnDimension();
  435.         if (v.length != nCols) {
  436.             throw new MathIllegalArgumentException(LocalizedCoreFormats.DIMENSIONS_MISMATCH,
  437.                                                    v.length, nCols);
  438.         }
  439.         final double[] out = new double[nRows];
  440.         for (int row = 0; row < nRows; row++) {
  441.             final double[] dataRow = data[row];
  442.             double sum = 0;
  443.             for (int i = 0; i < nCols; i++) {
  444.                 sum += dataRow[i] * v[i];
  445.             }
  446.             out[row] = sum;
  447.         }
  448.         return out;
  449.     }

  450.     /** {@inheritDoc} */
  451.     @Override
  452.     public double[] preMultiply(final double[] v)
  453.         throws MathIllegalArgumentException {
  454.         final int nRows = getRowDimension();
  455.         final int nCols = getColumnDimension();
  456.         if (v.length != nRows) {
  457.             throw new MathIllegalArgumentException(LocalizedCoreFormats.DIMENSIONS_MISMATCH,
  458.                                                    v.length, nRows);
  459.         }

  460.         final double[] out = new double[nCols];
  461.         for (int col = 0; col < nCols; ++col) {
  462.             double sum = 0;
  463.             for (int i = 0; i < nRows; ++i) {
  464.                 sum += data[i][col] * v[i];
  465.             }
  466.             out[col] = sum;
  467.         }

  468.         return out;

  469.     }

  470.     /** {@inheritDoc} */
  471.     @Override
  472.     public RealMatrix getSubMatrix(final int startRow, final int endRow,
  473.                                    final int startColumn, final int endColumn)
  474.         throws MathIllegalArgumentException {
  475.         MatrixUtils.checkSubMatrixIndex(this, startRow, endRow, startColumn, endColumn);
  476.         final int rowCount = endRow - startRow + 1;
  477.         final int columnCount = endColumn - startColumn + 1;
  478.         final double[][] outData = new double[rowCount][columnCount];
  479.         for (int i = 0; i < rowCount; ++i) {
  480.             System.arraycopy(data[startRow + i], startColumn, outData[i], 0, columnCount);
  481.         }

  482.         Array2DRowRealMatrix subMatrix = new Array2DRowRealMatrix();
  483.         subMatrix.data = outData;
  484.         return subMatrix;
  485.     }

  486.     /** {@inheritDoc} */
  487.     @Override
  488.     public double walkInRowOrder(final RealMatrixChangingVisitor visitor) {
  489.         final int rows    = getRowDimension();
  490.         final int columns = getColumnDimension();
  491.         visitor.start(rows, columns, 0, rows - 1, 0, columns - 1);
  492.         for (int i = 0; i < rows; ++i) {
  493.             final double[] rowI = data[i];
  494.             for (int j = 0; j < columns; ++j) {
  495.                 rowI[j] = visitor.visit(i, j, rowI[j]);
  496.             }
  497.         }
  498.         return visitor.end();
  499.     }

  500.     /** {@inheritDoc} */
  501.     @Override
  502.     public double walkInRowOrder(final RealMatrixPreservingVisitor visitor) {
  503.         final int rows    = getRowDimension();
  504.         final int columns = getColumnDimension();
  505.         visitor.start(rows, columns, 0, rows - 1, 0, columns - 1);
  506.         for (int i = 0; i < rows; ++i) {
  507.             final double[] rowI = data[i];
  508.             for (int j = 0; j < columns; ++j) {
  509.                 visitor.visit(i, j, rowI[j]);
  510.             }
  511.         }
  512.         return visitor.end();
  513.     }

  514.     /** {@inheritDoc} */
  515.     @Override
  516.     public double walkInRowOrder(final RealMatrixChangingVisitor visitor,
  517.                                  final int startRow, final int endRow,
  518.                                  final int startColumn, final int endColumn)
  519.         throws MathIllegalArgumentException {
  520.         MatrixUtils.checkSubMatrixIndex(this, startRow, endRow, startColumn, endColumn);
  521.         visitor.start(getRowDimension(), getColumnDimension(),
  522.                       startRow, endRow, startColumn, endColumn);
  523.         for (int i = startRow; i <= endRow; ++i) {
  524.             final double[] rowI = data[i];
  525.             for (int j = startColumn; j <= endColumn; ++j) {
  526.                 rowI[j] = visitor.visit(i, j, rowI[j]);
  527.             }
  528.         }
  529.         return visitor.end();
  530.     }

  531.     /** {@inheritDoc} */
  532.     @Override
  533.     public double walkInRowOrder(final RealMatrixPreservingVisitor visitor,
  534.                                  final int startRow, final int endRow,
  535.                                  final int startColumn, final int endColumn)
  536.         throws MathIllegalArgumentException {
  537.         MatrixUtils.checkSubMatrixIndex(this, startRow, endRow, startColumn, endColumn);
  538.         visitor.start(getRowDimension(), getColumnDimension(),
  539.                       startRow, endRow, startColumn, endColumn);
  540.         for (int i = startRow; i <= endRow; ++i) {
  541.             final double[] rowI = data[i];
  542.             for (int j = startColumn; j <= endColumn; ++j) {
  543.                 visitor.visit(i, j, rowI[j]);
  544.             }
  545.         }
  546.         return visitor.end();
  547.     }

  548.     /** {@inheritDoc} */
  549.     @Override
  550.     public double walkInColumnOrder(final RealMatrixChangingVisitor visitor) {
  551.         final int rows    = getRowDimension();
  552.         final int columns = getColumnDimension();
  553.         visitor.start(rows, columns, 0, rows - 1, 0, columns - 1);
  554.         for (int j = 0; j < columns; ++j) {
  555.             for (int i = 0; i < rows; ++i) {
  556.                 final double[] rowI = data[i];
  557.                 rowI[j] = visitor.visit(i, j, rowI[j]);
  558.             }
  559.         }
  560.         return visitor.end();
  561.     }

  562.     /** {@inheritDoc} */
  563.     @Override
  564.     public double walkInColumnOrder(final RealMatrixPreservingVisitor visitor) {
  565.         final int rows    = getRowDimension();
  566.         final int columns = getColumnDimension();
  567.         visitor.start(rows, columns, 0, rows - 1, 0, columns - 1);
  568.         for (int j = 0; j < columns; ++j) {
  569.             for (int i = 0; i < rows; ++i) {
  570.                 visitor.visit(i, j, data[i][j]);
  571.             }
  572.         }
  573.         return visitor.end();
  574.     }

  575.     /** {@inheritDoc} */
  576.     @Override
  577.     public double walkInColumnOrder(final RealMatrixChangingVisitor visitor,
  578.                                     final int startRow, final int endRow,
  579.                                     final int startColumn, final int endColumn)
  580.         throws MathIllegalArgumentException {
  581.         MatrixUtils.checkSubMatrixIndex(this, startRow, endRow, startColumn, endColumn);
  582.         visitor.start(getRowDimension(), getColumnDimension(),
  583.                       startRow, endRow, startColumn, endColumn);
  584.         for (int j = startColumn; j <= endColumn; ++j) {
  585.             for (int i = startRow; i <= endRow; ++i) {
  586.                 final double[] rowI = data[i];
  587.                 rowI[j] = visitor.visit(i, j, rowI[j]);
  588.             }
  589.         }
  590.         return visitor.end();
  591.     }

  592.     /** {@inheritDoc} */
  593.     @Override
  594.     public double walkInColumnOrder(final RealMatrixPreservingVisitor visitor,
  595.                                     final int startRow, final int endRow,
  596.                                     final int startColumn, final int endColumn)
  597.         throws MathIllegalArgumentException {
  598.         MatrixUtils.checkSubMatrixIndex(this, startRow, endRow, startColumn, endColumn);
  599.         visitor.start(getRowDimension(), getColumnDimension(),
  600.                       startRow, endRow, startColumn, endColumn);
  601.         for (int j = startColumn; j <= endColumn; ++j) {
  602.             for (int i = startRow; i <= endRow; ++i) {
  603.                 visitor.visit(i, j, data[i][j]);
  604.             }
  605.         }
  606.         return visitor.end();
  607.     }

  608.     /**
  609.      * Get a fresh copy of the underlying data array.
  610.      *
  611.      * @return a copy of the underlying data array.
  612.      */
  613.     private double[][] copyOut() {
  614.         final int nRows = this.getRowDimension();
  615.         final double[][] out = new double[nRows][this.getColumnDimension()];
  616.         // can't copy 2-d array in one shot, otherwise get row references
  617.         for (int i = 0; i < nRows; i++) {
  618.             System.arraycopy(data[i], 0, out[i], 0, data[i].length);
  619.         }
  620.         return out;
  621.     }

  622.     /**
  623.      * Replace data with a fresh copy of the input array.
  624.      *
  625.      * @param in Data to copy.
  626.      * @throws MathIllegalArgumentException if the input array is empty.
  627.      * @throws MathIllegalArgumentException if the input array is not rectangular.
  628.      * @throws NullArgumentException if the input array is {@code null}.
  629.      */
  630.     private void copyIn(final double[][] in)
  631.         throws MathIllegalArgumentException, NullArgumentException {
  632.         setSubMatrix(in, 0, 0);
  633.     }

  634.     /** {@inheritDoc} */
  635.     @Override
  636.     public double[] getRow(final int row) throws MathIllegalArgumentException {
  637.         MatrixUtils.checkRowIndex(this, row);
  638.         final int nCols = getColumnDimension();
  639.         final double[] out = new double[nCols];
  640.         System.arraycopy(data[row], 0, out, 0, nCols);
  641.         return out;
  642.     }

  643.     /** {@inheritDoc} */
  644.     @Override
  645.     public void setRow(final int row, final double[] array)
  646.         throws MathIllegalArgumentException {
  647.         MatrixUtils.checkRowIndex(this, row);
  648.         final int nCols = getColumnDimension();
  649.         if (array.length != nCols) {
  650.             throw new MathIllegalArgumentException(LocalizedCoreFormats.DIMENSIONS_MISMATCH_2x2,
  651.                                                    1, array.length, 1, nCols);
  652.         }
  653.         System.arraycopy(array, 0, data[row], 0, nCols);
  654.     }

  655.     /**
  656.      * Kronecker product of the current matrix and the parameter matrix.
  657.      *
  658.      * @param b matrix to post Kronecker-multiply by
  659.      * @return this ⨂ b
  660.      */
  661.     public RealMatrix kroneckerProduct(final RealMatrix b) {
  662.         final int m = getRowDimension();
  663.         final int n = getColumnDimension();

  664.         final int p = b.getRowDimension();
  665.         final int q = b.getColumnDimension();

  666.         final RealMatrix kroneckerProduct = MatrixUtils.createRealMatrix(m * p, n * q);

  667.         for (int i = 0; i < m; i++) {
  668.             for (int j = 0; j < n; j++) {
  669.                 kroneckerProduct.setSubMatrix(b.scalarMultiply(getEntry(i, j)) .getData(), i * p, j * q);
  670.             }
  671.         }

  672.         return kroneckerProduct;
  673.     }

  674.     /**
  675.      * Transforms a matrix in a vector (Vectorization).
  676.      * @return a one column matrix
  677.      */
  678.     public RealMatrix stack() {
  679.         final int m = getRowDimension();
  680.         final int n = getColumnDimension();

  681.         final RealMatrix stacked = MatrixUtils.createRealMatrix(m * n, 1);

  682.         for (int i = 0; i < m; i++) {
  683.             stacked.setSubMatrix(getColumnMatrix(i).getData(), i * n, 0);
  684.         }

  685.         return stacked;
  686.     }

  687.     /**
  688.      * Transforms a one-column stacked matrix into a squared matrix (devectorization).
  689.      * @return square matrix
  690.      */
  691.     public RealMatrix unstackSquare() {
  692.         final int m = getRowDimension();
  693.         final int n = getColumnDimension();
  694.         final int s = (int) FastMath.round(FastMath.sqrt(m));

  695.         if (n != 1) {
  696.             throw new MathIllegalArgumentException(LocalizedCoreFormats.DIMENSIONS_MISMATCH, n, 1);
  697.         }
  698.         if (s * s != m) {
  699.             throw new MathIllegalArgumentException(LocalizedCoreFormats.NON_SQUARE_MATRIX, s, ((double) m) / s);
  700.         }

  701.         final RealMatrix unstacked = MatrixUtils.createRealMatrix(s, s);

  702.         for (int i = 0; i < s; i++) {
  703.             unstacked.setColumnMatrix(i, getSubMatrix(i * s, i * s + s - 1, 0, 0));
  704.         }

  705.         return unstacked;
  706.     }

  707. }