├── Eval ├── README.md ├── __pycache__ │ └── evaluation.cpython-311.pyc ├── .ipynb_checkpoints │ ├── 2_Opcion_Multiple-checkpoint.ipynb │ ├── 3_Expresiones_Simbolicas-checkpoint.ipynb │ ├── 4_Valores_Numericos-checkpoint.ipynb │ ├── 6_Diccionarios-checkpoint.ipynb │ ├── 1_Intro_macti_lib-checkpoint.ipynb │ ├── 5_Estructuras_Datos-checkpoint.ipynb │ └── 7_Ejercicio-checkpoint.ipynb ├── 2_Opcion_Multiple.ipynb ├── 5_Estructuras_Datos.ipynb ├── 6_Diccionarios.ipynb ├── 4_Valores_Numericos.ipynb ├── 3_Expresiones_Simbolicas.ipynb ├── Ejemplos │ └── Perceptron.ipynb ├── 1_Intro_macti_lib.ipynb └── 7_Ejercicio.ipynb └── macti_setup_course.py /Eval/README.md: -------------------------------------------------------------------------------- 1 | # TallerMeIA 2 | -------------------------------------------------------------------------------- /Eval/__pycache__/evaluation.cpython-311.pyc: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/jugernaut/TallerMeIA/main/Eval/__pycache__/evaluation.cpython-311.pyc -------------------------------------------------------------------------------- /macti_setup_course.py: -------------------------------------------------------------------------------- 1 | import os, shutil, pkg_resources 2 | 3 | from colorama import Fore, Back, Style 4 | 5 | def print_macti_info(msg): 6 | print(Fore.GREEN + '[MACTI | INFO] ' + Style.RESET_ALL, end = '') 7 | print(Back.WHITE + ' --> ' + msg + Style.RESET_ALL, end='\n') 8 | 9 | def make_dirs(paths): 10 | for p in paths: 11 | if not os.path.exists(p): 12 | print_macti_info('Creando el directorio : {} '.format(p)) 13 | os.makedirs(p , exist_ok=True) 14 | else: 15 | print_macti_info('El directorio : {} ya existe '.format(p)) 16 | 17 | def copy_files(filenames, abspath, path): 18 | for f in filenames: 19 | stream = pkg_resources.resource_stream('macti', os.path.join("resources", f)) 20 | print_macti_info('Copiando {} al directorio {} '.format(stream.name.split(sep='/')[-1], path)) 21 | shutil.copy2(stream.name, os.path.join(abspath, path)) 22 | 23 | # --------------------------- 24 | if __name__ == "__main__": 25 | 26 | os.system('clear') 27 | 28 | line_len = 50 29 | print() 30 | print(Fore.WHITE + Back.GREEN + line_len*'-') 31 | print(Fore.WHITE + Back.GREEN + ' MACTI: Creación del repositorio del curso ' + Style.RESET_ALL) 32 | print(Fore.WHITE + Back.GREEN + line_len*'-') 33 | print(Style.RESET_ALL) 34 | 35 | c_name = input(' Nombre del curso : ') 36 | print() 37 | 38 | # --- Creación de directorios --- 39 | abspath = os.getcwd() 40 | paths = [c_name, 41 | os.path.join(c_name, 'Tema1'), 42 | os.path.join(c_name, '.ans'), 43 | os.path.join(c_name, 'resources'), 44 | ] 45 | make_dirs(paths) 46 | 47 | # --- Iniciar el repositorio local con git --- 48 | print_macti_info('Cambiando al directorio : {} '.format('/' + c_name + '/')) 49 | os.chdir(c_name) 50 | 51 | print_macti_info('Iniciando el repositorio ') 52 | os.system('git init') 53 | 54 | print_macti_info('Cambiando el nombre de la rama principal a main') 55 | os.system('git branch -M main') 56 | 57 | # --- Crear el archivo .gitignore --- 58 | lines = ["# NBGRADER \n", 59 | "nbg/ \n\n", 60 | "# QUIZ \n", 61 | "q*.ipynb \n", 62 | ".ans/ \n", 63 | ".nbgex \n", 64 | "# TOOLS \n", 65 | "resources/ \n", 66 | "macti_nbg_qs.py \n", 67 | "assignments_creation.csv \n", 68 | "assignments_update.csv \n"] 69 | 70 | print_macti_info('Creando ' + Style.BRIGHT + '.gitignore ') 71 | with open(".gitignore", "w") as f: 72 | f.writelines(lines) 73 | 74 | # --- Copiar archivos --- 75 | filenames = ['plantilla.ipynb', 76 | 'q1_plantilla.ipynb'] 77 | copy_files(filenames, abspath, paths[1]) 78 | 79 | filenames = ['nbgex', 80 | 'assignments_creation.csv', 81 | 'assignments_update.csv', 82 | 'macti_nbg_qs.py'] 83 | copy_files(filenames, abspath, paths[0]) 84 | os.rename(os.path.join(abspath, paths[0],'nbgex'), 85 | os.path.join(abspath, paths[0],'.nbgex')) 86 | 87 | filenames = ['calificador.ipynb', 88 | 'preproc_gb.ipynb', 89 | 'test_evaluation.ipynb', 90 | 'test_visual.ipynb', 91 | 'interactivo_test.ipynb'] 92 | copy_files(filenames, abspath, paths[3]) 93 | 94 | # --- Actualizar el repositorio --- 95 | print_macti_info('Estado del repositorio (git status)') 96 | os.system('git status') 97 | print_macti_info('Actualizando los cambios (git add .) ') 98 | os.system('git add .') 99 | os.system('git status') 100 | print_macti_info('Confirmando los cambios (git commit -m " ... ")') 101 | os.system('git commit -m "Iniciando el repositorio"') 102 | print_macti_info('Estado del repositorio (git status)') 103 | os.system('git status') 104 | 105 | 106 | 107 | -------------------------------------------------------------------------------- /Eval/.ipynb_checkpoints/2_Opcion_Multiple-checkpoint.ipynb: -------------------------------------------------------------------------------- 1 | { 2 | "cells": [ 3 | { 4 | "cell_type": "markdown", 5 | "id": "553d37d8-c924-47b4-8739-449782094694", 6 | "metadata": {}, 7 | "source": [ 8 | "\n", 9 | "

\n", 10 | " Evaluación de opción múltiple\n", 11 | "

\n", 12 | "\n", 13 | "\n", 14 | "\n", 15 | "La **evaluación multiple** es util para validar si una respuesta elegida (como `'a'`, `'b'`, `'c'`) es correcta.\n", 16 | "\n", 17 | "**¿Cómo funciona?**\n", 18 | "\n", 19 | "\n", 20 | "- El usuario debe de proporcionar una letra/ opción como repuesta correcta.\n", 21 | "- Se compara la respuesta propociona por el usuario con la repsuesta previamente almacenada con `FileAnswer.write()`.\n", 22 | "- Si la respuesta coincide (ignorando mayúsculas/minúsculas y espacios), se considera correcta.\n", 23 | "- Si es incorrecta, se muestra retroalimentación y se lanza una excepción (error).\n", 24 | "\n", 25 | "**¿Qué se puede cambiar en el código?**\n", 26 | "- El texto de retroalimentación mostrado cuando la respuesta es incorrecta.\n", 27 | "\n", 28 | "---\n" 29 | ] 30 | }, 31 | { 32 | "cell_type": "markdown", 33 | "id": "f802a673-1585-4f5b-887a-bfd072684115", 34 | "metadata": {}, 35 | "source": [ 36 | "## ¿Cómo se utiliza la evaluación de opción múltiple?\n", 37 | "\n", 38 | "Para usar este tipo de evaluación se debe de ajustar dos partes del flujo de trabajo:\n", 39 | "\n", 40 | "1. **Al registrar las respuestas correctas** \n", 41 | " Justo después de crear `FileAnswer()` y antes de llamar a `.to_file()`, define:\n", 42 | "\n", 43 | " ```python\n", 44 | " # 1) Definir la respuesta correcta para el ejercicio 1\n", 45 | " file_answer.write(\n", 46 | " '1', # → ID del ejercicio\n", 47 | " 'c', # → la opción correcta que quieres validar\n", 48 | " 'feedback personalizado' # → mensaje que verá el alumno si falla\n", 49 | " )\n", 50 | "\n", 51 | " ```\n", 52 | "\n", 53 | "\n", 54 | "\n", 55 | "2. **Ejecutar la comparación con lo que envió el usuario**\n", 56 | "\n", 57 | " ```python\n", 58 | " quiz.eval_option(\n", 59 | " '1', # → el mismo ID de ejercicio que se uso al definir la respuesta\n", 60 | " 'respuesta_alumno' # → la opción que el estudiante eligió (p. ej. 'a', 'b', 'c')\n", 61 | " )\n", 62 | " ```\n" 63 | ] 64 | }, 65 | { 66 | "cell_type": "markdown", 67 | "id": "239dc77a-57ea-446d-8dc8-669cfcd20784", 68 | "metadata": {}, 69 | "source": [ 70 | "## Ejemplos: evaluación de Opción Multiple\n", 71 | "\n", 72 | "A continuación se presentan ejemplos para el tipo de evaluación de Opción Multiple\n", 73 | "\n", 74 | "---" 75 | ] 76 | }, 77 | { 78 | "cell_type": "code", 79 | "execution_count": 1, 80 | "id": "fa5d1907-2a15-4471-9a2d-942889bf0968", 81 | "metadata": {}, 82 | "outputs": [], 83 | "source": [ 84 | "# Importamos los módulos necesarios para poder hacer uso de la biblioteca de MACTI\n", 85 | "from macti.eval import FileAnswer, Quiz \n", 86 | "import sympy as sy\n", 87 | "import numpy as np\n", 88 | "import pandas as pd" 89 | ] 90 | }, 91 | { 92 | "cell_type": "code", 93 | "execution_count": 2, 94 | "id": "64aeda0d-c990-431e-8b95-f94353b61ce7", 95 | "metadata": {}, 96 | "outputs": [ 97 | { 98 | "name": "stdout", 99 | "output_type": "stream", 100 | "text": [ 101 | "El directorio :/home/jovyan/MACTI_LIB/.ans/Eval/ ya existe\n", 102 | "Respuestas y retroalimentación almacenadas.\n" 103 | ] 104 | } 105 | ], 106 | "source": [ 107 | "# 1) Inicializar FileAnswer y registrar varias preguntas de opción múltiple\n", 108 | "file_answer = FileAnswer()\n", 109 | "\n", 110 | "# • '1' → ID del ejercicio; 'c' → respuesta correcta; mensaje de feedback si falla\n", 111 | "file_answer.write('1', 'c', 'Revisa tus opciones.')\n", 112 | "\n", 113 | "# • '2' → ID del ejercicio; 'a' → respuesta correcta; mensaje de feedback si falla\n", 114 | "file_answer.write('2', 'a', 'Fíjate en la definición de la variable.')\n", 115 | "\n", 116 | "# • '3' → ID del ejercicio; 'd' → respuesta correcta; mensaje de feedback si falla\n", 117 | "file_answer.write('3', 'd', 'Verifica la tabla de valores.')\n", 118 | "\n", 119 | "# • '4' → ID del ejercicio; 'b' → respuesta correcta; mensaje de feedback si falla\n", 120 | "file_answer.write('4', 'b', 'Recuerda el ejemplo visto en clase.')\n", 121 | "\n", 122 | "# 2) Exportar todas las preguntas de opción múltiple a Parquet\n", 123 | "file_answer.to_file('demo_opcion_ext')\n", 124 | "\n", 125 | "# 3) Crear Quiz para evaluar estas preguntas\n", 126 | "quiz = Quiz(qnum='demo_opcion_ext', server='local')" 127 | ] 128 | }, 129 | { 130 | "cell_type": "code", 131 | "execution_count": 3, 132 | "id": "e0149b88-d6de-4705-9006-bc93de1ef042", 133 | "metadata": {}, 134 | "outputs": [ 135 | { 136 | "name": "stdout", 137 | "output_type": "stream", 138 | "text": [ 139 | "\u001b[39m――――――――――――――――――――――――――――――――――――――――\n", 140 | "\u001b[32m1 | Tu respuesta: \u001b[39mc\u001b[32m, es correcta.\n", 141 | "\u001b[39m――――――――――――――――――――――――――――――――――――――――\n", 142 | "\u001b[39m――――――――――――――――――――――――――――――――――――――――\n", 143 | "\u001b[32m2 | Tu respuesta: \u001b[39ma\u001b[32m, es correcta.\n", 144 | "\u001b[39m――――――――――――――――――――――――――――――――――――――――\n", 145 | "\u001b[39m――――――――――――――――――――――――――――――――――――――――\n", 146 | "\u001b[32m3 | Tu respuesta: \u001b[39md\u001b[32m, es correcta.\n", 147 | "\u001b[39m――――――――――――――――――――――――――――――――――――――――\n", 148 | "\u001b[39m――――――――――――――――――――――――――――――――――――――――\n", 149 | "\u001b[32m4 | Tu respuesta: \u001b[39mb\u001b[32m, es correcta.\n", 150 | "\u001b[39m――――――――――――――――――――――――――――――――――――――――\n" 151 | ] 152 | } 153 | ], 154 | "source": [ 155 | "# 4) Evaluar respuestas de ejercicio 1\n", 156 | "quiz.eval_option('1', 'c') # ✅ coincide con la respuesta registrada\n", 157 | "#quiz.eval_option('1', 'b') # ❌ incorrecto → muestra \"Revisa tus opciones.\"\n", 158 | "\n", 159 | "# 5) Evaluar respuestas de ejercicio 2\n", 160 | "quiz.eval_option('2', 'a') # ✅ coincide\n", 161 | "#quiz.eval_option('2', 'c') # ❌ incorrecto → muestra \"Fíjate en la definición de la variable.\"\n", 162 | "\n", 163 | "# 6) Evaluar respuestas de ejercicio 3\n", 164 | "quiz.eval_option('3', 'd') # ✅ coincide\n", 165 | "#quiz.eval_option('3', 'a') # ❌ incorrecto → muestra \"Verifica la tabla de valores.\"\n", 166 | "\n", 167 | "# 7) Evaluar respuestas de ejercicio 4\n", 168 | "quiz.eval_option('4', 'b') # ✅ coincide\n", 169 | "#quiz.eval_option('4', 'c') # ❌ incorrecto → muestra \"Recuerda el ejemplo visto en clase.\"" 170 | ] 171 | }, 172 | { 173 | "cell_type": "markdown", 174 | "id": "66d0563c-b53a-4794-b545-5c407fdf7374", 175 | "metadata": {}, 176 | "source": [ 177 | "---\n", 178 | "## Conclusión: Evaluación de opción múltiple\n", 179 | "\n", 180 | "La evaluación de opción múltiple con **macti_lib** nos permite:\n", 181 | "\n", 182 | "- **Definir de forma sencilla** la respuesta correcta y el mensaje de ayuda para cada pregunta. \n", 183 | "- **Automatizar** la comparación entre la opción elegida por el alumno y la respuesta de referencia, ahorrando tiempo en la corrección manual. \n", 184 | "- **Proporcionar feedback inmediato**, mostrando en verde las respuestas correctas y en rojo las incorrectas, junto con sugerencias personalizadas. \n", 185 | " \n" 186 | ] 187 | } 188 | ], 189 | "metadata": { 190 | "kernelspec": { 191 | "display_name": "Python 3 (ipykernel)", 192 | "language": "python", 193 | "name": "python3" 194 | }, 195 | "language_info": { 196 | "codemirror_mode": { 197 | "name": "ipython", 198 | "version": 3 199 | }, 200 | "file_extension": ".py", 201 | "mimetype": "text/x-python", 202 | "name": "python", 203 | "nbconvert_exporter": "python", 204 | "pygments_lexer": "ipython3", 205 | "version": "3.11.6" 206 | } 207 | }, 208 | "nbformat": 4, 209 | "nbformat_minor": 5 210 | } 211 | -------------------------------------------------------------------------------- /Eval/2_Opcion_Multiple.ipynb: -------------------------------------------------------------------------------- 1 | { 2 | "cells": [ 3 | { 4 | "cell_type": "markdown", 5 | "id": "553d37d8-c924-47b4-8739-449782094694", 6 | "metadata": {}, 7 | "source": [ 8 | "\n", 9 | "

\n", 10 | " Evaluación de opción múltiple\n", 11 | "

\n", 12 | "\n", 13 | "\n", 14 | "\n", 15 | "La **evaluación multiple** es util para validar si una respuesta elegida (como `'a'`, `'b'`, `'c'`) es correcta.\n", 16 | "\n", 17 | "**¿Cómo funciona?**\n", 18 | "\n", 19 | "\n", 20 | "- El usuario debe de proporcionar una letra/ opción como repuesta correcta.\n", 21 | "- Se compara la respuesta propociona por el usuario con la repsuesta previamente almacenada con `FileAnswer.write()`.\n", 22 | "- Si la respuesta coincide (ignorando mayúsculas/minúsculas y espacios), se considera correcta.\n", 23 | "- Si es incorrecta, se muestra retroalimentación y se lanza una excepción (error).\n", 24 | "\n", 25 | "

¿Qué se puede personalizar?

\n", 26 | "\n", 27 | "- El texto de retroalimentación mostrado cuando la respuesta es incorrecta.\n", 28 | "\n", 29 | "---\n" 30 | ] 31 | }, 32 | { 33 | "cell_type": "markdown", 34 | "id": "f802a673-1585-4f5b-887a-bfd072684115", 35 | "metadata": {}, 36 | "source": [ 37 | "## ¿Cómo se utiliza la evaluación de opción múltiple?\n", 38 | "\n", 39 | "Para usar este tipo de evaluación se debe de ajustar dos partes del flujo de trabajo:\n", 40 | "\n", 41 | "1. **Al registrar las respuestas correctas** \n", 42 | " Justo después de crear `FileAnswer()` y antes de llamar a `.to_file()`, define:\n", 43 | "\n", 44 | " ```python\n", 45 | " # 1) Definir la respuesta correcta para el ejercicio 1\n", 46 | " file_answer.write(\n", 47 | " '1', # → ID del ejercicio\n", 48 | " 'c', # → la opción correcta que quieres validar\n", 49 | " 'feedback personalizado' # → mensaje que verá el alumno si falla\n", 50 | " )\n", 51 | "\n", 52 | " ```\n", 53 | "\n", 54 | "\n", 55 | "\n", 56 | "2. **Ejecutar la comparación con lo que envió el usuario**\n", 57 | "\n", 58 | " ```python\n", 59 | " quiz.eval_option(\n", 60 | " '1', # → el mismo ID de ejercicio que se uso al definir la respuesta\n", 61 | " 'respuesta_alumno' # → la opción que el estudiante eligió (p. ej. 'a', 'b', 'c')\n", 62 | " )\n", 63 | " ```\n" 64 | ] 65 | }, 66 | { 67 | "cell_type": "markdown", 68 | "id": "239dc77a-57ea-446d-8dc8-669cfcd20784", 69 | "metadata": {}, 70 | "source": [ 71 | "---\n", 72 | "## Ejemplos: evaluación de Opción Multiple\n", 73 | "\n", 74 | "A continuación se presentan ejemplos para el tipo de evaluación de Opción Multiple\n", 75 | "\n" 76 | ] 77 | }, 78 | { 79 | "cell_type": "code", 80 | "execution_count": 5, 81 | "id": "fa5d1907-2a15-4471-9a2d-942889bf0968", 82 | "metadata": {}, 83 | "outputs": [], 84 | "source": [ 85 | "# Importamos los módulos necesarios para poder hacer uso de la biblioteca de MACTI\n", 86 | "from macti.eval import FileAnswer, Quiz \n", 87 | "import sympy as sy\n", 88 | "import numpy as np\n", 89 | "import pandas as pd" 90 | ] 91 | }, 92 | { 93 | "cell_type": "code", 94 | "execution_count": 6, 95 | "id": "64aeda0d-c990-431e-8b95-f94353b61ce7", 96 | "metadata": {}, 97 | "outputs": [ 98 | { 99 | "name": "stdout", 100 | "output_type": "stream", 101 | "text": [ 102 | "El directorio :/home/jovyan/MACTI_LIB/.ans/Eval/ ya existe\n", 103 | "Respuestas y retroalimentación almacenadas.\n" 104 | ] 105 | } 106 | ], 107 | "source": [ 108 | "# 1) Inicializar FileAnswer y registrar varias preguntas de opción múltiple\n", 109 | "file_answer = FileAnswer()\n", 110 | "\n", 111 | "# • '1' → ID del ejercicio; 'c' → respuesta correcta; mensaje de feedback si falla\n", 112 | "file_answer.write('1', 'c', 'Revisa tus opciones.')\n", 113 | "\n", 114 | "# • '2' → ID del ejercicio; 'a' → respuesta correcta; mensaje de feedback si falla\n", 115 | "file_answer.write('2', 'a', 'Fíjate en la definición de la variable.')\n", 116 | "\n", 117 | "# • '3' → ID del ejercicio; 'd' → respuesta correcta; mensaje de feedback si falla\n", 118 | "file_answer.write('3', 'd', 'Verifica la tabla de valores.')\n", 119 | "\n", 120 | "# • '4' → ID del ejercicio; 'b' → respuesta correcta; mensaje de feedback si falla\n", 121 | "file_answer.write('4', 'b', 'Recuerda el ejemplo visto en clase.')\n", 122 | "\n", 123 | "# 2) Exportar todas las preguntas de opción múltiple a Parquet\n", 124 | "file_answer.to_file('demo_opcion_ext')\n", 125 | "\n", 126 | "# 3) Crear Quiz para evaluar estas preguntas\n", 127 | "quiz = Quiz(qnum='demo_opcion_ext', server='local')" 128 | ] 129 | }, 130 | { 131 | "cell_type": "code", 132 | "execution_count": 7, 133 | "id": "e0149b88-d6de-4705-9006-bc93de1ef042", 134 | "metadata": {}, 135 | "outputs": [ 136 | { 137 | "name": "stdout", 138 | "output_type": "stream", 139 | "text": [ 140 | "\u001b[39m――――――――――――――――――――――――――――――――――――――――\n", 141 | "\u001b[32m1 | Tu respuesta: \u001b[39mc\u001b[32m, es correcta.\n", 142 | "\u001b[39m――――――――――――――――――――――――――――――――――――――――\n", 143 | "\u001b[39m――――――――――――――――――――――――――――――――――――――――\n", 144 | "\u001b[32m2 | Tu respuesta: \u001b[39ma\u001b[32m, es correcta.\n", 145 | "\u001b[39m――――――――――――――――――――――――――――――――――――――――\n", 146 | "\u001b[39m――――――――――――――――――――――――――――――――――――――――\n", 147 | "\u001b[32m3 | Tu respuesta: \u001b[39md\u001b[32m, es correcta.\n", 148 | "\u001b[39m――――――――――――――――――――――――――――――――――――――――\n", 149 | "\u001b[39m――――――――――――――――――――――――――――――――――――――――\n", 150 | "\u001b[32m4 | Tu respuesta: \u001b[39mb\u001b[32m, es correcta.\n", 151 | "\u001b[39m――――――――――――――――――――――――――――――――――――――――\n" 152 | ] 153 | } 154 | ], 155 | "source": [ 156 | "# 4) Evaluar respuestas de ejercicio 1\n", 157 | "quiz.eval_option('1', 'c') # ✅ coincide con la respuesta registrada\n", 158 | "#quiz.eval_option('1', 'b') # ❌ incorrecto → muestra \"Revisa tus opciones.\"\n", 159 | "\n", 160 | "# 5) Evaluar respuestas de ejercicio 2\n", 161 | "quiz.eval_option('2', 'a') # ✅ coincide\n", 162 | "#quiz.eval_option('2', 'c') # ❌ incorrecto → muestra \"Fíjate en la definición de la variable.\"\n", 163 | "\n", 164 | "# 6) Evaluar respuestas de ejercicio 3\n", 165 | "quiz.eval_option('3', 'd') # ✅ coincide\n", 166 | "#quiz.eval_option('3', 'a') # ❌ incorrecto → muestra \"Verifica la tabla de valores.\"\n", 167 | "\n", 168 | "# 7) Evaluar respuestas de ejercicio 4\n", 169 | "quiz.eval_option('4', 'b') # ✅ coincide\n", 170 | "#quiz.eval_option('4', 'c') # ❌ incorrecto → muestra \"Recuerda el ejemplo visto en clase.\"" 171 | ] 172 | }, 173 | { 174 | "cell_type": "markdown", 175 | "id": "66d0563c-b53a-4794-b545-5c407fdf7374", 176 | "metadata": {}, 177 | "source": [ 178 | "---\n", 179 | "## Conclusión: Evaluación de opción múltiple\n", 180 | "\n", 181 | "La evaluación de opción múltiple con **macti_lib** nos permite:\n", 182 | "\n", 183 | "- **Definir de forma sencilla** la respuesta correcta y el mensaje de ayuda para cada pregunta. \n", 184 | "- **Automatizar** la comparación entre la opción elegida por el alumno y la respuesta de referencia, ahorrando tiempo en la corrección manual. \n", 185 | "- **Proporcionar feedback inmediato**, mostrando en verde las respuestas correctas y en rojo las incorrectas, junto con sugerencias personalizadas. \n", 186 | " \n" 187 | ] 188 | } 189 | ], 190 | "metadata": { 191 | "kernelspec": { 192 | "display_name": "Python 3 (ipykernel)", 193 | "language": "python", 194 | "name": "python3" 195 | }, 196 | "language_info": { 197 | "codemirror_mode": { 198 | "name": "ipython", 199 | "version": 3 200 | }, 201 | "file_extension": ".py", 202 | "mimetype": "text/x-python", 203 | "name": "python", 204 | "nbconvert_exporter": "python", 205 | "pygments_lexer": "ipython3", 206 | "version": "3.11.6" 207 | } 208 | }, 209 | "nbformat": 4, 210 | "nbformat_minor": 5 211 | } 212 | -------------------------------------------------------------------------------- /Eval/5_Estructuras_Datos.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 evaluar respuestas con 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 | "\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 la respuesta que se entregue sea exactamente la misma lista (en el mismo orden), se debe de ajusta dos pasos en el flujo de trabajo:\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 | "\n", 51 | "\n", 52 | "\n", 53 | "\n", 54 | "2. **Evaluar la lista enviada por el usuario**\n", 55 | "\n", 56 | "\n", 57 | " ```python\n", 58 | " quiz.eval_datastruct(\n", 59 | " '4', # → mismo ID de ejercicio que usaste arriba\n", 60 | " respuesta_alumno, # → lista que envió el estudiante\n", 61 | " inorder=True # → exige que el orden coincida\n", 62 | " )\n", 63 | "```\n" 64 | ] 65 | }, 66 | { 67 | "cell_type": "markdown", 68 | "id": "5f88a974-4caa-49f3-aca6-9017321cfcf6", 69 | "metadata": {}, 70 | "source": [ 71 | "---" 72 | ] 73 | }, 74 | { 75 | "cell_type": "markdown", 76 | "id": "d95075fb-9a3e-45ca-abe7-549f9794937e", 77 | "metadata": {}, 78 | "source": [ 79 | "## Ejemplos: evaluación de Estructuras de datos\n", 80 | "\n", 81 | "A continuación se presentan ejemplos para el tipo de Estructuras de datos\n", 82 | "\n" 83 | ] 84 | }, 85 | { 86 | "cell_type": "code", 87 | "execution_count": 4, 88 | "id": "48f85c7c-c0cb-442b-a161-068729df6c00", 89 | "metadata": {}, 90 | "outputs": [], 91 | "source": [ 92 | "# Importamos los módulos necesarios para poder hacer uso de la biblioteca de MACTI\n", 93 | "from macti.eval import FileAnswer, Quiz \n", 94 | "import sympy as sy\n", 95 | "import numpy as np\n", 96 | "import pandas as pd" 97 | ] 98 | }, 99 | { 100 | "cell_type": "code", 101 | "execution_count": 19, 102 | "id": "5dca4ccd-21fe-4bb5-b0d9-3ced52d2d937", 103 | "metadata": {}, 104 | "outputs": [ 105 | { 106 | "name": "stdout", 107 | "output_type": "stream", 108 | "text": [ 109 | "El directorio :/home/jovyan/MACTI_LIB/.ans/Eval/ ya existe\n", 110 | "Respuestas y retroalimentación almacenadas.\n" 111 | ] 112 | } 113 | ], 114 | "source": [ 115 | "# --- 1) Registrar estructuras de datos de referencia ---\n", 116 | "file_answer = FileAnswer()\n", 117 | "\n", 118 | "# Ejercicio '9': lista ordenada de nombres\n", 119 | "lista = ['luis', 'miguel', 'delacruz']\n", 120 | "file_answer.write(\n", 121 | " '9', \n", 122 | " lista, \n", 123 | " 'Checa la estructura de tipo lista.'\n", 124 | ")\n", 125 | "\n", 126 | "# Ejercicio '11': tupla ordenada de letras\n", 127 | "tupla = ('a', 'b', 'c')\n", 128 | "file_answer.write(\n", 129 | " '11', \n", 130 | " tupla, \n", 131 | " 'Checa la estructura de tipo tupla.'\n", 132 | ")\n", 133 | "\n", 134 | "# Ejercicio '13': conjunto (el orden no importa)\n", 135 | "conjunto = {'a', 'b', 'c'}\n", 136 | "file_answer.write(\n", 137 | " '13', \n", 138 | " conjunto, \n", 139 | " 'Checa la estructura de tipo conjunto.'\n", 140 | ")\n", 141 | "\n", 142 | "# Ejercicio '20': lista desordenada\n", 143 | "lista_no = ['a', 'b', 'x', '4', 'c']\n", 144 | "file_answer.write(\n", 145 | " '20', \n", 146 | " lista_no, \n", 147 | " 'Checa la lista desordenada.'\n", 148 | ")\n", 149 | "\n", 150 | "# Ejercicio '21': tupla desordenada\n", 151 | "tupla_no = ('a', 'b', 'x', '4', 'c')\n", 152 | "file_answer.write(\n", 153 | " '21', \n", 154 | " tupla_no, \n", 155 | " 'Checa la tupla desordenada.'\n", 156 | ")\n", 157 | "\n", 158 | "# Exportar a Parquet para que Quiz pueda leerlo\n", 159 | "file_answer.to_file('demo_structures')\n" 160 | ] 161 | }, 162 | { 163 | "cell_type": "code", 164 | "execution_count": 30, 165 | "id": "6054e403-beef-4949-b969-b4838d24b899", 166 | "metadata": {}, 167 | "outputs": [ 168 | { 169 | "name": "stdout", 170 | "output_type": "stream", 171 | "text": [ 172 | "\u001b[39m――――――――――――――――――――――――――――――――――――――――\n", 173 | "\u001b[32m9 | Tu resultado es correcto.\n", 174 | "\u001b[39m――――――――――――――――――――――――――――――――――――――――\n", 175 | "\u001b[39m――――――――――――――――――――――――――――――――――――――――\n", 176 | "\u001b[32m11 | Tu resultado es correcto.\n", 177 | "\u001b[39m――――――――――――――――――――――――――――――――――――――――\n", 178 | "\u001b[39m――――――――――――――――――――――――――――――――――――――――\n", 179 | "\u001b[32m13 | Tu resultado es correcto.\n", 180 | "\u001b[39m――――――――――――――――――――――――――――――――――――――――\n", 181 | "\u001b[39m――――――――――――――――――――――――――――――――――――――――\n", 182 | "\u001b[32m20 | Tu resultado es correcto.\n", 183 | "\u001b[39m――――――――――――――――――――――――――――――――――――――――\n", 184 | "\u001b[39m――――――――――――――――――――――――――――――――――――――――\n", 185 | "\u001b[32m21 | Tu resultado es correcto.\n", 186 | "\u001b[39m――――――――――――――――――――――――――――――――――――――――\n" 187 | ] 188 | } 189 | ], 190 | "source": [ 191 | "# --- 2) Evaluar estructuras de datos con Quiz ---\n", 192 | "\n", 193 | "quiz = Quiz(qnum='demo_structures', server='local')\n", 194 | "\n", 195 | "# Lista ordenada (ejercicio '9')\n", 196 | "quiz.eval_datastruct('9', ['luis', 'miguel', 'delacruz'])\n", 197 | "\n", 198 | "# Tupla ordenada (ejercicio '11')\n", 199 | "quiz.eval_datastruct('11', ('a', 'b', 'c'))\n", 200 | "\n", 201 | "# Conjunto (ejercicio '13', orden no importa)\n", 202 | "quiz.eval_datastruct('13', {'c', 'b', 'a'}, in_order= False )\n", 203 | "\n", 204 | "# Lista desordenada (ejercicio '20', permite cualquier orden)\n", 205 | "quiz.eval_datastruct('20', ['b', 'a', 'x', 'c', '4'], in_order= False )\n", 206 | "\n", 207 | "# Tupla desordenada (ejercicio '21', permite cualquier orden)\n", 208 | "quiz.eval_datastruct('21', ('x', '4', 'a', 'c', 'b'), in_order= False )\n" 209 | ] 210 | }, 211 | { 212 | "cell_type": "markdown", 213 | "id": "ee89a517-46a5-465a-aedc-5b43aa405e6e", 214 | "metadata": {}, 215 | "source": [ 216 | "---\n", 217 | "## Conclusión: Evaluación de estructuras de datos\n", 218 | "\n", 219 | "Con la biblioteca **macti_lib** la evaluación de estructuras de datos te permite:\n", 220 | "\n", 221 | "- **Definir fácilmente** la colección de referencia (lista, tupla o conjunto). \n", 222 | "- **Elegir si importa el orden** (`in_order=True`) o no (`in_order=False`) según el tipo de ejercicio. \n", 223 | "- **Comparar automáticamente** los elementos entregados por el alumno con los de referencia. \n", 224 | "- **Mostrar feedback inmediato**, pintando en verde cuando coincide y en rojo con sugerencias cuando falla. \n", 225 | "\n" 226 | ] 227 | } 228 | ], 229 | "metadata": { 230 | "kernelspec": { 231 | "display_name": "Python 3 (ipykernel)", 232 | "language": "python", 233 | "name": "python3" 234 | }, 235 | "language_info": { 236 | "codemirror_mode": { 237 | "name": "ipython", 238 | "version": 3 239 | }, 240 | "file_extension": ".py", 241 | "mimetype": "text/x-python", 242 | "name": "python", 243 | "nbconvert_exporter": "python", 244 | "pygments_lexer": "ipython3", 245 | "version": "3.11.6" 246 | } 247 | }, 248 | "nbformat": 4, 249 | "nbformat_minor": 5 250 | } 251 | -------------------------------------------------------------------------------- /Eval/6_Diccionarios.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 | "editable": true, 31 | "slideshow": { 32 | "slide_type": "" 33 | }, 34 | "tags": [] 35 | }, 36 | "source": [ 37 | "\n", 38 | "## ¿Cómo se utiliza la evaluación de diccionarios numéricos?\n", 39 | "\n", 40 | "Para validar que el usuario entregue un diccionario con las mismas claves y valores (numéricos), se debe de ajustar dos pasos en tu flujo de trabajo:\n", 41 | "\n", 42 | "1. **Registrar el diccionario de referencia** \n", 43 | " Después de crear `FileAnswer()` y antes de llamar a `.to_file()`, define el diccionario correcto:\n", 44 | "\n", 45 | " ```python\n", 46 | " # 1) Definir la respuesta de referencia para el ejercicio '5'\n", 47 | " file_answer.write(\n", 48 | " '5', # → ID del ejercicio\n", 49 | " {1: 2.0, 2: 4.0}, # → diccionario de referencia\n", 50 | " 'Comprueba claves y valores.' # → mensaje si el alumno falla\n", 51 | " )\n", 52 | "\n", 53 | " ```\n", 54 | "\n", 55 | "2. **Al evaluar la respuesta del usuario**\n", 56 | "\n", 57 | " ```python\n", 58 | " quiz.eval_dict(\n", 59 | " '5', # → mismo ID de ejercicio que usaste arriba\n", 60 | " respuesta_alumno, # → dict que envió el estudiante\n", 61 | " numeric=True # → compara valores numéricos\n", 62 | " )\n", 63 | " ```\n" 64 | ] 65 | }, 66 | { 67 | "cell_type": "markdown", 68 | "id": "1205dcfe-f720-4ada-ba3e-1ff6aaea95b2", 69 | "metadata": {}, 70 | "source": [ 71 | "## Ejemplos: evaluación de Estructuras de datos\n", 72 | "\n", 73 | "A continuación se presentan ejemplos para el tipo de Estructuras de datos\n", 74 | "\n", 75 | "---" 76 | ] 77 | }, 78 | { 79 | "cell_type": "code", 80 | "execution_count": 1, 81 | "id": "5356bec2-e34a-4111-ad70-552a0faa4b53", 82 | "metadata": {}, 83 | "outputs": [], 84 | "source": [ 85 | "# Importamos los módulos necesarios para poder hacer uso de la biblioteca de MACTI\n", 86 | "from macti.eval import FileAnswer, Quiz \n", 87 | "import sympy as sy\n", 88 | "import numpy as np\n", 89 | "import pandas as pd" 90 | ] 91 | }, 92 | { 93 | "cell_type": "code", 94 | "execution_count": 4, 95 | "id": "c99e22e4-8fe3-4146-9e5f-ab7a58b495ab", 96 | "metadata": {}, 97 | "outputs": [ 98 | { 99 | "name": "stdout", 100 | "output_type": "stream", 101 | "text": [ 102 | "El directorio :/home/jovyan/MACTI_LIB/.ans/Eval/ ya existe\n", 103 | "Respuestas y retroalimentación almacenadas.\n" 104 | ] 105 | } 106 | ], 107 | "source": [ 108 | "# --- 1) Registrar diccionarios de referencia ---\n", 109 | "file_answer = FileAnswer()\n", 110 | "\n", 111 | "# Ejercicio '5': diccionario numérico\n", 112 | "file_answer.write(\n", 113 | " '5',\n", 114 | " {1: 3.446, 2: 5.6423, 3: 2.234324},\n", 115 | " 'Checa las claves y valores numéricos.'\n", 116 | ")\n", 117 | "\n", 118 | "# Ejercicio '14': otro diccionario numérico\n", 119 | "file_answer.write(\n", 120 | " '14',\n", 121 | " {10: 0.123, 20: 0.456, 30: 0.789},\n", 122 | " 'Verifica tus valores flotantes.'\n", 123 | ")\n", 124 | "\n", 125 | "# Ejercicio '15': diccionario con claves de texto y valores numéricos\n", 126 | "file_answer.write(\n", 127 | " '15',\n", 128 | " {'k1': 1, 'k2': 2, 'k3': 3},\n", 129 | " 'Asegúrate de usar las mismas claves y valores numéricos.'\n", 130 | ")\n", 131 | "\n", 132 | "# Ejercicio '16': diccionario de texto (comparación exacta)\n", 133 | "file_answer.write(\n", 134 | " '16',\n", 135 | " {'a': 'hola', 'b': 'mundo'},\n", 136 | " 'Comprueba tus cadenas de texto.'\n", 137 | ")\n", 138 | "\n", 139 | "# Ejercicio '18': diccionario con listas numéricas como valores\n", 140 | "#file_answer.write(\n", 141 | " # '18',\n", 142 | " # {1: [1, 2], 2: [3, 4]},\n", 143 | " # 'Revisa cada lista de valores numéricos.'\n", 144 | "#)\n", 145 | "\n", 146 | "# Exportar respuestas y feedback a Parquet\n", 147 | "file_answer.to_file('demo_dict_extended_01')\n" 148 | ] 149 | }, 150 | { 151 | "cell_type": "code", 152 | "execution_count": 5, 153 | "id": "b8f16f02-9989-4e3c-a53b-4f9e04b70c08", 154 | "metadata": {}, 155 | "outputs": [ 156 | { 157 | "name": "stdout", 158 | "output_type": "stream", 159 | "text": [ 160 | "\u001b[39m――――――――――――――――――――――――――――――――――――――――\n", 161 | "\u001b[32m5_val_2 | Tu resultado es correcto.\n", 162 | "\u001b[39m――――――――――――――――――――――――――――――――――――――――\n", 163 | "\u001b[39m――――――――――――――――――――――――――――――――――――――――\n", 164 | "\u001b[32m14_val_2 | Tu resultado es correcto.\n", 165 | "\u001b[39m――――――――――――――――――――――――――――――――――――――――\n", 166 | "\u001b[39m――――――――――――――――――――――――――――――――――――――――\n", 167 | "\u001b[32m15_val_2 | Tu resultado es correcto.\n", 168 | "\u001b[39m――――――――――――――――――――――――――――――――――――――――\n", 169 | "\u001b[39m――――――――――――――――――――――――――――――――――――――――\n", 170 | "\u001b[32m16_val_1 | Tu resultado es correcto.\n", 171 | "\u001b[39m――――――――――――――――――――――――――――――――――――――――\n" 172 | ] 173 | } 174 | ], 175 | "source": [ 176 | "# --- 2) Evaluar diccionarios con Quiz ---\n", 177 | "\n", 178 | "quiz = Quiz(qnum='demo_dict_extended_01', server='local')\n", 179 | "\n", 180 | "# Ejercicio '5': diccionario numérico simple\n", 181 | "quiz.eval_dict('5', {1: 3.446, 2: 5.6423, 3: 2.234324}, numeric=True)\n", 182 | "\n", 183 | "# Ejercicio '14': otro diccionario de flotantes\n", 184 | "quiz.eval_dict('14', {10: 0.123, 20: 0.456, 30: 0.789}, numeric=True)\n", 185 | "\n", 186 | "# Ejercicio '15': diccionario con claves de texto y valores numéricos\n", 187 | "quiz.eval_dict('15', {'k1': 1, 'k2': 2, 'k3': 3}, numeric=True)\n", 188 | "\n", 189 | "# Ejercicio '16': diccionario de cadenas (comparación exacta)\n", 190 | "quiz.eval_dict('16', {'a': 'hola', 'b': 'mundo'}, numeric=False)\n", 191 | "\n", 192 | "# Ejercicio '18': diccionario con listas numéricas como valores\n", 193 | "# quiz.eval_dict('18', {1: [1, 2], 2: [3, 4]}, numeric=True)" 194 | ] 195 | }, 196 | { 197 | "cell_type": "markdown", 198 | "id": "1509971e-a6fe-44bf-bcf0-2e8c553566ed", 199 | "metadata": {}, 200 | "source": [ 201 | "---\n", 202 | "## Conclusión: Evaluación de diccionarios\n", 203 | "\n", 204 | "La evaluación de diccionarios la biblioteca de **macti_lib** permite:\n", 205 | "\n", 206 | "- **Definir de forma precisa** la “respuesta correcta” como un objeto `dict`, registrando tanto claves como valores. \n", 207 | "- **Desglosar automáticamente** el dict en sub-IDs (`_len`, `_key`, `_val_i`) para validar por separado la longitud, las claves y cada valor. \n", 208 | "- **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", 209 | "- **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" 210 | ] 211 | } 212 | ], 213 | "metadata": { 214 | "kernelspec": { 215 | "display_name": "Python 3 (ipykernel)", 216 | "language": "python", 217 | "name": "python3" 218 | }, 219 | "language_info": { 220 | "codemirror_mode": { 221 | "name": "ipython", 222 | "version": 3 223 | }, 224 | "file_extension": ".py", 225 | "mimetype": "text/x-python", 226 | "name": "python", 227 | "nbconvert_exporter": "python", 228 | "pygments_lexer": "ipython3", 229 | "version": "3.11.6" 230 | } 231 | }, 232 | "nbformat": 4, 233 | "nbformat_minor": 5 234 | } 235 | -------------------------------------------------------------------------------- /Eval/4_Valores_Numericos.ipynb: -------------------------------------------------------------------------------- 1 | { 2 | "cells": [ 3 | { 4 | "cell_type": "markdown", 5 | "id": "6ee01713-eb76-48b3-8751-c530f093bb1a", 6 | "metadata": {}, 7 | "source": [ 8 | "\n", 9 | "

\n", 10 | " Evaluación de valores numéricos\n", 11 | "

\n", 12 | "\n", 13 | "La evaluación de **valores numéricos** permite comprobar respuestas como:\n", 14 | "\n", 15 | "- Números simples (`int`, `float`) \n", 16 | "- Números complejos (`complex`) \n", 17 | "- Vectores y arreglos (`list`, `tuple`, `np.ndarray`)\n", 18 | "\n", 19 | "**¿Cómo funciona?** \n", 20 | "- Compara la respuesta del usuario con los valores de referencia mediante tolerancia numérica (`np.allclose`).\n", 21 | "\n", 22 | "**¿Qué se puede personalizar?** \n", 23 | "- El tipo de dato numérico o la estructura de datos evaluada. \n", 24 | "\n", 25 | "---" 26 | ] 27 | }, 28 | { 29 | "cell_type": "markdown", 30 | "id": "84c36c17-7872-45f5-af19-7ba3ffee7cee", 31 | "metadata": {}, 32 | "source": [ 33 | "## ¿Cómo se utiliza la evaluación numérica?\n", 34 | "\n", 35 | "Para usar este tipo de evaluación se debe de ajustar dos partes del flujo de trabajo:\n", 36 | "\n", 37 | "1. **Registrar el valor de referencia** \n", 38 | " Después de crear `FileAnswer()` y antes de llamar a `.to_file()`, escribe el valor correcto:\n", 39 | "\n", 40 | " ```python\n", 41 | " # 1) Definir el valor de referencia para el ejercicio '3'\n", 42 | " file_answer.write(\n", 43 | " '3', # → ID del ejercicio\n", 44 | " valor_correcto, # → valor numérico de referencia (int, float, etc.)\n", 45 | " 'Aquí va tu feedback personalizado' # → mensaje que verá el alumno si falla\n", 46 | " )\n", 47 | "\n", 48 | " ```\n", 49 | " \n", 50 | "\n", 51 | "2. **Ejecutar la comparación con lo que envió el usuario**\n", 52 | "\n", 53 | "\n", 54 | " ```python\n", 55 | " quiz.eval_numeric(\n", 56 | " '3', # → mismo ID de ejercicio que usaste arriba\n", 57 | " respuesta_del_alumno # → valor calculado por el estudiante\n", 58 | " )\n", 59 | "\n", 60 | " ```\n", 61 | "\n", 62 | "---" 63 | ] 64 | }, 65 | { 66 | "cell_type": "markdown", 67 | "id": "07b845f8-2a6f-46be-83ac-be61730069cb", 68 | "metadata": {}, 69 | "source": [ 70 | "## Ejemplos: evaluación de valores númericos\n", 71 | "\n", 72 | "A continuación se presentan ejemplos para el tipo de valores númericos\n", 73 | "\n" 74 | ] 75 | }, 76 | { 77 | "cell_type": "code", 78 | "execution_count": 1, 79 | "id": "8793032d-ae15-40e1-83b2-dffd94776d77", 80 | "metadata": {}, 81 | "outputs": [], 82 | "source": [ 83 | "# Importamos los módulos necesarios para poder hacer uso de la biblioteca de MACTI\n", 84 | "from macti.eval import FileAnswer, Quiz \n", 85 | "import sympy as sy\n", 86 | "import numpy as np\n", 87 | "import pandas as pd" 88 | ] 89 | }, 90 | { 91 | "cell_type": "code", 92 | "execution_count": 2, 93 | "id": "5c68da7a-a3f3-4de1-863f-3782cf937874", 94 | "metadata": {}, 95 | "outputs": [ 96 | { 97 | "name": "stdout", 98 | "output_type": "stream", 99 | "text": [ 100 | "El directorio :/home/jovyan/MACTI_LIB/.ans/Eval/ ya existe\n", 101 | "Respuestas y retroalimentación almacenadas.\n" 102 | ] 103 | } 104 | ], 105 | "source": [ 106 | "# --- 1) Registrar valores de referencia numéricos ---\n", 107 | "\n", 108 | "file_answer = FileAnswer()\n", 109 | "\n", 110 | "# Ejercicio '4': valor float\n", 111 | "file_answer.write(\n", 112 | " '4',\n", 113 | " 0.1,\n", 114 | " 'Calcula con mayor precisión.'\n", 115 | ")\n", 116 | "\n", 117 | "# Ejercicio '5': valor entero\n", 118 | "file_answer.write(\n", 119 | " '5',\n", 120 | " 1,\n", 121 | " 'Verifica que sea un entero.'\n", 122 | ")\n", 123 | "\n", 124 | "# Ejercicio '6': valor booleano\n", 125 | "file_answer.write(\n", 126 | " '6',\n", 127 | " True,\n", 128 | " 'Recuerda distinguir True de False.'\n", 129 | ")\n", 130 | "\n", 131 | "# Ejercicio '7': número complejo\n", 132 | "file_answer.write(\n", 133 | " '7',\n", 134 | " 1 + 5j,\n", 135 | " 'Comprueba las partes real e imaginaria.'\n", 136 | ")\n", 137 | "\n", 138 | "# Ejercicio '8': lista de números\n", 139 | "file_answer.write(\n", 140 | " '8',\n", 141 | " [0, 1, 3.4],\n", 142 | " 'Revisa cada elemento de la lista.'\n", 143 | ")\n", 144 | "\n", 145 | "# Ejercicio '12': conjunto numérico (el orden no importa)\n", 146 | "file_answer.write(\n", 147 | " '12',\n", 148 | " {1, 2, 3, 4, 5, 6},\n", 149 | " 'Asegúrate de incluir todos los elementos.'\n", 150 | ")\n", 151 | "\n", 152 | "# Ejercicio '17': arreglo NumPy\n", 153 | "w = np.sin(np.linspace(0, 1, 10))\n", 154 | "file_answer.write(\n", 155 | " '17',\n", 156 | " w,\n", 157 | " 'Comprueba tu arreglo numérico.'\n", 158 | ")\n", 159 | "\n", 160 | "# 1.8) Exportar a Parquet para que Quiz pueda leerlo\n", 161 | "file_answer.to_file('demo_numeric')\n" 162 | ] 163 | }, 164 | { 165 | "cell_type": "code", 166 | "execution_count": 3, 167 | "id": "bedeac0d-ac8f-4ed2-a6ee-9b90968f70d9", 168 | "metadata": {}, 169 | "outputs": [ 170 | { 171 | "name": "stdout", 172 | "output_type": "stream", 173 | "text": [ 174 | "\u001b[39m――――――――――――――――――――――――――――――――――――――――\n", 175 | "\u001b[32m4 | Tu resultado es correcto.\n", 176 | "\u001b[39m――――――――――――――――――――――――――――――――――――――――\n", 177 | "\u001b[39m――――――――――――――――――――――――――――――――――――――――\n", 178 | "\u001b[32m5 | Tu resultado es correcto.\n", 179 | "\u001b[39m――――――――――――――――――――――――――――――――――――――――\n", 180 | "\u001b[39m――――――――――――――――――――――――――――――――――――――――\n", 181 | "\u001b[32m6 | Tu resultado es correcto.\n", 182 | "\u001b[39m――――――――――――――――――――――――――――――――――――――――\n", 183 | "\u001b[39m――――――――――――――――――――――――――――――――――――――――\n", 184 | "\u001b[32m7 | Tu resultado es correcto.\n", 185 | "\u001b[39m――――――――――――――――――――――――――――――――――――――――\n", 186 | "\u001b[39m――――――――――――――――――――――――――――――――――――――――\n", 187 | "\u001b[32m8 | Tu resultado es correcto.\n", 188 | "\u001b[39m――――――――――――――――――――――――――――――――――――――――\n", 189 | "\u001b[39m――――――――――――――――――――――――――――――――――――――――\n", 190 | "\u001b[32m12 | Tu resultado es correcto.\n", 191 | "\u001b[39m――――――――――――――――――――――――――――――――――――――――\n", 192 | "\u001b[39m――――――――――――――――――――――――――――――――――――――――\n", 193 | "\u001b[32m17 | Tu resultado es correcto.\n", 194 | "\u001b[39m――――――――――――――――――――――――――――――――――――――――\n" 195 | ] 196 | } 197 | ], 198 | "source": [ 199 | "# --- 2) Evaluar valores numéricos con Quiz ---\n", 200 | "\n", 201 | "quiz = Quiz(qnum='demo_numeric', server='local')\n", 202 | "\n", 203 | "# Flotante\n", 204 | "quiz.eval_numeric('4', 0.1) # ✅ coincide exactamente\n", 205 | "# quiz.eval_numeric('4', 0.100001) # ✅ dentro de la tolerancia\n", 206 | "\n", 207 | "# Entero\n", 208 | "quiz.eval_numeric('5', 1) # ✅ coincide\n", 209 | "# quiz.eval_numeric('5', 0) # ❌ lanza AssertionError\n", 210 | "\n", 211 | "# Booleano\n", 212 | "quiz.eval_numeric('6', True) # ✅ coincide\n", 213 | "# quiz.eval_numeric('6', False) # ❌ lanza AssertionError\n", 214 | "\n", 215 | "# Número complejo\n", 216 | "quiz.eval_numeric('7', 1 + 5j) # ✅ coincide\n", 217 | "# quiz.eval_numeric('7', 1 + 4.9j) # ❌ lanza AssertionError\n", 218 | "\n", 219 | "# Lista\n", 220 | "quiz.eval_numeric('8', [0, 1, 3.4]) # ✅ coincide\n", 221 | "# quiz.eval_numeric('8', [0, 1, 3.5]) # ❌ lanza AssertionError\n", 222 | "\n", 223 | "# Conjunto (el orden no importa)\n", 224 | "quiz.eval_numeric('12', {1, 2, 3, 4, 5, 6}) # ✅ coincide\n", 225 | "# quiz.eval_numeric('12', {1, 2, 3, 4, 5}) # ❌ lanza AssertionError\n", 226 | "\n", 227 | "# Arreglo de NumPy\n", 228 | "quiz.eval_numeric('17', w) # ✅ coincide\n", 229 | "# quiz.eval_numeric('17', w + 0.001) # ❌ fuera de tolerancia\n" 230 | ] 231 | }, 232 | { 233 | "cell_type": "markdown", 234 | "id": "dee24374-93c9-419e-b572-650c1bbe6d23", 235 | "metadata": {}, 236 | "source": [ 237 | "---\n", 238 | "## Conclusión: Evaluación de valores numéricos\n", 239 | "\n", 240 | "Con la biblioteca de **macti_lib** la evaluación numérica en notebooks nos ofrece:\n", 241 | "\n", 242 | "- **Soporte versátil** para distintos tipos de datos: enteros, flotantes, booleanos, complejos, listas, conjuntos y arreglos NumPy. \n", 243 | "- **Comparaciones con tolerancia** que permiten pequeñas variaciones (por ejemplo, en cálculos de punto flotante) sin penalizar respuestas válidas. \n", 244 | "- **Feedback inmediato** y detallado: se muestran resultados correctos en verde y, en caso de error, en rojo con sugerencias específicas para corregir la respuesta. \n" 245 | ] 246 | } 247 | ], 248 | "metadata": { 249 | "kernelspec": { 250 | "display_name": "Python 3 (ipykernel)", 251 | "language": "python", 252 | "name": "python3" 253 | }, 254 | "language_info": { 255 | "codemirror_mode": { 256 | "name": "ipython", 257 | "version": 3 258 | }, 259 | "file_extension": ".py", 260 | "mimetype": "text/x-python", 261 | "name": "python", 262 | "nbconvert_exporter": "python", 263 | "pygments_lexer": "ipython3", 264 | "version": "3.11.6" 265 | } 266 | }, 267 | "nbformat": 4, 268 | "nbformat_minor": 5 269 | } 270 | -------------------------------------------------------------------------------- /Eval/3_Expresiones_Simbolicas.ipynb: -------------------------------------------------------------------------------- 1 | { 2 | "cells": [ 3 | { 4 | "cell_type": "markdown", 5 | "id": "5782f249-c963-4e3b-ae37-8ed3461c415d", 6 | "metadata": {}, 7 | "source": [ 8 | "

\n", 9 | " Evaluación de expresiones simbólicas\n", 10 | "

\n", 11 | "\n", 12 | "

\n", 13 | "La evaluación de expresiones simbólicas permite comprobar respuestas equivalentes usando SymPy —por ejemplo, derivadas, integrales u otras transformaciones simbólicas— de forma totalmente automática.\n", 14 | "

\n", 15 | "\n", 16 | "

¿Cómo funciona?

\n", 17 | "\n", 22 | "\n", 23 | "

¿Qué se puede personalizar?

\n", 24 | "\n", 28 | "\n", 29 | "---" 30 | ] 31 | }, 32 | { 33 | "cell_type": "markdown", 34 | "id": "bd0d8523-fc56-4b37-9864-68d5042b57fe", 35 | "metadata": {}, 36 | "source": [ 37 | "## ¿Cómo se utiliza la evaluación de expresiones simbólicas?\n", 38 | "\n", 39 | "Para usar este tipo de evaluación se debe de ajustar dos partes del flujo de trabajo:\n", 40 | "\n", 41 | "1. **Registrar la expresión de referencia** \n", 42 | " Después de crear `FileAnswer()` y antes de llamar a `.to_file()`, define la expresión correcta como cadena:\n", 43 | "\n", 44 | " ```python\n", 45 | " # 1) Definir la expresión de referencia para el ejercicio '2'\n", 46 | " from sympy import Symbol\n", 47 | "\n", 48 | " x = Symbol('x')\n", 49 | " expr = x**2 # ejemplo: la función cuya derivada queremos evaluar\n", 50 | " ```\n", 51 | " \n", 52 | "2. **Ejecutar la comparación con lo que envió el usuario**\n", 53 | "\n", 54 | " ```python\n", 55 | " file_answer.write(\n", 56 | " '2', # → ID del ejercicio\n", 57 | " str(expr), # → la expresión correcta como string\n", 58 | " 'Revisa la derivación simbólica.' # → mensaje si el alumno falla\n", 59 | " )\n", 60 | "\n", 61 | " ```\n" 62 | ] 63 | }, 64 | { 65 | "cell_type": "markdown", 66 | "id": "cec26e64-face-4b3e-8d4f-a8320d81fd1d", 67 | "metadata": {}, 68 | "source": [ 69 | "---\n", 70 | "## Ejemplos: evaluación de expresiones simbólicas\n", 71 | "\n", 72 | "A continuación se presentan ejemplos para el tipo de evaluación simbolica\n", 73 | "\n" 74 | ] 75 | }, 76 | { 77 | "cell_type": "code", 78 | "execution_count": 1, 79 | "id": "340d7a5a-03db-4d86-a7fb-0eaf284a2fbf", 80 | "metadata": {}, 81 | "outputs": [], 82 | "source": [ 83 | "# Importamos los módulos necesarios para poder hacer uso de la biblioteca de MACTI\n", 84 | "from macti.eval import FileAnswer, Quiz \n", 85 | "import sympy as sy\n", 86 | "import numpy as np\n", 87 | "import pandas as pd" 88 | ] 89 | }, 90 | { 91 | "cell_type": "code", 92 | "execution_count": 2, 93 | "id": "46f337ce-0c60-40e1-8766-8319cae9e3d2", 94 | "metadata": {}, 95 | "outputs": [ 96 | { 97 | "name": "stdout", 98 | "output_type": "stream", 99 | "text": [ 100 | "El directorio :/home/jovyan/MACTI_LIB/.ans/Eval/ ya existe\n", 101 | "Respuestas y retroalimentación almacenadas.\n" 102 | ] 103 | } 104 | ], 105 | "source": [ 106 | "# --- 1) Registrar las expresiones simbólicas (respuestas correctas) ---\n", 107 | "\n", 108 | "file_answer = FileAnswer()\n", 109 | "\n", 110 | "# Ejercicio '2': derivada de x*x\n", 111 | "x = sy.Symbol('x')\n", 112 | "derivada = x * x\n", 113 | "file_answer.write('2', str(derivada), 'Checa las reglas de derivación')\n", 114 | "\n", 115 | "# Ejercicio '3': forma cuadrática\n", 116 | "y = sy.Symbol('y')\n", 117 | "A = np.array([[0.10, -1.], [0.30, -1.]])\n", 118 | "B = np.array([-200, 20])\n", 119 | "forma_cuadratica = (\n", 120 | " 0.5 * A[0,0] * x**2\n", 121 | " + 0.5 * A[1,1] * y**2\n", 122 | " + 0.5 * (A[0,1] + A[1,0]) * x * y\n", 123 | " - B[0] * x\n", 124 | " - B[1] * y\n", 125 | ")\n", 126 | "file_answer.write('3', str(forma_cuadratica), 'Revisa tus operaciones algebraicas para calcular f(x)')\n", 127 | "\n", 128 | "# Ejercicio '4': integral de sin(x) dx\n", 129 | "int_sin = sy.integrate(sy.sin(x), x)\n", 130 | "file_answer.write('4', str(int_sin), 'Verifica tu resultado de la integral')\n", 131 | "\n", 132 | "# Ejercicio '5': simplificación de identidad trigonométrica\n", 133 | "expr_id = sy.sin(x)**2 + sy.cos(x)**2\n", 134 | "simplified = sy.simplify(expr_id)\n", 135 | "file_answer.write('5', str(simplified), 'Comprueba la identidad trigonométrica')\n", 136 | "\n", 137 | "# Ejercicio '6': serie de Taylor de e^x hasta orden 3\n", 138 | "series_exp = sy.series(sy.exp(x), x, 0, 4).removeO()\n", 139 | "file_answer.write('6', str(series_exp), 'Revisa tu serie de Taylor')\n", 140 | "\n", 141 | "# Ejercicio '7': derivada parcial ∂/∂y de x^2 * y^3\n", 142 | "partial_y = sy.diff(x**2 * y**3, y)\n", 143 | "file_answer.write('7', str(partial_y), 'Verifica tu derivada parcial')\n", 144 | "\n", 145 | "# 1.8) Exportar a Parquet para que Quiz pueda leerlo\n", 146 | "file_answer.to_file('test01')\n" 147 | ] 148 | }, 149 | { 150 | "cell_type": "code", 151 | "execution_count": 3, 152 | "id": "ea6dc1f8-8621-48a0-9aaf-755c93e4a3ea", 153 | "metadata": {}, 154 | "outputs": [ 155 | { 156 | "name": "stdout", 157 | "output_type": "stream", 158 | "text": [ 159 | "\u001b[39m――――――――――――――――――――――――――――――――――――――――\n", 160 | "\u001b[32m2 | Tu respuesta:\n" 161 | ] 162 | }, 163 | { 164 | "data": { 165 | "text/latex": [ 166 | "$\\displaystyle x^{2}$" 167 | ], 168 | "text/plain": [ 169 | "x**2" 170 | ] 171 | }, 172 | "metadata": {}, 173 | "output_type": "display_data" 174 | }, 175 | { 176 | "name": "stdout", 177 | "output_type": "stream", 178 | "text": [ 179 | "\u001b[32mes correcta.\n", 180 | "\u001b[39m――――――――――――――――――――――――――――――――――――――――\n", 181 | "\u001b[39m――――――――――――――――――――――――――――――――――――――――\n", 182 | "\u001b[32m3 | Tu respuesta:\n" 183 | ] 184 | }, 185 | { 186 | "data": { 187 | "text/latex": [ 188 | "$\\displaystyle 0.05 x^{2} - 0.35 x y + 200 x - 0.5 y^{2} - 20 y$" 189 | ], 190 | "text/plain": [ 191 | "0.05*x**2 - 0.35*x*y + 200*x - 0.5*y**2 - 20*y" 192 | ] 193 | }, 194 | "metadata": {}, 195 | "output_type": "display_data" 196 | }, 197 | { 198 | "name": "stdout", 199 | "output_type": "stream", 200 | "text": [ 201 | "\u001b[32mes correcta.\n", 202 | "\u001b[39m――――――――――――――――――――――――――――――――――――――――\n", 203 | "\u001b[39m――――――――――――――――――――――――――――――――――――――――\n", 204 | "\u001b[32m4 | Tu respuesta:\n" 205 | ] 206 | }, 207 | { 208 | "data": { 209 | "text/latex": [ 210 | "$\\displaystyle - \\cos{\\left(x \\right)}$" 211 | ], 212 | "text/plain": [ 213 | "-cos(x)" 214 | ] 215 | }, 216 | "metadata": {}, 217 | "output_type": "display_data" 218 | }, 219 | { 220 | "name": "stdout", 221 | "output_type": "stream", 222 | "text": [ 223 | "\u001b[32mes correcta.\n", 224 | "\u001b[39m――――――――――――――――――――――――――――――――――――――――\n", 225 | "\u001b[39m――――――――――――――――――――――――――――――――――――――――\n", 226 | "\u001b[32m5 | Tu respuesta:\n" 227 | ] 228 | }, 229 | { 230 | "data": { 231 | "text/latex": [ 232 | "$\\displaystyle 1$" 233 | ], 234 | "text/plain": [ 235 | "1" 236 | ] 237 | }, 238 | "metadata": {}, 239 | "output_type": "display_data" 240 | }, 241 | { 242 | "name": "stdout", 243 | "output_type": "stream", 244 | "text": [ 245 | "\u001b[32mes correcta.\n", 246 | "\u001b[39m――――――――――――――――――――――――――――――――――――――――\n", 247 | "\u001b[39m――――――――――――――――――――――――――――――――――――――――\n", 248 | "\u001b[32m6 | Tu respuesta:\n" 249 | ] 250 | }, 251 | { 252 | "data": { 253 | "text/latex": [ 254 | "$\\displaystyle \\frac{x^{3}}{6} + \\frac{x^{2}}{2} + x + 1$" 255 | ], 256 | "text/plain": [ 257 | "x**3/6 + x**2/2 + x + 1" 258 | ] 259 | }, 260 | "metadata": {}, 261 | "output_type": "display_data" 262 | }, 263 | { 264 | "name": "stdout", 265 | "output_type": "stream", 266 | "text": [ 267 | "\u001b[32mes correcta.\n", 268 | "\u001b[39m――――――――――――――――――――――――――――――――――――――――\n", 269 | "\u001b[39m――――――――――――――――――――――――――――――――――――――――\n", 270 | "\u001b[32m7 | Tu respuesta:\n" 271 | ] 272 | }, 273 | { 274 | "data": { 275 | "text/latex": [ 276 | "$\\displaystyle 3 x^{2} y^{2}$" 277 | ], 278 | "text/plain": [ 279 | "3*x**2*y**2" 280 | ] 281 | }, 282 | "metadata": {}, 283 | "output_type": "display_data" 284 | }, 285 | { 286 | "name": "stdout", 287 | "output_type": "stream", 288 | "text": [ 289 | "\u001b[32mes correcta.\n", 290 | "\u001b[39m――――――――――――――――――――――――――――――――――――――――\n" 291 | ] 292 | } 293 | ], 294 | "source": [ 295 | "# --- 2) Evaluar las expresiones simbólicas con Quiz ---\n", 296 | "\n", 297 | "# 2.1 Inicializar Quiz (usa el mismo qnum que pasaste a to_file)\n", 298 | "quiz = Quiz(qnum='test01', server='local') # Carga las expresiones de referencia\n", 299 | "\n", 300 | "# 2.2 Evaluar la derivada de x*x (ejercicio '2')\n", 301 | "quiz.eval_expression('2', derivada)\n", 302 | "\n", 303 | "# 2.3 Evaluar la forma cuadrática (ejercicio '3')\n", 304 | "quiz.eval_expression('3', forma_cuadratica)\n", 305 | "\n", 306 | "# 2.4 Evaluar la integral de sin(x) dx (ejercicio '4')\n", 307 | "quiz.eval_expression('4', int_sin)\n", 308 | "\n", 309 | "# 2.5 Evaluar la simplificación de la identidad sin²(x)+cos²(x) (ejercicio '5')\n", 310 | "quiz.eval_expression('5', simplified)\n", 311 | "\n", 312 | "# 2.6 Evaluar la serie de Taylor de e^x hasta orden 3 (ejercicio '6')\n", 313 | "quiz.eval_expression('6', series_exp)\n", 314 | "\n", 315 | "# 2.7 Evaluar la derivada parcial ∂/∂y de x²·y³ (ejercicio '7')\n", 316 | "quiz.eval_expression('7', partial_y)\n" 317 | ] 318 | }, 319 | { 320 | "cell_type": "markdown", 321 | "id": "8da3b574-54c3-46a2-a99e-921983c53f7d", 322 | "metadata": {}, 323 | "source": [ 324 | "---\n", 325 | "## Conclusión: Evaluación de expresiones simbólicas\n", 326 | "\n", 327 | "La evaluación de expresiones simbólicas con la libreria de **macti_lib** nos permite:\n", 328 | "\n", 329 | "- **Definir de forma clara** la expresión de referencia como cadena de texto. \n", 330 | "- **Automatizar** la comparación simbólica usando SymPy (`sympify()` + `equals()`), lo que detecta equivalencias algebraicas más allá de la forma literal. \n", 331 | "- **Ofrecer feedback inmediato**, coloreando en verde las expresiones correctas y en rojo las incorrectas, acompañado de sugerencias para corregir errores de cálculo. \n" 332 | ] 333 | } 334 | ], 335 | "metadata": { 336 | "kernelspec": { 337 | "display_name": "Python 3 (ipykernel)", 338 | "language": "python", 339 | "name": "python3" 340 | }, 341 | "language_info": { 342 | "codemirror_mode": { 343 | "name": "ipython", 344 | "version": 3 345 | }, 346 | "file_extension": ".py", 347 | "mimetype": "text/x-python", 348 | "name": "python", 349 | "nbconvert_exporter": "python", 350 | "pygments_lexer": "ipython3", 351 | "version": "3.11.6" 352 | } 353 | }, 354 | "nbformat": 4, 355 | "nbformat_minor": 5 356 | } 357 | -------------------------------------------------------------------------------- /Eval/.ipynb_checkpoints/3_Expresiones_Simbolicas-checkpoint.ipynb: -------------------------------------------------------------------------------- 1 | { 2 | "cells": [ 3 | { 4 | "cell_type": "markdown", 5 | "id": "5782f249-c963-4e3b-ae37-8ed3461c415d", 6 | "metadata": {}, 7 | "source": [ 8 | "

\n", 9 | " Evaluación de expresiones simbólicas\n", 10 | "

\n", 11 | "\n", 12 | "

\n", 13 | "La evaluación de expresiones simbólicas permite comprobar respuestas equivalentes usando SymPy —por ejemplo, derivadas, integrales u otras transformaciones simbólicas— de forma totalmente automática.\n", 14 | "

\n", 15 | "\n", 16 | "

¿Cómo funciona?

\n", 17 | "\n", 22 | "\n", 23 | "

¿Qué se puede personalizar?

\n", 24 | "\n", 28 | "\n", 29 | "---" 30 | ] 31 | }, 32 | { 33 | "cell_type": "markdown", 34 | "id": "bd0d8523-fc56-4b37-9864-68d5042b57fe", 35 | "metadata": {}, 36 | "source": [ 37 | "## ¿Cómo se utiliza la evaluación de expresiones simbólicas?\n", 38 | "\n", 39 | "Para usar este tipo de evaluación se debe de ajustar dos partes del flujo de trabajo:\n", 40 | "\n", 41 | "1. **Registrar la expresión de referencia** \n", 42 | " Después de crear `FileAnswer()` y antes de llamar a `.to_file()`, define la expresión correcta como cadena:\n", 43 | "\n", 44 | " ```python\n", 45 | " # 1) Definir la expresión de referencia para el ejercicio '2'\n", 46 | " from sympy import Symbol\n", 47 | "\n", 48 | " x = Symbol('x')\n", 49 | " expr = x**2 # ejemplo: la función cuya derivada queremos evaluar\n", 50 | " ```\n", 51 | " \n", 52 | "2. **Ejecutar la comparación con lo que envió el usuario**\n", 53 | "\n", 54 | " ```python\n", 55 | " file_answer.write(\n", 56 | " '2', # → ID del ejercicio\n", 57 | " str(expr), # → la expresión correcta como string\n", 58 | " 'Revisa la derivación simbólica.' # → mensaje si el alumno falla\n", 59 | " )\n", 60 | "\n", 61 | " ```\n" 62 | ] 63 | }, 64 | { 65 | "cell_type": "markdown", 66 | "id": "cec26e64-face-4b3e-8d4f-a8320d81fd1d", 67 | "metadata": {}, 68 | "source": [ 69 | "---\n", 70 | "## Ejemplos: evaluación de expresiones simbólicas\n", 71 | "\n", 72 | "A continuación se presentan ejemplos para el tipo de evaluación simbolica\n", 73 | "\n" 74 | ] 75 | }, 76 | { 77 | "cell_type": "code", 78 | "execution_count": 1, 79 | "id": "340d7a5a-03db-4d86-a7fb-0eaf284a2fbf", 80 | "metadata": {}, 81 | "outputs": [], 82 | "source": [ 83 | "# Importamos los módulos necesarios para poder hacer uso de la biblioteca de MACTI\n", 84 | "from macti.eval import FileAnswer, Quiz \n", 85 | "import sympy as sy\n", 86 | "import numpy as np\n", 87 | "import pandas as pd" 88 | ] 89 | }, 90 | { 91 | "cell_type": "code", 92 | "execution_count": 2, 93 | "id": "46f337ce-0c60-40e1-8766-8319cae9e3d2", 94 | "metadata": {}, 95 | "outputs": [ 96 | { 97 | "name": "stdout", 98 | "output_type": "stream", 99 | "text": [ 100 | "El directorio :/home/jovyan/MACTI_LIB/.ans/Eval/ ya existe\n", 101 | "Respuestas y retroalimentación almacenadas.\n" 102 | ] 103 | } 104 | ], 105 | "source": [ 106 | "# --- 1) Registrar las expresiones simbólicas (respuestas correctas) ---\n", 107 | "\n", 108 | "file_answer = FileAnswer()\n", 109 | "\n", 110 | "# Ejercicio '2': derivada de x*x\n", 111 | "x = sy.Symbol('x')\n", 112 | "derivada = x * x\n", 113 | "file_answer.write('2', str(derivada), 'Checa las reglas de derivación')\n", 114 | "\n", 115 | "# Ejercicio '3': forma cuadrática\n", 116 | "y = sy.Symbol('y')\n", 117 | "A = np.array([[0.10, -1.], [0.30, -1.]])\n", 118 | "B = np.array([-200, 20])\n", 119 | "forma_cuadratica = (\n", 120 | " 0.5 * A[0,0] * x**2\n", 121 | " + 0.5 * A[1,1] * y**2\n", 122 | " + 0.5 * (A[0,1] + A[1,0]) * x * y\n", 123 | " - B[0] * x\n", 124 | " - B[1] * y\n", 125 | ")\n", 126 | "file_answer.write('3', str(forma_cuadratica), 'Revisa tus operaciones algebraicas para calcular f(x)')\n", 127 | "\n", 128 | "# Ejercicio '4': integral de sin(x) dx\n", 129 | "int_sin = sy.integrate(sy.sin(x), x)\n", 130 | "file_answer.write('4', str(int_sin), 'Verifica tu resultado de la integral')\n", 131 | "\n", 132 | "# Ejercicio '5': simplificación de identidad trigonométrica\n", 133 | "expr_id = sy.sin(x)**2 + sy.cos(x)**2\n", 134 | "simplified = sy.simplify(expr_id)\n", 135 | "file_answer.write('5', str(simplified), 'Comprueba la identidad trigonométrica')\n", 136 | "\n", 137 | "# Ejercicio '6': serie de Taylor de e^x hasta orden 3\n", 138 | "series_exp = sy.series(sy.exp(x), x, 0, 4).removeO()\n", 139 | "file_answer.write('6', str(series_exp), 'Revisa tu serie de Taylor')\n", 140 | "\n", 141 | "# Ejercicio '7': derivada parcial ∂/∂y de x^2 * y^3\n", 142 | "partial_y = sy.diff(x**2 * y**3, y)\n", 143 | "file_answer.write('7', str(partial_y), 'Verifica tu derivada parcial')\n", 144 | "\n", 145 | "# 1.8) Exportar a Parquet para que Quiz pueda leerlo\n", 146 | "file_answer.to_file('test01')\n" 147 | ] 148 | }, 149 | { 150 | "cell_type": "code", 151 | "execution_count": 3, 152 | "id": "ea6dc1f8-8621-48a0-9aaf-755c93e4a3ea", 153 | "metadata": {}, 154 | "outputs": [ 155 | { 156 | "name": "stdout", 157 | "output_type": "stream", 158 | "text": [ 159 | "\u001b[39m――――――――――――――――――――――――――――――――――――――――\n", 160 | "\u001b[32m2 | Tu respuesta:\n" 161 | ] 162 | }, 163 | { 164 | "data": { 165 | "text/latex": [ 166 | "$\\displaystyle x^{2}$" 167 | ], 168 | "text/plain": [ 169 | "x**2" 170 | ] 171 | }, 172 | "metadata": {}, 173 | "output_type": "display_data" 174 | }, 175 | { 176 | "name": "stdout", 177 | "output_type": "stream", 178 | "text": [ 179 | "\u001b[32mes correcta.\n", 180 | "\u001b[39m――――――――――――――――――――――――――――――――――――――――\n", 181 | "\u001b[39m――――――――――――――――――――――――――――――――――――――――\n", 182 | "\u001b[32m3 | Tu respuesta:\n" 183 | ] 184 | }, 185 | { 186 | "data": { 187 | "text/latex": [ 188 | "$\\displaystyle 0.05 x^{2} - 0.35 x y + 200 x - 0.5 y^{2} - 20 y$" 189 | ], 190 | "text/plain": [ 191 | "0.05*x**2 - 0.35*x*y + 200*x - 0.5*y**2 - 20*y" 192 | ] 193 | }, 194 | "metadata": {}, 195 | "output_type": "display_data" 196 | }, 197 | { 198 | "name": "stdout", 199 | "output_type": "stream", 200 | "text": [ 201 | "\u001b[32mes correcta.\n", 202 | "\u001b[39m――――――――――――――――――――――――――――――――――――――――\n", 203 | "\u001b[39m――――――――――――――――――――――――――――――――――――――――\n", 204 | "\u001b[32m4 | Tu respuesta:\n" 205 | ] 206 | }, 207 | { 208 | "data": { 209 | "text/latex": [ 210 | "$\\displaystyle - \\cos{\\left(x \\right)}$" 211 | ], 212 | "text/plain": [ 213 | "-cos(x)" 214 | ] 215 | }, 216 | "metadata": {}, 217 | "output_type": "display_data" 218 | }, 219 | { 220 | "name": "stdout", 221 | "output_type": "stream", 222 | "text": [ 223 | "\u001b[32mes correcta.\n", 224 | "\u001b[39m――――――――――――――――――――――――――――――――――――――――\n", 225 | "\u001b[39m――――――――――――――――――――――――――――――――――――――――\n", 226 | "\u001b[32m5 | Tu respuesta:\n" 227 | ] 228 | }, 229 | { 230 | "data": { 231 | "text/latex": [ 232 | "$\\displaystyle 1$" 233 | ], 234 | "text/plain": [ 235 | "1" 236 | ] 237 | }, 238 | "metadata": {}, 239 | "output_type": "display_data" 240 | }, 241 | { 242 | "name": "stdout", 243 | "output_type": "stream", 244 | "text": [ 245 | "\u001b[32mes correcta.\n", 246 | "\u001b[39m――――――――――――――――――――――――――――――――――――――――\n", 247 | "\u001b[39m――――――――――――――――――――――――――――――――――――――――\n", 248 | "\u001b[32m6 | Tu respuesta:\n" 249 | ] 250 | }, 251 | { 252 | "data": { 253 | "text/latex": [ 254 | "$\\displaystyle \\frac{x^{3}}{6} + \\frac{x^{2}}{2} + x + 1$" 255 | ], 256 | "text/plain": [ 257 | "x**3/6 + x**2/2 + x + 1" 258 | ] 259 | }, 260 | "metadata": {}, 261 | "output_type": "display_data" 262 | }, 263 | { 264 | "name": "stdout", 265 | "output_type": "stream", 266 | "text": [ 267 | "\u001b[32mes correcta.\n", 268 | "\u001b[39m――――――――――――――――――――――――――――――――――――――――\n", 269 | "\u001b[39m――――――――――――――――――――――――――――――――――――――――\n", 270 | "\u001b[32m7 | Tu respuesta:\n" 271 | ] 272 | }, 273 | { 274 | "data": { 275 | "text/latex": [ 276 | "$\\displaystyle 3 x^{2} y^{2}$" 277 | ], 278 | "text/plain": [ 279 | "3*x**2*y**2" 280 | ] 281 | }, 282 | "metadata": {}, 283 | "output_type": "display_data" 284 | }, 285 | { 286 | "name": "stdout", 287 | "output_type": "stream", 288 | "text": [ 289 | "\u001b[32mes correcta.\n", 290 | "\u001b[39m――――――――――――――――――――――――――――――――――――――――\n" 291 | ] 292 | } 293 | ], 294 | "source": [ 295 | "# --- 2) Evaluar las expresiones simbólicas con Quiz ---\n", 296 | "\n", 297 | "# 2.1 Inicializar Quiz (usa el mismo qnum que pasaste a to_file)\n", 298 | "quiz = Quiz(qnum='test01', server='local') # Carga las expresiones de referencia\n", 299 | "\n", 300 | "# 2.2 Evaluar la derivada de x*x (ejercicio '2')\n", 301 | "quiz.eval_expression('2', derivada)\n", 302 | "\n", 303 | "# 2.3 Evaluar la forma cuadrática (ejercicio '3')\n", 304 | "quiz.eval_expression('3', forma_cuadratica)\n", 305 | "\n", 306 | "# 2.4 Evaluar la integral de sin(x) dx (ejercicio '4')\n", 307 | "quiz.eval_expression('4', int_sin)\n", 308 | "\n", 309 | "# 2.5 Evaluar la simplificación de la identidad sin²(x)+cos²(x) (ejercicio '5')\n", 310 | "quiz.eval_expression('5', simplified)\n", 311 | "\n", 312 | "# 2.6 Evaluar la serie de Taylor de e^x hasta orden 3 (ejercicio '6')\n", 313 | "quiz.eval_expression('6', series_exp)\n", 314 | "\n", 315 | "# 2.7 Evaluar la derivada parcial ∂/∂y de x²·y³ (ejercicio '7')\n", 316 | "quiz.eval_expression('7', partial_y)\n" 317 | ] 318 | }, 319 | { 320 | "cell_type": "markdown", 321 | "id": "8da3b574-54c3-46a2-a99e-921983c53f7d", 322 | "metadata": {}, 323 | "source": [ 324 | "---\n", 325 | "## Conclusión: Evaluación de expresiones simbólicas\n", 326 | "\n", 327 | "La evaluación de expresiones simbólicas con la libreria de **macti_lib** nos permite:\n", 328 | "\n", 329 | "- **Definir de forma clara** la expresión de referencia como cadena de texto. \n", 330 | "- **Automatizar** la comparación simbólica usando SymPy (`sympify()` + `equals()`), lo que detecta equivalencias algebraicas más allá de la forma literal. \n", 331 | "- **Ofrecer feedback inmediato**, coloreando en verde las expresiones correctas y en rojo las incorrectas, acompañado de sugerencias para corregir errores de cálculo. \n" 332 | ] 333 | } 334 | ], 335 | "metadata": { 336 | "kernelspec": { 337 | "display_name": "Python 3 (ipykernel)", 338 | "language": "python", 339 | "name": "python3" 340 | }, 341 | "language_info": { 342 | "codemirror_mode": { 343 | "name": "ipython", 344 | "version": 3 345 | }, 346 | "file_extension": ".py", 347 | "mimetype": "text/x-python", 348 | "name": "python", 349 | "nbconvert_exporter": "python", 350 | "pygments_lexer": "ipython3", 351 | "version": "3.11.6" 352 | } 353 | }, 354 | "nbformat": 4, 355 | "nbformat_minor": 5 356 | } 357 | -------------------------------------------------------------------------------- /Eval/.ipynb_checkpoints/4_Valores_Numericos-checkpoint.ipynb: -------------------------------------------------------------------------------- 1 | { 2 | "cells": [ 3 | { 4 | "cell_type": "markdown", 5 | "id": "6ee01713-eb76-48b3-8751-c530f093bb1a", 6 | "metadata": {}, 7 | "source": [ 8 | "\n", 9 | "

\n", 10 | " Evaluación de valores numéricos\n", 11 | "

\n", 12 | "\n", 13 | "La evaluación de \"valores numéricos\" se utiliza para comprobar:\n", 14 | "\n", 15 | "- Números simples (`int`, `float`) \n", 16 | "- Números complejos (`complex`) \n", 17 | "- Vectores y arreglos (`list`, `tuple`, `np.ndarray`)\n", 18 | "\n", 19 | "**¿Cómo funciona?** \n", 20 | "- Compara la respuesta del usuario con los valores de referencia mediante tolerancia numérica (`np.allclose`).\n", 21 | "\n", 22 | "**¿Qué se puede personalizar?** \n", 23 | "- El tipo de dato numérico o la estructura de datos evaluada. \n", 24 | "\n", 25 | "---" 26 | ] 27 | }, 28 | { 29 | "cell_type": "markdown", 30 | "id": "84c36c17-7872-45f5-af19-7ba3ffee7cee", 31 | "metadata": {}, 32 | "source": [ 33 | "## ¿Cómo se utiliza la evaluación numérica?\n", 34 | "\n", 35 | "Para usar este tipo de evaluación debes ajustar dos pasos en tu flujo de trabajo, ambos dentro del mismo notebook:\n", 36 | "\n", 37 | "1. **Registrar el valor de referencia** \n", 38 | " Después de crear `FileAnswer()` y antes de llamar a `.to_file()`, escribe el valor correcto:\n", 39 | "\n", 40 | " ```python\n", 41 | " # 1) Definir el valor de referencia para el ejercicio '3'\n", 42 | " file_answer.write(\n", 43 | " '3', # → ID del ejercicio\n", 44 | " valor_correcto, # → valor numérico de referencia (int, float, etc.)\n", 45 | " 'Aquí va tu feedback personalizado' # → mensaje que verá el alumno si falla\n", 46 | " )\n", 47 | "\n", 48 | "2. **Ejecutar la comparación con lo que envió el usuario**\n", 49 | "\n", 50 | "\n", 51 | " ```python\n", 52 | " quiz.eval_numeric(\n", 53 | " '3', # → mismo ID de ejercicio que usaste arriba\n", 54 | " respuesta_del_alumno # → valor calculado por el estudiante\n", 55 | " )\n", 56 | "\n", 57 | "---" 58 | ] 59 | }, 60 | { 61 | "cell_type": "markdown", 62 | "id": "8689c35e-ac10-4b2f-b234-55d9b4f19170", 63 | "metadata": {}, 64 | "source": [ 65 | "# Código\n", 66 | "\n", 67 | "En `src/macti/eval/quiz.py`, dentro de la clase `Quiz`, el método `eval_numeric` se encarga de:\n", 68 | "\n", 69 | "1. Leer el **valor de referencia** (el que registraste previamente). \n", 70 | "2. Detectar el tipo de respuesta del alumno (número, lista, arreglo, complejo, etc.) y normalizarla para compararla. \n", 71 | "3. Usar comparaciones numéricas con tolerancia (`np.allclose`) o `math.isclose` para validar la respuesta. \n", 72 | "4. Mostrar el resultado en verde si coincide o feedback en rojo y lanzar una excepción si no coincide.\n", 73 | "\n", 74 | "```python\n", 75 | "def eval_numeric(self, enum, ans):\n", 76 | " \"\"\"\n", 77 | " Evalúa una respuesta numérica (número o arreglo).\n", 78 | "\n", 79 | " Parameters\n", 80 | " ----------\n", 81 | " enum : str\n", 82 | " Identificador del ejercicio (por ejemplo, '3').\n", 83 | " ans : int | float | bool | complex | ndarray | list | tuple | set\n", 84 | " Respuesta proporcionada por el alumno.\n", 85 | " \"\"\"\n", 86 | " # 1) Recupero el valor de referencia guardado en disco\n", 87 | " value = self.__read(enum) # DataFrame con la columna [enum]\n", 88 | " correct = value[enum][0] # Extraigo el valor de referencia\n", 89 | " msg = \"\"\n", 90 | "\n", 91 | " try:\n", 92 | " # 2a) Si es un arreglo NumPy\n", 93 | " if isinstance(ans, np.ndarray):\n", 94 | " # -> complejos: convierto en vector real/imag\n", 95 | " if ans.dtype == complex:\n", 96 | " b = np.array([[c.real, c.imag] for c in ans.flatten()]).flatten()\n", 97 | " msg = self.__test_numeric_array(b, correct)\n", 98 | " np.testing.assert_allclose(b, correct)\n", 99 | " # -> reales: comparo con tolerancia\n", 100 | " else:\n", 101 | " msg = self.__test_numeric_array(ans, correct)\n", 102 | " np.testing.assert_allclose(ans, correct)\n", 103 | "\n", 104 | " # 2b) Si es lista o tupla: lo flatten y trato como arreglo\n", 105 | " elif isinstance(ans, (list, tuple)):\n", 106 | " b = np.array(ans).flatten()\n", 107 | " msg = self.__test_numeric_array(b, correct)\n", 108 | " np.testing.assert_allclose(b, correct)\n", 109 | "\n", 110 | " # 2c) Si es set: convierto a lista y comparo\n", 111 | " elif isinstance(ans, set):\n", 112 | " b = np.array(list(ans))\n", 113 | " msg = self.__test_numeric_array(b, correct)\n", 114 | " np.testing.assert_allclose(b, correct)\n", 115 | "\n", 116 | " # 2d) Si es número complejo aislado\n", 117 | " elif isinstance(ans, complex):\n", 118 | " a = complex(correct[0], correct[1])\n", 119 | " b = np.array([ans.real, ans.imag])\n", 120 | " if not np.allclose(correct, b):\n", 121 | " msg = f\"\\n Valor correcto : {a}\\n Valor calculado : {ans}\\n\"\n", 122 | " raise AssertionError from None\n", 123 | "\n", 124 | " # 2e) Si es int, float o bool: uso math.isclose\n", 125 | " elif isinstance(ans, (int, float, bool)):\n", 126 | " if not math.isclose(correct, ans):\n", 127 | " msg = f\"\\n Valor correcto : {correct}\\n Valor calculado : {ans}\\n\"\n", 128 | " raise AssertionError from None\n", 129 | "\n", 130 | " # 2f) Tipo no soportado\n", 131 | " else:\n", 132 | " print(f\"{enum} | Respuesta inválida: {ans} es de tipo {type(ans)}\")\n", 133 | " raise AssertionError from None\n", 134 | "\n", 135 | " except AssertionError as info:\n", 136 | " # 3) Si falla, muestro el hint y la excepción\n", 137 | " self.__print_error_hint(enum, msg=msg, info=info)\n", 138 | " raise AssertionError from None\n", 139 | "\n", 140 | " else:\n", 141 | " # 4) Si todo coincide, muestro mensaje de éxito\n", 142 | " self.__print_correct(enum)\n" 143 | ] 144 | }, 145 | { 146 | "cell_type": "markdown", 147 | "id": "07b845f8-2a6f-46be-83ac-be61730069cb", 148 | "metadata": {}, 149 | "source": [ 150 | "## Ejemplos: evaluación de valores númericos\n", 151 | "\n", 152 | "A continuación se presentan ejemplos para el tipo de valores númericos\n", 153 | "\n", 154 | "---" 155 | ] 156 | }, 157 | { 158 | "cell_type": "code", 159 | "execution_count": 2, 160 | "id": "8793032d-ae15-40e1-83b2-dffd94776d77", 161 | "metadata": {}, 162 | "outputs": [], 163 | "source": [ 164 | "from evaluation import FileAnswer, Quiz\n", 165 | "import sympy as sy\n", 166 | "import numpy as np\n", 167 | "import pandas as pd" 168 | ] 169 | }, 170 | { 171 | "cell_type": "code", 172 | "execution_count": 3, 173 | "id": "5c68da7a-a3f3-4de1-863f-3782cf937874", 174 | "metadata": {}, 175 | "outputs": [ 176 | { 177 | "name": "stdout", 178 | "output_type": "stream", 179 | "text": [ 180 | "El directorio :/home/jovyan/.ans/MACTI_LIB/ ya existe\n", 181 | "Respuestas y retroalimentación almacenadas.\n" 182 | ] 183 | } 184 | ], 185 | "source": [ 186 | "# --- 1) Registrar valores de referencia numéricos ---\n", 187 | "\n", 188 | "file_answer = FileAnswer()\n", 189 | "\n", 190 | "# Ejercicio '4': valor float\n", 191 | "file_answer.write(\n", 192 | " '4',\n", 193 | " 0.1,\n", 194 | " 'Calcula con mayor precisión.'\n", 195 | ")\n", 196 | "\n", 197 | "# Ejercicio '5': valor entero\n", 198 | "file_answer.write(\n", 199 | " '5',\n", 200 | " 1,\n", 201 | " 'Verifica que sea un entero.'\n", 202 | ")\n", 203 | "\n", 204 | "# Ejercicio '6': valor booleano\n", 205 | "file_answer.write(\n", 206 | " '6',\n", 207 | " True,\n", 208 | " 'Recuerda distinguir True de False.'\n", 209 | ")\n", 210 | "\n", 211 | "# Ejercicio '7': número complejo\n", 212 | "file_answer.write(\n", 213 | " '7',\n", 214 | " 1 + 5j,\n", 215 | " 'Comprueba las partes real e imaginaria.'\n", 216 | ")\n", 217 | "\n", 218 | "# Ejercicio '8': lista de números\n", 219 | "file_answer.write(\n", 220 | " '8',\n", 221 | " [0, 1, 3.4],\n", 222 | " 'Revisa cada elemento de la lista.'\n", 223 | ")\n", 224 | "\n", 225 | "# Ejercicio '12': conjunto numérico (el orden no importa)\n", 226 | "file_answer.write(\n", 227 | " '12',\n", 228 | " {1, 2, 3, 4, 5, 6},\n", 229 | " 'Asegúrate de incluir todos los elementos.'\n", 230 | ")\n", 231 | "\n", 232 | "# Ejercicio '17': arreglo NumPy\n", 233 | "w = np.sin(np.linspace(0, 1, 10))\n", 234 | "file_answer.write(\n", 235 | " '17',\n", 236 | " w,\n", 237 | " 'Comprueba tu arreglo numérico.'\n", 238 | ")\n", 239 | "\n", 240 | "# 1.8) Exportar a Parquet para que Quiz pueda leerlo\n", 241 | "file_answer.to_file('demo_numeric')\n" 242 | ] 243 | }, 244 | { 245 | "cell_type": "code", 246 | "execution_count": 4, 247 | "id": "bedeac0d-ac8f-4ed2-a6ee-9b90968f70d9", 248 | "metadata": {}, 249 | "outputs": [ 250 | { 251 | "name": "stdout", 252 | "output_type": "stream", 253 | "text": [ 254 | "\u001b[39m――――――――――――――――――――――――――――――――――――――――\n", 255 | "\u001b[32m4 | Tu resultado es correcto.\n", 256 | "\u001b[39m――――――――――――――――――――――――――――――――――――――――\n", 257 | "\u001b[39m――――――――――――――――――――――――――――――――――――――――\n", 258 | "\u001b[32m5 | Tu resultado es correcto.\n", 259 | "\u001b[39m――――――――――――――――――――――――――――――――――――――――\n", 260 | "\u001b[39m――――――――――――――――――――――――――――――――――――――――\n", 261 | "\u001b[32m6 | Tu resultado es correcto.\n", 262 | "\u001b[39m――――――――――――――――――――――――――――――――――――――――\n", 263 | "\u001b[39m――――――――――――――――――――――――――――――――――――――――\n", 264 | "\u001b[32m7 | Tu resultado es correcto.\n", 265 | "\u001b[39m――――――――――――――――――――――――――――――――――――――――\n", 266 | "\u001b[39m――――――――――――――――――――――――――――――――――――――――\n", 267 | "\u001b[32m8 | Tu resultado es correcto.\n", 268 | "\u001b[39m――――――――――――――――――――――――――――――――――――――――\n", 269 | "\u001b[39m――――――――――――――――――――――――――――――――――――――――\n", 270 | "\u001b[32m12 | Tu resultado es correcto.\n", 271 | "\u001b[39m――――――――――――――――――――――――――――――――――――――――\n", 272 | "\u001b[39m――――――――――――――――――――――――――――――――――――――――\n", 273 | "\u001b[32m17 | Tu resultado es correcto.\n", 274 | "\u001b[39m――――――――――――――――――――――――――――――――――――――――\n" 275 | ] 276 | } 277 | ], 278 | "source": [ 279 | "# --- 2) Evaluar valores numéricos con Quiz ---\n", 280 | "\n", 281 | "quiz = Quiz(qnum='demo_numeric', server='local')\n", 282 | "\n", 283 | "# Flotante\n", 284 | "quiz.eval_numeric('4', 0.1) # ✅ coincide exactamente\n", 285 | "# quiz.eval_numeric('4', 0.100001) # ✅ dentro de la tolerancia\n", 286 | "\n", 287 | "# Entero\n", 288 | "quiz.eval_numeric('5', 1) # ✅ coincide\n", 289 | "# quiz.eval_numeric('5', 0) # ❌ lanza AssertionError\n", 290 | "\n", 291 | "# Booleano\n", 292 | "quiz.eval_numeric('6', True) # ✅ coincide\n", 293 | "# quiz.eval_numeric('6', False) # ❌ lanza AssertionError\n", 294 | "\n", 295 | "# Número complejo\n", 296 | "quiz.eval_numeric('7', 1 + 5j) # ✅ coincide\n", 297 | "# quiz.eval_numeric('7', 1 + 4.9j) # ❌ lanza AssertionError\n", 298 | "\n", 299 | "# Lista\n", 300 | "quiz.eval_numeric('8', [0, 1, 3.4]) # ✅ coincide\n", 301 | "# quiz.eval_numeric('8', [0, 1, 3.5]) # ❌ lanza AssertionError\n", 302 | "\n", 303 | "# Conjunto (el orden no importa)\n", 304 | "quiz.eval_numeric('12', {1, 2, 3, 4, 5, 6}) # ✅ coincide\n", 305 | "# quiz.eval_numeric('12', {1, 2, 3, 4, 5}) # ❌ lanza AssertionError\n", 306 | "\n", 307 | "# Arreglo de NumPy\n", 308 | "quiz.eval_numeric('17', w) # ✅ coincide\n", 309 | "# quiz.eval_numeric('17', w + 0.001) # ❌ fuera de tolerancia\n" 310 | ] 311 | }, 312 | { 313 | "cell_type": "markdown", 314 | "id": "dee24374-93c9-419e-b572-650c1bbe6d23", 315 | "metadata": {}, 316 | "source": [ 317 | "---\n", 318 | "## Conclusión: Evaluación de valores numéricos\n", 319 | "\n", 320 | "Con **macti_lib** la evaluación numérica en notebooks te ofrece:\n", 321 | "\n", 322 | "- **Soporte versátil** para distintos tipos de datos: enteros, flotantes, booleanos, complejos, listas, conjuntos y arreglos NumPy. \n", 323 | "- **Comparaciones con tolerancia** que permiten pequeñas variaciones (por ejemplo, en cálculos de punto flotante) sin penalizar respuestas válidas. \n", 324 | "- **Feedback inmediato** y detallado: se muestran resultados correctos en verde y, en caso de error, en rojo con sugerencias específicas para corregir la respuesta. \n" 325 | ] 326 | } 327 | ], 328 | "metadata": { 329 | "kernelspec": { 330 | "display_name": "Python 3 (ipykernel)", 331 | "language": "python", 332 | "name": "python3" 333 | }, 334 | "language_info": { 335 | "codemirror_mode": { 336 | "name": "ipython", 337 | "version": 3 338 | }, 339 | "file_extension": ".py", 340 | "mimetype": "text/x-python", 341 | "name": "python", 342 | "nbconvert_exporter": "python", 343 | "pygments_lexer": "ipython3", 344 | "version": "3.11.6" 345 | } 346 | }, 347 | "nbformat": 4, 348 | "nbformat_minor": 5 349 | } 350 | -------------------------------------------------------------------------------- /Eval/Ejemplos/Perceptron.ipynb: -------------------------------------------------------------------------------- 1 | { 2 | "cells": [ 3 | { 4 | "cell_type": "markdown", 5 | "metadata": { 6 | "id": "view-in-github", 7 | "colab_type": "text" 8 | }, 9 | "source": [ 10 | "\"Open" 11 | ] 12 | }, 13 | { 14 | "cell_type": "markdown", 15 | "metadata": { 16 | "id": "PJkb2AKbDWq7" 17 | }, 18 | "source": [ 19 | "\n", 20 | "

Perceptrón

\n", 21 | "
\n", 22 | " \n", 23 | "
Profesor: M. en C. Miguel Angel Pérez León
\n", 24 | "
" 25 | ] 26 | }, 27 | { 28 | "cell_type": "code", 29 | "execution_count": null, 30 | "metadata": { 31 | "nbgrader": { 32 | "grade": true, 33 | "grade_id": "cell-51e0133df82c9254", 34 | "locked": true, 35 | "points": 0, 36 | "schema_version": 3, 37 | "solution": false, 38 | "task": false 39 | }, 40 | "tags": [], 41 | "id": "sA4pEr5vDWrA" 42 | }, 43 | "outputs": [], 44 | "source": [ 45 | "# bibliotecas que se van a usar\n", 46 | "import numpy as np\n", 47 | "import matplotlib.pyplot as plt\n", 48 | "from macti.evaluation import *\n", 49 | "#file_answer = FileAnswer()" 50 | ] 51 | }, 52 | { 53 | "cell_type": "code", 54 | "execution_count": null, 55 | "metadata": { 56 | "nbgrader": { 57 | "grade": true, 58 | "grade_id": "cell-eedb39b21ab1e329", 59 | "locked": true, 60 | "points": 0, 61 | "schema_version": 3, 62 | "solution": false, 63 | "task": false 64 | }, 65 | "id": "fo-TSjOzDWrB" 66 | }, 67 | "outputs": [], 68 | "source": [ 69 | "# EJECUTAR ESTA CELDA SOLO SI EL NOTEBOOK ESTA EN MACTI\n", 70 | "#from macti.evaluation import Quizz\n", 71 | "#quizz = Quizz('1', 'AnalisisNumerico', 'local')" 72 | ] 73 | }, 74 | { 75 | "cell_type": "markdown", 76 | "metadata": { 77 | "id": "FdOfFXdrDWrC" 78 | }, 79 | "source": [ 80 | "
\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 | "
  1. \n", 79 | " Importa evaluation desde el repositorio macti_lib.\n", 80 | "
  2. \n", 81 | "
  3. \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 | "
  4. \n", 86 | "
  5. \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 | "
  6. \n", 90 | "
  7. \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 | "
  8. \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 | "
  1. \n", 79 | " Importa evaluation desde el repositorio macti_lib.\n", 80 | "
  2. \n", 81 | "
  3. \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 | "
  4. \n", 86 | "
  5. \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 | "
  6. \n", 90 | "
  7. \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 | "
  8. \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 | --------------------------------------------------------------------------------