mirror of
https://github.com/velocitatem/PHANTOM.git
synced 2026-05-31 08:33:36 +00:00
preparing defense content pushing
This commit is contained in:
6
Makefile
6
Makefile
@@ -44,7 +44,7 @@ SWEEP_ENV_LOAD = set -a; [ -f "$(SWEEP_ENV_FILE)" ] && . "$(SWEEP_ENV_FILE)" ||
|
|||||||
|
|
||||||
.PHONY: help
|
.PHONY: help
|
||||||
help:
|
help:
|
||||||
@echo "pdf.build pdf.watch pdf.clean pdf.genpop pdf.genpop.watch pdf.summary pdf.summary.watch pdf.arxiv | test.backend test.e2e test.all | web.dev | install | train | benchmark | benchmark.simple | benchmark.agent | train.agent | train.bootstrap | stats.lines | docs.platform | manim.defense manim.defense.hq manim.render manim.render.full manim.render.poster manim.render.appendix manim.render.all"
|
@echo "pdf.build pdf.watch pdf.clean pdf.genpop pdf.genpop.watch pdf.summary pdf.summary.watch pdf.arxiv pdf.defense | test.backend test.e2e test.all | web.dev | install | train | benchmark | benchmark.simple | benchmark.agent | train.agent | train.bootstrap | stats.lines | docs.platform | manim.defense manim.defense.hq manim.render manim.render.full manim.render.poster manim.render.appendix manim.render.all"
|
||||||
@echo "backend.server backend.provider backend.worker | platform.up platform.down platform.logs | docker.train.publish"
|
@echo "backend.server backend.provider backend.worker | platform.up platform.down platform.logs | docker.train.publish"
|
||||||
@echo "data.pull data.push data.whoclicked.publish | study.margin-erosion study.margin-erosion.quick study.margin-erosion.plot"
|
@echo "data.pull data.push data.whoclicked.publish | study.margin-erosion study.margin-erosion.quick study.margin-erosion.plot"
|
||||||
@echo "tpu.ray.bootstrap tpu.ray.deps tpu.ray.verify tpu.ray.teardown"
|
@echo "tpu.ray.bootstrap tpu.ray.deps tpu.ray.verify tpu.ray.teardown"
|
||||||
@@ -110,6 +110,10 @@ pdf.summary:
|
|||||||
pdf.summary.watch:
|
pdf.summary.watch:
|
||||||
@bash scripts/nx_paper.sh watch-summary
|
@bash scripts/nx_paper.sh watch-summary
|
||||||
|
|
||||||
|
.PHONY: pdf.defense
|
||||||
|
pdf.defense:
|
||||||
|
@cd paper/defense && pdflatex -interaction=nonstopmode defense.tex && pdflatex -interaction=nonstopmode defense.tex
|
||||||
|
|
||||||
.PHONY: test.backend
|
.PHONY: test.backend
|
||||||
test.backend:
|
test.backend:
|
||||||
@$(NX) run research:test
|
@$(NX) run research:test
|
||||||
|
|||||||
51
paper/defense/NARRATIVE.md
Normal file
51
paper/defense/NARRATIVE.md
Normal file
@@ -0,0 +1,51 @@
|
|||||||
|
---
|
||||||
|
present_time: 15 minutes
|
||||||
|
qa: 15 minutes
|
||||||
|
---
|
||||||
|
|
||||||
|
> Notes for presentation deck: keep minimal text, highlight only key metrics or keywords and diagrams, if possible do progressive reveal of items on slides, if going through a list, make each appear progressively on new slides like an animation.
|
||||||
|
|
||||||
|
# Introduction [2min]
|
||||||
|
> Hook: Extracting margin in markets with high density of AI agents.
|
||||||
|
- Say what today's agenda is (show in the blocks at the botton of each slide and with each slide indicate which stage we are at)
|
||||||
|
- Highlight problem (add financial consequence)
|
||||||
|
- What are we trying to answer?
|
||||||
|
|
||||||
|
# First Stage (Platform Development) [4min]
|
||||||
|
- Talk about designing the platform (nextjs design and apache airflow and kafka)
|
||||||
|
|
||||||
|
## About the Platform
|
||||||
|
- Show an architecture diagram.
|
||||||
|
|
||||||
|
## Dataset Brief
|
||||||
|
- Screenshot of the HF dataset and highlight some key features of the dataset with big numbers indicated.
|
||||||
|
|
||||||
|
## Experimental Design
|
||||||
|
- Say how we collected data and how we used AI Agents
|
||||||
|
|
||||||
|
### AI Agents
|
||||||
|
- browser use
|
||||||
|
- models used (say we used the LLM router for different models)
|
||||||
|
|
||||||
|
# Second Stage (Distinguishability Construction) [4min]
|
||||||
|
- Explain kernels of behavior (what is a kernel)
|
||||||
|
- How we separate kernels and finally how we turn that into a probability.
|
||||||
|
|
||||||
|
# DR-RL [4min]
|
||||||
|
- Explain simple wesserstein balls and ambiguity
|
||||||
|
- Highlight computational complexity
|
||||||
|
|
||||||
|
## Results [1min]
|
||||||
|
- Empirical results from experiments
|
||||||
|
|
||||||
|
# Conclusions
|
||||||
|
- Consequences of our work (financial and future implications for pricing systems)
|
||||||
|
- Did we answer what we wanted? How?
|
||||||
|
|
||||||
|
# Appendix
|
||||||
|
|
||||||
|
## Derivation of the COI theorem
|
||||||
|
## Reward Structure Composition
|
||||||
|
## On our Sample Size
|
||||||
|
|
||||||
|
|
||||||
125
paper/defense/defense.nav
Normal file
125
paper/defense/defense.nav
Normal file
@@ -0,0 +1,125 @@
|
|||||||
|
\headcommand {\slideentry {0}{0}{1}{1/1}{}{0}}
|
||||||
|
\headcommand {\beamer@framepages {1}{1}}
|
||||||
|
\headcommand {\slideentry {0}{0}{2}{2/2}{}{0}}
|
||||||
|
\headcommand {\beamer@framepages {2}{2}}
|
||||||
|
\headcommand {\slideentry {0}{0}{3}{3/3}{}{0}}
|
||||||
|
\headcommand {\beamer@framepages {3}{3}}
|
||||||
|
\headcommand {\slideentry {0}{0}{4}{4/6}{}{0}}
|
||||||
|
\headcommand {\beamer@framepages {4}{6}}
|
||||||
|
\headcommand {\beamer@sectionpages {1}{6}}
|
||||||
|
\headcommand {\beamer@subsectionpages {1}{6}}
|
||||||
|
\headcommand {\sectionentry {1}{Platform Development}{7}{Platform Development}{0}}
|
||||||
|
\headcommand {\slideentry {1}{0}{1}{7/8}{}{0}}
|
||||||
|
\headcommand {\beamer@framepages {7}{8}}
|
||||||
|
\headcommand {\slideentry {1}{0}{2}{9/9}{}{0}}
|
||||||
|
\headcommand {\beamer@framepages {9}{9}}
|
||||||
|
\headcommand {\slideentry {1}{0}{3}{10/12}{}{0}}
|
||||||
|
\headcommand {\beamer@framepages {10}{12}}
|
||||||
|
\headcommand {\beamer@sectionpages {7}{12}}
|
||||||
|
\headcommand {\beamer@subsectionpages {7}{12}}
|
||||||
|
\headcommand {\sectionentry {2}{Distinguishability Construction}{13}{Distinguishability Construction}{0}}
|
||||||
|
\headcommand {\slideentry {2}{0}{1}{13/14}{}{0}}
|
||||||
|
\headcommand {\beamer@framepages {13}{14}}
|
||||||
|
\headcommand {\slideentry {2}{0}{2}{15/15}{}{0}}
|
||||||
|
\headcommand {\beamer@framepages {15}{15}}
|
||||||
|
\headcommand {\slideentry {2}{0}{3}{16/17}{}{0}}
|
||||||
|
\headcommand {\beamer@framepages {16}{17}}
|
||||||
|
\headcommand {\beamer@sectionpages {13}{17}}
|
||||||
|
\headcommand {\beamer@subsectionpages {13}{17}}
|
||||||
|
\headcommand {\sectionentry {3}{Distributionally Robust RL}{18}{Distributionally Robust RL}{0}}
|
||||||
|
\headcommand {\slideentry {3}{0}{1}{18/18}{}{0}}
|
||||||
|
\headcommand {\beamer@framepages {18}{18}}
|
||||||
|
\headcommand {\slideentry {3}{0}{2}{19/20}{}{0}}
|
||||||
|
\headcommand {\beamer@framepages {19}{20}}
|
||||||
|
\headcommand {\slideentry {3}{0}{3}{21/22}{}{0}}
|
||||||
|
\headcommand {\beamer@framepages {21}{22}}
|
||||||
|
\headcommand {\beamer@sectionpages {18}{22}}
|
||||||
|
\headcommand {\beamer@subsectionpages {18}{22}}
|
||||||
|
\headcommand {\sectionentry {4}{Results}{23}{Results}{0}}
|
||||||
|
\headcommand {\slideentry {4}{0}{1}{23/23}{}{0}}
|
||||||
|
\headcommand {\beamer@framepages {23}{23}}
|
||||||
|
\headcommand {\beamer@sectionpages {23}{23}}
|
||||||
|
\headcommand {\beamer@subsectionpages {23}{23}}
|
||||||
|
\headcommand {\sectionentry {5}{Conclusions}{24}{Conclusions}{0}}
|
||||||
|
\headcommand {\slideentry {5}{0}{1}{24/24}{}{0}}
|
||||||
|
\headcommand {\beamer@framepages {24}{24}}
|
||||||
|
\headcommand {\slideentry {5}{0}{2}{25/28}{}{0}}
|
||||||
|
\headcommand {\beamer@framepages {25}{28}}
|
||||||
|
\headcommand {\slideentry {5}{0}{3}{29/29}{}{0}}
|
||||||
|
\headcommand {\beamer@framepages {29}{29}}
|
||||||
|
\headcommand {\gdef \insertmainframenumber {17}}
|
||||||
|
\headcommand {\partentry {\translate {Appendix}}{1}}
|
||||||
|
\headcommand {\beamer@partpages {1}{29}}
|
||||||
|
\headcommand {\beamer@sectionpages {24}{29}}
|
||||||
|
\headcommand {\beamer@subsectionpages {24}{29}}
|
||||||
|
\headcommand {\beamer@appendixpages {30}}
|
||||||
|
\headcommand {\beamer@sectionpages {30}{29}}
|
||||||
|
\headcommand {\beamer@subsectionpages {30}{29}}
|
||||||
|
\headcommand {\sectionentry {6}{Appendix}{30}{Appendix}{1}}
|
||||||
|
\headcommand {\slideentry {6}{0}{1}{30/30}{}{1}}
|
||||||
|
\headcommand {\beamer@framepages {30}{30}}
|
||||||
|
\headcommand {\slideentry {6}{0}{2}{31/31}{}{1}}
|
||||||
|
\headcommand {\beamer@framepages {31}{31}}
|
||||||
|
\headcommand {\slideentry {6}{0}{3}{32/32}{}{1}}
|
||||||
|
\headcommand {\beamer@framepages {32}{32}}
|
||||||
|
\headcommand {\slideentry {6}{0}{4}{33/33}{}{1}}
|
||||||
|
\headcommand {\beamer@framepages {33}{33}}
|
||||||
|
\headcommand {\slideentry {6}{0}{5}{34/34}{}{1}}
|
||||||
|
\headcommand {\beamer@framepages {34}{34}}
|
||||||
|
\headcommand {\slideentry {6}{0}{6}{35/35}{}{1}}
|
||||||
|
\headcommand {\beamer@framepages {35}{35}}
|
||||||
|
\headcommand {\slideentry {6}{0}{7}{36/36}{}{1}}
|
||||||
|
\headcommand {\beamer@framepages {36}{36}}
|
||||||
|
\headcommand {\slideentry {6}{0}{8}{37/37}{}{1}}
|
||||||
|
\headcommand {\beamer@framepages {37}{37}}
|
||||||
|
\headcommand {\slideentry {6}{0}{9}{38/38}{}{1}}
|
||||||
|
\headcommand {\beamer@framepages {38}{38}}
|
||||||
|
\headcommand {\slideentry {6}{0}{10}{39/39}{}{1}}
|
||||||
|
\headcommand {\beamer@framepages {39}{39}}
|
||||||
|
\headcommand {\slideentry {6}{0}{11}{40/40}{}{1}}
|
||||||
|
\headcommand {\beamer@framepages {40}{40}}
|
||||||
|
\headcommand {\slideentry {6}{0}{12}{41/41}{}{1}}
|
||||||
|
\headcommand {\beamer@framepages {41}{41}}
|
||||||
|
\headcommand {\slideentry {6}{0}{13}{42/42}{}{1}}
|
||||||
|
\headcommand {\beamer@framepages {42}{42}}
|
||||||
|
\headcommand {\slideentry {6}{0}{14}{43/43}{}{1}}
|
||||||
|
\headcommand {\beamer@framepages {43}{43}}
|
||||||
|
\headcommand {\slideentry {6}{0}{15}{44/44}{}{1}}
|
||||||
|
\headcommand {\beamer@framepages {44}{44}}
|
||||||
|
\headcommand {\slideentry {6}{0}{16}{45/45}{}{1}}
|
||||||
|
\headcommand {\beamer@framepages {45}{45}}
|
||||||
|
\headcommand {\slideentry {6}{0}{17}{46/46}{}{1}}
|
||||||
|
\headcommand {\beamer@framepages {46}{46}}
|
||||||
|
\headcommand {\slideentry {6}{0}{18}{47/47}{}{1}}
|
||||||
|
\headcommand {\beamer@framepages {47}{47}}
|
||||||
|
\headcommand {\slideentry {6}{0}{19}{48/48}{}{1}}
|
||||||
|
\headcommand {\beamer@framepages {48}{48}}
|
||||||
|
\headcommand {\slideentry {6}{0}{20}{49/49}{}{1}}
|
||||||
|
\headcommand {\beamer@framepages {49}{49}}
|
||||||
|
\headcommand {\slideentry {6}{0}{21}{50/50}{}{1}}
|
||||||
|
\headcommand {\beamer@framepages {50}{50}}
|
||||||
|
\headcommand {\slideentry {6}{0}{22}{51/51}{}{1}}
|
||||||
|
\headcommand {\beamer@framepages {51}{51}}
|
||||||
|
\headcommand {\slideentry {6}{0}{23}{52/52}{}{1}}
|
||||||
|
\headcommand {\beamer@framepages {52}{52}}
|
||||||
|
\headcommand {\slideentry {6}{0}{24}{53/53}{}{1}}
|
||||||
|
\headcommand {\beamer@framepages {53}{53}}
|
||||||
|
\headcommand {\slideentry {6}{0}{25}{54/54}{}{1}}
|
||||||
|
\headcommand {\beamer@framepages {54}{54}}
|
||||||
|
\headcommand {\slideentry {6}{0}{26}{55/55}{}{1}}
|
||||||
|
\headcommand {\beamer@framepages {55}{55}}
|
||||||
|
\headcommand {\slideentry {6}{0}{27}{56/56}{}{1}}
|
||||||
|
\headcommand {\beamer@framepages {56}{56}}
|
||||||
|
\headcommand {\slideentry {6}{0}{28}{57/57}{}{1}}
|
||||||
|
\headcommand {\beamer@framepages {57}{57}}
|
||||||
|
\headcommand {\slideentry {6}{0}{29}{58/58}{}{1}}
|
||||||
|
\headcommand {\beamer@framepages {58}{58}}
|
||||||
|
\headcommand {\slideentry {6}{0}{30}{59/59}{}{1}}
|
||||||
|
\headcommand {\beamer@framepages {59}{59}}
|
||||||
|
\headcommand {\beamer@partpages {30}{59}}
|
||||||
|
\headcommand {\beamer@subsectionpages {30}{59}}
|
||||||
|
\headcommand {\beamer@sectionpages {30}{59}}
|
||||||
|
\headcommand {\beamer@documentpages {59}}
|
||||||
|
\headcommand {\gdef \inserttotalframenumber {30}}
|
||||||
|
\headcommand {\gdef \inserttotalframenumber {17}}
|
||||||
|
\headcommand {\gdef \appendixtotalframenumber {30}}
|
||||||
BIN
paper/defense/defense.pdf
Normal file
BIN
paper/defense/defense.pdf
Normal file
Binary file not shown.
0
paper/defense/defense.snm
Normal file
0
paper/defense/defense.snm
Normal file
559
paper/defense/defense.tex
Normal file
559
paper/defense/defense.tex
Normal file
@@ -0,0 +1,559 @@
|
|||||||
|
% Final thesis defense (PHANTOM)
|
||||||
|
% Build: cd paper/defense && pdflatex defense.tex && pdflatex defense.tex
|
||||||
|
\documentclass[aspectratio=169,11pt]{beamer}
|
||||||
|
|
||||||
|
\usepackage[utf8]{inputenc}
|
||||||
|
\usepackage[T1]{fontenc}
|
||||||
|
\usepackage{lmodern}
|
||||||
|
\usepackage{microtype}
|
||||||
|
\usepackage{amsmath,amssymb}
|
||||||
|
\usepackage{graphicx}
|
||||||
|
\usepackage{booktabs}
|
||||||
|
\usepackage{appendixnumberbeamer}
|
||||||
|
\usepackage{hyperref}
|
||||||
|
\usepackage{tikz}
|
||||||
|
\usetikzlibrary{arrows.meta,calc,positioning,fit,shapes.geometric,shapes.misc}
|
||||||
|
|
||||||
|
\graphicspath{{../src/chapters/figures/results/generated/final/plots/}{../src/chapters/}}
|
||||||
|
|
||||||
|
\usetheme[
|
||||||
|
progressbar=frametitle,
|
||||||
|
]{moloch}
|
||||||
|
\molochset{sectionpage=none,subsectionpage=none}
|
||||||
|
\usefonttheme{professionalfonts}
|
||||||
|
\setbeamertemplate{frame numbering}[fraction]
|
||||||
|
|
||||||
|
% Palette
|
||||||
|
\definecolor{PhantomPaper}{HTML}{F6F1E9}
|
||||||
|
\definecolor{PhantomInk}{HTML}{0F1B2D}
|
||||||
|
\definecolor{PhantomSlate}{HTML}{24364C}
|
||||||
|
\definecolor{PhantomCyan}{HTML}{C97A3D}
|
||||||
|
\definecolor{PhantomIndigo}{HTML}{2F8F8A}
|
||||||
|
|
||||||
|
\setbeamercolor{normal text}{fg=PhantomSlate,bg=PhantomPaper}
|
||||||
|
\setbeamercolor{alerted text}{fg=PhantomCyan!95!black}
|
||||||
|
\setbeamercolor{example text}{fg=PhantomIndigo!95!black}
|
||||||
|
\setbeamercolor{palette primary}{fg=white,bg=PhantomInk}
|
||||||
|
\setbeamercolor{frametitle}{parent=palette primary}
|
||||||
|
\setbeamercolor{progress bar}{fg=PhantomCyan,bg=PhantomInk!28!white}
|
||||||
|
\setbeamercolor{title separator}{use=progress bar,parent=progress bar}
|
||||||
|
\setbeamercolor{structure}{fg=PhantomIndigo!90!black}
|
||||||
|
\setbeamercolor{block title}{fg=white,bg=PhantomIndigo!85!black}
|
||||||
|
\setbeamercolor{block body}{fg=PhantomSlate,bg=PhantomIndigo!8!white}
|
||||||
|
\setbeamercolor{alertblock title}{fg=white,bg=PhantomCyan!92!black}
|
||||||
|
\setbeamercolor{alertblock body}{fg=PhantomSlate,bg=PhantomCyan!10!white}
|
||||||
|
\setbeamercolor{exampleblock title}{fg=white,bg=PhantomIndigo!70!black}
|
||||||
|
\setbeamercolor{exampleblock body}{fg=PhantomSlate,bg=PhantomIndigo!8!white}
|
||||||
|
|
||||||
|
\setbeamertemplate{navigation symbols}{}
|
||||||
|
\setbeamertemplate{itemize item}{\small\raise0.3ex\hbox{$\bullet$}}
|
||||||
|
\setbeamertemplate{itemize subitem}{\tiny\raise0.2ex\hbox{$\circ$}}
|
||||||
|
|
||||||
|
\hypersetup{colorlinks=true,urlcolor=PhantomIndigo!90!black,linkcolor=PhantomSlate}
|
||||||
|
|
||||||
|
\title{PHANTOM}
|
||||||
|
\subtitle{Pricing Heuristics Against Non-human Transaction Orchestration Mechanisms}
|
||||||
|
\author{Daniel Rösel}
|
||||||
|
\institute{IE University, Madrid \\ Supervisor: Alberto Martín Izquierdo}
|
||||||
|
\date{\today}
|
||||||
|
|
||||||
|
\titlegraphic{%
|
||||||
|
\begin{tikzpicture}
|
||||||
|
\shade[left color=PhantomCyan,right color=PhantomIndigo] (0,0) rectangle (0.55\paperwidth,0.06);
|
||||||
|
\end{tikzpicture}%
|
||||||
|
}
|
||||||
|
|
||||||
|
\newcommand{\stagebar}[1]{}
|
||||||
|
|
||||||
|
\newcommand{\metriccard}[2]{%
|
||||||
|
\begin{tikzpicture}
|
||||||
|
\node[
|
||||||
|
draw=PhantomInk,
|
||||||
|
rounded corners=3pt,
|
||||||
|
fill=PhantomCyan!10,
|
||||||
|
minimum width=3.05cm,
|
||||||
|
minimum height=1.25cm,
|
||||||
|
align=center
|
||||||
|
] {\Large\bfseries #1\\[-0.2em]{\scriptsize #2}};
|
||||||
|
\end{tikzpicture}%
|
||||||
|
}
|
||||||
|
|
||||||
|
\begin{document}
|
||||||
|
|
||||||
|
{
|
||||||
|
\setbeamercolor{background canvas}{bg=PhantomInk}
|
||||||
|
\begin{frame}[plain]
|
||||||
|
\vfill
|
||||||
|
\centering
|
||||||
|
{\color{white}\Huge\bfseries PHANTOM\par}
|
||||||
|
\vspace{0.6em}
|
||||||
|
{\color{PhantomCyan}\rule{0.45\paperwidth}{0.06cm}\par}
|
||||||
|
\vspace{0.8em}
|
||||||
|
{\large\color{white!90!black}Pricing heuristics against non-human transaction orchestration\par}
|
||||||
|
\vfill
|
||||||
|
{\color{white!75!black}\normalsize Daniel Rösel\par}
|
||||||
|
{\color{white!65!black}\small IE University \textbullet\ Supervisor: Alberto Martín Izquierdo\par}
|
||||||
|
\vspace{1.2em}
|
||||||
|
{\footnotesize\color{PhantomCyan!80!white}\href{https://velocitatem.github.io/PHANTOM/}{\texttt{velocitatem.github.io/PHANTOM}}}
|
||||||
|
\vfill
|
||||||
|
\end{frame}
|
||||||
|
}
|
||||||
|
|
||||||
|
\begin{frame}{Roadmap: one argument in six stages (15 min)}
|
||||||
|
\centering
|
||||||
|
\begin{tikzpicture}[
|
||||||
|
font=\scriptsize\sffamily,
|
||||||
|
stage/.style={draw=PhantomInk,rounded corners=3pt,fill=PhantomCyan!10,minimum width=1.95cm,minimum height=1.05cm,align=center},
|
||||||
|
flow/.style={-{Stealth[length=2.0mm,width=1.8mm]},line width=1pt,PhantomSlate}
|
||||||
|
]
|
||||||
|
\node[stage,fill=PhantomCyan!14] (intro) {Intro\\2m};
|
||||||
|
\node[stage,right=0.30cm of intro] (platform) {Platform\\4m};
|
||||||
|
\node[stage,right=0.30cm of platform] (signal) {Signal\\4m};
|
||||||
|
\node[stage,right=0.30cm of signal] (drrl) {DR-RL\\4m};
|
||||||
|
\node[stage,right=0.30cm of drrl] (results) {Results\\1m};
|
||||||
|
\node[stage,right=0.30cm of results] (close) {Close};
|
||||||
|
|
||||||
|
\draw[flow,shorten <=2pt,shorten >=2pt] (intro.east) -- (platform.west);
|
||||||
|
\draw[flow,shorten <=2pt,shorten >=2pt] (platform.east) -- (signal.west);
|
||||||
|
\draw[flow,shorten <=2pt,shorten >=2pt] (signal.east) -- (drrl.west);
|
||||||
|
\draw[flow,shorten <=2pt,shorten >=2pt] (drrl.east) -- (results.west);
|
||||||
|
\draw[flow,shorten <=2pt,shorten >=2pt] (results.east) -- (close.west);
|
||||||
|
\end{tikzpicture}
|
||||||
|
|
||||||
|
\vspace{0.75em}
|
||||||
|
\begin{block}{Main research question}
|
||||||
|
How can dynamic pricing preserve margin integrity when transactions are increasingly mediated by non-human agents?
|
||||||
|
\end{block}
|
||||||
|
\stagebar{1}
|
||||||
|
\end{frame}
|
||||||
|
|
||||||
|
\begin{frame}{Agentic recon creates direct financial pressure on pricing power}
|
||||||
|
\centering
|
||||||
|
\begin{tikzpicture}[
|
||||||
|
font=\small\sffamily,
|
||||||
|
flow/.style={draw=PhantomInk,rounded corners=6pt,minimum width=5.3cm,minimum height=1.25cm,align=center},
|
||||||
|
note/.style={draw=PhantomInk!55,rounded corners=4pt,minimum width=11.2cm,minimum height=0.95cm,align=center,fill=white,font=\scriptsize}
|
||||||
|
]
|
||||||
|
\node[flow,fill=PhantomCyan!18] (recon) at (-3.1,1.1)
|
||||||
|
{\textbf{Recon session}\\samples multiple quotes};
|
||||||
|
\node[flow,fill=PhantomIndigo!16] (buy) at (3.1,1.1)
|
||||||
|
{\textbf{Clean execution session}\\buys using the best found quote};
|
||||||
|
\draw[-{Stealth[length=3mm]},ultra thick,PhantomSlate] (recon.east) -- (buy.west);
|
||||||
|
\node[font=\scriptsize\bfseries,text=PhantomSlate] at (0,1.98)
|
||||||
|
{query and purchase are decoupled};
|
||||||
|
\draw[densely dashed,thick,PhantomCyan!90!black]
|
||||||
|
(recon.south east) .. controls +(1.15,-0.95) and +(-1.15,-0.95) .. (buy.south west);
|
||||||
|
\node[note] at (0,-0.65)
|
||||||
|
{The platform sees behavior proxy $\hat q$, while true demand response $d(p\mid\theta)$ stays latent.};
|
||||||
|
\end{tikzpicture}
|
||||||
|
|
||||||
|
\vspace{0.25em}
|
||||||
|
\begin{tikzpicture}[font=\scriptsize\sffamily,
|
||||||
|
card/.style={draw=PhantomInk,rounded corners=4pt,minimum width=3.85cm,text width=3.55cm,minimum height=1.4cm,align=center}]
|
||||||
|
\node[card,fill=PhantomInk,text=white] at (-4.05,0)
|
||||||
|
{\large$\mathrm{COI}(\pi)=\mathbb{E}[P]-\underline p$\\[-0.05em]\footnotesize pricing power KPI};
|
||||||
|
\node[card,fill=PhantomCyan!16,text=PhantomSlate] at (0,0)
|
||||||
|
{\Large\bfseries$-9{,}014$\\[-0.05em]\footnotesize revenue units\\per +0.1 contamination};
|
||||||
|
\node[card,fill=PhantomIndigo!12,text=PhantomSlate] at (4.05,0)
|
||||||
|
{\large$\lim_{N\to\infty}\mathrm{COI}=0$\\[-0.05em]\footnotesize theorem-level pressure};
|
||||||
|
\end{tikzpicture}
|
||||||
|
|
||||||
|
\vspace{0.15em}
|
||||||
|
{\footnotesize\textbf{Implication:} if quote discovery and purchase split, standard session-based pricing overestimates willingness to pay.}
|
||||||
|
\stagebar{1}
|
||||||
|
\end{frame}
|
||||||
|
|
||||||
|
\begin{frame}{The thesis answers one chain: mechanism \(\to\) signal \(\to\) control}
|
||||||
|
\begin{enumerate}[<+->]\setlength{\itemsep}{0.45em}
|
||||||
|
\item \textbf{Mechanism (SQ2):} independent reconnaissance pushes realizable price toward the order-statistics floor.
|
||||||
|
\item \textbf{Signal (SQ1):} human and agent sessions are behaviorally separable from trajectories alone.
|
||||||
|
\item \textbf{Control (SQ3):} the session score feeds a robust pricing learner under contamination uncertainty.
|
||||||
|
\end{enumerate}
|
||||||
|
|
||||||
|
\vspace{0.35em}
|
||||||
|
\stagebar{1}
|
||||||
|
\end{frame}
|
||||||
|
|
||||||
|
\section{Platform Development}
|
||||||
|
|
||||||
|
\begin{frame}{Stage 1: We built a dual-loop platform to observe behavior and price exposure together}
|
||||||
|
\centering
|
||||||
|
\begin{tikzpicture}[
|
||||||
|
font=\scriptsize\sffamily,
|
||||||
|
box/.style={draw=PhantomInk,rounded corners=3pt,minimum width=2.5cm,minimum height=0.9cm,align=center},
|
||||||
|
arr/.style={-{Stealth[length=2.2mm]},thick,PhantomSlate}
|
||||||
|
]
|
||||||
|
\node[box,fill=PhantomCyan!14] (actors) at (0,1.45) {Humans + Agents};
|
||||||
|
\node[box,fill=white] (web) at (2.9,1.45) {Next.js\\storefront};
|
||||||
|
\node[box,fill=white] (provider) at (5.8,1.45) {Pricing\\provider};
|
||||||
|
\node[box,fill=white] (redis) at (8.7,1.45) {Redis\\serve layer};
|
||||||
|
\node[box,fill=PhantomIndigo!10,minimum width=3.1cm] (kafka) at (4.35,-0.15) {Kafka topics\\behavior + price logs};
|
||||||
|
\node[box,fill=PhantomCyan!10,minimum width=2.8cm] (airflow) at (8.0,-0.15) {Airflow + worker\\batch updates};
|
||||||
|
|
||||||
|
\draw[arr] (actors) -- (web);
|
||||||
|
\draw[arr] (web) -- (provider);
|
||||||
|
\draw[arr] (provider) -- (redis);
|
||||||
|
\draw[arr] (web.south) -- (kafka.north west);
|
||||||
|
\draw[arr] (provider.south) -- (kafka.north east);
|
||||||
|
\draw[arr] (kafka) -- (airflow);
|
||||||
|
\draw[arr] (airflow.north) -| (redis.south);
|
||||||
|
\draw[arr] (redis.west) to[bend left=35] (provider.east);
|
||||||
|
|
||||||
|
\node[font=\tiny\itshape,text=PhantomSlate] at (2.2,-1.0) {Kappa: streaming telemetry};
|
||||||
|
\node[font=\tiny\itshape,text=PhantomSlate] at (8.1,-1.0) {Lambda: offline learning + refresh};
|
||||||
|
\end{tikzpicture}
|
||||||
|
|
||||||
|
\vspace{0.35em}
|
||||||
|
\begin{itemize}[<+->]
|
||||||
|
\item Every quote has a matching behavioral context in the log stream.
|
||||||
|
\item The same architecture supports reproducible stress tests before any live deployment.
|
||||||
|
\end{itemize}
|
||||||
|
\stagebar{2}
|
||||||
|
\end{frame}
|
||||||
|
|
||||||
|
\begin{frame}{Dataset card: compact, labeled, and experiment-ready}
|
||||||
|
\begin{columns}[T,onlytextwidth]
|
||||||
|
\column{0.60\textwidth}
|
||||||
|
\centering
|
||||||
|
\begin{tikzpicture}[
|
||||||
|
font=\scriptsize\sffamily,
|
||||||
|
chip/.style={draw=PhantomInk!40,rounded corners=2pt,inner sep=2.7pt},
|
||||||
|
body/.style={anchor=west,text width=6.0cm,align=left,font=\scriptsize}
|
||||||
|
]
|
||||||
|
\node[draw=PhantomInk,rounded corners=5pt,fill=white,minimum width=6.85cm,minimum height=4.45cm] at (0,0) {};
|
||||||
|
\node[anchor=west,font=\footnotesize\bfseries,text=PhantomInk] at (-3.2,1.72) {WhoClickedIt dataset card};
|
||||||
|
\node[anchor=west,draw=PhantomInk!35,rounded corners=2pt,fill=PhantomCyan!10,inner xsep=4pt,inner ysep=3pt,font=\scriptsize\ttfamily,text=PhantomSlate] at (-3.2,1.22)
|
||||||
|
{huggingface.co/datasets/velocitatem/whoclickedit};
|
||||||
|
|
||||||
|
\node[anchor=west,chip,fill=PhantomCyan!12] at (-3.2,0.65) {\textbf{Rows} 3874};
|
||||||
|
\node[anchor=west,chip,fill=PhantomCyan!12] at (-1.70,0.65) {\textbf{Cols} 42};
|
||||||
|
\node[anchor=west,chip,fill=PhantomCyan!12] at (-0.25,0.65) {\textbf{Sessions} 36};
|
||||||
|
\node[anchor=west,chip,fill=PhantomIndigo!12] (humanrows) at (-3.2,0.03) {\textbf{Human rows} 798};
|
||||||
|
\node[anchor=west,chip,fill=PhantomIndigo!12] at ([xshift=0.16cm]humanrows.east) {\textbf{Agent rows} 3076};
|
||||||
|
|
||||||
|
\node[body,text=PhantomSlate] at (-3.2,-0.68)
|
||||||
|
{Flat schema and explicit actor labels simplify session-aware train/test splits.};
|
||||||
|
\node[body,font=\tiny\itshape,text=PhantomSlate!85] at (-3.2,-1.36)
|
||||||
|
{Kafka provenance is retained for reproducibility and downstream analysis.};
|
||||||
|
\end{tikzpicture}
|
||||||
|
|
||||||
|
\column{0.38\textwidth}
|
||||||
|
\centering
|
||||||
|
\begin{tikzpicture}[font=\scriptsize\sffamily,
|
||||||
|
stat/.style={draw=PhantomInk,rounded corners=5pt,minimum width=4.95cm,minimum height=1.33cm,align=center}]
|
||||||
|
\node[stat,fill=PhantomInk,text=white] at (0,1.95)
|
||||||
|
{\Large\bfseries 13 H / 16 A\\[-0.1em]\footnotesize labeled trajectories in thesis cohort};
|
||||||
|
\node[stat,fill=PhantomCyan!14,text=PhantomSlate] at (0,0.25)
|
||||||
|
{\Large\bfseries 45\% / 55\%\\[-0.1em]\footnotesize human/agent trajectory split};
|
||||||
|
\node[stat,fill=PhantomIndigo!12,text=PhantomSlate] at (0,-1.45)
|
||||||
|
{\Large\bfseries 2 streams\\[-0.1em]\footnotesize interaction + price-log records};
|
||||||
|
\end{tikzpicture}
|
||||||
|
\end{columns}
|
||||||
|
|
||||||
|
\vspace{0.1em}
|
||||||
|
{\footnotesize\textbf{Use in practice:} this card gives immediate cohort context before any modeling step.}
|
||||||
|
\stagebar{2}
|
||||||
|
\end{frame}
|
||||||
|
|
||||||
|
\begin{frame}{Experimental design controls goals, not navigation paths}
|
||||||
|
\begin{columns}[T,onlytextwidth]
|
||||||
|
\column{0.58\textwidth}
|
||||||
|
\centering
|
||||||
|
\begin{tikzpicture}[
|
||||||
|
font=\scriptsize\sffamily,
|
||||||
|
box/.style={draw=PhantomInk,rounded corners=3pt,minimum width=3.65cm,minimum height=0.95cm,align=center},
|
||||||
|
arr/.style={-{Stealth[length=2.2mm]},thick,PhantomSlate}
|
||||||
|
]
|
||||||
|
\node[box,fill=PhantomCyan!14] (tasks) at (0,1.8) {JTBD task pool\\hotel + airline modes};
|
||||||
|
\node[box,fill=white] (assign) at (0,0.55) {Random assignment\\mode + task + actor id};
|
||||||
|
\node[box,fill=PhantomIndigo!12] (run) at (0,-0.7) {Execution\\human or browser-use agent};
|
||||||
|
\node[box,fill=white] (logs) at (0,-1.95) {Session logs\\$e=(a,i,t,\mu,\delta)$ + quotes};
|
||||||
|
\draw[arr] (tasks) -- (assign);
|
||||||
|
\draw[arr] (assign) -- (run);
|
||||||
|
\draw[arr] (run) -- (logs);
|
||||||
|
\end{tikzpicture}
|
||||||
|
|
||||||
|
\column{0.40\textwidth}
|
||||||
|
\begin{itemize}[<+->]\setlength{\itemsep}{0.55em}
|
||||||
|
\item Agents run with \textbf{browser-use} and a model-swappable LLM router (default \texttt{gpt-5-mini}).
|
||||||
|
\item Tasks are defined by outcomes, not scripted clicks, to preserve behavioral variety.
|
||||||
|
\item Current release is stronger on hotel flows than airline flows.
|
||||||
|
\end{itemize}
|
||||||
|
\end{columns}
|
||||||
|
\stagebar{2}
|
||||||
|
\end{frame}
|
||||||
|
|
||||||
|
\section{Distinguishability Construction}
|
||||||
|
|
||||||
|
\begin{frame}{Stage 2: A behavior kernel is a compact signature of navigation dynamics}
|
||||||
|
\begin{columns}[T,onlytextwidth]
|
||||||
|
\column{0.48\textwidth}
|
||||||
|
\begin{block}{Definition}
|
||||||
|
\[
|
||||||
|
\hat P(s'\mid s)=\frac{N(s,s')}{\sum_k N(s,k)}
|
||||||
|
\]
|
||||||
|
\end{block}
|
||||||
|
\begin{itemize}[<+->]
|
||||||
|
\item Build one kernel per session, then prototypes for human and agent cohorts.
|
||||||
|
\item Compare each incoming session to both prototypes with KL divergence.
|
||||||
|
\end{itemize}
|
||||||
|
|
||||||
|
\column{0.50\textwidth}
|
||||||
|
\centering
|
||||||
|
\begin{tikzpicture}[font=\scriptsize\sffamily]
|
||||||
|
\node[draw=PhantomInk,rounded corners=3pt,fill=PhantomCyan!12,minimum width=3.9cm,minimum height=0.85cm] (a) at (0,1.4) {page\_view};
|
||||||
|
\node[draw=PhantomInk,rounded corners=3pt,fill=white,minimum width=3.9cm,minimum height=0.85cm] (b) at (0,0.25) {view\_item\_page};
|
||||||
|
\node[draw=PhantomInk,rounded corners=3pt,fill=PhantomIndigo!12,minimum width=3.9cm,minimum height=0.85cm] (c) at (0,-0.9) {add\_item\_to\_cart};
|
||||||
|
\draw[-{Stealth[length=2.2mm]},thick,PhantomSlate] (a) -- node[right,font=\tiny]{0.64} (b);
|
||||||
|
\draw[-{Stealth[length=2.2mm]},thick,PhantomSlate] (b) -- node[right,font=\tiny]{0.31} (c);
|
||||||
|
\draw[-{Stealth[length=2.2mm]},thick,PhantomSlate!70] (b.east) .. controls +(1.1,0.5) and +(1.1,-0.5) .. node[right,font=\tiny]{0.52} (b.east);
|
||||||
|
\node[font=\tiny\itshape,text=PhantomSlate] at (0,-1.7) {Kernel rows encode ``what usually comes next.''};
|
||||||
|
\end{tikzpicture}
|
||||||
|
\end{columns}
|
||||||
|
\stagebar{3}
|
||||||
|
\end{frame}
|
||||||
|
|
||||||
|
\begin{frame}{Human and agent kernels are separable in the controlled cohort}
|
||||||
|
\begin{columns}[T,onlytextwidth]
|
||||||
|
\column{0.48\textwidth}
|
||||||
|
\centering
|
||||||
|
\textbf{Human transition structure}\par\vspace{0.2em}
|
||||||
|
\includegraphics[width=\linewidth,height=0.46\textheight,keepaspectratio]{mdp_human.pdf}
|
||||||
|
\column{0.48\textwidth}
|
||||||
|
\centering
|
||||||
|
\textbf{Agent transition structure}\par\vspace{0.2em}
|
||||||
|
\includegraphics[width=\linewidth,height=0.46\textheight,keepaspectratio]{mdp_agent.pdf}
|
||||||
|
\end{columns}
|
||||||
|
|
||||||
|
\vspace{0.15em}
|
||||||
|
\begin{columns}[T,onlytextwidth]
|
||||||
|
\column{0.32\textwidth}\centering\metriccard{-3.35}{mean gap (human)}
|
||||||
|
\column{0.32\textwidth}\centering\metriccard{+1.65}{mean gap (agent)}
|
||||||
|
\column{0.32\textwidth}\centering\metriccard{$p<0.001$}{Mann-Whitney rank test}
|
||||||
|
\end{columns}
|
||||||
|
\stagebar{3}
|
||||||
|
\end{frame}
|
||||||
|
|
||||||
|
\begin{frame}{Two divergence scores become one continuous control signal}
|
||||||
|
\centering
|
||||||
|
\[
|
||||||
|
f(\tau') = P(A\mid\tau') = \sigma\!\left(\frac{\Delta_H-\Delta_A}{T}\right)
|
||||||
|
\]
|
||||||
|
|
||||||
|
\vspace{0.4em}
|
||||||
|
\begin{tikzpicture}[font=\scriptsize\sffamily]
|
||||||
|
\draw[very thick,PhantomSlate] (-4,0) -- (4,0);
|
||||||
|
\draw[thick,PhantomSlate] (0,-0.16) -- (0,0.16);
|
||||||
|
\node[anchor=north] at (-4,0) {human-like};
|
||||||
|
\node[anchor=north] at (4,0) {agent-like};
|
||||||
|
\node[anchor=north] at (0,0) {$\Delta_H-\Delta_A=0$};
|
||||||
|
\fill[PhantomCyan!75!black] (-2.2,0) circle (2.2pt);
|
||||||
|
\fill[PhantomIndigo!75!black] (2.2,0) circle (2.2pt);
|
||||||
|
\node[anchor=south,text=PhantomCyan!75!black] at (-2.2,0) {low $f(\tau')$};
|
||||||
|
\node[anchor=south,text=PhantomIndigo!75!black] at (2.2,0) {high $f(\tau')$};
|
||||||
|
\end{tikzpicture}
|
||||||
|
|
||||||
|
\vspace{0.25em}
|
||||||
|
\begin{itemize}[<+->]
|
||||||
|
\item Continuous scoring is used to steer contamination-aware pricing.
|
||||||
|
\item The design target is guidance, not a hard user-level ban decision.
|
||||||
|
\end{itemize}
|
||||||
|
\stagebar{3}
|
||||||
|
\end{frame}
|
||||||
|
|
||||||
|
\section{Distributionally Robust RL}
|
||||||
|
|
||||||
|
\begin{frame}{Stage 3: DR-RL trains against plausible contamination shifts, not one fixed world}
|
||||||
|
\small
|
||||||
|
\begin{columns}[T,onlytextwidth]
|
||||||
|
\column{0.48\textwidth}
|
||||||
|
\begin{block}{Ideal robust object}
|
||||||
|
\[
|
||||||
|
\mathcal U_\epsilon(\hat P_N)=\{Q: W_p(Q,\hat P_N)\le\epsilon\}
|
||||||
|
\]
|
||||||
|
\centering
|
||||||
|
robust against distribution shift around the empirical demand law
|
||||||
|
\end{block}
|
||||||
|
|
||||||
|
\column{0.50\textwidth}
|
||||||
|
\begin{block}{Engine approximation used in experiments}
|
||||||
|
\[
|
||||||
|
\mathcal A_{\epsilon_\alpha}(\alpha_0)=\{\alpha:|\alpha-\alpha_0|\le\epsilon_\alpha\}
|
||||||
|
\]
|
||||||
|
\centering
|
||||||
|
small grid over $\alpha$ \;\textrightarrow\; inner worst-case candidate
|
||||||
|
\end{block}
|
||||||
|
\end{columns}
|
||||||
|
\vspace{0.2em}
|
||||||
|
\begin{alertblock}{Practical boundary}
|
||||||
|
In code we solve a local robust loop around $\alpha_0$, not the full continuous Wasserstein adversary.
|
||||||
|
\end{alertblock}
|
||||||
|
\stagebar{4}
|
||||||
|
\end{frame}
|
||||||
|
|
||||||
|
\begin{frame}{Reward composition penalizes leakage while guarding user experience}
|
||||||
|
\[
|
||||||
|
r_t =
|
||||||
|
{\color{PhantomInk}\underline{R(p_t,\hat Q_t)}}
|
||||||
|
- {\color{PhantomCyan!95!black}\underline{\lambda\,f(\tau'_t)\,c_{\text{info}}}}
|
||||||
|
- {\color{PhantomIndigo!95!black}\underline{\eta_{\text{ux}}\,UX(\tau'_t,p_t)}}
|
||||||
|
\]
|
||||||
|
|
||||||
|
\vspace{0.45em}
|
||||||
|
\begin{columns}[T,onlytextwidth]
|
||||||
|
\column{0.32\textwidth}
|
||||||
|
\centering
|
||||||
|
\begin{tikzpicture}[font=\scriptsize\sffamily]
|
||||||
|
\node[
|
||||||
|
draw=PhantomInk,
|
||||||
|
rounded corners=4pt,
|
||||||
|
fill=PhantomInk!12,
|
||||||
|
minimum width=0.98\linewidth,
|
||||||
|
text width=0.88\linewidth,
|
||||||
|
minimum height=1.28cm,
|
||||||
|
align=center,
|
||||||
|
text=PhantomInk
|
||||||
|
] {\textbf{Revenue term}\\[-0.08em]keeps market objective explicit};
|
||||||
|
\end{tikzpicture}
|
||||||
|
\column{0.32\textwidth}
|
||||||
|
\centering
|
||||||
|
\begin{tikzpicture}[font=\scriptsize\sffamily]
|
||||||
|
\node[
|
||||||
|
draw=PhantomInk,
|
||||||
|
rounded corners=4pt,
|
||||||
|
fill=PhantomCyan!16,
|
||||||
|
minimum width=0.98\linewidth,
|
||||||
|
text width=0.88\linewidth,
|
||||||
|
minimum height=1.28cm,
|
||||||
|
align=center,
|
||||||
|
text=PhantomCyan!95!black
|
||||||
|
] {\textbf{Leakage term}\\[-0.08em]scales with agent-likelihood score};
|
||||||
|
\end{tikzpicture}
|
||||||
|
\column{0.32\textwidth}
|
||||||
|
\centering
|
||||||
|
\begin{tikzpicture}[font=\scriptsize\sffamily]
|
||||||
|
\node[
|
||||||
|
draw=PhantomInk,
|
||||||
|
rounded corners=4pt,
|
||||||
|
fill=PhantomIndigo!16,
|
||||||
|
minimum width=0.98\linewidth,
|
||||||
|
text width=0.88\linewidth,
|
||||||
|
minimum height=1.28cm,
|
||||||
|
align=center,
|
||||||
|
text=PhantomIndigo!95!black
|
||||||
|
] {\textbf{UX term}\\[-0.08em]discourages unstable pricing behavior};
|
||||||
|
\end{tikzpicture}
|
||||||
|
\end{columns}
|
||||||
|
|
||||||
|
\vspace{0.25em}
|
||||||
|
\begin{itemize}[<+->]
|
||||||
|
\item Baseline experiments use a query-tax leakage surrogate for tractability.
|
||||||
|
\item Supra-competitive anchor penalties are tracked as an additional safety rail.
|
||||||
|
\end{itemize}
|
||||||
|
\stagebar{4}
|
||||||
|
\end{frame}
|
||||||
|
|
||||||
|
\begin{frame}{Computationally, wide sweeps are feasible only with aggressive optimization}
|
||||||
|
\begin{columns}[T,onlytextwidth]
|
||||||
|
\column{0.47\textwidth}
|
||||||
|
\centering
|
||||||
|
{\Large\(4\times4\times3\times2\times2=\mathbf{192}\)}\\[0.25em]
|
||||||
|
{\scriptsize algorithms $\times$ contamination $\times$ robustness $\times$ COI penalty $\times$ action grid}
|
||||||
|
|
||||||
|
\vspace{0.5em}
|
||||||
|
\metriccard{160 PFLOPS}{peak aggregate TPU budget}\\[0.45em]
|
||||||
|
\metriccard{\textasciitilde180 days}{net compute logged in full study}
|
||||||
|
|
||||||
|
\column{0.51\textwidth}
|
||||||
|
\begin{block}{Hot-path rewrite impact}
|
||||||
|
\centering
|
||||||
|
\begin{tabular}{@{}lcc@{}}
|
||||||
|
\toprule
|
||||||
|
Mode & Before & After \\
|
||||||
|
\midrule
|
||||||
|
Baseline step/s & 26.0 & 220.0 \\
|
||||||
|
Robust step/s & 7.2 & 136.0 \\
|
||||||
|
\bottomrule
|
||||||
|
\end{tabular}
|
||||||
|
\end{block}
|
||||||
|
\vspace{0.1em}
|
||||||
|
{\footnotesize
|
||||||
|
\begin{itemize}[<+->]
|
||||||
|
\item pandas lookup bottlenecks replaced with array/JAX-style loops.
|
||||||
|
\item Throughput gains (8.5$\times$, 19$\times$) made broad sweeps practical.
|
||||||
|
\end{itemize}}
|
||||||
|
\end{columns}
|
||||||
|
\stagebar{4}
|
||||||
|
\end{frame}
|
||||||
|
|
||||||
|
\section{Results}
|
||||||
|
|
||||||
|
\begin{frame}{Results: contamination hurts revenue; defended policies recover COI}
|
||||||
|
\begin{columns}[T,onlytextwidth]
|
||||||
|
\column{0.62\textwidth}
|
||||||
|
\centering
|
||||||
|
\includegraphics[width=\linewidth,height=0.60\textheight,keepaspectratio]{final_focus_coi_by_alpha.pdf}
|
||||||
|
|
||||||
|
\column{0.30\textwidth}
|
||||||
|
\metriccard{-90{,}140}{baseline contamination slope}\\[0.3em]
|
||||||
|
\metriccard{\textasciitilde3\%}{short-run revenue cost of defense}\\[0.3em]
|
||||||
|
\metriccard{Regime-dependent}{COI gains strongest at harder settings}
|
||||||
|
\end{columns}
|
||||||
|
\stagebar{5}
|
||||||
|
\end{frame}
|
||||||
|
|
||||||
|
\section{Conclusions}
|
||||||
|
|
||||||
|
\begin{frame}{Yes, with boundaries: we can defend margin integrity under agentic orchestration}
|
||||||
|
\begin{columns}[T,onlytextwidth]
|
||||||
|
\column{0.32\textwidth}
|
||||||
|
\begin{block}{SQ1\;Distinguishability}
|
||||||
|
\centering
|
||||||
|
kernels are separable\\$p<0.001$
|
||||||
|
\end{block}
|
||||||
|
\column{0.32\textwidth}
|
||||||
|
\begin{block}{SQ2\;Theoretical impact}
|
||||||
|
\centering
|
||||||
|
COI erosion mechanism\\proved in baseline limit
|
||||||
|
\end{block}
|
||||||
|
\column{0.32\textwidth}
|
||||||
|
\begin{block}{SQ3\;Mitigation}
|
||||||
|
\centering
|
||||||
|
robust control shifts\\COI/revenue/UX trade-off
|
||||||
|
\end{block}
|
||||||
|
\end{columns}
|
||||||
|
|
||||||
|
\vspace{0.35em}
|
||||||
|
\begin{alertblock}{Boundary conditions}
|
||||||
|
Evidence is from a controlled platform and a small labeled cohort; this is mechanism validation, not full production external validity.
|
||||||
|
\end{alertblock}
|
||||||
|
\stagebar{6}
|
||||||
|
\end{frame}
|
||||||
|
|
||||||
|
\begin{frame}{What this implies for real pricing systems}
|
||||||
|
\begin{itemize}[<+->]\setlength{\itemsep}{0.7em}
|
||||||
|
\item \textbf{Financially:} untreated reconnaissance behaves like an information leak and can compress sustainable margins.
|
||||||
|
\item \textbf{Operationally:} behavior-only session scoring can be wired into pricing without relying on device fingerprinting.
|
||||||
|
\item \textbf{Strategically:} robust pricing should be calibrated by regime; there is no single penalty that wins everywhere.
|
||||||
|
\item \textbf{Before deployment:} larger human baselines, governance review, and legal safeguards are mandatory.
|
||||||
|
\end{itemize}
|
||||||
|
\stagebar{6}
|
||||||
|
\end{frame}
|
||||||
|
|
||||||
|
\begin{frame}[plain]
|
||||||
|
\centering
|
||||||
|
\vfill
|
||||||
|
{\LARGE\bfseries Thank you}
|
||||||
|
\vspace{0.8em}
|
||||||
|
|
||||||
|
{\large Questions and discussion}
|
||||||
|
|
||||||
|
\vfill
|
||||||
|
{\footnotesize\color{PhantomSlate!80}Appendix follows: COI theorem derivation, reward composition, and sample-size notes.}
|
||||||
|
\vfill
|
||||||
|
\end{frame}
|
||||||
|
|
||||||
|
\appendix
|
||||||
|
\input{defense_appendix}
|
||||||
|
|
||||||
|
\end{document}
|
||||||
322
paper/defense/defense_appendix.tex
Normal file
322
paper/defense/defense_appendix.tex
Normal file
@@ -0,0 +1,322 @@
|
|||||||
|
% Included by defense.tex after the main deck (extensive appendix).
|
||||||
|
|
||||||
|
\section{Appendix}
|
||||||
|
|
||||||
|
\begin{frame}{Appendix roadmap}
|
||||||
|
\footnotesize
|
||||||
|
\begin{columns}[T,onlytextwidth]
|
||||||
|
\column{0.31\textwidth}
|
||||||
|
\begin{block}{A.\ Objects}
|
||||||
|
Notation, COI, proxies
|
||||||
|
\end{block}
|
||||||
|
\column{0.31\textwidth}
|
||||||
|
\begin{block}{B.\ Mechanism}
|
||||||
|
Order stats, kernels, KL
|
||||||
|
\end{block}
|
||||||
|
\column{0.31\textwidth}
|
||||||
|
\begin{block}{C.\ Control}
|
||||||
|
Simulator, robust loop, factorial grid
|
||||||
|
\end{block}
|
||||||
|
\end{columns}
|
||||||
|
\vfill
|
||||||
|
\begin{alertblock}{Figures}
|
||||||
|
Full charts, MDPs, extra revenue view
|
||||||
|
\end{alertblock}
|
||||||
|
\end{frame}
|
||||||
|
|
||||||
|
% ----- A. Notation & definitions -----
|
||||||
|
|
||||||
|
\begin{frame}{Appendix: core notation (quick reference, I)}
|
||||||
|
\scriptsize
|
||||||
|
\begin{align*}
|
||||||
|
\tau_s &= (e_{s,1},\ldots,e_{s,L_s}) && \text{session} \\
|
||||||
|
\hat{q}_{t,i} &= \sum_{s\in S_t}\sum_k \omega(a_{s,k})\,\mathbf{1}[i_{s,k}=i] && \text{proxy} \\
|
||||||
|
Q(p) &= (1-\alpha)\,\mathbb{E}_{\theta\sim D_H}[d(p;\theta)] \\
|
||||||
|
&\quad + \alpha\,\mathbb{E}_{\theta\sim D_A}[d(p;\theta)] + \epsilon_t && \text{mixture} \\
|
||||||
|
\mathrm{COI}(\pi) &= \mathbb{E}[P]-\underline{p} && \text{COI}
|
||||||
|
\end{align*}
|
||||||
|
\end{frame}
|
||||||
|
|
||||||
|
\begin{frame}{Appendix: core notation (quick reference, II)}
|
||||||
|
\footnotesize
|
||||||
|
\begin{itemize}
|
||||||
|
\item \(\underline{p}\): minimum viable price anchor (thesis simplification).
|
||||||
|
\item \(\alpha\): contamination with agent traffic in the mixture.
|
||||||
|
\item \(\omega(a)\): hand-engineered action weights for the proxy (baseline).
|
||||||
|
\end{itemize}
|
||||||
|
\begin{alertblock}{Reading guide}
|
||||||
|
Objects on the left are \textbf{observable}; \(d(\cdot)\) and many \(\theta\) remain hidden.
|
||||||
|
\end{alertblock}
|
||||||
|
\end{frame}
|
||||||
|
|
||||||
|
\begin{frame}{Appendix: COI as a reporting functional}
|
||||||
|
\[
|
||||||
|
\mathrm{COI}(\pi) = \mathbb{E}_{P\sim F_\pi}[P] - \underline{p}
|
||||||
|
\]
|
||||||
|
\begin{block}{Interpretation}
|
||||||
|
Premium above the floor induced by policy \(\pi\); used as a KPI and as the object Theorem 1 attacks under query saturation.
|
||||||
|
\end{block}
|
||||||
|
\end{frame}
|
||||||
|
|
||||||
|
\begin{frame}{Appendix: demand proxy vs.\ latent demand}
|
||||||
|
\[
|
||||||
|
\hat{q}_{t,i}=\sum_{s\in S_t}\sum_{k=1}^{L_s} \omega(a_{s,k})\,\mathbf{1}[i_{s,k}=i]
|
||||||
|
\]
|
||||||
|
\begin{alertblock}{Key distinction}
|
||||||
|
\(\hat{q}\) is an operational sensor from logs; true demand \(d(p;\theta)\) stays latent. Pricing reacts to \(\hat{q}\), so agent-shaped behavior poisons the signal.
|
||||||
|
\end{alertblock}
|
||||||
|
\end{frame}
|
||||||
|
|
||||||
|
% ----- B. Mechanism -----
|
||||||
|
|
||||||
|
\begin{frame}{Appendix: independent draws and order statistics (intuition)}
|
||||||
|
\begin{columns}[T]
|
||||||
|
\column{0.55\textwidth}
|
||||||
|
\begin{itemize}
|
||||||
|
\item Independent price draws \(\{P_i\}_{i=1}^N\) from fixed offer law.
|
||||||
|
\item Purchase-side minimum behaves like \(P_{(1)}\): mass shifts left as \(N\) grows.
|
||||||
|
\item Expected premium vs.\ \(\underline{p}\) compresses: COI pressure.
|
||||||
|
\end{itemize}
|
||||||
|
\column{0.42\textwidth}
|
||||||
|
\centering
|
||||||
|
\begin{tikzpicture}[scale=0.85]
|
||||||
|
\draw[->,thick] (0,0)--(3.2,0) node[right] {\small queries \(N\)};
|
||||||
|
\draw[->,thick] (0,0)--(0,2.2) node[above] {\small COI};
|
||||||
|
\draw[PhantomCyan,very thick] (0.2,2) .. controls (1.5,1.2) and (2.2,0.5) .. (3,0.15);
|
||||||
|
\node[below right] at (2.4,0.6) {\footnotesize saturation};
|
||||||
|
\end{tikzpicture}
|
||||||
|
\end{columns}
|
||||||
|
\end{frame}
|
||||||
|
|
||||||
|
\begin{frame}{Appendix: Theorem 1 scope (what is and is not claimed)}
|
||||||
|
\small
|
||||||
|
\begin{block}{Inside the baseline proof}
|
||||||
|
Non-collusive sessions, independent draws, fixed offer distribution across queries.
|
||||||
|
\end{block}
|
||||||
|
\begin{alertblock}{Outside (handled elsewhere)}
|
||||||
|
Collusion, pooled recon, sequential repricing that breaks iid structure: evidence moves to the simulator.
|
||||||
|
\end{alertblock}
|
||||||
|
\end{frame}
|
||||||
|
|
||||||
|
\begin{frame}{Appendix: empirical transition kernel (MLE)}
|
||||||
|
\[
|
||||||
|
\hat{P}(s'\mid s)=\frac{N(s,s')}{\sum_k N(s,k)}
|
||||||
|
\]
|
||||||
|
\begin{block}{Use}
|
||||||
|
Human and agent centroids \(\bar{T}_H,\bar{T}_A\) for divergence-to-prototype scores.
|
||||||
|
\end{block}
|
||||||
|
\end{frame}
|
||||||
|
|
||||||
|
\begin{frame}{Appendix: KL to prototypes (shared support)}
|
||||||
|
\[
|
||||||
|
\Delta_H = D_{\mathrm{KL}}(\hat{T}'\,\|\,\bar{T}_H),\qquad
|
||||||
|
\Delta_A = D_{\mathrm{KL}}(\hat{T}'\,\|\,\bar{T}_A)
|
||||||
|
\]
|
||||||
|
\begin{exampleblock}{Asymmetric choice}
|
||||||
|
KL measures deviation from the \textbf{human} reference; symmetric JS/Wasserstein on behavior was not the design target.
|
||||||
|
\end{exampleblock}
|
||||||
|
\end{frame}
|
||||||
|
|
||||||
|
\begin{frame}{Appendix: softmax to sigmoid (algebra)}
|
||||||
|
\small
|
||||||
|
Let \(z_A=-\Delta_A/T\), \(z_H=-\Delta_H/T\). Then
|
||||||
|
\begin{align*}
|
||||||
|
P(A\mid\tau) &= \frac{e^{z_A}}{e^{z_A}+e^{z_H}}
|
||||||
|
= \frac{1}{1+e^{z_H-z_A}}
|
||||||
|
= \sigma\bigl(z_A-z_H\bigr) \\
|
||||||
|
&= \sigma\!\left(\frac{\Delta_H-\Delta_A}{T}\right).
|
||||||
|
\end{align*}
|
||||||
|
\begin{block}{Takeaway}
|
||||||
|
Two-class softmax over \((z_A,z_H)\) is exactly one sigmoid on the gap \((\Delta_H-\Delta_A)\).
|
||||||
|
\end{block}
|
||||||
|
\end{frame}
|
||||||
|
|
||||||
|
\begin{frame}{Appendix: contamination generator \(\mathcal{G}(\alpha)\)}
|
||||||
|
\[
|
||||||
|
\mathcal{G}(\alpha):\ \text{inject synthetic agent trajectories until mixture reaches target }\alpha
|
||||||
|
\]
|
||||||
|
\begin{alertblock}{Role in the lab}
|
||||||
|
Supplies controlled stress tests for the pricing learner; not a claim of production-faithful agents.
|
||||||
|
\end{alertblock}
|
||||||
|
\end{frame}
|
||||||
|
|
||||||
|
% ----- C. Robust control -----
|
||||||
|
|
||||||
|
\begin{frame}{Appendix: Wasserstein ambiguity (ideal object)}
|
||||||
|
\[
|
||||||
|
\mathcal{U}_\epsilon(\hat{P}_N)=\left\{ Q:\ W_p(Q,\hat{P}_N)\le \epsilon \right\}
|
||||||
|
\]
|
||||||
|
\begin{block}{What the code implements instead}
|
||||||
|
A \textbf{local} grid over \(\alpha\) near \(\alpha_0\) with radius \(\epsilon_\alpha\): tractable inner worst case, not a full ball solver.
|
||||||
|
\end{block}
|
||||||
|
\end{frame}
|
||||||
|
|
||||||
|
\begin{frame}{Appendix: per-step reward sketch}
|
||||||
|
\small
|
||||||
|
\[
|
||||||
|
r = R(p,d) - \lambda\,\mathrm{COI}_{\mathrm{leak}}(p,\tau') - \eta\,\mathrm{UX}(\tau',p) - \text{(supra-competitive excess)}
|
||||||
|
\]
|
||||||
|
\begin{itemize}
|
||||||
|
\item Query-tax style \(\mathrm{COI}_{\mathrm{leak}}\): minimal nonzero surrogate to expose the control channel.
|
||||||
|
\item UX and anchor penalties prevent trivial solutions (flat but exploitative prices).
|
||||||
|
\end{itemize}
|
||||||
|
\end{frame}
|
||||||
|
|
||||||
|
\begin{frame}{Appendix: factorial design (192 cells)}
|
||||||
|
\footnotesize
|
||||||
|
\centering
|
||||||
|
\begin{tabular}{@{}llr@{}}
|
||||||
|
\toprule
|
||||||
|
Axis & Levels & Count \\
|
||||||
|
\midrule
|
||||||
|
RL algorithm & PPO, A2C, DQN, Q-table & 4 \\
|
||||||
|
Contamination \(\alpha\) & 4 representative values in \([0.1,0.6]\) & 4 \\
|
||||||
|
Robustness radius \(\epsilon_\alpha\) & 3 & 3 \\
|
||||||
|
COI penalty \(\lambda_{\mathrm{coi}}\) & 2 & 2 \\
|
||||||
|
Action granularity & 2 & 2 \\
|
||||||
|
\midrule
|
||||||
|
\textbf{Total} & & \(4\times4\times3\times2\times2=\mathbf{192}\) \\
|
||||||
|
\bottomrule
|
||||||
|
\end{tabular}
|
||||||
|
\end{frame}
|
||||||
|
|
||||||
|
\begin{frame}{Appendix: engineering note (pandas \(\to\) JAX)}
|
||||||
|
\begin{itemize}
|
||||||
|
\item Hot path was label-indexed transition lookups; profiling showed pandas overhead dominated.
|
||||||
|
\item Integer-indexed arrays + JAX inner loop: large step/s throughput (thesis numbers; environment dependent).
|
||||||
|
\item Kronecker expansion of product-conditioned kernels: research simulator cost, scales with catalog.
|
||||||
|
\end{itemize}
|
||||||
|
\end{frame}
|
||||||
|
|
||||||
|
% ----- Extended figures (all PDFs in repo) -----
|
||||||
|
|
||||||
|
\begin{frame}{Appendix figure: COI by \(\alpha\) (full)}
|
||||||
|
\centering
|
||||||
|
\includegraphics[width=0.92\linewidth,height=0.78\textheight,keepaspectratio]{final_focus_coi_by_alpha.pdf}
|
||||||
|
\end{frame}
|
||||||
|
|
||||||
|
\begin{frame}{Appendix figure: revenue deltas (full)}
|
||||||
|
\centering
|
||||||
|
\includegraphics[width=0.92\linewidth,height=0.78\textheight,keepaspectratio]{final_focus_revenue_delta.pdf}
|
||||||
|
\end{frame}
|
||||||
|
|
||||||
|
\begin{frame}{Appendix figure: revenue by \(\alpha\) (full)}
|
||||||
|
\centering
|
||||||
|
\includegraphics[width=0.92\linewidth,height=0.78\textheight,keepaspectratio]{final_focus_revenue_by_alpha.pdf}
|
||||||
|
\end{frame}
|
||||||
|
|
||||||
|
\begin{frame}{Appendix figure: risk / stability deltas (full)}
|
||||||
|
\centering
|
||||||
|
\includegraphics[width=0.92\linewidth,height=0.78\textheight,keepaspectratio]{final_focus_risk_deltas.pdf}
|
||||||
|
\end{frame}
|
||||||
|
|
||||||
|
\begin{frame}{Appendix figure: COI preservation grid (full)}
|
||||||
|
\centering
|
||||||
|
\includegraphics[width=0.92\linewidth,height=0.78\textheight,keepaspectratio]{final_focus_coi_preservation_grid.pdf}
|
||||||
|
\end{frame}
|
||||||
|
|
||||||
|
\begin{frame}{Appendix figure: human MDP (full)}
|
||||||
|
\centering
|
||||||
|
\includegraphics[width=0.75\linewidth,height=0.82\textheight,keepaspectratio]{mdp_human.pdf}
|
||||||
|
\end{frame}
|
||||||
|
|
||||||
|
\begin{frame}{Appendix figure: agent MDP (full)}
|
||||||
|
\centering
|
||||||
|
\includegraphics[width=0.75\linewidth,height=0.82\textheight,keepaspectratio]{mdp_agent.pdf}
|
||||||
|
\end{frame}
|
||||||
|
|
||||||
|
% ----- Threat model & evaluation -----
|
||||||
|
|
||||||
|
\begin{frame}{Appendix: threat model map}
|
||||||
|
\centering
|
||||||
|
\resizebox{0.98\linewidth}{!}{%
|
||||||
|
\begin{tikzpicture}[
|
||||||
|
font=\sffamily\footnotesize,
|
||||||
|
box/.style={draw=PhantomInk,rounded corners=2pt,thick,align=center,inner sep=5pt,minimum width=2.8cm},
|
||||||
|
arr/.style={-Stealth,thick,PhantomSlate}
|
||||||
|
]
|
||||||
|
\node[box,fill=PhantomCyan!18] (A) at (0,0) {\textbf{Focus}\\[0.15em]browser agents\\into \(\hat{q}\)};
|
||||||
|
\node[box,fill=white] (B) at (3.8,0) {\textbf{Complementary}\\[0.15em]WAF, CAPTCHA,\\rate limits};
|
||||||
|
\node[box,fill=white] (C) at (7.6,0) {\textbf{Upstream}\\[0.15em]API scrape,\\no UI semantics};
|
||||||
|
\draw[arr] (A) -- node[above] {\tiny scope} (B);
|
||||||
|
\draw[arr] (B) -- node[above] {\tiny out of scope} (C);
|
||||||
|
\end{tikzpicture}%
|
||||||
|
}
|
||||||
|
\vfill
|
||||||
|
\begin{block}{Claim boundary}
|
||||||
|
Residual contamination after security controls is the motivating scenario.
|
||||||
|
\end{block}
|
||||||
|
\end{frame}
|
||||||
|
|
||||||
|
\begin{frame}{Appendix: evaluation checklist (robustness culture)}
|
||||||
|
\footnotesize
|
||||||
|
\begin{enumerate}
|
||||||
|
\item Session-aware labels: avoid splitting rows inside a trajectory if that inflates scores.
|
||||||
|
\item Document how prototypes \(\bar{T}_H,\bar{T}_A\) were fit (full cohort vs.\ held-out); state explicitly in writing.
|
||||||
|
\item Report temperature \(T\) as calibration, not as a tuned hyperparameter unless a sweep is shown.
|
||||||
|
\item Separate \textbf{architecture} claims from \textbf{coverage} claims (hotel vs.\ airline balance at release).
|
||||||
|
\end{enumerate}
|
||||||
|
\end{frame}
|
||||||
|
|
||||||
|
\begin{frame}{Appendix: sim-to-real gap (explicit)}
|
||||||
|
\begin{itemize}
|
||||||
|
\item Kernels and generators reflect a \textbf{small labeled cohort} and a \textbf{browser-use style} agent class.
|
||||||
|
\item RL policies are trained in a \textbf{surrogate} market with engineered rewards and discretized prices.
|
||||||
|
\item Deployment would require legal review, fairness testing, and refreshed baselines at scale.
|
||||||
|
\end{itemize}
|
||||||
|
\end{frame}
|
||||||
|
|
||||||
|
\begin{frame}{Appendix: leakage surrogate (query-tax form)}
|
||||||
|
\small
|
||||||
|
\[
|
||||||
|
\mathrm{COI}_{\mathrm{leak}}(p,\tau') \approx f(\tau')\cdot c_{\mathrm{info}}
|
||||||
|
\]
|
||||||
|
\begin{block}{Reading}
|
||||||
|
\(f(\tau')\) is the weak agent score; \(c_{\mathrm{info}}\) is a minimal constant leakage proxy to expose the control channel. Revelation-style \(-\log \pi(p\mid\tau')\) is the natural upgrade.
|
||||||
|
\end{block}
|
||||||
|
\end{frame}
|
||||||
|
|
||||||
|
\begin{frame}{Appendix: robust pricing template (symbolic)}
|
||||||
|
\footnotesize
|
||||||
|
\[
|
||||||
|
\max_\pi\ \min_{Q\in\mathcal{U}_\epsilon(\hat{P}_N)} \mathbb{E}_{d\sim Q}\bigl[ R(p,d) - \lambda\,\mathrm{COI}_{\mathrm{leak}} - \eta\,\mathrm{UX} \bigr]
|
||||||
|
\]
|
||||||
|
\begin{alertblock}{Code-level substitute}
|
||||||
|
Inner min over a \textbf{finite grid} of \(\alpha_k\in[\alpha_0\pm\epsilon_\alpha]\) around the nominal generator mix, not a continuous adversary over all \(Q\) in the ball.
|
||||||
|
\end{alertblock}
|
||||||
|
\end{frame}
|
||||||
|
|
||||||
|
\begin{frame}{Appendix: Stackelberg timing (words)}
|
||||||
|
\begin{itemize}
|
||||||
|
\item Leader: platform sets price vector given current state and policy.
|
||||||
|
\item Follower: demand proxy updates from simulated trajectories drawn from \(\mathcal{G}(\alpha)\) and kernels \((\hat{T}_H,\hat{T}_A)\).
|
||||||
|
\item \textbf{Limbo} buffer stores alternating moves for a clean game history; relaxing strict alternation is listed future work.
|
||||||
|
\end{itemize}
|
||||||
|
\end{frame}
|
||||||
|
|
||||||
|
\begin{frame}{Appendix: three layers of evidence}
|
||||||
|
\footnotesize
|
||||||
|
\begin{description}
|
||||||
|
\item[Theorem 1] Formal COI erosion under independence and fixed-offer assumptions.
|
||||||
|
\item[Simulator] Dynamic, adaptive pricing and contamination sweeps (different status).
|
||||||
|
\item[Implementation] Local-$\alpha$ robust training; spirit of DRO without claiming a full numerical Wasserstein solver.
|
||||||
|
\end{description}
|
||||||
|
\end{frame}
|
||||||
|
|
||||||
|
\begin{frame}{Appendix: composite strip (five plots, small multiples)}
|
||||||
|
\centering
|
||||||
|
{\footnotesize\itshape Same PDFs as the main talk, shrunk to scan the full panel at once.\par}
|
||||||
|
\vspace{0.25em}
|
||||||
|
\begin{columns}[T,onlytextwidth]
|
||||||
|
\column{0.19\textwidth}
|
||||||
|
\includegraphics[width=\linewidth,height=0.26\textheight,keepaspectratio]{final_focus_coi_by_alpha.pdf}
|
||||||
|
\column{0.19\textwidth}
|
||||||
|
\includegraphics[width=\linewidth,height=0.26\textheight,keepaspectratio]{final_focus_revenue_delta.pdf}
|
||||||
|
\column{0.19\textwidth}
|
||||||
|
\includegraphics[width=\linewidth,height=0.26\textheight,keepaspectratio]{final_focus_revenue_by_alpha.pdf}
|
||||||
|
\column{0.19\textwidth}
|
||||||
|
\includegraphics[width=\linewidth,height=0.26\textheight,keepaspectratio]{final_focus_risk_deltas.pdf}
|
||||||
|
\column{0.19\textwidth}
|
||||||
|
\includegraphics[width=\linewidth,height=0.26\textheight,keepaspectratio]{final_focus_coi_preservation_grid.pdf}
|
||||||
|
\end{columns}
|
||||||
|
\end{frame}
|
||||||
3
paper/defense/manim/.gitignore
vendored
Normal file
3
paper/defense/manim/.gitignore
vendored
Normal file
@@ -0,0 +1,3 @@
|
|||||||
|
__pycache__/
|
||||||
|
*.pyc
|
||||||
|
media/
|
||||||
176
paper/defense/manim/common.py
Normal file
176
paper/defense/manim/common.py
Normal file
@@ -0,0 +1,176 @@
|
|||||||
|
from __future__ import annotations
|
||||||
|
|
||||||
|
from typing import Iterable
|
||||||
|
|
||||||
|
import numpy as np
|
||||||
|
from manim import (
|
||||||
|
Arrow,
|
||||||
|
BLUE_D,
|
||||||
|
CurvedArrow,
|
||||||
|
DOWN,
|
||||||
|
DashedLine,
|
||||||
|
GREEN_C,
|
||||||
|
GREY_B,
|
||||||
|
LEFT,
|
||||||
|
Line,
|
||||||
|
MathTex,
|
||||||
|
Matrix,
|
||||||
|
RIGHT,
|
||||||
|
RoundedRectangle,
|
||||||
|
SurroundingRectangle,
|
||||||
|
Text,
|
||||||
|
UP,
|
||||||
|
VGroup,
|
||||||
|
config,
|
||||||
|
)
|
||||||
|
|
||||||
|
P_MIN = 80.0
|
||||||
|
P_MAX = 160.0
|
||||||
|
LIGHT_BG = "#F8F8F4"
|
||||||
|
INK = "#1E1E1E"
|
||||||
|
AXIS_INK = "#2C2C2C"
|
||||||
|
HIGHLIGHT = "#8F5F00"
|
||||||
|
|
||||||
|
config.background_color = LIGHT_BG
|
||||||
|
Text.set_default(color=INK)
|
||||||
|
MathTex.set_default(color=INK)
|
||||||
|
Line.set_default(color=AXIS_INK)
|
||||||
|
Arrow.set_default(color=AXIS_INK)
|
||||||
|
CurvedArrow.set_default(color=AXIS_INK)
|
||||||
|
DashedLine.set_default(color=AXIS_INK)
|
||||||
|
|
||||||
|
|
||||||
|
def normal_pdf(x: float, mu: float, sigma: float) -> float:
|
||||||
|
z = (x - mu) / sigma
|
||||||
|
return float(np.exp(-0.5 * z * z) / (sigma * np.sqrt(2.0 * np.pi)))
|
||||||
|
|
||||||
|
|
||||||
|
def scene_title(text: str) -> Text:
|
||||||
|
return Text(text, font_size=44, weight="BOLD", color=INK).to_edge(UP)
|
||||||
|
|
||||||
|
|
||||||
|
def card(
|
||||||
|
label: str,
|
||||||
|
color: str = BLUE_D,
|
||||||
|
width: float = 3.3,
|
||||||
|
height: float = 1.15,
|
||||||
|
font_size: float = 24,
|
||||||
|
) -> VGroup:
|
||||||
|
box = RoundedRectangle(corner_radius=0.15, width=width, height=height)
|
||||||
|
box.set_stroke(color=color, width=2.0)
|
||||||
|
box.set_fill(color=color, opacity=0.12)
|
||||||
|
text = Text(label, font_size=font_size).move_to(box.get_center())
|
||||||
|
return VGroup(box, text)
|
||||||
|
|
||||||
|
|
||||||
|
def to_matrix(
|
||||||
|
values: Iterable[Iterable[float]],
|
||||||
|
title: str,
|
||||||
|
color: str,
|
||||||
|
header_buff: float = 0.28,
|
||||||
|
fmt: str = ".2f",
|
||||||
|
) -> VGroup:
|
||||||
|
mat = Matrix(
|
||||||
|
[[f"{v:{fmt}}" for v in row] for row in values], h_buff=1.15, v_buff=0.75
|
||||||
|
)
|
||||||
|
header = Text(title, font_size=25, weight="BOLD", color=color).next_to(
|
||||||
|
mat, UP, buff=header_buff
|
||||||
|
)
|
||||||
|
frame = SurroundingRectangle(mat, color=color, buff=0.2)
|
||||||
|
return VGroup(header, frame, mat)
|
||||||
|
|
||||||
|
|
||||||
|
def rank_from_scale(scale: int) -> str:
|
||||||
|
clamped = max(1, min(scale, 10))
|
||||||
|
return "A" if clamped == 1 else str(clamped)
|
||||||
|
|
||||||
|
|
||||||
|
def actor_face_card(
|
||||||
|
rank: str,
|
||||||
|
role: str,
|
||||||
|
accent: str,
|
||||||
|
width: float = 1.6,
|
||||||
|
height: float = 2.25,
|
||||||
|
show_role: bool = True,
|
||||||
|
) -> VGroup:
|
||||||
|
frame = RoundedRectangle(corner_radius=0.1, width=width, height=height)
|
||||||
|
frame.set_stroke(color=AXIS_INK, width=2.0)
|
||||||
|
frame.set_fill(color="#FFFFFF", opacity=1.0)
|
||||||
|
|
||||||
|
top_rank = Text(rank, font_size=30, color=accent).move_to(
|
||||||
|
frame.get_corner(UP + LEFT) + RIGHT * 0.2 + DOWN * 0.22
|
||||||
|
)
|
||||||
|
bottom_rank = (
|
||||||
|
Text(rank, font_size=30, color=accent)
|
||||||
|
.rotate(np.pi)
|
||||||
|
.move_to(frame.get_corner(DOWN + RIGHT) + LEFT * 0.2 + UP * 0.22)
|
||||||
|
)
|
||||||
|
center_rank = Text(rank, font_size=56, weight="BOLD", color=accent).move_to(
|
||||||
|
frame.get_center() + UP * 0.03
|
||||||
|
)
|
||||||
|
|
||||||
|
parts = [frame, top_rank, bottom_rank, center_rank]
|
||||||
|
if show_role:
|
||||||
|
role_label = Text(role, font_size=18, color=GREY_B).next_to(
|
||||||
|
frame, DOWN, buff=0.08
|
||||||
|
)
|
||||||
|
parts.append(role_label)
|
||||||
|
return VGroup(*parts)
|
||||||
|
|
||||||
|
|
||||||
|
def product_suit_card(
|
||||||
|
suit: str,
|
||||||
|
scale: int,
|
||||||
|
accent: str,
|
||||||
|
width: float = 1.86,
|
||||||
|
height: float = 1.04,
|
||||||
|
show_label: bool = False,
|
||||||
|
) -> tuple[VGroup, Text]:
|
||||||
|
frame = RoundedRectangle(corner_radius=0.08, width=width, height=height)
|
||||||
|
frame.set_stroke(color=AXIS_INK, width=2.0)
|
||||||
|
frame.set_fill(color="#FFFFFF", opacity=1.0)
|
||||||
|
|
||||||
|
suit_left = Text(suit, font_size=28, color=accent).move_to(
|
||||||
|
frame.get_left() + RIGHT * 0.22
|
||||||
|
)
|
||||||
|
suit_right = Text(suit, font_size=28, color=accent).move_to(
|
||||||
|
frame.get_right() + LEFT * 0.22
|
||||||
|
)
|
||||||
|
scale_text = Text(
|
||||||
|
rank_from_scale(scale),
|
||||||
|
font_size=40,
|
||||||
|
weight="BOLD",
|
||||||
|
color=accent,
|
||||||
|
).move_to(frame.get_center())
|
||||||
|
|
||||||
|
parts = [frame, suit_left, suit_right, scale_text]
|
||||||
|
if show_label:
|
||||||
|
scale_label = Text("scale", font_size=14, color=GREY_B).next_to(
|
||||||
|
frame, DOWN, buff=0.04
|
||||||
|
)
|
||||||
|
parts.append(scale_label)
|
||||||
|
return VGroup(*parts), scale_text
|
||||||
|
|
||||||
|
|
||||||
|
def private_valuation_card(value: int, show_label: bool = False) -> VGroup:
|
||||||
|
frame = RoundedRectangle(corner_radius=0.08, width=1.86, height=1.04)
|
||||||
|
frame.set_stroke(color=AXIS_INK, width=2.0)
|
||||||
|
frame.set_fill(color="#FFFFFF", opacity=1.0)
|
||||||
|
|
||||||
|
rank = Text(
|
||||||
|
rank_from_scale(value), font_size=40, weight="BOLD", color=GREEN_C
|
||||||
|
).move_to(frame.get_center())
|
||||||
|
left_tag = Text("v", font_size=28, color=INK).move_to(
|
||||||
|
frame.get_left() + RIGHT * 0.22
|
||||||
|
)
|
||||||
|
right_tag = Text("*", font_size=28, color=INK).move_to(
|
||||||
|
frame.get_right() + LEFT * 0.22
|
||||||
|
)
|
||||||
|
|
||||||
|
parts = [frame, left_tag, right_tag, rank]
|
||||||
|
if show_label:
|
||||||
|
title = Text("private value", font_size=14, color=GREY_B).next_to(
|
||||||
|
frame, DOWN, buff=0.04
|
||||||
|
)
|
||||||
|
parts.append(title)
|
||||||
|
return VGroup(*parts)
|
||||||
23
paper/defense/manim/defense.py
Normal file
23
paper/defense/manim/defense.py
Normal file
@@ -0,0 +1,23 @@
|
|||||||
|
"""Manim entry module only.
|
||||||
|
|
||||||
|
Scene implementations are in scenes/main.py and scenes/appendix.py. Manim names
|
||||||
|
output folders after the file you pass to the CLI; pointing everything at this
|
||||||
|
file keeps all MP4s under media/videos/defense/ instead of splitting by source file.
|
||||||
|
"""
|
||||||
|
|
||||||
|
from __future__ import annotations
|
||||||
|
|
||||||
|
import importlib
|
||||||
|
|
||||||
|
from manim import Scene
|
||||||
|
|
||||||
|
_modname = __name__
|
||||||
|
|
||||||
|
for _mod in ("scenes.main", "scenes.appendix"):
|
||||||
|
m = importlib.import_module(_mod)
|
||||||
|
for _name, _val in list(vars(m).items()):
|
||||||
|
if _name.startswith("_"):
|
||||||
|
continue
|
||||||
|
if isinstance(_val, type) and issubclass(_val, Scene) and _val is not Scene:
|
||||||
|
_val.__module__ = _modname
|
||||||
|
globals()[_name] = _val
|
||||||
14
paper/defense/manim/defense_scene_order.txt
Normal file
14
paper/defense/manim/defense_scene_order.txt
Normal file
@@ -0,0 +1,14 @@
|
|||||||
|
# One scene name per line; order matches `python src/render.py --group final-full`.
|
||||||
|
# Used by scripts/ffmpeg_concat_defense.sh after rendering.
|
||||||
|
DefenseOpening
|
||||||
|
CardMarketAnalogyScene
|
||||||
|
COIFirstPrinciplesScene
|
||||||
|
COIOrderStatisticProofScene
|
||||||
|
BehaviorKernelConstructionScene
|
||||||
|
SeparabilitySignalScene
|
||||||
|
ContaminationGeneratorScene
|
||||||
|
RewardAndLeakageScene
|
||||||
|
StackelbergAmbiguityScene
|
||||||
|
RobustControlScene
|
||||||
|
SystemLoopScene
|
||||||
|
ObjectiveAndResultsScene
|
||||||
47
paper/defense/manim/project.json
Normal file
47
paper/defense/manim/project.json
Normal file
@@ -0,0 +1,47 @@
|
|||||||
|
{
|
||||||
|
"$schema": "../../../node_modules/nx/schemas/project-schema.json",
|
||||||
|
"name": "manim",
|
||||||
|
"projectType": "application",
|
||||||
|
"sourceRoot": "paper/defense/manim",
|
||||||
|
"targets": {
|
||||||
|
"render": {
|
||||||
|
"executor": "nx:run-commands",
|
||||||
|
"options": {
|
||||||
|
"command": "bash -c 'source ../.venv/bin/activate && PYTHONPATH=. python render.py'",
|
||||||
|
"cwd": "paper/defense/manim"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"render-all": {
|
||||||
|
"executor": "nx:run-commands",
|
||||||
|
"options": {
|
||||||
|
"command": "bash -c 'source ../.venv/bin/activate && PYTHONPATH=. python render.py --all'",
|
||||||
|
"cwd": "paper/defense/manim"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"render-full": {
|
||||||
|
"executor": "nx:run-commands",
|
||||||
|
"options": {
|
||||||
|
"command": "bash -c 'source ../.venv/bin/activate && PYTHONPATH=. python render.py --group final-full'",
|
||||||
|
"cwd": "paper/defense/manim"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"render-poster": {
|
||||||
|
"executor": "nx:run-commands",
|
||||||
|
"options": {
|
||||||
|
"command": "bash -c 'source ../.venv/bin/activate && PYTHONPATH=. python render.py --group poster'",
|
||||||
|
"cwd": "paper/defense/manim"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"render-appendix": {
|
||||||
|
"executor": "nx:run-commands",
|
||||||
|
"options": {
|
||||||
|
"command": "bash -c 'source ../.venv/bin/activate && PYTHONPATH=. python render.py --group behavior-appendix && PYTHONPATH=. python render.py --group coi-appendix'",
|
||||||
|
"cwd": "paper/defense/manim"
|
||||||
|
}
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"tags": [
|
||||||
|
"scope:presentation",
|
||||||
|
"type:manim"
|
||||||
|
]
|
||||||
|
}
|
||||||
176
paper/defense/manim/render.py
Normal file
176
paper/defense/manim/render.py
Normal file
@@ -0,0 +1,176 @@
|
|||||||
|
from __future__ import annotations
|
||||||
|
|
||||||
|
import argparse
|
||||||
|
import os
|
||||||
|
import subprocess
|
||||||
|
import sys
|
||||||
|
from pathlib import Path
|
||||||
|
|
||||||
|
from scenes.appendix import BEHAVIOR_SCENES, COI_SCENES
|
||||||
|
from scenes.main import POSTER_SCENES, SCENE_ORDER as MAIN_SCENES
|
||||||
|
|
||||||
|
# ---------------------------------------------------------------------------
|
||||||
|
# Batch render: groups are just ordered lists of scene class names.
|
||||||
|
# Every scene is rendered via defense.py so outputs stay in media/videos/defense/.
|
||||||
|
# Scene code itself lives in scenes/main.py and scenes/appendix.py.
|
||||||
|
# ---------------------------------------------------------------------------
|
||||||
|
|
||||||
|
|
||||||
|
def _ordered_unique(items: list[str]) -> list[str]:
|
||||||
|
seen: set[str] = set()
|
||||||
|
return [item for item in items if not (item in seen or seen.add(item))]
|
||||||
|
|
||||||
|
|
||||||
|
FINAL_CORE = [
|
||||||
|
"DefenseOpening",
|
||||||
|
"CardMarketAnalogyScene",
|
||||||
|
"COIFirstPrinciplesScene",
|
||||||
|
"COIOrderStatisticProofScene",
|
||||||
|
"BehaviorKernelConstructionScene",
|
||||||
|
"SeparabilitySignalScene",
|
||||||
|
"ContaminationGeneratorScene",
|
||||||
|
"RewardAndLeakageScene",
|
||||||
|
"StackelbergAmbiguityScene",
|
||||||
|
"RobustControlScene",
|
||||||
|
"SystemLoopScene",
|
||||||
|
"ObjectiveAndResultsScene",
|
||||||
|
]
|
||||||
|
|
||||||
|
SCENE_GROUPS: dict[str, list[str]] = {
|
||||||
|
"poster": list(POSTER_SCENES),
|
||||||
|
"final-core": FINAL_CORE,
|
||||||
|
"final-full": list(MAIN_SCENES),
|
||||||
|
"behavior-appendix": list(BEHAVIOR_SCENES),
|
||||||
|
"coi-appendix": list(COI_SCENES),
|
||||||
|
}
|
||||||
|
|
||||||
|
SCENE_GROUPS["all"] = _ordered_unique(
|
||||||
|
[
|
||||||
|
*SCENE_GROUPS["final-full"],
|
||||||
|
*SCENE_GROUPS["poster"],
|
||||||
|
*SCENE_GROUPS["behavior-appendix"],
|
||||||
|
*SCENE_GROUPS["coi-appendix"],
|
||||||
|
]
|
||||||
|
)
|
||||||
|
|
||||||
|
ENTRY = "defense.py"
|
||||||
|
SCENE_TO_FILE: dict[str, str] = {name: ENTRY for name in SCENE_GROUPS["all"]}
|
||||||
|
|
||||||
|
DEFAULT_GROUP = "final-core"
|
||||||
|
|
||||||
|
|
||||||
|
def parse_args() -> argparse.Namespace:
|
||||||
|
parser = argparse.ArgumentParser(
|
||||||
|
description=(
|
||||||
|
"Batch-render scenes. Code: scenes/main.py + scenes/appendix.py. "
|
||||||
|
"Manim entry: defense.py. Output: media/videos/defense/<quality>/"
|
||||||
|
)
|
||||||
|
)
|
||||||
|
parser.add_argument(
|
||||||
|
"--quality",
|
||||||
|
default="qm",
|
||||||
|
choices=["ql", "qm", "qh", "qk"],
|
||||||
|
help="Manim quality preset",
|
||||||
|
)
|
||||||
|
selection = parser.add_mutually_exclusive_group()
|
||||||
|
selection.add_argument(
|
||||||
|
"--scene",
|
||||||
|
action="append",
|
||||||
|
dest="scenes",
|
||||||
|
help="Scene name; repeat to render many",
|
||||||
|
)
|
||||||
|
selection.add_argument(
|
||||||
|
"--group",
|
||||||
|
choices=sorted(SCENE_GROUPS.keys()),
|
||||||
|
default=DEFAULT_GROUP,
|
||||||
|
help=f"Named list of scenes (default: {DEFAULT_GROUP})",
|
||||||
|
)
|
||||||
|
selection.add_argument("--all", action="store_true", help="Render every scene")
|
||||||
|
parser.add_argument(
|
||||||
|
"--media-dir",
|
||||||
|
default="media",
|
||||||
|
help="Relative to this folder (default: media)",
|
||||||
|
)
|
||||||
|
parser.add_argument("--preview", action="store_true", help="Open each video")
|
||||||
|
parser.add_argument("--list", action="store_true", help="Print groups and exit")
|
||||||
|
return parser.parse_args()
|
||||||
|
|
||||||
|
|
||||||
|
def validate_requested(requested: list[str]) -> list[str]:
|
||||||
|
missing = [name for name in requested if name not in SCENE_TO_FILE]
|
||||||
|
if missing:
|
||||||
|
choices = ", ".join(SCENE_TO_FILE.keys())
|
||||||
|
raise ValueError(
|
||||||
|
f"Unknown scenes: {', '.join(missing)}\nAvailable choices: {choices}"
|
||||||
|
)
|
||||||
|
return requested
|
||||||
|
|
||||||
|
|
||||||
|
def resolve_scenes(args: argparse.Namespace) -> list[str]:
|
||||||
|
if args.all:
|
||||||
|
return list(SCENE_GROUPS["all"])
|
||||||
|
if args.scenes:
|
||||||
|
return validate_requested(args.scenes)
|
||||||
|
return list(SCENE_GROUPS[args.group])
|
||||||
|
|
||||||
|
|
||||||
|
def run_manim(
|
||||||
|
scene_file: Path,
|
||||||
|
scene_name: str,
|
||||||
|
quality: str,
|
||||||
|
preview: bool,
|
||||||
|
working_dir: Path,
|
||||||
|
media_dir: str,
|
||||||
|
pythonpath: str,
|
||||||
|
) -> None:
|
||||||
|
env = os.environ.copy()
|
||||||
|
prev = env.get("PYTHONPATH")
|
||||||
|
env["PYTHONPATH"] = pythonpath if not prev else f"{pythonpath}:{prev}"
|
||||||
|
|
||||||
|
cmd = [sys.executable, "-m", "manim"]
|
||||||
|
if preview:
|
||||||
|
cmd.append("-p")
|
||||||
|
cmd.extend(["--media_dir", media_dir])
|
||||||
|
cmd.extend([f"-{quality}", str(scene_file), scene_name])
|
||||||
|
subprocess.run(cmd, cwd=working_dir, check=True, env=env)
|
||||||
|
|
||||||
|
|
||||||
|
def main() -> int:
|
||||||
|
args = parse_args()
|
||||||
|
if args.list:
|
||||||
|
for group_name in sorted(SCENE_GROUPS):
|
||||||
|
print(f"[{group_name}]")
|
||||||
|
for scene in SCENE_GROUPS[group_name]:
|
||||||
|
print(f" {scene}")
|
||||||
|
return 0
|
||||||
|
|
||||||
|
root = Path(__file__).resolve().parent
|
||||||
|
py_path = str(root)
|
||||||
|
names = resolve_scenes(args)
|
||||||
|
|
||||||
|
try:
|
||||||
|
for scene_name in names:
|
||||||
|
scene_file = root / SCENE_TO_FILE[scene_name]
|
||||||
|
run_manim(
|
||||||
|
scene_file=scene_file,
|
||||||
|
scene_name=scene_name,
|
||||||
|
quality=args.quality,
|
||||||
|
preview=args.preview,
|
||||||
|
working_dir=root,
|
||||||
|
media_dir=args.media_dir,
|
||||||
|
pythonpath=py_path,
|
||||||
|
)
|
||||||
|
except FileNotFoundError:
|
||||||
|
print("manim not found.", file=sys.stderr)
|
||||||
|
return 2
|
||||||
|
except ValueError as exc:
|
||||||
|
print(str(exc), file=sys.stderr)
|
||||||
|
return 2
|
||||||
|
except subprocess.CalledProcessError as exc:
|
||||||
|
return exc.returncode
|
||||||
|
|
||||||
|
return 0
|
||||||
|
|
||||||
|
|
||||||
|
if __name__ == "__main__":
|
||||||
|
raise SystemExit(main())
|
||||||
89
paper/defense/manim/render_defense
Executable file
89
paper/defense/manim/render_defense
Executable file
@@ -0,0 +1,89 @@
|
|||||||
|
#!/usr/bin/env bash
|
||||||
|
# Render thesis-defense Manim clips. Run from anywhere (script cd's to its dir).
|
||||||
|
#
|
||||||
|
# ./render_defense # main reel: final-full, medium quality
|
||||||
|
# ./render_defense --quality qh # high quality for recording
|
||||||
|
# ./render_defense core # shorter committee cut (final-core)
|
||||||
|
# ./render_defense all # everything: main + poster + both appendices
|
||||||
|
# ./render_defense appendix # behavior + COI appendix only
|
||||||
|
# ./render_defense poster
|
||||||
|
# ./render_defense list
|
||||||
|
# ./render_defense --scene DefenseOpening --scene CardMarketAnalogyScene
|
||||||
|
#
|
||||||
|
# Env: MANIM_PYTHON=/path/to/python overrides auto-detected venv.
|
||||||
|
|
||||||
|
set -euo pipefail
|
||||||
|
|
||||||
|
ROOT="$(cd "$(dirname "$0")" && pwd)"
|
||||||
|
cd "$ROOT"
|
||||||
|
|
||||||
|
if [[ -n "${MANIM_PYTHON:-}" ]]; then
|
||||||
|
PY="$MANIM_PYTHON"
|
||||||
|
elif [[ -x "$ROOT/../.venv/bin/python" ]]; then
|
||||||
|
PY="$ROOT/../.venv/bin/python"
|
||||||
|
else
|
||||||
|
PY="$(command -v python3 2>/dev/null || command -v python)"
|
||||||
|
fi
|
||||||
|
|
||||||
|
if [[ ! -x "$PY" ]] && ! command -v "$PY" &>/dev/null; then
|
||||||
|
echo "No Python found. Set MANIM_PYTHON or create paper/defense/.venv" >&2
|
||||||
|
exit 1
|
||||||
|
fi
|
||||||
|
|
||||||
|
export PYTHONPATH="$ROOT"
|
||||||
|
|
||||||
|
run() {
|
||||||
|
"$PY" "$ROOT/render.py" "$@"
|
||||||
|
}
|
||||||
|
|
||||||
|
CMD=full
|
||||||
|
case "${1-}" in
|
||||||
|
full|core|all|appendix|poster|list|help|-h|--help)
|
||||||
|
CMD="$1"
|
||||||
|
shift
|
||||||
|
;;
|
||||||
|
esac
|
||||||
|
|
||||||
|
case "$CMD" in
|
||||||
|
help|-h|--help)
|
||||||
|
cat <<'EOF'
|
||||||
|
Render thesis-defense Manim clips (cd to paper/defense/manim is automatic).
|
||||||
|
|
||||||
|
./render_defense main reel (final-full), default quality qm
|
||||||
|
./render_defense --quality qh same, high quality for recording
|
||||||
|
./render_defense core shorter cut (final-core)
|
||||||
|
./render_defense all main + poster + both appendices
|
||||||
|
./render_defense appendix behavior-appendix + coi-appendix
|
||||||
|
./render_defense poster
|
||||||
|
./render_defense list scene names and source files
|
||||||
|
./render_defense --scene Name [--scene Name2 ...]
|
||||||
|
|
||||||
|
Env MANIM_PYTHON overrides Python (default: ../.venv/bin/python next to this dir).
|
||||||
|
EOF
|
||||||
|
exit 0
|
||||||
|
;;
|
||||||
|
list)
|
||||||
|
run --list "$@"
|
||||||
|
exit 0
|
||||||
|
;;
|
||||||
|
full)
|
||||||
|
run --group final-full "$@"
|
||||||
|
;;
|
||||||
|
core)
|
||||||
|
run --group final-core "$@"
|
||||||
|
;;
|
||||||
|
all)
|
||||||
|
run --all "$@"
|
||||||
|
;;
|
||||||
|
appendix)
|
||||||
|
run --group behavior-appendix "$@"
|
||||||
|
run --group coi-appendix "$@"
|
||||||
|
;;
|
||||||
|
poster)
|
||||||
|
run --group poster "$@"
|
||||||
|
;;
|
||||||
|
*)
|
||||||
|
echo "Unknown command: $CMD" >&2
|
||||||
|
exit 1
|
||||||
|
;;
|
||||||
|
esac
|
||||||
0
paper/defense/manim/scenes/__init__.py
Normal file
0
paper/defense/manim/scenes/__init__.py
Normal file
670
paper/defense/manim/scenes/appendix.py
Normal file
670
paper/defense/manim/scenes/appendix.py
Normal file
@@ -0,0 +1,670 @@
|
|||||||
|
from __future__ import annotations
|
||||||
|
|
||||||
|
import numpy as np
|
||||||
|
from manim import *
|
||||||
|
from common import AXIS_INK, HIGHLIGHT, INK, P_MAX, P_MIN, card, normal_pdf, scene_title, to_matrix
|
||||||
|
|
||||||
|
|
||||||
|
class LogsToKernelsScene(Scene):
|
||||||
|
def construct(self):
|
||||||
|
title = scene_title("From Event Logs to Transition Kernels")
|
||||||
|
self.play(Write(title))
|
||||||
|
|
||||||
|
# 1. Logs
|
||||||
|
log_lines = VGroup(
|
||||||
|
Text('{"session": "H1", "event": "start"}', font="monospace", font_size=16),
|
||||||
|
Text('{"session": "A1", "event": "start"}', font="monospace", font_size=16),
|
||||||
|
Text('{"session": "H1", "event": "view"}', font="monospace", font_size=16),
|
||||||
|
Text('{"session": "A1", "event": "view"}', font="monospace", font_size=16),
|
||||||
|
Text(
|
||||||
|
'{"session": "H1", "event": "detail"}', font="monospace", font_size=16
|
||||||
|
),
|
||||||
|
Text(
|
||||||
|
'{"session": "A1", "event": "detail"}', font="monospace", font_size=16
|
||||||
|
),
|
||||||
|
Text('{"session": "H1", "event": "cart"}', font="monospace", font_size=16),
|
||||||
|
Text('{"session": "A1", "event": "view"}', font="monospace", font_size=16),
|
||||||
|
Text('{"session": "H1", "event": "buy"}', font="monospace", font_size=16),
|
||||||
|
Text(
|
||||||
|
'{"session": "A1", "event": "detail"}', font="monospace", font_size=16
|
||||||
|
),
|
||||||
|
).arrange(DOWN, aligned_edge=LEFT, buff=0.1)
|
||||||
|
log_lines.to_edge(LEFT, buff=1.0).shift(UP * 0.5)
|
||||||
|
|
||||||
|
self.play(
|
||||||
|
LaggedStart(
|
||||||
|
*[FadeIn(line, shift=UP * 0.1) for line in log_lines], lag_ratio=0.1
|
||||||
|
)
|
||||||
|
)
|
||||||
|
self.wait(0.5)
|
||||||
|
|
||||||
|
# 2. Nodes in a grid
|
||||||
|
def create_node(text, color):
|
||||||
|
circ = Circle(radius=0.4, color=color, fill_opacity=0.2)
|
||||||
|
lbl = Text(text, font_size=14).move_to(circ)
|
||||||
|
return VGroup(circ, lbl)
|
||||||
|
|
||||||
|
h_states = ["start", "view", "detail", "cart", "buy"]
|
||||||
|
a_states = ["start", "view", "detail", "view", "detail"]
|
||||||
|
|
||||||
|
h_nodes = VGroup(*[create_node(s, BLUE_D) for s in h_states]).arrange(
|
||||||
|
RIGHT, buff=0.5
|
||||||
|
)
|
||||||
|
a_nodes = VGroup(*[create_node(s, RED_C) for s in a_states]).arrange(
|
||||||
|
RIGHT, buff=0.5
|
||||||
|
)
|
||||||
|
|
||||||
|
trajectories = VGroup(h_nodes, a_nodes).arrange(DOWN, buff=1.0)
|
||||||
|
trajectories.to_edge(RIGHT, buff=1.0).shift(UP * 0.5)
|
||||||
|
|
||||||
|
h_label = Text("Human Trajectory", font_size=18, color=BLUE_D).next_to(
|
||||||
|
h_nodes, UP
|
||||||
|
)
|
||||||
|
a_label = Text("Agent Trajectory", font_size=18, color=RED_C).next_to(
|
||||||
|
a_nodes, UP
|
||||||
|
)
|
||||||
|
|
||||||
|
self.play(
|
||||||
|
ReplacementTransform(log_lines[0::2], h_nodes),
|
||||||
|
ReplacementTransform(log_lines[1::2], a_nodes),
|
||||||
|
FadeIn(h_label),
|
||||||
|
FadeIn(a_label),
|
||||||
|
)
|
||||||
|
|
||||||
|
# Add connecting lines
|
||||||
|
h_lines = VGroup(
|
||||||
|
*[
|
||||||
|
Line(h_nodes[i].get_right(), h_nodes[i + 1].get_left(), color=BLUE_D)
|
||||||
|
for i in range(len(h_nodes) - 1)
|
||||||
|
]
|
||||||
|
)
|
||||||
|
a_lines = VGroup(
|
||||||
|
*[
|
||||||
|
Line(a_nodes[i].get_right(), a_nodes[i + 1].get_left(), color=RED_C)
|
||||||
|
for i in range(len(a_nodes) - 1)
|
||||||
|
]
|
||||||
|
)
|
||||||
|
|
||||||
|
self.play(Create(h_lines), Create(a_lines))
|
||||||
|
self.wait(1)
|
||||||
|
|
||||||
|
# 3. Counts to Kernel
|
||||||
|
mle_text = MathTex(
|
||||||
|
r"\hat P(s'\mid s) = \frac{N(s,s')}{\sum_k N(s,k)}",
|
||||||
|
font_size=36,
|
||||||
|
color=HIGHLIGHT,
|
||||||
|
)
|
||||||
|
mle_text.next_to(trajectories, DOWN, buff=0.8)
|
||||||
|
self.play(Write(mle_text))
|
||||||
|
|
||||||
|
counts = to_matrix(
|
||||||
|
[
|
||||||
|
[0, 8, 0, 0],
|
||||||
|
[0, 2, 5, 1],
|
||||||
|
[0, 3, 2, 4],
|
||||||
|
[0, 1, 0, 6],
|
||||||
|
],
|
||||||
|
"Count Matrix N",
|
||||||
|
color=BLUE_D,
|
||||||
|
fmt=".0f",
|
||||||
|
)
|
||||||
|
|
||||||
|
probs = to_matrix(
|
||||||
|
[
|
||||||
|
[0.00, 1.00, 0.00, 0.00],
|
||||||
|
[0.00, 0.25, 0.62, 0.13],
|
||||||
|
[0.00, 0.33, 0.22, 0.45],
|
||||||
|
[0.00, 0.14, 0.00, 0.86],
|
||||||
|
],
|
||||||
|
"Kernel T",
|
||||||
|
color=GREEN_C,
|
||||||
|
)
|
||||||
|
|
||||||
|
mats = VGroup(counts, probs).arrange(RIGHT, buff=1.5).scale(0.65)
|
||||||
|
|
||||||
|
arrow = Arrow(counts.get_right(), probs.get_left(), buff=0.2)
|
||||||
|
arrow_lbl = MathTex(
|
||||||
|
r"\text{normalize}", font_size=18, color=GREY_B
|
||||||
|
).next_to(arrow, UP)
|
||||||
|
|
||||||
|
# clear top half to make space if needed
|
||||||
|
self.play(
|
||||||
|
FadeOut(h_nodes),
|
||||||
|
FadeOut(a_nodes),
|
||||||
|
FadeOut(h_lines),
|
||||||
|
FadeOut(a_lines),
|
||||||
|
FadeOut(h_label),
|
||||||
|
FadeOut(a_label),
|
||||||
|
mle_text.animate.to_edge(UP, buff=1.5).set_x(0),
|
||||||
|
)
|
||||||
|
mats.next_to(mle_text, DOWN, buff=0.5)
|
||||||
|
arrow.move_to((counts.get_right() + probs.get_left()) / 2)
|
||||||
|
arrow_lbl.next_to(arrow, UP)
|
||||||
|
|
||||||
|
self.play(FadeIn(counts, shift=UP * 0.2))
|
||||||
|
self.play(GrowArrow(arrow), FadeIn(arrow_lbl))
|
||||||
|
self.play(FadeIn(probs, shift=UP * 0.2))
|
||||||
|
self.wait(1)
|
||||||
|
|
||||||
|
|
||||||
|
class KLSeparabilityAndSignificanceScene(Scene):
|
||||||
|
def construct(self):
|
||||||
|
title = scene_title("Behavioral Separability & Significance")
|
||||||
|
self.play(Write(title))
|
||||||
|
|
||||||
|
human_mat = to_matrix(
|
||||||
|
[
|
||||||
|
[0.05, 0.70, 0.20, 0.05],
|
||||||
|
[0.05, 0.20, 0.60, 0.15],
|
||||||
|
[0.10, 0.25, 0.30, 0.35],
|
||||||
|
[0.00, 0.00, 0.00, 1.00],
|
||||||
|
],
|
||||||
|
"Human Centroid T_H",
|
||||||
|
BLUE_D,
|
||||||
|
).scale(0.7)
|
||||||
|
|
||||||
|
agent_mat = to_matrix(
|
||||||
|
[
|
||||||
|
[0.03, 0.82, 0.12, 0.03],
|
||||||
|
[0.06, 0.55, 0.21, 0.18],
|
||||||
|
[0.08, 0.48, 0.14, 0.30],
|
||||||
|
[0.00, 0.00, 0.00, 1.00],
|
||||||
|
],
|
||||||
|
"Agent Centroid T_A",
|
||||||
|
RED_C,
|
||||||
|
).scale(0.7)
|
||||||
|
|
||||||
|
centroids = VGroup(human_mat, agent_mat).arrange(RIGHT, buff=1.0)
|
||||||
|
centroids.next_to(title, DOWN, buff=0.5)
|
||||||
|
self.play(FadeIn(centroids, shift=DOWN * 0.2))
|
||||||
|
|
||||||
|
# Trajectory
|
||||||
|
t_prime = MathTex(r"\hat T'", font_size=36, color=HIGHLIGHT)
|
||||||
|
d_h = MathTex(r"\Delta_H = D_{KL}(\hat T' \parallel \bar T_H)", font_size=32)
|
||||||
|
d_a = MathTex(r"\Delta_A = D_{KL}(\hat T' \parallel \bar T_A)", font_size=32)
|
||||||
|
gap = MathTex(r"g = \Delta_H - \Delta_A", font_size=36, color=HIGHLIGHT)
|
||||||
|
|
||||||
|
eqs = VGroup(t_prime, d_h, d_a, gap).arrange(DOWN, buff=0.2)
|
||||||
|
eqs.to_edge(LEFT, buff=1.0).shift(DOWN * 1.0)
|
||||||
|
|
||||||
|
self.play(Write(eqs))
|
||||||
|
|
||||||
|
# Distributions
|
||||||
|
axis = (
|
||||||
|
Axes(
|
||||||
|
x_range=[-8, 8, 2],
|
||||||
|
y_range=[0, 0.2, 0.05],
|
||||||
|
x_length=6,
|
||||||
|
y_length=3,
|
||||||
|
tips=False,
|
||||||
|
axis_config={"color": AXIS_INK, "stroke_width": 2},
|
||||||
|
)
|
||||||
|
.to_edge(RIGHT, buff=1.0)
|
||||||
|
.shift(DOWN * 1.0)
|
||||||
|
)
|
||||||
|
|
||||||
|
mu_h, sig_h = -3.5, 2.0
|
||||||
|
mu_a, sig_a = 3.5, 2.0
|
||||||
|
|
||||||
|
h_curve = axis.plot(
|
||||||
|
lambda x: normal_pdf(x, mu_h, sig_h), color=BLUE_D, stroke_width=4
|
||||||
|
)
|
||||||
|
a_curve = axis.plot(
|
||||||
|
lambda x: normal_pdf(x, mu_a, sig_a), color=RED_C, stroke_width=4
|
||||||
|
)
|
||||||
|
|
||||||
|
h_lbl = (
|
||||||
|
Text("Human", color=BLUE_D, font_size=20)
|
||||||
|
.next_to(h_curve, UP, buff=-0.5)
|
||||||
|
.shift(LEFT * 1)
|
||||||
|
)
|
||||||
|
a_lbl = (
|
||||||
|
Text("Agent", color=RED_C, font_size=20)
|
||||||
|
.next_to(a_curve, UP, buff=-0.5)
|
||||||
|
.shift(RIGHT * 1)
|
||||||
|
)
|
||||||
|
|
||||||
|
boundary = DashedLine(axis.c2p(0, 0), axis.c2p(0, 0.18), color=GREY_B)
|
||||||
|
|
||||||
|
self.play(FadeIn(axis))
|
||||||
|
self.play(Create(h_curve), Create(a_curve))
|
||||||
|
self.play(FadeIn(h_lbl), FadeIn(a_lbl), FadeIn(boundary))
|
||||||
|
|
||||||
|
sig_text = MathTex(
|
||||||
|
r"p<10^{-3}\ \text{(Mann--Whitney)}", font_size=24, color=GREEN_C
|
||||||
|
)
|
||||||
|
sig_text.next_to(axis, DOWN, buff=0.3)
|
||||||
|
self.play(Write(sig_text))
|
||||||
|
self.wait(1)
|
||||||
|
|
||||||
|
|
||||||
|
class TrajectorySamplingScene(Scene):
|
||||||
|
def construct(self):
|
||||||
|
title = scene_title("Generative Trajectory Sampling")
|
||||||
|
self.play(Write(title))
|
||||||
|
|
||||||
|
agent_mat = to_matrix(
|
||||||
|
[
|
||||||
|
[0.00, 0.80, 0.20, 0.00, 0.00],
|
||||||
|
[0.00, 0.30, 0.50, 0.20, 0.00],
|
||||||
|
[0.00, 0.40, 0.30, 0.30, 0.00],
|
||||||
|
[0.00, 0.10, 0.10, 0.10, 0.70],
|
||||||
|
[0.00, 0.00, 0.00, 0.00, 1.00],
|
||||||
|
],
|
||||||
|
"Agent Kernel T_A",
|
||||||
|
RED_C,
|
||||||
|
).scale(0.6)
|
||||||
|
agent_mat.to_edge(LEFT, buff=1.0)
|
||||||
|
|
||||||
|
self.play(FadeIn(agent_mat))
|
||||||
|
|
||||||
|
states = ["Start", "View", "Detail", "Cart", "Buy"]
|
||||||
|
|
||||||
|
def create_node(text):
|
||||||
|
circ = Circle(radius=0.4, color=AXIS_INK, fill_opacity=0.1)
|
||||||
|
lbl = Text(text, font_size=16).move_to(circ)
|
||||||
|
return VGroup(circ, lbl)
|
||||||
|
|
||||||
|
nodes = VGroup(*[create_node(s) for s in states]).arrange(RIGHT, buff=0.6)
|
||||||
|
nodes.to_edge(RIGHT, buff=0.5).shift(UP * 1.0)
|
||||||
|
|
||||||
|
self.play(FadeIn(nodes))
|
||||||
|
|
||||||
|
# Output trajectory string
|
||||||
|
traj_label = (
|
||||||
|
Text("Sampled Trajectory:", font_size=24, color=HIGHLIGHT)
|
||||||
|
.to_edge(DOWN)
|
||||||
|
.shift(UP * 1.5 + LEFT * 1)
|
||||||
|
)
|
||||||
|
self.play(FadeIn(traj_label))
|
||||||
|
|
||||||
|
walker = Dot(color=HIGHLIGHT, radius=0.15)
|
||||||
|
walker.move_to(nodes[0].get_top() + UP * 0.2)
|
||||||
|
|
||||||
|
self.play(FadeIn(walker))
|
||||||
|
|
||||||
|
# Simulation
|
||||||
|
path = [0, 1, 2, 1, 2] # Start -> View -> Detail -> View -> Detail
|
||||||
|
|
||||||
|
# We will build the string
|
||||||
|
current_traj = VGroup(Text("Start", font_size=24, color=RED_C)).next_to(
|
||||||
|
traj_label, RIGHT
|
||||||
|
)
|
||||||
|
self.play(FadeIn(current_traj))
|
||||||
|
|
||||||
|
for i in range(len(path) - 1):
|
||||||
|
curr_state = path[i]
|
||||||
|
next_state = path[i + 1]
|
||||||
|
|
||||||
|
# highlight row
|
||||||
|
mat_core = agent_mat[2] # the matrix itself
|
||||||
|
|
||||||
|
# Using get_rows() which is standard in Mobject Matrix
|
||||||
|
row_entries = mat_core.get_rows()[curr_state]
|
||||||
|
row_rect = SurroundingRectangle(row_entries, color=HIGHLIGHT, buff=0.1)
|
||||||
|
self.play(Create(row_rect), run_time=0.5)
|
||||||
|
|
||||||
|
# move walker
|
||||||
|
arc = CurvedArrow(
|
||||||
|
walker.get_center(),
|
||||||
|
nodes[next_state].get_top() + UP * 0.2,
|
||||||
|
angle=-TAU / 4,
|
||||||
|
)
|
||||||
|
self.play(MoveAlongPath(walker, arc), run_time=1.0)
|
||||||
|
|
||||||
|
# Update string
|
||||||
|
arrow_str = MathTex(r"\rightarrow", font_size=24).next_to(
|
||||||
|
current_traj, RIGHT
|
||||||
|
)
|
||||||
|
next_str = Text(states[next_state], font_size=24, color=RED_C).next_to(
|
||||||
|
arrow_str, RIGHT
|
||||||
|
)
|
||||||
|
|
||||||
|
self.play(
|
||||||
|
FadeIn(arrow_str), FadeIn(next_str), FadeOut(row_rect), run_time=0.5
|
||||||
|
)
|
||||||
|
current_traj.add(arrow_str, next_str)
|
||||||
|
|
||||||
|
self.wait(1)
|
||||||
|
|
||||||
|
|
||||||
|
class KroneckerExpansionScene(Scene):
|
||||||
|
def construct(self):
|
||||||
|
title = scene_title("State-Space Expansion")
|
||||||
|
self.play(Write(title))
|
||||||
|
|
||||||
|
t_mat = to_matrix([[0.2, 0.8], [0.4, 0.6]], "Behavior T", BLUE_D)
|
||||||
|
|
||||||
|
d_mat = to_matrix([[0.9, 0.1], [0.5, 0.5]], "Demand D", RED_C)
|
||||||
|
|
||||||
|
kron_sym = MathTex(r"\otimes", font_size=60)
|
||||||
|
eq_sym = MathTex(r"=", font_size=60)
|
||||||
|
|
||||||
|
lhs = VGroup(t_mat, kron_sym, d_mat).arrange(RIGHT, buff=0.5)
|
||||||
|
lhs.next_to(title, DOWN, buff=1.0)
|
||||||
|
|
||||||
|
self.play(FadeIn(t_mat), FadeIn(d_mat), Write(kron_sym))
|
||||||
|
self.wait(1)
|
||||||
|
|
||||||
|
self.play(lhs.animate.scale(0.6).to_edge(LEFT, buff=0.5))
|
||||||
|
|
||||||
|
# Show expanded
|
||||||
|
# T tensor D
|
||||||
|
expanded = to_matrix(
|
||||||
|
[
|
||||||
|
[0.18, 0.02, 0.72, 0.08],
|
||||||
|
[0.10, 0.10, 0.40, 0.40],
|
||||||
|
[0.36, 0.04, 0.54, 0.06],
|
||||||
|
[0.20, 0.20, 0.30, 0.30],
|
||||||
|
],
|
||||||
|
r"Expanded P = T \otimes D",
|
||||||
|
HIGHLIGHT,
|
||||||
|
).scale(0.6)
|
||||||
|
|
||||||
|
eq_sym.next_to(lhs, RIGHT, buff=0.5)
|
||||||
|
expanded.next_to(eq_sym, RIGHT, buff=0.5)
|
||||||
|
|
||||||
|
self.play(Write(eq_sym), FadeIn(expanded, shift=LEFT * 0.5))
|
||||||
|
|
||||||
|
# Highlight a block
|
||||||
|
# the top right block (0.8 * D)
|
||||||
|
# rows 0,1 cols 2,3
|
||||||
|
# In expanded:
|
||||||
|
# row 0: 0, 1, 2, 3
|
||||||
|
# row 1: 4, 5, 6, 7
|
||||||
|
t_entries = t_mat[2].get_entries()
|
||||||
|
if len(t_entries) >= 2:
|
||||||
|
rect_T = SurroundingRectangle(
|
||||||
|
t_entries[1], color=HIGHLIGHT
|
||||||
|
) # T[0,1] is 0.8
|
||||||
|
else:
|
||||||
|
rect_T = VGroup()
|
||||||
|
|
||||||
|
exp_entries = expanded[2].get_entries()
|
||||||
|
if len(exp_entries) >= 8:
|
||||||
|
block_entries = VGroup(
|
||||||
|
exp_entries[2], exp_entries[3], exp_entries[6], exp_entries[7]
|
||||||
|
)
|
||||||
|
rect_block = SurroundingRectangle(block_entries, color=HIGHLIGHT)
|
||||||
|
else:
|
||||||
|
rect_block = VGroup()
|
||||||
|
|
||||||
|
desc = MathTex(
|
||||||
|
r"P(s', d' \mid s, d)=T(s'\mid s)\,D(d'\mid d, s')",
|
||||||
|
font_size=26,
|
||||||
|
color=HIGHLIGHT,
|
||||||
|
)
|
||||||
|
desc.next_to(expanded, DOWN, buff=0.5)
|
||||||
|
|
||||||
|
if len(t_entries) >= 2 and len(exp_entries) >= 8:
|
||||||
|
self.play(Create(rect_T), Create(rect_block))
|
||||||
|
self.play(Write(desc))
|
||||||
|
self.wait(1)
|
||||||
|
|
||||||
|
|
||||||
|
class SamplingAndReservationScene(Scene):
|
||||||
|
def construct(self):
|
||||||
|
title = scene_title("Pricing Policy & Reservation Price")
|
||||||
|
self.play(Write(title))
|
||||||
|
|
||||||
|
# 1. The setup
|
||||||
|
setup = VGroup(
|
||||||
|
MathTex(r"p_i \sim \pi(p \mid \tau)", font_size=44),
|
||||||
|
MathTex(
|
||||||
|
r"\underline p = \text{reservation price}", font_size=38, color=ORANGE
|
||||||
|
),
|
||||||
|
).arrange(DOWN, aligned_edge=LEFT, buff=0.3)
|
||||||
|
setup.to_edge(LEFT, buff=1.0).shift(UP * 1.0)
|
||||||
|
|
||||||
|
self.play(Write(setup[0]))
|
||||||
|
self.play(Write(setup[1]))
|
||||||
|
|
||||||
|
# 2. Number line sampling
|
||||||
|
number_line = NumberLine(
|
||||||
|
x_range=[P_MIN, P_MAX, 10],
|
||||||
|
length=9.8,
|
||||||
|
color=AXIS_INK,
|
||||||
|
include_numbers=True,
|
||||||
|
decimal_number_config={"num_decimal_places": 0, "color": INK},
|
||||||
|
).shift(DOWN * 1.0)
|
||||||
|
|
||||||
|
self.play(FadeIn(number_line))
|
||||||
|
|
||||||
|
# Floor marker
|
||||||
|
floor_marker = Line(
|
||||||
|
number_line.n2p(P_MIN),
|
||||||
|
number_line.n2p(P_MIN) + UP * 0.85,
|
||||||
|
color=ORANGE,
|
||||||
|
stroke_width=5,
|
||||||
|
)
|
||||||
|
floor_label = MathTex(r"\underline p", color=ORANGE).next_to(
|
||||||
|
floor_marker, UP, buff=0.05
|
||||||
|
)
|
||||||
|
self.play(Create(floor_marker), FadeIn(floor_label))
|
||||||
|
|
||||||
|
# Animate sampling
|
||||||
|
rng = np.random.default_rng(42)
|
||||||
|
n_samples = 5
|
||||||
|
draws = np.sort(rng.beta(2.5, 2.0, size=n_samples) * (P_MAX - P_MIN) + P_MIN)
|
||||||
|
|
||||||
|
dots = VGroup()
|
||||||
|
for i, val in enumerate(draws):
|
||||||
|
# Show drawing process
|
||||||
|
temp_dot = Dot(number_line.n2p(120), radius=0.08, color=BLUE_D).shift(
|
||||||
|
UP * 1.5
|
||||||
|
)
|
||||||
|
self.play(FadeIn(temp_dot), run_time=0.2)
|
||||||
|
|
||||||
|
final_pos = number_line.n2p(float(val))
|
||||||
|
self.play(temp_dot.animate.move_to(final_pos), run_time=0.3)
|
||||||
|
dots.add(temp_dot)
|
||||||
|
|
||||||
|
self.wait(0.5)
|
||||||
|
|
||||||
|
# Highlight minimum
|
||||||
|
min_dot = dots[0]
|
||||||
|
min_highlight = Circle(radius=0.15, color=RED_C).move_to(min_dot)
|
||||||
|
min_tag = MathTex(r"p_{(1)}", color=RED_C).next_to(min_highlight, UP, buff=0.1)
|
||||||
|
|
||||||
|
self.play(Create(min_highlight), Write(min_tag))
|
||||||
|
|
||||||
|
desc = MathTex(
|
||||||
|
r"\text{realized price }p_{(1)}=\min\{p_1,\ldots,p_N\}",
|
||||||
|
font_size=26,
|
||||||
|
color=GREY_B,
|
||||||
|
).to_edge(DOWN)
|
||||||
|
|
||||||
|
self.play(FadeIn(desc, shift=UP * 0.2))
|
||||||
|
self.wait(1.5)
|
||||||
|
|
||||||
|
|
||||||
|
class COIDistributionScene(Scene):
|
||||||
|
def construct(self):
|
||||||
|
title = scene_title("Cost of Information (COI)")
|
||||||
|
self.play(Write(title))
|
||||||
|
|
||||||
|
# COI definition
|
||||||
|
coi_def = MathTex(
|
||||||
|
r"\mathrm{COI} = \mathbb{E}[P] - \underline p",
|
||||||
|
font_size=46,
|
||||||
|
color=HIGHLIGHT,
|
||||||
|
).next_to(title, DOWN, buff=0.5)
|
||||||
|
|
||||||
|
self.play(Write(coi_def))
|
||||||
|
|
||||||
|
# Distribution plot
|
||||||
|
floor_x = 86.0
|
||||||
|
mean_x = 116.0
|
||||||
|
axes = Axes(
|
||||||
|
x_range=[80, 160, 10],
|
||||||
|
y_range=[0.0, 0.04, 0.01],
|
||||||
|
x_length=8.0,
|
||||||
|
y_length=4.0,
|
||||||
|
tips=False,
|
||||||
|
axis_config={"stroke_width": 2, "color": AXIS_INK},
|
||||||
|
).shift(DOWN * 0.5)
|
||||||
|
|
||||||
|
density = axes.plot(
|
||||||
|
lambda x: normal_pdf(x, mean_x, 12.0),
|
||||||
|
x_range=[80, 160],
|
||||||
|
color=BLUE_D,
|
||||||
|
stroke_width=6,
|
||||||
|
)
|
||||||
|
|
||||||
|
area = axes.get_area(density, x_range=[80, 160], color=BLUE_D, opacity=0.2)
|
||||||
|
|
||||||
|
self.play(FadeIn(axes))
|
||||||
|
self.play(Create(density), FadeIn(area))
|
||||||
|
|
||||||
|
# Markers
|
||||||
|
floor_line = DashedLine(
|
||||||
|
axes.c2p(floor_x, 0.0),
|
||||||
|
axes.c2p(floor_x, 0.038),
|
||||||
|
color=ORANGE,
|
||||||
|
stroke_width=4,
|
||||||
|
)
|
||||||
|
mean_line = DashedLine(
|
||||||
|
axes.c2p(mean_x, 0.0),
|
||||||
|
axes.c2p(mean_x, 0.038),
|
||||||
|
color=GREEN_C,
|
||||||
|
stroke_width=4,
|
||||||
|
)
|
||||||
|
|
||||||
|
floor_tag = MathTex(r"\underline p", color=ORANGE).next_to(
|
||||||
|
floor_line, UP, buff=0.1
|
||||||
|
)
|
||||||
|
mean_tag = MathTex(r"\mathbb{E}[P]", color=GREEN_C).next_to(
|
||||||
|
mean_line, UP, buff=0.1
|
||||||
|
)
|
||||||
|
|
||||||
|
self.play(Create(floor_line), Write(floor_tag))
|
||||||
|
self.play(Create(mean_line), Write(mean_tag))
|
||||||
|
|
||||||
|
# COI span
|
||||||
|
coi_arrow = DoubleArrow(
|
||||||
|
axes.c2p(floor_x, 0.02), axes.c2p(mean_x, 0.02), color=HIGHLIGHT, buff=0
|
||||||
|
)
|
||||||
|
coi_label = Text("COI", font_size=24, color=HIGHLIGHT).next_to(
|
||||||
|
coi_arrow, UP, buff=0.1
|
||||||
|
)
|
||||||
|
|
||||||
|
self.play(GrowFromCenter(coi_arrow), Write(coi_label))
|
||||||
|
|
||||||
|
desc = MathTex(
|
||||||
|
r"\mathrm{COI}=\mathbb{E}[P]-\underline p",
|
||||||
|
font_size=28,
|
||||||
|
color=GREY_B,
|
||||||
|
).to_edge(DOWN)
|
||||||
|
|
||||||
|
self.play(FadeIn(desc, shift=UP * 0.2))
|
||||||
|
self.wait(1.5)
|
||||||
|
|
||||||
|
|
||||||
|
class COIErosionMathScene(Scene):
|
||||||
|
def construct(self):
|
||||||
|
title = scene_title("Mathematical Proof of COI Erosion")
|
||||||
|
self.play(Write(title))
|
||||||
|
|
||||||
|
# Step 1: Expected value of minimum
|
||||||
|
eq1 = MathTex(
|
||||||
|
r"\mathbb{E}[p_{(1)}] = \underline p + \int_{\underline p}^{\bar p} \mathbb{P}(p_{(1)} > t) dt",
|
||||||
|
font_size=36,
|
||||||
|
)
|
||||||
|
|
||||||
|
# Step 2: Probability of minimum > t
|
||||||
|
eq2 = MathTex(
|
||||||
|
r"\mathbb{P}(p_{(1)} > t) = \mathbb{P}(p_1 > t) \times \dots \times \mathbb{P}(p_N > t)",
|
||||||
|
font_size=36,
|
||||||
|
)
|
||||||
|
|
||||||
|
# Step 3: Assuming i.i.d
|
||||||
|
eq3 = MathTex(r"= [1 - F_\pi(t)]^N", font_size=36, color=HIGHLIGHT)
|
||||||
|
|
||||||
|
# Step 4: Substitute back
|
||||||
|
eq4 = MathTex(
|
||||||
|
r"\mathbb{E}[p_{(1)}] = \underline p + \int_{\underline p}^{\bar p} [1 - F_\pi(t)]^N dt",
|
||||||
|
font_size=36,
|
||||||
|
)
|
||||||
|
|
||||||
|
# Step 5: Limit as N -> inf
|
||||||
|
eq5_pt1 = MathTex(
|
||||||
|
r"\text{Since } [1 - F_\pi(t)] < 1 \text{ for } t > \underline p:",
|
||||||
|
font_size=32,
|
||||||
|
color=GREY_B,
|
||||||
|
)
|
||||||
|
|
||||||
|
eq5_pt2 = MathTex(
|
||||||
|
r"\lim_{N \to \infty} \mathbb{E}[p_{(1)}] = \underline p",
|
||||||
|
font_size=42,
|
||||||
|
color=RED_C,
|
||||||
|
)
|
||||||
|
|
||||||
|
eq6 = MathTex(
|
||||||
|
r"\lim_{N \to \infty} \mathrm{COI} = 0", font_size=46, color=HIGHLIGHT
|
||||||
|
)
|
||||||
|
|
||||||
|
group = VGroup(eq1, eq2, eq3, eq4, eq5_pt1, eq5_pt2, eq6).arrange(
|
||||||
|
DOWN, aligned_edge=LEFT, buff=0.4
|
||||||
|
)
|
||||||
|
group.next_to(title, DOWN, buff=0.5).shift(RIGHT * 1.5)
|
||||||
|
|
||||||
|
# We want eq3 to be right after eq2
|
||||||
|
eq3.next_to(eq2, RIGHT, buff=0.2)
|
||||||
|
|
||||||
|
# Re-arrange carefully
|
||||||
|
step1 = eq1.copy().to_edge(LEFT, buff=1.0).shift(UP * 1.5)
|
||||||
|
step2 = (
|
||||||
|
VGroup(eq2.copy(), eq3.copy())
|
||||||
|
.arrange(RIGHT, buff=0.2)
|
||||||
|
.next_to(step1, DOWN, aligned_edge=LEFT, buff=0.5)
|
||||||
|
)
|
||||||
|
step3 = eq4.copy().next_to(step2, DOWN, aligned_edge=LEFT, buff=0.5)
|
||||||
|
|
||||||
|
step4_group = (
|
||||||
|
VGroup(eq5_pt1.copy(), eq5_pt2.copy())
|
||||||
|
.arrange(DOWN, aligned_edge=LEFT, buff=0.2)
|
||||||
|
.next_to(step3, DOWN, aligned_edge=LEFT, buff=0.5)
|
||||||
|
)
|
||||||
|
|
||||||
|
step5 = eq6.copy().next_to(step4_group, DOWN, buff=0.6).match_x(title)
|
||||||
|
|
||||||
|
# Animate
|
||||||
|
self.play(Write(step1))
|
||||||
|
self.wait(0.5)
|
||||||
|
|
||||||
|
self.play(Write(step2[0]))
|
||||||
|
self.play(Write(step2[1]))
|
||||||
|
self.wait(0.5)
|
||||||
|
|
||||||
|
self.play(Write(step3))
|
||||||
|
self.wait(0.5)
|
||||||
|
|
||||||
|
self.play(Write(step4_group[0]))
|
||||||
|
self.play(Write(step4_group[1]))
|
||||||
|
self.wait(0.5)
|
||||||
|
|
||||||
|
# Put a box around the final conclusion
|
||||||
|
box = SurroundingRectangle(step5, color=HIGHLIGHT, buff=0.2)
|
||||||
|
self.play(Write(step5), Create(box))
|
||||||
|
|
||||||
|
desc = MathTex(
|
||||||
|
r"N\to\infty\ \Rightarrow\ \mathrm{COI}\to 0",
|
||||||
|
font_size=28,
|
||||||
|
color=GREY_B,
|
||||||
|
).to_edge(DOWN)
|
||||||
|
|
||||||
|
self.play(FadeIn(desc, shift=UP * 0.2))
|
||||||
|
self.wait(2)
|
||||||
|
|
||||||
|
BEHAVIOR_SCENES = [
|
||||||
|
"LogsToKernelsScene",
|
||||||
|
"KLSeparabilityAndSignificanceScene",
|
||||||
|
"TrajectorySamplingScene",
|
||||||
|
"KroneckerExpansionScene",
|
||||||
|
]
|
||||||
|
|
||||||
|
COI_SCENES = [
|
||||||
|
"SamplingAndReservationScene",
|
||||||
|
"COIDistributionScene",
|
||||||
|
"COIErosionMathScene",
|
||||||
|
]
|
||||||
1523
paper/defense/manim/scenes/main.py
Normal file
1523
paper/defense/manim/scenes/main.py
Normal file
File diff suppressed because it is too large
Load Diff
25
paper/defense/manim/scripts/ffmpeg_concat_defense.sh
Executable file
25
paper/defense/manim/scripts/ffmpeg_concat_defense.sh
Executable file
@@ -0,0 +1,25 @@
|
|||||||
|
#!/usr/bin/env bash
|
||||||
|
# Concatenate rendered defense scenes (all under media/videos/defense/<quality>/).
|
||||||
|
# Usage from paper/defense/manim after: ./render_defense full --quality qh
|
||||||
|
# ./scripts/ffmpeg_concat_defense.sh qh
|
||||||
|
set -euo pipefail
|
||||||
|
QUALITY="${1:-qm}"
|
||||||
|
ROOT="$(cd "$(dirname "$0")/.." && pwd)"
|
||||||
|
LIST="$(mktemp)"
|
||||||
|
trap 'rm -f "$LIST"' EXIT
|
||||||
|
DIR="$ROOT/media/videos/defense/$QUALITY"
|
||||||
|
|
||||||
|
while IFS= read -r line || [[ -n "$line" ]]; do
|
||||||
|
[[ "$line" =~ ^#.*$ || -z "${line// }" ]] && continue
|
||||||
|
name="$line"
|
||||||
|
f="$DIR/${name}.mp4"
|
||||||
|
if [[ ! -f "$f" ]]; then
|
||||||
|
echo "missing: $f" >&2
|
||||||
|
exit 1
|
||||||
|
fi
|
||||||
|
echo "file '$f'" >>"$LIST"
|
||||||
|
done <"$ROOT/defense_scene_order.txt"
|
||||||
|
|
||||||
|
OUT="$ROOT/media/defense_rehearsal_${QUALITY}.mp4"
|
||||||
|
ffmpeg -y -f concat -safe 0 -i "$LIST" -c copy "$OUT"
|
||||||
|
echo "wrote $OUT"
|
||||||
Reference in New Issue
Block a user