# The formula against brute force: for several lattices and filters, the exact J_N (lattice.py) and a
# direct simulation (simulate.py: dither, round, filter, compare; 4096 levels on a canvas the lattice
# tiles) must agree. Also the textbook cases where a lattice tiles its window and the error is exactly
# 1 / (12 |S|^2). Prints out/check.txt.
import numpy as np
import filters as F, lattice as L, simulate as S

def brute(A, B, N, taps, levels=4096):
    n = N * max(1, int(np.ceil(48 / N)))  # a canvas that's a whole number of periods, at least 48 wide
    u = S.lattice_field(A, B, N, n); FK = S.kernel_fft(taps, n)
    e2 = 0
    for f in (np.arange(levels) + .5) / levels:
        e2 += (S.filt(np.floor(f + u) - f, FK) ** 2).mean()
    return np.sqrt(e2 / levels)

CASES = [('Starlock full', F.kuwahara(5), [(54, 11, 56), (5, 1, 24), (2, 1, 5)]),
         ('Starlock lite', F.kuwahara(2), [(2, 1, 5), (54, 11, 56)]),
         ('Gaussian 1.5 + centre .2', F.centre_plus_gaussian(.2, 1.5), [(5, 3, 12), (7, 2, 31)]),
         ('box 3x3', F.box(3), [(3, 1, 9), (2, 5, 17)])]
for name, taps, lats in CASES:
    for A, B, N in lats:
        f = np.sqrt(L.J(A, B, N, F.grid_response(taps, N))[0]); b = brute(A, B, N, taps)
        print(f'{name:26s} ({A},{B})/{N:<4d} formula {f:.5f}  brute force {b:.5f}  {"agree" if abs(f - b) < 2e-4 else "DISAGREE"}')
for name, taps, (A, B, N) in (('Lee ball r=2 (13 taps)', F.lee_disc(2), (1, 8, 13)), ('box 4x4', F.box(4), (4, 1, 16))):
    j = L.J(A, B, N, F.grid_response(taps, N))[0]; k = len(taps)
    print(f'{name:26s} ({A},{B})/{N:<4d} J = {j:.8f}, 1/(12 |S|^2) = {1 / (12 * k * k):.8f}  {"exact" if abs(j - 1 / (12 * k * k)) < 1e-12 else "OFF"}')
