{
 "cells": [
  {
   "cell_type": "markdown",
   "id": "fada0991-4122-48fa-bd8a-ab83248809a7",
   "metadata": {},
   "source": [
    "# 0. Connect to IBM Quantum (optional hardware section)"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "id": "b382e45d-4c15-4ae3-95d7-e6b92fb60b18",
   "metadata": {},
   "outputs": [],
   "source": [
    "from qiskit_ibm_runtime import QiskitRuntimeService\n",
    "\n",
    "# Save your personal Open Plan credentials once by following README.md.\n",
    "# Never store an API key in this notebook.\n",
    "service = QiskitRuntimeService()"
   ]
  },
  {
   "cell_type": "markdown",
   "id": "50bf9b09-410b-426e-b96d-70ef27059ca4",
   "metadata": {},
   "source": [
    "# 1.Choose the quantum chip"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "id": "afda4988-6491-4168-ad0a-213d91591ea0",
   "metadata": {},
   "outputs": [],
   "source": [
    "from qiskit import QuantumCircuit\n",
    "from qiskit_ibm_runtime import SamplerV2 as Sampler\n",
    "from qiskit.transpiler.preset_passmanagers import generate_preset_pass_manager\n",
    "\n",
    "\n",
    "# ------------------------------\n",
    "# 1. choose the quantum computer\n",
    "# ------------------------------\n",
    "hardware_backend = service.least_busy(\n",
    "    min_num_qubits=4,\n",
    "    operational=True,\n",
    "    simulator=False,\n",
    ")\n",
    "hardware_name = hardware_backend.name\n",
    "print(\"Using hardware:\", hardware_name)\n",
    "\n",
    "\n",
    "# 1.1 get the transpiler\n",
    "pass_manager = generate_preset_pass_manager(\n",
    "    backend=hardware_backend, optimization_level=3\n",
    ")\n",
    "\n",
    "print(\"Generated pass manager with optimization_level=3.\")\n",
    "\n",
    "# 1.2 get the sampler\n",
    "sampler = Sampler(mode=hardware_backend)\n",
    "\n",
    "\n",
    "\n",
    "# 1.3 choose the error mitigation methods\n",
    "\n",
    "# sampler.options.dynamical_decoupling.enable = True\n",
    "# sampler.options.dynamical_decoupling.sequence_type = \"XpXm\"\n",
    "# sampler.options.twirling.enable_gates = True\n",
    "# # sampler.options.twirling.num_randomizations = 128\n",
    "# # sampler.options.twirling.shots_per_randomization = 100\n",
    "\n",
    "# sampler.options.twirling.num_randomizations = 64\n",
    "# sampler.options.twirling.shots_per_randomization = 128\n"
   ]
  },
  {
   "cell_type": "markdown",
   "id": "3ea14e98-331d-420f-89a6-7d9362c0ad49",
   "metadata": {},
   "source": [
    "# 2.Construct quantum circuit to generate the GHZ state  $\\ket{000...00}+\\ket{111...11}$"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "id": "a1ae6371-05ee-459c-9b3f-886220a8ae6f",
   "metadata": {},
   "outputs": [],
   "source": [
    "n_qubits = 4\n",
    "ghz = QuantumCircuit(n_qubits)\n",
    "ghz.h(0)\n",
    "for q_idx in range(1,n_qubits):\n",
    "    ghz.cx(0, q_idx)\n",
    "\n",
    "ghz.measure_all()\n",
    "\n",
    "circuit_list = [ghz]\n",
    "\n",
    "ghz.draw(output=\"mpl\")"
   ]
  },
  {
   "cell_type": "markdown",
   "id": "00e61913-956c-446e-863d-a9c396a1081b",
   "metadata": {},
   "source": [
    "# 3.Transpile the circuit"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "id": "3a40aec9-4f5c-4328-8d1b-0684c5779f7f",
   "metadata": {
    "scrolled": true
   },
   "outputs": [],
   "source": [
    "transpiled_ghz = pass_manager.run(ghz)\n",
    "transpiled_ghz.draw()"
   ]
  },
  {
   "cell_type": "markdown",
   "id": "598601ca-a608-48a0-8808-e8c97ac599de",
   "metadata": {},
   "source": [
    "# 4. Submit the circuit\n",
    "\n",
    "Submit one small job to conserve personal Open Plan QPU time."
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "id": "ab3181c0-014f-4fe2-ab3c-c964e52ee511",
   "metadata": {},
   "outputs": [],
   "source": [
    "shots = 1024\n",
    "job = sampler.run([transpiled_ghz], shots=shots)\n",
    "jobs = [job]\n",
    "print(\"Submitted job:\", job.job_id())"
   ]
  },
  {
   "cell_type": "markdown",
   "id": "a45814b0-1f53-4b90-b370-4ad10e39b3ee",
   "metadata": {},
   "source": [
    "# 5. Keep the job ID"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "id": "4b4f47dc-6b55-4a17-bc6b-b345ac486706",
   "metadata": {},
   "outputs": [],
   "source": [
    "job_id = jobs[0].job_id()\n",
    "print(\"Your job ID:\", job_id)\n",
    "\n",
    "# To retrieve this job after restarting Python, use your own job ID:\n",
    "# jobs = [service.job(\"YOUR_JOB_ID\")]"
   ]
  },
  {
   "cell_type": "markdown",
   "id": "0d54a870-4fba-4561-9497-1f15f6e6a5e1",
   "metadata": {},
   "source": [
    "# 6.data post-processing"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "id": "b57f28b2-82f6-4510-92f0-df9187519d64",
   "metadata": {},
   "outputs": [],
   "source": [
    "from qiskit.visualization import plot_histogram\n",
    "\n",
    "\n",
    "# plot the measurement results\n",
    "result = jobs[0].result()\n",
    "\n",
    "counts = result[0].data.meas.get_counts()\n",
    "\n",
    "plot_histogram(counts)"
   ]
  },
  {
   "cell_type": "markdown",
   "id": "4b3b615a-14dd-45b7-8b67-6cd36358b3f3",
   "metadata": {},
   "source": [
    "# Computing the magnetization $\\langle Z_i\\rangle $"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "id": "65d4fcdc-a9c5-4384-8241-f961d18a8b1a",
   "metadata": {},
   "outputs": [],
   "source": [
    "def get_Z_exp(Z_op,counts):\n",
    "    n_shots = 0\n",
    "    \n",
    "    Z_shots = 0\n",
    "    for string,times in counts.items():\n",
    "        sign = 1\n",
    "        for char_Z,char_01 in zip(Z_op,string):\n",
    "            if char_Z=='Z' and char_01=='1':\n",
    "                sign = -sign\n",
    "        Z_shots+= sign*times\n",
    "        n_shots+= times\n",
    "    \n",
    "    exp = Z_shots/n_shots\n",
    "    return exp\n",
    "\n",
    "identity_list = ['I'] * n_qubits\n",
    "for q_idx in range(n_qubits):\n",
    "    Z_list = identity_list.copy()\n",
    "    \n",
    "    Z_list[n_qubits-1-q_idx]='Z' # little endian\n",
    "\n",
    "    Z_exp = get_Z_exp(\"\".join(Z_list),counts)\n",
    "\n",
    "    print(f'Z{q_idx} expectation value:',Z_exp)\n"
   ]
  },
  {
   "cell_type": "markdown",
   "id": "29cbc145-7ee3-421e-8ffa-be3586841818",
   "metadata": {},
   "source": [
    "## Quantum computer can only measure $Z$ basis (computational basis)\n",
    "\n",
    "## Questions: \n",
    "## 1. How to compute the expectation $\\langle X_0\\rangle$, $\\langle X_1Y_0\\rangle$ ?\n",
    "## 2. Can we measure $\\langle X_0\\rangle$ and $\\langle Z_0\\rangle$ simultaneously?"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "id": "e0bfc97a-6277-4563-89e6-7d126ae26ff7",
   "metadata": {},
   "outputs": [],
   "source": []
  }
 ],
 "metadata": {
  "kernelspec": {
   "display_name": "qiskit_k",
   "language": "python",
   "name": "qiskit_k"
  },
  "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.19"
  }
 },
 "nbformat": 4,
 "nbformat_minor": 5
}
