File size: 1,020 Bytes
c30b460
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
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