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}