Martin Horvat 2 дней назад
Родитель
Сommit
6091fcf2df
100 измененных файлов с 7600 добавлено и 12078 удалено
  1. 0 82
      BayesianResult.ipynb
  2. 0 359
      Bayesian_Zahra.py
  3. BIN
      Figures/DTTA-DREFIT.png
  4. BIN
      Figures/Eigenvectors.png
  5. BIN
      Figures/Elasiticty.png
  6. BIN
      Figures/Fitting plus Distributions.png
  7. BIN
      Figures/Fitting trim plus distributions.png
  8. BIN
      Figures/Log-Logistic.png
  9. BIN
      Figures/Log-SUV.png
  10. BIN
      Figures/Noise Box1.png
  11. BIN
      Figures/Noise Box2.png
  12. BIN
      Figures/Noise Box3.png
  13. BIN
      Figures/Noise Box4.png
  14. BIN
      Figures/Noise Effect.png
  15. BIN
      Figures/ORIG-BANDS.png
  16. BIN
      Figures/ORIGIN-BANDS.png
  17. BIN
      Figures/RAW-Logistic.png
  18. BIN
      Figures/Raw-SUV.png
  19. BIN
      Figures/Sensitivity.png
  20. BIN
      Figures/Slope.png
  21. BIN
      Figures/TRIM-BANDS.png
  22. BIN
      Figures/TTA1.png
  23. BIN
      Figures/TTA2.png
  24. 0 292
      LogitResult.ipynb
  25. BIN
      archive/Paper__Modeling_the_probability_of_toxicity_with_discussion_of_uncertainties.zip
  26. 0 1245
      bayesian.py
  27. 0 402
      bayesian_noise.py
  28. 0 139
      bayesianconstraints.py
  29. 0 0
      data/raw/cases_retroMManon.csv
  30. 0 0
      data/raw/flags_combined.mat
  31. 0 0
      data/raw/normal_range.mat
  32. 0 0
      data/raw/suv_percentilesSLOthenUWM.mat
  33. 0 55
      data_utils.py
  34. 0 0
      legacy/mathematica/cost_checks.nb
  35. 0 0
      legacy/mathematica/distrib.nb
  36. 0 0
      legacy/matlab/distinguishable_colors.m
  37. 0 0
      legacy/matlab/irAE_plotting.m
  38. 0 0
      legacy/matlab/maxbowel.m
  39. 0 1845
      logit.py
  40. 0 0
      meetings/minutes/20250606_minutes.txt
  41. 0 0
      meetings/minutes/20250628_tasks.txt
  42. 0 0
      meetings/photos/Note 1.jpg
  43. 0 0
      meetings/photos/Note 2.jpg
  44. 0 0
      meetings/photos/Note 3.jpg
  45. 0 0
      meetings/photos/meeting1.png
  46. 0 0
      meetings/photos/meeting2.png
  47. 0 0
      meetings/photos/meeting3.jpg
  48. 586 0
      notebooks/logit_all_models.ipynb
  49. 5821 0
      notebooks/logit_mono-cubic4paper.ipynb
  50. 1193 0
      notebooks/logit_review_boots.ipynb
  51. 0 0
      notes/Instruction_Manual.txt
  52. 0 0
      notes/comment_on_logistic_regression_results.tex
  53. 0 0
      notes/pipeline_for_cond_prob_modeling.ipynb
  54. 0 0
      notes/refs.bib
  55. 0 13
      paper_MD/Makefile
  56. BIN
      paper_MD/archive/IOPGraphicsGuidelines.pdf
  57. BIN
      paper_MD/archive/IOPLaTeXGuidelines.pdf
  58. 0 222
      paper_MD/archive/IOPLaTeXGuidelines.tex
  59. BIN
      paper_MD/figs/Bayes_bs_Gauss_bowel.pdf
  60. BIN
      paper_MD/figs/Bayes_bs_Gauss_lung.pdf
  61. BIN
      paper_MD/figs/Bayes_bs_Gauss_thyroid.pdf
  62. BIN
      paper_MD/figs/Bayes_bs_log_normal_bowel.pdf
  63. BIN
      paper_MD/figs/Bayes_bs_log_normal_lung.pdf
  64. BIN
      paper_MD/figs/Bayes_bs_log_normal_thyroid.pdf
  65. BIN
      paper_MD/figs/logit_boots.pdf
  66. BIN
      paper_MD/figs/logit_boots_sel.pdf
  67. BIN
      paper_MD/figs/logit_boots_zoom.pdf
  68. BIN
      paper_MD/figs/logit_bs_bowel.pdf
  69. BIN
      paper_MD/figs/logit_bs_lung.pdf
  70. BIN
      paper_MD/figs/logit_bs_thyroid.pdf
  71. BIN
      paper_MD/figs/logit_mvn.pdf
  72. BIN
      paper_MD/figs/logit_mvn_bowel.pdf
  73. BIN
      paper_MD/figs/logit_mvn_lung.pdf
  74. BIN
      paper_MD/figs/logit_mvn_thyroid.pdf
  75. 0 87
      paper_MD/iopams.sty
  76. 0 1722
      paper_MD/iopart-num.bst
  77. 0 1107
      paper_MD/iopart.cls
  78. 0 124
      paper_MD/iopart10.clo
  79. 0 125
      paper_MD/iopart12.clo
  80. 0 523
      paper_MD/refs.bib
  81. 0 48
      paper_MD/risk_modeling.tex
  82. 0 139
      paper_MD/setstack.sty
  83. 0 0
      presentations/cover_image/pet_ct_risk_modeling_cover.pdf
  84. 0 0
      presentations/cover_image/pet_ct_risk_modeling_cover.png
  85. 0 40
      python/Bayesian with differentDistributions .ipynb
  86. 0 67
      python/Logisticregression Method_MLE copy.ipynb
  87. 0 56
      python/Logisticregression Method_MLE_After Meeting.ipynb
  88. BIN
      python/artifacts/phi_raw_ORIG.npy
  89. 0 176
      python/bayesian/Bayesian_Zahra.py
  90. 0 190
      python/bayesian/Bayesian_Zahra_v1.1.py
  91. 0 153
      python/bayesian/bayesian.ipynb
  92. 0 473
      python/bayesian/bayesian.py
  93. 0 59
      python/bayesian/data_utils.py
  94. BIN
      python/bayesian/results/bayesian_CI_cmp.pdf
  95. BIN
      python/bayesian/results/bayesian_fit.pdf
  96. 0 141
      python/bayesian/zahra_plus_comments.py
  97. 0 170
      python/fitting_distribution_to_data.ipynb
  98. 0 499
      python/logistic/logit_boots.ipynb
  99. 0 584
      python/logistic/logit_fit.ipynb
  100. 0 941
      python/logistic/logit_gen.ipynb

Разница между файлами не показана из-за своего большого размера
+ 0 - 82
BayesianResult.ipynb


+ 0 - 359
Bayesian_Zahra.py

@@ -1,359 +0,0 @@
-#BetaPrime vs Gamma, hard-mono fit WITH constant + weak regularization
-
-import numpy as np
-import matplotlib.pyplot as plt
-from scipy import optimize
-from scipy.special import betaln, gammaln
-import scipy.io as io
-
-# ---------- Data ----------
-data_path = "../data/"
-
-# === Load data ===
-data_path = "../data/"
-suv = io.loadmat(data_path + "suv_percentilesSLOthenUWM.mat")['lung_SUVperc_COMBINED'][0:58, :, :]
-flags = io.loadmat(data_path + "flags_combined.mat")['flags'][0:58, 3]
-
-X = np.nanmax(suv[:, :, 94], axis=1).reshape(-1)
-X_NC = X[flags == 0]
-X_AE = X[flags == 1]
-
-
-y = np.array([1]*len(X_AE) + [0]*len(X_NC), int) # 1=AE, 0=NC
-X = np.concatenate([X_AE, X_NC], axis=0)
-# sanity checks now that X,y actually exist
-n = len(y); n1 = int(y.sum()); p_emp = n1 / n
-rng = np.random.default_rng(12345)
-
-# ---------- Helpers ----------
-def logistic(z):
-    z = np.clip(z, -60, 60)
-    return 1.0/(1.0+np.exp(-z))
-
-def sigmoid(t):
-    return 1.0/(1.0+np.exp(-t))
-
-def softplus(t):
-    t = np.asarray(t, float)
-    return np.log1p(np.exp(-np.abs(t))) + np.maximum(t, 0.0)
-
-# --- Eq: logit P(AE|x) = log(p/(1-p)) + dE(x) ---
-# where dE(x) = dE_ess(x) + C(params)
-
-def dE_ess(x, a, b, s, k, th):
-    # Essential (x-dependent) terms:
-    # (a - k) * log(x) - (a + b) * log(1 + x/s) + x/th
-    x = np.asarray(x, float)
-    return (a - k) * np.log(x) - (a + b) * np.log1p(x/s) + x/th
-
-def dE_const(a, b, s, k, th):
-    # Constant (parameter-only) terms:
-    # C = -a*log(s) - log B(a,b) + k*log(th) + log Γ(k)
-    return -(a*np.log(s)) - betaln(a, b) + k*np.log(th) + gammaln(k)
-
-def dE_full(x, a, b, s, k, th):
-    # Total evidence term: dE(x) = dE_ess(x) + C
-    return dE_ess(x, a, b, s, k, th) + dE_const(a, b, s, k, th)
-
-# ---------- Global monotonicity cap for theta ----------
-def theta_max(a, b, k, s, eps=1e-12):
-    A = a - k
-    if A <= 0:
-        return np.inf
-    r = np.sqrt(a + b) - np.sqrt(max(A, eps))
-    if r <= 1e-12:
-        return np.inf
-    return s/(r*r)
-
-# phi = [p_raw, b_raw, s_raw, k_raw, d_raw, u_raw]
-def unpack_phi_mono(phi):
-    p_raw, b_raw, s_raw, k_raw, d_raw, u_raw = phi
-    
-    # Map raw parameters into valid constrained space:
-    # p = sigmoid(p_raw) ∈ (0,1) → AE prior (class prior)
-    p = sigmoid(p_raw)                     
-    
-    # b = softplus(b_raw) > 0 → Beta–Prime shape parameter
-    b = softplus(b_raw) + 1e-6             
-    
-    # s = softplus(s_raw) > 0 → Beta–Prime scale parameter
-    s = softplus(s_raw) + 1e-6             
-    
-    # k = softplus(k_raw) > 0 → Gamma shape parameter
-    k = softplus(k_raw) + 1e-6             
-    
-    # delta = softplus(d_raw) > 0; a = k + delta > k
-    delta = softplus(d_raw) + 1e-6         
-    a = k + delta                          
-    
-    # θ (theta) is constrained: 0 < θ ≤ θ_max(a,b,k,s)
-    th_cap = theta_max(a, b, k, s)         
-    th = th_cap * sigmoid(u_raw)            # map u_raw ∈ R into (0, th_cap]
-    
-    return p, a, b, s, k, th
-
-# ---------- Priors ----------
-# Beta prior on p centered at empirical rate
-TAU = 25.0   # reduce to ~5 if you want it weaker
-alpha = max(TAU * float(p_emp), 1e-6)
-beta  = max(TAU * (1.0 - float(p_emp)), 1e-6)
-
-# Weak log-normal shrinkage on positive parameters
-def nlog_lognormal(x, mu, sigma, eps=1e-12):
-    # -log LogNormal(x | mu, sigma) up to additive const
-    x = np.maximum(x, eps)
-    lx = np.log(x)
-    return 0.5 * ((lx - mu)/sigma)**2 + lx
-
-# ---------- Objective ----------
-def neg_post_phi_mono_WITH_CONST_REG(phi, X, y):
-    p, a, b, s, k, th = unpack_phi_mono(phi)
-    eps = 1e-12
-
-    # Likelihood with constant included
-    z  = (np.log(p) - np.log(1-p)) + dE_full(X, a, b, s, k, th)
-    px = logistic(z)
-    nll = -np.sum(y*np.log(px + eps) + (1-y)*np.log(1 - px + eps))
-
-    # Prior on p ~ Beta(alpha, beta)
-    npr_p = -((alpha-1)*np.log(p + eps) + (beta-1)*np.log(1 - p + eps))
-
-    # --- Regularization (weak priors) ---
-    # AE median m1: use AE median if present; otherwise overall median.
-    if (y == 1).any():
-        m1 = np.median(X[y == 1])
-    else:
-        m1 = np.median(X)
-
-    reg = 0.0  # total penalty starts at zero
-
-    # 1) Gamma shape k (>0): very weak prior centered at 2 (σ=1.2).
-    reg += nlog_lognormal(k, mu=np.log(2.0), sigma=1.2)
-
-    # 2) Beta-Prime shape b (>0): same weak prior.
-    reg += nlog_lognormal(b, mu=np.log(2.0), sigma=1.2)
-
-    # 3) Beta-Prime scale s (>0): center near AE median (tighter σ=0.5).
-    reg += nlog_lognormal(s, mu=np.log(max(m1, 1e-6)), sigma=0.5)
-
-    # 4) Left-tail gap delta = a - k (>0): center around ~1.5 (σ=0.5)
-    delta = a - k
-    reg += nlog_lognormal(delta, mu=np.log(1.5), sigma=0.5)
-
-    # Keep theta away from the boundary: Beta(3,3) on r = th/th_cap
-    thcap = theta_max(a, b, k, s)
-    if np.isfinite(thcap) and thcap > 0:
-        r = np.clip(th/thcap, 1e-9, 1-1e-9)
-        npr_r = -((3-1)*np.log(r) + (3-1)*np.log(1 - r))
-    else:
-        npr_r = 0.0
-
-    return nll + npr_p + reg + npr_r
-
-# ---------- Initialization ----------
-def init_phi(X, y):
-    # Method-of-moments init for Gamma(k, theta) using NC data (y==0)
-    # ref: https://en.wikipedia.org/wiki/Gamma_distribution#Estimation_of_parameters
-    X0 = X[y==0]
-    m0 = X0.mean() if X0.size else X.mean()  # sample mean
-    v0 = X0.var()  if X0.size else X.var()   # sample variance
-
-    if v0 <= 0:
-        # If variance is degenerate, pick a safe, sane starting point
-        k0, th0 = 2.0, max(m0/2, 0.1)
-    else:
-        # MoM: k = m^2 / v, theta = v / m, with small eps and lower bounds
-        k0  = max((m0**2)/(v0 + 1e-9), 1.5)
-        th0 = max(v0/(m0 + 1e-9), 0.3)
-
-    X1 = X[y==1]
-    m1 = np.median(X1) if X1.size else np.median(X)
-
-
-# Empirical AE rate as a starting prior for p. Clip away from 0/1 so logit is finite.
-# p0 = n_AE / n, but truncated to [1e-3, 1-1e-3] to avoid infinities in log(p/(1-p)).
-    p0 = np.clip(float(y.mean()), 1e-3, 1 - 1e-3)
-    
-    
-    
-# Simple, stable seeds for AE Beta–Prime:
-#   b0 = 1.5   → mild shape; not too spiky, not too flat.
-#   s0 = max(m1, 0.5) → anchor scale near the AE median, but don’t go tiny.
-    b0, s0 = 1.5, max(m1, 0.5)
-
-
-# Pack raw parameters φ for the optimizer.
-# We optimize in an unconstrained space and map with:
-#   p      = sigmoid(p_raw)
-#   b,s,k  = softplus(raw) + 1e-6
-#   a      = k + softplus(delta_raw) + 1e-6
-#   theta  = theta_max * sigmoid(u_raw)
-# To “invert” softplus for the initial guess we use log(expm1(v)) which is the exact inverse
-# of softplus when you define softplus(t) = log(1 + exp(t)). The +1e-9 is just numerical padding.
-    raw = np.array([
-        np.log(p0/(1-p0)),                # p_raw
-        np.log(np.expm1(b0) + 1e-9),      # b_raw
-        np.log(np.expm1(s0) + 1e-9),      # s_raw
-        np.log(np.expm1(k0) + 1e-9),      # k_raw
-        np.log(np.expm1(1.0) + 1e-9),     # delta_raw
-        -0.2                              # u_raw (keeps theta a bit below cap initially)
-    ], float) 
-    return raw
-
-# ---------- Fitting ----------
-def fit_hard_mono_WITH_CONST_REG(X, y, phi_start=None, maxtries=6, jitter=0.3, rng=None):
-    if rng is None:
-        rng = np.random.default_rng(12345)
-    if phi_start is None:
-        phi_start = init_phi(X, y)
-    phi = phi_start.copy()
-    last_err = None
-    for _ in range(maxtries):
-        res = optimize.minimize(
-            neg_post_phi_mono_WITH_CONST_REG, phi, args=(X, y),
-            method="L-BFGS-B",
-            options=dict(maxiter=12000, ftol=1e-10)
-        )
-        if res.success and np.isfinite(res.fun):
-            return unpack_phi_mono(res.x), res
-        last_err = res
-        phi = phi + rng.normal(0, jitter, size=phi.shape)
-    raise RuntimeError(f"Fit failed. Last status: {getattr(last_err, 'message', 'n/a')}")
-
-# ---------- Convenience ----------
-def P_with(theta, x):
-    p, a, b, s, k, th = theta
-    L = (np.log(p) - np.log(1-p)) + dE_full(x, a, b, s, k, th)
-    return logistic(L)
-
-def diag_report(theta, X):
-    p, a, b, s, k, th = theta
-    thcap = theta_max(a, b, k, s)
-    C = dE_const(a, b, s, k, th)
-    logit_p = np.log(p) - np.log(1 - p)
-    A = a - k
-    den = np.sqrt(a + b) - np.sqrt(max(A, 1e-12))
-    xs = np.inf if den <= 1e-12 else s*np.sqrt(max(A,1e-12))/den
-    print({
-        "p": p, "a": a, "b": b, "s": s, "k": k, "theta": th,
-        "theta_max": thcap, "theta/theta_max": (th/thcap if np.isfinite(thcap) else np.nan),
-        "logit(p)": logit_p, "C": C, "x* (bottleneck)": xs
-    })
-
-def plot_s_shape(theta, X, y, rng=None, ax=None, label='P(AE | x)'):
-    if rng is None:
-        rng = np.random.default_rng(0)
-    if ax is None:
-        fig, ax = plt.subplots(figsize=(7, 4.5))
-
-    x_lo = max(1e-6, float(X.min())*0.8)
-    x_hi = float(X.max())*1.2
-    xg = np.linspace(x_lo, x_hi, 600)
-    pg = P_with(theta, xg)
-
-    ax.plot(xg, pg, lw=2, label=label)
-    jit = (rng.random(len(X)) - 0.5) * 0.06
-    y_jit = y + jit
-    ax.scatter(X[y==0], y_jit[y==0], s=22, alpha=0.35, label='NC (y=0)', edgecolors='none')
-    ax.scatter(X[y==1], y_jit[y==1], s=28, alpha=0.60, label='AE (y=1)', edgecolors='none')
-
-    ax.set_ylim(-0.05, 1.05)
-    ax.set_xlim(x_lo, x_hi)
-    ax.set_xlabel('x')
-    ax.set_ylabel('P(AE | x)')
-    ax.set_title('S-shaped P(AE | x) with hard-mono fit (constant included, regularized)')
-    ax.grid(True, alpha=0.3)
-    ax.legend(loc='lower right', frameon=False)
-    return ax
-
-# ---------- Run fit ----------
-theta_hat, res = fit_hard_mono_WITH_CONST_REG(X, y, rng=rng)
-print("Optimization success:", res.success, "fval:", res.fun)
-diag_report(theta_hat, X)
-
-ax = plot_s_shape(theta_hat, X, y, rng=rng)
-plt.show()
-
-
-
-
-#CI Estimation
-
-
-
-# Delta-method 
-import numdifftools as nd  
-
-# wrap scalar objective for numdifftools
-def build_objective(X, y):
-    def f(phi):
-        return neg_post_phi_mono_WITH_CONST_REG(np.asarray(phi, float), X, y)
-    return f
-
-# compute Σ_φ (covariance in phi-space) at MAP using numdifftools.Hessian
-phi_hat = res.x.copy()                    # MAP in raw-phi space 
-f_obj = build_objective(X, y)             # scalar negative log-posterior
-H = nd.Hessian(f_obj, method='central')(phi_hat)
-Sigma_phi = invert_with_eigenfloor(H, floor=1e-6)
-
-
-# 95% Wald band via Delta method
-z = norm.ppf(0.975)  # 1.96 for 95%  ppf stands for percent point function — it’s the inverse CDF
-
-
-def g_px_at_x(x):
-    """Return g(φ) = P(AE | x, φ), so we can get ∇g(φ̂) via numdifftools.Gradient."""
-    #Build a scalar function g(φ) = P(AE | x, φ) for a fixed x.
-    #We return this function so numdifftools.Gradient can compute ∇g(φ̂).
-    def g(phi):
-        p, a, b, s, k, th = unpack_phi_mono(np.asarray(phi, float))
-        L = (np.log(p) - np.log(1 - p)) + dE_full(x, a, b, s, k, th)
-        return logistic(L)
-    return g
-
-# x-grid
-x_lo = max(1e-6, float(X.min()) * 0.8)
-x_hi = min(10.0, float(X.max()) * 1.2)
-xg = np.linspace(x_lo, x_hi, 500)
-
-p_hat = np.empty_like(xg)  # point estimate at MAP
-p_lo  = np.empty_like(xg)  # lower 95%
-p_hi  = np.empty_like(xg)  # upper 95%
-
-for i, x in enumerate(xg):
-    gx = g_px_at_x(x)
-    # point estimate at MAP
-    ph = gx(phi_hat)
-    # gradient wrt φ at φ̂ via numdifftools.Gradient
-    grad = nd.Gradient(gx, method='central')(phi_hat)  # shape (d,)
-    # Delta-method variance on probability scale: var ≈ ∇g^T Σ_φ ∇g
-    var = float(grad @ Sigma_phi @ grad)
-    se  = np.sqrt(max(var, 0.0))
-
-    p_hat[i] = ph
-    p_lo[i]  = np.clip(ph - z * se, 0.0, 1.0)
-    p_hi[i]  = np.clip(ph + z * se, 0.0, 1.0)
-
-# plot
-fig, ax = plt.subplots(figsize=(7,4.5 ))
-
-# curve + band (sharp colors)
-ax.plot(xg, p_hat, color="#000000", lw=2.2, label='P(AE|x) at MAP')
-ax.fill_between(xg, p_lo, p_hi, facecolor="#1f77b4", alpha=0.18, label='95% Wald band (Delta)')
-ax.plot(xg, p_lo, color="#1f77b4")
-ax.plot(xg, p_hi, color="#1f77b4")
-
-# overlay data with tiny vertical jitter
-rng_plot = np.random.default_rng(999)
-jit = (rng_plot.random(len(X)) - 0.5) * 0.06
-ax.scatter(X[y==0], (y + jit)[y==0], s=22, alpha=0.55, color="#2ca02c", edgecolors='none', label='NC')
-ax.scatter(X[y==1], (y + jit)[y==1], s=26, alpha=0.75, color="#ff7f0e", edgecolors='none', label='AE')
-ax.set_ylim(-0.05, 1.05)
-ax.set_xlabel('x')
-ax.set_ylabel('P(AE | x)')
-ax.set_title('Delta–method band using numdifftools Hessian/Gradient')
-ax.grid(alpha=0.3)
-ax.legend(loc='lower right')
-plt.show()
-
-

BIN
Figures/DTTA-DREFIT.png


BIN
Figures/Eigenvectors.png


BIN
Figures/Elasiticty.png


BIN
Figures/Fitting plus Distributions.png


BIN
Figures/Fitting trim plus distributions.png


BIN
Figures/Log-Logistic.png


BIN
Figures/Log-SUV.png


BIN
Figures/Noise Box1.png


BIN
Figures/Noise Box2.png


BIN
Figures/Noise Box3.png


BIN
Figures/Noise Box4.png


BIN
Figures/Noise Effect.png


BIN
Figures/ORIG-BANDS.png


BIN
Figures/ORIGIN-BANDS.png


BIN
Figures/RAW-Logistic.png


BIN
Figures/Raw-SUV.png


BIN
Figures/Sensitivity.png


BIN
Figures/Slope.png


BIN
Figures/TRIM-BANDS.png


BIN
Figures/TTA1.png


BIN
Figures/TTA2.png


Разница между файлами не показана из-за своего большого размера
+ 0 - 292
LogitResult.ipynb


BIN
archive/Paper__Modeling_the_probability_of_toxicity_with_discussion_of_uncertainties.zip


+ 0 - 1245
bayesian.py

@@ -1,1245 +0,0 @@
-# bayesian.py
-# ============================================================
-# BAYESIAN FIT + CI + ELASTICITY
-# ============================================================
-
-import os
-import numpy as np
-import pandas as pd
-import matplotlib.pyplot as plt
-
-from scipy import optimize, stats
-from scipy.io import loadmat
-from scipy.optimize import brentq
-from scipy.special import betaln, gammaln
-
-from data_utils import get_data
-
-
-# ============================================================
-# 1) DATA LOADING
-# ============================================================
-
-def load_xy(
-    perc=95,
-    suv_path="suv_percentilesSLOthenUWM.mat",
-    flags_path="flags_combined.mat",
-):
-    """
-    Load feature x and binary label y.
-    """
-    here = os.path.dirname(os.path.abspath(__file__))
-
-    suv_full = os.path.join(here, suv_path)
-    flags_full = os.path.join(here, flags_path)
-
-    print("Loading SUV from:", suv_full)
-    print("Loading FLAGS from:", flags_full)
-
-    suv_dict = loadmat(suv_full)
-    flags_dict = loadmat(flags_full)
-
-    x, y = get_data(perc, suv_dict, flags_dict)
-
-    x = np.asarray(x, float).ravel()
-    y = np.asarray(y, int).ravel()
-
-    m = np.isfinite(x)
-    x, y = x[m], y[m]
-
-    x = np.clip(x, 1e-12, None)
-    return x, y
-
-
-# ============================================================
-# 2) CORE MODEL FUNCTIONS
-# ============================================================
-
-def logistic(z):
-    return 1.0 / (1.0 + np.exp(-np.clip(z, -60, 60)))
-
-
-def sigmoid(t):
-    return 1.0 / (1.0 + np.exp(-np.clip(t, -60, 60)))
-
-
-def dE_full(x, a, b, s, k, th):
-    """
-    log f_BP(x|a,b,s) - log f_Gamma(x|k,th), including constants.
-    """
-    x = np.asarray(x, float)
-    return (
-        (a - k) * np.log(x)
-        - (a + b) * np.log1p(x / s)
-        + x / th
-        - a * np.log(s)
-        - betaln(a, b)
-        + k * np.log(th)
-        + gammaln(k)
-    )
-
-
-def softplus(t):
-    t = np.asarray(t, float)
-    return np.log1p(np.exp(-np.abs(t))) + np.maximum(t, 0.0)
-
-
-def theta_max(a, b, k, s, eps=1e-12):
-    """
-    Monotonicity cap for theta.
-    """
-    A = a - k
-    if A <= 0:
-        return np.inf
-    r = np.sqrt(a + b) - np.sqrt(max(A, eps))
-    return np.inf if r <= 1e-12 else s / (r * r)
-
-
-def unpack(phi):
-    """
-    Reparameterisation:
-      phi = [p_raw, b_raw, s_raw, k_raw, d_raw, u_raw]
-
-      p in (0,1)
-      b,s,k > 0
-      a = k + delta with delta > 0
-      theta = theta_cap * sigmoid(u_raw)
-    """
-    p_raw, b_raw, s_raw, k_raw, d_raw, u_raw = phi
-
-    p = sigmoid(p_raw)
-
-    b = softplus(b_raw) + 1e-6
-    s = softplus(s_raw) + 1e-6
-    k = softplus(k_raw) + 1e-6
-
-    delta = softplus(d_raw) + 1e-6
-    a = k + delta
-
-    thcap = theta_max(a, b, k, s)
-    th = thcap * sigmoid(u_raw)
-
-    return p, a, b, s, k, th, thcap
-
-
-def make_priors(y, tau=25.0):
-    """
-    Beta(TAU*p_emp, TAU*(1-p_emp)) prior on prevalence p.
-    """
-    p_emp = float(np.mean(y))
-    alpha = max(tau * p_emp, 1e-6)
-    beta = max(tau * (1.0 - p_emp), 1e-6)
-    return alpha, beta
-
-
-def neg_post(phi, X, y, alpha, beta, use_prior_p=True, prior_r=(1.05, 1.05)):
-    """
-    Negative log-posterior = NLL + optional priors.
-
-    Priors used here:
-      - Beta prior on prevalence p
-      - Beta prior on r = theta/theta_cap
-
-    No extra priors on a, b, s, k.
-    """
-    p, a, b, s, k, th, thcap = unpack(phi)
-    eps = 1e-12
-
-    logit_val = (np.log(p) - np.log(1.0 - p)) + dE_full(X, a, b, s, k, th)
-    px = logistic(logit_val)
-
-    nll = -np.sum(y * np.log(px + eps) + (1 - y) * np.log(1 - px + eps))
-
-    if use_prior_p:
-        nll += -((alpha - 1) * np.log(p + eps) + (beta - 1) * np.log(1 - p + eps))
-
-    if prior_r is not None and np.isfinite(thcap) and thcap > 0:
-        r = np.clip(th / thcap, 1e-9, 1 - 1e-9)
-        nll += -((prior_r[0] - 1) * np.log(r) + (prior_r[1] - 1) * np.log(1 - r))
-
-    return float(nll)
-
-
-def init_phi(X, y):
-    """
-    Stable initial values.
-    """
-    X = np.asarray(X, float)
-    y = np.asarray(y, int)
-
-    X0 = X[y == 0]
-    m0 = X0.mean() if X0.size else X.mean()
-    v0 = X0.var() if X0.size else X.var()
-    k0 = 2.0 if v0 <= 0 else max((m0 * m0) / (v0 + 1e-9), 1.5)
-
-    X1 = X[y == 1]
-    m1 = np.median(X1) if X1.size else np.median(X)
-
-    p0 = np.clip(float(np.mean(y)), 1e-3, 1 - 1e-3)
-    b0 = 1.5
-    s0 = max(m1, 0.5)
-
-    return np.array(
-        [
-            np.log(p0 / (1 - p0)),         # p_raw
-            np.log(np.expm1(b0) + 1e-9),   # b_raw
-            np.log(np.expm1(s0) + 1e-9),   # s_raw
-            np.log(np.expm1(k0) + 1e-9),   # k_raw
-            np.log(np.expm1(1.0) + 1e-9),  # d_raw
-            -0.2,                          # u_raw
-        ],
-        dtype=float,
-    )
-
-
-def fit_bayes(X, y, seed=0, use_prior_p=True, prior_r=(1.05, 1.05), tau=25.0):
-    """
-    MAP fit using L-BFGS-B.
-    """
-    X = np.asarray(X, float)
-    y = np.asarray(y, int)
-
-    alpha, beta = make_priors(y, tau=tau)
-
-    obj = lambda w: neg_post(
-        w,
-        X,
-        y,
-        alpha,
-        beta,
-        use_prior_p=use_prior_p,
-        prior_r=prior_r,
-    )
-
-    w0 = init_phi(X, y)
-    res = optimize.minimize(
-        obj,
-        w0,
-        method="L-BFGS-B",
-        options={"maxiter": 6000, "ftol": 1e-9},
-    )
-
-    if not (res.success and np.isfinite(res.fun)):
-        rng = np.random.default_rng(seed)
-        w1 = w0 + rng.normal(0, 0.2, size=w0.shape)
-        res = optimize.minimize(
-            obj,
-            w1,
-            method="L-BFGS-B",
-            options={"maxiter": 6000, "ftol": 1e-9},
-        )
-
-    theta_hat = unpack(res.x)
-    return theta_hat, res
-
-
-def P_with(theta_hat, x):
-    """
-    Posterior risk curve P(AE|x) under fitted model.
-    """
-    p, a, b, s, k, th, _ = theta_hat
-    x = np.asarray(x, float)
-    logit_val = (np.log(p) - np.log(1 - p)) + dE_full(x, a, b, s, k, th)
-    return logistic(logit_val)
-
-
-# ============================================================
-# 3) ORIGINAL / TRIM DATASETS
-# ============================================================
-
-def make_trimmed_dataset(X, y, value_to_drop=2.48122597, tol=1e-3):
-    """
-    Remove point(s) with x approximately equal to value_to_drop.
-    """
-    X = np.asarray(X, float)
-    y = np.asarray(y, int)
-
-    mask_keep = np.abs(X - value_to_drop) > tol
-    removed_idx = np.where(~mask_keep)[0]
-
-    return {
-        "X_orig": X.copy(),
-        "y_orig": y.copy(),
-        "X_trim": X[mask_keep],
-        "y_trim": y[mask_keep],
-        "removed_idx": removed_idx,
-    }
-
-
-def run_bayesian_group_fit(
-    perc=95,
-    suv_path="suv_percentilesSLOthenUWM.mat",
-    flags_path="flags_combined.mat",
-    value_to_drop=2.48122597,
-    tol=1e-3,
-    use_prior_p=True,
-    prior_r=(1.05, 1.05),
-    tau=25.0,
-):
-    """
-    Load data, create ORIGINAL/TRIM datasets,
-    and fit constrained Bayesian group model on both.
-    """
-    X_all, y_all = load_xy(perc=perc, suv_path=suv_path, flags_path=flags_path)
-
-    ds = make_trimmed_dataset(X_all, y_all, value_to_drop=value_to_drop, tol=tol)
-
-    theta_orig, res_orig = fit_bayes(
-        ds["X_orig"],
-        ds["y_orig"],
-        seed=0,
-        use_prior_p=use_prior_p,
-        prior_r=prior_r,
-        tau=tau,
-    )
-
-    theta_trim, res_trim = fit_bayes(
-        ds["X_trim"],
-        ds["y_trim"],
-        seed=1,
-        use_prior_p=use_prior_p,
-        prior_r=prior_r,
-        tau=tau,
-    )
-
-    return {
-        **ds,
-        "theta_orig": theta_orig,
-        "theta_trim": theta_trim,
-        "res_orig": res_orig,
-        "res_trim": res_trim,
-    }
-
-
-def summarize_theta(theta_hat):
-    p, a, b, s, k, th, thcap = theta_hat
-    return {
-        "p": p,
-        "a": a,
-        "b": b,
-        "s": s,
-        "k": k,
-        "theta": th,
-        "theta_cap": thcap,
-        "r": th / thcap if np.isfinite(thcap) and thcap > 0 else np.nan,
-    }
-
-
-def plot_bayesian_orig_trim_raw(
-    fit_results,
-    xmax=6.0,
-    suptitle="Conditional Probability of AE",
-    figsize=(12, 7),
-    dpi=140,
-):
-    """
-    One raw-x plot:
-      - ORIGINAL curve
-      - TRIM curve
-      - ORIGINAL data dots
-      - highlight removed point(s)
-    """
-    X_orig = fit_results["X_orig"]
-    y_orig = fit_results["y_orig"]
-    removed_idx = fit_results["removed_idx"]
-    theta_orig = fit_results["theta_orig"]
-    theta_trim = fit_results["theta_trim"]
-
-    fig, ax = plt.subplots(figsize=figsize, dpi=dpi)
-    fig.text(0.02, 0.5, suptitle, va="center", rotation="vertical", fontsize=14)
-
-    x_min = max(float(np.min(X_orig)), 1e-8)
-    x_max = float(xmax)
-
-    ax.set_xlim(x_min, x_max)
-    ax.set_xlabel("x")
-    ax.set_ylabel("P(AE | x)")
-    ax.set_ylim(-0.10, 1.10)
-    ax.grid(alpha=0.35)
-
-    x_grid = np.exp(np.linspace(np.log(x_min), np.log(x_max), 900))
-    p_curve_orig = P_with(theta_orig, x_grid)
-    p_curve_trim = P_with(theta_trim, x_grid)
-
-    l1, = ax.plot(x_grid, p_curve_orig, lw=2.2, color="C0", label="ORIGINAL (Bayesian fit)")
-    l2, = ax.plot(x_grid, p_curve_trim, lw=2.2, color="C1", label="TRIM (Bayesian fit)")
-
-    rng = np.random.default_rng(999)
-    jit = (rng.random(len(y_orig)) - 0.5) * 0.06
-
-    d_nc = ax.scatter(
-        X_orig[y_orig == 0],
-        (y_orig + jit)[y_orig == 0],
-        s=22,
-        alpha=0.65,
-        edgecolors="none",
-        color="C0",
-        label="NC samples (ORIGINAL)",
-    )
-    d_ae = ax.scatter(
-        X_orig[y_orig == 1],
-        (y_orig + jit)[y_orig == 1],
-        s=26,
-        alpha=0.85,
-        edgecolors="none",
-        color="C1",
-        label="AE samples (ORIGINAL)",
-    )
-
-    dout = None
-    if removed_idx.size > 0:
-        for j, i in enumerate(removed_idx):
-            jit_out = (rng.random() - 0.5) * 0.06
-            label = "Removed point" if j == 0 else None
-            dout = ax.scatter(
-                [float(X_orig[i])],
-                [float(y_orig[i] + jit_out)],
-                marker="x",
-                s=90,
-                linewidths=2,
-                color="k",
-                label=label,
-            )
-
-    handles = [l1, l2, d_nc, d_ae]
-    if dout is not None:
-        handles.append(dout)
-    labels = [h.get_label() for h in handles]
-    ax.legend(handles, labels, frameon=False, ncol=2, loc="lower right")
-
-    plt.tight_layout(rect=(0.06, 0.0, 1.0, 1.0))
-    return fig, ax
-
-
-# ============================================================
-# 4) CI ESTIMATION
-# ============================================================
-
-def x_at_p(theta_hat, p_target=0.5, lo=1e-6, hi=10.0):
-    """
-    Solve P(AE|x) = p_target for x.
-    """
-    f = lambda x: P_with(theta_hat, x) - p_target
-    try:
-        if f(lo) * f(hi) > 0:
-            return np.nan
-        return float(brentq(f, lo, hi))
-    except Exception:
-        return np.nan
-
-
-def slope_at_x(theta_hat, x0):
-    """
-    Numerical derivative of P(AE|x) at x0.
-    """
-    if not np.isfinite(x0):
-        return np.nan
-    h = 1e-3 * (1 + abs(x0))
-    return float((P_with(theta_hat, x0 + h) - P_with(theta_hat, x0 - h)) / (2 * h))
-
-
-def hess_fd(F, x):
-    """
-    Finite-difference Hessian.
-    """
-    x = np.asarray(x, float)
-    n = x.size
-    H = np.zeros((n, n))
-    h = 1e-4 * (1 + np.abs(x))
-
-    def grad_fd(G, z):
-        g = np.zeros_like(z)
-        for j in range(n):
-            ej = np.zeros_like(z)
-            ej[j] = 1.0
-            g[j] = (G(z + h[j] * ej) - G(z - h[j] * ej)) / (2 * h[j])
-        return g
-
-    for i in range(n):
-        ei = np.zeros_like(x)
-        ei[i] = 1.0
-        g_plus = grad_fd(F, x + h[i] * ei)
-        g_minus = grad_fd(F, x - h[i] * ei)
-        H[:, i] = (g_plus - g_minus) / (2 * h[i])
-
-    return 0.5 * (H + H.T)
-
-
-def jac_fd(Fvec, w):
-    """
-    Finite-difference Jacobian for vector-valued function.
-    """
-    f0 = Fvec(w)
-    m = f0.size
-    n = w.size
-    J = np.zeros((m, n))
-    h = 1e-4 * (1 + np.abs(w))
-
-    for j in range(n):
-        ej = np.zeros_like(w)
-        ej[j] = 1.0
-        J[:, j] = (Fvec(w + h[j] * ej) - Fvec(w - h[j] * ej)) / (2 * h[j])
-
-    return J
-
-
-def estimate_ci_bundle(
-    X,
-    y,
-    label,
-    x_grid,
-    B_nonpar=400,
-    B_param=400,
-    seed=123,
-    use_prior_p=True,
-    prior_r=(1.05, 1.05),
-    tau=25.0,
-):
-    X = np.asarray(X, float)
-    y = np.asarray(y, int)
-    rng = np.random.default_rng(seed)
-    n = len(X)
-
-    theta_hat, res = fit_bayes(
-        X,
-        y,
-        seed=seed,
-        use_prior_p=use_prior_p,
-        prior_r=prior_r,
-        tau=tau,
-    )
-
-    pmap = P_with(theta_hat, x_grid)
-    x50 = x_at_p(theta_hat, 0.5, lo=max(1e-6, x_grid.min()), hi=x_grid.max())
-    s50 = slope_at_x(theta_hat, x50)
-
-    phi_hat = res.x
-    alpha, beta = make_priors(y, tau=tau)
-
-    H = hess_fd(
-        lambda w: neg_post(
-            w,
-            X,
-            y,
-            alpha,
-            beta,
-            use_prior_p=use_prior_p,
-            prior_r=prior_r,
-        ),
-        phi_hat,
-    )
-
-    Jp = jac_fd(lambda w: P_with(unpack(w), x_grid), phi_hat)
-
-    try:
-        Sigma_phi = np.linalg.inv(H)
-    except np.linalg.LinAlgError:
-        Sigma_phi = np.linalg.pinv(H)
-
-    var_p = np.einsum("ij,jk,ik->i", Jp, Sigma_phi, Jp)
-    se_p = np.sqrt(np.maximum(var_p, 0.0))
-    wald_lo = np.clip(pmap - 1.96 * se_p, 0, 1)
-    wald_hi = np.clip(pmap + 1.96 * se_p, 0, 1)
-
-    def theta_vec_from_phi(w):
-        p, a, b, s, k, th, thcap = unpack(w)
-        r = th / thcap if np.isfinite(thcap) and thcap > 0 else np.nan
-        return np.array([p, a, b, s, k, th, r], float)
-
-    Jtheta = jac_fd(theta_vec_from_phi, phi_hat)
-    Sigma_theta = Jtheta @ Sigma_phi @ Jtheta.T
-    theta_hat_vec = theta_vec_from_phi(phi_hat)
-    se_theta = np.sqrt(np.maximum(np.diag(Sigma_theta), 0.0))
-    wald_param_lo = theta_hat_vec - 1.96 * se_theta
-    wald_param_hi = theta_hat_vec + 1.96 * se_theta
-
-    curves_np = []
-    theta_np = []
-    x50_np = []
-    used_np = 0
-
-    for _ in range(B_nonpar):
-        idx = rng.integers(0, n, n)
-        Xb, yb = X[idx], y[idx]
-
-        if yb.sum() == 0 or yb.sum() == len(yb):
-            continue
-
-        try:
-            thb, rb = fit_bayes(
-                Xb,
-                yb,
-                seed=int(rng.integers(0, 10_000_000)),
-                use_prior_p=use_prior_p,
-                prior_r=prior_r,
-                tau=tau,
-            )
-            if not rb.success or not np.isfinite(rb.fun):
-                continue
-
-            curves_np.append(P_with(thb, x_grid))
-
-            p_b, a_b, b_b, s_b, k_b, th_b, thcap_b = thb
-            r_b = th_b / thcap_b if np.isfinite(thcap_b) and thcap_b > 0 else np.nan
-            theta_np.append([p_b, a_b, b_b, s_b, k_b, th_b, r_b])
-
-            x50_b = x_at_p(thb, 0.5, lo=max(1e-6, x_grid.min()), hi=x_grid.max())
-            x50_np.append(x50_b)
-
-            used_np += 1
-        except Exception:
-            continue
-
-    curves_np = np.asarray(curves_np)
-    theta_np = np.asarray(theta_np, float) if len(theta_np) else np.empty((0, 7))
-    x50_np = np.asarray(x50_np, float) if len(x50_np) else np.empty((0,))
-
-    np_lo = np.percentile(curves_np, 2.5, axis=0) if used_np else None
-    np_hi = np.percentile(curves_np, 97.5, axis=0) if used_np else None
-
-    curves_pb = []
-    theta_pb = []
-    x50_pb = []
-    used_pb = 0
-
-    p_hat, a_hat, b_hat, s_hat, k_hat, th_hat, _ = theta_hat
-
-    for _ in range(B_param):
-        yb = rng.binomial(1, p_hat, size=n)
-
-        if yb.sum() == 0 or yb.sum() == n:
-            continue
-
-        Xb = np.zeros(n, dtype=float)
-
-        idx_nc = np.where(yb == 0)[0]
-        idx_ae = np.where(yb == 1)[0]
-
-        if len(idx_nc) > 0:
-            Xb[idx_nc] = stats.gamma.rvs(
-                k_hat,
-                scale=th_hat,
-                size=len(idx_nc),
-                random_state=rng,
-            )
-
-        if len(idx_ae) > 0:
-            Xb[idx_ae] = stats.betaprime.rvs(
-                a_hat,
-                b_hat,
-                scale=s_hat,
-                size=len(idx_ae),
-                random_state=rng,
-            )
-
-        Xb = np.clip(Xb, 1e-12, None)
-
-        try:
-            thb, rb = fit_bayes(
-                Xb,
-                yb,
-                seed=int(rng.integers(0, 10_000_000)),
-                use_prior_p=use_prior_p,
-                prior_r=prior_r,
-                tau=tau,
-            )
-            if not rb.success or not np.isfinite(rb.fun):
-                continue
-
-            curves_pb.append(P_with(thb, x_grid))
-
-            p_b, a_b, b_b, s_b, k_b, th_b, thcap_b = thb
-            r_b = th_b / thcap_b if np.isfinite(thcap_b) and thcap_b > 0 else np.nan
-            theta_pb.append([p_b, a_b, b_b, s_b, k_b, th_b, r_b])
-
-            x50_b = x_at_p(thb, 0.5, lo=max(1e-6, x_grid.min()), hi=x_grid.max())
-            x50_pb.append(x50_b)
-
-            used_pb += 1
-        except Exception:
-            continue
-
-    curves_pb = np.asarray(curves_pb)
-    theta_pb = np.asarray(theta_pb, float) if len(theta_pb) else np.empty((0, 7))
-    x50_pb = np.asarray(x50_pb, float) if len(x50_pb) else np.empty((0,))
-
-    pb_lo = np.percentile(curves_pb, 2.5, axis=0) if used_pb else None
-    pb_hi = np.percentile(curves_pb, 97.5, axis=0) if used_pb else None
-
-    return {
-        "label": label,
-        "theta_hat": theta_hat,
-        "res": res,
-        "x50": x50,
-        "s50": s50,
-        "pmap": pmap,
-        "wald_lo": wald_lo,
-        "wald_hi": wald_hi,
-        "np_lo": np_lo,
-        "np_hi": np_hi,
-        "pb_lo": pb_lo,
-        "pb_hi": pb_hi,
-        "used_np": used_np,
-        "used_pb": used_pb,
-        "theta_hat_vec": theta_hat_vec,
-        "wald_param_lo": wald_param_lo,
-        "wald_param_hi": wald_param_hi,
-        "theta_np": theta_np,
-        "theta_pb": theta_pb,
-        "x50_np": x50_np,
-        "x50_pb": x50_pb,
-    }
-
-
-def run_bayesian_ci(
-    perc=95,
-    suv_path="suv_percentilesSLOthenUWM.mat",
-    flags_path="flags_combined.mat",
-    value_to_drop=2.48122597,
-    tol=1e-3,
-    xmax=10.0,
-    n_grid=600,
-    B_nonpar=400,
-    B_param=400,
-    seed=123,
-    use_prior_p=True,
-    prior_r=(1.05, 1.05),
-    tau=25.0,
-):
-    """
-    Run CI estimation for both ORIGINAL and TRIM datasets.
-    """
-    X_all, y_all = load_xy(perc=perc, suv_path=suv_path, flags_path=flags_path)
-    ds = make_trimmed_dataset(X_all, y_all, value_to_drop=value_to_drop, tol=tol)
-
-    x_grid = np.linspace(0, xmax, n_grid)
-
-    out_orig = estimate_ci_bundle(
-        ds["X_orig"],
-        ds["y_orig"],
-        label="ORIGINAL",
-        x_grid=x_grid,
-        B_nonpar=B_nonpar,
-        B_param=B_param,
-        seed=seed,
-        use_prior_p=use_prior_p,
-        prior_r=prior_r,
-        tau=tau,
-    )
-
-    out_trim = estimate_ci_bundle(
-        ds["X_trim"],
-        ds["y_trim"],
-        label="TRIM",
-        x_grid=x_grid,
-        B_nonpar=B_nonpar,
-        B_param=B_param,
-        seed=seed + 1,
-        use_prior_p=use_prior_p,
-        prior_r=prior_r,
-        tau=tau,
-    )
-
-    return {
-        **ds,
-        "x_grid": x_grid,
-        "orig": out_orig,
-        "trim": out_trim,
-    }
-
-
-def make_param_ci_table(ci_res):
-    """
-    Parameter CI table for FULL and TRIM, for Wald / Nonparam / Parametric.
-    """
-    rows = []
-    names = ["p", "a", "b", "s", "k", "theta", "r"]
-
-    for dataset_key, dataset_name in [("orig", "FULL"), ("trim", "TRIM")]:
-        out = ci_res[dataset_key]
-        hat = out["theta_hat_vec"]
-
-        for i, name in enumerate(names):
-            rows.append(
-                {
-                    "Dataset": dataset_name,
-                    "Method": "Wald",
-                    "Parameter": name,
-                    "Estimate": hat[i],
-                    "LL": out["wald_param_lo"][i],
-                    "UL": out["wald_param_hi"][i],
-                }
-            )
-
-        if out["theta_np"].shape[0] > 0:
-            lo = np.nanpercentile(out["theta_np"], 2.5, axis=0)
-            hi = np.nanpercentile(out["theta_np"], 97.5, axis=0)
-            for i, name in enumerate(names):
-                rows.append(
-                    {
-                        "Dataset": dataset_name,
-                        "Method": "Nonparam",
-                        "Parameter": name,
-                        "Estimate": hat[i],
-                        "LL": lo[i],
-                        "UL": hi[i],
-                    }
-                )
-
-        if out["theta_pb"].shape[0] > 0:
-            lo = np.nanpercentile(out["theta_pb"], 2.5, axis=0)
-            hi = np.nanpercentile(out["theta_pb"], 97.5, axis=0)
-            for i, name in enumerate(names):
-                rows.append(
-                    {
-                        "Dataset": dataset_name,
-                        "Method": "Parametric",
-                        "Parameter": name,
-                        "Estimate": hat[i],
-                        "LL": lo[i],
-                        "UL": hi[i],
-                    }
-                )
-
-    return pd.DataFrame(rows)
-
-
-def make_x50_ci_table(ci_res):
-    """
-    x50 CI table for FULL and TRIM, for Wald / Nonparam / Parametric.
-    """
-    rows = []
-
-    for dataset_key, dataset_name in [("orig", "FULL"), ("trim", "TRIM")]:
-        out = ci_res[dataset_key]
-
-        wald_x50_lo = np.nan
-        wald_x50_hi = np.nan
-        try:
-            wald_x50_lo = np.interp(0.5, out["wald_lo"], ci_res["x_grid"])
-            wald_x50_hi = np.interp(0.5, out["wald_hi"], ci_res["x_grid"])
-        except Exception:
-            pass
-
-        rows.append(
-            {
-                "Dataset": dataset_name,
-                "Method": "Wald",
-                "Estimate": out["x50"],
-                "LL": wald_x50_lo,
-                "UL": wald_x50_hi,
-            }
-        )
-
-        if len(out["x50_np"]) > 0:
-            rows.append(
-                {
-                    "Dataset": dataset_name,
-                    "Method": "Nonparam",
-                    "Estimate": out["x50"],
-                    "LL": np.nanpercentile(out["x50_np"], 2.5),
-                    "UL": np.nanpercentile(out["x50_np"], 97.5),
-                }
-            )
-
-        if len(out["x50_pb"]) > 0:
-            rows.append(
-                {
-                    "Dataset": dataset_name,
-                    "Method": "Parametric",
-                    "Estimate": out["x50"],
-                    "LL": np.nanpercentile(out["x50_pb"], 2.5),
-                    "UL": np.nanpercentile(out["x50_pb"], 97.5),
-                }
-            )
-
-    return pd.DataFrame(rows)
-
-
-def make_curve_ci_table(ci_res, grid_every=25):
-    """
-    Long-format curve CI table.
-    Contains LL/UL of P(AE|X) across x-grid for all methods.
-    """
-    rows = []
-    x_grid = ci_res["x_grid"][::grid_every]
-
-    for dataset_key, dataset_name in [("orig", "FULL"), ("trim", "TRIM")]:
-        out = ci_res[dataset_key]
-
-        for method, lo_key, hi_key in [
-            ("Wald", "wald_lo", "wald_hi"),
-            ("Nonparam", "np_lo", "np_hi"),
-            ("Parametric", "pb_lo", "pb_hi"),
-        ]:
-            lo = out.get(lo_key, None)
-            hi = out.get(hi_key, None)
-            if lo is None or hi is None:
-                continue
-
-            lo = lo[::grid_every]
-            hi = hi[::grid_every]
-            est = out["pmap"][::grid_every]
-
-            for x, e, l, u in zip(x_grid, est, lo, hi):
-                rows.append(
-                    {
-                        "Dataset": dataset_name,
-                        "Method": method,
-                        "X": x,
-                        "Estimate": e,
-                        "LL": l,
-                        "UL": u,
-                    }
-                )
-
-    return pd.DataFrame(rows)
-
-
-def plot_ci_original_trim(ci_res, xmax=6.0):
-    """
-    2-panel figure:
-      left  = FULL
-      right = TRIM
-    """
-    x_grid = ci_res["x_grid"]
-    rng = np.random.default_rng(999)
-
-    fig, axes = plt.subplots(1, 2, figsize=(16, 7.0), dpi=150, sharey=True)
-
-    for ax, X, y, out, title, panel in [
-        (axes[0], ci_res["X_orig"], ci_res["y_orig"], ci_res["orig"], "FULL", "A"),
-        (axes[1], ci_res["X_trim"], ci_res["y_trim"], ci_res["trim"], "TRIM", "B"),
-    ]:
-        ax.fill_between(x_grid, out["wald_lo"], out["wald_hi"], color="#2ca02c", alpha=0.10)
-
-        if out["used_np"]:
-            ax.fill_between(x_grid, out["np_lo"], out["np_hi"], color="#17becf", alpha=0.10)
-
-        if out["used_pb"]:
-            ax.fill_between(x_grid, out["pb_lo"], out["pb_hi"], color="#e91e63", alpha=0.10)
-
-        ax.plot(x_grid, out["wald_lo"], color="#2ca02c", lw=1.6, ls="--")
-        h_wald, = ax.plot(
-            x_grid,
-            out["wald_hi"],
-            color="#2ca02c",
-            lw=1.6,
-            ls="--",
-            label="CI: Wald (delta) 95%",
-        )
-
-        h_np = None
-        if out["used_np"]:
-            ax.plot(x_grid, out["np_lo"], color="#17becf", lw=1.6, ls=(0, (1, 2)))
-            h_np, = ax.plot(
-                x_grid,
-                out["np_hi"],
-                color="#17becf",
-                lw=1.6,
-                ls=(0, (1, 2)),
-                label="CI: Nonparam bootstrap 95%",
-            )
-
-        h_pb = None
-        if out["used_pb"]:
-            ax.plot(x_grid, out["pb_lo"], color="#e91e63", lw=1.6, ls="-.")
-            h_pb, = ax.plot(
-                x_grid,
-                out["pb_hi"],
-                color="#e91e63",
-                lw=1.6,
-                ls="-.",
-                label="CI: Parametric bootstrap 95%",
-            )
-
-        h_fit, = ax.plot(x_grid, out["pmap"], color="k", lw=2.4, label="Bayesian fit")
-
-        jit = (rng.random(len(y)) - 0.5) * 0.035
-
-        h_nc = ax.scatter(
-            X[y == 0],
-            (y + jit)[y == 0],
-            s=18,
-            alpha=0.55,
-            color="#5dade2",
-            edgecolors="none",
-            label="NC",
-        )
-
-        h_ae = ax.scatter(
-            X[y == 1],
-            (y + jit)[y == 1],
-            s=24,
-            alpha=0.80,
-            color="#f39c3d",
-            edgecolors="none",
-            label="AE",
-        )
-
-        ax.text(
-            0.02,
-            0.98,
-            panel,
-            transform=ax.transAxes,
-            ha="left",
-            va="top",
-            fontsize=16,
-            fontweight="bold",
-        )
-
-        ax.set_xlim(0, xmax)
-        ax.set_ylim(-0.05, 1.05)
-        ax.set_xlabel("X", fontsize=13, fontweight="bold")
-        ax.set_title(title, fontsize=13, fontweight="bold")
-        ax.grid(alpha=0.25)
-
-        handles = [h_nc, h_ae, h_fit, h_wald]
-        if h_np is not None:
-            handles.append(h_np)
-        if h_pb is not None:
-            handles.append(h_pb)
-
-        labels = [h.get_label() for h in handles]
-
-        ax.legend(
-            handles,
-            labels,
-            loc="upper center",
-            bbox_to_anchor=(0.5, -0.20),
-            ncol=2,
-            frameon=False,
-            fontsize=10,
-        )
-
-    axes[0].set_ylabel("P(AE | X)", fontsize=13, fontweight="bold")
-    plt.tight_layout(rect=(0, 0.08, 1, 1))
-    return fig, axes
-
-
-# ============================================================
-# 5) X50 ELASTICITY ANALYSIS
-# ============================================================
-
-PARAM_NAMES_X50_ELAS = [r"$\pi$", r"$a$", r"$b$", r"$s$", r"$k$", r"$\vartheta$"]
-
-
-def theta6_from_hat(theta_hat):
-    """
-    Extract the first 6 raw model parameters from theta_hat:
-      (p, a, b, s, k, th)
-    """
-    th = np.asarray(theta_hat, float).ravel()
-    if th.size < 6:
-        raise ValueError(f"Expected at least 6 parameters, got {th.size}")
-    return th[:6].copy()
-
-
-def step_vec_theta(theta, rel_step=1e-6, abs_min=1e-10):
-    """
-    Relative finite-difference step on raw theta scale.
-    """
-    theta = np.asarray(theta, float).ravel()
-    return np.maximum(abs_min, rel_step * np.maximum(1.0, np.abs(theta)))
-
-
-def grad_central_theta(F_theta, theta0, rel_step=1e-6, abs_min=1e-10, pi_eps=1e-12):
-    """
-    Central differences in RAW theta.
-    Keeps:
-      - p in (pi_eps, 1-pi_eps)
-      - positive parameters > 0
-    """
-    theta0 = np.asarray(theta0, float).ravel()
-    h = step_vec_theta(theta0, rel_step=rel_step, abs_min=abs_min)
-    g = np.zeros_like(theta0)
-
-    for j in range(theta0.size):
-        th_plus = theta0.copy()
-        th_minus = theta0.copy()
-        hj = h[j]
-
-        if j == 0:
-            p0 = float(np.clip(theta0[0], pi_eps, 1 - pi_eps))
-            hj = min(hj, p0 - pi_eps, (1 - pi_eps) - p0)
-            hj = max(hj, abs_min)
-            th_plus[0] = np.clip(p0 + hj, pi_eps, 1 - pi_eps)
-            th_minus[0] = np.clip(p0 - hj, pi_eps, 1 - pi_eps)
-        else:
-            q0 = float(max(theta0[j], 1e-15))
-            hj = min(hj, 0.5 * q0)
-            hj = max(hj, abs_min)
-            th_plus[j] = q0 + hj
-            th_minus[j] = max(q0 - hj, 1e-15)
-
-        g[j] = (F_theta(th_plus) - F_theta(th_minus)) / (2.0 * hj)
-
-    return g
-
-
-def P_with_theta6(theta6, x):
-    """
-    Same posterior risk curve as P_with(), but accepts only the 6 raw parameters:
-    (p, a, b, s, k, th)
-    """
-    p, a, b, s, k, th = np.asarray(theta6, float).ravel()[:6]
-    x = np.asarray(x, float)
-    eps = 1e-12
-
-    logit_val = (
-        np.log(np.clip(p, eps, 1 - eps))
-        - np.log(np.clip(1 - p, eps, 1.0))
-        + dE_full(x, a, b, s, k, th)
-    )
-    return logistic(logit_val)
-
-
-def x50_theta6(theta6, lo=1e-6, hi=6.0, hi_max=100.0):
-    """
-    Solve P(AE|x) = 0.5 using theta6 = (p, a, b, s, k, th),
-    with adaptive bracketing.
-    """
-    f = lambda x: P_with_theta6(theta6, x) - 0.5
-
-    fa = f(lo)
-    fb = f(hi)
-
-    while np.isfinite(fa) and np.isfinite(fb) and fa * fb > 0 and hi < hi_max:
-        hi *= 2.0
-        fb = f(hi)
-
-    if (not np.isfinite(fa)) or (not np.isfinite(fb)) or fa * fb > 0:
-        return np.nan
-
-    try:
-        return float(brentq(f, lo, hi))
-    except Exception:
-        return np.nan
-
-
-def compute_x50_elasticity_rawtheta(
-    theta0,
-    x50_fun=x50_theta6,
-    rel_step=1e-6,
-    abs_min=1e-10,
-    pi_eps=1e-12,
-):
-    """
-    x50 elasticity on RAW theta scale:
-
-      E_x50_j = | (theta_j / x50) * d x50 / d theta_j |
-
-    where theta0 = [p, a, b, s, k, th]
-    """
-    theta0 = np.asarray(theta0, float).ravel()
-    if theta0.size != 6:
-        raise ValueError(f"Expected theta0 of length 6, got {theta0.size}")
-
-    x50_0 = float(x50_fun(theta0))
-
-    d_x_dth = grad_central_theta(
-        x50_fun, theta0, rel_step=rel_step, abs_min=abs_min, pi_eps=pi_eps
-    )
-
-    eps = 1e-12
-    x_safe = max(abs(x50_0), eps)
-
-    th_safe = theta0.copy()
-    th_safe[0] = float(np.clip(th_safe[0], pi_eps, 1 - pi_eps))
-    th_safe[1:] = np.maximum(th_safe[1:], 1e-15)
-
-    elas_x = np.abs(d_x_dth) * np.abs(th_safe) / x_safe
-
-    return {
-        "theta0": theta0,
-        "x50": x50_0,
-        "d_x_dtheta": d_x_dth,
-        "elas_x50": elas_x,
-        "param_names": PARAM_NAMES_X50_ELAS,
-    }
-
-
-def run_x50_elasticity_from_fit_results(
-    fit_results,
-    rel_step=1e-6,
-    abs_min=1e-10,
-    pi_eps=1e-12,
-):
-    """
-    Compute x50 elasticity for FULL (orig) and TRIM directly from fit_results.
-    """
-    elas_orig = compute_x50_elasticity_rawtheta(
-        theta6_from_hat(fit_results["theta_orig"]),
-        x50_fun=x50_theta6,
-        rel_step=rel_step,
-        abs_min=abs_min,
-        pi_eps=pi_eps,
-    )
-
-    elas_trim = compute_x50_elasticity_rawtheta(
-        theta6_from_hat(fit_results["theta_trim"]),
-        x50_fun=x50_theta6,
-        rel_step=rel_step,
-        abs_min=abs_min,
-        pi_eps=pi_eps,
-    )
-
-    return {
-        "orig": elas_orig,
-        "trim": elas_trim,
-    }
-
-
-def make_x50_elasticity_table(elas_res, dataset_name="FULL"):
-    """
-    Tidy x50 elasticity table.
-    """
-    rows = []
-    for name, ex in zip(
-        elas_res["param_names"],
-        elas_res["elas_x50"],
-    ):
-        rows.append(
-            {
-                "Dataset": dataset_name,
-                "Parameter": name,
-                "Elasticity_x50": float(ex),
-            }
-        )
-    return pd.DataFrame(rows)
-
-
-def plot_x50_elasticity_bars(elas_full, elas_trim, figsize=(7, 5), dpi=150):
-    """
-    One-panel bar plot for x50 elasticity.
-    """
-    names = elas_full["param_names"]
-    x = np.arange(len(names))
-    width = 0.36
-
-    fig, ax = plt.subplots(figsize=figsize, dpi=dpi)
-
-    ax.bar(
-        x - width / 2,
-        elas_full["elas_x50"],
-        width=width,
-        label="FULL",
-        alpha=0.85,
-    )
-    ax.bar(
-        x + width / 2,
-        elas_trim["elas_x50"],
-        width=width,
-        label="TRIM",
-        alpha=0.85,
-    )
-
-    ax.set_xticks(x)
-    ax.set_xticklabels(names)
-    ax.set_ylabel("Elasticity", fontweight="bold")
-    ax.set_title("Elasticity of x50", fontweight="bold")
-    ax.grid(axis="y", alpha=0.25)
-    ax.legend(frameon=False)
-
-    plt.tight_layout()
-    return fig, ax

+ 0 - 402
bayesian_noise.py

@@ -1,402 +0,0 @@
-# bayesian_noise.py
-# ============================================================
-# Bayesian noise propagation on RAW X
-# Reference location and Δ widths are evaluated at exact clean-fit x50
-# Function-only module for notebook use
-# ============================================================
-
-import numpy as np
-import matplotlib.pyplot as plt
-from scipy.optimize import brentq
-
-from bayesian import load_xy, fit_bayes, P_with, make_trimmed_dataset
-
-# ---------------- Defaults ----------------
-XMAX = 5.0
-GRID_N = 1000
-
-SIGMA_MULT = 0.129
-SIGMA_ADD = 0.144
-
-N_REFIT = 150
-N_TTA = 300
-SEED = 1234
-
-CI_LEVEL = 0.95
-ALPHA = 1.0 - CI_LEVEL
-Q_LO, Q_MD, Q_HI = ALPHA / 2.0, 0.5, 1.0 - ALPHA / 2.0
-
-USE_PRIOR_P = True
-PRIOR_R = (1.05, 1.05)
-TAU = 25.0
-
-plt.rcParams["legend.frameon"] = False
-plt.rcParams["axes.titleweight"] = "bold"
-plt.rcParams["axes.labelweight"] = "bold"
-
-
-# ============================================================
-# 1) DATA
-# ============================================================
-
-def load_original(
-    perc=95,
-    suv_path="suv_percentilesSLOthenUWM.mat",
-    flags_path="flags_combined.mat",
-):
-    return load_xy(perc=perc, suv_path=suv_path, flags_path=flags_path)
-
-
-def load_trimmed(
-    perc=95,
-    suv_path="suv_percentilesSLOthenUWM.mat",
-    flags_path="flags_combined.mat",
-    value_to_drop=2.48122597,
-    tol=1e-3,
-):
-    X, y = load_xy(perc=perc, suv_path=suv_path, flags_path=flags_path)
-    ds = make_trimmed_dataset(X, y, value_to_drop=value_to_drop, tol=tol)
-    return ds["X_trim"], ds["y_trim"]
-
-
-# ============================================================
-# 2) FIT + X50
-# ============================================================
-
-def fit_once(X, y, rng, use_prior_p=USE_PRIOR_P, prior_r=PRIOR_R, tau=TAU):
-    theta, res = fit_bayes(
-        X,
-        y,
-        seed=int(rng.integers(0, 10_000_000)),
-        use_prior_p=use_prior_p,
-        prior_r=prior_r,
-        tau=tau,
-    )
-    return theta, res
-
-
-def x_at_p(theta_hat, p_target=0.5, lo=1e-6, hi=6.0, hi_max=100.0):
-    """
-    Exact root solve for P(AE|x)=p_target.
-    """
-    f = lambda x: P_with(theta_hat, x) - p_target
-    fa, fb = f(lo), f(hi)
-
-    while np.isfinite(fa) and np.isfinite(fb) and fa * fb > 0 and hi < hi_max:
-        hi *= 2.0
-        fb = f(hi)
-
-    if (not np.isfinite(fa)) or (not np.isfinite(fb)) or fa * fb > 0:
-        return np.nan
-
-    try:
-        return float(brentq(f, lo, hi))
-    except Exception:
-        return np.nan
-
-
-# ============================================================
-# 3) NOISE
-# ============================================================
-
-def add_noise_mult(X, sigma, rng):
-    X = np.asarray(X, float)
-    return np.clip(X * np.exp(rng.normal(0, sigma, size=X.shape)), 1e-12, None)
-
-
-def add_noise_add(X, sigma, rng):
-    X = np.asarray(X, float)
-    return np.clip(X + rng.normal(0, sigma, size=X.shape), 1e-12, None)
-
-
-# ============================================================
-# 4) BAND HELPERS
-# ============================================================
-
-def monotone_nondec(y):
-    y = np.asarray(y, float)
-    return np.maximum.accumulate(np.clip(y, 0, 1))
-
-
-def band_quantiles(curves, q_lo=Q_LO, q_md=Q_MD, q_hi=Q_HI):
-    C = np.vstack(curves)
-    ql = monotone_nondec(np.quantile(C, q_lo, axis=0))
-    qm = monotone_nondec(np.quantile(C, q_md, axis=0))
-    qh = monotone_nondec(np.quantile(C, q_hi, axis=0))
-    return ql, qm, qh
-
-
-def delta_width_at_x(lo, hi, xc, x0):
-    if not np.isfinite(x0):
-        return np.nan
-    lo_x = float(np.interp(x0, xc, lo))
-    hi_x = float(np.interp(x0, xc, hi))
-    return hi_x - lo_x
-
-
-# ============================================================
-# 5) CORE ANALYSIS
-# ============================================================
-
-def build_bands_for_dataset(
-    X,
-    y,
-    sigma_mult=SIGMA_MULT,
-    sigma_add=SIGMA_ADD,
-    x_max=XMAX,
-    grid_n=GRID_N,
-    n_refit=N_REFIT,
-    n_tta=N_TTA,
-    seed=SEED,
-    use_prior_p=USE_PRIOR_P,
-    prior_r=PRIOR_R,
-    tau=TAU,
-):
-    rng = np.random.default_rng(seed)
-    xc = np.linspace(1e-12, x_max, grid_n)
-
-    theta_clean, res_clean = fit_once(
-        X, y, rng,
-        use_prior_p=use_prior_p,
-        prior_r=prior_r,
-        tau=tau,
-    )
-    clean_curve = P_with(theta_clean, xc)
-    x50 = x_at_p(theta_clean, p_target=0.5, lo=1e-6, hi=max(6.0, x_max))
-
-    # multiplicative: refit
-    curves_refit_m = []
-    for _ in range(n_refit):
-        Xn = add_noise_mult(X, sigma_mult, rng)
-        thetab, resb = fit_once(Xn, y, rng, use_prior_p=use_prior_p, prior_r=prior_r, tau=tau)
-        if resb.success and np.isfinite(resb.fun):
-            curves_refit_m.append(P_with(thetab, xc))
-    if not curves_refit_m:
-        raise RuntimeError("No successful multiplicative-refit curves.")
-    lo_rm, md_rm, hi_rm = band_quantiles(curves_refit_m)
-
-    # multiplicative: TTA
-    curves_tta_m = []
-    for _ in range(n_tta):
-        xc_n = np.clip(xc * np.exp(rng.normal(0, sigma_mult, size=xc.size)), 1e-12, None)
-        curves_tta_m.append(P_with(theta_clean, xc_n))
-    lo_tm, md_tm, hi_tm = band_quantiles(curves_tta_m)
-
-    # additive: refit
-    curves_refit_a = []
-    for _ in range(n_refit):
-        Xn = add_noise_add(X, sigma_add, rng)
-        thetab, resb = fit_once(Xn, y, rng, use_prior_p=use_prior_p, prior_r=prior_r, tau=tau)
-        if resb.success and np.isfinite(resb.fun):
-            curves_refit_a.append(P_with(thetab, xc))
-    if not curves_refit_a:
-        raise RuntimeError("No successful additive-refit curves.")
-    lo_ra, md_ra, hi_ra = band_quantiles(curves_refit_a)
-
-    # additive: TTA
-    curves_tta_a = []
-    for _ in range(n_tta):
-        xc_n = np.clip(xc + rng.normal(0, sigma_add, size=xc.size), 1e-12, None)
-        curves_tta_a.append(P_with(theta_clean, xc_n))
-    lo_ta, md_ta, hi_ta = band_quantiles(curves_tta_a)
-
-    return {
-        "xc": xc,
-        "theta_clean": theta_clean,
-        "fit_success": bool(res_clean.success),
-        "clean_curve": clean_curve,
-        "x50": x50,
-        "mult": {
-            "sigma": sigma_mult,
-            "refit": (lo_rm, md_rm, hi_rm),
-            "tta": (lo_tm, md_tm, hi_tm),
-            "D_refit": delta_width_at_x(lo_rm, hi_rm, xc, x50),
-            "D_tta": delta_width_at_x(lo_tm, hi_tm, xc, x50),
-            "n_refit_success": len(curves_refit_m),
-            "n_tta": len(curves_tta_m),
-        },
-        "add": {
-            "sigma": sigma_add,
-            "refit": (lo_ra, md_ra, hi_ra),
-            "tta": (lo_ta, md_ta, hi_ta),
-            "D_refit": delta_width_at_x(lo_ra, hi_ra, xc, x50),
-            "D_tta": delta_width_at_x(lo_ta, hi_ta, xc, x50),
-            "n_refit_success": len(curves_refit_a),
-            "n_tta": len(curves_tta_a),
-        },
-    }
-
-
-def run_noise_analysis(
-    perc=95,
-    suv_path="suv_percentilesSLOthenUWM.mat",
-    flags_path="flags_combined.mat",
-    value_to_drop=2.48122597,
-    tol=1e-3,
-    sigma_mult=SIGMA_MULT,
-    sigma_add=SIGMA_ADD,
-    x_max=XMAX,
-    grid_n=GRID_N,
-    n_refit=N_REFIT,
-    n_tta=N_TTA,
-    seed=SEED,
-    use_prior_p=USE_PRIOR_P,
-    prior_r=PRIOR_R,
-    tau=TAU,
-):
-    X_full, y_full = load_original(
-        perc=perc, suv_path=suv_path, flags_path=flags_path
-    )
-    X_trim, y_trim = load_trimmed(
-        perc=perc, suv_path=suv_path, flags_path=flags_path,
-        value_to_drop=value_to_drop, tol=tol
-    )
-
-    full_res = build_bands_for_dataset(
-        X_full, y_full,
-        sigma_mult=sigma_mult, sigma_add=sigma_add,
-        x_max=x_max, grid_n=grid_n,
-        n_refit=n_refit, n_tta=n_tta,
-        seed=seed,
-        use_prior_p=use_prior_p, prior_r=prior_r, tau=tau,
-    )
-    trim_res = build_bands_for_dataset(
-        X_trim, y_trim,
-        sigma_mult=sigma_mult, sigma_add=sigma_add,
-        x_max=x_max, grid_n=grid_n,
-        n_refit=n_refit, n_tta=n_tta,
-        seed=seed + 100,
-        use_prior_p=use_prior_p, prior_r=prior_r, tau=tau,
-    )
-
-    return {"full": full_res, "trim": trim_res}
-
-
-# ============================================================
-# 6) SUMMARY TABLE
-# ============================================================
-
-def make_noise_summary_table(noise_res):
-    rows = []
-    for dataset_name, block in [("FULL", noise_res["full"]), ("TRIM", noise_res["trim"])]:
-        for noise_name, key in [("multiplicative", "mult"), ("additive", "add")]:
-            rows.append({
-                "Dataset": dataset_name,
-                "NoiseType": noise_name,
-                "Sigma": float(block[key]["sigma"]),
-                "x50": float(block["x50"]),
-                "Delta_refit_at_x50": float(block[key]["D_refit"]),
-                "Delta_tta_at_x50": float(block[key]["D_tta"]),
-                "N_refit_success": int(block[key]["n_refit_success"]),
-                "N_tta": int(block[key]["n_tta"]),
-            })
-    import pandas as pd
-    return pd.DataFrame(rows)
-
-
-# ============================================================
-# 7) PLOTTING
-# ============================================================
-
-def plot_4panels(
-    full_res,
-    trim_res,
-    save_prefix="noise_cb_raw_4panels_sigma129_0144_x50",
-    x_max=XMAX,
-    sigma_mult=SIGMA_MULT,
-    sigma_add=SIGMA_ADD,
-):
-    fig, axs = plt.subplots(2, 2, figsize=(12.5, 7.5), dpi=160, sharex=True, sharey=True)
-
-    COL = {"mult": "#1f78b4", "add": "#ff7f00"}
-    ALP = {"refit": 0.25, "tta": 0.12}
-
-    def draw_panel(ax, res, mode, letter, dataset_label):
-        xc = res["xc"]
-        clean = res["clean_curve"]
-        x50 = float(res["x50"])
-
-        lo_r, _, hi_r = res[mode]["refit"]
-        lo_t, _, hi_t = res[mode]["tta"]
-        Dref = res[mode]["D_refit"]
-        Dtta = res[mode]["D_tta"]
-
-        ax.plot(xc, clean, color="k", lw=2.6, zorder=3)
-        ax.fill_between(xc, lo_r, hi_r, color=COL[mode], alpha=ALP["refit"], zorder=1)
-        ax.fill_between(xc, lo_t, hi_t, color=COL[mode], alpha=ALP["tta"], zorder=0)
-
-        # exact x50 reference
-        if np.isfinite(x50):
-            ax.axvline(x50, color="#666", ls="--", lw=1.2, alpha=0.9, zorder=4)
-
-            # vertical band-width markers at x50
-            lo_r_x = float(np.interp(x50, xc, lo_r))
-            hi_r_x = float(np.interp(x50, xc, hi_r))
-            lo_t_x = float(np.interp(x50, xc, lo_t))
-            hi_t_x = float(np.interp(x50, xc, hi_t))
-
-            ax.plot([x50, x50], [lo_r_x, hi_r_x], color=COL[mode], lw=2.2, alpha=0.95, zorder=6)
-            ax.scatter([x50, x50], [lo_r_x, hi_r_x], color=COL[mode], s=18, alpha=0.95, zorder=7)
-
-            ax.plot([x50, x50], [lo_t_x, hi_t_x], color=COL[mode], lw=2.2, alpha=0.45, zorder=5)
-            ax.scatter([x50, x50], [lo_t_x, hi_t_x], color=COL[mode], s=18, alpha=0.45, zorder=6)
-
-        ax.set_title(letter, fontsize=14, fontweight="bold", pad=8)
-
-        ax.text(
-            0.02, 0.96, dataset_label,
-            transform=ax.transAxes, ha="left", va="top",
-            fontsize=10, color="#111"
-        )
-        ax.text(
-            0.02, 0.88, f"x50={x50:.2f}",
-            transform=ax.transAxes, ha="left", va="top",
-            fontsize=10, color="#111"
-        )
-        ax.text(
-            0.03, 0.10, f"Δr@x50={Dref:.2f}  Δt@x50={Dtta:.2f}",
-            transform=ax.transAxes, ha="left", va="center", fontsize=9,
-            bbox=dict(
-                facecolor="white",
-                edgecolor=COL[mode],
-                boxstyle="round,pad=0.25,rounding_size=0.02",
-                lw=0.9, alpha=0.95
-            )
-        )
-
-        ax.set_xlim(0, x_max)
-        ax.set_ylim(-0.05, 1.05)
-        ax.grid(alpha=0.25)
-
-    draw_panel(axs[0, 0], full_res, "mult", "A", "FULL (F)")
-    draw_panel(axs[0, 1], full_res, "add",  "B", "FULL (F)")
-    draw_panel(axs[1, 0], trim_res, "mult", "C", "TRIM (T)")
-    draw_panel(axs[1, 1], trim_res, "add",  "D", "TRIM (T)")
-
-    axs[1, 0].set_xlabel("X")
-    axs[1, 1].set_xlabel("X")
-    axs[0, 0].set_ylabel("P(AE | x)")
-    axs[1, 0].set_ylabel("P(AE | x)")
-
-    handles = [
-        plt.Line2D([0], [0], color="k", lw=2.6, label="clean Bayesian fit"),
-        plt.Rectangle((0, 0), 1, 1, facecolor=COL["mult"], alpha=ALP["refit"],
-                      label=f"refit band, mult σ={sigma_mult:.3f}"),
-        plt.Rectangle((0, 0), 1, 1, facecolor=COL["mult"], alpha=ALP["tta"],
-                      label=f"TTA band, mult σ={sigma_mult:.3f}"),
-        plt.Rectangle((0, 0), 1, 1, facecolor=COL["add"], alpha=ALP["refit"],
-                      label=f"refit band, add σ={sigma_add:.3f}"),
-        plt.Rectangle((0, 0), 1, 1, facecolor=COL["add"], alpha=ALP["tta"],
-                      label=f"TTA band, add σ={sigma_add:.3f}"),
-        plt.Line2D([0], [0], color="#666", lw=1.2, ls="--", label="x50"),
-    ]
-    fig.legend(handles, [h.get_label() for h in handles],
-               loc="lower center", ncol=3, fontsize=10)
-
-    plt.tight_layout(rect=[0, 0.08, 1, 1])
-
-    if save_prefix is not None:
-        fig.savefig(f"{save_prefix}.png", dpi=300, bbox_inches="tight")
-        fig.savefig(f"{save_prefix}.pdf", bbox_inches="tight")
-
-    return fig, axs

+ 0 - 139
bayesianconstraints.py

@@ -1,139 +0,0 @@
-# bayesianconstraints.py
-import numpy as np
-import pandas as pd
-import matplotlib.pyplot as plt
-
-
-def logistic(z):
-    z = np.clip(z, -60, 60)
-    return 1.0 / (1.0 + np.exp(-z))
-
-
-def logit(p):
-    p = np.clip(p, 1e-12, 1 - 1e-12)
-    return np.log(p) - np.log(1 - p)
-
-
-def dE_gamma(x, a, b, k, theta, s=1.0):
-    x = np.asarray(x, float)
-    return (a - k) * np.log(x) - (a + b) * np.log1p(x / s) + x / theta
-
-
-def dE_lognorm(x, a, b, mu, sigma, s=1.0):
-    x = np.asarray(x, float)
-    return ((mu - np.log(x)) ** 2) / (2.0 * sigma ** 2) + a * np.log(x) - (a + b) * np.log1p(x / s)
-
-
-def check_gamma_constraints(a, b, k, theta, s):
-    positivity = (a > 0) and (b > 0) and (k > 0) and (theta > 0) and (s > 0)
-
-    if not positivity:
-        status = "FAIL"
-        note = "all parameters must be > 0"
-    elif a > k:
-        status = "MEET"
-        note = "a > k"
-    elif a == k:
-        status = "EDGE"
-        note = "a = k"
-    else:
-        status = "FAIL"
-        note = "a < k"
-
-    return {
-        "model": "BetaPrime vs Gamma",
-        "a": a,
-        "b": b,
-        "k": k,
-        "theta": theta,
-        "s": s,
-        "all_positive": positivity,
-        "a_ge_k": positivity and (a >= k),
-        "status": status,
-        "note": note,
-    }
-
-
-def check_lognorm_constraints(a, b, mu, sigma, s):
-    positivity = (a > 0) and (b > 0) and (sigma > 0) and (s > 0)
-
-    if not positivity:
-        status = "FAIL"
-        note = "a,b,sigma,s must be > 0"
-    else:
-        status = "FAIL"
-        note = "left tail goes to 1, not 0"
-
-    return {
-        "model": "BetaPrime vs LogNormal",
-        "a": a,
-        "b": b,
-        "mu": mu,
-        "sigma": sigma,
-        "s": s,
-        "all_positive": positivity,
-        "status": status,
-        "note": note,
-    }
-
-
-def make_gamma_constraint_table(param_list):
-    return pd.DataFrame([check_gamma_constraints(**p) for p in param_list])
-
-
-def make_lognorm_constraint_table(param_list):
-    return pd.DataFrame([check_lognorm_constraints(**p) for p in param_list])
-
-
-def plot_gamma_constraint_curves(param_meet, param_edge_fail, p_prior=5/58,
-                                 x=None, figsize=(10, 6)):
-    if x is None:
-        x = np.logspace(-12, 3, 900)
-
-    c0 = logit(p_prior)
-    fig, ax = plt.subplots(figsize=figsize)
-
-    for P in param_meet:
-        p = logistic(c0 + dE_gamma(x, **P))
-        label = f"MEET (a={P['a']}, b={P['b']}, k={P['k']}, θ={P['theta']}, s={P['s']})"
-        ax.plot(x, p, label=label)
-
-    for P in param_edge_fail:
-        p = logistic(c0 + dE_gamma(x, **P))
-        tag = "EDGE" if P["a"] == P["k"] else "FAIL"
-        label = f"{tag} (a={P['a']}, b={P['b']}, k={P['k']}, θ={P['theta']}, s={P['s']})"
-        ax.plot(x, p, linestyle="--", label=label)
-
-    ax.set_xscale("log")
-    ax.set_ylim(-0.05, 1.05)
-    ax.set_xlabel("x")
-    ax.set_ylabel("P(AE | x)")
-    ax.set_title("Gamma NC — posterior-like curves")
-    ax.grid(True, which="both")
-    ax.legend(fontsize=8)
-    fig.tight_layout()
-    return fig, ax
-
-
-def plot_lognorm_constraint_curves(param_list, p_prior=5/58,
-                                   x=None, figsize=(10, 6)):
-    if x is None:
-        x = np.logspace(-12, 3, 900)
-
-    c0 = logit(p_prior)
-    fig, ax = plt.subplots(figsize=figsize)
-
-    for P in param_list:
-        p = logistic(c0 + dE_lognorm(x, **P))
-        label = f"(a={P['a']}, b={P['b']}, μ={P['mu']}, σ={P['sigma']}, s={P['s']})"
-        ax.plot(x, p, label=label)
-
-    ax.set_xscale("log")
-    ax.set_ylim(-0.05, 1.05)
-    ax.set_xlabel("x")
-    ax.set_ylabel("P(AE | x)")
-    ax.set_title("LogNormal NC — posterior-like curves")
-    ax.grid(True, which="both")
-    ax.legend(fontsize=8)
-    fig.tight_layout()
-    return fig, ax

+ 0 - 0
data/cases_retroMManon.csv → data/raw/cases_retroMManon.csv


+ 0 - 0
data/flags_combined.mat → data/raw/flags_combined.mat


+ 0 - 0
data/normal_range.mat → data/raw/normal_range.mat


+ 0 - 0
data/suv_percentilesSLOthenUWM.mat → data/raw/suv_percentilesSLOthenUWM.mat


+ 0 - 55
data_utils.py

@@ -1,55 +0,0 @@
-# data.py
-import numpy as np
-
-"""
-LUNG data extraction (with NaN filtering)
-
-This file does one job:
-1) Read lung SUV percentile data from `suv_dict`
-2) Build one feature per patient:
-      x[i] = max value (ignoring NaNs) of the chosen percentile for patient i
-3) Read lung labels from `flags_dict`:
-      y[i] = 0 (NC) or 1 (AE)
-4) Remove patients where x is NaN (and keep y aligned)
-
-Important:
-- Logistic regression (sklearn) cannot use NaNs in X.
-- So we filter NaNs here to always return clean data.
-
-Inputs:
-- perc: percentile number (1..100), e.g. 95
-- suv_dict: dict loaded from the SUV .mat file
-- flags_dict: dict loaded from the flags .mat file
-- nr_patient: number of patients to use (default 58)
-
-Outputs:
-- x: 1D numpy array (NaNs removed)
-- y: 1D numpy array (aligned with x)
-"""
-
-
-def get_data(perc, suv_dict, flags_dict):
-    """
-    Extract SUV percentile feature and AE labels.
-
-    perc = 95 -> uses column index 94
-    """
-
-    # SUV matrix: (patients × percentiles × organs)
-    suv = suv_dict["lung_SUVperc_COMBINED"]
-
-    # Flags: AE indicator
-    flags = flags_dict["flags"]
-
-    # We only use first 58 patients and column 3 for AE
-    y = flags[:58, 3].astype(int).ravel()
-
-    # Percentile index (95th -> column 94)
-    p_idx = perc - 1
-
-    # Extract feature: max over organs at that percentile
-    x = np.nanmax(suv[:58, :, p_idx], axis=1).astype(float)
-
-    # Remove NaNs
-    mask = np.isfinite(x)
-    return x[mask], y[mask]

+ 0 - 0
python/logistic/cost_checks.nb → legacy/mathematica/cost_checks.nb


+ 0 - 0
mathematica/distrib.nb → legacy/mathematica/distrib.nb


+ 0 - 0
matlab/distinguishable_colors.m → legacy/matlab/distinguishable_colors.m


+ 0 - 0
matlab/irAE_plotting.m → legacy/matlab/irAE_plotting.m


+ 0 - 0
matlab/maxbowel.m → legacy/matlab/maxbowel.m


+ 0 - 1845
logit.py

@@ -1,1845 +0,0 @@
-import numpy as np
-import matplotlib.pyplot as plt
-from scipy.optimize import minimize
-
-
-# ============================================================
-# Stable sigmoid
-# ============================================================
-
-def _sigmoid_stable(z):
-    z = np.asarray(z, float)
-    z = np.clip(z, -50.0, 50.0)
-    return 1.0 / (1.0 + np.exp(-z))
-
-
-# ============================================================
-# 1) Model
-# ============================================================
-
-def model_p(x, b):
-    """p(x|b) = sigmoid(b0 + b1*x)."""
-    x = np.asarray(x, float).reshape(-1)
-    b0, b1 = np.asarray(b, float).reshape(2)
-    return _sigmoid_stable(b0 + b1 * x)
-
-
-def design_matrix(x):
-    """Design matrix X = [1, x]."""
-    x = np.asarray(x, float).reshape(-1)
-    return np.column_stack([np.ones_like(x), x])
-
-
-# ============================================================
-# 2) Likelihood
-# ============================================================
-
-def nll(x, y, b, l2=0.0):
-    """
-    Penalized negative log-likelihood:
-        NLL(b) = -sum[y log p + (1-y) log(1-p)] + 0.5*l2*||b||^2
-    """
-    x = np.asarray(x, float).reshape(-1)
-    y = np.asarray(y, float).reshape(-1)
-    b = np.asarray(b, float).reshape(2)
-
-    p = model_p(x, b)
-    eps = 1e-12
-    p = np.clip(p, eps, 1 - eps)
-
-    base = -np.sum(y * np.log(p) + (1 - y) * np.log(1 - p))
-    pen = 0.5 * l2 * float(np.dot(b, b))
-    return base + pen
-
-
-def llf(x, y, b):
-    """
-    Ordinary (unpenalized) log-likelihood at fitted parameters.
-    """
-    x = np.asarray(x, float).reshape(-1)
-    y = np.asarray(y, float).reshape(-1)
-    b = np.asarray(b, float).reshape(2)
-
-    p = model_p(x, b)
-    eps = 1e-12
-    p = np.clip(p, eps, 1 - eps)
-    return float(np.sum(y * np.log(p) + (1 - y) * np.log(1 - p)))
-
-
-# ============================================================
-# 3) Gradient / Hessian / Covariance
-# ============================================================
-
-def grad_nll(x, y, b, l2=0.0):
-    """
-    Gradient of penalized NLL:
-        g(b) = X^T (p - y) + l2*b
-    """
-    X = design_matrix(x)
-    y = np.asarray(y, float).reshape(-1)
-    b = np.asarray(b, float).reshape(2)
-
-    p = model_p(x, b)
-    return X.T @ (p - y) + l2 * b
-
-
-def hess_nll(x, b, l2=0.0):
-    """
-    Hessian of penalized NLL:
-        H(b) = X^T W X + l2*I
-        W = diag(p*(1-p))
-    """
-    X = design_matrix(x)
-    b = np.asarray(b, float).reshape(2)
-
-    p = model_p(x, b)
-    w = p * (1 - p)
-    return X.T @ (w[:, None] * X) + l2 * np.eye(2)
-
-
-def covariance(x, b, l2=0.0):
-    """
-    Cov(b) ≈ H(b)^(-1), where H is the penalized Hessian if l2 > 0.
-    Robust to near-singular Hessians.
-    """
-    H = hess_nll(x, b, l2=l2)
-    try:
-        return np.linalg.inv(H)
-    except np.linalg.LinAlgError:
-        return np.linalg.pinv(H)
-
-
-def standard_errors(x, b, l2=0.0):
-    """
-    SE = sqrt(diag(Cov)).
-    """
-    C = covariance(x, b, l2=l2)
-    return np.sqrt(np.maximum(np.diag(C), 0.0))
-
-
-# Compatibility alias
-def logit_poly_cov(x, b, l2=0.0):
-    return covariance(x, b, l2=l2)
-
-
-# ============================================================
-# 4) Fit
-# ============================================================
-def fit_newton(x, y, b_start=None, max_iter=50, tol=1e-8, l2=0.0):
-    """
-    Newton updates for penalized NLL with backtracking line-search.
-
-    Update:
-        b_new = b - alpha * H^{-1} g
-    alpha shrinks until NLL decreases.
-    """
-    x = np.asarray(x, float).reshape(-1)
-    y = np.asarray(y, int).reshape(-1)
-
-    if b_start is None:
-        b = np.array([0.0, 0.0], float)
-    else:
-        b = np.asarray(b_start, float).reshape(2)
-
-    f = nll(x, y, b, l2=l2)
-
-    for _ in range(max_iter):
-        g = grad_nll(x, y, b, l2=l2)
-        H = hess_nll(x, b, l2=l2)
-
-        try:
-            step = np.linalg.solve(H, g)
-        except np.linalg.LinAlgError:
-            step = np.linalg.pinv(H) @ g
-
-        alpha = 1.0
-        while alpha > 1e-6:
-            b_new = b - alpha * step
-            f_new = nll(x, y, b_new, l2=l2)
-            if np.isfinite(f_new) and f_new <= f:
-                break
-            alpha *= 0.5
-
-        if alpha <= 1e-6:
-            break
-
-        if np.max(np.abs(b_new - b)) < tol:
-            b = b_new
-            break
-
-        b, f = b_new, f_new
-
-    return b
-
-
-# ============================================================
-# 14) Overlay plot (LOG left, RAW right)
-# ============================================================
-def plot_overlay_two_panels_final(
-    r_log_full, r_log_trim, r_raw_full, r_raw_trim,
-    dy_full=-0.010, dy_trim=0.010
-):
-    import numpy as np
-    import matplotlib.pyplot as plt
-
-    COL_NC   = "#4C78A8"
-    COL_AE   = "#F58518"
-    COL_FULL = "#1f77b4"
-    COL_TRIM = "#ff7f0e"
-
-    fig, axes = plt.subplots(1, 2, figsize=(9.5, 3.5), sharey=True)
-    ax1, ax2 = axes
-
-    def draw_panel(ax, r_full, r_trim, xlabel, panel_label,
-                   show_legend=False):
-
-        xF = np.asarray(r_full["x"], float)
-        yF = np.asarray(r_full["y"], int)
-
-        xT = np.asarray(r_trim["x"], float)
-        yT = np.asarray(r_trim["y"], int)
-
-        xx = np.linspace(
-            min(xF.min(), xT.min()),
-            max(xF.max(), xT.max()),
-            500
-        )
-
-        # keep x-values unchanged
-        xF_plot = xF
-        xT_plot = xT
-
-        # vertical offsets only
-        yF_plot = yF + np.where(yF == 0, dy_full, -dy_full)
-        yT_plot = yT + np.where(yT == 0, dy_trim, -dy_trim)
-
-        # FULL = filled markers
-        ax.scatter(
-            xF_plot[yF == 0], yF_plot[yF == 0],
-            s=16,
-            color=COL_NC,
-            alpha=0.70,
-            edgecolors="none",
-            label="data: FULL NC",
-            zorder=3
-        )
-
-        ax.scatter(
-            xF_plot[yF == 1], yF_plot[yF == 1],
-            s=16,
-            color=COL_AE,
-            alpha=0.80,
-            edgecolors="none",
-            label="data: FULL AE",
-            zorder=3
-        )
-
-        # TRIM = outlined markers
-        ax.scatter(
-            xT_plot[yT == 0], yT_plot[yT == 0],
-            s=24,
-            facecolors=COL_NC,
-            edgecolors="black",
-            linewidths=0.45,
-            alpha=0.95,
-            label="data: TRIM NC",
-            zorder=4
-        )
-
-        ax.scatter(
-            xT_plot[yT == 1], yT_plot[yT == 1],
-            s=24,
-            facecolors=COL_AE,
-            edgecolors="black",
-            linewidths=0.45,
-            alpha=0.95,
-            label="data: TRIM AE",
-            zorder=4
-        )
-
-        # logistic fits
-        ax.plot(
-            xx,
-            model_p(xx, r_full["b"]),
-            lw=1.8,
-            color=COL_FULL,
-            label="fit FULL",
-            zorder=2
-        )
-
-        ax.plot(
-            xx,
-            model_p(xx, r_trim["b"]),
-            lw=1.8,
-            color=COL_TRIM,
-            label="fit TRIM",
-            zorder=2
-        )
-
-        # legend only in panel B
-        if show_legend:
-            ax.legend(
-                loc="lower right",
-                fontsize=7,
-                markerscale=0.9,
-                frameon=True,
-                framealpha=1.0,
-                edgecolor="0.7",
-                handlelength=1.8,
-                borderpad=0.4,
-                labelspacing=0.4,
-                handletextpad=0.5
-            )
-
-        ax.set_xlabel(xlabel)
-        ax.set_ylim(-0.08, 1.08)
-
-        ax.text(
-            0.05, 0.90,
-            panel_label,
-            transform=ax.transAxes,
-            fontsize=11
-        )
-
-    draw_panel(
-        ax1,
-        r_log_full,
-        r_log_trim,
-        "log(X)",
-        "A",
-        show_legend=False
-    )
-
-    draw_panel(
-        ax2,
-        r_raw_full,
-        r_raw_trim,
-        "X",
-        "B",
-        show_legend=True
-    )
-
-    ax1.set_ylabel("P(AE | X = x)")
-
-    for ax in axes:
-        ax.grid(False)
-        ax.tick_params(labelsize=8)
-
-    plt.tight_layout()
-    plt.show()
-
-    return fig, axes
-
-    return fig, axes
-# ============================================================
-# 5) Goodness of fit
-# ============================================================
-
-def goodness_of_fit(x, y, b, thresh=0.5, l2=0.0):
-    """
-    Returns:
-      LLF, NLL, AIC, BIC, Accuracy, n, k
-
-    Notes
-    -----
-    Fit may use l2 > 0, but GOF metrics below are computed from the
-    ordinary (unpenalized) likelihood evaluated at the fitted parameters.
-    The argument l2 is kept only for interface consistency.
-    """
-    x = np.asarray(x, float).reshape(-1)
-    y = np.asarray(y, int).reshape(-1)
-    b = np.asarray(b, float).reshape(2)
-
-    p = model_p(x, b)
-    eps = 1e-12
-    p = np.clip(p, eps, 1 - eps)
-
-    LLF = np.sum(y * np.log(p) + (1 - y) * np.log(1 - p))
-    NLL = -LLF
-
-    n = len(x)
-    k = len(b)
-
-    AIC = 2 * k - 2 * LLF
-    BIC = k * np.log(n) - 2 * LLF
-
-    yhat = (p >= thresh).astype(int)
-    acc = np.mean(yhat == y)
-
-    return {
-        "LLF": float(LLF),
-        "NLL": float(NLL),
-        "AIC": float(AIC),
-        "BIC": float(BIC),
-        "A": float(acc),
-        "n": int(n),
-        "k": int(k),
-    }
-
-
-# ============================================================
-# 6) x50 / Wald helpers / compact fit
-# ============================================================
-def x50(b):
-    """
-    Model-scale midpoint:
-        x50 = -b0 / b1
-
-    For LOG panels, this is on the log(x) scale.
-    Raw-scale SUV50 is exp(x50).
-    """
-    b0, b1 = np.asarray(b, float).reshape(2)
-    return np.nan if np.abs(b1) < 1e-12 else (-b0 / b1)
-
-
-def check_x50_consistency(P):
-    """
-    Diagnostic check for x50 consistency.
-
-    For LOG models:
-        x50_model is on log(X) scale
-        SUV50 is on raw X scale = exp(x50_model)
-
-    For RAW models:
-        x50_model = SUV50
-
-    Correct result:
-        P(x50_model) should be approximately 0.5
-    """
-    for key, pk in P.items():
-        b = np.asarray(pk["b"], float).reshape(2)
-        trans = pk.get("transform", "")
-
-        x50_model = x50(b)
-        suv50 = np.exp(x50_model) if trans == "log" else x50_model
-        p_at_x50 = model_p(np.array([x50_model]), b)[0]
-
-        print(
-            key,
-            "| transform =", trans,
-            "| x50_model =", x50_model,
-            "| SUV50 =", suv50,
-            "| P(x50) =", p_at_x50
-        )
-
-
-def x50_wald_ci(b, cov, z=1.959963984540054):
-    """
-    Wald CI for x50 = -b0/b1 via delta method.
-    Returned on MODEL scale.
-    """
-    b = np.asarray(b, float).reshape(2)
-    cov = np.asarray(cov, float).reshape(2, 2)
-    b0, b1 = b
-
-    if np.abs(b1) < 1e-12:
-        return np.nan, np.nan
-
-    xhat = -b0 / b1
-    grad = np.array([-1.0 / b1, b0 / (b1 ** 2)], float)
-    var = float(grad.T @ cov @ grad)
-    se = np.sqrt(max(var, 0.0))
-    return float(xhat - z * se), float(xhat + z * se)
-
-
-def wald_ci(b, cov, z=1.959963984540054):
-    """
-    Wald CI for parameters: b_i ± z*SE_i.
-    """
-    b = np.asarray(b, float).reshape(2)
-    cov = np.asarray(cov, float).reshape(2, 2)
-    se = np.sqrt(np.maximum(np.diag(cov), 0.0))
-    return b - z * se, b + z * se
-
-
-def fit_pack(x, y, name="", thresh=0.5, l2=0.0, z=1.959963984540054):
-    """
-    Fit + covariance + GOF + parameter Wald CI.
-    x should already be on the MODEL scale.
-    """
-    x = np.asarray(x, float).reshape(-1)
-    y = np.asarray(y, int).reshape(-1)
-
-    b = fit_newton(x, y, l2=l2)
-    cov = covariance(x, b, l2=l2)
-    gof = goodness_of_fit(x, y, b, thresh=thresh, l2=l2)
-    lcl, ucl = wald_ci(b, cov, z=z)
-
-    return {
-        "name": name,
-        "x": x,
-        "y": y,
-        "b": b,
-        "cov": cov,
-        "gof": gof,
-        "LCL": lcl,
-        "UCL": ucl,
-        "l2": float(l2),
-    }
-
-
-def trim_nc_by_value(x_raw, y, target=2.48, tol=0.05):
-    """
-    Remove ONE NC sample (y==0) with x_raw closest to target.
-    """
-    x_raw = np.asarray(x_raw, float).reshape(-1)
-    y = np.asarray(y, int).reshape(-1)
-
-    nc_idx = np.where(y == 0)[0]
-    if len(nc_idx) == 0:
-        raise ValueError("No NC samples found (y==0).")
-
-    j = nc_idx[np.argmin(np.abs(x_raw[nc_idx] - target))]
-    diff = float(np.abs(x_raw[j] - target))
-    if diff > tol:
-        print(f"[trim warning] closest NC to {target} is {x_raw[j]:.6f} (diff={diff:.6f}) > tol={tol}")
-
-    mask = np.ones_like(y, dtype=bool)
-    mask[j] = False
-    print(f"[trim] removed index={j}, x_raw={x_raw[j]:.6f}, y={y[j]}")
-    return x_raw[mask], y[mask]
-
-
-# ============================================================
-# 7) Analytic CI bands on a grid
-# ============================================================
-
-def eta_se_grid(x_grid, cov):
-    """
-    Standard error of eta(x) = b0 + b1*x on a grid.
-    x_grid must be on the MODEL scale.
-    """
-    x_grid = np.asarray(x_grid, float).reshape(-1)
-    cov = np.asarray(cov, float).reshape(2, 2)
-
-    Xg = design_matrix(x_grid)
-    var_eta = np.einsum("ij,jk,ik->i", Xg, cov, Xg)
-    return np.sqrt(np.maximum(var_eta, 0.0))
-
-
-def ci_band_normal_mle_sim(
-    x_grid, b, cov,
-    M=20000,
-    seed=123,
-    alpha=0.05,
-    enforce_positive_slope=True,
-    enforce_x50_in_grid=True,
-    slope_eps=1e-10
-):
-    """
-    Normal-on-MLE simulation CI band with admissible logistic draws.
-
-    Draw beta* ~ N(beta_hat, Cov_hat), then keep only curves that:
-      1) are increasing: beta1 > 0
-      2) have x50 inside the plotted model-scale grid, if requested
-
-    This avoids pathological Normal curves in near-separated TRIM data.
-    """
-    rng = np.random.default_rng(seed)
-
-    x_grid = np.asarray(x_grid, float).reshape(-1)
-    b = np.asarray(b, float).reshape(2)
-    cov = np.asarray(cov, float).reshape(2, 2)
-
-    x_min = float(np.min(x_grid))
-    x_max = float(np.max(x_grid))
-
-    curves = []
-    tries = 0
-    max_tries = 50 * M
-
-    while len(curves) < M and tries < max_tries:
-        tries += 1
-
-        try:
-            bb = rng.multivariate_normal(mean=b, cov=cov)
-        except Exception:
-            break
-
-        if not np.all(np.isfinite(bb)):
-            continue
-
-        b0, b1 = bb
-
-        if enforce_positive_slope and b1 <= slope_eps:
-            continue
-
-        x50_draw = x50(bb)
-        if not np.isfinite(x50_draw):
-            continue
-
-        if enforce_x50_in_grid and not (x_min <= x50_draw <= x_max):
-            continue
-
-        pp = model_p(x_grid, bb)
-
-        if np.all(np.isfinite(pp)):
-            curves.append(pp)
-
-    if len(curves) == 0:
-        nan = np.full_like(x_grid, np.nan, dtype=float)
-        return nan, nan, nan
-
-    curves = np.asarray(curves, float)
-    q = np.quantile(curves, [alpha / 2, 0.5, 1.0 - alpha / 2], axis=0)
-
-    return q[0], q[1], q[2]
-
-def x50_normal_ci_from_mvnorm(
-    b, cov, M=200000, seed=123, alpha=0.05,
-    enforce_positive_slope=True, slope_eps=1e-10
-):
-    """
-    Normal-on-MLE CI for x50.
-
-    Draw beta* ~ N(beta_hat, Cov_hat), optionally retain only
-    monotone increasing draws beta1 > 0, then compute x50 = -b0/b1.
-    """
-    rng = np.random.default_rng(seed)
-
-    b = np.asarray(b, float).reshape(2)
-    cov = np.asarray(cov, float).reshape(2, 2)
-
-    vals = []
-    tries = 0
-    max_tries = 20 * M
-
-    while len(vals) < M and tries < max_tries:
-        tries += 1
-
-        try:
-            bb = rng.multivariate_normal(mean=b, cov=cov)
-        except Exception:
-            break
-
-        if not np.all(np.isfinite(bb)):
-            continue
-
-        if enforce_positive_slope and bb[1] <= slope_eps:
-            continue
-
-        val = x50(bb)
-        if np.isfinite(val):
-            vals.append(val)
-
-    if len(vals) == 0:
-        return np.nan, np.nan, np.nan, 0
-
-    vals = np.asarray(vals, float)
-    q = np.quantile(vals, [alpha / 2, 0.5, 1.0 - alpha / 2])
-
-    return float(q[0]), float(q[1]), float(q[2]), int(len(vals))
-
-
-def ci_band_delta(x_grid, b, cov, z=1.959963984540054):
-    """
-    Delta-method CI band on probability scale:
-        p(x) ± z * SE_p(x)
-    where
-        SE_p = p(1-p) * SE_eta
-    Returns: lo, mid, hi
-    """
-    x_grid = np.asarray(x_grid, float).reshape(-1)
-    b = np.asarray(b, float).reshape(2)
-
-    p = model_p(x_grid, b)
-    se_eta = eta_se_grid(x_grid, cov)
-    se_p = p * (1.0 - p) * se_eta
-
-    lo = np.clip(p - z * se_p, 0.0, 1.0)
-    md = p
-    hi = np.clip(p + z * se_p, 0.0, 1.0)
-    return lo, md, hi
-
-
-# ============================================================
-# 8) Bootstrap parameter generators
-# ============================================================
-
-def bootstrap_params_stratified(x, y, B=2000, seed=123, l2=0.0, b_start=None):
-    """
-    Stratified nonparametric bootstrap on MODEL-scale x.
-    Preserves class counts exactly.
-    Returns array of shape (n_ok, 2).
-    """
-    rng = np.random.default_rng(seed)
-
-    x = np.asarray(x, float).reshape(-1)
-    y = np.asarray(y, int).reshape(-1)
-
-    x0 = x[y == 0]
-    x1 = x[y == 1]
-
-    n0 = len(x0)
-    n1 = len(x1)
-
-    if n0 == 0 or n1 == 0:
-        return np.empty((0, 2), float)
-
-    out = []
-    for _ in range(B):
-        xb0 = rng.choice(x0, size=n0, replace=True)
-        xb1 = rng.choice(x1, size=n1, replace=True)
-
-        xb = np.concatenate([xb0, xb1])
-        yb = np.concatenate([np.zeros(n0, dtype=int), np.ones(n1, dtype=int)])
-
-        try:
-            bb = fit_newton(xb, yb, b_start=b_start, l2=l2)
-            if np.all(np.isfinite(bb)):
-                out.append(bb)
-        except Exception:
-            pass
-
-    if len(out) == 0:
-        return np.empty((0, 2), float)
-    return np.asarray(out, float)
-
-
-def bootstrap_params_parametric(x, b, B=2000, seed=123, l2=0.0, min_ae=2):
-    """
-    Parametric bootstrap on MODEL-scale x.
-    Simulates y* ~ Bernoulli(p_hat(x)).
-    Keeps only samples with at least min_ae positives and at least one negative.
-    Returns array of shape (n_ok, 2).
-    """
-    rng = np.random.default_rng(seed)
-
-    x = np.asarray(x, float).reshape(-1)
-    b = np.asarray(b, float).reshape(2)
-
-    p = model_p(x, b)
-    n = len(x)
-
-    out = []
-    tries = 0
-    max_tries = max(10 * B, 1000)
-
-    while len(out) < B and tries < max_tries:
-        tries += 1
-        yb = rng.binomial(1, p, size=n).astype(int)
-
-        n1 = int(np.sum(yb))
-        n0 = n - n1
-        if n1 < min_ae or n0 < 1:
-            continue
-
-        try:
-            bb = fit_newton(x, yb, b_start=b, l2=l2)
-            if np.all(np.isfinite(bb)):
-                out.append(bb)
-        except Exception:
-            pass
-
-    if len(out) == 0:
-        return np.empty((0, 2), float)
-    return np.asarray(out, float)
-
-
-# ============================================================
-# 9) Convert bootstrap parameters to curve bands
-# ============================================================
-
-def bootstrap_band_from_params(x_grid, pars, alpha=0.05):
-    """
-    Build bootstrap CI band from bootstrap parameter draws.
-    x_grid is on MODEL scale.
-    Returns: lo, mid, hi
-    """
-    x_grid = np.asarray(x_grid, float).reshape(-1)
-    pars = np.asarray(pars, float)
-
-    if pars.ndim != 2 or pars.shape[0] == 0:
-        nan = np.full_like(x_grid, np.nan, dtype=float)
-        return nan, nan, nan
-
-    curves = np.array([model_p(x_grid, bb) for bb in pars], float)
-    q = np.quantile(curves, [alpha / 2, 0.5, 1.0 - alpha / 2], axis=0)
-    return q[0], q[1], q[2]
-
-
-# ============================================================
-# 10) High-level wrapper for one panel
-# ============================================================
-
-def fit_ci_pack_rawgrid(
-    x_raw, y, transform="raw", xmax_raw=None, grid_n=500,
-    name="", l2=0.0, B=2000, seed=123, min_ae=2,
-    z=1.959963984540054,
-):
-    x_raw = np.asarray(x_raw, float).reshape(-1)
-    y = np.asarray(y, int).reshape(-1)
-
-    if transform not in ("raw", "log"):
-        raise ValueError("transform must be 'raw' or 'log'")
-
-    x_raw = np.clip(x_raw, 1e-12, None)
-    x_model = x_raw if transform == "raw" else np.log(x_raw)
-
-    b = fit_newton(x_model, y, l2=l2)
-    cov = covariance(x_model, b, l2=l2)
-    gof = goodness_of_fit(x_model, y, b, l2=l2)
-
-    xmin_raw = float(np.min(x_raw))
-    xmax0 = float(np.max(x_raw))
-    xmax_use = xmax0 if xmax_raw is None else max(float(xmax_raw), xmax0)
-
-    x_grid_raw = np.linspace(xmin_raw, xmax_use, int(grid_n))
-    x_grid_raw = np.clip(x_grid_raw, 1e-12, None)
-    x_grid_model = x_grid_raw if transform == "raw" else np.log(x_grid_raw)
-
-    lo_n, md_n, hi_n = ci_band_normal_mle_sim(
-        x_grid_model,
-        b,
-        cov,
-        M=20000,
-        seed=seed + 10,
-        alpha=0.05,
-        enforce_positive_slope=True,
-        enforce_x50_in_grid=True
-    )
-
-    lo_d, md_d, hi_d = ci_band_delta(
-        x_grid_model,
-        b,
-        cov,
-        z=z
-    )
-
-    pars_np = bootstrap_params_stratified(
-        x_model, y,
-        B=B,
-        seed=seed + 1,
-        l2=l2,
-        b_start=b
-    )
-
-    pars_pm = bootstrap_params_parametric(
-        x_model, b,
-        B=B,
-        seed=seed + 2,
-        l2=l2,
-        min_ae=min_ae
-    )
-
-    lo_np, md_np, hi_np = bootstrap_band_from_params(x_grid_model, pars_np)
-    lo_pm, md_pm, hi_pm = bootstrap_band_from_params(x_grid_model, pars_pm)
-
-    return {
-        "name": name,
-        "transform": transform,
-        "l2": float(l2),
-        "x_raw": x_raw,
-        "x_model": x_model,
-        "y": y,
-        "x_grid_raw": x_grid_raw,
-        "x_grid_model": x_grid_model,
-        "b": b,
-        "cov": cov,
-        "gof": gof,
-        "bands": {
-            "Normal":     (lo_n,  md_n,  hi_n),
-            "Delta":      (lo_d,  md_d,  hi_d),
-            "Nonparam":   (lo_np, md_np, hi_np),
-            "Parametric": (lo_pm, md_pm, hi_pm),
-        },
-        "pars_nonparam": pars_np,
-        "pars_parametric": pars_pm,
-    }
-# ============================================================
-# 11) Model-band table with LL / UL
-# ============================================================
-
-def model_ci_table_4methods(
-    P,
-    keys=("FULL-RAW", "TRIM-RAW", "FULL-LOG", "TRIM-LOG"),
-):
-    """
-    Long table of model CI bands on the grid.
-    Includes:
-      x_grid_model, x_grid_raw, fit, LL, UL, width
-    """
-    import pandas as pd
-
-    rows = []
-
-    for key in keys:
-        pk = P[key]
-        xg_raw = np.asarray(pk["x_grid_raw"], float)
-        xg_mod = np.asarray(pk["x_grid_model"], float)
-        trans = pk.get("transform", "")
-        bands = pk["bands"]
-
-        for method, (lo, md, hi) in bands.items():
-            lo = np.asarray(lo, float)
-            md = np.asarray(md, float)
-            hi = np.asarray(hi, float)
-
-            for i in range(len(xg_raw)):
-                rows.append({
-                    "Panel": key,
-                    "Method": method,
-                    "transform": trans,
-                    "x_grid_raw": float(xg_raw[i]),
-                    "x_grid_model": float(xg_mod[i]),
-                    "fit": float(md[i]),
-                    "LL": float(lo[i]),
-                    "UL": float(hi[i]),
-                    "width": float(hi[i] - lo[i]),
-                })
-
-    return pd.DataFrame(rows)
-
-
-# ============================================================
-# 12) Parameter/x50 CI summary table
-# ============================================================
-
-def param_ci_table_4methods(
-    P,
-    keys=("FULL-RAW", "TRIM-RAW", "FULL-LOG", "TRIM-LOG"),
-    z=1.959963984540054,
-    alpha=0.05,
-    include_point_est=True,
-    M_normal=200000,
-    seed_normal=123,
-):
-    """
-    Build tidy parameter/x50 CI table for:
-      Normal, Delta, Nonparam, Parametric
-
-    Definitions
-    -----------
-    Normal:
-        - b0, b1: Wald CI from MLE covariance
-        - x50: beta ~ N(b_hat, cov_hat), transform x50 = -b0/b1, take quantiles
-
-    Delta:
-        - b0, b1: Wald CI from MLE covariance
-        - x50: delta/Wald CI using gradient of x50 = -b0/b1
-
-    Nonparam:
-        - bootstrap quantiles from nonparametric bootstrap parameter draws
-
-    Parametric:
-        - bootstrap quantiles from parametric bootstrap parameter draws
-
-    Notes
-    -----
-    - x50 is on MODEL scale.
-    - SUV50 is on RAW scale:
-        raw panel -> same as x50
-        log panel -> exp(x50)
-    """
-    import pandas as pd
-
-    def _boot_ci_from_pars(pars, alpha=0.05):
-        if pars is None or len(pars) == 0:
-            nan2 = (np.nan, np.nan)
-            return nan2, nan2, nan2, np.nan, 0
-
-        pars = np.asarray(pars, float)
-        q = np.quantile(pars, [alpha / 2, 0.5, 1.0 - alpha / 2], axis=0)
-
-        b0_ci = (float(q[0, 0]), float(q[2, 0]))
-        b1_ci = (float(q[0, 1]), float(q[2, 1]))
-
-        x50s = np.array([x50(bb) for bb in pars], float)
-        x50s = x50s[np.isfinite(x50s)]
-
-        if len(x50s) == 0:
-            x50_ci = (np.nan, np.nan)
-            x50_med = np.nan
-        else:
-            xq = np.quantile(x50s, [alpha / 2, 0.5, 1.0 - alpha / 2])
-            x50_ci = (float(xq[0]), float(xq[2]))
-            x50_med = float(xq[1])
-
-        return b0_ci, b1_ci, x50_ci, x50_med, int(len(pars))
-
-    def _to_suv50(x50_pair, trans):
-        lo, hi = x50_pair
-        if not (np.isfinite(lo) and np.isfinite(hi)):
-            return (np.nan, np.nan)
-        if trans == "log":
-            return (float(np.exp(lo)), float(np.exp(hi)))
-        return (float(lo), float(hi))
-
-    def _to_suv50_scalar(x50_val, trans):
-        if not np.isfinite(x50_val):
-            return np.nan
-        if trans == "log":
-            return float(np.exp(x50_val))
-        return float(x50_val)
-
-    rows = []
-
-    for ik, key in enumerate(keys):
-        pk = P[key]
-        b = np.asarray(pk["b"], float).reshape(2)
-        cov = np.asarray(pk["cov"], float).reshape(2, 2)
-        trans = pk.get("transform", "")
-        l2 = float(pk.get("l2", 0.0))
-
-        b0_hat, b1_hat = float(b[0]), float(b[1])
-        x50_hat = float(x50(b))
-        suv50_hat = _to_suv50_scalar(x50_hat, trans)
-
-        lcl, ucl = wald_ci(b, cov, z=z)
-        b0_wald = (float(lcl[0]), float(ucl[0]))
-        b1_wald = (float(lcl[1]), float(ucl[1]))
-
-        x50_l_d, x50_u_d = x50_wald_ci(b, cov, z=z)
-        x50_med_d = x50_hat
-        x50_delta = (float(x50_l_d), float(x50_u_d))
-        suv50_delta = _to_suv50(x50_delta, trans)
-
-        x50_l_n, x50_med_n, x50_u_n, n_ok_norm = x50_normal_ci_from_mvnorm(
-            b, cov,
-            M=M_normal,
-            seed=seed_normal + 1000 * ik,
-            alpha=alpha
-        )
-        x50_normal = (float(x50_l_n), float(x50_u_n))
-        suv50_normal = _to_suv50(x50_normal, trans)
-
-        pars_np = pk.get("pars_nonparam", np.empty((0, 2)))
-        pars_pm = pk.get("pars_parametric", np.empty((0, 2)))
-
-        b0_np, b1_np, x50_np, x50_med_np, n_np = _boot_ci_from_pars(pars_np, alpha=alpha)
-        b0_pm, b1_pm, x50_pm, x50_med_pm, n_pm = _boot_ci_from_pars(pars_pm, alpha=alpha)
-
-        suv50_np = _to_suv50(x50_np, trans)
-        suv50_pm = _to_suv50(x50_pm, trans)
-
-        def _width(ci):
-            lo, hi = ci
-            if np.isfinite(lo) and np.isfinite(hi):
-                return float(hi - lo)
-            return np.nan
-
-        def add_row(method, b0_ci, b1_ci, x50_ci, x50_med, suv50_ci, B_used):
-            row = {
-                "Panel": key,
-                "Method": method,
-
-                "b0_hat": b0_hat,
-                "b0_LCL": float(b0_ci[0]),
-                "b0_UCL": float(b0_ci[1]),
-                "b0_width": _width(b0_ci),
-
-                "b1_hat": b1_hat,
-                "b1_LCL": float(b1_ci[0]),
-                "b1_UCL": float(b1_ci[1]),
-                "b1_width": _width(b1_ci),
-
-                "x50_hat": x50_hat,
-                "x50_med": float(x50_med) if np.isfinite(x50_med) else np.nan,
-                "x50_LCL": float(x50_ci[0]),
-                "x50_UCL": float(x50_ci[1]),
-                "x50_width": _width(x50_ci),
-
-                "SUV50_hat": suv50_hat,
-                "SUV50_med": _to_suv50_scalar(x50_med, trans),
-                "SUV50_LCL": float(suv50_ci[0]),
-                "SUV50_UCL": float(suv50_ci[1]),
-                "SUV50_width": _width(suv50_ci),
-
-                "transform": trans,
-                "l2": l2,
-                "B_used": B_used,
-            }
-
-            if not include_point_est:
-                for col in [
-                    "b0_hat", "b1_hat", "x50_hat", "x50_med",
-                    "SUV50_hat", "SUV50_med", "transform", "l2"
-                ]:
-                    row.pop(col, None)
-
-            rows.append(row)
-
-        add_row("Normal", b0_wald, b1_wald, x50_normal, x50_med_n, suv50_normal, n_ok_norm)
-        add_row("Delta", b0_wald, b1_wald, x50_delta, x50_med_d, suv50_delta, np.nan)
-        add_row("Nonparam", b0_np, b1_np, x50_np, x50_med_np, suv50_np, n_np)
-        add_row("Parametric", b0_pm, b1_pm, x50_pm, x50_med_pm, suv50_pm, n_pm)
-
-    return pd.DataFrame(rows)
-
-
-def combined_x50_model_bounds_table(
-    P,
-    keys=("FULL-RAW", "TRIM-RAW", "FULL-LOG", "TRIM-LOG"),
-    z=1.959963984540054,
-    alpha=0.05,
-    M_normal=200000,
-    seed_normal=123,
-):
-    """
-    Combine x50/SUV50 CI with global model-band bounds in one table.
-
-    Global model bounds are defined as:
-        global_LL = min_x LL(x)
-        global_UL = max_x UL(x)
-
-    Returns one row per Panel × Method.
-    """
-    import pandas as pd
-
-    # x50 / SUV50 table
-    param_df = param_ci_table_4methods(
-        P,
-        keys=keys,
-        z=z,
-        alpha=alpha,
-        include_point_est=True,
-        M_normal=M_normal,
-        seed_normal=seed_normal,
-    ).copy()
-
-    # pointwise model-band table
-    model_df = model_ci_table_4methods(P, keys=keys).copy()
-
-    # global envelope over x-grid
-    global_df = (
-        model_df
-        .groupby(["Panel", "Method"], as_index=False)
-        .agg(
-            global_LL=("LL", "min"),
-            global_UL=("UL", "max"),
-            fit_min=("fit", "min"),
-            fit_max=("fit", "max"),
-            mean_width=("width", "mean"),
-            max_width=("width", "max"),
-        )
-    )
-
-    global_df["global_width"] = global_df["global_UL"] - global_df["global_LL"]
-
-    # merge
-    out = pd.merge(
-        param_df,
-        global_df,
-        on=["Panel", "Method"],
-        how="left"
-    )
-
-    # choose a nice column order
-    preferred = [
-        "Panel", "Method", "transform",
-        "x50_hat", "x50_LCL", "x50_UCL", "x50_width",
-        "SUV50_hat", "SUV50_LCL", "SUV50_UCL", "SUV50_width",
-        "global_LL", "global_UL", "global_width",
-        "fit_min", "fit_max",
-        "mean_width", "max_width",
-        "B_used"
-    ]
-
-    cols = [c for c in preferred if c in out.columns] + [
-        c for c in out.columns if c not in preferred
-    ]
-
-    return out[cols]
-
-# ============================================================
-def plot_ci_four_panels(P):
-    import numpy as np
-    import matplotlib.pyplot as plt
-    import matplotlib.lines as mlines
-
-    plt.style.use("default")
-
-    COL_NC   = "#4c9ed9"
-    COL_AE   = "#f28e2b"
-    COL_FIT  = "#000000"
-
-    COL_NORMAL = "#d62728"   # red
-    COL_DELTA  = "#2ca02c"   # green
-    COL_NP     = "#1f77b4"   # blue
-    COL_PB     = "#17becf"   # cyan
-
-    FILL_NORMAL = "#d62728"
-    FILL_DELTA  = "#2ca02c"
-    FILL_NP     = "#1f77b4"
-    FILL_PB     = "#17becf"  
-    
-
-    METHOD_ORDER = ["Normal", "Delta", "Nonparam", "Parametric"]
-
-    panel_order   = ["FULL-LOG", "FULL-RAW", "TRIM-LOG", "TRIM-RAW"]
-    panel_letters = ["A", "B", "C", "D"]
-
-    fig, axs = plt.subplots(2, 2, figsize=(15, 10), dpi=180, sharex="col", sharey=True)
-
-    styles = {
-        "Normal":     (FILL_NORMAL, COL_NORMAL, "--"),
-        "Delta":      (FILL_DELTA,  COL_DELTA,  "-."),
-        "Nonparam":   (FILL_NP,     COL_NP,     ":"),
-        "Parametric": (FILL_PB,     COL_PB,     (0, (6, 2))),
-    }
-
-    for ax, key, letter in zip(axs.flat, panel_order, panel_letters):
-        pk = P[key]
-
-        x_raw = np.asarray(pk["x_raw"], float)
-        y = np.asarray(pk["y"], int)
-        xg_raw = np.asarray(pk["x_grid_raw"], float)
-        xg_model = np.asarray(pk["x_grid_model"], float)
-        bands = pk["bands"]
-        transform = pk["transform"]
-
-        if transform == "raw":
-            xs = x_raw
-            xg = xg_raw
-        else:
-            xs = np.log(x_raw)
-            xg = xg_model
-
-        rng = np.random.default_rng(123 + ord(letter))
-        jit = (rng.random(len(y)) - 0.5) * 0.04
-
-        ax.scatter(xs[y == 0], (y + jit)[y == 0],
-                   s=22, alpha=0.45, color=COL_NC,
-                   edgecolors="none", zorder=5)
-
-        ax.scatter(xs[y == 1], (y + jit)[y == 1],
-                   s=24, alpha=0.85, color=COL_AE,
-                   edgecolors="none", zorder=5)
-
-        for method in METHOD_ORDER:
-            lo, md, hi = bands[method]
-            fill_c, edge_c, ls = styles[method]
-
-            ax.fill_between(xg, lo, hi, color=fill_c, alpha=0.18, zorder=1)
-            ax.plot(xg, lo, color=edge_c, linestyle=ls, lw=1.8, zorder=2)
-            ax.plot(xg, hi, color=edge_c, linestyle=ls, lw=1.8, zorder=2)
-
-        fit_curve = model_p(xg_model, pk["b"])
-        ax.plot(xg, fit_curve, color=COL_FIT, lw=2.5, zorder=6)
-
-        ax.text(0.03, 0.95, letter,
-                transform=ax.transAxes,
-                fontsize=15, ha="left", va="top")
-
-        ax.set_ylim(-0.05, 1.05)
-        ax.grid(False)
-        ax.tick_params(axis="both", which="major",
-                       labelsize=11, length=4, width=0.8,
-                       direction="out")
-
-    axs[0, 0].set_ylabel(r"$\mathrm{P(AE \mid X = x)}$", fontsize=13)
-    axs[1, 0].set_ylabel(r"$\mathrm{P(AE \mid X = x)}$", fontsize=13)
-
-    axs[1, 0].set_xlabel(r"$\log(\mathrm{X})$", fontsize=13)
-    axs[1, 1].set_xlabel(r"$\mathrm{X}$", fontsize=13)
-
-    for ax in axs[0, :]:
-        ax.tick_params(axis="x", which="both", labelbottom=False)
-
-    for ax in axs[:, 1]:
-        ax.tick_params(axis="y", which="both", labelleft=False)
-
-    axD = axs[1, 1]
-    legend_handles = [
-        mlines.Line2D([], [], marker="o", color=COL_NC,
-                      linestyle="None", markersize=8, label="data: NC"),
-        mlines.Line2D([], [], marker="o", color=COL_AE,
-                      linestyle="None", markersize=8, label="data: AE"),
-        mlines.Line2D([], [], color="black", lw=2.5, label="fit"),
-        mlines.Line2D([], [], color=COL_NORMAL, lw=2, linestyle="--", label="CI: normal 95%"),
-        mlines.Line2D([], [], color=COL_DELTA, lw=2, linestyle="-.", label="CI: delta 95%"),
-        mlines.Line2D([], [], color=COL_NP, lw=2, linestyle=":", label="CI: nonparam_boots 95%"),
-        mlines.Line2D([], [], color=COL_PB, lw=2, linestyle=(0, (6, 2)), label="CI: parametric_boots 95%"),
-    ]
-
-    leg = axD.legend(handles=legend_handles, loc="lower right",
-                     bbox_to_anchor=(0.95, 0.05),
-                     fontsize=10, frameon=True)
-
-    frame = leg.get_frame()
-    frame.set_facecolor("white")
-    frame.set_edgecolor("#bdbdbd")
-    frame.set_linewidth(0.8)
-
-    fig.subplots_adjust(left=0.08, right=0.98,
-                        bottom=0.08, top=0.98,
-                        wspace=0.06, hspace=0.06)
-
-    return fig, axs
-# ============================================================
-# ELASTICITY ANALYSIS (x50 and s50)
-# ============================================================
-
-import numpy as np
-import matplotlib.pyplot as plt
-
-
-# ------------------------------------------------------------
-# Core elasticity computation
-# ------------------------------------------------------------
-def elasticity_x50_s50(theta, mode="raw"):
-    """
-    Elasticity for x50 and s50 with respect to theta0 and theta1.
-
-    mode
-    ----
-    'raw' : eta = theta0 + theta1*x
-    'log' : eta = theta0 + theta1*log(x)
-
-    Returns
-    -------
-    dict with:
-        theta0, theta1,
-        x50, s50,
-        E_x50_theta0, E_x50_theta1,
-        E_s50_theta0, E_s50_theta1
-    """
-    theta0, theta1 = map(float, np.asarray(theta).reshape(2))
-
-    if np.abs(theta1) < 1e-12:
-        return dict(
-            theta0=theta0,
-            theta1=theta1,
-            x50=np.nan,
-            s50=np.nan,
-            E_x50_theta0=np.nan,
-            E_x50_theta1=np.nan,
-            E_s50_theta0=np.nan,
-            E_s50_theta1=np.nan,
-        )
-
-    # =========================
-    # RAW MODEL
-    # =========================
-    if mode == "raw":
-        x50 = -theta0 / theta1
-        s50 = theta1 / 4.0
-
-        E_x50_theta0 = 1.0
-        E_x50_theta1 = -1.0
-
-        E_s50_theta0 = 0.0
-        E_s50_theta1 = 1.0
-
-    # =========================
-    # LOG MODEL
-    # =========================
-    elif mode == "log":
-        x50 = float(np.exp(-theta0 / theta1))
-        s50 = theta1 / (4.0 * x50)
-
-        E_x50_theta0 = -theta0 / theta1
-        E_x50_theta1 = theta0 / theta1
-
-        E_s50_theta0 = -E_x50_theta0
-        E_s50_theta1 = 1.0 - E_x50_theta1
-
-    else:
-        raise ValueError("mode must be 'raw' or 'log'")
-
-    return dict(
-        theta0=theta0,
-        theta1=theta1,
-        x50=x50,
-        s50=s50,
-        E_x50_theta0=E_x50_theta0,
-        E_x50_theta1=E_x50_theta1,
-        E_s50_theta0=E_s50_theta0,
-        E_s50_theta1=E_s50_theta1,
-    )
-
-
-# ------------------------------------------------------------
-# Table for 4 panels
-# ------------------------------------------------------------
-def elasticity_table_4panels(
-    P,
-    keys=("FULL-RAW", "FULL-LOG", "TRIM-RAW", "TRIM-LOG"),
-    make_plots=True
-):
-    """
-    Build elasticity table for all panels.
-
-    Notes
-    -----
-    This expects each P[key] entry to contain:
-        - "theta" : fitted parameter vector [theta0, theta1]
-        - "transform" : "raw" or "log"
-    """
-    import pandas as pd
-
-    rows = []
-
-    for key in keys:
-        pk = P[key]
-        theta = np.asarray(pk["theta"]).reshape(2)
-        transform = pk["transform"]
-
-        res = elasticity_x50_s50(theta, mode=transform)
-
-        rows.append({
-            "Panel": key,
-            "transform": transform,
-            **res
-        })
-
-    df = pd.DataFrame(rows)
-
-    if make_plots:
-        plot_x50_values(df)
-        plot_s50_values(df)
-        plot_x50_theta1_elasticity(df)
-        plot_s50_theta1_elasticity(df)
-
-    return df
-
-
-# ------------------------------------------------------------
-# Plots
-# ------------------------------------------------------------
-def plot_x50_values(df):
-    fig, ax = plt.subplots(figsize=(7, 4))
-    ax.bar(df["Panel"], df["x50"])
-    ax.set_ylabel("x50")
-    ax.set_title("x50 across panels")
-    plt.xticks(rotation=30)
-    plt.tight_layout()
-    plt.show()
-
-
-def plot_s50_values(df):
-    fig, ax = plt.subplots(figsize=(7, 4))
-    ax.bar(df["Panel"], df["s50"])
-    ax.set_ylabel("s50")
-    ax.set_title("s50 across panels")
-    plt.xticks(rotation=30)
-    plt.tight_layout()
-    plt.show()
-
-
-def plot_x50_theta1_elasticity(df):
-    fig, ax = plt.subplots(figsize=(7, 4))
-    ax.bar(df["Panel"], df["E_x50_theta1"])
-    ax.set_ylabel("Elasticity")
-    ax.set_title("Elasticity of x50 w.r.t. theta1")
-    plt.xticks(rotation=30)
-    plt.tight_layout()
-    plt.show()
-
-
-def plot_s50_theta1_elasticity(df):
-    fig, ax = plt.subplots(figsize=(7, 4))
-    ax.bar(df["Panel"], df["E_s50_theta1"])
-    ax.set_ylabel("Elasticity")
-    ax.set_title("Elasticity of s50 w.r.t. theta1")
-    plt.xticks(rotation=30)
-    plt.tight_layout()
-    plt.show()
-# ------------------------------------------------------------
-# logistic helpers for noise analysis
-# ------------------------------------------------------------
-
-# ============================================================
-# NOISE ANALYSIS FOR LOGISTIC MODEL
-# Correct x50 for RAW and LOG models
-# ============================================================
-
-import os
-import numpy as np
-import matplotlib.pyplot as plt
-import matplotlib.lines as mlines
-
-
-# ------------------------------------------------------------
-# logistic fit / prediction / x50
-# CONSISTENT WITH MAIN LOGISTIC ANALYSIS
-# ------------------------------------------------------------
-
-def fit_logistic_x(x_raw, y, transform="raw", l2=1e-8):
-    x_raw = np.clip(np.asarray(x_raw, float).ravel(), 1e-12, None)
-    y = np.asarray(y, int).ravel()
-
-    if transform == "raw":
-        x_model = x_raw
-    elif transform == "log":
-        x_model = np.log(x_raw)
-    else:
-        raise ValueError("transform must be 'raw' or 'log'")
-
-    return fit_newton(x_model, y, l2=l2)
-
-
-def predict_curve_x(b, x_grid_raw, transform="raw"):
-    x_grid_raw = np.clip(np.asarray(x_grid_raw, float), 1e-12, None)
-
-    if transform == "raw":
-        x_model = x_grid_raw
-    elif transform == "log":
-        x_model = np.log(x_grid_raw)
-    else:
-        raise ValueError("transform must be 'raw' or 'log'")
-
-    return model_p(x_model, b)
-
-
-def x50_from_b(b, transform="raw"):
-    b = np.asarray(b, float).reshape(2)
-    x50_model = x50(b)
-
-    if not np.isfinite(x50_model):
-        return np.nan
-
-    if transform == "raw":
-        return float(x50_model)
-    elif transform == "log":
-        return float(np.exp(x50_model))
-    else:
-        raise ValueError("transform must be 'raw' or 'log'")
-
-
-def check_noise_x50(pack):
-    b = np.asarray(pack["b_clean"], float).reshape(2)
-    transform = pack["transform"]
-    x50_raw = pack["x50"]
-
-    x50_model = x50_raw if transform == "raw" else np.log(x50_raw)
-    p50 = model_p(np.array([x50_model]), b)[0]
-
-    print(
-        "transform =", transform,
-        "| x50_raw =", x50_raw,
-        "| P(x50) =", p50
-    )
-
-
-# ------------------------------------------------------------
-# noise helpers
-# ------------------------------------------------------------
-
-def add_noise_mult(x, sigma, rng):
-    x = np.asarray(x, float)
-    return np.clip(x * np.exp(rng.normal(0, sigma, size=x.shape)), 1e-12, None)
-
-
-def add_noise_add(x, sigma, rng):
-    x = np.asarray(x, float)
-    return np.clip(x + rng.normal(0, sigma, size=x.shape), 1e-12, None)
-
-
-def band_quantiles(curves):
-    C = np.vstack(curves)
-    return np.quantile(C, [0.025, 0.5, 0.975], axis=0)
-
-
-# ------------------------------------------------------------
-# build noise bands
-# ------------------------------------------------------------
-
-def noise_logistic_bands(
-    x_raw,
-    y,
-    transform="raw",
-    sigma_mult=0.129,
-    sigma_add=0.144,
-    x_max=5,
-    grid_n=1000,
-    n_refit=200,
-    n_tta=3000,
-    seed=1234,
-    l2=1e-8,
-):
-    rng = np.random.default_rng(seed)
-
-    x_raw = np.clip(np.asarray(x_raw, float).ravel(), 1e-12, None)
-    y = np.asarray(y).astype(int).ravel()
-
-    xc = np.linspace(1e-12, x_max, grid_n)
-
-    b_clean = fit_logistic_x(x_raw, y, transform=transform, l2=l2)
-    clean = predict_curve_x(b_clean, xc, transform=transform)
-    x50_val = x50_from_b(b_clean, transform=transform)
-
-    curves = []
-    for _ in range(n_refit):
-        xn = add_noise_mult(x_raw, sigma_mult, rng)
-        bn = fit_logistic_x(xn, y, transform=transform, l2=l2)
-        curves.append(predict_curve_x(bn, xc, transform=transform))
-    mult_refit = band_quantiles(curves)
-
-    curves = []
-    for _ in range(n_tta):
-        xn = add_noise_mult(xc, sigma_mult, rng)
-        curves.append(predict_curve_x(b_clean, xn, transform=transform))
-    mult_tta = band_quantiles(curves)
-
-    curves = []
-    for _ in range(n_refit):
-        xn = add_noise_add(x_raw, sigma_add, rng)
-        bn = fit_logistic_x(xn, y, transform=transform, l2=l2)
-        curves.append(predict_curve_x(bn, xc, transform=transform))
-    add_refit = band_quantiles(curves)
-
-    curves = []
-    for _ in range(n_tta):
-        xn = add_noise_add(xc, sigma_add, rng)
-        curves.append(predict_curve_x(b_clean, xn, transform=transform))
-    add_tta = band_quantiles(curves)
-
-    return {
-        "xc": xc,
-        "clean": clean,
-        "x50": x50_val,
-        "b_clean": b_clean,
-        "transform": transform,
-        "l2": float(l2),
-        "mult_refit": mult_refit,
-        "mult_tta": mult_tta,
-        "add_refit": add_refit,
-        "add_tta": add_tta,
-    }
-
-    from scipy.ndimage import gaussian_filter1d
-
-    lo = np.quantile(curves, 0.025, axis=0)
-    md = np.quantile(curves, 0.500, axis=0)
-    hi = np.quantile(curves, 0.975, axis=0)
-
-# smooth boundaries
-    lo = gaussian_filter1d(lo, sigma=8)
-    md = gaussian_filter1d(md, sigma=8)
-    hi = gaussian_filter1d(hi, sigma=8)
-
-    return lo, md, hi
-
-# ------------------------------------------------------------
-# legend
-# ------------------------------------------------------------
-
-def noise_legend_handles():
-    return [
-        mlines.Line2D([], [], marker="o", color="#2b8cbe",
-                      linestyle="None", markersize=7, label="NC data"),
-        mlines.Line2D([], [], marker="o", color="#d7301f",
-                      linestyle="None", markersize=7, label="AE data"),
-        mlines.Line2D([], [], color="black", lw=2.2, label="clean fit"),
-        mlines.Line2D([], [], color="#1f78b4", lw=6, alpha=0.24,
-                      label="refit band, multiplicative noise"),
-        mlines.Line2D([], [], color="#1f78b4", lw=6, alpha=0.10,
-                      label="TTA band, multiplicative noise"),
-        mlines.Line2D([], [], color="#e66101", lw=6, alpha=0.24,
-                      label="refit band, additive noise"),
-        mlines.Line2D([], [], color="#e66101", lw=6, alpha=0.10,
-                      label="TTA band, additive noise"),
-        mlines.Line2D([], [], color="#666666", ls="--", lw=1.2,
-                      label=r"$x_{50}$"),
-    ]
-
-
-# ------------------------------------------------------------
-# plot one panel
-# ------------------------------------------------------------
-
-def plot_noise_panel(ax, pack, kind="mult", label="A", X=None, y=None):
-    COL_MULT = "#1f78b4"
-    COL_ADD  = "#e66101"
-    COL_NC   = "#2b8cbe"
-    COL_AE   = "#d7301f"
-
-    xc = pack["xc"]
-    clean = pack["clean"]
-    x50_val = pack["x50"]
-
-    if kind == "mult":
-        refit = pack["mult_refit"]
-        tta = pack["mult_tta"]
-        color = COL_MULT
-    elif kind == "add":
-        refit = pack["add_refit"]
-        tta = pack["add_tta"]
-        color = COL_ADD
-    else:
-        raise ValueError("kind must be 'mult' or 'add'")
-
-    lo_r, _, hi_r = refit
-    lo_t, _, hi_t = tta
-
-    ax.fill_between(xc, lo_t, hi_t, color=color, alpha=0.10, zorder=1)
-    ax.fill_between(xc, lo_r, hi_r, color=color, alpha=0.24, zorder=2)
-
-    ax.plot(xc, lo_r, color=color, lw=1.0, alpha=0.65, zorder=3)
-    ax.plot(xc, hi_r, color=color, lw=1.0, alpha=0.65, zorder=3)
-
-    ax.plot(xc, clean, color="black", lw=2.2, zorder=5)
-    ax.axvline(x50_val, color="#666666", ls="--", lw=1.2, alpha=0.9, zorder=4)
-
-    lo_r_x = np.interp(x50_val, xc, lo_r)
-    hi_r_x = np.interp(x50_val, xc, hi_r)
-    lo_t_x = np.interp(x50_val, xc, lo_t)
-    hi_t_x = np.interp(x50_val, xc, hi_t)
-
-    if X is not None and y is not None:
-        X = np.asarray(X).ravel()
-        y = np.asarray(y).astype(int).ravel()
-
-        ax.scatter(
-            X[y == 0], np.zeros(np.sum(y == 0)),
-            color=COL_NC, s=24, alpha=0.75,
-            edgecolors="none", zorder=7
-        )
-        ax.scatter(
-            X[y == 1], np.ones(np.sum(y == 1)),
-            color=COL_AE, s=24, alpha=0.75,
-            edgecolors="none", zorder=7
-        )
-
-    ax.text(0.03, 0.97, label, transform=ax.transAxes,
-            ha="left", va="top", fontsize=15)
-
-    variant_txt = "FULL" if label in ["A", "B"] else "TRIM"
-    d_ref = hi_r_x - lo_r_x
-    d_tta = hi_t_x - lo_t_x
-
-    info_txt = (
-        f"{variant_txt}\n"
-        f"$x_{{50}}$={x50_val:.2f}\n"
-        f"$\\Delta r$={d_ref:.2f}  $\\Delta t$={d_tta:.2f}"
-    )
-
-    ax.text(
-        0.02, 0.14,
-        info_txt,
-        transform=ax.transAxes,
-        fontsize=10,
-        color="#222",
-        ha="left", va="bottom",
-        bbox=dict(facecolor="white", edgecolor=color,
-                  boxstyle="square,pad=0.25", alpha=0.9)
-    )
-
-    ax.set_xlim(0, xc.max())
-    ax.set_ylim(-0.05, 1.05)
-    ax.grid(alpha=0.25)
-    ax.tick_params(axis="both", labelsize=10)
-
-
-# ------------------------------------------------------------
-# full noise figure
-# ------------------------------------------------------------
-
-def plot_noise_figure(
-    pack_full,
-    pack_trim,
-    X_full,
-    y_full,
-    X_trim,
-    y_trim,
-    figsize=(12, 9),
-    dpi=300,
-):
-    fig, axes = plt.subplots(
-        2, 2,
-        figsize=figsize,
-        dpi=dpi,
-        sharex=True,
-        sharey=True
-    )
-
-    axes = axes.ravel()
-
-    plot_noise_panel(axes[0], pack_full, kind="mult", label="A", X=X_full, y=y_full)
-    plot_noise_panel(axes[1], pack_full, kind="add",  label="B", X=X_full, y=y_full)
-    plot_noise_panel(axes[2], pack_trim, kind="mult", label="C", X=X_trim, y=y_trim)
-    plot_noise_panel(axes[3], pack_trim, kind="add",  label="D", X=X_trim, y=y_trim)
-
-    axes[0].set_ylabel(r"$P(\mathrm{AE}\mid X=x)$", fontsize=12)
-    axes[2].set_ylabel(r"$P(\mathrm{AE}\mid X=x)$", fontsize=12)
-    axes[2].set_xlabel(r"$X$", fontsize=12)
-    axes[3].set_xlabel(r"$X$", fontsize=12)
-
-    handles = noise_legend_handles()
-
-    leg = axes[3].legend(
-        handles=handles,
-        loc="lower right",
-        bbox_to_anchor=(0.97, 0.05),
-        fontsize=9,
-        frameon=True
-    )
-
-    frame = leg.get_frame()
-    frame.set_facecolor("white")
-    frame.set_edgecolor("#bdbdbd")
-    frame.set_linewidth(0.8)
-
-    fig.tight_layout()
-    return fig, axes
-
-
-# ------------------------------------------------------------
-# wrapper
-# ------------------------------------------------------------
-
-def make_noise_figure(
-    X_full,
-    y_full,
-    X_trim,
-    y_trim,
-    transform="raw",
-    sigma_mult=0.129,
-    sigma_add=0.144,
-    x_max=5,
-    grid_n=1000,
-    n_refit=1100,
-    n_tta=10000,
-    seed=1234,
-    l2=1e-8,
-    save_path=None,
-):
-    pack_full = noise_logistic_bands(
-        X_full, y_full,
-        transform=transform,
-        sigma_mult=sigma_mult,
-        sigma_add=sigma_add,
-        x_max=x_max,
-        grid_n=grid_n,
-        n_refit=n_refit,
-        n_tta=n_tta,
-        seed=seed,
-        l2=l2,
-    )
-
-    pack_trim = noise_logistic_bands(
-        X_trim, y_trim,
-        transform=transform,
-        sigma_mult=sigma_mult,
-        sigma_add=sigma_add,
-        x_max=x_max,
-        grid_n=grid_n,
-        n_refit=n_refit,
-        n_tta=n_tta,
-        seed=seed + 100,
-        l2=l2,
-    )
-
-    print("FULL n:", len(X_full), "x50:", pack_full["x50"])
-    print("TRIM n:", len(X_trim), "x50:", pack_trim["x50"])
-    check_noise_x50(pack_full)
-    check_noise_x50(pack_trim)
-
-    fig, axes = plot_noise_figure(
-        pack_full, pack_trim,
-        X_full, y_full,
-        X_trim, y_trim,
-        figsize=(12, 9),
-        dpi=300,
-    )
-
-    if save_path is not None:
-        folder = os.path.dirname(save_path)
-        if folder:
-            os.makedirs(folder, exist_ok=True)
-
-        fig.savefig(f"{save_path}.png", dpi=300, bbox_inches="tight")
-        fig.savefig(f"{save_path}.pdf", bbox_inches="tight")
-
-    return fig, axes, pack_full, pack_trim

+ 0 - 0
notes/20250606_minutes.txt → meetings/minutes/20250606_minutes.txt


+ 0 - 0
Task → meetings/minutes/20250628_tasks.txt


+ 0 - 0
Meetings Photos/Note 1.jpg → meetings/photos/Note 1.jpg


+ 0 - 0
Meetings Photos/Note 2.jpg → meetings/photos/Note 2.jpg


+ 0 - 0
Meetings Photos/Note 3.jpg → meetings/photos/Note 3.jpg


+ 0 - 0
Meetings Photos/meeting1.png → meetings/photos/meeting1.png


+ 0 - 0
Meetings Photos/meeting2.png → meetings/photos/meeting2.png


+ 0 - 0
Meetings Photos/meeting3.jpg → meetings/photos/meeting3.jpg


Разница между файлами не показана из-за своего большого размера
+ 586 - 0
notebooks/logit_all_models.ipynb


Разница между файлами не показана из-за своего большого размера
+ 5821 - 0
notebooks/logit_mono-cubic4paper.ipynb


Разница между файлами не показана из-за своего большого размера
+ 1193 - 0
notebooks/logit_review_boots.ipynb


+ 0 - 0
Instruction_Manual.txt → notes/Instruction_Manual.txt


+ 0 - 0
python/logistic/notes/comment_results.tex → notes/comment_on_logistic_regression_results.tex


+ 0 - 0
notes/PipeLine.ipynb → notes/pipeline_for_cond_prob_modeling.ipynb


+ 0 - 0
python/logistic/notes/refs.bib → notes/refs.bib


+ 0 - 13
paper_MD/Makefile

@@ -1,13 +0,0 @@
-DOCUMENT = risk_modeling
-
-all: $(DOCUMENT).pdf
-
-$(DOCUMENT).pdf: $(DOCUMENT).tex
-	pdflatex $(DOCUMENT).tex
-	bibtex $(DOCUMENT) || true
-	pdflatex $(DOCUMENT).tex
-	pdflatex $(DOCUMENT).tex
-
-clean:
-	rm -f $(DOCUMENT).aux $(DOCUMENT).bbl $(DOCUMENT).blg $(DOCUMENT).log $(DOCUMENT).out $(DOCUMENT).pdf $(DOCUMENT).toc
-

BIN
paper_MD/archive/IOPGraphicsGuidelines.pdf


BIN
paper_MD/archive/IOPLaTeXGuidelines.pdf


Разница между файлами не показана из-за своего большого размера
+ 0 - 222
paper_MD/archive/IOPLaTeXGuidelines.tex


BIN
paper_MD/figs/Bayes_bs_Gauss_bowel.pdf


BIN
paper_MD/figs/Bayes_bs_Gauss_lung.pdf


BIN
paper_MD/figs/Bayes_bs_Gauss_thyroid.pdf


BIN
paper_MD/figs/Bayes_bs_log_normal_bowel.pdf


BIN
paper_MD/figs/Bayes_bs_log_normal_lung.pdf


BIN
paper_MD/figs/Bayes_bs_log_normal_thyroid.pdf


BIN
paper_MD/figs/logit_boots.pdf


BIN
paper_MD/figs/logit_boots_sel.pdf


BIN
paper_MD/figs/logit_boots_zoom.pdf


BIN
paper_MD/figs/logit_bs_bowel.pdf


BIN
paper_MD/figs/logit_bs_lung.pdf


BIN
paper_MD/figs/logit_bs_thyroid.pdf


BIN
paper_MD/figs/logit_mvn.pdf


BIN
paper_MD/figs/logit_mvn_bowel.pdf


BIN
paper_MD/figs/logit_mvn_lung.pdf


BIN
paper_MD/figs/logit_mvn_thyroid.pdf


+ 0 - 87
paper_MD/iopams.sty

@@ -1,87 +0,0 @@
-%% 
-%% This is file `iopams.sty'
-%% File to include AMS fonts and extra definitions for bold greek 
-%% characters for use with iopart.cls
-%%
-\NeedsTeXFormat{LaTeX2e}
-\ProvidesPackage{iopams}[1997/02/13 v1.0]
-\RequirePackage{amsgen}[1995/01/01]
-\RequirePackage{amsfonts}[1995/01/01]
-\RequirePackage{amssymb}[1995/01/01]
-\RequirePackage{amsbsy}[1995/01/01]
-%
-\iopamstrue   % \newif\ifiopams in iopart.cls & iopbk2e.cls
-%             % allows optional text to be in author guidelines
-%
-% Bold lower case Greek letters
-%
-\newcommand{\balpha}{\boldsymbol{\alpha}}
-\newcommand{\bbeta}{\boldsymbol{\beta}}
-\newcommand{\bgamma}{\boldsymbol{\gamma}}
-\newcommand{\bdelta}{\boldsymbol{\delta}}
-\newcommand{\bepsilon}{\boldsymbol{\epsilon}}
-\newcommand{\bzeta}{\boldsymbol{\zeta}}
-\newcommand{\bfeta}{\boldsymbol{\eta}}
-\newcommand{\btheta}{\boldsymbol{\theta}}
-\newcommand{\biota}{\boldsymbol{\iota}}
-\newcommand{\bkappa}{\boldsymbol{\kappa}}
-\newcommand{\blambda}{\boldsymbol{\lambda}}
-\newcommand{\bmu}{\boldsymbol{\mu}}
-\newcommand{\bnu}{\boldsymbol{\nu}}
-\newcommand{\bxi}{\boldsymbol{\xi}}
-\newcommand{\bpi}{\boldsymbol{\pi}}
-\newcommand{\brho}{\boldsymbol{\rho}}
-\newcommand{\bsigma}{\boldsymbol{\sigma}}
-\newcommand{\btau}{\boldsymbol{\tau}}
-\newcommand{\bupsilon}{\boldsymbol{\upsilon}}
-\newcommand{\bphi}{\boldsymbol{\phi}}
-\newcommand{\bchi}{\boldsymbol{\chi}}
-\newcommand{\bpsi}{\boldsymbol{\psi}}
-\newcommand{\bomega}{\boldsymbol{\omega}}
-\newcommand{\bvarepsilon}{\boldsymbol{\varepsilon}}
-\newcommand{\bvartheta}{\boldsymbol{\vartheta}}
-\newcommand{\bvaromega}{\boldsymbol{\varomega}}
-\newcommand{\bvarrho}{\boldsymbol{\varrho}}
-\newcommand{\bvarzeta}{\boldsymbol{\varsigma}}  %NB really sigma
-\newcommand{\bvarsigma}{\boldsymbol{\varsigma}}
-\newcommand{\bvarphi}{\boldsymbol{\varphi}}
-%
-% Bold upright capital Greek letters
-%
-\newcommand{\bGamma}{\boldsymbol{\Gamma}}
-\newcommand{\bDelta}{\boldsymbol{\Delta}}
-\newcommand{\bTheta}{\boldsymbol{\Theta}}
-\newcommand{\bLambda}{\boldsymbol{\Lambda}}
-\newcommand{\bXi}{\boldsymbol{\Xi}}
-\newcommand{\bPi}{\boldsymbol{\Pi}}
-\newcommand{\bSigma}{\boldsymbol{\Sigma}}
-\newcommand{\bUpsilon}{\boldsymbol{\Upsilon}}
-\newcommand{\bPhi}{\boldsymbol{\Phi}}
-\newcommand{\bPsi}{\boldsymbol{\Psi}}
-\newcommand{\bOmega}{\boldsymbol{\Omega}}
-%
-% Bold versions of miscellaneous symbols
-%
-\newcommand{\bpartial}{\boldsymbol{\partial}}
-\newcommand{\bell}{\boldsymbol{\ell}}
-\newcommand{\bimath}{\boldsymbol{\imath}}
-\newcommand{\bjmath}{\boldsymbol{\jmath}}
-\newcommand{\binfty}{\boldsymbol{\infty}}
-\newcommand{\bnabla}{\boldsymbol{\nabla}}
-\newcommand{\bdot}{\boldsymbol{\cdot}}
-%
-% Symbols for caption
-%
-\renewcommand{\opensquare}{\mbox{$\square$}}
-\renewcommand{\opentriangle}{\mbox{$\vartriangle$}}
-\renewcommand{\opentriangledown}{\mbox{$\triangledown$}}
-\renewcommand{\opendiamond}{\mbox{$\lozenge$}}
-\renewcommand{\fullsquare}{\mbox{$\blacksquare$}}
-\newcommand{\fulldiamond}{\mbox{$\blacklozenge$}}
-\newcommand{\fullstar}{\mbox{$\bigstar$}}
-\newcommand{\fulltriangle}{\mbox{$\blacktriangle$}}
-\newcommand{\fulltriangledown}{\mbox{$\blacktriangledown$}}
-
-\endinput
-%% 
-%% End of file `iopams.sty'.

+ 0 - 1722
paper_MD/iopart-num.bst

@@ -1,1722 +0,0 @@
-% iopart-num.bst -- BibTeX style for IOP journals (Harvard-like numeric style)
-% M. A. Caprio
-%
-% DESCRIPTION
-%
-%   Further documenation may be found in iopart-num.pdf.
-%
-%   Available from CTAN as /biblio/bibtex/contrib/iopart-num.
-%
-% COPYRIGHT/LICENSE
-%
-%   Copyright 2009 M. A. Caprio
-%
-%   This work may be distributed and/or modified under the
-%   conditions of the LaTeX Project Public License, either 
-%   version 1.3 of this license or (at your option) any later 
-%   version.  The latest version of this license is in
-%     http://www.latex-project.org/lppl.txt
-%   and version 1.3 or later is part of all distributions of 
-%   LaTeX version 2005/12/01 or later.
-%
-%   This work has the LPPL maintenance status "maintained".
-% 
-%   The Current Maintainer of this work is the author.
-%
-%   The contents of this work are listed in the README file.
-%
-% HISTORY
-% 
-% Version 1.0 (2005/07/11)
-%   Created using custom-bib (merlin.mbs), with following manual modifications:
-%   -- remove trailing period from predefined volume, page, etc., abbreviations
-%   -- provide command \newblock to fix incompatibility between natbib
-%      and iopart (as of iopart version 1996/06/10) 
-%   -- move edition after booktitle
-%   -- add version identifier to generated output
-%   -- for incollection and inproceedings, move volume from after publisher to before
-%   -- for any series with number, number after series
-% Version 2.0 (2006/12/21)
-%   -- define section field for proper formatting of lettered journal sections 
-%      (suggested by Chris Latham)
-%   -- suppress printing of number for article, but provide issue field
-%      for periodicals with issue-based page numbering (suggested by Chris Latham)
-%   -- patch remove.dots to not strip "\." control sequence (bug reported by Kevin Bube)
-%   -- define epilog field (undocumented)
-%   -- delete predefined computer science journal names
-%   -- bring book volume+number or series+number formatting into IOP form
-%   -- for book, inbook, and proceedings with editors but no author, fix formating of editors
-%   -- for incollection and inproceedings, put editors in correct location
-%   -- for journal: use same page formatting even if volume missing
-% Version 2.1 (2009/01/22)
-%   -- for incollection and inproceedings: support title of chapter (not appropriate 
-%      to inbook)
-%   -- for book, proceedings, etc.: support volumetitle for multivolume book
-%
-% LIMITATIONS
-%
-% Still not in IOP form: 
-%   -- for incollection and inproceedings, editors initials should preceed rather 
-%      than follow last name
-% Other:
-%   -- hyphenated first names lose hyphen
-
-%% This is file `iopart-num.bst',
-%% generated with the docstrip utility.
-%%
-%% The original source files were:
-%%
-%% merlin.mbs  (with options: `seq-no,nm-rv,dt-beg,yr-blk,xmth,yrp-x,jtit-x,vol-bf,volp-blk,num-xser,jnm-x,add-pub,pub-par,pre-pub,isbn,issn,blk-com,com-blank,fin-bare,pp,ed,abr,ednx,mth-bare,ord,jabr,and-xcom,etal-it,revdata,eprint,url,url-blk')
-%% ----------------------------------------
-%% *** Institute of Physics (IOP) journals; Harvard-like numeric style ***
-%% 
-%% Copyright 1994-2002 Patrick W Daly
- % ===============================================================
- % IMPORTANT NOTICE:
- % This bibliographic style (bst) file has been generated from one or
- % more master bibliographic style (mbs) files, listed above.
- %
- % This generated file can be redistributed and/or modified under the terms
- % of the LaTeX Project Public License Distributed from CTAN
- % archives in directory macros/latex/base/lppl.txt; either
- % version 1 of the License, or any later version.
- % ===============================================================
- % Name and version information of the main mbs file:
- % \ProvidesFile{merlin.mbs}[2002/10/21 4.05 (PWD, AO, DPC)]
- %   For use with BibTeX version 0.99a or later
- %-------------------------------------------------------------------
- % This bibliography style file is intended for texts in ENGLISH
- % This is a numerical citation style, and as such is standard LaTeX.
- % It requires no extra package to interface to the main text.
- % The form of the \bibitem entries is
- %   \bibitem{key}...
- % Usage of \cite is as follows:
- %   \cite{key} ==>>          [#]
- %   \cite[chap. 2]{key} ==>> [#, chap. 2]
- % where # is a number determined by the ordering in the reference list.
- % The order in the reference list is that by which the works were originally
- %   cited in the text, or that in the database.
- %---------------------------------------------------------------------
-
-ENTRY
-  { address
-    archive
-    author
-    booktitle
-    chapter
-    collaboration
-    edition
-    editor
-    eid
-    eprint
-    howpublished
-    institution
-    isbn
-    issn
-    journal
-    key
-    month
-    note
-    number
-    numpages
-    organization
-    pages
-    publisher
-    school
-    series
-    title
-    type
-    url
-    volume
-    year
-%mc
-    issue
-    section
-    epilog
-    volumetitle
-    transjournal
-    transsection
-    transvolume
-    transnumber
-    transissue
-    transpages
-    transyear
-  }
-  {}
-  { label }
-
-FUNCTION {not}
-{   { #0 }
-    { #1 }
-  if$
-}
-FUNCTION {and}
-{   'skip$
-    { pop$ #0 }
-  if$
-}
-FUNCTION {or}
-{   { pop$ #1 }
-    'skip$
-  if$
-}
-
-%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
-% mc utilities
-%   require merlin.mbs logical operators and field.or.null
-%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
-
-% hang -- {hang} suspends execution, for debugging purposes
-%   Note that not all pending output may have been flushed.
-FUNCTION {hang}
-{
-  {#1} {skip$} while$
-}
-
-% string.length -- {s string.length} returns the true character length of s
-%   In contrast, text.length$ gives special treatment to LaTeX
-%   accents ("special characters") and braces.
-%   Example:   "" string.length     -> 0
-%   Example:   "hello" string.length    -> 5
-
-STRINGS {string.length.s }
-INTEGERS {string.length.i }
-FUNCTION {string.length}
-{
- 'string.length.s :=
- #0 'string.length.i :=
-  {
-    string.length.s #1 #1 substring$ "" = not
-  }
-  { 
-   string.length.i #1 + 'string.length.i := 
-   string.length.s #2 global.max$ substring$ 'string.length.s :=
-  }
-  while$
-  string.length.i
-}
-
-% shared working variables for stripping functions
-STRINGS { strip.s strip.t }
-INTEGERS { strip.i }
-
-% strip.leading -- {s t strip.leading} strips t from s if it appears
-%   as an initial substring 
-%   Example:   "abcdef" "abc" strip.leading   -> "def"
-%   Example:   "abcdef" "xyz" strip.leading   -> "abcdef"
-
-FUNCTION{strip.leading}
-{
-  'strip.t :=
-  'strip.s :=
-  strip.t string.length 'strip.i :=
-  strip.s #1 strip.i substring$ strip.t =
-    { strip.s strip.i #1 + global.max$ substring$ }
-    { strip.s }
-  if$
-}
-
-% strip.trailing -- {s t strip.trailing} strips t from s if it appears
-%   as a terminal substring 
-%   Example:   "abcdef" "def" strip.trailing  -> "abc"
-%   Example:   "abcdef" "xyz" strip.trailing  -> "abcdef"
-FUNCTION{strip.trailing}
-{
-  'strip.t :=
-  'strip.s :=
-  strip.t string.length 'strip.i :=
-  strip.s #-1 strip.i substring$ strip.t =
-    { strip.s #-1 strip.i - global.max$ substring$ }
-    { strip.s }
-  if$
-}
-
-% trim -- {s trim} strips any trailing whitespace from s
-%   Example:   "abcdef  " trim  -> "abcdef"
-STRINGS {trim.s trim.t}
-FUNCTION{trim}
-{
-  'trim.s :=
-  {
-   trim.s #-1 #1 substring$ 'trim.t :=
-   trim.t empty$ trim.t string.length #0 > and
-  }
-    { trim.s #-2 global.max$ substring$ 'trim.s := }
-  while$
-  trim.s
-}
-
-%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
-
-
-INTEGERS { output.state before.all mid.sentence after.sentence after.block }
-FUNCTION {init.state.consts}
-{ #0 'before.all :=
-  #1 'mid.sentence :=
-  #2 'after.sentence :=
-  #3 'after.block :=
-}
-STRINGS { s t}
-
-FUNCTION {output.nonnull}
-{ 's :=
-  output.state mid.sentence =
-    { " " * write$ }
-    { output.state after.block =
-        { add.period$ write$
-          newline$
-          "\newblock " write$
-        }
-        { output.state before.all =
-            'write$
-            { add.period$ " " * write$ }
-          if$
-        }
-      if$
-      mid.sentence 'output.state :=
-    }
-  if$
-  s
-}
-FUNCTION {output}
-{ duplicate$ empty$
-    'pop$
-    'output.nonnull
-  if$
-}
-FUNCTION {output.check}
-{ 't :=
-  duplicate$ empty$
-    { pop$ "empty " t * " in " * cite$ * warning$ }
-    'output.nonnull
-  if$
-}
-
-%mc
-FUNCTION {format.epilog}
-{ epilog duplicate$ empty$
-    { pop$ }
-    { * }
-  if$
-}
-%mc end
-
-
-FUNCTION {fin.entry}
-{   
-%mc
-format.epilog 
-%mc end
-  duplicate$ empty$
-    'pop$
-    'write$
-  if$
-  newline$
-}
-
-FUNCTION {new.block}
-{ output.state before.all =
-    'skip$
-    { after.block 'output.state := }
-  if$
-}
-FUNCTION {new.sentence}
-{ output.state after.block =
-    'skip$
-    { output.state before.all =
-        'skip$
-        { after.sentence 'output.state := }
-      if$
-    }
-  if$
-}
-FUNCTION {add.blank}
-{  " " * before.all 'output.state :=
-}
-
-FUNCTION {date.block}
-{
-  add.blank
-}
-
-STRINGS {z}
-FUNCTION {remove.dots}
-{ 'z :=
-  ""
-  { z empty$ not }
-  {
-%mc patch to preserve the control sequence \. if it appears in a name
-   z #1 #2 substring$ "\." = 
-      { 
-        % process "\." sequence
-        z #3 global.max$ substring$ 'z :=
-        "\." * 
-      }
-      {    
-        % process regular character
-        z #1 #1 substring$
-        z #2 global.max$ substring$ 'z :=
-        duplicate$ "." = 'pop$
-         { * }
-        if$
-      }
-    if$
-%mc
-  }
-  while$
-}
-FUNCTION {new.block.checka}
-{ empty$
-    'skip$
-    'new.block
-  if$
-}
-FUNCTION {new.block.checkb}
-{ empty$
-  swap$ empty$
-  and
-    'skip$
-    'new.block
-  if$
-}
-FUNCTION {new.sentence.checka}
-{ empty$
-    'skip$
-    'new.sentence
-  if$
-}
-FUNCTION {new.sentence.checkb}
-{ empty$
-  swap$ empty$
-  and
-    'skip$
-    'new.sentence
-  if$
-}
-FUNCTION {field.or.null}
-{ duplicate$ empty$
-    { pop$ "" }
-    'skip$
-  if$
-}
-FUNCTION {emphasize}
-{ duplicate$ empty$
-    { pop$ "" }
-    { "{\em " swap$ * "\/}" * }
-  if$
-}
-FUNCTION {bolden}
-{ duplicate$ empty$
-    { pop$ "" }
-    { "{\bf " swap$ * "}" * }
-  if$
-}
-FUNCTION {tie.or.space.prefix}
-{ duplicate$ text.length$ #3 <
-    { "~" }
-    { " " }
-  if$
-  swap$
-}
-
-FUNCTION {capitalize}
-{ "u" change.case$ "t" change.case$ }
-
-FUNCTION {space.word}
-{ " " swap$ * " " * }
- % Here are the language-specific definitions for explicit words.
- % Each function has a name bbl.xxx where xxx is the English word.
- % The language selected here is ENGLISH
-FUNCTION {bbl.and}
-{ "and"}
-
-FUNCTION {bbl.etal}
-{ "et~al." }
-
-FUNCTION {bbl.editors}
-{ "eds" }
-
-FUNCTION {bbl.editor}
-{ "ed" }
-
-FUNCTION {bbl.edby}
-{ "edited by" }
-
-FUNCTION {bbl.edition}
-{ "ed" }
-
-FUNCTION {bbl.volume}
-{ "vol" }
-
-FUNCTION {bbl.of}
-{ "of" }
-
-FUNCTION {bbl.number}
-{ "no" }
-
-FUNCTION {bbl.nr}
-{ "no" }
-
-FUNCTION {bbl.in}
-{ "in" }
-
-FUNCTION {bbl.pages}
-{ "pp" }
-
-FUNCTION {bbl.page}
-{ "p" }
-
-FUNCTION {bbl.eidpp}
-{ "pages" }
-
-FUNCTION {bbl.chapter}
-{ "chap" }
-
-FUNCTION {bbl.techrep}
-{ "Tech. Rep." }
-
-FUNCTION {bbl.mthesis}
-{ "Master's thesis" }
-
-FUNCTION {bbl.phdthesis}
-{ "Ph.D. thesis" }
-
-FUNCTION {bbl.first}
-{ "1st" }
-
-FUNCTION {bbl.second}
-{ "2nd" }
-
-FUNCTION {bbl.third}
-{ "3rd" }
-
-FUNCTION {bbl.fourth}
-{ "4th" }
-
-FUNCTION {bbl.fifth}
-{ "5th" }
-
-FUNCTION {bbl.st}
-{ "st" }
-
-FUNCTION {bbl.nd}
-{ "nd" }
-
-FUNCTION {bbl.rd}
-{ "rd" }
-
-FUNCTION {bbl.th}
-{ "th" }
-
-MACRO {jan} {"Jan."}
-
-MACRO {feb} {"Feb."}
-
-MACRO {mar} {"Mar."}
-
-MACRO {apr} {"Apr."}
-
-MACRO {may} {"May"}
-
-MACRO {jun} {"Jun."}
-
-MACRO {jul} {"Jul."}
-
-MACRO {aug} {"Aug."}
-
-MACRO {sep} {"Sep."}
-
-MACRO {oct} {"Oct."}
-
-MACRO {nov} {"Nov."}
-
-MACRO {dec} {"Dec."}
-
-FUNCTION {eng.ord}
-{ duplicate$ "1" swap$ *
-  #-2 #1 substring$ "1" =
-     { bbl.th * }
-     { duplicate$ #-1 #1 substring$
-       duplicate$ "1" =
-         { pop$ bbl.st * }
-         { duplicate$ "2" =
-             { pop$ bbl.nd * }
-             { "3" =
-                 { bbl.rd * }
-                 { bbl.th * }
-               if$
-             }
-           if$
-          }
-       if$
-     }
-   if$
-}
-
-FUNCTION {bibinfo.check}
-{ swap$
-  duplicate$ missing$
-    {
-      pop$ pop$
-      ""
-    }
-    { duplicate$ empty$
-        {
-          swap$ pop$
-        }
-        { swap$
-          pop$
-        }
-      if$
-    }
-  if$
-}
-FUNCTION {bibinfo.warn}
-{ swap$
-  duplicate$ missing$
-    {
-      swap$ "missing " swap$ * " in " * cite$ * warning$ pop$
-      ""
-    }
-    { duplicate$ empty$
-        {
-          swap$ "empty " swap$ * " in " * cite$ * warning$
-        }
-        { swap$
-          pop$
-        }
-      if$
-    }
-  if$
-}
-%% FUNCTION {format.eprint}
-%% { eprint duplicate$ empty$
-%%     'skip$
-%%     { "\eprint"
-%%       archive empty$
-%%         'skip$
-%%         { "[" * archive * "]" * }
-%%       if$
-%%       "{" * swap$ * "}" *
-%%     }
-%%   if$
-%% }
-FUNCTION {format.eprint}
-{ eprint duplicate$ empty$
-    'skip$
-    { 
-      "(\textit{Preprint} " 
-      swap$
-       "\eprint"
-      archive empty$
-        'skip$
-        { "[" * archive * "]" * }
-      if$
-      "{" * swap$ * "}" *
-      *
-      ")"
-      *
-    }
-  if$
-}
-
-FUNCTION {format.url}
-{ url empty$
-    { "" }
-    { "\urlprefix\url{" url * "}" * }
-  if$
-}
-
-STRINGS  { bibinfo}
-INTEGERS { nameptr namesleft numnames }
-
-FUNCTION {format.names}
-{ 'bibinfo :=
-  duplicate$ empty$ 'skip$ {
-  's :=
-  "" 't :=
-  #1 'nameptr :=
-  s num.names$ 'numnames :=
-  numnames 'namesleft :=
-    { namesleft #0 > }
-    { s nameptr
-      "{vv~}{ll}{ jj}{ f{~}}"
-      format.name$
-      remove.dots
-      bibinfo bibinfo.check
-      't :=
-      nameptr #1 >
-        {
-          namesleft #1 >
-            { ", " * t * }
-            {
-              s nameptr "{ll}" format.name$ duplicate$ "others" =
-                { 't := }
-                { pop$ }
-              if$
-              t "others" =
-                {
-                  " " * bbl.etal emphasize *
-                }
-                {
-                  bbl.and
-                  space.word * t *
-                }
-              if$
-            }
-          if$
-        }
-        't
-      if$
-      nameptr #1 + 'nameptr :=
-      namesleft #1 - 'namesleft :=
-    }
-  while$
-  } if$
-}
-FUNCTION {format.names.ed}
-{
-  'bibinfo :=
-  duplicate$ empty$ 'skip$ {
-  's :=
-  "" 't :=
-  #1 'nameptr :=
-  s num.names$ 'numnames :=
-  numnames 'namesleft :=
-    { namesleft #0 > }
-    { s nameptr
-      "{f{~}~}{vv~}{ll}{ jj}"
-      format.name$
-      remove.dots
-      bibinfo bibinfo.check
-      't :=
-      nameptr #1 >
-        {
-          namesleft #1 >
-            { ", " * t * }
-            {
-              s nameptr "{ll}" format.name$ duplicate$ "others" =
-                { 't := }
-                { pop$ }
-              if$
-              t "others" =
-                {
-
-                  " " * bbl.etal emphasize *
-                }
-                {
-                  bbl.and
-                  space.word * t *
-                }
-              if$
-            }
-          if$
-        }
-        't
-      if$
-      nameptr #1 + 'nameptr :=
-      namesleft #1 - 'namesleft :=
-    }
-  while$
-  } if$
-}
-FUNCTION {format.authors}
-{ author "author" format.names
-    duplicate$ empty$ 'skip$
-    { collaboration "collaboration" bibinfo.check
-      duplicate$ empty$ 'skip$
-        { " (" swap$ * ")" * }
-      if$
-      *
-    }
-  if$
-}
-FUNCTION {get.bbl.editor}
-{ editor num.names$ #1 > 'bbl.editors 'bbl.editor if$ }
-
-FUNCTION {format.editors}
-{ editor "editor" format.names duplicate$ empty$ 'skip$
-    {
-%%      "," *
-%%      " " *
-%%      get.bbl.editor
-%%      *
-%mc
-      " " *
-      "(" *
-      get.bbl.editor
-      *
-      ")" *
-%mc end
-    }
-  if$
-}
-%mc
-FUNCTION {format.editors.inline}
-{ editor "editor" format.names duplicate$ empty$ 'skip$
-    {
-      bbl.editor " " *
-      swap$
-      *
-    }
-  if$
-}
-%mc end
-
-FUNCTION {format.isbn}
-{ isbn "isbn" bibinfo.check
-  duplicate$ empty$ 'skip$
-    {
-      "ISBN " swap$ *
-    }
-  if$
-}
-
-FUNCTION {format.issn}
-{ issn "issn" bibinfo.check
-  duplicate$ empty$ 'skip$
-    {
-      "ISSN " swap$ *
-    }
-  if$
-}
-
-FUNCTION {format.note}
-{
- note empty$
-    { "" }
-    { note #1 #1 substring$
-      duplicate$ "{" =
-        'skip$
-        { output.state mid.sentence =
-          { "l" }
-          { "u" }
-        if$
-        change.case$
-        }
-      if$
-      note #2 global.max$ substring$ * "note" bibinfo.check
-    }
-  if$
-}
-
-FUNCTION {format.title}
-{ title
-  duplicate$ empty$ 'skip$
-    { "t" change.case$ }
-  if$
-  "title" bibinfo.check
-}
-FUNCTION {output.bibitem}
-{ newline$
-  "\bibitem{" write$
-  cite$ write$
-  "}" write$
-  newline$
-  ""
-  before.all 'output.state :=
-}
-
-FUNCTION {n.dashify}
-{
-  't :=
-  ""
-    { t empty$ not }
-    { t #1 #1 substring$ "-" =
-        { t #1 #2 substring$ "--" = not
-            { "--" *
-              t #2 global.max$ substring$ 't :=
-            }
-            {   { t #1 #1 substring$ "-" = }
-                { "-" *
-                  t #2 global.max$ substring$ 't :=
-                }
-              while$
-            }
-          if$
-        }
-        { t #1 #1 substring$ *
-          t #2 global.max$ substring$ 't :=
-        }
-      if$
-    }
-  while$
-}
-
-FUNCTION {word.in}
-{ bbl.in
-  " " * }
-
-FUNCTION {format.date}
-{
-  ""
-  duplicate$ empty$
-  year  "year"  bibinfo.check duplicate$ empty$
-    { swap$ 'skip$
-        { "there's a month but no year in " cite$ * warning$ }
-      if$
-      *
-    }
-    { swap$ 'skip$
-        {
-          swap$
-          " " * swap$
-        }
-      if$
-      *
-      remove.dots
-    }
-  if$
-  duplicate$ empty$
-    'skip$
-    {
-      before.all 'output.state :=
-    " " swap$ *
-    }
-  if$
-}
-FUNCTION {format.btitle}
-{ title "title" bibinfo.check
-  duplicate$ empty$ 'skip$
-    {
-      emphasize
-    }
-  if$
-}
-FUNCTION {either.or.check}
-{ empty$
-    'pop$
-    { "can't use both " swap$ * " fields in " * cite$ * warning$ }
-  if$
-}
-FUNCTION {format.bvolume}
-{ volume empty$
-    % no volume: return blank
-    { "" }
-%%    { bbl.volume volume tie.or.space.prefix
-%%      "volume" bibinfo.check * *
-%%      series "series" bibinfo.check
-%%      duplicate$ empty$ 'pop$
-%%        { swap$ bbl.of space.word * swap$
-%%         emphasize * }
-%%      if$
-%%      "volume and number" number either.or.check
-%%    }
-%mc
-    {
-      series "series" bibinfo.check
-      empty$ 
-        % no series: must be multivolume book
-        {
-          bbl.volume volume tie.or.space.prefix "volume" bibinfo.check * *
-          volumetitle empty$
-            'skip$
-            % volumetitle: book volume has title
-            { " " volumetitle "volumetitle" bibinfo.check emphasize * * }
-          if$
-        }
-        % series: format as volume in series
-        { 
-          "(" 
-          series "series" bibinfo.check emphasize *
-          " " * bbl.volume * 
-          volume tie.or.space.prefix "volume" bibinfo.check * 
-          ")" * *
-        }
-      if$
-      "volume and number" number either.or.check
-    }
-%mc end
-  if$
-}
-FUNCTION {format.number.series}
-{ volume empty$
-    { number empty$
-        { series field.or.null }
-        { series empty$
-            { number "number" bibinfo.check }
-        { 
-          %% output.state mid.sentence =
-          %%   { bbl.number }
-          %%   { bbl.number capitalize }
-          %% if$
-          %% number tie.or.space.prefix "number" bibinfo.check * *
-          %% bbl.in space.word *
-          %% series "series" bibinfo.check *
-          %% " " * bbl.number * 
-          %% number tie.or.space.prefix "number" bibinfo.check * *
-%mc
-              "(" 
-              series "series" bibinfo.check emphasize *
-              " " * bbl.number * 
-              number tie.or.space.prefix "number" bibinfo.check * 
-              ")" *
-              *
-%mc end
-        }
-      if$
-    }
-      if$
-    }
-    { "" }
-  if$
-}
-
-
-FUNCTION {is.num}
-{ chr.to.int$
-  duplicate$ "0" chr.to.int$ < not
-  swap$ "9" chr.to.int$ > not and
-}
-
-FUNCTION {extract.num}
-{ duplicate$ 't :=
-  "" 's :=
-  { t empty$ not }
-  { t #1 #1 substring$
-    t #2 global.max$ substring$ 't :=
-    duplicate$ is.num
-      { s swap$ * 's := }
-      { pop$ "" 't := }
-    if$
-  }
-  while$
-  s empty$
-    'skip$
-    { pop$ s }
-  if$
-}
-
-FUNCTION {convert.edition}
-{ extract.num "l" change.case$ 's :=
-  s "first" = s "1" = or
-    { bbl.first 't := }
-    { s "second" = s "2" = or
-        { bbl.second 't := }
-        { s "third" = s "3" = or
-            { bbl.third 't := }
-            { s "fourth" = s "4" = or
-                { bbl.fourth 't := }
-                { s "fifth" = s "5" = or
-                    { bbl.fifth 't := }
-                    { s #1 #1 substring$ is.num
-                        { s eng.ord 't := }
-                        { edition 't := }
-                      if$
-                    }
-                  if$
-                }
-              if$
-            }
-          if$
-        }
-      if$
-    }
-  if$
-  t
-}
-
-FUNCTION {format.edition}
-{ edition duplicate$ empty$ 'skip$
-    {
-      convert.edition
-      output.state mid.sentence =
-        { "l" }
-        { "t" }
-      if$ change.case$
-      "edition" bibinfo.check
-      " " * bbl.edition *
-    }
-  if$
-}
-INTEGERS { multiresult }
-FUNCTION {multi.page.check}
-{ 't :=
-  #0 'multiresult :=
-    { multiresult not
-      t empty$ not
-      and
-    }
-    { t #1 #1 substring$
-      duplicate$ "-" =
-      swap$ duplicate$ "," =
-      swap$ "+" =
-      or or
-        { #1 'multiresult := }
-        { t #2 global.max$ substring$ 't := }
-      if$
-    }
-  while$
-  multiresult
-}
-FUNCTION {format.pages}
-{ pages duplicate$ empty$ 'skip$
-    { duplicate$ multi.page.check
-        {
-          bbl.pages swap$
-          n.dashify
-        }
-        {
-          bbl.page swap$
-        }
-      if$
-      tie.or.space.prefix
-      "pages" bibinfo.check
-      * *
-    }
-  if$
-}
-FUNCTION {format.journal.pages}
-{ pages duplicate$ empty$ 'pop$
-%mc     { swap$ duplicate$ empty$
-%mc         { pop$ pop$ format.pages }
-%mc         {
-%mc           " " *
-%mc           swap$
-%mc           n.dashify
-%mc           "pages" bibinfo.check
-%mc           *
-%mc         }
-%mc       if$
-%mc     }
-    { swap$
-          " " *
-          swap$
-          n.dashify
-          "pages" bibinfo.check
-          *
-    }
-  if$
-}
-FUNCTION {format.journal.eid}
-{ eid "eid" bibinfo.check
-  duplicate$ empty$ 'skip$
-    { swap$ duplicate$ empty$ 'skip$
-      {
-          " " *
-      }
-      if$
-      swap$
-      numpages empty$ 'skip$
-        { bbl.eidpp numpages tie.or.space.prefix
-          "numpages" bibinfo.check * *
-          " (" swap$ * ")" * *
-        }
-      if$
-    }
-  if$ *
-}
-FUNCTION {format.vol.num.pages}
-{ volume field.or.null
-%mc section handling
-    section field.or.null strip.leading
-    section field.or.null strip.trailing trim
-%mc end
-  duplicate$ empty$ 'skip$
-    {
-      "volume" bibinfo.check
-    }
-  if$
-  bolden
-%mc  number "number" bibinfo.check duplicate$ empty$ 'skip$
-  issue "issue" bibinfo.check duplicate$ empty$ 'skip$
-    {
-      swap$ duplicate$ empty$
-%mc        { "there's a number but no volume in " cite$ * warning$ }
-        { "there's an issue but no volume in " cite$ * warning$ }
-        'skip$
-      if$
-      swap$
-      "(" swap$ * ")" *
-    }
-  if$ *
-  eid empty$
-    { format.journal.pages }
-    { format.journal.eid }
-  if$
-}
-
-FUNCTION {format.chapter.pages}
-{ chapter empty$
-    'format.pages
-    { type empty$
-        { bbl.chapter }
-        { type "l" change.case$
-          "type" bibinfo.check
-        }
-      if$
-      chapter tie.or.space.prefix
-      "chapter" bibinfo.check
-      * *
-      pages empty$
-        'skip$
-        { ", " * format.pages * }
-      if$
-    }
-  if$
-}
-
-FUNCTION {format.booktitle}
-{
-  booktitle "booktitle" bibinfo.check
-  emphasize
-}
-%% FUNCTION {format.in.ed.booktitle}
-%% { format.booktitle duplicate$ empty$ 'skip$
-%%     {
-%%       editor "editor" format.names.ed duplicate$ empty$ 'pop$
-%%         {
-%%           "," *
-%%           " " *
-%%           get.bbl.editor
-%%           ", " *
-%%           * swap$
-%%           * }
-%%       if$
-%%       word.in swap$ *
-%%     }
-%%   if$
-%% }
-FUNCTION {empty.misc.check}
-{ author empty$ title empty$ howpublished empty$
-  month empty$ year empty$ note empty$
-  and and and and and
-    { "all relevant fields are empty in " cite$ * warning$ }
-    'skip$
-  if$
-}
-FUNCTION {format.thesis.type}
-{ type duplicate$ empty$
-    'pop$
-    { swap$ pop$
-      "t" change.case$ "type" bibinfo.check
-    }
-  if$
-}
-FUNCTION {format.tr.number}
-{ number "number" bibinfo.check
-  type duplicate$ empty$
-    { pop$ bbl.techrep }
-    'skip$
-  if$
-  "type" bibinfo.check
-  swap$ duplicate$ empty$
-    { pop$ "t" change.case$ }
-    { tie.or.space.prefix * * }
-  if$
-}
-FUNCTION {format.article.crossref}
-{
-  key duplicate$ empty$
-    { pop$
-      journal duplicate$ empty$
-        { "need key or journal for " cite$ * " to crossref " * crossref * warning$ }
-        { "journal" bibinfo.check emphasize word.in swap$ * }
-      if$
-    }
-    { word.in swap$ * " " *}
-  if$
-  " \cite{" * crossref * "}" *
-}
-FUNCTION {format.crossref.editor}
-{ editor #1 "{vv~}{ll}" format.name$
-  "editor" bibinfo.check
-  editor num.names$ duplicate$
-  #2 >
-    { pop$
-      "editor" bibinfo.check
-      " " * bbl.etal
-      emphasize
-      *
-    }
-    { #2 <
-        'skip$
-        { editor #2 "{ff }{vv }{ll}{ jj}" format.name$ "others" =
-            {
-              "editor" bibinfo.check
-              " " * bbl.etal
-              emphasize
-              *
-            }
-            {
-             bbl.and space.word
-              * editor #2 "{vv~}{ll}" format.name$
-              "editor" bibinfo.check
-              *
-            }
-          if$
-        }
-      if$
-    }
-  if$
-}
-
-FUNCTION {format.book.crossref}
-{ volume duplicate$ empty$
-    { "empty volume in " cite$ * "'s crossref of " * crossref * warning$
-      pop$ word.in
-    }
-    { bbl.volume
-      swap$ tie.or.space.prefix "volume" bibinfo.check * * bbl.of space.word *
-    }
-  if$
-  editor empty$
-  editor field.or.null author field.or.null =
-  or
-    { key empty$
-        { series empty$
-            { "need editor, key, or series for " cite$ * " to crossref " *
-              crossref * warning$
-              "" *
-            }
-            { series emphasize * }
-          if$
-        }
-        { key * }
-      if$
-    }
-    { format.crossref.editor * }
-  if$
-  " \cite{" * crossref * "}" *
-}
-FUNCTION {format.incoll.inproc.crossref}
-{
-  editor empty$
-  editor field.or.null author field.or.null =
-  or
-    { key empty$
-        { format.booktitle duplicate$ empty$
-            { "need editor, key, or booktitle for " cite$ * " to crossref " *
-              crossref * warning$
-            }
-            { word.in swap$ * }
-          if$
-        }
-        { word.in key * " " *}
-      if$
-    }
-    { word.in format.crossref.editor * " " *}
-  if$
-  " \cite{" * crossref * "}" *
-}
-FUNCTION {format.org.or.pub}
-{ 't :=
-  ""
-  address empty$ t empty$ and
-    'skip$
-    {
-      add.blank "(" *
-      address "address" bibinfo.check *
-      t empty$
-        'skip$
-        { address empty$
-            'skip$
-            { ": " * }
-          if$
-          t *
-        }
-      if$
-      ")" *
-    }
-  if$
-}
-FUNCTION {format.publisher.address}
-{ publisher "publisher" bibinfo.warn format.org.or.pub
-}
-
-FUNCTION {format.organization.address}
-{ organization "organization" bibinfo.check format.org.or.pub
-}
-
-
-
-FUNCTION {article}
-{ output.bibitem
-  format.authors "author" output.check
-  format.date "year" output.check
-  date.block
-  crossref missing$
-    {
-%mc add section handling
-%mc       journal
-%mc       "journal" bibinfo.check
-%mc       emphasize
-%mc       "journal" output.check
-%mc       add.blank
-      journal
-      "journal" bibinfo.check
-      section field.or.null strip.trailing trim
-      emphasize
-      "journal" output.check
-      add.blank
-      section empty$
-        { skip$ }
-        { section * add.blank}
-      if$
-%mc end
-      format.vol.num.pages output
-    }
-    { format.article.crossref output.nonnull
-      format.pages output
-    }
-  if$
-  format.issn output
-  format.note output
-  format.eprint output
-  format.url output
-  fin.entry
-}
-FUNCTION {book}
-{ output.bibitem
-  author empty$
-    { format.editors "author and editor" output.check
-    }
-    { format.authors output.nonnull
-      crossref missing$
-        { "author and editor" editor either.or.check }
-        'skip$
-      if$
-    }
-  if$
-  format.date "year" output.check
-  date.block
-  format.btitle "title" output.check
-  format.edition output
-  crossref missing$
-    { format.bvolume output
-      format.number.series output
-      format.publisher.address output
-    }
-    {
-      format.book.crossref output.nonnull
-    }
-  if$
-  %% format.edition output
-  format.isbn output
-  format.note output
-  format.eprint output
-  format.url output
-  fin.entry
-}
-FUNCTION {booklet}
-{ output.bibitem
-  format.authors output
-  format.date output
-  date.block
-  format.title "title" output.check
-  howpublished "howpublished" bibinfo.check output
-  address "address" bibinfo.check output
-  format.isbn output
-  format.note output
-  format.eprint output
-  format.url output
-  fin.entry
-}
-
-FUNCTION {inbook}
-{ output.bibitem
-  author empty$
-    { format.editors "author and editor" output.check
-    }
-    { format.authors output.nonnull
-      crossref missing$
-        { "author and editor" editor either.or.check }
-        'skip$
-      if$
-    }
-  if$
-  format.date "year" output.check
-  date.block
-  format.btitle "title" output.check
-  crossref missing$
-    {
-      format.bvolume output
-      format.publisher.address output
-      %% format.bvolume output
-      format.chapter.pages "chapter and pages" output.check
-      format.number.series output
-    }
-    {
-      format.chapter.pages "chapter and pages" output.check
-      format.book.crossref output.nonnull
-    }
-  if$
-  format.edition output
-  crossref missing$
-    { format.isbn output }
-    'skip$
-  if$
-  format.note output
-  format.eprint output
-  format.url output
-  fin.entry
-}
-
-FUNCTION {incollection}
-{ output.bibitem
-  format.authors "author" output.check
-  format.date "year" output.check
-  date.block
-  format.title "title" output.check
-  crossref missing$
-    { 
-      %% format.in.ed.booktitle "booktitle" output.check
-%mc   
-      format.booktitle "booktitle" output.check
-      format.bvolume output
-      format.number.series output
-      format.editors.inline output
-%mc end
-      format.publisher.address output
-      %% format.bvolume output
-      %% format.number.series output
-      format.chapter.pages output
-      format.edition output
-      format.isbn output
-    }
-    { format.incoll.inproc.crossref output.nonnull
-      format.chapter.pages output
-    }
-  if$
-  format.note output
-  format.eprint output
-  format.url output
-  fin.entry
-}
-FUNCTION {inproceedings}
-{ output.bibitem
-  format.authors "author" output.check
-  format.date "year" output.check
-  date.block
-  format.title "title" output.check
-  crossref missing$
-    { 
-
-      %%format.in.ed.booktitle "booktitle" output.check
-%mc   
-      format.booktitle "booktitle" output.check
-      format.bvolume output
-      format.number.series output
-      format.editors.inline output
-%mc end
-      publisher empty$
-        { format.organization.address output }
-        { organization "organization" bibinfo.check output
-          format.publisher.address output
-        }
-      if$
-      %% format.bvolume output
-      %% format.number.series output
-      format.pages output
-      format.isbn output
-      format.issn output
-    }
-    { format.incoll.inproc.crossref output.nonnull
-      format.pages output
-    }
-  if$
-  format.note output
-  format.eprint output
-  format.url output
-  fin.entry
-}
-FUNCTION {conference} { inproceedings }
-FUNCTION {manual}
-{ output.bibitem
-  author empty$
-    { organization "organization" bibinfo.check
-      duplicate$ empty$ 'pop$
-        { output
-          address "address" bibinfo.check output
-        }
-      if$
-    }
-    { format.authors output.nonnull }
-  if$
-  format.date output
-  date.block
-  format.btitle "title" output.check
-  author empty$
-    { organization empty$
-        {
-          address "address" bibinfo.check output
-        }
-        'skip$
-      if$
-    }
-    {
-      organization "organization" bibinfo.check output
-      address "address" bibinfo.check output
-    }
-  if$
-  format.edition output
-  format.note output
-  format.eprint output
-  format.url output
-  fin.entry
-}
-
-FUNCTION {mastersthesis}
-{ output.bibitem
-  format.authors "author" output.check
-  format.date "year" output.check
-  date.block
-  format.btitle
-  "title" output.check
-  bbl.mthesis format.thesis.type output.nonnull
-  school "school" bibinfo.warn output
-  address "address" bibinfo.check output
-  format.note output
-  format.eprint output
-  format.url output
-  fin.entry
-}
-
-FUNCTION {misc}
-{ output.bibitem
-  format.authors output
-  format.date output
-  format.title output
-  howpublished "howpublished" bibinfo.check output
-  format.note output
-  format.eprint output
-  format.url output
-  fin.entry
-  empty.misc.check
-}
-FUNCTION {phdthesis}
-{ output.bibitem
-  format.authors "author" output.check
-  format.date "year" output.check
-  date.block
-  format.btitle
-  "title" output.check
-  bbl.phdthesis format.thesis.type output.nonnull
-  school "school" bibinfo.warn output
-  address "address" bibinfo.check output
-  format.note output
-  format.eprint output
-  format.url output
-  fin.entry
-}
-
-FUNCTION {proceedings}
-{ output.bibitem
-  editor empty$
-    { organization "organization" bibinfo.check output
-    }
-    { format.editors output.nonnull }
-  if$
-  format.date "year" output.check
-  date.block
-  format.btitle "title" output.check
-  format.bvolume output
-  format.number.series output
-  editor empty$
-    { publisher empty$
-        'skip$
-        {
-          format.publisher.address output
-        }
-      if$
-    }
-    { publisher empty$
-        {
-          format.organization.address output }
-        {
-          organization "organization" bibinfo.check output
-          format.publisher.address output
-        }
-      if$
-     }
-  if$
-  format.isbn output
-  format.issn output
-  format.note output
-  format.eprint output
-  format.url output
-  fin.entry
-}
-
-FUNCTION {techreport}
-{ output.bibitem
-  format.authors "author" output.check
-  format.date "year" output.check
-  date.block
-  format.title
-  "title" output.check
-  format.tr.number output.nonnull
-  institution "institution" bibinfo.warn output
-  address "address" bibinfo.check output
-  format.note output
-  format.eprint output
-  format.url output
-  fin.entry
-}
-
-FUNCTION {unpublished}
-{ output.bibitem
-  format.authors "author" output.check
-  format.date output
-  date.block
-  format.title "title" output.check
-  format.note "note" output.check
-  format.eprint output
-  format.url output
-  fin.entry
-}
-
-FUNCTION {default.type} { misc }
-READ
-STRINGS { longest.label }
-INTEGERS { number.label longest.label.width }
-FUNCTION {initialize.longest.label}
-{ "" 'longest.label :=
-  #1 'number.label :=
-  #0 'longest.label.width :=
-}
-FUNCTION {longest.label.pass}
-{ number.label int.to.str$ 'label :=
-  number.label #1 + 'number.label :=
-  label width$ longest.label.width >
-    { label 'longest.label :=
-      label width$ 'longest.label.width :=
-    }
-    'skip$
-  if$
-}
-EXECUTE {initialize.longest.label}
-ITERATE {longest.label.pass}
-FUNCTION {begin.bib}
-{ preamble$ empty$
-    'skip$
-    { preamble$ write$ newline$ }
-  if$
-  "\providecommand{\newblock}{}"
-  write$ newline$
-  "\begin{thebibliography}{"  longest.label  * "}" *
-  write$ newline$
-  "\expandafter\ifx\csname url\endcsname\relax"
-  write$ newline$
-  "  \def\url#1{{\tt #1}}\fi"
-  write$ newline$
-  "\expandafter\ifx\csname urlprefix\endcsname\relax\def\urlprefix{URL }\fi"
-  write$ newline$
-  "\providecommand{\eprint}[2][]{\url{#2}}"
-  write$ newline$
-  "% Bibliography created with iopart-num v2.1"
-  write$ newline$
-  "% /biblio/bibtex/contrib/iopart-num"
-  write$ newline$
-}
-EXECUTE {begin.bib}
-EXECUTE {init.state.consts}
-ITERATE {call.type$}
-FUNCTION {end.bib}
-{ newline$
-  "\end{thebibliography}" write$ newline$
-}
-EXECUTE {end.bib}
-%% End of customized bst file
-%%
-%% End of file `iopart-num.bst'.

+ 0 - 1107
paper_MD/iopart.cls

@@ -1,1107 +0,0 @@
-%% 
-%% This is file `iopart.cls'
-%% 
-%% This file is distributed in the hope that it will be useful, 
-%% but WITHOUT ANY WARRANTY; without even the implied warranty of 
-%% MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. 
-%% 
-%% Licensed under the LPPL: http://www.latex-project.org/lppl.txt
-%% Current Maintainer: IOP Publishing Ltd
-%% 
-%% \CharacterTable
-%%  {Upper-case    \A\B\C\D\E\F\G\H\I\J\K\L\M\N\O\P\Q\R\S\T\U\V\W\X\Y\Z
-%%   Lower-case    \a\b\c\d\e\f\g\h\i\j\k\l\m\n\o\p\q\r\s\t\u\v\w\x\y\z
-%%   Digits        \0\1\2\3\4\5\6\7\8\9
-%%   Exclamation   \!     Double quote  \"     Hash (number) \#
-%%   Dollar        \$     Percent       \%     Ampersand     \&
-%%   Acute accent  \'     Left paren    \(     Right paren   \)
-%%   Asterisk      \*     Plus          \+     Comma         \,
-%%   Minus         \-     Point         \.     Solidus       \/
-%%   Colon         \:     Semicolon     \;     Less than     \<
-%%   Equals        \=     Greater than  \>     Question mark \?
-%%   Commercial at \@     Left bracket  \[     Backslash     \\
-%%   Right bracket \]     Circumflex    \^     Underscore    \_
-%%   Grave accent  \`     Left brace    \{     Vertical bar  \|
-%%   Right brace   \}     Tilde         \~}
-%
-\NeedsTeXFormat{LaTeX2e}
-\ProvidesClass{iopart}[1996/06/10 v0.0 IOP Journals LaTeX article class]
-\newcommand\@ptsize{0}
-\newif\if@restonecol
-\newif\if@titlepage
-\newif\ifiopams
-\@titlepagefalse
-\DeclareOption{a4paper}
-   {\setlength\paperheight {297mm}%
-    \setlength\paperwidth  {210mm}}
-\DeclareOption{letterpaper}
-   {\setlength\paperheight {11in}%
-    \setlength\paperwidth  {8.5in}}
-\DeclareOption{landscape}
-   {\setlength\@tempdima   {\paperheight}%
-    \setlength\paperheight {\paperwidth}%
-    \setlength\paperwidth  {\@tempdima}}
-\DeclareOption{10pt}{\renewcommand\@ptsize{0}}
-\DeclareOption{11pt}{\renewcommand\@ptsize{2}} % No 11pt version
-\DeclareOption{12pt}{\renewcommand\@ptsize{2}}
-\DeclareOption{draft}{\setlength\overfullrule{5pt}}
-\DeclareOption{final}{\setlength\overfullrule{0pt}}
-\DeclareOption{titlepage}{\@titlepagetrue}
-\DeclareOption{notitlepage}{\@titlepagefalse}
-\ExecuteOptions{letterpaper,final}
-\ProcessOptions
-\DeclareMathAlphabet{\bi}{OML}{cmm}{b}{it}
-\DeclareMathAlphabet{\bcal}{OMS}{cmsy}{b}{n}
-\input{iopart1\@ptsize.clo}
-\setlength\lineskip{1\p@}
-\setlength\normallineskip{1\p@}
-\renewcommand\baselinestretch{}
-\setlength\parskip{0\p@ \@plus \p@}
-\@lowpenalty   51
-\@medpenalty  151
-\@highpenalty 301
-\setlength\parindent{2em}
-\setcounter{topnumber}{8}
-\renewcommand\topfraction{1}
-\setcounter{bottomnumber}{3}
-\renewcommand\bottomfraction{.99}
-\setcounter{totalnumber}{8}
-\renewcommand\textfraction{0.01}
-\renewcommand\floatpagefraction{.8}
-\setcounter{dbltopnumber}{6}
-\renewcommand\dbltopfraction{1}
-\renewcommand\dblfloatpagefraction{.8}
-%
-\pretolerance=5000
-\tolerance=8000
-%
-% Headings for all pages apart from first
-%
-\def\ps@headings{\let\@oddfoot\@empty
-      \let\@evenfoot\@empty
-      \def\@evenhead{\thepage\hfil\itshape\rightmark}%
-      \def\@oddhead{{\itshape\leftmark}\hfil\thepage}%
-      \let\@mkboth\markboth
-      \let\sectionmark\@gobble
-      \let\subsectionmark\@gobble}
-%
-% Headings for first page
-%
-\def\ps@myheadings{\let\@oddfoot\@empty\let\@evenfoot\@empty
-    \let\@oddhead\@empty\let\@evenhead\@empty
-    \let\@mkboth\@gobbletwo
-    \let\sectionmark\@gobble
-    \let\subsectionmark\@gobble}
-%
-% \maketitle just ends page
-%
-\newcommand\maketitle{\newpage}
-%
-% Article titles
-%
-% Usage: \title[Short title]{Full title}
-% [Short title] is optional; use where title is too long
-% or contains footnotes, 50 characters maximum 
-%
-\renewcommand{\title}{\@ifnextchar[{\@stitle}{\@ftitle}}
-\def\@stitle[#1]#2{\markboth{#1}{#1}%
-    \thispagestyle{myheadings}%
-    \vspace*{3pc}{\exhyphenpenalty=10000\hyphenpenalty=10000 
-    \Large\raggedright\noindent
-    \bf#2\par}}
-\def\@ftitle#1{\markboth{#1}{#1}%
-    \thispagestyle{myheadings}%
-    \vspace*{3pc}{\exhyphenpenalty=10000\hyphenpenalty=10000 
-    \Large\raggedright\noindent
-    \bf#1\par}}
-%
-% Can use \paper instead of \title
-%
-\let\paper=\title
-%
-% Generic title command for articles other than papers
-%
-% Usage: \article[Short title]{Article Type}{Full title}
-% [Short title] is optional; use where title is too long
-% or contains footnotes, 50 characters maximum 
-%
-\newcommand{\article}{\@ifnextchar[{\@sarticle}{\@farticle}}
-\def\@sarticle[#1]#2#3{\markboth{#1}{#1}%
-    \thispagestyle{myheadings}%
-     \vspace*{.5pc}%
-    {\parindent=\mathindent \bf #2\par}%
-     \vspace*{1.5pc}%
-    {\exhyphenpenalty=10000\hyphenpenalty=10000
-     \Large\raggedright\noindent
-     \bf#3\par}}%
-\def\@farticle#1#2{\markboth{#2}{#2}%
-    \thispagestyle{myheadings}%
-     \vspace*{.5pc}%
-    {\parindent=\mathindent \bf #1\par}%
-     \vspace*{1.5pc}%
-    {\exhyphenpenalty=10000\hyphenpenalty=10000
-     \Large\raggedright\noindent
-     \bf#2\par}}%
-%
-% Letters to the Editor
-%
-% Usage \letter{Full title}
-% No short title is required for Letters
-%
-\def\letter#1{\article[Letter to the Editor]{Letter to the Editor}{#1}}
-%
-% Fast Track Communications (added by sxb 9 March 2011)
-%
-% Usage \ftc{Full title} - there's no short title
-\def\ftc#1{\article[Fast Track Communication]{Fast Track Communication}{#1}}
-%
-%
-% Review articles
-%
-% Usage: \review[Short title]{Full title}
-% [Short title] is optional; use where title is too long
-% or contains footnotes, 50 characters maximum 
-%
-\def\review{\@ifnextchar[{\@sreview}{\@freview}}
-\def\@sreview[#1]#2{\@sarticle[#1]{Review Article}{#2}}
-\def\@freview#1{\@farticle{Review Article}{#1}}
-%
-% Topical Review
-%
-% Usage: \topical[Short title]{Full title}
-% [Short title] is optional; use where title is too long
-% or contains footnotes, 50 characters maximum 
-%
-\def\topical{\@ifnextchar[{\@stopical}{\@ftopical}}
-\def\@stopical[#1]#2{\@sarticle[#1]{Topical Review}{#2}}
-\def\@ftopical#1{\@farticle{Topical Review}{#1}}
-%
-% Comments
-%
-% Usage: \comment[Short title]{Full title}
-% [Short title] is optional; use where title is too long
-% or contains footnotes, 50 characters maximum 
-%
-\def\comment{\@ifnextchar[{\@scomment}{\@fcomment}}
-\def\@scomment[#1]#2{\@sarticle[#1]{Comment}{#2}}
-\def\@fcomment#1{\@farticle{Comment}{#1}}
-%
-% Rapid Communications
-%
-% Usage: \rapid[Short title]{Full title}
-% [Short title] is optional; use where title is too long
-% or contains footnotes, 50 characters maximum 
-%
-\def\rapid{\@ifnextchar[{\@srapid}{\@frapid}}
-\def\@srapid[#1]#2{\@sarticle[#1]{Rapid Communication}{#2}}
-\def\@frapid#1{\@farticle{Rapid Communication}{#1}}
-%
-% Notes
-%
-% Usage: \note[Short title]{Full title}
-% [Short title] is optional; use where title is too long
-% or contains footnotes, 50 characters maximum 
-%
-\def\note{\@ifnextchar[{\@snote}{\@fnote}}
-\def\@snote[#1]#2{\@sarticle[#1]{Note}{#2}}
-\def\@fnote#1{\@farticle{Note}{#1}}
-%
-% Preliminary Communications
-%
-% Usage: \prelim[Short title]{Full title}
-% [Short title] is optional; use where title is too long
-% or contains footnotes, 50 characters maximum 
-%
-\def\prelim{\@ifnextchar[{\@sprelim}{\@fprelim}}
-\def\@sprelim[#1]#2{\@sarticle[#1]{Preliminary Communication}{#2}}
-\def\@fprelim#1{\@farticle{Preliminary Communication}{#1}}
-%
-% List of authors
-%
-% Usage \author[Short form]{List of all authors}
-% The short form excludes footnote symbols linking authors to addresses 
-% and is used for running heads in printed version (but not on preprints)
-%
-\renewcommand{\author}{\@ifnextchar[{\@sauthor}{\@fauthor}}
-\def\@sauthor[#1]#2{\markright{#1}    % for production only
-   \vspace*{1.5pc}%
-   \begin{indented}%
-   \item[]\normalsize\bf\raggedright#2
-   \end{indented}%
-   \smallskip}
-\def\@fauthor#1{%\markright{#1}         for production only
-   \vspace*{1.5pc}%
-   \begin{indented}%
-   \item[]\normalsize\bf\raggedright#1
-   \end{indented}%
-   \smallskip}
-%
-% Affiliation (authors address)
-%
-% Usage: \address{Address of first author}
-%        \address{Address of second author}
-% Use once for each address, use symbols \dag \ddag \S \P $\|$
-% to connect authors with addresses
-%
-\newcommand{\address}[1]{\begin{indented}
-   \item[]\rm\raggedright #1
-   \end{indented}}
-%
-% American Mathematical Society Classification Numbers
-% Usage: \ams{57.XX, 58.XX}
-%
-\def\ams#1{\vspace{10pt}
-     \begin{indented}
-     \item[]\rm AMS classification scheme numbers: #1\par
-     \end{indented}}
-%
-% A single Physics & Astronomy Classification Number
-% Usage \pacno{31.10}
-%
-\def\pacno#1{\vspace{10pt}
-     \begin{indented}
-     \item[]\rm PACS number: #1\par
-     \end{indented}}
-%
-% Physics & Astronomy Classification Numbers (more than one)
-% Usage \pacs{31.10, 31.20T}
-%
-\def\pacs#1{\vspace{10pt}
-     \begin{indented}
-     \item[]\rm PACS numbers: #1\par
-     \end{indented}}
-%
-% Submission details. If \jl command used journals name printed
-% otherwise Institute of Physics Publishing 
-%
-\def\submitted{\vspace{28pt plus 10pt minus 18pt}
-     \noindent{\small\rm Submitted to: {\it \journal}\par}}
-%
-\def\submitto#1{\vspace{28pt plus 10pt minus 18pt}
-     \noindent{\small\rm Submitted to: {\it #1}\par}}
-%
-% For articles (other than Letters) not divided into sections
-% Usage \nosections Start of text
-%
-\def\nosections{\vspace{30\p@ plus12\p@ minus12\p@}
-    \noindent\ignorespaces}
-%
-% Acknowledgments (no heading if letter)
-% Usage \ack for Acknowledgments, \ackn for Acknowledgement
-%
-\def\ack{\ifletter\bigskip\noindent\ignorespaces\else
-    \section*{Acknowledgments}\fi}
-\def\ackn{\ifletter\bigskip\noindent\ignorespaces\else
-    \section*{Acknowledgment}\fi}
-%
-% Footnotes: symbols selected in order \dag (1), \ddag (2), \S (3), 
-% $\|$ (4), $\P$ (5), $^+$ (6), $^*$ (7), \sharp (8), \dagger\dagger (9)
-% unless optional argument of [<num>] use to specify required symbol, 
-% 1=\dag, 2=\ddag, etc
-% Usage: \footnote{Text of footnote}
-%        \footnote[3]{Text of footnote}
-%
-\def\footnoterule{}%
-\setcounter{footnote}{1}
-\long\def\@makefntext#1{\parindent 1em\noindent 
- \makebox[1em][l]{\footnotesize\rm$\m@th{\fnsymbol{footnote}}$}%
- \footnotesize\rm #1}
-\def\@makefnmark{\hbox{${\fnsymbol{footnote}}\m@th$}}
-\def\@thefnmark{\fnsymbol{footnote}}
-\def\footnote{\@ifnextchar[{\@xfootnote}{\stepcounter{\@mpfn}%
-       \begingroup\let\protect\noexpand
-       \xdef\@thefnmark{\thempfn}\endgroup
-     \@footnotemark\@footnotetext}}
-\def\@xfootnote[#1]{\setcounter{footnote}{#1}%
-   \addtocounter{footnote}{-1}\footnote}
-\def\@fnsymbol#1{\ifcase#1\or \dagger\or \ddagger\or \S\or
-   \|\or \P\or ^{+}\or ^{\tsty *}\or \sharp
-   \or \dagger\dagger \else\@ctrerr\fi\relax}
-%
-% IOP Journals
-%
-\newcounter{jnl}
-\newcommand{\jl}[1]{\setcounter{jnl}{#1}}
-\def\journal{\ifnum\thejnl=0 Institute of Physics Publishing\fi
-        \ifnum\thejnl=1 J. Phys.\ A: Math.\ Gen.\ \fi
-        \ifnum\thejnl=2 J. Phys.\ B: At.\ Mol.\ Opt.\ Phys.\ \fi
-        \ifnum\thejnl=3 J. Phys.:\ Condens. Matter\ \fi
-        \ifnum\thejnl=4 J. Phys.\ G: Nucl.\ Part.\ Phys.\ \fi
-        \ifnum\thejnl=5 Inverse Problems\ \fi
-        \ifnum\thejnl=6 Class. Quantum Grav.\ \fi
-        \ifnum\thejnl=7 Network: Comput.\ Neural Syst.\ \fi
-        \ifnum\thejnl=8 Nonlinearity\ \fi
-        \ifnum\thejnl=9 J. Opt. B: Quantum Semiclass. Opt.\ \fi
-        \ifnum\thejnl=10 Waves Random Media\ \fi
-        \ifnum\thejnl=11 J. Opt. A: Pure Appl. Opt.\ \fi
-        \ifnum\thejnl=12 Phys. Med. Biol.\ \fi
-        \ifnum\thejnl=13 Modelling Simul.\ Mater.\ Sci.\ Eng.\ \fi
-        \ifnum\thejnl=14 Plasma Phys. Control. Fusion\ \fi
-        \ifnum\thejnl=15 Physiol. Meas.\ \fi
-        \ifnum\thejnl=16 Combust. Theory Modelling\ \fi
-        \ifnum\thejnl=17 High Perform.\ Polym.\ \fi
-        \ifnum\thejnl=18 Public Understand. Sci.\ \fi
-        \ifnum\thejnl=19 Rep.\ Prog.\ Phys.\ \fi
-        \ifnum\thejnl=20 J.\ Phys.\ D: Appl.\ Phys.\ \fi
-        \ifnum\thejnl=21 Supercond.\ Sci.\ Technol.\ \fi
-        \ifnum\thejnl=22 Semicond.\ Sci.\ Technol.\ \fi
-        \ifnum\thejnl=23 Nanotechnology\ \fi
-        \ifnum\thejnl=24 Measur.\ Sci.\ Technol.\ \fi
-        \ifnum\thejnl=25 Plasma.\ Sources\ Sci.\ Technol.\ \fi
-        \ifnum\thejnl=26 Smart\ Mater.\ Struct.\ \fi
-        \ifnum\thejnl=27 J.\ Micromech.\ Microeng.\ \fi
-        \ifnum\thejnl=28 Distrib.\ Syst.\ Engng\ \fi
-        \ifnum\thejnl=29 Bioimaging\ \fi
-        \ifnum\thejnl=30 J.\ Radiol. Prot.\ \fi
-        \ifnum\thejnl=31 Europ. J. Phys.\ \fi
-        \ifnum\thejnl=32 J. Opt. A: Pure Appl. Opt.\ \fi
-        \ifnum\thejnl=33 New. J. Phys.\ \fi}
-%
-% E-mail addresses (to provide links from headers)
-%
-\def\eads#1{\vspace*{5pt}\address{E-mail: #1}}
-\def\ead#1{\vspace*{5pt}\address{E-mail: \mailto{#1}}}
-\def\mailto#1{{\tt #1}}
-%
-% Switches
-%
-\newif\ifletter
-%
-\setcounter{secnumdepth}{3}
-\newcounter {section}
-\newcounter {subsection}[section]
-\newcounter {subsubsection}[subsection]
-\newcounter {paragraph}[subsubsection]
-\newcounter {subparagraph}[paragraph]
-\renewcommand\thesection       {\arabic{section}}
-\renewcommand\thesubsection    {\thesection.\arabic{subsection}}
-\renewcommand\thesubsubsection {\thesubsection.\arabic{subsubsection}}
-\renewcommand\theparagraph     {\thesubsubsection.\arabic{paragraph}}
-\renewcommand\thesubparagraph  {\theparagraph.\arabic{subparagraph}}
-\def\@chapapp{Section}
-
-\newcommand\section{\@startsection {section}{1}{\z@}%
-                   {-3.5ex \@plus -1ex \@minus -.2ex}%
-                   {2.3ex \@plus.2ex}%
-                   {\reset@font\normalsize\bfseries\raggedright}}
-\newcommand\subsection{\@startsection{subsection}{2}{\z@}%
-                   {-3.25ex\@plus -1ex \@minus -.2ex}%
-                   {1.5ex \@plus .2ex}%
-                   {\reset@font\normalsize\itshape\raggedright}}
-\newcommand\subsubsection{\@startsection{subsubsection}{3}{\z@}%
-                                     {-3.25ex\@plus -1ex \@minus -.2ex}%
-                                     {-1em \@plus .2em}%
-                                     {\reset@font\normalsize\itshape}}
-\newcommand\paragraph{\@startsection{paragraph}{4}{\z@}%
-                                    {3.25ex \@plus1ex \@minus.2ex}%
-                                    {-1em}%
-                                    {\reset@font\normalsize\itshape}}
-\newcommand\subparagraph{\@startsection{subparagraph}{5}{\parindent}%
-                                       {3.25ex \@plus1ex \@minus .2ex}%
-                                       {-1em}%
-                                      {\reset@font\normalsize\itshape}}
-\def\@sect#1#2#3#4#5#6[#7]#8{\ifnum #2>\c@secnumdepth
-     \let\@svsec\@empty\else
-     \refstepcounter{#1}\edef\@svsec{\csname the#1\endcsname. }\fi
-     \@tempskipa #5\relax
-      \ifdim \@tempskipa>\z@
-        \begingroup #6\relax
-          \noindent{\hskip #3\relax\@svsec}{\interlinepenalty \@M #8\par}%
-        \endgroup
-       \csname #1mark\endcsname{#7}\addcontentsline
-         {toc}{#1}{\ifnum #2>\c@secnumdepth \else
-                      \protect\numberline{\csname the#1\endcsname}\fi
-                    #7}\else
-        \def\@svsechd{#6\hskip #3\relax  %% \relax added 2 May 90
-                   \@svsec #8\csname #1mark\endcsname
-                      {#7}\addcontentsline
-                           {toc}{#1}{\ifnum #2>\c@secnumdepth \else
-                             \protect\numberline{\csname the#1\endcsname}\fi
-                       #7}}\fi
-     \@xsect{#5}}
-%
-\def\@ssect#1#2#3#4#5{\@tempskipa #3\relax
-   \ifdim \@tempskipa>\z@
-     \begingroup #4\noindent{\hskip #1}{\interlinepenalty \@M #5\par}\endgroup
-   \else \def\@svsechd{#4\hskip #1\relax #5}\fi
-    \@xsect{#3}}
-
-\setlength\leftmargini{2em}
-\setlength\leftmarginii{2em}
-\setlength\leftmarginiii{1.8em}
-\setlength\leftmarginiv{1.6em}
-\setlength\leftmarginv{1em}
-\setlength\leftmarginvi{1em}
-\setlength\leftmargin{\leftmargini}
-\setlength\labelsep{0.5em}
-\setlength\labelwidth{\leftmargini}
-\addtolength\labelwidth{-\labelsep}
-\@beginparpenalty -\@lowpenalty
-\@endparpenalty   -\@lowpenalty
-\@itempenalty     -\@lowpenalty
-\renewcommand\theenumi{\roman{enumi}}
-\renewcommand\theenumii{\alph{enumii}}
-\renewcommand\theenumiii{\arabic{enumiii}}
-\renewcommand\theenumiv{\Alph{enumiv}}
-\newcommand\labelenumi{(\theenumi)}
-\newcommand\labelenumii{(\theenumii)}
-\newcommand\labelenumiii{\theenumiii.}
-\newcommand\labelenumiv{(\theenumiv)}
-\renewcommand\p@enumii{(\theenumi)}
-\renewcommand\p@enumiii{(\theenumi.\theenumii)}
-\renewcommand\p@enumiv{(\theenumi.\theenumii.\theenumiii)}
-\newcommand\labelitemi{$\m@th\bullet$}
-\newcommand\labelitemii{\normalfont\bfseries --}
-\newcommand\labelitemiii{$\m@th\ast$}
-\newcommand\labelitemiv{$\m@th\cdot$}
-\newenvironment{description}
-               {\list{}{\labelwidth\z@ \itemindent-\leftmargin
-                        \let\makelabel\descriptionlabel}}
-               {\endlist}
-\newcommand\descriptionlabel[1]{\hspace\labelsep
-                                \normalfont\bfseries #1}
-\newenvironment{abstract}{%
-      \vspace{16pt plus3pt minus3pt}
-      \begin{indented}
-      \item[]{\bfseries \abstractname.}\quad\rm\ignorespaces} 
-      {\end{indented}\if@titlepage\newpage\else\vspace{18\p@ plus18\p@}\fi}
-\newenvironment{verse}
-               {\let\\=\@centercr
-                \list{}{\itemsep      \z@
-                        \itemindent   -1.5em%
-                        \listparindent\itemindent
-                        \rightmargin  \leftmargin
-                        \advance\leftmargin 1.5em}%
-                \item[]}
-               {\endlist}
-\newenvironment{quotation}
-               {\list{}{\listparindent 1.5em%
-                        \itemindent    \listparindent
-                        \rightmargin   \leftmargin
-                        \parsep        \z@ \@plus\p@}%
-                \item[]}
-               {\endlist}
-\newenvironment{quote}
-               {\list{}{\rightmargin\leftmargin}%
-                \item[]}
-               {\endlist}
-\newenvironment{titlepage}
-    {%
-        \@restonecolfalse\newpage
-      \thispagestyle{empty}%
-      \if@compatibility
-        \setcounter{page}{0}
-      \else
-        \setcounter{page}{1}%
-      \fi}%
-    {\newpage\setcounter{page}{1}}
-\def\appendix{\@ifnextchar*{\@appendixstar}{\@appendix}}
-\def\@appendix{\eqnobysec\@appendixstar}
-\def\@appendixstar{\@@par
- \ifnumbysec                         %  Added 30/4/94 to get Table A1,
- \@addtoreset{table}{section}        %  Table B1 etc if numbering by
- \@addtoreset{figure}{section}\fi    %  section
- \setcounter{section}{0}
- \setcounter{subsection}{0}
- \setcounter{subsubsection}{0}
- \setcounter{equation}{0}
- \setcounter{figure}{0}
- \setcounter{table}{0}
- \def\thesection{Appendix \Alph{section}}   
- \def\theequation{\ifnumbysec
-      \Alph{section}.\arabic{equation}\else
-      \Alph{section}\arabic{equation}\fi}  % Comment A\arabic{equation} maybe
- \def\thetable{\ifnumbysec                 % better? 15/4/95
-      \Alph{section}\arabic{table}\else
-      A\arabic{table}\fi}
- \def\thefigure{\ifnumbysec
-      \Alph{section}\arabic{figure}\else
-      A\arabic{figure}\fi}}
-\def\noappendix{\setcounter{figure}{0}
-     \setcounter{table}{0}
-     \def\thetable{\arabic{table}}
-     \def\thefigure{\arabic{figure}}}
-\setlength\arraycolsep{5\p@}
-\setlength\tabcolsep{6\p@}
-\setlength\arrayrulewidth{.4\p@}
-\setlength\doublerulesep{2\p@}
-\setlength\tabbingsep{\labelsep}
-\skip\@mpfootins = \skip\footins
-\setlength\fboxsep{3\p@}
-\setlength\fboxrule{.4\p@}
-\renewcommand\theequation{\arabic{equation}}
-\newcounter{figure}
-\renewcommand\thefigure{\@arabic\c@figure}
-\def\fps@figure{tbp}
-\def\ftype@figure{1}
-\def\ext@figure{lof}
-\def\fnum@figure{\figurename~\thefigure}
-\newenvironment{figure}{\footnotesize\rm\@float{figure}}%
-    {\end@float\normalsize\rm}
-\newenvironment{figure*}{\footnotesize\rm\@dblfloat{figure}}{\end@dblfloat}
-\newcounter{table}
-\renewcommand\thetable{\@arabic\c@table}
-\def\fps@table{tbp}
-\def\ftype@table{2}
-\def\ext@table{lot}
-\def\fnum@table{\tablename~\thetable}
-\newenvironment{table}{\footnotesize\rm\@float{table}}%
-   {\end@float\normalsize\rm}
-\newenvironment{table*}{\footnotesize\rm\@dblfloat{table}}%
-   {\end@dblfloat\normalsize\rm}
-\newlength\abovecaptionskip
-\newlength\belowcaptionskip
-\setlength\abovecaptionskip{10\p@}
-\setlength\belowcaptionskip{0\p@}
-%
-% Added redefinition of \@caption so captions are not written to 
-% aux file therefore less need to \protect fragile commands
-%
-\long\def\@caption#1[#2]#3{\par\begingroup
-    \@parboxrestore
-    \normalsize
-    \@makecaption{\csname fnum@#1\endcsname}{\ignorespaces #3}\par
-  \endgroup}
-% 
-\long\def\@makecaption#1#2{\vskip \abovecaptionskip 
- \begin{indented}
- \item[]{\bf #1.} #2
- \end{indented}\vskip\belowcaptionskip}
-\let\@portraitcaption=\@makecaption
-
-\DeclareOldFontCommand{\rm}{\normalfont\rmfamily}{\mathrm}
-\DeclareOldFontCommand{\sf}{\normalfont\sffamily}{\mathsf}
-\DeclareOldFontCommand{\tt}{\normalfont\ttfamily}{\mathtt}
-\DeclareOldFontCommand{\bf}{\normalfont\bfseries}{\mathbf}
-\DeclareOldFontCommand{\it}{\normalfont\itshape}{\mathit}
-\DeclareOldFontCommand{\sl}{\normalfont\slshape}{\@nomath\sl}
-\DeclareOldFontCommand{\sc}{\normalfont\scshape}{\@nomath\sc}
-\ifiopams
-\renewcommand{\cal}{\protect\pcal}
-\else
-\newcommand{\cal}{\protect\pcal}
-\fi
-\newcommand{\pcal}{\@fontswitch{\relax}{\mathcal}}
-\ifiopams
-\renewcommand{\mit}{\protect\pmit}
-\else
-\newcommand{\mit}{\protect\pmit}
-\fi
-\newcommand{\pmit}{\@fontswitch{\relax}{\mathnormal}}
-\newcommand\@pnumwidth{1.55em}
-\newcommand\@tocrmarg {2.55em}
-\newcommand\@dotsep{4.5}
-\setcounter{tocdepth}{3}
-\newcommand\tableofcontents{%
-    \section*{\contentsname
-        \@mkboth{\uppercase{\contentsname}}{\uppercase{\contentsname}}}%
-    \@starttoc{toc}%
-    }
-\newcommand\l@part[2]{%
-  \ifnum \c@tocdepth >-2\relax
-    \addpenalty{\@secpenalty}%
-    \addvspace{2.25em \@plus\p@}%
-    \begingroup
-      \setlength\@tempdima{3em}%
-      \parindent \z@ \rightskip \@pnumwidth
-      \parfillskip -\@pnumwidth
-      {\leavevmode
-       \large \bfseries #1\hfil \hbox to\@pnumwidth{\hss #2}}\par
-       \nobreak
-       \if@compatibility
-         \global\@nobreaktrue
-         \everypar{\global\@nobreakfalse\everypar{}}
-      \fi
-    \endgroup
-  \fi}
-\newcommand\l@section[2]{%
-  \ifnum \c@tocdepth >\z@
-    \addpenalty{\@secpenalty}%
-    \addvspace{1.0em \@plus\p@}%
-    \setlength\@tempdima{1.5em}%
-    \begingroup
-      \parindent \z@ \rightskip \@pnumwidth
-      \parfillskip -\@pnumwidth
-      \leavevmode \bfseries
-      \advance\leftskip\@tempdima
-      \hskip -\leftskip
-      #1\nobreak\hfil \nobreak\hbox to\@pnumwidth{\hss #2}\par
-    \endgroup
-  \fi}
-\newcommand\l@subsection   {\@dottedtocline{2}{1.5em}{2.3em}}
-\newcommand\l@subsubsection{\@dottedtocline{3}{3.8em}{3.2em}}
-\newcommand\l@paragraph    {\@dottedtocline{4}{7.0em}{4.1em}}
-\newcommand\l@subparagraph {\@dottedtocline{5}{10em}{5em}}
-\newcommand\listoffigures{%
-    \section*{\listfigurename
-      \@mkboth{\uppercase{\listfigurename}}%
-              {\uppercase{\listfigurename}}}%
-    \@starttoc{lof}%
-    }
-\newcommand\l@figure{\@dottedtocline{1}{1.5em}{2.3em}}
-\newcommand\listoftables{%
-    \section*{\listtablename
-      \@mkboth{\uppercase{\listtablename}}{\uppercase{\listtablename}}}%
-    \@starttoc{lot}%
-    }
-\let\l@table\l@figure
-\newenvironment{theindex}
-               {\if@twocolumn
-                  \@restonecolfalse
-                \else
-                  \@restonecoltrue
-                \fi
-                \columnseprule \z@
-                \columnsep 35\p@
-                \twocolumn[\section*{\indexname}]%
-                \@mkboth{\uppercase{\indexname}}%
-                        {\uppercase{\indexname}}%
-                \thispagestyle{plain}\parindent\z@
-                \parskip\z@ \@plus .3\p@\relax
-                \let\item\@idxitem}
-               {\if@restonecol\onecolumn\else\clearpage\fi}
-\newcommand\@idxitem  {\par\hangindent 40\p@}
-\newcommand\subitem   {\par\hangindent 40\p@ \hspace*{20\p@}}
-\newcommand\subsubitem{\par\hangindent 40\p@ \hspace*{30\p@}}
-\newcommand\indexspace{\par \vskip 10\p@ \@plus5\p@ \@minus3\p@\relax}
-\newcommand\contentsname{Contents}
-\newcommand\listfigurename{List of Figures}
-\newcommand\listtablename{List of Tables}
-\newcommand\refname{References}
-\newcommand\indexname{Index}
-\newcommand\figurename{Figure}
-\newcommand\tablename{Table}
-\newcommand\partname{Part}
-\newcommand\appendixname{Appendix}
-\newcommand\abstractname{Abstract}
-\newcommand\today{\number\day\space\ifcase\month\or
-  January\or February\or March\or April\or May\or June\or
-  July\or August\or September\or October\or November\or December\fi
-  \space\number\year}
-\setlength\columnsep{10\p@}
-\setlength\columnseprule{0\p@}
-
-\newcommand{\Tables}{\clearpage\section*{Tables and table captions}
-    \def\fps@table{hp}\noappendix}
-\newcommand{\Figures}{\clearpage\section*{Figure captions}
-    \def\fps@figure{hp}\noappendix}
-%
-\newcommand{\Figure}[1]{\begin{figure}
-  \caption{#1}
-  \end{figure}}
-%
-\newcommand{\Table}[1]{\begin{table}
-  \caption{#1}
-  \begin{indented}
-  \lineup
-  \item[]\begin{tabular}{@{}l*{15}{l}}}
-
-\def\endTable{\end{tabular}\end{indented}\end{table}}
-\let\endtab=\endTable
-%
-\newcommand{\fulltable}[1]{\begin{table}
-  \caption{#1}
-  \footnotesize
-  \lineup
-  \begin{tabular*}{\textwidth}{@{}l*{15}{@{\extracolsep{0pt plus 12pt}}l}}}
-\def\endfulltable{\end{tabular*}\end{table}\normalsize}
-%
-%
-\newcommand{\Bibliography}[1]{\section*{References}\par\numrefs{#1}}
-\newcommand{\References}{\section*{References}\par\refs}
-
-\def\thebibliography#1{\list
- {\hfil[\arabic{enumi}]}{\topsep=0\p@\parsep=0\p@
- \partopsep=0\p@\itemsep=0\p@
- \labelsep=5\p@\itemindent=-10\p@
- \settowidth\labelwidth{\footnotesize[#1]}%
- \leftmargin\labelwidth
- \advance\leftmargin\labelsep
- \advance\leftmargin -\itemindent
- \usecounter{enumi}}\footnotesize
- \def\newblock{\ }
- \sloppy\clubpenalty4000\widowpenalty4000
- \sfcode`\.=1000\relax}
-\let\endthebibliography=\endlist
-\def\numrefs#1{\begin{thebibliography}{#1}}
-\def\endnumrefs{\end{thebibliography}}
-\let\endbib=\endnumrefs
-%
-\def\thereferences{\list{}{\topsep=0\p@\parsep=0\p@
- \partopsep=0\p@\itemsep=0\p@\labelsep=0\p@\itemindent=-18\p@
-\labelwidth=0\p@\leftmargin=18\p@
-}\footnotesize\rm
-\def\newblock{\ }
-\sloppy\clubpenalty4000\widowpenalty4000
-\sfcode`\.=1000\relax
-}
-%
-\let\endthereferences=\endlist
-\newlength{\indentedwidth}
-\newdimen\mathindent
-\indentedwidth=\mathindent
-%
-% Macro to used for references in the Harvard system
-%
-\newenvironment{harvard}{\list{}{\topsep=0\p@\parsep=0\p@
-\partopsep=0\p@\itemsep=0\p@\labelsep=0\p@\itemindent=-18\p@
-\labelwidth=0\p@\leftmargin=18\p@
-}\footnotesize\rm
-\def\newblock{\ }
-\sloppy\clubpenalty4000\widowpenalty4000
-\sfcode`\.=1000\relax}{\endlist}
-%
-\def\refs{\begin{harvard}}
-\def\endrefs{\end{harvard}}
-%
-\newenvironment{indented}{\begin{indented}}{\end{indented}}
-\newenvironment{varindent}[1]{\begin{varindent}{#1}}{\end{varindent}}
-%
-\def\indented{\list{}{\itemsep=0\p@\labelsep=0\p@\itemindent=0\p@
-   \labelwidth=0\p@\leftmargin=\mathindent\topsep=0\p@\partopsep=0\p@
-   \parsep=0\p@\listparindent=15\p@}\footnotesize\rm}
-
-\let\endindented=\endlist 
-
-\def\varindent#1{\setlength{\varind}{#1}%
-   \list{}{\itemsep=0\p@\labelsep=0\p@\itemindent=0\p@
-   \labelwidth=0\p@\leftmargin=\varind\topsep=0\p@\partopsep=0\p@
-   \parsep=0\p@\listparindent=15\p@}\footnotesize\rm}
-
-\let\endvarindent=\endlist 
-
-\def\[{\relax\ifmmode\@badmath\else
- \begin{trivlist}
- \@beginparpenalty\predisplaypenalty
- \@endparpenalty\postdisplaypenalty
- \item[]\leavevmode
- \hbox to\linewidth\bgroup$ \displaystyle
- \hskip\mathindent\bgroup\fi}
-\def\]{\relax\ifmmode \egroup $\hfil \egroup \end{trivlist}\else \@badmath \fi}
-\def\equation{\@beginparpenalty\predisplaypenalty
- \@endparpenalty\postdisplaypenalty
-\refstepcounter{equation}\trivlist \item[]\leavevmode
- \hbox to\linewidth\bgroup $ \displaystyle
-\hskip\mathindent}
-\def\endequation{$\hfil \displaywidth\linewidth\@eqnnum\egroup \endtrivlist}
-%
-\@namedef{equation*}{\[}
-\@namedef{endequation*}{\]}
-%
-\def\eqnarray{\stepcounter{equation}\let\@currentlabel=\theequation
-\global\@eqnswtrue
-\global\@eqcnt\z@\tabskip\mathindent\let\\=\@eqncr
-\abovedisplayskip\topsep\ifvmode\advance\abovedisplayskip\partopsep\fi
-\belowdisplayskip\abovedisplayskip
-\belowdisplayshortskip\abovedisplayskip
-\abovedisplayshortskip\abovedisplayskip
-$$\halign to
-\linewidth\bgroup\@eqnsel$\displaystyle\tabskip\z@
- {##{}}$&\global\@eqcnt\@ne $\displaystyle{{}##{}}$\hfil
- &\global\@eqcnt\tw@ $\displaystyle{{}##}$\hfil
- \tabskip\@centering&\llap{##}\tabskip\z@\cr}
-\def\endeqnarray{\@@eqncr\egroup
- \global\advance\c@equation\m@ne$$\global\@ignoretrue }
-\mathindent = 6pc
-%
-\def\eqalign#1{\null\vcenter{\def\\{\cr}\openup\jot\m@th
-  \ialign{\strut$\displaystyle{##}$\hfil&$\displaystyle{{}##}$\hfil
-      \crcr#1\crcr}}\,}
-%
-\def\eqalignno#1{\displ@y \tabskip\z@skip
-  \halign to\displaywidth{\hspace{5pc}$\@lign\displaystyle{##}$%
-    \tabskip\z@skip
-    &$\@lign\displaystyle{{}##}$\hfill\tabskip\@centering
-    &\llap{$\@lign\hbox{\rm##}$}\tabskip\z@skip\crcr
-    #1\crcr}}
-%
-\newif\ifnumbysec
-\def\theequation{\ifnumbysec
-      \arabic{section}.\arabic{equation}\else
-      \arabic{equation}\fi}
-\def\eqnobysec{\numbysectrue\@addtoreset{equation}{section}}
-
-\newcounter{eqnval}
-
-% 2012: if you have an eqn numbered by parts (eg eqn 6a, 6b) this allows
-% you to refer to it by just the number (eg eqn 6) if the label is between
-% the \multiparteqn and the \numparts
-\def\multiparteqn{\addtocounter{equation}{1}
-\eqnarray\nonumber
-\endeqnarray
-
-\vspace{-72pt}
-}
-
-\def\numparts{\addtocounter{equation}{1}%
-     \setcounter{eqnval}{\value{equation}}%
-     \setcounter{equation}{0}%
-     \def\theequation{\ifnumbysec
-     \arabic{section}.\arabic{eqnval}{\it\alph{equation}}%
-     \else\arabic{eqnval}{\it\alph{equation}}\fi}}
-
-\def\endnumparts{\def\theequation{\ifnumbysec
-     \arabic{section}.\arabic{equation}\else
-     \arabic{equation}\fi}%
-     \setcounter{equation}{\value{eqnval}}}
-%
-\def\cases#1{%
-     \left\{\,\vcenter{\def\\{\cr}\normalbaselines\openup1\jot\m@th%
-     \ialign{\strut$\displaystyle{##}\hfil$&\tqs
-     \rm##\hfil\crcr#1\crcr}}\right.}%
-%
-\newcommand{\e}{\mathrm{e}}
-\newcommand{\rme}{\mathrm{e}}
-\newcommand{\rmi}{\mathrm{i}}
-\newcommand{\rmd}{\mathrm{d}}
-\renewcommand{\qquad}{\hspace*{25pt}}
-\newcommand{\tdot}[1]{\stackrel{\dots}{#1}}   % Added 1/9/94
-\newcommand{\tqs}{\hspace*{25pt}}
-\newcommand{\fl}{\hspace*{-\mathindent}}
-\newcommand{\Tr}{\mathop{\mathrm{Tr}}\nolimits}
-\newcommand{\tr}{\mathop{\mathrm{tr}}\nolimits}
-\newcommand{\Or}{\mathord{\mathrm{O}}} %changed from \mathop 20/1/95
-\newcommand{\lshad}{[\![}
-\newcommand{\rshad}{]\!]}
-\newcommand{\case}[2]{{\textstyle\frac{#1}{#2}}}
-\def\pt(#1){({\it #1\/})}
-\newcommand{\dsty}{\displaystyle}
-\newcommand{\tsty}{\textstyle}
-\newcommand{\ssty}{\scriptstyle}
-\newcommand{\sssty}{\scriptscriptstyle}
-\def\lo#1{\llap{${}#1{}$}}
-\def\eql{\llap{${}={}$}}
-\def\lsim{\llap{${}\sim{}$}}
-\def\lsimeq{\llap{${}\simeq{}$}}
-\def\lequiv{\llap{${}\equiv{}$}}
-%
-\newcommand{\eref}[1]{(\ref{#1})}
-\newcommand{\sref}[1]{section~\ref{#1}}
-\newcommand{\fref}[1]{figure~\ref{#1}}
-\newcommand{\tref}[1]{table~\ref{#1}}
-\newcommand{\Eref}[1]{Equation (\ref{#1})}
-\newcommand{\Sref}[1]{Section~\ref{#1}}
-\newcommand{\Fref}[1]{Figure~\ref{#1}}
-\newcommand{\Tref}[1]{Table~\ref{#1}}
-
-\newcommand{\opencircle}{\mbox{\Large$\circ\,$}}  % moved Large outside maths
-\newcommand{\opensquare}{\mbox{$\rlap{$\sqcap$}\sqcup$}}
-\newcommand{\opentriangle}{\mbox{$\triangle$}}
-\newcommand{\opentriangledown}{\mbox{$\bigtriangledown$}}
-\newcommand{\opendiamond}{\mbox{$\diamondsuit$}}
-\newcommand{\fullcircle}{\mbox{{\Large$\bullet\,$}}} % moved Large outside maths
-\newcommand{\fullsquare}{\,\vrule height5pt depth0pt width5pt}
-\newcommand{\dotted}{\protect\mbox{${\mathinner{\cdotp\cdotp\cdotp\cdotp\cdotp\cdotp}}$}}
-\newcommand{\dashed}{\protect\mbox{-\; -\; -\; -}}
-\newcommand{\broken}{\protect\mbox{-- -- --}}
-\newcommand{\longbroken}{\protect\mbox{--- --- ---}}
-\newcommand{\chain}{\protect\mbox{--- $\cdot$ ---}}
-\newcommand{\dashddot}{\protect\mbox{--- $\cdot$ $\cdot$ ---}}
-\newcommand{\full}{\protect\mbox{------}}
-
-\def\;{\protect\psemicolon}
-\def\psemicolon{\relax\ifmmode\mskip\thickmuskip\else\kern .3333em\fi}
-\def\lineup{\def\0{\hbox{\phantom{\footnotesize\rm 0}}}%
-    \def\m{\hbox{$\phantom{-}$}}%
-    \def\-{\llap{$-$}}}
-%
-%%%%%%%%%%%%%%%%%%%%%
-% Tables rules      %
-%%%%%%%%%%%%%%%%%%%%%
-
-\newcommand{\boldarrayrulewidth}{1\p@} 
-% Width of bold rule in tabular environment.
-
-\def\bhline{\noalign{\ifnum0=`}\fi\hrule \@height  
-\boldarrayrulewidth \futurelet \@tempa\@xhline}
-
-\def\@xhline{\ifx\@tempa\hline\vskip \doublerulesep\fi
-      \ifnum0=`{\fi}}
-
-%
-% Rules for tables with extra space around
-%
-\newcommand{\br}{\ms\bhline\ms}
-\newcommand{\mr}{\ms\hline\ms}
-%
-\newcommand{\centre}[2]{\multispan{#1}{\hfill #2\hfill}}
-\newcommand{\crule}[1]{\multispan{#1}{\hspace*{\tabcolsep}\hrulefill
-  \hspace*{\tabcolsep}}}
-\newcommand{\fcrule}[1]{\ifnum\thetabtype=1\multispan{#1}{\hrulefill
-  \hspace*{\tabcolsep}}\else\multispan{#1}{\hrulefill}\fi}
-%
-% Extra spaces for tables and displayed equations
-%
-\newcommand{\ms}{\noalign{\vspace{3\p@ plus2\p@ minus1\p@}}}
-\newcommand{\bs}{\noalign{\vspace{6\p@ plus2\p@ minus2\p@}}}
-\newcommand{\ns}{\noalign{\vspace{-3\p@ plus-1\p@ minus-1\p@}}}
-\newcommand{\es}{\noalign{\vspace{6\p@ plus2\p@ minus2\p@}}\displaystyle}%
-%
-\newcommand{\etal}{{\it et al\/}\ }
-\newcommand{\dash}{------}
-\newcommand{\nonum}{\par\item[]}                %\par added 1/9/93
-\newcommand{\mat}[1]{\underline{\underline{#1}}}
-%
-% abbreviations for IOPP journals
-%
-\newcommand{\CQG}{{\it Class. Quantum Grav.} }
-\newcommand{\CTM}{{\it Combust. Theory Modelling\/} }
-\newcommand{\DSE}{{\it Distrib. Syst. Engng.\/} }
-\newcommand{\EJP}{{\it Eur. J. Phys.} } 
-\newcommand{\JNE}{{\it J. Neural Eng.} } %added 30/11/2004 GMD
-\newcommand{\PB}{{\it Phys. Biol.} } %added 30/11/2004 GMD
-\newcommand{\SMS}{{\it Smart Mater. Struct.} } %added 30/11/2004 GMD
-\newcommand{\HPP}{{\it High Perform. Polym.} }              % added 4/5/93
-\newcommand{\IP}{{\it Inverse Problems\/} }
-\newcommand{\JHM}{{\it J. Hard Mater.} }                    % added 4/5/93
-\newcommand{\JO}{{\it J. Opt.} }
-\newcommand{\JOA}{{\it J. Opt. A: Pure Appl. Opt.} }
-\newcommand{\JOB}{{\it J. Opt. B: Quantum Semiclass. Opt.} }
-\newcommand{\JPA}{{\it J. Phys. A: Math. Gen.} } % superseded by \jpa below
-\newcommand{\JPB}{{\it J. Phys. B: At. Mol. Phys.} }      %1968-87
-\newcommand{\jpb}{{\it J. Phys. B: At. Mol. Opt. Phys.} } %1988 and onwards
-\newcommand{\JPC}{{\it J. Phys. C: Solid State Phys.} }   %1968--1988
-\newcommand{\JPCM}{{\it J. Phys.: Condens. Matter\/} }    %1989 and onwards
-\newcommand{\JPD}{{\it J. Phys. D: Appl. Phys.} }
-\newcommand{\JPE}{{\it J. Phys. E: Sci. Instrum.} }
-\newcommand{\JPF}{{\it J. Phys. F: Met. Phys.} }
-\newcommand{\JPG}{{\it J. Phys. G: Nucl. Phys.} }         %1975--1988
-\newcommand{\jpg}{{\it J. Phys. G: Nucl. Part. Phys.} }   %1989 and onwards
-\newcommand{\JMM}{{\it J. Micromech. Microeng.\/} }
-\newcommand{\MSMSE}{{\it Modelling Simul. Mater. Sci. Eng.} } % sxb changed to 'Simul' 15 Mar 2011
-\newcommand{\MST}{{\it Meas. Sci. Technol.} }                 %1990 and onwards
-\newcommand{\NET}{{\it Network: Comput. Neural Syst.} }
-\newcommand{\NJP}{{\it New J. Phys.} }
-\newcommand{\NL}{{\it Nonlinearity\/} }
-\newcommand{\NT}{{\it Nanotechnology} }
-\newcommand{\PAO}{{\it Pure Appl. Optics\/} }
-\newcommand{\PM}{{\it Physiol. Meas.} }                        % added 4/5/93
-\newcommand{\PMB}{{\it Phys. Med. Biol.} }
-\newcommand{\PPCF}{{\it Plasma Phys. Control. Fusion\/} }      % added 4/5/93
-\newcommand{\PSST}{{\it Plasma Sources Sci. Technol.} }
-\newcommand{\PUS}{{\it Public Understand. Sci.} }
-\newcommand{\QO}{{\it Quantum Opt.} }
-\newcommand{\QSO}{{\em Quantum Semiclass. Opt.} }
-\newcommand{\RPP}{{\it Rep. Prog. Phys.} }
-\newcommand{\SLC}{{\it Sov. Lightwave Commun.} }               % added 4/5/93 
-\newcommand{\SST}{{\it Semicond. Sci. Technol.} }
-\newcommand{\SUST}{{\it Supercond. Sci. Technol.} }
-\newcommand{\WRM}{{\it Waves Random Media\/} }
-%
-% Other commonly quoted journals
-%
-\newcommand{\AC}{{\it Acta Crystallogr.} }
-\newcommand{\AM}{{\it Acta Metall.} }
-\newcommand{\AP}{{\it Ann. Phys., Lpz.} }
-\newcommand{\APNY}{{\it Ann. Phys., NY\/} }
-\newcommand{\APP}{{\it Ann. Phys., Paris\/} }
-\newcommand{\CJP}{{\it Can. J. Phys.} }
-\newcommand{\JAP}{{\it J. Appl. Phys.} }
-\newcommand{\JCP}{{\it J. Chem. Phys.} }
-\newcommand{\JJAP}{{\it Jpn. J. Appl. Phys.} }
-\newcommand{\JP}{{\it J. Physique\/} }
-\newcommand{\JPhCh}{{\it J. Phys. Chem.} }
-\newcommand{\JMMM}{{\it J. Magn. Magn. Mater.} }
-\newcommand{\JMP}{{\it J. Math. Phys.} }
-\newcommand{\JOSA}{{\it J. Opt. Soc. Am.} }
-\newcommand{\JPSJ}{{\it J. Phys. Soc. Jpn.\/} }
-\newcommand{\JQSRT}{{\it J. Quant. Spectrosc. Radiat. Transfer\/} }
-\newcommand{\NC}{{\it Nuovo Cimento\/} }
-\newcommand{\NIM}{{\it Nucl. Instrum. Methods\/} }
-\newcommand{\NP}{{\it Nucl. Phys.} }
-\newcommand{\PL}{{\it Phys. Lett.} }
-\newcommand{\PR}{{\it Phys. Rev.} }
-\newcommand{\PRL}{{\it Phys. Rev. Lett.} }
-\newcommand{\PRS}{{\it Proc. R. Soc.} }
-\newcommand{\PS}{{\it Phys. Scr.} }
-\newcommand{\PSS}{{\it Phys. Status Solidi\/} }
-\newcommand{\PTRS}{{\it Phil. Trans. R. Soc.} }
-\newcommand{\RMP}{{\it Rev. Mod. Phys.} }
-\newcommand{\RSI}{{\it Rev. Sci. Instrum.} }
-\newcommand{\SSC}{{\it Solid State Commun.} }
-\newcommand{\ZP}{{\it Z. Phys.} }
-\newcommand{\GRG}{{\it Gen. Rel. Grav.} }
-\newcommand{\PF}{{\it Phys. Fluids\/} }
-\newcommand{\SPJ}{{\it Sov. Phys.--JETP\/} }
-%
-% More journals added 8 Mar 2011, below (sxb)
-%
-\newcommand{\jpa}{{\it J. Phys. A: Math. Theor.} }
-\newcommand{\BF}{{\it Biofabrication\/} }
-\newcommand{\BB}{{\it Bioinspir. Biomim.} }
-\newcommand{\BMM}{{\it Biomed. Mater.} }
-\newcommand{\CSD}{{\it Comput. Sci. Disc.} }
-\newcommand{\ERL}{{\it Environ. Res. Lett.} }
-\newcommand{\JBR}{{\it J. Breath Res.} }
-\newcommand{\JGE}{{\it J. Geophys. Eng.} }
-\newcommand{\JOPT}{{\it J. Opt.} }
-\newcommand{\JRP}{{\it J. Radiol. Prot.} }
-\newcommand{\MET}{{\it Metrologia\/} }
-\newcommand{\NF}{{\it Nucl. Fusion\/} }
-\newcommand{\PED}{{\it Phys. Educ.} }
-%
-% More journals added 6 Feb 2014, below (sxb)
-%
-\newcommand{\TDM}{{\it 2D Mater.} }
-\newcommand{\MRE}{{\it Mater. Res. Express\/} }
-\newcommand{\MAF}{{\it Methods Appl. Fluoresc.} }
-\newcommand{\TMR}{{\it Transl. Mater. Res.} }
-\newcommand{\STMP}{{\it Surf. Topogr.: Metrol. Prop.} }
-%
-% The following journals are externally-edited and the usual IOP Publishing
-% submission guidelines do *not* apply if you're submitting to them.
-%
-\newcommand{\AJ}{{\it AJ\/} }
-\newcommand{\APJ}{{\it ApJ\/} }
-\newcommand{\APJL}{{\it ApJL\/} }
-\newcommand{\APJS}{{\it ApJS\/} }
-\newcommand{\ANSN}{{\it Adv. Nat. Sci: Nanosci. Nanotechnol.} }
-\newcommand{\CJCP}{{\it Chin. J. Chem. Phys.} }
-\newcommand{\CPB}{{\it Chinese Phys. B\/} }
-\newcommand{\CPC}{{\it Chinese Phys. C\/} }
-\newcommand{\CPL}{{\it Chinese Phys. Lett.} }
-\newcommand{\CTP}{{\it Commun. Theor. Phys.} }
-\newcommand{\EPL}{{\it EPL\/} }
-\newcommand{\FDR}{{\it Fluid Dyn. Res.} }
-\newcommand{\IZV}{{\it Izv. Math.} }
-\newcommand{\JOS}{{\it J. Semicond.} }
-\newcommand{\PHU}{{\it Phys.-Usp.} }
-\newcommand{\PST}{{\it Plasma Sci. Technol.} }
-\newcommand{\QEL}{{\it Quantum Electron.} }
-\newcommand{\RAA}{{\it Res. Astron. Astrophys.} }
-\newcommand{\RCR}{{\it Russ. Chem. Rev.} }
-\newcommand{\RMS}{{\it Russ. Math. Surv.} }
-\newcommand{\MSB}{{\it Sb. Math.} }
-\newcommand{\SFC}{{\it Science Foundation in China\/} }
-\newcommand{\STAM}{{\it Sci. Technol. Adv. Mater.} }
-\newcommand{\LP}{{\it Laser Phys.} }
-\newcommand{\LPL}{{\it Laser Phys. Lett.} }
-\newcommand{\APEX}{{\it Appl. Phys. Express\/} }
-%
-% SISSA journals
-%
-\newcommand{\JCAP}{{\it JCAP\/} }
-\newcommand{\JHEP}{{\it J. High Energy Phys.\/} }
-\newcommand{\JSTAT}{{\it J. Stat. Mech.} }
-\newcommand{\JINST}{{\it JINST\/} }
-%
-% These are the IOP Conference Series journals: again, if you're
-% submitting to one of these journals you shouldn't be using iopart.cls
-%
-\newcommand{\JPCS}{{\it J. Phys.: Conf. Ser.} }
-\newcommand{\EES}{{\it IOP Conf. Ser.: Earth Environ. Sci.} }
-\newcommand{\MSE}{{\it IOP Conf. Ser.: Mater. Sci. Eng.} }
-
-% 2012 new option for twocolumn output
-\def\ioptwocol{\setlength\hoffset{-0.5in}\setlength\voffset{-0.5in}\setlength\textwidth{6.75in}
-\setlength\columnsep{0.2in}\setlength\textheight{9.25in}\mathindent=0in\twocolumn}
-%
-%
-\pagestyle{headings}
-\pagenumbering{arabic}      % Arabic page numbers
-\raggedbottom
-\onecolumn
-\endinput
-%% 
-%% End of file `iopart.cls'.
-

+ 0 - 124
paper_MD/iopart10.clo

@@ -1,124 +0,0 @@
-%% 
-%% This is file `iopart10.clo'
-%% 
-%% This file is distributed in the hope that it will be useful, 
-%% but WITHOUT ANY WARRANTY; without even the implied warranty of 
-%% MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. 
-%% 
-%% \CharacterTable
-%%  {Upper-case    \A\B\C\D\E\F\G\H\I\J\K\L\M\N\O\P\Q\R\S\T\U\V\W\X\Y\Z
-%%   Lower-case    \a\b\c\d\e\f\g\h\i\j\k\l\m\n\o\p\q\r\s\t\u\v\w\x\y\z
-%%   Digits        \0\1\2\3\4\5\6\7\8\9
-%%   Exclamation   \!     Double quote  \"     Hash (number) \#
-%%   Dollar        \$     Percent       \%     Ampersand     \&
-%%   Acute accent  \'     Left paren    \(     Right paren   \)
-%%   Asterisk      \*     Plus          \+     Comma         \,
-%%   Minus         \-     Point         \.     Solidus       \/
-%%   Colon         \:     Semicolon     \;     Less than     \<
-%%   Equals        \=     Greater than  \>     Question mark \?
-%%   Commercial at \@     Left bracket  \[     Backslash     \\
-%%   Right bracket \]     Circumflex    \^     Underscore    \_
-%%   Grave accent  \`     Left brace    \{     Vertical bar  \|
-%%   Right brace   \}     Tilde         \~}
-\ProvidesFile{iopart10.clo}[1997/01/13 v1.0 IOP Book file (size option)]
-\renewcommand\normalsize{%
-   \@setfontsize\normalsize\@xpt\@xiipt
-   \abovedisplayskip 10\p@ \@plus2\p@ \@minus5\p@
-   \abovedisplayshortskip \z@ \@plus3\p@
-   \belowdisplayshortskip 6\p@ \@plus3\p@ \@minus3\p@
-   \belowdisplayskip \abovedisplayskip
-   \let\@listi\@listI}
-\normalsize
-\newcommand\small{%
-   \@setfontsize\small\@ixpt{11}%
-   \abovedisplayskip 8.5\p@ \@plus3\p@ \@minus4\p@
-   \abovedisplayshortskip \z@ \@plus2\p@
-   \belowdisplayshortskip 4\p@ \@plus2\p@ \@minus2\p@
-   \def\@listi{\leftmargin\leftmargini
-               \topsep 4\p@ \@plus2\p@ \@minus2\p@
-               \parsep 2\p@ \@plus\p@ \@minus\p@
-               \itemsep \parsep}%
-   \belowdisplayskip \abovedisplayskip
-}
-\newcommand\footnotesize{%
-   \@setfontsize\footnotesize\@viiipt{9.5}%
-   \abovedisplayskip 6\p@ \@plus2\p@ \@minus4\p@
-   \abovedisplayshortskip \z@ \@plus\p@
-   \belowdisplayshortskip 3\p@ \@plus\p@ \@minus2\p@
-   \def\@listi{\leftmargin\leftmargini
-               \topsep 3\p@ \@plus\p@ \@minus\p@
-               \parsep 2\p@ \@plus\p@ \@minus\p@
-               \itemsep \parsep}%
-   \belowdisplayskip \abovedisplayskip
-}
-\newcommand\scriptsize{\@setfontsize\scriptsize\@viipt\@viiipt}
-\newcommand\tiny{\@setfontsize\tiny\@vpt\@vipt}
-\newcommand\large{\@setfontsize\large\@xiipt{14}}
-\newcommand\Large{\@setfontsize\Large\@xivpt{18}}
-\newcommand\LARGE{\@setfontsize\LARGE\@xviipt{22}}
-\newcommand\huge{\@setfontsize\huge\@xxpt{25}}
-\newcommand\Huge{\@setfontsize\Huge\@xxvpt{30}}
-\if@twocolumn
-  \setlength\parindent{12\p@}
-\else
-  \setlength\parindent{15\p@}
-\fi
-\setlength\headheight{12\p@}
-\setlength\headsep   {12\p@}
-\setlength\topskip   {10\p@}
-\setlength\footskip{20\p@}
-\setlength\maxdepth{.5\topskip}
-\setlength\@maxdepth\maxdepth
-\setlength\textwidth{31pc}
-\setlength\textheight{49pc}
-\setlength\oddsidemargin  {24\p@}
-\setlength\evensidemargin {24\p@}
-\setlength\marginparwidth {72\p@}
-\setlength\marginparsep {10\p@}
-\setlength\marginparpush{5\p@}
-\setlength\topmargin{\z@}
-\setlength\footnotesep{6.65\p@}
-\setlength{\skip\footins}  {9\p@ \@plus 4\p@ \@minus 2\p@}
-\setlength\floatsep       {12\p@ \@plus 2\p@ \@minus 2\p@}
-\setlength\textfloatsep   {20\p@ \@plus 2\p@ \@minus 4\p@}
-\setlength\intextsep      {12\p@ \@plus 2\p@ \@minus 2\p@}
-\setlength\dblfloatsep    {12\p@ \@plus 2\p@ \@minus 2\p@}
-\setlength\dbltextfloatsep{20\p@ \@plus 2\p@ \@minus 4\p@}
-\setlength\@fptop{0\p@}
-\setlength\@fpsep{8\p@ \@plus 2fil}
-\setlength\@fpbot{0\p@}
-\setlength\@dblfptop{0\p@}
-\setlength\@dblfpsep{8\p@ \@plus 2fil}
-\setlength\@dblfpbot{0\p@}
-\setlength\partopsep{2\p@ \@plus 1\p@ \@minus 1\p@}
-\def\@listI{\leftmargin\leftmargini
-            \parsep=\z@ 
-            \topsep=5\p@ \@plus3\p@ \@minus3\p@
-            \itemsep=3\p@ \@plus2\p@ \@minus\p@}
-\let\@listi\@listI
-\@listi
-\def\@listii {\leftmargin\leftmarginii
-     \labelwidth\leftmarginii
-     \advance\labelwidth-\labelsep
-     \topsep=2\p@ \@plus2\p@ \@minus\p@
-     \parsep=\z@
-     \itemsep=\parsep}
-\def\@listiii{\leftmargin\leftmarginiii
-     \labelwidth\leftmarginiii
-     \advance\labelwidth-\labelsep
-     \topsep=\z@
-     \parsep=\z@
-     \partopsep=\z@
-     \itemsep=\z@}
-\def\@listiv {\leftmargin\leftmarginiv
-     \labelwidth\leftmarginiv
-     \advance\labelwidth-\labelsep}
-\def\@listv  {\leftmargin\leftmarginv
-     \labelwidth\leftmarginv
-     \advance\labelwidth-\labelsep}
-\def\@listvi {\leftmargin\leftmarginvi
-     \labelwidth\leftmarginvi
-     \advance\labelwidth-\labelsep}
-\endinput
-%% 
-%% End of file `iopart.clo'.

+ 0 - 125
paper_MD/iopart12.clo

@@ -1,125 +0,0 @@
-%% 
-%% This is file `iopart12.clo'
-%% 
-%% This file is distributed in the hope that it will be useful, 
-%% but WITHOUT ANY WARRANTY; without even the implied warranty of 
-%% MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. 
-%% 
-%% \CharacterTable
-%%  {Upper-case    \A\B\C\D\E\F\G\H\I\J\K\L\M\N\O\P\Q\R\S\T\U\V\W\X\Y\Z
-%%   Lower-case    \a\b\c\d\e\f\g\h\i\j\k\l\m\n\o\p\q\r\s\t\u\v\w\x\y\z
-%%   Digits        \0\1\2\3\4\5\6\7\8\9
-%%   Exclamation   \!     Double quote  \"     Hash (number) \#
-%%   Dollar        \$     Percent       \%     Ampersand     \&
-%%   Acute accent  \'     Left paren    \(     Right paren   \)
-%%   Asterisk      \*     Plus          \+     Comma         \,
-%%   Minus         \-     Point         \.     Solidus       \/
-%%   Colon         \:     Semicolon     \;     Less than     \<
-%%   Equals        \=     Greater than  \>     Question mark \?
-%%   Commercial at \@     Left bracket  \[     Backslash     \\
-%%   Right bracket \]     Circumflex    \^     Underscore    \_
-%%   Grave accent  \`     Left brace    \{     Vertical bar  \|
-%%   Right brace   \}     Tilde         \~}
-\ProvidesFile{iopart12.clo}[1997/01/15 v1.0 LaTeX2e file (size option)]
-\renewcommand\normalsize{%
-   \@setfontsize\normalsize\@xiipt{16}%
-   \abovedisplayskip 12\p@ \@plus3\p@ \@minus7\p@
-   \abovedisplayshortskip \z@ \@plus3\p@
-   \belowdisplayshortskip 6.5\p@ \@plus3.5\p@ \@minus3\p@
-   \belowdisplayskip \abovedisplayskip
-   \let\@listi\@listI}
-\normalsize
-\newcommand\small{%
-   \@setfontsize\small\@xipt{14}%
-   \abovedisplayskip 11\p@ \@plus3\p@ \@minus6\p@
-   \abovedisplayshortskip \z@ \@plus3\p@
-   \belowdisplayshortskip 6.5\p@ \@plus3.5\p@ \@minus3\p@
-   \def\@listi{\leftmargin\leftmargini
-               \topsep 9\p@ \@plus3\p@ \@minus5\p@
-               \parsep 4.5\p@ \@plus2\p@ \@minus\p@
-               \itemsep \parsep}%
-   \belowdisplayskip \abovedisplayskip
-}
-\newcommand\footnotesize{%
-%   \@setfontsize\footnotesize\@xpt\@xiipt
-   \@setfontsize\footnotesize\@xpt{13}%
-   \abovedisplayskip 10\p@ \@plus2\p@ \@minus5\p@
-   \abovedisplayshortskip \z@ \@plus3\p@
-   \belowdisplayshortskip 6\p@ \@plus3\p@ \@minus3\p@
-   \def\@listi{\leftmargin\leftmargini
-               \topsep 6\p@ \@plus2\p@ \@minus2\p@
-               \parsep 3\p@ \@plus2\p@ \@minus\p@
-               \itemsep \parsep}%
-   \belowdisplayskip \abovedisplayskip
-}
-\newcommand\scriptsize{\@setfontsize\scriptsize\@viiipt{9.5}}
-\newcommand\tiny{\@setfontsize\tiny\@vipt\@viipt}
-\newcommand\large{\@setfontsize\large\@xivpt{18}}
-\newcommand\Large{\@setfontsize\Large\@xviipt{22}}
-\newcommand\LARGE{\@setfontsize\LARGE\@xxpt{25}}
-\newcommand\huge{\@setfontsize\huge\@xxvpt{30}}
-\let\Huge=\huge
-\if@twocolumn
-  \setlength\parindent{14\p@}
-\else
-  \setlength\parindent{18\p@}
-\fi
-\setlength\headheight{14\p@}
-\setlength\headsep{14\p@}
-\setlength\topskip{12\p@}
-\setlength\footskip{24\p@}
-\setlength\maxdepth{.5\topskip}
-\setlength\@maxdepth\maxdepth
-\setlength\textwidth{37.2pc}
-\setlength\textheight{56pc}
-\setlength\oddsidemargin  {\z@}
-\setlength\evensidemargin {\z@}
-\setlength\marginparwidth {72\p@}
-\setlength\marginparsep{10\p@}
-\setlength\marginparpush{5\p@}
-\setlength\topmargin{-12pt}
-\setlength\footnotesep{8.4\p@}
-\setlength{\skip\footins} {10.8\p@ \@plus 4\p@ \@minus 2\p@}
-\setlength\floatsep       {14\p@ \@plus 2\p@ \@minus 4\p@}
-\setlength\textfloatsep   {24\p@ \@plus 2\p@ \@minus 4\p@}
-\setlength\intextsep      {16\p@ \@plus 4\p@ \@minus 4\p@}
-\setlength\dblfloatsep    {16\p@ \@plus 2\p@ \@minus 4\p@}
-\setlength\dbltextfloatsep{24\p@ \@plus 2\p@ \@minus 4\p@}
-\setlength\@fptop{0\p@}
-\setlength\@fpsep{10\p@ \@plus 1fil}
-\setlength\@fpbot{0\p@}
-\setlength\@dblfptop{0\p@}
-\setlength\@dblfpsep{10\p@ \@plus 1fil}
-\setlength\@dblfpbot{0\p@}
-\setlength\partopsep{3\p@ \@plus 2\p@ \@minus 2\p@}
-\def\@listI{\leftmargin\leftmargini
-     \parsep=\z@
-     \topsep=6\p@  \@plus3\p@ \@minus3\p@
-     \itemsep=3\p@ \@plus2\p@ \@minus1\p@}
-\let\@listi\@listI
-\@listi
-\def\@listii {\leftmargin\leftmarginii
-     \labelwidth\leftmarginii
-     \advance\labelwidth-\labelsep
-     \topsep=3\p@ \@plus2\p@ \@minus\p@
-     \parsep=\z@
-     \itemsep=\parsep}
-\def\@listiii{\leftmargin\leftmarginiii
-     \labelwidth\leftmarginiii
-     \advance\labelwidth-\labelsep
-     \topsep=\z@
-     \parsep=\z@
-     \partopsep=\z@
-     \itemsep=\z@}
-\def\@listiv {\leftmargin\leftmarginiv
-     \labelwidth\leftmarginiv
-     \advance\labelwidth-\labelsep}
-\def\@listv{\leftmargin\leftmarginv
-     \labelwidth\leftmarginv
-     \advance\labelwidth-\labelsep}
-\def\@listvi {\leftmargin\leftmarginvi
-     \labelwidth\leftmarginvi
-     \advance\labelwidth-\labelsep}
-\endinput
-%% 
-%% End of file `iopart12.clo'.

Разница между файлами не показана из-за своего большого размера
+ 0 - 523
paper_MD/refs.bib


Разница между файлами не показана из-за своего большого размера
+ 0 - 48
paper_MD/risk_modeling.tex


+ 0 - 139
paper_MD/setstack.sty

@@ -1,139 +0,0 @@
-%%
-%% This is file `setstack.sty', created by VIK 15 Dec 1998
-%% Reproduces useful macros from amsmath.sty, thus avoiding the need to load the entire
-%% amsmath.sty and run into conflicts
-%% Adds definitions for \overset, \underset, \sideset, \substack, \boxed, \leftroot,
-%% \uproot, \dddot, \ddddot, \varrow, \harrow (see The LateX Companion, pp 225-227)
-\NeedsTeXFormat{LaTeX2e}% LaTeX 2.09 can't be used (nor non-LaTeX)
-[1998/12/15]% LaTeX date must December 1998 or later
-\ProvidesPackage{setstack}
-\DeclareRobustCommand{\text}{%
-  \ifmmode\expandafter\text@\else\expandafter\mbox\fi}
-  \let\nfss@text\text
-  \def\text@#1{\mathchoice
-    {\textdef@\displaystyle\f@size{#1}}%
-      {\textdef@\textstyle\tf@size{\firstchoice@false #1}}%
-        {\textdef@\textstyle\sf@size{\firstchoice@false #1}}%
-          {\textdef@\textstyle \ssf@size{\firstchoice@false #1}}%
-            \check@mathfonts
-}
-\def\textdef@#1#2#3{\hbox{{%
-             \everymath{#1}%
-             \let\f@size#2\selectfont #3}}}
-
-% adds underset, overset, sideset and 
-% substack features from amsmath.sty (Companion p. 226)
-
-\def\invalid@tag#1{\@amsmath@err{#1}{\the\tag@help}\gobble@tag}
-\def\dft@tag{\invalid@tag{\string\tag\space not allowed here}}
-\def\default@tag{\let\tag\dft@tag}
-
-\def\Let@{\let\\\math@cr}
-\def\restore@math@cr{\def\math@cr@@@{\cr}}
-
-\def\overset#1#2{\binrel@{#2}%
-\binrel@@{\mathop{\kern\z@#2}\limits^{#1}}}
-\def\underset#1#2{\binrel@{#2}%
-\binrel@@{\mathop{\kern\z@#2}\limits_{#1}}}
-\def\sideset#1#2#3{%
-\@mathmeasure\z@\displaystyle{#3}%
-\global\setbox\@ne\vbox to\ht\z@{}\dp\@ne\dp\z@
- \setbox\tw@\box\@ne
-\@mathmeasure4\displaystyle{\copy\tw@#1}%
-\@mathmeasure6\displaystyle{#3\nolimits#2}%
-\dimen@-\wd6 \advance\dimen@\wd4 \advance\dimen@\wd\z@
-\hbox to\dimen@{}\mathop{\kern-\dimen@\box4\box6}%
-}
-
-\newenvironment{subarray}[1]{%
-\vcenter\bgroup
-\Let@ \restore@math@cr \default@tag
-\baselineskip\fontdimen10 \scriptfont\tw@
-\advance\baselineskip\fontdimen12 \scriptfont\tw@
-\lineskip\thr@@\fontdimen8 \scriptfont\thr@@
-\lineskiplimit\lineskip
-\ialign\bgroup\ifx c#1\hfil\fi
-$\m@th\scriptstyle##$\hfil\crcr
-}{%
-\crcr\egroup\egroup
-}
-\newcommand{\substack}[1]{\subarray{c}#1\endsubarray}
-
-% definitions of dddot and ddddot(p. 225)
-
-\def\dddot#1{{\mathop{#1}\limits^{\vbox to-1.4\ex@{\kern-\tw@\ex@
- \hbox{\normalfont ...}\vss}}}}
-\def\ddddot#1{{\mathop{#1}\limits^{\vbox to-1.4\ex@{\kern-\tw@\ex@
- \hbox{\normalfont....}\vss}}}}
-
-% definitions of leftroot, uproot (p.225)
-
-\begingroup \catcode`\"=12
-\gdef\@@sqrt#1{\radical"270370 {#1}}
-\endgroup
-
-\def\leftroot{\@amsmath@err{\Invalid@@\leftroot}\@eha}
-\def\uproot{\@amsmath@err{\Invalid@@\uproot}\@eha}
-\newcount\uproot@
-\newcount\leftroot@
-\def\root{\relaxnext@
-  \DN@{\ifx\@let@token\uproot\let\next@\nextii@\else
-   \ifx\@let@token\leftroot\let\next@\nextiii@\else
-   \let\next@\plainroot@\fi\fi\next@}%
-  \def\nextii@\uproot##1{\uproot@##1\relax\FN@\nextiv@}%
-  \def\nextiv@{\ifx\@let@token\@sptoken\DN@. {\FN@\nextv@}\else
-   \DN@.{\FN@\nextv@}\fi\next@.}%
-  \def\nextv@{\ifx\@let@token\leftroot\let\next@\nextvi@\else
-   \let\next@\plainroot@\fi\next@}%
-  \def\nextvi@\leftroot##1{\leftroot@##1\relax\plainroot@}%
-   \def\nextiii@\leftroot##1{\leftroot@##1\relax\FN@\nextvii@}%
-  \def\nextvii@{\ifx\@let@token\@sptoken
-   \DN@. {\FN@\nextviii@}\else
-   \DN@.{\FN@\nextviii@}\fi\next@.}%
-  \def\nextviii@{\ifx\@let@token\uproot\let\next@\nextix@\else
-   \let\next@\plainroot@\fi\next@}%
-  \def\nextix@\uproot##1{\uproot@##1\relax\plainroot@}%
-  \bgroup\uproot@\z@\leftroot@\z@\FN@\next@}
-\def\plainroot@#1\of#2{\setbox\rootbox\hbox{%
- $\m@th\scriptscriptstyle{#1}$}%
- \mathchoice{\r@@t\displaystyle{#2}}{\r@@t\textstyle{#2}}
- {\r@@t\scriptstyle{#2}}{\r@@t\scriptscriptstyle{#2}}\egroup}
-\def\r@@t#1#2{\setboxz@h{$\m@th#1\@@sqrt{#2}$}%
- \dimen@\ht\z@\advance\dimen@-\dp\z@
- \setbox\@ne\hbox{$\m@th#1\mskip\uproot@ mu$}%
- \advance\dimen@ by1.667\wd\@ne
- \mkern-\leftroot@ mu\mkern5mu\raise.6\dimen@\copy\rootbox
- \mkern-10mu\mkern\leftroot@ mu\boxz@}
- 
-%   definition of \boxed (math in frame, no dollars) p 225
-
-\def\boxed#1{\fbox{\m@th$\displaystyle#1$}}
-
-% definition of \smash for top and bottom parts of expression in braces (p.227)
-\renewcommand{\smash}[2][tb]{%
-  \def\smash@{#1}%
-  \ifmmode\@xp\mathpalette\@xp\mathsm@sh\else
-        \@xp\makesm@sh\fi{#2}}
-
-% additional difinitions for arrows 
-% zero mm wide #2 mm long vertical arrow shifted 1 mm to left, 1 mm up
-\newcommand{\varrow}[2]{%
-\unitlength=1mm
-  \begin{picture}(0,6) % (0,0)
-  % - for #1 to point arrow down,+ to point arrow up
-  \end{picture}%
-  \put(0,6){\vector(0,#1 3){#2}}    % 6,- for down, 0, + for up
-}
-% 1 mm high #2 mm long horizontal arrow shifted 1 mm up (0,-1)
-\newcommand{\harrow}[2]{%
-\unitlength=1mm
-  \begin{picture}(8,1)(0,-1) %
-  % 1 mm distance between arrow and stackreled object over it (8,1)
-  \put(0,0){\vector(#1 2,0){#2}}     % - to point arrow left, + right
-  \end{picture}%
-}
-
-\endinput
-%% end of setstack.sty
-%% Corrections history:
-%% 

+ 0 - 0
cover_image/pet_ct_risk_modeling_cover.pdf → presentations/cover_image/pet_ct_risk_modeling_cover.pdf


+ 0 - 0
cover_image/pet_ct_risk_modeling_cover.png → presentations/cover_image/pet_ct_risk_modeling_cover.png


Разница между файлами не показана из-за своего большого размера
+ 0 - 40
python/Bayesian with differentDistributions .ipynb


Разница между файлами не показана из-за своего большого размера
+ 0 - 67
python/Logisticregression Method_MLE copy.ipynb


Разница между файлами не показана из-за своего большого размера
+ 0 - 56
python/Logisticregression Method_MLE_After Meeting.ipynb


BIN
python/artifacts/phi_raw_ORIG.npy


+ 0 - 176
python/bayesian/Bayesian_Zahra.py

@@ -1,176 +0,0 @@
-# Constrained Bayesian fit (Gamma for NC, Beta-Prime for AE) — no regularization, no r-prior
-import numpy as np
-import matplotlib.pyplot as plt
-from scipy import optimize
-from scipy.special import betaln, gammaln
-import scipy.io as io
-
-data_path = "../data/"
-suv   = io.loadmat(data_path + "suv_percentilesSLOthenUWM.mat")['lung_SUVperc_COMBINED'][0:58, :, :]
-flags = io.loadmat(data_path + "flags_combined.mat")['flags'][0:58, 3]   # 0=NC, 1=AE
-
-# Feature X = max SUV_94 per subject; label y = flags
-X = np.nanmax(suv[:, :, 94], axis=1).astype(float).ravel()
-y = np.asarray(flags, int).ravel()
-
-# Guard for logs
-X = np.clip(X, 1e-12, None)
-p_emp = float(y.mean())
-
-# Small helpers
-
-def logistic(z):
-    z = np.clip(z, -60, 60)
-    return 1.0 / (1.0 + np.exp(-z))
-
-def sigmoid(t):
-    return 1.0 / (1.0 + np.exp(-t))
-
-def softplus(t):
-    t = np.asarray(t, float)
-    return np.log1p(np.exp(-np.abs(t))) + np.maximum(t, 0.0)
-
-# dE(x) pieces for log-odds
-def dE_ess(x, a, b, s, k, th):
-    x = np.asarray(x, float)
-    return (a - k) * np.log(x) - (a + b) * np.log1p(x / s) + x / th
-
-def dE_const(a, b, s, k, th):
-    return -(a * np.log(s)) - betaln(a, b) + k * np.log(th) + gammaln(k)
-
-def dE_full(x, a, b, s, k, th):
-    return dE_ess(x, a, b, s, k, th) + dE_const(a, b, s, k, th)
-
-# Monotonicity cap for theta
-def theta_max(a, b, k, s, eps=1e-12):
-    A = a - k
-    if A <= 0:
-        return np.inf
-    r = np.sqrt(a + b) - np.sqrt(max(A, eps))
-    if r <= 1e-12:
-        return np.inf
-    return s / (r * r)
-
-# φ = [p_raw, b_raw, s_raw, k_raw, d_raw, u_raw]  (unconstrained)
-def unpack_phi_mono(phi):
-    p_raw, b_raw, s_raw, k_raw, d_raw, u_raw = phi
-    p = sigmoid(p_raw)                       # (0,1)
-    b = softplus(b_raw) + 1e-6               # >0
-    s = softplus(s_raw) + 1e-6               # >0
-    k = softplus(k_raw) + 1e-6               # >0
-    delta = softplus(d_raw) + 1e-6           # >0
-    a = k + delta                            # enforce a > k
-    th_cap = theta_max(a, b, k, s)           # theta cap from monotonicity
-    th = th_cap * sigmoid(u_raw)             # 0 < theta <= th_cap
-    return p, a, b, s, k, th
-
-
-
-# Prior on r = theta / theta_max (softly avoid boundaries)
-
-thcap = theta_max(a, b, k, s)
-if np.isfinite(thcap) and thcap > 0:
-    r = np.clip(th / thcap, 1e-9, 1 - 1e-9)
-    # Negative log Beta prior:  -[(α-1)log r + (β-1)log(1-r)]  (const dropped)
-    npr_r = -((0.5) * np.log(r) + (0.5) * np.log(1.0 - r))
-else:
-    npr_r = 0.0
-
-#  Prior on p 
-TAU = 25.0                                   # shrink toward empirical AE rate
-alpha = max(TAU * p_emp, 1e-6)
-beta  = max(TAU * (1.0 - p_emp), 1e-6)
-
-# Objective: negative log-posterior (likelihood + Beta prior on p)
-def neg_post_phi_mono(phi, X, y):
-    p, a, b, s, k, th = unpack_phi_mono(phi)
-    eps = 1e-12
-
-    L  = (np.log(p) - np.log(1 - p)) + dE_full(X, a, b, s, k, th)
-    px = logistic(L)
-    nll = -np.sum(y * np.log(px + eps) + (1 - y) * np.log(1 - px + eps))
-
-    # Beta(alpha, beta) prior on p → negative log-prior
-    npr_p = -((alpha - 1) * np.log(p + eps) + (beta - 1) * np.log(1 - p + eps))
-
-    return nll + npr_p
-
-# Initialization (stable, simple)
-def init_phi(X, y):
-    # Gamma(k, theta) MoM for NC group (only need k0 as a safe size proxy)
-    X0 = X[y == 0]
-    m0 = X0.mean() if X0.size else X.mean()
-    v0 = X0.var()  if X0.size else X.var()
-    k0 = 2.0 if v0 <= 0 else max((m0**2)/(v0 + 1e-9), 1.5)
-
-    # AE median to seed s0
-    X1 = X[y == 1]
-    m1 = np.median(X1) if X1.size else np.median(X)
-
-    p0 = np.clip(float(y.mean()), 1e-3, 1 - 1e-3)
-    b0, s0 = 1.5, max(m1, 0.5)
-
-    return np.array([
-        np.log(p0 / (1 - p0)),             # p_raw
-        np.log(np.expm1(b0) + 1e-9),       # b_raw
-        np.log(np.expm1(s0) + 1e-9),       # s_raw
-        np.log(np.expm1(k0) + 1e-9),       # k_raw
-        np.log(np.expm1(1.0) + 1e-9),      # d_raw  (delta)
-        -0.2                               # u_raw  (keeps theta a bit below cap initially)
-    ], float)
-
-#  Fit wrapper (one retry)
-def fit_bayes_mono(X, y, phi_start=None, rng=None):
-    if rng is None:
-        rng = np.random.default_rng(0)
-    if phi_start is None:
-        phi_start = init_phi(X, y)
-
-    obj = lambda phi: neg_post_phi_mono(phi, X, y)
-
-    res = optimize.minimize(
-        obj, phi_start, method="L-BFGS-B",
-        options={"maxiter": 6000, "ftol": 1e-9}
-    )
-    if not (res.success and np.isfinite(res.fun)):
-        phi_try = phi_start + rng.normal(0, 0.2, size=phi_start.shape)
-        res = optimize.minimize(
-            obj, phi_try, method="L-BFGS-B",
-            options={"maxiter": 6000, "ftol": 1e-9}
-        )
-    return unpack_phi_mono(res.x), res
-
-#  prediction 
-def P_with(theta, x):
-    p, a, b, s, k, th = theta
-    L = (np.log(p) - np.log(1 - p)) + dE_full(x, a, b, s, k, th)
-    return logistic(L)
-
-# Run fit + plot
-theta_hat, res = fit_bayes_mono(X, y)
-print("Optimization success:", res.success, " fval:", float(res.fun))
-print("theta (p,a,b,s,k,theta):", tuple(float(t) for t in theta_hat))
-
-# x-range (cap right end at 10 for readability)
-x_lo = max(1e-6, float(X.min()) * 0.8)
-x_hi = min(10.0, float(X.max()) * 1.2)
-xg   = np.linspace(x_lo, x_hi, 600)
-p_curve = P_with(theta_hat, xg)
-
-fig, ax = plt.subplots(figsize=(7.0, 4.6), dpi=140)
-ax.plot(xg, p_curve, color="#000000", lw=2.2, label="P(AE|x) (MAP)")
-
-# overlay data with tiny vertical jitter so points don't overlap
-rng_plot = np.random.default_rng(999)
-jit = (rng_plot.random(len(y)) - 0.5) * 0.06
-ax.scatter(X[y==0], (y + jit)[y==0], s=22, alpha=0.55, color="#2ca02c", edgecolors='none', label='NC')
-ax.scatter(X[y==1], (y + jit)[y==1], s=26, alpha=0.75, color="#ff7f0e", edgecolors='none', label='AE')
-
-ax.set_ylim(-0.05, 1.05)
-ax.set_xlabel('x')
-ax.set_ylabel('P(AE | x)')
-ax.set_title('Constrained Bayesian fit (no regularization  prior on p and r:alpha and beta=1.5')
-ax.grid(alpha=0.3)
-ax.legend(loc='lower right', frameon=False)
-plt.tight_layout()
-plt.show()

+ 0 - 190
python/bayesian/Bayesian_Zahra_v1.1.py

@@ -1,190 +0,0 @@
-# Constrained Bayesian fit (Gamma for NC, Beta-Prime for AE) — no regularization, no r-prior
-import numpy as np
-import matplotlib.pyplot as plt
-from scipy import optimize
-from scipy.special import betaln, gammaln
-import scipy.io as io
-import os
-
-# determine git root
-root = os.popen("git rev-parse --show-toplevel").read().strip()
-
-suv   = io.loadmat(os.path.join(root, "data", "suv_percentilesSLOthenUWM.mat"))['lung_SUVperc_COMBINED'][0:58, :, :]
-flags = io.loadmat(os.path.join(root, "data", "flags_combined.mat"))['flags'][0:58, 3]   # 0=NC, 1=AE
-
-# Feature X = max SUV_94 per subject; label y = flags
-X = np.nanmax(suv[:, :, 94], axis=1).astype(float).ravel()
-y = np.asarray(flags, int).ravel()
-
-# Guard for logs
-X = np.clip(X, 1e-12, None)
-p_emp = float(y.mean())
-
-# Small helpers
-
-def logistic(z):
-    z = np.clip(z, -60, 60)
-    return 1.0 / (1.0 + np.exp(-z))
-
-def sigmoid(t):
-    return 1.0 / (1.0 + np.exp(-t))
-
-def softplus(t):
-    t = np.asarray(t, float)
-    return np.log1p(np.exp(-np.abs(t))) + np.maximum(t, 0.0)
-
-# dE(x) pieces for log-odds
-def dE_ess(x, a, b, s, k, th):
-    x = np.asarray(x, float)
-    return (a - k) * np.log(x) - (a + b) * np.log1p(x / s) + x / th
-
-def dE_const(a, b, s, k, th):
-    return -(a * np.log(s)) - betaln(a, b) + k * np.log(th) + gammaln(k)
-
-def dE_full(x, a, b, s, k, th):
-    return dE_ess(x, a, b, s, k, th) + dE_const(a, b, s, k, th)
-
-# Monotonicity cap for theta
-def theta_max(a, b, k, s, eps=1e-12):
-    A = a - k
-    if A <= 0:
-        return np.inf
-    r = np.sqrt(a + b) - np.sqrt(max(A, eps))
-    if r <= 1e-12:
-        return np.inf
-    return s / (r * r)
-
-# φ = [p_raw, b_raw, s_raw, k_raw, d_raw, u_raw]  (unconstrained)
-def unpack_phi_mono(phi):
-    p_raw, b_raw, s_raw, k_raw, d_raw, u_raw = phi
-    p = sigmoid(p_raw)                       # (0,1)
-    b = softplus(b_raw) + 1e-6               # >0
-    s = softplus(s_raw) + 1e-6               # >0
-    k = softplus(k_raw) + 1e-6               # >0
-    delta = softplus(d_raw) + 1e-6           # >0
-    a = k + delta                            # enforce a > k
-    th_cap = theta_max(a, b, k, s)           # theta cap from monotonicity
-    th = th_cap * sigmoid(u_raw)             # 0 < theta <= th_cap
-    return p, a, b, s, k, th
-
-#  Prior on p 
-TAU = 25.0                                   # shrink toward empirical AE rate
-alpha = max(TAU * p_emp, 1e-6)
-beta  = max(TAU * (1.0 - p_emp), 1e-6)
-
-prior_r = None
-#prior_r = (1.01, 1.01)
-#prior_r = (3, 3)
-
-# Objective: negative log-posterior (likelihood + Beta prior on p)
-def neg_post_phi_mono(phi, X, y):
-    p, a, b, s, k, th = unpack_phi_mono(phi)
-    eps = 1e-12
-
-    L  = (np.log(p) - np.log(1 - p)) + dE_full(X, a, b, s, k, th)
-    px = logistic(L)
-    nll = -np.sum(y * np.log(px + eps) + (1 - y) * np.log(1 - px + eps))
-
-    # Beta(alpha, beta) prior on p → negative log-prior
-    npr_p = -((alpha - 1) * np.log(p + eps) + (beta - 1) * np.log(1 - p + eps))
-
-    if prior_r is None: return nll + npr_p
-        
-    # Prior on r = theta / theta_max (softly avoid boundaries)
-    thcap = theta_max(a, b, k, s)
-    if np.isfinite(thcap) and thcap > 0:
-        r = np.clip(th / thcap, 1e-9, 1 - 1e-9)
-        # Negative log Beta prior:  -[(α-1)log r + (β-1)log(1-r)]  (const dropped)
-        npr_r = -((prior_r[0] -1) * np.log(r) + (prior_r[1]-1)* np.log(1.0 - r))
-    else:
-        npr_r = 0.0
-
-    return nll + npr_p + npr_r
-
-# Initialization (stable, simple)
-def init_phi(X, y):
-    # Gamma(k, theta) MoM for NC group (only need k0 as a safe size proxy)
-    X0 = X[y == 0]
-    m0 = X0.mean() if X0.size else X.mean()
-    v0 = X0.var()  if X0.size else X.var()
-    k0 = 2.0 if v0 <= 0 else max((m0**2)/(v0 + 1e-9), 1.5)
-
-    # AE median to seed s0
-    X1 = X[y == 1]
-    m1 = np.median(X1) if X1.size else np.median(X)
-
-    p0 = np.clip(float(y.mean()), 1e-3, 1 - 1e-3)
-    b0, s0 = 1.5, max(m1, 0.5)
-
-    return np.array([
-        np.log(p0 / (1 - p0)),             # p_raw
-        np.log(np.expm1(b0) + 1e-9),       # b_raw
-        np.log(np.expm1(s0) + 1e-9),       # s_raw
-        np.log(np.expm1(k0) + 1e-9),       # k_raw
-        np.log(np.expm1(1.0) + 1e-9),      # d_raw  (delta)
-        -0.2                               # u_raw  (keeps theta a bit below cap initially)
-    ], float)
-
-#  Fit wrapper (one retry)
-def fit_bayes_mono(X, y, phi_start=None, rng=None):
-    if rng is None:
-        rng = np.random.default_rng(0)
-    if phi_start is None:
-        phi_start = init_phi(X, y)
-
-    obj = lambda phi: neg_post_phi_mono(phi, X, y)
-
-    res = optimize.minimize(
-        obj, phi_start, method="L-BFGS-B",
-        options={"maxiter": 6000, "ftol": 1e-9}
-    )
-    if not (res.success and np.isfinite(res.fun)):
-        phi_try = phi_start + rng.normal(0, 0.2, size=phi_start.shape)
-        res = optimize.minimize(
-            obj, phi_try, method="L-BFGS-B",
-            options={"maxiter": 6000, "ftol": 1e-9}
-        )
-    return unpack_phi_mono(res.x), res
-
-#  prediction 
-def P_with(theta, x):
-    p, a, b, s, k, th = theta
-    L = (np.log(p) - np.log(1 - p)) + dE_full(x, a, b, s, k, th)
-    return logistic(L)
-
-# Run fit + plot
-theta_hat, res = fit_bayes_mono(X, y)
-print("Optimization success:", res.success, " fval:", float(res.fun))
-
-(p,a,b,s,k,th) = theta_hat
-thcap = theta_max(a, b, k, s)
-print("theta (p,a,b,s,k,theta):", tuple(float(t) for t in theta_hat), "ratio(th):", th/thcap)
-
-# x-range (cap right end at 10 for readability)
-x_lo = max(1e-6, float(X.min()) * 0.8)
-x_hi = min(10.0, float(X.max()) * 1.2)
-xg   = np.linspace(x_lo, x_hi, 600)
-p_curve = P_with(theta_hat, xg)
-
-fig, ax = plt.subplots(figsize=(7.0, 4.6), dpi=140)
-ax.plot(xg, p_curve, color="#000000", lw=2.2, label="P(AE|x) (MAP)")
-
-# overlay data with tiny vertical jitter so points don't overlap
-rng_plot = np.random.default_rng(999)
-jit = (rng_plot.random(len(y)) - 0.5) * 0.06
-ax.scatter(X[y==0], (y + jit)[y==0], s=22, alpha=0.55, color="#2ca02c", edgecolors='none', label='NC')
-ax.scatter(X[y==1], (y + jit)[y==1], s=26, alpha=0.75, color="#ff7f0e", edgecolors='none', label='AE')
-
-ax.set_ylim(-0.05, 1.05)
-ax.set_xlabel('x')
-ax.set_ylabel('P(AE | x)')
-
-if prior_r is None:
-    ax.set_title('Constrained Bayesian fit (no regularization, prior on p)')
-else:
-    ax.set_title(f'Constrained Bayesian fit (no regularization, prior on p and prior r{prior_r})')
-
-ax.grid(alpha=0.3)
-ax.legend(loc='lower right', frameon=False)
-plt.tight_layout()
-plt.show()

Разница между файлами не показана из-за своего большого размера
+ 0 - 153
python/bayesian/bayesian.ipynb


+ 0 - 473
python/bayesian/bayesian.py

@@ -1,473 +0,0 @@
-import numpy as np
-import scipy
-
-"""
-    Setting up scipy distribution to be used in Bayesian model
-
-    Input:
-        distr_str: string of scipy distribution
-        n_pars: int, number of parameters
-        parse_pars: function(pars) -> dict
-    
-    Return: 
-        (log_pdf, distr_sample)
-"""
-def setup_scipy_distr(distr_str, n_pars, parse_pars):
-    
-
-    # log of pdf for all choice
-    def log_pdfs(x, pars, choice = 2):
-        logpdf = eval(distr_str).logpdf
-        if choice in [0,1]: return logpdf(x, **parse_pars(pars))
-        return (logpdf(x, **parse_pars(pars)), logpdf(x, **parse_pars(pars[n_pars:])))
-
-    # sample w.r.t. distribution
-    def distr_sample(rng, pars, n, choice = 2):    
-        rvs = eval(distr_str).rvs
-        if choice in [0,1]: return rvs( **parse_pars(pars), size = n, random_state = rng)
-        return np.concatenate((rvs(**parse_pars(pars), size = n[0], random_state = rng), 
-                            rvs(**parse_pars(pars[n_pars:]), size = n[1], random_state = rng)))
-    
-    return log_pdfs, distr_sample
-
-"""
-    Bayesian model describing conditional probability 
-
-        Prob(X|Y = 1) 
-            = Prob(Y=1)p(X|Y=1)/(Prob(Y=0) p(X|Y=0) + Prob(Y=1) p(X|Y=1))
-            = 1 /(1 + O p(X|Y=0)/p(X|Y=1)) 
-            = 1/(1 + exp(-F))
-
-    where F is the decision function
-
-        F =  log(p(X|Y=1)) - log(p(X|Y=0)) + log(O)
-    
-    and O are the odds
-
-        O = Prob(Y=1)/Prob(Y=0)
-"""
-class BayesianModelRegression:
-    
-    """
-        Constructor
-
-        Input:
-            odds: float, ratio Prob(Y=0)/Prob(Y=1)
-            log_pdfs: function (x, pars, choice = 2) 
-                        match choice:
-                            case 0: return log_pdf0
-                            case 1: return log_pdf1
-                            case _: return (log_pdf0, log_pdf1)
-            bounds: tuple of bounds, (bounds0, bound1)
-
-            distr_sample: function (rng, x, pars, n, choice):
-                          generate n sampled os points using pdfs(choice, pars) 
-    """   
-    def __init__(self, odds, log_pdfs, bounds, distr_sample = None):
-        
-        self.odds = odds
-        self.log_odds = np.log(odds)
-        self.log_pdfs = log_pdfs
-        self.bounds = bounds
-        self.distr_sample = distr_sample
-
-    """
-        Calculate decision function:
-
-             decision = log(p(X|Y=1)) - log(p(X|Y=0)) + log(odds)
-
-        Input:
-            x: float or array of floats
-            pars: parameters for log_pdfs
-
-        Return:
-            float or array of float
-    """
-    def decision(self, x, pars):
-
-        # log of pdf for each group
-        lf0, lf1 = self.log_pdfs(x, pars)
-        
-        return lf1 - lf0 + self.log_odds
-    
-    """
-        Calculate model of the conditional probability Prob(X|Y = 1)
-        
-        Input:
-            x: float or array of floats
-            pars: parameters for log_pdfs
-    """    
-    def model(self, x, pars):
-    
-        # decision function
-        F = self.decision(x, pars)
-
-        # calculating model
-        return 1/(1 + np.exp(-F))
-    
-    """
-        Negative Log Likelihood function:
-
-            neg. log likelihood = -sum_i log(Prob(X = x_i, Y = y_i))
-        
-        where
-
-            Prob(X, Y = 1) = 1/(1 + exp(-F))
-            Prob(X, Y = 0) = 1 -  Prob(X, Y = 1) = 1/(1 + exp(+F))
-        
-        with
-
-            log Prob(X, Y = y) = -log(1 + exp(-S(y) F))
-            S(y) =  [ +1 : y = 1
-                    [ -1 : y = 0
-
-        Input:
-            x: array of floats
-            y: array of ints in {0,1}
-            pars: array of floats, model parameters
-        
-        Return:
-            float: negative log likelihood
-
-    """
-    def nllf(self, x, y, pars):
-        
-        # signs for the groups:
-        # group 1 has + sign and group 0 has - sign
-        S = 2.0*y - 1
-
-        # decision function
-        F = self.decision(x, pars)
-        
-        return np.sum(np.log(1 + np.exp(-S*F)))
-    
-
-    """
-        MLE fitting of a distribution,  given by log_pdf, to data x associated 
-        to the group 0 or 1 by maximizing 
-
-            loglikehood_{single group} = sum_i log_pdf(x | pars)
-
-        Input:
-            x: array of floats
-            choice: int in {0,1}, selecting the group
-            method: string in ["local", "diff_evol", "anneal"]
-            seed: int, seed of the random generator
-        
-        Return:
-            {"pars": pars_MLE, "cost": NLLF at pars_MLE}
-    """
-    
-    def fit_distr(self, x, choice, method = "local", seed = 1977):
-        fname = "fit_distr"
-
-        cost = lambda pars: -np.sum(self.log_pdfs(x, pars, choice))
-        bnds = self.bounds[choice]
-
-        match method:
-            case "local":
-                # random parameters from boundaries
-                pars0 = np.random.default_rng(seed).uniform(*zip(*bnds))
-                # use local optimizer
-                res = scipy.optimize.minimize(cost, pars0, bounds = bnds, method = "L-BFGS-B")
-            case "diff_evol":
-                res = scipy.optimize.differential_evolution(cost, bounds = bnds)
-            case "annel":
-                res = scipy.optimize.dual_annealing(cost, bounds = bnds)
-            case _:
-                assert False, f"{fname}::this method does not exist"
-    
-        return {"pars": res.x, "success": res.success, "cost": res.fun} 
-
-
-    """
-        MLE fitting of the Bayesian model:
-
-            pars_MLE = argmin_pars NLLF(pars| x, y)
-
-        Input:
-            x: array of floats
-            y: array of ints in {0,1}
-            method: string in ["local", "diff_evol", "anneal"], optimizer
-        
-        Return:
-            {"pars": pars_MLE, "cost": NLLF at pars_MLE}
-    """
-    def fit(self, x, y, pars0 = None, method = "local"):
-        fname = "fit"
-
-        # defined nllf as function of parameters, data is already included
-        cost = lambda pars: self.nllf(x, y, pars)
-
-        # joint bounds of two groups
-        bnds = np.concatenate(self.bounds)
-        
-        match method:
-            case "local":
-                # estimate initial guess of parameters (for local method)
-                if pars0 is None:
-                    get_pars = lambda choice: self.fit_distr(x[y == choice], choice)["pars"]
-                    pars0 = np.r_[get_pars(0), get_pars(1)]
-          
-                # optimize using local optimizer
-                res = scipy.optimize.minimize(cost, pars0, bounds = bnds, method = "L-BFGS-B")
-            case "diff_evol":
-                res = scipy.optimize.differential_evolution(cost, bounds = bnds)
-            case "anneal":
-                res = scipy.optimize.dual_annealing(cost, bounds = bnds)
-            case _:
-                assert False, f"{fname}::this method does not exist"
-
-        return {"pars": res.x, "success": res.success, "cost": res.fun} 
-
-    """
-        Producing goodness of fit measures:
-    
-            LLF = log_likelihood function
-            AIC = Akaike information criterion
-            BIC = Bayesian information criterion
-            
-        Input:
-            x: array of floats
-            y: array of ints in {0,1}
-            pars: array of floats,  model parameters
-            thresh: float, default 0.5, threshold value for classification
-
-        Return:
-            {"n": n, "k":k, "dof":n-k, 
-            "LLF": log_likelihood, 
-            "AIC": AIC, 
-            "BIC": BIC, 
-            "A": classification accuracy (threshold values = 0.5 prob)}    
-    """
-    def goodness_of_fit(self, x, y, pars, thresh = 0.5):
-
-        # model probabilities
-        p = self.model(x, pars)
-
-        # log likelihood
-        llf = -self.nllf(x, y, pars)
-        
-        # information criteria
-        k, n = len(pars), len(x)
-        AIC = 2*k - 2*llf
-        BIC = k*np.log(n) - 2*llf
-
-        # chi2
-        dof = n - k
-        r = (y - p)/np.sqrt(p*(1-p))
-        chi2 = np.sum(r**2)
-        p_val = scipy.stats.chi2.sf(chi2, dof)
-
-        # using model as classifier
-        matches = y == np.heaviside(p - thresh, 1)
-
-        return {"LLF": llf, "AIC": AIC, "BIC": BIC, 
-                "A" : np.count_nonzero (matches)/n,
-                "chi2": chi2, "p-value(chi2)": p_val,  # not very useful
-                "n": n, "k": k, "dof": dof}
-
-    """
-        Generate m parameters via non-parametric bootstrapping with minimal constraint
-
-            bootstrapped sampled = (xb, yb) sampled with replacement from (x,y)
-
-        Input:
-            x : array of n floats
-            y : array of n int in {0,1}
-            m: integer, number of samples
-            seed : int, seed for the random generator
-            method: string in ["local", "diff_evol", "anneal"], optimizer
-        
-        Return:
-            array of m x len(pars) floats
-    """
-    def get_nonparam_boots_pars(self, x, y, m, seed = 1, method = "local"):
-        fname = "get_nonparam_boots_pars"
-
-        rng = np.random.default_rng(seed)
-
-        # discussing original data 
-        res = self.fit(x, y, method = method)
-        assert res["success"], f"{fname}::fitting original data failed."
-
-        # generate bootstrapped parameters
-        pars = res["pars"] 
-        lst = [pars]
-        n = len(x)
-        
-        while True:
-            
-            # sampling with replacement with restrictions
-            idx = rng.choice(n, n)
-            if np.sum(y[idx]) in [0, n]: continue
-            
-            res = self.fit(x[idx], y[idx], pars0 = pars, method = method)
-            if not res["success"]: continue
-
-            lst.append(res["pars"])
-            if len(lst) == m: break
-
-        return np.array(lst)
-
-
-    """
-        Generate m parameters via non-parametric stratified bootstrapping:
-
-            bootstrapped sampled = (xb, yb) sampled with replacement from (x,y) for each groups separately
-
-        meaning         
-          
-            xb = (sampled with replacement from x0, sampled with replacement from x1)
-            yb = (0 ... 0, 1 ... 1)
-                    n0        n1
-        
-        Note samples from each group in yb is constant and same as in y.
-
-        Input:
-            x : array of n floats
-            y : array of n int in {0,1}
-            m: integer, number of samples
-            seed : int, seed for the random generator
-            method: string in ["local", "diff_evol", "anneal"], optimizer
-        
-        Return:
-            array of m x len(pars) floats
-    """
-    def get_nonparam_strat_boots_pars(self, x, y, m, seed = 1, method = "local"):
-        fname = "get_nonparam_strat_boots_pars"
-
-        rng = np.random.default_rng(seed)
-
-        # discussing original data 
-        res = self.fit(x, y, method = method)
-        assert res["success"], f"{fname}::fitting original data failed."
-
-        # separate data of both groups
-        xs = [x[y == i] for i in range(2)]
-        ns = [len(e) for e in xs]
-        
-        # common vector states
-        yb = np.concatenate([np.full(ns[i], i) for i in range(2)])
-        
-        # generate bootstrapped parameters
-        pars = res["pars"]   
-        lst = [pars]
-        while True:
-            # stratified sampling with replacement
-            xb = np.concatenate([rng.choice(xs[i], ns[i]) for i in range(2)])
-        
-            # do fitting
-            res = self.fit(xb, yb, pars0 = pars, method = method)
-            if not res["success"]: continue
-
-            lst.append(res["pars"])
-            if len(lst) == m: break
-
-        return np.array(lst)
-    
-    """
-        Generate m parameters via parametric bootstrapping:
-            
-            bootstrapped sample = (x, yb)  yb ~ B(ymodel)
-        
-        Input:
-            x : array of n floats
-            y : array of n int in {0,1}
-            m: integer, number of samples
-            seed : int, seed for the random generator
-            method: 
-        
-        Return:
-            array of m x len(pars) floats
-    """
-    def get_param_boots_pars(self, x, y, m, seed = 1, method = "local"):
-        fname = "get_param_boots_pars"
-
-        rng = np.random.default_rng(seed)
-        
-        # discussing original data 
-        res = self.fit(x, y, method = method)
-        assert res["success"], f"{fname}::fitting original data failed."
-
-        # calculate predicted conditional probabilities 
-        pars = res["pars"]
-        p = self.model(x, pars)
-
-        # generate bootstrapped parameters
-        lst = [pars]
-        n = len(x)
-
-        while True:
-
-            # Generate new binary outcomes from Bernoulli(p_i)
-            y_sim = rng.binomial(n = 1, p = p)
-
-            if np.sum(y_sim) in [0, n]: continue
-            
-            # fit and get new parameter
-            res = self.fit(x, y_sim, pars0 = pars, method=method)
-            if not res["success"]: continue
-
-            lst.append(res["pars"])
-            if len(lst) == m: break
-
-        return np.array(lst)
-    
-    """
-        Generate m parameters via parametric stratified bootstrapping by 
-        sampling x from parametrized distributions associated to individual groups:
-
-            bootstrapped sample = (xb, yb)
-                xb = (sampled from distr for x0, sampled from distr for x1)
-                yb = (0 ... 0, 1 ... 1)
-                        n0        n1
-
-        Input:
-            x : array of n floats
-            y : array of n int in {0,1}
-            m: integer, number of samples
-            seed : int, seed for the random generator
-            method: 
-        
-        Return:
-            array of m x len(pars) floats
-    """
-    def get_param_strat_boots_pars(self, x, y, m, seed = 1, method = "local"):
-        fname = "get_param_strat_boots_pars"
-
-        assert self.distr_sample is not None, f"{fname}::distr_sample is not defined"
-
-        rng = np.random.default_rng(seed)
-        
-        # separate data of both groups
-        xs = [x[y == i] for i in range(2)]
-        ns = [len(e) for e in xs]
-        
-        # separate data of both groups
-        pars_g = np.concatenate([self.fit_distr(e, i)["pars"] for i, e in enumerate(xs)])
-        
-        # discussing original data 
-        res = self.fit(x, y, method = method)
-        assert res["success"], f"{fname}::fitting original data failed."
-
-        # common vector states
-        yb = np.concatenate([np.full(ns[i], i) for i in range(2)])
-
-        # generate bootstrapped parameters
-        pars = res["pars"]
-        lst = [pars]
-        
-        while True:
-
-            # Generate new sample of points for each group
-            xb = self.distr_sample(rng, pars_g, ns)
-            
-            # fit and get new parameter
-            res = self.fit(xb, yb, pars0 = pars, method = method)
-            if not res["success"]: continue
-
-            lst.append(res["pars"])
-            if len(lst) == m: break
-
-        return np.array(lst)

+ 0 - 59
python/bayesian/data_utils.py

@@ -1,59 +0,0 @@
-import numpy as np
-
-
-"""
-  Extract data fom dictionaries for specific organ
-
-  Input: 
-    organ: string in ["lung", "bowel", "thyroid"]
-    perc: int, percentiles [1, ... , 100]
-    suv_dict: dict containing percentiles of suv
-    flags_dict: dict containing states
-"""
-
-def get_data(organ, perc, suv_dict, flags_dict, nr_patient = 58):
-    fname = "get_data"
-
-    # get concrete data set
-    suv = suv_dict[organ + '_SUVperc_COMBINED'][:nr_patient,:,:]  # suv percentiles
-    
-    # index of percentile
-    perc_idx = perc -1
-
-    # computing max SUV percentile per patient, ignoring nans
-    x = np.nanmax(suv[:,:,perc_idx], axis = 1)
-
-    # determining index in the flags based on organ
-    match organ:
-        case "lung":
-            flags_idx = 3
-        case "bowel":
-            flags_idx = 1
-        case "thyroid":
-            flags_idx = 5
-        case _:
-            assert False, f"{fname}::this organ {organ = } is not supported"
-
-    # getting state of patients: 0 == NC, 1  == AE
-    y = flags_dict['flags'][:nr_patient, flags_idx]  
-
-    return x, y
-
-
-"""
-    Check if a vector lies within the specified bounds for each dimension.
-
-    Parameters:
-    - vector (np.ndarray): 1D array representing the point to check. Shape: (n,)
-    - bounds (np.ndarray): 2D array of shape (n, 2), where each row is (min, max) for a dimension.
-
-    Returns:
-    - bool: True if the vector is within bounds in all dimensions, False otherwise.
-"""
-def within_bounds(vector: np.ndarray, bounds: np.ndarray) -> bool:
-
-    if vector.shape[-1] != bounds.shape[0]:
-        raise ValueError("Dimension mismatch: vector length and bounds rows must be equal.")
-    
-    return np.apply_along_axis(lambda x: np.all((x >= bounds[:, 0]) & (x <= bounds[:, 1])), -1, vector)
-

BIN
python/bayesian/results/bayesian_CI_cmp.pdf


BIN
python/bayesian/results/bayesian_fit.pdf


+ 0 - 141
python/bayesian/zahra_plus_comments.py

@@ -1,141 +0,0 @@
-"""
-    Working on Bayesian formula model + penalty  == MAP approach with prior = penalty
-"""
-
-import numpy as np
-import matplotlib.pyplot as plt
-from scipy import optimize, stats
-
-#here is data
-assert np.all(X > 0), "All X must be > 0"
-n1, n0 = int(y.sum()), int((1-y).sum())
-
-m_emp = n1 / (n1 + n0)  # approx Prob(AE)
-
-print(f"AE={n1}, NC={n0}, empirical p_AE={m_emp:.6f}")
-
-# Model: AE ~ BetaPrime(a,b,scale), NC ~ LogNormal(mu, sigma)
-# p_ae = Prob(AE)
-# θ = [p_ae, a, b, sc, mu_nc, sig_nc]
-def logpdf_betaprime(x, a, b, scale):
-    return stats.betaprime.logpdf(x, a=a, b=b, scale=scale)
-
-def logpdf_lognorm(x, mu, sigma):
-    return stats.lognorm.logpdf(x, s=sigma, scale=np.exp(mu))
-
-def neg_conditional_ll(theta, X, y, eps=1e-12):
-    
-    p_ae, a, b, sc, mu_nc, sig_nc = theta
-
-    logf1 = logpdf_betaprime(X, a, b, sc)     # AE
-    logf0 = logpdf_lognorm(X, mu_nc, sig_nc)  # NC
-
-    # computing p(AE|x) = 1/(1 + exp(-logit))
-    logit = np.log(p_ae) - np.log(1.0 - p_ae) + (logf1 - logf0)
-    p = 1.0 / (1.0 + np.exp(-np.clip(logit, -50, 50)))
-
-    # computing general nllf = -llf
-    #  llf = sum_i log(p(y_i|x_i)) 
-    #      = sum_i y_i log( p(AE|x) + (1- y_i) log(1 - p(AE|x));  p(NC|x) = 1 -p(AE|x)
-
-    nllf = -np.sum(y*np.log(p+eps) + (1-y)*np.log(1-p+eps))
-    return nllf
-
-"""
-    MAP regularization
-        mean = m_emp, concentration = TAU
-    using beta distribution B(alpha, beta). The parameters are set as
-        alpha = m_emp * TAU, beta = (1-m_emp) * TAU  
-    this yields E[X] = alpha/(alpha+beta) = m_emp
-        Var[X] = m_emp(1- m_emp)/(tau +1)  
-    this could be variance between institutions collected by Katja, 
-    my estimate is 
-        var = 5%^2 
-    This yields tau about 30. 
-"""
-TAU = 100.0            # ↑ increase to pull p_AE closer to empirical prior
-alpha = max(m_emp * TAU, 1e-6)
-beta  = max((1 - m_emp) * TAU, 1e-6)
-
-
-def neg_log_prior_p(p, eps=1e-12):
-    # -log Beta(p | alpha, beta) up to a constant
-    return -( (alpha - 1)*np.log(p + eps) + (beta - 1)*np.log(1 - p + eps) )
-
-
-def neg_posterior(theta, X, y):
-    nll = neg_conditional_ll(theta, X, y)
-    return nll + neg_log_prior_p(theta[0])   # add prior penalty on p_AE only
-
-
-# Bounds (optionally enforce heavy AE tail with b ≤ 1)
-# =========================
-HEAVY_TAIL = True     # set False if you don't want to force the right asymptote
-b_upper = 1.0 if HEAVY_TAIL else 50.0
-bounds = [
-    (1e-3, 1-1e-3),                           # p_ae (free, but regularized by Beta prior)
-    (0.20, 50.0),                             # a (AE BetaPrime)
-    (0.20, b_upper),                          # b (AE BetaPrime)  <-- heavy tail if ≤ 1
-    (0.01, 10.0),                             # scale (AE BetaPrime)
-    (np.log(X).min()-2.0, np.log(X).max()+2.0),  # mu_nc (LogNormal)
-    (0.05, 2.0),                              # sigma_nc (LogNormal)
-]
-# Initialization
-p0 = np.clip(m_emp, bounds[0][0], bounds[0][1])
-X0 = X[y==0]
-mu0 = float(np.mean(np.log(X0)))
-sig0 = float(np.std(np.log(X0), ddof=0))
-mu0 = np.clip(mu0, bounds[4][0], bounds[4][1])
-sig0 = np.clip(sig0, bounds[5][0], bounds[5][1])
-X1 = X[y==1]
-m1 = float(np.mean(X1))
-a0, b0 = 2.5, min(0.8, b_upper)  # start with heavy-tail-ish b if allowed
-sc0 = np.clip(m1 * (b0 - 1 + 1e-6) / max(a0, 1e-6), bounds[3][0], bounds[3][1])
-theta0 = np.array([p0, a0, b0, sc0, mu0, sig0], dtype=float)
-# FREE prior (for comparison)
-# =========================
-res_free = optimize.minimize(
-    fun=neg_conditional_ll,
-    x0=theta0,
-    args=(X, y),
-    method="L-BFGS-B",
-    bounds=bounds,
-    options=dict(maxiter=4000, ftol=1e-12)
-)
-theta_free = res_free.x
-print("\n[FREE prior] p_AE =", float(theta_free[0]), "   CLL =", -res_free.fun)
-# MAP prior (regularized toward empirical)
-# =========================
-res_map = optimize.minimize(
-    fun=neg_posterior,
-    x0=theta0,
-    args=(X, y),
-    method="L-BFGS-B",
-    bounds=bounds,
-    options=dict(maxiter=4000, ftol=1e-12)
-)
-theta_map = res_map.x
-print("[MAP prior]  p_AE =", float(theta_map[0]), "   CLL(post) =", -res_map.fun)
-# MAP parameters
-p_hat, a_hat, b_hat, sc_hat, mu_hat, sig_hat = theta_map
-print("\nFitted (MAP) parameters:")
-print(f"  p_AE = {p_hat:.6f}  (empirical {m_emp:.6f}, TAU={TAU})")
-print(f"  AE BetaPrime: a={a_hat:.4f}, b={b_hat:.4f}, scale={sc_hat:.4f}")
-print(f"  NC LogNormal: mu={mu_hat:.4f}, sigma={sig_hat:.4f}")
-# Posterior & plot
-def predict_proba(x):
-    x = np.asarray(x, dtype=float)
-    logf1 = logpdf_betaprime(x, a_hat, b_hat, sc_hat)
-    logf0 = logpdf_lognorm(x, mu_hat, sig_hat)
-    logit = np.log(p_hat) - np.log(1.0 - p_hat) + (logf1 - logf0)
-    return 1.0 / (1.0 + np.exp(-np.clip(logit, -50, 50)))
-x_grid = np.linspace(max(1e-6, X.min()*0.6), max(X.max()*2.0, 8.0), 600)
-p_grid = predict_proba(x_grid)
-plt.figure(figsize=(8,5))
-plt.plot(x_grid, p_grid, 'k-', linewidth=2, label="P(AE | X) [MAP]")
-plt.scatter(X[y==1], np.ones(n1), marker='x', label="AE samples")
-plt.scatter(X[y==0], np.zeros(n0), marker='o', label="NC samples")
-plt.xlabel("SUV feature X"); plt.ylabel("Predicted P(AE | X)")
-plt.title("BetaPrime–LogNormal with MAP prior on p_AE")
-plt.ylim(-0.05, 1.05); plt.legend(); plt.grid(True)
-plt.show() (edited) 

Разница между файлами не показана из-за своего большого размера
+ 0 - 170
python/fitting_distribution_to_data.ipynb


Разница между файлами не показана из-за своего большого размера
+ 0 - 499
python/logistic/logit_boots.ipynb


Разница между файлами не показана из-за своего большого размера
+ 0 - 584
python/logistic/logit_fit.ipynb


Разница между файлами не показана из-за своего большого размера
+ 0 - 941
python/logistic/logit_gen.ipynb


Некоторые файлы не были показаны из-за большого количества измененных файлов