initial commit

This commit is contained in:
2026-03-02 20:55:36 +09:00
commit f224644b49
86 changed files with 1065250 additions and 0 deletions
+166
View File
@@ -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에 대한 명확한 답
• 이론과 실제의 간극 강조
• 실무적 함의
• 한계 및 향후 연구
View File
View File
+46
View File
@@ -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
+32
View File
@@ -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]
View File
+75
View File
@@ -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)
+177
View File
@@ -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
View File
@@ -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
+149
View File
@@ -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
)
+34
View File
@@ -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()
+18
View File
@@ -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