AbstractFieldMatrix.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 org.apache.commons.math4.legacy.core.Field;
  20. import org.apache.commons.math4.legacy.core.FieldElement;
  21. import org.apache.commons.math4.legacy.exception.DimensionMismatchException;
  22. import org.apache.commons.math4.legacy.exception.NoDataException;
  23. import org.apache.commons.math4.legacy.exception.NotPositiveException;
  24. import org.apache.commons.math4.legacy.exception.NotStrictlyPositiveException;
  25. import org.apache.commons.math4.legacy.exception.NullArgumentException;
  26. import org.apache.commons.math4.legacy.exception.NumberIsTooSmallException;
  27. import org.apache.commons.math4.legacy.exception.OutOfRangeException;
  28. import org.apache.commons.math4.legacy.exception.util.LocalizedFormats;
  29. import org.apache.commons.math4.legacy.core.MathArrays;

  30. /**
  31.  * Basic implementation of {@link FieldMatrix} methods regardless of the underlying storage.
  32.  * <p>All the methods implemented here use {@link #getEntry(int, int)} to access
  33.  * matrix elements. Derived class can provide faster implementations. </p>
  34.  *
  35.  * @param <T> Type of the field elements.
  36.  *
  37.  * @since 2.0
  38.  */
  39. public abstract class AbstractFieldMatrix<T extends FieldElement<T>>
  40.     implements FieldMatrix<T> {
  41.     /** Field to which the elements belong. */
  42.     private final Field<T> field;

  43.     /**
  44.      * Constructor for use with Serializable.
  45.      */
  46.     protected AbstractFieldMatrix() {
  47.         field = null;
  48.     }

  49.     /**
  50.      * Creates a matrix with no data.
  51.      * @param field field to which the elements belong
  52.      */
  53.     protected AbstractFieldMatrix(final Field<T> field) {
  54.         this.field = field;
  55.     }

  56.     /**
  57.      * Create a new {@code FieldMatrix<T>} with the supplied row and column dimensions.
  58.      *
  59.      * @param field Field to which the elements belong.
  60.      * @param rowDimension Number of rows in the new matrix.
  61.      * @param columnDimension Number of columns in the new matrix.
  62.      * @throws NotStrictlyPositiveException if row or column dimension is not
  63.      * positive.
  64.      */
  65.     protected AbstractFieldMatrix(final Field<T> field,
  66.                                   final int rowDimension,
  67.                                   final int columnDimension)
  68.         throws NotStrictlyPositiveException {
  69.         if (rowDimension <= 0) {
  70.             throw new NotStrictlyPositiveException(LocalizedFormats.DIMENSION,
  71.                                                    rowDimension);
  72.         }
  73.         if (columnDimension <= 0) {
  74.             throw new NotStrictlyPositiveException(LocalizedFormats.DIMENSION,
  75.                                                    columnDimension);
  76.         }
  77.         this.field = field;
  78.     }

  79.     /**
  80.      * Get the elements type from an array.
  81.      *
  82.      * @param <T> Type of the field elements.
  83.      * @param d Data array.
  84.      * @return the field to which the array elements belong.
  85.      * @throws NullArgumentException if the array is {@code null}.
  86.      * @throws NoDataException if the array is empty.
  87.      */
  88.     protected static <T extends FieldElement<T>> Field<T> extractField(final T[][] d)
  89.         throws NoDataException, NullArgumentException {
  90.         if (d == null) {
  91.             throw new NullArgumentException();
  92.         }
  93.         if (d.length == 0) {
  94.             throw new NoDataException(LocalizedFormats.AT_LEAST_ONE_ROW);
  95.         }
  96.         if (d[0].length == 0) {
  97.             throw new NoDataException(LocalizedFormats.AT_LEAST_ONE_COLUMN);
  98.         }
  99.         return d[0][0].getField();
  100.     }

  101.     /**
  102.      * Get the elements type from an array.
  103.      *
  104.      * @param <T> Type of the field elements.
  105.      * @param d Data array.
  106.      * @return the field to which the array elements belong.
  107.      * @throws NoDataException if array is empty.
  108.      */
  109.     protected static <T extends FieldElement<T>> Field<T> extractField(final T[] d)
  110.         throws NoDataException {
  111.         if (d.length == 0) {
  112.             throw new NoDataException(LocalizedFormats.AT_LEAST_ONE_ROW);
  113.         }
  114.         return d[0].getField();
  115.     }

  116.     /** {@inheritDoc} */
  117.     @Override
  118.     public Field<T> getField() {
  119.         return field;
  120.     }

  121.     /** {@inheritDoc} */
  122.     @Override
  123.     public abstract FieldMatrix<T> createMatrix(int rowDimension,
  124.                                                 int columnDimension)
  125.         throws NotStrictlyPositiveException;

  126.     /** {@inheritDoc} */
  127.     @Override
  128.     public abstract FieldMatrix<T> copy();

  129.     /** {@inheritDoc} */
  130.     @Override
  131.     public FieldMatrix<T> add(FieldMatrix<T> m)
  132.         throws MatrixDimensionMismatchException {
  133.         // safety check
  134.         checkAdd(m);

  135.         final int rowCount    = getRowDimension();
  136.         final int columnCount = getColumnDimension();
  137.         final FieldMatrix<T> out = createMatrix(rowCount, columnCount);
  138.         for (int row = 0; row < rowCount; ++row) {
  139.             for (int col = 0; col < columnCount; ++col) {
  140.                 out.setEntry(row, col, getEntry(row, col).add(m.getEntry(row, col)));
  141.             }
  142.         }

  143.         return out;
  144.     }

  145.     /** {@inheritDoc} */
  146.     @Override
  147.     public FieldMatrix<T> subtract(final FieldMatrix<T> m)
  148.         throws MatrixDimensionMismatchException {
  149.         // safety check
  150.         checkAdd(m);

  151.         final int rowCount    = getRowDimension();
  152.         final int columnCount = getColumnDimension();
  153.         final FieldMatrix<T> out = createMatrix(rowCount, columnCount);
  154.         for (int row = 0; row < rowCount; ++row) {
  155.             for (int col = 0; col < columnCount; ++col) {
  156.                 out.setEntry(row, col, getEntry(row, col).subtract(m.getEntry(row, col)));
  157.             }
  158.         }

  159.         return out;
  160.     }

  161.     /** {@inheritDoc} */
  162.     @Override
  163.     public FieldMatrix<T> scalarAdd(final T d) {

  164.         final int rowCount    = getRowDimension();
  165.         final int columnCount = getColumnDimension();
  166.         final FieldMatrix<T> out = createMatrix(rowCount, columnCount);
  167.         for (int row = 0; row < rowCount; ++row) {
  168.             for (int col = 0; col < columnCount; ++col) {
  169.                 out.setEntry(row, col, getEntry(row, col).add(d));
  170.             }
  171.         }

  172.         return out;
  173.     }

  174.     /** {@inheritDoc} */
  175.     @Override
  176.     public FieldMatrix<T> scalarMultiply(final T d) {
  177.         final int rowCount    = getRowDimension();
  178.         final int columnCount = getColumnDimension();
  179.         final FieldMatrix<T> out = createMatrix(rowCount, columnCount);
  180.         for (int row = 0; row < rowCount; ++row) {
  181.             for (int col = 0; col < columnCount; ++col) {
  182.                 out.setEntry(row, col, getEntry(row, col).multiply(d));
  183.             }
  184.         }

  185.         return out;
  186.     }

  187.     /** {@inheritDoc} */
  188.     @Override
  189.     public FieldMatrix<T> multiply(final FieldMatrix<T> m)
  190.         throws DimensionMismatchException {
  191.         // safety check
  192.         checkMultiply(m);

  193.         final int nRows = getRowDimension();
  194.         final int nCols = m.getColumnDimension();
  195.         final int nSum  = getColumnDimension();
  196.         final FieldMatrix<T> out = createMatrix(nRows, nCols);
  197.         for (int row = 0; row < nRows; ++row) {
  198.             for (int col = 0; col < nCols; ++col) {
  199.                 T sum = field.getZero();
  200.                 for (int i = 0; i < nSum; ++i) {
  201.                     sum = sum.add(getEntry(row, i).multiply(m.getEntry(i, col)));
  202.                 }
  203.                 out.setEntry(row, col, sum);
  204.             }
  205.         }

  206.         return out;
  207.     }

  208.     /** {@inheritDoc} */
  209.     @Override
  210.     public FieldMatrix<T> preMultiply(final FieldMatrix<T> m)
  211.         throws DimensionMismatchException {
  212.         return m.multiply(this);
  213.     }

  214.     /** {@inheritDoc} */
  215.     @Override
  216.     public FieldMatrix<T> power(final int p) throws NonSquareMatrixException,
  217.     NotPositiveException {
  218.         if (p < 0) {
  219.             throw new NotPositiveException(p);
  220.         }

  221.         if (!isSquare()) {
  222.             throw new NonSquareMatrixException(getRowDimension(), getColumnDimension());
  223.         }

  224.         if (p == 0) {
  225.             return MatrixUtils.createFieldIdentityMatrix(this.getField(), this.getRowDimension());
  226.         }

  227.         if (p == 1) {
  228.             return this.copy();
  229.         }

  230.         final int power = p - 1;

  231.         /*
  232.          * Only log_2(p) operations is used by doing as follows:
  233.          * 5^214 = 5^128 * 5^64 * 5^16 * 5^4 * 5^2
  234.          *
  235.          * In general, the same approach is used for A^p.
  236.          */

  237.         final char[] binaryRepresentation = Integer.toBinaryString(power)
  238.                 .toCharArray();
  239.         final ArrayList<Integer> nonZeroPositions = new ArrayList<>();

  240.         for (int i = 0; i < binaryRepresentation.length; ++i) {
  241.             if (binaryRepresentation[i] == '1') {
  242.                 final int pos = binaryRepresentation.length - i - 1;
  243.                 nonZeroPositions.add(pos);
  244.             }
  245.         }

  246.         ArrayList<FieldMatrix<T>> results = new ArrayList<>(
  247.                 binaryRepresentation.length);

  248.         results.add(0, this.copy());

  249.         for (int i = 1; i < binaryRepresentation.length; ++i) {
  250.             final FieldMatrix<T> s = results.get(i - 1);
  251.             final FieldMatrix<T> r = s.multiply(s);
  252.             results.add(i, r);
  253.         }

  254.         FieldMatrix<T> result = this.copy();

  255.         for (Integer i : nonZeroPositions) {
  256.             result = result.multiply(results.get(i));
  257.         }

  258.         return result;
  259.     }

  260.     /** {@inheritDoc} */
  261.     @Override
  262.     public T[][] getData() {
  263.         final T[][] data = MathArrays.buildArray(field, getRowDimension(), getColumnDimension());

  264.         for (int i = 0; i < data.length; ++i) {
  265.             final T[] dataI = data[i];
  266.             for (int j = 0; j < dataI.length; ++j) {
  267.                 dataI[j] = getEntry(i, j);
  268.             }
  269.         }

  270.         return data;
  271.     }

  272.     /** {@inheritDoc} */
  273.     @Override
  274.     public FieldMatrix<T> getSubMatrix(final int startRow, final int endRow,
  275.                                        final int startColumn, final int endColumn)
  276.         throws NumberIsTooSmallException, OutOfRangeException {
  277.         checkSubMatrixIndex(startRow, endRow, startColumn, endColumn);

  278.         final FieldMatrix<T> subMatrix =
  279.             createMatrix(endRow - startRow + 1, endColumn - startColumn + 1);
  280.         for (int i = startRow; i <= endRow; ++i) {
  281.             for (int j = startColumn; j <= endColumn; ++j) {
  282.                 subMatrix.setEntry(i - startRow, j - startColumn, getEntry(i, j));
  283.             }
  284.         }

  285.         return subMatrix;
  286.     }

  287.     /** {@inheritDoc} */
  288.     @Override
  289.     public FieldMatrix<T> getSubMatrix(final int[] selectedRows,
  290.                                        final int[] selectedColumns)
  291.     throws NoDataException, NullArgumentException, OutOfRangeException {

  292.         // safety checks
  293.         checkSubMatrixIndex(selectedRows, selectedColumns);

  294.         // copy entries
  295.         final FieldMatrix<T> subMatrix =
  296.             createMatrix(selectedRows.length, selectedColumns.length);
  297.         subMatrix.walkInOptimizedOrder(new DefaultFieldMatrixChangingVisitor<T>(field.getZero()) {

  298.             /** {@inheritDoc} */
  299.             @Override
  300.             public T visit(final int row, final int column, final T value) {
  301.                 return getEntry(selectedRows[row], selectedColumns[column]);
  302.             }
  303.         });

  304.         return subMatrix;
  305.     }

  306.     /** {@inheritDoc} */
  307.     @Override
  308.     public void copySubMatrix(final int startRow, final int endRow,
  309.                               final int startColumn, final int endColumn,
  310.                               final T[][] destination)
  311.     throws MatrixDimensionMismatchException, NumberIsTooSmallException,
  312.     OutOfRangeException{
  313.         // safety checks
  314.         checkSubMatrixIndex(startRow, endRow, startColumn, endColumn);
  315.         final int rowsCount    = endRow + 1 - startRow;
  316.         final int columnsCount = endColumn + 1 - startColumn;
  317.         if (destination.length < rowsCount || destination[0].length < columnsCount) {
  318.             throw new MatrixDimensionMismatchException(destination.length,
  319.                                                        destination[0].length,
  320.                                                        rowsCount,
  321.                                                        columnsCount);
  322.         }

  323.         // copy entries
  324.         walkInOptimizedOrder(new DefaultFieldMatrixPreservingVisitor<T>(field.getZero()) {

  325.             /** Initial row index. */
  326.             private int startRow;

  327.             /** Initial column index. */
  328.             private int startColumn;

  329.             /** {@inheritDoc} */
  330.             @Override
  331.             public void start(final int rows, final int columns,
  332.                               final int startRow, final int endRow,
  333.                               final int startColumn, final int endColumn) {
  334.                 this.startRow    = startRow;
  335.                 this.startColumn = startColumn;
  336.             }

  337.             /** {@inheritDoc} */
  338.             @Override
  339.             public void visit(final int row, final int column, final T value) {
  340.                 destination[row - startRow][column - startColumn] = value;
  341.             }
  342.         }, startRow, endRow, startColumn, endColumn);
  343.     }

  344.     /** {@inheritDoc} */
  345.     @Override
  346.     public void copySubMatrix(int[] selectedRows, int[] selectedColumns, T[][] destination)
  347.         throws MatrixDimensionMismatchException, NoDataException,
  348.         NullArgumentException, OutOfRangeException {
  349.         // safety checks
  350.         checkSubMatrixIndex(selectedRows, selectedColumns);
  351.         if (destination.length < selectedRows.length ||
  352.             destination[0].length < selectedColumns.length) {
  353.             throw new MatrixDimensionMismatchException(destination.length,
  354.                                                        destination[0].length,
  355.                                                        selectedRows.length,
  356.                                                        selectedColumns.length);
  357.         }

  358.         // copy entries
  359.         for (int i = 0; i < selectedRows.length; i++) {
  360.             final T[] destinationI = destination[i];
  361.             for (int j = 0; j < selectedColumns.length; j++) {
  362.                 destinationI[j] = getEntry(selectedRows[i], selectedColumns[j]);
  363.             }
  364.         }
  365.     }

  366.     /** {@inheritDoc} */
  367.     @Override
  368.     public void setSubMatrix(final T[][] subMatrix, final int row,
  369.                              final int column)
  370.         throws DimensionMismatchException, OutOfRangeException,
  371.         NoDataException, NullArgumentException {
  372.         if (subMatrix == null) {
  373.             throw new NullArgumentException();
  374.         }
  375.         final int nRows = subMatrix.length;
  376.         if (nRows == 0) {
  377.             throw new NoDataException(LocalizedFormats.AT_LEAST_ONE_ROW);
  378.         }

  379.         final int nCols = subMatrix[0].length;
  380.         if (nCols == 0) {
  381.             throw new NoDataException(LocalizedFormats.AT_LEAST_ONE_COLUMN);
  382.         }

  383.         for (int r = 1; r < nRows; ++r) {
  384.             if (subMatrix[r].length != nCols) {
  385.                 throw new DimensionMismatchException(nCols, subMatrix[r].length);
  386.             }
  387.         }

  388.         checkRowIndex(row);
  389.         checkColumnIndex(column);
  390.         checkRowIndex(nRows + row - 1);
  391.         checkColumnIndex(nCols + column - 1);

  392.         for (int i = 0; i < nRows; ++i) {
  393.             for (int j = 0; j < nCols; ++j) {
  394.                 setEntry(row + i, column + j, subMatrix[i][j]);
  395.             }
  396.         }
  397.     }

  398.     /** {@inheritDoc} */
  399.     @Override
  400.     public FieldMatrix<T> getRowMatrix(final int row) throws OutOfRangeException {
  401.         checkRowIndex(row);
  402.         final int nCols = getColumnDimension();
  403.         final FieldMatrix<T> out = createMatrix(1, nCols);
  404.         for (int i = 0; i < nCols; ++i) {
  405.             out.setEntry(0, i, getEntry(row, i));
  406.         }

  407.         return out;
  408.     }

  409.     /** {@inheritDoc} */
  410.     @Override
  411.     public void setRowMatrix(final int row, final FieldMatrix<T> matrix)
  412.         throws OutOfRangeException, MatrixDimensionMismatchException {
  413.         checkRowIndex(row);
  414.         final int nCols = getColumnDimension();
  415.         if (matrix.getRowDimension() != 1 ||
  416.             matrix.getColumnDimension() != nCols) {
  417.             throw new MatrixDimensionMismatchException(matrix.getRowDimension(),
  418.                                                        matrix.getColumnDimension(),
  419.                                                        1, nCols);
  420.         }
  421.         for (int i = 0; i < nCols; ++i) {
  422.             setEntry(row, i, matrix.getEntry(0, i));
  423.         }
  424.     }

  425.     /** {@inheritDoc} */
  426.     @Override
  427.     public FieldMatrix<T> getColumnMatrix(final int column)
  428.     throws OutOfRangeException {

  429.         checkColumnIndex(column);
  430.         final int nRows = getRowDimension();
  431.         final FieldMatrix<T> out = createMatrix(nRows, 1);
  432.         for (int i = 0; i < nRows; ++i) {
  433.             out.setEntry(i, 0, getEntry(i, column));
  434.         }

  435.         return out;
  436.     }

  437.     /** {@inheritDoc} */
  438.     @Override
  439.     public void setColumnMatrix(final int column, final FieldMatrix<T> matrix)
  440.         throws OutOfRangeException, MatrixDimensionMismatchException {
  441.         checkColumnIndex(column);
  442.         final int nRows = getRowDimension();
  443.         if (matrix.getRowDimension() != nRows ||
  444.             matrix.getColumnDimension() != 1) {
  445.             throw new MatrixDimensionMismatchException(matrix.getRowDimension(),
  446.                                                        matrix.getColumnDimension(),
  447.                                                        nRows, 1);
  448.         }
  449.         for (int i = 0; i < nRows; ++i) {
  450.             setEntry(i, column, matrix.getEntry(i, 0));
  451.         }
  452.     }

  453.     /** {@inheritDoc} */
  454.     @Override
  455.     public FieldVector<T> getRowVector(final int row)
  456.         throws OutOfRangeException {
  457.         return new ArrayFieldVector<>(field, getRow(row), false);
  458.     }

  459.     /** {@inheritDoc} */
  460.     @Override
  461.     public void setRowVector(final int row, final FieldVector<T> vector)
  462.         throws OutOfRangeException, MatrixDimensionMismatchException {
  463.         checkRowIndex(row);
  464.         final int nCols = getColumnDimension();
  465.         if (vector.getDimension() != nCols) {
  466.             throw new MatrixDimensionMismatchException(1, vector.getDimension(),
  467.                                                        1, nCols);
  468.         }
  469.         for (int i = 0; i < nCols; ++i) {
  470.             setEntry(row, i, vector.getEntry(i));
  471.         }
  472.     }

  473.     /** {@inheritDoc} */
  474.     @Override
  475.     public FieldVector<T> getColumnVector(final int column)
  476.         throws OutOfRangeException {
  477.         return new ArrayFieldVector<>(field, getColumn(column), false);
  478.     }

  479.     /** {@inheritDoc} */
  480.     @Override
  481.     public void setColumnVector(final int column, final FieldVector<T> vector)
  482.         throws OutOfRangeException, MatrixDimensionMismatchException {

  483.         checkColumnIndex(column);
  484.         final int nRows = getRowDimension();
  485.         if (vector.getDimension() != nRows) {
  486.             throw new MatrixDimensionMismatchException(vector.getDimension(), 1,
  487.                                                        nRows, 1);
  488.         }
  489.         for (int i = 0; i < nRows; ++i) {
  490.             setEntry(i, column, vector.getEntry(i));
  491.         }
  492.     }

  493.     /** {@inheritDoc} */
  494.     @Override
  495.     public T[] getRow(final int row) throws OutOfRangeException {
  496.         checkRowIndex(row);
  497.         final int nCols = getColumnDimension();
  498.         final T[] out = MathArrays.buildArray(field, nCols);
  499.         for (int i = 0; i < nCols; ++i) {
  500.             out[i] = getEntry(row, i);
  501.         }

  502.         return out;
  503.     }

  504.     /** {@inheritDoc} */
  505.     @Override
  506.     public void setRow(final int row, final T[] array)
  507.         throws OutOfRangeException, MatrixDimensionMismatchException {
  508.         checkRowIndex(row);
  509.         final int nCols = getColumnDimension();
  510.         if (array.length != nCols) {
  511.             throw new MatrixDimensionMismatchException(1, array.length, 1, nCols);
  512.         }
  513.         for (int i = 0; i < nCols; ++i) {
  514.             setEntry(row, i, array[i]);
  515.         }
  516.     }

  517.     /** {@inheritDoc} */
  518.     @Override
  519.     public T[] getColumn(final int column) throws OutOfRangeException {
  520.         checkColumnIndex(column);
  521.         final int nRows = getRowDimension();
  522.         final T[] out = MathArrays.buildArray(field, nRows);
  523.         for (int i = 0; i < nRows; ++i) {
  524.             out[i] = getEntry(i, column);
  525.         }

  526.         return out;
  527.     }

  528.     /** {@inheritDoc} */
  529.     @Override
  530.     public void setColumn(final int column, final T[] array)
  531.         throws OutOfRangeException, MatrixDimensionMismatchException {
  532.         checkColumnIndex(column);
  533.         final int nRows = getRowDimension();
  534.         if (array.length != nRows) {
  535.             throw new MatrixDimensionMismatchException(array.length, 1, nRows, 1);
  536.         }
  537.         for (int i = 0; i < nRows; ++i) {
  538.             setEntry(i, column, array[i]);
  539.         }
  540.     }

  541.     /** {@inheritDoc} */
  542.     @Override
  543.     public abstract T getEntry(int row, int column) throws OutOfRangeException;

  544.     /** {@inheritDoc} */
  545.     @Override
  546.     public abstract void setEntry(int row, int column, T value) throws OutOfRangeException;

  547.     /** {@inheritDoc} */
  548.     @Override
  549.     public abstract void addToEntry(int row, int column, T increment) throws OutOfRangeException;

  550.     /** {@inheritDoc} */
  551.     @Override
  552.     public abstract void multiplyEntry(int row, int column, T factor) throws OutOfRangeException;

  553.     /** {@inheritDoc} */
  554.     @Override
  555.     public FieldMatrix<T> transpose() {
  556.         final int nRows = getRowDimension();
  557.         final int nCols = getColumnDimension();
  558.         final FieldMatrix<T> out = createMatrix(nCols, nRows);
  559.         walkInOptimizedOrder(new DefaultFieldMatrixPreservingVisitor<T>(field.getZero()) {
  560.             /** {@inheritDoc} */
  561.             @Override
  562.             public void visit(final int row, final int column, final T value) {
  563.                 out.setEntry(column, row, value);
  564.             }
  565.         });

  566.         return out;
  567.     }

  568.     /** {@inheritDoc} */
  569.     @Override
  570.     public T getTrace() throws NonSquareMatrixException {
  571.         final int nRows = getRowDimension();
  572.         final int nCols = getColumnDimension();
  573.         if (nRows != nCols) {
  574.             throw new NonSquareMatrixException(nRows, nCols);
  575.        }
  576.         T trace = field.getZero();
  577.         for (int i = 0; i < nRows; ++i) {
  578.             trace = trace.add(getEntry(i, i));
  579.         }
  580.         return trace;
  581.     }

  582.     /** {@inheritDoc} */
  583.     @Override
  584.     public T[] operate(final T[] v) throws DimensionMismatchException {

  585.         final int nRows = getRowDimension();
  586.         final int nCols = getColumnDimension();
  587.         if (v.length != nCols) {
  588.             throw new DimensionMismatchException(v.length, nCols);
  589.         }

  590.         final T[] out = MathArrays.buildArray(field, nRows);
  591.         for (int row = 0; row < nRows; ++row) {
  592.             T sum = field.getZero();
  593.             for (int i = 0; i < nCols; ++i) {
  594.                 sum = sum.add(getEntry(row, i).multiply(v[i]));
  595.             }
  596.             out[row] = sum;
  597.         }

  598.         return out;
  599.     }

  600.     /** {@inheritDoc} */
  601.     @Override
  602.     public FieldVector<T> operate(final FieldVector<T> v)
  603.         throws DimensionMismatchException {
  604.         if (v instanceof ArrayFieldVector) {
  605.             return new ArrayFieldVector<>(field, operate(((ArrayFieldVector<T>) v).getDataRef()), false);
  606.         }

  607.         final int nRows = getRowDimension();
  608.         final int nCols = getColumnDimension();
  609.         if (v.getDimension() != nCols) {
  610.             throw new DimensionMismatchException(v.getDimension(), nCols);
  611.         }

  612.         final T[] out = MathArrays.buildArray(field, nRows);
  613.         for (int row = 0; row < nRows; ++row) {
  614.             T sum = field.getZero();
  615.             for (int i = 0; i < nCols; ++i) {
  616.                 sum = sum.add(getEntry(row, i).multiply(v.getEntry(i)));
  617.             }
  618.             out[row] = sum;
  619.         }

  620.         return new ArrayFieldVector<>(field, out, false);
  621.     }

  622.     /** {@inheritDoc} */
  623.     @Override
  624.     public T[] preMultiply(final T[] v) throws DimensionMismatchException {

  625.         final int nRows = getRowDimension();
  626.         final int nCols = getColumnDimension();
  627.         if (v.length != nRows) {
  628.             throw new DimensionMismatchException(v.length, nRows);
  629.         }

  630.         final T[] out = MathArrays.buildArray(field, nCols);
  631.         for (int col = 0; col < nCols; ++col) {
  632.             T sum = field.getZero();
  633.             for (int i = 0; i < nRows; ++i) {
  634.                 sum = sum.add(getEntry(i, col).multiply(v[i]));
  635.             }
  636.             out[col] = sum;
  637.         }

  638.         return out;
  639.     }

  640.     /** {@inheritDoc} */
  641.     @Override
  642.     public FieldVector<T> preMultiply(final FieldVector<T> v)
  643.         throws DimensionMismatchException {
  644.         if (v instanceof ArrayFieldVector) {
  645.             return new ArrayFieldVector<>(field, preMultiply(((ArrayFieldVector<T>) v).getDataRef()), false);
  646.         }

  647.         final int nRows = getRowDimension();
  648.         final int nCols = getColumnDimension();
  649.         if (v.getDimension() != nRows) {
  650.             throw new DimensionMismatchException(v.getDimension(), nRows);
  651.         }

  652.         final T[] out = MathArrays.buildArray(field, nCols);
  653.         for (int col = 0; col < nCols; ++col) {
  654.             T sum = field.getZero();
  655.             for (int i = 0; i < nRows; ++i) {
  656.                 sum = sum.add(getEntry(i, col).multiply(v.getEntry(i)));
  657.             }
  658.             out[col] = sum;
  659.         }

  660.         return new ArrayFieldVector<>(field, out, false);
  661.     }

  662.     /** {@inheritDoc} */
  663.     @Override
  664.     public T walkInRowOrder(final FieldMatrixChangingVisitor<T> visitor) {
  665.         final int rows    = getRowDimension();
  666.         final int columns = getColumnDimension();
  667.         visitor.start(rows, columns, 0, rows - 1, 0, columns - 1);
  668.         for (int row = 0; row < rows; ++row) {
  669.             for (int column = 0; column < columns; ++column) {
  670.                 final T oldValue = getEntry(row, column);
  671.                 final T newValue = visitor.visit(row, column, oldValue);
  672.                 setEntry(row, column, newValue);
  673.             }
  674.         }
  675.         return visitor.end();
  676.     }

  677.     /** {@inheritDoc} */
  678.     @Override
  679.     public T walkInRowOrder(final FieldMatrixPreservingVisitor<T> visitor) {
  680.         final int rows    = getRowDimension();
  681.         final int columns = getColumnDimension();
  682.         visitor.start(rows, columns, 0, rows - 1, 0, columns - 1);
  683.         for (int row = 0; row < rows; ++row) {
  684.             for (int column = 0; column < columns; ++column) {
  685.                 visitor.visit(row, column, getEntry(row, column));
  686.             }
  687.         }
  688.         return visitor.end();
  689.     }

  690.     /** {@inheritDoc} */
  691.     @Override
  692.     public T walkInRowOrder(final FieldMatrixChangingVisitor<T> visitor,
  693.                             final int startRow, final int endRow,
  694.                             final int startColumn, final int endColumn)
  695.         throws NumberIsTooSmallException, OutOfRangeException {
  696.         checkSubMatrixIndex(startRow, endRow, startColumn, endColumn);
  697.         visitor.start(getRowDimension(), getColumnDimension(),
  698.                       startRow, endRow, startColumn, endColumn);
  699.         for (int row = startRow; row <= endRow; ++row) {
  700.             for (int column = startColumn; column <= endColumn; ++column) {
  701.                 final T oldValue = getEntry(row, column);
  702.                 final T newValue = visitor.visit(row, column, oldValue);
  703.                 setEntry(row, column, newValue);
  704.             }
  705.         }
  706.         return visitor.end();
  707.     }

  708.     /** {@inheritDoc} */
  709.     @Override
  710.     public T walkInRowOrder(final FieldMatrixPreservingVisitor<T> visitor,
  711.                             final int startRow, final int endRow,
  712.                             final int startColumn, final int endColumn)
  713.         throws NumberIsTooSmallException, OutOfRangeException {
  714.         checkSubMatrixIndex(startRow, endRow, startColumn, endColumn);
  715.         visitor.start(getRowDimension(), getColumnDimension(),
  716.                       startRow, endRow, startColumn, endColumn);
  717.         for (int row = startRow; row <= endRow; ++row) {
  718.             for (int column = startColumn; column <= endColumn; ++column) {
  719.                 visitor.visit(row, column, getEntry(row, column));
  720.             }
  721.         }
  722.         return visitor.end();
  723.     }

  724.     /** {@inheritDoc} */
  725.     @Override
  726.     public T walkInColumnOrder(final FieldMatrixChangingVisitor<T> visitor) {
  727.         final int rows    = getRowDimension();
  728.         final int columns = getColumnDimension();
  729.         visitor.start(rows, columns, 0, rows - 1, 0, columns - 1);
  730.         for (int column = 0; column < columns; ++column) {
  731.             for (int row = 0; row < rows; ++row) {
  732.                 final T oldValue = getEntry(row, column);
  733.                 final T newValue = visitor.visit(row, column, oldValue);
  734.                 setEntry(row, column, newValue);
  735.             }
  736.         }
  737.         return visitor.end();
  738.     }

  739.     /** {@inheritDoc} */
  740.     @Override
  741.     public T walkInColumnOrder(final FieldMatrixPreservingVisitor<T> visitor) {
  742.         final int rows    = getRowDimension();
  743.         final int columns = getColumnDimension();
  744.         visitor.start(rows, columns, 0, rows - 1, 0, columns - 1);
  745.         for (int column = 0; column < columns; ++column) {
  746.             for (int row = 0; row < rows; ++row) {
  747.                 visitor.visit(row, column, getEntry(row, column));
  748.             }
  749.         }
  750.         return visitor.end();
  751.     }

  752.     /** {@inheritDoc} */
  753.     @Override
  754.     public T walkInColumnOrder(final FieldMatrixChangingVisitor<T> visitor,
  755.                                final int startRow, final int endRow,
  756.                                final int startColumn, final int endColumn)
  757.     throws NumberIsTooSmallException, OutOfRangeException {
  758.         checkSubMatrixIndex(startRow, endRow, startColumn, endColumn);
  759.         visitor.start(getRowDimension(), getColumnDimension(),
  760.                       startRow, endRow, startColumn, endColumn);
  761.         for (int column = startColumn; column <= endColumn; ++column) {
  762.             for (int row = startRow; row <= endRow; ++row) {
  763.                 final T oldValue = getEntry(row, column);
  764.                 final T newValue = visitor.visit(row, column, oldValue);
  765.                 setEntry(row, column, newValue);
  766.             }
  767.         }
  768.         return visitor.end();
  769.     }

  770.     /** {@inheritDoc} */
  771.     @Override
  772.     public T walkInColumnOrder(final FieldMatrixPreservingVisitor<T> visitor,
  773.                                final int startRow, final int endRow,
  774.                                final int startColumn, final int endColumn)
  775.     throws NumberIsTooSmallException, OutOfRangeException{
  776.         checkSubMatrixIndex(startRow, endRow, startColumn, endColumn);
  777.         visitor.start(getRowDimension(), getColumnDimension(),
  778.                       startRow, endRow, startColumn, endColumn);
  779.         for (int column = startColumn; column <= endColumn; ++column) {
  780.             for (int row = startRow; row <= endRow; ++row) {
  781.                 visitor.visit(row, column, getEntry(row, column));
  782.             }
  783.         }
  784.         return visitor.end();
  785.     }

  786.     /** {@inheritDoc} */
  787.     @Override
  788.     public T walkInOptimizedOrder(final FieldMatrixChangingVisitor<T> visitor) {
  789.         return walkInRowOrder(visitor);
  790.     }

  791.     /** {@inheritDoc} */
  792.     @Override
  793.     public T walkInOptimizedOrder(final FieldMatrixPreservingVisitor<T> visitor) {
  794.         return walkInRowOrder(visitor);
  795.     }

  796.     /** {@inheritDoc} */
  797.     @Override
  798.     public T walkInOptimizedOrder(final FieldMatrixChangingVisitor<T> visitor,
  799.                                   final int startRow, final int endRow,
  800.                                   final int startColumn, final int endColumn)
  801.         throws NumberIsTooSmallException, OutOfRangeException {
  802.         return walkInRowOrder(visitor, startRow, endRow, startColumn, endColumn);
  803.     }

  804.     /** {@inheritDoc} */
  805.     @Override
  806.     public T walkInOptimizedOrder(final FieldMatrixPreservingVisitor<T> visitor,
  807.                                   final int startRow, final int endRow,
  808.                                   final int startColumn, final int endColumn)
  809.         throws NumberIsTooSmallException, OutOfRangeException {
  810.         return walkInRowOrder(visitor, startRow, endRow, startColumn, endColumn);
  811.     }

  812.     /**
  813.      * Get a string representation for this matrix.
  814.      * @return a string representation for this matrix
  815.      */
  816.     @Override
  817.     public String toString() {
  818.         final int nRows = getRowDimension();
  819.         final int nCols = getColumnDimension();
  820.         final StringBuffer res = new StringBuffer();
  821.         String fullClassName = getClass().getName();
  822.         String shortClassName = fullClassName.substring(fullClassName.lastIndexOf('.') + 1);
  823.         res.append(shortClassName).append("{");

  824.         for (int i = 0; i < nRows; ++i) {
  825.             if (i > 0) {
  826.                 res.append(",");
  827.             }
  828.             res.append("{");
  829.             for (int j = 0; j < nCols; ++j) {
  830.                 if (j > 0) {
  831.                     res.append(",");
  832.                 }
  833.                 res.append(getEntry(i, j));
  834.             }
  835.             res.append("}");
  836.         }

  837.         res.append("}");
  838.         return res.toString();
  839.     }

  840.     /**
  841.      * Returns true iff <code>object</code> is a
  842.      * <code>FieldMatrix</code> instance with the same dimensions as this
  843.      * and all corresponding matrix entries are equal.
  844.      *
  845.      * @param object the object to test equality against.
  846.      * @return true if object equals this
  847.      */
  848.     @Override
  849.     public boolean equals(final Object object) {
  850.         if (object == this ) {
  851.             return true;
  852.         }
  853.         if (!(object instanceof FieldMatrix<?>)) {
  854.             return false;
  855.         }
  856.         FieldMatrix<?> m = (FieldMatrix<?>) object;
  857.         final int nRows = getRowDimension();
  858.         final int nCols = getColumnDimension();
  859.         if (m.getColumnDimension() != nCols || m.getRowDimension() != nRows) {
  860.             return false;
  861.         }
  862.         for (int row = 0; row < nRows; ++row) {
  863.             for (int col = 0; col < nCols; ++col) {
  864.                 if (!getEntry(row, col).equals(m.getEntry(row, col))) {
  865.                     return false;
  866.                 }
  867.             }
  868.         }
  869.         return true;
  870.     }

  871.     /**
  872.      * Computes a hash code for the matrix.
  873.      *
  874.      * @return hash code for matrix
  875.      */
  876.     @Override
  877.     public int hashCode() {
  878.         int ret = 322562;
  879.         final int nRows = getRowDimension();
  880.         final int nCols = getColumnDimension();
  881.         ret = ret * 31 + nRows;
  882.         ret = ret * 31 + nCols;
  883.         for (int row = 0; row < nRows; ++row) {
  884.             for (int col = 0; col < nCols; ++col) {
  885.                ret = ret * 31 + (11 * (row+1) + 17 * (col+1)) * getEntry(row, col).hashCode();
  886.            }
  887.         }
  888.         return ret;
  889.     }

  890.     /**
  891.      * Check if a row index is valid.
  892.      *
  893.      * @param row Row index to check.
  894.      * @throws OutOfRangeException if {@code index} is not valid.
  895.      */
  896.     protected void checkRowIndex(final int row) throws OutOfRangeException {
  897.         if (row < 0 || row >= getRowDimension()) {
  898.             throw new OutOfRangeException(LocalizedFormats.ROW_INDEX,
  899.                                           row, 0, getRowDimension() - 1);
  900.         }
  901.     }

  902.     /**
  903.      * Check if a column index is valid.
  904.      *
  905.      * @param column Column index to check.
  906.      * @throws OutOfRangeException if {@code index} is not valid.
  907.      */
  908.     protected void checkColumnIndex(final int column)
  909.         throws OutOfRangeException {
  910.         if (column < 0 || column >= getColumnDimension()) {
  911.             throw new OutOfRangeException(LocalizedFormats.COLUMN_INDEX,
  912.                                           column, 0, getColumnDimension() - 1);
  913.         }
  914.     }

  915.     /**
  916.      * Check if submatrix ranges indices are valid.
  917.      * Rows and columns are indicated counting from 0 to n-1.
  918.      *
  919.      * @param startRow Initial row index.
  920.      * @param endRow Final row index.
  921.      * @param startColumn Initial column index.
  922.      * @param endColumn Final column index.
  923.      * @throws OutOfRangeException if the indices are not valid.
  924.      * @throws NumberIsTooSmallException if {@code endRow < startRow} or
  925.      * {@code endColumn < startColumn}.
  926.      */
  927.     protected void checkSubMatrixIndex(final int startRow, final int endRow,
  928.                                        final int startColumn, final int endColumn)
  929.         throws NumberIsTooSmallException, OutOfRangeException {
  930.         checkRowIndex(startRow);
  931.         checkRowIndex(endRow);
  932.         if (endRow < startRow) {
  933.             throw new NumberIsTooSmallException(LocalizedFormats.INITIAL_ROW_AFTER_FINAL_ROW,
  934.                                                 endRow, startRow, true);
  935.         }

  936.         checkColumnIndex(startColumn);
  937.         checkColumnIndex(endColumn);
  938.         if (endColumn < startColumn) {
  939.             throw new NumberIsTooSmallException(LocalizedFormats.INITIAL_COLUMN_AFTER_FINAL_COLUMN,
  940.                                                 endColumn, startColumn, true);
  941.         }
  942.     }

  943.     /**
  944.      * Check if submatrix ranges indices are valid.
  945.      * Rows and columns are indicated counting from 0 to n-1.
  946.      *
  947.      * @param selectedRows Array of row indices.
  948.      * @param selectedColumns Array of column indices.
  949.      * @throws NullArgumentException if the arrays are {@code null}.
  950.      * @throws NoDataException if the arrays have zero length.
  951.      * @throws OutOfRangeException if row or column selections are not valid.
  952.      */
  953.     protected void checkSubMatrixIndex(final int[] selectedRows, final int[] selectedColumns)
  954.         throws NoDataException, NullArgumentException, OutOfRangeException {
  955.         if (selectedRows == null ||
  956.             selectedColumns == null) {
  957.             throw new NullArgumentException();
  958.         }
  959.         if (selectedRows.length == 0 ||
  960.             selectedColumns.length == 0) {
  961.             throw new NoDataException();
  962.         }

  963.         for (final int row : selectedRows) {
  964.             checkRowIndex(row);
  965.         }
  966.         for (final int column : selectedColumns) {
  967.             checkColumnIndex(column);
  968.         }
  969.     }
  970. }