Files
dijkstra-runtime-analysis/codes/experiments/synthetic_data/analysis/processing_time_analysis.py
T
2026-04-23 22:54:17 +09:00

196 lines
7.0 KiB
Python
Raw Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
import numpy as np
import pandas as pd
import matplotlib.pyplot as plt
import os
from sklearn.linear_model import LinearRegression
from sklearn.metrics import r2_score
# Runtime = Add + Extract-min + Relax-attempts + Relax-success
# = VlogV * k1 + VlogV * k2 + E * k3 + \alpha * logV * k4 (Binary)
# = V * k1 + VlogV * k2 + E * k3 + \alpha * k4 (Fibonacci)
# (\alpha = relax_success)
#
# V increases -> Add, Extract-min, Relax-attempts, Relax-success all increases.
# Therfore, critical multicollinearlity occurs.
#
# To solve, run regression per each V.
# Then V becomes constant.
#
# Runtime(Binary) = VlogV * k1 + VlogV * k2 + E * k3 + \alpha * logV * k4 (Binary)
# = intercept + E * k3 + \alpha * k4
# Runtime(Fibonacci) = V * k1 + VlogV * k2 + E * k3 + \alpha * k4 (Fibonacci)
# = intercept + E * k3 + \alpha * k4
#
# Final equation
# Runtime of specific V = intercept + E * k3 + \alpha * k4
#
# intercept absorbs V*(k1+k2) which is constant within each N.
# k3: cost per relax_attempt (should be equal across heaps)
# k4: cost per decrease-key (binary: should scale with log2N; fibonacci: should be constant)
csv_file = "results/synthetic_data/raw/20260421_031740.csv"
save_folder = f"results/synthetic_data/derived/{os.path.splitext(os.path.basename(csv_file))[0]}/processing_time_analysis"
os.makedirs(save_folder, exist_ok=True)
df = pd.read_csv(csv_file)
nodes = sorted(df["nodes"].unique())
algos = ["binary", "fibonacci"]
records = []
for algo in algos:
sub = df[df["algorithm"] == algo]
for n in nodes:
g = sub[sub["nodes"] == n]
X = g[["relax_attempts", "relax_success"]].to_numpy()
y = g["time"].to_numpy()
model = LinearRegression().fit(X, y)
r2 = r2_score(y, model.predict(X))
records.append({
"algorithm": algo,
"N": n,
"log2N": round(np.log2(n), 4),
"intercept": model.intercept_,
"k3 (E)": model.coef_[0],
"k4 (alpha)":model.coef_[1],
"r2": r2,
"n": len(g),
})
results = pd.DataFrame(records)
for algo in algos:
print(f"=== {algo} ===")
r = results[results["algorithm"] == algo][["N","log2N","intercept","k3 (E)","k4 (alpha)","r2","n"]]
print(r.to_string(index=False))
print()
grouped = results.set_index(["N", "algorithm"])
def get_param(param):
return (
grouped.loc[(nodes, "binary"), param].values,
grouped.loc[(nodes, "fibonacci"), param].values
)
k3_bin, k3_fib = get_param("k3 (E)")
k4_bin, k4_fib = get_param("k4 (alpha)")
int_bin, int_fib = get_param("intercept")
# binary: k4 ~ log₂N 회귀
log_n = np.log2(np.array(nodes)).reshape(-1, 1)
bin_reg = LinearRegression().fit(log_n, k4_bin)
r2_bin = r2_score(k4_bin, bin_reg.predict(log_n))
# fibonacci: k4 ~ log₂N 회귀
fib_reg = LinearRegression().fit(log_n, k4_fib)
r2_fib = r2_score(k4_fib, fib_reg.predict(log_n))
n_line = np.linspace(min(nodes), max(nodes), 300)
log_n_line = np.log2(n_line).reshape(-1, 1)
print(f"\nbinary log₂N regression: coef={bin_reg.coef_[0]:.4e}, intercept={bin_reg.intercept_:.4e}, R²={r2_bin:.4f}")
# Plot
fig, ax = plt.subplots(figsize=(7, 5))
ax.plot(nodes, k4_bin, marker="o", color="steelblue", label="binary k4")
ax.plot(nodes, k4_fib, marker="s", color="darkorange", label="fibonacci k4")
ax.plot(n_line, bin_reg.predict(log_n_line), color="steelblue", linestyle="--", linewidth=1.5,
label=f"binary fit (∝ log₂N) R²={r2_bin:.3f}")
ax.plot(n_line, fib_reg.predict(log_n_line), color="steelblue", linestyle="--", linewidth=1.5,
label=f"fibonacci fit (∝ log₂N) R²={r2_fib:.3f}")
ax.set_xlabel("N (nodes)")
ax.set_ylabel("k4 — decrease-key cost per call [s]")
ax.set_title("k4 (decrease-key unit cost) vs N")
ax.legend(fontsize=8)
ax.grid(True, alpha=0.4)
fig.tight_layout()
fig.savefig(f"{save_folder}/k4_vs_N.png", dpi=300)
plt.close(fig)
print(f"Saved: {save_folder}/k4_vs_N.png")
# k3
fig, ax = plt.subplots(figsize=(7, 5))
ax.plot(nodes, k3_bin, marker="o", color="steelblue", label="binary k4")
ax.plot(nodes, k3_fib, marker="s", color="darkorange", label="fibonacci k4")
ax.set_xlabel("N (nodes)")
# ax.set_ylabel("k3 — decrease-key cost per call [s]")
# ax.set_title("k3 (decrease-key unit cost) vs N")
ax.legend(fontsize=8)
ax.grid(True, alpha=0.4)
fig.tight_layout()
fig.savefig(f"{save_folder}/k3_vs_N.png", dpi=300)
plt.close(fig)
print(f"Saved: {save_folder}/k3_vs_N.png")
# Intercept
fig, ax = plt.subplots(figsize=(7, 5))
ax.plot(nodes, int_bin, marker="o", color="steelblue", label="binary k4")
ax.plot(nodes, int_fib, marker="s", color="darkorange", label="fibonacci k4")
ax.set_xlabel("N (nodes)")
# ax.set_ylabel("k4 — decrease-key cost per call [s]")
# ax.set_title("k4 (decrease-key unit cost) vs N")
ax.legend(fontsize=8)
ax.grid(True, alpha=0.4)
fig.tight_layout()
fig.savefig(f"{save_folder}/int_vs_N.png", dpi=300)
plt.close(fig)
print(f"Saved: {save_folder}/int_vs_N.png")
# ── VIF Check ──────────────────────────────────────────────────────────────────
# relax_success = ratio × relax_attempts → 두 변수가 선형 상관될 수 있음
# VIF = 1 / (1 - R²), where R² is from regressing X1 on X2 (2-predictor case)
# VIF > 10: severe multicollinearity, coefficients become unstable
vif_records = []
for algo in algos:
sub = df[df["algorithm"] == algo]
for n in nodes:
g = sub[sub["nodes"] == n]
X = g[["relax_attempts", "relax_success"]].to_numpy()
# Regress relax_attempts on relax_success
reg_vif = LinearRegression().fit(X[:, 1].reshape(-1, 1), X[:, 0])
r2_vif = r2_score(X[:, 0], reg_vif.predict(X[:, 1].reshape(-1, 1)))
vif = 1 / (1 - r2_vif) if r2_vif < 1.0 else float("inf")
# Pearson correlation (simpler diagnostic)
corr = np.corrcoef(X[:, 0], X[:, 1])[0, 1]
vif_records.append({
"algorithm": algo,
"N": n,
"corr(E, alpha)": round(corr, 6),
"R2_vif": round(r2_vif, 6),
"VIF": round(vif, 2),
})
vif_df = pd.DataFrame(vif_records)
for algo in algos:
print(f"\n=== VIF — {algo} ===")
v = vif_df[vif_df["algorithm"] == algo][["N", "corr(E, alpha)", "R2_vif", "VIF"]]
print(v.to_string(index=False))
# Plot VIF vs N
fig, ax = plt.subplots(figsize=(7, 4))
for algo, color, marker in [("binary", "steelblue", "o"), ("fibonacci", "darkorange", "s")]:
v = vif_df[vif_df["algorithm"] == algo]
ax.plot(v["N"], v["VIF"], marker=marker, color=color, label=algo)
ax.axhline(10, color="red", linestyle="--", linewidth=1.2, label="VIF = 10 (threshold)")
ax.set_xlabel("N (nodes)")
ax.set_ylabel("VIF")
ax.set_title("VIF (relax_attempts vs relax_success) per N")
ax.legend(fontsize=8)
ax.grid(True, alpha=0.4)
fig.tight_layout()
fig.savefig(f"{save_folder}/vif_vs_N.png", dpi=300)
plt.close(fig)
print(f"\nSaved: {save_folder}/vif_vs_N.png")