001/*
002 * JScience - Java(TM) Tools and Libraries for the Advancement of Sciences.
003 * Copyright (C) 2006 - JScience (http://jscience.org/)
004 * All rights reserved.
005 * 
006 * Permission to use, copy, modify, and distribute this software is
007 * freely granted, provided that this notice is preserved.
008 */
009package org.jscience.mathematics.vector;
010
011import java.util.Iterator;
012import java.util.List;
013
014import javolution.context.ConcurrentContext;
015import javolution.context.ObjectFactory;
016import javolution.lang.MathLib;
017import javolution.util.FastTable;
018import org.jscience.mathematics.structure.Field;
019
020/**
021 * <p> This class represents a matrix made of {@link DenseVector dense
022 *     vectors} (as rows). To create a dense matrix made of column vectors the 
023 *     {@link #transpose} method can be used. 
024 *     For example:[code]
025 *        DenseVector<Rational> column0 = DenseVector.valueOf(...);
026 *        DenseVector<Rational> column1 = DenseVector.valueOf(...);
027 *        DenseMatrix<Rational> M = DenseMatrix.valueOf(column0, column1).transpose();
028 *     [/code]</p>
029 * <p> As for any concrete {@link org.jscience.mathematics.structure.Structure
030 *     structure}, this class is declared <code>final</code> (otherwise most
031 *     operations would have to be overridden to return the appropriate type).
032 *     Specialized dense matrix should sub-class {@link Matrix} directly.
033 *     For example:[code]
034 *        // Extension through composition.
035 *        final class TriangularMatrix <F extends Field<F>> extends Matrix<F> {
036 *             private DenseMatrix<F> _value; // Possible implementation.
037 *             ...
038 *             public TriangularMatrix opposite() { // Returns the right type.
039 *                 return TriangularMatrix.valueOf(_value.opposite());
040 *             }
041 *             ...
042 *        }[/code]
043 *     </p>   
044 * @author <a href="mailto:jean-marie@dautelle.com">Jean-Marie Dautelle</a>
045 * @version 3.3, January 2, 2007
046 */
047public final class DenseMatrix<F extends Field<F>> extends Matrix<F> {
048
049    /**
050     * Holds the number of columns n.
051     */
052    int _n;
053
054    /**
055     * Indicates if this matrix is transposed (the rows are then the columns).
056     */
057    boolean _transposed;
058
059    /**
060     * Holds this matrix rows (or columns when transposed).
061     */
062    final FastTable<DenseVector<F>> _rows = new FastTable<DenseVector<F>>();
063
064    /**
065     * Returns a dense matrix from the specified 2-dimensional array.
066     * The first dimension being the row and the second being the column.
067     * 
068     * @param elements this matrix elements.
069     * @return the matrix having the specified elements.
070     * @throws DimensionException if rows have different length.
071     * @see    DenseMatrix 
072     */
073    public static <F extends Field<F>> DenseMatrix<F> valueOf(F[][] elements) {
074        int m = elements.length;
075        int n = elements[0].length;
076        DenseMatrix<F> M = DenseMatrix.newInstance(n, false);
077        for (int i = 0; i < m; i++) {
078            DenseVector<F> row = DenseVector.valueOf(elements[i]);
079            if (row.getDimension() != n)
080                throw new DimensionException();
081            M._rows.add(row);
082        }
083        return M;
084    }
085
086    /**
087     * Returns a dense matrix holding the specified row vectors 
088     * (column vectors if {@link #transpose transposed}).
089     *
090     * @param rows the row vectors.
091     * @return the matrix having the specified rows.
092     * @throws DimensionException if the rows do not have the same dimension.
093     */
094    public static <F extends Field<F>> DenseMatrix<F> valueOf(
095            DenseVector<F>... rows) {
096        final int n = rows[0].getDimension();
097        DenseMatrix<F> M = DenseMatrix.newInstance(n, false);
098        for (int i = 0, m = rows.length; i < m; i++) {
099            DenseVector<F> rowi = rows[i];
100            if (rowi.getDimension() != n)
101                throw new DimensionException(
102                        "All vectors must have the same dimension.");
103            M._rows.add(rowi);
104        }
105        return M;
106    }
107    
108    /**
109     * Returns a dense matrix holding the row vectors from the specified 
110     * collection (column vectors if {@link #transpose transposed}).
111     *
112     * @param rows the list of row vectors.
113     * @return the matrix having the specified rows.
114     * @throws DimensionException if the rows do not have the same dimension.
115     */
116    public static <F extends Field<F>> DenseMatrix<F> valueOf(
117            List<DenseVector<F>> rows) {
118        final int n = rows.get(0).getDimension();
119        DenseMatrix<F> M = DenseMatrix.newInstance(n, false);
120        Iterator<DenseVector<F>> iterator = rows.iterator();
121        for (int i = 0, m = rows.size(); i < m; i++) {
122            DenseVector<F> rowi = iterator.next();
123            if (rowi.getDimension() != n)
124                throw new DimensionException(
125                        "All vectors must have the same dimension.");
126            M._rows.add(rowi);
127        }
128        return M;
129    }
130
131    /**
132     * Returns a dense matrix equivalent to the specified matrix.
133     *
134     * @param that the matrix to convert.
135     * @return <code>that</code> or a dense matrix holding the same elements
136     *         as the specified matrix.
137     */
138    public static <F extends Field<F>> DenseMatrix<F> valueOf(Matrix<F> that) {
139        if (that instanceof DenseMatrix)
140            return (DenseMatrix<F>) that;
141        int n = that.getNumberOfColumns();
142        int m = that.getNumberOfRows();
143        DenseMatrix<F> M = DenseMatrix.newInstance(n, false);
144        for (int i = 0; i < m; i++) {
145            DenseVector<F> rowi = DenseVector.valueOf(that.getRow(i));
146            M._rows.add(rowi);
147        }
148        return M;
149    }
150
151    @Override
152    public int getNumberOfRows() {
153        return _transposed ? _n : _rows.size();
154    }
155
156    @Override
157    public int getNumberOfColumns() {
158        return _transposed ? _rows.size() : _n;
159    }
160
161    @Override
162    public F get(int i, int j) {
163        return _transposed ? _rows.get(j).get(i) : _rows.get(i).get(j);
164    }
165
166    @Override
167    public DenseVector<F> getRow(int i) {
168        if (!_transposed)
169            return _rows.get(i);
170        // Else transposed.
171        int n = _rows.size();
172        int m = _n;
173        if ((i < 0) || (i >= m))
174            throw new DimensionException();
175        DenseVector<F> V = DenseVector.newInstance();
176        for (int j = 0; j < n; j++) {
177            V._elements.add(_rows.get(j).get(i));
178        }
179        return V;
180    }
181
182    @Override
183    public DenseVector<F> getColumn(int j) {
184        if (_transposed)
185            return _rows.get(j);
186        int m = _rows.size();
187        if ((j < 0) || (j >= _n))
188            throw new DimensionException();
189        DenseVector<F> V = DenseVector.newInstance();
190        for (int i = 0; i < m; i++) {
191            V._elements.add(_rows.get(i).get(j));
192        }
193        return V;
194    }
195
196    @Override
197    public DenseVector<F> getDiagonal() {
198        int m = this.getNumberOfRows();
199        int n = this.getNumberOfColumns();
200        int dimension = MathLib.min(m, n);
201        DenseVector<F> V = DenseVector.newInstance();
202        for (int i = 0; i < dimension; i++) {
203            V._elements.add(this.get(i, i));
204        }
205        return V;
206    }
207
208    @Override
209    public DenseMatrix<F> opposite() {
210        DenseMatrix<F> M = DenseMatrix.newInstance(_n, _transposed);
211        for (int i = 0, p = _rows.size(); i < p; i++) {
212            M._rows.add(_rows.get(i).opposite());
213        }
214        return M;
215    }
216
217    @Override
218    public DenseMatrix<F> plus(Matrix<F> that) {
219        if (this.getNumberOfRows() != that.getNumberOfRows())
220            throw new DimensionException();
221        DenseMatrix<F> M = DenseMatrix.newInstance(_n, _transposed);
222        for (int i = 0, p = _rows.size(); i < p; i++) {
223            M._rows.add(_rows.get(i).plus(
224                    _transposed ? that.getColumn(i) : that.getRow(i)));
225        }
226        return M;
227    }
228
229    @Override
230    public DenseMatrix<F> minus(Matrix<F> that) { // Returns more specialized type.
231        return this.plus(that.opposite());
232    }
233
234    @Override
235    public DenseMatrix<F> times(F k) {
236        DenseMatrix<F> M = DenseMatrix.newInstance(_n, _transposed);
237        for (int i = 0, p = _rows.size(); i < p; i++) {
238            M._rows.add(_rows.get(i).times(k));
239        }
240        return M;
241    }
242
243    @Override
244    public DenseVector<F> times(Vector<F> v) {
245        if (v.getDimension() != this.getNumberOfColumns())
246            throw new DimensionException();
247        final int m = this.getNumberOfRows();
248        DenseVector<F> V = DenseVector.newInstance();
249        for (int i = 0; i < m; i++) {
250            V._elements.add(this.getRow(i).times(v));
251        }
252        return V;
253    }
254
255    @Override
256    public DenseMatrix<F> times(Matrix<F> that) {
257        final int n = this.getNumberOfColumns();
258        final int m = this.getNumberOfRows();
259        final int p = that.getNumberOfColumns();
260        if (that.getNumberOfRows() != n)
261            throw new DimensionException();
262        // Creates a mxp matrix in transposed form (p columns vectors of size m)
263        DenseMatrix<F> M = DenseMatrix.newInstance(m, true); // Transposed.
264        M._rows.setSize(p);
265        Multiply<F> multiply = Multiply.valueOf(this, that, 0, p, M._rows);
266        multiply.run();
267        Multiply.recycle(multiply);
268        return M;
269    }
270
271    // Logic to multiply two matrices. 
272    private static class Multiply<F extends Field<F>> implements Runnable {
273        private static final ObjectFactory<Multiply> FACTORY = new ObjectFactory<Multiply>() {
274
275            @Override
276            protected Multiply create() {
277                return new Multiply();
278            }
279        };
280
281        private DenseMatrix<F> _left;
282
283        private Matrix<F> _right;
284
285        private int _rightColumnStart;
286
287        private int _rightColumnEnd;
288
289        private FastTable<DenseVector<F>> _columnsResult;
290
291        @SuppressWarnings("unchecked")
292        static <F extends Field<F>> Multiply<F> valueOf(DenseMatrix<F> left, Matrix<F> right,
293                int rightColumnStart, int rightColumnEnd,
294                FastTable<DenseVector<F>> columnsResult) {
295            Multiply<F> multiply = Multiply.FACTORY.object();
296            multiply._left = left;
297            multiply._right = right;
298            multiply._rightColumnStart = rightColumnStart;
299            multiply._rightColumnEnd = rightColumnEnd;
300            multiply._columnsResult = columnsResult;
301            return multiply;
302        }
303
304        static <F extends Field<F>> void recycle(Multiply<F> multiply) {
305            multiply._left = null;
306            multiply._right = null;
307            multiply._columnsResult = null;
308            Multiply.FACTORY.recycle(multiply);
309        }
310
311        public void run() {
312            if (_rightColumnEnd - _rightColumnStart < 32) { // Direct calculation.
313                FastTable<DenseVector<F>> rows = _left.getRows();
314                final int m = rows.size();
315                for (int j = _rightColumnStart; j < _rightColumnEnd; j++) {
316                    Vector<F> thatColj = _right.getColumn(j);
317                    DenseVector<F> column = DenseVector.newInstance();
318                    _columnsResult.set(j, column);
319                    for (int i = 0; i < m; i++) {
320                        column._elements.add(rows.get(i).times(thatColj));
321                    }
322                }
323            } else { // Concurrent/Recursive calculation.
324                int halfIndex = (_rightColumnStart + _rightColumnEnd) >> 1;
325                Multiply<F> firstHalf = Multiply.valueOf(_left, _right,
326                        _rightColumnStart, halfIndex, _columnsResult);
327                Multiply<F> secondHalf = Multiply.valueOf(_left, _right,
328                        halfIndex, _rightColumnEnd, _columnsResult);
329                ConcurrentContext.enter();
330                try {
331                    ConcurrentContext.execute(firstHalf);
332                    ConcurrentContext.execute(secondHalf);
333                } finally {
334                    ConcurrentContext.exit();
335                }
336                Multiply.recycle(firstHalf);
337                Multiply.recycle(secondHalf);
338            }
339        }
340    }
341
342    private FastTable<DenseVector<F>> getRows() {
343        if (!_transposed)
344            return _rows;
345        FastTable<DenseVector<F>> rows = FastTable.newInstance();
346        for (int i = 0; i < _n; i++) {
347            rows.add(this.getRow(i));
348        }
349        return rows;
350    }
351
352    @Override
353    public DenseMatrix<F> inverse() {
354        if (!isSquare())
355            throw new DimensionException("Matrix not square");
356        return LUDecomposition.valueOf(this).inverse();
357    }
358
359    @Override
360    public F determinant() {
361        return LUDecomposition.valueOf(this).determinant();
362    }
363
364    @Override
365    public DenseMatrix<F> transpose() {
366        DenseMatrix<F> M = DenseMatrix.newInstance(_n, !_transposed);
367        M._rows.addAll(this._rows);
368        return M;
369    }
370
371    @Override
372    public F cofactor(int i, int j) {
373        if (_transposed) {
374            int k = i;
375            i = j;
376            j = k; // Swaps i,j
377        }
378        int m = _rows.size();
379        DenseMatrix<F> M = DenseMatrix.newInstance(m - 1, _transposed);
380        for (int k1 = 0; k1 < m; k1++) {
381            if (k1 == i)
382                continue;
383            DenseVector<F> row = _rows.get(k1);
384            DenseVector<F> V = DenseVector.newInstance();
385            M._rows.add(V);
386            for (int k2 = 0; k2 < _n; k2++) {
387                if (k2 == j)
388                    continue;
389                V._elements.add(row.get(k2));
390            }
391        }
392        return M.determinant();
393    }
394
395    @Override
396    public DenseMatrix<F> adjoint() {
397        DenseMatrix<F> M = DenseMatrix.newInstance(_n, _transposed);
398        int m = _rows.size();
399        for (int i = 0; i < m; i++) {
400            DenseVector<F> row = DenseVector.newInstance();
401            M._rows.add(row);
402            for (int j = 0; j < _n; j++) {
403                F cofactor = _transposed ? cofactor(j, i) : cofactor(i, j);
404                row._elements.add(((i + j) % 2 == 0) ? cofactor : cofactor
405                        .opposite());
406            }
407        }
408        return M.transpose();
409    }
410
411    @Override
412    public Matrix<F> tensor(Matrix<F> that) {
413        final int thism = this.getNumberOfRows();
414        final int thisn = this.getNumberOfColumns();
415        final int thatm = that.getNumberOfRows();
416        final int thatn = that.getNumberOfColumns();
417        int n = thisn * thatn; // Number of columns,
418        int m = thism * thatm; // Number of rows.
419        DenseMatrix<F> M = DenseMatrix.newInstance(n, false);
420        for (int i = 0; i < m; i++) { // Row index.
421            final int i_rem_thatm = i % thatm;
422            final int i_div_thatm = i / thatm;
423            DenseVector<F> row = DenseVector.newInstance();
424            M._rows.add(row);
425            for (int j = 0; j < thisn; j++) {
426                F a = this.get(i_div_thatm, j);
427                for (int k = 0; k < thatn; k++) {
428                    row._elements.add(a.times(that.get(i_rem_thatm, k)));
429                }
430            }
431        }
432        return M;
433    }
434
435    @Override
436    public Vector<F> vectorization() {
437        DenseVector<F> V = DenseVector.newInstance();
438        for (int j = 0, n = this.getNumberOfColumns(); j < n; j++) {
439            Vector<F> column = this.getColumn(j);
440            for (int i = 0, m = column.getDimension(); i < m; i++) {
441                V._elements.add(column.get(i));
442            }
443        }
444        return V;
445    }
446
447    @Override
448    public DenseMatrix<F> copy() {
449        DenseMatrix<F> M = DenseMatrix.newInstance(_n, _transposed);
450        for (DenseVector<F> row : _rows) {
451            M._rows.add(row.copy());
452        }
453        return M;
454    }
455
456    ///////////////////////////////
457    // Package Private Utilities //
458    ///////////////////////////////
459
460    void set(int i, int j, F e) {
461        if (_transposed) {
462            _rows.get(j)._elements.set(i, e);
463        } else {
464            _rows.get(i)._elements.set(j, e);
465        }
466    }
467
468    ///////////////////////
469    // Factory creation. //
470    ///////////////////////
471
472    @SuppressWarnings("unchecked")
473    static <F extends Field<F>> DenseMatrix<F> newInstance(int n,
474            boolean transposed) {
475        DenseMatrix<F> M = FACTORY.object();
476        M._n = n;
477        M._transposed = transposed;
478        return M;
479    }
480
481    private static ObjectFactory<DenseMatrix> FACTORY = new ObjectFactory<DenseMatrix>() {
482        @Override
483        protected DenseMatrix create() {
484            return new DenseMatrix();
485        }
486
487        @Override
488        protected void cleanup(DenseMatrix matrix) {
489            matrix._rows.reset();
490        }
491    };
492
493    private DenseMatrix() {
494    }
495
496    private static final long serialVersionUID = 1L;
497
498}