initial commit
This commit is contained in:
+13
@@ -0,0 +1,13 @@
|
||||
# Latex
|
||||
latex/aux/
|
||||
latex/build/*
|
||||
!latex/build/*.pdf
|
||||
|
||||
# Codes
|
||||
__pycache__/
|
||||
.venv/
|
||||
codes/results/
|
||||
codes/experiments/real_data/data/
|
||||
|
||||
# System
|
||||
.DS_Store
|
||||
+166
@@ -0,0 +1,166 @@
|
||||
python -V
|
||||
Python 3.12.12
|
||||
|
||||
|
||||
pip -V
|
||||
pip 26.0.1 from /root/dijkstra/src/.venv/lib/python3.12/site-packages/pip (python 3.12)
|
||||
|
||||
|
||||
python -c "import platform; print(platform.platform())"
|
||||
Linux-6.8.12-17-pve-x86_64-with-glibc2.41
|
||||
|
||||
|
||||
lscpu | head
|
||||
Architecture: x86_64
|
||||
CPU op-mode(s): 32-bit, 64-bit
|
||||
Address sizes: 48 bits physical, 48 bits virtual
|
||||
Byte Order: Little Endian
|
||||
CPU(s): 16
|
||||
On-line CPU(s) list: 1-3,8
|
||||
Off-line CPU(s) list: 0,4-7,9-15
|
||||
Vendor ID: AuthenticAMD
|
||||
Model name: AMD Ryzen 7 7700 8-Core Processor
|
||||
CPU family: 25
|
||||
|
||||
|
||||
|
||||
## I. Introduction
|
||||
• 이론적 복잡도 vs 실제 성능 문제 제기
|
||||
• 기존 연구 간략 언급
|
||||
• RQ 제시
|
||||
• 핵심 주장 요약
|
||||
|
||||
## II. Theoretical Background
|
||||
이 부분이 추가되어야 한다.
|
||||
|
||||
### 2.1 Dijkstra 시간복잡도 구조
|
||||
Binary:
|
||||
T_B = c_1 E \log V
|
||||
|
||||
Fibonacci:
|
||||
T_F = c_2 E + c_3 V \log V
|
||||
|
||||
### 2.2 decrease-key의 역할
|
||||
• relax_success = decrease_key 발생 빈도
|
||||
• 입력 분포와 그래프 밀도가 이를 결정
|
||||
|
||||
→ 여기서 “역전 조건의 이론적 형태”를 먼저 제시
|
||||
|
||||
예:
|
||||
|
||||
c_{dec}^{F} \cdot D < c_{dec}^{B} \cdot D \log V
|
||||
|
||||
이게 논문의 수학적 중심이 된다.
|
||||
|
||||
⸻
|
||||
|
||||
III. Methodology
|
||||
|
||||
이건 반드시 독립 섹션으로.
|
||||
|
||||
3.1 실제 데이터 분석 방법
|
||||
• USA-road 기반 분포 추정
|
||||
• mean, std 계산
|
||||
• lognormal 변환 공식
|
||||
|
||||
3.2 가상 그래프 생성 방법
|
||||
• outdegree 기반 생성
|
||||
• density 정의
|
||||
• std 범위 정당화
|
||||
|
||||
3.3 측정 지표
|
||||
• relax_attempts
|
||||
• relax_success
|
||||
• relax_ratio
|
||||
• speedup 정의
|
||||
|
||||
3.4 연산 단위 비용 모델
|
||||
|
||||
선형 모델:
|
||||
|
||||
T = \beta_0 + \beta_1 extract + \beta_2 relax + \beta_3 decrease
|
||||
|
||||
이걸 명확히 수식으로 써야 함.
|
||||
|
||||
⸻
|
||||
|
||||
IV. Empirical Analysis
|
||||
|
||||
이제 네가 말한 흐름을 그대로 쓰면 된다.
|
||||
|
||||
⸻
|
||||
|
||||
4.1 실제 데이터 분포 분석
|
||||
• mean ≈ 3000
|
||||
• std ≈ 4000
|
||||
• lognormal 적합성
|
||||
|
||||
→ 실험 파라미터의 정당화
|
||||
|
||||
⸻
|
||||
|
||||
4.2 변수 간 관계 분석 (가상 데이터)
|
||||
|
||||
4.2.1 Density ↔ Relax_attempts
|
||||
|
||||
→ 거의 선형 관계
|
||||
|
||||
4.2.2 Sigma ↔ Relax_success_ratio
|
||||
|
||||
→ 양의 상관관계
|
||||
|
||||
4.2.3 Decrease_key ↔ Speedup
|
||||
|
||||
→ 거의 무관
|
||||
|
||||
⸻
|
||||
|
||||
4.3 런타임 다중 선형 회귀 분석
|
||||
• 단위 연산 비용 추정
|
||||
• Binary vs Fibonacci 비교
|
||||
• R² 제시
|
||||
|
||||
이 부분이 핵심 증거.
|
||||
|
||||
⸻
|
||||
|
||||
V. Deriving the Crossover Condition
|
||||
|
||||
여기가 논문의 “기여”다.
|
||||
|
||||
회귀 계수를 이용해:
|
||||
|
||||
Binary:
|
||||
T_B = a_1 extract\log V + a_2 decrease\log V + ...
|
||||
|
||||
Fibonacci:
|
||||
T_F = b_1 extract\log V + b_2 decrease + ...
|
||||
|
||||
역전 조건:
|
||||
|
||||
T_F < T_B
|
||||
|
||||
정리하면:
|
||||
|
||||
(b_2 - a_2 \log V) D + (b_1 - a_1)\log V + ... < 0
|
||||
|
||||
여기서:
|
||||
• 실제 계수 대입
|
||||
• 부등식이 성립하는 V, D 범위 계산
|
||||
|
||||
이게 논문의 가장 강력한 부분.
|
||||
|
||||
⸻
|
||||
|
||||
VI. Feasibility Analysis
|
||||
• Python 환경에서는 성립 불가
|
||||
• 상수항이 지배
|
||||
• C++ 가능성 언급
|
||||
|
||||
⸻
|
||||
|
||||
VII. Conclusion
|
||||
• RQ에 대한 명확한 답
|
||||
• 이론과 실제의 간극 강조
|
||||
• 실무적 함의
|
||||
• 한계 및 향후 연구
|
||||
@@ -0,0 +1,46 @@
|
||||
class DijkstraStats:
|
||||
def __init__(self):
|
||||
self.extract_min_calls = 0
|
||||
self.relax_attempts = 0
|
||||
self.relax_success = 0
|
||||
# self.decrease_key_calls = 0
|
||||
# self.add_calls = 0
|
||||
|
||||
def heap_dijkstra(nodes, adj, heap, start, end):
|
||||
INF = float('inf')
|
||||
dist = [INF] * nodes
|
||||
visited = [False] * nodes
|
||||
stats = DijkstraStats()
|
||||
|
||||
dist[start] = 0
|
||||
|
||||
for v in range(nodes):
|
||||
heap.add(v, dist[v])
|
||||
# stats.add_calls += 1
|
||||
|
||||
while True:
|
||||
res = heap.extract_min()
|
||||
stats.extract_min_calls += 1
|
||||
if res is None:
|
||||
break
|
||||
cur, cur_dist = res
|
||||
|
||||
if cur_dist == INF:
|
||||
break
|
||||
|
||||
if cur == end:
|
||||
break
|
||||
|
||||
for nxt, d in adj[cur]:
|
||||
stats.relax_attempts += 1
|
||||
if visited[nxt]:
|
||||
continue
|
||||
new = cur_dist + d
|
||||
if new < dist[nxt]:
|
||||
stats.relax_success += 1
|
||||
dist[nxt] = new
|
||||
heap.decrease_key(nxt, new)
|
||||
|
||||
visited[cur] = True
|
||||
|
||||
return dist[end], stats
|
||||
@@ -0,0 +1,32 @@
|
||||
def pure_dijkstra(nodes, adj, start, end):
|
||||
dist = [float('inf')] * nodes
|
||||
dist[start] = 0
|
||||
visited = [False] * nodes
|
||||
|
||||
cur = start
|
||||
|
||||
while True:
|
||||
if cur == -1:
|
||||
break
|
||||
|
||||
if cur == end:
|
||||
break
|
||||
|
||||
for next, d in adj[cur]:
|
||||
if not visited[next]:
|
||||
new = dist[cur] + d
|
||||
if new < dist[next]:
|
||||
dist[next] = new
|
||||
|
||||
visited[cur] = True
|
||||
|
||||
# Finding min node
|
||||
min_node = -1
|
||||
min_val = float('inf')
|
||||
for n in range(nodes):
|
||||
if not visited[n] and dist[n] < min_val:
|
||||
min_node = n
|
||||
min_val = dist[n]
|
||||
cur = min_node
|
||||
|
||||
return dist[end]
|
||||
@@ -0,0 +1,75 @@
|
||||
class BinHeap:
|
||||
def __init__(self, nodes):
|
||||
self.heap = []
|
||||
self.pos = [-1] * nodes
|
||||
|
||||
def sift_up(self, idx):
|
||||
heap = self.heap
|
||||
pos = self.pos
|
||||
|
||||
backup = heap[idx]
|
||||
cur = idx
|
||||
|
||||
while cur > 0:
|
||||
par = (cur - 1) // 2
|
||||
if backup[1] >= heap[par][1]:
|
||||
break
|
||||
heap[cur] = heap[par]
|
||||
pos[heap[cur][0]] = cur
|
||||
cur = par
|
||||
heap[cur] = backup
|
||||
pos[backup[0]] = cur
|
||||
|
||||
def sift_down(self, idx):
|
||||
heap = self.heap
|
||||
pos = self.pos
|
||||
|
||||
n = len(heap)
|
||||
|
||||
backup = heap[idx]
|
||||
cur = idx
|
||||
|
||||
while True:
|
||||
left = cur * 2 + 1
|
||||
if left >= n:
|
||||
break
|
||||
right = left + 1
|
||||
tar = right if right < n and heap[right][1] < heap[left][1] else left
|
||||
if backup[1] <= heap[tar][1]:
|
||||
break
|
||||
heap[cur] = heap[tar]
|
||||
pos[heap[cur][0]] = cur
|
||||
cur = tar
|
||||
heap[cur] = backup
|
||||
pos[backup[0]] = cur
|
||||
|
||||
def add(self, key, dist):
|
||||
idx = len(self.heap)
|
||||
self.heap.append([key, dist])
|
||||
self.pos[key] = idx
|
||||
self.sift_up(idx)
|
||||
|
||||
def extract_min(self):
|
||||
heap = self.heap
|
||||
pos = self.pos
|
||||
if not heap:
|
||||
return None
|
||||
min_node, min_dist = heap[0]
|
||||
pos[min_node] = -1
|
||||
|
||||
last = heap.pop()
|
||||
if heap:
|
||||
heap[0] = last
|
||||
pos[last[0]] = 0
|
||||
self.sift_down(0)
|
||||
return (min_node, min_dist)
|
||||
|
||||
def decrease_key(self, key, new_dist):
|
||||
idx = self.pos[key]
|
||||
if idx == -1:
|
||||
return None
|
||||
node = self.heap[idx]
|
||||
if new_dist >= node[1]:
|
||||
return None
|
||||
node[1] = new_dist
|
||||
self.sift_up(idx)
|
||||
@@ -0,0 +1,177 @@
|
||||
import math
|
||||
|
||||
class Node:
|
||||
__slots__ = ('key', 'dist', 'left', 'right', 'parent', 'child', 'degree', 'lost')
|
||||
|
||||
def __init__(self, key, dist):
|
||||
self.key = key
|
||||
self.dist = dist
|
||||
|
||||
self.left = self
|
||||
self.right = self
|
||||
|
||||
self.parent = None
|
||||
self.child = None
|
||||
|
||||
self.degree = 0
|
||||
self.lost = False
|
||||
|
||||
def connect_right(self, new_right):
|
||||
old_right = self.right
|
||||
new_left = new_right.left
|
||||
|
||||
new_right.left = self
|
||||
new_left.right = old_right
|
||||
|
||||
old_right.left = new_left
|
||||
self.right = new_right
|
||||
|
||||
def remove(self):
|
||||
self.left.right = self.right
|
||||
self.right.left = self.left
|
||||
self.left = self
|
||||
self.right = self
|
||||
|
||||
def connect_child(self, child):
|
||||
child.parent = self
|
||||
child.lost = False
|
||||
|
||||
if self.child is None:
|
||||
self.child = child
|
||||
else:
|
||||
self.child.connect_right(child)
|
||||
|
||||
self.degree += 1
|
||||
|
||||
class FiboHeap:
|
||||
def __init__(self, nodes):
|
||||
self.min = None
|
||||
self.n = 0
|
||||
self.pos = [None] * nodes
|
||||
|
||||
def cut(self, cur):
|
||||
p = cur.parent
|
||||
if p.child is cur:
|
||||
if cur.right is cur:
|
||||
p.child = None
|
||||
else:
|
||||
p.child = cur.right
|
||||
|
||||
cur.remove()
|
||||
p.degree -= 1
|
||||
|
||||
cur.parent = None
|
||||
cur.lost = False
|
||||
|
||||
self.min.connect_right(cur)
|
||||
if cur.dist < self.min.dist:
|
||||
self.min = cur
|
||||
|
||||
def cascading_cut(self, cur):
|
||||
while True:
|
||||
p = cur.parent
|
||||
if p is None:
|
||||
return
|
||||
if not cur.lost:
|
||||
cur.lost = True
|
||||
return
|
||||
self.cut(cur)
|
||||
cur = p
|
||||
|
||||
def add(self, key, dist):
|
||||
cur = Node(key, dist)
|
||||
|
||||
if self.min is None:
|
||||
self.min = cur
|
||||
else:
|
||||
self.min.connect_right(cur)
|
||||
if cur.dist < self.min.dist:
|
||||
self.min = cur
|
||||
|
||||
self.n += 1
|
||||
self.pos[key] = cur
|
||||
|
||||
def extract_min(self):
|
||||
# 1. Find min node
|
||||
min_node = self.min
|
||||
self.n -= 1
|
||||
|
||||
# 2. Make min node's child into individual tree
|
||||
c = min_node.child
|
||||
if c is not None:
|
||||
start = c
|
||||
cur = c
|
||||
while True:
|
||||
cur.parent = None
|
||||
cur.lost = False
|
||||
cur = cur.right
|
||||
if cur == start:
|
||||
break
|
||||
|
||||
min_node.connect_right(start)
|
||||
|
||||
if min_node.right is min_node:
|
||||
self.min = None
|
||||
return (min_node.key, min_node.dist)
|
||||
|
||||
nxt = min_node.right
|
||||
min_node.remove()
|
||||
self.min = nxt
|
||||
|
||||
min_node.child = None
|
||||
min_node.degree = 0
|
||||
self.pos[min_node.key] = None
|
||||
|
||||
# 3. Make into binomial tree
|
||||
roots = []
|
||||
start = self.min
|
||||
cur = start
|
||||
while True:
|
||||
roots.append(cur)
|
||||
cur = cur.right
|
||||
if cur == start:
|
||||
break
|
||||
|
||||
max_deg = int(math.log2(self.n)) + 2 if self.n > 0 else 1 # 여기서 +2 하는 이유는 사실은 log2가 아니라 fibonacci 수열 기반이기 때문에 +1 더 해주는 거임.
|
||||
A = [None] * (max_deg + 1)
|
||||
|
||||
for cur in roots:
|
||||
x = cur
|
||||
d = x.degree
|
||||
|
||||
while A[d] is not None:
|
||||
y = A[d]
|
||||
if y.dist < x.dist:
|
||||
x, y = y, x
|
||||
y.remove()
|
||||
x.connect_child(y)
|
||||
A[d] = None
|
||||
d = x.degree
|
||||
A[d] = x
|
||||
|
||||
# 4. Find new min
|
||||
self.min = None
|
||||
for cur in A:
|
||||
if cur is None:
|
||||
continue
|
||||
if self.min is None:
|
||||
self.min = cur
|
||||
else:
|
||||
if cur.dist < self.min.dist:
|
||||
self.min = cur
|
||||
|
||||
return (min_node.key, min_node.dist)
|
||||
|
||||
def decrease_key(self, key, new_dist):
|
||||
cur = self.pos[key]
|
||||
if cur is None or new_dist >= cur.dist:
|
||||
return
|
||||
cur.dist = new_dist
|
||||
p = cur.parent
|
||||
|
||||
if p is not None and cur.dist < p.dist:
|
||||
self.cut(cur)
|
||||
self.cascading_cut(p)
|
||||
|
||||
if cur.dist < self.min.dist:
|
||||
self.min = cur
|
||||
@@ -0,0 +1,95 @@
|
||||
import os
|
||||
import numpy as np
|
||||
import pandas as pd
|
||||
import matplotlib.pyplot as plt
|
||||
import random
|
||||
|
||||
|
||||
def read_dimacs(file):
|
||||
idx = 0
|
||||
with open(f"{folder}/{file}", "r") as f:
|
||||
for line in f:
|
||||
line = line.strip()
|
||||
if line.startswith("c"):
|
||||
continue
|
||||
elif line.startswith("p"):
|
||||
_, _, n, e = line.split()
|
||||
edges = int(e)
|
||||
data = [0] * edges
|
||||
elif line.startswith("a"):
|
||||
_, u, v, w = line.split()
|
||||
data[idx] = int(w)
|
||||
idx += 1
|
||||
return data
|
||||
|
||||
|
||||
def visualize_weights(file):
|
||||
data = read_dimacs(file)
|
||||
sample = np.array(data)
|
||||
|
||||
save_folder = f"{res_folder}/{file}"
|
||||
os.makedirs(save_folder, exist_ok=True)
|
||||
|
||||
plt.figure(figsize=(8, 5))
|
||||
plt.hist(sample, bins=100)
|
||||
plt.title("Edge Weight Distribution (Original Scale)")
|
||||
plt.xlabel("Weight")
|
||||
plt.ylabel("Frequency")
|
||||
plt.tight_layout()
|
||||
plt.savefig(f"{save_folder}/hist_original.png")
|
||||
plt.close()
|
||||
|
||||
log_sample = np.log(sample[sample > 0])
|
||||
|
||||
plt.figure(figsize=(8, 5))
|
||||
plt.hist(log_sample, bins=100)
|
||||
plt.title("Log(Weight) Distribution")
|
||||
plt.xlabel("log(Weight)")
|
||||
plt.ylabel("Frequency")
|
||||
plt.tight_layout()
|
||||
plt.savefig(f"{save_folder}/hist_log.png")
|
||||
plt.close()
|
||||
|
||||
plt.figure(figsize=(8, 5))
|
||||
plt.hist(log_sample, bins=100, density=True)
|
||||
plt.title("Log(Weight) Density")
|
||||
plt.xlabel("log(Weight)")
|
||||
plt.ylabel("Density")
|
||||
plt.tight_layout()
|
||||
plt.savefig(f"{save_folder}/hist_log_density.png")
|
||||
plt.close()
|
||||
|
||||
return {
|
||||
"file": file,
|
||||
"edges": len(sample),
|
||||
"mean": np.mean(sample),
|
||||
"std": np.std(sample),
|
||||
"min": np.min(sample),
|
||||
"max": np.max(sample)
|
||||
}
|
||||
|
||||
folder = "experiments/real_data/data/dimacs_data"
|
||||
files = [
|
||||
"USA-road-d.BAY.gr",
|
||||
"USA-road-d.CAL.gr",
|
||||
"USA-road-d.COL.gr",
|
||||
"USA-road-d.CTR.gr",
|
||||
"USA-road-d.E.gr",
|
||||
"USA-road-d.FLA.gr",
|
||||
"USA-road-d.LKS.gr",
|
||||
"USA-road-d.NE.gr",
|
||||
"USA-road-d.NW.gr",
|
||||
"USA-road-d.NY.gr",
|
||||
"USA-road-d.USA.gr",
|
||||
"USA-road-d.W.gr"
|
||||
]
|
||||
|
||||
res_folder = "results/real_data/derived/dimacs_graph_distribution"
|
||||
os.makedirs(res_folder, exist_ok=True)
|
||||
|
||||
rows = []
|
||||
for file in files:
|
||||
row = visualize_weights(file)
|
||||
rows.append(row)
|
||||
df = pd.DataFrame(rows)
|
||||
df.to_csv(f"{res_folder}/distribution.csv", index=False)
|
||||
@@ -0,0 +1,21 @@
|
||||
def dimacs_convert_graph(filename):
|
||||
with open(filename, 'r') as f:
|
||||
for line in f:
|
||||
line = line.strip()
|
||||
|
||||
if line.startswith('c'):
|
||||
continue
|
||||
|
||||
elif line.startswith('p'):
|
||||
_, _, n, e = line.split()
|
||||
nodes = int(n)
|
||||
edges = int(e)
|
||||
adj = [[] for _ in range(nodes + 1)]
|
||||
|
||||
elif line.startswith('a'):
|
||||
_, u, v, w = line.split()
|
||||
u, v, w = int(u) - 1, int(v) - 1, int(w)
|
||||
|
||||
adj[u].append((v, w))
|
||||
|
||||
return nodes, adj
|
||||
@@ -0,0 +1,102 @@
|
||||
import os
|
||||
import time
|
||||
import pandas as pd
|
||||
import numpy as np
|
||||
|
||||
from experiments.real_data.graph_converters.dimacs_graph_converter import dimacs_convert_graph
|
||||
from core.dijkstra.heap_dijkstra import heap_dijkstra
|
||||
from core.heaps.binary_heap import BinHeap
|
||||
from core.heaps.fibonacci_heap import FiboHeap
|
||||
|
||||
def run_test(
|
||||
folder,
|
||||
files,
|
||||
trials,
|
||||
base_seed
|
||||
):
|
||||
rows = []
|
||||
timer = time.perf_counter
|
||||
rng = np.random.default_rng(base_seed)
|
||||
INF = float('inf')
|
||||
|
||||
for file in files:
|
||||
nodes, adj = dimacs_convert_graph(f'{folder}/{file}')
|
||||
density = len(adj) / (nodes * (nodes - 1))
|
||||
|
||||
for trial in range(1, trials + 1):
|
||||
start, end = rng.choice(nodes, size=2, replace=False) + 1
|
||||
|
||||
bin_heap = BinHeap(nodes)
|
||||
st = timer()
|
||||
dist, stats = heap_dijkstra(nodes, adj, bin_heap, start, end)
|
||||
et = timer()
|
||||
rows.append(
|
||||
{
|
||||
"file": file,
|
||||
"nodes": nodes,
|
||||
"density": density,
|
||||
"trial": trial,
|
||||
"start": start,
|
||||
"end": end,
|
||||
"time": et - st,
|
||||
"algorithm": "binary",
|
||||
"reached": dist != INF,
|
||||
"extract_min_calls": stats.extract_min_calls,
|
||||
"relax_attempts": stats.relax_attempts,
|
||||
"relax_success": stats.relax_success,
|
||||
}
|
||||
)
|
||||
|
||||
fibo_heap = FiboHeap(nodes)
|
||||
st = timer()
|
||||
dist, stats = heap_dijkstra(nodes, adj, fibo_heap, start, end)
|
||||
et = timer()
|
||||
rows.append(
|
||||
{
|
||||
"file": file,
|
||||
"nodes": nodes,
|
||||
"density": density,
|
||||
"trial": trial,
|
||||
"start": start,
|
||||
"end": end,
|
||||
"time": et - st,
|
||||
"algorithm": "fibonacci",
|
||||
"reached": dist != INF,
|
||||
"extract_min_calls": stats.extract_min_calls,
|
||||
"relax_attempts": stats.relax_attempts,
|
||||
"relax_success": stats.relax_success,
|
||||
}
|
||||
)
|
||||
|
||||
df = pd.DataFrame(rows)
|
||||
return df
|
||||
|
||||
# Settings
|
||||
folder = "experiments/real_data/data/dimacs_data"
|
||||
files = [
|
||||
"USA-road-d.BAY.gr",
|
||||
"USA-road-d.CAL.gr",
|
||||
"USA-road-d.COL.gr",
|
||||
"USA-road-d.CTR.gr",
|
||||
"USA-road-d.E.gr",
|
||||
"USA-road-d.FLA.gr",
|
||||
"USA-road-d.LKS.gr",
|
||||
"USA-road-d.NE.gr",
|
||||
"USA-road-d.NW.gr",
|
||||
"USA-road-d.NY.gr",
|
||||
"USA-road-d.USA.gr",
|
||||
"USA-road-d.W.gr"
|
||||
]
|
||||
trials = 200
|
||||
base_seed = 42
|
||||
|
||||
df = run_test(
|
||||
folder=folder,
|
||||
files=files,
|
||||
trials=trials,
|
||||
base_seed=base_seed
|
||||
)
|
||||
|
||||
save_folder = "results/real_data/raw"
|
||||
os.makedirs(save_folder, exist_ok=True)
|
||||
df.to_csv(f"{save_folder}/dimacs_t{trials}_s{base_seed}.csv", index=False)
|
||||
@@ -0,0 +1,50 @@
|
||||
import os
|
||||
import pandas as pd
|
||||
import matplotlib.pyplot as plt
|
||||
|
||||
csv_file = "results/synthetic_data/raw/20260302_183202.csv"
|
||||
save_folder = f"results/synthetic_data/derived/{os.path.splitext(os.path.basename(csv_file))[0]}"
|
||||
os.makedirs(save_folder, exist_ok=True)
|
||||
|
||||
df = pd.read_csv(csv_file)
|
||||
df = df[df["algorithm"] == "binary"].copy()
|
||||
df["relax_success_ratio"] = df["relax_success"] / df["relax_attempts"]
|
||||
|
||||
# N vs extract_min_calls
|
||||
grouped = df.groupby("nodes")["extract_min_calls"].mean()
|
||||
|
||||
plt.figure(figsize=(6,4))
|
||||
plt.plot(grouped.index, grouped.values, marker='o')
|
||||
plt.xlabel("N (nodes)")
|
||||
plt.ylabel("Average extract_min_calls")
|
||||
plt.title("Nodes vs Extract-Min Calls")
|
||||
plt.grid(True)
|
||||
plt.tight_layout()
|
||||
plt.savefig(f"{save_folder}/N_vs_extract_min.png", dpi=300)
|
||||
plt.close()
|
||||
|
||||
# Density vs relax_attempts
|
||||
grouped = df.groupby("density")["relax_attempts"].mean()
|
||||
|
||||
plt.figure(figsize=(6,4))
|
||||
plt.plot(grouped.index, grouped.values, marker='o')
|
||||
plt.xlabel("Density")
|
||||
plt.ylabel("Average relax_attempts")
|
||||
plt.title("Density vs Relax Attempts")
|
||||
plt.grid(True)
|
||||
plt.tight_layout()
|
||||
plt.savefig(f"{save_folder}/density_vs_relax_attempts.png", dpi=300)
|
||||
plt.close()
|
||||
|
||||
# Sigma vs relax_success_ratio
|
||||
grouped = df.groupby("sigma")["relax_success_ratio"].mean()
|
||||
|
||||
plt.figure(figsize=(6,4))
|
||||
plt.plot(grouped.index, grouped.values, marker='o')
|
||||
plt.xlabel("Sigma (lognormal)")
|
||||
plt.ylabel("Relax Success Ratio")
|
||||
plt.title("Sigma vs Relax Success Ratio")
|
||||
plt.grid(True)
|
||||
plt.tight_layout()
|
||||
plt.savefig(f"{save_folder}/sigma_vs_relax_ratio.png", dpi=300)
|
||||
plt.close()
|
||||
@@ -0,0 +1,48 @@
|
||||
import numpy as np
|
||||
import pandas as pd
|
||||
from sklearn.linear_model import LinearRegression
|
||||
from sklearn.metrics import r2_score
|
||||
|
||||
def fit_op_cost_functional(df, algo):
|
||||
sub = df[(df["algorithm"] == algo) & (df["reached"] == True)].copy()
|
||||
|
||||
sub["logN"] = np.log(sub["nodes"])
|
||||
sub = sub.rename(columns={"relax_success":"decrease_key_calls",
|
||||
"nodes":"add_calls"})
|
||||
|
||||
if algo == "binary":
|
||||
sub["f_extract"] = sub["extract_min_calls"] * sub["logN"]
|
||||
sub["f_decrease"] = sub["decrease_key_calls"] * sub["logN"]
|
||||
else: # fibonacci
|
||||
sub["f_extract"] = sub["extract_min_calls"] * sub["logN"]
|
||||
sub["f_decrease"] = sub["decrease_key_calls"]
|
||||
|
||||
X = sub[["add_calls", "f_extract", "relax_attempts", "f_decrease"]].to_numpy()
|
||||
y = sub["time"].to_numpy()
|
||||
|
||||
model = LinearRegression()
|
||||
model.fit(X, y)
|
||||
|
||||
y_pred = model.predict(X)
|
||||
r2 = r2_score(y, y_pred)
|
||||
|
||||
return {
|
||||
"algo": algo,
|
||||
"intercept": model.intercept_,
|
||||
"coef_add": model.coef_[0],
|
||||
"coef_extract": model.coef_[1],
|
||||
"coef_relax": model.coef_[2],
|
||||
"coef_decrease": model.coef_[3],
|
||||
"r2": r2,
|
||||
"n_samples": len(sub)
|
||||
}
|
||||
|
||||
def op_cost_functional_analysis(df):
|
||||
return pd.DataFrame([
|
||||
fit_op_cost_functional(df, "binary"),
|
||||
fit_op_cost_functional(df, "fibonacci")
|
||||
])
|
||||
|
||||
df = pd.read_csv("results/synthetic_data/raw/20260302_183202.csv")
|
||||
summary = op_cost_functional_analysis(df)
|
||||
print(summary)
|
||||
@@ -0,0 +1,38 @@
|
||||
import pandas as pd
|
||||
import matplotlib.pyplot as plt
|
||||
import os
|
||||
|
||||
csv_file = "results/synthetic_data/raw/20260302_183202.csv"
|
||||
save_folder = f"results/synthetic_data/derived/{os.path.splitext(os.path.basename(csv_file))[0]}"
|
||||
os.makedirs(save_folder, exist_ok=True)
|
||||
|
||||
df = pd.read_csv(csv_file)
|
||||
# df = df[df["reached"] == True].copy()
|
||||
|
||||
key_cols = ["nodes", "density", "std", "sigma", "trial", "seed"]
|
||||
|
||||
pivot_time = (
|
||||
df.pivot_table(index=key_cols, columns="algorithm", values="time", aggfunc="mean")
|
||||
.reset_index()
|
||||
)
|
||||
pivot_time["speed_ratio"] = pivot_time["binary"] / pivot_time["fibonacci"]
|
||||
|
||||
# print((pivot_time["speed_ratio"] > 1).sum())
|
||||
# print((pivot_time["speed_ratio"] < 1).sum())
|
||||
|
||||
relax = (
|
||||
df[df["algorithm"] == "binary"][key_cols + ["relax_success"]]
|
||||
)
|
||||
|
||||
merged = pivot_time.merge(relax, on=key_cols, how="left")
|
||||
|
||||
plt.figure(figsize=(6, 4))
|
||||
plt.scatter(merged["relax_success"], merged["speed_ratio"], marker=".")
|
||||
plt.axhline(y=1.0, color='red', linestyle='--')
|
||||
plt.xlabel("decrease_key (binary)")
|
||||
plt.ylabel("speed_ratio (binary / fibonacci)")
|
||||
plt.title("decrease_key vs speed_ratio")
|
||||
plt.grid(True)
|
||||
plt.tight_layout()
|
||||
plt.savefig(f"{save_folder}/decrease_key_vs_speed_ratio.png", dpi=300)
|
||||
plt.close()
|
||||
@@ -0,0 +1,36 @@
|
||||
import numpy as np
|
||||
|
||||
def generate_graph(NODES=10, DENSITY=0.1, DISTRIBUTION=('lognormal', (100, 1)), SEED=42):
|
||||
rng = np.random.default_rng(SEED)
|
||||
|
||||
# Calculate variables
|
||||
max_edges = (NODES - 1) * NODES
|
||||
edges = int(round(DENSITY * max_edges))
|
||||
|
||||
# Make edges
|
||||
sel = rng.choice(max_edges, size=edges, replace=False)
|
||||
|
||||
# Make distance array
|
||||
dist_name, dist_params = DISTRIBUTION
|
||||
|
||||
if dist_name == "lognormal":
|
||||
mean, sigma = dist_params
|
||||
distances = rng.lognormal(mean=mean, sigma=sigma, size=edges)
|
||||
elif dist_name == "uniform":
|
||||
mean = dist_params[0]
|
||||
distances = rng.uniform(0.0, 2.0 * mean, size=edges)
|
||||
elif dist_name == "exponential":
|
||||
mean = dist_params[0]
|
||||
distances = rng.exponential(scale=mean, size=edges)
|
||||
else:
|
||||
raise ValueError("Unknown DISTRIBUTION")
|
||||
|
||||
# Make adj
|
||||
adj = [[] for _ in range(NODES)]
|
||||
for idx, dist in zip(sel, distances):
|
||||
u = idx // (NODES-1)
|
||||
r = idx % (NODES-1)
|
||||
v = r if r < u else r + 1
|
||||
adj[u].append((v, dist))
|
||||
|
||||
return adj
|
||||
@@ -0,0 +1,44 @@
|
||||
import numpy as np
|
||||
|
||||
def outdegree_generate_graph(NODES, DENSITY, DISTRIBUTION, SEED=42):
|
||||
rng = np.random.default_rng(SEED)
|
||||
|
||||
max_edges = (NODES - 1) * NODES
|
||||
edges = int(round(DENSITY * max_edges))
|
||||
|
||||
base = edges // NODES
|
||||
rem = edges % NODES
|
||||
|
||||
adj = [[] for _ in range(NODES)]
|
||||
|
||||
dist_name, dist_params = DISTRIBUTION
|
||||
|
||||
if dist_name == "lognormal":
|
||||
mean, sigma = dist_params
|
||||
dist_func = lambda size: rng.lognormal(mean=mean, sigma=sigma, size=size)
|
||||
elif dist_name == "uniform":
|
||||
mean = dist_params[0]
|
||||
dist_func = lambda size: rng.uniform(0.0, 2.0 * mean, size=size)
|
||||
elif dist_name == "exponential":
|
||||
mean = dist_params[0]
|
||||
dist_func = lambda size: rng.exponential(scale=mean, size=size)
|
||||
else:
|
||||
raise ValueError("Unknown DISTRIBUTION")
|
||||
|
||||
for u in range(NODES):
|
||||
d_u = base + (1 if u < rem else 0)
|
||||
|
||||
if d_u == 0:
|
||||
continue
|
||||
|
||||
targets = rng.choice(NODES-1, size=d_u, replace=False)
|
||||
targets = np.where(targets < u, targets, targets + 1)
|
||||
|
||||
weights = dist_func(d_u)
|
||||
weights = np.rint(weights).astype(np.int64)
|
||||
weights = np.maximum(weights, 1)
|
||||
|
||||
for v, w in zip(targets, weights):
|
||||
adj[u].append((v, float(w)))
|
||||
|
||||
return adj
|
||||
@@ -0,0 +1,149 @@
|
||||
import time
|
||||
import pandas as pd
|
||||
import numpy as np
|
||||
from tqdm import tqdm
|
||||
import datetime
|
||||
import json
|
||||
import os
|
||||
|
||||
from experiments.synthetic_data.graph_generators.outdegree_graph_generator import outdegree_generate_graph
|
||||
from core.dijkstra.heap_dijkstra import heap_dijkstra
|
||||
from core.heaps.binary_heap import BinHeap
|
||||
from core.heaps.fibonacci_heap import FiboHeap
|
||||
|
||||
def run_test(
|
||||
nodes_li,
|
||||
densities,
|
||||
stds,
|
||||
trials,
|
||||
mean_dist,
|
||||
start,
|
||||
end,
|
||||
base_seed
|
||||
):
|
||||
timer = time.perf_counter
|
||||
file_exists = False
|
||||
INF = float('inf')
|
||||
|
||||
total_jobs = (
|
||||
len(nodes_li) *
|
||||
len(densities) *
|
||||
len(stds) *
|
||||
trials
|
||||
)
|
||||
|
||||
with tqdm(total=total_jobs) as pbar:
|
||||
for nodes in nodes_li:
|
||||
rows = []
|
||||
|
||||
for density in densities:
|
||||
for std in stds:
|
||||
sigma = np.sqrt(np.log((std / mean_dist)**2 + 1))
|
||||
mu = np.log(mean_dist) - (sigma**2) / 2
|
||||
distribution = ('lognormal', (mu, sigma))
|
||||
|
||||
for trial in range(1, trials + 1):
|
||||
seed = (base_seed * 1_000_003) ^ (nodes * 9176) ^ int(density * 1e9) ^ int(sigma * 1e6) ^ trial
|
||||
seed &= 0xFFFFFFFF
|
||||
|
||||
adj = outdegree_generate_graph(
|
||||
NODES=nodes,
|
||||
DENSITY=density,
|
||||
DISTRIBUTION=distribution,
|
||||
SEED=seed
|
||||
)
|
||||
|
||||
bin_heap = BinHeap(nodes)
|
||||
st = timer()
|
||||
dist, stats = heap_dijkstra(nodes, adj, bin_heap, start, end)
|
||||
et = timer()
|
||||
rows.append(
|
||||
{
|
||||
"nodes": nodes,
|
||||
"density": density,
|
||||
"std": std,
|
||||
"sigma": sigma,
|
||||
"trial": trial,
|
||||
"seed": seed,
|
||||
"time": et - st,
|
||||
"algorithm": "binary",
|
||||
"reached": dist != INF,
|
||||
"extract_min_calls": stats.extract_min_calls,
|
||||
"relax_attempts": stats.relax_attempts,
|
||||
"relax_success": stats.relax_success,
|
||||
}
|
||||
)
|
||||
|
||||
fibo_heap = FiboHeap(nodes)
|
||||
st = timer()
|
||||
dist, stats = heap_dijkstra(nodes, adj, fibo_heap, start, end)
|
||||
et = timer()
|
||||
rows.append(
|
||||
{
|
||||
"nodes": nodes,
|
||||
"density": density,
|
||||
"std": std,
|
||||
"sigma": sigma,
|
||||
"trial": trial,
|
||||
"seed": seed,
|
||||
"time": et - st,
|
||||
"algorithm": "fibonacci",
|
||||
"reached": dist != INF,
|
||||
"extract_min_calls": stats.extract_min_calls,
|
||||
"relax_attempts": stats.relax_attempts,
|
||||
"relax_success": stats.relax_success,
|
||||
}
|
||||
)
|
||||
|
||||
pbar.update(1)
|
||||
|
||||
df_nodes = pd.DataFrame(rows)
|
||||
df_nodes.to_csv(
|
||||
csv_file,
|
||||
mode='a',
|
||||
header=not file_exists,
|
||||
index=False
|
||||
)
|
||||
file_exists = True
|
||||
print(f"=== SAVED nodes = {nodes} ({len(df_nodes)} rows) ===")
|
||||
return
|
||||
|
||||
# Settings
|
||||
nodes_li = [2000, 4000, 8000, 16000]
|
||||
densities = [0.00015, 0.0003, 0.0006, 0.0012, 0.0024, 0.0048, 0.0096, 0.0192, 0.0384]
|
||||
stds = [1000, 1500, 2000, 3000, 4000, 6000, 8000, 12000, 16000]
|
||||
trials = 400
|
||||
mean_dist = 3000
|
||||
start = 0
|
||||
end = 1
|
||||
base_seed = 42
|
||||
|
||||
save_folder = "results/synthetic_data/raw"
|
||||
os.makedirs(save_folder, exist_ok=True)
|
||||
timestamp = datetime.datetime.now().strftime("%Y%m%d_%H%M%S")
|
||||
csv_file = f"{save_folder}/{timestamp}.csv"
|
||||
config_file = f"{save_folder}/{timestamp}.json"
|
||||
|
||||
config = {
|
||||
"nodes_li": nodes_li,
|
||||
"densities": densities,
|
||||
"stds": stds,
|
||||
"trials": trials,
|
||||
"mean_dist": mean_dist,
|
||||
"start": start,
|
||||
"end": end,
|
||||
"base_seed": base_seed,
|
||||
}
|
||||
with open(config_file, "w") as f:
|
||||
json.dump(config, f, indent=4)
|
||||
|
||||
df = run_test(
|
||||
nodes_li = nodes_li,
|
||||
densities = densities,
|
||||
stds = stds,
|
||||
trials = trials,
|
||||
mean_dist = mean_dist,
|
||||
start = start,
|
||||
end = end,
|
||||
base_seed = base_seed
|
||||
)
|
||||
@@ -0,0 +1,34 @@
|
||||
import numpy as np
|
||||
import matplotlib.pyplot as plt
|
||||
|
||||
mu = 3.5
|
||||
sigmas = [0.1, 0.3]
|
||||
size = 100000
|
||||
rng = np.random.default_rng(42)
|
||||
|
||||
fig, axes = plt.subplots(1, 2, figsize=(16, 6))
|
||||
|
||||
for sigma in sigmas:
|
||||
samples = rng.lognormal(mean=mu, sigma=sigma, size=size)
|
||||
|
||||
# lognormal → normal 변환
|
||||
log_samples = np.log(samples)
|
||||
|
||||
# Lognormal 플롯
|
||||
axes[0].hist(samples, bins=200, density=True, alpha=0.5, label=f"sigma={sigma}")
|
||||
axes[0].set_xlim(0, 200)
|
||||
axes[0].set_title("Lognormal Distribution")
|
||||
axes[0].set_xlabel("Weight")
|
||||
axes[0].set_ylabel("Density")
|
||||
axes[0].legend()
|
||||
|
||||
# Normal 플롯
|
||||
axes[1].hist(log_samples, bins=200, density=True, alpha=0.5, label=f"sigma={sigma}")
|
||||
axes[1].set_title("log(samples) → Normal Distribution")
|
||||
axes[1].set_xlabel("log(Weight)")
|
||||
axes[1].set_ylabel("Density")
|
||||
axes[1].legend()
|
||||
|
||||
plt.suptitle("Lognormal vs Normal (μ fixed)")
|
||||
plt.tight_layout()
|
||||
plt.show()
|
||||
@@ -0,0 +1,18 @@
|
||||
contourpy==1.3.3
|
||||
cycler==0.12.1
|
||||
fonttools==4.61.1
|
||||
joblib==1.5.3
|
||||
kiwisolver==1.4.9
|
||||
matplotlib==3.10.8
|
||||
numpy==2.4.2
|
||||
packaging==26.0
|
||||
pandas==3.0.1
|
||||
pillow==12.1.1
|
||||
pyparsing==3.3.2
|
||||
python-dateutil==2.9.0.post0
|
||||
scikit-learn==1.8.0
|
||||
scipy==1.17.1
|
||||
seaborn==0.13.2
|
||||
six==1.17.0
|
||||
threadpoolctl==3.6.0
|
||||
tqdm==4.67.3
|
||||
@@ -0,0 +1,34 @@
|
||||
```mermaid
|
||||
flowchart LR
|
||||
subgraph A[dijkstra]
|
||||
AA[pure dijkstra]
|
||||
AB[heap dijkstra]
|
||||
end
|
||||
|
||||
subgraph B[heap]
|
||||
BA[binary heap]
|
||||
BB[fibonacci heap]
|
||||
end
|
||||
|
||||
C[outdegree graph generator]
|
||||
D[dimacs graph converter]
|
||||
|
||||
subgraph E[test]
|
||||
EA[synthesized test]
|
||||
EB[dimacs test]
|
||||
end
|
||||
|
||||
subgraph F[analysis]
|
||||
FA[analysis all]
|
||||
FB[analysis call]
|
||||
end
|
||||
|
||||
|
||||
```
|
||||
|
||||
read_dimacs.py: dimacs 파일을 읽어서 분포를 시각화 해줌.
|
||||
regression.py: test.py 결과물을 바탕으로 dijkstra 작업별 시간 회귀 분석함.
|
||||
lognormal_visual.py: lognormal 데이터의 분포를 시각화 해줌. (그냥 공부용이고 본 연구와 관계 없음)
|
||||
test_dicmac.py: dicmac 실제 그래프 바탕으로 dijkstra 적용. 동일 그래프에 대해 여러 start, end 테스트함.
|
||||
analysis_all.py:
|
||||
analysis_call.py: dijkstra 변인간의 상관관계 분석함. (nodes <-> extract_min_calls, density <-> relax_attempts, sigma <-> relax_success_ratio)
|
||||
Binary file not shown.
Binary file not shown.
|
After Width: | Height: | Size: 101 KiB |
Binary file not shown.
|
After Width: | Height: | Size: 94 KiB |
Binary file not shown.
|
After Width: | Height: | Size: 16 KiB |
Binary file not shown.
|
After Width: | Height: | Size: 15 KiB |
Binary file not shown.
|
After Width: | Height: | Size: 90 KiB |
Binary file not shown.
|
After Width: | Height: | Size: 118 KiB |
@@ -0,0 +1,325 @@
|
||||
\documentclass{article}
|
||||
\usepackage{float}
|
||||
\usepackage{hyperref}
|
||||
\hypersetup{
|
||||
pdfborder={0 0 0}
|
||||
}
|
||||
\usepackage{graphicx}
|
||||
\graphicspath{{images/}}
|
||||
|
||||
\setlength{\parindent}{0pt}
|
||||
\setlength{\parskip}{0.6em}
|
||||
\linespread{1.08}
|
||||
|
||||
\title{Outline of EE}
|
||||
\author{Seungjun Lee}
|
||||
\date{February 22, 2026}
|
||||
|
||||
\begin{document}
|
||||
\maketitle
|
||||
|
||||
\begin{abstract}
|
||||
|
||||
\textbf{Title}:
|
||||
When Asymptotic Complexity Fails: An Empirical and Cost-Based Study of Binary and Fibonacci Heaps in Python
|
||||
|
||||
\textbf{RQ}:
|
||||
Why does the theoretical asymptotic advantage of Fibonacci heap in Dijkstra’s algorithm not translate into practical runtime improvements in Python implementations?
|
||||
|
||||
\textbf{Category}:
|
||||
Computer Science
|
||||
|
||||
\end{abstract}
|
||||
|
||||
\newpage
|
||||
\tableofcontents
|
||||
\newpage
|
||||
|
||||
\section{Introduction}
|
||||
|
||||
\subsection*{Context}
|
||||
\begin{itemize}
|
||||
\item Dijkstra’s algorithm widely used for shortest path problems
|
||||
\item Priority queue choice affects theoretical time complexity
|
||||
\item Pure Dijkstra: $O(E+ V^2)$
|
||||
\item Binary heap: $O(E \log V)$
|
||||
\item Fibonacci heap: $O(E + V \log V)$
|
||||
\item Theoretical advantage not clearly observed in practical implementations
|
||||
\end{itemize}
|
||||
|
||||
\subsection*{Outline of argument}
|
||||
\begin{itemize}
|
||||
\item Graph structure influences decrease-key frequency
|
||||
\item Decrease-key frequency determines theoretical advantage
|
||||
\item Empirical runtime does not reflect the theory
|
||||
\item Operation level cost explains the gap between the thoery and reality
|
||||
\end{itemize}
|
||||
|
||||
\subsection*{Scope}
|
||||
\begin{itemize}
|
||||
\item Python implementation only
|
||||
\item Synthetic directed graphs (using outdegree-based generation)
|
||||
\item Lognormal edge weight distribution
|
||||
\item Nodes: 2000--16000, density: 0.00015--0.0384, stds: 1000--16000, trials: 200
|
||||
\item Single-source single-target shortest path
|
||||
\end{itemize}
|
||||
|
||||
\subsection*{Worthiness}
|
||||
\begin{itemize}
|
||||
\item Evaluates limits of asymptotic complexity in practice
|
||||
\item Provides empirical basis for heap selection
|
||||
\item Bridges theory and implementation level cost analysis
|
||||
\end{itemize}
|
||||
|
||||
\section{Theoretical Framework}
|
||||
|
||||
\begin{itemize}
|
||||
\item Formal runtime models:
|
||||
\begin{itemize}
|
||||
\item $T_B = c_1 E \log V$
|
||||
\item $T_F = c_2 E + c_3 V \log V$
|
||||
\end{itemize}
|
||||
\item Role of decrease-key in Dijkstra
|
||||
\item Relation between relax\_success and decrease-key calls
|
||||
\item Theoretical crossover condition:
|
||||
\[
|
||||
T_F < T_B
|
||||
\]
|
||||
\end{itemize}
|
||||
|
||||
\section{Methodology}
|
||||
|
||||
\subsection*{Development}
|
||||
\begin{itemize}
|
||||
\item Real-world road dataset used to estimate distribution of real-world data
|
||||
\item Lognormal parameters derived from real data
|
||||
\item Synthetic graph generation with various nodes, density, std
|
||||
\item Measurement metrics:
|
||||
\begin{itemize}
|
||||
\item reached
|
||||
\item extract\_min\_calls
|
||||
\item relax\_attempts
|
||||
\item relax\_success
|
||||
\item relax\_success\_ratio
|
||||
\item runtime
|
||||
\end{itemize}
|
||||
\end{itemize}
|
||||
|
||||
\subsection*{Evidence}
|
||||
\begin{itemize}
|
||||
\item Experimental configuration
|
||||
\begin{verbatim}
|
||||
python -V
|
||||
Python 3.12.12
|
||||
|
||||
pip -V
|
||||
pip 26.0.1
|
||||
|
||||
python -c "import platform; print(platform.platform())"
|
||||
Linux-6.8.12-17-pve-x86_64-with-glibc2.41
|
||||
|
||||
lscpu | head
|
||||
Architecture: x86_64
|
||||
CPU op-mode(s): 32-bit, 64-bit
|
||||
Address sizes: 48 bits physical, 48 bits virtual
|
||||
Byte Order: Little Endian
|
||||
CPU(s): 16
|
||||
On-line CPU(s) list: 1-3,8
|
||||
Off-line CPU(s) list: 0,4-7,9-15
|
||||
Vendor ID: AuthenticAMD
|
||||
Model name: AMD Ryzen 7 7700 8-Core Processor
|
||||
CPU family: 25
|
||||
\end{verbatim}
|
||||
\end{itemize}
|
||||
|
||||
\subsection*{Analysis}
|
||||
\begin{itemize}
|
||||
\item Justification of parameter intervals
|
||||
\item Retain stability by 200 trials
|
||||
\end{itemize}
|
||||
|
||||
\subsection*{Connection}
|
||||
\begin{itemize}
|
||||
\item Method is the fundament of runtime investigation
|
||||
\end{itemize}
|
||||
|
||||
\section{Real Data Analysis}
|
||||
|
||||
\subsection*{Development}
|
||||
\begin{itemize}
|
||||
\item Get real data from DIMACS
|
||||
\item Extraction of edge weight distribution
|
||||
\item Calculation of mean and std
|
||||
\end{itemize}
|
||||
|
||||
\subsection*{Evidence}
|
||||
\begin{itemize}
|
||||
\item Edge weight distribition
|
||||
\begin{figure}[H]
|
||||
\centering
|
||||
\includegraphics[width=0.7\textwidth]{hist_original.png}
|
||||
\end{figure}
|
||||
\begin{figure}[H]
|
||||
\centering
|
||||
\includegraphics[width=0.7\textwidth]{hist_log.png}
|
||||
\end{figure}
|
||||
\item Summary statistics tableofcontents
|
||||
\begin{table}[H]
|
||||
\centering
|
||||
\begin{tabular}{ll}
|
||||
\hline
|
||||
Key & Value \\ \hline
|
||||
Total edges & 58333344 \\
|
||||
Mean & 2950.322 \\
|
||||
Std & 4071.694 \\
|
||||
Min & 1 \\
|
||||
Max & 368855 \\ \hline
|
||||
\end{tabular}
|
||||
\end{table}
|
||||
\end{itemize}
|
||||
|
||||
\subsection*{Analysis}
|
||||
\begin{itemize}
|
||||
\item Lognormal approximation calculation
|
||||
\item Justification of synthetic distribution parameters
|
||||
\end{itemize}
|
||||
|
||||
\subsection*{Connection}
|
||||
\begin{itemize}
|
||||
\item Synthetic data is based on real-world data
|
||||
\end{itemize}
|
||||
|
||||
\section{Relationship between variables}
|
||||
|
||||
\subsection*{Development}
|
||||
\begin{itemize}
|
||||
\item Density vs relax\_attempts
|
||||
\item Sigma vs relax\_success\_ratio
|
||||
\item Decrease-key vs speedup
|
||||
\end{itemize}
|
||||
|
||||
\subsection*{Evidence}
|
||||
\begin{itemize}
|
||||
\item Density vs relax\_attempts plot
|
||||
\begin{figure}[H]
|
||||
\centering
|
||||
\includegraphics[width=0.7\textwidth]{density_vs_relax_attempts.png}
|
||||
\end{figure}
|
||||
\item Sigma vs relax\_success\_ratio platform
|
||||
\begin{figure}[H]
|
||||
\centering
|
||||
\includegraphics[width=0.7\textwidth]{sigma_vs_relax_ratio.png}
|
||||
\end{figure}
|
||||
\item Decrease-key vs speedup correlation
|
||||
\begin{figure}[H]
|
||||
\centering
|
||||
\includegraphics[width=0.7\textwidth]{speedup_corr.png}
|
||||
\end{figure}
|
||||
\end{itemize}
|
||||
|
||||
\subsection*{Analysis}
|
||||
\begin{itemize}
|
||||
\item Density increases relax attempts nearly linearly
|
||||
\item Higher variance increases relax\_success ratio
|
||||
\item Speedup weakly correlated with decrease-key frequency
|
||||
\end{itemize}
|
||||
|
||||
\subsection*{Connection}
|
||||
\begin{itemize}
|
||||
\item Structural conditions necessary but insufficient for crossover
|
||||
\end{itemize}
|
||||
|
||||
\section{Runtime}
|
||||
|
||||
\subsection*{Development}
|
||||
\begin{itemize}
|
||||
\item Multiple linear regression of runtime
|
||||
\item Operation level cost estimation
|
||||
\end{itemize}
|
||||
|
||||
\subsection*{Evidence}
|
||||
\begin{itemize}
|
||||
\item Regression summary table
|
||||
\begin{table}[H]
|
||||
\small
|
||||
\centering
|
||||
\begin{tabular}{llllllll}
|
||||
\hline
|
||||
algorithm & intercept & $coef_{add}$ & $coef_{extract}$ & $coef_{relax}$ & $coef_{decrease}$ \\ \hline
|
||||
binary & 0.000492 & -3.496595e-07 & 3.259253e-07 & 9.095429e-08 & 1.702164e-07 \\
|
||||
fibonacci & -0.001191 & 7.446706e-07 & 3.938917e-07 & 9.333419e-08 & 1.504052e-06 \\ \hline
|
||||
\end{tabular}
|
||||
\end{table}
|
||||
\item $R^2$ comparison between models
|
||||
\begin{table}[H]
|
||||
\centering
|
||||
\begin{tabular}{lll}
|
||||
\hline
|
||||
algorithm & $r_2$ & $n_{samples}$ \\ \hline
|
||||
binary & 0.980930 & 54801 \\
|
||||
fibonacci & 0.980877 & 54801 \\ \hline
|
||||
\end{tabular}
|
||||
\end{table}
|
||||
\end{itemize}
|
||||
|
||||
\subsection*{Analysis}
|
||||
\begin{itemize}
|
||||
\item Fibonacci decrease-key cost significantly larger in Python
|
||||
\item Constant factors dominate asymptotic differences
|
||||
\end{itemize}
|
||||
|
||||
\subsection*{Connection}
|
||||
\begin{itemize}
|
||||
\item Explains absence of empirical speedup
|
||||
\end{itemize}
|
||||
|
||||
\section{Deriving the Crossover Condition}
|
||||
|
||||
\subsection*{Development}
|
||||
\begin{itemize}
|
||||
\item Substitute empirical coefficients into:
|
||||
\[
|
||||
T_F < T_B
|
||||
\]
|
||||
\end{itemize}
|
||||
|
||||
\subsection*{Evidence}
|
||||
\begin{itemize}
|
||||
\item Derived inequality expression
|
||||
\end{itemize}
|
||||
|
||||
\subsection*{Analysis}
|
||||
\begin{itemize}
|
||||
\item Required conditions exceed practical graph scale
|
||||
\item Python constant overhead prevents crossover
|
||||
\end{itemize}
|
||||
|
||||
\subsection*{Connection}
|
||||
\begin{itemize}
|
||||
\item Theoretical superiority does not always linked to practical improvement
|
||||
\end{itemize}
|
||||
|
||||
\section{Conclusion}
|
||||
|
||||
\subsection*{Conclusion}
|
||||
\begin{itemize}
|
||||
\item Fibonacci heap does not outperform Binary heap in Python
|
||||
\item Operation level costs dominate asymptotic complexity
|
||||
\item Crossover condition impractical under tested environment
|
||||
\end{itemize}
|
||||
|
||||
\subsection*{Limitation \& Evaulation}
|
||||
\begin{itemize}
|
||||
\item Python-only implementation
|
||||
\item Synthetic graph model assumptions
|
||||
\item No low-level memory/cache analysis
|
||||
\end{itemize}
|
||||
|
||||
\subsection*{Summarize main points}
|
||||
\begin{itemize}
|
||||
\item Graph structure affects decrease-key frequency
|
||||
\item Empirical runtime does not follow asymptotic expectation
|
||||
\item Constant factors determine real-world performance
|
||||
\end{itemize}
|
||||
|
||||
\end{document}
|
||||
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
File diff suppressed because one or more lines are too long
Reference in New Issue
Block a user