From 253364acae806befa53734ae92552adffa97939a Mon Sep 17 00:00:00 2001 From: Daniel Rosel Date: Mon, 16 Mar 2026 15:18:07 +0100 Subject: [PATCH] chore: plotting things and setting up her o better --- paper/src/chapters/03-methodology.tex | 41 ++- .../results/first_sweep_tier_revenue.tex | 1 + .../first_sweep_headline_summary.json | 10 + .../first_sweep_tier_alpha_deltas.csv | 31 ++ .../first_sweep_tier_alpha_mode_summary.csv | 61 ++++ .../first_sweep_tier_mode_summary.csv | 11 + .../generated/first_sweep_top_configs.csv | 26 ++ .../plots/first_sweep_tier_revenue.pdf | Bin 0 -> 17510 bytes .../generated/plots/ppo_alpha_curves.pdf | Bin 0 -> 25398 bytes .../generated/plots/ppo_delta_curves.pdf | Bin 0 -> 21999 bytes .../generated/plots/ppo_tradeoff_scatter.pdf | Bin 0 -> 26824 bytes .../results/generated/ppo_alpha_deltas.csv | 7 + .../generated/ppo_alpha_mode_summary.csv | 13 + .../generated/ppo_headline_summary.json | 7 + .../generated/ppo_overall_mode_summary.csv | 3 + .../generated/ppo_pairwise_win_rates.csv | 25 ++ .../chapters/figures/results/plot_results.py | 313 ++++++++++++++++++ .../figures/results/ppo_alpha_curves.tex | 1 + .../figures/results/ppo_delta_curves.tex | 1 + .../figures/results/ppo_tradeoff_scatter.tex | 1 + .../figures/results/process_all_results.py | 51 +++ .../figures/results/process_first_sweep.py | 272 +++++++++++++++ .../figures/results/process_ppo_benchmark.py | 277 ++++++++++++++++ .../src/chapters/hero_architecture_figure.tex | 166 ++++++++++ paper/src/preamble.tex | 2 +- 25 files changed, 1306 insertions(+), 14 deletions(-) create mode 100644 paper/src/chapters/figures/results/first_sweep_tier_revenue.tex create mode 100644 paper/src/chapters/figures/results/generated/first_sweep_headline_summary.json create mode 100644 paper/src/chapters/figures/results/generated/first_sweep_tier_alpha_deltas.csv create mode 100644 paper/src/chapters/figures/results/generated/first_sweep_tier_alpha_mode_summary.csv create mode 100644 paper/src/chapters/figures/results/generated/first_sweep_tier_mode_summary.csv create mode 100644 paper/src/chapters/figures/results/generated/first_sweep_top_configs.csv create mode 100644 paper/src/chapters/figures/results/generated/plots/first_sweep_tier_revenue.pdf create mode 100644 paper/src/chapters/figures/results/generated/plots/ppo_alpha_curves.pdf create mode 100644 paper/src/chapters/figures/results/generated/plots/ppo_delta_curves.pdf create mode 100644 paper/src/chapters/figures/results/generated/plots/ppo_tradeoff_scatter.pdf create mode 100644 paper/src/chapters/figures/results/generated/ppo_alpha_deltas.csv create mode 100644 paper/src/chapters/figures/results/generated/ppo_alpha_mode_summary.csv create mode 100644 paper/src/chapters/figures/results/generated/ppo_headline_summary.json create mode 100644 paper/src/chapters/figures/results/generated/ppo_overall_mode_summary.csv create mode 100644 paper/src/chapters/figures/results/generated/ppo_pairwise_win_rates.csv create mode 100644 paper/src/chapters/figures/results/plot_results.py create mode 100644 paper/src/chapters/figures/results/ppo_alpha_curves.tex create mode 100644 paper/src/chapters/figures/results/ppo_delta_curves.tex create mode 100644 paper/src/chapters/figures/results/ppo_tradeoff_scatter.tex create mode 100644 paper/src/chapters/figures/results/process_all_results.py create mode 100644 paper/src/chapters/figures/results/process_first_sweep.py create mode 100644 paper/src/chapters/figures/results/process_ppo_benchmark.py create mode 100644 paper/src/chapters/hero_architecture_figure.tex diff --git a/paper/src/chapters/03-methodology.tex b/paper/src/chapters/03-methodology.tex index 1653757..e07dcac 100644 --- a/paper/src/chapters/03-methodology.tex +++ b/paper/src/chapters/03-methodology.tex @@ -193,6 +193,17 @@ Operationally, goals and experiment runs are tracked in PostgreSQL (goal table, Our process follows three stages: (1) observe and \textit{vectorize} behavioral interactions, (2) learn distinguishability to characterize human versus agent patterns, and (3) use the learned signal to train a defensive policy in a controlled dynamic-pricing simulator. +Figure~\ref{fig:phantom_unified_architecture} summarizes the full mechanism from online interaction capture to divergence-based contamination scoring and robust control of pricing decisions. + +\begin{figure}[ht] + \centering + \resizebox{\textwidth}{!}{% + \input{chapters/hero_architecture_figure.tex} + } + \caption{Unified PHANTOM defense architecture. (a) Online serving and logging with behavioral and price-query streams. (b) Distinguishability layer that estimates KL divergence to human/agent prototypes and derives session-level contamination scores. (c) Distributionally robust pricing control that optimizes under an ambiguity set while penalizing COI leakage and tracking UX cost.} + \label{fig:phantom_unified_architecture} +\end{figure} + \begin{figure}[ht] \resizebox{\columnwidth}{!}{% \input{chapters/loop_figure.tex} @@ -392,7 +403,7 @@ The complete pricing-demand-trajectory loop is illustrated in Figure~\ref{fig:or \begin{figure}[ht] \centering {\setlength{\arraycolsep}{4pt}% -\resizebox{0.98\linewidth}{!}{$ +\resizebox{0.85\linewidth}{!}{$ \begin{aligned} &\text{Oracle}(\vec{p}_{t-1},\vec{\hat{q}})\to \begin{pmatrix} @@ -517,23 +528,27 @@ The baseline achieves approximately 26 steps per second. Enabling the robustness \centering \caption{Per-step profiling results (20 steps, $M=10$ sessions, $N=3$ products). Self-time measures time spent inside the function excluding callees; cumulative time includes the full call subtree.} \label{tab:profile_results} -\begin{tabular}{@{}lrrrrl@{}} +\begingroup +\small +\setlength{\tabcolsep}{4pt} +\begin{tabular}{@{}lrrrr@{}} \toprule -\textbf{Function} & \textbf{Calls} & \textbf{Self (ms)} & \textbf{Cum. (ms)} & \textbf{Cum. \%} & \textbf{Module} \\ +\textbf{Function} & \textbf{Calls} & \textbf{Self (ms)} & \textbf{Cum. (ms)} & \textbf{Cum. \%} \\ \midrule -\multicolumn{6}{l}{\textit{Baseline ($K=1$, 0.77\,s total, 26 steps/s)}} \\ -\texttt{sample\_behavior\_from\_transitions} & 420 & 131 & 658 & 86\% & \texttt{lib/behavior} \\ -\texttt{DataFrame.xs} & 4,820 & 30 & 201 & 26\% & pandas \\ -\texttt{numpy.nan\_to\_num} & 4,904 & 43 & 97 & 13\% & numpy \\ -\texttt{adjust\_behavior\_to\_condition} & 84 & 3 & 54 & 7\% & \texttt{lib/behavior} \\ +\multicolumn{5}{l}{\textit{Baseline ($K=1$, 0.77\,s total, 26 steps/s)}} \\ +\texttt{sample\_behavior\_from\_transitions} & 420 & 131 & 658 & 86\% \\ +\texttt{DataFrame.xs} & 4,820 & 30 & 201 & 26\% \\ +\texttt{numpy.nan\_to\_num} & 4,904 & 43 & 97 & 13\% \\ +\texttt{adjust\_behavior\_to\_condition} & 84 & 3 & 54 & 7\% \\ \midrule -\multicolumn{6}{l}{\textit{Robust ($K=5$, 2.79\,s total, 7.2 steps/s)}} \\ -\texttt{sample\_behavior\_from\_transitions} & 1,220 & 519 & 2,447 & 88\% & \texttt{lib/behavior} \\ -\texttt{DataFrame.xs} & 16,668 & 108 & 729 & 26\% & pandas \\ -\texttt{numpy.nan\_to\_num} & 16,912 & 164 & 363 & 13\% & numpy \\ -\texttt{adjust\_behavior\_to\_condition} & 244 & 11 & 108 & 4\% & \texttt{lib/behavior} \\ +\multicolumn{5}{l}{\textit{Robust ($K=5$, 2.79\,s total, 7.2 steps/s)}} \\ +\texttt{sample\_behavior\_from\_transitions} & 1,220 & 519 & 2,447 & 88\% \\ +\texttt{DataFrame.xs} & 16,668 & 108 & 729 & 26\% \\ +\texttt{numpy.nan\_to\_num} & 16,912 & 164 & 363 & 13\% \\ +\texttt{adjust\_behavior\_to\_condition} & 244 & 11 & 108 & 4\% \\ \bottomrule \end{tabular} +\endgroup \end{table} Across both configurations, \texttt{sample\_behavior\_from\_transitions} accounts for 86--88\% of total wall time. The function implements the Markov chain sampler described in Section~\ref{sec:tpe}: at each transition it retrieves the current-state row from the expanded transition \texttt{DataFrame} via label-based indexing, which internally dispatches through the pandas \texttt{xs} and \texttt{fast\_xs} code paths. For $M$ sessions each running up to $L_{\max}=40$ transitions, a single \texttt{market.act()} call issues up to $M \cdot L_{\max}$ individual row lookups. With $K=5$ robustness candidates per outer step this accumulates to $5 \times 10 \times 40 = 2{,}000$ row accesses per outer step, producing the 16k \texttt{xs} invocations observed in Table~\ref{tab:profile_results}. diff --git a/paper/src/chapters/figures/results/first_sweep_tier_revenue.tex b/paper/src/chapters/figures/results/first_sweep_tier_revenue.tex new file mode 100644 index 0000000..f319a81 --- /dev/null +++ b/paper/src/chapters/figures/results/first_sweep_tier_revenue.tex @@ -0,0 +1 @@ +\includegraphics[width=0.99\linewidth]{chapters/figures/results/generated/plots/first_sweep_tier_revenue.pdf} diff --git a/paper/src/chapters/figures/results/generated/first_sweep_headline_summary.json b/paper/src/chapters/figures/results/generated/first_sweep_headline_summary.json new file mode 100644 index 0000000..caf3d15 --- /dev/null +++ b/paper/src/chapters/figures/results/generated/first_sweep_headline_summary.json @@ -0,0 +1,10 @@ +{ + "runs": 340, + "tiers": 5, + "alphas": 6, + "status": "ok", + "mean_tier_revenue_robust": 190714.62212212436, + "mean_tier_revenue_no_robust": 197371.17216609977, + "mean_tier_revenue_delta": -6656.5500439754105, + "mean_tier_revenue_delta_pct": -3.3726050116242514 +} \ No newline at end of file diff --git a/paper/src/chapters/figures/results/generated/first_sweep_tier_alpha_deltas.csv b/paper/src/chapters/figures/results/generated/first_sweep_tier_alpha_deltas.csv new file mode 100644 index 0000000..fcddcd6 --- /dev/null +++ b/paper/src/chapters/figures/results/generated/first_sweep_tier_alpha_deltas.csv @@ -0,0 +1,31 @@ +tier,alpha,runs_robust,runs_no_robust,eval_revenue_mean_delta,eval_revenue_mean_delta_pct,eval_reward_mean_delta,eval_reward_mean_delta_pct,eval_coi_level_mean_delta,eval_coi_level_mean_delta_pct,eval_margin_mean_delta,eval_margin_mean_delta_pct,objective_score_delta,objective_score_delta_pct,train_alpha_adv_delta,train_alpha_adv_delta_pct +dqn,0.0,5.0,2.0,-31308.987414117495,-8.73651226889534,-1909.7427407095092,-0.5742991901121623,-2.8982436567700063,-2.1108702433020436,-0.001972064237093285,-0.2116777198290971,-1909.7427407095092,-0.5742991901121623,, +dqn,0.1,8.0,4.0,-7723.542755668925,-2.2789188721535494,-74239.37371836061,-21.063854618469847,1.7435833801418141,1.2859365583872486,0.0011891962142838164,0.1278074871971924,-74239.37371836061,-21.063854618469847,0.17619791666666657,176.19791666666694 +dqn,0.25,7.0,3.0,-12344.82818986749,-3.7035466052614323,93154.03627578515,36.06691230407512,0.03214544949867104,0.023426184113378143,1.763733457238459e-05,0.001893256490383175,93154.03627578515,36.06691230407512,0.14530952380952394,58.12380952380958 +dqn,0.4,5.0,10.0,-7816.300706216833,-2.4694340725162824,-42362.74668471434,-13.411888482380219,0.6251272343707797,0.4579446603861758,0.0002750615520492605,0.02953644634355915,-42362.74668471434,-13.411888482380219,0.09856666666666747,24.64166666666691 +dqn,0.6,5.0,4.0,-16150.011887742497,-5.347485987139731,-28508.74710866122,-10.151356300001888,-0.63306323164079,-0.46056970247177387,-0.00034537433455417155,-0.0370668515552649,-28508.74710866122,-10.151356300001888,0.1361999999999981,22.699999999999644 +dqn,0.8,7.0,6.0,-18191.8826663699,-6.440527544692988,-55296.94441124235,-20.19273590083627,-0.796733634735034,-0.579832425016392,-0.0006423984775592029,-0.0689476165584585,-55296.94441124235,-20.19273590083627,0.1532857142857158,19.160714285714512 +linear,0.0,9.0,8.0,-14967.67388588126,-4.273413942959129,-20107.23171681742,-6.60039931288617,-0.06127790826209889,-0.04564810574240612,-7.607744079518586e-05,-0.008177885913528719,-20107.23171681742,-6.60039931288617,, +linear,0.1,3.0,5.0,-24531.399901538738,-7.171831328305365,-96669.7835552101,-26.44920711447249,-0.3680976907859872,-0.2733723058172187,-0.0002515287835096469,-0.02702956778346356,-96669.7835552101,-26.44920711447249,, +linear,0.25,6.0,9.0,-14840.859479571285,-4.520682292638562,-26510.179456423968,-8.033117756667396,-0.13734776448131925,-0.10212641096230607,-9.41162442338328e-05,-0.010115001392981545,-26510.179456423968,-8.033117756667396,, +linear,0.4,4.0,11.0,-17196.7642560167,-5.486915251242723,-74520.10209817477,-25.042311510043184,0.12217076984330788,0.09098828726103136,0.00010713887099822461,0.011516865671259795,-74520.10209817477,-25.042311510043184,, +linear,0.6,5.0,3.0,-14284.06615788641,-4.854766876637072,38417.71856593515,14.088596762512362,0.24251461234271687,0.1806530855220358,0.0002606811969937395,0.028024824619509187,38417.71856593515,14.088596762512362,, +linear,0.8,4.0,11.0,-10840.488575784548,-3.933600919557566,15749.581078662042,6.447651726824251,0.028051260535562506,0.020876236575910773,5.361882659971062e-05,0.005763158099097226,15749.581078662042,6.447651726824251,, +qtable,0.0,9.0,8.0,-18644.457288398524,-8.15323701554329,32993.42568058451,20.675688115613053,10.369779227648095,10.682768960780463,0.018566897519637582,2.0803084179092814,32993.42568058451,20.675688115613053,0.11839814814814797, +qtable,0.1,6.0,5.0,-12549.400855549495,-4.616991193742389,-37207.79701261924,-15.336047254435487,0.0884057957559321,0.07703761042583206,-0.01127789819771663,-1.2272540823820444,-37207.79701261924,-15.336047254435487,0.07577777777777787,75.77777777777803 +qtable,0.25,6.0,5.0,-1534.3527429780224,-0.5456640130847226,18433.43663451099,7.304472653867784,-0.5776125938941306,-0.45734160960552755,-0.003316338490628068,-0.3584028328803385,18433.43663451099,7.304472653867784,0.1181458333333334,47.258333333333354 +qtable,0.4,8.0,6.0,-15146.258176090778,-5.274860187729517,-37364.22587794208,-13.005651205148677,0.4611471727478005,0.3629050099230144,0.0071046453227539,0.7751478467862876,-37364.22587794208,-13.005651205148677,0.11010416666666772,27.52604166666698 +qtable,0.6,6.0,6.0,-9577.578548656049,-3.9322693501816666,-19088.152339068736,-9.571307395166029,0.9081750157567683,0.7495917946306662,0.0015520804425310786,0.16838348372043557,-19088.152339068736,-9.571307395166029,0.16983333333333228,28.305555555555333 +qtable,0.8,5.0,2.0,-52751.680936846446,-19.699089872409548,-16508.209313987172,-7.589601869470744,-15.022454081083623,-11.215398490282094,-0.007791824761087751,-0.8384414846099099,-16508.209313987172,-7.589601869470744,0.11120000000000174,13.900000000000245 +static,0.0,5.0,6.0,-4782.871053113384,-5.233544525848519,14411.4689779756,25.538141347978577,1.307060701942973,1.8731997380823568,0.002537468952847566,0.2911381045328444,14411.4689779756,25.538141347978577,, +static,0.1,8.0,5.0,1629.4524528499896,1.880088900553112,-5347.078589385725,-8.14812684380662,0.3600324838305795,0.5019134064795009,-4.6492644957929485e-05,-0.005316014641356001,-5347.078589385725,-8.14812684380662,, +static,0.25,5.0,6.0,-9938.662276761897,-10.398087633377964,-23616.087243780566,-27.701108621456626,-3.0513860773271233,-4.099238223547561,-0.003519771479853273,-0.40113716461596144,-23616.087243780566,-27.701108621456626,, +static,0.4,3.0,4.0,1850.8400595222774,2.1912497828943436,15058.659457798465,23.67199439061036,3.669612467486587,5.430169778169349,0.006763447803564415,0.7804393835882188,15058.659457798465,23.67199439061036,, +static,0.6,6.0,5.0,1038.893948415236,1.2765037688226162,-6062.864079504681,-9.363144945348399,-1.712609061865976,-2.3996341009364213,-0.0042285583442709385,-0.48362088973179423,-6062.864079504681,-9.363144945348399,, +static,0.8,3.0,7.0,2696.6340631967323,3.6826150812750567,149.22406835677975,0.27280281303997084,0.8491716126507072,1.2427748744725668,0.0032786525965587954,0.3777595573932637,149.22406835677975,0.27280281303997084,, +surge,0.0,6.0,6.0,-606.73760243367,-5.066579306500225,-244.17585425326251,-5.525800641331023,0.014874931199557295,0.09186560988877175,0.0019308940532419272,0.4471794260021321,-244.17585425326251,-5.525800641331023,, +surge,0.1,2.0,5.0,169.78743573408792,1.446343107913299,-1012.7706974660168,-20.02053666691211,-0.14459518037699226,-0.864651254901582,-0.0018650458785858248,-0.4260349899970559,-1012.7706974660168,-20.02053666691211,, +surge,0.25,10.0,7.0,-128.20993816584632,-1.1276930411162496,-81.21373487263281,-1.7081453033360994,0.3008506477195141,1.839047728806548,0.0030750148302954305,0.7102446987902812,-81.21373487263281,-1.7081453033360994,, +surge,0.4,6.0,6.0,-473.03722764431404,-4.297928307550563,28.557452243338048,0.6755106104955642,-0.5027452173053764,-3.072002360121898,-0.005581380442163164,-1.288152985482699,28.557452243338048,0.6755106104955642,, +surge,0.6,2.0,5.0,307.79436325796996,3.0356727142643067,2060.57396030564,63.382050333909866,0.2339650444065704,1.438519400758399,0.001302270025389629,0.30077697380833807,2060.57396030564,63.382050333909866,, +surge,0.8,3.0,3.0,423.15386247993047,4.372210191290083,1117.0942083304312,34.86182570616373,0.8971464536957541,5.327339899805159,0.007068630716831503,1.6094191039618562,1117.0942083304312,34.86182570616373,, diff --git a/paper/src/chapters/figures/results/generated/first_sweep_tier_alpha_mode_summary.csv b/paper/src/chapters/figures/results/generated/first_sweep_tier_alpha_mode_summary.csv new file mode 100644 index 0000000..dba8d81 --- /dev/null +++ b/paper/src/chapters/figures/results/generated/first_sweep_tier_alpha_mode_summary.csv @@ -0,0 +1,61 @@ +tier,alpha,mode,runs,eval_revenue_mean_mean,eval_revenue_mean_std,eval_reward_mean_mean,eval_reward_mean_std,eval_coi_level_mean_mean,eval_coi_level_mean_std,eval_margin_mean_mean,eval_margin_mean_std,objective_score_mean,objective_score_std,train_alpha_adv_mean,train_alpha_adv_std +dqn,0.0,no_robust,2,358369.40933039243,3531.782519351935,332534.46523867303,114183.5587841961,137.30089123035202,0.8184776440325546,0.9316352418598786,0.0006839003676302996,332534.46523867303,114183.5587841961,, +dqn,0.0,robust,5,327060.42191627494,24311.17412598574,330624.7224979635,62834.39223547943,134.40264757358202,6.160000643680792,0.9296631776227853,0.004262039730140749,330624.7224979635,62834.39223547943,0.17835000000000004,0.08829347371125472 +dqn,0.1,no_robust,4,338912.58043645386,19584.736810155388,352449.13650924934,34076.74819101191,135.58860029055563,3.4055508991301524,0.9304589585186211,0.0023438665484978773,352449.13650924934,34076.74819101191,0.0999999999999998,0.0 +dqn,0.1,robust,8,331189.03768078494,8060.912085646968,278209.7627908887,57861.69545853692,137.33218367069745,0.43113256118808096,0.931648154732905,0.000296560958972609,278209.7627908887,57861.69545853692,0.2761979166666664,0.09826648189130198 +dqn,0.25,no_robust,3,333324.4996115304,6101.717861804452,258281.15112936878,46772.05216097596,137.2201692904545,0.9866477887862672,0.9315871706751672,0.0006356053229300815,258281.15112936878,46772.05216097596,0.25,0.0 +dqn,0.25,robust,7,320979.6714216629,7345.8761269427705,351435.18740515393,40320.63699261721,137.25231473995316,0.3527287960309152,0.9316048080097395,0.0002575240668471541,351435.18740515393,40320.63699261721,0.39530952380952394,0.073021206240698 +dqn,0.4,no_robust,10,316521.94295076875,3631.1820920182718,315859.66987697606,59129.03566963754,136.50715652926755,0.5085743959240285,0.931261495881483,0.00031280530251053175,315859.66987697606,59129.03566963754,0.3999999999999993,0.0 +dqn,0.4,robust,5,308705.6422445519,10654.571556448245,273496.9231922617,68868.59270778317,137.13228376363833,0.9543108715306617,0.9315365574335323,0.0006302636717132419,273496.9231922617,68868.59270778317,0.49856666666666677,0.05745573175159429 +dqn,0.6,no_robust,4,302011.2988903938,2354.1141598720183,280836.828756133,58683.00124997926,137.4522093492651,0.4692723362517602,0.9317606434396914,0.0003317518021682495,280836.828756133,58683.00124997926,0.600000000000001,0.0 +dqn,0.6,robust,5,285861.2870026513,10386.571631344234,252328.08164747176,59388.56063758225,136.8191461176243,1.0629203361893034,0.9314152691051373,0.0005692783702932289,252328.08164747176,59388.56063758225,0.7361999999999991,0.07108625433623189 +dqn,0.8,no_robust,6,282459.51189759385,2625.018247527438,273845.72691287595,66378.16690732416,137.4075681801531,0.29728950101826707,0.9317196295169007,0.00022799290978965786,273845.72691287595,66378.16690732416,0.7999999999999985,0.0 +dqn,0.8,robust,7,264267.62923122395,6771.288971321149,218548.7825016336,50043.2009443344,136.61083454541807,1.2319662937254596,0.9310772310393415,0.0010118564779437284,218548.7825016336,50043.2009443344,0.9532857142857143,0.04709817507333055 +linear,0.0,no_robust,8,350250.9723061577,3156.286820918861,304636.59490360576,71682.88027353655,134.2397614654424,0.32611787466946035,0.9302824910938235,0.00024020749661685483,304636.59490360576,71682.88027353655,, +linear,0.0,robust,9,335283.29842027643,7707.594869976611,284529.36318678834,55524.58819004573,134.1784835571803,0.4477314164684001,0.9302064136530284,0.00034781034181738526,284529.36318678834,55524.58819004573,, +linear,0.1,no_robust,5,342052.1032713031,2576.546352056584,365492.17954557994,44890.93522299766,134.65068807375954,0.2181027640393531,0.930569018064469,0.00014058935916940913,365492.17954557994,44890.93522299766,, +linear,0.1,robust,3,317520.7033697644,4796.580459456527,268822.39599036984,39256.421140635124,134.28259038297355,0.24570499109363475,0.9303174892809594,0.00018817899183709092,268822.39599036984,39256.421140635124,, +linear,0.25,no_robust,9,328288.0441241802,2178.525494145428,330011.0898339667,38591.36053388808,134.48799697074742,0.2199303973026469,0.9304619997297959,0.00015341642413402035,330011.0898339667,38591.36053388808,, +linear,0.25,robust,6,313447.18464460893,11811.426711620714,303500.9103775427,63358.917144214036,134.3506492062661,0.2947034403278951,0.9303678834855621,0.00021446628431268986,303500.9103775427,63358.917144214036,, +linear,0.4,no_robust,11,313414.0672597746,1982.9537556159262,297576.7714904776,69396.90446617964,134.2708754290745,0.3062093691351849,0.9302780292522507,0.00023067974755288992,297576.7714904776,69396.90446617964,, +linear,0.4,robust,4,296217.3030037579,5109.898340355844,223056.66939230284,38293.73688466607,134.3930461989178,0.12347753686382154,0.9303851681232489,7.324605809708878e-05,223056.66939230284,38293.73688466607,, +linear,0.6,no_robust,3,294227.64307441004,2081.9176570448135,272686.62176604365,66672.50905805513,134.24327165069943,0.30764332256042104,0.9301795837547151,0.00020453921786790446,272686.62176604365,66672.50905805513,, +linear,0.6,robust,5,279943.5769165236,9866.031719660255,311104.3403319788,28363.930707781863,134.48578626304214,0.21280262186464388,0.9304402649517088,0.00020533894868120649,311104.3403319788,28363.930707781863,, +linear,0.8,no_robust,11,275586.89347174135,1618.038877505867,244268.4832547461,56201.44465269986,134.36933631960773,0.2845660213184439,0.9303723007028001,0.00017640716421186918,244268.4832547461,56201.44465269986,, +linear,0.8,robust,4,264746.4048959568,7976.6279174956235,260018.06433340814,57942.49882730146,134.3973875801433,0.31511916357643405,0.9304259195293998,0.00023606570471334208,260018.06433340814,57942.49882730146,, +qtable,0.0,no_robust,8,228675.52179404112,103199.70453252994,159575.94976328663,95848.81008103945,97.07014413321637,33.0637115678536,0.8925069648229078,0.04890522141482132,159575.94976328663,95848.81008103945,0.0,0.0 +qtable,0.0,robust,9,210031.0645056426,84361.3834579348,192569.37544387113,116824.7880426837,107.43992336086447,21.41128645838254,0.9110738623425454,0.019188350719133364,192569.37544387113,116824.7880426837,0.11839814814814797,0.061909456985161225 +qtable,0.1,no_robust,5,271809.0706466638,14898.209045050968,242616.60384397948,49181.45526408063,114.75666919996793,3.461383158930426,0.9189538140159812,0.002294693249439748,242616.60384397948,49181.45526408063,0.0999999999999998,0.0 +qtable,0.1,robust,6,259259.66979111428,102995.29934229614,205408.80683136024,94155.1845420674,114.84507499572386,36.206421837506966,0.9076759158182646,0.048591979839360346,205408.80683136024,94155.1845420674,0.17577777777777767,0.06720562696899951 +qtable,0.25,no_robust,5,281190.01916657295,70274.10208723843,252358.2126733039,129868.46825082717,126.29784427276161,15.368804047323954,0.9253103453385114,0.009044883517550522,252358.2126733039,129868.46825082717,0.25,0.0 +qtable,0.25,robust,6,279655.6664235949,93056.2549557545,270791.6493078149,116021.46257259768,125.72023167886748,26.760714047253796,0.9219940068478834,0.022785695882060884,270791.6493078149,116021.46257259768,0.3681458333333334,0.08845114686619042 +qtable,0.4,no_robust,6,287140.4669895195,32698.16434426399,287292.23388022534,83855.95000252876,127.07104066863859,9.200301166154173,0.9165535777734913,0.01306001923887748,287292.23388022534,83855.95000252876,0.3999999999999993,0.0 +qtable,0.4,robust,8,271994.2088134287,79259.3185780895,249928.00800228326,88265.30801790548,127.53218784138639,23.406428094683015,0.9236582230962452,0.020073747007871224,249928.00800228326,88265.30801790548,0.510104166666667,0.09294655989347765 +qtable,0.6,no_robust,6,243563.64469828535,67006.60707045678,199430.98211127534,79119.52886604435,121.15594411011905,17.91243944823949,0.9217533740470492,0.011558797825966702,199430.98211127534,79119.52886604435,0.600000000000001,0.0 +qtable,0.6,robust,6,233986.0661496293,43155.478617087436,180342.8297722066,48117.79957836251,122.06411912587582,12.160951090203252,0.9233054544895802,0.006840854872863436,180342.8297722066,48117.79957836251,0.7698333333333333,0.09107066853090896 +qtable,0.8,no_robust,2,267787.4017455507,1552.038101264713,217510.87340156303,45358.788584678456,133.9448981157492,0.47346860040111405,0.9293224278749692,0.0002998116010539045,217510.87340156303,45358.788584678456,0.7999999999999985,0.0 +qtable,0.8,robust,5,215035.72080870424,32869.73253165852,201002.66408757586,63247.67956376057,118.92244403466557,8.586916805142152,0.9215306031138815,0.004644709320891907,201002.66408757586,63247.67956376057,0.9112000000000002,0.07381653307732307 +static,0.0,no_robust,6,91388.75248869567,13415.65534300268,56431.15832748852,8525.098185703384,69.77689967440658,3.670744870085874,0.8715688236409825,0.005831496806767582,56431.15832748852,8525.098185703384,, +static,0.0,robust,5,86605.88143558228,7614.909395960895,70842.62730546412,8033.737230392738,71.08396037634955,3.6802889678420283,0.8741062925938301,0.005083911544334936,70842.62730546412,8033.737230392738,, +static,0.1,no_robust,5,86668.90445290186,8037.955688932984,65623.40881389238,19329.448262530004,71.73199185012882,4.199046495412734,0.874577067494122,0.006610505646022198,65623.40881389238,19329.448262530004,, +static,0.1,robust,8,88298.35690575185,9576.838833058617,60276.33022450666,13359.490452744656,72.0920243339594,6.7706096714767865,0.8745305748491641,0.010083585815241344,60276.33022450666,13359.490452744656,, +static,0.25,no_robust,6,95581.63603909909,8345.698435455577,85253.22060752509,13111.526873622026,74.43788116042678,2.1078820386097368,0.8774483618896327,0.0037254791853004897,85253.22060752509,13111.526873622026,, +static,0.25,robust,5,85642.97376233719,9472.880627242153,61637.13336374452,15937.429780623212,71.38649508309966,4.0264905454627264,0.8739285904097794,0.005323853359397925,61637.13336374452,15937.429780623212,, +static,0.4,no_robust,4,84465.04245981346,12101.831388745604,63613.81812329075,7778.361846092061,67.5782271530322,3.9088888968092,0.8666205147756862,0.007149121199217965,63613.81812329075,7778.361846092061,, +static,0.4,robust,3,86315.88251933573,8642.748496122398,78672.47758108922,17823.74997200773,71.24783962051879,2.790416943786253,0.8733839625792507,0.005990544453538607,78672.47758108922,17823.74997200773,, +static,0.6,no_robust,5,81385.88962988024,12343.523894997037,64752.43216774836,23486.779472906223,71.36959177224794,5.100226704959064,0.874353948320141,0.007787250295491337,64752.43216774836,23486.779472906223,, +static,0.6,robust,6,82424.78357829548,9831.886701625144,58689.56808824368,12672.506035553573,69.65698271038197,3.484982360048201,0.8701253899758701,0.005917711231889304,58689.56808824368,12672.506035553573,, +static,0.8,no_robust,7,73226.06364450825,4447.877985963851,54700.340767716196,14406.881298569717,68.32867561883204,3.68262917356943,0.8679204886788817,0.007467501164611224,54700.340767716196,14406.881298569717,, +static,0.8,robust,3,75922.69770770498,5046.089536162847,54849.564836072976,22780.98012221352,69.17784723148274,1.5268167784698885,0.8711991412754405,0.0033278715575433297,54849.564836072976,22780.98012221352,, +surge,0.0,no_robust,6,11975.290738176132,411.4052900076416,4418.832131346071,896.5828048394391,16.192056219479124,0.8040364003224534,0.4317940274006973,0.008271862690929055,4418.832131346071,896.5828048394391,, +surge,0.0,robust,6,11368.553135742462,623.8217438159004,4174.6562770928085,639.9963040241264,16.20693115067868,0.9853827520149101,0.4337249214539392,0.010371668289035135,4174.6562770928085,639.9963040241264,, +surge,0.1,no_robust,5,11739.084232858655,332.778792718381,5058.659087494994,1110.8409258976824,16.722948073839394,0.6578121995950104,0.4377682402562083,0.005683401047550787,5058.659087494994,1110.8409258976824,, +surge,0.1,robust,2,11908.871668592743,81.41250285550258,4045.8883900289775,784.7169500268457,16.5783528934624,0.4088194924856508,0.4359031943776225,0.004531137621699143,4045.8883900289775,784.7169500268457,, +surge,0.25,no_robust,7,11369.223138855004,236.1121240061105,4754.4980344481255,1038.0550037539617,16.359045119223275,0.3945156775653057,0.4329514652531622,0.0038762110261952457,4754.4980344481255,1038.0550037539617,, +surge,0.25,robust,10,11241.013200689158,684.503587066406,4673.284299575493,1187.78635131025,16.65989576694279,1.0515950311117155,0.4360264800834576,0.009701952962125513,4673.284299575493,1187.78635131025,, +surge,0.4,no_robust,6,11006.168409400554,364.6584583108646,4227.535704048808,1414.7964077877168,16.365391636138824,0.9138430058543858,0.4332855262584901,0.008024003783434592,4227.535704048808,1414.7964077877168,, +surge,0.4,robust,6,10533.13118175624,526.0758051960169,4256.093156292146,783.7965507386594,15.862646418833448,0.7732699435426456,0.42770414581632693,0.008967505611725135,4256.093156292146,783.7965507386594,, +surge,0.6,no_robust,5,10139.2472848498,97.448078425168,3251.037082975553,742.2100315641153,16.26429537781848,0.4432465691073604,0.4329686574409998,0.004121820888165019,3251.037082975553,742.2100315641153,, +surge,0.6,robust,2,10447.04164810777,524.0029334247373,5311.611043281193,1808.6200710093085,16.49826042222505,0.6088756908260344,0.43427092746638946,0.007817511630542989,5311.611043281193,1808.6200710093085,, +surge,0.8,no_robust,3,9678.259826640971,272.83530913170915,3204.3479815026553,556.8799617962688,16.840420745981802,0.4589959822922529,0.43920385308157944,0.004953937449529005,3204.3479815026553,556.8799617962688,, +surge,0.8,robust,3,10101.413689120902,526.8318040489241,4321.442189833087,1284.166148011517,17.737567199677557,0.6586775330563983,0.44627248379841095,0.004644261847052545,4321.442189833087,1284.166148011517,, diff --git a/paper/src/chapters/figures/results/generated/first_sweep_tier_mode_summary.csv b/paper/src/chapters/figures/results/generated/first_sweep_tier_mode_summary.csv new file mode 100644 index 0000000..e296749 --- /dev/null +++ b/paper/src/chapters/figures/results/generated/first_sweep_tier_mode_summary.csv @@ -0,0 +1,11 @@ +tier,mode,runs,eval_revenue_mean_mean,eval_revenue_mean_std,eval_reward_mean_mean,eval_reward_mean_std,eval_coi_level_mean_mean,eval_coi_level_mean_std,eval_margin_mean_mean,eval_margin_mean_std,objective_score_mean,objective_score_std,train_alpha_adv_mean,train_alpha_adv_std +dqn,no_robust,29,315185.66674813855,23538.781000060844,302576.8036266896,62951.88633145167,136.82560356086017,1.3692652218935986,0.9313739013618878,0.0009314135057224836,302576.8036266896,62951.88633145167,0.45740740740740693,0.2368477698794438 +dqn,robust,37,306875.13950902375,27585.74444520695,283724.7169827867,69843.05611741856,136.68837571992978,2.3797541654948753,0.9312171495138941,0.0016512408492580111,283724.7169827867,69843.05611741856,0.5058198198198196,0.28324483129860284 +linear,no_robust,47,315501.15296155965,27105.014861872147,298149.1730416604,67664.7308344108,134.36884359609928,0.29743647613433244,0.9303607531364,0.0002152647006739543,298149.1730416604,67664.7308344108,, +linear,robust,31,306269.9232239004,26399.875293394463,279872.824370329,54401.104602086416,134.32737693008372,0.31909212993628877,0.9303375215162144,0.00025000448833182963,279872.824370329,54401.104602086416,, +qtable,no_robust,32,259818.72178238883,67188.58622318009,222088.83510765125,94450.12569617687,116.84641954166946,22.42810298937963,0.9140582213134033,0.02778864370791322,222088.83510765125,94450.12569617687,0.29218749999999993,0.2559326319498438 +qtable,robust,40,244470.50673219413,78666.30912808319,216920.53697298188,93983.50987622296,118.94013969887506,23.1428303249914,0.9178608956089163,0.023827311253270544,216920.53697298188,93983.50987622296,0.4396239583333334,0.29521865862482416 +static,no_robust,33,85228.452028227,12041.415672002751,64828.579890468536,17681.280330831738,70.58818912317687,4.204964531595236,0.8721419294578765,0.007107262779462876,64828.579890468536,17681.280330831738,, +static,robust,30,84963.18577955024,8926.291379160475,63243.76603076817,14880.924342692271,70.94358095957392,4.363134562111469,0.8730306888410219,0.006660289247744752,63243.76603076817,14880.924342692271,, +surge,no_robust,32,11121.867310184698,809.9895800277001,4260.038064073964,1160.4282377968032,16.416108827015794,0.641203520341943,0.43413855082681374,0.006214799767130059,4260.038064073964,1160.4282377968032,, +surge,robust,29,10994.355365953365,750.5115890942825,4448.160863178768,1000.7519971246122,16.495943148858906,0.9823026347466668,0.4347587896392907,0.009698591291108968,4448.160863178768,1000.7519971246122,, diff --git a/paper/src/chapters/figures/results/generated/first_sweep_top_configs.csv b/paper/src/chapters/figures/results/generated/first_sweep_top_configs.csv new file mode 100644 index 0000000..e51fd74 --- /dev/null +++ b/paper/src/chapters/figures/results/generated/first_sweep_top_configs.csv @@ -0,0 +1,26 @@ +Name,tier,alpha,mode,objective/score,eval/revenue_mean,eval/reward_mean,eval/coi_level_mean,lambda_coi,robust_radius,learning_rate,batch_size,n_steps,total_timesteps +eager-sweep-244,dqn,0.0,no_robust,413274.4339549909,355872.06196128257,413274.4339549909,136.722140138007,0.2,0.1,0.0003,256,4096,15000 +efficient-sweep-319,linear,0.0,no_robust,410094.0151741567,353309.5198146561,410094.0151741567,134.55152038805429,0.4,0.1,0.001,128,4096,15000 +swept-sweep-422,linear,0.0,no_robust,403130.32747386186,347611.2815474988,403130.32747386186,133.8559785775022,0.4,0.3,0.0001,512,1024,15000 +decent-sweep-478,linear,0.1,no_robust,400452.36418713134,345284.5750647792,400452.36418713134,134.73082941975588,0.1,0.2,0.001,128,1024,50000 +eternal-sweep-339,linear,0.1,no_robust,399628.4231731644,344154.38525771734,399628.4231731644,134.89479277649667,0.4,0.1,0.0001,256,1024,50000 +ethereal-sweep-21,dqn,0.1,no_robust,398492.807245857,343580.6802427996,398492.807245857,136.67160732585188,0.1,0.2,0.001,512,2048,50000 +dark-sweep-418,linear,0.1,no_robust,394615.3720658343,339749.76272695075,394615.3720658343,134.39233246711,0.2,0.1,0.0003,256,1024,50000 +wandering-sweep-122,dqn,0.0,robust,394061.3617726404,339512.43434806296,394061.3617726404,137.6864755964331,0.1,0.3,0.0001,256,2048,30000 +laced-sweep-132,dqn,0.1,robust,389274.54998495104,335600.5979215904,389274.54998495104,137.36888574027677,0.4,0.2,0.001,256,2048,30000 +rich-sweep-53,qtable,0.0,robust,388601.2626147048,335630.6853337664,388601.2626147048,133.4414069888203,0.2,0.1,0.0001,512,1024,50000 +faithful-sweep-430,qtable,0.25,no_robust,387035.6970938766,333255.5771210341,387035.6970938766,137.4906091183188,0.1,0.2,0.0003,128,1024,15000 +dark-sweep-280,qtable,0.25,no_robust,386318.8845004527,332220.0316564078,386318.8845004527,137.26992450099925,0.4,0.1,0.0001,256,1024,50000 +chocolate-sweep-383,linear,0.25,no_robust,383989.49015403807,331071.7003244704,383989.49015403807,134.60590742050857,0.1,0.2,0.001,512,1024,30000 +dry-sweep-263,dqn,0.0,robust,383372.6880637367,330436.0312615148,383372.6880637367,137.40558130223476,0.1,0.3,0.001,128,1024,50000 +different-sweep-143,qtable,0.0,robust,383278.4198015018,330546.16800945485,383278.4198015018,135.9021538079678,0.1,0.3,0.001,256,2048,30000 +woven-sweep-139,dqn,0.25,robust,382788.1296637251,329427.735752473,382788.1296637251,136.8968339394894,0.1,0.1,0.001,512,1024,15000 +dark-sweep-215,dqn,0.25,robust,382358.2401374872,329330.0097603144,382358.2401374872,137.64528612332785,0.2,0.1,0.0001,512,4096,30000 +charmed-sweep-136,linear,0.25,no_robust,382249.5728044314,329646.2053260979,382249.5728044314,134.46825608007862,0.4,0.1,0.0001,256,2048,15000 +light-sweep-308,linear,0.0,robust,381939.1275250679,329628.9436641051,381939.1275250679,133.6209821974879,0.2,0.2,0.001,128,4096,30000 +treasured-sweep-325,linear,0.25,robust,381322.0104772589,328353.58675398555,381322.0104772589,134.8950293943581,0.1,0.1,0.0001,512,2048,15000 +fine-sweep-202,dqn,0.25,robust,378751.33572275366,326518.9068184018,378751.33572275366,137.2900973301052,0.1,0.2,0.0001,512,2048,30000 +treasured-sweep-380,linear,0.25,no_robust,377898.0979419424,325869.1953595453,377898.0979419424,134.54118723889738,0.4,0.3,0.001,128,1024,50000 +pretty-sweep-49,qtable,0.25,robust,377318.4766808995,325282.0152823859,377318.4766808995,137.19609012644068,0.4,0.1,0.0001,128,4096,50000 +desert-sweep-253,linear,0.25,robust,376808.6335063269,325146.3478714648,376808.6335063269,134.48396340732663,0.2,0.1,0.0003,256,1024,30000 +jolly-sweep-133,qtable,0.4,no_robust,376419.57394710975,323709.24588324485,376419.57394710975,137.8349363778071,0.1,0.3,0.0001,128,2048,50000 diff --git a/paper/src/chapters/figures/results/generated/plots/first_sweep_tier_revenue.pdf b/paper/src/chapters/figures/results/generated/plots/first_sweep_tier_revenue.pdf new file mode 100644 index 0000000000000000000000000000000000000000..a019aee4615d177aa840da1f218351311de822a5 GIT binary patch literal 17510 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 V-8}ZDF@z8}+l6p)%Baag{tr7N?@|B& literal 0 HcmV?d00001 diff --git a/paper/src/chapters/figures/results/generated/plots/ppo_alpha_curves.pdf b/paper/src/chapters/figures/results/generated/plots/ppo_alpha_curves.pdf new file mode 100644 index 0000000000000000000000000000000000000000..d012154f84dbfb68caa05c7cc37a6838173f4046 GIT binary patch literal 25398 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 GVE+gHJF!gw literal 0 HcmV?d00001 diff --git a/paper/src/chapters/figures/results/generated/plots/ppo_tradeoff_scatter.pdf b/paper/src/chapters/figures/results/generated/plots/ppo_tradeoff_scatter.pdf new file mode 100644 index 0000000000000000000000000000000000000000..34da3accf8ed857cd42c0291a2e41dcfd8af8299 GIT binary patch literal 26824 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 literal 0 HcmV?d00001 diff --git a/paper/src/chapters/figures/results/generated/ppo_alpha_deltas.csv b/paper/src/chapters/figures/results/generated/ppo_alpha_deltas.csv new file mode 100644 index 0000000..42cf5c9 --- /dev/null +++ b/paper/src/chapters/figures/results/generated/ppo_alpha_deltas.csv @@ -0,0 +1,7 @@ +alpha,runs_robust,runs_no_robust,eval_revenue_mean_robust,eval_revenue_mean_no_robust,eval_revenue_mean_delta,eval_revenue_mean_delta_pct,eval_reward_mean_robust,eval_reward_mean_no_robust,eval_reward_mean_delta,eval_reward_mean_delta_pct,eval_coi_level_mean_robust,eval_coi_level_mean_no_robust,eval_coi_level_mean_delta,eval_coi_level_mean_delta_pct,eval_coi_leakage_mean_robust,eval_coi_leakage_mean_no_robust,eval_coi_leakage_mean_delta,eval_coi_leakage_mean_delta_pct,eval_volatility_mean_robust,eval_volatility_mean_no_robust,eval_volatility_mean_delta,eval_volatility_mean_delta_pct,eval_margin_mean_robust,eval_margin_mean_no_robust,eval_margin_mean_delta,eval_margin_mean_delta_pct,train_alpha_adv_robust,train_alpha_adv_no_robust,train_alpha_adv_delta,train_alpha_adv_delta_pct,train_coi_penalty_robust,train_coi_penalty_no_robust,train_coi_penalty_delta,train_coi_penalty_delta_pct,train_ux_penalty_robust,train_ux_penalty_no_robust,train_ux_penalty_delta,train_ux_penalty_delta_pct,train_agent_prob_robust,train_agent_prob_no_robust,train_agent_prob_delta,train_agent_prob_delta_pct +0.0,4.0,4.0,3379.9042994670963,3565.2912010160844,-185.38690154898813,-5.199768857482219,313527.4707462,331300.229069,-17772.758322799986,-5.364547550342456,137.08358925982625,137.28764358955686,-0.2040543297306101,-0.14863269875959326,0.1146626165658294,0.11861133504329742,-0.003948718477468013,-3.3291240470622716,0.06687153537785637,0.06445662162531288,0.0024149137525434905,3.746572022625408,0.9315273502623671,0.9317078361627993,-0.00018048590043218127,-0.019371512552207898,0.18958333333333333,,,,5.553200113221484,,,,61.35134238638615,66.58479574844135,-5.233453362055201,-7.859832418540847,0.12778212146468534,0.11615891320235115,0.011623208262334192,10.00629907933654 +0.1,4.0,4.0,3307.028238366196,3458.002436284769,-150.97419791857283,-4.365936713473732,306772.49146475,321215.477968,-14442.986503249966,-4.4963544704059375,137.1182041122497,136.82757579763506,0.29062831461465066,0.21240478238427865,0.1128546052304944,0.11704917861668755,-0.004194573386193154,-3.5835991638433753,0.0685405649303561,0.06737596899527175,0.0011645959350843477,1.728503430007924,0.9315331673960889,0.9313276818191593,0.00020548557692967595,0.0220637248243606,0.2818749999999999,0.1,0.18187499999999987,181.87499999999986,5.079528726095333,,,,52.44772950699336,53.288869747139515,-0.841140240146153,-1.578453895039319,0.11644381911386253,0.11765277436070229,-0.0012089552468397546,-1.0275620387270383 +0.25,4.0,4.0,3134.3438215278165,3300.5539051855053,-166.21008365768876,-5.035823938416998,290691.4771835,306522.90003785,-15831.422854350007,-5.16484179563586,136.89990884669214,136.71752459667877,0.18238425001337077,0.1334022471160229,0.11113957413522965,0.1139905600539111,-0.0028509859186814507,-2.50107194607439,0.06427159998376095,0.06846858821082077,-0.004196988227059828,-6.12980103246314,0.9314501501825461,0.9313053225630614,0.0001448276194846443,0.015551035302371268,0.44833333333333336,0.25,0.19833333333333336,79.33333333333334,4.7183804755060255,,,,49.04307009982127,55.2030005738411,-6.159930474019831,-11.158687770568074,0.10998505830218755,0.11684259343269415,-0.0068575351305066035,-5.869037077182653 +0.4,4.0,4.0,2983.852437569374,3180.7872854626567,-196.9348478932825,-6.191386918369099,276545.26309355,295433.5405797,-18888.277486150037,-6.393409986248494,136.19210761854086,136.5783021470118,-0.38619452847095204,-0.2827641890402586,0.10875560547061063,0.11189234314151972,-0.0031367376709090927,-2.8033532794480807,0.07452230347799255,0.07104688223410768,0.003475421243884863,4.891729425132195,0.9307282962514367,0.9310542820602117,-0.0003259858087749645,-0.03501254599824534,0.5999999999999999,0.4000000000000001,0.1999999999999998,49.999999999999936,4.174996403604185,,,,47.99794119802058,50.794260008988424,-2.796318810967847,-5.505186630286606,0.10222958892923095,0.11161526349272373,-0.009385674563492777,-8.408952565976458 +0.6,4.0,4.0,2789.0434220430398,2982.2460998252786,-193.20267778223888,-6.4784283830083,258688.11700405,277051.95613675,-18363.8391327,-6.628301560749781,136.86774320500828,136.81931587629953,0.04842732870875466,0.035395096371142916,0.10501047827147733,0.10802266412956946,-0.0030121858580921257,-2.788475809557069,0.06914180963767007,0.06698591531512615,0.0021558943225439137,3.2184292957732996,0.9314130089130337,0.9313849217310588,2.8087181974889575e-05,0.003015636319588161,0.7733333333333334,0.5999999999999999,0.17333333333333356,28.888888888888935,4.178300996512875,,,,39.928062615509425,47.86860429278531,-7.940541677275881,-16.588203885594947,0.11297979438696983,0.1162670925925253,-0.0032872982055554695,-2.827367686122743 +0.8,4.0,4.0,2586.098242115281,2841.1305915063504,-255.03234939106915,-8.97643882169642,239765.24959855,264140.55002745,-24375.300428900024,-9.228155399224729,136.5038826686135,137.28163778418497,-0.7777551155714661,-0.5665397995864124,0.10253056902792507,0.1031498585902154,-0.0006192895622903344,-0.6003784888844036,0.07325665736408164,0.06592454978099352,0.007332107583088124,11.1219683827132,0.9311235469993302,0.9316596013994161,-0.0005360544000858614,-0.05753758124541101,1.0,0.8000000000000002,0.19999999999999984,24.99999999999998,3.5384100686094007,,,,37.14414699970415,37.43809775029793,-0.29395075059377973,-0.7851647606519765,0.09990322635678014,0.10432800196112454,-0.0044247756043444,-4.241215705437541 diff --git a/paper/src/chapters/figures/results/generated/ppo_alpha_mode_summary.csv b/paper/src/chapters/figures/results/generated/ppo_alpha_mode_summary.csv new file mode 100644 index 0000000..52cff7b --- /dev/null +++ b/paper/src/chapters/figures/results/generated/ppo_alpha_mode_summary.csv @@ -0,0 +1,13 @@ +alpha,mode,runs,eval_revenue_mean_mean,eval_revenue_mean_std,eval_reward_mean_mean,eval_reward_mean_std,eval_coi_level_mean_mean,eval_coi_level_mean_std,eval_coi_leakage_mean_mean,eval_coi_leakage_mean_std,eval_volatility_mean_mean,eval_volatility_mean_std,eval_margin_mean_mean,eval_margin_mean_std,train_alpha_adv_mean,train_alpha_adv_std,train_coi_penalty_mean,train_coi_penalty_std,train_ux_penalty_mean,train_ux_penalty_std,train_agent_prob_mean,train_agent_prob_std +0.0,no_robust,4,3565.2912010160844,52.219179508209216,331300.229069,5038.96659004527,137.28764358955686,0.6434240315013728,0.11861133504329742,0.004019332768284657,0.06445662162531288,0.004080405219050139,0.9317078361627993,0.00038018051704976865,,,,,66.58479574844135,32.282270089830455,0.11615891320235115,0.016558627227281013 +0.0,robust,4,3379.9042994670963,54.727408939657735,313527.4707462,5408.058196552377,137.08358925982625,1.047386315387148,0.1146626165658294,0.0025627354157035497,0.06687153537785637,0.008577061675868377,0.9315273502623671,0.0007274203134899985,0.18958333333333333,0.02083333333333336,5.553200113221484,0.45981481828856186,61.35134238638615,30.27964905193963,0.12778212146468534,0.027929667978205217 +0.1,no_robust,4,3458.002436284769,60.75923217871363,321215.477968,6016.373193216596,136.82757579763506,1.1899102161551907,0.11704917861668755,0.0021220259908233973,0.06737596899527175,0.006801136773079149,0.9313276818191593,0.0008352263172197586,0.1,0.0,,,53.288869747139515,18.480340945815023,0.11765277436070229,0.017544197575138736 +0.1,robust,4,3307.028238366196,35.58495715224888,306772.49146475,3488.2690530060245,137.1182041122497,0.8582218376452346,0.1128546052304944,0.0005963155492967403,0.0685405649303561,0.0050673362512629015,0.9315331673960889,0.0005217376436765336,0.2818749999999999,0.03624999999999999,5.079528726095333,0.6109585102054891,52.44772950699336,29.0263361696475,0.11644381911386253,0.021152545180088765 +0.25,no_robust,4,3300.5539051855053,50.460978662647115,306522.90003785,4860.668937531515,136.71752459667877,0.7410676951244369,0.1139905600539111,0.003319948537321803,0.06846858821082077,0.008614994548315848,0.9313053225630614,0.0004919872662680591,0.25,0.0,,,55.2030005738411,26.88247558235345,0.11684259343269415,0.013462146346772591 +0.25,robust,4,3134.3438215278165,64.06834403659167,290691.4771835,6331.196493752059,136.89990884669214,1.3796663751798552,0.11113957413522965,0.0015044942041406348,0.06427159998376095,0.0042331619171274894,0.9314501501825461,0.0008939739741734515,0.44833333333333336,0.0033333333333333518,4.7183804755060255,0.4538389380858333,49.04307009982127,28.20484665432831,0.10998505830218755,0.010731404693185651 +0.4,no_robust,4,3180.7872854626567,71.87564776824694,295433.5405797,7035.374110540269,136.5783021470118,1.7095219574599192,0.11189234314151972,0.0013821115134030936,0.07104688223410768,0.005766138692685495,0.9310542820602117,0.0013989725050689828,0.4000000000000001,0.0,,,50.794260008988424,24.836708377642946,0.11161526349272373,0.005787749200301594 +0.4,robust,4,2983.852437569374,45.51290575912758,276545.26309355,4555.1725323898245,136.19210761854086,1.5546063667946701,0.10875560547061063,0.001118798290958954,0.07452230347799255,0.0040446395928049874,0.9307282962514367,0.0013558080014763189,0.5999999999999999,0.0,4.174996403604185,0.12189448324552496,47.99794119802058,33.51782503281748,0.10222958892923095,0.0031686467591609474 +0.6,no_robust,4,2982.2460998252786,39.93674476199945,277051.95613675,3931.02017169463,136.81931587629953,1.1995405806950865,0.10802266412956946,0.000405835985606262,0.06698591531512615,0.002805894772223563,0.9313849217310588,0.0008100530228792662,0.5999999999999999,0.0,,,47.86860429278531,23.830502772642472,0.1162670925925253,0.028676813474186293 +0.6,robust,4,2789.0434220430398,35.297482315631626,258688.11700405,3420.6735023624556,136.86774320500828,0.7097303238857778,0.10501047827147733,0.0008273121554488608,0.06914180963767007,0.009066158371268139,0.9314130089130337,0.0005024421703994162,0.7733333333333334,0.053333333333333385,4.178300996512875,0.5865970573865015,39.928062615509425,30.25078643153115,0.11297979438696983,0.0274101056520461 +0.8,no_robust,4,2841.1305915063504,21.84043179776092,264140.55002745,2073.353315114627,137.28163778418497,0.6288968799501957,0.1031498585902154,0.0012877581835795701,0.06592454978099352,0.00340700896766341,0.9316596013994161,0.00038430108058413553,0.8000000000000002,0.0,,,37.43809775029793,32.01740090550489,0.10432800196112454,0.018337841526911584 +0.8,robust,4,2586.098242115281,48.05539265296157,239765.24959855,4681.6472175597555,136.5038826686135,1.0611320896043694,0.10253056902792507,0.002587472569909977,0.07325665736408164,0.0015359324114246234,0.9311235469993302,0.0006145440308596868,1.0,0.0,3.5384100686094007,0.391972726035734,37.14414699970415,25.614063825315505,0.09990322635678014,0.010269342031085898 diff --git a/paper/src/chapters/figures/results/generated/ppo_headline_summary.json b/paper/src/chapters/figures/results/generated/ppo_headline_summary.json new file mode 100644 index 0000000..5b106f2 --- /dev/null +++ b/paper/src/chapters/figures/results/generated/ppo_headline_summary.json @@ -0,0 +1,7 @@ +{ + "status": "ok", + "revenue_delta": -191.29017636530716, + "revenue_delta_pct": -5.938226273545598, + "coi_leakage_delta": -0.002960415145605702, + "coi_leakage_delta_pct": -2.6404147469510946 +} \ No newline at end of file diff --git a/paper/src/chapters/figures/results/generated/ppo_overall_mode_summary.csv b/paper/src/chapters/figures/results/generated/ppo_overall_mode_summary.csv new file mode 100644 index 0000000..c45b856 --- /dev/null +++ b/paper/src/chapters/figures/results/generated/ppo_overall_mode_summary.csv @@ -0,0 +1,3 @@ +mode,runs,eval_revenue_mean_mean,eval_revenue_mean_std,eval_reward_mean_mean,eval_reward_mean_std,eval_coi_level_mean_mean,eval_coi_level_mean_std,eval_coi_leakage_mean_mean,eval_coi_leakage_mean_std,eval_volatility_mean_mean,eval_volatility_mean_std,eval_margin_mean_mean,eval_margin_mean_std,train_alpha_adv_mean,train_alpha_adv_std,train_coi_penalty_mean,train_coi_penalty_std,train_ux_penalty_mean,train_ux_penalty_std,train_agent_prob_mean,train_agent_prob_std +no_robust,24,3221.335253213441,262.46595166337727,299277.442303125,24382.561944761477,136.9186666318945,1.0038463876967063,0.11211932326253345,0.005805494533542669,0.06737642102693879,0.005402738047823369,0.9314066076226178,0.0007436370959663933,0.43,0.2546411303445653,,,51.86293802024894,25.340287421525442,0.11381077317368686,0.016664235359362907 +robust,24,3030.0450768481337,288.262657026656,280998.34484843333,26820.020161880373,136.77757261848845,1.06224696086916,0.10915890811692774,0.004616462637659704,0.06943407846195294,0.006435789449278624,0.9312959200008004,0.0007858424519830652,0.5488541666666666,0.2860373751485706,4.540469463924883,0.7906156355346259,47.985382134405825,27.407657819442747,0.11155393475895271,0.01943348418653492 diff --git a/paper/src/chapters/figures/results/generated/ppo_pairwise_win_rates.csv b/paper/src/chapters/figures/results/generated/ppo_pairwise_win_rates.csv new file mode 100644 index 0000000..856cc8b --- /dev/null +++ b/paper/src/chapters/figures/results/generated/ppo_pairwise_win_rates.csv @@ -0,0 +1,25 @@ +alpha,metric,direction,wins,ties,total_pairs,win_probability +0.0,eval/revenue_mean,higher,0,0,16,0.0 +0.0,eval/reward_mean,higher,0,0,16,0.0 +0.0,eval/coi_leakage_mean,lower,14,0,16,0.875 +0.0,eval/volatility_mean,lower,8,0,16,0.5 +0.1,eval/revenue_mean,higher,0,0,16,0.0 +0.1,eval/reward_mean,higher,0,0,16,0.0 +0.1,eval/coi_leakage_mean,lower,16,0,16,1.0 +0.1,eval/volatility_mean,lower,8,0,16,0.5 +0.25,eval/revenue_mean,higher,0,0,16,0.0 +0.25,eval/reward_mean,higher,0,0,16,0.0 +0.25,eval/coi_leakage_mean,lower,12,0,16,0.75 +0.25,eval/volatility_mean,lower,11,0,16,0.6875 +0.4,eval/revenue_mean,higher,0,0,16,0.0 +0.4,eval/reward_mean,higher,0,0,16,0.0 +0.4,eval/coi_leakage_mean,lower,16,0,16,1.0 +0.4,eval/volatility_mean,lower,6,0,16,0.375 +0.6,eval/revenue_mean,higher,0,0,16,0.0 +0.6,eval/reward_mean,higher,0,0,16,0.0 +0.6,eval/coi_leakage_mean,lower,16,0,16,1.0 +0.6,eval/volatility_mean,lower,7,0,16,0.4375 +0.8,eval/revenue_mean,higher,0,0,16,0.0 +0.8,eval/reward_mean,higher,0,0,16,0.0 +0.8,eval/coi_leakage_mean,lower,11,0,16,0.6875 +0.8,eval/volatility_mean,lower,0,0,16,0.0 diff --git a/paper/src/chapters/figures/results/plot_results.py b/paper/src/chapters/figures/results/plot_results.py new file mode 100644 index 0000000..0b80926 --- /dev/null +++ b/paper/src/chapters/figures/results/plot_results.py @@ -0,0 +1,313 @@ +from __future__ import annotations + +import argparse +from pathlib import Path + +import matplotlib + +matplotlib.use("Agg") +import matplotlib.pyplot as plt +from matplotlib.ticker import FuncFormatter +import numpy as np +import pandas as pd + +from process_first_sweep import run as run_first_sweep +from process_ppo_benchmark import run as run_ppo_benchmark + + +def _output_dir() -> Path: + return Path(__file__).resolve().parent / "generated" + + +def _plot_dir() -> Path: + return _output_dir() / "plots" + + +def _configure_style() -> None: + plt.rcParams.update( + { + "font.family": "serif", + "font.size": 10, + "axes.titlesize": 10, + "axes.labelsize": 9, + "legend.fontsize": 8, + "xtick.labelsize": 8, + "ytick.labelsize": 8, + "figure.dpi": 220, + "savefig.dpi": 320, + "axes.spines.top": False, + "axes.spines.right": False, + "axes.grid": True, + "grid.alpha": 0.22, + } + ) + + +def _fmt_thousands(value: float, _: int) -> str: + return f"{int(value):,}" + + +def _load_csv(path: Path) -> pd.DataFrame: + if not path.exists(): + raise FileNotFoundError(f"Missing required input: {path}") + return pd.read_csv(path) + + +def _plot_ppo_alpha_curves(alpha_mode: pd.DataFrame, out_dir: Path) -> Path: + fig, axes = plt.subplots(2, 2, figsize=(9.3, 6.4), constrained_layout=True) + robust_color = "#C44E52" + baseline_color = "#4C72B0" + mode_colors = {"robust": robust_color, "no_robust": baseline_color} + mode_labels = {"robust": "Robust", "no_robust": "Non-robust"} + + panels = [ + ("eval_revenue_mean", "Mean Episode Revenue", "Revenue"), + ("eval_reward_mean", "Mean Episode Reward", "Reward"), + ("eval_coi_leakage_mean", "Mean COI Leakage", "COI Leakage"), + ("eval_volatility_mean", "Mean Price Volatility", "Volatility"), + ] + + for ax, (metric_prefix, title, ylabel) in zip(axes.flat, panels): + mean_col = f"{metric_prefix}_mean" + std_col = f"{metric_prefix}_std" + for mode in ("no_robust", "robust"): + sub = alpha_mode[alpha_mode["mode"] == mode].sort_values("alpha") + if sub.empty: + continue + x = sub["alpha"].to_numpy(dtype=float) + y = sub[mean_col].to_numpy(dtype=float) + ax.plot( + x, + y, + marker="o", + linewidth=1.8, + markersize=4, + color=mode_colors[mode], + label=mode_labels[mode], + ) + if std_col in sub.columns: + sigma = sub[std_col].fillna(0.0).to_numpy(dtype=float) + ax.fill_between( + x, + y - sigma, + y + sigma, + color=mode_colors[mode], + alpha=0.14, + linewidth=0, + ) + + ax.set_title(title) + ax.set_xlabel(r"Contamination $\alpha$") + ax.set_ylabel(ylabel) + ax.set_xticks(sorted(alpha_mode["alpha"].unique())) + if metric_prefix in {"eval_revenue_mean", "eval_reward_mean"}: + ax.yaxis.set_major_formatter(FuncFormatter(_fmt_thousands)) + + handles, labels = axes.flat[0].get_legend_handles_labels() + fig.legend(handles, labels, ncol=2, loc="upper center", bbox_to_anchor=(0.5, 1.02)) + + out_path = out_dir / "ppo_alpha_curves.pdf" + fig.savefig(out_path, bbox_inches="tight") + plt.close(fig) + return out_path + + +def _plot_ppo_delta_curves(deltas: pd.DataFrame, out_dir: Path) -> Path: + fig, axes = plt.subplots(2, 1, figsize=(8.6, 6.0), constrained_layout=True) + deltas = deltas.sort_values("alpha") + x = deltas["alpha"].to_numpy(dtype=float) + + top_metrics = [ + ("eval_revenue_mean_delta_pct", "Revenue", "#4C72B0"), + ("eval_reward_mean_delta_pct", "Reward", "#8172B3"), + ] + for col, label, color in top_metrics: + axes[0].plot( + x, + deltas[col].to_numpy(dtype=float), + marker="o", + linewidth=1.8, + markersize=4, + color=color, + label=label, + ) + axes[0].axhline(0.0, color="#444444", linewidth=1.0, linestyle="--") + axes[0].set_title("Robust Minus Non-robust Delta by Contamination") + axes[0].set_ylabel("Delta (%)") + axes[0].set_xlabel(r"Contamination $\alpha$") + axes[0].set_xticks(x) + axes[0].legend(loc="lower left") + + bottom_metrics = [ + ("eval_coi_leakage_mean_delta_pct", "COI Leakage", "#55A868"), + ("eval_volatility_mean_delta_pct", "Volatility", "#DD8452"), + ] + for col, label, color in bottom_metrics: + axes[1].plot( + x, + deltas[col].to_numpy(dtype=float), + marker="o", + linewidth=1.8, + markersize=4, + color=color, + label=label, + ) + axes[1].axhline(0.0, color="#444444", linewidth=1.0, linestyle="--") + axes[1].set_ylabel("Delta (%)") + axes[1].set_xlabel(r"Contamination $\alpha$") + axes[1].set_xticks(x) + axes[1].legend(loc="lower left") + + out_path = out_dir / "ppo_delta_curves.pdf" + fig.savefig(out_path, bbox_inches="tight") + plt.close(fig) + return out_path + + +def _plot_ppo_tradeoff_scatter(deltas: pd.DataFrame, out_dir: Path) -> Path: + fig, ax = plt.subplots(figsize=(6.4, 5.2), constrained_layout=True) + data = deltas.sort_values("alpha") + x = data["eval_coi_leakage_mean_delta_pct"].to_numpy(dtype=float) + y = data["eval_revenue_mean_delta_pct"].to_numpy(dtype=float) + alphas = data["alpha"].to_numpy(dtype=float) + + scatter = ax.scatter( + x, + y, + c=alphas, + cmap="viridis", + s=72, + edgecolor="#222222", + linewidth=0.5, + ) + for x_i, y_i, alpha in zip(x, y, alphas): + ax.annotate( + rf"$\alpha={alpha:.2f}$", + (x_i, y_i), + textcoords="offset points", + xytext=(5, 4), + fontsize=8, + ) + + ax.axhline(0.0, color="#555555", linewidth=1.0, linestyle="--") + ax.axvline(0.0, color="#555555", linewidth=1.0, linestyle="--") + ax.set_xlabel("COI Leakage Delta (%)") + ax.set_ylabel("Revenue Delta (%)") + ax.set_title("PPO Robust Tradeoff Frontier") + cbar = fig.colorbar(scatter, ax=ax) + cbar.set_label(r"Contamination $\alpha$") + + out_path = out_dir / "ppo_tradeoff_scatter.pdf" + fig.savefig(out_path, bbox_inches="tight") + plt.close(fig) + return out_path + + +def _plot_first_sweep_tier_revenue(tier_mode: pd.DataFrame, out_dir: Path) -> Path: + pivot = ( + tier_mode.pivot(index="tier", columns="mode", values="eval_revenue_mean_mean") + .dropna(subset=["robust", "no_robust"], how="any") + .copy() + ) + if pivot.empty: + raise ValueError("First sweep tier summary missing robust/non-robust pairs") + + order = sorted(pivot.index.tolist()) + pivot = pivot.loc[order] + delta_pct = 100.0 * (pivot["robust"] - pivot["no_robust"]) / pivot["no_robust"] + + fig, axes = plt.subplots(1, 2, figsize=(10.2, 4.3), constrained_layout=True) + x = np.arange(len(order)) + width = 0.36 + + axes[0].bar( + x - width / 2, + pivot["no_robust"].to_numpy(dtype=float), + width=width, + label="Non-robust", + color="#4C72B0", + ) + axes[0].bar( + x + width / 2, + pivot["robust"].to_numpy(dtype=float), + width=width, + label="Robust", + color="#C44E52", + ) + axes[0].set_xticks(x) + axes[0].set_xticklabels(order, rotation=20) + axes[0].set_ylabel("Mean Revenue") + axes[0].set_yscale("log") + axes[0].yaxis.set_major_formatter(FuncFormatter(_fmt_thousands)) + axes[0].set_title("First Sweep Tier Revenue (log scale)") + axes[0].legend() + + axes[1].bar(x, delta_pct.to_numpy(dtype=float), color="#55A868", width=0.55) + axes[1].axhline(0.0, color="#444444", linewidth=1.0, linestyle="--") + axes[1].set_xticks(x) + axes[1].set_xticklabels(order, rotation=20) + axes[1].set_ylabel("Revenue Delta (%)") + axes[1].set_title("Robust Minus Non-robust by Tier") + + out_path = out_dir / "first_sweep_tier_revenue.pdf" + fig.savefig(out_path, bbox_inches="tight") + plt.close(fig) + return out_path + + +def build_plots(data_dir: Path, out_dir: Path) -> list[Path]: + alpha_mode = _load_csv(data_dir / "ppo_alpha_mode_summary.csv") + deltas = _load_csv(data_dir / "ppo_alpha_deltas.csv") + tier_mode = _load_csv(data_dir / "first_sweep_tier_mode_summary.csv") + + out_dir.mkdir(parents=True, exist_ok=True) + paths = [ + _plot_ppo_alpha_curves(alpha_mode, out_dir), + _plot_ppo_delta_curves(deltas, out_dir), + _plot_ppo_tradeoff_scatter(deltas, out_dir), + _plot_first_sweep_tier_revenue(tier_mode, out_dir), + ] + return paths + + +def main() -> None: + parser = argparse.ArgumentParser( + description="Create paper-ready plots from result CSVs" + ) + parser.add_argument("--data-dir", type=Path, default=_output_dir()) + parser.add_argument("--plot-dir", type=Path, default=_plot_dir()) + parser.add_argument( + "--refresh-data", + action="store_true", + help="Regenerate processed CSVs before plotting", + ) + args = parser.parse_args() + + _configure_style() + + if bool(args.refresh_data): + run_ppo_benchmark( + input_path=Path(__file__).resolve().parents[5] + / "tpu_orchestration" + / "results" + / "ppo_benchmark.csv", + output_dir=args.data_dir, + include_non_finished=False, + ) + run_first_sweep( + input_path=Path(__file__).resolve().parents[5] + / "tpu_orchestration" + / "results" + / "first_sweep.csv", + output_dir=args.data_dir, + include_non_finished=False, + top_n=25, + ) + + outputs = build_plots(data_dir=args.data_dir, out_dir=args.plot_dir) + for path in outputs: + print(path) + + +if __name__ == "__main__": + main() diff --git a/paper/src/chapters/figures/results/ppo_alpha_curves.tex b/paper/src/chapters/figures/results/ppo_alpha_curves.tex new file mode 100644 index 0000000..2496584 --- /dev/null +++ b/paper/src/chapters/figures/results/ppo_alpha_curves.tex @@ -0,0 +1 @@ +\includegraphics[width=0.98\linewidth]{chapters/figures/results/generated/plots/ppo_alpha_curves.pdf} diff --git a/paper/src/chapters/figures/results/ppo_delta_curves.tex b/paper/src/chapters/figures/results/ppo_delta_curves.tex new file mode 100644 index 0000000..8c4eec0 --- /dev/null +++ b/paper/src/chapters/figures/results/ppo_delta_curves.tex @@ -0,0 +1 @@ +\includegraphics[width=0.98\linewidth]{chapters/figures/results/generated/plots/ppo_delta_curves.pdf} diff --git a/paper/src/chapters/figures/results/ppo_tradeoff_scatter.tex b/paper/src/chapters/figures/results/ppo_tradeoff_scatter.tex new file mode 100644 index 0000000..0117970 --- /dev/null +++ b/paper/src/chapters/figures/results/ppo_tradeoff_scatter.tex @@ -0,0 +1 @@ +\includegraphics[width=0.88\linewidth]{chapters/figures/results/generated/plots/ppo_tradeoff_scatter.pdf} diff --git a/paper/src/chapters/figures/results/process_all_results.py b/paper/src/chapters/figures/results/process_all_results.py new file mode 100644 index 0000000..2dc2a4d --- /dev/null +++ b/paper/src/chapters/figures/results/process_all_results.py @@ -0,0 +1,51 @@ +from __future__ import annotations + +import argparse +from pathlib import Path + +from process_first_sweep import run as run_first_sweep +from process_ppo_benchmark import run as run_ppo_benchmark + + +def _default_output_dir() -> Path: + return Path(__file__).resolve().parent / "generated" + + +def main() -> None: + parser = argparse.ArgumentParser( + description="Process all result CSV exports for paper figures" + ) + parser.add_argument("--output-dir", type=Path, default=_default_output_dir()) + parser.add_argument("--include-non-finished", action="store_true") + parser.add_argument("--top-n", type=int, default=25) + args = parser.parse_args() + + written: list[Path] = [] + written.extend( + run_ppo_benchmark( + input_path=Path(__file__).resolve().parents[5] + / "tpu_orchestration" + / "results" + / "ppo_benchmark.csv", + output_dir=args.output_dir, + include_non_finished=bool(args.include_non_finished), + ) + ) + written.extend( + run_first_sweep( + input_path=Path(__file__).resolve().parents[5] + / "tpu_orchestration" + / "results" + / "first_sweep.csv", + output_dir=args.output_dir, + include_non_finished=bool(args.include_non_finished), + top_n=int(args.top_n), + ) + ) + + for path in written: + print(path) + + +if __name__ == "__main__": + main() diff --git a/paper/src/chapters/figures/results/process_first_sweep.py b/paper/src/chapters/figures/results/process_first_sweep.py new file mode 100644 index 0000000..fd650b1 --- /dev/null +++ b/paper/src/chapters/figures/results/process_first_sweep.py @@ -0,0 +1,272 @@ +from __future__ import annotations + +import argparse +import json +from pathlib import Path +from typing import Iterable + +import numpy as np +import pandas as pd + + +def _project_root() -> Path: + return Path(__file__).resolve().parents[5] + + +def _default_input() -> Path: + return _project_root() / "tpu_orchestration" / "results" / "first_sweep.csv" + + +def _default_output_dir() -> Path: + return Path(__file__).resolve().parent / "generated" + + +def _sanitize(key: str) -> str: + return key.replace("/", "_").replace("-", "_") + + +def _coerce_numeric(frame: pd.DataFrame, columns: Iterable[str]) -> None: + for column in columns: + if column in frame.columns: + frame[column] = pd.to_numeric(frame[column], errors="coerce") + + +def _extract_alpha(frame: pd.DataFrame) -> pd.Series: + if "study/alpha" in frame.columns: + return pd.to_numeric(frame["study/alpha"], errors="coerce") + if "alpha" in frame.columns: + return pd.to_numeric(frame["alpha"], errors="coerce") + return pd.Series(np.nan, index=frame.index, dtype=float) + + +def _extract_mode(frame: pd.DataFrame) -> pd.Series: + if "study/mode" in frame.columns: + return frame["study/mode"].astype(str).str.strip().str.lower() + if "study/no_robust" in frame.columns: + no_robust = pd.to_numeric(frame["study/no_robust"], errors="coerce").fillna(0.0) + return pd.Series( + np.where(no_robust > 0.5, "no_robust", "robust"), + index=frame.index, + dtype="object", + ) + if "no_robust" in frame.columns: + no_robust = ( + frame["no_robust"].astype(str).str.lower().isin({"1", "true", "yes"}) + ) + return pd.Series( + np.where(no_robust, "no_robust", "robust"), + index=frame.index, + dtype="object", + ) + return pd.Series("", index=frame.index, dtype="object") + + +def _extract_tier(frame: pd.DataFrame) -> pd.Series: + for column in ("tiers", "runtime/backend", "algo", "run.backend", "run.algo"): + if column in frame.columns: + tier = frame[column].astype(str).str.strip().str.lower() + if tier.notna().any(): + return tier + return pd.Series("unknown", index=frame.index, dtype="object") + + +def _prepare_frame(frame: pd.DataFrame, include_non_finished: bool) -> pd.DataFrame: + data = frame.copy() + if not include_non_finished and "State" in data.columns: + data = data[data["State"].astype(str).str.lower() == "finished"].copy() + + data["alpha"] = _extract_alpha(data) + data["mode"] = _extract_mode(data) + data["tier"] = _extract_tier(data) + data = data[data["mode"].isin({"robust", "no_robust"})] + data = data[data["alpha"].notna()] + + _coerce_numeric( + data, + [ + "eval/revenue_mean", + "eval/reward_mean", + "eval/coi_level_mean", + "eval/coi_leakage_mean", + "eval/margin_mean", + "eval/volatility_mean", + "objective/score", + "train/alpha_adv", + "lambda_coi", + "robust_radius", + "learning_rate", + "batch_size", + "n_steps", + "total_timesteps", + ], + ) + return data.sort_values(["tier", "alpha", "mode"]).reset_index(drop=True) + + +def _group_summary( + frame: pd.DataFrame, by: list[str], metrics: list[str] +) -> pd.DataFrame: + agg_spec: dict[str, tuple[str, str]] = {"runs": ("mode", "size")} + for metric in metrics: + safe = _sanitize(metric) + agg_spec[f"{safe}_mean"] = (metric, "mean") + agg_spec[f"{safe}_std"] = (metric, "std") + return frame.groupby(by, as_index=False).agg(**agg_spec).sort_values(by) + + +def _tier_alpha_deltas(summary: pd.DataFrame, metrics: list[str]) -> pd.DataFrame: + rows: list[dict[str, float | str]] = [] + for (tier, alpha), group in summary.groupby(["tier", "alpha"], sort=True): + robust = group[group["mode"] == "robust"] + no_robust = group[group["mode"] == "no_robust"] + if robust.empty or no_robust.empty: + continue + + row: dict[str, float | str] = { + "tier": str(tier), + "alpha": float(alpha), + "runs_robust": float(robust["runs"].iloc[0]), + "runs_no_robust": float(no_robust["runs"].iloc[0]), + } + for metric in metrics: + safe = _sanitize(metric) + robust_value = float(robust[f"{safe}_mean"].iloc[0]) + no_robust_value = float(no_robust[f"{safe}_mean"].iloc[0]) + delta = robust_value - no_robust_value + row[f"{safe}_delta"] = delta + row[f"{safe}_delta_pct"] = ( + np.nan if no_robust_value == 0 else 100.0 * delta / no_robust_value + ) + rows.append(row) + + return pd.DataFrame(rows) + + +def _top_runs(frame: pd.DataFrame, n: int) -> pd.DataFrame: + rank_metric = "objective/score" + if rank_metric not in frame.columns or frame[rank_metric].notna().sum() == 0: + rank_metric = "eval/reward_mean" + + keep = [ + "Name", + "tier", + "alpha", + "mode", + rank_metric, + "eval/revenue_mean", + "eval/reward_mean", + "eval/coi_level_mean", + "eval/coi_leakage_mean", + "lambda_coi", + "robust_radius", + "learning_rate", + "batch_size", + "n_steps", + "total_timesteps", + ] + present = [column for column in keep if column in frame.columns] + ranked = frame[present].copy().sort_values(rank_metric, ascending=False) + return ranked.head(max(1, int(n))).reset_index(drop=True) + + +def _headline_json( + frame: pd.DataFrame, tier_mode: pd.DataFrame +) -> dict[str, float | str]: + out: dict[str, float | str] = { + "runs": int(len(frame)), + "tiers": int(frame["tier"].nunique()), + "alphas": int(frame["alpha"].nunique()), + } + + robust_rows = tier_mode[tier_mode["mode"] == "robust"] + no_robust_rows = tier_mode[tier_mode["mode"] == "no_robust"] + if robust_rows.empty or no_robust_rows.empty: + out["status"] = "incomplete_modes" + return out + + robust_mean = robust_rows["eval_revenue_mean_mean"].mean() + no_robust_mean = no_robust_rows["eval_revenue_mean_mean"].mean() + out.update( + { + "status": "ok", + "mean_tier_revenue_robust": float(robust_mean), + "mean_tier_revenue_no_robust": float(no_robust_mean), + "mean_tier_revenue_delta": float(robust_mean - no_robust_mean), + "mean_tier_revenue_delta_pct": float( + 100.0 * (robust_mean - no_robust_mean) / no_robust_mean + ) + if no_robust_mean + else np.nan, + } + ) + return out + + +def run( + input_path: Path, output_dir: Path, include_non_finished: bool, top_n: int +) -> list[Path]: + output_dir.mkdir(parents=True, exist_ok=True) + raw = pd.read_csv(input_path) + frame = _prepare_frame(raw, include_non_finished=include_non_finished) + + metrics = [ + metric + for metric in ( + "eval/revenue_mean", + "eval/reward_mean", + "eval/coi_level_mean", + "eval/coi_leakage_mean", + "eval/margin_mean", + "eval/volatility_mean", + "objective/score", + "train/alpha_adv", + ) + if metric in frame.columns + ] + + tier_mode = _group_summary(frame, ["tier", "mode"], metrics) + tier_alpha_mode = _group_summary(frame, ["tier", "alpha", "mode"], metrics) + deltas = _tier_alpha_deltas(tier_alpha_mode, metrics) + top_configs = _top_runs(frame, n=top_n) + headline = _headline_json(frame, tier_mode) + + outputs = { + "first_sweep_tier_mode_summary.csv": tier_mode, + "first_sweep_tier_alpha_mode_summary.csv": tier_alpha_mode, + "first_sweep_tier_alpha_deltas.csv": deltas, + "first_sweep_top_configs.csv": top_configs, + } + written_paths: list[Path] = [] + for filename, table in outputs.items(): + path = output_dir / filename + table.to_csv(path, index=False) + written_paths.append(path) + + headline_path = output_dir / "first_sweep_headline_summary.json" + headline_path.write_text(json.dumps(headline, indent=2)) + written_paths.append(headline_path) + return written_paths + + +def main() -> None: + parser = argparse.ArgumentParser( + description="Process first sweep CSV for paper tables" + ) + parser.add_argument("--input", type=Path, default=_default_input()) + parser.add_argument("--output-dir", type=Path, default=_default_output_dir()) + parser.add_argument("--include-non-finished", action="store_true") + parser.add_argument("--top-n", type=int, default=25) + args = parser.parse_args() + + written = run( + input_path=args.input, + output_dir=args.output_dir, + include_non_finished=bool(args.include_non_finished), + top_n=int(args.top_n), + ) + for path in written: + print(path) + + +if __name__ == "__main__": + main() diff --git a/paper/src/chapters/figures/results/process_ppo_benchmark.py b/paper/src/chapters/figures/results/process_ppo_benchmark.py new file mode 100644 index 0000000..dbced6a --- /dev/null +++ b/paper/src/chapters/figures/results/process_ppo_benchmark.py @@ -0,0 +1,277 @@ +from __future__ import annotations + +import argparse +import json +from pathlib import Path +from typing import Iterable + +import numpy as np +import pandas as pd + + +def _project_root() -> Path: + return Path(__file__).resolve().parents[5] + + +def _default_input() -> Path: + return _project_root() / "tpu_orchestration" / "results" / "ppo_benchmark.csv" + + +def _default_output_dir() -> Path: + return Path(__file__).resolve().parent / "generated" + + +def _sanitize(key: str) -> str: + return key.replace("/", "_").replace("-", "_") + + +def _coerce_numeric(frame: pd.DataFrame, columns: Iterable[str]) -> None: + for column in columns: + if column in frame.columns: + frame[column] = pd.to_numeric(frame[column], errors="coerce") + + +def _extract_alpha(frame: pd.DataFrame) -> pd.Series: + if "study/alpha" in frame.columns: + return pd.to_numeric(frame["study/alpha"], errors="coerce") + if "alpha" in frame.columns: + return pd.to_numeric(frame["alpha"], errors="coerce") + return pd.Series(np.nan, index=frame.index, dtype=float) + + +def _extract_mode(frame: pd.DataFrame) -> pd.Series: + if "study/mode" in frame.columns: + return frame["study/mode"].astype(str).str.strip().str.lower() + if "study/no_robust" in frame.columns: + no_robust = pd.to_numeric(frame["study/no_robust"], errors="coerce").fillna(0.0) + return pd.Series( + np.where(no_robust > 0.5, "no_robust", "robust"), + index=frame.index, + dtype="object", + ) + if "no_robust" in frame.columns: + no_robust = ( + frame["no_robust"].astype(str).str.lower().isin({"1", "true", "yes"}) + ) + return pd.Series( + np.where(no_robust, "no_robust", "robust"), + index=frame.index, + dtype="object", + ) + return pd.Series("", index=frame.index, dtype="object") + + +def _prepare_frame(frame: pd.DataFrame, include_non_finished: bool) -> pd.DataFrame: + data = frame.copy() + if not include_non_finished and "State" in data.columns: + data = data[data["State"].astype(str).str.lower() == "finished"].copy() + + data["alpha"] = _extract_alpha(data) + data["mode"] = _extract_mode(data) + data = data[data["mode"].isin({"robust", "no_robust"})] + data = data[data["alpha"].notna()] + + numeric_cols = [ + "eval/revenue_mean", + "eval/reward_mean", + "eval/coi_level_mean", + "eval/coi_leakage_mean", + "eval/volatility_mean", + "eval/margin_mean", + "train/alpha_adv", + "train/coi_penalty", + "train/ux_penalty", + "train/agent_prob", + ] + _coerce_numeric(data, numeric_cols) + return data.sort_values(["alpha", "mode"]).reset_index(drop=True) + + +def _summary_by_alpha_mode(frame: pd.DataFrame, metrics: list[str]) -> pd.DataFrame: + agg_spec: dict[str, tuple[str, str]] = {"runs": ("mode", "size")} + for metric in metrics: + safe = _sanitize(metric) + agg_spec[f"{safe}_mean"] = (metric, "mean") + agg_spec[f"{safe}_std"] = (metric, "std") + + return ( + frame.groupby(["alpha", "mode"], as_index=False) + .agg(**agg_spec) + .sort_values(["alpha", "mode"]) + .reset_index(drop=True) + ) + + +def _delta_by_alpha(summary: pd.DataFrame, metrics: list[str]) -> pd.DataFrame: + rows: list[dict[str, float]] = [] + for alpha, alpha_group in summary.groupby("alpha", sort=True): + robust = alpha_group[alpha_group["mode"] == "robust"] + no_robust = alpha_group[alpha_group["mode"] == "no_robust"] + if robust.empty or no_robust.empty: + continue + + row: dict[str, float] = { + "alpha": float(alpha), + "runs_robust": float(robust["runs"].iloc[0]), + "runs_no_robust": float(no_robust["runs"].iloc[0]), + } + for metric in metrics: + safe = _sanitize(metric) + robust_value = float(robust[f"{safe}_mean"].iloc[0]) + no_robust_value = float(no_robust[f"{safe}_mean"].iloc[0]) + delta = robust_value - no_robust_value + row[f"{safe}_robust"] = robust_value + row[f"{safe}_no_robust"] = no_robust_value + row[f"{safe}_delta"] = delta + row[f"{safe}_delta_pct"] = ( + np.nan if no_robust_value == 0 else 100.0 * delta / no_robust_value + ) + rows.append(row) + + return pd.DataFrame(rows) + + +def _pairwise_win_rates(frame: pd.DataFrame) -> pd.DataFrame: + rules = { + "eval/revenue_mean": "higher", + "eval/reward_mean": "higher", + "eval/coi_leakage_mean": "lower", + "eval/volatility_mean": "lower", + } + rows: list[dict[str, float]] = [] + for alpha, alpha_group in frame.groupby("alpha", sort=True): + robust = alpha_group[alpha_group["mode"] == "robust"] + no_robust = alpha_group[alpha_group["mode"] == "no_robust"] + if robust.empty or no_robust.empty: + continue + + for metric, direction in rules.items(): + if metric not in frame.columns: + continue + robust_values = robust[metric].dropna().to_numpy(dtype=float) + no_robust_values = no_robust[metric].dropna().to_numpy(dtype=float) + if robust_values.size == 0 or no_robust_values.size == 0: + continue + + if direction == "higher": + wins = (robust_values[:, None] > no_robust_values[None, :]).sum() + else: + wins = (robust_values[:, None] < no_robust_values[None, :]).sum() + ties = (robust_values[:, None] == no_robust_values[None, :]).sum() + total = robust_values.size * no_robust_values.size + win_prob = (wins + 0.5 * ties) / total + rows.append( + { + "alpha": float(alpha), + "metric": metric, + "direction": direction, + "wins": int(wins), + "ties": int(ties), + "total_pairs": int(total), + "win_probability": float(win_prob), + } + ) + return pd.DataFrame(rows) + + +def _overall_mode_summary(frame: pd.DataFrame, metrics: list[str]) -> pd.DataFrame: + agg_spec: dict[str, tuple[str, str]] = {"runs": ("mode", "size")} + for metric in metrics: + safe = _sanitize(metric) + agg_spec[f"{safe}_mean"] = (metric, "mean") + agg_spec[f"{safe}_std"] = (metric, "std") + return frame.groupby("mode", as_index=False).agg(**agg_spec).sort_values("mode") + + +def _headline_json(overall: pd.DataFrame) -> dict[str, float | str]: + if {"robust", "no_robust"} - set(overall["mode"].tolist()): + return {"status": "incomplete_modes"} + + robust = overall[overall["mode"] == "robust"].iloc[0] + no_robust = overall[overall["mode"] == "no_robust"].iloc[0] + + revenue_delta = float( + robust["eval_revenue_mean_mean"] - no_robust["eval_revenue_mean_mean"] + ) + leakage_delta = float( + robust["eval_coi_leakage_mean_mean"] - no_robust["eval_coi_leakage_mean_mean"] + ) + return { + "status": "ok", + "revenue_delta": revenue_delta, + "revenue_delta_pct": float( + 100.0 * revenue_delta / no_robust["eval_revenue_mean_mean"] + ), + "coi_leakage_delta": leakage_delta, + "coi_leakage_delta_pct": float( + 100.0 * leakage_delta / no_robust["eval_coi_leakage_mean_mean"] + ), + } + + +def run(input_path: Path, output_dir: Path, include_non_finished: bool) -> list[Path]: + output_dir.mkdir(parents=True, exist_ok=True) + raw = pd.read_csv(input_path) + frame = _prepare_frame(raw, include_non_finished=include_non_finished) + + metrics = [ + metric + for metric in ( + "eval/revenue_mean", + "eval/reward_mean", + "eval/coi_level_mean", + "eval/coi_leakage_mean", + "eval/volatility_mean", + "eval/margin_mean", + "train/alpha_adv", + "train/coi_penalty", + "train/ux_penalty", + "train/agent_prob", + ) + if metric in frame.columns + ] + + alpha_mode = _summary_by_alpha_mode(frame, metrics) + deltas = _delta_by_alpha(alpha_mode, metrics) + win_rates = _pairwise_win_rates(frame) + overall = _overall_mode_summary(frame, metrics) + headline = _headline_json(overall) + + outputs = { + "ppo_alpha_mode_summary.csv": alpha_mode, + "ppo_alpha_deltas.csv": deltas, + "ppo_pairwise_win_rates.csv": win_rates, + "ppo_overall_mode_summary.csv": overall, + } + written_paths: list[Path] = [] + for filename, table in outputs.items(): + path = output_dir / filename + table.to_csv(path, index=False) + written_paths.append(path) + + headline_path = output_dir / "ppo_headline_summary.json" + headline_path.write_text(json.dumps(headline, indent=2)) + written_paths.append(headline_path) + return written_paths + + +def main() -> None: + parser = argparse.ArgumentParser( + description="Process PPO benchmark CSV for paper tables" + ) + parser.add_argument("--input", type=Path, default=_default_input()) + parser.add_argument("--output-dir", type=Path, default=_default_output_dir()) + parser.add_argument("--include-non-finished", action="store_true") + args = parser.parse_args() + + written = run( + input_path=args.input, + output_dir=args.output_dir, + include_non_finished=bool(args.include_non_finished), + ) + for path in written: + print(path) + + +if __name__ == "__main__": + main() diff --git a/paper/src/chapters/hero_architecture_figure.tex b/paper/src/chapters/hero_architecture_figure.tex new file mode 100644 index 0000000..a706781 --- /dev/null +++ b/paper/src/chapters/hero_architecture_figure.tex @@ -0,0 +1,166 @@ +\definecolor{heroBlue}{RGB}{212, 228, 255} +\definecolor{heroBlueBorder}{RGB}{64, 103, 178} +\definecolor{heroGreen}{RGB}{214, 238, 216} +\definecolor{heroGreenBorder}{RGB}{48, 133, 66} +\definecolor{heroAmber}{RGB}{246, 230, 202} +\definecolor{heroAmberBorder}{RGB}{166, 121, 51} +\definecolor{heroGray}{RGB}{236, 236, 236} +\definecolor{heroGrayBorder}{RGB}{120, 120, 120} + +% Panels occupy y = 2.2 .. 10.0 +% Cross-panel connector gutter lives at y = 1.0 .. 2.2 (clearly below all nodes) +\begin{tikzpicture}[ + >=Stealth, + font=\small, + panel/.style={draw=black!65, dashed, rounded corners=4pt, line width=0.85pt}, + bB/.style={rectangle, rounded corners=3pt, draw=heroBlueBorder, fill=heroBlue, + line width=0.9pt, align=center, minimum height=0.85cm}, + bG/.style={rectangle, rounded corners=3pt, draw=heroGreenBorder, fill=heroGreen, + line width=0.9pt, align=center, minimum height=0.85cm}, + bA/.style={rectangle, rounded corners=3pt, draw=heroAmberBorder, fill=heroAmber, + line width=0.9pt, align=center, minimum height=0.85cm}, + bY/.style={rectangle, rounded corners=3pt, draw=heroGrayBorder, fill=heroGray, + line width=0.9pt, align=center, minimum height=0.82cm}, + pill/.style={ellipse, draw=black!50, fill=black!4, line width=0.75pt, + align=center, minimum width=1.6cm, minimum height=0.68cm}, + arr/.style={->, draw=black!80, line width=0.88pt}, + bidir/.style={<->, draw=black!80, line width=0.88pt}, + darr/.style={->, draw=black!60, line width=0.80pt, densely dashed}, + crossA/.style={->, draw=heroAmberBorder!90!black, line width=1.15pt, dash pattern=on 3.5pt off 2pt}, + crossG/.style={->, draw=heroGreenBorder!90!black, line width=1.15pt, dash pattern=on 3.5pt off 2pt}, + arrG/.style={->, draw=heroGreenBorder!90!black, line width=1.15pt}, + lbl/.style={font=\scriptsize, align=center, fill=white, inner sep=1.5pt, text=black} +] + +%% ============================================================ +%% Panel A x: 0.2–11.2 y: 2.2–10.0 +%% ============================================================ +\draw[panel] (0.2,2.2) rectangle (11.2,10.0); +\node[anchor=west, font=\small\bfseries] at (0.45,9.72) {(a) Online platform and data plane}; + +\node[pill] (human) at (1.3, 8.55) {Human}; +\node[pill] (agent) at (1.3, 7.45) {Agent}; + +\node[bB, minimum width=2.75cm] (web) at (4.2, 8.0) {Next.js\\Web App}; +\node[bB, minimum width=2.75cm] (provider) at (7.35, 8.0) {Pricing\\Provider}; +\node[bY, minimum width=1.85cm] (redis) at (9.85, 8.0) {Redis}; + +\node[bG, minimum width=3.1cm] (kBehav) at (4.0, 6.2) {Kafka stream\\Behavior events}; +\node[bG, minimum width=3.0cm] (kQuotes) at (7.5, 6.2) {Kafka stream\\Price quotes}; + +\node[bA, minimum width=3.1cm] (worker) at (4.0, 4.4) {Worker / ETL\\Feature jobs}; +\node[bA, minimum width=2.65cm] (registry) at (8.45, 4.4) {Model\\Registry}; + +% service row +\draw[arr] (human.east) -- (web.west); +\draw[arr] (agent.east) -- (web.west); +\draw[arr] (web.east) -- (provider.west); +\draw[bidir] (provider.east) -- (redis.west); + +% web/provider -> kafka +\draw[arr] (web.south) -- (kBehav.north) + node[midway, left, lbl] {$e=(a,i,t,\mu,\delta)$}; +\draw[arr] (provider.south) -- (kQuotes.north) + node[midway, right, lbl] {$(i,p,\mathrm{sid},\phi,t)$}; + +% kafka -> worker (straight south) +\draw[arr] (kBehav.south) -- (worker.north); +\draw[arr] (kQuotes.south) -- (worker.north); + +% worker -> registry +\draw[arr] (worker.east) -- (registry.west); + +% model refresh: registry east -> goes right to x=11.0, north to y=9.2, left to provider +% this keeps it entirely inside panel A with no crossing of nodes +\draw[crossA, rounded corners=6pt] + (registry.east) -- (11.0, 4.4) + -- (11.0, 9.2) + -- node[midway, lbl] {model refresh} (provider.north |- 0, 9.2) + -- (provider.north); + +%% ============================================================ +%% Panel B x: 11.6–20.4 y: 2.2–10.0 +%% ============================================================ +\draw[panel] (11.6,2.2) rectangle (19.8,10.0); +\node[anchor=west, font=\small\bfseries] at (11.85,9.72) {(b) Distinguishability layer}; + +\node[bG, minimum width=2.4cm] (session) at (14.0, 8.9) {Session prefix\\$\tau'$}; +\node[bB, minimum width=2.4cm] (empKern) at (13.65,7.45) {Empirical kernel\\$\hat T'$}; +\node[bY, minimum width=2.4cm] (weakLab) at (17.55,8.9) {Weak labels\\$\mathcal{D}_H,\mathcal{D}_A$}; +\node[bY, minimum width=2.2cm] (protoH) at (12.8, 5.9) {Prototype\\$\bar T_H$}; +\node[bA, minimum width=2.4cm] (kldist) at (15.55,5.9) {KL distances\\$\Delta_H,\Delta_A$}; +\node[bY, minimum width=2.2cm] (protoA) at (18.3, 5.9) {Prototype\\$\bar T_A$}; +\node[bB, minimum width=2.9cm] (calHead) at (13.55,4.25) {Contrastive\\calibration head}; +\node[bG, minimum width=2.55cm] (score) at (17.75,4.25) {Session score\\$f(\tau'),\hat\alpha(\tau')$}; + +\node[lbl] at (15.55, 3.15) {$\hat\alpha(\tau')=\sigma\!\left(\beta(\Delta_H-\Delta_A)\right)$}; + +\draw[arr, rounded corners=4pt] (session.south) -- (empKern.north); +\draw[arr, rounded corners=4pt] (empKern.south) -- (13.65, 6.8) -| (protoH.north); +\draw[arr, rounded corners=4pt] (weakLab.south) -- (17.55, 6.8) -| (protoA.north); +% weak labels -> protoH: go south then hard-left below weakLab +\draw[arr, rounded corners=4pt] (weakLab.south) -- (17.55,6.8) -| (protoH.north east); +\draw[arr] (protoH.east) -- (kldist.west); +\draw[arr] (protoA.west) -- (kldist.east); +\draw[arr] (kldist.south) -- (calHead.north east); +\draw[arr] (calHead.east) -- (score.west); + +%% ============================================================ +%% Panel C x: 20.8–31.0 y: 2.2–10.0 +%% ============================================================ +\draw[panel] (20.8,2.2) rectangle (31.0,10.0); +\node[anchor=west, font=\small\bfseries] at (21.05,9.72) {(c) Distributionally robust control}; + +\node[bB, minimum width=3.1cm] (state) at (23.15, 8.9) + {State summary\\$[p_{t-1},\hat q_{t-1},f(\tau')]$}; +\node[bY, minimum width=2.9cm] (ambSet) at (23.15, 7.45) {Ambiguity set\\$\mathcal U_\epsilon(\hat P_N)$}; +\node[bG, minimum width=2.9cm] (innerMin) at (28.55, 7.45) {Inner minimisation\\$\min_{Q\in\mathcal U_\epsilon}$}; +\node[bY, minimum width=8.2cm] (contScen) at (25.9, 5.9) + {Contamination scenarios $\;\alpha_k\in\mathcal A_{\epsilon_\alpha}(\alpha_0)$}; +\node[bA, minimum width=8.8cm] (reward) at (25.9, 4.45) + {$r_t = R(p_t,\hat q_t) - \lambda\,\mathrm{COI}_{\mathrm{leak}}(p_t,\tau_t') - \eta\,UX_t$}; +\node[bB, minimum width=2.85cm] (policy) at (22.75, 3.05) {Robust policy $\pi^*$}; +\node[bG, minimum width=2.85cm] (publish) at (29.05, 3.05) {Publish price\\vector $p_t$}; + +\node[lbl] at (25.9, 2.55) {$\pi^*=\arg\max_\pi\min_{Q\in\mathcal U_\epsilon}\mathbb{E}[r_t]$}; + +\draw[arr] (state.south) -- (ambSet.north); +\draw[arr] (ambSet.east) -- (innerMin.west); +\draw[arr, rounded corners=4pt] (ambSet.south) -- (23.15, 6.6) -| ([xshift=-2cm]contScen.north); +\draw[arr, rounded corners=4pt] (innerMin.south) -- (28.55, 6.6) -| ([xshift=2cm]contScen.north); +\draw[arr] (contScen.south) -- (reward.north); +\draw[arr, rounded corners=6pt] (reward.south) -- (25.9, 3.7) -| (policy.north); +\draw[arr] (policy.east) -- (publish.west); +% market response: up the right edge of panel C, entirely inside, rounded +\draw[arrG, rounded corners=6pt] (publish.east) -- (30.6, 3.05) + -- (30.6, 9.8) + -- node[midway, lbl] {market response} (state.north |- 0, 9.8) + -- (state.north); + +%% ============================================================ +%% Cross-panel connectors – gutter at y = 1.0..2.2 +%% Three separate depths: 1.85, 1.45, 1.05 (no overlaps) +%% ============================================================ + +% 1. Worker -> Session (depth y=1.85, shallowest) +\draw[crossA, rounded corners=6pt] + (worker.south) -- (worker.south |- 0, 1.85) + -- node[pos=0.5, lbl] {offline extraction} (11.4, 1.85) + -- (11.4, 8.9) + -- (session.west); + +% 2. Score -> State (depth y=1.45) +\draw[crossG, rounded corners=6pt] + (score.south) -- (score.south |- 0, 1.45) + -- node[pos=0.5, lbl] {contamination signal} (20.6, 1.45) + -- (20.6, 8.9) + -- (state.west); + +% 3. Publish -> Provider (depth y=1.05, deepest) +\draw[crossG, rounded corners=3pt] + (publish.south) -- (publish.south |- 0, 1.05) + -- node[pos=0.4, lbl] {serve online} (5.8, 1.05) + -- (5.8, 7.7) + -- ([yshift=-0.3cm]provider.west); + +\end{tikzpicture} diff --git a/paper/src/preamble.tex b/paper/src/preamble.tex index d8f9876..9b680c1 100644 --- a/paper/src/preamble.tex +++ b/paper/src/preamble.tex @@ -40,7 +40,7 @@ % Configure cleveref for algorithm2e \crefname{algocf}{Algorithm}{Algorithms} -\usetikzlibrary{positioning, shapes, arrows.meta, fit, backgrounds} +\usetikzlibrary{positioning, shapes, arrows.meta, fit, backgrounds, calc} \lstset{ basicstyle=\ttfamily\footnotesize, breaklines=true,