org.ejml.dense.row.MatrixFeatures_CDRM Maven / Gradle / Ivy
/*
* Copyright (c) 2009-2017, Peter Abeles. All Rights Reserved.
*
* This file is part of Efficient Java Matrix Library (EJML).
*
* 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 org.ejml.dense.row;
import org.ejml.data.*;
import org.ejml.dense.row.decompose.chol.CholeskyDecompositionInner_CDRM;
import org.ejml.dense.row.mult.VectorVectorMult_CDRM;
/**
*
* Functions for computing the features of complex matrices
*
*
* @author Peter Abeles
*/
@SuppressWarnings("Duplicates")
public class MatrixFeatures_CDRM {
/**
* Checks to see if the matrix is a vector or not.
*
* @param mat A matrix. Not modified.
*
* @return True if it is a vector and false if it is not.
*/
public static boolean isVector( Matrix mat ) {
return (mat.getNumCols() == 1 || mat.getNumRows() == 1);
}
/**
*
* Checks to see if the two matrices are the negative of each other:
*
* aij = -bij
*
*
* @param a First matrix. Not modified.
* @param b Second matrix. Not modified.
* @param tol Numerical tolerance.
* @return True if they are the negative of each other within tolerance.
*/
public static boolean isNegative(CMatrixD1 a, CMatrixD1 b, float tol) {
if( a.numRows != b.numRows || a.numCols != b.numCols )
throw new IllegalArgumentException("Matrix dimensions must match");
int length = a.getNumElements()*2;
for( int i = 0; i < length; i++ ) {
if( !(Math.abs(a.data[i]+b.data[i]) <= tol) )
return false;
}
return true;
}
/**
* Checks to see if any element in the matrix is NaN.
*
* @param m A matrix. Not modified.
* @return True if any element in the matrix is NaN.
*/
public static boolean hasNaN( CMatrixD1 m )
{
int length = m.getDataLength();
for( int i = 0; i < length; i++ ) {
if( Float.isNaN(m.data[i]))
return true;
}
return false;
}
/**
* Checks to see if any element in the matrix is NaN of Infinite.
*
* @param m A matrix. Not modified.
* @return True if any element in the matrix is NaN of Infinite.
*/
public static boolean hasUncountable( CMatrixD1 m )
{
int length = m.getDataLength();
for( int i = 0; i < length; i++ ) {
float a = m.data[i];
if( Float.isNaN(a) || Float.isInfinite(a))
return true;
}
return false;
}
/**
*
* Checks to see if each element in the two matrices are equal:
* aij == bij
*
*
*
* NOTE: If any of the elements are NaN then false is returned. If two corresponding
* elements are both positive or negative infinity then they are equal.
*
*
* @param a A matrix. Not modified.
* @param b A matrix. Not modified.
* @return true if identical and false otherwise.
*/
public static boolean isEquals(CMatrixD1 a, CMatrixD1 b ) {
if( a.numRows != b.numRows || a.numCols != b.numCols ) {
return false;
}
final int length = a.getDataLength();
for( int i = 0; i < length; i++ ) {
if( !(a.data[i] == b.data[i]) ) {
return false;
}
}
return true;
}
/**
*
* Checks to see if each element in the two matrices are within tolerance of
* each other: tol ≥ |aij - bij|.
*
*
*
* NOTE: If any of the elements are not countable then false is returned.
* NOTE: If a tolerance of zero is passed in this is equivalent to calling
* {@link #isEquals(CMatrixD1, CMatrixD1)}
*
*
* @param a A matrix. Not modified.
* @param b A matrix. Not modified.
* @param tol How close to being identical each element needs to be.
* @return true if equals and false otherwise.
*/
public static boolean isEquals(CMatrixD1 a , CMatrixD1 b , float tol )
{
if( a.numRows != b.numRows || a.numCols != b.numCols ) {
return false;
}
if( tol == 0.0f )
return isEquals(a,b);
final int length = a.getDataLength();
for( int i = 0; i < length; i++ ) {
if( !(tol >= Math.abs(a.data[i] - b.data[i])) ) {
return false;
}
}
return true;
}
/**
*
* Checks to see if each corresponding element in the two matrices are
* within tolerance of each other or have the some symbolic meaning. This
* can handle NaN and Infinite numbers.
*
*
*
* If both elements are countable then the following equality test is used:
* |aij - bij| ≤ tol.
* Otherwise both numbers must both be Float.NaN, Float.POSITIVE_INFINITY, or
* Float.NEGATIVE_INFINITY to be identical.
*
*
* @param a A matrix. Not modified.
* @param b A matrix. Not modified.
* @param tol Tolerance for equality.
* @return true if identical and false otherwise.
*/
public static boolean isIdentical(CMatrixD1 a, CMatrixD1 b , float tol ) {
if( a.numRows != b.numRows || a.numCols != b.numCols ) {
return false;
}
if( tol < 0 )
throw new IllegalArgumentException("Tolerance must be greater than or equal to zero.");
final int length = a.getDataLength();
for( int i = 0; i < length; i++ ) {
float valA = a.data[i];
float valB = b.data[i];
// if either is negative or positive infinity the result will be positive infinity
// if either is NaN the result will be NaN
float diff = Math.abs(valA-valB);
// diff = NaN == false
// diff = infinity == false
if( tol >= diff )
continue;
if( Float.isNaN(valA) ) {
return Float.isNaN(valB);
} else if( Float.isInfinite(valA) ) {
return valA == valB;
} else {
return false;
}
}
return true;
}
/**
* Checks to see if the provided matrix is within tolerance to an identity matrix.
*
* @param mat Matrix being examined. Not modified.
* @param tol Tolerance.
* @return True if it is within tolerance to an identify matrix.
*/
public static boolean isIdentity(CMatrix mat , float tol ) {
// see if the result is an identity matrix
Complex_F32 c = new Complex_F32();
for (int i = 0; i < mat.getNumRows(); i++) {
for (int j = 0; j < mat.getNumCols(); j++) {
mat.get(i, j, c);
if (i == j) {
if (!(Math.abs(c.real - 1) <= tol))
return false;
if (!(Math.abs(c.imaginary) <= tol))
return false;
} else {
if (!(Math.abs(c.real) <= tol))
return false;
if (!(Math.abs(c.imaginary) <= tol))
return false;
}
}
}
return true;
}
/**
* Hermitian matrix is a square matrix with complex entries that are equal to its own conjugate transpose.
*
* a[i,j] = conj(a[j,i])
*
* @param Q The matrix being tested. Not modified.
* @param tol Tolerance.
* @return True if it passes the test.
*/
public static boolean isHermitian(CMatrixRMaj Q , float tol ) {
if( Q.numCols != Q.numRows )
return false;
Complex_F32 a = new Complex_F32();
Complex_F32 b = new Complex_F32();
for( int i = 0; i < Q.numCols; i++ ) {
for( int j = i; j < Q.numCols; j++ ) {
Q.get(i,j,a);
Q.get(j,i,b);
if( Math.abs(a.real-b.real)>tol)
return false;
if( Math.abs(a.imaginary+b.imaginary)>tol)
return false;
}
}
return true;
}
/**
*
* Unitary matrices have the following properties:
* Q*QH = I
*
*
* This is the complex equivalent of orthogonal matrix.
*
* @param Q The matrix being tested. Not modified.
* @param tol Tolerance.
* @return True if it passes the test.
*/
public static boolean isUnitary(CMatrixRMaj Q , float tol ) {
if( Q.numRows < Q.numCols ) {
throw new IllegalArgumentException("The number of rows must be more than or equal to the number of columns");
}
Complex_F32 prod = new Complex_F32();
CMatrixRMaj u[] = CommonOps_CDRM.columnsToVector(Q, null);
for( int i = 0; i < u.length; i++ ) {
CMatrixRMaj a = u[i];
VectorVectorMult_CDRM.innerProdH(a, a, prod);
if( Math.abs(prod.real-1) > tol)
return false;
if( Math.abs(prod.imaginary) > tol)
return false;
for( int j = i+1; j < u.length; j++ ) {
VectorVectorMult_CDRM.innerProdH(a, u[j], prod);
if( !(prod.getMagnitude2() <= tol*tol))
return false;
}
}
return true;
}
/**
*
* Checks to see if the matrix is positive definite.
*
*
* xT A x > 0
* for all x where x is a non-zero vector and A is a hermitian matrix.
*
*
* @param A square hermitian matrix. Not modified.
*
* @return True if it is positive definite and false if it is not.
*/
public static boolean isPositiveDefinite( CMatrixRMaj A ) {
if( A.numCols != A.numRows)
return false;
CholeskyDecompositionInner_CDRM chol = new CholeskyDecompositionInner_CDRM(true);
if( chol.inputModified() )
A = A.copy();
return chol.decompose(A);
}
/**
*
* Checks to see if a matrix is upper triangular or Hessenberg. A Hessenberg matrix of degree N
* has the following property:
*
* aij ≤ 0 for all i < j+N
*
* A triangular matrix is a Hessenberg matrix of degree 0.
*
* @param A Matrix being tested. Not modified.
* @param hessenberg The degree of being hessenberg.
* @param tol How close to zero the lower left elements need to be.
* @return If it is an upper triangular/hessenberg matrix or not.
*/
public static boolean isUpperTriangle(CMatrixRMaj A , int hessenberg , float tol ) {
tol *= tol;
for( int i = hessenberg+1; i < A.numRows; i++ ) {
int maxCol = Math.min(i-hessenberg, A.numCols);
for( int j = 0; j < maxCol; j++ ) {
int index = (i*A.numCols+j)*2;
float real = A.data[index];
float imag = A.data[index+1];
float mag = real*real + imag*imag;
if( !(mag <= tol) ) {
return false;
}
}
}
return true;
}
/**
*
* Checks to see if a matrix is lower triangular or Hessenberg. A Hessenberg matrix of degree N
* has the following property:
*
* aij ≤ 0 for all i < j+N
*
* A triangular matrix is a Hessenberg matrix of degree 0.
*
* @param A Matrix being tested. Not modified.
* @param hessenberg The degree of being hessenberg.
* @param tol How close to zero the lower left elements need to be.
* @return If it is an upper triangular/hessenberg matrix or not.
*/
public static boolean isLowerTriangle(CMatrixRMaj A , int hessenberg , float tol ) {
tol *= tol;
for( int i = 0; i < A.numRows-hessenberg-1; i++ ) {
for( int j = i+hessenberg+1; j < A.numCols; j++ ) {
int index = (i*A.numCols+j)*2;
float real = A.data[index];
float imag = A.data[index+1];
float mag = real*real + imag*imag;
if( !(mag <= tol) ) {
return false;
}
}
}
return true;
}
/**
* Checks to see all the elements in the matrix are zeros
*
* @param m A matrix. Not modified.
* @return True if all elements are zeros or false if not
*/
public static boolean isZeros(CMatrixD1 m , float tol )
{
int length = m.getNumElements()*2;
for( int i = 0; i < length; i++ ) {
if( Math.abs(m.data[i]) > tol )
return false;
}
return true;
}
}