finish all analysis
This commit is contained in:
@@ -2,7 +2,8 @@ import os
|
||||
import numpy as np
|
||||
import pandas as pd
|
||||
import matplotlib.pyplot as plt
|
||||
import random
|
||||
import scipy.stats as stats
|
||||
from scipy.stats import shapiro
|
||||
|
||||
|
||||
def read_dimacs(file):
|
||||
@@ -14,24 +15,38 @@ def read_dimacs(file):
|
||||
continue
|
||||
elif line.startswith("p"):
|
||||
_, _, n, e = line.split()
|
||||
nodes = int(n)
|
||||
edges = int(e)
|
||||
data = [0] * edges
|
||||
elif line.startswith("a"):
|
||||
_, u, v, w = line.split()
|
||||
data[idx] = int(w)
|
||||
idx += 1
|
||||
return data
|
||||
return ((nodes, edges), data)
|
||||
|
||||
|
||||
def visualize_weights(file):
|
||||
data = read_dimacs(file)
|
||||
sample = np.array(data)
|
||||
(nodes, edges), data = read_dimacs(file)
|
||||
data = np.array(data)
|
||||
log_data = np.log(data)
|
||||
|
||||
skew = stats.skew(data)
|
||||
skew_log = stats.skew(log_data)
|
||||
kurt = stats.kurtosis(data) # excess kurtosis (정규=0)
|
||||
kurt_log = stats.kurtosis(log_data)
|
||||
print(f'\n--- Skewness / Kurtosis ---')
|
||||
print(f'Skewness (original): {skew:.4f} (정규 기준: 0)')
|
||||
print(f'Skewness (log): {skew_log:.4f} (정규 기준: 0)')
|
||||
print(f'Kurtosis (original): {kurt:.4f} (정규 기준: 0, excess)')
|
||||
print(f'Kurtosis (log): {kurt_log:.4f} (정규 기준: 0, excess)')
|
||||
|
||||
return
|
||||
|
||||
save_folder = f"{res_folder}/{file}"
|
||||
os.makedirs(save_folder, exist_ok=True)
|
||||
|
||||
plt.figure(figsize=(8, 5))
|
||||
plt.hist(sample, bins=100)
|
||||
plt.hist(data, bins=100)
|
||||
plt.title("Edge Weight Distribution (Original Scale)")
|
||||
plt.xlabel("Weight")
|
||||
plt.ylabel("Frequency")
|
||||
@@ -39,10 +54,16 @@ def visualize_weights(file):
|
||||
plt.savefig(f"{save_folder}/hist_original.png")
|
||||
plt.close()
|
||||
|
||||
log_sample = np.log(sample[sample > 0])
|
||||
plt.figure(figsize=(8, 5))
|
||||
stats.probplot(data, dist="norm", plot=plt)
|
||||
plt.title("Q-Q Plot (Original Scale)")
|
||||
plt.xlabel("Theoretical Quantiles (Normal)")
|
||||
plt.ylabel("Sample Quantiles (Weight)")
|
||||
plt.savefig(f"{save_folder}/Q-Q_original.png")
|
||||
plt.close()
|
||||
|
||||
plt.figure(figsize=(8, 5))
|
||||
plt.hist(log_sample, bins=100)
|
||||
plt.hist(log_data, bins=100)
|
||||
plt.title("Log(Weight) Distribution")
|
||||
plt.xlabel("log(Weight)")
|
||||
plt.ylabel("Frequency")
|
||||
@@ -51,37 +72,50 @@ def visualize_weights(file):
|
||||
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")
|
||||
stats.probplot(log_data, dist="norm", plot=plt)
|
||||
plt.title("Q-Q Plot (Log Weight)")
|
||||
plt.xlabel("Theoretical Quantiles (Normal)")
|
||||
plt.ylabel("Sample Quantiles (Weight)")
|
||||
plt.savefig(f"{save_folder}/Q-Q_log.png")
|
||||
plt.close()
|
||||
|
||||
# plt.figure(figsize=(8, 5))
|
||||
# plt.hist(log_data, 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()
|
||||
|
||||
print(f"finish {file}")
|
||||
return {
|
||||
"file": file,
|
||||
"edges": len(sample),
|
||||
"mean": np.mean(sample),
|
||||
"std": np.std(sample),
|
||||
"min": np.min(sample),
|
||||
"max": np.max(sample)
|
||||
"nodes": nodes,
|
||||
"edges": edges,
|
||||
"density": edges / (nodes * (nodes - 1)),
|
||||
"mean": np.mean(data),
|
||||
"std": np.std(data),
|
||||
"min": np.min(data),
|
||||
"max": np.max(data),
|
||||
"skew": stats.skew(data),
|
||||
"skew_log": stats.skew(log_data),
|
||||
}
|
||||
|
||||
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.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"
|
||||
# "USA-road-d.W.gr"
|
||||
]
|
||||
|
||||
res_folder = "results/real_data/derived/dimacs_graph_distribution"
|
||||
|
||||
@@ -0,0 +1,371 @@
|
||||
import os
|
||||
import matplotlib.pyplot as plt
|
||||
import pandas as pd
|
||||
from sklearn.linear_model import LinearRegression
|
||||
from sklearn.metrics import r2_score
|
||||
from scipy.optimize import curve_fit
|
||||
import numpy as np
|
||||
|
||||
|
||||
# Initial Setup
|
||||
csv_file = "results/synthetic_data/raw/20260418_095837.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()
|
||||
y = df["relax_attempts"].to_numpy()
|
||||
|
||||
reg = LinearRegression()
|
||||
reg.fit(X, y)
|
||||
y_hat = reg.predict(X)
|
||||
r2 = r2_score(y, y_hat)
|
||||
equation = f"y = {reg.coef_[0]:.4g}x + {reg.intercept_:.4g}\n$R^2$ = {r2:.4f}"
|
||||
|
||||
plt.figure(figsize=(6, 4))
|
||||
plt.scatter(X, y, marker="o")
|
||||
plt.plot(X, y_hat, color="red", label=equation)
|
||||
plt.xlabel("E (edges)")
|
||||
plt.ylabel("Average relax_attempts")
|
||||
plt.title("Edges vs Relax Attempts")
|
||||
plt.legend(loc="upper right", fontsize=8)
|
||||
plt.grid(True)
|
||||
plt.tight_layout()
|
||||
plt.savefig(f"{save_folder}/E_vs_relax_attempts.png", dpi=300)
|
||||
plt.close()
|
||||
|
||||
print(f"Saved E vs relax_attempts plots to {save_folder}")
|
||||
|
||||
# E_vs_relax_attempts(df)
|
||||
|
||||
|
||||
# sigma vs relax_success_ratio
|
||||
def sigma_vs_relax_success_ratio(df):
|
||||
rows = []
|
||||
sigma_save_folder = os.path.join(save_folder, "sigma_vs_relax_ratio_controlled")
|
||||
os.makedirs(sigma_save_folder, exist_ok=True)
|
||||
cnt = 1
|
||||
|
||||
for pair, group in df.groupby(["nodes", "density"]):
|
||||
nodes, density = pair
|
||||
grouped = group.groupby("sigma")["relax_success_ratio"].mean()
|
||||
|
||||
sigma_vals = grouped.index.to_numpy()
|
||||
ratio_vals = grouped.to_numpy()
|
||||
|
||||
valid = np.isfinite(ratio_vals) # When attempts = 0 -> ratio becomes infinite.
|
||||
sigma_vals = sigma_vals[valid]
|
||||
ratio_vals = ratio_vals[valid]
|
||||
|
||||
if len(sigma_vals) < 2: # When too many invalid values -> Can't do regression.
|
||||
plt.close()
|
||||
cnt += 1
|
||||
continue
|
||||
|
||||
log_sigma = np.log(sigma_vals).reshape(-1, 1)
|
||||
reg = LinearRegression()
|
||||
reg.fit(log_sigma, ratio_vals)
|
||||
r2 = r2_score(ratio_vals, reg.predict(log_sigma))
|
||||
|
||||
sigma_line = np.linspace(sigma_vals.min(), sigma_vals.max(), 200)
|
||||
ratio_line = reg.predict(np.log(sigma_line).reshape(-1, 1))
|
||||
equation = f"ratio = {reg.coef_[0]:.4g}$\\cdot \\ln{{\\sigma}}$ + {reg.intercept_:.4g}\n$R^2$ = {r2:.4f}"
|
||||
|
||||
fig, ax = plt.subplots(figsize=(6, 4))
|
||||
ax.scatter(sigma_vals, ratio_vals, marker="o")
|
||||
ax.plot(sigma_line, ratio_line, color="red", label=equation)
|
||||
ax.set_xlabel("Sigma")
|
||||
ax.set_ylabel("Relax Success Ratio")
|
||||
ax.set_title(
|
||||
f"Sigma vs Relax Success Ratio\n" f"nodes={nodes}, density={density}"
|
||||
)
|
||||
plt.legend(loc="upper left", fontsize=8)
|
||||
ax.grid(True)
|
||||
fig.tight_layout()
|
||||
fname = (
|
||||
f"{cnt}. nodes{nodes}_density{density:.20f}".rstrip("0").rstrip(".")
|
||||
+ ".png"
|
||||
)
|
||||
fig.savefig(os.path.join(sigma_save_folder, fname), dpi=300)
|
||||
plt.close(fig)
|
||||
|
||||
rows.append(
|
||||
{
|
||||
"nodes": nodes,
|
||||
"density": density,
|
||||
"avg_degree": (nodes - 1) * density,
|
||||
"coef": reg.coef_[0],
|
||||
"intercept": reg.intercept_,
|
||||
"r2": r2,
|
||||
}
|
||||
)
|
||||
cnt += 1
|
||||
|
||||
res = pd.DataFrame(rows)
|
||||
res.to_csv(os.path.join(sigma_save_folder, "r2.csv"))
|
||||
print(f"Saved controlled sigma vs relax_success_ratio plots to {sigma_save_folder}")
|
||||
|
||||
# sigma_vs_relax_success_ratio(df)
|
||||
|
||||
|
||||
# avg_degree vs relax_success_ratio
|
||||
def avg_degree_vs_relax_success_ratio(df):
|
||||
avgdeg_scatter_folder = os.path.join(save_folder, "avg_deg_vs_ratio_controlled")
|
||||
os.makedirs(avgdeg_scatter_folder, exist_ok=True)
|
||||
cnt = 1
|
||||
|
||||
for pair, group in df.groupby(["nodes", "sigma"]):
|
||||
nodes, sigma = pair
|
||||
grouped = group.groupby("avg_degree")["relax_success_ratio"].mean().reset_index()
|
||||
|
||||
fig, ax = plt.subplots(figsize=(6, 4))
|
||||
ax.plot(grouped["avg_degree"], grouped["relax_success_ratio"], marker="o")
|
||||
ax.set_xlabel("Avg Degree = (N-1) × density")
|
||||
ax.set_ylabel("Relax Success Ratio")
|
||||
ax.set_title(
|
||||
f"Avg Degree vs Relax Success Ratio\n"
|
||||
f"nodes={nodes}, sigma={sigma:.4f}"
|
||||
)
|
||||
ax.grid(True)
|
||||
fig.tight_layout()
|
||||
fname = f"{cnt}. nodes{nodes}_sigma{sigma:.6f}.png"
|
||||
fig.savefig(os.path.join(avgdeg_scatter_folder, fname), dpi=300)
|
||||
plt.close(fig)
|
||||
cnt += 1
|
||||
|
||||
print(f"Saved avg_degree vs ratio plots to {avgdeg_scatter_folder}")
|
||||
|
||||
# avg_degree_vs_relax_success_ratio(df)
|
||||
|
||||
|
||||
# log_avg_degree vs log_ratio
|
||||
def log_avg_degree_vs_log_ratio():
|
||||
CEILING = 1
|
||||
avgdeg_loglog_folder = os.path.join(save_folder, "avgdeg_vs_ratio_loglog")
|
||||
os.makedirs(avgdeg_loglog_folder, exist_ok=True)
|
||||
cnt = 0.99
|
||||
|
||||
for pair, group in df.groupby(["nodes", "sigma"]):
|
||||
nodes, sigma = pair
|
||||
grouped = group.groupby("avg_degree")["relax_success_ratio"].mean().reset_index()
|
||||
grouped = grouped[grouped["relax_success_ratio"] > 0]
|
||||
|
||||
deg_all = grouped["avg_degree"].to_numpy(dtype=float)
|
||||
ratio_all = grouped["relax_success_ratio"].to_numpy(dtype=float)
|
||||
|
||||
ceiling_mask = ratio_all >= CEILING
|
||||
decline_mask = ~ceiling_mask
|
||||
|
||||
fig, ax = plt.subplots(figsize=(6, 4))
|
||||
|
||||
if ceiling_mask.any():
|
||||
ax.scatter(
|
||||
deg_all[ceiling_mask],
|
||||
ratio_all[ceiling_mask],
|
||||
color="gray",
|
||||
label="ratio ≥ 0.99 (ceiling)",
|
||||
)
|
||||
|
||||
if decline_mask.sum() >= 2:
|
||||
x_dec = deg_all[decline_mask]
|
||||
y_dec = ratio_all[decline_mask]
|
||||
log_x = np.log2(x_dec)
|
||||
log_y = np.log2(y_dec)
|
||||
|
||||
reg = LinearRegression()
|
||||
reg.fit(log_x.reshape(-1, 1), log_y)
|
||||
r2 = r2_score(log_y, reg.predict(log_x.reshape(-1, 1)))
|
||||
slope = reg.coef_[0]
|
||||
intercept = reg.intercept_
|
||||
|
||||
log_x_line = np.linspace(log_x.min(), log_x.max(), 200)
|
||||
x_line = 2 ** log_x_line
|
||||
y_line = 2 ** (slope * log_x_line + intercept)
|
||||
|
||||
ax.scatter(
|
||||
x_dec, y_dec, color="blue", label="declining points"
|
||||
)
|
||||
ax.plot(
|
||||
x_line,
|
||||
y_line,
|
||||
color="blue",
|
||||
linestyle="--",
|
||||
label=f"fit (slope={slope:.3f}, R²={r2:.3f})",
|
||||
)
|
||||
elif decline_mask.any():
|
||||
ax.scatter(
|
||||
deg_all[decline_mask],
|
||||
ratio_all[decline_mask],
|
||||
color="blue",
|
||||
label="declining points",
|
||||
)
|
||||
|
||||
ax.set_xscale("log")
|
||||
ax.set_yscale("log")
|
||||
ax.set_xlabel("Avg Degree (log scale)")
|
||||
ax.set_ylabel("Relax Success Ratio (log scale)")
|
||||
ax.set_title(
|
||||
f"Avg Degree vs Relax Success Ratio (log-log)\n"
|
||||
f"nodes={nodes}, sigma={sigma:.4f}"
|
||||
)
|
||||
ax.legend(fontsize=8)
|
||||
ax.grid(True)
|
||||
fig.tight_layout()
|
||||
fname = f"{cnt}. nodes{nodes}_sigma{sigma:.6f}.png"
|
||||
fig.savefig(os.path.join(avgdeg_loglog_folder, fname), dpi=300)
|
||||
plt.close(fig)
|
||||
cnt += 1
|
||||
|
||||
print(f"Saved avg_degree vs ratio log-log plots to {avgdeg_loglog_folder}")
|
||||
|
||||
# log_avg_degree_vs_log_ratio()
|
||||
|
||||
|
||||
def regime_distribution():
|
||||
r2_csv = os.path.join(save_folder, "sigma_vs_relax_ratio_controlled", "r2.csv")
|
||||
res = pd.read_csv(r2_csv)
|
||||
|
||||
avg_deg = res["avg_degree"].to_numpy() # (nodes-1)*density
|
||||
r2 = res["r2"].to_numpy()
|
||||
coef = res["coef"].to_numpy()
|
||||
intercept = res["intercept"].to_numpy()
|
||||
|
||||
# ── Phase classification ──────────────────────────────────────────────────
|
||||
tree_mask = (intercept == 1) & (np.abs(coef) == 0)
|
||||
giant_mask = (~tree_mask) & (r2 >= 0.9)
|
||||
trans_mask = (~tree_mask) & (~giant_mask)
|
||||
|
||||
labels = np.empty(len(res), dtype=object)
|
||||
labels[tree_mask] = "Tree"
|
||||
labels[giant_mask] = "Giant"
|
||||
labels[trans_mask] = "Transition"
|
||||
|
||||
print("\n=== Phase counts ===")
|
||||
for phase in ["Tree", "Transition", "Giant"]:
|
||||
print(f" {phase}: {(labels == phase).sum()}")
|
||||
|
||||
regime_save_folder = os.path.join(save_folder, "regime_distribution")
|
||||
os.makedirs(regime_save_folder, exist_ok=True)
|
||||
|
||||
colors = {"Tree": "gray", "Transition": "darkorange", "Giant": "steelblue"}
|
||||
bins = np.logspace(
|
||||
np.log10(avg_deg[avg_deg > 0].min()),
|
||||
np.log10(avg_deg.max()),
|
||||
40
|
||||
)
|
||||
|
||||
# ── Histogram: avg_degree distribution per phase ──────────────────────────
|
||||
fig, ax = plt.subplots(figsize=(8, 5))
|
||||
for phase, color in colors.items():
|
||||
vals = avg_deg[labels == phase]
|
||||
ax.hist(vals, bins=bins, alpha=0.6, color=color, label=phase)
|
||||
ax.axvline(1.0, color="red", linestyle="--", linewidth=1.5, label="avg_degree = 1")
|
||||
ax.set_xscale("log")
|
||||
ax.set_xlabel("Avg Degree = (N-1) × density (log scale)")
|
||||
ax.set_ylabel("Count")
|
||||
ax.set_title("Phase Distribution by Avg Degree")
|
||||
ax.legend(fontsize=9)
|
||||
ax.grid(True, which="both", alpha=0.4)
|
||||
fig.tight_layout()
|
||||
fig.savefig(os.path.join(regime_save_folder, "phase_histogram.png"), dpi=300)
|
||||
plt.close(fig)
|
||||
|
||||
# ── Scatter: avg_degree vs R², colored by phase ───────────────────────────
|
||||
fig, ax = plt.subplots(figsize=(8, 5))
|
||||
for phase, color in colors.items():
|
||||
mask = labels == phase
|
||||
ax.scatter(avg_deg[mask], r2[mask], s=15, alpha=0.6, color=color, label=phase)
|
||||
ax.axvline(1.0, color="red", linestyle="--", linewidth=1.5, label="avg_degree = 1")
|
||||
ax.set_xscale("log")
|
||||
ax.set_xlabel("Avg Degree (log scale)")
|
||||
ax.set_ylabel("R²")
|
||||
ax.set_title("R² vs Avg Degree, colored by phase")
|
||||
ax.legend(fontsize=9)
|
||||
ax.grid(True, which="both", alpha=0.4)
|
||||
fig.tight_layout()
|
||||
fig.savefig(os.path.join(regime_save_folder, "r2_by_phase.png"), dpi=300)
|
||||
plt.close(fig)
|
||||
|
||||
print(f"Saved regime distribution plots to {regime_save_folder}")
|
||||
|
||||
# regime_distribution()
|
||||
|
||||
|
||||
# Nonlinear regression: r = (a·ln(sigma) + b) · avg_deg^c
|
||||
def nonlinear_regression(df):
|
||||
# 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"])
|
||||
|
||||
avg_deg = sub["avg_degree"].to_numpy()
|
||||
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
|
||||
|
||||
# Initial guess
|
||||
p0 = [0.05, 0.5, -0.7]
|
||||
|
||||
popt, pcov = curve_fit(model, (avg_deg, sigma), r, p0=p0, maxfev=10000)
|
||||
a, b, c = popt
|
||||
perr = np.sqrt(np.diag(pcov))
|
||||
|
||||
r_pred = model((avg_deg, sigma), a, b, c)
|
||||
ss_res = np.sum((r - r_pred) ** 2)
|
||||
ss_tot = np.sum((r - r.mean()) ** 2)
|
||||
r2 = 1 - ss_res / ss_tot
|
||||
|
||||
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}")
|
||||
print(f" c = {c:.6f} ± {perr[2]:.6f}")
|
||||
print(f" R² = {r2:.4f}")
|
||||
|
||||
# ── Predicted vs Actual ───────────────────────────────────────────────────
|
||||
nlr_save_folder = os.path.join(save_folder, "nonlinear_regression")
|
||||
os.makedirs(nlr_save_folder, exist_ok=True)
|
||||
|
||||
fig, ax = plt.subplots(figsize=(6, 5))
|
||||
ax.scatter(r, r_pred, s=5, alpha=0.3, color="steelblue")
|
||||
mn, mx = min(r.min(), r_pred.min()), max(r.max(), r_pred.max())
|
||||
ax.plot([mn, mx], [mn, mx], color="red", linewidth=1.5, linestyle="--")
|
||||
ax.set_xlabel("Actual ratio")
|
||||
ax.set_ylabel("Predicted ratio")
|
||||
ax.set_title(f"Nonlinear fit: r = (a·ln(σ)+b)·avg_deg^c\nR²={r2:.4f}")
|
||||
ax.grid(True, alpha=0.4)
|
||||
fig.tight_layout()
|
||||
fig.savefig(os.path.join(nlr_save_folder, "predicted_vs_actual.png"), dpi=300)
|
||||
plt.close(fig)
|
||||
|
||||
# ── Residuals by nodes ────────────────────────────────────────────────────
|
||||
residuals = r - r_pred
|
||||
fig, ax = plt.subplots(figsize=(7, 5))
|
||||
for n in sorted(sub["nodes"].unique()):
|
||||
mask = sub["nodes"].to_numpy() == n
|
||||
ax.scatter(r_pred[mask], residuals[mask], s=5, alpha=0.4, label=f"N={n}")
|
||||
ax.axhline(0, color="red", linewidth=1.2, linestyle="--")
|
||||
ax.set_xlabel("Predicted ratio")
|
||||
ax.set_ylabel("Residual")
|
||||
ax.set_title("Residuals by N")
|
||||
ax.legend(fontsize=6, ncol=3, markerscale=2)
|
||||
ax.grid(True, alpha=0.4)
|
||||
fig.tight_layout()
|
||||
fig.savefig(os.path.join(nlr_save_folder, "residuals_by_N.png"), dpi=300)
|
||||
plt.close(fig)
|
||||
|
||||
print(f"Saved nonlinear regression plots to {nlr_save_folder}")
|
||||
|
||||
nonlinear_regression(df)
|
||||
@@ -1,50 +0,0 @@
|
||||
import os
|
||||
import pandas as pd
|
||||
import matplotlib.pyplot as plt
|
||||
|
||||
csv_file = "results/synthetic_data/raw/20260303_083239.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,190 @@
|
||||
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/20260418_095837.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))
|
||||
|
||||
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.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")
|
||||
@@ -1,48 +0,0 @@
|
||||
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/20260303_083239.csv")
|
||||
summary = op_cost_functional_analysis(df)
|
||||
print(summary)
|
||||
@@ -1,38 +0,0 @@
|
||||
import pandas as pd
|
||||
import matplotlib.pyplot as plt
|
||||
import os
|
||||
|
||||
csv_file = "results/synthetic_data/raw/20260303_083239.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,2 @@
|
||||
|
||||
fig, ax = plt.subplots(figsize=(6, 4))
|
||||
@@ -18,7 +18,6 @@ def run_test(
|
||||
trials,
|
||||
mean_dist,
|
||||
start,
|
||||
end,
|
||||
base_seed
|
||||
):
|
||||
timer = time.perf_counter
|
||||
@@ -55,7 +54,7 @@ def run_test(
|
||||
|
||||
bin_heap = BinHeap(nodes)
|
||||
st = timer()
|
||||
dist, stats = heap_dijkstra(nodes, adj, bin_heap, start, end)
|
||||
stats = heap_dijkstra(nodes, adj, bin_heap, start)
|
||||
et = timer()
|
||||
rows.append(
|
||||
{
|
||||
@@ -67,7 +66,6 @@ def run_test(
|
||||
"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,
|
||||
@@ -76,7 +74,7 @@ def run_test(
|
||||
|
||||
fibo_heap = FiboHeap(nodes)
|
||||
st = timer()
|
||||
dist, stats = heap_dijkstra(nodes, adj, fibo_heap, start, end)
|
||||
stats = heap_dijkstra(nodes, adj, fibo_heap, start)
|
||||
et = timer()
|
||||
rows.append(
|
||||
{
|
||||
@@ -88,7 +86,6 @@ def run_test(
|
||||
"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,
|
||||
@@ -110,12 +107,11 @@ def run_test(
|
||||
|
||||
# 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]
|
||||
densities = [0.0000001, 0.0000003, 0.000001, 0.000003, 0.00001, 0.00003, 0.0001, 0.0003, 0.001, 0.003, 0.01, 0.03, 0.1, 0.3]
|
||||
stds = [1000, 1500, 2000, 3000, 4000, 6000, 8000, 12000, 16000]
|
||||
trials = 400
|
||||
trials = 10
|
||||
mean_dist = 3000
|
||||
start = 0
|
||||
end = 1
|
||||
base_seed = 42
|
||||
|
||||
save_folder = "results/synthetic_data/raw"
|
||||
@@ -131,7 +127,6 @@ config = {
|
||||
"trials": trials,
|
||||
"mean_dist": mean_dist,
|
||||
"start": start,
|
||||
"end": end,
|
||||
"base_seed": base_seed,
|
||||
}
|
||||
with open(config_file, "w") as f:
|
||||
@@ -144,6 +139,5 @@ df = run_test(
|
||||
trials = trials,
|
||||
mean_dist = mean_dist,
|
||||
start = start,
|
||||
end = end,
|
||||
base_seed = base_seed
|
||||
)
|
||||
Reference in New Issue
Block a user