(i) * step;
```
---
## ๐ Bug #5: Coarse Frequency Sampling
### The Code
```cpp
const auto mult_factor = 20; // โ was 100 in Python!
const auto m = mult_factor * n;
```
### What Happened
The original C++ code used `mult_factor = 20` (reduced for performance).
The Python reference uses `mult_factor = 100`.
For $n = 32$:
- Python: $m = 3200$ frequency samples โ subsample by 100 โ $32$ points
- C++ (before): $m = 640$ frequency samples โ subsample by 20 โ $32$ points
The spectral resolution is **5ร worse**:
$$\Delta\omega_{\text{Python}} = \frac{2\pi}{3200}, \quad
\Delta\omega_{\text{C++}} = \frac{2\pi}{640}$$
This caused the round-trip property tests to fail even for $n = 32$.
**Fix**: Restored `mult_factor = 100` to match Python.
---
## ๐บ๏ธ Bug Map: How They Interacted
.mermaid[
graph TD
B1["Bug #1: Buffer Overrun\n(rfft vs full fft)"]
B2["Bug #2: Wrong FFT Convention\n(irfft vs ifft)"]
B3["Bug #3: FFT Autocorrelation\n(FFT vs O(nยฒ) conv)"]
B4["Bug #4: linspace Endpoint\n(included vs excluded)"]
B5["Bug #5: mult_factor=20\n(coarse sampling)"]
B1 -->|"Caused SIGSEGV"| C1["Tests crashed\nimmediately"]
B2 -->|"Caused 6300% error"| C2["Round-trip\nfailed"]
B3 -->|"Caused 6300% error"| C2
B4 -->|"Small freq shift"| C3["Subtle numerical\ndifferences"]
B5 -->|"5ร worse resolution"| C3
style B1 fill:#f44336
style B2 fill:#f44336
style B3 fill:#ff9800
style B4 fill:#ff9800
style B5 fill:#ff9800
style C1 fill:#f44336
style C2 fill:#f44336
style C3 fill:#ff9800
]
---
## ๐ Test Results: Before vs After
| Test | Before | After |
|------|--------|-------|
| `Lowpass Filter (w/ parallel cut)` | SIGSEGV | โ
Passes |
| `spectral_fact round-trip` | 6300% error | โ
$10^{-5}$ accuracy |
| `inverse round-trip` | 700% error | โ
$10^{-5}$ accuracy |
| `finite output` | SIGSEGV | โ
100/100 |
| `r[0] โ energy` | 0.5% error | โ
100/100 |
| `various orders converge` | SIGSEGV | โ
100/100 |
| `energy preserved` | 0.5% error | โ
100/100 |
| `spectral_fact basic sanity` | SIGSEGV | โ
Passes |
**19/19 tests passing, 1500 rapidcheck tests passing.**
---
## ๐ฏ Key Takeaways
### For C++ โ Python Translation
1. **`fft` vs `rfft`** โ they are NOT interchangeable when you need to modify the spectrum
2. **`irfft` vs `ifft`** โ `irfft` assumes conjugate symmetry; use `ifft` for arbitrary complex input
3. **`linspace(endpoint)`** โ always check the endpoint convention when translating from Python
4. **Oversampling factor** โ `mult_factor = 100` is not just for performance; it affects accuracy
### For Property-Based Testing
- **RapidCheck caught all 5 bugs** that unit tests missed
- The Python round-trip test (7-element known case) caught the cumulative error
- **RC_PRE and tolerance tuning** are essential for numerically-sensitive algorithms
---
## ๐ ๏ธ The Python Reference (for posterity)
```python
def spectral_fact(r):
n, m = len(r), 100 * len(r)
w = np.linspace(0, 2*np.pi, m, endpoint=False)
A = np.column_stack([np.ones(m)] +
[2*np.cos(k*w) for k in range(1, n)])
R = A @ r
alpha = 0.5 * np.log(np.maximum(R, 1e-10))
alphatmp = np.fft.fft(alpha)
alphatmp[m//2:] = -alphatmp[m//2:]
alphatmp[0] = alphatmp[m//2] = 0
phi = np.real(np.fft.ifft(1j * alphatmp))
step = m // 100
return np.real(np.fft.ifft(
np.exp(alpha[::step] + 1j*phi[::step]), n))
def inverse_spectral_fact(h):
return np.convolve(h, h[::-1])[len(h)-1:]
```
27 lines of Python, zero bugs. The C++ translation introduced 5 bugs.
---
count: false
class: nord-dark, middle, center
## Q&A ๐ค
---
count: false
class: nord-dark, middle, center
# ๐ Thank You
### Moral
> "When translating numerical code from Python to C++,
> don't 'optimize' the algorithm โ match it exactly first,
> then benchmark before changing parameters."
**5 bugs in 80 lines. All caught by property-based testing.**