\n",
81 | "\n",
82 | "# Objetivos\n",
83 | "\n",
84 | "Construir un perceptrón que sea capas de aprender el comportamiento del operador lógico XOR."
85 | ]
86 | },
87 | {
88 | "cell_type": "markdown",
89 | "metadata": {
90 | "id": "tThan_E8DWrD"
91 | },
92 | "source": [
93 | "
\n",
94 | " \n",
95 | "## (10 Puntos) Perceptrón XOR\n",
96 | "\n",
97 | "Dado que ya conoces como funcionan los perceptrones vistos en clase, esta tarea consiste es encontrar la forma de aprender el comportamiento del operador lógico XOR mediante el uso de la clase `Perceptron`.\n",
98 | "\n",
99 | "A continuación se muestra la tabla de verdad del operador lógico XOR, así como el código de la clase antes mencionada.\n",
100 | "\n",
101 | "| $x_1$ | $x_2$ | $and$ |\n",
102 | "| :-: | :-:| :-: |\n",
103 | "| 0 | 0 | 0 |\n",
104 | "| 0 | 1 | 1 |\n",
105 | "| 1 | 0 | 1 |\n",
106 | "| 1 | 1 | 0 |"
107 | ]
108 | },
109 | {
110 | "cell_type": "code",
111 | "execution_count": null,
112 | "metadata": {
113 | "nbgrader": {
114 | "grade": true,
115 | "grade_id": "cell-bcdc4313a3efcd10",
116 | "locked": false,
117 | "points": 0,
118 | "schema_version": 3,
119 | "solution": true,
120 | "task": false
121 | },
122 | "tags": [],
123 | "id": "khFPQeANDWrE"
124 | },
125 | "outputs": [],
126 | "source": [
127 | "'''\n",
128 | "MIT License\n",
129 | "Copyright (c) 2018 Thomas Countz\n",
130 | "Codigo tomado del sitio\n",
131 | "https://medium.com/@thomascountz/19-line-line-by-line-python-perceptron-b6f113b161f3\n",
132 | "'''\n",
133 | "import numpy as np\n",
134 | "\n",
135 | "# Definicion de la clase que hereda de la clase object\n",
136 | "class Perceptron(object):\n",
137 | " '''\n",
138 | " Constructor que recibe los siguientes parametros\n",
139 | " num_entradas: numero de entradas del vector de entradas\n",
140 | " limite: es el limite de iteraciones mientras entrenamos\n",
141 | " tasa_aprendizaje: magnitud en la que se incrementan los pesos\n",
142 | " '''\n",
143 | " def __init__(self, num_entradas, limite=15, tasa_aprendizaje=0.01):\n",
144 | " self.limite = limite\n",
145 | " self.tasa_aprendizaje = tasa_aprendizaje\n",
146 | " self.pesos = np.zeros(num_entradas + 1) #se suma uno por el bias\n",
147 | "\n",
148 | " '''\n",
149 | " Metodo que nos devuelve la prediccion del perceptron\n",
150 | " entradas: vector de entradas para realizar la prediccion\n",
151 | " '''\n",
152 | " def prediccion(self, entradas):\n",
153 | " # suma ponderada x*w, pesos[0] = bias\n",
154 | " suma = np.dot(entradas, self.pesos[1:]) + self.pesos[0]\n",
155 | " # funcion de activacion equivalente a np.heaviside\n",
156 | " if suma > 0:\n",
157 | " activacion = 1\n",
158 | " else:\n",
159 | " activacion = 0\n",
160 | " return activacion\n",
161 | "\n",
162 | " '''\n",
163 | " Metodo que entrena al percetron\n",
164 | " entradas_ent: vector de vectores de entradas para entrenar\n",
165 | " etiquetas: valores esperados por cada entrada del vector de entradas\n",
166 | " '''\n",
167 | " def entrenamiento(self, entradas_ent, etiquetas, debbug=False):\n",
168 | " # por cada epoca en el limite de entrenamientos\n",
169 | " for _ in range(self.limite):\n",
170 | " # tomamos una entrada y su respectiva etiqueta\n",
171 | " for entrada, etiqueta in zip(entradas_ent, etiquetas):\n",
172 | " prediccion = self.prediccion(entrada)\n",
173 | " # ajuste de pesos w <- w + (y-f(x)) * x\n",
174 | " self.pesos[1:] += self.tasa_aprendizaje * (etiqueta - prediccion) * entrada\n",
175 | " # ajuste del bias\n",
176 | " self.pesos[0] += self.tasa_aprendizaje * (etiqueta - prediccion) # *1\n",
177 | " # (SECCION DE DEBUGEO)\n",
178 | " if debbug:\n",
179 | " if prediccion != etiqueta:\n",
180 | " print(\"chanclazo por no aprender\")\n",
181 | " input(\"Continuar?\")\n",
182 | " else:\n",
183 | " print(\"bien hecho muchacho\")\n",
184 | " input(\"Continuar?\")\n",
185 | " #self.grafica()\n",
186 | "\n",
187 | " def grafica(self):\n",
188 | " print(self.pesos)\n",
189 | " # dominio de la grafica\n",
190 | " dominio = np.linspace(-0.25, 1.25, 10)\n",
191 | " # funcion a graficar\n",
192 | " graf = lambda x: (-self.pesos[0]-self.pesos[1]*x)/self.pesos[2]\n",
193 | "\n",
194 | " # definimos algunos parámetros para la gráfica\n",
195 | " fig, ax = plt.subplots()\n",
196 | " # recta generada por el perceptron\n",
197 | " ax.plot(dominio, graf(dominio))\n",
198 | " # valores de entrada para el perceptron\n",
199 | " xs = [0,1,0,1]\n",
200 | " ys = [0,0,1,1]\n",
201 | " # etiquetas\n",
202 | " ax.scatter(xs, ys)\n",
203 | " ax.annotate('(0,0)', (xs[0],ys[0]), xytext=(0.125, 0.125), arrowprops = dict( arrowstyle=\"->\",\n",
204 | " connectionstyle=\"angle3,angleA=0,angleB=-90\"))\n",
205 | " ax.annotate('(1,0)', (xs[1],ys[1]), xytext=(1, 0.125), arrowprops = dict( arrowstyle=\"->\",\n",
206 | " connectionstyle=\"angle3,angleA=0,angleB=-90\"))\n",
207 | " ax.annotate('(0,1)', (xs[2],ys[2]), xytext=(0.125, 0.75), arrowprops = dict( arrowstyle=\"->\",\n",
208 | " connectionstyle=\"angle3,angleA=0,angleB=-90\"))\n",
209 | " ax.annotate('(1,1)', (xs[3],ys[3]), xytext=(1, 0.75), arrowprops = dict( arrowstyle=\"->\",\n",
210 | " connectionstyle=\"angle3,angleA=0,angleB=-90\"))\n",
211 | " # ejes coordenados\n",
212 | " ax.axhline(y=0, color='k')\n",
213 | " ax.axvline(x=0, color='k')\n",
214 | " plt.title(\"Perceptrón\")\n",
215 | "\n",
216 | " plt.grid()\n",
217 | " plt.show()"
218 | ]
219 | },
220 | {
221 | "cell_type": "markdown",
222 | "metadata": {
223 | "id": "3Fh74LlEDWrF"
224 | },
225 | "source": [
226 | "
\n",
227 | " \n",
228 | "## Solución al problema\n",
229 | "\n",
230 | "En el siguiente [enlace](https://towardsdatascience.com/how-neural-networks-solve-the-xor-problem-59763136bdd7) puedes encontrar una descripción más detallada del problema y de una posible solución. No es necesario redefinir la clase `Percetron`, solo hace falta usar la clase `Perceptron` que ya fue definida."
231 | ]
232 | },
233 | {
234 | "cell_type": "code",
235 | "execution_count": null,
236 | "metadata": {
237 | "id": "6t9RpZXGDWrF",
238 | "outputId": "8d742bc0-b7b0-4d22-baab-425102e24c0a"
239 | },
240 | "outputs": [
241 | {
242 | "name": "stdout",
243 | "output_type": "stream",
244 | "text": [
245 | "0\n",
246 | "1\n",
247 | "1\n",
248 | "0\n",
249 | "[-0.02 0.01 0.02]\n",
250 | "[0. 0.01 0.01]\n",
251 | "[ 0.03 -0.01 -0.02]\n"
252 | ]
253 | }
254 | ],
255 | "source": [
256 | "# entrenamiento OR\n",
257 | "entradas_ent0 = []\n",
258 | "entradas_ent0.append(np.array([1, 1]))\n",
259 | "entradas_ent0.append(np.array([1, 0]))\n",
260 | "entradas_ent0.append(np.array([0, 1]))\n",
261 | "entradas_ent0.append(np.array([0, 0]))\n",
262 | "\n",
263 | "etiquetas0 = np.array([1, 1, 1, 0])\n",
264 | "# entrenamiento NAND\n",
265 | "entradas_ent1 = []\n",
266 | "entradas_ent1.append(np.array([1, 1]))\n",
267 | "entradas_ent1.append(np.array([1, 0]))\n",
268 | "entradas_ent1.append(np.array([0, 1]))\n",
269 | "entradas_ent1.append(np.array([0, 0]))\n",
270 | "\n",
271 | "etiquetas1 = np.array([0, 1, 1, 1])\n",
272 | "\n",
273 | "# entrenamiento AND\n",
274 | "entradas_ent2 = []\n",
275 | "entradas_ent2.append(np.array([1, 1]))\n",
276 | "entradas_ent2.append(np.array([1, 0]))\n",
277 | "entradas_ent2.append(np.array([0, 1]))\n",
278 | "entradas_ent2.append(np.array([0, 0]))\n",
279 | "\n",
280 | "etiquetas2 = np.array([1, 0, 0, 0])\n",
281 | "\n",
282 | "perceptron_or = Perceptron(2)\n",
283 | "perceptron_or.entrenamiento(entradas_ent0, etiquetas0)\n",
284 | "\n",
285 | "\n",
286 | "perceptron_nand = Perceptron(2)\n",
287 | "perceptron_nand.entrenamiento(entradas_ent1, etiquetas1)\n",
288 | "\n",
289 | "perceptron_and = Perceptron(2)\n",
290 | "perceptron_and.entrenamiento(entradas_ent2, etiquetas2)\n",
291 | "\n",
292 | "entradas = np.array([0, 0])\n",
293 | "print(perceptron_and.prediccion(np.array([perceptron_nand.prediccion(entradas), perceptron_or.prediccion(entradas)])))\n",
294 | "\n",
295 | "entradas = np.array([1, 0])\n",
296 | "print(perceptron_and.prediccion(np.array([perceptron_nand.prediccion(entradas), perceptron_or.prediccion(entradas)])))\n",
297 | "\n",
298 | "entradas = np.array([0, 1])\n",
299 | "print(perceptron_and.prediccion(np.array([perceptron_nand.prediccion(entradas), perceptron_or.prediccion(entradas)])))\n",
300 | "\n",
301 | "entradas = np.array([1, 1])\n",
302 | "print(perceptron_and.prediccion(np.array([perceptron_nand.prediccion(entradas), perceptron_or.prediccion(entradas)])))\n",
303 | "\n",
304 | "# vector que contiene el sesgo y pesos\n",
305 | "print(perceptron_and.pesos)\n",
306 | "print(perceptron_or.pesos)\n",
307 | "print(perceptron_nand.pesos)"
308 | ]
309 | },
310 | {
311 | "cell_type": "code",
312 | "execution_count": null,
313 | "metadata": {
314 | "nbgrader": {
315 | "grade": true,
316 | "grade_id": "cell-0b41c598f6dbf864",
317 | "locked": true,
318 | "points": 3,
319 | "schema_version": 3,
320 | "solution": false,
321 | "task": false
322 | },
323 | "id": "Eeao8vtgDWrH"
324 | },
325 | "outputs": [],
326 | "source": [
327 | "# EJECUTAR ESTA CELDA SOLO SI EL NOTEBOOK ESTA EN MACTI\n",
328 | "#quizz.eval_numeric('1', documento.vector_caracteristico)\n",
329 | "entradas = np.array([0, 0])\n",
330 | "print(perceptron_and.prediccion(np.array([perceptron_nand.prediccion(entradas), perceptron_or.prediccion(entradas)])))\n",
331 | "\n",
332 | "file_answer.write('1', documento.vector_caracteristico, 'Revisa la solución del problema')"
333 | ]
334 | },
335 | {
336 | "cell_type": "code",
337 | "execution_count": null,
338 | "metadata": {
339 | "id": "yUQJrnqXDWrH"
340 | },
341 | "outputs": [],
342 | "source": [
343 | "entradas = np.array([1, 0])\n",
344 | "print(perceptron_and.prediccion(np.array([perceptron_nand.prediccion(entradas), perceptron_or.prediccion(entradas)])))\n",
345 | "\n",
346 | "file_answer.write('2', documento.vector_caracteristico, 'Revisa la solución del problema')"
347 | ]
348 | },
349 | {
350 | "cell_type": "code",
351 | "execution_count": null,
352 | "metadata": {
353 | "id": "0N-9jOHiDWrI"
354 | },
355 | "outputs": [],
356 | "source": [
357 | "entradas = np.array([0, 1])\n",
358 | "print(perceptron_and.prediccion(np.array([perceptron_nand.prediccion(entradas), perceptron_or.prediccion(entradas)])))\n",
359 | "\n",
360 | "file_answer.write('3', documento.vector_caracteristico, 'Revisa la solución del problema')"
361 | ]
362 | },
363 | {
364 | "cell_type": "code",
365 | "execution_count": null,
366 | "metadata": {
367 | "id": "gvzuerMDDWrI"
368 | },
369 | "outputs": [],
370 | "source": [
371 | "entradas = np.array([1, 1])\n",
372 | "print(perceptron_and.prediccion(np.array([perceptron_nand.prediccion(entradas), perceptron_or.prediccion(entradas)])))\n",
373 | "\n",
374 | "file_answer.write('4', documento.vector_caracteristico, 'Revisa la solución del problema')"
375 | ]
376 | }
377 | ],
378 | "metadata": {
379 | "kernelspec": {
380 | "display_name": "Python 3 (ipykernel)",
381 | "language": "python",
382 | "name": "python3"
383 | },
384 | "language_info": {
385 | "codemirror_mode": {
386 | "name": "ipython",
387 | "version": 3
388 | },
389 | "file_extension": ".py",
390 | "mimetype": "text/x-python",
391 | "name": "python",
392 | "nbconvert_exporter": "python",
393 | "pygments_lexer": "ipython3",
394 | "version": "3.11.6"
395 | },
396 | "colab": {
397 | "provenance": [],
398 | "include_colab_link": true
399 | }
400 | },
401 | "nbformat": 4,
402 | "nbformat_minor": 0
403 | }
--------------------------------------------------------------------------------
/Eval/.ipynb_checkpoints/6_Diccionarios-checkpoint.ipynb:
--------------------------------------------------------------------------------
1 | {
2 | "cells": [
3 | {
4 | "cell_type": "markdown",
5 | "id": "a4d795ac-c8bd-4451-8d1d-4a0a088d18b7",
6 | "metadata": {},
7 | "source": [
8 | "
\n",
9 | " Evaluación de diccionarios\n",
10 | "
\n",
11 | "\n",
12 | "\n",
13 | "La evaluación de **diccionarios** se utiliza para validar objetos de tipo `dict`, comprobando su longitud, las claves y cada uno de sus valores. Admite tanto valores numéricos como cadenas de texto.\n",
14 | "\n",
15 | "**¿Cómo funciona?** \n",
16 | "- Comprueba la longitud del diccionario, las claves y cada uno de los valores. \n",
17 | "- Utiliza varios identificadores internos (por ejemplo, `'5_len'`, `'5_key'`, `'5_val_0'`, etc.) para desglosar y validar cada parte. \n",
18 | "\n",
19 | "**¿Qué se puede personalizar?** \n",
20 | "- El tipo de claves y valores a evaluar (numéricos o texto). \n",
21 | "- El modo de comparación (`numeric=True/False`).\n",
22 | "\n",
23 | "---\n"
24 | ]
25 | },
26 | {
27 | "cell_type": "markdown",
28 | "id": "c091ffcb-20f6-4cb2-af9a-a4ddf5ca57c0",
29 | "metadata": {},
30 | "source": [
31 | "\n",
32 | "## ¿Cómo se utiliza la evaluación de diccionarios numéricos?\n",
33 | "\n",
34 | "Para validar que el alumno entregue un diccionario con las mismas claves y valores (numéricos), ajusta dos pasos en tu flujo:\n",
35 | "\n",
36 | "1. **Registrar el diccionario de referencia** \n",
37 | " Después de crear `FileAnswer()` y antes de llamar a `.to_file()`, define el diccionario correcto:\n",
38 | "\n",
39 | " ```python\n",
40 | " # 1) Definir la respuesta de referencia para el ejercicio '5'\n",
41 | " file_answer.write(\n",
42 | " '5', # → ID del ejercicio\n",
43 | " {1: 2.0, 2: 4.0}, # → diccionario de referencia\n",
44 | " 'Comprueba claves y valores.' # → mensaje si el alumno falla\n",
45 | " )\n",
46 | "\n",
47 | "\n",
48 | "2. **Al evaluar la respuesta del usuario**\n",
49 | "\n",
50 | " ```python\n",
51 | " quiz.eval_dict(\n",
52 | " '5', # → mismo ID de ejercicio que usaste arriba\n",
53 | " respuesta_alumno, # → dict que envió el estudiante\n",
54 | " numeric=True # → compara valores numéricos\n",
55 | " )\n"
56 | ]
57 | },
58 | {
59 | "cell_type": "markdown",
60 | "id": "05ce9747-dc1e-46ef-9a39-65a6bbe5cbc7",
61 | "metadata": {},
62 | "source": [
63 | "## Código: evaluación de diccionarios\n",
64 | "\n",
65 | "En `src/macti/eval/quiz.py`, dentro de la clase `Quiz`, el método `eval_dict` realiza los siguientes pasos:\n",
66 | "\n",
67 | "```python\n",
68 | "def eval_dict(self, enum, ans, numeric=True):\n",
69 | " \"\"\"\n",
70 | " Evalúa una respuesta en formato diccionario.\n",
71 | "\n",
72 | " Parameters\n",
73 | " ----------\n",
74 | " enum : str\n",
75 | " Identificador del ejercicio (por ejemplo, '5').\n",
76 | " ans : dict\n",
77 | " Diccionario que envió el alumno.\n",
78 | " numeric : bool, optional\n",
79 | " True para comparar valores numéricos con tolerancia;\n",
80 | " False para comparar cadenas de texto exactas.\n",
81 | " \"\"\"\n",
82 | " enum_base = enum # ID base para construir sub-IDs\n",
83 | " msg = \"\" # Mensaje de error parcial\n",
84 | "\n",
85 | " try:\n",
86 | " # 1) Verificar que ans sea un dict\n",
87 | " if not isinstance(ans, dict):\n",
88 | " print(f\"{enum} | Respuesta inválida: {ans} es de tipo {type(ans)}\")\n",
89 | " raise AssertionError\n",
90 | "\n",
91 | " # 2) Comparar longitud del diccionario\n",
92 | " dict_len = len(ans)\n",
93 | " enum_len = f\"{enum_base}_len\"\n",
94 | " correct_len = self.__read(enum_len)[enum_len][0]\n",
95 | " if not math.isclose(correct_len, dict_len):\n",
96 | " msg = f\"\\nValor correcto: {correct_len}\\nValor alumno: {dict_len}\\n\"\n",
97 | " raise AssertionError\n",
98 | "\n",
99 | " # 3) Comparar claves\n",
100 | " keys = np.array(list(ans.keys()))\n",
101 | " enum_key = f\"{enum_base}_key\"\n",
102 | " correct_keys = self.__read(enum_key)[enum_key][0]\n",
103 | " if np.any(keys != correct_keys):\n",
104 | " msg = f\"\\nClaves correctas: {correct_keys}\\nClaves alumno: {keys}\\n\"\n",
105 | " np.testing.assert_equal(keys, correct_keys)\n",
106 | "\n",
107 | " # 4) Comparar cada valor\n",
108 | " for i, alumno_val in enumerate(ans.values()):\n",
109 | " enum_val = f\"{enum_base}_val_{i}\"\n",
110 | " correct_val = self.__read(enum_val)[enum_val][0]\n",
111 | "\n",
112 | " if numeric:\n",
113 | " # 4a) Valores numéricos con tolerancia\n",
114 | " if isinstance(alumno_val, (int, float, bool)):\n",
115 | " if not math.isclose(correct_val, alumno_val):\n",
116 | " msg = f\"\\nValor correcto: {correct_val}\\nValor alumno: {alumno_val}\\n\"\n",
117 | " raise AssertionError\n",
118 | " else:\n",
119 | " arr = np.array(alumno_val).flatten()\n",
120 | " msg = self.__test_numeric_array(arr, correct_val)\n",
121 | " np.testing.assert_allclose(arr, correct_val)\n",
122 | " else:\n",
123 | " # 4b) Valores de texto exactos\n",
124 | " if isinstance(alumno_val, str):\n",
125 | " if correct_val != alumno_val:\n",
126 | " msg = f\"\\nValor correcto: {correct_val}\\nValor alumno: {alumno_val}\\n\"\n",
127 | " raise AssertionError\n",
128 | " else:\n",
129 | " arr = np.array(alumno_val).flatten()\n",
130 | " msg = self.__test_string_array(arr, correct_val)\n",
131 | " np.testing.assert_equal(arr, correct_val)\n",
132 | "\n",
133 | " except AssertionError as info:\n",
134 | " # 5) Si algo falla, mostrar feedback y detener la evaluación\n",
135 | " self.__print_error_hint(enum, msg=msg, info=info)\n",
136 | " raise\n",
137 | "\n",
138 | " else:\n",
139 | " # 6) Si todo coincide, mostrar mensaje de éxito\n",
140 | " self.__print_correct(enum)\n"
141 | ]
142 | },
143 | {
144 | "cell_type": "markdown",
145 | "id": "1205dcfe-f720-4ada-ba3e-1ff6aaea95b2",
146 | "metadata": {},
147 | "source": [
148 | "## Ejemplos: evaluación de Estructuras de datos\n",
149 | "\n",
150 | "A continuación se presentan ejemplos para el tipo de Estructuras de datos\n",
151 | "\n",
152 | "---"
153 | ]
154 | },
155 | {
156 | "cell_type": "code",
157 | "execution_count": 19,
158 | "id": "5356bec2-e34a-4111-ad70-552a0faa4b53",
159 | "metadata": {},
160 | "outputs": [],
161 | "source": [
162 | "from evaluation import FileAnswer, Quiz\n",
163 | "import sympy as sy\n",
164 | "import numpy as np\n",
165 | "import pandas as pd"
166 | ]
167 | },
168 | {
169 | "cell_type": "code",
170 | "execution_count": 20,
171 | "id": "c99e22e4-8fe3-4146-9e5f-ab7a58b495ab",
172 | "metadata": {},
173 | "outputs": [
174 | {
175 | "name": "stdout",
176 | "output_type": "stream",
177 | "text": [
178 | "El directorio :/home/jovyan/.ans/MACTI_LIB/ ya existe\n",
179 | "Respuestas y retroalimentación almacenadas.\n"
180 | ]
181 | }
182 | ],
183 | "source": [
184 | "# --- 1) Registrar diccionarios de referencia ---\n",
185 | "file_answer = FileAnswer()\n",
186 | "\n",
187 | "# Ejercicio '5': diccionario numérico\n",
188 | "file_answer.write(\n",
189 | " '5',\n",
190 | " {1: 3.446, 2: 5.6423, 3: 2.234324},\n",
191 | " 'Checa las claves y valores numéricos.'\n",
192 | ")\n",
193 | "\n",
194 | "# Ejercicio '14': otro diccionario numérico\n",
195 | "file_answer.write(\n",
196 | " '14',\n",
197 | " {10: 0.123, 20: 0.456, 30: 0.789},\n",
198 | " 'Verifica tus valores flotantes.'\n",
199 | ")\n",
200 | "\n",
201 | "# Ejercicio '15': diccionario con claves de texto y valores numéricos\n",
202 | "file_answer.write(\n",
203 | " '15',\n",
204 | " {'k1': 1, 'k2': 2, 'k3': 3},\n",
205 | " 'Asegúrate de usar las mismas claves y valores numéricos.'\n",
206 | ")\n",
207 | "\n",
208 | "# Ejercicio '16': diccionario de texto (comparación exacta)\n",
209 | "file_answer.write(\n",
210 | " '16',\n",
211 | " {'a': 'hola', 'b': 'mundo'},\n",
212 | " 'Comprueba tus cadenas de texto.'\n",
213 | ")\n",
214 | "\n",
215 | "# Ejercicio '18': diccionario con listas numéricas como valores\n",
216 | "file_answer.write(\n",
217 | " '18',\n",
218 | " {1: [1, 2], 2: [3, 4]},\n",
219 | " 'Revisa cada lista de valores numéricos.'\n",
220 | ")\n",
221 | "\n",
222 | "# Exportar respuestas y feedback a Parquet\n",
223 | "file_answer.to_file('demo_dict_extended_01')\n"
224 | ]
225 | },
226 | {
227 | "cell_type": "code",
228 | "execution_count": 21,
229 | "id": "b8f16f02-9989-4e3c-a53b-4f9e04b70c08",
230 | "metadata": {},
231 | "outputs": [
232 | {
233 | "name": "stdout",
234 | "output_type": "stream",
235 | "text": [
236 | "\u001b[39m――――――――――――――――――――――――――――――――――――――――\n",
237 | "\u001b[32m5_val_2 | Tu resultado es correcto.\n",
238 | "\u001b[39m――――――――――――――――――――――――――――――――――――――――\n",
239 | "\u001b[39m――――――――――――――――――――――――――――――――――――――――\n",
240 | "\u001b[32m14_val_2 | Tu resultado es correcto.\n",
241 | "\u001b[39m――――――――――――――――――――――――――――――――――――――――\n",
242 | "\u001b[39m――――――――――――――――――――――――――――――――――――――――\n",
243 | "\u001b[32m15_val_2 | Tu resultado es correcto.\n",
244 | "\u001b[39m――――――――――――――――――――――――――――――――――――――――\n",
245 | "\u001b[39m――――――――――――――――――――――――――――――――――――――――\n",
246 | "\u001b[32m16_val_1 | Tu resultado es correcto.\n",
247 | "\u001b[39m――――――――――――――――――――――――――――――――――――――――\n",
248 | "\u001b[39m――――――――――――――――――――――――――――――――――――――――\n",
249 | "\u001b[31m18_val_0 | Ocurrió un error en tus cálculos.\n",
250 | "\u001b[39m――――――――――――――――――――――――――――――――――――――――\n",
251 | "\u001b[31mHint: \u001b[31mRevisa cada lista de valores numéricos.. \n",
252 | "18_val_0 Valor en el diccionario incorrecto.\n",
253 | "Longitud correcta=2\n",
254 | "Longitud de tu respuesta=1\n",
255 | "\n",
256 | "Not equal to tolerance rtol=1e-07, atol=0\n",
257 | "\n",
258 | "(shapes (1,), (2,) mismatch)\n",
259 | " ACTUAL: array([{1: [1, 2], 2: [3, 4]}], dtype=object)\n",
260 | " DESIRED: array([1, 2])\n"
261 | ]
262 | },
263 | {
264 | "ename": "AssertionError",
265 | "evalue": "",
266 | "output_type": "error",
267 | "traceback": [
268 | "\u001b[0;31m---------------------------------------------------------------------------\u001b[0m",
269 | "\u001b[0;31mAssertionError\u001b[0m Traceback (most recent call last)",
270 | "Cell \u001b[0;32mIn[21], line 18\u001b[0m\n\u001b[1;32m 15\u001b[0m quiz\u001b[38;5;241m.\u001b[39meval_dict(\u001b[38;5;124m'\u001b[39m\u001b[38;5;124m16\u001b[39m\u001b[38;5;124m'\u001b[39m, {\u001b[38;5;124m'\u001b[39m\u001b[38;5;124ma\u001b[39m\u001b[38;5;124m'\u001b[39m: \u001b[38;5;124m'\u001b[39m\u001b[38;5;124mhola\u001b[39m\u001b[38;5;124m'\u001b[39m, \u001b[38;5;124m'\u001b[39m\u001b[38;5;124mb\u001b[39m\u001b[38;5;124m'\u001b[39m: \u001b[38;5;124m'\u001b[39m\u001b[38;5;124mmundo\u001b[39m\u001b[38;5;124m'\u001b[39m}, numeric\u001b[38;5;241m=\u001b[39m\u001b[38;5;28;01mFalse\u001b[39;00m)\n\u001b[1;32m 17\u001b[0m \u001b[38;5;66;03m# Ejercicio '18': diccionario con listas numéricas como valores\u001b[39;00m\n\u001b[0;32m---> 18\u001b[0m \u001b[43mquiz\u001b[49m\u001b[38;5;241;43m.\u001b[39;49m\u001b[43meval_dict\u001b[49m\u001b[43m(\u001b[49m\u001b[38;5;124;43m'\u001b[39;49m\u001b[38;5;124;43m18\u001b[39;49m\u001b[38;5;124;43m'\u001b[39;49m\u001b[43m,\u001b[49m\u001b[43m \u001b[49m\u001b[43m{\u001b[49m\u001b[38;5;241;43m1\u001b[39;49m\u001b[43m:\u001b[49m\u001b[43m \u001b[49m\u001b[43m[\u001b[49m\u001b[38;5;241;43m1\u001b[39;49m\u001b[43m,\u001b[49m\u001b[43m \u001b[49m\u001b[38;5;241;43m2\u001b[39;49m\u001b[43m]\u001b[49m\u001b[43m,\u001b[49m\u001b[43m \u001b[49m\u001b[38;5;241;43m2\u001b[39;49m\u001b[43m:\u001b[49m\u001b[43m \u001b[49m\u001b[43m[\u001b[49m\u001b[38;5;241;43m3\u001b[39;49m\u001b[43m,\u001b[49m\u001b[43m \u001b[49m\u001b[38;5;241;43m4\u001b[39;49m\u001b[43m]\u001b[49m\u001b[43m}\u001b[49m\u001b[43m,\u001b[49m\u001b[43m \u001b[49m\u001b[43mnumeric\u001b[49m\u001b[38;5;241;43m=\u001b[39;49m\u001b[38;5;28;43;01mTrue\u001b[39;49;00m\u001b[43m)\u001b[49m\n",
271 | "File \u001b[0;32m~/MACTI_LIB/evaluation.py:712\u001b[0m, in \u001b[0;36mQuiz.eval_dict\u001b[0;34m(self, enum, ans, numeric)\u001b[0m\n\u001b[1;32m 709\u001b[0m \u001b[38;5;28mself\u001b[39m\u001b[38;5;241m.\u001b[39m__print_error_hint(enum, msg\u001b[38;5;241m=\u001b[39mmsg, info\u001b[38;5;241m=\u001b[39minfo)\n\u001b[1;32m 711\u001b[0m \u001b[38;5;66;03m# Se lanza la excepción para que sea detectada por NBGrader\u001b[39;00m\n\u001b[0;32m--> 712\u001b[0m \u001b[38;5;28;01mraise\u001b[39;00m \u001b[38;5;167;01mAssertionError\u001b[39;00m \u001b[38;5;28;01mfrom\u001b[39;00m \u001b[38;5;28;01mNone\u001b[39;00m\n\u001b[1;32m 714\u001b[0m \u001b[38;5;28;01melse\u001b[39;00m:\n\u001b[1;32m 715\u001b[0m \u001b[38;5;28mself\u001b[39m\u001b[38;5;241m.\u001b[39m__print_correct(enum)\n",
272 | "\u001b[0;31mAssertionError\u001b[0m: "
273 | ]
274 | }
275 | ],
276 | "source": [
277 | "# --- 2) Evaluar diccionarios con Quiz ---\n",
278 | "\n",
279 | "quiz = Quiz(qnum='demo_dict_extended_01', server='local')\n",
280 | "\n",
281 | "# Ejercicio '5': diccionario numérico simple\n",
282 | "quiz.eval_dict('5', {1: 3.446, 2: 5.6423, 3: 2.234324}, numeric=True)\n",
283 | "\n",
284 | "# Ejercicio '14': otro diccionario de flotantes\n",
285 | "quiz.eval_dict('14', {10: 0.123, 20: 0.456, 30: 0.789}, numeric=True)\n",
286 | "\n",
287 | "# Ejercicio '15': diccionario con claves de texto y valores numéricos\n",
288 | "quiz.eval_dict('15', {'k1': 1, 'k2': 2, 'k3': 3}, numeric=True)\n",
289 | "\n",
290 | "# Ejercicio '16': diccionario de cadenas (comparación exacta)\n",
291 | "quiz.eval_dict('16', {'a': 'hola', 'b': 'mundo'}, numeric=False)\n",
292 | "\n",
293 | "# Ejercicio '18': diccionario con listas numéricas como valores\n",
294 | "quiz.eval_dict('18', {1: [1, 2], 2: [3, 4]}, numeric=True)"
295 | ]
296 | },
297 | {
298 | "cell_type": "markdown",
299 | "id": "1509971e-a6fe-44bf-bcf0-2e8c553566ed",
300 | "metadata": {},
301 | "source": [
302 | "---\n",
303 | "## Conclusión: Evaluación de diccionarios\n",
304 | "\n",
305 | "La evaluación de diccionarios con **macti_lib** te permite:\n",
306 | "\n",
307 | "- **Definir de forma precisa** la “respuesta correcta” como un objeto `dict`, registrando tanto claves como valores. \n",
308 | "- **Desglosar automáticamente** el dict en sub-IDs (`_len`, `_key`, `_val_i`) para validar por separado la longitud, las claves y cada valor. \n",
309 | "- **Adaptarse a distintos tipos de datos**: con `numeric=True` compara valores numéricos (con tolerancia), y con `numeric=False` valida cadenas de texto de forma exacta. \n",
310 | "- **Ofrecer feedback inmediato**: muestra en verde las validaciones correctas y en rojo los errores, indicando si faltó una clave, cambió un valor o hubo un problema de formato. \n"
311 | ]
312 | }
313 | ],
314 | "metadata": {
315 | "kernelspec": {
316 | "display_name": "Python 3 (ipykernel)",
317 | "language": "python",
318 | "name": "python3"
319 | },
320 | "language_info": {
321 | "codemirror_mode": {
322 | "name": "ipython",
323 | "version": 3
324 | },
325 | "file_extension": ".py",
326 | "mimetype": "text/x-python",
327 | "name": "python",
328 | "nbconvert_exporter": "python",
329 | "pygments_lexer": "ipython3",
330 | "version": "3.11.6"
331 | }
332 | },
333 | "nbformat": 4,
334 | "nbformat_minor": 5
335 | }
336 |
--------------------------------------------------------------------------------
/Eval/1_Intro_macti_lib.ipynb:
--------------------------------------------------------------------------------
1 | {
2 | "cells": [
3 | {
4 | "cell_type": "markdown",
5 | "id": "bd3174b6-0983-48df-b5f9-113f1b57c5eb",
6 | "metadata": {},
7 | "source": [
8 | "
\n",
9 | " Introducción a la biblioteca macti_lib--eval\n",
10 | "
\n",
11 | "\n",
12 | "
macti_lib es una biblioteca diseñada para facilitar la **evaluación automática**, en particular **eval**, de ejercicios dentro de entornos como Google Colab o Jupyter Notebook. La biblioteca está compuesta principalmente por dos elementos clave —
FileAnswer y
Quiz— con los cuales podemos capturar las respuestas de los estudiantes, almacenarlas en archivos Parquet y dar retroalimentación inmediata, detallada y configurable, todo ello sin salir del entorno.\n",
13 | "\n",
14 | "## ¿Para qué sirve?\n",
15 | "\n",
16 | "- Automatizar la evaluación de tareas prácticas \n",
17 | "- Dar retroalimentación personalizada \n",
18 | "- Aumentar la objetividad y eficiencia en la revisión \n",
19 | "- Permitir múltiples tipos de respuestas (desde texto hasta estructuras complejas)\n",
20 | "\n",
21 | "## ¿Qué tipos de evaluación soporta?\n",
22 | "\n",
23 | "| Tipo | Método | Ejemplo |\n",
24 | "|-------------------------|---------------------|--------------------------------------|\n",
25 | "| Opción múltiple | `eval_option()` | `'a'`, `'b'`, `'c'`, ... |\n",
26 | "| Expresiones simbólicas | `eval_expression()` | `x**2`, `sin(x)` |\n",
27 | "| Valores numéricos | `eval_numeric()` | `3.14`, `[1, 2, 3]`, `2 + 3j` |\n",
28 | "| Estructuras de datos | `eval_datastruct()` | `['a', 'b']`, `('x', 'y')`, `{1,2}` |\n",
29 | "| Diccionarios | `eval_dict()` | `{1: 2.5}`, `{'k1': 'rojo'}` |\n",
30 | "\n",
31 | "Durante este notebook conocerás cómo funciona internamente la biblioteca, con breves ejemplos de su uso.\n"
32 | ]
33 | },
34 | {
35 | "cell_type": "markdown",
36 | "id": "4478e4ee-8200-48de-bd36-f0bbf59f8261",
37 | "metadata": {},
38 | "source": [
39 | "
\n",
40 | "La biblioteca macti_lib está compuesta por dos clases principales: FileAnswer y Quiz, cada una con sus características particulares que se describen a continuación:\n",
41 | "
\n",
42 | "\n",
43 | "
\n",
44 | " - \n",
45 | " La clase FileAnswer se encarga de escribir respuestas y comentarios en memoria, para luego almacenarlas en archivos de texto.\n",
46 | "
\n",
47 | " - Almacena respuestas numéricas, simbólicas, listas, diccionarios y más.
\n",
48 | " - Convierte arreglos
numpy a vectores 1D y descompone diccionarios en longitudes, claves y valores. \n",
49 | " - Genera dos archivos por “quiz”: uno con respuestas (
.__ans_qnum) y otro con retroalimentación (.__fee_qnum). \n",
50 | "
\n",
51 | " \n",
52 | "\n",
53 | " - \n",
54 | " La clase Quiz es responsable de leer las respuestas almacenadas y de evaluar las respuestas del alumno.\n",
55 | " Ofrece métodos para distintos tipos de preguntas:\n",
56 | "
\n",
57 | " eval_option: opción múltiple, compara cadenas. \n",
58 | " eval_expression: expresiones simbólicas con sympy. \n",
59 | " eval_numeric: números y arreglos numéricos con tolerancia. \n",
60 | " eval_datastruct: listas y tuplas (con o sin orden). \n",
61 | " eval_dict: validación de diccionarios (tamaños, claves y valores). \n",
62 | "
\n",
63 | " Además, utiliza colorama para colorear la salida (verde para correcto, rojo para errores) y ofrece distintos niveles de verbosidad.\n",
64 | " \n",
65 | "
\n"
66 | ]
67 | },
68 | {
69 | "cell_type": "markdown",
70 | "id": "ce5b3c68-a1f2-449c-9750-8cc136fc5d5f",
71 | "metadata": {},
72 | "source": [
73 | "
\n",
74 | " ¿Cómo empezar?\n",
75 | "
\n",
76 | "\n",
77 | "
\n",
78 | " - \n",
79 | " Importa
evaluation desde el repositorio macti_lib.\n",
80 | " \n",
81 | " - \n",
82 | " En nuestro notebook, creamos un objeto
FileAnswer(). \n",
83 | " Utiliza el método write(enum, respuesta, feedback) para almacenar cada respuesta junto con su retroalimentación. \n",
84 | " Al finalizar, se guarda todo en archivos parquet usando el método to_file(<número_del_quiz>).\n",
85 | " \n",
86 | " - \n",
87 | " Posteriormente, creamos un objeto
Quiz(<número_del_quiz>) para cargar las respuestas almacenadas. \n",
88 | " Utilizamos los métodos eval_* (como eval_option, eval_expression, entre otros) para evaluar las respuestas de los estudiantes.\n",
89 | " \n",
90 | " - \n",
91 | " Ajustamos la propiedad
verb (niveles 0, 1 o 2) para definir el nivel de detalle en la retroalimentación proporcionada a los alumnos:\n",
92 | " \n",
93 | " - 0: Solo indica si la respuesta es correcta o incorrecta.
\n",
94 | " - 1: Muestra comentarios adicionales para ayudar al alumno.
\n",
95 | " - 2: Proporciona información detallada sobre el error o la respuesta correcta.
\n",
96 | "
\n",
97 | " \n",
98 | "
\n",
99 | "\n",
100 | "
\n",
101 | " Con macti_lib, la evaluación en notebooks se vuelve más sencilla y práctica para poder realizar evaluaciones y ejercicios de una manera más eficiente.\n",
102 | "
\n",
103 | "\n",
104 | "---\n"
105 | ]
106 | },
107 | {
108 | "cell_type": "markdown",
109 | "id": "83db462a-bcba-4b6e-b184-4bef67902e21",
110 | "metadata": {},
111 | "source": [
112 | "## Flujo de trabajo general para hacer evaluaciones\n",
113 | "\n",
114 | "Para aprovechar las funciones de evaluación automática, es importante conocer el flujo de trabajo y los pasos necesarios para llevar a cabo la evaluación de manera exitosa.\n",
115 | "\n",
116 | "A continuación se muestran los dos pasos básicos para usar **macti_lib** en un notebook:\n",
117 | "\n",
118 | "--- \n",
119 | "\n",
120 | "\n",
121 | "1. **Registrar las respuestas correctas** \n",
122 | "2. **Evaluar la respuesta del estudiante**\n",
123 | "\n",
124 | "### 1. Registrar respuestas correctas\n",
125 | "\n",
126 | "```python\n",
127 | "from macti.eval.file_answer import FileAnswer\n",
128 | "\n",
129 | "# 1.1 Inicializamos FileAnswer para almacenar:\n",
130 | "# - enum: identificador del ejercicio\n",
131 | "# - ans : respuesta correcta\n",
132 | "# - feed: retroalimentación si el estudiante falla\n",
133 | "file_answer = FileAnswer()\n",
134 | "\n",
135 | "# 1.2 Almacenamos el ejercicio y la respuesta correcta\n",
136 | "# file_answer.write(enum: str, ans: Any, feed: str)\n",
137 | "# • enum (str): identificador del ejercicio (p. ej. '1', '2', …)\n",
138 | "# • ans (Any): respuesta correcta (p. ej. 'b', número, lista, etc.)\n",
139 | "# • feed (str): mensaje de ayuda en caso de respuesta incorrecta\n",
140 | "file_answer.write(\n",
141 | " '1', # enum: identificador del ejercicio\n",
142 | " 'b', # ans : respuesta correcta\n",
143 | " 'Recuerda revisar las opciones...'# feed: sugerencia si el alumno falla\n",
144 | ")\n",
145 | "\n",
146 | "# 1.3 – Exportar todo a disco en formato Parquet\n",
147 | "# • .ans/
/.__ans_quiz01 (archivo de respuestas)\n",
148 | "# • .ans//.__fee_quiz01 (archivo de feedback)\n",
149 | "file_answer.to_file('quiz01')"
150 | ]
151 | },
152 | {
153 | "cell_type": "markdown",
154 | "id": "4455d0da-2cef-492e-b56b-c7e867798900",
155 | "metadata": {},
156 | "source": [
157 | "### 2. Evaluar la respuesta del estudiante\n",
158 | "\n",
159 | "Para comprobar las respuestas con **macti_lib**, instanciamos `Quiz` y usamos el método `eval_option`:\n",
160 | "\n",
161 | "```python\n",
162 | "from macti.eval.quiz import Quiz\n",
163 | "\n",
164 | "# 2.1 Inicializar Quiz:\n",
165 | "# - qnum (str): debe coincidir con el valor de file_answer.to_file('quiz01')\n",
166 | "# - server (str): ubicación de los archivos Parquet ('local' o 'hub')\n",
167 | "quiz = Quiz(qnum='quiz01', server='local')\n",
168 | "\n",
169 | "# 2.2 Evaluar la respuesta del alumno:\n",
170 | "# - enum (str): identificador del ejercicio ('1')\n",
171 | "# - ans (str): respuesta proporcionada por el estudiante ('b')\n",
172 | "quiz.eval_option('1', 'b')\n"
173 | ]
174 | },
175 | {
176 | "cell_type": "markdown",
177 | "id": "1d14066e-8fe5-4383-866d-962f8f461031",
178 | "metadata": {},
179 | "source": [
180 | "---\n",
181 | "## Ejemplo práctico de uso de **macti_lib**\n",
182 | "\n",
183 | "A continuación, se explica paso a paso en qué consiste este fragmento de código y cómo aprovecha la biblioteca:\n",
184 | "\n"
185 | ]
186 | },
187 | {
188 | "cell_type": "code",
189 | "execution_count": 14,
190 | "id": "57153ec5-99b6-4cef-9cf5-5abc0d64b83b",
191 | "metadata": {},
192 | "outputs": [],
193 | "source": [
194 | "# Importamos los módulos necesarios para poder hacer uso de la biblioteca de MACTI\n",
195 | "from macti.eval import FileAnswer, Quiz \n",
196 | "import sympy as sy\n",
197 | "import numpy as np\n",
198 | "import pandas as pd"
199 | ]
200 | },
201 | {
202 | "cell_type": "code",
203 | "execution_count": 15,
204 | "id": "69511362-20a6-4f27-a15a-50d9416ffb53",
205 | "metadata": {},
206 | "outputs": [
207 | {
208 | "name": "stdout",
209 | "output_type": "stream",
210 | "text": [
211 | "El directorio :/home/jovyan/MACTI_LIB/.ans/Eval/ ya existe\n",
212 | "Respuestas y retroalimentación almacenadas.\n"
213 | ]
214 | }
215 | ],
216 | "source": [
217 | "# 1) Inicializar el FileAnswer (recolector de respuestas) \n",
218 | "file_answer = FileAnswer()\n",
219 | "\n",
220 | "# 2) Registrar una pregunta de opción múltiple:\n",
221 | "# • '1' → identificador del ejercicio.\n",
222 | "# • 'c' → respuesta correcta.\n",
223 | "# • 'Revisa tus opciones.' → retroalimentación en caso de error.\n",
224 | "file_answer.write('1', 'c', 'Revisa tus opciones.')\n",
225 | "\n",
226 | "# 3) Registrar una pregunta de expresión simbólica:\n",
227 | "# • Definimos el símbolo x con SymPy.\n",
228 | "# • Guardamos \"x**2\" como cadena para evaluación simbólica.\n",
229 | "x = sy.Symbol('x')\n",
230 | "file_answer.write('2', str(x**2), 'Deriva correctamente.')\n",
231 | "\n",
232 | "# 4) Registrar una pregunta de valor numérico:\n",
233 | "# • '3' → identificador del ejercicio.\n",
234 | "# • 3.1416 → valor correcto.\n",
235 | "# • 'Calcula con mayor precisión.' → retroalimentación si la aproximación es imprecisa.\n",
236 | "file_answer.write('3', 3.1416, 'Calcula con mayor precisión.')\n",
237 | "\n",
238 | "# 5) Registrar una pregunta de estructura de datos (lista):\n",
239 | "# • '4' → identificador del ejercicio.\n",
240 | "# • ['a', 'b', 'c'] → lista esperada (el orden importa).\n",
241 | "# • 'Revisa el orden.' → retroalimentación si el orden difiere.\n",
242 | "file_answer.write('4', ['a', 'b', 'c'], 'Revisa el orden.')\n",
243 | "\n",
244 | "# 6) Registrar una pregunta de diccionario:\n",
245 | "# • '5' → identificador del ejercicio.\n",
246 | "# • {1: 2.0, 2: 4.0} → diccionario con claves y valores correctos.\n",
247 | "# • 'Revisa claves y valores.' → retroalimentación si falta o está mal algún par.\n",
248 | "file_answer.write('5', {1: 2.0, 2: 4.0}, 'Revisa claves y valores.')\n",
249 | "\n",
250 | "# 7) Exportar todas las respuestas y retroalimentación a un archivo de texto:\n",
251 | "# • crea \".ans//.__ans_intro_demo\" y \".ans//.__fee_intro_demo\".\n",
252 | "file_answer.to_file('intro_demo')\n"
253 | ]
254 | },
255 | {
256 | "cell_type": "code",
257 | "execution_count": 16,
258 | "id": "5bc6eef7-fdb5-4463-98ea-486a24fae2f3",
259 | "metadata": {},
260 | "outputs": [
261 | {
262 | "name": "stdout",
263 | "output_type": "stream",
264 | "text": [
265 | "\u001b[39m――――――――――――――――――――――――――――――――――――――――\n",
266 | "\u001b[32m1 | Tu respuesta: \u001b[39mc\u001b[32m, es correcta.\n",
267 | "\u001b[39m――――――――――――――――――――――――――――――――――――――――\n",
268 | "\u001b[39m――――――――――――――――――――――――――――――――――――――――\n",
269 | "\u001b[32m2 | Tu respuesta:\n"
270 | ]
271 | },
272 | {
273 | "data": {
274 | "text/latex": [
275 | "$\\displaystyle x^{2}$"
276 | ],
277 | "text/plain": [
278 | "x**2"
279 | ]
280 | },
281 | "metadata": {},
282 | "output_type": "display_data"
283 | },
284 | {
285 | "name": "stdout",
286 | "output_type": "stream",
287 | "text": [
288 | "\u001b[32mes correcta.\n",
289 | "\u001b[39m――――――――――――――――――――――――――――――――――――――――\n",
290 | "\u001b[39m――――――――――――――――――――――――――――――――――――――――\n",
291 | "\u001b[32m3 | Tu resultado es correcto.\n",
292 | "\u001b[39m――――――――――――――――――――――――――――――――――――――――\n",
293 | "\u001b[39m――――――――――――――――――――――――――――――――――――――――\n",
294 | "\u001b[32m4 | Tu resultado es correcto.\n",
295 | "\u001b[39m――――――――――――――――――――――――――――――――――――――――\n",
296 | "\u001b[39m――――――――――――――――――――――――――――――――――――――――\n",
297 | "\u001b[32m5_val_1 | Tu resultado es correcto.\n",
298 | "\u001b[39m――――――――――――――――――――――――――――――――――――――――\n"
299 | ]
300 | }
301 | ],
302 | "source": [
303 | "# 2) Evaluar las respuestas con Quiz (suponiendo que Quiz y sympy ya estén importados)\n",
304 | "\n",
305 | "# 2.1 Inicializar Quiz con los archivos generados por FileAnswer\n",
306 | "quiz = Quiz(qnum='intro_demo', server='local') # Carga respuestas y retroalimentación desde Parquet\n",
307 | "\n",
308 | "# 2.2 Opción múltiple (ejercicio '1')\n",
309 | "quiz.eval_option('1', 'c')\n",
310 | "# • Compara la respuesta del alumno ('c') con la correcta registrada.\n",
311 | "\n",
312 | "# 2.3 Expresión simbólica (ejercicio '2')\n",
313 | "quiz.eval_expression('2', sy.sympify('x**2'))\n",
314 | "# • Convierte 'x**2' a expresión de SymPy y la compara simbólicamente.\n",
315 | "\n",
316 | "# 2.4 Valor numérico (ejercicio '3')\n",
317 | "quiz.eval_numeric('3', 3.1416)\n",
318 | "# • Verifica que el valor entregado esté dentro de la tolerancia establecida.\n",
319 | "\n",
320 | "# 2.5 Estructura de datos: lista ordenada (ejercicio '4')\n",
321 | "quiz.eval_datastruct('4', ['a', 'b', 'c'])\n",
322 | "# • Comprueba que la lista coincida exactamente y en el orden correcto.\n",
323 | "\n",
324 | "# 2.6 Diccionario numérico (ejercicio '5')\n",
325 | "quiz.eval_dict('5', {1: 2.0, 2: 4.0}, numeric=True)\n",
326 | "# • Valida que las claves y valores coincidan con tolerancia numérica.\n"
327 | ]
328 | },
329 | {
330 | "cell_type": "markdown",
331 | "id": "b80b7522-3ca2-4373-b140-493056522203",
332 | "metadata": {},
333 | "source": [
334 | "## Conclusión\n",
335 | "\n",
336 | "Con estos pasos —registrar las respuestas correctas con `FileAnswer`, exportarlas a un archivo de texto y luego evaluarlas con `Quiz`— es posible automatizar el proceso de calificación en notebooks. La biblioteca de **macti_lib** cuenta con la capacidad de manejar diferentes tipos de preguntas (opción múltiple, expresiones simbólicas, valores numéricos, estructuras de datos y diccionarios), y ofrece retroalimentación directa al estudiante, ahorrando tiempo y asegurando consistencia en la evaluación.\n"
337 | ]
338 | }
339 | ],
340 | "metadata": {
341 | "kernelspec": {
342 | "display_name": "Python 3 (ipykernel)",
343 | "language": "python",
344 | "name": "python3"
345 | },
346 | "language_info": {
347 | "codemirror_mode": {
348 | "name": "ipython",
349 | "version": 3
350 | },
351 | "file_extension": ".py",
352 | "mimetype": "text/x-python",
353 | "name": "python",
354 | "nbconvert_exporter": "python",
355 | "pygments_lexer": "ipython3",
356 | "version": "3.11.6"
357 | }
358 | },
359 | "nbformat": 4,
360 | "nbformat_minor": 5
361 | }
362 |
--------------------------------------------------------------------------------
/Eval/.ipynb_checkpoints/1_Intro_macti_lib-checkpoint.ipynb:
--------------------------------------------------------------------------------
1 | {
2 | "cells": [
3 | {
4 | "cell_type": "markdown",
5 | "id": "bd3174b6-0983-48df-b5f9-113f1b57c5eb",
6 | "metadata": {},
7 | "source": [
8 | "\n",
9 | " Introducción a la biblioteca macti_lib--eval\n",
10 | "
\n",
11 | "\n",
12 | "macti_lib es una biblioteca diseñada para facilitar la **evaluación automática**, en particular **eval**, de ejercicios dentro de entornos como Google Colab o Jupyter Notebook. La biblioteca está compuesta principalmente por dos elementos clave —FileAnswer y Quiz— con los cuales podemos capturar las respuestas de los estudiantes, almacenarlas en archivos Parquet y dar retroalimentación inmediata, detallada y configurable, todo ello sin salir del entorno.\n",
13 | "\n",
14 | "## ¿Para qué sirve?\n",
15 | "\n",
16 | "- Automatizar la evaluación de tareas prácticas \n",
17 | "- Dar retroalimentación personalizada \n",
18 | "- Aumentar la objetividad y eficiencia en la revisión \n",
19 | "- Permitir múltiples tipos de respuestas (desde texto hasta estructuras complejas)\n",
20 | "\n",
21 | "## ¿Qué tipos de evaluación soporta?\n",
22 | "\n",
23 | "| Tipo | Método | Ejemplo |\n",
24 | "|-------------------------|---------------------|--------------------------------------|\n",
25 | "| Opción múltiple | `eval_option()` | `'a'`, `'b'`, `'c'`, ... |\n",
26 | "| Expresiones simbólicas | `eval_expression()` | `x**2`, `sin(x)` |\n",
27 | "| Valores numéricos | `eval_numeric()` | `3.14`, `[1, 2, 3]`, `2 + 3j` |\n",
28 | "| Estructuras de datos | `eval_datastruct()` | `['a', 'b']`, `('x', 'y')`, `{1,2}` |\n",
29 | "| Diccionarios | `eval_dict()` | `{1: 2.5}`, `{'k1': 'rojo'}` |\n",
30 | "\n",
31 | "Durante este notebook conocerás cómo funciona internamente la biblioteca, con breves ejemplos de su uso.\n"
32 | ]
33 | },
34 | {
35 | "cell_type": "markdown",
36 | "id": "4478e4ee-8200-48de-bd36-f0bbf59f8261",
37 | "metadata": {},
38 | "source": [
39 | "\n",
40 | "La biblioteca macti_lib está compuesta por dos clases principales: FileAnswer y Quiz, cada una con sus características particulares que se describen a continuación:\n",
41 | "
\n",
42 | "\n",
43 | "\n",
44 | " - \n",
45 | " La clase FileAnswer se encarga de escribir respuestas y comentarios en memoria, para luego almacenarlas en archivos de texto.\n",
46 | "
\n",
47 | " - Almacena respuestas numéricas, simbólicas, listas, diccionarios y más.
\n",
48 | " - Convierte arreglos
numpy a vectores 1D y descompone diccionarios en longitudes, claves y valores. \n",
49 | " - Genera dos archivos por “quiz”: uno con respuestas (
.__ans_qnum) y otro con retroalimentación (.__fee_qnum). \n",
50 | "
\n",
51 | " \n",
52 | "\n",
53 | " - \n",
54 | " La clase Quiz es responsable de leer las respuestas almacenadas y de evaluar las respuestas del alumno.\n",
55 | " Ofrece métodos para distintos tipos de preguntas:\n",
56 | "
\n",
57 | " eval_option: opción múltiple, compara cadenas. \n",
58 | " eval_expression: expresiones simbólicas con sympy. \n",
59 | " eval_numeric: números y arreglos numéricos con tolerancia. \n",
60 | " eval_datastruct: listas y tuplas (con o sin orden). \n",
61 | " eval_dict: validación de diccionarios (tamaños, claves y valores). \n",
62 | "
\n",
63 | " Además, utiliza colorama para colorear la salida (verde para correcto, rojo para errores) y ofrece distintos niveles de verbosidad.\n",
64 | " \n",
65 | "
\n"
66 | ]
67 | },
68 | {
69 | "cell_type": "markdown",
70 | "id": "ce5b3c68-a1f2-449c-9750-8cc136fc5d5f",
71 | "metadata": {},
72 | "source": [
73 | "\n",
74 | " ¿Cómo empezar?\n",
75 | "
\n",
76 | "\n",
77 | "\n",
78 | " - \n",
79 | " Importa
evaluation desde el repositorio macti_lib.\n",
80 | " \n",
81 | " - \n",
82 | " En nuestro notebook, creamos un objeto
FileAnswer(). \n",
83 | " Utiliza el método write(enum, respuesta, feedback) para almacenar cada respuesta junto con su retroalimentación. \n",
84 | " Al finalizar, se guarda todo en archivos parquet usando el método to_file(<número_del_quiz>).\n",
85 | " \n",
86 | " - \n",
87 | " Posteriormente, creamos un objeto
Quiz(<número_del_quiz>) para cargar las respuestas almacenadas. \n",
88 | " Utilizamos los métodos eval_* (como eval_option, eval_expression, entre otros) para evaluar las respuestas de los estudiantes.\n",
89 | " \n",
90 | " - \n",
91 | " Ajustamos la propiedad
verb (niveles 0, 1 o 2) para definir el nivel de detalle en la retroalimentación proporcionada a los alumnos:\n",
92 | " \n",
93 | " - 0: Solo indica si la respuesta es correcta o incorrecta.
\n",
94 | " - 1: Muestra comentarios adicionales para ayudar al alumno.
\n",
95 | " - 2: Proporciona información detallada sobre el error o la respuesta correcta.
\n",
96 | "
\n",
97 | " \n",
98 | "
\n",
99 | "\n",
100 | "\n",
101 | " Con macti_lib, la evaluación en notebooks se vuelve más sencilla y práctica para poder realizar evaluaciones y ejercicios de una manera más eficiente.\n",
102 | "
\n",
103 | "\n",
104 | "---\n"
105 | ]
106 | },
107 | {
108 | "cell_type": "markdown",
109 | "id": "83db462a-bcba-4b6e-b184-4bef67902e21",
110 | "metadata": {},
111 | "source": [
112 | "## Flujo de trabajo general para hacer evaluaciones\n",
113 | "\n",
114 | "Para aprovechar las funciones de evaluación automática, es importante conocer el flujo de trabajo y los pasos necesarios para llevar a cabo la evaluación de manera exitosa.\n",
115 | "\n",
116 | "A continuación se muestran los dos pasos básicos para usar **macti_lib** en un notebook:\n",
117 | "\n",
118 | "--- \n",
119 | "\n",
120 | "\n",
121 | "1. **Registrar las respuestas correctas** \n",
122 | "2. **Evaluar la respuesta del estudiante**\n",
123 | "\n",
124 | "### 1. Registrar respuestas correctas\n",
125 | "\n",
126 | "```python\n",
127 | "from macti.eval.file_answer import FileAnswer\n",
128 | "\n",
129 | "# 1.1 Inicializamos FileAnswer para almacenar:\n",
130 | "# - enum: identificador del ejercicio\n",
131 | "# - ans : respuesta correcta\n",
132 | "# - feed: retroalimentación si el estudiante falla\n",
133 | "file_answer = FileAnswer()\n",
134 | "\n",
135 | "# 1.2 Almacenamos el ejercicio y la respuesta correcta\n",
136 | "# file_answer.write(enum: str, ans: Any, feed: str)\n",
137 | "# • enum (str): identificador del ejercicio (p. ej. '1', '2', …)\n",
138 | "# • ans (Any): respuesta correcta (p. ej. 'b', número, lista, etc.)\n",
139 | "# • feed (str): mensaje de ayuda en caso de respuesta incorrecta\n",
140 | "file_answer.write(\n",
141 | " '1', # enum: identificador del ejercicio\n",
142 | " 'b', # ans : respuesta correcta\n",
143 | " 'Recuerda revisar las opciones...'# feed: sugerencia si el alumno falla\n",
144 | ")\n",
145 | "\n",
146 | "# 1.3 – Exportar todo a disco en formato Parquet\n",
147 | "# • .ans//.__ans_quiz01 (archivo de respuestas)\n",
148 | "# • .ans//.__fee_quiz01 (archivo de feedback)\n",
149 | "file_answer.to_file('quiz01')"
150 | ]
151 | },
152 | {
153 | "cell_type": "markdown",
154 | "id": "4455d0da-2cef-492e-b56b-c7e867798900",
155 | "metadata": {},
156 | "source": [
157 | "### 2. Evaluar la respuesta del estudiante\n",
158 | "\n",
159 | "Para comprobar las respuestas con **macti_lib**, instanciamos `Quiz` y usamos el método `eval_option`:\n",
160 | "\n",
161 | "```python\n",
162 | "from macti.eval.quiz import Quiz\n",
163 | "\n",
164 | "# 2.1 Inicializar Quiz:\n",
165 | "# - qnum (str): debe coincidir con el valor de file_answer.to_file('quiz01')\n",
166 | "# - server (str): ubicación de los archivos Parquet ('local' o 'hub')\n",
167 | "quiz = Quiz(qnum='quiz01', server='local')\n",
168 | "\n",
169 | "# 2.2 Evaluar la respuesta del alumno:\n",
170 | "# - enum (str): identificador del ejercicio ('1')\n",
171 | "# - ans (str): respuesta proporcionada por el estudiante ('b')\n",
172 | "quiz.eval_option('1', 'b')\n"
173 | ]
174 | },
175 | {
176 | "cell_type": "markdown",
177 | "id": "1d14066e-8fe5-4383-866d-962f8f461031",
178 | "metadata": {},
179 | "source": [
180 | "---\n",
181 | "## Ejemplo práctico de uso de **macti_lib**\n",
182 | "\n",
183 | "A continuación, se explica paso a paso en qué consiste este fragmento de código y cómo aprovecha la biblioteca:\n",
184 | "\n"
185 | ]
186 | },
187 | {
188 | "cell_type": "code",
189 | "execution_count": 14,
190 | "id": "57153ec5-99b6-4cef-9cf5-5abc0d64b83b",
191 | "metadata": {},
192 | "outputs": [],
193 | "source": [
194 | "# Importamos los módulos necesarios para poder hacer uso de la biblioteca de MACTI\n",
195 | "from macti.eval import FileAnswer, Quiz \n",
196 | "import sympy as sy\n",
197 | "import numpy as np\n",
198 | "import pandas as pd"
199 | ]
200 | },
201 | {
202 | "cell_type": "code",
203 | "execution_count": 15,
204 | "id": "69511362-20a6-4f27-a15a-50d9416ffb53",
205 | "metadata": {},
206 | "outputs": [
207 | {
208 | "name": "stdout",
209 | "output_type": "stream",
210 | "text": [
211 | "El directorio :/home/jovyan/MACTI_LIB/.ans/Eval/ ya existe\n",
212 | "Respuestas y retroalimentación almacenadas.\n"
213 | ]
214 | }
215 | ],
216 | "source": [
217 | "# 1) Inicializar el FileAnswer (recolector de respuestas) \n",
218 | "file_answer = FileAnswer()\n",
219 | "\n",
220 | "# 2) Registrar una pregunta de opción múltiple:\n",
221 | "# • '1' → identificador del ejercicio.\n",
222 | "# • 'c' → respuesta correcta.\n",
223 | "# • 'Revisa tus opciones.' → retroalimentación en caso de error.\n",
224 | "file_answer.write('1', 'c', 'Revisa tus opciones.')\n",
225 | "\n",
226 | "# 3) Registrar una pregunta de expresión simbólica:\n",
227 | "# • Definimos el símbolo x con SymPy.\n",
228 | "# • Guardamos \"x**2\" como cadena para evaluación simbólica.\n",
229 | "x = sy.Symbol('x')\n",
230 | "file_answer.write('2', str(x**2), 'Deriva correctamente.')\n",
231 | "\n",
232 | "# 4) Registrar una pregunta de valor numérico:\n",
233 | "# • '3' → identificador del ejercicio.\n",
234 | "# • 3.1416 → valor correcto.\n",
235 | "# • 'Calcula con mayor precisión.' → retroalimentación si la aproximación es imprecisa.\n",
236 | "file_answer.write('3', 3.1416, 'Calcula con mayor precisión.')\n",
237 | "\n",
238 | "# 5) Registrar una pregunta de estructura de datos (lista):\n",
239 | "# • '4' → identificador del ejercicio.\n",
240 | "# • ['a', 'b', 'c'] → lista esperada (el orden importa).\n",
241 | "# • 'Revisa el orden.' → retroalimentación si el orden difiere.\n",
242 | "file_answer.write('4', ['a', 'b', 'c'], 'Revisa el orden.')\n",
243 | "\n",
244 | "# 6) Registrar una pregunta de diccionario:\n",
245 | "# • '5' → identificador del ejercicio.\n",
246 | "# • {1: 2.0, 2: 4.0} → diccionario con claves y valores correctos.\n",
247 | "# • 'Revisa claves y valores.' → retroalimentación si falta o está mal algún par.\n",
248 | "file_answer.write('5', {1: 2.0, 2: 4.0}, 'Revisa claves y valores.')\n",
249 | "\n",
250 | "# 7) Exportar todas las respuestas y retroalimentación a un archivo de texto:\n",
251 | "# • crea \".ans//.__ans_intro_demo\" y \".ans//.__fee_intro_demo\".\n",
252 | "file_answer.to_file('intro_demo')\n"
253 | ]
254 | },
255 | {
256 | "cell_type": "code",
257 | "execution_count": 16,
258 | "id": "5bc6eef7-fdb5-4463-98ea-486a24fae2f3",
259 | "metadata": {},
260 | "outputs": [
261 | {
262 | "name": "stdout",
263 | "output_type": "stream",
264 | "text": [
265 | "\u001b[39m――――――――――――――――――――――――――――――――――――――――\n",
266 | "\u001b[32m1 | Tu respuesta: \u001b[39mc\u001b[32m, es correcta.\n",
267 | "\u001b[39m――――――――――――――――――――――――――――――――――――――――\n",
268 | "\u001b[39m――――――――――――――――――――――――――――――――――――――――\n",
269 | "\u001b[32m2 | Tu respuesta:\n"
270 | ]
271 | },
272 | {
273 | "data": {
274 | "text/latex": [
275 | "$\\displaystyle x^{2}$"
276 | ],
277 | "text/plain": [
278 | "x**2"
279 | ]
280 | },
281 | "metadata": {},
282 | "output_type": "display_data"
283 | },
284 | {
285 | "name": "stdout",
286 | "output_type": "stream",
287 | "text": [
288 | "\u001b[32mes correcta.\n",
289 | "\u001b[39m――――――――――――――――――――――――――――――――――――――――\n",
290 | "\u001b[39m――――――――――――――――――――――――――――――――――――――――\n",
291 | "\u001b[32m3 | Tu resultado es correcto.\n",
292 | "\u001b[39m――――――――――――――――――――――――――――――――――――――――\n",
293 | "\u001b[39m――――――――――――――――――――――――――――――――――――――――\n",
294 | "\u001b[32m4 | Tu resultado es correcto.\n",
295 | "\u001b[39m――――――――――――――――――――――――――――――――――――――――\n",
296 | "\u001b[39m――――――――――――――――――――――――――――――――――――――――\n",
297 | "\u001b[32m5_val_1 | Tu resultado es correcto.\n",
298 | "\u001b[39m――――――――――――――――――――――――――――――――――――――――\n"
299 | ]
300 | }
301 | ],
302 | "source": [
303 | "# 2) Evaluar las respuestas con Quiz (suponiendo que Quiz y sympy ya estén importados)\n",
304 | "\n",
305 | "# 2.1 Inicializar Quiz con los archivos generados por FileAnswer\n",
306 | "quiz = Quiz(qnum='intro_demo', server='local') # Carga respuestas y retroalimentación desde Parquet\n",
307 | "\n",
308 | "# 2.2 Opción múltiple (ejercicio '1')\n",
309 | "quiz.eval_option('1', 'c')\n",
310 | "# • Compara la respuesta del alumno ('c') con la correcta registrada.\n",
311 | "\n",
312 | "# 2.3 Expresión simbólica (ejercicio '2')\n",
313 | "quiz.eval_expression('2', sy.sympify('x**2'))\n",
314 | "# • Convierte 'x**2' a expresión de SymPy y la compara simbólicamente.\n",
315 | "\n",
316 | "# 2.4 Valor numérico (ejercicio '3')\n",
317 | "quiz.eval_numeric('3', 3.1416)\n",
318 | "# • Verifica que el valor entregado esté dentro de la tolerancia establecida.\n",
319 | "\n",
320 | "# 2.5 Estructura de datos: lista ordenada (ejercicio '4')\n",
321 | "quiz.eval_datastruct('4', ['a', 'b', 'c'])\n",
322 | "# • Comprueba que la lista coincida exactamente y en el orden correcto.\n",
323 | "\n",
324 | "# 2.6 Diccionario numérico (ejercicio '5')\n",
325 | "quiz.eval_dict('5', {1: 2.0, 2: 4.0}, numeric=True)\n",
326 | "# • Valida que las claves y valores coincidan con tolerancia numérica.\n"
327 | ]
328 | },
329 | {
330 | "cell_type": "markdown",
331 | "id": "b80b7522-3ca2-4373-b140-493056522203",
332 | "metadata": {},
333 | "source": [
334 | "## Conclusión\n",
335 | "\n",
336 | "Con estos pasos —registrar las respuestas correctas con `FileAnswer`, exportarlas a un archivo de texto y luego evaluarlas con `Quiz`— es posible automatizar el proceso de calificación en notebooks. La biblioteca de **macti_lib** cuenta con la capacidad de manejar diferentes tipos de preguntas (opción múltiple, expresiones simbólicas, valores numéricos, estructuras de datos y diccionarios), y ofrece retroalimentación directa al estudiante, ahorrando tiempo y asegurando consistencia en la evaluación.\n"
337 | ]
338 | }
339 | ],
340 | "metadata": {
341 | "kernelspec": {
342 | "display_name": "Python 3 (ipykernel)",
343 | "language": "python",
344 | "name": "python3"
345 | },
346 | "language_info": {
347 | "codemirror_mode": {
348 | "name": "ipython",
349 | "version": 3
350 | },
351 | "file_extension": ".py",
352 | "mimetype": "text/x-python",
353 | "name": "python",
354 | "nbconvert_exporter": "python",
355 | "pygments_lexer": "ipython3",
356 | "version": "3.11.6"
357 | }
358 | },
359 | "nbformat": 4,
360 | "nbformat_minor": 5
361 | }
362 |
--------------------------------------------------------------------------------
/Eval/.ipynb_checkpoints/5_Estructuras_Datos-checkpoint.ipynb:
--------------------------------------------------------------------------------
1 | {
2 | "cells": [
3 | {
4 | "cell_type": "markdown",
5 | "id": "57aef148-ea75-41ef-b65c-250257730aa4",
6 | "metadata": {},
7 | "source": [
8 | "\n",
9 | " Evaluación de estructuras de datos\n",
10 | "
\n",
11 | "\n",
12 | "La evaluación de **estructuras de datos** se utiliza para verificar el contenido de:\n",
13 | "\n",
14 | "- Listas (`list`) \n",
15 | "- Tuplas (`tuple`) \n",
16 | "- Conjuntos (`set`) \n",
17 | "\n",
18 | "**¿Cómo funciona?** \n",
19 | "- Realiza comparaciones directas de los elementos. \n",
20 | "- Permite especificar si el orden importa (`inorder=True/False`). \n",
21 | "\n",
22 | "**¿Qué podemos cambiar?** \n",
23 | "- El tipo de colección a evaluar. \n",
24 | "- Si se debe respetar el orden de los elementos. \n",
25 | "\n",
26 | "--- "
27 | ]
28 | },
29 | {
30 | "cell_type": "markdown",
31 | "id": "76a1e5e6-4368-4d31-94cc-5c966220e9b1",
32 | "metadata": {},
33 | "source": [
34 | "## ¿Cómo se utiliza la evaluación de estructuras de datos (lista ordenada)?\n",
35 | "\n",
36 | "Para validar que el alumno entregue exactamente la misma lista (en el mismo orden), ajusta dos pasos en tu flujo:\n",
37 | "\n",
38 | "1. **Registrar la lista de referencia** \n",
39 | " Después de crear `FileAnswer()` y antes de llamar a `.to_file()`, define la lista correcta:\n",
40 | "\n",
41 | " ```python\n",
42 | " # 1) Definir la lista de referencia para el ejercicio '4'\n",
43 | " file_answer.write(\n",
44 | " '4', # → ID del ejercicio\n",
45 | " ['a', 'b', 'c'], # → lista de referencia (p. ej. ['a','b','c'])\n",
46 | " 'Aquí va tu feedback personalizado' # → mensaje si el alumno falla\n",
47 | " )\n",
48 | "\n",
49 | "\n",
50 | "2. **Evaluar la lista enviada por el usuario**\n",
51 | "\n",
52 | "\n",
53 | " ```python\n",
54 | " quiz.eval_datastruct(\n",
55 | " '4', # → mismo ID de ejercicio que usaste arriba\n",
56 | " respuesta_alumno, # → lista que envió el estudiante\n",
57 | " inorder=True # → exige que el orden coincida\n",
58 | ")\n"
59 | ]
60 | },
61 | {
62 | "cell_type": "markdown",
63 | "id": "5f88a974-4caa-49f3-aca6-9017321cfcf6",
64 | "metadata": {},
65 | "source": [
66 | "---"
67 | ]
68 | },
69 | {
70 | "cell_type": "markdown",
71 | "id": "ce8ded4a-f390-4a68-adec-d00df873d69f",
72 | "metadata": {},
73 | "source": [
74 | "# Código\n",
75 | "\n",
76 | "En `src/macti/eval/quiz.py`, dentro de la clase `Quiz`, el método `eval_numeric` realiza:\n",
77 | "\n",
78 | "1. Leer el **valor de referencia** almacenado previamente. \n",
79 | "2. Detectar el tipo de respuesta del alumno (número, lista, arreglo, complejo, etc.) y normalizarla para la comparación. \n",
80 | "3. Realizar comparaciones numéricas con tolerancia (`np.testing.assert_allclose`, `math.isclose`). \n",
81 | "4. Mostrar mensaje en verde si coincide o feedback en rojo y lanzar excepción si no coincide.\n",
82 | "\n",
83 | "```python\n",
84 | "def eval_numeric(self, enum, ans):\n",
85 | " \"\"\"\n",
86 | " Evalúa una respuesta numérica (número o arreglo).\n",
87 | "\n",
88 | " Parameters\n",
89 | " ----------\n",
90 | " enum : str\n",
91 | " Identificador del ejercicio (por ejemplo, '3').\n",
92 | " ans : int | float | bool | complex | ndarray | list | tuple | set\n",
93 | " Respuesta proporcionada por el alumno.\n",
94 | " \"\"\"\n",
95 | " # 1) Recuperar el valor de referencia desde disco\n",
96 | " df = self.__read(enum) # DataFrame con la columna [enum]\n",
97 | " correct = df[enum][0] # Extraer el valor de referencia\n",
98 | " msg = \"\"\n",
99 | "\n",
100 | " try:\n",
101 | " # 2a) NumPy array\n",
102 | " if isinstance(ans, np.ndarray):\n",
103 | " if ans.dtype == complex:\n",
104 | " # Complejos: convertir a pares [real, imag]\n",
105 | " b = np.array([[c.real, c.imag] for c in ans.flatten()]).flatten()\n",
106 | " msg = self.__test_numeric_array(b, correct)\n",
107 | " np.testing.assert_allclose(b, correct)\n",
108 | " else:\n",
109 | " # Reales: comparar con tolerancia\n",
110 | " msg = self.__test_numeric_array(ans, correct)\n",
111 | " np.testing.assert_allclose(ans, correct)\n",
112 | "\n",
113 | " # 2b) Lista o tupla: convertir a array\n",
114 | " elif isinstance(ans, (list, tuple)):\n",
115 | " b = np.array(ans).flatten()\n",
116 | " msg = self.__test_numeric_array(b, correct)\n",
117 | " np.testing.assert_allclose(b, correct)\n",
118 | "\n",
119 | " # 2c) Set: convertir a array\n",
120 | " elif isinstance(ans, set):\n",
121 | " b = np.array(list(ans))\n",
122 | " msg = self.__test_numeric_array(b, correct)\n",
123 | " np.testing.assert_allclose(b, correct)\n",
124 | "\n",
125 | " # 2d) Número complejo suelto\n",
126 | " elif isinstance(ans, complex):\n",
127 | " a = complex(correct[0], correct[1])\n",
128 | " b = np.array([ans.real, ans.imag])\n",
129 | " if not np.allclose(correct, b):\n",
130 | " msg = f\"\\nValor correcto : {a}\\nValor calculado : {ans}\\n\"\n",
131 | " raise AssertionError\n",
132 | "\n",
133 | " # 2e) Entero, float o booleano\n",
134 | " elif isinstance(ans, (int, float, bool)):\n",
135 | " if not math.isclose(correct, ans):\n",
136 | " msg = f\"\\nValor correcto : {correct}\\nValor calculado : {ans}\\n\"\n",
137 | " raise AssertionError\n",
138 | "\n",
139 | " # 2f) Tipo no soportado\n",
140 | " else:\n",
141 | " print(f\"{enum} | Respuesta inválida: {ans} es de tipo {type(ans)}\")\n",
142 | " raise AssertionError\n",
143 | "\n",
144 | " except AssertionError as info:\n",
145 | " # 3) Feedback en rojo y excepción\n",
146 | " self.__print_error_hint(enum, msg=msg, info=info)\n",
147 | " raise\n",
148 | "\n",
149 | " else:\n",
150 | " # 4) Mensaje de éxito en verde\n",
151 | " self.__print_correct(enum)\n"
152 | ]
153 | },
154 | {
155 | "cell_type": "markdown",
156 | "id": "d95075fb-9a3e-45ca-abe7-549f9794937e",
157 | "metadata": {},
158 | "source": [
159 | "## Ejemplos: evaluación de Estructuras de datos\n",
160 | "\n",
161 | "A continuación se presentan ejemplos para el tipo de Estructuras de datos\n",
162 | "\n",
163 | "---"
164 | ]
165 | },
166 | {
167 | "cell_type": "code",
168 | "execution_count": 2,
169 | "id": "48f85c7c-c0cb-442b-a161-068729df6c00",
170 | "metadata": {},
171 | "outputs": [],
172 | "source": [
173 | "from evaluation import FileAnswer, Quiz\n",
174 | "import sympy as sy\n",
175 | "import numpy as np\n",
176 | "import pandas as pd"
177 | ]
178 | },
179 | {
180 | "cell_type": "code",
181 | "execution_count": 3,
182 | "id": "5dca4ccd-21fe-4bb5-b0d9-3ced52d2d937",
183 | "metadata": {},
184 | "outputs": [
185 | {
186 | "name": "stdout",
187 | "output_type": "stream",
188 | "text": [
189 | "El directorio :/home/jovyan/.ans/MACTI_LIB/ ya existe\n",
190 | "Respuestas y retroalimentación almacenadas.\n"
191 | ]
192 | }
193 | ],
194 | "source": [
195 | "# --- 1) Registrar estructuras de datos de referencia ---\n",
196 | "file_answer = FileAnswer()\n",
197 | "\n",
198 | "# Ejercicio '9': lista ordenada de nombres\n",
199 | "lista = ['luis', 'miguel', 'delacruz']\n",
200 | "file_answer.write(\n",
201 | " '9', \n",
202 | " lista, \n",
203 | " 'Checa la estructura de tipo lista.'\n",
204 | ")\n",
205 | "\n",
206 | "# Ejercicio '11': tupla ordenada de letras\n",
207 | "tupla = ('a', 'b', 'c')\n",
208 | "file_answer.write(\n",
209 | " '11', \n",
210 | " tupla, \n",
211 | " 'Checa la estructura de tipo tupla.'\n",
212 | ")\n",
213 | "\n",
214 | "# Ejercicio '13': conjunto (el orden no importa)\n",
215 | "conjunto = {'a', 'b', 'c'}\n",
216 | "file_answer.write(\n",
217 | " '13', \n",
218 | " conjunto, \n",
219 | " 'Checa la estructura de tipo conjunto.'\n",
220 | ")\n",
221 | "\n",
222 | "# Ejercicio '20': lista desordenada\n",
223 | "lista_no = ['a', 'b', 'x', '4', 'c']\n",
224 | "file_answer.write(\n",
225 | " '20', \n",
226 | " lista_no, \n",
227 | " 'Checa la lista desordenada.'\n",
228 | ")\n",
229 | "\n",
230 | "# Ejercicio '21': tupla desordenada\n",
231 | "tupla_no = ('a', 'b', 'x', '4', 'c')\n",
232 | "file_answer.write(\n",
233 | " '21', \n",
234 | " tupla_no, \n",
235 | " 'Checa la tupla desordenada.'\n",
236 | ")\n",
237 | "\n",
238 | "# Exportar a Parquet para que Quiz pueda leerlo\n",
239 | "file_answer.to_file('demo_structures')\n"
240 | ]
241 | },
242 | {
243 | "cell_type": "code",
244 | "execution_count": 4,
245 | "id": "6054e403-beef-4949-b969-b4838d24b899",
246 | "metadata": {},
247 | "outputs": [
248 | {
249 | "name": "stdout",
250 | "output_type": "stream",
251 | "text": [
252 | "\u001b[39m――――――――――――――――――――――――――――――――――――――――\n",
253 | "\u001b[32m9 | Tu resultado es correcto.\n",
254 | "\u001b[39m――――――――――――――――――――――――――――――――――――――――\n",
255 | "\u001b[39m――――――――――――――――――――――――――――――――――――――――\n",
256 | "\u001b[31m9 | Ocurrió un error en tus cálculos.\n",
257 | "\u001b[39m――――――――――――――――――――――――――――――――――――――――\n",
258 | "\u001b[31mHint: \u001b[31mCheca la estructura de tipo lista.\n",
259 | " Lugares donde hay diferencia: [0 1]\n",
260 | "\n",
261 | "Arrays are not equal\n",
262 | "\n",
263 | "Mismatched elements: 2 / 3 (66.7%)\n",
264 | " ACTUAL: array(['miguel', 'luis', 'delacruz'], dtype='\n",
138 | "\n",
139 | "Ejercicio 1.1\n",
140 | "¿Cuál de las siguientes clases se usa para almacenar respuestas y feedback en MactiLib?.\n",
141 | "\n",
142 | "A. Quiz.
\n",
143 | "B. FileAnswer.
\n",
144 | "C. NBGrader.
\n",
145 | "D. SolutionWriter.
\n",
146 | "\n",
147 | "Escribe tu respuesta en: respuesta = ¿?\n",
148 | "\n",
149 | "\n",
150 | ""
151 | ]
152 | },
153 | {
154 | "cell_type": "code",
155 | "execution_count": 81,
156 | "id": "88073215-4f88-4d3a-a555-d0e77d15c767",
157 | "metadata": {
158 | "nbgrader": {
159 | "grade": false,
160 | "grade_id": "cell-f288f347b28396c8",
161 | "locked": false,
162 | "schema_version": 3,
163 | "solution": true,
164 | "task": false
165 | }
166 | },
167 | "outputs": [],
168 | "source": [
169 | "### BEGIN SOLUTION\n",
170 | "respuesta1 = 'b'\n",
171 | "\n",
172 | "file_answer.write('1', respuesta1 , 'FileAnswer almacena respuestas y feedback')\n",
173 | "\n",
174 | "# Se guardan las respuestas en un archivo, una sola vez\n",
175 | "\n",
176 | "### END SOLUTION\n",
177 | "# respuesta1 = ''\n"
178 | ]
179 | },
180 | {
181 | "cell_type": "code",
182 | "execution_count": 91,
183 | "id": "005a9880-d1a0-4be4-ab2e-99721c76c44f",
184 | "metadata": {
185 | "nbgrader": {
186 | "grade": true,
187 | "grade_id": "cell-e8cf052d95a3b2f8",
188 | "locked": true,
189 | "points": 1,
190 | "schema_version": 3,
191 | "solution": false,
192 | "task": false
193 | }
194 | },
195 | "outputs": [
196 | {
197 | "name": "stdout",
198 | "output_type": "stream",
199 | "text": [
200 | "\u001b[39m――――――――――――――――――――――――――――――――――――――――\n",
201 | "\u001b[32m1 | Tu respuesta: \u001b[39mb\u001b[32m, es correcta.\n",
202 | "\u001b[39m――――――――――――――――――――――――――――――――――――――――\n"
203 | ]
204 | }
205 | ],
206 | "source": [
207 | "quiz.eval_option('1', respuesta1)"
208 | ]
209 | },
210 | {
211 | "cell_type": "markdown",
212 | "id": "1e0b0cc4-8158-43ed-a947-af8bf2e66c58",
213 | "metadata": {},
214 | "source": [
215 | "
\n",
216 | "\n",
217 | "Ejercicio 1.2\n",
218 | "Al llamar a FileAnswer().to_file('01'), ¿qué archivos se generan?\n",
219 | "\n",
220 | "A. Un .ipynb y un .py.
\n",
221 | "B. Dos archivos parquet: uno con respuestas y otro con feedback.
\n",
222 | "C. Un .csv con todas las respuestas.
\n",
223 | "D. Ninguno.
\n",
224 | "\n",
225 | "Escribe tu respuesta en: respuesta = ¿?\n",
226 | "\n",
227 | "\n",
228 | "
\n"
229 | ]
230 | },
231 | {
232 | "cell_type": "code",
233 | "execution_count": 82,
234 | "id": "22f71bf2-f9cc-48b5-96f1-cb0811ba5912",
235 | "metadata": {
236 | "nbgrader": {
237 | "grade": false,
238 | "grade_id": "cell-ac2c9ce147d56475",
239 | "locked": false,
240 | "schema_version": 3,
241 | "solution": true,
242 | "task": false
243 | }
244 | },
245 | "outputs": [],
246 | "source": [
247 | "### BEGIN SOLUTION\n",
248 | "repuesta2 = 'b'\n",
249 | "file_answer.write('2', repuesta2, 'Se generan dos archivos parquet (respuestas y feedback)')\n",
250 | "### END SOLUTION\n",
251 | "\n",
252 | "# repuesta2 = ''\n"
253 | ]
254 | },
255 | {
256 | "cell_type": "code",
257 | "execution_count": 92,
258 | "id": "bac99e7b-cdd1-4f05-80b3-43a065f7e7a1",
259 | "metadata": {
260 | "editable": true,
261 | "nbgrader": {
262 | "grade": true,
263 | "grade_id": "cell-aaaa5f6e9af94e62",
264 | "locked": true,
265 | "points": 1,
266 | "schema_version": 3,
267 | "solution": false,
268 | "task": false
269 | },
270 | "slideshow": {
271 | "slide_type": ""
272 | },
273 | "tags": []
274 | },
275 | "outputs": [
276 | {
277 | "name": "stdout",
278 | "output_type": "stream",
279 | "text": [
280 | "\u001b[39m――――――――――――――――――――――――――――――――――――――――\n",
281 | "\u001b[32m2 | Tu respuesta: \u001b[39mb\u001b[32m, es correcta.\n",
282 | "\u001b[39m――――――――――――――――――――――――――――――――――――――――\n"
283 | ]
284 | }
285 | ],
286 | "source": [
287 | "quiz.eval_option('2', repuesta2)"
288 | ]
289 | },
290 | {
291 | "cell_type": "markdown",
292 | "id": "7005df9d-690b-4592-b130-c6aa811fc924",
293 | "metadata": {},
294 | "source": [
295 | "
\n",
296 | "Ejercicio 1.3 \n",
297 | "¿Qué tipo de datos admite `FileAnswer.write`? \n",
298 | "A. Números
\n",
299 | "B. Cadenas de texto
\n",
300 | "C. Listas y diccionarios
\n",
301 | "D. Todos los anteriores
\n",
302 | "Escribe tu respuesta en: respuesta = ¿? \n",
303 | "
"
304 | ]
305 | },
306 | {
307 | "cell_type": "code",
308 | "execution_count": 83,
309 | "id": "9f1a89b0-2264-4ae1-9ecd-106691ec9913",
310 | "metadata": {
311 | "nbgrader": {
312 | "grade": false,
313 | "grade_id": "cell-6a2e7a5ab1a9912a",
314 | "locked": false,
315 | "schema_version": 3,
316 | "solution": true,
317 | "task": false
318 | }
319 | },
320 | "outputs": [],
321 | "source": [
322 | "### BEGIN SOLUTION\n",
323 | "respuesta3 = 'd'\n",
324 | "file_answer.write('3', respuesta3, 'FileAnswer.write admite todos esos tipos')\n",
325 | "### END SOLUTION\n",
326 | "\n",
327 | "#respuesta3 = ''"
328 | ]
329 | },
330 | {
331 | "cell_type": "code",
332 | "execution_count": 93,
333 | "id": "2e4cf94d-9a51-42f9-87ec-03eb7ac723b4",
334 | "metadata": {
335 | "nbgrader": {
336 | "grade": true,
337 | "grade_id": "cell-df32f5ca9cc59fad",
338 | "locked": true,
339 | "points": 1,
340 | "schema_version": 3,
341 | "solution": false,
342 | "task": false
343 | }
344 | },
345 | "outputs": [
346 | {
347 | "name": "stdout",
348 | "output_type": "stream",
349 | "text": [
350 | "\u001b[39m――――――――――――――――――――――――――――――――――――――――\n",
351 | "\u001b[32m3 | Tu respuesta: \u001b[39md\u001b[32m, es correcta.\n",
352 | "\u001b[39m――――――――――――――――――――――――――――――――――――――――\n"
353 | ]
354 | }
355 | ],
356 | "source": [
357 | "quiz.eval_option('3', respuesta3)"
358 | ]
359 | },
360 | {
361 | "cell_type": "markdown",
362 | "id": "749f644b-20c1-4770-aa80-d832becdb98f",
363 | "metadata": {},
364 | "source": [
365 | "
\n",
366 | "Ejercicio 1.4 \n",
367 | "¿Cuántos métodos `eval_*` proporciona la clase `Quiz`? \n",
368 | "Escribe tu respuesta en: respuesta_num = \n",
369 | "
\n"
370 | ]
371 | },
372 | {
373 | "cell_type": "code",
374 | "execution_count": 84,
375 | "id": "9687b7ab-a702-4f22-a86e-cf6c359e13af",
376 | "metadata": {
377 | "nbgrader": {
378 | "grade": false,
379 | "grade_id": "cell-34c223cb094b949c",
380 | "locked": false,
381 | "schema_version": 3,
382 | "solution": true,
383 | "task": false
384 | }
385 | },
386 | "outputs": [],
387 | "source": [
388 | "### BEGIN SOLUTION\n",
389 | "respuesta_num = 5\n",
390 | "file_answer.write('4', respuesta_num, 'Quiz tiene cinco métodos eval_option, eval_expression, eval_numeric, eval_datastruct y eval_dict')\n",
391 | "### END SOLUTION\n",
392 | "# respuesta_num = "
393 | ]
394 | },
395 | {
396 | "cell_type": "code",
397 | "execution_count": 94,
398 | "id": "4f225eac-f7de-4a4d-88a0-f1eb6a0a2f0a",
399 | "metadata": {
400 | "editable": true,
401 | "nbgrader": {
402 | "grade": true,
403 | "grade_id": "cell-9f72ea6424abc8d3",
404 | "locked": true,
405 | "points": 1,
406 | "schema_version": 3,
407 | "solution": false,
408 | "task": false
409 | },
410 | "slideshow": {
411 | "slide_type": ""
412 | },
413 | "tags": []
414 | },
415 | "outputs": [
416 | {
417 | "name": "stdout",
418 | "output_type": "stream",
419 | "text": [
420 | "\u001b[39m――――――――――――――――――――――――――――――――――――――――\n",
421 | "\u001b[32m4 | Tu resultado es correcto.\n",
422 | "\u001b[39m――――――――――――――――――――――――――――――――――――――――\n"
423 | ]
424 | }
425 | ],
426 | "source": [
427 | "quiz.eval_numeric('4', respuesta_num)"
428 | ]
429 | },
430 | {
431 | "cell_type": "markdown",
432 | "id": "6bd39c54-48f1-46e3-b99f-b26a4d2eed87",
433 | "metadata": {},
434 | "source": [
435 | "
\n",
436 | "Ejercicio 1.5 \n",
437 | "Enumera los nombres de los métodos de evaluación de `Quiz`.\n",
438 | " \n",
439 | " metodos = []\n",
440 | "
"
441 | ]
442 | },
443 | {
444 | "cell_type": "code",
445 | "execution_count": 85,
446 | "id": "45bb2345-4b7f-4ad1-948e-7e2c9fb468ec",
447 | "metadata": {
448 | "nbgrader": {
449 | "grade": false,
450 | "grade_id": "cell-284731f91e347559",
451 | "locked": false,
452 | "schema_version": 3,
453 | "solution": true,
454 | "task": false
455 | }
456 | },
457 | "outputs": [],
458 | "source": [
459 | "### BEGIN SOLUTION\n",
460 | "metodos = ['eval_option','eval_expression','eval_numeric','eval_datastruct','eval_dict']\n",
461 | "file_answer.write('5', metodos, 'Debes incluir los cinco métodos principales')\n",
462 | "### END SOLUTION\n",
463 | "\n",
464 | "# medodos = []"
465 | ]
466 | },
467 | {
468 | "cell_type": "code",
469 | "execution_count": 95,
470 | "id": "e1a69938-8a08-460f-8206-a96ac7e79612",
471 | "metadata": {
472 | "editable": true,
473 | "nbgrader": {
474 | "grade": true,
475 | "grade_id": "cell-178659e525f3b252",
476 | "locked": true,
477 | "points": 1,
478 | "schema_version": 3,
479 | "solution": false,
480 | "task": false
481 | },
482 | "slideshow": {
483 | "slide_type": ""
484 | },
485 | "tags": []
486 | },
487 | "outputs": [
488 | {
489 | "name": "stdout",
490 | "output_type": "stream",
491 | "text": [
492 | "\u001b[39m――――――――――――――――――――――――――――――――――――――――\n",
493 | "\u001b[32m5 | Tu resultado es correcto.\n",
494 | "\u001b[39m――――――――――――――――――――――――――――――――――――――――\n"
495 | ]
496 | }
497 | ],
498 | "source": [
499 | "quiz.eval_datastruct('5', metodos)"
500 | ]
501 | },
502 | {
503 | "cell_type": "markdown",
504 | "id": "c929a7cc-d191-4787-9729-f217b7d340f3",
505 | "metadata": {},
506 | "source": [
507 | "
\n",
508 | "\n",
509 | "### Ejercicio 1.6\n",
510 | "\n",
511 | "
\n",
512 | "Asocia cada método `eval_*` con el tipo de dato que evalúa, utilizando un diccionario de Python.\n",
513 | "\n",
514 | "\n",
515 | "| Funciones | Tipos de evaluación |\n",
516 | "|----------------------|----------------------------|\n",
517 | "| `eval_expression` | 1. opción múltiple |\n",
518 | "| `eval_dict` | 2. expresión simbólica |\n",
519 | "| `eval_datastruct` | 3. numérico |\n",
520 | "| `eval_option` | 4. estructura de datos |\n",
521 | "| `eval_numeric` | 5. diccionario |\n",
522 | "\n",
523 | "
\n",
524 | "Por ejemplo:\n",
525 | "\n",
526 | "```python\n",
527 | "[\n",
528 | " ('eval_option', 'opción múltiple'),\n",
529 | " # completa el resto ...\n",
530 | "]\n"
531 | ]
532 | },
533 | {
534 | "cell_type": "code",
535 | "execution_count": 86,
536 | "id": "9a03e57a-cf85-4077-ad2b-dc89cb8b9140",
537 | "metadata": {
538 | "nbgrader": {
539 | "grade": false,
540 | "grade_id": "cell-9a86f97a28ee9d24",
541 | "locked": false,
542 | "schema_version": 3,
543 | "solution": true,
544 | "task": false
545 | }
546 | },
547 | "outputs": [],
548 | "source": [
549 | "### BEGIN SOLUTION\n",
550 | "tipo_map = {\n",
551 | " 'eval_option': 'opción múltiple',\n",
552 | " 'eval_expression': 'expresión simbólica',\n",
553 | " 'eval_numeric': 'numérico',\n",
554 | " 'eval_datastruct': 'estructura de datos',\n",
555 | " 'eval_dict': 'diccionario'\n",
556 | "}\n",
557 | "\n",
558 | "\n",
559 | "file_answer.write('6', tipo_map, 'Mapea cada método con su tipo de dato')\n",
560 | "### END SOLUTION"
561 | ]
562 | },
563 | {
564 | "cell_type": "code",
565 | "execution_count": 96,
566 | "id": "f5df8246-8291-46ad-999a-6aa125989e7a",
567 | "metadata": {
568 | "editable": true,
569 | "nbgrader": {
570 | "grade": true,
571 | "grade_id": "cell-90cce500793a0a0e",
572 | "locked": true,
573 | "points": 1,
574 | "schema_version": 3,
575 | "solution": false,
576 | "task": false
577 | },
578 | "slideshow": {
579 | "slide_type": ""
580 | },
581 | "tags": []
582 | },
583 | "outputs": [
584 | {
585 | "name": "stdout",
586 | "output_type": "stream",
587 | "text": [
588 | "\u001b[39m――――――――――――――――――――――――――――――――――――――――\n",
589 | "\u001b[32m6_val_4 | Tu resultado es correcto.\n",
590 | "\u001b[39m――――――――――――――――――――――――――――――――――――――――\n"
591 | ]
592 | }
593 | ],
594 | "source": [
595 | "quiz.eval_dict('6', tipo_map, numeric=False)"
596 | ]
597 | },
598 | {
599 | "cell_type": "markdown",
600 | "id": "9e2563e3-9f59-4cf4-8dc5-5e7f81e66ad7",
601 | "metadata": {},
602 | "source": [
603 | "\n",
604 | "Ejercicio 1.7 \n",
605 | "¿Cuál es una ventaja de usar NBGrader con MactiLib? \n",
606 | "A. Generación manual de feedback
\n",
607 | "B. Calificación automática
\n",
608 | "C. No requiere Python
\n",
609 | "D. Soporta solo opción múltiple
\n",
610 | "Escribe tu respuesta en: respuesta = \n",
611 | "
"
612 | ]
613 | },
614 | {
615 | "cell_type": "code",
616 | "execution_count": 87,
617 | "id": "b24f0481-dd07-4027-a379-2c2a6e89255a",
618 | "metadata": {
619 | "nbgrader": {
620 | "grade": false,
621 | "grade_id": "cell-8d689920ace39a9f",
622 | "locked": false,
623 | "schema_version": 3,
624 | "solution": true,
625 | "task": false
626 | }
627 | },
628 | "outputs": [],
629 | "source": [
630 | "## BEGIN SOLUTION\n",
631 | "respuesta7 = 'b'\n",
632 | "file_answer.write('7', respuesta7, 'La calificación automática es la principal ventaja')\n",
633 | "### END SOLUTION\n",
634 | "# respuesta7 = ''"
635 | ]
636 | },
637 | {
638 | "cell_type": "code",
639 | "execution_count": 97,
640 | "id": "ec9276ba-e387-49ad-986d-fb175316d6d1",
641 | "metadata": {
642 | "nbgrader": {
643 | "grade": true,
644 | "grade_id": "cell-8d80f3f3f8487c76",
645 | "locked": true,
646 | "points": 1,
647 | "schema_version": 3,
648 | "solution": false,
649 | "task": false
650 | }
651 | },
652 | "outputs": [
653 | {
654 | "name": "stdout",
655 | "output_type": "stream",
656 | "text": [
657 | "\u001b[39m――――――――――――――――――――――――――――――――――――――――\n",
658 | "\u001b[32m7 | Tu respuesta: \u001b[39mb\u001b[32m, es correcta.\n",
659 | "\u001b[39m――――――――――――――――――――――――――――――――――――――――\n"
660 | ]
661 | }
662 | ],
663 | "source": [
664 | "quiz.eval_option('7', respuesta7)"
665 | ]
666 | },
667 | {
668 | "cell_type": "markdown",
669 | "id": "946e1242-6bc2-420f-8acf-66570a5722b1",
670 | "metadata": {
671 | "nbgrader": {
672 | "grade": false,
673 | "grade_id": "cell-897f0754e72da593",
674 | "locked": true,
675 | "schema_version": 3,
676 | "solution": false,
677 | "task": false
678 | }
679 | },
680 | "source": [
681 | "\n",
682 | "\n",
683 | "Ejercicio 8\n",
684 | "En Quiz.eval_numeric(), ¿qué ocurre si la respuesta no coincide?\n",
685 | "\n",
686 | "A. Imprime 'correcto'.
\n",
687 | "B. Lanza AssertionError.
\n",
688 | "C. Cierra el programa.
\n",
689 | "D. Silenciosamente marca error.
\n",
690 | "\n",
691 | "Escribe tu respuesta en: respuesta = ¿?\n",
692 | "\n",
693 | "\n",
694 | "
\n"
695 | ]
696 | },
697 | {
698 | "cell_type": "code",
699 | "execution_count": 88,
700 | "id": "a926e213-1dd3-4975-bbc2-5bcfc986369c",
701 | "metadata": {
702 | "editable": true,
703 | "nbgrader": {
704 | "grade": false,
705 | "grade_id": "cell-6a6107b082efe7fa",
706 | "locked": false,
707 | "schema_version": 3,
708 | "solution": true,
709 | "task": false
710 | },
711 | "slideshow": {
712 | "slide_type": ""
713 | },
714 | "tags": []
715 | },
716 | "outputs": [],
717 | "source": [
718 | "### BEGIN SOLUTION\n",
719 | "repuesta8 = 'b'\n",
720 | "file_answer.write('8', repuesta8, 'AssertionError se lanza si no coincide')\n",
721 | "### END SOLUTION\n",
722 | "\n",
723 | "# repuesta8 = ''"
724 | ]
725 | },
726 | {
727 | "cell_type": "code",
728 | "execution_count": 98,
729 | "id": "aa330b8f-dedc-43b7-8d3f-1e383cbe0bc8",
730 | "metadata": {
731 | "editable": true,
732 | "nbgrader": {
733 | "grade": true,
734 | "grade_id": "cell-16bfea838de42cb5",
735 | "locked": true,
736 | "points": 1,
737 | "schema_version": 3,
738 | "solution": false,
739 | "task": false
740 | },
741 | "slideshow": {
742 | "slide_type": ""
743 | },
744 | "tags": []
745 | },
746 | "outputs": [
747 | {
748 | "name": "stdout",
749 | "output_type": "stream",
750 | "text": [
751 | "\u001b[39m――――――――――――――――――――――――――――――――――――――――\n",
752 | "\u001b[32m8 | Tu respuesta: \u001b[39mb\u001b[32m, es correcta.\n",
753 | "\u001b[39m――――――――――――――――――――――――――――――――――――――――\n"
754 | ]
755 | }
756 | ],
757 | "source": [
758 | "quiz.eval_option('8', repuesta8)"
759 | ]
760 | },
761 | {
762 | "cell_type": "code",
763 | "execution_count": 89,
764 | "id": "3f724550-6d4f-4c46-82bd-1fb9fe0a9e66",
765 | "metadata": {
766 | "nbgrader": {
767 | "grade": false,
768 | "grade_id": "cell-e3bc2249537b0d25",
769 | "locked": true,
770 | "schema_version": 3,
771 | "solution": false,
772 | "task": false
773 | }
774 | },
775 | "outputs": [
776 | {
777 | "name": "stdout",
778 | "output_type": "stream",
779 | "text": [
780 | "El directorio :/home/jovyan/MACTI_LIB/.ans/Eval/ ya existe\n",
781 | "Respuestas y retroalimentación almacenadas.\n"
782 | ]
783 | }
784 | ],
785 | "source": [
786 | "# Se guardan las respuestas en un archivo, una sola vez\n",
787 | "file_answer.to_file('1') "
788 | ]
789 | }
790 | ],
791 | "metadata": {
792 | "kernelspec": {
793 | "display_name": "Python 3 (ipykernel)",
794 | "language": "python",
795 | "name": "python3"
796 | },
797 | "language_info": {
798 | "codemirror_mode": {
799 | "name": "ipython",
800 | "version": 3
801 | },
802 | "file_extension": ".py",
803 | "mimetype": "text/x-python",
804 | "name": "python",
805 | "nbconvert_exporter": "python",
806 | "pygments_lexer": "ipython3",
807 | "version": "3.11.6"
808 | }
809 | },
810 | "nbformat": 4,
811 | "nbformat_minor": 5
812 | }
813 |
--------------------------------------------------------------------------------
/Eval/.ipynb_checkpoints/7_Ejercicio-checkpoint.ipynb:
--------------------------------------------------------------------------------
1 | {
2 | "cells": [
3 | {
4 | "cell_type": "markdown",
5 | "id": "c11e43bb",
6 | "metadata": {
7 | "editable": true,
8 | "nbgrader": {
9 | "grade": false,
10 | "grade_id": "cell-08081af55f04f1c9",
11 | "locked": true,
12 | "schema_version": 3,
13 | "solution": false,
14 | "task": false
15 | },
16 | "slideshow": {
17 | "slide_type": ""
18 | },
19 | "tags": []
20 | },
21 | "source": [
22 | "# Quiz: Evaluación de Ejercicios con FileAnswer y Quiz\n",
23 | "\n",
24 | "\n",
25 | "Este ejercicio simula una evaluación completa con múltiples tipos de preguntas.\n",
26 | "\n",
27 | "### Objetivo\n",
28 | "El estudiante deberá resolver y validar diferentes tipos de ejercicios:\n",
29 | "- Opción múltiple\n",
30 | "- Expresión simbólica\n",
31 | "- Valor numérico\n",
32 | "- Lista desordenada\n",
33 | "- Diccionario con claves y valores numéricos\n",
34 | "- \n",
35 | "Este notebook evalúa ejercicios usando las clases FileAnswer y Quiz.\n",
36 | "---"
37 | ]
38 | },
39 | {
40 | "cell_type": "markdown",
41 | "id": "796c2796-722a-4191-ab7f-1125ca3cf087",
42 | "metadata": {
43 | "nbgrader": {
44 | "grade": false,
45 | "grade_id": "cell-34ae80a3780618c6",
46 | "locked": true,
47 | "schema_version": 3,
48 | "solution": false,
49 | "task": false
50 | }
51 | },
52 | "source": [
53 | "## Importamos bibliotecas"
54 | ]
55 | },
56 | {
57 | "cell_type": "code",
58 | "execution_count": 79,
59 | "id": "28b73445",
60 | "metadata": {
61 | "nbgrader": {
62 | "grade": false,
63 | "grade_id": "cell-65f92af3e8950e79",
64 | "locked": true,
65 | "schema_version": 3,
66 | "solution": false,
67 | "task": false
68 | }
69 | },
70 | "outputs": [],
71 | "source": [
72 | "from macti.eval import FileAnswer, Quiz \n",
73 | "import sympy as sy\n",
74 | "import numpy as np\n",
75 | "import pandas as pd\n"
76 | ]
77 | },
78 | {
79 | "cell_type": "code",
80 | "execution_count": 90,
81 | "id": "9ceb1f39-8ed6-42ea-a89a-66c9f04ce0ed",
82 | "metadata": {
83 | "editable": true,
84 | "nbgrader": {
85 | "grade": false,
86 | "grade_id": "cell-6d429f74db840a1c",
87 | "locked": true,
88 | "schema_version": 3,
89 | "solution": false,
90 | "task": false
91 | },
92 | "slideshow": {
93 | "slide_type": ""
94 | },
95 | "tags": []
96 | },
97 | "outputs": [],
98 | "source": [
99 | "#quiz = Quiz(\"1\", \"MACTI_LIB\", \"local\")\n",
100 | "quiz = Quiz(qnum=\"1\", server=\"local\", spath=\"MACTI_LIB\")\n"
101 | ]
102 | },
103 | {
104 | "cell_type": "code",
105 | "execution_count": 80,
106 | "id": "5e9863f8",
107 | "metadata": {
108 | "nbgrader": {
109 | "grade": false,
110 | "grade_id": "cell-e8996618b91eee0a",
111 | "locked": true,
112 | "schema_version": 3,
113 | "solution": false,
114 | "task": false
115 | }
116 | },
117 | "outputs": [],
118 | "source": [
119 | "# Inicializar almacenamiento de respuestas\n",
120 | "file_answer = FileAnswer()"
121 | ]
122 | },
123 | {
124 | "cell_type": "markdown",
125 | "id": "d2842ffc-7061-42b6-96c7-1e14eba484f1",
126 | "metadata": {
127 | "nbgrader": {
128 | "grade": false,
129 | "grade_id": "cell-bc0f76b40ae06dd7",
130 | "locked": true,
131 | "schema_version": 3,
132 | "solution": false,
133 | "task": false
134 | }
135 | },
136 | "source": [
137 | "\n",
138 | "\n",
139 | "Ejercicio 1.1\n",
140 | "¿Cuál de las siguientes clases se usa para almacenar respuestas y feedback en MactiLib?.\n",
141 | "\n",
142 | "A. Quiz.
\n",
143 | "B. FileAnswer.
\n",
144 | "C. NBGrader.
\n",
145 | "D. SolutionWriter.
\n",
146 | "\n",
147 | "Escribe tu respuesta en: respuesta = ¿?\n",
148 | "\n",
149 | "\n",
150 | "
"
151 | ]
152 | },
153 | {
154 | "cell_type": "code",
155 | "execution_count": 81,
156 | "id": "88073215-4f88-4d3a-a555-d0e77d15c767",
157 | "metadata": {
158 | "nbgrader": {
159 | "grade": false,
160 | "grade_id": "cell-f288f347b28396c8",
161 | "locked": false,
162 | "schema_version": 3,
163 | "solution": true,
164 | "task": false
165 | }
166 | },
167 | "outputs": [],
168 | "source": [
169 | "### BEGIN SOLUTION\n",
170 | "respuesta1 = 'b'\n",
171 | "\n",
172 | "file_answer.write('1', respuesta1 , 'FileAnswer almacena respuestas y feedback')\n",
173 | "\n",
174 | "# Se guardan las respuestas en un archivo, una sola vez\n",
175 | "\n",
176 | "### END SOLUTION\n",
177 | "# respuesta1 = ''\n"
178 | ]
179 | },
180 | {
181 | "cell_type": "code",
182 | "execution_count": 91,
183 | "id": "005a9880-d1a0-4be4-ab2e-99721c76c44f",
184 | "metadata": {
185 | "nbgrader": {
186 | "grade": true,
187 | "grade_id": "cell-e8cf052d95a3b2f8",
188 | "locked": true,
189 | "points": 1,
190 | "schema_version": 3,
191 | "solution": false,
192 | "task": false
193 | }
194 | },
195 | "outputs": [
196 | {
197 | "name": "stdout",
198 | "output_type": "stream",
199 | "text": [
200 | "\u001b[39m――――――――――――――――――――――――――――――――――――――――\n",
201 | "\u001b[32m1 | Tu respuesta: \u001b[39mb\u001b[32m, es correcta.\n",
202 | "\u001b[39m――――――――――――――――――――――――――――――――――――――――\n"
203 | ]
204 | }
205 | ],
206 | "source": [
207 | "quiz.eval_option('1', respuesta1)"
208 | ]
209 | },
210 | {
211 | "cell_type": "markdown",
212 | "id": "1e0b0cc4-8158-43ed-a947-af8bf2e66c58",
213 | "metadata": {},
214 | "source": [
215 | "\n",
216 | "\n",
217 | "Ejercicio 1.2\n",
218 | "Al llamar a FileAnswer().to_file('01'), ¿qué archivos se generan?\n",
219 | "\n",
220 | "A. Un .ipynb y un .py.
\n",
221 | "B. Dos archivos parquet: uno con respuestas y otro con feedback.
\n",
222 | "C. Un .csv con todas las respuestas.
\n",
223 | "D. Ninguno.
\n",
224 | "\n",
225 | "Escribe tu respuesta en: respuesta = ¿?\n",
226 | "\n",
227 | "\n",
228 | "
\n"
229 | ]
230 | },
231 | {
232 | "cell_type": "code",
233 | "execution_count": 82,
234 | "id": "22f71bf2-f9cc-48b5-96f1-cb0811ba5912",
235 | "metadata": {
236 | "nbgrader": {
237 | "grade": false,
238 | "grade_id": "cell-ac2c9ce147d56475",
239 | "locked": false,
240 | "schema_version": 3,
241 | "solution": true,
242 | "task": false
243 | }
244 | },
245 | "outputs": [],
246 | "source": [
247 | "### BEGIN SOLUTION\n",
248 | "repuesta2 = 'b'\n",
249 | "file_answer.write('2', repuesta2, 'Se generan dos archivos parquet (respuestas y feedback)')\n",
250 | "### END SOLUTION\n",
251 | "\n",
252 | "# repuesta2 = ''\n"
253 | ]
254 | },
255 | {
256 | "cell_type": "code",
257 | "execution_count": 92,
258 | "id": "bac99e7b-cdd1-4f05-80b3-43a065f7e7a1",
259 | "metadata": {
260 | "editable": true,
261 | "nbgrader": {
262 | "grade": true,
263 | "grade_id": "cell-aaaa5f6e9af94e62",
264 | "locked": true,
265 | "points": 1,
266 | "schema_version": 3,
267 | "solution": false,
268 | "task": false
269 | },
270 | "slideshow": {
271 | "slide_type": ""
272 | },
273 | "tags": []
274 | },
275 | "outputs": [
276 | {
277 | "name": "stdout",
278 | "output_type": "stream",
279 | "text": [
280 | "\u001b[39m――――――――――――――――――――――――――――――――――――――――\n",
281 | "\u001b[32m2 | Tu respuesta: \u001b[39mb\u001b[32m, es correcta.\n",
282 | "\u001b[39m――――――――――――――――――――――――――――――――――――――――\n"
283 | ]
284 | }
285 | ],
286 | "source": [
287 | "quiz.eval_option('2', repuesta2)"
288 | ]
289 | },
290 | {
291 | "cell_type": "markdown",
292 | "id": "7005df9d-690b-4592-b130-c6aa811fc924",
293 | "metadata": {},
294 | "source": [
295 | "\n",
296 | "Ejercicio 1.3 \n",
297 | "¿Qué tipo de datos admite `FileAnswer.write`? \n",
298 | "A. Números
\n",
299 | "B. Cadenas de texto
\n",
300 | "C. Listas y diccionarios
\n",
301 | "D. Todos los anteriores
\n",
302 | "Escribe tu respuesta en: respuesta = ¿? \n",
303 | "
"
304 | ]
305 | },
306 | {
307 | "cell_type": "code",
308 | "execution_count": 83,
309 | "id": "9f1a89b0-2264-4ae1-9ecd-106691ec9913",
310 | "metadata": {
311 | "nbgrader": {
312 | "grade": false,
313 | "grade_id": "cell-6a2e7a5ab1a9912a",
314 | "locked": false,
315 | "schema_version": 3,
316 | "solution": true,
317 | "task": false
318 | }
319 | },
320 | "outputs": [],
321 | "source": [
322 | "### BEGIN SOLUTION\n",
323 | "respuesta3 = 'd'\n",
324 | "file_answer.write('3', respuesta3, 'FileAnswer.write admite todos esos tipos')\n",
325 | "### END SOLUTION\n",
326 | "\n",
327 | "#respuesta3 = ''"
328 | ]
329 | },
330 | {
331 | "cell_type": "code",
332 | "execution_count": 93,
333 | "id": "2e4cf94d-9a51-42f9-87ec-03eb7ac723b4",
334 | "metadata": {
335 | "nbgrader": {
336 | "grade": true,
337 | "grade_id": "cell-df32f5ca9cc59fad",
338 | "locked": true,
339 | "points": 1,
340 | "schema_version": 3,
341 | "solution": false,
342 | "task": false
343 | }
344 | },
345 | "outputs": [
346 | {
347 | "name": "stdout",
348 | "output_type": "stream",
349 | "text": [
350 | "\u001b[39m――――――――――――――――――――――――――――――――――――――――\n",
351 | "\u001b[32m3 | Tu respuesta: \u001b[39md\u001b[32m, es correcta.\n",
352 | "\u001b[39m――――――――――――――――――――――――――――――――――――――――\n"
353 | ]
354 | }
355 | ],
356 | "source": [
357 | "quiz.eval_option('3', respuesta3)"
358 | ]
359 | },
360 | {
361 | "cell_type": "markdown",
362 | "id": "749f644b-20c1-4770-aa80-d832becdb98f",
363 | "metadata": {},
364 | "source": [
365 | "\n",
366 | "Ejercicio 1.4 \n",
367 | "¿Cuántos métodos `eval_*` proporciona la clase `Quiz`? \n",
368 | "Escribe tu respuesta en: respuesta_num = \n",
369 | "
\n"
370 | ]
371 | },
372 | {
373 | "cell_type": "code",
374 | "execution_count": 84,
375 | "id": "9687b7ab-a702-4f22-a86e-cf6c359e13af",
376 | "metadata": {
377 | "nbgrader": {
378 | "grade": false,
379 | "grade_id": "cell-34c223cb094b949c",
380 | "locked": false,
381 | "schema_version": 3,
382 | "solution": true,
383 | "task": false
384 | }
385 | },
386 | "outputs": [],
387 | "source": [
388 | "### BEGIN SOLUTION\n",
389 | "respuesta_num = 5\n",
390 | "file_answer.write('4', respuesta_num, 'Quiz tiene cinco métodos eval_option, eval_expression, eval_numeric, eval_datastruct y eval_dict')\n",
391 | "### END SOLUTION\n",
392 | "# respuesta_num = "
393 | ]
394 | },
395 | {
396 | "cell_type": "code",
397 | "execution_count": 94,
398 | "id": "4f225eac-f7de-4a4d-88a0-f1eb6a0a2f0a",
399 | "metadata": {
400 | "editable": true,
401 | "nbgrader": {
402 | "grade": true,
403 | "grade_id": "cell-9f72ea6424abc8d3",
404 | "locked": true,
405 | "points": 1,
406 | "schema_version": 3,
407 | "solution": false,
408 | "task": false
409 | },
410 | "slideshow": {
411 | "slide_type": ""
412 | },
413 | "tags": []
414 | },
415 | "outputs": [
416 | {
417 | "name": "stdout",
418 | "output_type": "stream",
419 | "text": [
420 | "\u001b[39m――――――――――――――――――――――――――――――――――――――――\n",
421 | "\u001b[32m4 | Tu resultado es correcto.\n",
422 | "\u001b[39m――――――――――――――――――――――――――――――――――――――――\n"
423 | ]
424 | }
425 | ],
426 | "source": [
427 | "quiz.eval_numeric('4', respuesta_num)"
428 | ]
429 | },
430 | {
431 | "cell_type": "markdown",
432 | "id": "6bd39c54-48f1-46e3-b99f-b26a4d2eed87",
433 | "metadata": {},
434 | "source": [
435 | "\n",
436 | "Ejercicio 1.5 \n",
437 | "Enumera los nombres de los métodos de evaluación de `Quiz`.\n",
438 | " \n",
439 | " metodos = []\n",
440 | "
"
441 | ]
442 | },
443 | {
444 | "cell_type": "code",
445 | "execution_count": 85,
446 | "id": "45bb2345-4b7f-4ad1-948e-7e2c9fb468ec",
447 | "metadata": {
448 | "nbgrader": {
449 | "grade": false,
450 | "grade_id": "cell-284731f91e347559",
451 | "locked": false,
452 | "schema_version": 3,
453 | "solution": true,
454 | "task": false
455 | }
456 | },
457 | "outputs": [],
458 | "source": [
459 | "### BEGIN SOLUTION\n",
460 | "metodos = ['eval_option','eval_expression','eval_numeric','eval_datastruct','eval_dict']\n",
461 | "file_answer.write('5', metodos, 'Debes incluir los cinco métodos principales')\n",
462 | "### END SOLUTION\n",
463 | "\n",
464 | "# medodos = []"
465 | ]
466 | },
467 | {
468 | "cell_type": "code",
469 | "execution_count": 95,
470 | "id": "e1a69938-8a08-460f-8206-a96ac7e79612",
471 | "metadata": {
472 | "editable": true,
473 | "nbgrader": {
474 | "grade": true,
475 | "grade_id": "cell-178659e525f3b252",
476 | "locked": true,
477 | "points": 1,
478 | "schema_version": 3,
479 | "solution": false,
480 | "task": false
481 | },
482 | "slideshow": {
483 | "slide_type": ""
484 | },
485 | "tags": []
486 | },
487 | "outputs": [
488 | {
489 | "name": "stdout",
490 | "output_type": "stream",
491 | "text": [
492 | "\u001b[39m――――――――――――――――――――――――――――――――――――――――\n",
493 | "\u001b[32m5 | Tu resultado es correcto.\n",
494 | "\u001b[39m――――――――――――――――――――――――――――――――――――――――\n"
495 | ]
496 | }
497 | ],
498 | "source": [
499 | "quiz.eval_datastruct('5', metodos)"
500 | ]
501 | },
502 | {
503 | "cell_type": "markdown",
504 | "id": "c929a7cc-d191-4787-9729-f217b7d340f3",
505 | "metadata": {},
506 | "source": [
507 | "\n",
508 | "\n",
509 | "### Ejercicio 1.6\n",
510 | "\n",
511 | "
\n",
512 | "Asocia cada método `eval_*` con el tipo de dato que evalúa, utilizando un diccionario de Python.\n",
513 | "\n",
514 | "\n",
515 | "| Funciones | Tipos de evaluación |\n",
516 | "|----------------------|----------------------------|\n",
517 | "| `eval_expression` | 1. opción múltiple |\n",
518 | "| `eval_dict` | 2. expresión simbólica |\n",
519 | "| `eval_datastruct` | 3. numérico |\n",
520 | "| `eval_option` | 4. estructura de datos |\n",
521 | "| `eval_numeric` | 5. diccionario |\n",
522 | "\n",
523 | "
\n",
524 | "Por ejemplo:\n",
525 | "\n",
526 | "```python\n",
527 | "[\n",
528 | " ('eval_option', 'opción múltiple'),\n",
529 | " # completa el resto ...\n",
530 | "]\n"
531 | ]
532 | },
533 | {
534 | "cell_type": "code",
535 | "execution_count": 86,
536 | "id": "9a03e57a-cf85-4077-ad2b-dc89cb8b9140",
537 | "metadata": {
538 | "nbgrader": {
539 | "grade": false,
540 | "grade_id": "cell-9a86f97a28ee9d24",
541 | "locked": false,
542 | "schema_version": 3,
543 | "solution": true,
544 | "task": false
545 | }
546 | },
547 | "outputs": [],
548 | "source": [
549 | "### BEGIN SOLUTION\n",
550 | "tipo_map = {\n",
551 | " 'eval_option': 'opción múltiple',\n",
552 | " 'eval_expression': 'expresión simbólica',\n",
553 | " 'eval_numeric': 'numérico',\n",
554 | " 'eval_datastruct': 'estructura de datos',\n",
555 | " 'eval_dict': 'diccionario'\n",
556 | "}\n",
557 | "\n",
558 | "\n",
559 | "file_answer.write('6', tipo_map, 'Mapea cada método con su tipo de dato')\n",
560 | "### END SOLUTION"
561 | ]
562 | },
563 | {
564 | "cell_type": "code",
565 | "execution_count": 96,
566 | "id": "f5df8246-8291-46ad-999a-6aa125989e7a",
567 | "metadata": {
568 | "editable": true,
569 | "nbgrader": {
570 | "grade": true,
571 | "grade_id": "cell-90cce500793a0a0e",
572 | "locked": true,
573 | "points": 1,
574 | "schema_version": 3,
575 | "solution": false,
576 | "task": false
577 | },
578 | "slideshow": {
579 | "slide_type": ""
580 | },
581 | "tags": []
582 | },
583 | "outputs": [
584 | {
585 | "name": "stdout",
586 | "output_type": "stream",
587 | "text": [
588 | "\u001b[39m――――――――――――――――――――――――――――――――――――――――\n",
589 | "\u001b[32m6_val_4 | Tu resultado es correcto.\n",
590 | "\u001b[39m――――――――――――――――――――――――――――――――――――――――\n"
591 | ]
592 | }
593 | ],
594 | "source": [
595 | "quiz.eval_dict('6', tipo_map, numeric=False)"
596 | ]
597 | },
598 | {
599 | "cell_type": "markdown",
600 | "id": "9e2563e3-9f59-4cf4-8dc5-5e7f81e66ad7",
601 | "metadata": {},
602 | "source": [
603 | "\n",
604 | "Ejercicio 1.7 \n",
605 | "¿Cuál es una ventaja de usar NBGrader con MactiLib? \n",
606 | "A. Generación manual de feedback
\n",
607 | "B. Calificación automática
\n",
608 | "C. No requiere Python
\n",
609 | "D. Soporta solo opción múltiple
\n",
610 | "Escribe tu respuesta en: respuesta = \n",
611 | "
"
612 | ]
613 | },
614 | {
615 | "cell_type": "code",
616 | "execution_count": 87,
617 | "id": "b24f0481-dd07-4027-a379-2c2a6e89255a",
618 | "metadata": {
619 | "nbgrader": {
620 | "grade": false,
621 | "grade_id": "cell-8d689920ace39a9f",
622 | "locked": false,
623 | "schema_version": 3,
624 | "solution": true,
625 | "task": false
626 | }
627 | },
628 | "outputs": [],
629 | "source": [
630 | "## BEGIN SOLUTION\n",
631 | "respuesta7 = 'b'\n",
632 | "file_answer.write('7', respuesta7, 'La calificación automática es la principal ventaja')\n",
633 | "### END SOLUTION\n",
634 | "# respuesta7 = ''"
635 | ]
636 | },
637 | {
638 | "cell_type": "code",
639 | "execution_count": 97,
640 | "id": "ec9276ba-e387-49ad-986d-fb175316d6d1",
641 | "metadata": {
642 | "nbgrader": {
643 | "grade": true,
644 | "grade_id": "cell-8d80f3f3f8487c76",
645 | "locked": true,
646 | "points": 1,
647 | "schema_version": 3,
648 | "solution": false,
649 | "task": false
650 | }
651 | },
652 | "outputs": [
653 | {
654 | "name": "stdout",
655 | "output_type": "stream",
656 | "text": [
657 | "\u001b[39m――――――――――――――――――――――――――――――――――――――――\n",
658 | "\u001b[32m7 | Tu respuesta: \u001b[39mb\u001b[32m, es correcta.\n",
659 | "\u001b[39m――――――――――――――――――――――――――――――――――――――――\n"
660 | ]
661 | }
662 | ],
663 | "source": [
664 | "quiz.eval_option('7', respuesta7)"
665 | ]
666 | },
667 | {
668 | "cell_type": "markdown",
669 | "id": "946e1242-6bc2-420f-8acf-66570a5722b1",
670 | "metadata": {
671 | "nbgrader": {
672 | "grade": false,
673 | "grade_id": "cell-897f0754e72da593",
674 | "locked": true,
675 | "schema_version": 3,
676 | "solution": false,
677 | "task": false
678 | }
679 | },
680 | "source": [
681 | "\n",
682 | "\n",
683 | "Ejercicio 8\n",
684 | "En Quiz.eval_numeric(), ¿qué ocurre si la respuesta no coincide?\n",
685 | "\n",
686 | "A. Imprime 'correcto'.
\n",
687 | "B. Lanza AssertionError.
\n",
688 | "C. Cierra el programa.
\n",
689 | "D. Silenciosamente marca error.
\n",
690 | "\n",
691 | "Escribe tu respuesta en: respuesta = ¿?\n",
692 | "\n",
693 | "\n",
694 | "
\n"
695 | ]
696 | },
697 | {
698 | "cell_type": "code",
699 | "execution_count": 88,
700 | "id": "a926e213-1dd3-4975-bbc2-5bcfc986369c",
701 | "metadata": {
702 | "editable": true,
703 | "nbgrader": {
704 | "grade": false,
705 | "grade_id": "cell-6a6107b082efe7fa",
706 | "locked": false,
707 | "schema_version": 3,
708 | "solution": true,
709 | "task": false
710 | },
711 | "slideshow": {
712 | "slide_type": ""
713 | },
714 | "tags": []
715 | },
716 | "outputs": [],
717 | "source": [
718 | "### BEGIN SOLUTION\n",
719 | "repuesta8 = 'b'\n",
720 | "file_answer.write('8', repuesta8, 'AssertionError se lanza si no coincide')\n",
721 | "### END SOLUTION\n",
722 | "\n",
723 | "# repuesta8 = ''"
724 | ]
725 | },
726 | {
727 | "cell_type": "code",
728 | "execution_count": 98,
729 | "id": "aa330b8f-dedc-43b7-8d3f-1e383cbe0bc8",
730 | "metadata": {
731 | "editable": true,
732 | "nbgrader": {
733 | "grade": true,
734 | "grade_id": "cell-16bfea838de42cb5",
735 | "locked": true,
736 | "points": 1,
737 | "schema_version": 3,
738 | "solution": false,
739 | "task": false
740 | },
741 | "slideshow": {
742 | "slide_type": ""
743 | },
744 | "tags": []
745 | },
746 | "outputs": [
747 | {
748 | "name": "stdout",
749 | "output_type": "stream",
750 | "text": [
751 | "\u001b[39m――――――――――――――――――――――――――――――――――――――――\n",
752 | "\u001b[32m8 | Tu respuesta: \u001b[39mb\u001b[32m, es correcta.\n",
753 | "\u001b[39m――――――――――――――――――――――――――――――――――――――――\n"
754 | ]
755 | }
756 | ],
757 | "source": [
758 | "quiz.eval_option('8', repuesta8)"
759 | ]
760 | },
761 | {
762 | "cell_type": "code",
763 | "execution_count": 89,
764 | "id": "3f724550-6d4f-4c46-82bd-1fb9fe0a9e66",
765 | "metadata": {
766 | "nbgrader": {
767 | "grade": false,
768 | "grade_id": "cell-e3bc2249537b0d25",
769 | "locked": true,
770 | "schema_version": 3,
771 | "solution": false,
772 | "task": false
773 | }
774 | },
775 | "outputs": [
776 | {
777 | "name": "stdout",
778 | "output_type": "stream",
779 | "text": [
780 | "El directorio :/home/jovyan/MACTI_LIB/.ans/Eval/ ya existe\n",
781 | "Respuestas y retroalimentación almacenadas.\n"
782 | ]
783 | }
784 | ],
785 | "source": [
786 | "# Se guardan las respuestas en un archivo, una sola vez\n",
787 | "file_answer.to_file('1') "
788 | ]
789 | }
790 | ],
791 | "metadata": {
792 | "kernelspec": {
793 | "display_name": "Python 3 (ipykernel)",
794 | "language": "python",
795 | "name": "python3"
796 | },
797 | "language_info": {
798 | "codemirror_mode": {
799 | "name": "ipython",
800 | "version": 3
801 | },
802 | "file_extension": ".py",
803 | "mimetype": "text/x-python",
804 | "name": "python",
805 | "nbconvert_exporter": "python",
806 | "pygments_lexer": "ipython3",
807 | "version": "3.11.6"
808 | }
809 | },
810 | "nbformat": 4,
811 | "nbformat_minor": 5
812 | }
813 |
--------------------------------------------------------------------------------