Linear Algebra Utilities

causationentropy.core.linalg.correlation_log_determinant(A, epsilon=1e-10)[source]

Compute the logarithm of the determinant of a correlation matrix.

This function calculates the signed log-determinant of the correlation matrix derived from the input data matrix A. The correlation matrix is defined as:

\[\mathbf{R}_{ij} = \frac{\text{Cov}(X_i, X_j)}{\sqrt{\text{Var}(X_i) \text{Var}(X_j)}}\]

The log-determinant is computed using:

\[\log |\mathbf{R}| = \text{sign}(|\mathbf{R}|) \cdot \log(||\mathbf{R}||)\]

This approach provides numerical stability for matrices that may be close to singular.

Parameters:
  • A (array-like of shape (n_samples, n_features)) – Input data matrix where rows are samples and columns are features.

  • epsilon (float, default=1e-10) – Small regularization parameter (currently unused but reserved for potential numerical stabilization).

Returns:

log_det – Logarithm of the determinant of the correlation matrix. Returns 0.0 for degenerate cases (empty matrix or scalar).

Return type:

float

Notes

Special Cases: - Empty matrix (n_features = 0): Returns 0.0 - Scalar correlation (1x1 matrix): Returns 0.0 - Singular matrix: May return -inf or raise warnings

Numerical Considerations: - Uses numpy.linalg.slogdet for stable computation of log-determinant - Handles edge cases gracefully without exceptions - More stable than computing log(det(R)) directly

Applications: - Gaussian mutual information calculation - Model selection criteria (AIC, BIC) - Multivariate normality testing - Information-theoretic measures

Interpretation: - Large positive values: High linear dependence among variables - Values near zero: Near-independence of variables - Large negative values: Multicollinearity, near-singular correlation matrix

Examples

>>> import numpy as np
>>> from causationentropy.core.linalg import correlation_log_determinant
>>>
>>> # Independent variables
>>> A_indep = np.random.randn(100, 3)
>>> log_det_indep = correlation_log_determinant(A_indep)
>>> print(f"Independent variables log-det: {log_det_indep:.3f}")
>>>
>>> # Correlated variables
>>> A_corr = np.random.randn(100, 1)
>>> A_corr = np.hstack([A_corr, A_corr + 0.1*np.random.randn(100, 1)])
>>> log_det_corr = correlation_log_determinant(A_corr)
>>> print(f"Correlated variables log-det: {log_det_corr:.3f}")
>>>
>>> # Expected: log_det_corr < log_det_indep due to correlation

See also

numpy.corrcoef

Compute correlation coefficients

numpy.linalg.slogdet

Compute sign and log-determinant

causationentropy.core.linalg.subnetwork(G, lag)[source]

Extract a subgraph containing only edges at a specific lag.

The general return value from discover_network is a NetworkX MultiDiGraph with lag, p-value, and cmi encoded as edge attributes. This method returns a DiGraph containing only edges at the specified lag value.

Since the input is a MultiDiGraph, bidirectional connections at the same lag are represented as two separate directed edges: one from i to j and one from j to i.

Parameters:
  • G (nx.MultiDiGraph) – The causal network graph from discover_network with edge attributes ‘lag’, ‘cmi’, and ‘p_value’.

  • lag (int) – The time lag to extract. Only edges with this lag value will be included.

Returns:

H – A directed graph containing only the edges at the specified lag. Edge attributes ‘cmi’ and ‘p_value’ are preserved.

Return type:

nx.DiGraph

Examples

>>> import networkx as nx
>>> from causationentropy.core.linalg import subnetwork
>>>
>>> G = nx.MultiDiGraph()
>>> G.add_edge(0, 1, lag=1, cmi=0.5, p_value=0.01)
>>> G.add_edge(1, 2, lag=2, cmi=0.3, p_value=0.05)
>>>
>>> H1 = subnetwork(G, lag=1)
>>> H1.number_of_edges()
1
causationentropy.core.linalg.companion_matrix(G)[source]

Construct the block companion matrix for a causal network.

The purpose of this method is to store the causal graph in a structure that this library prefers and is not necessarily the graph theoretical construction.

The companion matrix is a block-structured matrix used in vector autoregression (VAR) and dynamical systems analysis:

\[\begin{split}C = \begin{bmatrix} A^{(1)} & A^{(2)} & \cdots & A^{(K-1)} & A^{(K)} \\ I & 0 & \cdots & 0 & 0 \\ 0 & I & \cdots & 0 & 0 \\ \vdots & \vdots & \ddots & \vdots & \vdots \\ 0 & 0 & \cdots & I & 0 \end{bmatrix}\end{split}\]

Each \(A^{(k)}\) is the adjacency matrix of edges with lag = k, and I represents an identity matrix of size n x n.

Parameters:

G (nx.MultiDiGraph) – The causal network graph from discover_network. Must contain edge attribute ‘lag’.

Returns:

C – The block companion matrix. Returns empty (0, 0) array if max_lag = 0.

Return type:

np.ndarray of shape (n_nodes * max_lag, n_nodes * max_lag)

Notes

  • Nodes are ordered according to NetworkX’s default ordering (sorted)

  • Edges with lag=0 are ignored (contemporaneous effects not included)

  • The matrix enables analysis of temporal dynamics via eigenvalue analysis

Examples

>>> import networkx as nx
>>> import numpy as np
>>> from causationentropy.core.linalg import companion_matrix
>>>
>>> G = nx.MultiDiGraph()
>>> G.add_nodes_from([0, 1, 2])
>>> G.add_edge(0, 1, lag=1, cmi=0.5, p_value=0.01)
>>> G.add_edge(1, 2, lag=2, cmi=0.3, p_value=0.05)
>>>
>>> C = companion_matrix(G)
>>> print(C.shape)
(6, 6)