{
 "cells": [
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "# Using Quara's standard tomography features from Qiskit"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "Quara supports the wrappers for executing standard tomography from qiskit. Here, we demonstarate how to use them as several 1-qubit tomography."
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 1,
   "metadata": {},
   "outputs": [],
   "source": [
    "import numpy as np\n",
    "\n",
    "from quara.interface.qiskit.api import (\n",
    "    estimate_standard_qst_from_qiskit,\n",
    "    estimate_standard_povmt_from_qiskit,\n",
    "    estimate_standard_qpt_from_qiskit,\n",
    "    generate_empi_dists_from_qiskit_state,\n",
    "    generate_empi_dists_from_qiskit_povm,\n",
    "    generate_empi_dists_from_qiskit_gate,\n",
    "    generate_empi_dists_from_quara\n",
    ") \n",
    "\n",
    "from quara.objects.state_typical import (\n",
    "    generate_state_density_mat_from_name,\n",
    "    get_state_names_1qubit,\n",
    "    generate_state_from_name,\n",
    ")\n",
    "\n",
    "from qiskit.circuit.library.standard_gates import h\n",
    "from qiskit.quantum_info.operators.channel import Choi"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "When executing the tomography in Qiskit, state and POVM of testers are defined as TomographyBasis. Here,we use following representation matrices from TomographyBasis(PauliBasis)."
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 2,
   "metadata": {},
   "outputs": [],
   "source": [
    "# State\n",
    "Xp = np.array([[0.5, 0.5], [0.5, 0.5]], dtype=complex)\n",
    "Xm = np.array([[0.5,-0.5],[-0.5,0.5]],dtype=complex)\n",
    "Yp = np.array([[0.5, -0.5j], [0.5j, 0.5]], dtype=complex)\n",
    "Ym = np.array([[0.5,0.5j],[-0.5j,0.5]],dtype=complex)\n",
    "Zp = np.array([[1, 0], [0, 0]], dtype=complex)\n",
    "Zm = np.array([[0, 0], [0, 1]], dtype=complex)\n",
    "a = generate_state_density_mat_from_name(\"a\")\n",
    "\n",
    "#POVM\n",
    "X = [Xp,Xm]\n",
    "Y = [Yp,Ym]\n",
    "Z = [Zp,Zm]"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "## Quantum State Tomography(1-qubit)\n",
    "We demonstarate 1-qubit QST using the tester from Qiskit. We need to define tester POVMs as a list when we perform Quantum State tomography using quara."
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 3,
   "metadata": {},
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "[[0.5       +0.j         0.35355339-0.35355339j]\n",
      " [0.35355339+0.35355339j 0.5       +0.j        ]]\n"
     ]
    }
   ],
   "source": [
    "#Testers\n",
    "tester_povms = [X,Y,Z]\n",
    "#True objects\n",
    "true_state = a\n",
    "print(true_state)"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "We will generate the empirical distribution from given true state object. If you have your own list of empirical distributions make sure that the type matches to `List[Tuple [int,np.ndarray]]`."
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 18,
   "metadata": {},
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "(1000, array([0.864, 0.136]))\n",
      "(1000, array([0.844, 0.156]))\n",
      "(1000, array([0.49, 0.51]))\n"
     ]
    },
    {
     "data": {
      "text/plain": [
       "list"
      ]
     },
     "execution_count": 18,
     "metadata": {},
     "output_type": "execute_result"
    }
   ],
   "source": [
    "# define system\n",
    "mode = \"qubit\"\n",
    "num = 1\n",
    "\n",
    "# define requirement for empirical distribution\n",
    "num_data = 1000\n",
    "seed = 7896\n",
    "\n",
    "# calculate empirical distribution\n",
    "empi_dists = generate_empi_dists_from_qiskit_state(mode_system=mode, num_system=num, true_state=true_state, tester_povms=tester_povms, num_sum=num_data, seed=seed, schedules=\"all\")\n",
    "for f in empi_dists:\n",
    "    print(f)\n",
    "type(empi_dists)"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "Now, we execute quantum state tomography using linear estimation. You can estimate the quantum state just by calling `estimate_standard_qst_from_qiskit()`. You can choose linear estimation by specifying `estimator_name=\"linear\"`.\n",
    "You have to specify the empi_dists in qiskit."
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 6,
   "metadata": {},
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "[[0.49 +0.j    0.364-0.344j]\n",
      " [0.364+0.344j 0.51 +0.j   ]]\n"
     ]
    }
   ],
   "source": [
    "empi_dists_qiskit = generate_empi_dists_from_quara(empi_dists)\n",
    "estimate = estimate_standard_qst_from_qiskit(mode_system=mode,num_system=num,tester_povms=tester_povms,empi_dists=empi_dists_qiskit[1],shots=1000,label=empi_dists_qiskit[0],estimator_name=\"linear\", schedules=\"all\")\n",
    "print(estimate)"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "You can choose least squares estimation by specifying `estimator_name=\"least_squares\"`."
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 8,
   "metadata": {},
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "[[0.49001861+0.j         0.36332341-0.34336059j]\n",
      " [0.36332341+0.34336059j 0.50998144+0.j        ]]\n"
     ]
    }
   ],
   "source": [
    "empi_dists_qiskit = generate_empi_dists_from_quara(empi_dists)\n",
    "estimate = estimate_standard_qst_from_qiskit(mode_system=mode,num_system=num,tester_povms=tester_povms,empi_dists=empi_dists_qiskit[1],shots=1000,label=empi_dists_qiskit[0],estimator_name=\"least_squares\", schedules=\"all\")\n",
    "print(estimate)"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "## Quantum POVM Tomography (1qubit)"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "Here, we demonstarate 1-qubit POVMT using the tester from Qiskit. We need to define tester states as a list when we perform Quantum POVM tomography using quara."
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 9,
   "metadata": {},
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "[[0.5+0.j 0.5+0.j]\n",
      " [0.5+0.j 0.5+0.j]]\n",
      "[[ 0.5+0.j -0.5+0.j]\n",
      " [-0.5+0.j  0.5+0.j]]\n"
     ]
    }
   ],
   "source": [
    "#Testers\n",
    "tester_states = [Xp,Yp,Zp,Zm]\n",
    "#True objects\n",
    "true_povm = X\n",
    "for i in true_povm:\n",
    "    print(i)"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 10,
   "metadata": {},
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "(1000, array([1., 0.]))\n",
      "(1000, array([0.502, 0.498]))\n",
      "(1000, array([0.49, 0.51]))\n",
      "(1000, array([0.488, 0.512]))\n"
     ]
    }
   ],
   "source": [
    "# define system\n",
    "mode = \"qubit\"\n",
    "num = 1\n",
    "\n",
    "# define requirement for empirical distribution\n",
    "num_data = 1000\n",
    "seed = 7896\n",
    "\n",
    "# calculate empirical distribution\n",
    "empi_dists = generate_empi_dists_from_qiskit_povm(mode_system=mode, num_system=num, true_povm=true_povm, tester_states=tester_states, num_sum=num_data, seed=seed, schedules=\"all\")\n",
    "for i in empi_dists:\n",
    "    print(i)"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "Now, we execute quantum povm tomography using linear estimation. You can estimate the quantum povm just by calling `estimate_standard_povmt_from_qiskit()`. You can choose linear estimation by specifying `estimator_name=\"linear\"`.\n",
    "You have to specify num_outcomes, which is number of outcome values of the POVM that will be estimated."
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 11,
   "metadata": {},
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "[[0.49 +0.j    0.511-0.013j]\n",
      " [0.511+0.013j 0.488+0.j   ]]\n",
      "[[ 0.51 +0.j    -0.511+0.013j]\n",
      " [-0.511-0.013j  0.512+0.j   ]]\n"
     ]
    }
   ],
   "source": [
    "empi_dists_qiskit = generate_empi_dists_from_quara(empi_dists)\n",
    "estimate = estimate_standard_povmt_from_qiskit(mode_system=mode,num_system=num,tester_states=tester_states,empi_dists=empi_dists_qiskit[1],shots=1000,label=empi_dists_qiskit[0],num_outcomes=2,estimator_name=\"linear\", schedules=\"all\")\n",
    "for i in estimate:\n",
    "    print(i)"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "You can choose least squares estimation by specifying `estimator_name=\"least_squares\"`."
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 12,
   "metadata": {},
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "[[0.49735047+0.j         0.49632565-0.00556025j]\n",
      " [0.49632565+0.00556025j 0.4953651 +0.j        ]]\n",
      "[[ 0.50264953+0.j         -0.49632565+0.00556025j]\n",
      " [-0.49632565-0.00556025j  0.5046349 +0.j        ]]\n"
     ]
    }
   ],
   "source": [
    "empi_dists_qiskit = generate_empi_dists_from_quara(empi_dists)\n",
    "estimate = estimate_standard_povmt_from_qiskit(mode_system=mode,num_system=num,tester_states=tester_states,empi_dists=empi_dists_qiskit[1],shots=1000,label=empi_dists_qiskit[0],num_outcomes=2,estimator_name=\"least_squares\", schedules=\"all\")\n",
    "for i in estimate:\n",
    "    print(i)"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "## Quantum Process Tomography(1qubit)"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "Here, we demonstarate 1-qubit QPT using the tester from Qiskit. We need to define tester states and POVMs as a list when we perform Quantum Process tomography using quara.  When using gate here, we have to use it in Choi matrix."
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 14,
   "metadata": {},
   "outputs": [
    {
     "data": {
      "text/plain": [
       "array([[ 0.70710678,  0.70710678],\n",
       "       [ 0.70710678, -0.70710678]])"
      ]
     },
     "execution_count": 14,
     "metadata": {},
     "output_type": "execute_result"
    }
   ],
   "source": [
    "#Testers\n",
    "tester_povms = [X,Y,Z]\n",
    "tester_states = [Xp,Yp,Zp,Zm]\n",
    "#True objects\n",
    "true_gate = h.HGate()\n",
    "true_gate.__array__()"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 15,
   "metadata": {},
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "(1000, array([0.496, 0.504]))\n",
      "(1000, array([0.502, 0.498]))\n",
      "(1000, array([1., 0.]))\n",
      "(1000, array([0.488, 0.512]))\n",
      "(1000, array([0., 1.]))\n",
      "(1000, array([0.491, 0.509]))\n",
      "(1000, array([1., 0.]))\n",
      "(1000, array([0.507, 0.493]))\n",
      "(1000, array([0.513, 0.487]))\n",
      "(1000, array([0., 1.]))\n",
      "(1000, array([0.47, 0.53]))\n",
      "(1000, array([0.497, 0.503]))\n"
     ]
    }
   ],
   "source": [
    "# define system\n",
    "mode = \"qubit\"\n",
    "num = 1\n",
    "\n",
    "# define requirement for empirical distribution\n",
    "num_data = 1000\n",
    "seed = 7896\n",
    "\n",
    "# calculate empirical distribution\n",
    "t_gate = Choi(true_gate)\n",
    "empi_dists = generate_empi_dists_from_qiskit_gate(mode_system=mode, num_system=num, true_gate=t_gate, tester_states=tester_states,tester_povms=tester_povms, num_sum=num_data, seed=seed, schedules=\"all\")\n",
    "for i in empi_dists:\n",
    "    print(i)"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "Now, we execute quantum process tomography using linear estimation. You can estimate the quantum process just by calling `estimate_standard_qpt_from_qiskit()`. You can choose linear estimation by specifying `estimator_name=\"linear\"`.\n"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 16,
   "metadata": {},
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "[ 0.513 +0.j      0.5   -0.007j   0.495 -0.014j  -0.4925-0.0255j]\n",
      "[ 0.5   +0.007j   0.487 +0.j      0.4845+0.0015j -0.495 +0.014j ]\n",
      "[ 0.495 +0.014j   0.4845-0.0015j  0.497 +0.j     -0.5   +0.03j  ]\n",
      "[-0.4925+0.0255j -0.495 -0.014j  -0.5   -0.03j    0.503 +0.j    ]\n"
     ]
    }
   ],
   "source": [
    "empi_dists_qiskit = generate_empi_dists_from_quara(empi_dists)\n",
    "estimate = estimate_standard_qpt_from_qiskit(mode_system=mode,num_system=num,tester_states=tester_states,tester_povms=tester_povms,empi_dists=empi_dists_qiskit[1],shots=1000,label=empi_dists_qiskit[0],estimator_name=\"linear\", schedules=\"all\")\n",
    "for i in estimate:\n",
    "    print(i)"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "You can choose least squares estimation by specifying `estimator_name=\"least_squares\"`."
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 17,
   "metadata": {},
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "[ 0.51438824+0.j          0.49329968-0.00741707j  0.48853761-0.00725424j\n",
      " -0.49249075+0.00293811j]\n",
      "[ 0.49329968+0.00741707j  0.48561176+0.j          0.48871849+0.0007454j\n",
      " -0.48853761+0.00725424j]\n",
      "[ 0.48853761+0.00725424j  0.48871849-0.0007454j   0.49664456+0.j\n",
      " -0.49336835+0.01536569j]\n",
      "[-0.49249075-0.00293811j -0.48853761-0.00725424j -0.49336835-0.01536569j\n",
      "  0.50335544+0.j        ]\n"
     ]
    }
   ],
   "source": [
    "empi_dists_qiskit = generate_empi_dists_from_quara(empi_dists)\n",
    "estimate = estimate_standard_qpt_from_qiskit(mode_system=mode,num_system=num,tester_states=tester_states,tester_povms=tester_povms,empi_dists=empi_dists_qiskit[1],shots=1000,label=empi_dists_qiskit[0],estimator_name=\"least_squares\", schedules=\"all\")\n",
    "for i in estimate:\n",
    "    print(i)"
   ]
  }
 ],
 "metadata": {
  "interpreter": {
   "hash": "7df16140f85f61dcb3c657e5700bc439fcf5b8d0d77a26bb81ed3a9798e61f3d"
  },
  "kernelspec": {
   "display_name": "Python 3.9.4 64-bit ('venv': venv)",
   "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.9.4"
  }
 },
 "nbformat": 4,
 "nbformat_minor": 2
}
