{
 "cells": [
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "# MProcess and mprocess_typical"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 1,
   "metadata": {},
   "outputs": [],
   "source": [
    "import numpy as np\n",
    "np.set_printoptions(linewidth=200)"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "## MProcess (Measurement Process)\n",
    "MProcess $M = \\{ M_x \\}_{x=0,\\dots,m-1}$ maps State $\\rho \\mapsto \\{ \\rho_x \\}_{x=0,\\dots,m-1}$, where $\\rho_x = \\frac{M_x(\\rho)}{\\text{Tr}[M_x(\\rho)]}$, with probability $p(x) = \\text{Tr}[M_x(\\rho)] = \\text{Tr}[\\Pi_x\\rho]$.  \n",
    "Each $M_x$ is a linear trace-preserving and completely positive (L-TPCP) map on the space of quantum states.  \n",
    "The Hilbert-Schmidt matrix representations of these L-TPCP maps is denote `hss` in Quara. `hss` is a list of 2-dimensional numpy array.  \n",
    "\n",
    "The property `mode_sampling` of MProcess is whether to sample to determine one Hilbert-Schumidt matrix with `compose_qoperations()` function.  \n",
    "The property `random_seed_or_generator` of MProcess is the random seed or numpy.random.Generator to sample."
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "Generate from `mprocess_typical` module by specifying CompositeSystem and state mprocess (ex. “z-type1”)."
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 2,
   "metadata": {},
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "Type:\n",
      "MProcess\n",
      "\n",
      "Dim:\n",
      "2\n",
      "\n",
      "HSs:\n",
      "[array([[0.5, 0. , 0. , 0.5],\n",
      "       [0. , 0. , 0. , 0. ],\n",
      "       [0. , 0. , 0. , 0. ],\n",
      "       [0.5, 0. , 0. , 0.5]]), array([[ 0.5,  0. ,  0. , -0.5],\n",
      "       [ 0. ,  0. ,  0. ,  0. ],\n",
      "       [ 0. ,  0. ,  0. ,  0. ],\n",
      "       [-0.5,  0. ,  0. ,  0.5]])]\n",
      "\n",
      "ModeSampling:\n",
      "False\n"
     ]
    }
   ],
   "source": [
    "from quara.objects.composite_system_typical import generate_composite_system\n",
    "from quara.objects.mprocess_typical import generate_mprocess_from_name\n",
    "\n",
    "c_sys = generate_composite_system(\"qubit\", 1)\n",
    "mprocess = generate_mprocess_from_name(c_sys, \"z-type1\")\n",
    "print(mprocess)"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "Generate MProcess object directly using CompositeSystem and a numpy array."
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 3,
   "metadata": {},
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "Type:\n",
      "MProcess\n",
      "\n",
      "Dim:\n",
      "2\n",
      "\n",
      "HSs:\n",
      "[array([[0.5, 0. , 0. , 0.5],\n",
      "       [0. , 0. , 0. , 0. ],\n",
      "       [0. , 0. , 0. , 0. ],\n",
      "       [0.5, 0. , 0. , 0.5]]), array([[ 0.5,  0. ,  0. , -0.5],\n",
      "       [ 0. ,  0. ,  0. ,  0. ],\n",
      "       [ 0. ,  0. ,  0. ,  0. ],\n",
      "       [-0.5,  0. ,  0. ,  0.5]])]\n",
      "\n",
      "ModeSampling:\n",
      "False\n"
     ]
    }
   ],
   "source": [
    "import numpy as np\n",
    "\n",
    "from quara.objects.composite_system import CompositeSystem\n",
    "from quara.objects.elemental_system import ElementalSystem\n",
    "from quara.objects.matrix_basis import get_normalized_pauli_basis\n",
    "from quara.objects.mprocess import MProcess\n",
    "\n",
    "basis = get_normalized_pauli_basis(1)\n",
    "e_sys = ElementalSystem(0, basis)\n",
    "c_sys = CompositeSystem([e_sys])\n",
    "hss = [\n",
    "    np.array([[0.5, 0, 0, 0.5], [0, 0, 0, 0], [0, 0, 0, 0], [0.5, 0, 0, 0.5]]),\n",
    "    np.array([[0.5, 0, 0, -0.5], [0, 0, 0, 0], [0, 0, 0, 0], [-0.5, 0, 0, 0.5]]),\n",
    "]\n",
    "mprocess = MProcess(c_sys, hss)\n",
    "print(mprocess)"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "### specific properties\n",
    "The property `hss` of MProcess is a numpy array specified by the constructor argument `hss`."
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 4,
   "metadata": {},
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "hss: \n",
      "[array([[0.5, 0. , 0. , 0.5],\n",
      "       [0. , 0. , 0. , 0. ],\n",
      "       [0. , 0. , 0. , 0. ],\n",
      "       [0.5, 0. , 0. , 0.5]]), array([[ 0.5,  0. ,  0. , -0.5],\n",
      "       [ 0. ,  0. ,  0. ,  0. ],\n",
      "       [ 0. ,  0. ,  0. ,  0. ],\n",
      "       [-0.5,  0. ,  0. ,  0.5]])]\n"
     ]
    }
   ],
   "source": [
    "mprocess = MProcess(c_sys, hss)\n",
    "print(f\"hss: \\n{mprocess.hss}\")"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "The `hs()` function returns a numpy array specified by the constructor argument `hss`."
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 5,
   "metadata": {},
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "hs(0): \n",
      "[[0.5 0.  0.  0.5]\n",
      " [0.  0.  0.  0. ]\n",
      " [0.  0.  0.  0. ]\n",
      " [0.5 0.  0.  0.5]]\n",
      "hs(1): \n",
      "[[ 0.5  0.   0.  -0.5]\n",
      " [ 0.   0.   0.   0. ]\n",
      " [ 0.   0.   0.   0. ]\n",
      " [-0.5  0.   0.   0.5]]\n"
     ]
    }
   ],
   "source": [
    "mprocess = MProcess(c_sys, hss)\n",
    "print(f\"hs(0): \\n{mprocess.hs(0)}\")\n",
    "print(f\"hs(1): \\n{mprocess.hs(1)}\")"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "The property `dim` of MProcess is the size of square matrices `hss`."
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 6,
   "metadata": {},
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "dim: 2\n",
      "size of square matrices hss: 2\n"
     ]
    }
   ],
   "source": [
    "print(f\"dim: {mprocess.dim}\")\n",
    "print(f\"size of square matrices hss: {int(np.sqrt(hss[0].shape[0]))}\")"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "The property `num_outcomes` of MProcess is the number of `hss`."
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 7,
   "metadata": {},
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "num_outcomes: 2\n",
      "number of hss: 2\n"
     ]
    }
   ],
   "source": [
    "print(f\"num_outcomes: {mprocess.num_outcomes}\")\n",
    "print(f\"number of hss: {len(mprocess.hss)}\")"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "The property `mode_sampling` of MProcess is the mode of sampling."
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 8,
   "metadata": {},
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "False\n"
     ]
    }
   ],
   "source": [
    "print(mprocess.mode_sampling)"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "### functions to check constraints\n",
    "The `is_eq_constraint_satisfied()` function returns True, if and only if the sum of `hss` is TP(trace-preserving map)."
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 9,
   "metadata": {},
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "is_eq_constraint_satisfied(): True\n",
      "is_sum_tp(): True\n"
     ]
    }
   ],
   "source": [
    "print(f\"is_eq_constraint_satisfied(): {mprocess.is_eq_constraint_satisfied()}\")\n",
    "print(f\"is_sum_tp(): {mprocess.is_sum_tp()}\")"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "The `is_ineq_constraint_satisfied()` function returns True, if and only if all matrices of `hss` are CP(Complete-Positivity-Preserving), i.e. if and only if all Choi matrices of `hss` are positive semidifinite matrices."
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 10,
   "metadata": {},
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "is_ineq_constraint_satisfied(): True\n",
      "is_cp(): True\n"
     ]
    }
   ],
   "source": [
    "print(f\"is_ineq_constraint_satisfied(): {mprocess.is_ineq_constraint_satisfied()}\")\n",
    "print(f\"is_cp(): {mprocess.is_cp()}\")"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "### projection functions\n",
    "`calc_proj_eq_constraint()` function calculates the projection of MProcess on equal constraint.\n",
    "Let `hss` of MProcess be $\\{ M_0, \\dots, M_{m-1}\\}$, where $m$ is `num_outcomes` of MProcess.\n",
    "When MProcess object satifies on equal constraint, the first row of $\\sum_{x=0}^{m-1} M_x$ is equal to $[1, 0, \\dots, 0]$.  \n",
    "Therefore, `calc_proj_eq_constraint()` function calculates the projection of MProcess as follows:\n",
    "\n",
    "- $\\text{vec} :=$ the first row of $\\sum_{x=0}^{m-1} M_x$\n",
    "- for each $x$, calculates $M^{\\prime}_x = M_x - \\frac{1}{m}\\begin{bmatrix} \\text{vec} \\\\ 0  \\\\ \\vdots \\\\ 0 \\end{bmatrix} + \\frac{1}{m}\\begin{bmatrix} 1 & 0 & \\dots & 0 \\\\ 0 \\\\ \\vdots & & \\huge{0} \\\\ 0 \\end{bmatrix}$\n",
    "- The projection of MProcess is $\\{ M^{\\prime}_x \\}_{x=0}^{m-1}$."
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 11,
   "metadata": {},
   "outputs": [],
   "source": [
    "hss = [\n",
    "    np.array(range(16), dtype=np.float64).reshape((4, 4)),\n",
    "    np.array(range(16, 32), dtype=np.float64).reshape((4, 4)),\n",
    "]"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 12,
   "metadata": {},
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "hss: \n",
      "[array([[-7.5, -8. , -8. , -8. ],\n",
      "       [ 4. ,  5. ,  6. ,  7. ],\n",
      "       [ 8. ,  9. , 10. , 11. ],\n",
      "       [12. , 13. , 14. , 15. ]]), array([[ 8.5,  8. ,  8. ,  8. ],\n",
      "       [20. , 21. , 22. , 23. ],\n",
      "       [24. , 25. , 26. , 27. ],\n",
      "       [28. , 29. , 30. , 31. ]])]\n"
     ]
    }
   ],
   "source": [
    "mprocess = MProcess(c_sys, hss, is_physicality_required=False)\n",
    "proj_mprocess = mprocess.calc_proj_eq_constraint()\n",
    "print(f\"hss: \\n{proj_mprocess.hss}\")"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "`calc_proj_ineq_constraint()` function calculates the projection of MProcess with `hss` $\\{ M_x \\}_{x=0}^{m-1}$ on inequal constraint as follows:\n",
    "\n",
    "- For each $x$, calculate the following:\n",
    "  - Let $\\text{Choi}_x$ be Choi matrix of $M_x$\n",
    "  - Executes singular value decomposition on $\\text{Choi}_x$, $\\text{Choi}_x = U \\Lambda U^{\\dagger}$, where $\\Lambda = \\text{diag}[\\lambda_0, \\dots , \\lambda_{d-1}]$, and $\\lambda_{i} \\in \\mathbb{R}$.\n",
    "  - $\\lambda^{\\prime}_{i} := \\begin{cases} \\lambda_{i} & (\\lambda_{i} \\geq 0) \\\\ 0 & (\\lambda_{i} < 0) \\end{cases}$\n",
    "  - $\\Lambda^{\\prime} = \\text{diag}[\\lambda^{\\prime}_0, \\dots , \\lambda^{\\prime}_{d-1}]$\n",
    "  - $\\text{Choi}^{\\prime}_x = U \\Lambda^{\\prime} U^{\\dagger}$\n",
    "  - Let $M^{\\prime}_x$ be Hilbert-Schmidt matrix representation of $\\text{Choi}^{\\prime}_x$\n",
    "- The projection of MProcess is $\\{ M^{\\prime}_x \\}_{x=0}^{m-1}$."
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 13,
   "metadata": {},
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "hss: \n",
      "[array([[15.84558996,  4.43570942,  5.29265833,  6.14960724],\n",
      "       [ 2.63097854,  2.34702553,  3.08437192,  3.44443746],\n",
      "       [ 4.98440409,  4.50900796,  4.73510284,  5.71575945],\n",
      "       [ 7.33782964,  6.29370952,  7.14039548,  7.60980059]]), array([[47.32687829, 20.14755601, 21.1037168 , 22.0598776 ],\n",
      "       [17.5667235 , 12.54854821, 13.24883203, 13.79656536],\n",
      "       [20.93808076, 15.04184745, 15.53818711, 16.33962776],\n",
      "       [24.30943803, 17.3825962 , 18.13264319, 18.73013967]])]\n"
     ]
    }
   ],
   "source": [
    "mprocess = MProcess(c_sys, hss, is_physicality_required=False)\n",
    "proj_mprocess = mprocess.calc_proj_ineq_constraint()\n",
    "print(f\"hss: \\n{proj_mprocess.hss}\")"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "### functions to transform parameters\n",
    "`to_stacked_vector()` function returns a one-dimensional numpy array of all variables. This is equal to a concatenated vector of flattened matrices of `hss`."
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 14,
   "metadata": {},
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "to_stacked_vector(): \n",
      "[ 0.  1.  2.  3.  4.  5.  6.  7.  8.  9. 10. 11. 12. 13. 14. 15. 16. 17. 18. 19. 20. 21. 22. 23. 24. 25. 26. 27. 28. 29. 30. 31.]\n",
      "hss: \n",
      "[array([[ 0.,  1.,  2.,  3.],\n",
      "       [ 4.,  5.,  6.,  7.],\n",
      "       [ 8.,  9., 10., 11.],\n",
      "       [12., 13., 14., 15.]]), array([[16., 17., 18., 19.],\n",
      "       [20., 21., 22., 23.],\n",
      "       [24., 25., 26., 27.],\n",
      "       [28., 29., 30., 31.]])]\n"
     ]
    }
   ],
   "source": [
    "print(f\"to_stacked_vector(): \\n{mprocess.to_stacked_vector()}\")\n",
    "print(f\"hss: \\n{mprocess.hss}\")"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "Let `hss` of MProcess be $\\{ M_0, \\dots, M_{m-1}\\}$, where $m$ is `num_outcomes` of MProcess. Let $\\text{vec}(M_x) := |M_x\\rangle\\rangle$. Let $\\text{vec}(\\tilde{M}_x) $ be a flattened vector of the second and subsequent rows of matrix $M_x$.  \n",
    "If `on_para_eq_constraint` is True, then the first row of $\\sum_{x=0}^{m-1} M_x$ is equal to $[1, 0, \\dots, 0]$.  \n",
    "Therefore, `to_var()` function returns a concatenated vector of $\\text{vec}(M_0), \\dots, \\text{vec}(M_{m-2}), \\text{vec}(\\tilde{M}_{m-1})$, where `on_para_eq_constraint` is True."
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 15,
   "metadata": {},
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "to_var(): \n",
      "[ 0.  1.  2.  3.  4.  5.  6.  7.  8.  9. 10. 11. 12. 13. 14. 15. 20. 21. 22. 23. 24. 25. 26. 27. 28. 29. 30. 31.]\n"
     ]
    }
   ],
   "source": [
    "# on_para_eq_constraint=True\n",
    "mprocess = MProcess(c_sys, hss, is_physicality_required=False, on_para_eq_constraint=True)\n",
    "print(f\"to_var(): \\n{mprocess.to_var()}\")"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 16,
   "metadata": {},
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "to_var(): \n",
      "[ 0.  1.  2.  3.  4.  5.  6.  7.  8.  9. 10. 11. 12. 13. 14. 15. 16. 17. 18. 19. 20. 21. 22. 23. 24. 25. 26. 27. 28. 29. 30. 31.]\n"
     ]
    }
   ],
   "source": [
    "# on_para_eq_constraint=False\n",
    "mprocess = MProcess(c_sys, hss, is_physicality_required=False, on_para_eq_constraint=False)\n",
    "print(f\"to_var(): \\n{mprocess.to_var()}\")"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "### functions to generate special objects"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 17,
   "metadata": {},
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "zero: \n",
      "[array([[0., 0., 0., 0.],\n",
      "       [0., 0., 0., 0.],\n",
      "       [0., 0., 0., 0.],\n",
      "       [0., 0., 0., 0.]]), array([[0., 0., 0., 0.],\n",
      "       [0., 0., 0., 0.],\n",
      "       [0., 0., 0., 0.],\n",
      "       [0., 0., 0., 0.]])]\n",
      "origin: \n",
      "[array([[0.5, 0. , 0. , 0. ],\n",
      "       [0. , 0. , 0. , 0. ],\n",
      "       [0. , 0. , 0. , 0. ],\n",
      "       [0. , 0. , 0. , 0. ]]), array([[0.5, 0. , 0. , 0. ],\n",
      "       [0. , 0. , 0. , 0. ],\n",
      "       [0. , 0. , 0. , 0. ],\n",
      "       [0. , 0. , 0. , 0. ]])]\n"
     ]
    }
   ],
   "source": [
    "zero_mprocess = mprocess.generate_zero_obj()\n",
    "print(f\"zero: \\n{zero_mprocess.hss}\")\n",
    "origin_mprocess = mprocess.generate_origin_obj()\n",
    "print(f\"origin: \\n{origin_mprocess.hss}\")"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "### supports arithmetic operations"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 18,
   "metadata": {},
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "[array([[ 0.,  1.,  2.,  3.],\n",
      "       [ 4.,  5.,  6.,  7.],\n",
      "       [ 8.,  9., 10., 11.],\n",
      "       [12., 13., 14., 15.]]), array([[16., 17., 18., 19.],\n",
      "       [20., 21., 22., 23.],\n",
      "       [24., 25., 26., 27.],\n",
      "       [28., 29., 30., 31.]])]\n",
      "[array([[32., 33., 34., 35.],\n",
      "       [36., 37., 38., 39.],\n",
      "       [40., 41., 42., 43.],\n",
      "       [44., 45., 46., 47.]]), array([[48., 49., 50., 51.],\n",
      "       [52., 53., 54., 55.],\n",
      "       [56., 57., 58., 59.],\n",
      "       [60., 61., 62., 63.]])]\n"
     ]
    }
   ],
   "source": [
    "hs11 = np.array(range(16), dtype=np.float64).reshape((4, 4))\n",
    "hs12 = np.array(range(16, 32), dtype=np.float64).reshape((4, 4))\n",
    "mprocess1 = MProcess(c_sys, [hs11, hs12], is_physicality_required=False)\n",
    "hs21 = np.array(range(32, 48), dtype=np.float64).reshape((4, 4))\n",
    "hs22 = np.array(range(48, 64), dtype=np.float64).reshape((4, 4))\n",
    "mprocess2 = MProcess(c_sys, [hs21, hs22], is_physicality_required=False)\n",
    "\n",
    "print(mprocess1.hss)\n",
    "print(mprocess2.hss)"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 19,
   "metadata": {},
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "sum: \n",
      "[array([[32., 34., 36., 38.],\n",
      "       [40., 42., 44., 46.],\n",
      "       [48., 50., 52., 54.],\n",
      "       [56., 58., 60., 62.]]), array([[64., 66., 68., 70.],\n",
      "       [72., 74., 76., 78.],\n",
      "       [80., 82., 84., 86.],\n",
      "       [88., 90., 92., 94.]])]\n",
      "subtraction: \n",
      "[array([[-32., -32., -32., -32.],\n",
      "       [-32., -32., -32., -32.],\n",
      "       [-32., -32., -32., -32.],\n",
      "       [-32., -32., -32., -32.]]), array([[-32., -32., -32., -32.],\n",
      "       [-32., -32., -32., -32.],\n",
      "       [-32., -32., -32., -32.],\n",
      "       [-32., -32., -32., -32.]])]\n",
      "right multiplication: \n",
      "[array([[ 0.,  2.,  4.,  6.],\n",
      "       [ 8., 10., 12., 14.],\n",
      "       [16., 18., 20., 22.],\n",
      "       [24., 26., 28., 30.]]), array([[32., 34., 36., 38.],\n",
      "       [40., 42., 44., 46.],\n",
      "       [48., 50., 52., 54.],\n",
      "       [56., 58., 60., 62.]])]\n",
      "left multiplication: \n",
      "[array([[ 0.,  2.,  4.,  6.],\n",
      "       [ 8., 10., 12., 14.],\n",
      "       [16., 18., 20., 22.],\n",
      "       [24., 26., 28., 30.]]), array([[32., 34., 36., 38.],\n",
      "       [40., 42., 44., 46.],\n",
      "       [48., 50., 52., 54.],\n",
      "       [56., 58., 60., 62.]])]\n",
      "division: \n",
      "[array([[0. , 0.5, 1. , 1.5],\n",
      "       [2. , 2.5, 3. , 3.5],\n",
      "       [4. , 4.5, 5. , 5.5],\n",
      "       [6. , 6.5, 7. , 7.5]]), array([[ 8. ,  8.5,  9. ,  9.5],\n",
      "       [10. , 10.5, 11. , 11.5],\n",
      "       [12. , 12.5, 13. , 13.5],\n",
      "       [14. , 14.5, 15. , 15.5]])]\n"
     ]
    }
   ],
   "source": [
    "print(f\"sum: \\n{(mprocess1 + mprocess2).hss}\")\n",
    "print(f\"subtraction: \\n{(mprocess1 - mprocess2).hss}\")\n",
    "print(f\"right multiplication: \\n{(2 * mprocess1).hss}\")\n",
    "print(f\"left multiplication: \\n{(mprocess1 * 2).hss}\")\n",
    "print(f\"division: \\n{(mprocess1 / 2).hss}\")"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "### calc_gradient functions\n",
    "Calculates gradient of MProcess with variable index."
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 20,
   "metadata": {},
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "hss: \n",
      "[array([[1., 0., 0., 0.],\n",
      "       [0., 0., 0., 0.],\n",
      "       [0., 0., 0., 0.],\n",
      "       [0., 0., 0., 0.]]), array([[0., 0., 0., 0.],\n",
      "       [0., 0., 0., 0.],\n",
      "       [0., 0., 0., 0.],\n",
      "       [0., 0., 0., 0.]])]\n"
     ]
    }
   ],
   "source": [
    "grad_mprocess = mprocess.calc_gradient(0)\n",
    "print(f\"hss: \\n{grad_mprocess.hss}\")"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "### convert_basis function\n",
    "Returns `hss` converted to the specified basis."
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 21,
   "metadata": {},
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "hss: \n",
      "[array([[1.00000000e+00+0.j, 0.00000000e+00+0.j, 0.00000000e+00+0.j, 6.22328532e-19+0.j],\n",
      "       [0.00000000e+00+0.j, 0.00000000e+00+0.j, 0.00000000e+00+0.j, 0.00000000e+00+0.j],\n",
      "       [0.00000000e+00+0.j, 0.00000000e+00+0.j, 0.00000000e+00+0.j, 0.00000000e+00+0.j],\n",
      "       [3.25176795e-17+0.j, 0.00000000e+00+0.j, 0.00000000e+00+0.j, 5.97792087e-34+0.j]]), array([[5.97792087e-34+0.j, 0.00000000e+00+0.j, 0.00000000e+00+0.j, 3.25176795e-17+0.j],\n",
      "       [0.00000000e+00+0.j, 0.00000000e+00+0.j, 0.00000000e+00+0.j, 0.00000000e+00+0.j],\n",
      "       [0.00000000e+00+0.j, 0.00000000e+00+0.j, 0.00000000e+00+0.j, 0.00000000e+00+0.j],\n",
      "       [6.22328532e-19+0.j, 0.00000000e+00+0.j, 0.00000000e+00+0.j, 1.00000000e+00+0.j]])]\n"
     ]
    }
   ],
   "source": [
    "from quara.objects.matrix_basis import get_comp_basis\n",
    "\n",
    "mprocess = generate_mprocess_from_name(c_sys, \"z-type1\")\n",
    "converted_hss = mprocess.convert_basis(get_comp_basis())\n",
    "print(f\"hss: \\n{converted_hss}\")"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "### to_choi_matrix\n",
    "Returns Choi matrix of the specified index of `hss`."
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 22,
   "metadata": {},
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "to_choi_matrix(0): \n",
      "[[1.+0.j 0.+0.j 0.+0.j 0.+0.j]\n",
      " [0.+0.j 0.+0.j 0.+0.j 0.+0.j]\n",
      " [0.+0.j 0.+0.j 0.+0.j 0.+0.j]\n",
      " [0.+0.j 0.+0.j 0.+0.j 0.+0.j]]\n",
      "to_choi_matrix_with_dict(0): \n",
      "[[1.+0.j 0.+0.j 0.+0.j 0.+0.j]\n",
      " [0.+0.j 0.+0.j 0.+0.j 0.+0.j]\n",
      " [0.+0.j 0.+0.j 0.+0.j 0.+0.j]\n",
      " [0.+0.j 0.+0.j 0.+0.j 0.+0.j]]\n",
      "to_choi_matrix(0): \n",
      "[[1.+0.j 0.+0.j 0.+0.j 0.+0.j]\n",
      " [0.+0.j 0.+0.j 0.+0.j 0.+0.j]\n",
      " [0.+0.j 0.+0.j 0.+0.j 0.+0.j]\n",
      " [0.+0.j 0.+0.j 0.+0.j 0.+0.j]]\n"
     ]
    }
   ],
   "source": [
    "mprocess = generate_mprocess_from_name(c_sys, \"z-type1\")\n",
    "print(f\"to_choi_matrix(0): \\n{mprocess.to_choi_matrix(0)}\")\n",
    "print(f\"to_choi_matrix_with_dict(0): \\n{mprocess.to_choi_matrix_with_dict(0)}\")\n",
    "print(f\"to_choi_matrix(0): \\n{mprocess.to_choi_matrix(0)}\")"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "### to_kraus_matrices\n",
    "Returns Kraus matrices of the specified index of `hss`."
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 23,
   "metadata": {},
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "to_kraus_matrices(0): \n",
      "[array([[1.+0.j, 0.+0.j],\n",
      "       [0.+0.j, 0.+0.j]])]\n"
     ]
    }
   ],
   "source": [
    "mprocess = generate_mprocess_from_name(c_sys, \"z-type1\")\n",
    "print(f\"to_kraus_matrices(0): \\n{mprocess.to_kraus_matrices(0)}\")"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "### to_process_matrix\n",
    "Returns process matrix of the specified index of `hss`."
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 24,
   "metadata": {},
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "to_process_matrix(0): \n",
      "[[1.00000000e+00+0.j 0.00000000e+00+0.j 0.00000000e+00+0.j 0.00000000e+00+0.j]\n",
      " [0.00000000e+00+0.j 6.22328532e-19+0.j 0.00000000e+00+0.j 0.00000000e+00+0.j]\n",
      " [0.00000000e+00+0.j 0.00000000e+00+0.j 3.25176795e-17+0.j 0.00000000e+00+0.j]\n",
      " [0.00000000e+00+0.j 0.00000000e+00+0.j 0.00000000e+00+0.j 5.97792087e-34+0.j]]\n"
     ]
    }
   ],
   "source": [
    "mprocess = generate_mprocess_from_name(c_sys, \"z-type1\")\n",
    "print(f\"to_process_matrix(0): \\n{mprocess.to_process_matrix(0)}\")"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "### to_povm\n",
    "Generates Povm from MProcess."
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 25,
   "metadata": {},
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "Type:\n",
      "Povm\n",
      "\n",
      "Dim:\n",
      "2\n",
      "\n",
      "Number of outcomes:\n",
      "2\n",
      "\n",
      "Vecs:\n",
      "[[ 0.70710678  0.          0.          0.70710678]\n",
      " [ 0.70710678  0.          0.         -0.70710678]]\n"
     ]
    }
   ],
   "source": [
    "mprocess = generate_mprocess_from_name(c_sys, \"z-type1\")\n",
    "print(mprocess.to_povm())"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "### some utility functions"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 26,
   "metadata": {},
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "is_sum_tp(): True\n",
      "is_cp(): True\n"
     ]
    }
   ],
   "source": [
    "print(f\"is_sum_tp(): {mprocess.is_sum_tp()}\")\n",
    "print(f\"is_cp(): {mprocess.is_cp()}\")"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "## mprocess_typical\n",
    "`generate_mprocess_object_from_mprocess_name_object_name()` function in `mprocess_typical` module can easily generate objects related to MProcess.  \n",
    "The `generate_mprocess_object_from_mprocess_name_object_name()` function has the following arguments:\n",
    "\n",
    "- The string that can be specified for `mprocess_name` can be checked by executing the `get_mprocess_names_type1()` and `get_mprocess_names_type2()` functions. The tensor product of state_name \"a\", \"b\" is written \"a_b\".\n",
    "- `object_name` can be the following string:\n",
    "  - \"set_pure_state_vectors\" - The set of pure state vectors of MProcess.\n",
    "  - \"set_kraus_matrices\" - The set of Kraus matrices of MProcess.\n",
    "  - \"hss\" - The list of Hilbert-Schmidt matrix representations of MProcess.\n",
    "  - \"mprocess\" - MProcess object.\n",
    "- `c_sys` - CompositeSystem of objects related to MProcess. Specify when `object_name` is \"hss\" and \"mprocess\".\n",
    "- `is_physicality_required` - Whether the generated object is physicality required, by default True."
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 27,
   "metadata": {},
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "get_mprocess_names_type1(): \n",
      "['x-type1', 'y-type1', 'z-type1', 'bell-type1', 'z3-type1', 'z2-type1', 'xxparity-type1', 'zzparity-type1']\n",
      "get_mprocess_names_type2(): \n",
      "['x-type2', 'y-type2', 'z-type2', 'z3-type2', 'z2-type2']\n"
     ]
    }
   ],
   "source": [
    "from quara.objects.mprocess_typical import (\n",
    "    get_mprocess_names_type1,\n",
    "    get_mprocess_names_type2,\n",
    "    generate_mprocess_object_from_mprocess_name_object_name,\n",
    ")\n",
    "\n",
    "print(f\"get_mprocess_names_type1(): \\n{get_mprocess_names_type1()}\")\n",
    "print(f\"get_mprocess_names_type2(): \\n{get_mprocess_names_type2()}\")"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "### object_name = \"set_pure_state_vectors\""
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 28,
   "metadata": {},
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "[[array([1.+0.j, 0.+0.j])], [array([0.+0.j, 1.+0.j])]]\n"
     ]
    }
   ],
   "source": [
    "vecs = generate_mprocess_object_from_mprocess_name_object_name(\"z-type1\", \"set_pure_state_vectors\")\n",
    "print(vecs)"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "### object_name = \"set_kraus_matrices\""
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 29,
   "metadata": {},
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "[[array([[1.+0.j, 0.+0.j],\n",
      "       [0.+0.j, 0.+0.j]])], [array([[0.+0.j, 0.+0.j],\n",
      "       [0.+0.j, 1.+0.j]])]]\n"
     ]
    }
   ],
   "source": [
    "matrices = generate_mprocess_object_from_mprocess_name_object_name(\"z-type1\", \"set_kraus_matrices\")\n",
    "print(matrices)"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "### object_name = \"hss\""
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 30,
   "metadata": {},
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "[array([[0.5, 0. , 0. , 0.5],\n",
      "       [0. , 0. , 0. , 0. ],\n",
      "       [0. , 0. , 0. , 0. ],\n",
      "       [0.5, 0. , 0. , 0.5]]), array([[ 0.5,  0. ,  0. , -0.5],\n",
      "       [ 0. ,  0. ,  0. ,  0. ],\n",
      "       [ 0. ,  0. ,  0. ,  0. ],\n",
      "       [-0.5,  0. ,  0. ,  0.5]])]\n"
     ]
    }
   ],
   "source": [
    "c_sys = generate_composite_system(\"qubit\", 1)\n",
    "hss = generate_mprocess_object_from_mprocess_name_object_name(\"z-type1\", \"hss\", c_sys=c_sys)\n",
    "print(hss)"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "### object_name = \"mprocess\""
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 31,
   "metadata": {},
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "Type:\n",
      "MProcess\n",
      "\n",
      "Dim:\n",
      "2\n",
      "\n",
      "HSs:\n",
      "[array([[0.5, 0. , 0. , 0.5],\n",
      "       [0. , 0. , 0. , 0. ],\n",
      "       [0. , 0. , 0. , 0. ],\n",
      "       [0.5, 0. , 0. , 0.5]]), array([[ 0.5,  0. ,  0. , -0.5],\n",
      "       [ 0. ,  0. ,  0. ,  0. ],\n",
      "       [ 0. ,  0. ,  0. ,  0. ],\n",
      "       [-0.5,  0. ,  0. ,  0.5]])]\n",
      "\n",
      "ModeSampling:\n",
      "False\n"
     ]
    }
   ],
   "source": [
    "c_sys = generate_composite_system(\"qubit\", 1)\n",
    "mprocess = generate_mprocess_object_from_mprocess_name_object_name(\"z-type1\", \"mprocess\", c_sys=c_sys)\n",
    "print(mprocess)"
   ]
  }
 ],
 "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
}
