{
 "cells": [
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "# MultinomialDistribution"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 1,
   "metadata": {},
   "outputs": [],
   "source": [
    "import numpy as np\n",
    "np.set_printoptions(linewidth=200)"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "MultinomialDistribution is a joint probability distribution of a discrete random variables $(x_0, \\dots, x_{n-1})$, with events of $x_i$ are $A_i$ and $\\sum_{a_0 \\in A_0} \\cdots \\sum_{a_{n-1} \\in A_{n-1}} p(x_0=a_0, \\dots, x_{n-1}=a_{n-1}) = 1$.  \n",
    "The property `ps` of MultinomialDistribution is a flattened numpy array.  \n",
    "If $s_i$ be sizes of $A_i$, then the property `shape` of MultinomialDistribution is $(s_0, \\dots, s_{n-1})$.\n",
    "\n",
    "Exmaple.  \n",
    "Consider the following joint probability distribution:\n",
    "\n",
    "| x_0 \\\\ x_1 | 0 | 1 | 2 |\n",
    "| --- | --- | --- | --- |\n",
    "| 0 | 0.0 | 0.10 | 0.15 |\n",
    "| 1 | 0.20 | 0.25 | 0.30 |\n",
    "\n",
    "Then `ps` = $[0.0, 0.10, 0.15, 0.20, 0.25, 0.30]$, and `shape` = $[2, 3]$."
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "Generate MultinomialDistribution object directly."
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 2,
   "metadata": {},
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "shape = (2, 3)\n",
      "ps = [0.   0.1  0.15 0.2  0.25 0.3 ]\n"
     ]
    }
   ],
   "source": [
    "from quara.objects.multinomial_distribution import MultinomialDistribution\n",
    "\n",
    "ps = np.array([0.0, 0.10, 0.15, 0.20, 0.25, 0.30], dtype=np.float64)\n",
    "shape = (2, 3)\n",
    "dist = MultinomialDistribution(ps, shape=shape)\n",
    "print(dist)"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "If `shape` is omitted, the number of random variables are assumed to be one."
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 3,
   "metadata": {},
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "shape = (6,)\n",
      "ps = [0.   0.1  0.15 0.2  0.25 0.3 ]\n"
     ]
    }
   ],
   "source": [
    "dist = MultinomialDistribution(ps)\n",
    "print(dist)"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "### specific properties\n",
    "The property `ps` of MultinomialDistribution is a one-dimensional numpy array specified by the constructor argument `ps`."
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 4,
   "metadata": {},
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "ps: [0.   0.1  0.15 0.2  0.25 0.3 ]\n"
     ]
    }
   ],
   "source": [
    "dist = MultinomialDistribution(ps, shape=shape)\n",
    "print(f\"ps: {dist.ps}\")"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "The property `shape` of MultinomialDistribution is a tuple of int by the constructor argument `shape`."
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 5,
   "metadata": {},
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "shape: (2, 3)\n"
     ]
    }
   ],
   "source": [
    "dist = MultinomialDistribution(ps, shape=shape)\n",
    "print(f\"shape: {dist.shape}\")"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "### marginalize\n",
    "Returns MultinomialDistribution corresponding to marginal probability.  \n",
    "The marginal probability of variable ``outcome_indices_remain``.\n",
    "\n",
    "Exmaple.  \n",
    "Consider the following joint probability distribution:\n",
    "\n",
    "| x_0 \\\\ x_1 | 0 | 1 | 2 |\n",
    "| --- | --- | --- | --- |\n",
    "| 0 | 0.0 | 0.10 | 0.15 |\n",
    "| 1 | 0.20 | 0.25 | 0.30 |\n",
    "\n",
    "Let ``outcome_indices_remain`` = $[0] (= [x_0])$.  \n",
    "Then marginal probability is $p(x_0 = 0) = 0.25, p(x_0 = 1) = 0.75$."
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 6,
   "metadata": {},
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "marginalize([0]): \n",
      "shape = (2,)\n",
      "ps = [0.25 0.75]\n"
     ]
    }
   ],
   "source": [
    "dist = MultinomialDistribution(ps, shape=shape)\n",
    "marginalized_dist = dist.marginalize([0])\n",
    "print(f\"marginalize([0]): \\n{marginalized_dist}\")"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "### conditionalize\n",
    "Returns MultinomialDistribution corresponding to marginal probability.  \n",
    "The marginal probability of variable ``outcome_indices_remain``.\n",
    "\n",
    "Exmaple.  \n",
    "Consider the following joint probability distribution:\n",
    "\n",
    "| x_0 \\\\ x_1 | 0 | 1 | 2 | sum |\n",
    "| --- | --- | --- | --- | --- |\n",
    "| 0 | 0.0 | 0.10 | 0.15 | 0.25 |\n",
    "| 1 | 0.20 | 0.25 | 0.30 | 0.75 |\n",
    "\n",
    "Let `conditional_variable_indices` = $[0] (= [x_0])$, and `conditional_variable_values` = $[1]$ (i.e. $x_0 = 1$).  \n",
    "Then marginal probabilities are\n",
    "\n",
    "- $p(x_1 = 0|x_0 = 1) = p(x_0 = 1, x_1 = 0) / p(x_0 = 1) = 0.20 / 0.75 \\fallingdotseq 0.27$,\n",
    "- $p(x_1 = 1|x_0 = 1) = p(x_0 = 1, x_1 = 1) / p(x_0 = 1) = 0.25 / 0.75 \\fallingdotseq 0.33$,\n",
    "- $p(x_1 = 2|x_0 = 1) = p(x_0 = 1, x_1 = 2) / p(x_0 = 1) = 0.30 / 0.75 \\fallingdotseq 0.40$."
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 7,
   "metadata": {},
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "conditionalize([0], [1]): \n",
      "shape = (3,)\n",
      "ps = [0.26666667 0.33333333 0.4       ]\n"
     ]
    }
   ],
   "source": [
    "dist = MultinomialDistribution(ps, shape=shape)\n",
    "conditionalized_dist = dist.conditionalize([0], [1])\n",
    "print(f\"conditionalize([0], [1]): \\n{conditionalized_dist}\")"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "### execute_random_sampling\n",
    "Returns results of random sampling.  \n",
    "The first argument `num` is the number of trials per execution unit. The second argument `size` is the number of execution.  \n",
    "Optional argument `random_generator` is seed(int) or np.random.Generator used for sampling.  \n",
    "\n",
    "Examle.  \n",
    "`num` = 100, `size` = 3"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 8,
   "metadata": {},
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "execute_random_sampling(): \n",
      "[array([ 0, 14, 15, 21, 25, 25]), array([ 0,  9, 15, 15, 22, 39]), array([ 0,  9, 15, 27, 26, 23])]\n"
     ]
    }
   ],
   "source": [
    "dist = MultinomialDistribution(ps, shape=shape)\n",
    "samples = dist.execute_random_sampling(100, 3)\n",
    "print(f\"execute_random_sampling(): \\n{samples}\")"
   ]
  }
 ],
 "metadata": {
  "hide_input": false,
  "kernelspec": {
   "display_name": "Python 3",
   "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.8.10"
  },
  "toc": {
   "base_numbering": 1,
   "nav_menu": {},
   "number_sections": true,
   "sideBar": true,
   "skip_h1_title": false,
   "title_cell": "Table of Contents",
   "title_sidebar": "Contents",
   "toc_cell": false,
   "toc_position": {},
   "toc_section_display": true,
   "toc_window_display": false
  }
 },
 "nbformat": 4,
 "nbformat_minor": 2
}
