{
 "cells": [
  {
   "cell_type": "markdown",
   "metadata": {
    "id": "d8uIS7qdD2Y3"
   },
   "source": [
    "# Tarea 4 — Inferencia (Forward Propagation) en Redes Neuronales\n",
    "\n",
    "En esta tarea vas a implementar la **inferencia** (*forward propagation*) de **tres redes neuronales distintas** usando **NumPy** y **multiplicación matricial**.\n",
    "\n",
    "Las tres son clasificadores **binarios**: tienen una **única neurona de salida con activación sigmoide** y usan **sigmoide** también en las capas ocultas.\n",
    "\n",
    "**Los pesos ya están entrenados y te los entregamos dibujados en el diagrama de cada red**: cada peso está anotado sobre su conexión (en amarillo) y cada *bias* junto a su neurona (`b=...`). Tu trabajo es **leer** esos valores del diagrama y programar el forward propagation.\n",
    "\n",
    "## Qué debes hacer en cada red\n",
    "\n",
    "1. **Transcribir** los pesos y biases del diagrama a arreglos de NumPy.\n",
    "2. **Contar** el número total de parámetros de la red.\n",
    "3. **Implementar** el forward propagation con multiplicación matricial.\n",
    "4. **Probar** tu red con las entradas dadas y compararlas con el resultado esperado.\n",
    "\n",
    "> 💡 Aquí solo hacemos **inferencia**: los pesos ya están dados, **no** hay entrenamiento."
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {
    "id": "JsBA_RlXD2Y8"
   },
   "source": [
    "## Repaso: producto punto y multiplicación matricial\n",
    "\n",
    "Una neurona toma un vector de entrada $\\vec{a}_{in}$, lo combina con su vector de pesos $\\vec{w}_j$ y su bias $b_j$, y aplica la activación $g$ (aquí, la sigmoide):\n",
    "\n",
    "$$a_j = g\\!\\left(\\vec{w}_j \\cdot \\vec{a}_{in} + b_j\\right)$$\n",
    "\n",
    "donde $\\vec{w}_j \\cdot \\vec{a}_{in} = \\sum_i w_{ij}\\,a_i$ es el **producto punto**.\n",
    "\n",
    "💡 **Relación clave (multiplicación matricial ↔ producto punto).** Calcular **todas** las neuronas de una capa a la vez es una **multiplicación matricial**:\n",
    "\n",
    "$$\\vec{z} = \\vec{a}_{in}\\,W + \\vec{b}, \\qquad \\vec{a} = g(\\vec{z})$$\n",
    "\n",
    "Cada elemento del resultado es **exactamente un producto punto**: la entrada $\\vec{a}_{in}$ por una **columna** de $W$ (los pesos de una neurona). Es decir, **una multiplicación matricial es muchos productos punto calculados de una sola vez**. Por eso en NumPy `a_in @ W` (o np.matmul) calcula toda la capa con una sola operación.\n",
    "\n",
    "**Convención de formas** (importante para transcribir):\n",
    "\n",
    "- $W$ tiene forma `(n_entradas, n_neuronas)` → la **columna $j$** son los pesos de la neurona $j$.\n",
    "- $\\vec{b}$ tiene forma `(n_neuronas,)`.\n",
    "\n",
    "Forward propagation = aplicar esto **capa por capa**: $\\vec{a}_{in} \\to \\vec{a}^{[1]} \\to \\vec{a}^{[2]} \\to \\cdots \\to \\hat{y}$.\n",
    "\n",
    "**Cómo leer el diagrama:** el número amarillo sobre cada conexión es $w_{ij}$ (de la entrada/neurona $i$ hacia la neurona $j$); el valor `b=...` debajo de cada neurona es su bias. Para una misma neurona de origen, las etiquetas van ordenadas de la neurona destino más cercana ($j=1$) a la más lejana."
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 15,
   "metadata": {
    "id": "yR6x7yT3D2Y9"
   },
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "Listo. sigmoid(0) = 0.5\n"
     ]
    }
   ],
   "source": [
    "import numpy as np\n",
    "\n",
    "# La funcion de activacion sigmoide ya esta implementada (NO la modifiques).\n",
    "def sigmoid(z):\n",
    "    z = np.clip(z, -500, 500)   # estabilidad numerica\n",
    "    return 1 / (1 + np.exp(-z))\n",
    "\n",
    "print(\"Listo. sigmoid(0) =\", sigmoid(0.0))"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {
    "id": "0ubNbYhhD2ZA"
   },
   "source": [
    "## Ejercicio 0 — La función `dense` (una capa)\n",
    "\n",
    "Implementa **una sola vez** la función `dense`, que calcula **una capa completa** con multiplicación matricial y activación sigmoide. La reutilizarás en las tres redes.\n",
    "\n",
    "$$\\vec{a}_{out} = g\\!\\left(\\vec{a}_{in}\\,W + \\vec{b}\\right)$$\n",
    "\n",
    "Recuerda: `a_in @ W` es la multiplicación matricial; cada elemento de su resultado es el producto punto de `a_in` con una columna de `W`."
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 16,
   "metadata": {
    "id": "WcXI0Mt2D2ZB"
   },
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "[0.73105858 0.88079708 0.95257413]\n"
     ]
    }
   ],
   "source": [
    "def dense(a_in, W, b):\n",
    "    \"\"\"Calcula UNA capa:  a_in (n_in,)  ->  a_out (n_neuronas,).\n",
    "       Debe usar multiplicacion matricial: sigmoid(a_in @ W + b).\"\"\"\n",
    "    # a_out = None\n",
    "    # YOUR CODE HERE\n",
    "    a_out = sigmoid(a_in @ W + b)   # a_in @ W = un producto punto por cada neurona (columna de W)\n",
    "    #\n",
    "    return a_out\n",
    "\n",
    "# Prueba rapida (NO la cambies): una capa de 2 entradas -> 3 neuronas\n",
    "W_test = np.array([[1.0, 0.0, -1.0],\n",
    "                   [0.0, 1.0,  2.0]])\n",
    "b_test = np.array([0.0, 0.0, 0.0])\n",
    "print(dense(np.array([1.0, 2.0]), W_test, b_test))\n",
    "# Deberias obtener aprox: [0.731 0.881 0.953]"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {
    "id": "-cicgOk9D2ZB"
   },
   "source": [
    "---\n",
    "\n",
    "## Red A — ¿Aprueba el examen?  (2 → 2 → 1)\n",
    "\n",
    "Predice si un estudiante **aprueba** un examen a partir de:\n",
    "\n",
    "- $x_1$: horas de **estudio**\n",
    "- $x_2$: horas de **sueño**\n",
    "\n",
    "Arquitectura: **2 entradas → 1 capa oculta de 2 neuronas → 1 salida**. Los pesos están en el diagrama:"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {
    "id": "QuZLxur6D2ZC"
   },
   "source": [
    "![Red A](data:image/png;base64,[encoded data, 45380 characters])"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {
    "id": "cXOBWGZYD2ZE"
   },
   "source": [
    "### A.1 — Transcribe los pesos\n",
    "\n",
    "Lee el diagrama y crea los arreglos. `A_W1` tiene forma `(2, 2)`; `A_W2` tiene forma `(2, 1)`."
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 17,
   "metadata": {
    "id": "ETBJ8ytuD2ZF"
   },
   "outputs": [],
   "source": [
    "# Capa oculta: 2 entradas -> 2 neuronas\n",
    "# A_W1 = None   # forma (2, 2)   # YOUR CODE HERE\n",
    "A_W1 = np.array([[ 1.0, -1.5],    # fila = entrada x1:  x1->a1=+1.0 , x1->a2=-1.5\n",
    "                 [ 0.5,  2.0]])   # fila = entrada x2:  x2->a1=+0.5 , x2->a2=+2.0\n",
    "# A_b1 = None   # forma (2,)\n",
    "A_b1 = np.array([-1.0, -2.0])     # bias de a1 y a2\n",
    "# Capa de salida: 2 -> 1\n",
    "# A_W2 = None   # forma (2, 1)   # YOUR CODE HERE\n",
    "A_W2 = np.array([[ 2.0],          # a1 -> y = +2.0\n",
    "                 [-1.5]])         # a2 -> y = -1.5\n",
    "# A_b2 = None   # forma (1,)\n",
    "A_b2 = np.array([-1.0])           # bias de la salida"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {
    "id": "KbJOlRACD2ZG"
   },
   "source": [
    "### A.2 — Número de parámetros\n",
    "\n",
    "Calcula el total de parámetros = (todos los pesos) + (todos los biases). Pista: `W.size` te da cuántos números tiene una matriz."
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 18,
   "metadata": {
    "id": "Z1jm22PGD2ZG"
   },
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "Parametros Red A: 9\n"
     ]
    }
   ],
   "source": [
    "# A_n_params = None   # YOUR CODE HERE\n",
    "A_n_params = A_W1.size + A_b1.size + A_W2.size + A_b2.size\n",
    "print(\"Parametros Red A:\", A_n_params)\n",
    "# Deberias obtener: 9"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {
    "id": "7G_RimX_D2ZH"
   },
   "source": [
    "### A.3 — Forward propagation\n",
    "\n",
    "Encadena `dense` capa por capa. La Red A tiene **2 capas**: $\\vec{a}^{[1]} \\to \\hat{y}$."
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 19,
   "metadata": {
    "id": "vdTChhgbD2ZH"
   },
   "outputs": [],
   "source": [
    "def forward_A(x):\n",
    "    \"\"\"x: arreglo (2,)  ->  probabilidad de aprobar.\"\"\"\n",
    "    # YOUR CODE HERE: usa dense con (A_W1, A_b1) y luego con (A_W2, A_b2)\n",
    "    # y = None\n",
    "    a1 = dense(x,  A_W1, A_b1)   # capa oculta:  (2,) -> (2,)\n",
    "    y  = dense(a1, A_W2, A_b2)   # capa salida:  (2,) -> (1,)\n",
    "    return y"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {
    "id": "XKY-nFj0D2ZH"
   },
   "source": [
    "### A.4 — Prueba tu red"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 20,
   "metadata": {
    "id": "uRgEIspsD2ZJ"
   },
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "estudio=2  sueno=6  ->  p=0.3694\n",
      "estudio=5  sueno=5  ->  p=0.5158\n",
      "estudio=8  sueno=1  ->  p=0.7308\n"
     ]
    },
    {
     "name": "stderr",
     "output_type": "stream",
     "text": [
      "/tmp/ipykernel_102539/2121402088.py:3: DeprecationWarning: Conversion of an array with ndim > 0 to a scalar is deprecated, and will error in future. Ensure you extract a single element from your array before performing this operation. (Deprecated NumPy 1.25.)\n",
      "  print(f\"estudio={x[0]}  sueno={x[1]}  ->  p={float(p):.4f}\")\n"
     ]
    }
   ],
   "source": [
    "for x in [[2, 6], [5, 5], [8, 1]]:\n",
    "    p = forward_A(np.array(x, dtype=float))\n",
    "    print(f\"estudio={x[0]}  sueno={x[1]}  ->  p={float(p):.4f}\")\n",
    "\n",
    "# Deberias obtener aprox:\n",
    "#   estudio=2  sueno=6  ->  p=0.3694   (no aprueba)\n",
    "#   estudio=5  sueno=5  ->  p=0.5158   (apenas aprueba)\n",
    "#   estudio=8  sueno=1  ->  p=0.7308   (aprueba)"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {
    "id": "zyR0m35KD2ZK"
   },
   "source": [
    "---\n",
    "\n",
    "## Red B — ¿El correo es spam?  (3 → 4 → 2 → 1)\n",
    "\n",
    "Clasifica un correo como **spam** (1) o no (0) a partir de:\n",
    "\n",
    "- $x_1$: número de **enlaces**\n",
    "- $x_2$: número de palabras en **MAYÚSCULAS**\n",
    "- $x_3$: menciones de **dinero/premios**\n",
    "\n",
    "Arquitectura: **3 entradas → oculta de 4 → oculta de 2 → 1 salida**. Lee los pesos:"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {
    "id": "zA-RPF_KD2ZK"
   },
   "source": [
    "![Red B](data:image/png;base64,[encoded data, 140296 characters])"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {
    "id": "Ott8ugrKD2ZN"
   },
   "source": [
    "### B.1 — Transcribe los pesos\n",
    "\n",
    "Formas: `B_W1` `(3, 4)`, `B_b1` `(4,)`, `B_W2` `(4, 2)`, `B_b2` `(2,)`, `B_W3` `(2, 1)`, `B_b3` `(1,)`."
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 21,
   "metadata": {
    "id": "s0-Ly5aID2ZN"
   },
   "outputs": [],
   "source": [
    "# Capa oculta 1: 3 entradas -> 4 neuronas\n",
    "# B_W1 = None   # forma (3, 4)   # YOUR CODE HERE\n",
    "B_W1 = np.array([[ 0.5, -1.0,  2.0,  0.3],   # x1 -> a1,a2,a3,a4\n",
    "                 [-1.5,  0.8, -0.5,  1.0],   # x2 -> a1,a2,a3,a4\n",
    "                 [ 1.0,  0.4, -2.0, -0.6]])  # x3 -> a1,a2,a3,a4\n",
    "# B_b1 = None   # forma (4,)\n",
    "B_b1 = np.array([-0.5, 1.0, 0.2, -1.0])\n",
    "# Capa oculta 2: 4 -> 2\n",
    "# B_W2 = None   # forma (4, 2)   # YOUR CODE HERE\n",
    "B_W2 = np.array([[ 1.0, -0.5],   # a1 -> A1,A2\n",
    "                 [-2.0,  1.5],   # a2 -> A1,A2\n",
    "                 [ 0.6,  0.9],   # a3 -> A1,A2\n",
    "                 [-1.0, -0.4]])  # a4 -> A1,A2\n",
    "# B_b2 = None   # forma (2,)\n",
    "B_b2 = np.array([0.3, -0.7])\n",
    "# Capa de salida: 2 -> 1\n",
    "# B_W3 = None   # forma (2, 1)   # YOUR CODE HERE\n",
    "B_W3 = np.array([[ 2.0],    # A1 -> y\n",
    "                 [-1.8]])   # A2 -> y\n",
    "# B_b3 = None   # forma (1,)\n",
    "B_b3 = np.array([-0.2])"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {
    "id": "qwoABh6fD2ZN"
   },
   "source": [
    "### B.2 — Número de parámetros"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 22,
   "metadata": {
    "id": "2SflR0JmD2ZN"
   },
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "Parametros Red B: 29\n"
     ]
    }
   ],
   "source": [
    "# B_n_params = None   # YOUR CODE HERE\n",
    "B_n_params = B_W1.size + B_b1.size + B_W2.size + B_b2.size + B_W3.size + B_b3.size\n",
    "print(\"Parametros Red B:\", B_n_params)\n",
    "# Deberias obtener: 29"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {
    "id": "yq6uljKVD2ZN"
   },
   "source": [
    "### B.3 — Forward propagation\n",
    "\n",
    "La Red B tiene **3 capas**: $\\vec{a}^{[1]} \\to \\vec{a}^{[2]} \\to \\hat{y}$."
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 23,
   "metadata": {
    "id": "3bWYYk5HD2ZN"
   },
   "outputs": [],
   "source": [
    "def forward_B(x):\n",
    "    \"\"\"x: arreglo (3,)  ->  probabilidad de spam.\"\"\"\n",
    "    # YOUR CODE HERE: encadena dense tres veces\n",
    "    # y = None\n",
    "    a1 = dense(x,  B_W1, B_b1)   # (3,) -> (4,)\n",
    "    a2 = dense(a1, B_W2, B_b2)   # (4,) -> (2,)\n",
    "    y  = dense(a2, B_W3, B_b3)   # (2,) -> (1,)\n",
    "    return y"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {
    "id": "aYJbOwjTD2ZN"
   },
   "source": [
    "### B.4 — Prueba tu red"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 24,
   "metadata": {
    "id": "szqEdHdID2ZN"
   },
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "enlaces=1  mayus=3  dinero=0  ->  p=0.2226\n",
      "enlaces=2  mayus=1  dinero=1  ->  p=0.3922\n",
      "enlaces=3  mayus=0  dinero=2  ->  p=0.6114\n"
     ]
    },
    {
     "name": "stderr",
     "output_type": "stream",
     "text": [
      "/tmp/ipykernel_102539/2199352188.py:3: DeprecationWarning: Conversion of an array with ndim > 0 to a scalar is deprecated, and will error in future. Ensure you extract a single element from your array before performing this operation. (Deprecated NumPy 1.25.)\n",
      "  print(f\"enlaces={x[0]}  mayus={x[1]}  dinero={x[2]}  ->  p={float(p):.4f}\")\n"
     ]
    }
   ],
   "source": [
    "for x in [[1, 3, 0], [2, 1, 1], [3, 0, 2]]:\n",
    "    p = forward_B(np.array(x, dtype=float))\n",
    "    print(f\"enlaces={x[0]}  mayus={x[1]}  dinero={x[2]}  ->  p={float(p):.4f}\")\n",
    "\n",
    "# Deberias obtener aprox:\n",
    "#   enlaces=1  mayus=3  dinero=0  ->  p=0.2226   (no spam)\n",
    "#   enlaces=2  mayus=1  dinero=1  ->  p=0.3922   (no spam)\n",
    "#   enlaces=3  mayus=0  dinero=2  ->  p=0.6114   (spam)"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {
    "id": "GQ21r6ZRD2ZN"
   },
   "source": [
    "---\n",
    "\n",
    "## Red C — ¿Transacción fraudulenta?  (4 → 3 → 3 → 2 → 1)\n",
    "\n",
    "Detecta si una transacción con tarjeta es **fraude** (1) o no (0) a partir de:\n",
    "\n",
    "- $x_1$: **monto** (en miles)\n",
    "- $x_2$: **hora** del día (0–3, codificada)\n",
    "- $x_3$: número de **transacciones recientes**\n",
    "- $x_4$: **distancia** al domicilio\n",
    "\n",
    "Arquitectura: **4 entradas → oculta de 3 → oculta de 3 → oculta de 2 → 1 salida**. Lee los pesos:"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {
    "id": "J4KlbSo5D2ZN"
   },
   "source": [
    "![Red C](data:image/png;base64,[encoded data, 165212 characters])"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {
    "id": "LmAlxqXJD2ZP"
   },
   "source": [
    "### C.1 — Transcribe los pesos\n",
    "\n",
    "Formas: `C_W1` `(4, 3)`, `C_b1` `(3,)`, `C_W2` `(3, 3)`, `C_b2` `(3,)`, `C_W3` `(3, 2)`, `C_b3` `(2,)`, `C_W4` `(2, 1)`, `C_b4` `(1,)`."
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 25,
   "metadata": {
    "id": "ovXNmsTLD2ZQ"
   },
   "outputs": [],
   "source": [
    "# Capa oculta 1: 4 entradas -> 3 neuronas\n",
    "# C_W1 = None   # forma (4, 3)   # YOUR CODE HERE\n",
    "C_W1 = np.array([[ 0.8, -1.0,  0.5],   # x1 -> a1,a2,a3\n",
    "                 [-0.6,  1.2,  0.3],   # x2 -> a1,a2,a3\n",
    "                 [ 1.0, -0.4, -1.5],   # x3 -> a1,a2,a3\n",
    "                 [ 0.2,  0.7,  1.0]])  # x4 -> a1,a2,a3\n",
    "# C_b1 = None   # forma (3,)\n",
    "C_b1 = np.array([-0.5, 0.4, 1.0])\n",
    "# Capa oculta 2: 3 -> 3\n",
    "# C_W2 = None   # forma (3, 3)   # YOUR CODE HERE\n",
    "C_W2 = np.array([[ 1.5, -0.8,  0.6],   # a1 -> b1,b2,b3\n",
    "                 [-1.0,  1.0, -0.5],   # a2 -> b1,b2,b3\n",
    "                 [ 0.4,  1.2, -1.4]])  # a3 -> b1,b2,b3\n",
    "# C_b2 = None   # forma (3,)\n",
    "C_b2 = np.array([0.2, -1.0, 0.5])\n",
    "# Capa oculta 3: 3 -> 2\n",
    "# C_W3 = None   # forma (3, 2)   # YOUR CODE HERE\n",
    "C_W3 = np.array([[ 1.0, -1.2],   # b1 -> c1,c2\n",
    "                 [-0.7,  0.9],   # b2 -> c1,c2\n",
    "                 [ 1.4,  0.5]])  # b3 -> c1,c2\n",
    "# C_b3 = None   # forma (2,)\n",
    "C_b3 = np.array([-0.3, 0.6])\n",
    "# Capa de salida: 2 -> 1\n",
    "# C_W4 = None   # forma (2, 1)   # YOUR CODE HERE\n",
    "C_W4 = np.array([[ 1.8],    # c1 -> y\n",
    "                 [-2.0]])   # c2 -> y\n",
    "# C_b4 = None   # forma (1,)\n",
    "C_b4 = np.array([0.1])"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {
    "id": "CWvJkM_RD2ZQ"
   },
   "source": [
    "### C.2 — Número de parámetros"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 26,
   "metadata": {
    "id": "w0YU6Gv6D2ZQ"
   },
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "Parametros Red C: 38\n"
     ]
    }
   ],
   "source": [
    "# C_n_params = None   # YOUR CODE HERE\n",
    "C_n_params = (C_W1.size + C_b1.size + C_W2.size + C_b2.size +\n",
    "              C_W3.size + C_b3.size + C_W4.size + C_b4.size)\n",
    "print(\"Parametros Red C:\", C_n_params)\n",
    "# Deberias obtener: 38"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {
    "id": "AHnYVtRLD2ZQ"
   },
   "source": [
    "### C.3 — Forward propagation\n",
    "\n",
    "La Red C tiene **4 capas**: $\\vec{a}^{[1]} \\to \\vec{a}^{[2]} \\to \\vec{a}^{[3]} \\to \\hat{y}$."
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 27,
   "metadata": {
    "id": "ab9Qwn3HD2ZQ"
   },
   "outputs": [],
   "source": [
    "def forward_C(x):\n",
    "    \"\"\"x: arreglo (4,)  ->  probabilidad de fraude.\"\"\"\n",
    "    # YOUR CODE HERE: encadena dense cuatro veces\n",
    "    # y = None\n",
    "    a1 = dense(x,  C_W1, C_b1)   # (4,) -> (3,)\n",
    "    a2 = dense(a1, C_W2, C_b2)   # (3,) -> (3,)\n",
    "    a3 = dense(a2, C_W3, C_b3)   # (3,) -> (2,)\n",
    "    y  = dense(a3, C_W4, C_b4)   # (2,) -> (1,)\n",
    "    return y"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {
    "id": "VxHdwgSwD2ZQ"
   },
   "source": [
    "### C.4 — Prueba tu red"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 28,
   "metadata": {
    "id": "OGn-edBED2ZQ"
   },
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "x=[0, 3, 0, 1]  ->  p=0.3936\n",
      "x=[1, 1, 1, 1]  ->  p=0.5109\n",
      "x=[3, 0, 3, 0]  ->  p=0.6247\n"
     ]
    },
    {
     "name": "stderr",
     "output_type": "stream",
     "text": [
      "/tmp/ipykernel_102539/2859525198.py:3: DeprecationWarning: Conversion of an array with ndim > 0 to a scalar is deprecated, and will error in future. Ensure you extract a single element from your array before performing this operation. (Deprecated NumPy 1.25.)\n",
      "  print(f\"x={x}  ->  p={float(p):.4f}\")\n"
     ]
    }
   ],
   "source": [
    "for x in [[0, 3, 0, 1], [1, 1, 1, 1], [3, 0, 3, 0]]:\n",
    "    p = forward_C(np.array(x, dtype=float))\n",
    "    print(f\"x={x}  ->  p={float(p):.4f}\")\n",
    "\n",
    "# Deberias obtener aprox:\n",
    "#   x=[0, 3, 0, 1]  ->  p=0.3936   (no fraude)\n",
    "#   x=[1, 1, 1, 1]  ->  p=0.5109   (frontera)\n",
    "#   x=[3, 0, 3, 0]  ->  p=0.6247   (fraude)"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {
    "id": "vgKGwLR_D2ZQ"
   },
   "source": [
    "---\n",
    "\n",
    "## ¡Felicidades! 🎉\n",
    "\n",
    "Implementaste la **inferencia** (forward propagation) de tres redes neuronales de distinto tamaño, usando solo **NumPy** y **multiplicación matricial**:\n",
    "\n",
    "- Leíste los pesos directamente del **diagrama** de cada red.\n",
    "- Contaste sus **parámetros** (9, 29 y 38).\n",
    "- Encadenaste la función `dense` **capa por capa**.\n",
    "\n",
    "**Idea clave:** sin importar cuántas entradas, capas o neuronas tenga la red, la inferencia es siempre lo mismo — propagar la entrada hacia adelante con una **multiplicación matricial por capa** (que no es más que muchos **productos punto** a la vez) seguida de la activación. El **entrenamiento** —encontrar esos pesos— es el tema de la siguiente unidad.\n",
    "\n",
    "*Material de Universidad Galileo / adaptado de DeepLearning.AI (CC BY-SA 2.0).*"
   ]
  }
 ],
 "metadata": {
  "colab": {
   "provenance": []
  },
  "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.10.12"
  }
 },
 "nbformat": 4,
 "nbformat_minor": 0
}
