{
 "cells": [
  {
   "cell_type": "markdown",
   "id": "07541c58",
   "metadata": {},
   "source": [
    "# Composition of QOperations\n",
    "\n",
    "This note describes how to calculate composition of qoperations."
   ]
  },
  {
   "cell_type": "markdown",
   "id": "293b97cf",
   "metadata": {},
   "source": [
    "## Composition\n",
    "\n",
    "Composition is an operation in the **time direction**. To compute the tensor product, use `compose_qoperations()` in the `quara.objects.operators` module.\n",
    "\n",
    "As a simple example, let's look at how to compute the composition of the following State and Gate.\n",
    "\n",
    "**formula:**\n",
    "\n",
    "$(G_{z}, \\rho_{z0})$\n",
    "\n",
    "**quantum circuit diagram:**\n",
    "\n",
    "── $\\rho_{z0}$ ─ $G_{z}$ ──"
   ]
  },
  {
   "cell_type": "markdown",
   "id": "7c316917",
   "metadata": {},
   "source": [
    "First, prepare State and Gate to be used for the operation. Note that the IDs of the ElementalSystems between QOperations to be calculated with composition must be same."
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 1,
   "id": "15fa8105",
   "metadata": {},
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "vec of state: \n",
      "[0.70710678 0.         0.         0.70710678]\n",
      "HS of gate: \n",
      "[[ 1.  0.  0.  0.]\n",
      " [ 0. -1.  0.  0.]\n",
      " [ 0.  0. -1.  0.]\n",
      " [ 0.  0.  0.  1.]]\n"
     ]
    }
   ],
   "source": [
    "from quara.objects.composite_system_typical import generate_composite_system\n",
    "from quara.objects.qoperation_typical import generate_qoperation\n",
    "\n",
    "# Prepare State and Gate\n",
    "c_sys = generate_composite_system(\"qubit\", 1, ids_esys=[0])\n",
    "state = generate_qoperation(mode=\"state\", name=\"z0\", c_sys=c_sys)\n",
    "gate = generate_qoperation(mode=\"gate\", name=\"z\", c_sys=c_sys)\n",
    "\n",
    "print(f\"vec of state: \\n{state.vec}\")\n",
    "print(f\"HS of gate: \\n{gate.hs}\")"
   ]
  },
  {
   "cell_type": "markdown",
   "id": "5f044f93",
   "metadata": {},
   "source": [
    " The composition of State and Gate can be written as follows. Note that the argument to `compose_qoperations()` specifies QOperations **in the same order as the formula**, not in the order on the quantum circuit."
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 2,
   "id": "19ef7011",
   "metadata": {},
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "Type:\n",
      "State\n",
      "\n",
      "Dim:\n",
      "2\n",
      "\n",
      "Vec:\n",
      "[0.70710678 0.         0.         0.70710678]\n"
     ]
    }
   ],
   "source": [
    "from quara.objects.operators import compose_qoperations\n",
    "\n",
    "# Composition\n",
    "result = compose_qoperations(gate, state)\n",
    "\n",
    "# Result\n",
    "print(result)"
   ]
  },
  {
   "cell_type": "markdown",
   "id": "b6b6a4bb",
   "metadata": {},
   "source": [
    "### Composition of three or more QOperations"
   ]
  },
  {
   "cell_type": "markdown",
   "id": "af35cf56",
   "metadata": {},
   "source": [
    "For three or more QOepration operations, add to the argument. Let's look at how to compute the composition of the following State, and Gate.\n",
    "\n",
    "**formula:**\n",
    "\n",
    "$(G_{x}, G_{z}, \\rho_{z0})$\n",
    "\n",
    "**quantum circuit diagram:**\n",
    "\n",
    "── $\\rho_{z0}$ ─ $G_{z}$ ─ $G_{x}$ ──"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 3,
   "id": "14999661",
   "metadata": {},
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "Type:\n",
      "State\n",
      "\n",
      "Dim:\n",
      "2\n",
      "\n",
      "Vec:\n",
      "[ 0.70710678  0.          0.         -0.70710678]\n"
     ]
    }
   ],
   "source": [
    "# Prepare State, POVM, and Gate\n",
    "c_sys_0 = generate_composite_system(\"qubit\", 1, ids_esys=[0])\n",
    "\n",
    "state = generate_qoperation(mode=\"state\", name=\"z0\", c_sys=c_sys)\n",
    "gate_0 = generate_qoperation(mode=\"gate\", name=\"z\", c_sys=c_sys)\n",
    "gate_1 = generate_qoperation(mode=\"gate\", name=\"x\", c_sys=c_sys)\n",
    "\n",
    "# Composition of three or more QOperations\n",
    "result = compose_qoperations(gate_1, gate_0, state)\n",
    "print(result)"
   ]
  },
  {
   "cell_type": "markdown",
   "id": "aca5aab9",
   "metadata": {},
   "source": [
    "It is also possible to specify QOperations as a list. For example, the following two expressions have the same meaning."
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 4,
   "id": "642aeb4e",
   "metadata": {},
   "outputs": [],
   "source": [
    "# Specify by appending to the argument\n",
    "result = compose_qoperations(gate_1, gate_0, state)\n",
    "\n",
    "# Specify by list\n",
    "result = compose_qoperations([gate_1, gate_0, state])"
   ]
  },
  {
   "cell_type": "markdown",
   "id": "c8f4acd8",
   "metadata": {},
   "source": [
    "## Supported operations"
   ]
  },
  {
   "cell_type": "markdown",
   "id": "07674be7",
   "metadata": {},
   "source": [
    "The `compose_qoperations()` supports the following combinations of QOperations.\n",
    "\n",
    "| Input | Output |\n",
    "|:-------|:---------|\n",
    "| (Gate, Gate) | Gate|\n",
    "| (Gate, MProcess) | MProcess |\n",
    "| (MProcess, Gate)  | MProcess |\n",
    "| (MProcess, MProcess) | MProcess |\n",
    "| (Gate, State)  |  State |\n",
    "| (MProcess, State) |  StateEnsemble |\n",
    "| (Mprocess, StateEnsemble) | StateEnsemble |\n",
    "| (Povm, Gate) | Povm |\n",
    "| (Povm, MProcess)  | Povm |\n",
    "| (Povm, State) | MultinomialDistribution |\n",
    "| (Povm, StateEnsemble) | MultinomialDistribution |\n"
   ]
  },
  {
   "cell_type": "markdown",
   "id": "0068a8ae",
   "metadata": {},
   "source": [
    "## Examples"
   ]
  },
  {
   "cell_type": "markdown",
   "id": "f7ebf981",
   "metadata": {},
   "source": [
    "### (Gate, Gate) -> Gate"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 5,
   "id": "03a184ee",
   "metadata": {},
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "Type:\n",
      "Gate\n",
      "\n",
      "Dim:\n",
      "2\n",
      "\n",
      "HS:\n",
      "[[ 1.  0.  0.  0.]\n",
      " [ 0. -1.  0.  0.]\n",
      " [ 0.  0.  1.  0.]\n",
      " [ 0.  0.  0. -1.]]\n"
     ]
    }
   ],
   "source": [
    "# Prepare\n",
    "c_sys = generate_composite_system(\"qubit\", 1, ids_esys=[0])\n",
    "gate_0 = generate_qoperation(mode=\"gate\", name=\"z\", c_sys=c_sys)\n",
    "gate_1 = generate_qoperation(mode=\"gate\", name=\"x\", c_sys=c_sys)\n",
    "\n",
    "# Compose\n",
    "result = compose_qoperations(gate_1, gate_0)\n",
    "print(result)  # Gate"
   ]
  },
  {
   "cell_type": "markdown",
   "id": "2b54445a",
   "metadata": {},
   "source": [
    "### (Gate, MProcess) -> MProcess"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 6,
   "id": "0850bf5d",
   "metadata": {},
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "Type:\n",
      "MProcess\n",
      "\n",
      "Dim:\n",
      "2\n",
      "\n",
      "HSs:\n",
      "[array([[ 0.5,  0.5,  0. ,  0. ],\n",
      "       [-0.5, -0.5,  0. ,  0. ],\n",
      "       [ 0. ,  0. ,  0. ,  0. ],\n",
      "       [ 0. ,  0. ,  0. ,  0. ]]), array([[ 0.5, -0.5,  0. ,  0. ],\n",
      "       [ 0.5, -0.5,  0. ,  0. ],\n",
      "       [ 0. ,  0. ,  0. ,  0. ],\n",
      "       [ 0. ,  0. ,  0. ,  0. ]])]\n",
      "\n",
      "ModeSampling:\n",
      "False\n"
     ]
    }
   ],
   "source": [
    "# Prepare\n",
    "c_sys = generate_composite_system(\"qubit\", 1, ids_esys=[0])\n",
    "gate = generate_qoperation(mode=\"gate\", name=\"z\", c_sys=c_sys)\n",
    "mprocess = generate_qoperation(mode=\"mprocess\", name=\"x-type1\", c_sys=c_sys)\n",
    "\n",
    "# Compose\n",
    "result = compose_qoperations(gate, mprocess)\n",
    "print(result)  # MProcess"
   ]
  },
  {
   "cell_type": "markdown",
   "id": "0b2a86ce",
   "metadata": {},
   "source": [
    "### (MProcess, Gate) -> MProcess"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 7,
   "id": "6b1bb244",
   "metadata": {},
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "Type:\n",
      "MProcess\n",
      "\n",
      "Dim:\n",
      "2\n",
      "\n",
      "HSs:\n",
      "[array([[ 0.5, -0.5,  0. ,  0. ],\n",
      "       [ 0.5, -0.5,  0. ,  0. ],\n",
      "       [ 0. ,  0. ,  0. ,  0. ],\n",
      "       [ 0. ,  0. ,  0. ,  0. ]]), array([[ 0.5,  0.5,  0. ,  0. ],\n",
      "       [-0.5, -0.5,  0. ,  0. ],\n",
      "       [ 0. ,  0. ,  0. ,  0. ],\n",
      "       [ 0. ,  0. ,  0. ,  0. ]])]\n",
      "\n",
      "ModeSampling:\n",
      "False\n"
     ]
    }
   ],
   "source": [
    "# Prepare\n",
    "c_sys = generate_composite_system(\"qubit\", 1, ids_esys=[0])\n",
    "mprocess = generate_qoperation(mode=\"mprocess\", name=\"x-type1\", c_sys=c_sys)\n",
    "gate = generate_qoperation(mode=\"gate\", name=\"z\", c_sys=c_sys)\n",
    "\n",
    "# Compose\n",
    "result = compose_qoperations(mprocess, gate)\n",
    "print(result)  # MProcess"
   ]
  },
  {
   "cell_type": "markdown",
   "id": "96c421db",
   "metadata": {},
   "source": [
    "### (Gate, State) -> State"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 8,
   "id": "14e62f3d",
   "metadata": {},
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "Type:\n",
      "State\n",
      "\n",
      "Dim:\n",
      "2\n",
      "\n",
      "Vec:\n",
      "[0.70710678 0.         0.         0.70710678]\n"
     ]
    }
   ],
   "source": [
    "# Prepare\n",
    "c_sys = generate_composite_system(\"qubit\", 1, ids_esys=[0])\n",
    "gate = generate_qoperation(mode=\"gate\", name=\"z\", c_sys=c_sys)\n",
    "state = generate_qoperation(mode=\"state\", name=\"z0\", c_sys=c_sys)\n",
    "\n",
    "# Compose\n",
    "result = compose_qoperations(gate, state)\n",
    "print(result)  # State"
   ]
  },
  {
   "cell_type": "markdown",
   "id": "f22014fa",
   "metadata": {},
   "source": [
    "### (MProcess, State) -> StateEnsemble"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 9,
   "id": "8a1dad31",
   "metadata": {},
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "Type:\n",
      "StateEnsemble\n",
      "\n",
      "States:\n",
      "states[0]: [0.70710678 0.70710678 0.         0.        ]\n",
      "states[1]: [ 0.70710678 -0.70710678  0.          0.        ]\n",
      "\n",
      "MultinomialDistribution:\n",
      "shape = (2,)\n",
      "ps = [0.5 0.5]\n"
     ]
    }
   ],
   "source": [
    "# Prepare\n",
    "c_sys = generate_composite_system(\"qubit\", 1, ids_esys=[0])\n",
    "mprocess = generate_qoperation(mode=\"mprocess\", name=\"x-type1\", c_sys=c_sys)\n",
    "state = generate_qoperation(mode=\"state\", name=\"z0\", c_sys=c_sys)\n",
    "\n",
    "# Compose\n",
    "result = compose_qoperations(mprocess, state)\n",
    "print(result)  # StateEnsemble"
   ]
  },
  {
   "cell_type": "markdown",
   "id": "09b00edd",
   "metadata": {},
   "source": [
    "### (MProcess, StateEnsemble) -> StateEnsemble"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 10,
   "id": "9395354c",
   "metadata": {},
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "Type:\n",
      "StateEnsemble\n",
      "\n",
      "States:\n",
      "states[0]: [0.70710678 0.70710678 0.         0.        ]\n",
      "states[1]: [ 0.70710678 -0.70710678  0.          0.        ]\n",
      "states[2]: [0. 0. 0. 0.]\n",
      "states[3]: [0. 0. 0. 0.]\n",
      "\n",
      "MultinomialDistribution:\n",
      "shape = (2, 2)\n",
      "ps = [0.5 0.5 0.  0. ]\n"
     ]
    }
   ],
   "source": [
    "# Prepare\n",
    "c_sys = generate_composite_system(\"qubit\", 1, ids_esys=[0])\n",
    "mprocess = generate_qoperation(mode=\"mprocess\", name=\"x-type1\", c_sys=c_sys)\n",
    "state_ensemble = generate_qoperation(mode=\"state_ensemble\", name=\"z0\", c_sys=c_sys)\n",
    "\n",
    "# Compose\n",
    "result = compose_qoperations(mprocess, state_ensemble)\n",
    "print(result)  # StateEnsemble"
   ]
  },
  {
   "cell_type": "markdown",
   "id": "e6f94ca3",
   "metadata": {},
   "source": [
    "### (Povm, Gate) -> Povm"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 11,
   "id": "e43471cf",
   "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.70710678  0.          0.        ]\n",
      " [ 0.70710678  0.70710678  0.          0.        ]]\n"
     ]
    }
   ],
   "source": [
    "# Prepare\n",
    "c_sys = generate_composite_system(\"qubit\", 1, ids_esys=[0])\n",
    "povm = generate_qoperation(mode=\"povm\", name=\"x\", c_sys=c_sys)\n",
    "gate = generate_qoperation(mode=\"gate\", name=\"z\", c_sys=c_sys)\n",
    "\n",
    "# Compose\n",
    "result = compose_qoperations(povm, gate)\n",
    "print(result)  # Povm"
   ]
  },
  {
   "cell_type": "markdown",
   "id": "004f38b2",
   "metadata": {},
   "source": [
    "### (Povm, MProcess) -> Povm"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 12,
   "id": "8ee04a6e",
   "metadata": {},
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "Type:\n",
      "Povm\n",
      "\n",
      "Dim:\n",
      "2\n",
      "\n",
      "Number of outcomes:\n",
      "4\n",
      "\n",
      "Vecs:\n",
      "[[ 0.70710678  0.70710678  0.          0.        ]\n",
      " [ 0.          0.          0.          0.        ]\n",
      " [ 0.          0.          0.          0.        ]\n",
      " [ 0.70710678 -0.70710678  0.          0.        ]]\n"
     ]
    }
   ],
   "source": [
    "# Prepare\n",
    "c_sys = generate_composite_system(\"qubit\", 1, ids_esys=[0])\n",
    "povm = generate_qoperation(mode=\"povm\", name=\"x\", c_sys=c_sys)\n",
    "mprocess = generate_qoperation(mode=\"mprocess\", name=\"x-type1\", c_sys=c_sys)\n",
    "\n",
    "# Compose\n",
    "result = compose_qoperations(povm, mprocess)\n",
    "print(result)  # Povm"
   ]
  },
  {
   "cell_type": "markdown",
   "id": "28000e82",
   "metadata": {},
   "source": [
    "### (Povm, State) -> MultinomialDistribution"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 13,
   "id": "8a813286",
   "metadata": {},
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "<class 'quara.objects.multinomial_distribution.MultinomialDistribution'>\n",
      "shape = (2,)\n",
      "ps = [0.5 0.5]\n"
     ]
    }
   ],
   "source": [
    "# Prepare\n",
    "c_sys = generate_composite_system(\"qubit\", 1, ids_esys=[0])\n",
    "povm = generate_qoperation(mode=\"povm\", name=\"x\", c_sys=c_sys)\n",
    "state = generate_qoperation(mode=\"state\", name=\"z0\", c_sys=c_sys)\n",
    "\n",
    "# Compose\n",
    "result = compose_qoperations(povm, state)\n",
    "print(type(result))\n",
    "print(result)  # MultinomialDistribution"
   ]
  },
  {
   "cell_type": "markdown",
   "id": "c5070c6e",
   "metadata": {},
   "source": [
    "### (Povm, StateEnsemble) -> MultinomialDistribution"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 14,
   "id": "5ed93490",
   "metadata": {},
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "<class 'quara.objects.multinomial_distribution.MultinomialDistribution'>\n",
      "shape = (2, 2)\n",
      "ps = [0.5 0.5 0.  0. ]\n"
     ]
    }
   ],
   "source": [
    "# Prepare\n",
    "c_sys = generate_composite_system(\"qubit\", 1, ids_esys=[0])\n",
    "povm = generate_qoperation(mode=\"povm\", name=\"x\", c_sys=c_sys)\n",
    "state_ensemble = generate_qoperation(mode=\"state_ensemble\", name=\"z0\", c_sys=c_sys)\n",
    "\n",
    "# Compose\n",
    "result = compose_qoperations(povm, state_ensemble)\n",
    "print(type(result))\n",
    "print(result)  # MultinomialDistribution"
   ]
  }
 ],
 "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": true
  }
 },
 "nbformat": 4,
 "nbformat_minor": 5
}
