Matrix Properties

Matrix Toolkit provides comprehensive property checking for matrices through the MatrixProperties class.

Supported Properties

Symmetry Properties

Symmetric

A matrix is symmetric if \(A = A^T\).

from matrix_toolkit.anymatrix import MatrixProperties
import numpy as np

A = np.array([[1, 2], [2, 3]])
is_sym = MatrixProperties.is_symmetric(A)

Hermitian

A matrix is Hermitian if \(A = A^H\) (conjugate transpose).

A = np.array([[1, 1+2j], [1-2j, 3]])
is_herm = MatrixProperties.is_hermitian(A)

Skew-Symmetric

A matrix is skew-symmetric if \(A^T = -A\).

A = np.array([[0, 2], [-2, 0]])
# Check if A^T = -A
is_skew = np.allclose(A.T, -A)

Definiteness Properties

Positive Definite

A matrix is positive definite if all eigenvalues are positive.

A = np.array([[2, 1], [1, 2]])
is_pd = MatrixProperties.is_positive_definite(A)

This uses Cholesky decomposition for efficient checking.

Orthogonality Properties

Orthogonal

A matrix \(Q\) is orthogonal if \(Q^T Q = I\).

Q = np.eye(3)  # Identity is orthogonal
is_ortho = MatrixProperties.is_orthogonal(Q)

Unitary

A matrix \(U\) is unitary if \(U^H U = I\).

U = np.array([[1, 1j], [1j, 1]]) / np.sqrt(2)
is_unitary = MatrixProperties.is_unitary(U)

Structure Properties

Diagonal

D = np.diag([1, 2, 3])
is_diag = MatrixProperties.is_diagonal(D)

Tridiagonal

T = np.diag([1, 2, 3]) + np.diag([1, 1], 1) + np.diag([1, 1], -1)
is_tri = MatrixProperties.is_tridiagonal(T)

Upper/Lower Triangular

U = np.triu(np.ones((3, 3)))
is_upper = MatrixProperties.is_upper_triangular(U)

L = np.tril(np.ones((3, 3)))
is_lower = MatrixProperties.is_lower_triangular(L)

Special Structure

Toeplitz

Constant along diagonals.

from scipy.linalg import toeplitz
T = toeplitz([1, 2, 3, 4])
is_toep = MatrixProperties.is_toeplitz(T)

Circulant

Each row is cyclic shift of previous row.

C = np.array([[1, 2, 3],
              [3, 1, 2],
              [2, 3, 1]])
is_circ = MatrixProperties.is_circulant(C)

Hankel

Constant along anti-diagonals.

H = np.array([[1, 2, 3],
              [2, 3, 4],
              [3, 4, 5]])
is_hank = MatrixProperties.is_hankel(H)

Stochastic Properties

Row Stochastic

All rows sum to 1, all entries non-negative.

S = np.array([[0.5, 0.5],
              [0.3, 0.7]])
is_stoch = MatrixProperties.is_stochastic(S)

Doubly Stochastic

Both rows and columns sum to 1.

DS = np.array([[0.5, 0.5],
               [0.5, 0.5]])
is_doubly = MatrixProperties.is_doubly_stochastic(DS)

Special Matrix Types

Nilpotent

\(A^k = 0\) for some positive integer k.

# Jordan block with eigenvalue 0
N = np.array([[0, 1, 0],
              [0, 0, 1],
              [0, 0, 0]])
is_nilp = MatrixProperties.is_nilpotent(N)

Involutory

\(A^2 = I\).

# Swap matrix
I = np.array([[0, 1],
              [1, 0]])
is_invol = MatrixProperties.is_involutory(I)

Data Type Properties

Sparse

from scipy import sparse
S = sparse.random(100, 100, density=0.01)
is_sparse = MatrixProperties.is_sparse(S)

Binary

All entries are 0 or 1.

B = np.array([[1, 0, 1],
              [0, 1, 0]])
is_bin = MatrixProperties.is_binary(B)

Integer

All entries are integers.

I = np.array([[1, 2], [3, 4]])
is_int = MatrixProperties.is_integer(I)

Checking Properties

Single Property

from matrix_toolkit.anymatrix import MatrixProperties

A = np.array([[1, 2], [2, 3]])

# Check if symmetric
if MatrixProperties.is_symmetric(A):
    print("Matrix is symmetric")

Multiple Properties

properties = ['symmetric', 'positive definite', 'tridiagonal']
results = MatrixProperties.check_properties(A, properties)

for prop, passed in results.items():
    status = "✓" if passed else "✗"
    print(f"{status} {prop}")

With Custom Tolerance

# Stricter tolerance
is_sym = MatrixProperties.is_symmetric(A, tol=1e-12)

# More lenient
is_ortho = MatrixProperties.is_orthogonal(Q, tol=1e-6)

Automated Testing

Using with Anymatrix

from matrix_toolkit.anymatrix import AnyMatrix, MatrixProperties

am = AnyMatrix()

# Generate matrix
matrix = am.generate('core/beta', 10)

# Get expected properties
expected_props = am.properties('core/beta')

# Verify all properties
results = MatrixProperties.check_properties(matrix, expected_props)

# Check if all passed
all_passed = all(results.values())
print(f"All properties verified: {all_passed}")

Property Test Suite

from matrix_toolkit.anymatrix.testing import run_all_tests

# Run comprehensive property tests
results = run_all_tests(
    groups=['core', 'gallery'],
    verbose=True,
    generate_report=True,
    report_file='property_tests.txt'
)

Custom Property Checker

You can create custom property checkers:

def is_magic_square(matrix, tol=1e-10):
    """Check if matrix is a magic square"""
    if matrix.shape[0] != matrix.shape[1]:
        return False

    n = matrix.shape[0]
    magic_sum = n * (n**2 + 1) / 2

    # Check rows
    if not np.allclose(matrix.sum(axis=1), magic_sum, atol=tol):
        return False

    # Check columns
    if not np.allclose(matrix.sum(axis=0), magic_sum, atol=tol):
        return False

    # Check diagonals
    if not np.isclose(np.trace(matrix), magic_sum, atol=tol):
        return False
    if not np.isclose(np.trace(np.fliplr(matrix)), magic_sum, atol=tol):
        return False

    return True

# Use it
M = am.generate('matlab/magic', 5)
assert is_magic_square(M)

Property Relationships

Some properties imply others:

  • Symmetric + Positive Definite → Invertible

  • Orthogonal → Invertible, \(\det(Q) = \pm 1\)

  • Unitary → Normal

  • Hermitian → Normal

  • Doubly Stochastic → Row Stochastic

  • Diagonal → Triangular (both upper and lower)

Example verification:

# If symmetric and positive definite, should be invertible
A = am.generate('core/beta', 10)

assert MatrixProperties.is_symmetric(A)
assert MatrixProperties.is_positive_definite(A)

# Should be invertible
det = np.linalg.det(A)
assert abs(det) > 1e-10

Property Preservation

Under Operations

Some operations preserve properties:

  • Sum of symmetric matrices → symmetric

  • Product of orthogonal matrices → orthogonal

  • Inverse of positive definite → positive definite

Example:

# Sum of symmetric matrices
A1 = am.generate('core/beta', 10)
A2 = am.generate('gallery/lehmer', 10)

A_sum = A1 + A2
assert MatrixProperties.is_symmetric(A_sum)

Performance Considerations

Computational Cost

Property checks have different computational costs:

  • O(n²): Symmetry, structure checks

  • O(n³): Positive definiteness (Cholesky), orthogonality

  • O(nk): Nilpotency (k matrix multiplications)

For large matrices:

# Fast checks
is_sym = MatrixProperties.is_symmetric(large_matrix)  # O(n²)
is_diag = MatrixProperties.is_diagonal(large_matrix)  # O(n²)

# Slower checks
is_pd = MatrixProperties.is_positive_definite(large_matrix)  # O(n³)

Sparse Matrix Optimization

Property checkers are optimized for sparse matrices:

from scipy import sparse

# Sparse matrix
S = sparse.random(10000, 10000, density=0.001, format='csr')

# Fast for sparse
is_sym = MatrixProperties.is_symmetric(S)  # Only checks nnz elements

See Also