{
 "cells": [
  {
   "cell_type": "markdown",
   "id": "034b66de",
   "metadata": {},
   "source": [
    "# Estructura de un circuito cuántico\n",
    "\n",
    "En este notebook recorres las piezas de un `QuantumCircuit`: qubits, bits clásicos, puertas, barreras y mediciones. Al terminar sabrás:\n",
    "\n",
    "- crear y dibujar circuitos con y sin bits clásicos;\n",
    "- medir la profundidad y contar las operaciones de un circuito;\n",
    "- leer los resultados en el orden correcto (el qubit 0 va a la derecha);\n",
    "- usar registros con nombre y leer sus resultados."
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 1,
   "id": "4a993c2b",
   "metadata": {
    "execution": {
     "iopub.execute_input": "2026-09-29T19:07:24.245276Z",
     "iopub.status.busy": "2026-09-29T19:07:24.244985Z",
     "iopub.status.idle": "2026-09-29T19:07:25.271684Z",
     "shell.execute_reply": "2026-09-29T19:07:25.271291Z"
    }
   },
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "Qiskit: 2.5.2\n",
      "Qiskit Aer: 0.17.2\n",
      "Qiskit IBM Runtime: 0.50.0\n"
     ]
    }
   ],
   "source": [
    "import qiskit, qiskit_aer, qiskit_ibm_runtime\n",
    "print(\"Qiskit:\", qiskit.__version__)\n",
    "print(\"Qiskit Aer:\", qiskit_aer.__version__)\n",
    "print(\"Qiskit IBM Runtime:\", qiskit_ibm_runtime.__version__)"
   ]
  },
  {
   "cell_type": "markdown",
   "id": "039024ac",
   "metadata": {},
   "source": [
    "## Un circuito completo\n",
    "\n",
    "`QuantumCircuit(2, 2)` crea 2 qubits y 2 bits clásicos. Todas las líneas empiezan en $|0\\rangle$. El diagrama se lee de izquierda a derecha."
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 2,
   "id": "6bc72769",
   "metadata": {
    "execution": {
     "iopub.execute_input": "2026-09-29T19:07:25.272924Z",
     "iopub.status.busy": "2026-09-29T19:07:25.272735Z",
     "iopub.status.idle": "2026-09-29T19:07:25.276765Z",
     "shell.execute_reply": "2026-09-29T19:07:25.276422Z"
    }
   },
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "     ┌───┐      ░ ┌─┐   \n",
      "q_0: ┤ H ├──■───░─┤M├───\n",
      "     └───┘┌─┴─┐ ░ └╥┘┌─┐\n",
      "q_1: ─────┤ X ├─░──╫─┤M├\n",
      "          └───┘ ░  ║ └╥┘\n",
      "c: 2/══════════════╩══╩═\n",
      "                   0  1 \n"
     ]
    }
   ],
   "source": [
    "from qiskit import QuantumCircuit\n",
    "\n",
    "qc = QuantumCircuit(2, 2)\n",
    "qc.h(0)\n",
    "qc.cx(0, 1)\n",
    "qc.barrier()\n",
    "qc.measure([0, 1], [0, 1])\n",
    "print(qc.draw(\"text\"))"
   ]
  },
  {
   "cell_type": "markdown",
   "id": "59273118",
   "metadata": {},
   "source": [
    "## Profundidad y conteo de operaciones\n",
    "\n",
    "- `depth()`: capas de operaciones que deben ejecutarse una tras otra.\n",
    "- `size()`: número total de instrucciones (sin contar barreras).\n",
    "- `count_ops()`: cuántas veces aparece cada operación.\n",
    "\n",
    "La profundidad importa porque los qubits reales pierden información con el tiempo."
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 3,
   "id": "7349de5a",
   "metadata": {
    "execution": {
     "iopub.execute_input": "2026-09-29T19:07:25.277846Z",
     "iopub.status.busy": "2026-09-29T19:07:25.277719Z",
     "iopub.status.idle": "2026-09-29T19:07:25.280588Z",
     "shell.execute_reply": "2026-09-29T19:07:25.280250Z"
    }
   },
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "Profundidad: 3\n",
      "Tamaño: 4\n",
      "Operaciones: {'measure': 2, 'h': 1, 'cx': 1, 'barrier': 1}\n",
      "Profundidad en paralelo: 1 | en secuencia: 2\n"
     ]
    }
   ],
   "source": [
    "print(\"Profundidad:\", qc.depth())\n",
    "print(\"Tamaño:\", qc.size())\n",
    "print(\"Operaciones:\", dict(qc.count_ops()))\n",
    "\n",
    "# Dos puertas sobre qubits distintos comparten capa; sobre el mismo qubit, no.\n",
    "paralelo = QuantumCircuit(2)\n",
    "paralelo.h(0)\n",
    "paralelo.h(1)\n",
    "secuencial = QuantumCircuit(2)\n",
    "secuencial.h(0)\n",
    "secuencial.x(0)\n",
    "print(\"Profundidad en paralelo:\", paralelo.depth(), \"| en secuencia:\", secuencial.depth())"
   ]
  },
  {
   "cell_type": "markdown",
   "id": "98f74621",
   "metadata": {},
   "source": [
    "## El orden de los bits\n",
    "\n",
    "Qiskit escribe los resultados con el qubit 0 a la **derecha** (convención *little-endian*). Comprobémoslo aplicando `x` a un solo qubit cada vez."
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 4,
   "id": "9693f68d",
   "metadata": {
    "execution": {
     "iopub.execute_input": "2026-09-29T19:07:25.281644Z",
     "iopub.status.busy": "2026-09-29T19:07:25.281523Z",
     "iopub.status.idle": "2026-09-29T19:07:25.288793Z",
     "shell.execute_reply": "2026-09-29T19:07:25.288409Z"
    }
   },
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "x en el qubit 0 -> {'001': 50}\n",
      "x en el qubit 1 -> {'010': 50}\n",
      "x en el qubit 2 -> {'100': 50}\n"
     ]
    }
   ],
   "source": [
    "from qiskit.primitives import StatevectorSampler\n",
    "\n",
    "sampler = StatevectorSampler(seed=1)\n",
    "for qubit in range(3):\n",
    "    qc = QuantumCircuit(3)\n",
    "    qc.x(qubit)\n",
    "    qc.measure_all()\n",
    "    conteos = sampler.run([qc], shots=50).result()[0].data.meas.get_counts()\n",
    "    print(f\"x en el qubit {qubit} ->\", conteos)"
   ]
  },
  {
   "cell_type": "markdown",
   "id": "390c5ffc",
   "metadata": {},
   "source": [
    "## measure_all y el registro `meas`\n",
    "\n",
    "`measure_all()` crea los bits clásicos, agrega una barrera y mide todo. El registro que crea se llama `meas`. Si defines los bits a mano con `QuantumCircuit(n, n)`, el registro se llama `c`."
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 5,
   "id": "6280e2af",
   "metadata": {
    "execution": {
     "iopub.execute_input": "2026-09-29T19:07:25.289691Z",
     "iopub.status.busy": "2026-09-29T19:07:25.289602Z",
     "iopub.status.idle": "2026-09-29T19:07:25.296844Z",
     "shell.execute_reply": "2026-09-29T19:07:25.296521Z"
    }
   },
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "        ┌───┐      ░ ┌─┐   \n",
      "   q_0: ┤ H ├──■───░─┤M├───\n",
      "        └───┘┌─┴─┐ ░ └╥┘┌─┐\n",
      "   q_1: ─────┤ X ├─░──╫─┤M├\n",
      "             └───┘ ░  ║ └╥┘\n",
      "meas: 2/══════════════╩══╩═\n",
      "                      0  1 \n",
      "measure_all -> {'11': 493, '00': 507}\n",
      "bits a mano -> {'11': 493, '00': 507}\n"
     ]
    }
   ],
   "source": [
    "auto = QuantumCircuit(2)\n",
    "auto.h(0)\n",
    "auto.cx(0, 1)\n",
    "auto.measure_all()\n",
    "print(auto.draw(\"text\"))\n",
    "\n",
    "manual = QuantumCircuit(2, 2)\n",
    "manual.h(0)\n",
    "manual.cx(0, 1)\n",
    "manual.measure([0, 1], [0, 1])\n",
    "\n",
    "res_auto, res_manual = sampler.run([auto, manual], shots=1000).result()\n",
    "print(\"measure_all ->\", res_auto.data.meas.get_counts())\n",
    "print(\"bits a mano ->\", res_manual.data.c.get_counts())"
   ]
  },
  {
   "cell_type": "markdown",
   "id": "b6eda16e",
   "metadata": {},
   "source": [
    "## Registros con nombre\n",
    "\n",
    "En circuitos grandes conviene agrupar qubits y bits en registros con nombre. El resultado se lee con el nombre del registro clásico."
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 6,
   "id": "6351376b",
   "metadata": {
    "execution": {
     "iopub.execute_input": "2026-09-29T19:07:25.297923Z",
     "iopub.status.busy": "2026-09-29T19:07:25.297790Z",
     "iopub.status.idle": "2026-09-29T19:07:25.302231Z",
     "shell.execute_reply": "2026-09-29T19:07:25.301853Z"
    }
   },
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "                  ┌─┐        \n",
      "    datos_0: ─────┤M├────────\n",
      "             ┌───┐└╥┘     ┌─┐\n",
      "    datos_1: ┤ X ├─╫───■──┤M├\n",
      "             └───┘ ║ ┌─┴─┐└╥┘\n",
      "        aux: ──────╫─┤ X ├─╫─\n",
      "                   ║ └───┘ ║ \n",
      "resultado: 2/══════╩═══════╩═\n",
      "                   0       1 \n",
      "{'10': 100}\n"
     ]
    }
   ],
   "source": [
    "from qiskit import QuantumRegister, ClassicalRegister\n",
    "\n",
    "datos = QuantumRegister(2, \"datos\")\n",
    "auxiliar = QuantumRegister(1, \"aux\")\n",
    "resultado = ClassicalRegister(2, \"resultado\")\n",
    "qc = QuantumCircuit(datos, auxiliar, resultado)\n",
    "qc.x(datos[1])\n",
    "qc.cx(datos[1], auxiliar[0])\n",
    "qc.measure(datos, resultado)\n",
    "print(qc.draw(\"text\"))\n",
    "print(sampler.run([qc], shots=100).result()[0].data.resultado.get_counts())"
   ]
  },
  {
   "cell_type": "markdown",
   "id": "6c24e98d",
   "metadata": {},
   "source": [
    "## Resumen y ejercicios\n",
    "\n",
    "- Un circuito es una secuencia de puertas y mediciones sobre qubits que empiezan en $|0\\rangle$.\n",
    "- `depth()` cuenta capas; más profundidad implica más error en hardware real.\n",
    "- El qubit 0 es el dígito de la derecha del resultado.\n",
    "- Con `measure_all` lee `data.meas`; con bits a mano, `data.c`; con registros propios, su nombre.\n",
    "\n",
    "**Ejercicios:**\n",
    "1. Crea un circuito de 4 qubits que produzca siempre el resultado `1010`.\n",
    "2. Construye dos circuitos con las mismas puertas y distinta profundidad.\n",
    "3. Agrega un segundo registro clásico al ejemplo anterior y mide en él el qubit auxiliar."
   ]
  }
 ],
 "metadata": {
  "kernelspec": {
   "display_name": "Python 3",
   "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.14"
  }
 },
 "nbformat": 4,
 "nbformat_minor": 5
}
