{
  "cells": [
    {
      "cell_type": "markdown",
      "id": "fc8e6edf",
      "metadata": {
        "id": "fc8e6edf"
      },
      "source": [
        "# QPrep — Sesión 1: Python para QBronze\n",
        "\n",
        "Este cuaderno condensa la parte de **Python Review** usada como preparación antes de QBronze: uso de Jupyter Notebook, variables, operadores, ciclos, condicionales y listas. La intención didáctica es que el estudiante pueda razonar código corto **sin depender de ejecutar la celda**, porque el quiz de QPrep evalúa precisamente trazas manuales, expresiones y errores de Python.\n",
        "\n",
        "**Fuentes curriculares usadas para el diseño:** QWorld QPrep y la sección `before-workshop` de Bronze-Qiskit. Material de referencia: `python/Python02_Into_Notebooks.ipynb`, `Python08_Basics_Variables.ipynb`, `Python12_Basics_Loops.ipynb`, `Python16_Basics_Conditionals.ipynb`, `Python20_Basics_Lists.ipynb` del paquete Bronze-Qiskit.\n",
        "\n",
        "**Duración sugerida:** 90 a 120 minutos."
      ]
    },
    {
      "cell_type": "markdown",
      "id": "ff637120",
      "metadata": {
        "id": "ff637120"
      },
      "source": [
        "## Objetivos de aprendizaje\n",
        "\n",
        "Al terminar esta sesión, el estudiante debe poder:\n",
        "\n",
        "1. Ejecutar celdas de Jupyter y distinguir entre orden visual y orden real de ejecución.\n",
        "2. Evaluar expresiones con `+`, `-`, `*`, `/`, `//`, `%` y `**` respetando precedencia.\n",
        "3. Trazar ciclos `for` con `range(...)` y ciclos simples con acumuladores.\n",
        "4. Trazar condicionales `if`, `elif`, `else`.\n",
        "5. Usar listas con indexación desde cero, índices negativos, *slicing* y operaciones básicas.\n",
        "6. Reconocer cuándo una operación produce un error, especialmente en listas."
      ]
    },
    {
      "cell_type": "markdown",
      "id": "c697449f",
      "metadata": {
        "id": "c697449f"
      },
      "source": [
        "## Método de trabajo\n",
        "\n",
        "En cada bloque hay tres niveles:\n",
        "\n",
        "- **Ejemplo guiado:** ejecuta y observa.\n",
        "- **Predicción manual:** calcula primero en papel o mentalmente.\n",
        "- **Verificación:** ejecuta después de razonar.\n",
        "\n",
        "Para QPrep conviene entrenar el razonamiento manual: no basta con saber ejecutar Python; hay que poder anticipar la salida."
      ]
    },
    {
      "cell_type": "code",
      "execution_count": null,
      "id": "7f90bea6",
      "metadata": {
        "id": "7f90bea6"
      },
      "outputs": [],
      "source": [
        "from math import isclose\n",
        "\n",
        "def _igual(a, b, tol=1e-9):\n",
        "    \"\"\"Comparación simple para números, booleanos y listas anidadas.\"\"\"\n",
        "    if isinstance(a, float) or isinstance(b, float):\n",
        "        try:\n",
        "            return isclose(float(a), float(b), rel_tol=tol, abs_tol=tol)\n",
        "        except Exception:\n",
        "            return False\n",
        "    if isinstance(a, (list, tuple)) and isinstance(b, (list, tuple)):\n",
        "        return len(a) == len(b) and all(_igual(x, y, tol) for x, y in zip(a, b))\n",
        "    return a == b\n",
        "\n",
        "def qprep_check(nombre, obtenido, esperado, tol=1e-9):\n",
        "    \"\"\"Verificador liviano. Deja None mientras el ejercicio esté pendiente.\"\"\"\n",
        "    if obtenido is None:\n",
        "        print(f\"{nombre}: pendiente. Reemplaza None por tu respuesta o función.\")\n",
        "        return False\n",
        "    if _igual(obtenido, esperado, tol):\n",
        "        print(f\"{nombre}: correcto.\")\n",
        "        return True\n",
        "    print(f\"{nombre}: revisa tu resultado. Obtenido = {obtenido!r}\")\n",
        "    return False"
      ]
    },
    {
      "cell_type": "markdown",
      "id": "eb442fbc",
      "metadata": {
        "id": "eb442fbc"
      },
      "source": [
        "## 1. Jupyter Notebook: ejecución por celdas\n",
        "\n",
        "Un cuaderno no se ejecuta necesariamente de arriba hacia abajo. El estado de memoria depende del orden real de ejecución. Esto es relevante cuando se reutilizan variables."
      ]
    },
    {
      "cell_type": "code",
      "execution_count": null,
      "id": "0742a619",
      "metadata": {
        "id": "0742a619"
      },
      "outputs": [],
      "source": [
        "x = 4\n",
        "x = x + 3\n",
        "print(\"x =\", x)\n",
        "\n",
        "# Cambia el valor de x, vuelve a ejecutar celdas anteriores y observa el efecto."
      ]
    },
    {
      "cell_type": "markdown",
      "id": "b56d6a2a",
      "metadata": {
        "id": "b56d6a2a"
      },
      "source": [
        "## 2. Variables, tipos y operadores\n",
        "\n",
        "Python evalúa expresiones usando precedencia matemática estándar:\n",
        "\n",
        "1. Paréntesis.\n",
        "2. Potencias `**`.\n",
        "3. Multiplicación, división, división entera y módulo: `*`, `/`, `//`, `%`.\n",
        "4. Suma y resta: `+`, `-`.\n",
        "\n",
        "Notas operativas:\n",
        "\n",
        "- `a / b` produce división real.\n",
        "- `a // b` produce división entera hacia abajo.\n",
        "- `a % b` produce el residuo.\n",
        "- `a ** b` calcula potencia."
      ]
    },
    {
      "cell_type": "code",
      "execution_count": null,
      "id": "48fda7bd",
      "metadata": {
        "id": "48fda7bd"
      },
      "outputs": [],
      "source": [
        "a = 17\n",
        "b = 5\n",
        "\n",
        "print(\"a + b =\", a + b)\n",
        "print(\"a - b =\", a - b)\n",
        "print(\"a * b =\", a * b)\n",
        "print(\"a / b =\", a / b)\n",
        "print(\"a // b =\", a // b)\n",
        "print(\"a % b =\", a % b)\n",
        "print(\"2 ** 5 =\", 2 ** 5)\n",
        "print(\"2 + 3 * 4 ** 2 =\", 2 + 3 * 4 ** 2)\n",
        "print(\"(2 + 3) * 4 ** 2 =\", (2 + 3) * 4 ** 2)"
      ]
    },
    {
      "cell_type": "markdown",
      "id": "1e83ea2b",
      "metadata": {
        "id": "1e83ea2b"
      },
      "source": [
        "### Ejercicio 1.1 — Evalúa sin ejecutar\n",
        "\n",
        "Reemplaza `None` por tu respuesta. Después ejecuta la celda para verificar."
      ]
    },
    {
      "cell_type": "code",
      "execution_count": null,
      "id": "b7bc1095",
      "metadata": {
        "id": "b7bc1095"
      },
      "outputs": [],
      "source": [
        "respuesta_1a = None  # 2 + 3 * 4**2 - 17 % 5\n",
        "respuesta_1b = None  # (21 // 4) + (21 % 4)\n",
        "respuesta_1c = None  # 5 * 2**3 - 9 // 2"
      ]
    },
    {
      "cell_type": "markdown",
      "id": "4986c9c1",
      "metadata": {
        "id": "4986c9c1"
      },
      "source": [
        "## 3. Booleanos como valores lógicos y numéricos\n",
        "\n",
        "En Python, `True` y `False` son booleanos. En operaciones aritméticas pueden comportarse como `1` y `0`, respectivamente. Esta regla aparece con frecuencia en preguntas breves de QPrep."
      ]
    },
    {
      "cell_type": "code",
      "execution_count": null,
      "id": "df97f476",
      "metadata": {
        "id": "df97f476"
      },
      "outputs": [],
      "source": [
        "print(True, int(True))\n",
        "print(False, int(False))\n",
        "print(\"True + False =\", True + False)\n",
        "print(\"True * False =\", True * False)\n",
        "print(\"True + False - True*False =\", True + False - True*False)\n",
        "print(\"False == 0:\", False == 0)"
      ]
    },
    {
      "cell_type": "markdown",
      "id": "9246da7b",
      "metadata": {
        "id": "9246da7b"
      },
      "source": [
        "### Ejercicio 1.2 — Booleanos\n",
        "\n",
        "Calcula manualmente."
      ]
    },
    {
      "cell_type": "code",
      "execution_count": null,
      "id": "1aef9354",
      "metadata": {
        "id": "1aef9354"
      },
      "outputs": [],
      "source": [
        "respuesta_2a = None  # True + True + False\n",
        "respuesta_2b = None  # True - False + (False == 0)\n",
        "respuesta_2c = None  # (True and False) or True"
      ]
    },
    {
      "cell_type": "markdown",
      "id": "fad2172b",
      "metadata": {
        "id": "fad2172b"
      },
      "source": [
        "## 4. Ciclos `for` y `range`\n",
        "\n",
        "La forma `range(inicio, fin, paso)` genera valores desde `inicio` hasta antes de `fin`, avanzando por `paso`.\n",
        "\n",
        "Ejemplos:\n",
        "\n",
        "- `range(5)` genera `0, 1, 2, 3, 4`.\n",
        "- `range(2, 8)` genera `2, 3, 4, 5, 6, 7`.\n",
        "- `range(10, 20, 2)` genera `10, 12, 14, 16, 18`."
      ]
    },
    {
      "cell_type": "code",
      "execution_count": null,
      "id": "dc7489f2",
      "metadata": {
        "id": "dc7489f2"
      },
      "outputs": [],
      "source": [
        "print(list(range(5)))\n",
        "print(list(range(2, 8)))\n",
        "print(list(range(10, 20, 2)))\n",
        "print(list(range(5, 0, -1)))"
      ]
    },
    {
      "cell_type": "markdown",
      "id": "b924aa27",
      "metadata": {
        "id": "b924aa27"
      },
      "source": [
        "### Ejemplo guiado: acumuladores\n",
        "\n",
        "Un acumulador es una variable que se actualiza repetidamente dentro de un ciclo."
      ]
    },
    {
      "cell_type": "code",
      "execution_count": null,
      "id": "ff780052",
      "metadata": {
        "id": "ff780052"
      },
      "outputs": [],
      "source": [
        "suma = 0\n",
        "for i in range(1, 6):\n",
        "    suma = suma + i\n",
        "    print(\"i =\", i, \"suma =\", suma)\n",
        "\n",
        "print(\"resultado final =\", suma)"
      ]
    },
    {
      "cell_type": "markdown",
      "id": "db8a31c4",
      "metadata": {
        "id": "db8a31c4"
      },
      "source": [
        "### Ejercicio 1.3 — Traza de ciclo\n",
        "\n",
        "Calcula la salida final sin ejecutar primero."
      ]
    },
    {
      "cell_type": "code",
      "execution_count": null,
      "id": "950df5af",
      "metadata": {
        "id": "950df5af"
      },
      "outputs": [],
      "source": [
        "respuesta_3a = None\n",
        "\n",
        "# Código que debes trazar:\n",
        "# x = 10\n",
        "# for i in range(10, 20, 2):\n",
        "#     x = x - i\n",
        "# y = x / 2"
      ]
    },
    {
      "cell_type": "code",
      "execution_count": null,
      "id": "ff2e9fce",
      "metadata": {
        "id": "ff2e9fce"
      },
      "outputs": [],
      "source": [
        "# Ejecuta esta celda únicamente después de haber hecho la predicción.\n",
        "x = 10\n",
        "for i in range(10, 20, 2):\n",
        "    x = x - i\n",
        "print(x / 2)"
      ]
    },
    {
      "cell_type": "markdown",
      "id": "b1d1badf",
      "metadata": {
        "id": "b1d1badf"
      },
      "source": [
        "## 5. Condicionales\n",
        "\n",
        "La estructura `if` ejecuta un bloque si una condición es verdadera. `elif` permite evaluar condiciones alternativas; `else` cubre el caso restante."
      ]
    },
    {
      "cell_type": "code",
      "execution_count": null,
      "id": "2c826851",
      "metadata": {
        "id": "2c826851"
      },
      "outputs": [],
      "source": [
        "valor = 7\n",
        "\n",
        "if valor < 0:\n",
        "    categoria = \"negativo\"\n",
        "elif valor == 0:\n",
        "    categoria = \"cero\"\n",
        "else:\n",
        "    categoria = \"positivo\"\n",
        "\n",
        "print(categoria)"
      ]
    },
    {
      "cell_type": "markdown",
      "id": "1caf811a",
      "metadata": {
        "id": "1caf811a"
      },
      "source": [
        "### Ejercicio 1.4 — Ciclos y condicionales combinados\n",
        "\n",
        "Traza el código. Observa que el valor de `x` puede cambiar dentro del ciclo."
      ]
    },
    {
      "cell_type": "code",
      "execution_count": null,
      "id": "17b222f9",
      "metadata": {
        "id": "17b222f9"
      },
      "outputs": [],
      "source": [
        "respuesta_4a = None\n",
        "\n",
        "# Código que debes trazar:\n",
        "# x = 3\n",
        "# for i in range(3):\n",
        "#     y = i / x\n",
        "#     if y < 0.5:\n",
        "#         x = x - i\n",
        "# resultado = x + y + 2"
      ]
    },
    {
      "cell_type": "code",
      "execution_count": null,
      "id": "ae8f1f76",
      "metadata": {
        "id": "ae8f1f76"
      },
      "outputs": [],
      "source": [
        "# Verificación posterior.\n",
        "x = 3\n",
        "for i in range(3):\n",
        "    y = i / x\n",
        "    if y < 0.5:\n",
        "        x = x - i\n",
        "resultado = x + y + 2\n",
        "print(resultado)"
      ]
    },
    {
      "cell_type": "markdown",
      "id": "a5f61a06",
      "metadata": {
        "id": "a5f61a06"
      },
      "source": [
        "## 6. Listas: índices, índices negativos y slicing\n",
        "\n",
        "Una lista es una secuencia ordenada. La indexación comienza en cero.\n",
        "\n",
        "Para `l = [3, 5, 1, 6, 0]`:\n",
        "\n",
        "- `l[0]` es `3`.\n",
        "- `l[2]` es `1`.\n",
        "- `l[-1]` es `0`.\n",
        "- `l[-2]` es `6`.\n",
        "\n",
        "El *slicing* tiene forma `l[inicio:fin:paso]` y excluye el índice `fin`."
      ]
    },
    {
      "cell_type": "code",
      "execution_count": null,
      "id": "4149ce54",
      "metadata": {
        "id": "4149ce54"
      },
      "outputs": [],
      "source": [
        "l = [3, 5, 1, 6, 0]\n",
        "\n",
        "print(\"l[0]  =\", l[0])\n",
        "print(\"l[2]  =\", l[2])\n",
        "print(\"l[-1] =\", l[-1])\n",
        "print(\"l[-2] =\", l[-2])\n",
        "print(\"l[1:4] =\", l[1:4])\n",
        "print(\"l[::-1] =\", l[::-1])\n",
        "print(\"l[::2] =\", l[::2])"
      ]
    },
    {
      "cell_type": "markdown",
      "id": "91b4b357",
      "metadata": {
        "id": "91b4b357"
      },
      "source": [
        "### Ejercicio 1.5 — Slicing"
      ]
    },
    {
      "cell_type": "code",
      "execution_count": null,
      "id": "6209d459",
      "metadata": {
        "id": "6209d459"
      },
      "outputs": [],
      "source": [
        "l = [1, 2, 3, 4, 5]\n",
        "\n",
        "respuesta_5a = None  # l[-1]\n",
        "respuesta_5b = None  # l[-1:-4:-1]\n",
        "respuesta_5c = None  # l[-1:-4:-1][::-1]\n",
        "respuesta_5d = None  # l[-1:-4:-1][::-1][-3] ** 3"
      ]
    },
    {
      "cell_type": "markdown",
      "id": "dbc31156",
      "metadata": {
        "id": "dbc31156"
      },
      "source": [
        "## 7. Operaciones con listas: concatenación, repetición y errores\n",
        "\n",
        "En Python puro, `l1 + l2` **concatena** listas; no suma elemento por elemento. Para suma vectorial usaremos funciones propias o NumPy en la sesión 2.\n",
        "\n",
        "Además, `l1 * 3` repite la lista, pero `l1 * l2` produce error porque Python no define multiplicación lista-lista."
      ]
    },
    {
      "cell_type": "code",
      "execution_count": null,
      "id": "078102ad",
      "metadata": {
        "id": "078102ad"
      },
      "outputs": [],
      "source": [
        "l1 = [1, 2, 3, 4]\n",
        "l2 = [5, 6, 7, 8]\n",
        "\n",
        "print(\"l1 + l2 =\", l1 + l2)\n",
        "print(\"l1 * 3  =\", l1 * 3)\n",
        "\n",
        "try:\n",
        "    print(l1 * l2)\n",
        "except TypeError as exc:\n",
        "    print(\"Error controlado:\", exc)"
      ]
    },
    {
      "cell_type": "markdown",
      "id": "a0e104f0",
      "metadata": {
        "id": "a0e104f0"
      },
      "source": [
        "### Ejercicio 1.6 — ¿Resultado o error?\n",
        "\n",
        "Indica el resultado exacto o la palabra `\"Error\"`."
      ]
    },
    {
      "cell_type": "code",
      "execution_count": null,
      "id": "0c353a1f",
      "metadata": {
        "id": "0c353a1f"
      },
      "outputs": [],
      "source": [
        "respuesta_6a = None  # [1,2] + [3,4]\n",
        "respuesta_6b = None  # [1,2] * 2\n",
        "respuesta_6c = None  # [1,2] * [3,4]"
      ]
    },
    {
      "cell_type": "markdown",
      "id": "c292f0da",
      "metadata": {
        "id": "c292f0da"
      },
      "source": [
        "## 8. Miniaplicación: contar resultados clásicos\n",
        "\n",
        "QBronze inicia modelando sistemas clásicos y probabilísticos. Antes de llegar a qubits, conviene dominar listas y conteos."
      ]
    },
    {
      "cell_type": "code",
      "execution_count": null,
      "id": "2ca36eb1",
      "metadata": {
        "id": "2ca36eb1"
      },
      "outputs": [],
      "source": [
        "resultados = [0, 1, 1, 0, 1, 0, 1, 1]\n",
        "ceros = 0\n",
        "unos = 0\n",
        "\n",
        "for bit in resultados:\n",
        "    if bit == 0:\n",
        "        ceros = ceros + 1\n",
        "    else:\n",
        "        unos = unos + 1\n",
        "\n",
        "print(\"ceros =\", ceros)\n",
        "print(\"unos  =\", unos)\n",
        "print(\"frecuencia de 1 =\", unos / len(resultados))"
      ]
    },
    {
      "cell_type": "markdown",
      "id": "6868c0b7",
      "metadata": {
        "id": "6868c0b7"
      },
      "source": [
        "### Ejercicio 1.7 — Conteo con condición\n",
        "\n",
        "Completa mentalmente el conteo antes de ejecutar la verificación."
      ]
    },
    {
      "cell_type": "code",
      "execution_count": null,
      "id": "8f604a7b",
      "metadata": {
        "id": "8f604a7b"
      },
      "outputs": [],
      "source": [
        "secuencia = [1, 0, 1, 1, 0, 0, 1, 0, 1]\n",
        "\n",
        "respuesta_7a = None  # número de unos\n",
        "respuesta_7b = None  # número de ceros\n",
        "respuesta_7c = None  # frecuencia de unos"
      ]
    },
    {
      "cell_type": "markdown",
      "id": "b038f426",
      "metadata": {
        "id": "b038f426"
      },
      "source": [
        "## Autoevaluación de la sesión 1\n",
        "\n",
        "Resuelve estas preguntas en papel. Después reemplaza los `None` y verifica. El formato está alineado con el tipo de razonamiento del quiz: expresiones, salidas de código y errores."
      ]
    },
    {
      "cell_type": "code",
      "execution_count": null,
      "id": "221beed4",
      "metadata": {
        "id": "221beed4"
      },
      "outputs": [],
      "source": [
        "# A. Expresión aritmética\n",
        "s1_A = None  # 6 + 2**3 * 5 - 14 % 4\n",
        "\n",
        "# B. Booleanos\n",
        "s1_B = None  # True + False + True*True\n",
        "\n",
        "# C. Código con lista\n",
        "# l = [3, 5, 1, 6, 0]\n",
        "# x = l[2]\n",
        "# y = l[-2]\n",
        "# z = len(l)\n",
        "# resultado = x + y + z\n",
        "s1_C = None\n",
        "\n",
        "# D. Slicing\n",
        "# l = [1, 2, 3, 4, 5]\n",
        "# resultado = l[::-2]\n",
        "s1_D = None\n",
        "\n",
        "# E. Operación inválida\n",
        "# [1, 2, 3] * [4, 5, 6]\n",
        "s1_E = None  # escribe \"Error\" si no corre"
      ]
    },
    {
      "cell_type": "markdown",
      "id": "96e2b9db",
      "metadata": {
        "id": "96e2b9db"
      },
      "source": [
        "## Cierre\n",
        "\n",
        "Antes de pasar a álgebra lineal, verifica que puedes hacer estas tareas sin mirar una referencia:\n",
        "\n",
        "- Determinar qué genera `range(10, 20, 2)`.\n",
        "- Trazar una variable que cambia dentro de un ciclo.\n",
        "- Explicar por qué `l1 + l2` concatena listas.\n",
        "- Explicar por qué `l1 * l2` genera error.\n",
        "- Usar índices negativos y *slicing* con paso negativo."
      ]
    }
  ],
  "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.11"
    },
    "colab": {
      "provenance": []
    }
  },
  "nbformat": 4,
  "nbformat_minor": 5
}