Workspace IndexAlgorithms › Day 18

Combinatorial Generation, Gray Codes, and Permutation Enumeration (TAOCP Vol. 4) TODO

Algorithms · Day 18 / 100 · A. Advanced Algorithms & Data Structures (Day 1-19)

Concept

Enumerating combinatorial objects means generating structures like subsets, combinations, or permutations one at a time, with no duplicates and none missed. A Gray code lists subsets so that any two consecutive codes differ in exactly one bit; the reflected binary Gray code is obtained simply by XORing index i with i shifted right by one. Permutations can be enumerated by producing the next permutation in lexicographic order, or by a method that swaps only two adjacent elements at each step to generate every permutation. The key benefit of this kind of minimal-change enumeration is that each next state's value can be computed incrementally from the previous one with a single small update. So the design goal isn't the cost of enumeration itself, but eliminating the cost of recomputing each state from scratch.

In test-vector generation, fuzzing-seed design, and exhaustive search of small state spaces, covering everything without duplication or omission is exactly what gives verification its confidence, and minimal-change ordering removes the cost of rewinding state.

Code & Formula

# 조합 생성·그레이 코드 — 반사 이진 그레이 코드를 생성하고 인접 코드의 해밍 거리가 항상 1임을 검증한다.

def gray_code(n):
    return [i ^ (i >> 1) for i in range(1 << n)]      # i와 i>>1의 XOR

def hamming_distance(a, b):
    return bin(a ^ b).count("1")

def to_bits(x, n):
    return format(x, f"0{n}b")

n = 4
codes = gray_code(n)

# 인접 코드가 정확히 1비트만 다른지 검증 (원형으로 마지막→처음도 포함)
distances = [hamming_distance(codes[i], codes[(i + 1) % len(codes)]) for i in range(len(codes))]
assert all(d == 1 for d in distances), "그레이 코드 인접 거리 위반!"

# 그레이 코드 순서로 만든 부분집합과 단순 이진 카운팅 순서로 만든 부분집합이
# "집합으로서는" 동일한지 확인 (순서만 다르고 원소 전체는 같아야 함)
binary_order = list(range(1 << n))
assert set(codes) == set(binary_order)

print(f"n={n} 그레이 코드 ({len(codes)}개):")
for i, c in enumerate(codes):
    prev_dist = distances[i - 1] if i else distances[-1]
    print(f"  step {i:2d}: {to_bits(c, n)}  (직전과 해밍거리={prev_dist})")
print("모든 인접 쌍의 해밍 거리 == 1:", all(d == 1 for d in distances))
print("이진 카운팅과 원소 집합 동일:", set(codes) == set(binary_order))

Exercise

Generate an n-bit Gray code using the XOR formula and unit-test that the Hamming distance between adjacent codes is always 1; then confirm that the same set of subsets, generated instead by plain binary counting, matches it as a set.

Practical Connection

For logic with a small, finite number of conditions or permission-flag combinations, like settlement logic, exhaustive enumeration gives a stronger guarantee than random fuzzing — combinatorial enumeration becomes a practical tool for writing branch tests for smart contracts.

If you study this on a given day, add a note link and a ✅ to this line in the source curriculum (docs/knowledge/dev-100-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/.


한국어

조합 생성·그레이 코드·순열 열거 (TAOCP 4권) TODO

Algorithms · Day 18 / 100 · A. 고급 알고리즘·자료구조 (Day 1–19)

테스트 벡터·퍼징·상태 공간 탐색의 도구

개념

조합적 대상의 열거란 부분집합, 조합, 순열 같은 구조를 중복 없이 빠짐없이 하나씩 생성하는 기법이다. 그레이 코드는 연속한 두 코드가 정확히 한 비트만 다르도록 부분집합을 나열하는 순서이며, 반사 이진 그레이 코드는 인덱스 i에 대해 i와 i를 오른쪽으로 한 칸 시프트한 값의 XOR로 간단히 얻는다. 순열은 사전순으로 다음 순열을 만드는 방법이나, 매 단계 인접 두 원소만 교환하며 모든 순열을 생성하는 방식으로 열거할 수 있다. 이런 최소 변화 열거의 핵심 이점은 이전 상태에서 한 번의 작은 갱신으로 다음 상태의 평가값을 증분 계산할 수 있다는 것이다. 따라서 열거 자체의 비용보다 각 상태를 처음부터 다시 계산하는 비용을 없애는 것이 설계의 목표가 된다.

테스트 벡터 생성, 퍼징 시드 설계, 작은 상태 공간의 완전 탐색에서 중복이나 누락 없이 전수를 도는 것이 곧 검증의 신뢰도이고, 최소 변화 순서를 쓰면 상태 되감기 비용이 사라진다.

코드 · 수식

# 조합 생성·그레이 코드 — 반사 이진 그레이 코드를 생성하고 인접 코드의 해밍 거리가 항상 1임을 검증한다.

def gray_code(n):
    return [i ^ (i >> 1) for i in range(1 << n)]      # i와 i>>1의 XOR

def hamming_distance(a, b):
    return bin(a ^ b).count("1")

def to_bits(x, n):
    return format(x, f"0{n}b")

n = 4
codes = gray_code(n)

# 인접 코드가 정확히 1비트만 다른지 검증 (원형으로 마지막→처음도 포함)
distances = [hamming_distance(codes[i], codes[(i + 1) % len(codes)]) for i in range(len(codes))]
assert all(d == 1 for d in distances), "그레이 코드 인접 거리 위반!"

# 그레이 코드 순서로 만든 부분집합과 단순 이진 카운팅 순서로 만든 부분집합이
# "집합으로서는" 동일한지 확인 (순서만 다르고 원소 전체는 같아야 함)
binary_order = list(range(1 << n))
assert set(codes) == set(binary_order)

print(f"n={n} 그레이 코드 ({len(codes)}개):")
for i, c in enumerate(codes):
    prev_dist = distances[i - 1] if i else distances[-1]
    print(f"  step {i:2d}: {to_bits(c, n)}  (직전과 해밍거리={prev_dist})")
print("모든 인접 쌍의 해밍 거리 == 1:", all(d == 1 for d in distances))
print("이진 카운팅과 원소 집합 동일:", set(codes) == set(binary_order))

연습

n비트 그레이 코드를 XOR 공식으로 생성해 인접 코드의 해밍 거리가 항상 1임을 단위 테스트로 검증하고, 같은 부분집합 집합을 단순 이진 카운팅으로 생성한 결과와 집합으로서 동일한지 확인하라.

실무 · Verex 연결

여러 조건이 걸린 정산 로직이나 권한 플래그 조합처럼 경우의 수가 작고 유한한 영역은 무작위 퍼징보다 전수 열거가 더 강한 보장을 주므로, 조합 열거는 스마트 컨트랙트 분기 테스트를 짜는 실전 도구가 된다.

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

← 17. 병렬 알고리즘 모델19. [복습] 알고리즘 선택의 실전 기준표 →