diff --git a/Grovers Algorithm.ipynb b/Grovers Algorithm.ipynb
new file mode 100644
index 0000000..c203e6f
--- /dev/null
+++ b/Grovers Algorithm.ipynb
@@ -0,0 +1,498 @@
+{
+ "cells": [
+ {
+ "cell_type": "markdown",
+ "metadata": {
+ "id": "view-in-github",
+ "colab_type": "text"
+ },
+ "source": [
+ ""
+ ]
+ },
+ {
+ "cell_type": "markdown",
+ "id": "e57d1e6b",
+ "metadata": {
+ "id": "e57d1e6b"
+ },
+ "source": [
+ "## Background\n",
+ "\n",
+ "*Usage estimate: 4 seconds on ibm\\_nairobi. (NOTE: This is an estimate only. Your runtime may vary.)*\n",
+ "\n",
+ "Amplitude amplification is a general purpose quantum algorithm, or subroutine, that can be used to obtain a quadratic speedup over a handful of classical algorithms. [Grover’s algorithm](https://arxiv.org/abs/quant-ph/9605043) was the first to demonstrate this speedup on unstructured search problems. Formulating a Grover's search problem requires an oracle function that marks one or more computational basis states as the states we are interested in finding, and an amplification circuit that increases the amplitude of marked states, consequently suppressing the remaining states.\n",
+ "\n",
+ "Here, we demonstrate how to construct Grover oracles and use the `GroverOperator` from the Qiskit circuit library to easily set up a Grover's search instance. The runtime `Sampler` primitive allows seamless execution of Grover circuits.\n"
+ ]
+ },
+ {
+ "cell_type": "markdown",
+ "id": "152c479f",
+ "metadata": {
+ "id": "152c479f"
+ },
+ "source": [
+ "## Requirements\n",
+ "\n",
+ "Before starting this tutorial, ensure that you have the following installed:\n",
+ "\n",
+ "* Qiskit SDK 1.0 or later, with visualization support (`pip install 'qiskit[visualization]'`)\n",
+ "* Qiskit Runtime (`pip install qiskit-ibm-runtime`) 0.22 or later\n"
+ ]
+ },
+ {
+ "cell_type": "markdown",
+ "id": "54602708",
+ "metadata": {
+ "id": "54602708"
+ },
+ "source": [
+ "## Setup\n",
+ "\n",
+ "Here we import the small number of tools we need for this tutorial.\n"
+ ]
+ },
+ {
+ "cell_type": "code",
+ "execution_count": null,
+ "id": "e2cb0472",
+ "metadata": {
+ "id": "e2cb0472"
+ },
+ "outputs": [],
+ "source": [
+ "# Built-in modules\n",
+ "import math\n",
+ "\n",
+ "# Imports from Qiskit\n",
+ "from qiskit import QuantumCircuit\n",
+ "from qiskit.circuit.library import GroverOperator, MCMT, ZGate\n",
+ "from qiskit.visualization import plot_distribution\n",
+ "\n",
+ "# Imports from Qiskit Runtime\n",
+ "from qiskit_ibm_runtime import QiskitRuntimeService\n",
+ "from qiskit_ibm_runtime import SamplerV2 as Sampler"
+ ]
+ },
+ {
+ "cell_type": "code",
+ "execution_count": null,
+ "id": "8668ab00",
+ "metadata": {
+ "id": "8668ab00",
+ "outputId": "e739803b-51e6-4778-bdaa-30d5b74a9e02"
+ },
+ "outputs": [
+ {
+ "data": {
+ "text/plain": [
+ "'ibm_algiers'"
+ ]
+ },
+ "execution_count": 2,
+ "metadata": {},
+ "output_type": "execute_result"
+ }
+ ],
+ "source": [
+ "# To run on hardware, select the backend with the fewest number of jobs in the queue\n",
+ "service = QiskitRuntimeService(channel=\"ibm_quantum\")\n",
+ "backend = service.least_busy(operational=True, simulator=False)\n",
+ "backend.name"
+ ]
+ },
+ {
+ "cell_type": "markdown",
+ "id": "d4845f4d",
+ "metadata": {
+ "id": "d4845f4d"
+ },
+ "source": [
+ "## Step 1: Map classical inputs to a quantum problem\n",
+ "\n",
+ "Grover's algorithm requires an [oracle](https://learning.quantum-computing.ibm.com/course/fundamentals-of-quantum-algorithms/grovers-algorithm) that specifies one or more marked computational basis states, where \"marked\" means a state with a phase of -1. A controlled-Z gate, or its multi-controlled generalization over $N$ qubits, marks the $2^{N}-1$ state (`'1'`\\*$N$ bit-string). Marking basis states with one or more `'0'` in the binary representation requires applying X-gates on the corresponding qubits before and after the controlled-Z gate; equivalent to having an open-control on that qubit. In the following code, we define an oracle that does just that, marking one or more input basis states defined through their bit-string representation. The `MCMT` gate is used to implement the multi-controlled Z-gate.\n"
+ ]
+ },
+ {
+ "cell_type": "code",
+ "execution_count": null,
+ "id": "7d27e3b4",
+ "metadata": {
+ "id": "7d27e3b4"
+ },
+ "outputs": [],
+ "source": [
+ "def grover_oracle(marked_states):\n",
+ " \"\"\"Build a Grover oracle for multiple marked states\n",
+ "\n",
+ " Here we assume all input marked states have the same number of bits\n",
+ "\n",
+ " Parameters:\n",
+ " marked_states (str or list): Marked states of oracle\n",
+ "\n",
+ " Returns:\n",
+ " QuantumCircuit: Quantum circuit representing Grover oracle\n",
+ " \"\"\"\n",
+ " if not isinstance(marked_states, list):\n",
+ " marked_states = [marked_states]\n",
+ " # Compute the number of qubits in circuit\n",
+ " num_qubits = len(marked_states[0])\n",
+ "\n",
+ " qc = QuantumCircuit(num_qubits)\n",
+ " # Mark each target state in the input list\n",
+ " for target in marked_states:\n",
+ " # Flip target bit-string to match Qiskit bit-ordering\n",
+ " rev_target = target[::-1]\n",
+ " # Find the indices of all the '0' elements in bit-string\n",
+ " zero_inds = [ind for ind in range(num_qubits) if rev_target.startswith(\"0\", ind)]\n",
+ " # Add a multi-controlled Z-gate with pre- and post-applied X-gates (open-controls)\n",
+ " # where the target bit-string has a '0' entry\n",
+ " qc.x(zero_inds)\n",
+ " qc.compose(MCMT(ZGate(), num_qubits - 1, 1), inplace=True)\n",
+ " qc.x(zero_inds)\n",
+ " return qc"
+ ]
+ },
+ {
+ "cell_type": "markdown",
+ "id": "bca14740",
+ "metadata": {
+ "id": "bca14740"
+ },
+ "source": [
+ "### Specific Grover's instance\n",
+ "\n",
+ "Now that we have the oracle function, we can define a specific instance of Grover search. In this example we will mark two computational states out of the eight available in a three-qubit computational space:\n"
+ ]
+ },
+ {
+ "cell_type": "code",
+ "execution_count": null,
+ "id": "c150298f",
+ "metadata": {
+ "id": "c150298f",
+ "outputId": "6dd177b4-7b7f-4646-8a7a-8d1750a487c9"
+ },
+ "outputs": [
+ {
+ "data": {
+ "image/svg+xml": [
+ ""
+ ],
+ "text/plain": [
+ ""
+ ]
+ },
+ "execution_count": 4,
+ "metadata": {},
+ "output_type": "execute_result"
+ }
+ ],
+ "source": [
+ "marked_states = [\"011\", \"100\"]\n",
+ "\n",
+ "oracle = grover_oracle(marked_states)\n",
+ "oracle.draw(output=\"mpl\", style=\"iqp\")"
+ ]
+ },
+ {
+ "cell_type": "markdown",
+ "id": "25487b93",
+ "metadata": {
+ "id": "25487b93"
+ },
+ "source": [
+ "### GroverOperator\n",
+ "\n",
+ "The built-in Qiskit `GroverOperator` takes an oracle circuit and returns a circuit that is composed of the oracle circuit itself and a circuit that amplifies the states marked by the oracle. Here, we `decompose` the circuit to see the gates within the operator:\n"
+ ]
+ },
+ {
+ "cell_type": "code",
+ "execution_count": null,
+ "id": "283d5265",
+ "metadata": {
+ "id": "283d5265",
+ "outputId": "5d7b7471-9a9b-4660-b2db-088f95d33916"
+ },
+ "outputs": [
+ {
+ "data": {
+ "image/svg+xml": [
+ ""
+ ],
+ "text/plain": [
+ ""
+ ]
+ },
+ "execution_count": 5,
+ "metadata": {},
+ "output_type": "execute_result"
+ }
+ ],
+ "source": [
+ "grover_op = GroverOperator(oracle)\n",
+ "grover_op.decompose().draw(output=\"mpl\", style=\"iqp\")"
+ ]
+ },
+ {
+ "cell_type": "markdown",
+ "id": "83c34dc9",
+ "metadata": {
+ "id": "83c34dc9"
+ },
+ "source": [
+ "Repeated applications of this `grover_op` circuit amplify the marked states, making them the most probable bit-strings in the output distribution from the circuit. There is an optimal number of such applications that is determined by the ratio of marked states to total number of possible computational states:\n"
+ ]
+ },
+ {
+ "cell_type": "code",
+ "execution_count": null,
+ "id": "f4c3d4b5",
+ "metadata": {
+ "id": "f4c3d4b5"
+ },
+ "outputs": [],
+ "source": [
+ "optimal_num_iterations = math.floor(\n",
+ " math.pi / (4 * math.asin(math.sqrt(len(marked_states) / 2**grover_op.num_qubits)))\n",
+ ")"
+ ]
+ },
+ {
+ "cell_type": "markdown",
+ "id": "e06c8238",
+ "metadata": {
+ "id": "e06c8238"
+ },
+ "source": [
+ "### Full Grover circuit\n",
+ "\n",
+ "A complete Grover experiment starts with a Hadamard gate on each qubit; creating an even superposition of all computational basis states, followed the Grover operator (`grover_op`) repeated the optimal number of times. Here we make use of the `QuantumCircuit.power(INT)` method to repeatedly apply the Grover operator.\n"
+ ]
+ },
+ {
+ "cell_type": "code",
+ "execution_count": null,
+ "id": "4933ae44",
+ "metadata": {
+ "id": "4933ae44",
+ "outputId": "d91c7b89-ef5a-4f23-96ed-a5807d20e8b5"
+ },
+ "outputs": [
+ {
+ "data": {
+ "image/svg+xml": [
+ ""
+ ],
+ "text/plain": [
+ ""
+ ]
+ },
+ "execution_count": 7,
+ "metadata": {},
+ "output_type": "execute_result"
+ }
+ ],
+ "source": [
+ "qc = QuantumCircuit(grover_op.num_qubits)\n",
+ "# Create even superposition of all basis states\n",
+ "qc.h(range(grover_op.num_qubits))\n",
+ "# Apply Grover operator the optimal number of times\n",
+ "qc.compose(grover_op.power(optimal_num_iterations), inplace=True)\n",
+ "# Measure all qubits\n",
+ "qc.measure_all()\n",
+ "qc.draw(output=\"mpl\", style=\"iqp\")"
+ ]
+ },
+ {
+ "cell_type": "markdown",
+ "id": "97eb3019",
+ "metadata": {
+ "id": "97eb3019"
+ },
+ "source": [
+ "## Step 2: Optimize problem for quantum execution\n"
+ ]
+ },
+ {
+ "cell_type": "code",
+ "execution_count": null,
+ "id": "c9a3020e",
+ "metadata": {
+ "id": "c9a3020e",
+ "outputId": "34844a16-36d4-48f1-91a5-382d67e24ce4"
+ },
+ "outputs": [
+ {
+ "data": {
+ "image/svg+xml": [
+ "