/*
* Copyright 2011-2014, by Vladimir Kostyukov and Contributors.
*
* This file is part of la4j project (http://la4j.org)
*
* 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.
*
* Contributor(s): Yuriy Drozd
* Ewald Grusk
* Maxim Samoylov
* Miron Aseev
* Todd Brunhoff
*
*/
package org.la4j;
import java.math.BigDecimal;
import java.math.RoundingMode;
import org.la4j.matrix.MatrixFactory;
import org.la4j.matrix.dense.Basic1DMatrix;
import org.la4j.matrix.dense.Basic2DMatrix;
import org.la4j.matrix.functor.AdvancedMatrixPredicate;
import org.la4j.matrix.functor.MatrixAccumulator;
import org.la4j.matrix.functor.MatrixFunction;
import org.la4j.matrix.functor.MatrixPredicate;
import org.la4j.matrix.functor.MatrixProcedure;
import org.la4j.matrix.sparse.CCSMatrix;
import org.la4j.matrix.sparse.CRSMatrix;
public final class Matrices {
/**
* The machine epsilon, that is calculated at runtime.
*/
public static final double EPS = LinearAlgebra.EPS;
/**
* Exponent of machine epsilon
*/
public static final int ROUND_FACTOR = LinearAlgebra.ROUND_FACTOR;
/**
* Checks whether the matrix is a
* <a href="http://mathworld.wolfram.com/DiagonalMatrix.html">diagonal
* matrix</a>.
*/
public static final MatrixPredicate DIAGONAL_MATRIX = new MatrixPredicate() {
@Override
public boolean test(int rows, int columns) {
return rows == columns;
}
@Override
public boolean test(int i, int j, double value) {
return (i == j) || Math.abs(value) < EPS;
}
};
/**
* Checks whether the matrix is an
* <a href="http://mathworld.wolfram.com/IdentityMatrix.html">identity
* matrix</a>.
*/
public static final MatrixPredicate IDENTITY_MATRIX = new MatrixPredicate() {
@Override
public boolean test(int rows, int columns) {
return rows == columns;
}
@Override
public boolean test(int i, int j, double value) {
return (i == j) ? Math.abs(1.0 - value) < EPS
: Math.abs(value) < EPS;
}
};
/**
* Checks whether the matrix is a
* <a href="http://mathworld.wolfram.com/ZeroMatrix.html">zero
* matrix</a>.
*/
public static final MatrixPredicate ZERO_MATRIX = new MatrixPredicate() {
@Override
public boolean test(int rows, int columns) {
return true;
}
@Override
public boolean test(int i, int j, double value) {
return Math.abs(value) < EPS;
}
};
/**
* Checks whether the matrix is a
* <a href="http://mathworld.wolfram.com/TridiagonalMatrix.html">tridiagonal
* matrix</a>.
*/
public static final MatrixPredicate TRIDIAGONAL_MATRIX = new MatrixPredicate() {
@Override
public boolean test(int rows, int columns) {
return rows == columns;
}
@Override
public boolean test(int i, int j, double value) {
return Math.abs(i - j) <= 1 || Math.abs(value) < EPS;
}
};
/**
* Checks whether the matrix is a
* <a href="http://mathworld.wolfram.com/PositiveMatrix.html">positive
* matrix</a>.
*/
public static final MatrixPredicate POSITIVE_MATRIX = new MatrixPredicate() {
@Override
public boolean test(int rows, int columns) {
return true;
}
@Override
public boolean test(int i, int j, double value) {
return value > 0.0;
}
};
/**
* Checks whether the matrix is a
* <a href="http://mathworld.wolfram.com/NegativeMatrix.html">negative
* matrix</a>.
*/
public static final MatrixPredicate NEGATIVE_MATRIX = new MatrixPredicate() {
@Override
public boolean test(int rows, int columns) {
return true;
}
@Override
public boolean test(int i, int j, double value) {
return value < 0.0;
}
};
/**
* Checks whether the matrix is a lower bi-diagonal matrix</a>.
*/
public static final MatrixPredicate LOWER_BIDIAGONAL_MATRIX = new MatrixPredicate() {
@Override
public boolean test(int rows, int columns) {
return rows == columns;
}
@Override
public boolean test(int i, int j, double value) {
return !((i == j) || (i == j + 1)) || Math.abs(value) < EPS;
}
};
/**
* Checks whether the matrix is an upper bidiagonal matrix.
*/
public static final MatrixPredicate UPPER_BIDIAGONAL_MATRIX = new MatrixPredicate() {
@Override
public boolean test(int rows, int columns) {
return rows == columns;
}
@Override
public boolean test(int i, int j, double value) {
return !((i == j) || (i == j - 1)) || Math.abs(value) < EPS;
}
};
/**
* Checks whether the matrix is a
* <a href="http://mathworld.wolfram.com/LowerTriangularMatrix.html">lower
* triangular matrix</a>.
*/
public static final MatrixPredicate LOWER_TRIANGULAR_MATRIX = new MatrixPredicate() {
@Override
public boolean test(int rows, int columns) {
return rows == columns;
}
@Override
public boolean test(int i, int j, double value) {
return (i <= j) || Math.abs(value) < EPS;
}
};
/**
* Checks whether the matrix is an
* <a href="http://mathworld.wolfram.com/UpperTriangularMatrix.html">upper
* triangular matrix</a>.
*/
public static final MatrixPredicate UPPER_TRIANGULAR_MATRIX = new MatrixPredicate() {
@Override
public boolean test(int rows, int columns) {
return rows == columns;
}
@Override
public boolean test(int i, int j, double value) {
return (i >= j) || Math.abs(value) < EPS;
}
};
/**
* Checks whether the matrix is a
* <a href="http://mathworld.wolfram.com/SymmetricMatrix.html">symmetric
* matrix</a>.
*/
public static final AdvancedMatrixPredicate SYMMETRIC_MATRIX =
new SymmetricMatrixPredicate();
/**
* Checks whether the matrix is a
* <a href="http://en.wikipedia.org/wiki/Diagonally_dominant_matrix">diagonally dominant matrix</a>.
*/
public static final AdvancedMatrixPredicate DIAGONALLY_DOMINANT_MATRIX =
new DiagonallyDominantPredicate();
/**
* Checks whether the matrix is positive definite.
*/
public static final AdvancedMatrixPredicate POSITIVE_DEFINITE_MATRIX =
new PositiveDefiniteMatrixPredicate();
/**
* A matrix factory that produces zero {@link Basic2DMatrix}.
*/
public static final MatrixFactory<Basic2DMatrix> BASIC_2D =
new MatrixFactory<Basic2DMatrix>() {
@Override
public Basic2DMatrix apply(int rows, int columns) {
return Basic2DMatrix.zero(rows, columns);
}
};
/**
* A matrix factory that produces zero {@link Basic1DMatrix}.
*/
public static final MatrixFactory<Basic1DMatrix> BASIC_1D =
new MatrixFactory<Basic1DMatrix>() {
@Override
public Basic1DMatrix apply(int rows, int columns) {
return Basic1DMatrix.zero(rows, columns);
}
};
/**
* A default matrix factory for dense matrices.
*/
public static final MatrixFactory<Basic2DMatrix> DENSE = BASIC_2D;
/**
* A matrix factory that produces zero {@link CCSMatrix}.
*/
public static final MatrixFactory<CCSMatrix> CCS =
new MatrixFactory<CCSMatrix>() {
@Override
public CCSMatrix apply(int rows, int columns) {
return CCSMatrix.zero(rows, columns);
}
};
/**
* A matrix factory that produces zero {@link CRSMatrix}.
*/
public static final MatrixFactory<CRSMatrix> CRS =
new MatrixFactory<CRSMatrix>() {
@Override
public CRSMatrix apply(int rows, int columns) {
return CRSMatrix.zero(rows, columns);
}
};
/**
* A default factory for sparse matrices.
*/
public static final MatrixFactory<CRSMatrix> SPARSE = CRS;
/**
* A default factory for sparse row-major matrices.
*/
public static final MatrixFactory<CRSMatrix> SPARSE_ROW_MAJOR = CRS;
/**
* A default factory for sparse column-major matrices.
*/
public static final MatrixFactory<CCSMatrix> SPARSE_COLUMN_MAJOR = CCS;
public static final MatrixFactory<?>[] CONVERTERS = {
BASIC_2D, BASIC_1D, CRS, CCS
};
/**
* Increases each element of matrix by <code>1</code>.
*/
public static final MatrixFunction INC_FUNCTION = new MatrixFunction() {
@Override
public double evaluate(int i, int j, double value) {
return value + 1.0;
}
};
/**
* Decreases each element of matrix by <code>1</code>.
*/
public static final MatrixFunction DEC_FUNCTION = new MatrixFunction() {
@Override
public double evaluate(int i, int j, double value) {
return value - 1.0;
}
};
/**
* Inverts each element of matrix.
*/
public static final MatrixFunction INV_FUNCTION = new MatrixFunction() {
@Override
public double evaluate(int i, int j, double value) {
return -value;
}
};
private Matrices() {}
private static class SymmetricMatrixPredicate
implements AdvancedMatrixPredicate {
@Override
public boolean test(Matrix matrix) {
if (matrix.rows() != matrix.columns()) {
return false;
}
for (int i = 0; i < matrix.rows(); i++) {
for (int j = i + 1; j < matrix.columns(); j++) {
double a = matrix.get(i, j);
double b = matrix.get(j, i);
double diff = Math.abs(a - b);
if (diff / Math.max(Math.abs(a), Math.abs(b)) > EPS) {
return false;
}
}
}
return true;
}
}
private static class DiagonallyDominantPredicate
implements AdvancedMatrixPredicate {
@Override
public boolean test(Matrix matrix) {
if (matrix.rows() != matrix.columns()) {
return false;
}
for (int i = 0; i < matrix.rows(); i++) {
double sum = 0;
for (int j = 0; j < matrix.columns(); j++) {
if (i != j) {
sum += Math.abs(matrix.get(i, j));
}
}
if (sum > Math.abs(matrix.get(i, i)) - EPS) {
return false;
}
}
return true;
}
}
private static class PositiveDefiniteMatrixPredicate implements AdvancedMatrixPredicate {
@Override
public boolean test(Matrix matrix) {
if (matrix.rows() != matrix.columns()) {
return false;
}
int size = matrix.columns();
int currentSize = 1;
while (currentSize <= size) {
Matrix topLeftMatrix = matrix.sliceTopLeft(currentSize, currentSize);
if (topLeftMatrix.determinant() < 0) {
return false;
}
currentSize++;
}
return true;
}
}
/**
* Creates a const function that evaluates it's argument to given {@code value}.
*
* @param arg a const value
*
* @return a closure object that does {@code _}
*/
public static MatrixFunction asConstFunction(final double arg) {
return new MatrixFunction() {
@Override
public double evaluate(int i, int j, double value) {
return arg;
}
};
}
/**
* Creates a plus function that adds given {@code value} to it's argument.
*
* @param arg a value to be added to function's argument
*
* @return a closure object that does {@code _ + _}
*/
public static MatrixFunction asPlusFunction(final double arg) {
return new MatrixFunction() {
@Override
public double evaluate(int i, int j, double value) {
return value + arg;
}
};
}
/**
* Creates a minus function that subtracts given {@code value} from it's argument.
*
* @param arg a value to be subtracted from function's argument
*
* @return a closure that does {@code _ - _}
*/
public static MatrixFunction asMinusFunction(final double arg) {
return new MatrixFunction() {
@Override
public double evaluate(int i, int j, double value) {
return value - arg;
}
};
}
/**
* Creates a mul function that multiplies given {@code value} by it's argument.
*
* @param arg a value to be multiplied by function's argument
*
* @return a closure that does {@code _ * _}
*/
public static MatrixFunction asMulFunction(final double arg) {
return new MatrixFunction() {
@Override
public double evaluate(int i, int j, double value) {
return value * arg;
}
};
}
/**
* Creates a div function that divides it's argument by given {@code value}.
*
* @param arg a divisor value
*
* @return a closure that does {@code _ / _}
*/
public static MatrixFunction asDivFunction(final double arg) {
return new MatrixFunction() {
@Override
public double evaluate(int i, int j, double value) {
return value / arg;
}
};
}
/**
* Creates a mod function that calculates the modulus of it's argument and given {@code value}.
*
* @param arg a divisor value
*
* @return a closure that does {@code _ % _}
*/
public static MatrixFunction asModFunction(final double arg) {
return new MatrixFunction() {
@Override
public double evaluate(int i, int j, double value) {
return value % arg;
}
};
}
/**
* Makes a minimum matrix accumulator that accumulates the minimum of matrix elements.
*
* @return a minimum vector accumulator
*/
public static MatrixAccumulator mkMinAccumulator() {
return new MatrixAccumulator() {
private double result = Double.POSITIVE_INFINITY;
@Override
public void update(int i, int j, double value) {
result = Math.min(result, value);
}
@Override
public double accumulate() {
double value = result;
result = Double.POSITIVE_INFINITY;
return value;
}
};
}
/**
* Makes a maximum matrix accumulator that accumulates the maximum of matrix elements.
*
* @return a maximum vector accumulator
*/
public static MatrixAccumulator mkMaxAccumulator() {
return new MatrixAccumulator() {
private double result = Double.NEGATIVE_INFINITY;
@Override
public void update(int i, int j, double value) {
result = Math.max(result, value);
}
@Override
public double accumulate() {
double value = result;
result = Double.NEGATIVE_INFINITY;
return value;
}
};
}
/**
* Makes an Euclidean norm accumulator that allows to use
* {@link org.la4j.Matrix#fold(org.la4j.vector.functor.MatrixAccumulator)}
* method for norm calculation.
*
* @return an Euclidean norm accumulator
*/
public static MatrixAccumulator mkEuclideanNormAccumulator() {
return new MatrixAccumulator() {
private BigDecimal result = BigDecimal.valueOf(0.0);
@Override
public void update(int i, int j, double value) {
result = result.add(BigDecimal.valueOf(value * value));
}
@Override
public double accumulate() {
double value = result.setScale(Matrices.ROUND_FACTOR, RoundingMode.CEILING).doubleValue();
result = BigDecimal.valueOf(0.0);
return Math.sqrt(value);
}
};
}
/**
* Makes an Manhattan norm accumulator that allows to use
* {@link org.la4j.Matrix#fold(org.la4j.vector.functor.MatrixAccumulator)}
* method for norm calculation.
*
* @return a Manhattan norm accumulator
*/
public static MatrixAccumulator mkManhattanNormAccumulator() {
return new MatrixAccumulator() {
private double result = 0.0;
@Override
public void update(int i, int j, double value) {
result += Math.abs(value);
}
@Override
public double accumulate() {
double value = result;
result = 0.0;
return value;
}
};
}
/**
* Makes an Infinity norm accumulator that allows to use
* {@link org.la4j.Matrix#fold(org.la4j.vector.functor.MatrixAccumulator)}
* method for norm calculation.
*
* @return an Infinity norm accumulator
*/
public static MatrixAccumulator mkInfinityNormAccumulator() {
return new MatrixAccumulator() {
private double result = Double.NEGATIVE_INFINITY;
@Override
public void update(int i, int j, double value) {
result = Math.max(result, Math.abs(value));
}
@Override
public double accumulate() {
double value = result;
result = Double.NEGATIVE_INFINITY;
return value;
}
};
}
/**
* Creates a sum matrix accumulator that calculates the sum of all elements in the matrix.
*
* @param neutral the neutral value
*
* @return a sum accumulator
*/
public static MatrixAccumulator asSumAccumulator(final double neutral) {
return new MatrixAccumulator() {
private BigDecimal result = BigDecimal.valueOf(neutral);
@Override
public void update(int i, int j, double value) {
result = result.add(BigDecimal.valueOf(value));
}
@Override
public double accumulate() {
double value = result.setScale(Matrices.ROUND_FACTOR, RoundingMode.CEILING).doubleValue();
result = BigDecimal.valueOf(neutral);
return value;
}
};
}
/**
* Creates a product matrix accumulator that calculates the product of all elements in the matrix.
*
* @param neutral the neutral value
*
* @return a product accumulator
*/
public static MatrixAccumulator asProductAccumulator(final double neutral) {
return new MatrixAccumulator() {
private BigDecimal result = BigDecimal.valueOf(neutral);
@Override
public void update(int i, int j, double value) {
result = result.multiply(BigDecimal.valueOf(value));
}
@Override
public double accumulate() {
double value = result.setScale(Matrices.ROUND_FACTOR, RoundingMode.CEILING).doubleValue();
result = BigDecimal.valueOf(neutral);
return value;
}
};
}
/**
* Creates a sum function accumulator, that calculates the sum of all
* elements in the matrix after applying given {@code function} to each of them.
*
* @param neutral the neutral value
* @param function the matrix function
*
* @return a sum function accumulator
*/
public static MatrixAccumulator asSumFunctionAccumulator(final double neutral, final MatrixFunction function) {
return new MatrixAccumulator() {
private final MatrixAccumulator sumAccumulator = Matrices.asSumAccumulator(neutral);
@Override
public void update(int i, int j, double value) {
sumAccumulator.update(i, j, function.evaluate(i, j, value));
}
@Override
public double accumulate() {
return sumAccumulator.accumulate();
}
};
}
/**
* Creates a product function accumulator, that calculates the product of
* all elements in the matrix after applying given {@code function} to
* each of them.
*
* @param neutral the neutral value
* @param function the matrix function
*
* @return a product function accumulator
*/
public static MatrixAccumulator asProductFunctionAccumulator(final double neutral,
final MatrixFunction function) {
return new MatrixAccumulator() {
private final MatrixAccumulator productAccumulator = Matrices.asProductAccumulator(neutral);
@Override
public void update(int i, int j, double value) {
productAccumulator.update(i, j, function.evaluate(i, j, value));
}
@Override
public double accumulate() {
return productAccumulator.accumulate();
}
};
}
/**
* Creates an accumulator procedure that adapts a matrix accumulator for procedure
* interface. This is useful for reusing a single accumulator for multiple fold operations
* in multiple matrices.
*
* @param accumulator the matrix accumulator
*
* @return an accumulator procedure
*/
public static MatrixProcedure asAccumulatorProcedure(final MatrixAccumulator accumulator) {
return new MatrixProcedure() {
@Override
public void apply(int i, int j, double value) {
accumulator.update(i, j, value);
}
};
}
}