Source code for multiplierless.spectral_fact
"""Spectral Factorization — root-finding (default) + FFT (legacy)."""
import numpy as np
from ginger.aberth import aberth_autocorr, initial_aberth_autocorr, poly_from_roots
from ginger.rootfinding import Options
__all__ = ["spectral_fact", "spectral_fact_fft", "spectral_fact_root",
"inverse_spectral_fact"]
[docs]
def spectral_fact_root(r: np.ndarray, tolerance: float = 1e-8) -> np.ndarray:
n = len(r)
deg = 2 * n - 2
coeffs = [0.0] * (deg + 1)
coeffs[0] = float(r[-1])
for i in range(n - 1):
coeffs[i + 1] = 2.0 * float(r[n - 2 - i])
for i in range(n - 2):
coeffs[deg - i - 1] = 2.0 * float(r[n - 2 - i])
coeffs[n - 1] = 2.0 * float(r[0])
coeffs[deg] = float(r[-1])
coeffs.reverse()
opts = Options()
opts.tolerance = tolerance
opts.max_iters = 500
zs = initial_aberth_autocorr(coeffs)
zs, _, _ = aberth_autocorr(coeffs, zs, opts)
inside = [z if abs(z) < 1.0 else 1.0 / z for z in zs]
hc = poly_from_roots(inside)
energy_h = sum(c * c for c in hc)
norm = np.sqrt(float(r[0]) / energy_h)
hc = [c * norm for c in hc]
h = np.zeros(n)
for i in range(min(n, len(hc))):
h[i] = hc[i]
return h
[docs]
def spectral_fact(r: np.ndarray) -> np.ndarray:
return spectral_fact_fft(r)
[docs]
def spectral_fact_fft(r: np.ndarray) -> np.ndarray:
"""Kolmogorov 1939 via FFT (legacy)."""
n = len(r)
mult_factor = 100
m = mult_factor * n
w = np.linspace(0, 2 * np.pi, m, endpoint=False)
Bn = np.outer(w, np.arange(1, n))
An = 2 * np.cos(Bn)
R = np.hstack((np.ones((m, 1)), An)) @ r
min_val = np.min(R)
if min_val <= 0:
if min_val > -1e-4:
R = np.maximum(R, 1e-10)
else:
raise RuntimeError(f"Spectral factorization failed: min={min_val:.6e}")
alpha = 0.5 * np.log(np.abs(R))
alphatmp = np.fft.fft(alpha)
ind = int(m / 2)
alphatmp[ind:m] = -alphatmp[ind:m]
alphatmp[0] = 0
alphatmp[ind] = 0
phi = np.real(np.fft.ifft(1j * alphatmp))
index = np.arange(0, m, step=int(mult_factor))
return np.real(np.fft.ifft(np.exp(alpha[index] + 1j * phi[index]), n))
[docs]
def inverse_spectral_fact(h: np.ndarray) -> np.ndarray:
return np.convolve(h, h[::-1])[len(h) - 1 :]