/// <summary>
 /// Check if a matrix is multiplication compatible with the instance.
 /// </summary>
 /// <param name="m">Matrix to check.</param>
 /// <exception cref="DimensionMismatchException"> if the matrix is not
 /// multiplication-compatible with instance.</exception>
 protected void checkMultiplicationCompatible(FieldMatrix <T> m)
 {
     if (getColumnDimension() != m.getRowDimension())
     {
         throw new DimensionMismatchException(m.getRowDimension(), getColumnDimension());
     }
 }
 /// <summary>
 /// Check if a matrix is subtraction compatible with the instance.
 /// </summary>
 /// <param name="m">Matrix to check.</param>
 /// <exception cref="MatrixDimensionMismatchExceptio">n if the matrix is not
 /// subtraction-compatible with instance.</exception>
 protected void checkSubtractionCompatible(FieldMatrix <T> m)
 {
     if ((getRowDimension() != m.getRowDimension()) ||
         (getColumnDimension() != m.getColumnDimension()))
     {
         throw new MatrixDimensionMismatchException(m.getRowDimension(), m.getColumnDimension(),
                                                    getRowDimension(), getColumnDimension());
     }
 }
        /// <summary>
        /// Returns true iff <c>object</c> is a
        /// <c>FieldMatrix</c> instance with the same dimensions as this
        /// and all corresponding matrix entries are equal.
        /// </summary>
        /// <param name="obj">the object to test equality against.</param>
        /// <returns>true if object equals this</returns>
        public override Boolean Equals(Object obj)
        {
            if (obj == this)
            {
                return(true);
            }
            if (obj is FieldMatrix <T> )
            {
                return(false);
            }
            FieldMatrix <T> m     = (FieldMatrix <T>)obj;
            int             nRows = getRowDimension();
            int             nCols = getColumnDimension();

            if (m.getColumnDimension() != nCols || m.getRowDimension() != nRows)
            {
                return(false);
            }
            for (int row = 0; row < nRows; ++row)
            {
                for (int col = 0; col < nCols; ++col)
                {
                    if (!getEntry(row, col).Equals(m.getEntry(row, col)))
                    {
                        return(false);
                    }
                }
            }
            return(true);
        }
        /// <inheritdoc/>
        public void setColumnMatrix(int column, FieldMatrix <T> matrix)
        {
            checkColumnIndex(column);
            int nRows = getRowDimension();

            if ((matrix.getRowDimension() != nRows) ||
                (matrix.getColumnDimension() != 1))
            {
                throw new MatrixDimensionMismatchException(matrix.getRowDimension(),
                                                           matrix.getColumnDimension(),
                                                           nRows, 1);
            }
            for (int i = 0; i < nRows; ++i)
            {
                setEntry(i, column, matrix.getEntry(i, 0));
            }
        }
        /// <inheritdoc/>
        public void setRowMatrix(int row, FieldMatrix <T> matrix)
        {
            checkRowIndex(row);
            int nCols = getColumnDimension();

            if ((matrix.getRowDimension() != 1) ||
                (matrix.getColumnDimension() != nCols))
            {
                throw new MatrixDimensionMismatchException(matrix.getRowDimension(),
                                                           matrix.getColumnDimension(),
                                                           1, nCols);
            }
            for (int i = 0; i < nCols; ++i)
            {
                setEntry(row, i, matrix.getEntry(0, i));
            }
        }
        /// <summary>
        /// Calculates the LU-decomposition of the given matrix.
        /// </summary>
        /// <param name="matrix">The matrix to decompose.</param>
        /// <exception cref="NonSquareMatrixException"> if matrix is not square</exception>
        public FieldLUDecomposition(FieldMatrix <T> matrix)
        {
            if (!matrix.isSquare())
            {
                throw new NonSquareMatrixException(matrix.getRowDimension(), matrix.getColumnDimension());
            }

            int m = matrix.getColumnDimension();

            field   = matrix.getField();
            lu      = matrix.getData();
            pivot   = new int[m];
            cachedL = null;
            cachedU = null;
            cachedP = null;

            // Initialize permutation array and parity
            for (int row = 0; row < m; row++)
            {
                pivot[row] = row;
            }
            even     = true;
            singular = false;

            // Loop over columns
            for (int col = 0; col < m; col++)
            {
                T sum = field.getZero();

                // upper
                for (int row = 0; row < col; row++)
                {
                    T[] luRow = lu[row];
                    sum = luRow[col];
                    for (int i = 0; i < row; i++)
                    {
                        sum = sum.subtract(luRow[i].multiply(lu[i][col]));
                    }
                    luRow[col] = sum;
                }

                // lower
                int nonZero = col; // permutation row
                for (int row = col; row < m; row++)
                {
                    T[] luRow = lu[row];
                    sum = luRow[col];
                    for (int i = 0; i < col; i++)
                    {
                        sum = sum.subtract(luRow[i].multiply(lu[i][col]));
                    }
                    luRow[col] = sum;

                    if (lu[nonZero][col].Equals(field.getZero()))
                    {
                        // try to select a better permutation choice
                        ++nonZero;
                    }
                }

                // Singularity check
                if (nonZero >= m)
                {
                    singular = true;
                    return;
                }

                // Pivot if necessary
                if (nonZero != col)
                {
                    T tmp = field.getZero();
                    for (int i = 0; i < m; i++)
                    {
                        tmp            = lu[nonZero][i];
                        lu[nonZero][i] = lu[col][i];
                        lu[col][i]     = tmp;
                    }
                    int temp = pivot[nonZero];
                    pivot[nonZero] = pivot[col];
                    pivot[col]     = temp;
                    even           = !even;
                }

                // Divide the lower elements by the "winning" diagonal elt.
                T luDiag = lu[col][col];
                for (int row = col + 1; row < m; row++)
                {
                    T[] luRow = lu[row];
                    luRow[col] = luRow[col].divide(luDiag);
                }
            }
        }
            /// <inheritdoc/>
            public FieldMatrix <U> solve(FieldMatrix <U> b)
            {
                int m = pivot.Length;

                if (b.getRowDimension() != m)
                {
                    throw new DimensionMismatchException(b.getRowDimension(), m);
                }
                if (singular)
                {
                    throw new SingularMatrixException();
                }

                int nColB = b.getColumnDimension();

                // Apply permutations to b
                U[][] bp = MathArrays.buildArray(field, m, nColB);
                for (int row = 0; row < m; row++)
                {
                    U[] bpRow = bp[row];
                    int pRow  = pivot[row];
                    for (int col = 0; col < nColB; col++)
                    {
                        bpRow[col] = b.getEntry(pRow, col);
                    }
                }

                // Solve LY = b
                for (int col = 0; col < m; col++)
                {
                    U[] bpCol = bp[col];
                    for (int i = col + 1; i < m; i++)
                    {
                        U[] bpI    = bp[i];
                        U   luICol = lu[i][col];
                        for (int j = 0; j < nColB; j++)
                        {
                            bpI[j] = bpI[j].subtract(bpCol[j].multiply(luICol));
                        }
                    }
                }

                // Solve UX = Y
                for (int col = m - 1; col >= 0; col--)
                {
                    U[] bpCol  = bp[col];
                    U   luDiag = lu[col][col];
                    for (int j = 0; j < nColB; j++)
                    {
                        bpCol[j] = bpCol[j].divide(luDiag);
                    }
                    for (int i = 0; i < col; i++)
                    {
                        U[] bpI    = bp[i];
                        U   luICol = lu[i][col];
                        for (int j = 0; j < nColB; j++)
                        {
                            bpI[j] = bpI[j].subtract(bpCol[j].multiply(luICol));
                        }
                    }
                }

                return(new Array2DRowFieldMatrix <U>(field, bp, false));
            }