change table of contents design, add activity outline

This commit is contained in:
2026-09-05 09:44:49 +09:00
parent e657b76b52
commit 9045520b57
2 changed files with 212 additions and 148 deletions
+78 -71
View File
@@ -55,15 +55,7 @@
#activity_cover(
name: [Dijkstra Runtime Analysis],
hook: [
`Big-O` 시간 복잡도의 한계를 넘어, \
알고리즘의 세부 작업 실행 횟수와 단위 실행 시간을 고려한 \
가장 정확한 `Dijkstra` 알고리즘 런타임 예측 모델
],
)[]
#activity_intro(
title: "Big-O가 답하지 못하는 것",
hook: [Big-O가 버린 세부 실행비용을 다시 세우고, 실행해야만 있던 감소 횟수를 그래프 특성만으로 구해, 이진 Dijkstra의 런타임 변동 96.9%를 실행 전에 설명한 모델.],
)[
네비게이션, 자율주행, 우주항공 많은 현대 기술들에게 최적 경로를 탐색하는 것은 중요한 일이며,
Dijkstra 알고리즘은 최적 경로를 도출하는 가장 효율적인 알고리즘이다. \
@@ -74,11 +66,26 @@
IB 소논문 활동에서 시작해 계속 발전시켜 현재는 외부 학술지에도 기제된 연구로, 목표는 그래프의 노드 수, 간선 수, 가중치의 분산, 기기 성능만으로 이집 힙이 적용된 Dijkstra의 실행시간을 예측하는 것이다.
]
// #activity_intro(
// title: "Big-O가 답하지 못하는 것",
// )[
// 네비게이션, 자율주행, 우주항공 등 많은 현대 기술들에게 최적 경로를 탐색하는 것은 중요한 일이며,
// Dijkstra 알고리즘은 최적 경로를 도출하는 가장 효율적인 알고리즘이다. \
// 그러나 자율주행과 같이 실시간성과 속도가 중요한 문제가 많아지자, 휴리스틱 기반의 A\* 알고리즘들이 적용되었다. 이들은 속도는 빠르지만, 항상 최적해를 보장하지는 않한다는 트레이드오프가 존재한다. \
// 상황에 따라 적절한 알고리즘을 선택하면 될 듯 하지만, Big-O 시간복잡도는 노드·간선 수 등 입력 크기에 따른 점근적 증가율만 나타낼 뿐, 상수항이나 그래프의 특성, 기기 성능 같은 요인은 반영하지 않기 때문에 Dijkstra의 실제 실행시간이 충분한지 알기 어렵다. \
// 그래서 *"이 트레이드오프를 감이 아닌 숫자로 계산해서 상황에 따른 정확한 알고리즘을 선택할 수는 없을까?"*라는 질문에서 출발하여 입력 그래프와 기기 성능만으로 Dijkstra의 실제 실행시간을 예측하는 모델을 연구했다.
// IB 소논문 활동에서 시작해 계속 발전시켜 현재는 외부 학술지에도 기제된 연구로, 목표는 그래프의 노드 수, 간선 수, 가중치의 분산, 기기 성능만으로 이집 힙이 적용된 Dijkstra의 실행시간을 예측하는 것이다.
// ]
#activity_table()
#let RS = math.italic("RS")
#let RSR = math.italic("RSR")
#activity_process(
title: "통제된 환경",
title: [*통제된 환경*],
hook: [통제된 환경에서 벗어나다.],
)[
#problem()[
실행 시간 측정의 신뢰도와 타당도를 높이기 위해서는 일정한 환경을 유지하는 것이 중요하다.
@@ -445,80 +452,80 @@
]
]
#activity_result(title: "예측할 수 있게 된 것")[
#block_equation(
title: [키 감소 횟수],
description: [$V$ : 노드 수, $E$ : 간선 수, $sigma$ : 가중치 표준편차],
)[
$
RSR(macron(k), sigma) & = macron(k)^0.0612 (0.928 log sigma - 0.711), quad
macron(k)(V, E) & = E \/ V \
RS(V, E, sigma) & = E dot RSR(macron(k)(V, E), sigma)
$
]
// #activity_result(title: "예측할 수 있게 된 것")[
// #block_equation(
// title: [키 감소 횟수],
// description: [$V$ : 노드 수, $E$ : 간선 수, $sigma$ : 가중치 표준편차],
// )[
// $
// RSR(macron(k), sigma) & = macron(k)^0.0612 (0.928 log sigma - 0.711), quad
// macron(k)(V, E) & = E \/ V \
// RS(V, E, sigma) & = E dot RSR(macron(k)(V, E), sigma)
// $
// ]
실행해야만 알 수 있던 $RS$를 세 변수만으로 계산할 수 있게 되었다.
// 실행해야만 알 수 있던 $RS$를 세 변수만으로 계산할 수 있게 되었다.
#block_equation(
title: [단위 실행시간],
description: [단위 : 초],
)[
$
"UC"_1 & = 2.15 times 10^(-7) \
k_3(V) & = 1.59 times 10^(-7) e^(-5.67 times 10^(-5) V) + 4.37 times 10^(-8) \
"UC"_2(V) & = 1.06 times 10^(-6) log_2 V - 1.09 times 10^(-5)
$
]
// #block_equation(
// title: [단위 실행시간],
// description: [단위 : 초],
// )[
// $
// "UC"_1 & = 2.15 times 10^(-7) \
// k_3(V) & = 1.59 times 10^(-7) e^(-5.67 times 10^(-5) V) + 4.37 times 10^(-8) \
// "UC"_2(V) & = 1.06 times 10^(-6) log_2 V - 1.09 times 10^(-5)
// $
// ]
세 값은 모두 $V$의 함수이거나 상수가 되어 식에 남아 있던 미지수가 전부 사라진다.
// 세 값은 모두 $V$의 함수이거나 상수가 되어 식에 남아 있던 미지수가 전부 사라진다.
#block_equation(
title: [최종 모델],
description: [입력 : $V$, $E$, $sigma$],
)[
$
"Runtime"(V, E, sigma) = V dot "UC"_1 + E dot k_3(V) + RS(V, E, sigma) dot "UC"_2(V)
$
]
// #block_equation(
// title: [최종 모델],
// description: [입력 : $V$, $E$, $sigma$],
// )[
// $
// "Runtime"(V, E, sigma) = V dot "UC"_1 + E dot k_3(V) + RS(V, E, sigma) dot "UC"_2(V)
// $
// ]
최종 식의 세 변수 모두 실행 전에 그래프에서 직접 추출할 수 있는 값이기에, \
*Dijkstra를 번도 실행하지 않고 실행시간을 예측할 있다.*
]
// 최종 식의 세 변수 모두 실행 전에 그래프에서 직접 추출할 수 있는 값이기에, \
// *Dijkstra를 한 번도 실행하지 않고 실행시간을 예측할 수 있다.*
// ]
#activity_result(title: "남은 오차")[
#figure(
image("assets/research/dijkstra/comparison_plot.png"),
caption: [실제 경로 데이터에 대한 실행시간 예측과 $RS$ 예측],
)
// #activity_result(title: "남은 오차")[
// #figure(
// image("assets/research/dijkstra/comparison_plot.png"),
// caption: [실제 경로 데이터에 대한 실행시간 예측과 $RS$ 예측],
// )
#figure(
image("assets/research/dijkstra/predicted_vs_real.png", width: 60%),
caption: [생성 그래프에 대한 예측값과 실측값],
)
// #figure(
// image("assets/research/dijkstra/predicted_vs_real.png", width: 60%),
// caption: [생성 그래프에 대한 예측값과 실측값],
// )
내삽에 대해 실행 시간 예측에 대해서 $96.9%$를 설명에 성공했다. \
게다가 실제 경로 데이터(외삽)에서도 $RS$예측에 대해 일관된 정확도를 보였다. \
그러나 실전 상황에서 그래프가 커질수록 실행시간 예측은 과대평가하는 경항이 보였다.\
// 내삽에 대해 실행 시간 예측에 대해서 $96.9%$를 설명에 성공했다. \
// 게다가 실제 경로 데이터(외삽)에서도 $RS$예측에 대해 일관된 정확도를 보였다. \
// 그러나 실전 상황에서 그래프가 커질수록 실행시간 예측은 과대평가하는 경항이 보였다.\
이 결과들에서 내 연구의 의의와 한계가 뚜렷하게 드러난다. \
$RS$는 그래프의 구조만으로 결정되므로, 그래프의 근본적인 특성까지 쪼개었더니 정확하게 설명이 가능해졌으나, 실행시간은 파이썬 아래의 캐싱이나 하드웨어적 특성까지 쪼개지 못해 예측과 실측값 차이가 벌어졌다.
// 이 결과들에서 내 연구의 의의와 한계가 뚜렷하게 드러난다. \
// $RS$는 그래프의 구조만으로 결정되므로, 그래프의 근본적인 특성까지 쪼개었더니 정확하게 설명이 가능해졌으나, 실행시간은 파이썬 아래의 캐싱이나 하드웨어적 특성까지 쪼개지 못해 예측과 실측값 차이가 벌어졌다.
#table(
columns: (auto, 1fr),
table.header([*문제 상황*], [*극복 방법*]),
[학습 데이터의 부재], [분포를 분석해 864,000개를 직접 생성],
[실행해야 있는 ], [$E times RSR$ 쪼개 미지수를 하나로 축소],
[다중공선성], [$V$ 개별 회귀 기여도 기준으로 정밀도 배분],
)
// #table(
// columns: (auto, 1fr),
// table.header([*문제 상황*], [*극복 방법*]),
// [학습 데이터의 부재], [분포를 분석해 864,000개를 직접 생성],
// [실행해야 알 수 있는 값], [$E times RSR$로 쪼개 미지수를 하나로 축소],
// [다중공선성], [$V$별 개별 회귀 후 기여도 기준으로 정밀도 배분],
// )
모든 문제 상황에서는 직면한 문제를 작은 단위들로 쪼개고, 작은 문제들의 해결책들을 종합하여 전체 문제를 해결해나갔다.
실행시간 측정을 위한 통제된 환경은 직접 구축한 홈서버의 가상화 환경(PVE)를 통해 구현했다.
// 모든 문제 상황에서는 직면한 큰 문제를 작은 단위들로 쪼개고, 작은 문제들의 해결책들을 종합하여 전체 문제를 해결해나갔다.
// 실행시간 측정을 위한 통제된 환경은 직접 구축한 홈서버의 가상화 환경(PVE)를 통해 구현했다.
이제 남은 오차는 파이썬이라는 언어 아래의 저차원에 위치해 있다. \
카이스트에서 언어와 하드웨어 수준의 저차원 요소를 배워 모델의 정확도를 끌어올리고, 완성한 모델을 실제 임베디드 시스템에서 알고리즘 선택의 지표로 적용하려 한다.
// 이제 남은 오차는 파이썬이라는 언어 아래의 저차원에 위치해 있다. \
// 카이스트에서 언어와 하드웨어 수준의 저차원 요소를 배워 이 모델의 정확도를 끌어올리고, 완성한 모델을 실제 임베디드 시스템에서 알고리즘 선택의 지표로 적용하려 한다.
#context ref_evidence()
]
// #context ref_evidence()
// ]
#add_evidence(
activity_ref: ref(label("Dijkstra Runtime Analysis")),
+122 -65
View File
@@ -326,7 +326,7 @@
align(bottom)[
#hl[]
*활동 증빙 자료:*
#underline[#ref(label("Evidence) " + ca.name))]
#underline[#ref(label("evidence) " + ca.name))]
]
}
@@ -364,7 +364,7 @@
)[
#context {
let m = meta.get()
link((page: 1, x: 0pt, y: 0pt))[#m.cur_domain. #m.domain_name]
link((page: 2, x: 0pt, y: 0pt))[#m.cur_domain. #m.domain_name]
h(1fr)
if show_activity {
let ca = cur_activity()
@@ -441,17 +441,47 @@
]
}
// Table of contents templage function
#let table_of_contents() = page(
footer: footer_template(),
)[
#context {
// Table of contents template function
#let table_of_contents() = context {
let cp = color-palette.get()
let m = meta.get()
heading(level: 1, outlined: false, numbering: none)[#m.cur_domain. #m.domain_name]
page(
footer: footer_template(),
)[
#show outline.entry.where(level: 1): it => link(it.element.location())[
#block(above: 25pt)[
#grid(
columns: (1fr, auto),
align: horizon,
text(font: font-subhead, size: 15pt, weight: 700)[
#it.indented(it.prefix(), heading_text(it.body()))
],
text(size: 10pt, fill: color-ink-helper)[
#it.page()
],
)
#let desc = it.element.supplement
#if desc != [domain] and desc != [evidence] {
text(fill: color-ink-helper, size: 10pt)[
#it.element.supplement
]
}
#outline(title: none, depth: 2)
]
#v(10pt)
#line(length: 100%, stroke: (paint: cp.accent-faint, thickness: 0.5pt))
]
]
#heading(level: 1, outlined: false, numbering: none)[#m.cur_domain. #m.domain_name]
#label("table_of_contents")
#outline(title: none, depth: 1)
]
}
// Domain frame template function
#let domain_frame(
@@ -477,7 +507,7 @@
#set text(fill: font_color)
#show strong: set text(fill: font_color)
#heading(level: 1)[
#heading(level: 1, supplement: [domain])[
#title
]
@@ -485,11 +515,16 @@
]
// Activity cover template function
#let activity_cover(name: "", hook: "", content) = page(
#let activity_cover(name: "", hook: "", content) = context {
let cp = color-palette.get()
page(
header: header_template(),
footer: footer_template(),
)[
#heading(level: 1)[
fill: cp.cover-surface,
)[
#show heading.where(level: 1): set block(above: 0em, below: 25pt)
#heading(level: 1, supplement: hook)[
#name
]
#label(heading_text(name))
@@ -498,8 +533,11 @@
#hook
]
#v(25pt)
#content
]
]
}
// Activity intro template function
#let activity_intro(title: "", content) = page(
@@ -508,21 +546,81 @@
)[
#kicker("프로젝트 소개")
#heading(level: 2)[
#heading(level: 2, outlined: false)[
#title
]
#content
]
#let activity_table() = context {
let cp = color-palette.get()
let ca = cur_activity()
let level1s = query(heading.where(level: 1, outlined: true))
let n = counter(heading).get().at(0)
let sel = heading.where(level: 2, outlined: true).after(ca.location)
if n < level1s.len() {
sel = sel.before(level1s.at(n).location(), inclusive: false)
}
page(
header: header_template(show_activity: true),
footer: footer_template(),
)[
#show outline: it => [
#line(length: 100%, stroke: (paint: cp.accent-faint, thickness: 0.5pt))
#it
]
#show outline.entry.where(level: 2): it => link(it.element.location())[
#set par(
spacing: 1em,
)
#block(above: 15pt)[
#grid(
columns: (1fr, auto),
align: horizon,
text(size: 12pt, weight: 700)[
#it.body()
],
text(size: 8pt, fill: color-ink-helper)[
#it.page()
],
)
#let desc = it.element.supplement
#par(
spacing: 0pt,
leading: 0pt,
)[
#text(fill: color-ink-helper, size: 10pt)[
#it.element.supplement
]
]
#line(length: 100%, stroke: (paint: cp.accent-faint, thickness: 0.5pt))
]
]
#heading(level: 2, outlined: false)[
시행착오 목차
]
#outline(title: none, target: sel)
]
}
// Activity process
#let activity_process(title: "", content) = page(
#let activity_process(title: "", hook: [], content) = page(
header: header_template(show_activity: true),
footer: footer_template(),
)[
#kicker("시행착오")
#heading(level: 2)[
#heading(level: 2, supplement: hook)[
#title
]
@@ -551,9 +649,12 @@
header: header_template(),
footer: footer_template(),
)[
#set heading(numbering: (..nums) => {
#set heading(
numbering: (..nums) => {
numbering("A", nums.at(1))
})
},
supplement: [evidence],
)
#show heading.where(level: 2): it => {
let num = counter(heading).display(
(..nums) => numbering("A", nums.at(1)),
@@ -576,7 +677,7 @@
#let cnt = ed.len()
#for (name, data) in ed [
#heading(level: 2, supplement: "evidence")[#name]
#label("Evidence) " + name)
#label("evidence) " + name)
#table(
columns: (10em, 1fr),
@@ -719,50 +820,6 @@
fill: color-ink,
)
// outline config
set outline(
indent: 2em,
)
show outline: set par(leading: 1em)
show outline.entry: it => link(
it.element.location(),
)[
#grid(
columns: (1fr, auto),
it.indented(it.prefix(), heading_text(it.body())), it.page(),
)
]
show outline.entry.where(level: 1): it => {
set text(
font: font-subhead,
size: 15pt,
weight: 700,
)
block(above: 50pt)[
#it
#line(length: 100%, stroke: (paint: color-ink-secondary, thickness: 1pt))
]
}
show outline.entry.where(level: 2): it => {
set text(
font: font-body,
size: 12pt,
weight: 400,
fill: color-ink-secondary,
)
if it.element.supplement.text != "evidence" {
block(above: 20pt)[
#it
]
}
}
// render content
doc
}