{
  "cells": [
    {
      "cell_type": "markdown",
      "metadata": {},
      "source": [
        "# When Dynamics Models Agree and Still Fail\n",
        "\n",
        "Within-model noise and between-model disagreement describe different uncertainty. An exact counterexample shows how shared bias escapes the second.\n",
        "\n",
        "Analytic mixture moments for hand-specified predictors and a shared-bias counterexample; no fitted ensemble, trajectory optimizer, or PETS benchmark.\n",
        "\n",
        "The code uses Python 3 and the standard library. Saved output is from the checked CPU run.\n"
      ],
      "id": "uncertainty-can-disagree-and-s-0"
    },
    {
      "cell_type": "code",
      "execution_count": 1,
      "metadata": {},
      "source": [
        "import math\n",
        "\n",
        "slopes = [0.8, 1.0, 1.2]\n",
        "member_variance = 0.04\n",
        "\n",
        "def mixture(x, coefficients):\n",
        "    means = [coefficient * x for coefficient in coefficients]\n",
        "    mean = sum(means) / len(means)\n",
        "    between = sum((value - mean) ** 2 for value in means) / len(means)\n",
        "    total = member_variance + between\n",
        "    second_moment = sum(member_variance + value ** 2 for value in means)\n",
        "    second_moment /= len(means)\n",
        "    assert abs(total - (second_moment - mean ** 2)) < 1e-12\n",
        "    return mean, between, total\n",
        "\n",
        "for x in [0.0, 0.5, 2.0]:\n",
        "    mean, between, total = mixture(x, slopes)\n",
        "    print(f\"x={x:.1f} mean={mean:.3f} within={member_variance:.5f} \"\n",
        "          f\"between={between:.5f} total_sd={math.sqrt(total):.3f}\")\n",
        "\n",
        "print(\"Shared-bias counterexample:\")\n",
        "for x in [0.5, 2.0]:\n",
        "    mean, between, total = mixture(x, [1.0, 1.0, 1.0])\n",
        "    truth = x + 0.5 * x * x\n",
        "    print(f\"x={x:.1f} error={abs(truth - mean):.3f} disagreement={between:.3f}\")\n",
        "    assert between == 0.0\n",
        "print(\"Mixture second-moment checks: passed\")\n"
      ],
      "outputs": [
        {
          "output_type": "stream",
          "name": "stdout",
          "text": [
            "x=0.0 mean=0.000 within=0.04000 between=0.00000 total_sd=0.200\n",
            "x=0.5 mean=0.500 within=0.04000 between=0.00667 total_sd=0.216\n",
            "x=2.0 mean=2.000 within=0.04000 between=0.10667 total_sd=0.383\n",
            "Shared-bias counterexample:\n",
            "x=0.5 error=0.125 disagreement=0.000\n",
            "x=2.0 error=2.000 disagreement=0.000\n",
            "Mixture second-moment checks: passed\n"
          ]
        }
      ],
      "id": "uncertainty-can-disagree-and-s-1"
    },
    {
      "cell_type": "markdown",
      "metadata": {},
      "source": [
        "## Sources\n",
        "\n",
        "- Deep Reinforcement Learning in a Handful of Trials using Probabilistic Dynamics Models: https://arxiv.org/abs/1805.12114\n"
      ],
      "id": "uncertainty-can-disagree-and-s-2"
    }
  ],
  "metadata": {
    "kernelspec": {
      "display_name": "Python 3",
      "language": "python",
      "name": "python3"
    },
    "language_info": {
      "name": "python",
      "version": "3.12.14"
    }
  },
  "nbformat": 4,
  "nbformat_minor": 5
}
