아래 튜토리얼은 graph-tool 라이브러리에서 제공하는 VoterState 클래스(일반화된 q-state Voter Model)를 예시로 다룹니다.
정성스러운 한글 해설, 중요 개념 정리, 파이썬 코드 샘플과 함께, 초보자를 위한 주석도 꼼꼼히 달아서 작성했습니다.
Voter Model(투표자 모형)은 사회학 혹은 생물학(상호작용 입자계)에서 자주 등장하는 확률적 동역학 모델입니다.
(\quad)### VoterState(g, q, r=0)
g: 그래프로 표현되는 네트워크 (예: 무향/유향 그래프). q: 가질 수 있는 의견(opinion, state)의 개수. (기본값 2 = 전통적인 “찬반 양자 택일” Voter Model) r: 노드가 무작위로 새로운 의견을 취할 확률 (0 ≤ r ≤ 1). s: 초기 상태(정수 배열) 가 주어지면 그걸로 시작, 아니면 내부적으로 임의로 q개 중 하나를 배정.Holley & Liggett(1975), Clifford & Sudbury(1973)가 고전적 Voter Model 연구의 대표 레퍼런스로 often 인용됩니다.
VoterState(g, q=2, r=0.0, s=None)
g, 의견 수 q, 무작위 전환률 r, 초기상태 s(VertexPropertyMap)를 인자로 준다.state.get_state()
current_map = state.get_state()
# current_map[v] => 그래프 정점 v의 현재 상태(0 ~ q-1 중 하나)state.iterate_async(niter=1)
state.iterate_sync(niter=1)
copy(), get_active(), set_active(), ...**
copy()는 상태를 복제해 새로운 state 객체를 만든다. get_active()/set_active()는 특정 노드를 “active”로 설정할 때(이후 갱신 대상이 될지 말지 등) 사용. (Classic voter model에선 잘 안 쓰일 수도.)아래는 graph-tool 문서에서 보여준 예시를 좀 더 자세히 풀어쓴 것입니다.
"pgp-strong-2009" (내장된 예시 네트워크, pgp trust network). iterate_sync()) 또는 비동기식(iterate_async()) 반복을 하면서, 매 시점마다 각 의견이 몇 명인지 기록해본다.import graph_tool.all as gt
import numpy as np
import matplotlib.pyplot as plt
def run_voter_model_example():
"""
q=4 상태를 갖는 Voter Model을 "pgp-strong-2009" 그래프에서 시뮬레이션.
동기식 업데이트를 2000번 반복하며, 각 타임스텝마다
'각 의견별 노드 수'를 저장하여 그래프 그리기.
"""
# 1) 그래프 로드
g = gt.collection.data["pgp-strong-2009"]
print("Number of vertices:", g.num_vertices())
print("Number of edges:", g.num_edges())
# 2) VoterState 초기화: q=4, r=0 => 이웃 복사만 일어나는 전통적 모델
state = gt.VoterState(g, q=4, r=0.0, s=None)
# s=None => 랜덤 초기 의견 배정
# 3) 시뮬레이션 파라미터
T_MAX = 2000
# 4) 각 시점별, 의견별 노드 개수를 저장할 리스트
opinion_counts = [[] for _ in range(4)]
# 5) 동기식(iterate_sync) 방식으로 T_MAX번 반복
for t in range(T_MAX):
# 한 번의 sweep(모든 노드를 업데이트)
changed = state.iterate_sync(niter=1)
# 현재 상태의 VertexPropertyMap 얻기
s = state.get_state().a # .a => numpy array
# s[i]는 i번째 노드의 의견(0~3)
for r_id in range(4):
cnt = np.sum(s == r_id)
opinion_counts[r_id].append(cnt)
# 6) 결과 시각화
plt.figure(figsize=(6,4))
for r_id in range(4):
plt.plot(opinion_counts[r_id], label=f"Opinion {r_id}")
plt.xlabel("Time")
plt.ylabel("Number of nodes")
plt.legend()
plt.tight_layout()
plt.savefig("voter_model_q4.png")
plt.show()
if __name__ == "__main__":
run_voter_model_example()
state = gt.VoterState(...): Voter Model 상태를 생성. 여기서 r=0.0 => 업데이트 시 무작위 전환 없이, 항상 이웃 의견을 따라감. iterate_sync(1) 호출 → 모든 노드가 직전 시점 이웃의 의견을 복사. changed = ... : 몇 개 노드가 실제로 바뀌었는지 알려주지만, 여기선 사용 안 함. s = state.get_state().a : 정수형 NumPy array를 반환. s[v] = 정점 v의 현재 의견. opinion_counts[r_id].append(...): r_id번째 의견이 몇 개인지 세서 저장. Tip: 큰 네트워크라면, iterate_sync(niter=100)으로 한 번에 100번 진행해도 동일하지만, 그럼 중간 관측이 힘들다.
r가 의미하는 것 (랜덤 flip)r>0이면, “노드가 업데이트 될 때, 확률 r로 임의 의견(0~q-1) 중 하나를 선택”. iterate_async) vs 동기(iterate_sync)iterate_async(niter=k) 하면, 임의 노드 한 개씩 k번 연속 업데이트. 즉, t단위가 정교하지 않고, 랜덤 순서로 업데이트됨.iterate_sync(niter=1) => 모든 노드를 동시에(or 병렬로) 업데이트해, 각 노드가 "이웃의 직전의견"을 본다.Voter Model 연구에서, 동기/비동기 업데이트가 미치는 영향이 가끔 다르지만, 그래프툴은 둘 다 지원.
실전 Tip
in-neighbor 중 하나를 복사)matplotlib 그래프 그리기로 “시간에 따른 각 의견(또는 몇 개 노드의 state) 변화”를 추적하면, 모델 동작을 직관적으로 이해할 수 있음.이상으로, VoterState 클래스의 개념과 사용법, 그리고 관련 파이썬 코드 샘플을 살펴봤습니다.
초보자도 따라해볼 수 있게끔, 그래프 로드 → VoterState 생성 → 일정 횟수 iterate → 결과 시각화 순서로 정리해보았습니다.
추가 문의나 테스트를 위해선, 위 코드를 실행한 뒤, 시각화 결과(voter_model_q4.png 등)를 비교해보며 실험을 확장해보시는 걸 권장합니다.