/*
 * 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.number.Float64;

/**
 * 

This class represents an optimized {@link Matrix matrix} implementation * for {@link Float64 64 bits floating-point} numbers.

* *

Instances of this class can be created from {@link Float64Vector}, * either as rows or columns if the matrix is transposed. For example:[code] * Float64Vector column0 = Float64Vector.valueOf(...); * Float64Vector column1 = Float64Vector.valueOf(...); * Float64Matrix M = Float64Matrix.valueOf(column0, column1).transpose(); * [/code]

* * @author Jean-Marie Dautelle * @version 3.3, January 2, 2007 */ public final class Float64Matrix 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 a 2-dimensional array of double * values. The first dimension being the row and the second being the * column. * * @param values the array of double values. * @return the matrix having the specified elements. * @throws DimensionException if rows have different length. * @see Float64Vector */ public static Float64Matrix valueOf(double[][] values) { int m = values.length; int n = values[0].length; Float64Matrix M = Float64Matrix.newInstance(n, false); for (int i = 0; i < m; i++) { Float64Vector row = Float64Vector.valueOf(values[i]); if (row.getDimension() != n) throw new DimensionException(); M._rows.add(row); } return M; } /** * Returns a complex 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 Float64Matrix valueOf(Float64Vector... rows) { final int n = rows[0].getDimension(); Float64Matrix M = Float64Matrix.newInstance(n, false); for (int i = 0, m = rows.length; i < m; i++) { Float64Vector 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 complex 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 Float64Matrix valueOf(List rows) { final int n = rows.get(0).getDimension(); Float64Matrix M = Float64Matrix.newInstance(n, false); Iterator iterator = rows.iterator(); for (int i = 0, m = rows.size(); i < m; i++) { Float64Vector 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 complex matrix equivalent to the specified matrix. * * @param that the matrix to convert. * @return that or a complex matrix holding the same elements * as the specified matrix. */ public static Float64Matrix valueOf(Matrix that) { if (that instanceof Float64Matrix) return (Float64Matrix) that; int n = that.getNumberOfColumns(); int m = that.getNumberOfRows(); Float64Matrix M = Float64Matrix.newInstance(n, false); for (int i = 0; i < m; i++) { Float64Vector rowi = Float64Vector.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 Float64 get(int i, int j) { return _transposed ? _rows.get(j).get(i) : _rows.get(i).get(j); } @Override public Float64Vector 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(); Float64Vector V = Float64Vector.newInstance(n); for (int j = 0; j < n; j++) { V.set(j, _rows.get(j).get(i).doubleValue()); } return V; } @Override public Float64Vector getColumn(int j) { if (_transposed) return _rows.get(j); int m = _rows.size(); if ((j < 0) || (j >= _n)) throw new DimensionException(); Float64Vector V = Float64Vector.newInstance(m); for (int i = 0; i < m; i++) { V.set(i, _rows.get(i).get(j).doubleValue()); } return V; } @Override public Float64Vector getDiagonal() { int m = this.getNumberOfRows(); int n = this.getNumberOfColumns(); int dimension = MathLib.min(m, n); Float64Vector V = Float64Vector.newInstance(dimension); for (int i = 0; i < dimension; i++) { V.set(i, this.get(i, i).doubleValue()); } return V; } @Override public Float64Matrix opposite() { Float64Matrix M = Float64Matrix.newInstance(_n, _transposed); for (int i = 0, p = _rows.size(); i < p; i++) { M._rows.add(_rows.get(i).opposite()); } return M; } @Override public Float64Matrix plus(Matrix that) { if (this.getNumberOfRows() != that.getNumberOfRows()) throw new DimensionException(); Float64Matrix M = Float64Matrix.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 Float64Matrix minus(Matrix that) { // Returns more specialized type. return this.plus(that.opposite()); } @Override public Float64Matrix times(Float64 k) { Float64Matrix M = Float64Matrix.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 Float64Vector times(Vector v) { if (v.getDimension() != this.getNumberOfColumns()) throw new DimensionException(); final int m = this.getNumberOfRows(); Float64Vector V = Float64Vector.newInstance(m); for (int i = 0; i < m; i++) { V.set(i, this.getRow(i).times(v).doubleValue()); } return V; } @Override public Float64Matrix 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) Float64Matrix M = Float64Matrix.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 Float64Matrix _left; private Matrix _right; private int _rightColumnStart; private int _rightColumnEnd; private FastTable _columnsResult; static Multiply valueOf(Float64Matrix 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); Float64Vector column = Float64Vector.newInstance(m); _columnsResult.set(j, column); for (int i = 0; i < m; i++) { column.set(i, rows.get(i).times(thatColj) .doubleValue()); } } } 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 Float64Matrix inverse() { if (!isSquare()) throw new DimensionException("Matrix not square"); return Float64Matrix.valueOf(LUDecomposition.valueOf(this).inverse()); } @Override public Float64 determinant() { return LUDecomposition.valueOf(this).determinant(); } @Override public Float64Matrix transpose() { Float64Matrix M = Float64Matrix.newInstance(_n, !_transposed); M._rows.addAll(this._rows); return M; } @Override public Float64 cofactor(int i, int j) { if (_transposed) { int k = i; i = j; j = k; // Swaps i,j } int m = _rows.size(); Float64Matrix M = Float64Matrix.newInstance(m - 1, _transposed); for (int k1 = 0; k1 < m; k1++) { if (k1 == i) continue; Float64Vector row = _rows.get(k1); Float64Vector V = Float64Vector.newInstance(_n - 1); M._rows.add(V); for (int k2 = 0, k = 0; k2 < _n; k2++) { if (k2 == j) continue; V.set(k++, row.get(k2).doubleValue()); } } return M.determinant(); } @Override public Float64Matrix adjoint() { Float64Matrix M = Float64Matrix.newInstance(_n, _transposed); int m = _rows.size(); for (int i = 0; i < m; i++) { Float64Vector row = Float64Vector.newInstance(_n); M._rows.add(row); for (int j = 0; j < _n; j++) { Float64 cofactor = _transposed ? cofactor(j, i) : cofactor(i, j); row.set(j, ((i + j) % 2 == 0) ? cofactor.doubleValue() : cofactor.opposite().doubleValue()); } } return M.transpose(); } @Override public Float64Matrix tensor(Matrix that) { return Float64Matrix.valueOf(DenseMatrix.valueOf(this).tensor(that)); } @Override public Float64Vector vectorization() { return Float64Vector.valueOf(DenseMatrix.valueOf(this).vectorization()); } @Override public Float64Matrix copy() { Float64Matrix M = Float64Matrix.newInstance(_n, _transposed); for (Float64Vector row : _rows) { M._rows.add(row.copy()); } return M; } /////////////////////// // Factory creation. // /////////////////////// static Float64Matrix newInstance(int n, boolean transposed) { Float64Matrix M = FACTORY.object(); M._n = n; M._transposed = transposed; return M; } private static ObjectFactory FACTORY = new ObjectFactory() { @Override protected Float64Matrix create() { return new Float64Matrix(); } @Override protected void cleanup(Float64Matrix matrix) { matrix._rows.reset(); } }; private Float64Matrix() { } private static final long serialVersionUID = 1L; }

Ads help maintain this website.