인과성 문서의 검증 코드다.

"""인과성 문서: 미래 입력만 다른 두 입력을 넣어 출력이 지금까지 같은지로 인과성을 판정한다 (예제 1.12와 본문 예)."""
import math, random
random.seed(3)
R = range(-30, 31)

def causal(S, trials=30):
    """n0 이전까지 같은 두 입력이 n0 이전까지 같은 출력을 내는가 (반례가 하나라도 있으면 비인과)."""
    for _ in range(trials):
        n0 = random.randint(-10, 10)
        a = {n: random.uniform(-1, 1) for n in range(-60, 61)}
        b = dict(a)
        for n in range(n0 + 1, 61): b[n] = random.uniform(-1, 1)   # n0 뒤(미래)만 바꾼다
        xa, xb = (lambda n, d=a: d.get(n, 0.0)), (lambda n, d=b: d.get(n, 0.0))
        if any(abs(S(xa, n) - S(xb, n)) > 1e-12 for n in range(-20, n0 + 1)):
            return False
    return True

acc   = lambda x, n: sum(x(k) for k in range(-60, n + 1))       # 누산기
delay = lambda x, n: x(n - 1)
sq    = lambda x, n: (2 * x(n) - x(n) ** 2) ** 2                  # 기억 없는 시스템
diff  = lambda x, n: x(n) - x(n + 1)
rev   = lambda x, n: x(-n)                                        # 예제 1.12-1
mod   = lambda x, n: x(n) * math.cos(n + 1)                        # 예제 1.12-2 (이산 버전)
M = 2
avg   = lambda x, n: sum(x(n - k) for k in range(-M, M + 1)) / (2 * M + 1)
assert causal(acc) and causal(delay) and causal(sq) and causal(mod)
assert not causal(diff) and not causal(rev) and not causal(avg)
# y[n] = x[-n]: n = -4에서 출력이 미래 입력 x[4]로 정해진다
x = lambda n: 7.0 if n == 4 else 0.0
assert rev(x, -4) == 7.0
print("ALL CHECKS PASSED")