From 33a4e86d205cc4df4596ae681fb3acce5beb02da Mon Sep 17 00:00:00 2001 From: Mahfuza Humayra Mohona Date: Tue, 10 Jun 2025 09:23:44 +0600 Subject: [PATCH] add monthly challenge --- README.md | 7 +- .../challenge_2025_10_jun.ipynb | 400 ++++++++++++++++++ 2 files changed, 406 insertions(+), 1 deletion(-) create mode 100644 challenge_2025_10_jun/challenge_2025_10_jun.ipynb diff --git a/README.md b/README.md index 1edac3d..a4a0419 100644 --- a/README.md +++ b/README.md @@ -173,4 +173,9 @@ Release date: March 2th, 2022 [September 2024 Challenge](challenge-2024.09-sep/challenge-2024.09-sep.ipynb): Sparse State-Preparation ---- \ No newline at end of file +--- + +[June 2025 Challenge](challenge_2025_10_jun/challenge_2025_10_jun.ipynb): Draper Adder with Mitiq ZNE +Release date: June 10th, 2025 + +--- diff --git a/challenge_2025_10_jun/challenge_2025_10_jun.ipynb b/challenge_2025_10_jun/challenge_2025_10_jun.ipynb new file mode 100644 index 0000000..70d47fc --- /dev/null +++ b/challenge_2025_10_jun/challenge_2025_10_jun.ipynb @@ -0,0 +1,400 @@ +{ + "nbformat": 4, + "nbformat_minor": 0, + "metadata": { + "colab": { + "provenance": [] + }, + "kernelspec": { + "name": "python3", + "display_name": "Python 3" + }, + "language_info": { + "name": "python" + } + }, + "cells": [ + { + "cell_type": "markdown", + "source": [ + "# 🧠 QOSF Monthly Challenge: Working with NISQ Devices (Draper Adder + Mitiq)\n", + "\n", + "\n", + "Welcome to the Quantum Open Source Foundation (QOSF) Monthly Challenge!\n", + "In this notebook, we’ll walk through building a **Draper Adder** using the **Quantum Fourier Transform (QFT)** and learn to mitigate noise using the Mitiq library's **Zero-Noise Extrapolation (ZNE)** technique.\n", + "\n", + "You’ll learn:\n", + "- How to encode integers into quantum states\n", + "- How QFT allows for arithmetic on quantum registers\n", + "- How real-world quantum noise affects computation\n", + "- How to apply error mitigation using Mitiq\n", + "\n", + "References:\n", + "- QFT: https://qiskit.org/textbook/ch-algorithms/quantum-fourier-transform.html\n", + "- Draper Adder: https://arxiv.org/abs/quant-ph/0008033\n", + "- Mitiq Docs: https://mitiq.readthedocs.io/\n", + "\n", + "\n", + "# 🎯 Objectives:\n", + "- Implement a `draper_adder(n, n1, n2)` quantum circuit\n", + "- Simulate the circuit in both **ideal** and **noisy** conditions\n", + "- Apply **Zero-Noise Extrapolation (ZNE)** using Mitiq\n", + "- Optimize your implementation and compare results" + ], + "metadata": { + "id": "NywlOtbu0j4D" + } + }, + { + "cell_type": "code", + "source": [ + "from qiskit import QuantumCircuit, Aer, transpile, assemble, execute\n", + "from qiskit.visualization import plot_histogram\n", + "from qiskit.quantum_info import Statevector\n", + "from qiskit.providers.aer.noise import NoiseModel, depolarizing_error\n", + "import numpy as np\n", + "import matplotlib.pyplot as plt\n", + "from mitiq import zne\n", + "from mitiq.zne.scaling import fold_global\n", + "from mitiq.zne.inference import LinearFactory, ExpFactory, RichardsonFactory, PolyFactory\n", + "from mitiq.interface.mitiq_qiskit import from_qiskit, to_qiskit" + ], + "metadata": { + "id": "cBpZ8UFM0ty6" + }, + "execution_count": null, + "outputs": [] + }, + { + "cell_type": "markdown", + "source": [ + "# 🧠 Section 1: QFT and Inverse QFT\n", + "\n", + "Quantum Fourier Transform (QFT) is a core building block in many quantum algorithms, and it enables addition using phase rotations. In this section, we define QFT and its inverse." + ], + "metadata": { + "id": "wTOr46yW0wFb" + } + }, + { + "cell_type": "code", + "source": [ + "def qft(circuit, n):\n", + " for i in range(n):\n", + " circuit.h(i)\n", + " for j in range(i + 1, n):\n", + " angle = np.pi / (2 ** (j - i))\n", + " circuit.cp(angle, j, i)\n", + " circuit.barrier()\n", + "\n", + "def inverse_qft(circuit, n):\n", + " for i in reversed(range(n)):\n", + " for j in reversed(range(i + 1, n)):\n", + " angle = -np.pi / (2 ** (j - i))\n", + " circuit.cp(angle, j, i)\n", + " circuit.h(i)\n", + " circuit.barrier()" + ], + "metadata": { + "id": "lflFrPeV01GT" + }, + "execution_count": null, + "outputs": [] + }, + { + "cell_type": "markdown", + "source": [ + "# πŸ—οΈ Section 2: Draper Adder Circuit\n", + "\n", + "We construct the Draper Adder circuit. This adds two integers using QFT.\n", + "Input: Integers n1 and n2 in `n` qubits\n", + "Output: Quantum state representing n1 + n2\n" + ], + "metadata": { + "id": "3YOD-KWE03Fq" + } + }, + { + "cell_type": "code", + "source": [ + "def draper_adder(n, n1, n2):\n", + " qc = QuantumCircuit(n)\n", + " for i in range(n):\n", + " if (n1 >> i) & 1:\n", + " qc.x(i)\n", + " qc.barrier()\n", + "\n", + " qft(qc, n)\n", + "\n", + " for i in range(n):\n", + " for j in range(n):\n", + " if (n2 >> j) & 1:\n", + " angle = np.pi / (2 ** (i - j)) if i >= j else 0\n", + " if angle:\n", + " qc.cp(angle, j, i)\n", + " qc.barrier()\n", + "\n", + " inverse_qft(qc, n)\n", + " qc.measure_all()\n", + " return qc" + ], + "metadata": { + "id": "rKI8ITIx09Hg" + }, + "execution_count": null, + "outputs": [] + }, + { + "cell_type": "markdown", + "source": [ + "# πŸ§ͺ Section 3: Ideal Simulation\n", + "\n", + "We simulate the circuit with no noise using Qiskit Aer.\n", + "Expected result: 5 + 2 = 7 β†’ '111' on 3 qubits." + ], + "metadata": { + "id": "19ap5xwD1C5C" + } + }, + { + "cell_type": "code", + "source": [ + "qc = draper_adder(3, 5, 2)\n", + "sim = Aer.get_backend(\"aer_simulator\")\n", + "t_qc = transpile(qc, sim)\n", + "result = sim.run(assemble(t_qc)).result()\n", + "counts = result.get_counts()\n", + "print(\"\\nβœ… Ideal Result (no noise):\", counts)\n", + "plot_histogram(counts)\n", + "plt.show()" + ], + "metadata": { + "id": "VbS-g_J11Ien" + }, + "execution_count": null, + "outputs": [] + }, + { + "cell_type": "markdown", + "source": [ + "# πŸ€– Section 4: Noisy Simulation\n", + "\n", + "To mimic real quantum devices, we add 2% depolarizing noise to X, H, and CP gates. Observe the degradation of the expected result." + ], + "metadata": { + "id": "5i9O0myI1LEs" + } + }, + { + "cell_type": "code", + "source": [ + "noise_model = NoiseModel()\n", + "error = depolarizing_error(0.02, 1)\n", + "noise_model.add_all_qubit_quantum_error(error, [\"x\", \"h\", \"cp\"])\n", + "\n", + "noisy_result = sim.run(assemble(t_qc), noise_model=noise_model).result()\n", + "noisy_counts = noisy_result.get_counts()\n", + "print(\"\\nπŸ”§ Noisy Result (with 2% depolarizing noise):\", noisy_counts)\n", + "plot_histogram(noisy_counts)\n", + "plt.show()" + ], + "metadata": { + "id": "3b5t9e301RN1" + }, + "execution_count": null, + "outputs": [] + }, + { + "cell_type": "markdown", + "source": [ + "# 🧰 Section 5: Error Mitigation using Mitiq (ZNE)\n", + "\n", + "Zero-Noise Extrapolation (ZNE) estimates ideal outcomes by executing circuits at multiple noise levels.\n", + "We use four factory methods to compare error mitigation effectiveness." + ], + "metadata": { + "id": "P0xWuJFj1Tcu" + } + }, + { + "cell_type": "code", + "source": [ + "from qiskit import ClassicalRegister\n", + "\n", + "def executor(circuit):\n", + " circuit.measure_all()\n", + " t_circ = transpile(to_qiskit(circuit), sim)\n", + " qobj = assemble(t_circ, shots=1024)\n", + " result = sim.run(qobj, noise_model=noise_model).result()\n", + " counts = result.get_counts()\n", + " return counts.get(\"111\", 0) / 1024\n", + "\n", + "mitiq_circuit = from_qiskit(qc.remove_final_measurements(inplace=False))\n", + "scale_factors = [1.0, 2.0, 3.0]\n", + "\n", + "factories = {\n", + " \"Linear\": LinearFactory(scale_factors=scale_factors),\n", + " \"Exponential\": ExpFactory(scale_factors=scale_factors, asymptote=0.0),\n", + " \"Richardson\": RichardsonFactory(scale_factors=scale_factors),\n", + " \"Polynomial\": PolyFactory(scale_factors=scale_factors, order=2),\n", + "}\n", + "\n", + "results = {}\n", + "for name, factory in factories.items():\n", + " results[name] = zne.execute_with_zne(\n", + " mitiq_circuit, executor, factory=factory, scale_noise=fold_global\n", + " )\n", + " print(f\"πŸ“ˆ {name} ZNE result:\", results[name])" + ], + "metadata": { + "id": "EzIu4Mlt1bCs" + }, + "execution_count": null, + "outputs": [] + }, + { + "cell_type": "markdown", + "source": [ + "# πŸ“Š Section 6: Summary of Results" + ], + "metadata": { + "id": "RD2GL3Lr1cO3" + } + }, + { + "cell_type": "code", + "source": [ + "print(\"\\nπŸ“Š Summary of Results:\")\n", + "print(\"Unmitigated:\", executor(mitiq_circuit))\n", + "for name, value in results.items():\n", + " print(f\"{name}: {value}\")" + ], + "metadata": { + "id": "1hQc-5Kb1ek7" + }, + "execution_count": null, + "outputs": [] + }, + { + "cell_type": "markdown", + "source": [ + "# πŸ” Section 7: Testing multiple 3-bit inputs\n", + "\n", + "This section systematically tests all possible 3-bit integer additions and compares quantum output to classical." + ], + "metadata": { + "id": "_nJzoDlp1mJG" + } + }, + { + "cell_type": "code", + "source": [ + "def classical_adder(n, n1, n2):\n", + " total = (n1 + n2) % (2**n)\n", + " return format(total, f\"0{n}b\")\n", + "\n", + "def test_draper_adder(n=3):\n", + " for n1 in range(2**n):\n", + " for n2 in range(2**n):\n", + " qc = draper_adder(n, n1, n2)\n", + " result = sim.run(assemble(transpile(qc, sim))).result()\n", + " counts = result.get_counts()\n", + " expected = classical_adder(n, n1, n2)\n", + " top = max(counts, key=counts.get)\n", + " status = \"βœ…\" if top == expected else \"❌\"\n", + " print(f\"{n1}+{n2} β†’ {top} (expected: {expected}) {status}\")\n", + "\n", + "test_draper_adder()" + ], + "metadata": { + "id": "Ft8prJS11oz3" + }, + "execution_count": null, + "outputs": [] + }, + { + "cell_type": "markdown", + "source": [ + "# πŸ“‰ Section 8: Analyze Noise Level Effects\n", + "\n", + "We now analyze how different depolarizing noise levels affect accuracy of the output." + ], + "metadata": { + "id": "-r3sI7AF1rSS" + } + }, + { + "cell_type": "code", + "source": [ + "noise_levels = np.linspace(0, 0.1, 10)\n", + "accuracies = []\n", + "\n", + "for level in noise_levels:\n", + " temp_model = NoiseModel()\n", + " temp_model.add_all_qubit_quantum_error(depolarizing_error(level, 1), [\"x\", \"h\", \"cp\"])\n", + " result = sim.run(assemble(t_qc), noise_model=temp_model).result()\n", + " counts = result.get_counts()\n", + " accuracies.append(counts.get(\"111\", 0) / 1024)\n", + "\n", + "plt.plot(noise_levels, accuracies, marker='o')\n", + "plt.title(\"Accuracy vs Depolarizing Noise Level\")\n", + "plt.xlabel(\"Depolarizing Error Rate\")\n", + "plt.ylabel(\"Probability of Correct Result\")\n", + "plt.grid(True)\n", + "plt.show()" + ], + "metadata": { + "id": "d-8hwDjy1xEA" + }, + "execution_count": null, + "outputs": [] + }, + { + "cell_type": "markdown", + "source": [ + "# βš™οΈ Section 9: Bonus Optimization (Optional TODO)\n", + "\n", + "Optional: Try optimizing your Draper Adder implementation to reduce circuit depth and improve resilience.\n" + ], + "metadata": { + "id": "rPA2yKtQ1x6g" + } + }, + { + "cell_type": "code", + "source": [ + "# TODO: Try implementing an optimized version of Draper Adder\n", + "def draper_adder_v2(n, n1, n2):\n", + " ..." + ], + "metadata": { + "id": "05-5s6b513rP" + }, + "execution_count": null, + "outputs": [] + }, + { + "cell_type": "markdown", + "source": [ + "# 🏁 Section 10: Conclusion\n", + "\n", + "In this challenge, we built a Draper adderβ€”a quantum circuit that adds numbers using the QFT.\n", + "We observed ideal vs noisy simulation and applied error mitigation via Mitiq’s ZNE.\n", + "We also evaluated different ZNE strategies and performed broad tests and noise analysis.\n", + "\n", + "You're now equipped with insights into quantum arithmetic and NISQ error mitigation!\n", + "\n", + "\n", + "# βœ… Submission Instructions:\n", + " - Submit your notebook to: https://github.com/qosf/monthly-challenges\n", + " - Include your name and GitHub handle\n", + " - Ask a peer to review your PR on Slack\n", + "\n", + "**πŸŽ‰ Good luck!**\n" + ], + "metadata": { + "id": "3e_-LOz20RRl" + } + } + ] +} \ No newline at end of file