AbstractRealMatrix.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.  *      http://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. package org.apache.commons.math4.legacy.linear;

  18. import java.util.ArrayList;
  19. import java.util.Locale;

  20. import org.apache.commons.math4.legacy.exception.DimensionMismatchException;
  21. import org.apache.commons.math4.legacy.exception.NoDataException;
  22. import org.apache.commons.math4.legacy.exception.NotPositiveException;
  23. import org.apache.commons.math4.legacy.exception.NotStrictlyPositiveException;
  24. import org.apache.commons.math4.legacy.exception.NullArgumentException;
  25. import org.apache.commons.math4.legacy.exception.NumberIsTooSmallException;
  26. import org.apache.commons.math4.legacy.exception.OutOfRangeException;
  27. import org.apache.commons.math4.legacy.exception.util.LocalizedFormats;
  28. import org.apache.commons.math4.core.jdkmath.JdkMath;

  29. /**
  30.  * Basic implementation of RealMatrix methods regardless of the underlying storage.
  31.  * <p>All the methods implemented here use {@link #getEntry(int, int)} to access
  32.  * matrix elements. Derived class can provide faster implementations.</p>
  33.  *
  34.  * @since 2.0
  35.  */
  36. public abstract class AbstractRealMatrix
  37.     extends RealLinearOperator
  38.     implements RealMatrix {

  39.     /** Default format. */
  40.     private static final RealMatrixFormat DEFAULT_FORMAT = RealMatrixFormat.getInstance(Locale.US);
  41.     static {
  42.         // set the minimum fraction digits to 1 to keep compatibility
  43.         DEFAULT_FORMAT.getFormat().setMinimumFractionDigits(1);
  44.     }

  45.     /**
  46.      * Creates a matrix with no data.
  47.      */
  48.     protected AbstractRealMatrix() {}

  49.     /**
  50.      * Create a new RealMatrix with the supplied row and column dimensions.
  51.      *
  52.      * @param rowDimension  the number of rows in the new matrix
  53.      * @param columnDimension  the number of columns in the new matrix
  54.      * @throws NotStrictlyPositiveException if row or column dimension is not positive
  55.      */
  56.     protected AbstractRealMatrix(final int rowDimension,
  57.         final int columnDimension)
  58.         throws NotStrictlyPositiveException {
  59.         if (rowDimension < 1) {
  60.             throw new NotStrictlyPositiveException(rowDimension);
  61.         }
  62.         if (columnDimension < 1) {
  63.             throw new NotStrictlyPositiveException(columnDimension);
  64.         }
  65.     }

  66.     /** {@inheritDoc} */
  67.     @Override
  68.     public RealMatrix add(RealMatrix m)
  69.         throws MatrixDimensionMismatchException {
  70.         checkAdd(m);

  71.         final int rowCount    = getRowDimension();
  72.         final int columnCount = getColumnDimension();
  73.         final RealMatrix out = createMatrix(rowCount, columnCount);
  74.         for (int row = 0; row < rowCount; ++row) {
  75.             for (int col = 0; col < columnCount; ++col) {
  76.                 out.setEntry(row, col, getEntry(row, col) + m.getEntry(row, col));
  77.             }
  78.         }

  79.         return out;
  80.     }

  81.     /** {@inheritDoc} */
  82.     @Override
  83.     public RealMatrix subtract(final RealMatrix m)
  84.         throws MatrixDimensionMismatchException {
  85.         checkAdd(m);

  86.         final int rowCount    = getRowDimension();
  87.         final int columnCount = getColumnDimension();
  88.         final RealMatrix out = createMatrix(rowCount, columnCount);
  89.         for (int row = 0; row < rowCount; ++row) {
  90.             for (int col = 0; col < columnCount; ++col) {
  91.                 out.setEntry(row, col, getEntry(row, col) - m.getEntry(row, col));
  92.             }
  93.         }

  94.         return out;
  95.     }

  96.     /** {@inheritDoc} */
  97.     @Override
  98.     public RealMatrix scalarAdd(final double d) {
  99.         final int rowCount    = getRowDimension();
  100.         final int columnCount = getColumnDimension();
  101.         final RealMatrix out = createMatrix(rowCount, columnCount);
  102.         for (int row = 0; row < rowCount; ++row) {
  103.             for (int col = 0; col < columnCount; ++col) {
  104.                 out.setEntry(row, col, getEntry(row, col) + d);
  105.             }
  106.         }

  107.         return out;
  108.     }

  109.     /** {@inheritDoc} */
  110.     @Override
  111.     public RealMatrix scalarMultiply(final double d) {
  112.         final int rowCount    = getRowDimension();
  113.         final int columnCount = getColumnDimension();
  114.         final RealMatrix out = createMatrix(rowCount, columnCount);
  115.         for (int row = 0; row < rowCount; ++row) {
  116.             for (int col = 0; col < columnCount; ++col) {
  117.                 out.setEntry(row, col, getEntry(row, col) * d);
  118.             }
  119.         }

  120.         return out;
  121.     }

  122.     /** {@inheritDoc} */
  123.     @Override
  124.     public RealMatrix multiply(final RealMatrix m)
  125.         throws DimensionMismatchException {
  126.         checkMultiply(m);

  127.         final int nRows = getRowDimension();
  128.         final int nCols = m.getColumnDimension();
  129.         final int nSum  = getColumnDimension();
  130.         final RealMatrix out = createMatrix(nRows, nCols);
  131.         for (int row = 0; row < nRows; ++row) {
  132.             for (int col = 0; col < nCols; ++col) {
  133.                 double sum = 0;
  134.                 for (int i = 0; i < nSum; ++i) {
  135.                     sum += getEntry(row, i) * m.getEntry(i, col);
  136.                 }
  137.                 out.setEntry(row, col, sum);
  138.             }
  139.         }

  140.         return out;
  141.     }

  142.     /** {@inheritDoc} */
  143.     @Override
  144.     public RealMatrix preMultiply(final RealMatrix m)
  145.         throws DimensionMismatchException {
  146.         return m.multiply(this);
  147.     }

  148.     /** {@inheritDoc} */
  149.     @Override
  150.     public RealMatrix power(final int p)
  151.         throws NotPositiveException, NonSquareMatrixException {
  152.         if (p < 0) {
  153.             throw new NotPositiveException(LocalizedFormats.NOT_POSITIVE_EXPONENT, p);
  154.         }

  155.         if (!isSquare()) {
  156.             throw new NonSquareMatrixException(getRowDimension(), getColumnDimension());
  157.         }

  158.         if (p == 0) {
  159.             return MatrixUtils.createRealIdentityMatrix(this.getRowDimension());
  160.         }

  161.         if (p == 1) {
  162.             return this.copy();
  163.         }

  164.         final int power = p - 1;

  165.         /*
  166.          * Only log_2(p) operations is used by doing as follows:
  167.          * 5^214 = 5^128 * 5^64 * 5^16 * 5^4 * 5^2
  168.          *
  169.          * In general, the same approach is used for A^p.
  170.          */

  171.         final char[] binaryRepresentation = Integer.toBinaryString(power).toCharArray();
  172.         final ArrayList<Integer> nonZeroPositions = new ArrayList<>();
  173.         int maxI = -1;

  174.         for (int i = 0; i < binaryRepresentation.length; ++i) {
  175.             if (binaryRepresentation[i] == '1') {
  176.                 final int pos = binaryRepresentation.length - i - 1;
  177.                 nonZeroPositions.add(pos);

  178.                 // The positions are taken in turn, so maxI is only changed once
  179.                 if (maxI == -1) {
  180.                     maxI = pos;
  181.                 }
  182.             }
  183.         }

  184.         RealMatrix[] results = new RealMatrix[maxI + 1];
  185.         results[0] = this.copy();

  186.         for (int i = 1; i <= maxI; ++i) {
  187.             results[i] = results[i-1].multiply(results[i-1]);
  188.         }

  189.         RealMatrix result = this.copy();

  190.         for (Integer i : nonZeroPositions) {
  191.             result = result.multiply(results[i]);
  192.         }

  193.         return result;
  194.     }

  195.     /** {@inheritDoc} */
  196.     @Override
  197.     public double[][] getData() {
  198.         final double[][] data = new double[getRowDimension()][getColumnDimension()];

  199.         for (int i = 0; i < data.length; ++i) {
  200.             final double[] dataI = data[i];
  201.             for (int j = 0; j < dataI.length; ++j) {
  202.                 dataI[j] = getEntry(i, j);
  203.             }
  204.         }

  205.         return data;
  206.     }

  207.     /** {@inheritDoc} */
  208.     @Override
  209.     public double getNorm() {
  210.         return walkInColumnOrder(new RealMatrixPreservingVisitor() {

  211.             /** Last row index. */
  212.             private double endRow;

  213.             /** Sum of absolute values on one column. */
  214.             private double columnSum;

  215.             /** Maximal sum across all columns. */
  216.             private double maxColSum;

  217.             /** {@inheritDoc} */
  218.             @Override
  219.             public void start(final int rows, final int columns,
  220.                               final int startRow, final int endRow,
  221.                               final int startColumn, final int endColumn) {
  222.                 this.endRow = endRow;
  223.                 columnSum   = 0;
  224.                 maxColSum   = 0;
  225.             }

  226.             /** {@inheritDoc} */
  227.             @Override
  228.             public void visit(final int row, final int column, final double value) {
  229.                 columnSum += JdkMath.abs(value);
  230.                 if (row == endRow) {
  231.                     maxColSum = JdkMath.max(maxColSum, columnSum);
  232.                     columnSum = 0;
  233.                 }
  234.             }

  235.             /** {@inheritDoc} */
  236.             @Override
  237.             public double end() {
  238.                 return maxColSum;
  239.             }
  240.         });
  241.     }

  242.     /** {@inheritDoc} */
  243.     @Override
  244.     public double getFrobeniusNorm() {
  245.         return walkInOptimizedOrder(new RealMatrixPreservingVisitor() {

  246.             /** Sum of squared entries. */
  247.             private double sum;

  248.             /** {@inheritDoc} */
  249.             @Override
  250.             public void start(final int rows, final int columns,
  251.                               final int startRow, final int endRow,
  252.                               final int startColumn, final int endColumn) {
  253.                 sum = 0;
  254.             }

  255.             /** {@inheritDoc} */
  256.             @Override
  257.             public void visit(final int row, final int column, final double value) {
  258.                 sum += value * value;
  259.             }

  260.             /** {@inheritDoc} */
  261.             @Override
  262.             public double end() {
  263.                 return JdkMath.sqrt(sum);
  264.             }
  265.         });
  266.     }

  267.     /** {@inheritDoc} */
  268.     @Override
  269.     public RealMatrix getSubMatrix(final int startRow, final int endRow,
  270.                                    final int startColumn, final int endColumn)
  271.         throws OutOfRangeException, NumberIsTooSmallException {
  272.         MatrixUtils.checkSubMatrixIndex(this, startRow, endRow, startColumn, endColumn);

  273.         final RealMatrix subMatrix =
  274.             createMatrix(endRow - startRow + 1, endColumn - startColumn + 1);
  275.         for (int i = startRow; i <= endRow; ++i) {
  276.             for (int j = startColumn; j <= endColumn; ++j) {
  277.                 subMatrix.setEntry(i - startRow, j - startColumn, getEntry(i, j));
  278.             }
  279.         }

  280.         return subMatrix;
  281.     }

  282.     /** {@inheritDoc} */
  283.     @Override
  284.     public RealMatrix getSubMatrix(final int[] selectedRows,
  285.                                    final int[] selectedColumns)
  286.         throws NullArgumentException, NoDataException, OutOfRangeException {
  287.         MatrixUtils.checkSubMatrixIndex(this, selectedRows, selectedColumns);

  288.         final RealMatrix subMatrix =
  289.             createMatrix(selectedRows.length, selectedColumns.length);
  290.         subMatrix.walkInOptimizedOrder(new DefaultRealMatrixChangingVisitor() {

  291.             /** {@inheritDoc} */
  292.             @Override
  293.             public double visit(final int row, final int column, final double value) {
  294.                 return getEntry(selectedRows[row], selectedColumns[column]);
  295.             }
  296.         });

  297.         return subMatrix;
  298.     }

  299.     /** {@inheritDoc} */
  300.     @Override
  301.     public void copySubMatrix(final int startRow, final int endRow,
  302.                               final int startColumn, final int endColumn,
  303.                               final double[][] destination)
  304.         throws OutOfRangeException, NumberIsTooSmallException,
  305.         MatrixDimensionMismatchException {
  306.         MatrixUtils.checkSubMatrixIndex(this, startRow, endRow, startColumn, endColumn);
  307.         final int rowsCount    = endRow + 1 - startRow;
  308.         final int columnsCount = endColumn + 1 - startColumn;
  309.         if (destination.length < rowsCount || destination[0].length < columnsCount) {
  310.             throw new MatrixDimensionMismatchException(destination.length, destination[0].length,
  311.                                                        rowsCount, columnsCount);
  312.         }

  313.         for (int i = 1; i < rowsCount; i++) {
  314.             if (destination[i].length < columnsCount) {
  315.                 throw new MatrixDimensionMismatchException(destination.length, destination[i].length,
  316.                                                            rowsCount, columnsCount);
  317.             }
  318.         }

  319.         walkInOptimizedOrder(new DefaultRealMatrixPreservingVisitor() {

  320.             /** Initial row index. */
  321.             private int startRow;

  322.             /** Initial column index. */
  323.             private int startColumn;

  324.             /** {@inheritDoc} */
  325.             @Override
  326.             public void start(final int rows, final int columns,
  327.                               final int startRow, final int endRow,
  328.                               final int startColumn, final int endColumn) {
  329.                 this.startRow    = startRow;
  330.                 this.startColumn = startColumn;
  331.             }

  332.             /** {@inheritDoc} */
  333.             @Override
  334.             public void visit(final int row, final int column, final double value) {
  335.                 destination[row - startRow][column - startColumn] = value;
  336.             }
  337.         }, startRow, endRow, startColumn, endColumn);
  338.     }

  339.     /** {@inheritDoc} */
  340.     @Override
  341.     public void copySubMatrix(int[] selectedRows, int[] selectedColumns,
  342.                               double[][] destination)
  343.         throws OutOfRangeException, NullArgumentException, NoDataException,
  344.         MatrixDimensionMismatchException {
  345.         MatrixUtils.checkSubMatrixIndex(this, selectedRows, selectedColumns);
  346.         final int nCols = selectedColumns.length;
  347.         if (destination.length < selectedRows.length ||
  348.             destination[0].length < nCols) {
  349.             throw new MatrixDimensionMismatchException(destination.length, destination[0].length,
  350.                                                        selectedRows.length, selectedColumns.length);
  351.         }

  352.         for (int i = 0; i < selectedRows.length; i++) {
  353.             final double[] destinationI = destination[i];
  354.             if (destinationI.length < nCols) {
  355.                 throw new MatrixDimensionMismatchException(destination.length, destinationI.length,
  356.                                                            selectedRows.length, selectedColumns.length);
  357.             }
  358.             for (int j = 0; j < selectedColumns.length; j++) {
  359.                 destinationI[j] = getEntry(selectedRows[i], selectedColumns[j]);
  360.             }
  361.         }
  362.     }

  363.     /** {@inheritDoc} */
  364.     @Override
  365.     public void setSubMatrix(final double[][] subMatrix, final int row, final int column)
  366.         throws NoDataException, OutOfRangeException,
  367.         DimensionMismatchException, NullArgumentException {
  368.         NullArgumentException.check(subMatrix);
  369.         final int nRows = subMatrix.length;
  370.         if (nRows == 0) {
  371.             throw new NoDataException(LocalizedFormats.AT_LEAST_ONE_ROW);
  372.         }

  373.         final int nCols = subMatrix[0].length;
  374.         if (nCols == 0) {
  375.             throw new NoDataException(LocalizedFormats.AT_LEAST_ONE_COLUMN);
  376.         }

  377.         for (int r = 1; r < nRows; ++r) {
  378.             if (subMatrix[r].length != nCols) {
  379.                 throw new DimensionMismatchException(nCols, subMatrix[r].length);
  380.             }
  381.         }

  382.         MatrixUtils.checkRowIndex(this, row);
  383.         MatrixUtils.checkColumnIndex(this, column);
  384.         MatrixUtils.checkRowIndex(this, nRows + row - 1);
  385.         MatrixUtils.checkColumnIndex(this, nCols + column - 1);

  386.         for (int i = 0; i < nRows; ++i) {
  387.             for (int j = 0; j < nCols; ++j) {
  388.                 setEntry(row + i, column + j, subMatrix[i][j]);
  389.             }
  390.         }
  391.     }

  392.     /** {@inheritDoc} */
  393.     @Override
  394.     public RealMatrix getRowMatrix(final int row) throws OutOfRangeException {
  395.         MatrixUtils.checkRowIndex(this, row);
  396.         final int nCols = getColumnDimension();
  397.         final RealMatrix out = createMatrix(1, nCols);
  398.         for (int i = 0; i < nCols; ++i) {
  399.             out.setEntry(0, i, getEntry(row, i));
  400.         }

  401.         return out;
  402.     }

  403.     /** {@inheritDoc} */
  404.     @Override
  405.     public void setRowMatrix(final int row, final RealMatrix matrix)
  406.         throws OutOfRangeException, MatrixDimensionMismatchException {
  407.         MatrixUtils.checkRowIndex(this, row);
  408.         final int nCols = getColumnDimension();
  409.         if (matrix.getRowDimension() != 1 ||
  410.             matrix.getColumnDimension() != nCols) {
  411.             throw new MatrixDimensionMismatchException(matrix.getRowDimension(),
  412.                                                        matrix.getColumnDimension(),
  413.                                                        1, nCols);
  414.         }
  415.         for (int i = 0; i < nCols; ++i) {
  416.             setEntry(row, i, matrix.getEntry(0, i));
  417.         }
  418.     }

  419.     /** {@inheritDoc} */
  420.     @Override
  421.     public RealMatrix getColumnMatrix(final int column)
  422.         throws OutOfRangeException {
  423.         MatrixUtils.checkColumnIndex(this, column);
  424.         final int nRows = getRowDimension();
  425.         final RealMatrix out = createMatrix(nRows, 1);
  426.         for (int i = 0; i < nRows; ++i) {
  427.             out.setEntry(i, 0, getEntry(i, column));
  428.         }

  429.         return out;
  430.     }

  431.     /** {@inheritDoc} */
  432.     @Override
  433.     public void setColumnMatrix(final int column, final RealMatrix matrix)
  434.         throws OutOfRangeException, MatrixDimensionMismatchException {
  435.         MatrixUtils.checkColumnIndex(this, column);
  436.         final int nRows = getRowDimension();
  437.         if (matrix.getRowDimension() != nRows ||
  438.             matrix.getColumnDimension() != 1) {
  439.             throw new MatrixDimensionMismatchException(matrix.getRowDimension(),
  440.                                                        matrix.getColumnDimension(),
  441.                                                        nRows, 1);
  442.         }
  443.         for (int i = 0; i < nRows; ++i) {
  444.             setEntry(i, column, matrix.getEntry(i, 0));
  445.         }
  446.     }

  447.     /** {@inheritDoc} */
  448.     @Override
  449.     public RealVector getRowVector(final int row)
  450.         throws OutOfRangeException {
  451.         return new ArrayRealVector(getRow(row), false);
  452.     }

  453.     /** {@inheritDoc} */
  454.     @Override
  455.     public void setRowVector(final int row, final RealVector vector)
  456.         throws OutOfRangeException, MatrixDimensionMismatchException {
  457.         MatrixUtils.checkRowIndex(this, row);
  458.         final int nCols = getColumnDimension();
  459.         if (vector.getDimension() != nCols) {
  460.             throw new MatrixDimensionMismatchException(1, vector.getDimension(),
  461.                                                        1, nCols);
  462.         }
  463.         for (int i = 0; i < nCols; ++i) {
  464.             setEntry(row, i, vector.getEntry(i));
  465.         }
  466.     }

  467.     /** {@inheritDoc} */
  468.     @Override
  469.     public RealVector getColumnVector(final int column)
  470.         throws OutOfRangeException {
  471.         return new ArrayRealVector(getColumn(column), false);
  472.     }

  473.     /** {@inheritDoc} */
  474.     @Override
  475.     public void setColumnVector(final int column, final RealVector vector)
  476.         throws OutOfRangeException, MatrixDimensionMismatchException {
  477.         MatrixUtils.checkColumnIndex(this, column);
  478.         final int nRows = getRowDimension();
  479.         if (vector.getDimension() != nRows) {
  480.             throw new MatrixDimensionMismatchException(vector.getDimension(), 1,
  481.                                                        nRows, 1);
  482.         }
  483.         for (int i = 0; i < nRows; ++i) {
  484.             setEntry(i, column, vector.getEntry(i));
  485.         }
  486.     }

  487.     /** {@inheritDoc} */
  488.     @Override
  489.     public double[] getRow(final int row) throws OutOfRangeException {
  490.         MatrixUtils.checkRowIndex(this, row);
  491.         final int nCols = getColumnDimension();
  492.         final double[] out = new double[nCols];
  493.         for (int i = 0; i < nCols; ++i) {
  494.             out[i] = getEntry(row, i);
  495.         }

  496.         return out;
  497.     }

  498.     /** {@inheritDoc} */
  499.     @Override
  500.     public void setRow(final int row, final double[] array)
  501.         throws OutOfRangeException, MatrixDimensionMismatchException {
  502.         MatrixUtils.checkRowIndex(this, row);
  503.         final int nCols = getColumnDimension();
  504.         if (array.length != nCols) {
  505.             throw new MatrixDimensionMismatchException(1, array.length, 1, nCols);
  506.         }
  507.         for (int i = 0; i < nCols; ++i) {
  508.             setEntry(row, i, array[i]);
  509.         }
  510.     }

  511.     /** {@inheritDoc} */
  512.     @Override
  513.     public double[] getColumn(final int column) throws OutOfRangeException {
  514.         MatrixUtils.checkColumnIndex(this, column);
  515.         final int nRows = getRowDimension();
  516.         final double[] out = new double[nRows];
  517.         for (int i = 0; i < nRows; ++i) {
  518.             out[i] = getEntry(i, column);
  519.         }

  520.         return out;
  521.     }

  522.     /** {@inheritDoc} */
  523.     @Override
  524.     public void setColumn(final int column, final double[] array)
  525.         throws OutOfRangeException, MatrixDimensionMismatchException {
  526.         MatrixUtils.checkColumnIndex(this, column);
  527.         final int nRows = getRowDimension();
  528.         if (array.length != nRows) {
  529.             throw new MatrixDimensionMismatchException(array.length, 1, nRows, 1);
  530.         }
  531.         for (int i = 0; i < nRows; ++i) {
  532.             setEntry(i, column, array[i]);
  533.         }
  534.     }

  535.     /** {@inheritDoc} */
  536.     @Override
  537.     public void addToEntry(int row, int column, double increment)
  538.         throws OutOfRangeException {
  539.         MatrixUtils.checkMatrixIndex(this, row, column);
  540.         setEntry(row, column, getEntry(row, column) + increment);
  541.     }

  542.     /** {@inheritDoc} */
  543.     @Override
  544.     public void multiplyEntry(int row, int column, double factor)
  545.         throws OutOfRangeException {
  546.         MatrixUtils.checkMatrixIndex(this, row, column);
  547.         setEntry(row, column, getEntry(row, column) * factor);
  548.     }

  549.     /** {@inheritDoc} */
  550.     @Override
  551.     public RealMatrix transpose() {
  552.         final int nRows = getRowDimension();
  553.         final int nCols = getColumnDimension();
  554.         final RealMatrix out = createMatrix(nCols, nRows);
  555.         walkInOptimizedOrder(new DefaultRealMatrixPreservingVisitor() {

  556.             /** {@inheritDoc} */
  557.             @Override
  558.             public void visit(final int row, final int column, final double value) {
  559.                 out.setEntry(column, row, value);
  560.             }
  561.         });

  562.         return out;
  563.     }

  564.     /** {@inheritDoc} */
  565.     @Override
  566.     public double getTrace() throws NonSquareMatrixException {
  567.         final int nRows = getRowDimension();
  568.         final int nCols = getColumnDimension();
  569.         if (nRows != nCols) {
  570.             throw new NonSquareMatrixException(nRows, nCols);
  571.        }
  572.         double trace = 0;
  573.         for (int i = 0; i < nRows; ++i) {
  574.             trace += getEntry(i, i);
  575.         }
  576.         return trace;
  577.     }

  578.     /** {@inheritDoc} */
  579.     @Override
  580.     public double[] operate(final double[] v)
  581.         throws DimensionMismatchException {
  582.         final int nRows = getRowDimension();
  583.         final int nCols = getColumnDimension();
  584.         if (v.length != nCols) {
  585.             throw new DimensionMismatchException(v.length, nCols);
  586.         }

  587.         final double[] out = new double[nRows];
  588.         for (int row = 0; row < nRows; ++row) {
  589.             double sum = 0;
  590.             for (int i = 0; i < nCols; ++i) {
  591.                 sum += getEntry(row, i) * v[i];
  592.             }
  593.             out[row] = sum;
  594.         }

  595.         return out;
  596.     }

  597.     /** {@inheritDoc} */
  598.     @Override
  599.     public RealVector operate(final RealVector v)
  600.         throws DimensionMismatchException {
  601.         if (v instanceof ArrayRealVector) {
  602.             return new ArrayRealVector(operate(((ArrayRealVector) v).getDataRef()), false);
  603.         }

  604.         final int nRows = getRowDimension();
  605.         final int nCols = getColumnDimension();
  606.         if (v.getDimension() != nCols) {
  607.             throw new DimensionMismatchException(v.getDimension(), nCols);
  608.         }

  609.         final double[] out = new double[nRows];
  610.         for (int row = 0; row < nRows; ++row) {
  611.             double sum = 0;
  612.             for (int i = 0; i < nCols; ++i) {
  613.                 sum += getEntry(row, i) * v.getEntry(i);
  614.             }
  615.             out[row] = sum;
  616.         }

  617.         return new ArrayRealVector(out, false);
  618.     }

  619.     /** {@inheritDoc} */
  620.     @Override
  621.     public double[] preMultiply(final double[] v) throws DimensionMismatchException {

  622.         final int nRows = getRowDimension();
  623.         final int nCols = getColumnDimension();
  624.         if (v.length != nRows) {
  625.             throw new DimensionMismatchException(v.length, nRows);
  626.         }

  627.         final double[] out = new double[nCols];
  628.         for (int col = 0; col < nCols; ++col) {
  629.             double sum = 0;
  630.             for (int i = 0; i < nRows; ++i) {
  631.                 sum += getEntry(i, col) * v[i];
  632.             }
  633.             out[col] = sum;
  634.         }

  635.         return out;
  636.     }

  637.     /** {@inheritDoc} */
  638.     @Override
  639.     public RealVector preMultiply(final RealVector v) throws DimensionMismatchException {
  640.         if (v instanceof ArrayRealVector) {
  641.             return new ArrayRealVector(preMultiply(((ArrayRealVector) v).getDataRef()), false);
  642.         }

  643.         final int nRows = getRowDimension();
  644.         final int nCols = getColumnDimension();
  645.         if (v.getDimension() != nRows) {
  646.             throw new DimensionMismatchException(v.getDimension(), nRows);
  647.         }

  648.         final double[] out = new double[nCols];
  649.         for (int col = 0; col < nCols; ++col) {
  650.             double sum = 0;
  651.             for (int i = 0; i < nRows; ++i) {
  652.                 sum += getEntry(i, col) * v.getEntry(i);
  653.             }
  654.             out[col] = sum;
  655.         }

  656.         return new ArrayRealVector(out, false);
  657.     }

  658.     /** {@inheritDoc} */
  659.     @Override
  660.     public double walkInRowOrder(final RealMatrixChangingVisitor visitor) {
  661.         final int rows    = getRowDimension();
  662.         final int columns = getColumnDimension();
  663.         visitor.start(rows, columns, 0, rows - 1, 0, columns - 1);
  664.         for (int row = 0; row < rows; ++row) {
  665.             for (int column = 0; column < columns; ++column) {
  666.                 final double oldValue = getEntry(row, column);
  667.                 final double newValue = visitor.visit(row, column, oldValue);
  668.                 setEntry(row, column, newValue);
  669.             }
  670.         }
  671.         return visitor.end();
  672.     }

  673.     /** {@inheritDoc} */
  674.     @Override
  675.     public double walkInRowOrder(final RealMatrixPreservingVisitor visitor) {
  676.         final int rows    = getRowDimension();
  677.         final int columns = getColumnDimension();
  678.         visitor.start(rows, columns, 0, rows - 1, 0, columns - 1);
  679.         for (int row = 0; row < rows; ++row) {
  680.             for (int column = 0; column < columns; ++column) {
  681.                 visitor.visit(row, column, getEntry(row, column));
  682.             }
  683.         }
  684.         return visitor.end();
  685.     }

  686.     /** {@inheritDoc} */
  687.     @Override
  688.     public double walkInRowOrder(final RealMatrixChangingVisitor visitor,
  689.                                  final int startRow, final int endRow,
  690.                                  final int startColumn, final int endColumn)
  691.         throws OutOfRangeException, NumberIsTooSmallException {
  692.         MatrixUtils.checkSubMatrixIndex(this, startRow, endRow, startColumn, endColumn);
  693.         visitor.start(getRowDimension(), getColumnDimension(),
  694.                       startRow, endRow, startColumn, endColumn);
  695.         for (int row = startRow; row <= endRow; ++row) {
  696.             for (int column = startColumn; column <= endColumn; ++column) {
  697.                 final double oldValue = getEntry(row, column);
  698.                 final double newValue = visitor.visit(row, column, oldValue);
  699.                 setEntry(row, column, newValue);
  700.             }
  701.         }
  702.         return visitor.end();
  703.     }

  704.     /** {@inheritDoc} */
  705.     @Override
  706.     public double walkInRowOrder(final RealMatrixPreservingVisitor visitor,
  707.                                  final int startRow, final int endRow,
  708.                                  final int startColumn, final int endColumn)
  709.         throws OutOfRangeException, NumberIsTooSmallException {
  710.         MatrixUtils.checkSubMatrixIndex(this, startRow, endRow, startColumn, endColumn);
  711.         visitor.start(getRowDimension(), getColumnDimension(),
  712.                       startRow, endRow, startColumn, endColumn);
  713.         for (int row = startRow; row <= endRow; ++row) {
  714.             for (int column = startColumn; column <= endColumn; ++column) {
  715.                 visitor.visit(row, column, getEntry(row, column));
  716.             }
  717.         }
  718.         return visitor.end();
  719.     }

  720.     /** {@inheritDoc} */
  721.     @Override
  722.     public double walkInColumnOrder(final RealMatrixChangingVisitor visitor) {
  723.         final int rows    = getRowDimension();
  724.         final int columns = getColumnDimension();
  725.         visitor.start(rows, columns, 0, rows - 1, 0, columns - 1);
  726.         for (int column = 0; column < columns; ++column) {
  727.             for (int row = 0; row < rows; ++row) {
  728.                 final double oldValue = getEntry(row, column);
  729.                 final double newValue = visitor.visit(row, column, oldValue);
  730.                 setEntry(row, column, newValue);
  731.             }
  732.         }
  733.         return visitor.end();
  734.     }

  735.     /** {@inheritDoc} */
  736.     @Override
  737.     public double walkInColumnOrder(final RealMatrixPreservingVisitor visitor) {
  738.         final int rows    = getRowDimension();
  739.         final int columns = getColumnDimension();
  740.         visitor.start(rows, columns, 0, rows - 1, 0, columns - 1);
  741.         for (int column = 0; column < columns; ++column) {
  742.             for (int row = 0; row < rows; ++row) {
  743.                 visitor.visit(row, column, getEntry(row, column));
  744.             }
  745.         }
  746.         return visitor.end();
  747.     }

  748.     /** {@inheritDoc} */
  749.     @Override
  750.     public double walkInColumnOrder(final RealMatrixChangingVisitor visitor,
  751.                                     final int startRow, final int endRow,
  752.                                     final int startColumn, final int endColumn)
  753.         throws OutOfRangeException, NumberIsTooSmallException {
  754.         MatrixUtils.checkSubMatrixIndex(this, startRow, endRow, startColumn, endColumn);
  755.         visitor.start(getRowDimension(), getColumnDimension(),
  756.                       startRow, endRow, startColumn, endColumn);
  757.         for (int column = startColumn; column <= endColumn; ++column) {
  758.             for (int row = startRow; row <= endRow; ++row) {
  759.                 final double oldValue = getEntry(row, column);
  760.                 final double newValue = visitor.visit(row, column, oldValue);
  761.                 setEntry(row, column, newValue);
  762.             }
  763.         }
  764.         return visitor.end();
  765.     }

  766.     /** {@inheritDoc} */
  767.     @Override
  768.     public double walkInColumnOrder(final RealMatrixPreservingVisitor visitor,
  769.                                     final int startRow, final int endRow,
  770.                                     final int startColumn, final int endColumn)
  771.         throws OutOfRangeException, NumberIsTooSmallException {
  772.         MatrixUtils.checkSubMatrixIndex(this, startRow, endRow, startColumn, endColumn);
  773.         visitor.start(getRowDimension(), getColumnDimension(),
  774.                       startRow, endRow, startColumn, endColumn);
  775.         for (int column = startColumn; column <= endColumn; ++column) {
  776.             for (int row = startRow; row <= endRow; ++row) {
  777.                 visitor.visit(row, column, getEntry(row, column));
  778.             }
  779.         }
  780.         return visitor.end();
  781.     }

  782.     /** {@inheritDoc} */
  783.     @Override
  784.     public double walkInOptimizedOrder(final RealMatrixChangingVisitor visitor) {
  785.         return walkInRowOrder(visitor);
  786.     }

  787.     /** {@inheritDoc} */
  788.     @Override
  789.     public double walkInOptimizedOrder(final RealMatrixPreservingVisitor visitor) {
  790.         return walkInRowOrder(visitor);
  791.     }

  792.     /** {@inheritDoc} */
  793.     @Override
  794.     public double walkInOptimizedOrder(final RealMatrixChangingVisitor visitor,
  795.                                        final int startRow, final int endRow,
  796.                                        final int startColumn,
  797.                                        final int endColumn)
  798.         throws OutOfRangeException, NumberIsTooSmallException {
  799.         return walkInRowOrder(visitor, startRow, endRow, startColumn, endColumn);
  800.     }

  801.     /** {@inheritDoc} */
  802.     @Override
  803.     public double walkInOptimizedOrder(final RealMatrixPreservingVisitor visitor,
  804.                                        final int startRow, final int endRow,
  805.                                        final int startColumn,
  806.                                        final int endColumn)
  807.         throws OutOfRangeException, NumberIsTooSmallException {
  808.         return walkInRowOrder(visitor, startRow, endRow, startColumn, endColumn);
  809.     }

  810.     /**
  811.      * Get a string representation for this matrix.
  812.      * @return a string representation for this matrix
  813.      */
  814.     @Override
  815.     public String toString() {
  816.         final StringBuilder res = new StringBuilder();
  817.         String fullClassName = getClass().getName();
  818.         String shortClassName = fullClassName.substring(fullClassName.lastIndexOf('.') + 1);
  819.         res.append(shortClassName);
  820.         res.append(DEFAULT_FORMAT.format(this));
  821.         return res.toString();
  822.     }

  823.     /**
  824.      * Returns true iff <code>object</code> is a
  825.      * <code>RealMatrix</code> instance with the same dimensions as this
  826.      * and all corresponding matrix entries are equal.
  827.      *
  828.      * @param object the object to test equality against.
  829.      * @return true if object equals this
  830.      */
  831.     @Override
  832.     public boolean equals(final Object object) {
  833.         if (object == this ) {
  834.             return true;
  835.         }
  836.         if (!(object instanceof RealMatrix)) {
  837.             return false;
  838.         }
  839.         RealMatrix m = (RealMatrix) object;
  840.         final int nRows = getRowDimension();
  841.         final int nCols = getColumnDimension();
  842.         if (m.getColumnDimension() != nCols || m.getRowDimension() != nRows) {
  843.             return false;
  844.         }
  845.         for (int row = 0; row < nRows; ++row) {
  846.             for (int col = 0; col < nCols; ++col) {
  847.                 if (getEntry(row, col) != m.getEntry(row, col)) {
  848.                     return false;
  849.                 }
  850.             }
  851.         }
  852.         return true;
  853.     }

  854.     /**
  855.      * Computes a hash code for the matrix.
  856.      *
  857.      * @return hash code for matrix
  858.      */
  859.     @Override
  860.     public int hashCode() {
  861.         int ret = 7;
  862.         final int nRows = getRowDimension();
  863.         final int nCols = getColumnDimension();
  864.         ret = ret * 31 + nRows;
  865.         ret = ret * 31 + nCols;
  866.         for (int row = 0; row < nRows; ++row) {
  867.             for (int col = 0; col < nCols; ++col) {
  868.                ret = ret * 31 + (11 * (row+1) + 17 * (col+1)) *
  869.                    Double.hashCode(getEntry(row, col));
  870.            }
  871.         }
  872.         return ret;
  873.     }


  874.     /*
  875.      * Empty implementations of these methods are provided in order to allow for
  876.      * the use of the @Override tag with Java 1.5.
  877.      */

  878.     /** {@inheritDoc} */
  879.     @Override
  880.     public abstract RealMatrix createMatrix(int rowDimension, int columnDimension)
  881.         throws NotStrictlyPositiveException;

  882.     /** {@inheritDoc} */
  883.     @Override
  884.     public abstract RealMatrix copy();

  885.     /** {@inheritDoc} */
  886.     @Override
  887.     public abstract double getEntry(int row, int column)
  888.         throws OutOfRangeException;

  889.     /** {@inheritDoc} */
  890.     @Override
  891.     public abstract void setEntry(int row, int column, double value)
  892.         throws OutOfRangeException;
  893. }