/*
* Copyright 2011, Vladimir Kostyukov
*
* This file is part of la4j project (http://la4j.googlecode.com)
*
* Licensed under the Apache License, Version 2.0 (the "License");
* You may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package la4j.matrix;
import la4j.decomposition.MatrixDecompositor;
import la4j.err.MatrixDecompositionException;
import la4j.err.MatrixException;
import la4j.err.MatrixInversionException;
import la4j.factory.Factory;
import la4j.inversion.MatrixInvertor;
import la4j.vector.Vector;
public abstract class AbstractMatrix implements Matrix {
protected int rows;
protected int columns;
protected Factory factory;
public AbstractMatrix(Factory factory) {
this.factory = factory;
}
@Override
public int rows() {
return rows;
}
@Override
public int columns() {
return columns;
}
@Override
public Matrix transpose() {
return transpose(factory);
}
@Override
public double determinant() {
return triangularize().trace();
}
@Override
public Matrix multiply(double value) {
return multiply(value, factory);
}
@Override
public Matrix multiply(double value, Factory factory) {
if (factory == null) throw new NullPointerException();
Matrix result = factory.createMatrix(rows, columns);
for (int i = 0; i < rows; i++) {
for (int j = 0; j < columns; j++) {
result.set(i, j, get(i, j) * value);
}
}
return result;
}
@Override
public Vector multiply(Vector vector) throws MatrixException {
return multiply(vector, factory);
}
@Override
public Vector multiply(Vector vector, Factory factory) throws MatrixException {
if (vector == null || factory == null) throw new NullPointerException();
if (columns != vector.length()) {
throw new MatrixException("can not multiply this matrix on vector: wrong dimmentions");
}
Vector result = factory.createVector(columns);
for (int i = 0; i < rows; i++) {
double summand = 0;
for (int j = 0; j < columns; j++) {
summand += get(i, j) * vector.get(j);
}
result.set(i, summand);
}
return result;
}
@Override
public Matrix multiply(Matrix matrix) throws MatrixException {
return multiply(matrix, factory);
}
@Override
public Matrix multiply(Matrix matrix, Factory factory) throws MatrixException {
if (matrix == null || factory == null) throw new NullPointerException();
if (columns != matrix.rows()) {
throw new MatrixException("can not multiply this matrix: wrong dimmentions");
}
Matrix result = factory.createMatrix(rows, columns);
for (int j = 0; j < matrix.columns(); j++) {
Vector thatColumn = matrix.getColumn(j);
for (int i = 0; i < rows; i++) {
Vector thisRow = getRow(i);
double summand = 0;
for (int k = 0; k < columns; k++) {
summand += thisRow.get(k) * thatColumn.get(k);
}
result.set(i, j, summand);
}
}
return result;
}
@Override
public Matrix subtract(double value) {
return subtract(value, factory);
}
@Override
public Matrix subtract(double value, Factory factory) {
return add(-value, factory);
}
@Override
public Matrix subtract(Matrix matrix) throws MatrixException {
return subtract(matrix, factory);
}
@Override
public Matrix subtract(Matrix matrix, Factory factory) throws MatrixException {
return add(matrix.multiply(-1.0), factory);
}
@Override
public Matrix add(double value) {
return add(value, factory);
}
@Override
public Matrix add(double value, Factory factory) {
if (factory == null) throw new NullPointerException();
Matrix result = factory.createMatrix(rows, columns);
for (int i = 0; i < rows; i++) {
for (int j = 0; j < columns; j++) {
result.set(i, j, get(i, j) + value);
}
}
return result;
}
@Override
public Matrix add(Matrix matrix) throws MatrixException {
return add(matrix, factory);
}
@Override
public Matrix add(Matrix matrix, Factory factory) throws MatrixException {
if (matrix == null || factory == null) throw new NullPointerException();
if (rows != matrix.rows() || columns != matrix.columns()) {
throw new MatrixException("can not sum this matrix: wrong dimmentions");
}
Matrix result = factory.createMatrix(rows, columns);
for (int i = 0; i < rows; i++) {
for (int j = 0; j < columns; j++) {
result.set(i, j, get(i, j) + matrix.get(i, j));
}
}
return result;
}
@Override
public Matrix div(double value) {
return div(value, factory);
}
@Override
public Matrix div(double value, Factory factory) {
return multiply(1.0 / value, factory);
}
@Override
public double trace() {
double result = 1;
for (int i = 0; i < rows; i++) {
result *= get(i, i);
}
return result;
}
@Override
public boolean isSymmetric() {
if (rows != columns) return false;
boolean result = true;
for (int i = 0; i < rows; i++) {
for (int j = i + 1; j < columns; j++) {
result = result && (Math.abs(get(i, j) - get(j, i)) < EPS);
}
}
return result && rows > 0 && columns > 0;
}
@Override
public boolean isTriangle() {
boolean result = true;
for (int i = 1; i < rows; i++) {
for (int j = 0; j < i; j++) {
result = result && (Math.abs(get(i, j)) < EPS);
}
}
return result && rows > 0 && columns > 0;
}
@Override
public Matrix triangularize() {
return triangularize(factory);
}
@Override
public Matrix triangularize(Factory factory) {
if (isTriangle()) return this;
if (factory == null) throw new NullPointerException();
Matrix result = factory.createMatrix(rows, columns);
for (int i = 0; i < rows; i++) {
for (int j = i + 1; j < rows; j++) {
double c = get(j, i) / get(i, i);
for (int k = i; k < columns; k++) {
if (k == i) {
result.set(j, k, 0.0);
} else {
result.set(j, k, get(j, k) - (get(i, k) * c));
}
}
}
}
return result;
}
@Override
public Matrix[] decompose(MatrixDecompositor decompositor) throws MatrixDecompositionException {
return decompose(decompositor, factory);
}
@Override
public Matrix[] decompose(MatrixDecompositor decompositor, Factory factory) throws MatrixDecompositionException {
return decompositor.decompose(this, factory);
}
@Override
public Matrix inverse(MatrixInvertor invertor) throws MatrixInversionException {
return inverse(invertor, factory);
}
@Override
public Matrix inverse(MatrixInvertor invertor, Factory factory) throws MatrixInversionException {
return invertor.inverse(this, factory);
}
@Override
public Matrix blank() {
return blank(factory);
}
@Override
public Matrix blank(Factory factory) {
if (factory == null) throw new NullPointerException();
return factory.createMatrix(rows, columns);
}
@Override
public Matrix copy() {
return copy(factory);
}
@Override
public Matrix copy(Factory factory) {
if (factory == null) throw new NullPointerException();
Matrix result = factory.createMatrix(rows, columns);
for (int i = 0; i < rows; i++) {
for (int j = 0; j < columns; j++) {
result.set(i, j, get(i, j));
}
}
return result;
}
@Override
public int hashCode() {
int result = 17;
for (int i = 0; i < rows; i++) {
for (int j = 0; j < columns; j++) {
long value = (long) get(i, j);
result = 37 * result + (int) (value ^ (value >>> 32));
}
}
return result;
}
@Override
public boolean equals(Object object) {
if (this == object) return true;
if (object == null) return false;
if (!(object instanceof Matrix)) return false;
Matrix matrix = (Matrix) object;
if (rows != matrix.rows() || columns != matrix.columns()) return false;
boolean result = true;
for (int i = 0; result && i < rows; i++) {
for (int j = 0; result && j < columns; j++) {
result = result & (Math.abs(get(i, j) - matrix.get(i, j)) < EPS);
}
}
return result;
}
@Override
public String toString() {
StringBuilder sb = new StringBuilder();
for (int i = 0; i < rows; i++) {
for (int j = 0; j < columns; j++) {
sb.append(String.format("%8.3f", get(i, j)));
}
sb.append("\n");
}
return sb.toString();
}
@Override
public Matrix clone() {
try {
return (Matrix) super.clone();
} catch (CloneNotSupportedException ex) {
throw new InternalError();
}
}
}