Compare commits
6
Commits
de2484754e
...
main
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
0b5e918ddd | ||
|
|
a2f240c22b | ||
|
|
9045520b57 | ||
|
|
e657b76b52 | ||
|
|
5054ea6388 | ||
|
|
34f250e169 |
Binary file not shown.
|
After Width: | Height: | Size: 538 KiB |
Binary file not shown.
|
Before Width: | Height: | Size: 570 KiB |
+81
-73
@@ -27,7 +27,8 @@
|
||||
#table_of_contents()
|
||||
|
||||
#domain_frame(
|
||||
bg_img_path: "assets/research/bg.png",
|
||||
bg_img_path: "assets/research/bg.jpg",
|
||||
cover_color: rgb("0F0F0F").transparentize(40%),
|
||||
font_color: color.oklch(95%, 0.01, 250deg),
|
||||
chrome_color: color.oklch(80%, 0.01, 250deg),
|
||||
title: [본질을 향한 여정],
|
||||
@@ -54,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 알고리즘은 최적 경로를 도출하는 가장 효율적인 알고리즘이다. \
|
||||
@@ -73,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()[
|
||||
실행 시간 측정의 신뢰도와 타당도를 높이기 위해서는 일정한 환경을 유지하는 것이 중요하다.
|
||||
@@ -219,7 +227,7 @@
|
||||
그래프의 특성만으로 Dijkstra 실행 없이 $RS$를 예측하는 방법을 찾는다.
|
||||
]
|
||||
|
||||
#stack(
|
||||
#steps(
|
||||
(
|
||||
[$bold(RS)$ 재정의],
|
||||
[
|
||||
@@ -444,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")),
|
||||
|
||||
+131
-88
@@ -250,7 +250,7 @@
|
||||
)
|
||||
]
|
||||
|
||||
#let stack(..layers) = context {
|
||||
#let steps(..layers) = context {
|
||||
let cp = color-palette.get()
|
||||
let radius = 12pt
|
||||
let gutter = 12pt
|
||||
@@ -316,7 +316,7 @@
|
||||
}
|
||||
}
|
||||
|
||||
#let ref_evidence() = {
|
||||
#let ref_evidence(kinds: none) = {
|
||||
let ca = cur_activity()
|
||||
|
||||
set ref(
|
||||
@@ -326,7 +326,10 @@
|
||||
align(bottom)[
|
||||
#hl[]
|
||||
*활동 증빙 자료:*
|
||||
#underline[#ref(label("Evidence) " + ca.name))]
|
||||
#underline[#ref(label("evidence) " + ca.name))]
|
||||
#if kinds != none {
|
||||
text(fill: color-ink-helper)[(#kinds)]
|
||||
}
|
||||
]
|
||||
}
|
||||
|
||||
@@ -364,7 +367,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,32 +444,73 @@
|
||||
]
|
||||
}
|
||||
|
||||
// Table of contents templage function
|
||||
#let table_of_contents() = page(
|
||||
// Table of contents template function
|
||||
#let table_of_contents() = context {
|
||||
let cp = color-palette.get()
|
||||
let m = meta.get()
|
||||
|
||||
page(
|
||||
footer: footer_template(),
|
||||
)[
|
||||
#context {
|
||||
let m = meta.get()
|
||||
heading(level: 1, outlined: false, numbering: none)[#m.cur_domain. #m.domain_name]
|
||||
#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(title: "", bg_img_path: none, font_color: color-ink, chrome_color: color-ink-helper, content) = page(
|
||||
background: place(
|
||||
center + horizon,
|
||||
if bg_img_path != none {
|
||||
image(bg_img_path, width: 100.5%, height: 100.5%, fit: "cover")
|
||||
},
|
||||
#let domain_frame(
|
||||
title: "",
|
||||
bg_img_path: none,
|
||||
cover_color: white.transparentize(50%),
|
||||
font_color: color-ink,
|
||||
chrome_color: color-ink-helper,
|
||||
content,
|
||||
) = page(
|
||||
background: if bg_img_path != none {
|
||||
stack(
|
||||
image(bg_img_path, width: 100.5%, height: 100.5%, fit: "cover"),
|
||||
move(
|
||||
dy: -50%,
|
||||
rect(width: 100.5%, height: 100.5%, fill: cover_color),
|
||||
),
|
||||
)
|
||||
} else { none },
|
||||
header: header_template(font_color: chrome_color),
|
||||
footer: footer_template(font_color: chrome_color),
|
||||
)[
|
||||
#set text(fill: font_color)
|
||||
#show strong: set text(fill: font_color)
|
||||
|
||||
#heading(level: 1)[
|
||||
#heading(level: 1, supplement: [domain])[
|
||||
#title
|
||||
]
|
||||
|
||||
@@ -474,11 +518,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(),
|
||||
fill: cp.cover-surface,
|
||||
)[
|
||||
#heading(level: 1)[
|
||||
#show heading.where(level: 1): set block(above: 0em, below: 25pt)
|
||||
#heading(level: 1, supplement: hook)[
|
||||
#name
|
||||
]
|
||||
#label(heading_text(name))
|
||||
@@ -487,45 +536,80 @@
|
||||
#hook
|
||||
]
|
||||
|
||||
#v(25pt)
|
||||
|
||||
#content
|
||||
]
|
||||
}
|
||||
|
||||
// Activity intro template function
|
||||
#let activity_intro(title: "", content) = page(
|
||||
#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(),
|
||||
)[
|
||||
#kicker("프로젝트 소개")
|
||||
#show outline: it => [
|
||||
#line(length: 100%, stroke: (paint: cp.accent-faint, thickness: 0.5pt))
|
||||
|
||||
#heading(level: 2)[
|
||||
#title
|
||||
#it
|
||||
]
|
||||
|
||||
#content
|
||||
#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: 0.8em,
|
||||
)[
|
||||
#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)[
|
||||
#title
|
||||
]
|
||||
|
||||
#content
|
||||
]
|
||||
|
||||
// Activity result
|
||||
#let activity_result(title: "", content) = page(
|
||||
header: header_template(show_activity: true),
|
||||
footer: footer_template(),
|
||||
)[
|
||||
#kicker("결과")
|
||||
|
||||
#heading(level: 2)[
|
||||
#heading(level: 2, supplement: hook)[
|
||||
#title
|
||||
]
|
||||
|
||||
@@ -540,9 +624,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)),
|
||||
@@ -565,7 +652,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),
|
||||
@@ -708,50 +795,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
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user