from __future__ import annotations import numpy as np def power_law_spectrum(d: int, exponent: float = 1.2, floor: float = 0.02) -> np.ndarray: """Return a descending synthetic image-like covariance spectrum.""" if d <= 0: raise ValueError("d must be positive") ranks = np.arange(1, d + 1, dtype=np.float64) eig = ranks ** (-float(exponent)) eig = eig / eig[0] return eig + float(floor) def sample_covariance(eigenvalues: np.ndarray, n_samples: int, rng: np.random.Generator) -> np.ndarray: eig = np.asarray(eigenvalues, dtype=np.float64) if n_samples <= 1: raise ValueError("n_samples must exceed one") z = rng.standard_normal((n_samples, eig.size)) x = z * np.sqrt(eig) x = x - x.mean(axis=0, keepdims=True) return (x.T @ x) / float(n_samples - 1) def symmetric_matrix_sqrt(matrix: np.ndarray) -> np.ndarray: vals, vecs = np.linalg.eigh((matrix + matrix.T) * 0.5) vals = np.clip(vals, 0.0, None) return (vecs * np.sqrt(vals)) @ vecs.T