mirror of
https://github.com/saymrwulf/QuantumLearning.git
synced 2026-05-22 22:01:20 +00:00
339 lines
16 KiB
Text
339 lines
16 KiB
Text
{
|
|
"cells": [
|
|
{
|
|
"cell_type": "markdown",
|
|
"metadata": {},
|
|
"source": [
|
|
"# QFT and Periodic Structure Lab\n"
|
|
],
|
|
"id": "843c0b0b"
|
|
},
|
|
{
|
|
"cell_type": "markdown",
|
|
"metadata": {},
|
|
"source": [
|
|
"The lab focuses on explicit construction, verification, and controlled approximation. Unlike the previous modules, some of the most useful evidence will be statevector-based rather than count-based. That is deliberate.\n"
|
|
],
|
|
"id": "1fa8648a"
|
|
},
|
|
{
|
|
"cell_type": "markdown",
|
|
"metadata": {},
|
|
"source": [
|
|
"## Lab Protocol\n",
|
|
"\n",
|
|
"\n",
|
|
" Change one structural feature at a time and pair every change with a verification move. If you adjust an angle, say what contribution you are changing. If you remove a swap, say which ordering convention you are abandoning. If you approximate the transform, say how you intend to observe the cost.\n"
|
|
],
|
|
"id": "a5677df7"
|
|
},
|
|
{
|
|
"cell_type": "code",
|
|
"execution_count": null,
|
|
"metadata": {},
|
|
"outputs": [],
|
|
"source": [
|
|
"from pathlib import Path\n",
|
|
"import sys\n",
|
|
"\n",
|
|
"project_root = Path.cwd().resolve()\n",
|
|
"while not (project_root / \"pyproject.toml\").exists():\n",
|
|
" if project_root.parent == project_root:\n",
|
|
" raise RuntimeError(\"Could not locate the project root from this notebook.\")\n",
|
|
" project_root = project_root.parent\n",
|
|
"\n",
|
|
"src_path = project_root / \"src\"\n",
|
|
"if str(src_path) not in sys.path:\n",
|
|
" sys.path.insert(0, str(src_path))\n"
|
|
],
|
|
"id": "3e7046de"
|
|
},
|
|
{
|
|
"cell_type": "code",
|
|
"execution_count": null,
|
|
"metadata": {},
|
|
"outputs": [],
|
|
"source": [
|
|
"from math import pi\n",
|
|
"\n",
|
|
"from quantum_learning import (\n",
|
|
" counts_to_probabilities,\n",
|
|
" draw_circuit,\n",
|
|
" editable_circuit_lab,\n",
|
|
" plot_counts,\n",
|
|
" plot_probabilities,\n",
|
|
" quiz_block,\n",
|
|
" reflection_box,\n",
|
|
" simulate_counts,\n",
|
|
" statevector_probabilities,\n",
|
|
" step_reference_table,\n",
|
|
")\n",
|
|
"from qiskit import QuantumCircuit\n",
|
|
"from qiskit.quantum_info import Statevector\n"
|
|
],
|
|
"id": "319d85e5"
|
|
},
|
|
{
|
|
"cell_type": "markdown",
|
|
"metadata": {},
|
|
"source": [
|
|
"## Lab 1: Build The Transform Explicitly\n",
|
|
"\n",
|
|
"\n",
|
|
" Start by editing the explicit QFT itself. The goal is not speed. The goal is to learn how each visible region contributes to the full transform and to make the diagram readable enough that you can review it without hiding behind the name QFT.\n"
|
|
],
|
|
"id": "c10bf57f"
|
|
},
|
|
{
|
|
"cell_type": "code",
|
|
"execution_count": null,
|
|
"metadata": {},
|
|
"outputs": [],
|
|
"source": [
|
|
"step_reference_table([{'marker': '[1]', 'code_focus': 'Start with a small, fully explicit QFT instead of hiding it behind a library call.', 'diagram_effect': 'The circuit shows every controlled phase and swap directly.', 'why_it_matters': 'A professional designer needs to know which pieces are essential and which are optional approximations.'}, {'marker': '[2]', 'code_focus': 'Interpret each controlled phase as a graded correlation, not as a mysterious flourish.', 'diagram_effect': 'The middle of the circuit becomes a ladder of phase relationships.', 'why_it_matters': 'Controlled-phase structure is the real content of the QFT.'}, {'marker': '[3]', 'code_focus': 'Use swaps to state the intended output ordering explicitly.', 'diagram_effect': 'The end of the diagram makes the bit-reversal issue visible.', 'why_it_matters': 'Output ordering is part of the interface, not a postscript.'}, {'marker': '[4]', 'code_focus': 'Verify the transform with statevector or inverse-QFT checks instead of trusting the picture alone.', 'diagram_effect': 'The notebook connects circuit graphics to basis-change evidence.', 'why_it_matters': 'Basis-change circuits need stronger verification habits than simple compute-and-measure patterns.'}])\n"
|
|
],
|
|
"id": "54697b73"
|
|
},
|
|
{
|
|
"cell_type": "code",
|
|
"execution_count": null,
|
|
"metadata": {},
|
|
"outputs": [],
|
|
"source": [
|
|
"editable_code = '\\nfrom math import pi\\nfrom qiskit import QuantumCircuit\\n\\ndef qft3() -> QuantumCircuit:\\n circuit = QuantumCircuit(3, name=\"qft3\")\\n # [1] Start with explicit local structure.\\n circuit.h(2)\\n circuit.cp(pi / 2, 1, 2)\\n circuit.cp(pi / 4, 0, 2)\\n # [2] Continue the controlled-phase ladder.\\n circuit.h(1)\\n circuit.cp(pi / 2, 0, 1)\\n circuit.h(0)\\n # [3] State the output ordering explicitly.\\n circuit.swap(0, 2)\\n return circuit\\n\\ncircuit = qft3()\\n'\n",
|
|
"editable_circuit_lab(\n",
|
|
" initial_code=editable_code,\n",
|
|
" context={\"QuantumCircuit\": QuantumCircuit, \"simulate_counts\": simulate_counts},\n",
|
|
" title='Lab 1: Explicit QFT Builder',\n",
|
|
" instructions='Adjust one phase angle or swap at a time and explain which part of the interface or representation you changed.',\n",
|
|
" shots=256,\n",
|
|
")\n"
|
|
],
|
|
"id": "37aef59e"
|
|
},
|
|
{
|
|
"cell_type": "code",
|
|
"execution_count": null,
|
|
"metadata": {},
|
|
"outputs": [],
|
|
"source": [
|
|
"def qft3() -> QuantumCircuit:\n",
|
|
" circuit = QuantumCircuit(3, name=\"qft3\")\n",
|
|
" circuit.h(2)\n",
|
|
" circuit.cp(pi / 2, 1, 2)\n",
|
|
" circuit.cp(pi / 4, 0, 2)\n",
|
|
" circuit.h(1)\n",
|
|
" circuit.cp(pi / 2, 0, 1)\n",
|
|
" circuit.h(0)\n",
|
|
" circuit.swap(0, 2)\n",
|
|
" return circuit\n",
|
|
"\n",
|
|
"ax = draw_circuit(qft3())\n",
|
|
"ax\n"
|
|
],
|
|
"id": "99947a0d"
|
|
},
|
|
{
|
|
"cell_type": "code",
|
|
"execution_count": null,
|
|
"metadata": {},
|
|
"outputs": [],
|
|
"source": [
|
|
"quiz_block([{'prompt': 'If you drop the final swap layer in a QFT notebook, what changes first?', 'options': ['The output ordering convention becomes different even if the phase logic is otherwise intact', 'All controlled phases disappear', 'The circuit can no longer be simulated'], 'correct_index': 0, 'explanation': 'Removing swaps changes the interface contract of the transform.'}, {'prompt': 'What is the best reason to edit one controlled-phase angle at a time?', 'options': ['So you can connect a visible change in structure to a specific representational consequence', 'So the notebook runs faster', 'So the circuit has fewer qubits'], 'correct_index': 0, 'explanation': 'Controlled ablation is how you learn what each phase layer is doing.'}], heading='Lab Checkpoint A')\n"
|
|
],
|
|
"id": "01437840"
|
|
},
|
|
{
|
|
"cell_type": "code",
|
|
"execution_count": null,
|
|
"metadata": {},
|
|
"outputs": [],
|
|
"source": [
|
|
"reflection_box('Which verification move felt most convincing in this lab, and why?')\n"
|
|
],
|
|
"id": "fc4e12a7"
|
|
},
|
|
{
|
|
"cell_type": "markdown",
|
|
"metadata": {},
|
|
"source": [
|
|
"## Lab 2: Verify With Recovery\n",
|
|
"\n",
|
|
"\n",
|
|
" Use QFT followed by inverse QFT as a recovery pattern. This is a disciplined way to verify that your hand-written transform is not merely plausible-looking. A transform that cannot recover cleanly under its own inverse needs explanation.\n"
|
|
],
|
|
"id": "a878a93d"
|
|
},
|
|
{
|
|
"cell_type": "code",
|
|
"execution_count": null,
|
|
"metadata": {},
|
|
"outputs": [],
|
|
"source": [
|
|
"editable_code = '\\nfrom math import pi\\nfrom qiskit import QuantumCircuit\\n\\ndef qft3() -> QuantumCircuit:\\n circuit = QuantumCircuit(3, name=\"qft3\")\\n circuit.h(2)\\n circuit.cp(pi / 2, 1, 2)\\n circuit.cp(pi / 4, 0, 2)\\n circuit.h(1)\\n circuit.cp(pi / 2, 0, 1)\\n circuit.h(0)\\n circuit.swap(0, 2)\\n return circuit\\n\\ncircuit = QuantumCircuit(3, 3)\\ncircuit.x(0)\\ncircuit.compose(qft3(), inplace=True)\\ncircuit.compose(qft3().inverse(), inplace=True)\\ncircuit.measure([0, 1, 2], [0, 1, 2])\\n'\n",
|
|
"editable_circuit_lab(\n",
|
|
" initial_code=editable_code,\n",
|
|
" context={\"QuantumCircuit\": QuantumCircuit, \"simulate_counts\": simulate_counts},\n",
|
|
" title='Lab 2: QFT Plus Inverse Recovery',\n",
|
|
" instructions='Change the prepared basis state or slightly edit the transform. Then decide whether the recovery still matches the story you think the circuit is telling.',\n",
|
|
" shots=256,\n",
|
|
")\n"
|
|
],
|
|
"id": "57cc79d6"
|
|
},
|
|
{
|
|
"cell_type": "code",
|
|
"execution_count": null,
|
|
"metadata": {},
|
|
"outputs": [],
|
|
"source": [
|
|
"def qft3() -> QuantumCircuit:\n",
|
|
" circuit = QuantumCircuit(3, name=\"qft3\")\n",
|
|
" circuit.h(2)\n",
|
|
" circuit.cp(pi / 2, 1, 2)\n",
|
|
" circuit.cp(pi / 4, 0, 2)\n",
|
|
" circuit.h(1)\n",
|
|
" circuit.cp(pi / 2, 0, 1)\n",
|
|
" circuit.h(0)\n",
|
|
" circuit.swap(0, 2)\n",
|
|
" return circuit\n",
|
|
"\n",
|
|
"recovered = QuantumCircuit(3, 3)\n",
|
|
"recovered.x(0)\n",
|
|
"recovered.compose(qft3(), inplace=True)\n",
|
|
"recovered.compose(qft3().inverse(), inplace=True)\n",
|
|
"recovered.measure([0, 1, 2], [0, 1, 2])\n",
|
|
"simulate_counts(recovered, shots=256)\n"
|
|
],
|
|
"id": "8b8c468f"
|
|
},
|
|
{
|
|
"cell_type": "markdown",
|
|
"metadata": {},
|
|
"source": [
|
|
"## Lab 3: Approximation Tradeoff\n",
|
|
"\n",
|
|
"\n",
|
|
" Now remove the smallest-angle interaction and inspect the result like an engineer. The aim is not to decide that approximation is always good or always bad. The aim is to learn how to talk about the tradeoff in concrete, local terms.\n"
|
|
],
|
|
"id": "6453fde5"
|
|
},
|
|
{
|
|
"cell_type": "code",
|
|
"execution_count": null,
|
|
"metadata": {},
|
|
"outputs": [],
|
|
"source": [
|
|
"editable_code = '\\nfrom math import pi\\nfrom qiskit import QuantumCircuit\\n\\ndef qft3(drop_smallest_angle: bool = False) -> QuantumCircuit:\\n circuit = QuantumCircuit(3, name=\"qft3\")\\n circuit.h(2)\\n circuit.cp(pi / 2, 1, 2)\\n if not drop_smallest_angle:\\n circuit.cp(pi / 4, 0, 2)\\n circuit.h(1)\\n circuit.cp(pi / 2, 0, 1)\\n circuit.h(0)\\n circuit.swap(0, 2)\\n return circuit\\n\\ncircuit = qft3(drop_smallest_angle=True)\\n'\n",
|
|
"editable_circuit_lab(\n",
|
|
" initial_code=editable_code,\n",
|
|
" context={\"QuantumCircuit\": QuantumCircuit, \"simulate_counts\": simulate_counts},\n",
|
|
" title='Lab 3: Approximate QFT',\n",
|
|
" instructions='Toggle the smallest-angle term and explain what structural simplification you gained and what representational burden you may have lost.',\n",
|
|
" shots=256,\n",
|
|
")\n"
|
|
],
|
|
"id": "6606c74d"
|
|
},
|
|
{
|
|
"cell_type": "code",
|
|
"execution_count": null,
|
|
"metadata": {},
|
|
"outputs": [],
|
|
"source": [
|
|
"def qft3(drop_smallest_angle: bool) -> QuantumCircuit:\n",
|
|
" circuit = QuantumCircuit(3, name=\"qft3\")\n",
|
|
" circuit.h(2)\n",
|
|
" circuit.cp(pi / 2, 1, 2)\n",
|
|
" if not drop_smallest_angle:\n",
|
|
" circuit.cp(pi / 4, 0, 2)\n",
|
|
" circuit.h(1)\n",
|
|
" circuit.cp(pi / 2, 0, 1)\n",
|
|
" circuit.h(0)\n",
|
|
" circuit.swap(0, 2)\n",
|
|
" return circuit\n",
|
|
"\n",
|
|
"basis_one = QuantumCircuit(3)\n",
|
|
"basis_one.x(0)\n",
|
|
"full_probs = statevector_probabilities(basis_one.compose(qft3(False)))\n",
|
|
"approx_probs = statevector_probabilities(basis_one.compose(qft3(True)))\n",
|
|
"{\"full\": full_probs, \"approx\": approx_probs}\n"
|
|
],
|
|
"id": "023d88ba"
|
|
},
|
|
{
|
|
"cell_type": "code",
|
|
"execution_count": null,
|
|
"metadata": {},
|
|
"outputs": [],
|
|
"source": [
|
|
"quiz_block([{'prompt': 'Why is QFT plus inverse-QFT a useful lab pattern?', 'options': ['It checks whether your custom transform preserves information when composed with its inverse', 'It makes all swaps unnecessary', 'It amplifies noise automatically'], 'correct_index': 0, 'explanation': 'Recovery checks are a disciplined way to verify basis-change code.'}, {'prompt': 'What does an approximate-QFT comparison teach best?', 'options': ['How structural simplification can be defended as a tradeoff instead of guessed at', 'How to avoid ever drawing the circuit', 'How to replace controlled phases with measurements'], 'correct_index': 0, 'explanation': 'Approximation should be justified, not mystified.'}], heading='Lab Checkpoint B')\n"
|
|
],
|
|
"id": "10d715d9"
|
|
},
|
|
{
|
|
"cell_type": "markdown",
|
|
"metadata": {},
|
|
"source": [
|
|
"## Lab Debrief\n",
|
|
"\n",
|
|
"\n",
|
|
" The important outcome of the lab is not that you can rewrite one small QFT from memory. It is that you now have habits for reading, checking, and selectively simplifying basis-change circuits. Those habits are exactly what later algorithmic and professional modules will need.\n"
|
|
],
|
|
"id": "34735ee4"
|
|
},
|
|
{
|
|
"cell_type": "markdown",
|
|
"metadata": {},
|
|
"source": [
|
|
"## Why The Lab Is Slower Than A Tutorial\n",
|
|
"\n",
|
|
"These exercises are intentionally slower than ordinary click-through tutorials because the purpose is different. A tutorial can reward motion. A professional lab has to reward discrimination. You are being asked to notice which edit changed the semantic burden of the circuit, which edit only changed presentation, and which edit damaged the reporting contract even though the diagram still looked familiar. That is harder work, but it is the right work for someone trying to become a designer rather than a consumer of notebooks.\n"
|
|
],
|
|
"id": "e82e6c14"
|
|
},
|
|
{
|
|
"cell_type": "markdown",
|
|
"metadata": {},
|
|
"source": [
|
|
"## Prediction Ledger\n",
|
|
"\n",
|
|
"If the lab begins to feel messy, return to the prediction ledger idea. Before each edit, write down what should remain invariant, what should move, and which evidence will decide the question. That tiny discipline is what keeps experiments from collapsing into aimless button pushing. It also mirrors how real engineering work scales. Good engineers do not only make changes. They keep track of what they expected the change to prove.\n"
|
|
],
|
|
"id": "2952143c"
|
|
},
|
|
{
|
|
"cell_type": "code",
|
|
"execution_count": null,
|
|
"metadata": {},
|
|
"outputs": [],
|
|
"source": [
|
|
"reflection_box('Write a short engineering note defending either the full or approximate 3-qubit QFT for a small local study.')\n"
|
|
],
|
|
"id": "dd7317a0"
|
|
},
|
|
{
|
|
"cell_type": "code",
|
|
"execution_count": null,
|
|
"metadata": {},
|
|
"outputs": [],
|
|
"source": [
|
|
"reflection_box('Write one additional prediction habit you want to carry into later modules.')\n"
|
|
],
|
|
"id": "483aa598"
|
|
}
|
|
],
|
|
"metadata": {
|
|
"kernelspec": {
|
|
"display_name": "QuantumLearning (.venv)",
|
|
"language": "python",
|
|
"name": "quantum-learning"
|
|
},
|
|
"language_info": {
|
|
"name": "python",
|
|
"version": "3.12"
|
|
}
|
|
},
|
|
"nbformat": 4,
|
|
"nbformat_minor": 5
|
|
}
|