{
 "cells": [
  {
   "cell_type": "code",
   "execution_count": 48,
   "id": "96af9372-3368-4dfd-8882-7d6931539cf3",
   "metadata": {},
   "outputs": [],
   "source": [
    "import itertools"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 49,
   "id": "15c9f8d0-4bbe-41e5-897b-743088725e4a",
   "metadata": {},
   "outputs": [],
   "source": [
    "import numpy as np\n",
    "from scipy.special import factorial"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 50,
   "id": "854ab061-f9a1-4b74-b994-4938e21387c0",
   "metadata": {},
   "outputs": [
    {
     "data": {
      "text/plain": [
       "[('H', 'H'), ('H', 'T'), ('T', 'H'), ('T', 'T')]"
      ]
     },
     "execution_count": 50,
     "metadata": {},
     "output_type": "execute_result"
    }
   ],
   "source": [
    "list(itertools.product([\"H\", \"T\"], repeat=2))"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 51,
   "id": "04d9d096-e761-44a1-9449-9b9abf48eba5",
   "metadata": {},
   "outputs": [],
   "source": [
    "microstates = np.array(list(itertools.product([\"H\", \"T\"], repeat=4)))"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 52,
   "id": "4038e844-4bd5-4a41-a1a8-28c0b8f9278e",
   "metadata": {},
   "outputs": [
    {
     "data": {
      "text/plain": [
       "array([['H', 'H', 'H', 'H'],\n",
       "       ['H', 'H', 'H', 'T'],\n",
       "       ['H', 'H', 'T', 'H'],\n",
       "       ['H', 'H', 'T', 'T'],\n",
       "       ['H', 'T', 'H', 'H'],\n",
       "       ['H', 'T', 'H', 'T'],\n",
       "       ['H', 'T', 'T', 'H'],\n",
       "       ['H', 'T', 'T', 'T'],\n",
       "       ['T', 'H', 'H', 'H'],\n",
       "       ['T', 'H', 'H', 'T'],\n",
       "       ['T', 'H', 'T', 'H'],\n",
       "       ['T', 'H', 'T', 'T'],\n",
       "       ['T', 'T', 'H', 'H'],\n",
       "       ['T', 'T', 'H', 'T'],\n",
       "       ['T', 'T', 'T', 'H'],\n",
       "       ['T', 'T', 'T', 'T']], dtype='<U1')"
      ]
     },
     "execution_count": 52,
     "metadata": {},
     "output_type": "execute_result"
    }
   ],
   "source": [
    "microstates"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 53,
   "id": "c60b3937-bc36-40aa-9331-742efb878637",
   "metadata": {},
   "outputs": [
    {
     "data": {
      "text/plain": [
       "16"
      ]
     },
     "execution_count": 53,
     "metadata": {},
     "output_type": "execute_result"
    }
   ],
   "source": [
    "len(microstates)"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 54,
   "id": "e6760ef4-8639-4932-9f0b-7deb8ea6705b",
   "metadata": {
    "scrolled": true
   },
   "outputs": [
    {
     "data": {
      "text/plain": [
       "array([[ True,  True,  True,  True],\n",
       "       [ True,  True,  True, False],\n",
       "       [ True,  True, False,  True],\n",
       "       [ True,  True, False, False],\n",
       "       [ True, False,  True,  True],\n",
       "       [ True, False,  True, False],\n",
       "       [ True, False, False,  True],\n",
       "       [ True, False, False, False],\n",
       "       [False,  True,  True,  True],\n",
       "       [False,  True,  True, False],\n",
       "       [False,  True, False,  True],\n",
       "       [False,  True, False, False],\n",
       "       [False, False,  True,  True],\n",
       "       [False, False,  True, False],\n",
       "       [False, False, False,  True],\n",
       "       [False, False, False, False]])"
      ]
     },
     "execution_count": 54,
     "metadata": {},
     "output_type": "execute_result"
    }
   ],
   "source": [
    "# Filter rows where count of 'H' equals 3\n",
    "# First, generate an array of True/False entries \n",
    "(microstates==\"H\")"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 55,
   "id": "6e8e70a3-5f0a-44e3-85a4-2945f003bca6",
   "metadata": {},
   "outputs": [
    {
     "data": {
      "text/plain": [
       "array([8, 8, 8, 8])"
      ]
     },
     "execution_count": 55,
     "metadata": {},
     "output_type": "execute_result"
    }
   ],
   "source": [
    "# Just as an illustration of counting:\n",
    "# Count how many 'H's there are on each column.  (Column is \"axis=0\").  There are 4 columns, so we get \n",
    "# an array of 4 counts.  Each column has 8 heads.  \n",
    "(microstates==\"H\").sum(axis=0)"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 56,
   "id": "938238ba-55cb-4ffa-b587-50bdfed1a23b",
   "metadata": {},
   "outputs": [
    {
     "data": {
      "text/plain": [
       "array([4, 3, 3, 2, 3, 2, 2, 1, 3, 2, 2, 1, 2, 1, 1, 0])"
      ]
     },
     "execution_count": 56,
     "metadata": {},
     "output_type": "execute_result"
    }
   ],
   "source": [
    "# Now count how many 'H's there are on each row.  (Row is \"axis=1\").  There are 16 rows, so we get an\n",
    "# array of 16 counts.\n",
    "(microstates==\"H\").sum(axis=1)"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 57,
   "id": "ec0ec2e9-6549-49b4-aef3-0f77e8f27a9f",
   "metadata": {},
   "outputs": [],
   "source": [
    "# Now, make another True/False array for whether that count is 3.\n",
    "is_three = (microstates==\"H\").sum(axis=1) == 3"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 58,
   "id": "b7430dd7-1054-4624-9259-e4b5d0cd311c",
   "metadata": {},
   "outputs": [
    {
     "data": {
      "text/plain": [
       "array([['H', 'H', 'H', 'T'],\n",
       "       ['H', 'H', 'T', 'H'],\n",
       "       ['H', 'T', 'H', 'H'],\n",
       "       ['T', 'H', 'H', 'H']], dtype='<U1')"
      ]
     },
     "execution_count": 58,
     "metadata": {},
     "output_type": "execute_result"
    }
   ],
   "source": [
    "# Finally, use that array to pick out the True elements from the microstates array\n",
    "three_heads = microstates[is_three]\n",
    "three_heads"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 59,
   "id": "2ba6e0fb-e4d6-449d-8795-c2855019f428",
   "metadata": {},
   "outputs": [
    {
     "data": {
      "text/plain": [
       "array([['H', 'H', 'H', 'T'],\n",
       "       ['H', 'H', 'T', 'H'],\n",
       "       ['H', 'T', 'H', 'H'],\n",
       "       ['T', 'H', 'H', 'H']], dtype='<U1')"
      ]
     },
     "execution_count": 59,
     "metadata": {},
     "output_type": "execute_result"
    }
   ],
   "source": [
    "# Idiomatically, you would typically do this all as one command:\n",
    "three_heads = microstates[(microstates == \"H\").sum(axis=1) == 3]\n",
    "three_heads"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 60,
   "id": "a6fda6b4-dd8d-437a-8b54-70ddb987eaab",
   "metadata": {},
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "[['H' 'H' 'H' 'T']\n",
      " ['H' 'H' 'T' 'H']\n",
      " ['H' 'T' 'H' 'H']\n",
      " ['T' 'H' 'H' 'H']]\n"
     ]
    }
   ],
   "source": [
    "print(three_heads)"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 61,
   "id": "366adc29-bbc5-4cc0-a427-deef32adeb3c",
   "metadata": {},
   "outputs": [
    {
     "data": {
      "text/plain": [
       "4"
      ]
     },
     "execution_count": 61,
     "metadata": {},
     "output_type": "execute_result"
    }
   ],
   "source": [
    "# You would then count how many microstates correspond to the macrostate of '3 Heads'.\n",
    "len(three_heads)"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 65,
   "id": "04fbeaf6-3862-49bd-a34d-3aca08bdb214",
   "metadata": {},
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "N Heads Multiplicity Probability\n",
      "0 1 0.0625\n",
      "1 4 0.25\n",
      "2 6 0.375\n",
      "3 4 0.25\n",
      "4 1 0.0625\n"
     ]
    }
   ],
   "source": [
    "ntotal = 2**n\n",
    "print(\"N Heads\", \"Multiplicity\", \"Probability\")\n",
    "for n in range(5):\n",
    "    multiplicity = len(microstates[(microstates == \"H\").sum(axis=1) == n])\n",
    "    print(n, multiplicity, multiplicity/ntotal)"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 63,
   "id": "084f26c8-4965-4bc3-8f7a-45f174f57f06",
   "metadata": {},
   "outputs": [],
   "source": [
    "# Recalculate the same table using the binomial coefficient:\n",
    "def binomial(N, n):\n",
    "    return factorial(N)/(factorial(N-n)*factorial(n))"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 64,
   "id": "d7117b32-750f-4509-8950-b210b4288ecf",
   "metadata": {},
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "0 1.0 0.0625\n",
      "1 4.0 0.25\n",
      "2 6.0 0.375\n",
      "3 4.0 0.25\n",
      "4 1.0 0.0625\n"
     ]
    }
   ],
   "source": [
    "ntotal = 2**n\n",
    "for n in range(5):\n",
    "    multiplicity = binomial(4, n)\n",
    "    print(n, multiplicity, multiplicity/ntotal)"
   ]
  }
 ],
 "metadata": {
  "kernelspec": {
   "display_name": "Python 3 (ipykernel)",
   "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.7"
  }
 },
 "nbformat": 4,
 "nbformat_minor": 5
}
