Coverage for src/cvx/linalg/covariance/rand_cov.py: 100%
7 statements
« prev ^ index » next coverage.py v7.15.0, created at 2026-07-03 18:56 +0000
« prev ^ index » next coverage.py v7.15.0, created at 2026-07-03 18:56 +0000
1"""Random covariance matrix generation utilities.
3This module provides functions for generating random positive semi-definite
4covariance matrices. These are useful for testing and simulation purposes.
6Example:
7 Generate a random covariance matrix:
9 >>> import numpy as np
10 >>> from cvx.linalg import rand_cov
11 >>> # Generate a 5x5 random covariance matrix
12 >>> cov = rand_cov(5, seed=42)
13 >>> cov.shape
14 (5, 5)
15 >>> # Verify it's symmetric
16 >>> bool(np.allclose(cov, cov.T))
17 True
18 >>> # Verify it's positive semi-definite
19 >>> bool(np.all(np.linalg.eigvals(cov) >= -1e-10))
20 True
22"""
24from __future__ import annotations
26import numpy as np
28from ..core.types import Matrix
31def rand_cov(n: int, seed: int | None = None) -> Matrix:
32 """Construct a random positive semi-definite covariance matrix of size n x n.
34 The matrix is constructed as A^T @ A where A is a random n x n matrix with
35 elements drawn from a standard normal distribution. This ensures the result
36 is symmetric and positive semi-definite.
38 Args:
39 n: Size of the covariance matrix (n x n).
40 seed: Random seed for reproducibility. If None, uses the current
41 random state.
43 Returns:
44 A random positive semi-definite n x n covariance matrix.
46 Example:
47 Generate a reproducible random covariance matrix:
49 >>> import numpy as np
50 >>> from cvx.linalg import rand_cov
51 >>> cov1 = rand_cov(3, seed=42)
52 >>> cov2 = rand_cov(3, seed=42)
53 >>> np.allclose(cov1, cov2)
54 True
56 Verify positive definiteness via Cholesky decomposition:
58 >>> cov = rand_cov(5, seed=123)
59 >>> # If Cholesky succeeds without error, matrix is positive definite
60 >>> L = np.linalg.cholesky(cov)
61 >>> bool(np.allclose(L @ L.T, cov))
62 True
64 Eigenvalue verification:
66 >>> cov = rand_cov(3, seed=99)
67 >>> eigenvalues = np.linalg.eigvalsh(cov)
68 >>> # All eigenvalues should be positive for PD matrix
69 >>> bool(np.all(eigenvalues > 0))
70 True
72 Different seeds produce different matrices:
74 >>> cov1 = rand_cov(3, seed=1)
75 >>> cov2 = rand_cov(3, seed=2)
76 >>> bool(not np.allclose(cov1, cov2))
77 True
79 Without seed, consecutive calls may differ (random state):
81 >>> # These may or may not be equal depending on random state
82 >>> cov_a = rand_cov(2, seed=None)
83 >>> cov_b = rand_cov(2, seed=None)
84 >>> cov_a.shape == cov_b.shape == (2, 2)
85 True
87 Note:
88 The generated matrix is guaranteed to be positive semi-definite because
89 it is constructed as A^T @ A. In practice, it will typically be positive
90 definite (all eigenvalues strictly positive) unless n is very large.
92 """
93 rng = np.random.default_rng(seed)
94 a = rng.standard_normal((n, n))
95 return np.transpose(a) @ a