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: */
009: package org.jscience.mathematics.vector;
010:
011: import java.util.Iterator;
012: import java.util.List;
013:
014: import javolution.context.ConcurrentContext;
015: import javolution.context.ObjectFactory;
016: import javolution.lang.MathLib;
017: import javolution.util.FastTable;
018:
019: import 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: */
035: public 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,
278: Matrix<Complex> right, int rightColumnStart,
279: int rightColumnEnd,
280: FastTable<ComplexVector> columnsResult) {
281: Multiply multiply = Multiply.FACTORY.object();
282: multiply._left = left;
283: multiply._right = right;
284: multiply._rightColumnStart = rightColumnStart;
285: multiply._rightColumnEnd = rightColumnEnd;
286: multiply._columnsResult = columnsResult;
287: return multiply;
288: }
289:
290: static void recycle(Multiply multiply) {
291: multiply._left = null;
292: multiply._right = null;
293: multiply._columnsResult = null;
294: Multiply.FACTORY.recycle(multiply);
295: }
296:
297: public void run() {
298: if (_rightColumnEnd - _rightColumnStart < 32) { // Direct calculation.
299: FastTable<ComplexVector> rows = _left.getRows();
300: final int m = rows.size();
301: for (int j = _rightColumnStart; j < _rightColumnEnd; j++) {
302: Vector<Complex> thatColj = _right.getColumn(j);
303: ComplexVector column = ComplexVector.newInstance(m);
304: _columnsResult.set(j, column);
305: for (int i = 0; i < m; i++) {
306: column.set(i, rows.get(i).times(thatColj));
307: }
308: }
309: } else { // Concurrent/Recursive calculation.
310: int halfIndex = (_rightColumnStart + _rightColumnEnd) >> 1;
311: Multiply firstHalf = Multiply.valueOf(_left, _right,
312: _rightColumnStart, halfIndex, _columnsResult);
313: Multiply secondHalf = Multiply.valueOf(_left, _right,
314: halfIndex, _rightColumnEnd, _columnsResult);
315: ConcurrentContext.enter();
316: try {
317: ConcurrentContext.execute(firstHalf);
318: ConcurrentContext.execute(secondHalf);
319: } finally {
320: ConcurrentContext.exit();
321: }
322: Multiply.recycle(firstHalf);
323: Multiply.recycle(secondHalf);
324: }
325: }
326: }
327:
328: private FastTable<ComplexVector> getRows() {
329: if (!_transposed)
330: return _rows;
331: FastTable<ComplexVector> rows = FastTable.newInstance();
332: for (int i = 0; i < _n; i++) {
333: rows.add(this .getRow(i));
334: }
335: return rows;
336: }
337:
338: @Override
339: public ComplexMatrix inverse() {
340: if (!isSquare())
341: throw new DimensionException("Matrix not square");
342: return ComplexMatrix.valueOf(LUDecomposition.valueOf(this )
343: .inverse());
344: }
345:
346: @Override
347: public Complex determinant() {
348: return LUDecomposition.valueOf(this ).determinant();
349: }
350:
351: @Override
352: public ComplexMatrix transpose() {
353: ComplexMatrix M = ComplexMatrix.newInstance(_n, !_transposed);
354: M._rows.addAll(this ._rows);
355: return M;
356: }
357:
358: @Override
359: public Complex cofactor(int i, int j) {
360: if (_transposed) {
361: int k = i;
362: i = j;
363: j = k; // Swaps i,j
364: }
365: int m = _rows.size();
366: ComplexMatrix M = ComplexMatrix.newInstance(m - 1, _transposed);
367: for (int k1 = 0; k1 < m; k1++) {
368: if (k1 == i)
369: continue;
370: ComplexVector row = _rows.get(k1);
371: ComplexVector V = ComplexVector.newInstance(_n - 1);
372: M._rows.add(V);
373: for (int k2 = 0, k = 0; k2 < _n; k2++) {
374: if (k2 == j)
375: continue;
376: V.set(k++, row.get(k2));
377: }
378: }
379: return M.determinant();
380: }
381:
382: @Override
383: public ComplexMatrix adjoint() {
384: ComplexMatrix M = ComplexMatrix.newInstance(_n, _transposed);
385: int m = _rows.size();
386: for (int i = 0; i < m; i++) {
387: ComplexVector row = ComplexVector.newInstance(_n);
388: M._rows.add(row);
389: for (int j = 0; j < _n; j++) {
390: Complex cofactor = _transposed ? cofactor(j, i)
391: : cofactor(i, j);
392: row.set(j, ((i + j) % 2 == 0) ? cofactor : cofactor
393: .opposite());
394: }
395: }
396: return M.transpose();
397: }
398:
399: @Override
400: public ComplexMatrix tensor(Matrix<Complex> that) {
401: return ComplexMatrix.valueOf(DenseMatrix.valueOf(this ).tensor(
402: that));
403: }
404:
405: @Override
406: public ComplexVector vectorization() {
407: return ComplexVector.valueOf(DenseMatrix.valueOf(this )
408: .vectorization());
409: }
410:
411: @Override
412: public ComplexMatrix copy() {
413: ComplexMatrix M = ComplexMatrix.newInstance(_n, _transposed);
414: for (ComplexVector row : _rows) {
415: M._rows.add(row.copy());
416: }
417: return M;
418: }
419:
420: ///////////////////////
421: // Factory creation. //
422: ///////////////////////
423:
424: static ComplexMatrix newInstance(int n, boolean transposed) {
425: ComplexMatrix M = FACTORY.object();
426: M._rows.clear();
427: M._n = n;
428: M._transposed = transposed;
429: return M;
430: }
431:
432: private static ObjectFactory<ComplexMatrix> FACTORY = new ObjectFactory<ComplexMatrix>() {
433: @Override
434: protected ComplexMatrix create() {
435: return new ComplexMatrix();
436: }
437: };
438:
439: private ComplexMatrix() {
440: }
441:
442: private static final long serialVersionUID = 1L;
443:
444: }
|