{
 "nbformat": 4,
 "nbformat_minor": 5,
 "metadata": {
  "kernelspec": {
   "display_name": "Python 3",
   "language": "python",
   "name": "python3"
  },
  "language_info": {
   "name": "python",
   "version": "3.14"
  },
  "article_scope": "Fast analysis of the exact five-seed counts saved with the article. The full Bloom-filter experiment remains in experiment.ipynb and reproducibility.zip."
 },
 "cells": [
  {
   "cell_type": "markdown",
   "id": "saved-count-method",
   "metadata": {},
   "source": [
    "# Inspect the saved Bloom-filter counts\n",
    "\n",
    "This page reads the five recorded seeds for each allocation and recomputes the published means. The complete 250,000-query-per-policy run remains available in the full experiment notebook and reproducibility package.\n",
    "The saved five-seed probe comparison is shown below. It is available before running the analysis cell.\n",
    "\n",
    "![False-positive table probes per 1,000 absent lookups for uniform and size-aware allocation, averaged across five seeds.](figures/probes.svg)\n"
   ]
  },
  {
   "cell_type": "code",
   "id": "load-saved-counts",
   "metadata": {},
   "execution_count": 1,
   "source": [
    "import csv, json\n",
    "from pathlib import Path\n",
    "ROOT = Path.cwd()\n",
    "summary = json.loads((ROOT / \"data/summary.json\").read_text())\n",
    "with (ROOT / \"data/seed-results.csv\").open() as f:\n",
    "    rows = list(csv.DictReader(f))\n",
    "by_policy = {name: [r for r in rows if r[\"policy\"] == name] for name in (\"uniform\", \"optimized\")}\n",
    "means = {name: sum(float(r[\"probes_per_query\"]) for r in group) / len(group) for name, group in by_policy.items()}\n",
    "reduction = 100 * (1 - means[\"optimized\"] / means[\"uniform\"])\n",
    "assert all(len(group) == 5 for group in by_policy.values())\n",
    "assert round(means[\"uniform\"], 6) == summary[\"uniform_mean_probes_per_query\"]\n",
    "assert round(means[\"optimized\"], 6) == summary[\"optimized_mean_probes_per_query\"]\n",
    "assert round(reduction, 2) == round(summary[\"reduction_percent\"], 2)\n",
    "print(f\"Uniform mean: {means['uniform']:.6f} probes/query\")\n",
    "print(f\"Allocated mean: {means['optimized']:.6f} probes/query\")\n",
    "print(f\"Reduction from the saved counts: {reduction:.2f}%\")\n"
   ],
   "outputs": [
    {
     "output_type": "stream",
     "name": "stdout",
     "text": [
      "Uniform mean: 0.032848 probes/query\n",
      "Allocated mean: 0.017340 probes/query\n",
      "Reduction from the saved counts: 47.21%\n"
     ]
    }
   ]
  },
  {
   "cell_type": "markdown",
   "id": "seed-plot-method",
   "metadata": {},
   "source": [
    "## Compare the five saved seeds\n",
    "\n",
    "Each bar is false-positive probes per 1,000 absent queries. Edit the data-loading cell or plotting options to inspect the recorded variation."
   ]
  },
  {
   "cell_type": "code",
   "id": "plot-saved-counts",
   "metadata": {},
   "execution_count": null,
   "source": [
    "from IPython.display import Image, display\n",
    "import io\n",
    "import matplotlib.pyplot as plt\n",
    "import numpy as np\n",
    "seeds = [r[\"seed\"] for r in by_policy[\"uniform\"]]\n",
    "values = {name: [1000 * float(r[\"probes_per_query\"]) for r in by_policy[name]] for name in by_policy}\n",
    "x = np.arange(len(seeds)); width = 0.36\n",
    "fig, ax = plt.subplots(figsize=(7.2, 4.0), constrained_layout=True)\n",
    "ax.bar(x - width/2, values[\"uniform\"], width, label=\"Uniform\", color=\"#9a9a96\")\n",
    "ax.bar(x + width/2, values[\"optimized\"], width, label=\"Size-aware allocation\", color=\"#874345\")\n",
    "ax.set_ylabel(\"False-positive probes / 1,000 absent queries\")\n",
    "ax.set_xlabel(\"Saved random seed\")\n",
    "ax.set_xticks(x, seeds)\n",
    "ax.legend(frameon=False)\n",
    "ax.spines[[\"top\", \"right\"]].set_visible(False)\n",
    "buffer = io.BytesIO()\n",
    "fig.savefig(buffer, format=\"png\", dpi=120)\n",
    "display(Image(data=buffer.getvalue(), format=\"png\"))\n",
    "plt.close(fig)\n"
   ],
   "outputs": []
  }
 ]
}
