{
 "cells": [
  {
   "cell_type": "markdown",
   "metadata": {
    "nteract": {
     "transient": {
      "deleting": false
     }
    }
   },
   "source": [
    "# Repeat-Until-Success Sample\n",
    "This sample shows the use of branching on measurement and qubit reuse to implement a Repeat-Until-Success algorithm on Quantinuum hardware targets. It is drawn from a collaboration between Microsoft and Quantinuum research teams, specifically the authors Natalie C. Brown, John Peter Campora III, Ciarán Ryan-Anderson, Dominic Lucchetti, and Alex Chernoguzov from Quantinuum; Stefan Wernli, Adam Paetznick, Martin Roetteler, and Krysta Svore from Microsoft; as well as Bettina Heim and Cassandra Granade.\n",
    "\n",
    "The program uses RUS and two sub-circuits to perform the single-qubit unitary V<sub>3</sub> = (I + 2iZ)/(√5) as described in detail in [Repeat-Until-Success: Non-deterministic decomposition of single-qubit unitaries](https://arxiv.org/abs/1311.1074) by Adam Paetznik and Krysta Svore.\n",
    "\n"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {
    "nteract": {
     "transient": {
      "deleting": false
     }
    }
   },
   "source": [
    "## 1. Connect to Azure Quantum and set up target\n",
    "\n",
    "First, we must configure the qsharp module to connect the azure workspace and specify a target. The Quantinuum H2 emulator target `quantinuum.sim.h2-1e` is chosen by default, which performs hardware-modeled noisy simulation. Running the experiments in this notebook against that target will consume approximately 25 HQC.\n",
    "\n",
    "We also configure the target profile as `Adaptive_RI` to indicate we use the QIR profile with support for mid-circuit measurement, measurement-based control flow, and classical integer computation as part of compilation.\n",
    "\n",
    "Replace the `subscription_id`, `resource_group`, `name`, and `location` connection parameters with the values for your configured Azure Quantum Workspace, or try copying the Python code for connecting to your workspace from the VS Code Azure Quantum Extension."
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {
    "jupyter": {
     "outputs_hidden": false,
     "source_hidden": false
    },
    "nteract": {
     "transient": {
      "deleting": false
     }
    }
   },
   "outputs": [],
   "source": [
    "import qsharp\n",
    "\n",
    "qsharp.init(target_profile=qsharp.TargetProfile.Adaptive_RI)"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [],
   "source": [
    "import azure.quantum\n",
    "\n",
    "workspace = azure.quantum.Workspace(\n",
    "    subscription_id = \"SUBSCRIPTION ID\",\n",
    "    resource_group = \"RESOURCE GROUP\",\n",
    "    name = \"WORKSPACE NAME\",\n",
    "    location = \"LOCATION\",\n",
    ")"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [],
   "source": [
    "target = workspace.get_targets(\"quantinuum.sim.h2-1e\")"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {
    "nteract": {
     "transient": {
      "deleting": false
     }
    }
   },
   "source": [
    "## 2. Compile the RUS Program"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {
    "jupyter": {
     "outputs_hidden": false,
     "source_hidden": false
    },
    "microsoft": {
     "language": "qsharp"
    },
    "nteract": {
     "transient": {
      "deleting": false
     }
    },
    "vscode": {
     "languageId": "qsharp"
    }
   },
   "outputs": [],
   "source": [
    "%%qsharp\n",
    "import Std.Math.*;\n",
    "\n",
    "/// # Summary\n",
    "/// Example of a Repeat-until-success algorithm implementing a circuit\n",
    "/// that achieves exp(i*ArcTan(2)*Z), also known as the \"V gate\"\n",
    "/// by Paetznick & Svore.\n",
    "///\n",
    "/// # References\n",
    "/// - [ *Adam Paetznick, Krysta M. Svore*,\n",
    "/// Quantum Information & Computation 14(15 & 16): 1277-1301 (2014)\n",
    "/// ](https://arxiv.org/abs/1311.1074)\n",
    "/// For circuit diagram, see file RUS.png.\n",
    "///\n",
    "/// # Input\n",
    "/// ## inputValue\n",
    "/// Boolean value for input qubit (true maps to One, false maps to Zero)\n",
    "/// ## inputBasis\n",
    "/// Pauli basis in which to prepare input qubit\n",
    "/// ## limit\n",
    "/// Integer limit to number of repeats of circuit\n",
    "///\n",
    "/// # Remarks\n",
    "/// The program executes a circuit on a \"target\" qubit using an \"auxiliary\"\n",
    "/// and \"resource\" qubit. The circuit consists of two parts (red and blue\n",
    "/// in image).\n",
    "/// The goal is to measure Zero for both the auxiliary and resource qubit.\n",
    "/// If this succeeds, the program will have effectively applied an\n",
    "/// Rz(arctan(2)) gate (also known as V_3 gate) on the target qubit.\n",
    "/// If this fails, the program reruns the circuit up to <limit> times.\n",
    "operation AllocateQubitsAndApplyRzArcTan2 (\n",
    "    inputValue : Bool,\n",
    "    inputBasis : Pauli,\n",
    "    measurementBasis : Pauli,\n",
    "    limit : Int\n",
    ") : Result[] {\n",
    "    use (auxiliary, resource, target) = (Qubit(), Qubit(), Qubit());\n",
    "\n",
    "    // Prepare target qubit in a zero- or one-state, based on input value\n",
    "    if (inputValue) {\n",
    "        X(target);\n",
    "    }\n",
    "    PreparePauliEigenstate(inputBasis, target);\n",
    "\n",
    "    within {\n",
    "        H(auxiliary);\n",
    "        H(resource);\n",
    "    }\n",
    "    apply {\n",
    "        ApplyRzArcTan2(limit, auxiliary, resource, target);\n",
    "\n",
    "        let rotationAngle = 2.0 * ArcTan(2.0);\n",
    "        Rz(rotationAngle, target); // Rotate back to initial state\n",
    "    }\n",
    "\n",
    "    return [M(auxiliary), M(resource), Measure([measurementBasis], [target])];\n",
    "}\n",
    "\n",
    "/// # Summary\n",
    "/// Apply Rz(arctan(2)) on qubits using repeat until success algorithm.\n",
    "/// Updated to use for-loop sytle.\n",
    "operation ApplyRzArcTan2 (\n",
    "    limit : Int,\n",
    "    auxiliary : Qubit,\n",
    "    resource : Qubit,\n",
    "    target : Qubit\n",
    ") : Unit {\n",
    "    mutable (result1, result2) = (false, false);\n",
    "\n",
    "    // Run Part 1 of the program.\n",
    "    for _ in 1..limit {\n",
    "        if not result1 or not result2 {\n",
    "            set result1 = ApplyAndMeasurePart1(auxiliary, resource) == Zero;\n",
    "\n",
    "            // We’ll only run Part 2 if Part 1 returns Zero.\n",
    "            // Otherwise, we’ll skip and rerun Part 1 again.\n",
    "            if result1 {\n",
    "                set result2 = ApplyAndMeasurePart2(resource, target) == Zero;\n",
    "\n",
    "                if not result2 {\n",
    "                    Z(resource); // Reset resource\n",
    "                    Adjoint Z(target); // Correct effective Z rotation on target\n",
    "                }\n",
    "            } else {\n",
    "                Z(auxiliary);\n",
    "                Reset(resource);\n",
    "                H(resource);\n",
    "            }\n",
    "        }\n",
    "    }\n",
    "}\n",
    "\n",
    "/// # Summary\n",
    "/// Apply part 1 of RUS circuit and measure\n",
    "/// auxiliary qubit in Pauli X basis\n",
    "operation ApplyAndMeasurePart1(auxiliary : Qubit, resource : Qubit) : Result {\n",
    "    within {\n",
    "        T(auxiliary);\n",
    "    }\n",
    "    apply {\n",
    "        CNOT(resource, auxiliary);\n",
    "    }\n",
    "    return Measure([PauliX], [auxiliary]);\n",
    "}\n",
    "\n",
    "/// # Summary\n",
    "/// Apply part 2 of RUS circuit and measure\n",
    "/// resource qubit in Pauli X basis\n",
    "operation ApplyAndMeasurePart2(resource : Qubit, target : Qubit) : Result {\n",
    "    T(target);\n",
    "    Z(target);\n",
    "    CNOT(target, resource);\n",
    "    T(resource);\n",
    "    return Measure([PauliX], [resource]);\n",
    "}\n",
    "\n",
    "operation PreparePauliEigenstate(basis : Pauli, qubit : Qubit) : Unit {\n",
    "    if (basis == PauliX) {\n",
    "        H(qubit);\n",
    "    } elif (basis == PauliY) {\n",
    "        H(qubit);\n",
    "        S(qubit);\n",
    "    }\n",
    "}"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {
    "nteract": {
     "transient": {
      "deleting": false
     }
    }
   },
   "source": [
    "## 3. Run the Experiment\n",
    "We can now submit and wait on each of three experiments using different repeat limits, displaying the resulting histograms and saving them into variables for later analysis. We should see the percentage of resulting successes increase as more repeats are allowed to execute."
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [],
   "source": [
    "job0 = target.submit(qsharp.compile(\"AllocateQubitsAndApplyRzArcTan2(false, PauliX, PauliX, 0)\"), shots=100)\n",
    "job0.wait_until_completed()\n",
    "results0 = job0.get_results()"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [],
   "source": [
    "job1 = target.submit(qsharp.compile(\"AllocateQubitsAndApplyRzArcTan2(false, PauliX, PauliX, 1)\"), shots=100)\n",
    "job1.wait_until_completed()\n",
    "results1 = job1.get_results()"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [],
   "source": [
    "job2 = target.submit(qsharp.compile(\"AllocateQubitsAndApplyRzArcTan2(false, PauliX, PauliX, 2)\"), shots=100)\n",
    "job2.wait_until_completed()\n",
    "results2 = job2.get_results()"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {
    "nteract": {
     "transient": {
      "deleting": false
     }
    }
   },
   "source": [
    "## 4. Plot the Results\n",
    "Finally, we plot the results. When run against the emulator or hardware, each successive experiment should show increasing probability of success, indicating that increasing the allowed runs of RUS further refines the effectiveness of the program."
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {
    "jupyter": {
     "outputs_hidden": false,
     "source_hidden": false
    },
    "nteract": {
     "transient": {
      "deleting": false
     }
    }
   },
   "outputs": [],
   "source": [
    "from matplotlib import pyplot\n",
    "\n",
    "success = \"[0, 0, 0]\"\n",
    "xticks = [0, 1, 2]\n",
    "pyplot.title(\"Probability Success\")\n",
    "pyplot.plot(xticks, [results0[success], results1[success], results2[success]])\n",
    "pyplot.xticks([0, 1, 2])\n",
    "pyplot.xlabel(\"Repeat Limit\")\n",
    "pyplot.ylabel(\"Probability\")\n",
    "\n",
    "\n",
    "pyplot.show()"
   ]
  }
 ],
 "metadata": {
  "kernel_info": {
   "name": "python3"
  },
  "kernelspec": {
   "display_name": "Python 3 (ipykernel)",
   "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.6"
  },
  "nteract": {
   "version": "nteract-front-end@1.0.0"
  }
 },
 "nbformat": 4,
 "nbformat_minor": 0
}
