{
 "cells": [
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "# Simulating Pauli noise\n",
    "This notebook shows how to run simulations with Pauli noise, such as bit-flip or depolarizing noise.\n",
    "\n",
    "First, make sure prerequisites are available. Packages `qsharp` and `qsharp_widgets` must be already installed."
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 5,
   "metadata": {},
   "outputs": [],
   "source": [
    "import qsharp\n",
    "import qsharp_widgets"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "## Simulation with noise\n",
    "\n",
    "Define a simple program that creates a Bell state on two qubits and measures both qubits."
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 6,
   "metadata": {
    "vscode": {
     "languageId": "qsharp"
    }
   },
   "outputs": [],
   "source": [
    "%%qsharp\n",
    "\n",
    "operation BellPair() : Result[] {\n",
    "    use q = Qubit[2];\n",
    "    H(q[0]);\n",
    "    CNOT(q[0], q[1]);\n",
    "    MResetEachZ(q)\n",
    "}"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "Run 20 shots without noise and display results."
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [],
   "source": [
    "results = qsharp.run(\"BellPair()\", 20)\n",
    "results"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "Note that measurements always agree within a shot as expected. Now run 20 shots of the same program with 10% [depolarizing noise](https://en.wikipedia.org/wiki/Quantum_depolarizing_channel). Depolarizing noise is applied to each gate and each measurement."
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [],
   "source": [
    "results = qsharp.run(\"BellPair()\", 20, noise=qsharp.DepolarizingNoise(0.1))\n",
    "results"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "Note that measurements do not always agree within the shot."
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "## Histograms\n",
    "\n",
    "Define a program to prepare a cat state on five qubits and measure each qubit."
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 9,
   "metadata": {
    "vscode": {
     "languageId": "qsharp"
    }
   },
   "outputs": [],
   "source": [
    "%%qsharp\n",
    "\n",
    "operation Cat5() : Result[] {\n",
    "    use q = Qubit[5];\n",
    "    H(q[0]);\n",
    "    ApplyCNOTChain(q);\n",
    "    MResetEachZ(q)\n",
    "}"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "First, run this program without noise. Roughly half of the outcomes should be $\\ket{00000}$ and another half should be $\\ket{11111}$."
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [],
   "source": [
    "result = qsharp.run(\"Cat5()\", 1000)\n",
    "qsharp_widgets.Histogram(result)\n"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "Now, run the same program with bit-flip noise of 1%, 5%, 10%, 25%."
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [],
   "source": [
    "for p in [0.01, 0.05, 0.1, 0.25]:\n",
    "    result = qsharp.run(\"Cat5()\", 1000, noise=qsharp.BitFlipNoise(p))\n",
    "    display(f\"Noise probability = {p}\")\n",
    "    display(qsharp_widgets.Histogram(result))"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "We can see that with 1% noise, cat state can still be clearly seen, but when noise approaches 25%, the cat state is indistinguishable from noise."
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "## Arbitrary Pauli noise\n",
    "\n",
    "Standard bit-flip, phase-flip, and [depolarizing](https://en.wikipedia.org/wiki/Quantum_depolarizing_channel) noise are available, but arbitrary Pauli noise is also possible. The following example runs the same Cat5 program. First it applies noise with 20% probability (bit-flip half the time and phase-flip half the time). In a second experiment it applies Pauli-Y noise with 10% probability."
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [],
   "source": [
    "result = qsharp.run(\"Cat5()\", 1000, noise=(0.1, 0.0, 0.1))\n",
    "display(qsharp_widgets.Histogram(result))\n",
    "result = qsharp.run(\"Cat5()\", 1000, noise=(0.0, 0.1, 0.0))\n",
    "display(qsharp_widgets.Histogram(result))"
   ]
  }
 ],
 "metadata": {
  "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.11.9"
  }
 },
 "nbformat": 4,
 "nbformat_minor": 2
}
