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;
018
019import org.jscience.mathematics.number.Complex;
020
021/**
022 * <p> This class represents an optimized {@link Matrix matrix} implementation
023 *     for {@link Complex complex} numbers.</p>
024 *     
025 * <p> Instances of this class can be created from {@link ComplexVector}, 
026 *     either as rows or columns if the matrix is transposed. For example:[code]
027 *        ComplexVector<Rational> column0 = ComplexVector.valueOf(...);
028 *        ComplexVector<Rational> column1 = ComplexVector.valueOf(...);
029 *        ComplexMatrix<Rational> M = ComplexMatrix.valueOf(column0, column1).transpose();
030 *     [/code]</p>
031 *     
032 * @author <a href="mailto:jean-marie@dautelle.com">Jean-Marie Dautelle</a>
033 * @version 3.3, January 2, 2007
034 */
035public final class ComplexMatrix extends Matrix<Complex> {
036
037    /**
038     * Holds the number of columns n.
039     */
040    int _n;;
041
042    /**
043     * Indicates if this matrix is transposed (the rows are then the columns).
044     */
045    boolean _transposed;
046
047    /**
048     * Holds this matrix rows (or columns when transposed).
049     */
050    final FastTable<ComplexVector> _rows = new FastTable<ComplexVector>();
051
052    /**
053     * Returns a complex matrix from the specified 2-dimensional array.
054     * The first dimension being the row and the second being the column.
055     * 
056     * @param elements this matrix elements.
057     * @return the matrix having the specified elements.
058     * @throws DimensionException if rows have different length.
059     * @see    ComplexVector
060     */
061    public static ComplexMatrix valueOf(Complex[][] elements) {
062        int m = elements.length;
063        int n = elements[0].length;
064        ComplexMatrix M = ComplexMatrix.newInstance(n, false);
065        for (int i = 0; i < m; i++) {
066            ComplexVector row = ComplexVector.valueOf(elements[i]);
067            if (row.getDimension() != n)
068                throw new DimensionException();
069            M._rows.add(row);
070        }
071        return M;
072    }
073
074    /**
075     * Returns a complex matrix holding the specified row vectors 
076     * (column vectors if {@link #transpose transposed}).
077     *
078     * @param rows the row vectors.
079     * @return the matrix having the specified rows.
080     * @throws DimensionException if the rows do not have the same dimension.
081     */
082    public static ComplexMatrix valueOf(ComplexVector... rows) {
083        final int n = rows[0].getDimension();
084        ComplexMatrix M = ComplexMatrix.newInstance(n, false);
085        for (int i = 0, m = rows.length; i < m; i++) {
086            ComplexVector rowi = rows[i];
087            if (rowi.getDimension() != n)
088                throw new DimensionException(
089                        "All vectors must have the same dimension.");
090            M._rows.add(rowi);
091        }
092        return M;
093    }
094
095    /**
096     * Returns a complex matrix holding the row vectors from the specified 
097     * collection (column vectors if {@link #transpose transposed}).
098     *
099     * @param rows the list of row vectors.
100     * @return the matrix having the specified rows.
101     * @throws DimensionException if the rows do not have the same dimension.
102     */
103    public static ComplexMatrix valueOf(List<ComplexVector> rows) {
104        final int n = rows.get(0).getDimension();
105        ComplexMatrix M = ComplexMatrix.newInstance(n, false);
106        Iterator<ComplexVector> iterator = rows.iterator();
107        for (int i = 0, m = rows.size(); i < m; i++) {
108            ComplexVector rowi = iterator.next();
109            if (rowi.getDimension() != n)
110                throw new DimensionException(
111                        "All vectors must have the same dimension.");
112            M._rows.add(rowi);
113        }
114        return M;
115    }
116
117    /**
118     * Returns a complex matrix equivalent to the specified matrix.
119     *
120     * @param that the matrix to convert.
121     * @return <code>that</code> or a complex matrix holding the same elements
122     *         as the specified matrix.
123     */
124    public static ComplexMatrix valueOf(Matrix<Complex> that) {
125        if (that instanceof ComplexMatrix)
126            return (ComplexMatrix) that;
127        int n = that.getNumberOfColumns();
128        int m = that.getNumberOfRows();
129        ComplexMatrix M = ComplexMatrix.newInstance(n, false);
130        for (int i = 0; i < m; i++) {
131            ComplexVector rowi = ComplexVector.valueOf(that.getRow(i));
132            M._rows.add(rowi);
133        }
134        return M;
135    }
136
137    @Override
138    public int getNumberOfRows() {
139        return _transposed ? _n : _rows.size();
140    }
141
142    @Override
143    public int getNumberOfColumns() {
144        return _transposed ? _rows.size() : _n;
145    }
146
147    @Override
148    public Complex get(int i, int j) {
149        return _transposed ? _rows.get(j).get(i) : _rows.get(i).get(j);
150    }
151
152    @Override
153    public ComplexVector getRow(int i) {
154        if (!_transposed)
155            return _rows.get(i);
156        // Else transposed.
157        int n = _rows.size();
158        int m = _n;
159        if ((i < 0) || (i >= m))
160            throw new DimensionException();
161        ComplexVector V = ComplexVector.newInstance(n);
162        for (int j = 0; j < n; j++) {
163            V.set(j, _rows.get(j).get(i));
164        }
165        return V;
166    }
167
168    @Override
169    public ComplexVector getColumn(int j) {
170        if (_transposed)
171            return _rows.get(j);
172        int m = _rows.size();
173        if ((j < 0) || (j >= _n))
174            throw new DimensionException();
175        ComplexVector V = ComplexVector.newInstance(m);
176        for (int i = 0; i < m; i++) {
177            V.set(i, _rows.get(i).get(j));
178        }
179        return V;
180    }
181
182    @Override
183    public ComplexVector getDiagonal() {
184        int m = this.getNumberOfRows();
185        int n = this.getNumberOfColumns();
186        int dimension = MathLib.min(m, n);
187        ComplexVector V = ComplexVector.newInstance(dimension);
188        for (int i = 0; i < dimension; i++) {
189            V.set(i, this.get(i, i));
190        }
191        return V;
192    }
193
194    @Override
195    public ComplexMatrix opposite() {
196        ComplexMatrix M = ComplexMatrix.newInstance(_n, _transposed);
197        for (int i = 0, p = _rows.size(); i < p; i++) {
198            M._rows.add(_rows.get(i).opposite());
199        }
200        return M;
201    }
202
203    @Override
204    public ComplexMatrix plus(Matrix<Complex> that) {
205        if (this.getNumberOfRows() != that.getNumberOfRows())
206            throw new DimensionException();
207        ComplexMatrix M = ComplexMatrix.newInstance(_n, _transposed);
208        for (int i = 0, p = _rows.size(); i < p; i++) {
209            M._rows.add(_rows.get(i).plus(
210                    _transposed ? that.getColumn(i) : that.getRow(i)));
211        }
212        return M;
213    }
214
215    @Override
216    public ComplexMatrix minus(Matrix<Complex> that) { // Returns more specialized type.
217        return this.plus(that.opposite());
218    }
219
220    @Override
221    public ComplexMatrix times(Complex k) {
222        ComplexMatrix M = ComplexMatrix.newInstance(_n, _transposed);
223        for (int i = 0, p = _rows.size(); i < p; i++) {
224            M._rows.add(_rows.get(i).times(k));
225        }
226        return M;
227    }
228
229    @Override
230    public ComplexVector times(Vector<Complex> v) {
231        if (v.getDimension() != this.getNumberOfColumns())
232            throw new DimensionException();
233        final int m = this.getNumberOfRows();
234        ComplexVector V = ComplexVector.newInstance(m);
235        for (int i = 0; i < m; i++) {
236            V.set(i, this.getRow(i).times(v));
237        }
238        return V;
239    }
240
241    @Override
242    public ComplexMatrix times(Matrix<Complex> that) {
243        final int n = this.getNumberOfColumns();
244        final int m = this.getNumberOfRows();
245        final int p = that.getNumberOfColumns();
246        if (that.getNumberOfRows() != n)
247            throw new DimensionException();
248        // Creates a mxp matrix in transposed form (p columns vectors of size m)
249        ComplexMatrix M = ComplexMatrix.newInstance(m, true); // Transposed.
250        M._rows.setSize(p);
251        Multiply multiply = Multiply.valueOf(this, that, 0, p, M._rows);
252        multiply.run();
253        Multiply.recycle(multiply);
254        return M;
255    }
256
257    // Logic to multiply two matrices. 
258    private static class Multiply implements Runnable {
259        private static final ObjectFactory<Multiply> FACTORY = new ObjectFactory<Multiply>() {
260
261            @Override
262            protected Multiply create() {
263                return new Multiply();
264            }
265        };
266
267        private ComplexMatrix _left;
268
269        private Matrix<Complex> _right;
270
271        private int _rightColumnStart;
272
273        private int _rightColumnEnd;
274
275        private FastTable<ComplexVector> _columnsResult;
276
277        static Multiply valueOf(ComplexMatrix left, Matrix<Complex> right,
278                int rightColumnStart, int rightColumnEnd,
279                FastTable<ComplexVector> columnsResult) {
280            Multiply multiply = Multiply.FACTORY.object();
281            multiply._left = left;
282            multiply._right = right;
283            multiply._rightColumnStart = rightColumnStart;
284            multiply._rightColumnEnd = rightColumnEnd;
285            multiply._columnsResult = columnsResult;
286            return multiply;
287        }
288
289        static void recycle(Multiply multiply) {
290            multiply._left = null;
291            multiply._right = null;
292            multiply._columnsResult = null;
293            Multiply.FACTORY.recycle(multiply);
294        }
295
296        public void run() {
297            if (_rightColumnEnd - _rightColumnStart < 32) { // Direct calculation.
298                FastTable<ComplexVector> rows = _left.getRows();
299                final int m = rows.size();
300                for (int j = _rightColumnStart; j < _rightColumnEnd; j++) {
301                    Vector<Complex> thatColj = _right.getColumn(j);
302                    ComplexVector column = ComplexVector.newInstance(m);
303                    _columnsResult.set(j, column);
304                    for (int i = 0; i < m; i++) {
305                        column.set(i, rows.get(i).times(thatColj));
306                    }
307                }
308            } else { // Concurrent/Recursive calculation.
309                int halfIndex = (_rightColumnStart + _rightColumnEnd) >> 1;
310                Multiply firstHalf = Multiply.valueOf(_left, _right,
311                        _rightColumnStart, halfIndex, _columnsResult);
312                Multiply secondHalf = Multiply.valueOf(_left, _right,
313                        halfIndex, _rightColumnEnd, _columnsResult);
314                ConcurrentContext.enter();
315                try {
316                    ConcurrentContext.execute(firstHalf);
317                    ConcurrentContext.execute(secondHalf);
318                } finally {
319                    ConcurrentContext.exit();
320                }
321                Multiply.recycle(firstHalf);
322                Multiply.recycle(secondHalf);
323            }
324        }
325    }
326
327    private FastTable<ComplexVector> getRows() {
328        if (!_transposed)
329            return _rows;
330        FastTable<ComplexVector> rows = FastTable.newInstance();
331        for (int i = 0; i < _n; i++) {
332            rows.add(this.getRow(i));
333        }
334        return rows;
335    }
336
337    @Override
338    public ComplexMatrix inverse() {
339        if (!isSquare())
340            throw new DimensionException("Matrix not square");
341        return ComplexMatrix.valueOf(LUDecomposition.valueOf(this).inverse());
342    }
343
344    @Override
345    public Complex determinant() {
346        return LUDecomposition.valueOf(this).determinant();
347    }
348
349    @Override
350    public ComplexMatrix transpose() {
351        ComplexMatrix M = ComplexMatrix.newInstance(_n, !_transposed);
352        M._rows.addAll(this._rows);
353        return M;
354    }
355
356    @Override
357    public Complex cofactor(int i, int j) {
358        if (_transposed) {
359            int k = i;
360            i = j;
361            j = k; // Swaps i,j
362        }
363        int m = _rows.size();
364        ComplexMatrix M = ComplexMatrix.newInstance(m - 1, _transposed);
365        for (int k1 = 0; k1 < m; k1++) {
366            if (k1 == i)
367                continue;
368            ComplexVector row = _rows.get(k1);
369            ComplexVector V = ComplexVector.newInstance(_n - 1);
370            M._rows.add(V);
371            for (int k2 = 0, k = 0; k2 < _n; k2++) {
372                if (k2 == j)
373                    continue;
374                V.set(k++, row.get(k2));
375            }
376        }
377        return M.determinant();
378    }
379
380    @Override
381    public ComplexMatrix adjoint() {
382        ComplexMatrix M = ComplexMatrix.newInstance(_n, _transposed);
383        int m = _rows.size();
384        for (int i = 0; i < m; i++) {
385            ComplexVector row = ComplexVector.newInstance(_n);
386            M._rows.add(row);
387            for (int j = 0; j < _n; j++) {
388                Complex cofactor = _transposed ? cofactor(j, i)
389                        : cofactor(i, j);
390                row.set(j, ((i + j) % 2 == 0) ? cofactor : cofactor.opposite());
391            }
392        }
393        return M.transpose();
394    }
395
396    @Override
397    public ComplexMatrix tensor(Matrix<Complex> that) {
398        return ComplexMatrix.valueOf(DenseMatrix.valueOf(this).tensor(that));
399    }
400
401    @Override
402    public ComplexVector vectorization() {
403        return ComplexVector.valueOf(DenseMatrix.valueOf(this).vectorization());
404    }
405
406    @Override
407    public ComplexMatrix copy() {
408        ComplexMatrix M = ComplexMatrix.newInstance(_n, _transposed);
409        for (ComplexVector row : _rows) {
410            M._rows.add(row.copy());
411        }
412        return M;
413    }
414
415    ///////////////////////
416    // Factory creation. //
417    ///////////////////////
418
419    static ComplexMatrix newInstance(int n, boolean transposed) {
420        ComplexMatrix M = FACTORY.object();
421        M._rows.clear();
422        M._n = n;
423        M._transposed = transposed;
424        return M;
425    }
426
427    private static ObjectFactory<ComplexMatrix> FACTORY = new ObjectFactory<ComplexMatrix>() {
428        @Override
429        protected ComplexMatrix create() {
430            return new ComplexMatrix();
431        }
432    };
433
434    private ComplexMatrix() {
435    }
436
437    private static final long serialVersionUID = 1L;
438
439}