finish all analysis and upload data and results

This commit is contained in:
2026-04-26 10:33:02 +09:00
parent 9d76d82f5e
commit fc1386e572
376 changed files with 1059309 additions and 246 deletions
@@ -7,19 +7,6 @@ from scipy.optimize import curve_fit
import numpy as np
# Initial Setup
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]}/call_number_analysis"
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"]
df["E"] = df["nodes"] * (df["nodes"] - 1) * df["density"]
df["decrease_key"] = df["relax_success"]
df["avg_degree"] = (df["nodes"] - 1) * df["density"]
# 1. E vs relax_attempts
def E_vs_relax_attempts(df):
X = df[["E"]].to_numpy()
@@ -292,7 +279,7 @@ def regime_distribution(df):
# 6. Nonlinear regression: r = (a·ln(sigma) + b) · avg_deg^c
def nonlinear_regression(df):
def nonlinear_regression(compute_local=False):
# Filter: giant component regime only
sub = df[(df["avg_degree"] >= 1) & (df["relax_success_ratio"] < 0.99)].copy()
sub = sub[sub["relax_success_ratio"] > 0].dropna(subset=["relax_success_ratio", "avg_degree", "sigma"])
@@ -301,8 +288,6 @@ def nonlinear_regression(df):
sigma = sub["sigma"].to_numpy()
r = sub["relax_success_ratio"].to_numpy()
print(f"Fitting on {len(sub)} data points")
def model(X, a, b, c):
avg_deg_, sigma_ = X
return (a * np.log(sigma_) + b) * avg_deg_ ** c
@@ -319,6 +304,9 @@ def nonlinear_regression(df):
ss_tot = np.sum((r - r.mean()) ** 2)
r2 = 1 - ss_res / ss_tot
if compute_local == False:
return (a, b, c)
print("\n=== Nonlinear regression: r = (a·ln(σ) + b) · avg_deg^c ===")
print(f" a = {a:.6f} ± {perr[0]:.6f}")
print(f" b = {b:.6f} ± {perr[1]:.6f}")
@@ -360,9 +348,22 @@ def nonlinear_regression(df):
print(f"Saved nonlinear regression plots to {nlr_save_folder}")
# Initial Setup
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]}/call_number_analysis"
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"]
df["E"] = df["nodes"] * (df["nodes"] - 1) * df["density"]
df["decrease_key"] = df["relax_success"]
df["avg_degree"] = (df["nodes"] - 1) * df["density"]
E_vs_relax_attempts(df) # 1
sigma_vs_relax_success_ratio(df) # 2
avg_degree_vs_relax_success_ratio(df) # 3
log_avg_degree_vs_log_ratio(df) # 4
regime_distribution(df) # 5
nonlinear_regression(df) # 6
nonlinear_regression(compute_local=True) # 6
@@ -0,0 +1,123 @@
from experiments.synthetic_data.analysis.processing_time_analysis import mean_l
from experiments.synthetic_data.analysis.processing_time_analysis import regression_k3
from experiments.synthetic_data.analysis.processing_time_analysis import regression_m
from experiments.synthetic_data.analysis.call_number_analysis import nonlinear_regression
import numpy as np
import pandas as pd
import os
import matplotlib.pyplot as plt
from sklearn.metrics import mean_squared_error, mean_absolute_error
def k3(V):
return k3_a * np.exp(-k3_b * V) + k3_c
def m(V):
return m_a * np.log2(V) + m_b
def relax_success(E, S, AVG_DEG):
relax_attempts = E
relax_success_ratio = (rs_a * np.log(S) + rs_b) * AVG_DEG ** rs_c
return relax_attempts * relax_success_ratio
def runtime_predict(V, D, S):
E = V * (V - 1) * D
AVG_DEG = (V - 1) * D
if AVG_DEG < 1:
return False
runtime = V * l + E * k3(V) + relax_success(E, S, AVG_DEG) * m(V)
print(relax_success(E, S, AVG_DEG))
# runtime_eq = f"[V * {l}] + [E * {k3_a} * exp(-{k3_b} * V) + {k3_c}] + [E * ({rs_a} * log(S) + {rs_b}) * AVG_DEG ** {rs_c} * {m_a} * log_2(V) + {m_b}]"
return runtime
l = mean_l()
k3_a, k3_b, k3_c = regression_k3()
m_a, m_b = regression_m()
rs_a, rs_b, rs_c = nonlinear_regression()
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]}/prediction_result"
os.makedirs(save_folder, exist_ok=True)
df = pd.read_csv(csv_file)
df = df[df["algorithm"] == "binary"].copy()
records = []
for row in df.itertuples():
predicted = runtime_predict(row.nodes, row.density, row.sigma)
if predicted is False:
continue
records.append({
"nodes": row.nodes,
"density": row.density,
"sigma": row.sigma,
"trial": row.trial,
"real_time": row.time,
"predict_time": predicted,
"abs_error": abs(row.time - predicted),
"rel_error": abs(row.time - predicted) / row.time,
})
result = pd.DataFrame(records)
out_path = os.path.join(save_folder, "prediction.csv")
result.to_csv(out_path, index=False)
print(f"Saved {len(result)} rows → {out_path}")
real = result["real_time"].to_numpy()
pred = result["predict_time"].to_numpy()
ss_res = np.sum((real - pred) ** 2)
ss_tot = np.sum((real - real.mean()) ** 2)
r2 = 1 - ss_res / ss_tot
print(f"R² = {r2:.4f}")
rmse = np.sqrt(mean_squared_error(real, pred))
mae = mean_absolute_error(real, pred)
print(f"RMSE: {rmse:.4f} s") # 평균 제곱 오차의 제곱근
print(f"MAE: {mae:.4f} s") # 평균 절대 오차
mn, mx = min(real.min(), pred.min()), max(real.max(), pred.max())
fig, ax = plt.subplots(figsize=(6, 6))
ax.scatter(real, pred, s=5, alpha=0.3, color="steelblue")
ax.plot([mn, mx], [mn, mx], color="red", linewidth=1.5, linestyle="--", label="y = x")
ax.set_xlabel("real_time [s]")
ax.set_ylabel("predict_time [s]")
ax.set_title(f"Predicted vs Real Runtime R²={r2:.4f}")
ax.legend(fontsize=9)
ax.grid(True, alpha=0.4)
fig.tight_layout()
fig.savefig(os.path.join(save_folder, "predicted_vs_real.png"), dpi=300)
plt.close(fig)
print(f"Saved: {save_folder}/predicted_vs_real.png")
# rel_error distribution
rel_err = result["rel_error"].to_numpy()
fig, axes = plt.subplots(1, 2, figsize=(12, 5))
# histogram
axes[0].hist(rel_err, bins=50, color="steelblue", edgecolor="none", alpha=0.8)
axes[0].axvline(np.median(rel_err), color="red", linestyle="--", linewidth=1.5, label=f"median={np.median(rel_err):.3f}")
axes[0].axvline(np.mean(rel_err), color="orange", linestyle="--", linewidth=1.5, label=f"mean={np.mean(rel_err):.3f}")
axes[0].set_xlabel("rel_error")
axes[0].set_ylabel("count")
axes[0].set_title("Relative Error Distribution")
axes[0].legend(fontsize=9)
axes[0].grid(True, alpha=0.4)
# rel_error vs real_time
axes[1].scatter(real, rel_err, s=5, alpha=0.3, color="steelblue")
axes[1].set_xlabel("real_time [s]")
axes[1].set_ylabel("rel_error")
axes[1].set_title("Relative Error vs Real Time")
axes[1].grid(True, alpha=0.4)
fig.tight_layout()
fig.savefig(os.path.join(save_folder, "rel_error_dist.png"), dpi=300)
plt.close(fig)
print(f"Saved: {save_folder}/rel_error_dist.png")
@@ -4,193 +4,252 @@ import matplotlib.pyplot as plt
import os
from sklearn.linear_model import LinearRegression
from sklearn.metrics import r2_score
from scipy.optimize import curve_fit
# Heap: Binary
#
# 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)
# = VlogV * k1 + VlogV * k2 + E * k3 + \alpha * logV * k4
# (\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.
# To solve this problem, 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
# Runtime_V = (V) * (logV(k1 + k2)) + (E) * k3 + (\alpha) * (logV * k4)
#
# left part: call number, right part: cost per call
# call number is not concern in operation cost analysis.
# Important thing is that logV in right sides become constant.
#
# Final equation
# Runtime of specific V = intercept + E * k3 + \alpha * k4
# Runtime of specific V = V * l + E * k3 + \alpha * m
#
# 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)
# Using this equation, we can get l, k3, and m from each regression.
# l, m are defined like this.
# l = logV * (k1 + k2)
# m = logV * k4
#
#
# Final result
# l: cost per each add and extract-min (should scale with log2N)
# k3: cost per relax_attempt (should be equal across heaps)
# m: cost per decrease-key (should scale with log2N)
#
# (All base of log in this context is 2 due to binary heap.)
# contribution diagram
def contribution():
contribution_records = []
for n in nodes:
g = df[df['nodes'] == n]
g = g[g['relax_success'] > 0]
if len(g) < 3:
continue
# 해당 N의 l, k3, m 가져오기
row = results[results['N'] == n].iloc[0]
l_val = row['l']
k3_val = row['k3'] # k3_fixed
m_val = row['m']
# 각 항의 평균값 계산
E_mean = g['relax_attempts'].mean()
alpha_mean = g['relax_success'].mean()
Vl = n * l_val # V·l
Ek3 = E_mean * k3_val # E·k3
am = alpha_mean * m_val # α·m
total = Vl + Ek3 + am
contribution_records.append({
'N' : n,
'V·l' : Vl,
'E·k3' : Ek3,
'α·m' : am,
'total' : total,
'V·l %' : Vl / total * 100,
'E·k3 %' : Ek3 / total * 100,
'α·m %' : am / total * 100,
})
contrib = pd.DataFrame(contribution_records)
print("\n=== Contribution of each operations ===")
print(contrib[['N','V·l %','E·k3 %','α·m %']].to_string(index=False))
# 시각화
fig, ax = plt.subplots(figsize=(9, 5))
x = np.arange(len(contrib))
w = 0.25
ax.bar(x - w, contrib['V·l %'], width=w, label='V·l (add+extract)')
ax.bar(x, contrib['E·k3 %'], width=w, label='E·k3 (relax-attempt)')
ax.bar(x + w, contrib['α·m %'], width=w, label='α·m (decrease-key)')
ax.set_xticks(x)
ax.set_xticklabels(contrib['N'].astype(int))
ax.set_xlabel('N (nodes)')
ax.set_ylabel('Contribution (%)')
ax.set_title('Runtime contribution by operation')
ax.legend()
ax.grid(True, alpha=0.4)
fig.tight_layout()
fig.savefig(f"{save_folder}/contribution_vs_N.png", dpi=300)
plt.close(fig)
print(f"Saved: contribution_vs_N.png")
# l
def mean_l():
return results["l"].mean()
def plot_l():
fig, ax = plt.subplots(figsize=(7, 5))
ax.plot(nodes, l_bin, marker="o", color="steelblue", label="l")
ax.set_xlabel("N (nodes)")
ax.set_ylabel("l — add + extract-min unit cost [s]")
ax.set_title("l (add + extract-min unit cost) vs N")
ax.legend(fontsize=8)
ax.grid(True, alpha=0.4)
fig.tight_layout()
fig.savefig(f"{save_folder}/l_vs_N.png", dpi=300)
plt.close(fig)
print(f"Saved: {save_folder}/l_vs_N.png")
# k3
def regression_k3():
n_arr = np.array(nodes, dtype=float)
def exp_conv(n, a, b, c):
return a * np.exp(-b * n) + c
k3_arr = np.array(k3_bin, dtype=float)
popt_ec, _ = curve_fit(exp_conv, n_arr, k3_arr,
p0=[float(k3_arr.max() - k3_arr.min()), 1/float(n_arr.mean()), float(k3_arr.min())],
maxfev=20000)
return popt_ec
def plot_k3():
n_arr = np.array(nodes, dtype=float)
n_line = np.linspace(min(nodes), max(nodes), 300)
def exp_conv(n, a, b, c):
return a * np.exp(-b * n) + c
k3_arr = np.array(k3_bin, dtype=float)
popt_ec, _ = curve_fit(exp_conv, n_arr, k3_arr,
p0=[float(k3_arr.max() - k3_arr.min()), 1/float(n_arr.mean()), float(k3_arr.min())],
maxfev=20000)
pred_ec = exp_conv(n_line, *popt_ec)
r2_ec = r2_score(k3_bin, exp_conv(n_arr, *popt_ec))
print("\n=== k3 exp_conv regression ===")
print("a * exp(-b*N) + c")
print(popt_ec)
fig, ax = plt.subplots(figsize=(9, 5))
ax.plot(nodes, k3_bin, marker="o", color="black", zorder=5, label="k3 (data)")
ax.plot(n_line, pred_ec, linestyle="--", linewidth=1.5, label=f"exp conv R²={r2_ec:.4f}")
ax.set_xlabel("N (nodes)")
ax.set_ylabel("k3 — iteration cost per call [s]")
ax.set_title("k3 (iteration unit cost) vs N — model comparison")
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")
# m
def regression_m():
log_n = np.log2(np.array(nodes)).reshape(-1, 1)
reg = LinearRegression().fit(log_n, m_bin)
return (reg.coef_[0], reg.intercept_)
def plot_m():
log_n = np.log2(np.array(nodes)).reshape(-1, 1)
reg = LinearRegression().fit(log_n, m_bin)
r2_bin = r2_score(m_bin, reg.predict(log_n))
n_line = np.linspace(min(nodes), max(nodes), 300)
log_n_line = np.log2(n_line).reshape(-1, 1)
print("\n=== m log regression ===")
print("m = a * log_2(N) + b")
print(reg.coef_[0], reg.intercept_)
fig, ax = plt.subplots(figsize=(7, 5))
ax.plot(nodes, m_bin, marker="o", color="steelblue", label="binary k4")
ax.plot(n_line, reg.predict(log_n_line), color="steelblue", linestyle="--", linewidth=1.5,
label=f"fit (∝ log₂N) R²={r2_bin:.3f}")
ax.set_xlabel("N (nodes)")
ax.set_ylabel("m — decrease-key cost per call [s]")
ax.set_title("m (decrease-key unit cost) vs N")
ax.legend(fontsize=8)
ax.grid(True, alpha=0.4)
fig.tight_layout()
fig.savefig(f"{save_folder}/m_vs_N.png", dpi=300)
plt.close(fig)
print(f"Saved: {save_folder}/m_vs_N.png")
# Initial process
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"]
df = df[df["algorithm"] == "binary"]
records = []
for algo in algos:
sub = df[df["algorithm"] == algo]
for n in nodes:
g = sub[sub["nodes"] == n]
for n in nodes:
g = df[df["nodes"] == n]
X = g[["relax_attempts", "relax_success"]].to_numpy()
y = g["time"].to_numpy()
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))
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),
})
l = model.intercept_ / n
k3 = model.coef_[0]
m = model.coef_[1]
records.append({
"N": n,
"log2N": round(np.log2(n), 4),
"l": l,
"k3": k3,
"m": m,
"r2": r2,
"data": len(g),
})
results = pd.DataFrame(records)
grouped = results.set_index(["N"])
l_bin = grouped.loc[nodes, "l"].values
k3_bin = grouped.loc[nodes, "k3"].values
m_bin = grouped.loc[nodes, "m"].values
for algo in algos:
print(f"=== {algo} ===")
r = results[results["algorithm"] == algo][["N","log2N","intercept","k3 (E)","k4 (alpha)","r2","n"]]
# Directly run
if __name__ == "__main__":
r = results[["N","log2N","l","k3","m","r2","data"]]
print("=== Regression Result ===")
print(r.to_string(index=False))
print()
print("\n=== l representative value ===\n", results["l"].describe(), sep="")
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 k3")
ax.plot(nodes, k3_fib, marker="s", color="darkorange", label="fibonacci k3")
ax.set_xlabel("N (nodes)")
ax.set_ylabel("k3 — iteration cost per call [s]")
ax.set_title("k3 (iteration 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")
contribution()
plot_l()
plot_k3()
plot_m()