{
 "nbformat": 4,
 "nbformat_minor": 5,
 "metadata": {
  "kernelspec": {
   "display_name": "Python 3",
   "language": "python",
   "name": "python3"
  },
  "language_info": {
   "name": "python",
   "version": "3.11.0"
  },
  "qlh": {
   "lab": "lab-01-first-circuit",
   "lang": "en",
   "note": "Companion notebook for Quantum Learning Hub Lab 01. Written from scratch."
  }
 },
 "cells": [
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "# Lab 01 — Your first quantum circuit\n\nSet up Python and Qiskit, build a 1-qubit circuit, run it on a simulator, and watch superposition show up in the measurement counts."
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "## Step 1 — Get Python\n\nEverything here runs on Python 3.10+. The Anaconda distribution bundles Python plus the scientific tools, or grab Python directly from python.org."
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "source": [
    "!python --version\n# you want to see: Python 3.10 (or newer)"
   ],
   "outputs": [
    {
     "output_type": "stream",
     "name": "stdout",
     "text": [
      "Python 3.11.9\n"
     ]
    }
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "## Step 2 — Make a clean room\n\nKeep quantum libraries isolated in their own environment:"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "source": [
    "!conda create -n qc-lab python=3.11\n!conda activate qc-lab"
   ],
   "outputs": []
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "No conda? The built-in alternative works the same way:"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "source": [
    "!python -m venv qc-lab\n!source qc-lab/bin/activate   # Windows: qc-lab\\Scripts\\activate"
   ],
   "outputs": []
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "## Step 3 — Install Jupyter\n\nNotebooks let you run code cell-by-cell and see results instantly:"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "source": [
    "!pip install notebook\n!jupyter --version"
   ],
   "outputs": []
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "Then run `jupyter notebook` — a browser tab should open."
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "## Step 4 — Install the quantum stack"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "source": [
    "!pip install qiskit qiskit-aer"
   ],
   "outputs": []
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "Verify it took:"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "source": [
    "import qiskit\nprint(qiskit.__version__)"
   ],
   "outputs": [
    {
     "output_type": "stream",
     "name": "stdout",
     "text": [
      "2.5.2\n"
     ]
    }
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "## Step 5 — Python warm-up (3 minutes)\n\nQiskit is a Python library, so here are the three constructs you'll use constantly:"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "source": [
    "# variables + f-strings\nshots = 1000\nprint(f\"Running {shots} shots\")\n\n# loops\ntotal = 0\nfor i in range(10):\n    total += i\nprint(total)   # 45\n\n# functions\ndef greet(name):\n    return f\"Hello, {name}!\"\nprint(greet(\"qubit\"))"
   ],
   "outputs": [
    {
     "output_type": "stream",
     "name": "stdout",
     "text": [
      "Running 1000 shots\n45\nHello, qubit!\n"
     ]
    }
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "## Step 6 — Build your first circuit\n\nA quantum circuit has **qubits** (quantum registers) and **classical bits** (where measurement results land). One qubit, one classical bit, one measurement:"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "source": [
    "from qiskit import QuantumCircuit\n\nqc = QuantumCircuit(1, 1)  # 1 qubit, 1 classical bit\nqc.measure(0, 0)           # measure qubit 0 -> bit 0\nprint(qc.draw())"
   ],
   "outputs": [
    {
     "output_type": "stream",
     "name": "stdout",
     "text": [
      "     ┌─┐\n  q: ┤M├\n     └╥┘\nc: 1/═╩═\n      0\n"
     ]
    }
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "## Step 7 — Run it on a simulator\n\nNo quantum hardware needed — `AerSimulator` mimics an ideal quantum computer. Run the circuit 1,000 times and count the outcomes:"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "source": [
    "from qiskit_aer import AerSimulator\n\nsim = AerSimulator()\njob = sim.run(qc, shots=1000)\ncounts = job.result().get_counts()\nprint(counts)"
   ],
   "outputs": [
    {
     "output_type": "stream",
     "name": "stdout",
     "text": [
      "{'0': 1000}\n"
     ]
    }
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "A qubit in state |0⟩ measures 0 every single time. So far, boringly classical. That changes now."
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "## Step 8 — Your turn: flip the qubit\n\nThe **X gate** is the quantum NOT — it flips |0⟩ to |1⟩. Add it *before* the measurement. Before running: **predict** the counts out loud."
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "source": [
    "qc2 = QuantumCircuit(1, 1)\nqc2.x(0)          # flip |0> -> |1>\nqc2.measure(0, 0)\n\ncounts2 = sim.run(qc2, shots=1000).result().get_counts()\nprint(counts2)"
   ],
   "outputs": [
    {
     "output_type": "stream",
     "name": "stdout",
     "text": [
      "{'1': 1000}\n"
     ]
    }
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "## Step 9 — Your turn: superposition\n\nThe **H (Hadamard) gate** puts |0⟩ into a superposition — neither 0 nor 1 until measured. Predict first, then run:"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "source": [
    "qc3 = QuantumCircuit(1, 1)\nqc3.h(0)          # |0> -> superposition\nqc3.measure(0, 0)\n\ncounts3 = sim.run(qc3, shots=1000).result().get_counts()\nprint(counts3)"
   ],
   "outputs": [
    {
     "output_type": "stream",
     "name": "stdout",
     "text": [
      "{'0': 498, '1': 502}\n"
     ]
    }
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "Roughly half and half — never exactly 500/500, and different every run. That randomness is not a bug: it is quantum mechanics, observed."
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "## Debrief — what did you prove?\n\nWith three tiny circuits you verified the core facts of quantum computing: a qubit starts at |0⟩, gates transform its state, measurement collapses it to classical bits, and superposition produces genuinely random outcomes.\n\nNext: two qubits, where things get *entangled* — that's Lab 02."
   ]
  }
 ]
}
