Files
PHANTOM/paper/src/chapters/hero_architecture_figure.tex

167 lines
8.3 KiB
TeX
Raw Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

\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.211.2 y: 2.210.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.620.4 y: 2.210.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.831.0 y: 2.210.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}