Workspace IndexMath › Day 10

Recurrence Relations and Generating Functions TODO

Math · Day 10 / 52 · July — Discrete Math & Logic (Day 3-10)

Concept

A recurrence relation defines a sequence's terms in terms of earlier terms, and it's the most natural language for describing an algorithm's cost. A linear homogeneous recurrence with constant coefficients has a closed-form solution derivable from the roots of its characteristic equation, and when there's a nonhomogeneous term, you add a particular solution to build the general solution. A generating function packages a sequence as the coefficients of a formal power series, treating it as a single function; you turn the recurrence into an algebraic equation on that function, solve it, and read the coefficients back off to derive a closed form. Recurrences of the shape that comes out of divide-and-conquer algorithms can be solved directly for their asymptotic order using the master theorem, which tells you whether the recursive cost or the divide/combine cost dominates. What matters isn't always finding a closed form — it's the ability to set up the recurrence correctly and read off the growth rate from it.

Real work like algorithm complexity analysis, cumulative delay in retry backoff, and recursive estimates of queue length all starts from setting up a recurrence correctly.

Code & Formula

# 재귀관계와 생성함수(가볍게) — 피보나치 점화식을 (1) 메모이제이션 재귀, (2) 반복 계산,
# (3) 특성방정식 닫힌 형태(비네 공식)로 각각 구현해 세 방법의 결과가 일치하는지 확인.

from functools import lru_cache
import math

@lru_cache(maxsize=None)
def fib_memo(n):
    if n <= 1:
        return n
    return fib_memo(n - 1) + fib_memo(n - 2)   # F(n) = F(n-1) + F(n-2)

def fib_iter(n):
    a, b = 0, 1
    for _ in range(n):
        a, b = b, a + b
    return a

def fib_closed(n):
    # 특성방정식 x^2 = x + 1 의 근 phi, psi 로부터 얻는 닫힌 형태(비네 공식).
    phi = (1 + math.sqrt(5)) / 2
    psi = (1 - math.sqrt(5)) / 2
    return round((phi ** n - psi ** n) / math.sqrt(5))

print(" n | memo | iter | closed")
for n in range(0, 16):
    m, i, c = fib_memo(n), fib_iter(n), fib_closed(n)
    assert m == i == c, f"불일치 at n={n}: {m}, {i}, {c}"
    print(f"{n:2} | {m:4} | {i:4} | {c:4}")

print("\n세 방법 모두 n=0..15 에서 일치.")

# 생성함수 관점: F(x) = x / (1 - x - x^2) 의 계수를 급수 전개로 뽑아 같은 수열이 나오는지 확인.
def fib_via_series(order):
    coeffs = [0] * (order + 1)
    coeffs[1] = 1  # 분자 x
    # (1 - x - x^2) * F(x) = x  =>  F[n] = F[n-1] + F[n-2] (n>=2), F[0]=0, F[1]=1
    for k in range(2, order + 1):
        coeffs[k] = coeffs[k - 1] + coeffs[k - 2]
    return coeffs

series = fib_via_series(15)
print("생성함수 급수 전개로 얻은 F(0..15):", series)

Exercise

Pick a linear recurrence and implement it three ways — memoized recursion, iteration, and the characteristic-equation closed form — then compare results and running time for large n.

Practical Connection

For self-similar systems whose cost repeats at each level — Merkle tree verification cost, per-depth cost of recursive proof aggregation, total wait time under exponential backoff retries — setting up a recurrence relation is the most accurate way to work out the cost.

If you study this on a given day, add a note link and a ✅ to this line in the source curriculum (docs/knowledge/math-50-curriculum.md) and this spot will lead straight to the note body. You can also write directly on this page — but regenerating overwrites it, so it's safer to keep anything you want to save as markdown under docs/algorithms/.


한국어

재귀관계와 생성함수(가볍게) TODO

Math · Day 10 / 52 · 7월 — 이산수학·논리 (Day 3–10)

점화식을 코드로

개념

점화식은 수열의 항을 이전 항들로 정의하는 관계식이며, 알고리즘의 비용을 서술하는 가장 자연스러운 언어다. 상수 계수를 갖는 선형 동차 점화식은 특성방정식의 근으로부터 닫힌 형태의 해를 얻을 수 있고, 비동차 항이 있으면 특수해를 더해 일반해를 구성한다. 생성함수는 수열을 형식적 멱급수의 계수로 담아 하나의 함수로 다루는 도구이며, 점화식을 이 함수에 대한 대수 방정식으로 바꿔 풀고 다시 계수를 읽어 내는 방식으로 닫힌 형태를 유도한다. 분할정복 알고리즘에서 나오는 형태의 점화식은 마스터 정리로 재귀 비용과 분할 비용 중 어느 쪽이 지배적인지 판정해 점근적 해를 바로 얻을 수 있다. 중요한 것은 닫힌 형태를 항상 구하는 것이 아니라, 점화식을 정확히 세우고 그로부터 성장률을 읽어 내는 능력이다.

알고리즘 복잡도 분석, 재시도 백오프의 누적 지연, 큐 길이의 재귀적 추정 같은 실무 계산이 모두 점화식 세우기에서 출발한다.

코드 · 수식

# 재귀관계와 생성함수(가볍게) — 피보나치 점화식을 (1) 메모이제이션 재귀, (2) 반복 계산,
# (3) 특성방정식 닫힌 형태(비네 공식)로 각각 구현해 세 방법의 결과가 일치하는지 확인.

from functools import lru_cache
import math

@lru_cache(maxsize=None)
def fib_memo(n):
    if n <= 1:
        return n
    return fib_memo(n - 1) + fib_memo(n - 2)   # F(n) = F(n-1) + F(n-2)

def fib_iter(n):
    a, b = 0, 1
    for _ in range(n):
        a, b = b, a + b
    return a

def fib_closed(n):
    # 특성방정식 x^2 = x + 1 의 근 phi, psi 로부터 얻는 닫힌 형태(비네 공식).
    phi = (1 + math.sqrt(5)) / 2
    psi = (1 - math.sqrt(5)) / 2
    return round((phi ** n - psi ** n) / math.sqrt(5))

print(" n | memo | iter | closed")
for n in range(0, 16):
    m, i, c = fib_memo(n), fib_iter(n), fib_closed(n)
    assert m == i == c, f"불일치 at n={n}: {m}, {i}, {c}"
    print(f"{n:2} | {m:4} | {i:4} | {c:4}")

print("\n세 방법 모두 n=0..15 에서 일치.")

# 생성함수 관점: F(x) = x / (1 - x - x^2) 의 계수를 급수 전개로 뽑아 같은 수열이 나오는지 확인.
def fib_via_series(order):
    coeffs = [0] * (order + 1)
    coeffs[1] = 1  # 분자 x
    # (1 - x - x^2) * F(x) = x  =>  F[n] = F[n-1] + F[n-2] (n>=2), F[0]=0, F[1]=1
    for k in range(2, order + 1):
        coeffs[k] = coeffs[k - 1] + coeffs[k - 2]
    return coeffs

series = fib_via_series(15)
print("생성함수 급수 전개로 얻은 F(0..15):", series)

연습

선형 점화식 하나를 골라 메모이제이션 재귀, 반복 계산, 특성방정식 닫힌 형태 세 가지로 각각 구현하고 큰 n에서 결과와 실행 시간을 비교하라.

실무 · Verex 연결

머클 트리 검증 비용, 재귀적 증명 집계의 깊이별 비용, 지수 백오프 재시도의 총 대기 시간처럼 자기 유사 구조가 반복되는 시스템의 비용은 점화식으로 세우는 것이 가장 정확하다.

공부한 날 원본 커리큘럼(docs/knowledge/math-50-curriculum.md)의 이 줄에 노트 링크와 ✅ 를 붙이면, 이 자리는 노트 본문으로 바로 이어집니다. 노트 없이 이 페이지에 바로 적어도 됩니다 — 다만 다시 생성하면 덮어쓰이므로, 남길 글은 docs/algorithms/ 의 마크다운으로 쓰는 편이 안전합니다.

← 9. 카운팅 원리(순열·조합·이항계수)11. 내시균형·죄수의 딜레마 →