/*
 * JScience - Java(TM) Tools and Libraries for the Advancement of Sciences.
 * Copyright (C) 2006 - JScience (http://jscience.org/)
 * All rights reserved.
 * 
 * Permission to use, copy, modify, and distribute this software is
 * freely granted, provided that this notice is preserved.
 */
package org.jscience.mathematics.vector;

import java.util.Iterator;
import java.util.List;

import javolution.context.ConcurrentContext;
import javolution.context.ObjectFactory;
import javolution.lang.MathLib;
import javolution.util.FastTable;
import org.jscience.mathematics.structure.Field;

/**
 * 

This class represents a matrix made of {@link DenseVector dense * vectors} (as rows). To create a dense matrix made of column vectors the * {@link #transpose} method can be used. * For example:[code] * DenseVector column0 = DenseVector.valueOf(...); * DenseVector column1 = DenseVector.valueOf(...); * DenseMatrix M = DenseMatrix.valueOf(column0, column1).transpose(); * [/code]

*

As for any concrete {@link org.jscience.mathematics.structure.Structure * structure}, this class is declared final (otherwise most * operations would have to be overridden to return the appropriate type). * Specialized dense matrix should sub-class {@link Matrix} directly. * For example:[code] * // Extension through composition. * final class TriangularMatrix > extends Matrix { * private DenseMatrix _value; // Possible implementation. * ... * public TriangularMatrix opposite() { // Returns the right type. * return TriangularMatrix.valueOf(_value.opposite()); * } * ... * }[/code] *

* @author Jean-Marie Dautelle * @version 3.3, January 2, 2007 */ public final class DenseMatrix> extends Matrix { /** * Holds the number of columns n. */ int _n; /** * Indicates if this matrix is transposed (the rows are then the columns). */ boolean _transposed; /** * Holds this matrix rows (or columns when transposed). */ final FastTable> _rows = new FastTable>(); /** * Returns a dense matrix from the specified 2-dimensional array. * The first dimension being the row and the second being the column. * * @param elements this matrix elements. * @return the matrix having the specified elements. * @throws DimensionException if rows have different length. * @see DenseMatrix */ public static > DenseMatrix valueOf(F[][] elements) { int m = elements.length; int n = elements[0].length; DenseMatrix M = DenseMatrix.newInstance(n, false); for (int i = 0; i < m; i++) { DenseVector row = DenseVector.valueOf(elements[i]); if (row.getDimension() != n) throw new DimensionException(); M._rows.add(row); } return M; } /** * Returns a dense matrix holding the specified row vectors * (column vectors if {@link #transpose transposed}). * * @param rows the row vectors. * @return the matrix having the specified rows. * @throws DimensionException if the rows do not have the same dimension. */ public static > DenseMatrix valueOf( DenseVector... rows) { final int n = rows[0].getDimension(); DenseMatrix M = DenseMatrix.newInstance(n, false); for (int i = 0, m = rows.length; i < m; i++) { DenseVector rowi = rows[i]; if (rowi.getDimension() != n) throw new DimensionException( "All vectors must have the same dimension."); M._rows.add(rowi); } return M; } /** * Returns a dense matrix holding the row vectors from the specified * collection (column vectors if {@link #transpose transposed}). * * @param rows the list of row vectors. * @return the matrix having the specified rows. * @throws DimensionException if the rows do not have the same dimension. */ public static > DenseMatrix valueOf( List> rows) { final int n = rows.get(0).getDimension(); DenseMatrix M = DenseMatrix.newInstance(n, false); Iterator> iterator = rows.iterator(); for (int i = 0, m = rows.size(); i < m; i++) { DenseVector rowi = iterator.next(); if (rowi.getDimension() != n) throw new DimensionException( "All vectors must have the same dimension."); M._rows.add(rowi); } return M; } /** * Returns a dense matrix equivalent to the specified matrix. * * @param that the matrix to convert. * @return that or a dense matrix holding the same elements * as the specified matrix. */ public static > DenseMatrix valueOf(Matrix that) { if (that instanceof DenseMatrix) return (DenseMatrix) that; int n = that.getNumberOfColumns(); int m = that.getNumberOfRows(); DenseMatrix M = DenseMatrix.newInstance(n, false); for (int i = 0; i < m; i++) { DenseVector rowi = DenseVector.valueOf(that.getRow(i)); M._rows.add(rowi); } return M; } @Override public int getNumberOfRows() { return _transposed ? _n : _rows.size(); } @Override public int getNumberOfColumns() { return _transposed ? _rows.size() : _n; } @Override public F get(int i, int j) { return _transposed ? _rows.get(j).get(i) : _rows.get(i).get(j); } @Override public DenseVector getRow(int i) { if (!_transposed) return _rows.get(i); // Else transposed. int n = _rows.size(); int m = _n; if ((i < 0) || (i >= m)) throw new DimensionException(); DenseVector V = DenseVector.newInstance(); for (int j = 0; j < n; j++) { V._elements.add(_rows.get(j).get(i)); } return V; } @Override public DenseVector getColumn(int j) { if (_transposed) return _rows.get(j); int m = _rows.size(); if ((j < 0) || (j >= _n)) throw new DimensionException(); DenseVector V = DenseVector.newInstance(); for (int i = 0; i < m; i++) { V._elements.add(_rows.get(i).get(j)); } return V; } @Override public DenseVector getDiagonal() { int m = this.getNumberOfRows(); int n = this.getNumberOfColumns(); int dimension = MathLib.min(m, n); DenseVector V = DenseVector.newInstance(); for (int i = 0; i < dimension; i++) { V._elements.add(this.get(i, i)); } return V; } @Override public DenseMatrix opposite() { DenseMatrix M = DenseMatrix.newInstance(_n, _transposed); for (int i = 0, p = _rows.size(); i < p; i++) { M._rows.add(_rows.get(i).opposite()); } return M; } @Override public DenseMatrix plus(Matrix that) { if (this.getNumberOfRows() != that.getNumberOfRows()) throw new DimensionException(); DenseMatrix M = DenseMatrix.newInstance(_n, _transposed); for (int i = 0, p = _rows.size(); i < p; i++) { M._rows.add(_rows.get(i).plus( _transposed ? that.getColumn(i) : that.getRow(i))); } return M; } @Override public DenseMatrix minus(Matrix that) { // Returns more specialized type. return this.plus(that.opposite()); } @Override public DenseMatrix times(F k) { DenseMatrix M = DenseMatrix.newInstance(_n, _transposed); for (int i = 0, p = _rows.size(); i < p; i++) { M._rows.add(_rows.get(i).times(k)); } return M; } @Override public DenseVector times(Vector v) { if (v.getDimension() != this.getNumberOfColumns()) throw new DimensionException(); final int m = this.getNumberOfRows(); DenseVector V = DenseVector.newInstance(); for (int i = 0; i < m; i++) { V._elements.add(this.getRow(i).times(v)); } return V; } @Override public DenseMatrix times(Matrix that) { final int n = this.getNumberOfColumns(); final int m = this.getNumberOfRows(); final int p = that.getNumberOfColumns(); if (that.getNumberOfRows() != n) throw new DimensionException(); // Creates a mxp matrix in transposed form (p columns vectors of size m) DenseMatrix M = DenseMatrix.newInstance(m, true); // Transposed. M._rows.setSize(p); Multiply multiply = Multiply.valueOf(this, that, 0, p, M._rows); multiply.run(); Multiply.recycle(multiply); return M; } // Logic to multiply two matrices. private static class Multiply> implements Runnable { private static final ObjectFactory FACTORY = new ObjectFactory() { @Override protected Multiply create() { return new Multiply(); } }; private DenseMatrix _left; private Matrix _right; private int _rightColumnStart; private int _rightColumnEnd; private FastTable> _columnsResult; @SuppressWarnings("unchecked") static > Multiply valueOf(DenseMatrix left, Matrix right, int rightColumnStart, int rightColumnEnd, FastTable> columnsResult) { Multiply multiply = Multiply.FACTORY.object(); multiply._left = left; multiply._right = right; multiply._rightColumnStart = rightColumnStart; multiply._rightColumnEnd = rightColumnEnd; multiply._columnsResult = columnsResult; return multiply; } static > void recycle(Multiply multiply) { multiply._left = null; multiply._right = null; multiply._columnsResult = null; Multiply.FACTORY.recycle(multiply); } public void run() { if (_rightColumnEnd - _rightColumnStart < 32) { // Direct calculation. FastTable> rows = _left.getRows(); final int m = rows.size(); for (int j = _rightColumnStart; j < _rightColumnEnd; j++) { Vector thatColj = _right.getColumn(j); DenseVector column = DenseVector.newInstance(); _columnsResult.set(j, column); for (int i = 0; i < m; i++) { column._elements.add(rows.get(i).times(thatColj)); } } } else { // Concurrent/Recursive calculation. int halfIndex = (_rightColumnStart + _rightColumnEnd) >> 1; Multiply firstHalf = Multiply.valueOf(_left, _right, _rightColumnStart, halfIndex, _columnsResult); Multiply secondHalf = Multiply.valueOf(_left, _right, halfIndex, _rightColumnEnd, _columnsResult); ConcurrentContext.enter(); try { ConcurrentContext.execute(firstHalf); ConcurrentContext.execute(secondHalf); } finally { ConcurrentContext.exit(); } Multiply.recycle(firstHalf); Multiply.recycle(secondHalf); } } } private FastTable> getRows() { if (!_transposed) return _rows; FastTable> rows = FastTable.newInstance(); for (int i = 0; i < _n; i++) { rows.add(this.getRow(i)); } return rows; } @Override public DenseMatrix inverse() { if (!isSquare()) throw new DimensionException("Matrix not square"); return LUDecomposition.valueOf(this).inverse(); } @Override public F determinant() { return LUDecomposition.valueOf(this).determinant(); } @Override public DenseMatrix transpose() { DenseMatrix M = DenseMatrix.newInstance(_n, !_transposed); M._rows.addAll(this._rows); return M; } @Override public F cofactor(int i, int j) { if (_transposed) { int k = i; i = j; j = k; // Swaps i,j } int m = _rows.size(); DenseMatrix M = DenseMatrix.newInstance(m - 1, _transposed); for (int k1 = 0; k1 < m; k1++) { if (k1 == i) continue; DenseVector row = _rows.get(k1); DenseVector V = DenseVector.newInstance(); M._rows.add(V); for (int k2 = 0; k2 < _n; k2++) { if (k2 == j) continue; V._elements.add(row.get(k2)); } } return M.determinant(); } @Override public DenseMatrix adjoint() { DenseMatrix M = DenseMatrix.newInstance(_n, _transposed); int m = _rows.size(); for (int i = 0; i < m; i++) { DenseVector row = DenseVector.newInstance(); M._rows.add(row); for (int j = 0; j < _n; j++) { F cofactor = _transposed ? cofactor(j, i) : cofactor(i, j); row._elements.add(((i + j) % 2 == 0) ? cofactor : cofactor .opposite()); } } return M.transpose(); } @Override public Matrix tensor(Matrix that) { final int thism = this.getNumberOfRows(); final int thisn = this.getNumberOfColumns(); final int thatm = that.getNumberOfRows(); final int thatn = that.getNumberOfColumns(); int n = thisn * thatn; // Number of columns, int m = thism * thatm; // Number of rows. DenseMatrix M = DenseMatrix.newInstance(n, false); for (int i = 0; i < m; i++) { // Row index. final int i_rem_thatm = i % thatm; final int i_div_thatm = i / thatm; DenseVector row = DenseVector.newInstance(); M._rows.add(row); for (int j = 0; j < thisn; j++) { F a = this.get(i_div_thatm, j); for (int k = 0; k < thatn; k++) { row._elements.add(a.times(that.get(i_rem_thatm, k))); } } } return M; } @Override public Vector vectorization() { DenseVector V = DenseVector.newInstance(); for (int j = 0, n = this.getNumberOfColumns(); j < n; j++) { Vector column = this.getColumn(j); for (int i = 0, m = column.getDimension(); i < m; i++) { V._elements.add(column.get(i)); } } return V; } @Override public DenseMatrix copy() { DenseMatrix M = DenseMatrix.newInstance(_n, _transposed); for (DenseVector row : _rows) { M._rows.add(row.copy()); } return M; } /////////////////////////////// // Package Private Utilities // /////////////////////////////// void set(int i, int j, F e) { if (_transposed) { _rows.get(j)._elements.set(i, e); } else { _rows.get(i)._elements.set(j, e); } } /////////////////////// // Factory creation. // /////////////////////// @SuppressWarnings("unchecked") static > DenseMatrix newInstance(int n, boolean transposed) { DenseMatrix M = FACTORY.object(); M._n = n; M._transposed = transposed; return M; } private static ObjectFactory FACTORY = new ObjectFactory() { @Override protected DenseMatrix create() { return new DenseMatrix(); } @Override protected void cleanup(DenseMatrix matrix) { matrix._rows.reset(); } }; private DenseMatrix() { } private static final long serialVersionUID = 1L; }

Ads help maintain this website.