이 글에서는 시뮬레이션 및 모델링의 기초를 살펴볼 예정입니다. 시뮬레이션이란 무엇일까요? 제가 애용하는 Claude에게 물어본 결과 시뮬레이션은 실제 세계의 시스템, 상태 또는 프로세스를 컴퓨터나 물리적 모델을 통해 모방하는 것 이라고 합니다. 시뮬레이션을 통해 실제 세상을 예측할 수 있다면 정말 유용하지 않을까요?
해당 글은 KAIST의 온라인 공개강좌인 모델링 및 시뮬레이션 개론을 주로 수강하며 작성한 글입니다.
세상에는 여러 공공자원이 있습니다. 대표적으로는 물, 땅, 석유 등이 있는데요, 이러한 공유자원들이 따로 관리되지 않고, 개인이 이익에 따라 소비한다면 해당 자원은 고갈되어버린다는 경제 과학적 상황을 공유지의 비극이라고 표현합니다. 이 예시는 시뮬레이션과 모델링을 설명할 때 많이 사용하는 예시입니다.
상황을 가정해봅시다. 목자가 두 명이 있고, 각각 자신의 양떼를 가지고 있습니다. 둘은 일종의 경쟁관계입니다. 양들이 풀을 먹을 수 있는 목초지는 제한되어있다고 할 때, 목자들은 어떤 선택을 해야 자신의 이익을 극대화 할 수 있을까요?
등등 여러가지 선택을 할 수 있겠지만, 결과적으로는 공유자원인 목초지를 경쟁자보다 더 빨리, 많이 소비 할 수록 이익이 극대화됩니다. 이러한 선택지를 통해 제한된 공공재를 소비한다면, 결과는 고갈이 될 수밖에 없을 것입니다.
해당 예시에 대한 모델링을 진행한다면 어떤 방법이 있을까요? 먼저 중요한 오브젝트 객체를 정의 해 봅시다.
등으로 정의를 할 수 있겠습니다. 하지만 아쉽게도 여기서 끝이 아닙니다. 각 오브젝트의 속성과 관계도 정의해야 합니다.
여기서 정의된 속성/관계는 일부에 불과합니다. 이외에도 고려해야 할 것들이 많습니다.
Causal loop diagram은 시스템 내의 변수들의 인과 관계를 시각적으로 표현하는 도구입니다. 화살표로 변수 간 관계를 나타내며, 양의 관계(+)와 음의 관계(-)를 구분합니다. 시뮬레이션을 위해 모델링할 때 Causal Loop Diagram을 이용하면 모델의 대략적인 모양(abstracted view)을 관찰할 수 있습니다.
Causal Loop Diagram에는 세 가지 주요 구성 요소가 있습니다:
긍정적/부정적 링크는 루프를 생성할 수 있으며, 두 가지 종류의 루프가 있습니다:
지연이 없다면 모델링을 간단하게 표현하고 이상적으로 작동하도록 만들 수 있습니다. 하지만 현실세계의 대부분의 문제에는 지연이 포함됩니다.
예를 들어, 발주를 넣었는데 상품이 도착하지 않아 계속 발주를 넣는 경우 기대치보다 더 많은 상품이 도착할 수 있습니다. 이 때 이것을 해결하기 위해 반납을 할 수 있는데요, 반납 또한 지연되는 시간이 있기 때문에 발주때와 비슷한 문제가 발생할 수 있습니다. 이것을 진동(oscillations) 이라고 표현합니다.
진동이 목표치에 Converge한다면 목표값에 도달할 수 있지만, 오차가 계속 커지는 상황이 발생한다면 이를 채찍 효과(bullwhip effect)라고 합니다. 이는 주로 공급망 관리(SCM)에서 발생할 수 있는 일반적인 문제입니다.
System archetype은 조직이나 시스템에서 반복적으로 나타나는 행동 패턴을 설명하는 개념적 모델입니다. archetype을 이해하면 복잡한 시스템의 문제를 더 쉽게 파악하고 해결할 수 있습니다.
아래의 예시들은 System Archetype에서 이미지와 더 자세한 설명을 확인할 수 있습니다.
이 타입에는 치킨 게임, 군사력 경쟁 등이 포함됩니다. 두 개의 루프 사이에 공통 Factor가 있고, 이 요인이 두 루프를 모두 제어합니다. 예를 들어, A 국가에서 군사력을 증강하면 B 국가도 군사력을 증강해야 하고, 이로 인해 양측에서 지속적인 상승 효과가 발생하게 됩니다.
이 타입은 한정된 자원 상황에서 A와 B가 있을 때, A에 자원이 투자될수록 B의 힘이 약해지는 현상을 설명합니다. 두 루프 모두 강화 루프이지만, 방향이 다릅니다.
Causal Diagram에서는 시나리오를 Conceptual하게 모델링하기에는 좋았지만, 실제 복잡한 문제에서 해당 방식으로 모델링하기에는 복잡도나, 가시성의 문제가 발생합니다. 즉, 정성적 모델에서 정량적 모델로 발전시키기 위해서는 System Dynamics Model로 발전해야합니다. 이 과정에는 변수의 수학적 정의, 초기값 설정, 방정식 구성 등이 포함됩니다.
추가적인 이미지와 예시들은 System Dynamics에서 확인할 수 있습니다.
Causal loop diagram:
출생률 (+) --> 인구 --> (+) 출생률
인구 --> (+) 사망률 --> (-) 인구
System dynamics model:
인구(t) = 인구(t-dt) + (출생률 - 사망률) * dt
초기 인구 = 1000
출생률 = 인구 * 출생률_계수
사망률 = 인구 * 사망률_계수
출생률_계수 = 0.03
사망률_계수 = 0.02
시뮬레이션에서 시간은 연속적 또는 이산적으로 모델링될 수 있습니다. 유한 상태 기계는 시스템이 가질 수 있는 상태의 수가 유한하며, 특정 조건에 따라 상태 간 전이가 일어나는 모델입니다.
이 두 개념은 다양한 시스템의 동적 행동을 모델링하는 데 중요한 역할을 합니다.
시뮬레이션에서 시간의 흐름을 모델링하는 방식은 크게 두 가지로 나눌 수 있습니다:
시간 흐름의 선택은 모델링하려는 시스템의 특성과 시뮬레이션의 목적에 따라 결정됩니다.
유한 상태 기계는 시스템의 동작을 유한한 수의 상태와 그 사이의 전이로 표현하는 수학적 모델입니다.
추가적인 이미지와 예시들은 Finite State Machine에서 확인할 수 있습니다.
States: 대기, 선택, 지불, 배출
Transitions:
대기 -> 선택 (상품 버튼 누름)
선택 -> 지불 (금액 투입)
지불 -> 배출 (결제 완료)
배출 -> 대기 (상품 배출 완료)
페트리넷(Petri net)은 병렬 시스템과 분산 시스템을 모델링하는 데 사용되는 수학적 도구입니다. 이 모델은 시스템의 동적 행동을 그래픽적으로 표현할 수 있어 복잡한 시스템을 이해하고 분석하는 데 유용합니다.
페트리넷은 다음과 같은 기본 요소로 구성됩니다:
페트리넷의 수학적 표현은 다음과 같습니다: PN = (P, T, F, W, M0)
이러한 표기법을 통해 복잡한 시스템의 구조와 동작을 정확하게 표현할 수 있습니다.
페트리넷은 시스템의 동적 행동을 시뮬레이션하는 데 매우 유용합니다. 시뮬레이션을 통해 시스템의 다양한 상태와 이벤트 시퀀스를 분석할 수 있습니다.
페트리넷에서 자주 나타나는 패턴들:
이러한 패턴들을 조합하여 복잡한 시스템의 동작을 모델링할 수 있습니다.
페트리넷은 시스템의 다양한 특성과 속성을 분석하는 데 사용됩니다. 이를 통해 시스템의 동작을 이해하고 잠재적인 문제를 식별할 수 있습니다.
Places: P1(생산된 아이템), P2(버퍼 공간), P3(소비된 아이템)
Transitions: T1(생산), T2(소비)
초기 마킹: M0 = (0, N, 0) (N은 버퍼 크기)
아크:
P2 -> T1 (생산 조건: 버퍼 공간 있음)
T1 -> P1 (아이템 생산)
P1 -> T2 (소비 조건: 아이템 존재)
T2 -> P3 (아이템 소비)
T2 -> P2 (버퍼 공간 반환)
이 예제는 유한한 버퍼를 가진 생산자-소비자 시스템을 모델링합니다. 페트리넷을 통해 버퍼 오버플로우나 언더플로우와 같은 문제를 쉽게 식별하고 분석할 수 있습니다.
8-퀸 문제는 체스판에 8개의 퀸을 서로 공격할 수 없게 배치하는 문제입니다. 이 문제는 조합 최적화와 백트래킹 알고리즘을 이해하는 데 자주 사용되는 예제입니다.
def is_safe(board, row, col):
# 같은 열에 퀸이 있는지 확인
for i in range(row):
if board[i] == col:
return False
# 왼쪽 위 대각선 확인
for i, j in zip(range(row-1, -1, -1), range(col-1, -1, -1)):
if board[i] == j:
return False
# 오른쪽 위 대각선 확인
for i, j in zip(range(row-1, -1, -1), range(col+1, 8)):
if board[i] == j:
return False
return True
def solve_queens(board, row):
if row == 8:
print(board)
return True
for col in range(8):
if is_safe(board, row, col):
board[row] = col
if solve_queens(board, row + 1):
return True
board[row] = -1
return False
board = [-1] * 8
solve_queens(board, 0)
이 코드는 백트래킹 방식으로 8-퀸 문제를 해결합니다. 각 행에 하나의 퀸을 배치하며, 충돌이 발생하면 다른 위치를 시도합니다.
오토마타(Automata)는 추상적인 기계 또는 계산 모델을 나타냅니다. 이는 컴퓨터 과학에서 계산 과정을 형식화하고 분석하는 데 사용되는 중요한 개념입니다.
오토마타 이론은 계산 이론의 기초를 제공하며, 알고리즘 설계와 복잡도 분석에 중요한 역할을 합니다.