{
 "cells": [
  {
   "cell_type": "code",
   "execution_count": 4,
   "id": "16ca28a2",
   "metadata": {},
   "outputs": [],
   "source": [
    "# Week 3 — Probability Basics (Navidi Ch. 2) — Jupyter/Python Lab\n",
    "# --------------------------------------------------------------\n",
    "# Suggested run order: top to bottom.\n",
    "# This notebook focuses on: sample spaces, events, relative frequency,\n",
    "# conditional probability, independence, Bayes (via simulation), and Monte Carlo.\n",
    "\n",
    "import numpy as np\n",
    "import math\n",
    "import matplotlib.pyplot as plt\n",
    "\n",
    "rng = np.random.default_rng(12345)\n",
    "\n",
    "def relfreq(successes, trials):\n",
    "    return successes / trials\n",
    "\n",
    "def simulate_repeated(trials, sim_fn):\n",
    "    \"\"\"Run sim_fn() 'trials' times; sim_fn returns True/False for success.\"\"\"\n",
    "    x = np.fromiter((sim_fn() for _ in range(trials)), dtype=bool, count=trials)\n",
    "    return x.mean()\n",
    "\n",
    "def running_estimate(trials, sim_fn):\n",
    "    \"\"\"Return running estimate of P(success) over time.\"\"\"\n",
    "    x = np.fromiter((sim_fn() for _ in range(trials)), dtype=np.int8, count=trials)\n",
    "    return np.cumsum(x) / np.arange(1, trials + 1)\n",
    "\n",
    "def plot_running(est, p_true=None, title=\"Running estimate\"):\n",
    "    plt.figure()\n",
    "    plt.plot(est, '.k')\n",
    "    if p_true is not None:\n",
    "        plt.axhline(p_true)\n",
    "    plt.xlabel(\"n\")\n",
    "    plt.ylabel(\"estimate\")\n",
    "    plt.title(title)\n",
    "    plt.show()\n",
    "\n",
    "def bernoulli(p, rng=rng):\n",
    "    return rng.random() < p"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 2,
   "id": "8e213def",
   "metadata": {},
   "outputs": [
    {
     "data": {
      "image/png": "[encoded data, 24680 characters]",
      "text/plain": [
       "<Figure size 640x480 with 1 Axes>"
      ]
     },
     "metadata": {},
     "output_type": "display_data"
    },
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "Final estimate: 0.558\n"
     ]
    }
   ],
   "source": [
    "# Cell 1 — Basic: coin flips as Bernoulli trials\n",
    "p = 0.5\n",
    "N = 500\n",
    "\n",
    "est = running_estimate(N, lambda: bernoulli(p))\n",
    "plot_running(est, p_true=p, title=\"Coin: running estimate of P(Heads)=0.5\")\n",
    "\n",
    "print(\"Final estimate:\", est[-1])"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 3,
   "id": "c7e376bc",
   "metadata": {},
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "Simulated P(Red): 0.351385\n",
      "Exact P(Red):     0.35\n"
     ]
    }
   ],
   "source": [
    "# Cell 2 — Law of Total Probability via simulation (urn example)\n",
    "# Urn A chosen with probability 0.3; Urn B with probability 0.7\n",
    "# Urn A: 70% red; Urn B: 20% red\n",
    "pA = 0.3\n",
    "p_red_A = 0.7\n",
    "p_red_B = 0.2\n",
    "\n",
    "N = 200_000\n",
    "\n",
    "def draw_red():\n",
    "    # choose urn then draw color\n",
    "    choose_A = bernoulli(pA)\n",
    "    if choose_A:\n",
    "        return bernoulli(p_red_A)\n",
    "    else:\n",
    "        return bernoulli(p_red_B)\n",
    "\n",
    "p_hat = simulate_repeated(N, draw_red)\n",
    "\n",
    "p_exact = pA * p_red_A + (1 - pA) * p_red_B\n",
    "print(\"Simulated P(Red):\", p_hat)\n",
    "print(\"Exact P(Red):    \", p_exact)"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 12,
   "id": "cca32796",
   "metadata": {},
   "outputs": [
    {
     "data": {
      "text/plain": [
       "array([0, 0, 0, 1, 0, 1, 0, 0, 1, 1], dtype=int8)"
      ]
     },
     "execution_count": 12,
     "metadata": {},
     "output_type": "execute_result"
    }
   ],
   "source": [
    "trials = 10\n",
    "sim_fn = lambda: rng.random() < 0.5\n",
    "x = np.fromiter((sim_fn() for _ in range(trials)), dtype=np.int8, count=trials)\n",
    "# x might be: array([1, 0, 1, 1, 0], dtype=int8)\n",
    "x"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 18,
   "id": "d3782b57",
   "metadata": {},
   "outputs": [
    {
     "data": {
      "text/plain": [
       "array([1, 0, 1, 1, 0, 1, 1, 1, 1, 1], dtype=int8)"
      ]
     },
     "execution_count": 18,
     "metadata": {},
     "output_type": "execute_result"
    }
   ],
   "source": [
    "x = np.fromiter((sim_fn() for _ in range(trials)), dtype=np.int8, count=trials)\n",
    "x"
   ]
  }
 ],
 "metadata": {
  "kernelspec": {
   "display_name": ".venv (3.14.2)",
   "language": "python",
   "name": "python3"
  },
  "language_info": {
   "codemirror_mode": {
    "name": "ipython",
    "version": 3
   },
   "file_extension": ".py",
   "mimetype": "text/x-python",
   "name": "python",
   "nbconvert_exporter": "python",
   "pygments_lexer": "ipython3",
   "version": "3.14.2"
  }
 },
 "nbformat": 4,
 "nbformat_minor": 5
}
