001    /*
002     * Licensed to the Apache Software Foundation (ASF) under one or more
003     * contributor license agreements.  See the NOTICE file distributed with
004     * this work for additional information regarding copyright ownership.
005     * The ASF licenses this file to You under the Apache License, Version 2.0
006     * (the "License"); you may not use this file except in compliance with
007     * the License.  You may obtain a copy of the License at
008     *
009     *      http://www.apache.org/licenses/LICENSE-2.0
010     *
011     * Unless required by applicable law or agreed to in writing, software
012     * distributed under the License is distributed on an "AS IS" BASIS,
013     * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
014     * See the License for the specific language governing permissions and
015     * limitations under the License.
016     */
017    
018    package org.apache.commons.math.linear;
019    
020    import java.lang.reflect.Array;
021    import java.util.ArrayList;
022    import java.util.Arrays;
023    
024    import org.apache.commons.math.Field;
025    import org.apache.commons.math.FieldElement;
026    import org.apache.commons.math.exception.DimensionMismatchException;
027    import org.apache.commons.math.exception.NoDataException;
028    import org.apache.commons.math.exception.OutOfRangeException;
029    import org.apache.commons.math.exception.NumberIsTooSmallException;
030    import org.apache.commons.math.exception.NotStrictlyPositiveException;
031    import org.apache.commons.math.exception.NullArgumentException;
032    import org.apache.commons.math.exception.util.LocalizedFormats;
033    
034    /**
035     * Basic implementation of {@link FieldMatrix} methods regardless of the underlying storage.
036     * <p>All the methods implemented here use {@link #getEntry(int, int)} to access
037     * matrix elements. Derived class can provide faster implementations. </p>
038     *
039     * @param <T> Type of the field elements.
040     *
041     * @version $Id: AbstractFieldMatrix.java 1178009 2011-10-01 15:15:00Z luc $
042     * @since 2.0
043     */
044    public abstract class AbstractFieldMatrix<T extends FieldElement<T>>
045        implements FieldMatrix<T> {
046        /** Field to which the elements belong. */
047        private final Field<T> field;
048    
049        /**
050         * Constructor for use with Serializable
051         */
052        protected AbstractFieldMatrix() {
053            field = null;
054        }
055    
056        /**
057         * Creates a matrix with no data
058         * @param field field to which the elements belong
059         */
060        protected AbstractFieldMatrix(final Field<T> field) {
061            this.field = field;
062        }
063    
064        /**
065         * Create a new FieldMatrix<T> with the supplied row and column dimensions.
066         *
067         * @param field Field to which the elements belong.
068         * @param rowDimension Number of rows in the new matrix.
069         * @param columnDimension Number of columns in the new matrix.
070         * @throws NotStrictlyPositiveException if row or column dimension is not
071         * positive.
072         */
073        protected AbstractFieldMatrix(final Field<T> field,
074                                      final int rowDimension,
075                                      final int columnDimension) {
076            if (rowDimension <= 0) {
077                throw new NotStrictlyPositiveException(LocalizedFormats.DIMENSION,
078                                                       rowDimension);
079            }
080            if (columnDimension <= 0) {
081                throw new NotStrictlyPositiveException(LocalizedFormats.DIMENSION,
082                                                       columnDimension);
083            }
084            this.field = field;
085        }
086    
087        /**
088         * Get the elements type from an array.
089         *
090         * @param <T> Type of the field elements.
091         * @param d Data array.
092         * @return the field to which the array elements belong.
093         * @throws NullArgumentException if the array is {@code null}.
094         * @throws NoDataException if the array is empty.
095         */
096        protected static <T extends FieldElement<T>> Field<T> extractField(final T[][] d) {
097            if (d == null) {
098                throw new NullArgumentException();
099            }
100            if (d.length == 0) {
101                throw new NoDataException(LocalizedFormats.AT_LEAST_ONE_ROW);
102            }
103            if (d[0].length == 0) {
104                throw new NoDataException(LocalizedFormats.AT_LEAST_ONE_COLUMN);
105            }
106            return d[0][0].getField();
107        }
108    
109        /**
110         * Get the elements type from an array.
111         *
112         * @param <T> Type of the field elements.
113         * @param d Data array.
114         * @return the field to which the array elements belong.
115         * @throws NoDataException if array is empty.
116         */
117        protected static <T extends FieldElement<T>> Field<T> extractField(final T[] d) {
118            if (d.length == 0) {
119                throw new NoDataException(LocalizedFormats.AT_LEAST_ONE_ROW);
120            }
121            return d[0].getField();
122        }
123    
124        /** Build an array of elements.
125         * <p>
126         * Complete arrays are filled with field.getZero()
127         * </p>
128         * @param <T> Type of the field elements
129         * @param field field to which array elements belong
130         * @param rows number of rows
131         * @param columns number of columns (may be negative to build partial
132         * arrays in the same way <code>new Field[rows][]</code> works)
133         * @return a new array
134         */
135        @SuppressWarnings("unchecked")
136        protected static <T extends FieldElement<T>> T[][] buildArray(final Field<T> field,
137                                                                      final int rows,
138                                                                      final int columns) {
139            if (columns < 0) {
140                T[] dummyRow = (T[]) Array.newInstance(field.getRuntimeClass(), 0);
141                return (T[][]) Array.newInstance(dummyRow.getClass(), rows);
142            }
143            T[][] array =
144                (T[][]) Array.newInstance(field.getRuntimeClass(), new int[] { rows, columns });
145            for (int i = 0; i < array.length; ++i) {
146                Arrays.fill(array[i], field.getZero());
147            }
148            return array;
149        }
150    
151        /** Build an array of elements.
152         * <p>
153         * Arrays are filled with field.getZero()
154         * </p>
155         * @param <T> the type of the field elements
156         * @param field field to which array elements belong
157         * @param length of the array
158         * @return a new array
159         */
160        protected static <T extends FieldElement<T>> T[] buildArray(final Field<T> field,
161                                                                    final int length) {
162            @SuppressWarnings("unchecked") // OK because field must be correct class
163            T[] array = (T[]) Array.newInstance(field.getRuntimeClass(), length);
164            Arrays.fill(array, field.getZero());
165            return array;
166        }
167    
168        /** {@inheritDoc} */
169        public Field<T> getField() {
170            return field;
171        }
172    
173        /** {@inheritDoc} */
174        public abstract FieldMatrix<T> createMatrix(final int rowDimension, final int columnDimension);
175    
176        /** {@inheritDoc} */
177        public abstract FieldMatrix<T> copy();
178    
179        /** {@inheritDoc} */
180        public FieldMatrix<T> add(FieldMatrix<T> m) {
181            // safety check
182            checkAdditionCompatible(m);
183    
184            final int rowCount    = getRowDimension();
185            final int columnCount = getColumnDimension();
186            final FieldMatrix<T> out = createMatrix(rowCount, columnCount);
187            for (int row = 0; row < rowCount; ++row) {
188                for (int col = 0; col < columnCount; ++col) {
189                    out.setEntry(row, col, getEntry(row, col).add(m.getEntry(row, col)));
190                }
191            }
192    
193            return out;
194        }
195    
196        /** {@inheritDoc} */
197        public FieldMatrix<T> subtract(final FieldMatrix<T> m) {
198            // safety check
199            checkSubtractionCompatible(m);
200    
201            final int rowCount    = getRowDimension();
202            final int columnCount = getColumnDimension();
203            final FieldMatrix<T> out = createMatrix(rowCount, columnCount);
204            for (int row = 0; row < rowCount; ++row) {
205                for (int col = 0; col < columnCount; ++col) {
206                    out.setEntry(row, col, getEntry(row, col).subtract(m.getEntry(row, col)));
207                }
208            }
209    
210            return out;
211        }
212    
213        /** {@inheritDoc} */
214        public FieldMatrix<T> scalarAdd(final T d) {
215    
216            final int rowCount    = getRowDimension();
217            final int columnCount = getColumnDimension();
218            final FieldMatrix<T> out = createMatrix(rowCount, columnCount);
219            for (int row = 0; row < rowCount; ++row) {
220                for (int col = 0; col < columnCount; ++col) {
221                    out.setEntry(row, col, getEntry(row, col).add(d));
222                }
223            }
224    
225            return out;
226        }
227    
228        /** {@inheritDoc} */
229        public FieldMatrix<T> scalarMultiply(final T d) {
230            final int rowCount    = getRowDimension();
231            final int columnCount = getColumnDimension();
232            final FieldMatrix<T> out = createMatrix(rowCount, columnCount);
233            for (int row = 0; row < rowCount; ++row) {
234                for (int col = 0; col < columnCount; ++col) {
235                    out.setEntry(row, col, getEntry(row, col).multiply(d));
236                }
237            }
238    
239            return out;
240        }
241    
242        /** {@inheritDoc} */
243        public FieldMatrix<T> multiply(final FieldMatrix<T> m) {
244            // safety check
245            checkMultiplicationCompatible(m);
246    
247            final int nRows = getRowDimension();
248            final int nCols = m.getColumnDimension();
249            final int nSum  = getColumnDimension();
250            final FieldMatrix<T> out = createMatrix(nRows, nCols);
251            for (int row = 0; row < nRows; ++row) {
252                for (int col = 0; col < nCols; ++col) {
253                    T sum = field.getZero();
254                    for (int i = 0; i < nSum; ++i) {
255                        sum = sum.add(getEntry(row, i).multiply(m.getEntry(i, col)));
256                    }
257                    out.setEntry(row, col, sum);
258                }
259            }
260    
261            return out;
262        }
263    
264        /** {@inheritDoc} */
265        public FieldMatrix<T> preMultiply(final FieldMatrix<T> m) {
266            return m.multiply(this);
267        }
268    
269        /** {@inheritDoc} */
270        public FieldMatrix<T> power(final int p) {
271            if (p < 0) {
272                throw new IllegalArgumentException("p must be >= 0");
273            }
274    
275            if (!isSquare()) {
276                throw new NonSquareMatrixException(getRowDimension(), getColumnDimension());
277            }
278    
279            if (p == 0) {
280                return MatrixUtils.createFieldIdentityMatrix(this.getField(), this.getRowDimension());
281            }
282    
283            if (p == 1) {
284                return this.copy();
285            }
286    
287            final int power = p - 1;
288    
289            /*
290             * Only log_2(p) operations is used by doing as follows:
291             * 5^214 = 5^128 * 5^64 * 5^16 * 5^4 * 5^2
292             *
293             * In general, the same approach is used for A^p.
294             */
295    
296            final char[] binaryRepresentation = Integer.toBinaryString(power)
297                    .toCharArray();
298            final ArrayList<Integer> nonZeroPositions = new ArrayList<Integer>();
299    
300            for (int i = 0; i < binaryRepresentation.length; ++i) {
301                if (binaryRepresentation[i] == '1') {
302                    final int pos = binaryRepresentation.length - i - 1;
303                    nonZeroPositions.add(pos);
304                }
305            }
306    
307            ArrayList<FieldMatrix<T>> results = new ArrayList<FieldMatrix<T>>(
308                    binaryRepresentation.length);
309    
310            results.add(0, this.copy());
311    
312            for (int i = 1; i < binaryRepresentation.length; ++i) {
313                final FieldMatrix<T> s = results.get(i - 1);
314                final FieldMatrix<T> r = s.multiply(s);
315                results.add(i, r);
316            }
317    
318            FieldMatrix<T> result = this.copy();
319    
320            for (Integer i : nonZeroPositions) {
321                result = result.multiply(results.get(i));
322            }
323    
324            return result;
325        }
326    
327        /** {@inheritDoc} */
328        public T[][] getData() {
329            final T[][] data = buildArray(field, getRowDimension(), getColumnDimension());
330    
331            for (int i = 0; i < data.length; ++i) {
332                final T[] dataI = data[i];
333                for (int j = 0; j < dataI.length; ++j) {
334                    dataI[j] = getEntry(i, j);
335                }
336            }
337    
338            return data;
339        }
340    
341        /** {@inheritDoc} */
342        public FieldMatrix<T> getSubMatrix(final int startRow, final int endRow,
343                                           final int startColumn, final int endColumn) {
344            checkSubMatrixIndex(startRow, endRow, startColumn, endColumn);
345    
346            final FieldMatrix<T> subMatrix =
347                createMatrix(endRow - startRow + 1, endColumn - startColumn + 1);
348            for (int i = startRow; i <= endRow; ++i) {
349                for (int j = startColumn; j <= endColumn; ++j) {
350                    subMatrix.setEntry(i - startRow, j - startColumn, getEntry(i, j));
351                }
352            }
353    
354            return subMatrix;
355    
356        }
357    
358        /** {@inheritDoc} */
359        public FieldMatrix<T> getSubMatrix(final int[] selectedRows,
360                                           final int[] selectedColumns) {
361    
362            // safety checks
363            checkSubMatrixIndex(selectedRows, selectedColumns);
364    
365            // copy entries
366            final FieldMatrix<T> subMatrix =
367                createMatrix(selectedRows.length, selectedColumns.length);
368            subMatrix.walkInOptimizedOrder(new DefaultFieldMatrixChangingVisitor<T>(field.getZero()) {
369    
370                /** {@inheritDoc} */
371                @Override
372                public T visit(final int row, final int column, final T value) {
373                    return getEntry(selectedRows[row], selectedColumns[column]);
374                }
375    
376            });
377    
378            return subMatrix;
379    
380        }
381    
382        /** {@inheritDoc} */
383        public void copySubMatrix(final int startRow, final int endRow,
384                                  final int startColumn, final int endColumn,
385                                  final T[][] destination) {
386            // safety checks
387            checkSubMatrixIndex(startRow, endRow, startColumn, endColumn);
388            final int rowsCount    = endRow + 1 - startRow;
389            final int columnsCount = endColumn + 1 - startColumn;
390            if ((destination.length < rowsCount) || (destination[0].length < columnsCount)) {
391                throw new MatrixDimensionMismatchException(destination.length,
392                                                           destination[0].length,
393                                                           rowsCount,
394                                                           columnsCount);
395            }
396    
397            // copy entries
398            walkInOptimizedOrder(new DefaultFieldMatrixPreservingVisitor<T>(field.getZero()) {
399    
400                /** Initial row index. */
401                private int startRow;
402    
403                /** Initial column index. */
404                private int startColumn;
405    
406                /** {@inheritDoc} */
407                @Override
408                public void start(final int rows, final int columns,
409                                  final int startRow, final int endRow,
410                                  final int startColumn, final int endColumn) {
411                    this.startRow    = startRow;
412                    this.startColumn = startColumn;
413                }
414    
415                /** {@inheritDoc} */
416                @Override
417                public void visit(final int row, final int column, final T value) {
418                    destination[row - startRow][column - startColumn] = value;
419                }
420    
421            }, startRow, endRow, startColumn, endColumn);
422    
423        }
424    
425        /** {@inheritDoc} */
426        public void copySubMatrix(int[] selectedRows, int[] selectedColumns, T[][] destination) {
427            // safety checks
428            checkSubMatrixIndex(selectedRows, selectedColumns);
429            if ((destination.length < selectedRows.length) ||
430                (destination[0].length < selectedColumns.length)) {
431                throw new MatrixDimensionMismatchException(destination.length,
432                                                           destination[0].length,
433                                                           selectedRows.length,
434                                                           selectedColumns.length);
435            }
436    
437            // copy entries
438            for (int i = 0; i < selectedRows.length; i++) {
439                final T[] destinationI = destination[i];
440                for (int j = 0; j < selectedColumns.length; j++) {
441                    destinationI[j] = getEntry(selectedRows[i], selectedColumns[j]);
442                }
443            }
444    
445        }
446    
447        /** {@inheritDoc} */
448        public void setSubMatrix(final T[][] subMatrix, final int row, final int column) {
449            if (subMatrix == null) {
450                throw new NullArgumentException();
451            }
452            final int nRows = subMatrix.length;
453            if (nRows == 0) {
454                throw new NoDataException(LocalizedFormats.AT_LEAST_ONE_ROW);
455            }
456    
457            final int nCols = subMatrix[0].length;
458            if (nCols == 0) {
459                throw new NoDataException(LocalizedFormats.AT_LEAST_ONE_COLUMN);
460            }
461    
462            for (int r = 1; r < nRows; ++r) {
463                if (subMatrix[r].length != nCols) {
464                    throw new DimensionMismatchException(nCols, subMatrix[r].length);
465                }
466            }
467    
468            checkRowIndex(row);
469            checkColumnIndex(column);
470            checkRowIndex(nRows + row - 1);
471            checkColumnIndex(nCols + column - 1);
472    
473            for (int i = 0; i < nRows; ++i) {
474                for (int j = 0; j < nCols; ++j) {
475                    setEntry(row + i, column + j, subMatrix[i][j]);
476                }
477            }
478        }
479    
480        /** {@inheritDoc} */
481        public FieldMatrix<T> getRowMatrix(final int row) {
482            checkRowIndex(row);
483            final int nCols = getColumnDimension();
484            final FieldMatrix<T> out = createMatrix(1, nCols);
485            for (int i = 0; i < nCols; ++i) {
486                out.setEntry(0, i, getEntry(row, i));
487            }
488    
489            return out;
490    
491        }
492    
493        /** {@inheritDoc} */
494        public void setRowMatrix(final int row, final FieldMatrix<T> matrix) {
495            checkRowIndex(row);
496            final int nCols = getColumnDimension();
497            if ((matrix.getRowDimension() != 1) ||
498                (matrix.getColumnDimension() != nCols)) {
499                throw new MatrixDimensionMismatchException(matrix.getRowDimension(),
500                                                           matrix.getColumnDimension(),
501                                                           1, nCols);
502            }
503            for (int i = 0; i < nCols; ++i) {
504                setEntry(row, i, matrix.getEntry(0, i));
505            }
506    
507        }
508    
509        /** {@inheritDoc} */
510        public FieldMatrix<T> getColumnMatrix(final int column) {
511    
512            checkColumnIndex(column);
513            final int nRows = getRowDimension();
514            final FieldMatrix<T> out = createMatrix(nRows, 1);
515            for (int i = 0; i < nRows; ++i) {
516                out.setEntry(i, 0, getEntry(i, column));
517            }
518    
519            return out;
520    
521        }
522    
523        /** {@inheritDoc} */
524        public void setColumnMatrix(final int column, final FieldMatrix<T> matrix) {
525            checkColumnIndex(column);
526            final int nRows = getRowDimension();
527            if ((matrix.getRowDimension() != nRows) ||
528                (matrix.getColumnDimension() != 1)) {
529                throw new MatrixDimensionMismatchException(matrix.getRowDimension(),
530                                                           matrix.getColumnDimension(),
531                                                           nRows, 1);
532            }
533            for (int i = 0; i < nRows; ++i) {
534                setEntry(i, column, matrix.getEntry(i, 0));
535            }
536    
537        }
538    
539        /** {@inheritDoc} */
540        public FieldVector<T> getRowVector(final int row) {
541            return new ArrayFieldVector<T>(field, getRow(row), false);
542        }
543    
544        /** {@inheritDoc} */
545        public void setRowVector(final int row, final FieldVector<T> vector) {
546            checkRowIndex(row);
547            final int nCols = getColumnDimension();
548            if (vector.getDimension() != nCols) {
549                throw new MatrixDimensionMismatchException(1, vector.getDimension(),
550                                                           1, nCols);
551            }
552            for (int i = 0; i < nCols; ++i) {
553                setEntry(row, i, vector.getEntry(i));
554            }
555    
556        }
557    
558        /** {@inheritDoc} */
559        public FieldVector<T> getColumnVector(final int column) {
560            return new ArrayFieldVector<T>(field, getColumn(column), false);
561        }
562    
563        /** {@inheritDoc} */
564        public void setColumnVector(final int column, final FieldVector<T> vector) {
565            checkColumnIndex(column);
566            final int nRows = getRowDimension();
567            if (vector.getDimension() != nRows) {
568                throw new MatrixDimensionMismatchException(vector.getDimension(), 1,
569                                                           nRows, 1);
570            }
571            for (int i = 0; i < nRows; ++i) {
572                setEntry(i, column, vector.getEntry(i));
573            }
574    
575        }
576    
577        /** {@inheritDoc} */
578        public T[] getRow(final int row) {
579            checkRowIndex(row);
580            final int nCols = getColumnDimension();
581            final T[] out = buildArray(field, nCols);
582            for (int i = 0; i < nCols; ++i) {
583                out[i] = getEntry(row, i);
584            }
585    
586            return out;
587    
588        }
589    
590        /** {@inheritDoc} */
591        public void setRow(final int row, final T[] array) {
592            checkRowIndex(row);
593            final int nCols = getColumnDimension();
594            if (array.length != nCols) {
595                throw new MatrixDimensionMismatchException(1, array.length, 1, nCols);
596            }
597            for (int i = 0; i < nCols; ++i) {
598                setEntry(row, i, array[i]);
599            }
600    
601        }
602    
603        /** {@inheritDoc} */
604        public T[] getColumn(final int column) {
605            checkColumnIndex(column);
606            final int nRows = getRowDimension();
607            final T[] out = buildArray(field, nRows);
608            for (int i = 0; i < nRows; ++i) {
609                out[i] = getEntry(i, column);
610            }
611    
612            return out;
613    
614        }
615    
616        /** {@inheritDoc} */
617        public void setColumn(final int column, final T[] array) {
618            checkColumnIndex(column);
619            final int nRows = getRowDimension();
620            if (array.length != nRows) {
621                throw new MatrixDimensionMismatchException(array.length, 1, nRows, 1);
622            }
623            for (int i = 0; i < nRows; ++i) {
624                setEntry(i, column, array[i]);
625            }
626        }
627    
628        /** {@inheritDoc} */
629        public abstract T getEntry(int row, int column);
630    
631        /** {@inheritDoc} */
632        public abstract void setEntry(int row, int column, T value);
633    
634        /** {@inheritDoc} */
635        public abstract void addToEntry(int row, int column, T increment);
636    
637        /** {@inheritDoc} */
638        public abstract void multiplyEntry(int row, int column, T factor);
639    
640        /** {@inheritDoc} */
641        public FieldMatrix<T> transpose() {
642            final int nRows = getRowDimension();
643            final int nCols = getColumnDimension();
644            final FieldMatrix<T> out = createMatrix(nCols, nRows);
645            walkInOptimizedOrder(new DefaultFieldMatrixPreservingVisitor<T>(field.getZero()) {
646                /** {@inheritDoc} */
647                @Override
648                public void visit(final int row, final int column, final T value) {
649                    out.setEntry(column, row, value);
650                }
651            });
652    
653            return out;
654        }
655    
656        /** {@inheritDoc} */
657        public boolean isSquare() {
658            return getColumnDimension() == getRowDimension();
659        }
660    
661        /** {@inheritDoc} */
662        public abstract int getRowDimension();
663    
664        /** {@inheritDoc} */
665        public abstract int getColumnDimension();
666    
667        /** {@inheritDoc} */
668        public T getTrace() {
669            final int nRows = getRowDimension();
670            final int nCols = getColumnDimension();
671            if (nRows != nCols) {
672                throw new NonSquareMatrixException(nRows, nCols);
673           }
674            T trace = field.getZero();
675            for (int i = 0; i < nRows; ++i) {
676                trace = trace.add(getEntry(i, i));
677            }
678            return trace;
679        }
680    
681        /** {@inheritDoc} */
682        public T[] operate(final T[] v) {
683    
684            final int nRows = getRowDimension();
685            final int nCols = getColumnDimension();
686            if (v.length != nCols) {
687                throw new DimensionMismatchException(v.length, nCols);
688            }
689    
690            final T[] out = buildArray(field, nRows);
691            for (int row = 0; row < nRows; ++row) {
692                T sum = field.getZero();
693                for (int i = 0; i < nCols; ++i) {
694                    sum = sum.add(getEntry(row, i).multiply(v[i]));
695                }
696                out[row] = sum;
697            }
698    
699            return out;
700        }
701    
702        /** {@inheritDoc} */
703        public FieldVector<T> operate(final FieldVector<T> v) {
704            try {
705                return new ArrayFieldVector<T>(field, operate(((ArrayFieldVector<T>) v).getDataRef()), false);
706            } catch (ClassCastException cce) {
707                final int nRows = getRowDimension();
708                final int nCols = getColumnDimension();
709                if (v.getDimension() != nCols) {
710                    throw new DimensionMismatchException(v.getDimension(), nCols);
711                }
712    
713                final T[] out = buildArray(field, nRows);
714                for (int row = 0; row < nRows; ++row) {
715                    T sum = field.getZero();
716                    for (int i = 0; i < nCols; ++i) {
717                        sum = sum.add(getEntry(row, i).multiply(v.getEntry(i)));
718                    }
719                    out[row] = sum;
720                }
721    
722                return new ArrayFieldVector<T>(field, out, false);
723            }
724        }
725    
726        /** {@inheritDoc} */
727        public T[] preMultiply(final T[] v) {
728    
729            final int nRows = getRowDimension();
730            final int nCols = getColumnDimension();
731            if (v.length != nRows) {
732                throw new DimensionMismatchException(v.length, nRows);
733            }
734    
735            final T[] out = buildArray(field, nCols);
736            for (int col = 0; col < nCols; ++col) {
737                T sum = field.getZero();
738                for (int i = 0; i < nRows; ++i) {
739                    sum = sum.add(getEntry(i, col).multiply(v[i]));
740                }
741                out[col] = sum;
742            }
743    
744            return out;
745        }
746    
747        /** {@inheritDoc} */
748        public FieldVector<T> preMultiply(final FieldVector<T> v) {
749            try {
750                return new ArrayFieldVector<T>(field, preMultiply(((ArrayFieldVector<T>) v).getDataRef()), false);
751            } catch (ClassCastException cce) {
752                final int nRows = getRowDimension();
753                final int nCols = getColumnDimension();
754                if (v.getDimension() != nRows) {
755                    throw new DimensionMismatchException(v.getDimension(), nRows);
756                }
757    
758                final T[] out = buildArray(field, nCols);
759                for (int col = 0; col < nCols; ++col) {
760                    T sum = field.getZero();
761                    for (int i = 0; i < nRows; ++i) {
762                        sum = sum.add(getEntry(i, col).multiply(v.getEntry(i)));
763                    }
764                    out[col] = sum;
765                }
766    
767                return new ArrayFieldVector<T>(field, out, false);
768            }
769        }
770    
771        /** {@inheritDoc} */
772        public T walkInRowOrder(final FieldMatrixChangingVisitor<T> visitor) {
773            final int rows    = getRowDimension();
774            final int columns = getColumnDimension();
775            visitor.start(rows, columns, 0, rows - 1, 0, columns - 1);
776            for (int row = 0; row < rows; ++row) {
777                for (int column = 0; column < columns; ++column) {
778                    final T oldValue = getEntry(row, column);
779                    final T newValue = visitor.visit(row, column, oldValue);
780                    setEntry(row, column, newValue);
781                }
782            }
783            return visitor.end();
784        }
785    
786        /** {@inheritDoc} */
787        public T walkInRowOrder(final FieldMatrixPreservingVisitor<T> visitor) {
788            final int rows    = getRowDimension();
789            final int columns = getColumnDimension();
790            visitor.start(rows, columns, 0, rows - 1, 0, columns - 1);
791            for (int row = 0; row < rows; ++row) {
792                for (int column = 0; column < columns; ++column) {
793                    visitor.visit(row, column, getEntry(row, column));
794                }
795            }
796            return visitor.end();
797        }
798    
799        /** {@inheritDoc} */
800        public T walkInRowOrder(final FieldMatrixChangingVisitor<T> visitor,
801                                final int startRow, final int endRow,
802                                final int startColumn, final int endColumn) {
803            checkSubMatrixIndex(startRow, endRow, startColumn, endColumn);
804            visitor.start(getRowDimension(), getColumnDimension(),
805                          startRow, endRow, startColumn, endColumn);
806            for (int row = startRow; row <= endRow; ++row) {
807                for (int column = startColumn; column <= endColumn; ++column) {
808                    final T oldValue = getEntry(row, column);
809                    final T newValue = visitor.visit(row, column, oldValue);
810                    setEntry(row, column, newValue);
811                }
812            }
813            return visitor.end();
814        }
815    
816        /** {@inheritDoc} */
817        public T walkInRowOrder(final FieldMatrixPreservingVisitor<T> visitor,
818                                final int startRow, final int endRow,
819                                final int startColumn, final int endColumn) {
820            checkSubMatrixIndex(startRow, endRow, startColumn, endColumn);
821            visitor.start(getRowDimension(), getColumnDimension(),
822                          startRow, endRow, startColumn, endColumn);
823            for (int row = startRow; row <= endRow; ++row) {
824                for (int column = startColumn; column <= endColumn; ++column) {
825                    visitor.visit(row, column, getEntry(row, column));
826                }
827            }
828            return visitor.end();
829        }
830    
831        /** {@inheritDoc} */
832        public T walkInColumnOrder(final FieldMatrixChangingVisitor<T> visitor) {
833            final int rows    = getRowDimension();
834            final int columns = getColumnDimension();
835            visitor.start(rows, columns, 0, rows - 1, 0, columns - 1);
836            for (int column = 0; column < columns; ++column) {
837                for (int row = 0; row < rows; ++row) {
838                    final T oldValue = getEntry(row, column);
839                    final T newValue = visitor.visit(row, column, oldValue);
840                    setEntry(row, column, newValue);
841                }
842            }
843            return visitor.end();
844        }
845    
846        /** {@inheritDoc} */
847        public T walkInColumnOrder(final FieldMatrixPreservingVisitor<T> visitor) {
848            final int rows    = getRowDimension();
849            final int columns = getColumnDimension();
850            visitor.start(rows, columns, 0, rows - 1, 0, columns - 1);
851            for (int column = 0; column < columns; ++column) {
852                for (int row = 0; row < rows; ++row) {
853                    visitor.visit(row, column, getEntry(row, column));
854                }
855            }
856            return visitor.end();
857        }
858    
859        /** {@inheritDoc} */
860        public T walkInColumnOrder(final FieldMatrixChangingVisitor<T> visitor,
861                                   final int startRow, final int endRow,
862                                   final int startColumn, final int endColumn) {
863            checkSubMatrixIndex(startRow, endRow, startColumn, endColumn);
864            visitor.start(getRowDimension(), getColumnDimension(),
865                          startRow, endRow, startColumn, endColumn);
866            for (int column = startColumn; column <= endColumn; ++column) {
867                for (int row = startRow; row <= endRow; ++row) {
868                    final T oldValue = getEntry(row, column);
869                    final T newValue = visitor.visit(row, column, oldValue);
870                    setEntry(row, column, newValue);
871                }
872            }
873            return visitor.end();
874        }
875    
876        /** {@inheritDoc} */
877        public T walkInColumnOrder(final FieldMatrixPreservingVisitor<T> visitor,
878                                   final int startRow, final int endRow,
879                                   final int startColumn, final int endColumn) {
880            checkSubMatrixIndex(startRow, endRow, startColumn, endColumn);
881            visitor.start(getRowDimension(), getColumnDimension(),
882                          startRow, endRow, startColumn, endColumn);
883            for (int column = startColumn; column <= endColumn; ++column) {
884                for (int row = startRow; row <= endRow; ++row) {
885                    visitor.visit(row, column, getEntry(row, column));
886                }
887            }
888            return visitor.end();
889        }
890    
891        /** {@inheritDoc} */
892        public T walkInOptimizedOrder(final FieldMatrixChangingVisitor<T> visitor) {
893            return walkInRowOrder(visitor);
894        }
895    
896        /** {@inheritDoc} */
897        public T walkInOptimizedOrder(final FieldMatrixPreservingVisitor<T> visitor) {
898            return walkInRowOrder(visitor);
899        }
900    
901        /** {@inheritDoc} */
902        public T walkInOptimizedOrder(final FieldMatrixChangingVisitor<T> visitor,
903                                      final int startRow, final int endRow,
904                                      final int startColumn, final int endColumn) {
905            return walkInRowOrder(visitor, startRow, endRow, startColumn, endColumn);
906        }
907    
908        /** {@inheritDoc} */
909        public T walkInOptimizedOrder(final FieldMatrixPreservingVisitor<T> visitor,
910                                      final int startRow, final int endRow,
911                                      final int startColumn, final int endColumn) {
912            return walkInRowOrder(visitor, startRow, endRow, startColumn, endColumn);
913        }
914    
915        /**
916         * Get a string representation for this matrix.
917         * @return a string representation for this matrix
918         */
919        @Override
920        public String toString() {
921            final int nRows = getRowDimension();
922            final int nCols = getColumnDimension();
923            final StringBuffer res = new StringBuffer();
924            String fullClassName = getClass().getName();
925            String shortClassName = fullClassName.substring(fullClassName.lastIndexOf('.') + 1);
926            res.append(shortClassName).append("{");
927    
928            for (int i = 0; i < nRows; ++i) {
929                if (i > 0) {
930                    res.append(",");
931                }
932                res.append("{");
933                for (int j = 0; j < nCols; ++j) {
934                    if (j > 0) {
935                        res.append(",");
936                    }
937                    res.append(getEntry(i, j));
938                }
939                res.append("}");
940            }
941    
942            res.append("}");
943            return res.toString();
944        }
945    
946        /**
947         * Returns true iff <code>object</code> is a
948         * <code>FieldMatrix</code> instance with the same dimensions as this
949         * and all corresponding matrix entries are equal.
950         *
951         * @param object the object to test equality against.
952         * @return true if object equals this
953         */
954        @Override
955        public boolean equals(final Object object) {
956            if (object == this ) {
957                return true;
958            }
959            if (object instanceof FieldMatrix<?> == false) {
960                return false;
961            }
962            FieldMatrix<?> m = (FieldMatrix<?>) object;
963            final int nRows = getRowDimension();
964            final int nCols = getColumnDimension();
965            if (m.getColumnDimension() != nCols || m.getRowDimension() != nRows) {
966                return false;
967            }
968            for (int row = 0; row < nRows; ++row) {
969                for (int col = 0; col < nCols; ++col) {
970                    if (!getEntry(row, col).equals(m.getEntry(row, col))) {
971                        return false;
972                    }
973                }
974            }
975            return true;
976        }
977    
978        /**
979         * Computes a hashcode for the matrix.
980         *
981         * @return hashcode for matrix
982         */
983        @Override
984        public int hashCode() {
985            int ret = 322562;
986            final int nRows = getRowDimension();
987            final int nCols = getColumnDimension();
988            ret = ret * 31 + nRows;
989            ret = ret * 31 + nCols;
990            for (int row = 0; row < nRows; ++row) {
991                for (int col = 0; col < nCols; ++col) {
992                   ret = ret * 31 + (11 * (row+1) + 17 * (col+1)) * getEntry(row, col).hashCode();
993               }
994            }
995            return ret;
996        }
997    
998        /**
999         * Check if a row index is valid.
1000         *
1001         * @param row Row index to check.
1002         * @throws OutOfRangeException if {@code index} is not valid.
1003         */
1004        protected void checkRowIndex(final int row) {
1005            if (row < 0 || row >= getRowDimension()) {
1006                throw new OutOfRangeException(LocalizedFormats.ROW_INDEX,
1007                                              row, 0, getRowDimension() - 1);
1008            }
1009        }
1010    
1011        /**
1012         * Check if a column index is valid.
1013         *
1014         * @param column Column index to check.
1015         * @throws OutOfRangeException if {@code index} is not valid.
1016         */
1017        protected void checkColumnIndex(final int column) {
1018            if (column < 0 || column >= getColumnDimension()) {
1019                throw new OutOfRangeException(LocalizedFormats.COLUMN_INDEX,
1020                                              column, 0, getColumnDimension() - 1);
1021            }
1022        }
1023    
1024        /**
1025         * Check if submatrix ranges indices are valid.
1026         * Rows and columns are indicated counting from 0 to n-1.
1027         *
1028         * @param startRow Initial row index.
1029         * @param endRow Final row index.
1030         * @param startColumn Initial column index.
1031         * @param endColumn Final column index.
1032         * @throws OutOfRangeException if the indices are not valid.
1033         * @throws NumberIsTooSmallException if {@code endRow < startRow} or
1034         * {@code endColumn < startColumn}.
1035         */
1036        protected void checkSubMatrixIndex(final int startRow, final int endRow,
1037                                           final int startColumn, final int endColumn) {
1038            checkRowIndex(startRow);
1039            checkRowIndex(endRow);
1040            if (endRow < startRow) {
1041                throw new NumberIsTooSmallException(LocalizedFormats.INITIAL_ROW_AFTER_FINAL_ROW,
1042                                                    endRow, startRow, true);
1043            }
1044    
1045            checkColumnIndex(startColumn);
1046            checkColumnIndex(endColumn);
1047            if (endColumn < startColumn) {
1048                throw new NumberIsTooSmallException(LocalizedFormats.INITIAL_COLUMN_AFTER_FINAL_COLUMN,
1049                                                    endColumn, startColumn, true);
1050            }
1051        }
1052    
1053        /**
1054         * Check if submatrix ranges indices are valid.
1055         * Rows and columns are indicated counting from 0 to n-1.
1056         *
1057         * @param selectedRows Array of row indices.
1058         * @param selectedColumns Array of column indices.
1059         * @throws NullArgumentException if the arrays are {@code null}.
1060         * @throws NoDataException if the arrays have zero length.
1061         * @throws OutOfRangeException if row or column selections are not valid.
1062         */
1063        protected void checkSubMatrixIndex(final int[] selectedRows, final int[] selectedColumns) {
1064            if (selectedRows == null ||
1065                selectedColumns == null) {
1066                throw new NullArgumentException();
1067            }
1068            if (selectedRows.length == 0 ||
1069                selectedColumns.length == 0) {
1070                throw new NoDataException();
1071            }
1072    
1073            for (final int row : selectedRows) {
1074                checkRowIndex(row);
1075            }
1076            for (final int column : selectedColumns) {
1077                checkColumnIndex(column);
1078            }
1079        }
1080    
1081        /**
1082         * Check if a matrix is addition compatible with the instance.
1083         *
1084         * @param m Matrix to check.
1085         * @throws MatrixDimensionMismatchException if the matrix is not
1086         * addition-compatible with instance.
1087         */
1088        protected void checkAdditionCompatible(final FieldMatrix<T> m) {
1089            if ((getRowDimension() != m.getRowDimension()) ||
1090                (getColumnDimension() != m.getColumnDimension())) {
1091                throw new MatrixDimensionMismatchException(m.getRowDimension(), m.getColumnDimension(),
1092                                                           getRowDimension(), getColumnDimension());
1093            }
1094        }
1095    
1096        /**
1097         * Check if a matrix is subtraction compatible with the instance.
1098         *
1099         * @param m Matrix to check.
1100         * @throws MatrixDimensionMismatchException if the matrix is not
1101         * subtraction-compatible with instance.
1102         */
1103        protected void checkSubtractionCompatible(final FieldMatrix<T> m) {
1104            if ((getRowDimension() != m.getRowDimension()) ||
1105                (getColumnDimension() != m.getColumnDimension())) {
1106                throw new MatrixDimensionMismatchException(m.getRowDimension(), m.getColumnDimension(),
1107                                                           getRowDimension(), getColumnDimension());
1108            }
1109        }
1110    
1111        /**
1112         * Check if a matrix is multiplication compatible with the instance.
1113         *
1114         * @param m Matrix to check.
1115         * @throws DimensionMismatchException if the matrix is not
1116         * multiplication-compatible with instance.
1117         */
1118        protected void checkMultiplicationCompatible(final FieldMatrix<T> m) {
1119            if (getColumnDimension() != m.getRowDimension()) {
1120                throw new DimensionMismatchException(m.getRowDimension(), getColumnDimension());
1121            }
1122        }
1123    }