/*
* Concept profile generation tool suite
* Copyright (C) 2015 Biosemantics Group, Erasmus University Medical Center,
* Rotterdam, The Netherlands
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU Affero General Public License as published
* by the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU Affero General Public License for more details.
*
* You should have received a copy of the GNU Affero General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/>
*/
package org.erasmusmc.math.matrix;
import java.io.FileOutputStream;
import java.io.IOException;
import java.util.Iterator;
import org.erasmusmc.math.space.Space;
import org.erasmusmc.math.vector.ColumnVector;
import org.erasmusmc.math.vector.RowVector;
import org.erasmusmc.math.vector.Vector;
import org.erasmusmc.math.vector.VectorCursor;
public abstract class Matrix<R, C> {
public Matrix() {
}
public Matrix(Space<R> rowSpace, Space<C> columnSpace) {
setSpaces(rowSpace, columnSpace);
}
public Matrix(Matrix<R, C> matrix) {
setSpaces(matrix.getRowSpace(), matrix.getColumnSpace());
set(matrix);
}
public abstract void set(R row, C column, double value);
public abstract double get(R row, C column);
public abstract Space<R> getRowSpace();
public abstract Space<C> getColumnSpace();
public abstract void setSpaces(Space<R> rowSpace, Space<C> columnSpace);
public abstract MatrixCursor<R, C> getRowCursor();
public abstract MatrixCursor<C, R> getColumnCursor();
public Vector<R> getColumn(C column) {
return new ColumnVector<R, C>(this, column);
}
public Vector<C> getRow(R row) {
return new RowVector<R, C>(this, row);
}
public void zeroes() {
constants(0);
}
public void ones() {
constants(1);
}
public void constants(double value) {
for (R row: getRowSpace())
for (C column: getColumnSpace())
set(row, column, value);
}
public void identity() {
zeroes();
setMainDiagonal(1);
}
public void set(Matrix<R, C> matrix) {
MatrixCursor<R, C> rowCursor = getRowCursor();
MatrixCursor<R, C> sourceRowCursor = matrix.getRowCursor();
while (rowCursor.isValid()) {
VectorCursor<C> columnCursor = rowCursor.get().getCursor();
VectorCursor<C> sourceColumnCursor = sourceRowCursor.get().getCursor();
while (columnCursor.isValid()) {
columnCursor.set(sourceColumnCursor.get());
columnCursor.next();
sourceColumnCursor.next();
}
rowCursor.next();
sourceRowCursor.next();
}
}
public void copyFrom(Matrix<R, C> matrix) {
setSpaces(matrix.getRowSpace(), matrix.getColumnSpace());
set(matrix);
}
public AllValueCursor<R, C> getAllValueCursor() {
return new AllValueCursor<R, C>(this);
}
public void dump() {
for (R row: getRowSpace()) {
for (C column: getColumnSpace())
System.out.print(get(row, column) + " | ");
System.out.println();
}
System.out.println();
}
public void dumpToFile(FileOutputStream os) {
try {
StringBuffer line = new StringBuffer();
for (C column: getColumnSpace()) {
line.append("\t");
line.append(column.toString());
}
line.append("\n");
os.write(line.toString().getBytes());
for (R row: getRowSpace()) {
line = new StringBuffer();
line.append(row.toString());
for (C column: getColumnSpace()) {
line.append("\t");
line.append(get(row, column));
}
line.append("\n");
os.write(line.toString().getBytes());
}
} catch (IOException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
}
public String dumpToString() {
StringBuffer result = new StringBuffer();
for (C column: getColumnSpace()) {
result.append("\t");
result.append(column.toString());
}
result.append("\n");
for (R row: getRowSpace()) {
result.append(row.toString());
for (C column: getColumnSpace()) {
result.append("\t");
result.append(get(row, column));
}
result.append("\n");
}
return result.toString();
}
public <D> void multiply(Matrix<R, D> result, Matrix<C, D> rhs) {
MatrixCursor<R, D> resultRowCursor = result.getRowCursor();
MatrixCursor<R, C> lhsRowCursor = getRowCursor();
while (lhsRowCursor.isValid()) {
Vector<C> rowVector = lhsRowCursor.get();
Vector<D> resultRowVector = resultRowCursor.get();
VectorCursor<D> resultColumnCursor = resultRowVector.getCursor();
MatrixCursor<D, C> rhsColumnCursor = rhs.getColumnCursor();
while (rhsColumnCursor.isValid()) {
resultColumnCursor.set(rowVector.innerProduct(rhsColumnCursor.get()));
rhsColumnCursor.next();
resultColumnCursor.next();
}
lhsRowCursor.next();
resultRowCursor.next();
}
}
public <D> RowArrayMatrix<R, D> multiply(Matrix<C, D> rhs) {
RowArrayMatrix<R, D> result = new RowArrayMatrix<R, D>(getRowSpace(), rhs.getColumnSpace());
multiply(result, rhs);
return result;
}
public void multiply(double value) {
AllValueCursor<R, C> cursor = getAllValueCursor();
while (cursor.isValid()) {
cursor.set(cursor.get() * value);
cursor.next();
}
}
public void divide(double value) {
AllValueCursor<R, C> cursor = getAllValueCursor();
while (cursor.isValid()) {
cursor.set(cursor.get() / value);
cursor.next();
}
}
public void add(double value) {
AllValueCursor<R, C> cursor = getAllValueCursor();
while (cursor.isValid()) {
cursor.set(cursor.get() + value);
cursor.next();
}
}
public Matrix<C, R> invert() throws Exception {
PermutedLUDecomposition<R, C> decomposition = new PermutedLUDecomposition<R, C>(this);
Matrix<C, R> inverse = new RowArrayMatrix<C, R>(getColumnSpace(), getRowSpace());
inverse.identity();
decomposition.substituteBack(inverse);
return inverse;
}
public void setMainDiagonal(double value) {
Iterator<R> rowIterator = getRowSpace().iterator();
Iterator<C> columnIterator = getColumnSpace().iterator();
while (rowIterator.hasNext() && columnIterator.hasNext())
set(rowIterator.next(), columnIterator.next(), value);
}
public double maximum() {
double result = Double.MIN_VALUE;
for (R row: getRowSpace())
for (C column: getColumnSpace())
result = Math.max(get(row, column), result);
return result;
}
public double minimum() {
double result = Double.MAX_VALUE;
AllValueCursor<R, C> cursor = getAllValueCursor();
while (cursor.isValid()) {
result = Math.min(cursor.get(), result);
cursor.next();
}
return result;
}
}