{
 "cells": [
  {
   "cell_type": "markdown",
   "id": "90f546a9",
   "metadata": {},
   "source": [
    "# Submitting Qiskit Circuits to Azure Quantum with the QDK\n",
    "\n",
    "This notebook shows how to take an arbitrary Qiskit `QuantumCircuit`, compile it to QIR using the Microsoft Quantum Development Kit (QDK) Python APIs, and submit it as a job to an Azure Quantum target. It also demonstrates how to handle parameterized circuits by binding parameters before submission."
   ]
  },
  {
   "cell_type": "markdown",
   "id": "2b838c23",
   "metadata": {},
   "source": [
    "The workflow demonstrated here:\n",
    "\n",
    "1. Build (or load) a Qiskit `QuantumCircuit`.\n",
    "2. Convert it to OpenQASM 3 text (`qiskit.qasm3.dumps`).\n",
    "3. Compile that OpenQASM 3 source to QIR with `qdk.openqasm.compile`.\n",
    "4. Create (or attach to) an Azure Quantum workspace with `qdk.azure.Workspace`.\n",
    "5. Select a target (e.g. a simulator such as `rigetti.sim.qvm`).\n",
    "6. Submit the QIR payload and retrieve measurement results.\n",
    "\n",
    "Why use the QDK in this flow?\n",
    "\n",
    "- Local compilation: QIR generation happens locally—no external CLI needed.\n",
    "- Consistency: The same compiler stack powers Q#, OpenQASM, and (via translation) Qiskit interoperability.\n",
    "\n",
    "This notebook focuses strictly on submission. For local resource estimation of Qiskit circuits, see the separate estimation sample."
   ]
  },
  {
   "cell_type": "markdown",
   "id": "004e5982",
   "metadata": {},
   "source": [
    "## Prerequisites\n",
    "\n",
    "This notebook assumes the `qdk`, Azure Quantum integration, and Qiskit packages are installed. You can install everything (including the Azure + Qiskit extras) with:"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "id": "dfa160e8",
   "metadata": {},
   "outputs": [],
   "source": [
    "%pip install qdk[azure,qiskit]"
   ]
  },
  {
   "cell_type": "markdown",
   "id": "b7f37bcd",
   "metadata": {},
   "source": [
    "This installs:\n",
    "- The base qdk package (compiler, OpenQASM/QIR tooling)\n",
    "- Azure Quantum client dependencies for submission\n",
    "- Qiskit for circuit construction\n",
    "\n",
    "After installing, restart the notebook kernel if it was already running. You can verify installation with:"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "id": "f7446ed1",
   "metadata": {},
   "outputs": [],
   "source": [
    "import qiskit, qdk, qdk.azure  # should import without errors"
   ]
  },
  {
   "cell_type": "markdown",
   "id": "4f761649",
   "metadata": {},
   "source": [
    "## Submitting a simple Qiskit circuit\n",
    "\n",
    "We start with a minimal circuit that prepares single-qubit superpositions on two qubits and measures them. After constructing the circuit we’ll submit it to an Azure Quantum target."
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "id": "e91dd2d7",
   "metadata": {},
   "outputs": [],
   "source": [
    "from qiskit import QuantumCircuit\n",
    "\n",
    "circuit = QuantumCircuit(2, 2)\n",
    "\n",
    "circuit.h(0)\n",
    "circuit.measure(0, 0)\n",
    "\n",
    "circuit.h(1)\n",
    "circuit.measure(1, 1)\n",
    "\n",
    "circuit.draw(output=\"text\")"
   ]
  },
  {
   "cell_type": "markdown",
   "id": "efd50528",
   "metadata": {},
   "source": [
    "## Configure Azure Quantum workspace connection\n",
    "\n",
    "To connect to an Azure workspace replace the following variables with your own values."
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "id": "54206752",
   "metadata": {},
   "outputs": [],
   "source": [
    "subscription_id = 'xxxxxxxx-xxxx-xxxx-xxxx-xxxxxxxxxxxx'\n",
    "resource_group = 'myresourcegroup'\n",
    "workspace_name = 'myworkspace'\n",
    "location = 'westus'"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "id": "d9a0f59b",
   "metadata": {},
   "outputs": [],
   "source": [
    "from qiskit import qasm3\n",
    "from qdk.openqasm import compile\n",
    "from qdk.azure import Workspace\n",
    "from qdk import TargetProfile\n",
    "\n",
    "def submit_qiskit_circuit_to_azure(circuit, target_name, name, shots=100):\n",
    "    qasm3_str = qasm3.dumps(circuit)\n",
    "    qir = compile(qasm3_str, target_profile=TargetProfile.Base)\n",
    "\n",
    "    workspace = Workspace(\n",
    "        subscription_id=subscription_id,\n",
    "        resource_group=resource_group,\n",
    "        name=workspace_name,\n",
    "        location=location,\n",
    "    )\n",
    "    target = workspace.get_targets(target_name)\n",
    "    job = target.submit(qir, name, shots=shots)\n",
    "    return job.get_results()\n",
    "\n",
    "results = submit_qiskit_circuit_to_azure(circuit, \"rigetti.sim.qvm\", \"qiskit-job\")\n",
    "print(results)"
   ]
  },
  {
   "cell_type": "markdown",
   "id": "9c84df75",
   "metadata": {},
   "source": [
    "## Parameterized Qiskit circuits\n",
    "\n",
    "Many algorithms use symbolic parameters. Before compiling to QIR and submitting, all circuit parameters must be bound to numeric values. Below we build a simple entangling ladder, apply a rotation parameterized by θ across all qubits, then uncompute the entanglement and measure the first qubit."
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "id": "5d766661",
   "metadata": {},
   "outputs": [],
   "source": [
    "from qiskit import QuantumCircuit\n",
    "from qiskit.circuit import Parameter\n",
    "\n",
    "\n",
    "def get_parameterized_circuit(n = 5) -> QuantumCircuit:\n",
    "    theta = Parameter(\"θ\")\n",
    "    qc = QuantumCircuit(n, 1)\n",
    "    qc.h(0)\n",
    "    for i in range(n - 1):\n",
    "        qc.cx(i, i + 1)\n",
    "    qc.rz(theta, range(n))\n",
    "\n",
    "    for i in reversed(range(n - 1)):\n",
    "        qc.cx(i, i + 1)\n",
    "    qc.h(0)\n",
    "    qc.measure(0, 0)\n",
    "    return qc\n",
    "\n",
    "# Build the symbolic (parameterized) circuit\n",
    "circuit = get_parameterized_circuit()\n",
    "\n",
    "# Bind θ to a numeric value, then visualize the bound circuit\n",
    "circuit.assign_parameters({\"θ\": 0.5}).draw(output=\"text\")"
   ]
  },
  {
   "cell_type": "markdown",
   "id": "ee4d57b4",
   "metadata": {},
   "source": [
    "## Submitting a bound parameterized circuit\n",
    "\n",
    "Below we reuse the parameterized circuit from above, bind θ to 0.5, and submit the resulting (fully concrete) circuit to the Azure Quantum target using the same helper function as before. The printed result shows the measurement counts. Change the value of θ (or loop over several values) to explore how the outcome distribution varies."
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "id": "d9bb3eb0",
   "metadata": {},
   "outputs": [],
   "source": [
    "# Reuse the previously defined parameterized circuit\n",
    "# (circuit is symbolic and must have θ bound to a value before submission)\n",
    "\n",
    "results = submit_qiskit_circuit_to_azure(\n",
    "    circuit.assign_parameters({\"θ\": 0.5}),\n",
    "    \"rigetti.sim.qvm\",\n",
    "    \"qiskit-parameterized-job\"\n",
    ")\n",
    "print(results)"
   ]
  }
 ],
 "metadata": {
  "kernelspec": {
   "display_name": ".venv",
   "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.13.8"
  }
 },
 "nbformat": 4,
 "nbformat_minor": 5
}
