시불변성 문서의 검증 코드다.

"""시불변성 문서: 입력을 미룬 뒤 넣은 출력과 출력을 미룬 것이 같은지로 판정한다 (예제 1.14~1.16)."""
import math, random
random.seed(7)

def ti_dt(S, shifts=(1, 3, -2)):
    for n0 in shifts:
        vals = {n: random.uniform(-1, 1) for n in range(-80, 81)}
        x1 = lambda n: vals.get(n, 0.0)
        x2 = lambda n: x1(n - n0)
        if any(abs(S(x2, n) - S(x1, n - n0)) > 1e-12 for n in range(-30, 31)):
            return False
    return True

def ti_ct(S, shifts=(0.5, 2.0)):
    for t0 in shifts:
        x1 = lambda t: math.sin(1.3 * t) + 0.5 * math.cos(0.4 * t) * t
        x2 = lambda t: x1(t - t0)
        if any(abs(S(x2, t) - S(x1, t - t0)) > 1e-9 for t in [i * 0.37 - 5 for i in range(30)]):
            return False
    return True

assert ti_ct(lambda x, t: math.sin(x(t)))                 # 예제 1.14: 시불변
assert not ti_dt(lambda x, n: n * x(n))                   # 예제 1.15: 시변
assert not ti_ct(lambda x, t: x(2 * t))                   # 예제 1.16: 시변
assert ti_dt(lambda x, n: x(n - 1)) and ti_dt(lambda x, n: sum(x(k) for k in range(-200, n + 1)))
# 예제 1.15의 반례: δ[n] -> 0, δ[n-1] -> δ[n-1]
d = lambda n: 1 if n == 0 else 0
assert all(n * d(n) == 0 for n in range(-5, 6))
assert all(n * d(n - 1) == d(n - 1) for n in range(-5, 6))
# 예제 1.16: x2(t) = x1(t-2) 이면 y2(t) = y1(t-1) (2가 아니라 1만큼만 밀린다)
x1 = lambda t: 1.0 if -2 <= t <= 2 else 0.0
y1 = lambda t: x1(2 * t)
y2 = lambda t: x1(2 * t - 2)
ts = [i * 0.05 - 4 for i in range(200)]
assert all(y2(t) == y1(t - 1) for t in ts) and any(y2(t) != y1(t - 2) for t in ts)
# 계수가 상수인 미분방정식 y' + αy = βx 는 시불변, α(t)가 시간에 따라 변하면 시변 (오일러 방법으로 확인)
def solve(alpha, x, t_end, dt=1e-3):
    y, t = 0.0, 0.0
    while t < t_end - 1e-12:
        y += dt * (-alpha(t) * y + x(t)); t += dt
    return y
pulse = lambda t: 1.0 if 0 <= t < 1 else 0.0
shifted = lambda t: pulse(t - 1)
for alpha, same in ((lambda t: 0.8, True), (lambda t: 0.8 + 0.5 * t, False)):
    assert (abs(solve(alpha, shifted, 3.0) - solve(alpha, pulse, 2.0)) < 1e-3) == same
print("ALL CHECKS PASSED")