├── Utils ├── md ├── secuencial.jar ├── tiaAly.tar.xz └── concurrente.jar ├── Imagenes ├── CUDA │ ├── test │ ├── gpu.png │ ├── smile.png │ ├── bitmap.jpg │ ├── seleccion.png │ └── sumavect.png ├── MPI │ ├── test │ ├── barrier.png │ └── broadcast.png ├── OpenMP │ ├── test │ ├── cuda.png │ ├── aproxpi.png │ ├── thread3.png │ ├── thread4.png │ ├── SBParalela.png │ ├── SBSecuencial.png │ ├── circunferencia.png │ └── ejemploSumaBinaria.png ├── Envoltorios │ ├── test │ ├── som.gif │ ├── powTF.png │ ├── sumaTF.png │ ├── reco_ropa.png │ └── fashion-mnist-sprite.png ├── Introduccion │ ├── test │ ├── Test │ │ ├── test │ │ ├── m1.png │ │ ├── desc.png │ │ ├── json.png │ │ ├── my0.png │ │ ├── my1.png │ │ ├── my2.png │ │ ├── my3.png │ │ ├── my4.png │ │ ├── my5.png │ │ ├── my6.png │ │ ├── my7.png │ │ ├── my8.png │ │ ├── derPar4.png │ │ ├── comprobacion.png │ │ └── CreaJSON.json │ ├── cota.png │ ├── lcpu.png │ ├── url.png │ ├── 3discos.gif │ ├── 4discos.gif │ ├── Flynn.png │ ├── GFLOPS.png │ ├── MeShare.png │ ├── campos.png │ ├── cocos.png │ ├── cocosp.png │ ├── colab.png │ ├── eclipse.png │ ├── merge.gif │ ├── nomen.png │ ├── quick.gif │ ├── repos.png │ ├── top500.png │ ├── LeyATime.png │ ├── LeyAmdahl.png │ ├── MemShare.png │ ├── branches.png │ ├── colabhub.png │ ├── comparar.png │ ├── multicore.png │ ├── proyecto.png │ ├── quicksort.jpg │ ├── SumaParaLDA.png │ ├── brontobyte.jpg │ ├── complejidad.png │ ├── nuevocolab.png │ ├── repositorio.jpg │ └── git_branch_merge.png └── RedesNeuronales │ ├── test │ ├── Capa.png │ ├── NeuronaAND.png │ └── perceptronReg.png ├── README.md ├── 01_OpenMP ├── 04_SumaBinaria_Paralela.ipynb ├── .ipynb_checkpoints │ └── 04_SumaBinaria_Paralela-checkpoint.ipynb └── 01_OpenMP_SCP.ipynb ├── 04_Envoltorios └── 03_EjemplosModelosIA.ipynb ├── 00_Introduccion ├── 01_GitHub.ipynb ├── .ipynb_checkpoints │ ├── 01_GitHub-checkpoint.ipynb │ ├── 06_MergeQuick-checkpoint.ipynb │ ├── 07_RadixBucket-checkpoint.ipynb │ └── 12_Ley_Amdahl-checkpoint.ipynb ├── 06_MergeQuick.ipynb ├── 07_RadixBucket.ipynb └── 12_Ley_Amdahl.ipynb └── 02_MPI ├── 03_Algoritmos_MPI_SCP.ipynb └── .ipynb_checkpoints └── 03_Algoritmos_MPI_SCP-checkpoint.ipynb /Utils/md: -------------------------------------------------------------------------------- 1 | 2 | -------------------------------------------------------------------------------- /Imagenes/CUDA/test: -------------------------------------------------------------------------------- 1 | 2 | -------------------------------------------------------------------------------- /Imagenes/MPI/test: -------------------------------------------------------------------------------- 1 | 2 | -------------------------------------------------------------------------------- /Imagenes/OpenMP/test: -------------------------------------------------------------------------------- 1 | 2 | -------------------------------------------------------------------------------- /Imagenes/Envoltorios/test: -------------------------------------------------------------------------------- 1 | 2 | -------------------------------------------------------------------------------- /Imagenes/Introduccion/test: -------------------------------------------------------------------------------- 1 | 2 | -------------------------------------------------------------------------------- /Imagenes/Introduccion/Test/test: -------------------------------------------------------------------------------- 1 | 2 | -------------------------------------------------------------------------------- /Imagenes/RedesNeuronales/test: -------------------------------------------------------------------------------- 1 | 2 | -------------------------------------------------------------------------------- /Utils/secuencial.jar: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/jugernaut/MACTI-programacionparalelo/HEAD/Utils/secuencial.jar -------------------------------------------------------------------------------- /Utils/tiaAly.tar.xz: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/jugernaut/MACTI-programacionparalelo/HEAD/Utils/tiaAly.tar.xz -------------------------------------------------------------------------------- /Imagenes/CUDA/gpu.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/jugernaut/MACTI-programacionparalelo/HEAD/Imagenes/CUDA/gpu.png -------------------------------------------------------------------------------- /Imagenes/CUDA/smile.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/jugernaut/MACTI-programacionparalelo/HEAD/Imagenes/CUDA/smile.png -------------------------------------------------------------------------------- /Utils/concurrente.jar: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/jugernaut/MACTI-programacionparalelo/HEAD/Utils/concurrente.jar -------------------------------------------------------------------------------- /Imagenes/CUDA/bitmap.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/jugernaut/MACTI-programacionparalelo/HEAD/Imagenes/CUDA/bitmap.jpg -------------------------------------------------------------------------------- /Imagenes/MPI/barrier.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/jugernaut/MACTI-programacionparalelo/HEAD/Imagenes/MPI/barrier.png -------------------------------------------------------------------------------- /Imagenes/OpenMP/cuda.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/jugernaut/MACTI-programacionparalelo/HEAD/Imagenes/OpenMP/cuda.png -------------------------------------------------------------------------------- /Imagenes/CUDA/seleccion.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/jugernaut/MACTI-programacionparalelo/HEAD/Imagenes/CUDA/seleccion.png -------------------------------------------------------------------------------- /Imagenes/CUDA/sumavect.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/jugernaut/MACTI-programacionparalelo/HEAD/Imagenes/CUDA/sumavect.png -------------------------------------------------------------------------------- /Imagenes/Envoltorios/som.gif: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/jugernaut/MACTI-programacionparalelo/HEAD/Imagenes/Envoltorios/som.gif -------------------------------------------------------------------------------- /Imagenes/MPI/broadcast.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/jugernaut/MACTI-programacionparalelo/HEAD/Imagenes/MPI/broadcast.png -------------------------------------------------------------------------------- /Imagenes/OpenMP/aproxpi.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/jugernaut/MACTI-programacionparalelo/HEAD/Imagenes/OpenMP/aproxpi.png -------------------------------------------------------------------------------- /Imagenes/OpenMP/thread3.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/jugernaut/MACTI-programacionparalelo/HEAD/Imagenes/OpenMP/thread3.png -------------------------------------------------------------------------------- /Imagenes/OpenMP/thread4.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/jugernaut/MACTI-programacionparalelo/HEAD/Imagenes/OpenMP/thread4.png -------------------------------------------------------------------------------- /Imagenes/Envoltorios/powTF.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/jugernaut/MACTI-programacionparalelo/HEAD/Imagenes/Envoltorios/powTF.png -------------------------------------------------------------------------------- /Imagenes/Introduccion/cota.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/jugernaut/MACTI-programacionparalelo/HEAD/Imagenes/Introduccion/cota.png -------------------------------------------------------------------------------- /Imagenes/Introduccion/lcpu.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/jugernaut/MACTI-programacionparalelo/HEAD/Imagenes/Introduccion/lcpu.png -------------------------------------------------------------------------------- /Imagenes/Introduccion/url.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/jugernaut/MACTI-programacionparalelo/HEAD/Imagenes/Introduccion/url.png -------------------------------------------------------------------------------- /Imagenes/OpenMP/SBParalela.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/jugernaut/MACTI-programacionparalelo/HEAD/Imagenes/OpenMP/SBParalela.png -------------------------------------------------------------------------------- /Imagenes/Envoltorios/sumaTF.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/jugernaut/MACTI-programacionparalelo/HEAD/Imagenes/Envoltorios/sumaTF.png -------------------------------------------------------------------------------- /Imagenes/Introduccion/3discos.gif: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/jugernaut/MACTI-programacionparalelo/HEAD/Imagenes/Introduccion/3discos.gif -------------------------------------------------------------------------------- /Imagenes/Introduccion/4discos.gif: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/jugernaut/MACTI-programacionparalelo/HEAD/Imagenes/Introduccion/4discos.gif -------------------------------------------------------------------------------- /Imagenes/Introduccion/Flynn.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/jugernaut/MACTI-programacionparalelo/HEAD/Imagenes/Introduccion/Flynn.png -------------------------------------------------------------------------------- /Imagenes/Introduccion/GFLOPS.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/jugernaut/MACTI-programacionparalelo/HEAD/Imagenes/Introduccion/GFLOPS.png -------------------------------------------------------------------------------- /Imagenes/Introduccion/MeShare.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/jugernaut/MACTI-programacionparalelo/HEAD/Imagenes/Introduccion/MeShare.png -------------------------------------------------------------------------------- /Imagenes/Introduccion/Test/m1.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/jugernaut/MACTI-programacionparalelo/HEAD/Imagenes/Introduccion/Test/m1.png -------------------------------------------------------------------------------- /Imagenes/Introduccion/campos.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/jugernaut/MACTI-programacionparalelo/HEAD/Imagenes/Introduccion/campos.png -------------------------------------------------------------------------------- /Imagenes/Introduccion/cocos.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/jugernaut/MACTI-programacionparalelo/HEAD/Imagenes/Introduccion/cocos.png -------------------------------------------------------------------------------- /Imagenes/Introduccion/cocosp.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/jugernaut/MACTI-programacionparalelo/HEAD/Imagenes/Introduccion/cocosp.png -------------------------------------------------------------------------------- /Imagenes/Introduccion/colab.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/jugernaut/MACTI-programacionparalelo/HEAD/Imagenes/Introduccion/colab.png -------------------------------------------------------------------------------- /Imagenes/Introduccion/eclipse.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/jugernaut/MACTI-programacionparalelo/HEAD/Imagenes/Introduccion/eclipse.png -------------------------------------------------------------------------------- /Imagenes/Introduccion/merge.gif: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/jugernaut/MACTI-programacionparalelo/HEAD/Imagenes/Introduccion/merge.gif -------------------------------------------------------------------------------- /Imagenes/Introduccion/nomen.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/jugernaut/MACTI-programacionparalelo/HEAD/Imagenes/Introduccion/nomen.png -------------------------------------------------------------------------------- /Imagenes/Introduccion/quick.gif: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/jugernaut/MACTI-programacionparalelo/HEAD/Imagenes/Introduccion/quick.gif -------------------------------------------------------------------------------- /Imagenes/Introduccion/repos.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/jugernaut/MACTI-programacionparalelo/HEAD/Imagenes/Introduccion/repos.png -------------------------------------------------------------------------------- /Imagenes/Introduccion/top500.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/jugernaut/MACTI-programacionparalelo/HEAD/Imagenes/Introduccion/top500.png -------------------------------------------------------------------------------- /Imagenes/OpenMP/SBSecuencial.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/jugernaut/MACTI-programacionparalelo/HEAD/Imagenes/OpenMP/SBSecuencial.png -------------------------------------------------------------------------------- /Imagenes/RedesNeuronales/Capa.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/jugernaut/MACTI-programacionparalelo/HEAD/Imagenes/RedesNeuronales/Capa.png -------------------------------------------------------------------------------- /Imagenes/Envoltorios/reco_ropa.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/jugernaut/MACTI-programacionparalelo/HEAD/Imagenes/Envoltorios/reco_ropa.png -------------------------------------------------------------------------------- /Imagenes/Introduccion/LeyATime.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/jugernaut/MACTI-programacionparalelo/HEAD/Imagenes/Introduccion/LeyATime.png -------------------------------------------------------------------------------- /Imagenes/Introduccion/LeyAmdahl.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/jugernaut/MACTI-programacionparalelo/HEAD/Imagenes/Introduccion/LeyAmdahl.png -------------------------------------------------------------------------------- /Imagenes/Introduccion/MemShare.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/jugernaut/MACTI-programacionparalelo/HEAD/Imagenes/Introduccion/MemShare.png -------------------------------------------------------------------------------- /Imagenes/Introduccion/Test/desc.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/jugernaut/MACTI-programacionparalelo/HEAD/Imagenes/Introduccion/Test/desc.png -------------------------------------------------------------------------------- /Imagenes/Introduccion/Test/json.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/jugernaut/MACTI-programacionparalelo/HEAD/Imagenes/Introduccion/Test/json.png -------------------------------------------------------------------------------- /Imagenes/Introduccion/Test/my0.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/jugernaut/MACTI-programacionparalelo/HEAD/Imagenes/Introduccion/Test/my0.png -------------------------------------------------------------------------------- /Imagenes/Introduccion/Test/my1.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/jugernaut/MACTI-programacionparalelo/HEAD/Imagenes/Introduccion/Test/my1.png -------------------------------------------------------------------------------- /Imagenes/Introduccion/Test/my2.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/jugernaut/MACTI-programacionparalelo/HEAD/Imagenes/Introduccion/Test/my2.png -------------------------------------------------------------------------------- /Imagenes/Introduccion/Test/my3.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/jugernaut/MACTI-programacionparalelo/HEAD/Imagenes/Introduccion/Test/my3.png -------------------------------------------------------------------------------- /Imagenes/Introduccion/Test/my4.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/jugernaut/MACTI-programacionparalelo/HEAD/Imagenes/Introduccion/Test/my4.png -------------------------------------------------------------------------------- /Imagenes/Introduccion/Test/my5.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/jugernaut/MACTI-programacionparalelo/HEAD/Imagenes/Introduccion/Test/my5.png -------------------------------------------------------------------------------- /Imagenes/Introduccion/Test/my6.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/jugernaut/MACTI-programacionparalelo/HEAD/Imagenes/Introduccion/Test/my6.png -------------------------------------------------------------------------------- /Imagenes/Introduccion/Test/my7.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/jugernaut/MACTI-programacionparalelo/HEAD/Imagenes/Introduccion/Test/my7.png -------------------------------------------------------------------------------- /Imagenes/Introduccion/Test/my8.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/jugernaut/MACTI-programacionparalelo/HEAD/Imagenes/Introduccion/Test/my8.png -------------------------------------------------------------------------------- /Imagenes/Introduccion/branches.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/jugernaut/MACTI-programacionparalelo/HEAD/Imagenes/Introduccion/branches.png -------------------------------------------------------------------------------- /Imagenes/Introduccion/colabhub.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/jugernaut/MACTI-programacionparalelo/HEAD/Imagenes/Introduccion/colabhub.png -------------------------------------------------------------------------------- /Imagenes/Introduccion/comparar.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/jugernaut/MACTI-programacionparalelo/HEAD/Imagenes/Introduccion/comparar.png -------------------------------------------------------------------------------- /Imagenes/Introduccion/multicore.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/jugernaut/MACTI-programacionparalelo/HEAD/Imagenes/Introduccion/multicore.png -------------------------------------------------------------------------------- /Imagenes/Introduccion/proyecto.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/jugernaut/MACTI-programacionparalelo/HEAD/Imagenes/Introduccion/proyecto.png -------------------------------------------------------------------------------- /Imagenes/Introduccion/quicksort.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/jugernaut/MACTI-programacionparalelo/HEAD/Imagenes/Introduccion/quicksort.jpg -------------------------------------------------------------------------------- /Imagenes/OpenMP/circunferencia.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/jugernaut/MACTI-programacionparalelo/HEAD/Imagenes/OpenMP/circunferencia.png -------------------------------------------------------------------------------- /Imagenes/Introduccion/SumaParaLDA.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/jugernaut/MACTI-programacionparalelo/HEAD/Imagenes/Introduccion/SumaParaLDA.png -------------------------------------------------------------------------------- /Imagenes/Introduccion/Test/derPar4.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/jugernaut/MACTI-programacionparalelo/HEAD/Imagenes/Introduccion/Test/derPar4.png -------------------------------------------------------------------------------- /Imagenes/Introduccion/brontobyte.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/jugernaut/MACTI-programacionparalelo/HEAD/Imagenes/Introduccion/brontobyte.jpg -------------------------------------------------------------------------------- /Imagenes/Introduccion/complejidad.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/jugernaut/MACTI-programacionparalelo/HEAD/Imagenes/Introduccion/complejidad.png -------------------------------------------------------------------------------- /Imagenes/Introduccion/nuevocolab.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/jugernaut/MACTI-programacionparalelo/HEAD/Imagenes/Introduccion/nuevocolab.png -------------------------------------------------------------------------------- /Imagenes/Introduccion/repositorio.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/jugernaut/MACTI-programacionparalelo/HEAD/Imagenes/Introduccion/repositorio.jpg -------------------------------------------------------------------------------- /Imagenes/OpenMP/ejemploSumaBinaria.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/jugernaut/MACTI-programacionparalelo/HEAD/Imagenes/OpenMP/ejemploSumaBinaria.png -------------------------------------------------------------------------------- /Imagenes/RedesNeuronales/NeuronaAND.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/jugernaut/MACTI-programacionparalelo/HEAD/Imagenes/RedesNeuronales/NeuronaAND.png -------------------------------------------------------------------------------- /Imagenes/Introduccion/Test/comprobacion.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/jugernaut/MACTI-programacionparalelo/HEAD/Imagenes/Introduccion/Test/comprobacion.png -------------------------------------------------------------------------------- /Imagenes/Introduccion/git_branch_merge.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/jugernaut/MACTI-programacionparalelo/HEAD/Imagenes/Introduccion/git_branch_merge.png -------------------------------------------------------------------------------- /Imagenes/RedesNeuronales/perceptronReg.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/jugernaut/MACTI-programacionparalelo/HEAD/Imagenes/RedesNeuronales/perceptronReg.png -------------------------------------------------------------------------------- /Imagenes/Envoltorios/fashion-mnist-sprite.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/jugernaut/MACTI-programacionparalelo/HEAD/Imagenes/Envoltorios/fashion-mnist-sprite.png -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # Programación en Paralelo 2 | Repositorio de jupyternotebooks para el seminario de programación en paralelo. 3 | 4 | Licencia Creative Commons
Esta obra está bajo una Licencia Creative Commons Atribución-NoComercial-CompartirIgual 4.0 Internacional. 5 | -------------------------------------------------------------------------------- /Imagenes/Introduccion/Test/CreaJSON.json: -------------------------------------------------------------------------------- 1 | { 2 | "alumnos": [ 3 | { 4 | "Nombre": "Peter", 5 | "Tutor": "Mario Molina", 6 | "Especilidad": "actuaria" 7 | }, 8 | { 9 | "Nombre": "Pedro", 10 | "Tutor": "Miguel de Icaza", 11 | "Especilidad": "ciencias de la computacion" 12 | }, 13 | { 14 | "Nombre": "Sonia", 15 | "Tutor": "Miguel de Icaza", 16 | "Especilidad": "ciencias de la computacion" 17 | }, 18 | { 19 | "Nombre": "Alvaro", 20 | "Tutor": "Isaac Newton", 21 | "Especilidad": "matematicas" 22 | }, 23 | { 24 | "Nombre": "Alfa", 25 | "Tutor": "Isaac Newton", 26 | "Especilidad": "matematicas" 27 | }, 28 | { 29 | "Nombre": "Almendra", 30 | "Tutor": "Charles Darwin", 31 | "Especilidad": "biologia" 32 | }, 33 | { 34 | "Nombre": "Gisel", 35 | "Tutor": "Charles Darwin", 36 | "Especilidad": "biologia" 37 | }, 38 | { 39 | "Nombre": "Mike", 40 | "Tutor": "Mark Musk", 41 | "Especilidad": "ciencia de datos" 42 | }, 43 | { 44 | "Nombre": "Canek", 45 | "Tutor": "Mark Musk", 46 | "Especilidad": "ciencia de datos" 47 | }, 48 | { 49 | "Nombre": "Arturo", 50 | "Tutor": "Mark Musk", 51 | "Especilidad": "ciencia de datos" 52 | } 53 | ] 54 | } -------------------------------------------------------------------------------- /01_OpenMP/04_SumaBinaria_Paralela.ipynb: -------------------------------------------------------------------------------- 1 | { 2 | "cells": [ 3 | { 4 | "cell_type": "markdown", 5 | "metadata": {}, 6 | "source": [ 7 | "\"Open" 8 | ] 9 | }, 10 | { 11 | "cell_type": "markdown", 12 | "metadata": { 13 | "id": "i4hKF5yxLZ38" 14 | }, 15 | "source": [ 16 | "\n", 17 | "

Suma Binaria Paralela

\n", 18 | "
\n", 19 | " \n", 20 | "
Profesor: M. en C. Miguel Angel Pérez León
\n", 21 | "
Ayudante: Lucía Martínez Rivas
\n", 22 | "
Ayudante: Erick Jesús Rios Gonzalez
\n", 23 | "
Materia: Seminario de programación en paralelo
\n", 24 | "
" 25 | ] 26 | }, 27 | { 28 | "cell_type": "markdown", 29 | "metadata": { 30 | "id": "jYpFnteADTSh" 31 | }, 32 | "source": [ 33 | "\n", 34 | "# Suma Binaria Paralela\n", 35 | "\n", 36 | "### Teoría\n", 37 | "\n", 38 | "A continuación se presenta un ejemplo de la suma binaria secuencial de dos números.\n", 39 | "Se sumará el número 77 con 36 en su representación binaria, de manera secuencial. A continuación se muestra la representación binaria de ambos números.\n", 40 | "\n", 41 | "
\n", 42 | " \n", 43 | "
\n", 44 | "\n", 45 | "### Suma secuencial\n", 46 | "\n", 47 | "La suma se realiza de derecha a izquierda, sumando dígito a dígito, recordando que $0 + 1 = 1$ e inversamente tenemos que $1 + 0 = 1$ y que $0 + 0 = 0$ y que sumar uno más uno es igual a cero pero acarreando un uno $1 + 1 = 0$. Hasta el momento de sumar el tercer dígito obtenemos un acarreo, esto se muestra en el Cuadro \\ref{Acarreo}.\n", 48 | "\n", 49 | "\n", 50 | "
\n", 51 | " \n", 52 | "
\n", 53 | "\n", 54 | "### Suma paralela\n", 55 | "\n", 56 | "A continuación se plantea la suma binaria paralela vista en la clase teórica. \\\\\n", 57 | "\n", 58 | "Se tiene una suma que tiene ocho pares de dígitos y la estrategia indica que hay que dividir en sumas hasta tener de dos pares de dígitos. \n", 59 | "Para el ejemplo planteado de forma secuencial tenemos inicialmente una suma de ocho dígitos, ésta se parte en dos y cada una tiene que sumar cuatro pares de dígitos las cuales a la vez se dividen a la mitad obteniendo así cuatro sumas de dos pares de dígitos, para este paso ya se puede realizar la suma, puesto que tenemos el caso base. Luego se realiza **backtracking** sumando el acarreo a la suma del lado izquierdo que se presente. \n", 60 | "\n", 61 | "\n", 62 | "
\n", 63 | " \n", 64 | "
\n", 65 | "\n", 66 | "\n", 67 | "## Actividad\n", 68 | "\n", 69 | "1. Implementar la suma de cualesquiera dos números binarios de forma secuencial y paralela usando arreglos de tamaño $k$ con $k = 2^n$; es decir, cada número será representado en un arreglo, tal que el tamaño de éste es potencia de dos. Esto es sin pérdida de generalidad.\n", 70 | " \n", 71 | "2. Realizar un experimento práctico el cual consiste en obtener los valores de Tiempo de ejecución, Velocidad, Eficiencia y Fracción serial.\n", 72 | " \n", 73 | "3. Elaborar un reporte donde especifiques el número de procesadores y núcleos que tiene el equipo donde ejecutaste la práctica, así cómo una descripción de como obtuviste esta información. \n", 74 | " \n", 75 | "4. Indicar en el reporte los valores de tiempo obtenidos para ambos algoritmos, así como un análisis de estos valores.\n", 76 | " \n", 77 | "\n" 78 | ] 79 | } 80 | ], 81 | "metadata": { 82 | "colab": { 83 | "name": "04_SumaBinaria_Paralela.ipynb", 84 | "provenance": [] 85 | }, 86 | "kernelspec": { 87 | "display_name": "Python 3 (ipykernel)", 88 | "language": "python", 89 | "name": "python3" 90 | }, 91 | "language_info": { 92 | "codemirror_mode": { 93 | "name": "ipython", 94 | "version": 3 95 | }, 96 | "file_extension": ".py", 97 | "mimetype": "text/x-python", 98 | "name": "python", 99 | "nbconvert_exporter": "python", 100 | "pygments_lexer": "ipython3", 101 | "version": "3.11.6" 102 | } 103 | }, 104 | "nbformat": 4, 105 | "nbformat_minor": 4 106 | } 107 | -------------------------------------------------------------------------------- /01_OpenMP/.ipynb_checkpoints/04_SumaBinaria_Paralela-checkpoint.ipynb: -------------------------------------------------------------------------------- 1 | { 2 | "cells": [ 3 | { 4 | "cell_type": "markdown", 5 | "metadata": {}, 6 | "source": [ 7 | "\"Open" 8 | ] 9 | }, 10 | { 11 | "cell_type": "markdown", 12 | "metadata": { 13 | "id": "i4hKF5yxLZ38" 14 | }, 15 | "source": [ 16 | "\n", 17 | "

Suma Binaria Paralela

\n", 18 | "
\n", 19 | " \n", 20 | "
Profesor: M. en C. Miguel Angel Pérez León
\n", 21 | "
Ayudante: Lucía Martínez Rivas
\n", 22 | "
Ayudante: Erick Jesús Rios Gonzalez
\n", 23 | "
Materia: Seminario de programación en paralelo
\n", 24 | "
" 25 | ] 26 | }, 27 | { 28 | "cell_type": "markdown", 29 | "metadata": { 30 | "id": "jYpFnteADTSh" 31 | }, 32 | "source": [ 33 | "\n", 34 | "# Suma Binaria Paralela\n", 35 | "\n", 36 | "### Teoría\n", 37 | "\n", 38 | "A continuación se presenta un ejemplo de la suma binaria secuencial de dos números.\n", 39 | "Se sumará el número 77 con 36 en su representación binaria, de manera secuencial. A continuación se muestra la representación binaria de ambos números.\n", 40 | "\n", 41 | "
\n", 42 | " \n", 43 | "
\n", 44 | "\n", 45 | "### Suma secuencial\n", 46 | "\n", 47 | "La suma se realiza de derecha a izquierda, sumando dígito a dígito, recordando que $0 + 1 = 1$ e inversamente tenemos que $1 + 0 = 1$ y que $0 + 0 = 0$ y que sumar uno más uno es igual a cero pero acarreando un uno $1 + 1 = 0$. Hasta el momento de sumar el tercer dígito obtenemos un acarreo, esto se muestra en el Cuadro \\ref{Acarreo}.\n", 48 | "\n", 49 | "\n", 50 | "
\n", 51 | " \n", 52 | "
\n", 53 | "\n", 54 | "### Suma paralela\n", 55 | "\n", 56 | "A continuación se plantea la suma binaria paralela vista en la clase teórica. \\\\\n", 57 | "\n", 58 | "Se tiene una suma que tiene ocho pares de dígitos y la estrategia indica que hay que dividir en sumas hasta tener de dos pares de dígitos. \n", 59 | "Para el ejemplo planteado de forma secuencial tenemos inicialmente una suma de ocho dígitos, ésta se parte en dos y cada una tiene que sumar cuatro pares de dígitos las cuales a la vez se dividen a la mitad obteniendo así cuatro sumas de dos pares de dígitos, para este paso ya se puede realizar la suma, puesto que tenemos el caso base. Luego se realiza **backtracking** sumando el acarreo a la suma del lado izquierdo que se presente. \n", 60 | "\n", 61 | "\n", 62 | "
\n", 63 | " \n", 64 | "
\n", 65 | "\n", 66 | "\n", 67 | "## Actividad\n", 68 | "\n", 69 | "1. Implementar la suma de cualesquiera dos números binarios de forma secuencial y paralela usando arreglos de tamaño $k$ con $k = 2^n$; es decir, cada número será representado en un arreglo, tal que el tamaño de éste es potencia de dos. Esto es sin pérdida de generalidad.\n", 70 | " \n", 71 | "2. Realizar un experimento práctico el cual consiste en obtener los valores de Tiempo de ejecución, Velocidad, Eficiencia y Fracción serial.\n", 72 | " \n", 73 | "3. Elaborar un reporte donde especifiques el número de procesadores y núcleos que tiene el equipo donde ejecutaste la práctica, así cómo una descripción de como obtuviste esta información. \n", 74 | " \n", 75 | "4. Indicar en el reporte los valores de tiempo obtenidos para ambos algoritmos, así como un análisis de estos valores.\n", 76 | " \n", 77 | "\n" 78 | ] 79 | } 80 | ], 81 | "metadata": { 82 | "colab": { 83 | "name": "04_SumaBinaria_Paralela.ipynb", 84 | "provenance": [] 85 | }, 86 | "kernelspec": { 87 | "display_name": "Python 3 (ipykernel)", 88 | "language": "python", 89 | "name": "python3" 90 | }, 91 | "language_info": { 92 | "codemirror_mode": { 93 | "name": "ipython", 94 | "version": 3 95 | }, 96 | "file_extension": ".py", 97 | "mimetype": "text/x-python", 98 | "name": "python", 99 | "nbconvert_exporter": "python", 100 | "pygments_lexer": "ipython3", 101 | "version": "3.11.6" 102 | } 103 | }, 104 | "nbformat": 4, 105 | "nbformat_minor": 4 106 | } 107 | -------------------------------------------------------------------------------- /04_Envoltorios/03_EjemplosModelosIA.ipynb: -------------------------------------------------------------------------------- 1 | { 2 | "nbformat": 4, 3 | "nbformat_minor": 0, 4 | "metadata": { 5 | "colab": { 6 | "provenance": [], 7 | "toc_visible": true, 8 | "authorship_tag": "ABX9TyN08o7E6z0ZK736C7h8PBqL", 9 | "include_colab_link": true 10 | }, 11 | "kernelspec": { 12 | "name": "python3", 13 | "display_name": "Python 3" 14 | }, 15 | "language_info": { 16 | "name": "python" 17 | } 18 | }, 19 | "cells": [ 20 | { 21 | "cell_type": "markdown", 22 | "metadata": { 23 | "id": "view-in-github", 24 | "colab_type": "text" 25 | }, 26 | "source": [ 27 | "\"Open" 28 | ] 29 | }, 30 | { 31 | "cell_type": "markdown", 32 | "source": [ 33 | "# Ejemplos de modelos recientes\n", 34 | "\n", 35 | "Ejemplos de modelos recientes by Miguel Angel Pérez León is licensed under CC BY-NC-SA 4.0

" 36 | ], 37 | "metadata": { 38 | "id": "4c1ULJt43NVg" 39 | } 40 | }, 41 | { 42 | "cell_type": "markdown", 43 | "source": [ 44 | "# Herramientas estilo ChatGPT\n", 45 | "\n", 46 | "Las herramientas estilo GPT, son modelos de inteligencia artificial que utilizan una arquitectura llamada **Transformer, que es una red neuronal profunda** que procesa los datos secuenciales mediante la atención. La atención es un mecanismo que le permite al modelo enfocarse en las partes más relevantes de los datos para generar una salida. Estos modelos se entrenan con una gran cantidad de textos conversacionales extraídos de internet, y aprende a generar respuestas coherentes y naturales a partir de palabras clave. ChatGPT o Bing Chat puede adaptarse a diferentes contextos y personalidades, y puede generar textos en diferentes idiomas.\n", 47 | "\n", 48 | "Estas son algunas de las aplicaciones de las herramientas estilo GPT son la generación de contenido creativo, la escritura de resúmenes, la traducción automática y la asistencia en la búsqueda de información.\n", 49 | "\n", 50 | "Algunos ejemplos de herramientas de estilo GPT son:\n", 51 | "\n", 52 | "- **OpenAI GPT-3**: Es el modelo de lenguaje más avanzado y potente hasta la fecha, capaz de generar textos coherentes y relevantes sobre cualquier tema, con diferentes estilos y formatos. Se puede acceder a él a través de una API o de plataformas como Playground o Codex.\n", 53 | "- **Bing chat**: es un chatbot de búsqueda de Microsoft Bing que ayuda a los usuarios a encontrar información y responder preguntas. Como Bing chat, puedo ayudarte a encontrar información en la web y proporcionarte respuestas precisas y detalladas a tus preguntas.\n", 54 | "- **Bard**: es un chatbot de inteligencia artificial (IA) desarrollado por Google que permite a los usuarios colaborar con IA generativa1. A diferencia de su competidor ChatGPT, Bard puede acceder a información actualizada de internet y tiene un botón “Google it” que da acceso directo al buscador. Como un colaborador creativo y útil, Bard puede mejorar tu creatividad y ayudarte a generar contenido.\n", 55 | "- **Hugging Face Transformers**: Es una biblioteca de código abierto que ofrece una colección de modelos de lenguaje pre-entrenados y personalizables, basados en arquitecturas como GPT, BERT o T5. Se puede usar para tareas como la clasificación de textos, el análisis de sentimientos, la generación de resúmenes o la extracción de entidades.\n", 56 | "- **InferKit**: Es una herramienta en línea que permite generar textos a partir de palabras clave o frases iniciales, usando un modelo de lenguaje similar a GPT-3. Se puede ajustar el tono, la longitud y el formato del texto generado, así como elegir entre diferentes temas o categorías.\n", 57 | "\n" 58 | ], 59 | "metadata": { 60 | "id": "_wq9ZDG-O5FH" 61 | } 62 | }, 63 | { 64 | "cell_type": "markdown", 65 | "source": [ 66 | "## GitHub Copilot\n", 67 | "\n", 68 | "GitHub Copilot es un nuevo asistente de codificación impulsado por la inteligencia artificial que fue desarrollado por GitHub en colaboración con OpenAI. Este asistente utiliza un modelo de lenguaje de última generación para sugerir y autocompletar el código de manera eficiente. Es un programador de pares de IA que puedes usar para obtener sugerencias para líneas o funciones completas directamente en el editor.\n", 69 | "\n", 70 | "
\n", 71 | "\n", 72 | "
\n", 73 | "\n" 74 | ], 75 | "metadata": { 76 | "id": "MgQo-GblUdOR" 77 | } 78 | }, 79 | { 80 | "cell_type": "markdown", 81 | "source": [ 82 | "## Otras IA's\n", 83 | "\n", 84 | "- **Midjourney**: es un laboratorio independiente de investigación que explora nuevos medios de pensamiento y expande los poderes imaginativos de la especie humana. Está enfocado en diseño, infraestructura humana y IA. El equipo está dirigido por David Holz, cofundador de LeapMotion y cuenta con un increíble conjunto de asesores. También es el nombre que le han dado a su IA, que sirve para crear imágenes a partir de texto, lo que se conoce como text to image. Actualmente, solo se puede utilizar mediante un bot en el Discord oficial del proyecto.\n", 85 | "\n", 86 | "- **DALL·E**: es un sistema de IA desarrollado por OpenAI que puede crear imágenes y arte realistas a partir de una descripción en lenguaje natural. Puede combinar conceptos, atributos y estilos para generar imágenes originales y realistas a partir de una descripción de texto. En enero de 2021, OpenAI presentó DALL·E y un año después, su nuevo sistema, DALL·E 2, genera imágenes más realistas y precisas con una resolución 4 veces mayor.\n", 87 | "\n", 88 | "
\n", 89 | "\n", 90 | "
\n" 91 | ], 92 | "metadata": { 93 | "id": "yQixh9UnbpvO" 94 | } 95 | }, 96 | { 97 | "cell_type": "markdown", 98 | "source": [ 99 | "# ¿Qué necesitamos?\n", 100 | "\n", 101 | "En este curso, vamos a aprender sobre inteligencia Artificial, cómo funciona el aprendizaje de máquina y las aplicaciones que se le ha dado. Para ello vamo a necesitar 3 herramientas fundamentales:\n", 102 | "\n", 103 | "- Matemáticas: Las matemáticas son el estudio de las propiedades y relaciones de los números, las formas, las cantidades y los patrones. Las matemáticas son fundamentales para la inteligencia artificial, ya que permiten modelar y resolver problemas complejos con precisión y eficiencia. Algunas ramas de las matemáticas que se aplican a la **inteligencia artificial son el álgebra lineal, el cálculo, la estadística, la probabilidad, la optimización**, etc. Estas ramas nos ayudan a entender y **manipular los datos, las funciones, las matrices, los vectores, las derivadas, las integrales, las distribuciones, las variables aleatorias, los algoritmos**, etc.\n", 104 | "\n", 105 | "- Programación: La programación es el proceso de crear instrucciones que le dicen a una computadora qué hacer. Para programar, se utiliza un lenguaje de programación, que es un conjunto de reglas y símbolos que permiten expresar las instrucciones de forma comprensible para la computadora. Algunos ejemplos de lenguajes de programación son **Python**, Java, C++, etc. La programación es una habilidad esencial para crear y modificar modelos de inteligencia artificial como chatGPT o Bing chat.\n", 106 | "\n", 107 | "- Los Chats estilo GPT: son modelos de inteligencia artificial que utilizan una arquitectura llamada **Transformer, que es una red neuronal profunda** que procesa los datos secuenciales mediante la atención. La atención es un mecanismo que le permite al modelo enfocarse en las partes más relevantes de los datos para generar una salida. Estos modelos se entrenan con una gran cantidad de textos conversacionales extraídos de internet, y aprende a generar respuestas coherentes y naturales a partir de palabras clave. ChatGPT o Bing Chat puede adaptarse a diferentes contextos y personalidades, y puede generar textos en diferentes idiomas.\n", 108 | "\n", 109 | "Como pueden ver, este tipo de tecnologìas son modelos muy avanzados y potentes que requiere de conocimientos previos de programación y matemáticas para comprender su funcionamiento y sus posibilidades. En este curso, vamos a explorar de manera superficial estos conceptos y a ver cómo podemos utilizar cestas herramientas a nuestro favor para comprender lo que hay detrás del aprendizaje de máquina.\n", 110 | "\n", 111 | "Después de lo mostrado hasta el momento, te planteo la siguiente pregunta, **¿podrías distinguir si este notebook fue creado por una IA o por un humano?**.\n", 112 | "\n", 113 | "¿La siguiente imágen fue creada por un ser humano?\n", 114 | "\n", 115 | "
\n", 116 | "\n", 117 | "
\n", 118 | "\n", 119 | "¿La siguiente imágen es real o falsa?\n", 120 | "\n", 121 | "
\n", 122 | "\n", 123 | "
\n", 124 | "\n", 125 | "Desde hace mucho tiempo las IA's han estado presentes en nuestras vidas, solo que no lo habíamos notado, **¿alguna vez te has preguntado como sabe facebook o youtube qué anuncios mostrarte?**\n", 126 | "\n", 127 | "Después de lo visto en este notebook lo mejor que podemos hacer es adaptarnos a esta revolución digital (sin mencionar la computación cuántica) y aprovechar la técnología a nuestro favor, ya que de no hacerlo así la selección natural hara su trabajo." 128 | ], 129 | "metadata": { 130 | "id": "YkH0p54n4g47" 131 | } 132 | }, 133 | { 134 | "cell_type": "markdown", 135 | "source": [ 136 | "## Referencias\n", 137 | "\n", 138 | "* Prueba de Turing - Wikipedia, la enciclopedia libre. https://es.wikipedia.org/wiki/Prueba_de_Turing\n", 139 | "* Test de Turing: qué es, cómo funciona, ventajas y limitaciones. https://psicologiaymente.com/cultura/test-turing\n", 140 | "* Medir la inteligencia artificial: el test de Turing | OpenMind. https://www.bbvaopenmind.com/tecnologia/inteligencia-artificial/medir-la-inteligencia-artificial-el-test-de-turing/" 141 | ], 142 | "metadata": { 143 | "id": "8jDqfTViMSkU" 144 | } 145 | } 146 | ] 147 | } -------------------------------------------------------------------------------- /00_Introduccion/01_GitHub.ipynb: -------------------------------------------------------------------------------- 1 | { 2 | "cells": [ 3 | { 4 | "cell_type": "markdown", 5 | "metadata": { 6 | "colab_type": "text", 7 | "id": "view-in-github" 8 | }, 9 | "source": [ 10 | "\"Open" 11 | ] 12 | }, 13 | { 14 | "cell_type": "markdown", 15 | "metadata": { 16 | "id": "4hZLrKGISFdt" 17 | }, 18 | "source": [ 19 | "\n", 20 | "

Google Colab y GitHub Fundación TELMEX

\n", 21 | "
\n", 22 | " \n", 23 | "
Profesor: M. en C. Miguel Angel Pérez León.
\n", 24 | "
correo: zeus@ciencias.unam.mx
\n", 25 | "
" 26 | ] 27 | }, 28 | { 29 | "cell_type": "markdown", 30 | "metadata": { 31 | "id": "MvR-pOHCSXLg" 32 | }, 33 | "source": [ 34 | "# Introducción\n", 35 | "\n", 36 | "En esta presentaciónvamos a ver cuáles son las principales carcaterísticas de *GitHub* y como usarlo para nuestros proyectos.\n", 37 | "\n", 38 | "Como ya se ha mnencionado previamente *GitHub* es un conjunto de herramientas en una plataforma que nos permite principalmente alojar nuestros proyectos informaticos en repositorios.\n", 39 | "\n", 40 | "Para mayor documentació e información al respecto, visitar el sitio oficial de [*GitHub*](https://github.com)." 41 | ] 42 | }, 43 | { 44 | "cell_type": "markdown", 45 | "metadata": { 46 | "id": "YXDk2MHbUjKK" 47 | }, 48 | "source": [ 49 | "# ¿Qué es *GitHub*?\n", 50 | "\n", 51 | "*Github* es una plataforma creada con la finalidad de alojar el código de los proyectos de cualquier desarrollador, fue comprada por *Microsoft* en junio del 2018. La plataforma tiene la intención de que los desarrolladores suban el código de sus aplicaciones y herramientas, y que como usuario no sólo puedas descargar el proyecto o la aplicación, sino también entrar a su perfil para leer sobre ella o **colaborar con su desarrollo**.\n", 52 | "\n", 53 | "Como su nombre indica, esta herramienta utiliza el sistema de control de versiones *Git* diseñado por [Linus Torvalds](https://www.xataka.com/preview-main/219296/d48f7c92ccc696c85361158ae4ac26f8). *Git* es un sistema de gestión de versiones con el que los desarrolladores pueden **administrar y organizar su proyecto**, ordenando el código de cada una de las nuevas versiones que sacan de sus aplicaciones para tratar de minimizar los errores potenciales y en caso de ser necesario **volver a una versión previa** a esto se le conoce como *rollback*.\n", 54 | "\n", 55 | "*GitHub* tiene una característica muy útil llamada [*GitHub pages*](https://pages.github.com), que te permite publicar el código del sitio en vivo en la Web.\n", 56 | "\n", 57 | "Así que en pocas palabras podemos decir que *GitHub* es la unión de 2 herramientas *Git* para controlar y organizar versión de los proyectos y al agregarle la palabra *Hub* se le añade la función social y web mediante la cual se puede compartir y facilitar la colaboración de otros desarrolladores. De tal manera que en suma *GitHub* es una herramienta que nos permite organizar y compartir los proyectos que así lo necesiten. " 58 | ] 59 | }, 60 | { 61 | "cell_type": "markdown", 62 | "metadata": { 63 | "id": "se7Qhnb7X0i6" 64 | }, 65 | "source": [ 66 | "# ¿Cómo comenzar a utilizar *GitHub*?\n", 67 | "\n", 68 | "Existen varios caminos para comenzar a utilizar *GitHub* pero lo primero que necesitamos es generar una cuenta de *GitHub* en el siguiente\n", 69 | "[enlace](https://github.com/signup?ref_cta=Sign+up&ref_loc=header+logged+out&ref_page=%2F&source=header-home).\n" 70 | ] 71 | }, 72 | { 73 | "cell_type": "markdown", 74 | "metadata": { 75 | "id": "LjloCBJsZ8NY" 76 | }, 77 | "source": [ 78 | "### Crear un repositorio\n", 79 | "\n", 80 | "Incluso sin necesidad de cuenta, podemos ingresar a *GitHub* y descargar los proyectos que sean de nuestro interes. Pero una vez que ya tenemos cuenta de *GitHUb* lo siguiente es crear un repositorio (proyecto), esto es necesario para almacenar nuestro código y todo lo relacionado al mismo. Para hacer esto basta con dar click en el botón *New*, como se muestra en la siguiente imagen.\n", 81 | "\n", 82 | "
\n", 83 | " \n", 84 | "
\n", 85 | "\n", 86 | "Y finalmente completamos los campos necesarios para la creación del repositorio.\n", 87 | "\n", 88 | "
\n", 89 | " \n", 90 | "
\n", 91 | "\n", 92 | "Con esto ya hemos creado el respositorio en *GitHub* y ya estamos listos para comenzar a publicar lo ncesario en el mismo." 93 | ] 94 | }, 95 | { 96 | "cell_type": "markdown", 97 | "metadata": { 98 | "id": "nc_N5wuRdb4D" 99 | }, 100 | "source": [ 101 | "### Publicar desde *Google Colab*\n", 102 | "\n", 103 | "Ya que tenemos nuestro repositorio es importante identificar la *URL* que lo caracteriza, ya que esta va a ser su \"matricula\" y será la forma en cómo vamos a poder acceder al mismo. Esta *URL* la podemos ver en la página principal de nuestro repositorio.\n", 104 | "\n", 105 | "
\n", 106 | " \n", 107 | "
\n", 108 | "\n", 109 | "Bien, ahora existen muchos caminos para poder publicar contenido en nuestro repositorio, uno de estos caminos es instalar *GitHub* en nuestra computadora local y mediante linea de comandos crear un **repositorio local** que se vincule a nuestro repositorio en *GitHub*, este es el mejor camino pero también el que requiere más tiempo y conocimiento.\n", 110 | "\n", 111 | "
\n", 112 | " \n", 113 | "
\n", 114 | "\n", 115 | "Otro camino es instalar un *IDE* (Entorno de Desarrollo), como lo puede ser *Eclipse*, *NetBeans*, *Visual Studio*, etc. e instalar el correspondiente *plugin* de *GitHub*.\n", 116 | "\n", 117 | "
\n", 118 | " \n", 119 | "
\n", 120 | "\n", 121 | "Para fines de este curso, por sencillez vamos a publicar nuestro código directamente desde *Google Colab* ya que de esta forma **nos ahorramos la instalación y configuración** que requieren las 2 opciones previamente descritas.\n", 122 | "\n", 123 | "Lo primero que necesitamos es iniciar sesión en nuestra cuenta de *Gmail* y posteriormente ir a nuestro drive y seleccionar *nuevo*, después *mas* y finalmente *Google Colaboratory*.\n", 124 | "\n", 125 | "
\n", 126 | " \n", 127 | "
\n", 128 | "\n", 129 | "Esto nos va a generar un documento en blanco (*jupyter notebook* o *colab*) en el cual podemos comenzar a escribir lo que necesitemos.\n", 130 | "\n", 131 | "
\n", 132 | " \n", 133 | "
\n", 134 | "\n", 135 | "Es importante mencionar que este documento nuevo, su nombre inicial es *Untitled0.ipynb* lo primero que debemos hacer es cambiarle el nombre por el que nosotros queramos. Una vez que ya hayamos hecho este cambio y este documento contenga lo que necesitemos lo siguiente es guardarlo en *GitHub*, para esto es necesario dar click en *Archivo* y seleccionar *Guardar una copia en GitHub*.\n", 136 | "\n", 137 | "
\n", 138 | " \n", 139 | "
\n", 140 | "\n", 141 | "Al hacer esto se nos pedirá autenticarnos con nuestra cuenta de usuario de *GitHub*, una vez que nos hayamos autenticado de manera correcta ya podremos ver nuestros repositorios (y los repositorios en los que seamos colaboradores).\n", 142 | "\n", 143 | "
\n", 144 | " \n", 145 | "
\n", 146 | "\n", 147 | "Una vez aquí, es necesario dar el nombre de donde queremos que se guarde nuestro \"documento\" y la rama donde deseamos que se almacene dicho documento. " 148 | ] 149 | }, 150 | { 151 | "cell_type": "markdown", 152 | "metadata": { 153 | "id": "9QEBRicRfbPE" 154 | }, 155 | "source": [ 156 | "#### Rutas\n", 157 | "\n", 158 | "Para que nuestro documento se alamcenece en la ruta correcta, es necesario especificar la ruta absoluta del mismo.\n", 159 | "\n", 160 | "Por ejemplo si mi documento se llama *prueba.ipynb* y quiero que este se alamcenece en dentro de la carpeta *Introduccion* que se encuentra en mi repostorio, entonces al momento de almacenar dicho documento, es necesario poner la ruta.\n", 161 | "\n", 162 | "*Introducci/prueba.ipynb*" 163 | ] 164 | }, 165 | { 166 | "cell_type": "markdown", 167 | "metadata": { 168 | "id": "59KxPr97jnY8" 169 | }, 170 | "source": [ 171 | "#### Ramas (*Branch*)\n", 172 | "\n", 173 | "Una rama es un \"camino\" paralelo que ha tomado nuestro proyecto, eso se hace con la intención de que multiples colaboradores puedna trabajar en una parte en especifico del proyecto.\n", 174 | "\n", 175 | "Inicialmente contamos con la rama principal o *main*, pero podémos crear tantas ramas como se necesiten.\n", 176 | "\n", 177 | "
\n", 178 | " \n", 179 | "
\n", 180 | "\n", 181 | "El concepto de rama, es muy importante ya que forma parte fundamental del control de versiones.\n", 182 | "\n", 183 | "
\n", 184 | " \n", 185 | "
" 186 | ] 187 | }, 188 | { 189 | "cell_type": "markdown", 190 | "metadata": { 191 | "id": "kwMpCXtgJrtV" 192 | }, 193 | "source": [ 194 | "#### Publicar (*commit*)\n", 195 | "\n", 196 | "Una vez que ya especificamos la *URL* y la rama, basta con dar click en aceptar (se recomienda seleccionar el *checkbox* que genera el boton de *google colab* y con esto estamos publicando (haciendo *commit*) en el repositorio remoto, es decir *GitHub*.\n", 197 | "\n", 198 | "
\n", 199 | " \n", 200 | "
" 201 | ] 202 | }, 203 | { 204 | "cell_type": "markdown", 205 | "metadata": { 206 | "id": "13yU0yLt04il" 207 | }, 208 | "source": [ 209 | "### Arquitecto\n", 210 | "\n", 211 | "Una vez que ya se publico lo necesario, ahora del lado de *GitHub* podemos proceder a revisar y en caso de ser aprobada el commit, entonces podemos realizar la mezcla con el código principal del proyecto. \n", 212 | "\n", 213 | "
\n", 214 | " \n", 215 | "
\n" 216 | ] 217 | }, 218 | { 219 | "cell_type": "markdown", 220 | "metadata": { 221 | "id": "XXz9fc-J0R9T" 222 | }, 223 | "source": [ 224 | "## Git desde linea de comandos en google colab\n", 225 | "\n", 226 | "Lo primero que necesitamos hacer es clonar un repositorio existente, eso lo hacemos con el comando" 227 | ] 228 | }, 229 | { 230 | "cell_type": "code", 231 | "execution_count": 3, 232 | "metadata": { 233 | "colab": { 234 | "base_uri": "https://localhost:8080/" 235 | }, 236 | "id": "bEzXIh2i0jak", 237 | "outputId": "4dade45b-8edf-49aa-c4a6-3bf9920167e6" 238 | }, 239 | "outputs": [ 240 | { 241 | "name": "stdout", 242 | "output_type": "stream", 243 | "text": [ 244 | "Cloning into 'Telmex'...\n", 245 | "remote: Enumerating objects: 3, done.\u001b[K\n", 246 | "remote: Counting objects: 100% (3/3), done.\u001b[K\n", 247 | "remote: Total 3 (delta 0), reused 0 (delta 0), pack-reused 0\u001b[K\n", 248 | "Unpacking objects: 100% (3/3), done.\n" 249 | ] 250 | } 251 | ], 252 | "source": [ 253 | "!git clone https://github.com/jugernaut/Telmex.git" 254 | ] 255 | }, 256 | { 257 | "cell_type": "markdown", 258 | "metadata": { 259 | "id": "mrm7HB3H0pVm" 260 | }, 261 | "source": [ 262 | "Una vez que ya colnamos el repositorio lo siguiente es desplazarnos a la carpeta clonada y ahí inicializamos el repositorio." 263 | ] 264 | }, 265 | { 266 | "cell_type": "code", 267 | "execution_count": 4, 268 | "metadata": { 269 | "colab": { 270 | "base_uri": "https://localhost:8080/" 271 | }, 272 | "id": "qzgrW41_03BX", 273 | "outputId": "e95ef4b1-6063-41f9-b6e7-d361d54329d8" 274 | }, 275 | "outputs": [ 276 | { 277 | "name": "stdout", 278 | "output_type": "stream", 279 | "text": [ 280 | "Reinitialized existing Git repository in /content/Telmex/.git/\n" 281 | ] 282 | } 283 | ], 284 | "source": [ 285 | "!cd Telmex && git init" 286 | ] 287 | } 288 | ], 289 | "metadata": { 290 | "colab": { 291 | "authorship_tag": "ABX9TyOLVr7lxUDv8m3O52gkH4tL", 292 | "collapsed_sections": [], 293 | "include_colab_link": true, 294 | "provenance": [] 295 | }, 296 | "kernelspec": { 297 | "display_name": "Python 3 (ipykernel)", 298 | "language": "python", 299 | "name": "python3" 300 | }, 301 | "language_info": { 302 | "codemirror_mode": { 303 | "name": "ipython", 304 | "version": 3 305 | }, 306 | "file_extension": ".py", 307 | "mimetype": "text/x-python", 308 | "name": "python", 309 | "nbconvert_exporter": "python", 310 | "pygments_lexer": "ipython3", 311 | "version": "3.11.6" 312 | } 313 | }, 314 | "nbformat": 4, 315 | "nbformat_minor": 4 316 | } 317 | -------------------------------------------------------------------------------- /00_Introduccion/.ipynb_checkpoints/01_GitHub-checkpoint.ipynb: -------------------------------------------------------------------------------- 1 | { 2 | "cells": [ 3 | { 4 | "cell_type": "markdown", 5 | "metadata": { 6 | "colab_type": "text", 7 | "id": "view-in-github" 8 | }, 9 | "source": [ 10 | "\"Open" 11 | ] 12 | }, 13 | { 14 | "cell_type": "markdown", 15 | "metadata": { 16 | "id": "4hZLrKGISFdt" 17 | }, 18 | "source": [ 19 | "\n", 20 | "

Google Colab y GitHub Fundación TELMEX

\n", 21 | "
\n", 22 | " \n", 23 | "
Profesor: M. en C. Miguel Angel Pérez León.
\n", 24 | "
correo: zeus@ciencias.unam.mx
\n", 25 | "
" 26 | ] 27 | }, 28 | { 29 | "cell_type": "markdown", 30 | "metadata": { 31 | "id": "MvR-pOHCSXLg" 32 | }, 33 | "source": [ 34 | "# Introducción\n", 35 | "\n", 36 | "En esta presentaciónvamos a ver cuáles son las principales carcaterísticas de *GitHub* y como usarlo para nuestros proyectos.\n", 37 | "\n", 38 | "Como ya se ha mnencionado previamente *GitHub* es un conjunto de herramientas en una plataforma que nos permite principalmente alojar nuestros proyectos informaticos en repositorios.\n", 39 | "\n", 40 | "Para mayor documentació e información al respecto, visitar el sitio oficial de [*GitHub*](https://github.com)." 41 | ] 42 | }, 43 | { 44 | "cell_type": "markdown", 45 | "metadata": { 46 | "id": "YXDk2MHbUjKK" 47 | }, 48 | "source": [ 49 | "# ¿Qué es *GitHub*?\n", 50 | "\n", 51 | "*Github* es una plataforma creada con la finalidad de alojar el código de los proyectos de cualquier desarrollador, fue comprada por *Microsoft* en junio del 2018. La plataforma tiene la intención de que los desarrolladores suban el código de sus aplicaciones y herramientas, y que como usuario no sólo puedas descargar el proyecto o la aplicación, sino también entrar a su perfil para leer sobre ella o **colaborar con su desarrollo**.\n", 52 | "\n", 53 | "Como su nombre indica, esta herramienta utiliza el sistema de control de versiones *Git* diseñado por [Linus Torvalds](https://www.xataka.com/preview-main/219296/d48f7c92ccc696c85361158ae4ac26f8). *Git* es un sistema de gestión de versiones con el que los desarrolladores pueden **administrar y organizar su proyecto**, ordenando el código de cada una de las nuevas versiones que sacan de sus aplicaciones para tratar de minimizar los errores potenciales y en caso de ser necesario **volver a una versión previa** a esto se le conoce como *rollback*.\n", 54 | "\n", 55 | "*GitHub* tiene una característica muy útil llamada [*GitHub pages*](https://pages.github.com), que te permite publicar el código del sitio en vivo en la Web.\n", 56 | "\n", 57 | "Así que en pocas palabras podemos decir que *GitHub* es la unión de 2 herramientas *Git* para controlar y organizar versión de los proyectos y al agregarle la palabra *Hub* se le añade la función social y web mediante la cual se puede compartir y facilitar la colaboración de otros desarrolladores. De tal manera que en suma *GitHub* es una herramienta que nos permite organizar y compartir los proyectos que así lo necesiten. " 58 | ] 59 | }, 60 | { 61 | "cell_type": "markdown", 62 | "metadata": { 63 | "id": "se7Qhnb7X0i6" 64 | }, 65 | "source": [ 66 | "# ¿Cómo comenzar a utilizar *GitHub*?\n", 67 | "\n", 68 | "Existen varios caminos para comenzar a utilizar *GitHub* pero lo primero que necesitamos es generar una cuenta de *GitHub* en el siguiente\n", 69 | "[enlace](https://github.com/signup?ref_cta=Sign+up&ref_loc=header+logged+out&ref_page=%2F&source=header-home).\n" 70 | ] 71 | }, 72 | { 73 | "cell_type": "markdown", 74 | "metadata": { 75 | "id": "LjloCBJsZ8NY" 76 | }, 77 | "source": [ 78 | "### Crear un repositorio\n", 79 | "\n", 80 | "Incluso sin necesidad de cuenta, podemos ingresar a *GitHub* y descargar los proyectos que sean de nuestro interes. Pero una vez que ya tenemos cuenta de *GitHUb* lo siguiente es crear un repositorio (proyecto), esto es necesario para almacenar nuestro código y todo lo relacionado al mismo. Para hacer esto basta con dar click en el botón *New*, como se muestra en la siguiente imagen.\n", 81 | "\n", 82 | "
\n", 83 | " \n", 84 | "
\n", 85 | "\n", 86 | "Y finalmente completamos los campos necesarios para la creación del repositorio.\n", 87 | "\n", 88 | "
\n", 89 | " \n", 90 | "
\n", 91 | "\n", 92 | "Con esto ya hemos creado el respositorio en *GitHub* y ya estamos listos para comenzar a publicar lo ncesario en el mismo." 93 | ] 94 | }, 95 | { 96 | "cell_type": "markdown", 97 | "metadata": { 98 | "id": "nc_N5wuRdb4D" 99 | }, 100 | "source": [ 101 | "### Publicar desde *Google Colab*\n", 102 | "\n", 103 | "Ya que tenemos nuestro repositorio es importante identificar la *URL* que lo caracteriza, ya que esta va a ser su \"matricula\" y será la forma en cómo vamos a poder acceder al mismo. Esta *URL* la podemos ver en la página principal de nuestro repositorio.\n", 104 | "\n", 105 | "
\n", 106 | " \n", 107 | "
\n", 108 | "\n", 109 | "Bien, ahora existen muchos caminos para poder publicar contenido en nuestro repositorio, uno de estos caminos es instalar *GitHub* en nuestra computadora local y mediante linea de comandos crear un **repositorio local** que se vincule a nuestro repositorio en *GitHub*, este es el mejor camino pero también el que requiere más tiempo y conocimiento.\n", 110 | "\n", 111 | "
\n", 112 | " \n", 113 | "
\n", 114 | "\n", 115 | "Otro camino es instalar un *IDE* (Entorno de Desarrollo), como lo puede ser *Eclipse*, *NetBeans*, *Visual Studio*, etc. e instalar el correspondiente *plugin* de *GitHub*.\n", 116 | "\n", 117 | "
\n", 118 | " \n", 119 | "
\n", 120 | "\n", 121 | "Para fines de este curso, por sencillez vamos a publicar nuestro código directamente desde *Google Colab* ya que de esta forma **nos ahorramos la instalación y configuración** que requieren las 2 opciones previamente descritas.\n", 122 | "\n", 123 | "Lo primero que necesitamos es iniciar sesión en nuestra cuenta de *Gmail* y posteriormente ir a nuestro drive y seleccionar *nuevo*, después *mas* y finalmente *Google Colaboratory*.\n", 124 | "\n", 125 | "
\n", 126 | " \n", 127 | "
\n", 128 | "\n", 129 | "Esto nos va a generar un documento en blanco (*jupyter notebook* o *colab*) en el cual podemos comenzar a escribir lo que necesitemos.\n", 130 | "\n", 131 | "
\n", 132 | " \n", 133 | "
\n", 134 | "\n", 135 | "Es importante mencionar que este documento nuevo, su nombre inicial es *Untitled0.ipynb* lo primero que debemos hacer es cambiarle el nombre por el que nosotros queramos. Una vez que ya hayamos hecho este cambio y este documento contenga lo que necesitemos lo siguiente es guardarlo en *GitHub*, para esto es necesario dar click en *Archivo* y seleccionar *Guardar una copia en GitHub*.\n", 136 | "\n", 137 | "
\n", 138 | " \n", 139 | "
\n", 140 | "\n", 141 | "Al hacer esto se nos pedirá autenticarnos con nuestra cuenta de usuario de *GitHub*, una vez que nos hayamos autenticado de manera correcta ya podremos ver nuestros repositorios (y los repositorios en los que seamos colaboradores).\n", 142 | "\n", 143 | "
\n", 144 | " \n", 145 | "
\n", 146 | "\n", 147 | "Una vez aquí, es necesario dar el nombre de donde queremos que se guarde nuestro \"documento\" y la rama donde deseamos que se almacene dicho documento. " 148 | ] 149 | }, 150 | { 151 | "cell_type": "markdown", 152 | "metadata": { 153 | "id": "9QEBRicRfbPE" 154 | }, 155 | "source": [ 156 | "#### Rutas\n", 157 | "\n", 158 | "Para que nuestro documento se alamcenece en la ruta correcta, es necesario especificar la ruta absoluta del mismo.\n", 159 | "\n", 160 | "Por ejemplo si mi documento se llama *prueba.ipynb* y quiero que este se alamcenece en dentro de la carpeta *Introduccion* que se encuentra en mi repostorio, entonces al momento de almacenar dicho documento, es necesario poner la ruta.\n", 161 | "\n", 162 | "*Introducci/prueba.ipynb*" 163 | ] 164 | }, 165 | { 166 | "cell_type": "markdown", 167 | "metadata": { 168 | "id": "59KxPr97jnY8" 169 | }, 170 | "source": [ 171 | "#### Ramas (*Branch*)\n", 172 | "\n", 173 | "Una rama es un \"camino\" paralelo que ha tomado nuestro proyecto, eso se hace con la intención de que multiples colaboradores puedna trabajar en una parte en especifico del proyecto.\n", 174 | "\n", 175 | "Inicialmente contamos con la rama principal o *main*, pero podémos crear tantas ramas como se necesiten.\n", 176 | "\n", 177 | "
\n", 178 | " \n", 179 | "
\n", 180 | "\n", 181 | "El concepto de rama, es muy importante ya que forma parte fundamental del control de versiones.\n", 182 | "\n", 183 | "
\n", 184 | " \n", 185 | "
" 186 | ] 187 | }, 188 | { 189 | "cell_type": "markdown", 190 | "metadata": { 191 | "id": "kwMpCXtgJrtV" 192 | }, 193 | "source": [ 194 | "#### Publicar (*commit*)\n", 195 | "\n", 196 | "Una vez que ya especificamos la *URL* y la rama, basta con dar click en aceptar (se recomienda seleccionar el *checkbox* que genera el boton de *google colab* y con esto estamos publicando (haciendo *commit*) en el repositorio remoto, es decir *GitHub*.\n", 197 | "\n", 198 | "
\n", 199 | " \n", 200 | "
" 201 | ] 202 | }, 203 | { 204 | "cell_type": "markdown", 205 | "metadata": { 206 | "id": "13yU0yLt04il" 207 | }, 208 | "source": [ 209 | "### Arquitecto\n", 210 | "\n", 211 | "Una vez que ya se publico lo necesario, ahora del lado de *GitHub* podemos proceder a revisar y en caso de ser aprobada el commit, entonces podemos realizar la mezcla con el código principal del proyecto. \n", 212 | "\n", 213 | "
\n", 214 | " \n", 215 | "
\n" 216 | ] 217 | }, 218 | { 219 | "cell_type": "markdown", 220 | "metadata": { 221 | "id": "XXz9fc-J0R9T" 222 | }, 223 | "source": [ 224 | "## Git desde linea de comandos en google colab\n", 225 | "\n", 226 | "Lo primero que necesitamos hacer es clonar un repositorio existente, eso lo hacemos con el comando" 227 | ] 228 | }, 229 | { 230 | "cell_type": "code", 231 | "execution_count": 3, 232 | "metadata": { 233 | "colab": { 234 | "base_uri": "https://localhost:8080/" 235 | }, 236 | "id": "bEzXIh2i0jak", 237 | "outputId": "4dade45b-8edf-49aa-c4a6-3bf9920167e6" 238 | }, 239 | "outputs": [ 240 | { 241 | "name": "stdout", 242 | "output_type": "stream", 243 | "text": [ 244 | "Cloning into 'Telmex'...\n", 245 | "remote: Enumerating objects: 3, done.\u001b[K\n", 246 | "remote: Counting objects: 100% (3/3), done.\u001b[K\n", 247 | "remote: Total 3 (delta 0), reused 0 (delta 0), pack-reused 0\u001b[K\n", 248 | "Unpacking objects: 100% (3/3), done.\n" 249 | ] 250 | } 251 | ], 252 | "source": [ 253 | "!git clone https://github.com/jugernaut/Telmex.git" 254 | ] 255 | }, 256 | { 257 | "cell_type": "markdown", 258 | "metadata": { 259 | "id": "mrm7HB3H0pVm" 260 | }, 261 | "source": [ 262 | "Una vez que ya colnamos el repositorio lo siguiente es desplazarnos a la carpeta clonada y ahí inicializamos el repositorio." 263 | ] 264 | }, 265 | { 266 | "cell_type": "code", 267 | "execution_count": 4, 268 | "metadata": { 269 | "colab": { 270 | "base_uri": "https://localhost:8080/" 271 | }, 272 | "id": "qzgrW41_03BX", 273 | "outputId": "e95ef4b1-6063-41f9-b6e7-d361d54329d8" 274 | }, 275 | "outputs": [ 276 | { 277 | "name": "stdout", 278 | "output_type": "stream", 279 | "text": [ 280 | "Reinitialized existing Git repository in /content/Telmex/.git/\n" 281 | ] 282 | } 283 | ], 284 | "source": [ 285 | "!cd Telmex && git init" 286 | ] 287 | } 288 | ], 289 | "metadata": { 290 | "colab": { 291 | "authorship_tag": "ABX9TyOLVr7lxUDv8m3O52gkH4tL", 292 | "collapsed_sections": [], 293 | "include_colab_link": true, 294 | "provenance": [] 295 | }, 296 | "kernelspec": { 297 | "display_name": "Python 3 (ipykernel)", 298 | "language": "python", 299 | "name": "python3" 300 | }, 301 | "language_info": { 302 | "codemirror_mode": { 303 | "name": "ipython", 304 | "version": 3 305 | }, 306 | "file_extension": ".py", 307 | "mimetype": "text/x-python", 308 | "name": "python", 309 | "nbconvert_exporter": "python", 310 | "pygments_lexer": "ipython3", 311 | "version": "3.11.6" 312 | } 313 | }, 314 | "nbformat": 4, 315 | "nbformat_minor": 4 316 | } 317 | -------------------------------------------------------------------------------- /00_Introduccion/06_MergeQuick.ipynb: -------------------------------------------------------------------------------- 1 | { 2 | "cells": [ 3 | { 4 | "cell_type": "markdown", 5 | "metadata": { 6 | "colab_type": "text", 7 | "id": "view-in-github" 8 | }, 9 | "source": [ 10 | "\"Open" 11 | ] 12 | }, 13 | { 14 | "cell_type": "markdown", 15 | "metadata": { 16 | "id": "JAsbRnI2Mz94" 17 | }, 18 | "source": [ 19 | "\n", 20 | "

MergeSort y QuickSort (análisis)

\n", 21 | "
\n", 22 | " \n", 23 | "
Profesor: M. en C. Miguel Angel Pérez León
\n", 24 | "
Ayudante: Lucía Martínez Rivas
\n", 25 | "
Ayudante: Erick Jesús Rios Gonzalez
\n", 26 | "
Materia: Seminario de programación en paralelo
\n", 27 | "
" 28 | ] 29 | }, 30 | { 31 | "cell_type": "markdown", 32 | "metadata": { 33 | "id": "Z2HsvTi77D9Y" 34 | }, 35 | "source": [ 36 | "# MergeSort\n", 37 | "\n", 38 | "El algoritmo de ordenamiento *MergeSort*, es uno de los algoritmos que se estudia con frecuencia cuando se comienza con el análisis de algoritmos.\n", 39 | " \n", 40 | "La estrategia principal de este algoritmo de ordenamiento es la conocida como \"divide y venceras\". Inicialmente se tiene un conjunto o estructura de datos (lista, vector, arreglo, etc) de tamaño $n$ que se encuentran desordenados y que mediante algún atributo podemos ordenar, la idea de este algoritmo es la siguiente:\n", 41 | "\n", 42 | "1. Partir el conjunto en 2 subconjuntos de tamaño $\\frac{n}2$.\n", 43 | "2. Posteriormente volver a dividir estos en 4 subconjuntos de tamaño $\\frac{n}4$, se repite este proceso hasta que se tienen subconjuntos de tamaño 2.\n", 44 | "3. Ya que se tienen conjuntos de tamaño a lo más 1, se toma un par de estos elementos y se mezclan para formar un subconjunto ordenado.\n", 45 | "4. Cada uno de estos subconjuntos ordenados se mezclan de manera recursiva y ordenada, hasta que todo el conjunto de datos se encuentra ordenado.\n", 46 | "\n", 47 | "
\n", 48 | "\n", 49 | "
\n", 50 | "\n", 51 | "Dado estos antecedentes procedemos a definir la función de recurrencia, para poder identificar a que orden de complejidad pertenece este algoritmo recursivo." 52 | ] 53 | }, 54 | { 55 | "cell_type": "markdown", 56 | "metadata": { 57 | "id": "mlm6KfnURLCA" 58 | }, 59 | "source": [ 60 | "## Análisis\n", 61 | "\n", 62 | "Para el caso cuando se requiere ordenar una colección (lista) de tamaño 1 (o 0 caso trivial), basta con devolver dicha lista ya que esta ya esta ordenada, lo cual toma tiempo constante, digamos $b$.\n", 63 | "\n", 64 | "Para el caso de una colección de tamaño 2 ó mayor, es necesario partir a la mitad dicha colección, ordenar ambas subcolecciones y mezclarlas. Ahora consideremos que para simplificar el análisis de la complejidad diremos que $a$ es el tiempo que toma al microprocesador realizar una operación.\n", 65 | "\n", 66 | "Es por esto que ordenar una colección de tamaño $n$ tomará en total.\n", 67 | "\n", 68 | "$$2T(\\frac{n}{2})+a\\cdot n$$\n", 69 | "\n" 70 | ] 71 | }, 72 | { 73 | "cell_type": "markdown", 74 | "metadata": { 75 | "id": "eEEEkd74Ra-s" 76 | }, 77 | "source": [ 78 | "## Algoritmo básico\n", 79 | "\n", 80 | "A continuación se muestra el pseudocódigo del algoritmo para ordenar por mezcla.\n", 81 | "\n", 82 | "
\n", 83 | " \n", 84 | "
" 85 | ] 86 | }, 87 | { 88 | "cell_type": "markdown", 89 | "metadata": { 90 | "id": "A8nU41pJRxKf" 91 | }, 92 | "source": [ 93 | "## ¿Qué sucede con colecciones de tamaño $n$?\n", 94 | "\n", 95 | "Dado el análisis (y el pseudocódigo del algoritmo) podemos ver que ordenar una colección de tamaño $n$ tomara $2T(\\frac{n}{2})+a\\cdot n$. Pero este valor aun no permite identificar a que orden de complejidad pertenece este algoritmo.\n", 96 | "\n", 97 | "Es por eso que necesitamos definir la función de recurrencia de la siguiente forma.\n", 98 | "\n", 99 | "Función de recurrencia para el algoritmo de ordenamiento *MergeSort*:\n", 100 | "\n", 101 | "$$T(n)=\\begin{cases}\n", 102 | "b & n=0\\,\\acute{o}\\,n=1\\\\\n", 103 | "2T(\\frac{n}{2})+a\\cdot n & n\\geq2\n", 104 | "\\end{cases} \\tag{1}$$\n", 105 | "\n", 106 | "A la función (1), se le conoce como la función de recurrencia asociada al algoritmo de ordenamiento *MergeSort*. Ya que conocemos la función de recurrencia podemos tratar de determinar de manera formal cuantas operaciones le toma a este algoritmo ordenar una colección de datos.\n" 107 | ] 108 | }, 109 | { 110 | "cell_type": "markdown", 111 | "metadata": { 112 | "id": "iczZjvRuSCCk" 113 | }, 114 | "source": [ 115 | "## Demostración\n", 116 | "\n", 117 | "Esta demostración se sustenta en el análisis realizado previamene y en el [teorema maestro](https://es.wikipedia.org/wiki/Teorema_maestro).\n", 118 | "\n", 119 | "Sea $T(n)$ el número de operaciones que le toma al algoritmo anterior ordenar una lista de tamaño $n$ y dada la función de recurrencia. \n", 120 | "\n", 121 | "P.D. $$T(n)=n\\cdot b+a\\cdot n\\cdot\\log_{2}n$$\n", 122 | "\n", 123 | "Para mayor claridad de la demostración definimos $n=2^{k}$\n", 124 | "\n", 125 | "$$\\begin{eqnarray*}\n", 126 | "T(n)\t& = &\tT(2^{k}) \\\\\n", 127 | " & = & 2T(2^{k-1})+a\\cdot2^{k}....Definición\\\\\n", 128 | " & = & 2(2T(2^{k-2})+a\\cdot2^{k-1})+a\\cdot2^{k}.....Leyes\\,exponentes\\,y\\,Función\\,recurrencia \\\\\n", 129 | " & = & 2^{2}T(2^{k-2})+a\\cdot2^{k}+a\\cdot2^{k}.......Algebra\\,elemental\\\\\n", 130 | "\t& = & 2^{2}(2T(2^{k-3})+a\\cdot2^{k-2})+2\\cdot a\\cdot2^{k}.....Función\\,recurrencia\\\\ \n", 131 | "i-veces & \\vdots & \\\\\n", 132 | "\t& = & 2^{i}T(2^{k-i})+i\\cdot a\\cdot2^{k} \\\\\n", 133 | "i=k\t\t& \\vdots & \\\\\n", 134 | "\t& = & 2^{k}T(2^{k-k})+k\\cdot a\\cdot2^{k}......2^{k-k}=1 \\\\\n", 135 | "\t& = &\t2^{k}b+k\\cdot a\\cdot2^{k}........T(1)=b \\\\\n", 136 | "\t& = &\tn\\cdot b+k\\cdot a\\cdot n......n=2^{k} \\\\\n", 137 | "\t& = &\tn\\cdot \\color{red}b+ \\color{red}a\\cdot n\\cdot\\log_{2}n....(2) \\\\\n", 138 | "\\end{eqnarray*}$$\n", 139 | "\n" 140 | ] 141 | }, 142 | { 143 | "cell_type": "markdown", 144 | "metadata": { 145 | "id": "7NJYrNzSSYxe" 146 | }, 147 | "source": [ 148 | "## Orden de complejidad (cota superior asintótica)\n", 149 | "\n", 150 | "Ya que $a$ y $b$ son constantes podemos concluir que de la ecuación (2), la función que 'crece' más rápido es \n", 151 | "\n", 152 | "$$a\\cdot n\\cdot\\log_{2}n$$\n", 153 | "\n", 154 | "Esa es la función que **acota superiormente el desempeño del algoritmo** *MergeSort*.\n", 155 | "\n", 156 | "Finalmente si asumimos que $a=c$, entonces se puede concluir que $T(n)\\in O(n\\cdot\\log_{2}n)$, es decir que el orden de complejidad al cual pertenece el algoritmo *MergeSort* es $n\\cdot\\log_{2}n$.\n", 157 | "\n", 158 | "En otras palabras podemos decir que el número de operaciones que le toma a *MergeSort* ordenar una colección de tamaño $n$ es proporcional a $n\\cdot\\log_{2}n$.\n", 159 | "\n", 160 | "Esto significa (con sustento matemático) que *MergeSort* tiene un mejor desempeño que *InsertionSort, SeleccionSort* o *BubbleSort* en cuanto a la cantidad de operaciones (tiempo) que le toma ordenar una colección de datos.\n", 161 | "\n", 162 | "En otras palabras podemos decir que si pusiéramos a competir (en términos de tiempo) a *MergeSort* contra, por ejemplo *BubbleSort*, el ganador seria *MergeSort*.\n" 163 | ] 164 | }, 165 | { 166 | "cell_type": "markdown", 167 | "metadata": { 168 | "id": "qjDkvoF89_3n" 169 | }, 170 | "source": [ 171 | "# QuickSort\n", 172 | "\n", 173 | "Otro de los algoritmos que ha mostrado un desempeño muy bueno en términos de tiempo de ejecución es el algoritmo conocido como *QuickSort*.\n", 174 | " \n", 175 | "La forma en la que funciona *QuickSort* es muy similar a *MergeSort* en el sentido de que inicialmente se tiene un conjunto o estructura de datos (lista, vector, arreglo, etc) de tamaño $n$ que se encuentra desordenado y que mediante algún atributo podemos ordenar. La diferencia entre ambos algoritmos es que *QuickSort* se toma un **pivote** para poder acomodar a los menores y mayores. \n", 176 | "\n", 177 | "1. Tomamos un valor de la lista de datos a ordenar (que idealmente parte a la colección a la mitad), a ese valor le llamamos pivote.\n", 178 | "2. Una vez que se eligió al pivote, comparamos a todos los elementos contra el pivote y **almacenamos los menores al lado izquierdo del pivote y a los mayores del lado derecho** los cual nos deja 2 subconjuntos de tamaño $\\frac{n}2$.\n", 179 | "2. Posteriormente volvemos a tomar un pivote en cada una de las respectivas subconjuntos, e idealmente volvemos a dividir estas en 4 subconjuntos de tamaño $\\frac{n}4$, se repite este proceso hasta que se tienen subconjuntos de tamaño 2.\n", 180 | "3. Ya que se tienen conjuntos de tamaño a lo mas 2, se ordenan de manera individual cada uno de ellos.\n", 181 | "4. Cada uno de estos subconjuntos ordenados se mezclan de manera recursiva y ordenada, hasta que todo el conjunto de datos se encuentra ordenado.\n", 182 | "\n", 183 | "
\n", 184 | "\n", 185 | "
" 186 | ] 187 | }, 188 | { 189 | "cell_type": "markdown", 190 | "metadata": { 191 | "id": "gsxkxdZvznIp" 192 | }, 193 | "source": [ 194 | "## Análisis\n", 195 | "\n", 196 | "Hint, para identificar el peor caso es necesario prestar especial atención al pivote." 197 | ] 198 | }, 199 | { 200 | "cell_type": "markdown", 201 | "metadata": { 202 | "id": "d0eTfDUJSTjm" 203 | }, 204 | "source": [ 205 | "## Algoritmo recurviso\n", 206 | "\n", 207 | "En la celda siguiente se muestra el códgio correspondiente a la versión recursiva del algoritmo *QuickSort*." 208 | ] 209 | }, 210 | { 211 | "cell_type": "code", 212 | "execution_count": 2, 213 | "metadata": { 214 | "colab": { 215 | "base_uri": "https://localhost:8080/" 216 | }, 217 | "id": "x1UrNM561WKo", 218 | "outputId": "fd0baeee-05cc-4422-bc23-bc414446c5b5" 219 | }, 220 | "outputs": [ 221 | { 222 | "name": "stdout", 223 | "output_type": "stream", 224 | "text": [ 225 | "[1, 2, 3, 4, 5, 7, 8, 9]\n" 226 | ] 227 | } 228 | ], 229 | "source": [ 230 | "# Definicion recursiva de quicksort\n", 231 | "def quickSort(lista):\n", 232 | " # si la lista es de tamano 1 o menor se devuelve\n", 233 | " if len(lista) < 2:\n", 234 | " return lista\n", 235 | " # en otro caso se parte la lista y se resuelve recursivamente\n", 236 | " else:\n", 237 | " # se parte la lista original (n operaciones)\n", 238 | " menores, pivote, mayores = particion(lista) \n", 239 | " # 2*T(n/2)\n", 240 | " return quickSort(menores)+[pivote]+quickSort(mayores)\n", 241 | "\n", 242 | "# Definicion del algoritmo para partir una lista en mayores y menores\n", 243 | "def particion(lista):\n", 244 | " mayores, menores = [], []\n", 245 | " # pivote para realizar la comparación\n", 246 | " pivote = lista[0]\n", 247 | " for i in range(1,len(lista)):\n", 248 | " if lista[i] < pivote:\n", 249 | " menores.append(lista[i])\n", 250 | " else:\n", 251 | " mayores.append(lista[i])\n", 252 | " # se devuelven ambas listas y el pivote\n", 253 | " return menores, pivote, mayores\n", 254 | "\n", 255 | "print(quickSort([2,8,5,3,9,4,1,7]))" 256 | ] 257 | }, 258 | { 259 | "cell_type": "markdown", 260 | "metadata": { 261 | "id": "ou8sIl3O27CY" 262 | }, 263 | "source": [ 264 | "## Orden de complejidad (cota superior asintótica)\n", 265 | "\n", 266 | "Se deja como ejercicio al lector.\n", 267 | "\n" 268 | ] 269 | }, 270 | { 271 | "cell_type": "markdown", 272 | "metadata": { 273 | "id": "dTMtQcsc4QA8" 274 | }, 275 | "source": [ 276 | "# Secuencial v.s. Paralelo\n", 277 | "\n", 278 | "Existen muchas restricciones y detalles a tomar en cuenta antes de comenzar con el análisis de algoritmos en paralelo, si embargo una de las más importantes es la ley de Amdahal." 279 | ] 280 | }, 281 | { 282 | "cell_type": "markdown", 283 | "metadata": { 284 | "id": "pc6ND99T6HDA" 285 | }, 286 | "source": [ 287 | "## Ley de Amdahal\n", 288 | "\n", 289 | "Sea $f$ la fracción de operaciones en un cálculo computacional que será llevado a cabo de manera secuencial, donde $0\\leq f\\leq1$. La máxima velocidad $\\Psi$ alcanzada mediante programación en paralelo con una computadora con $p$ procesadores enfocados en el mismo cálculo es:\n", 290 | "\n", 291 | "$$\\Psi\\leq\\frac{1}{f+(1-f)/p}$$" 292 | ] 293 | }, 294 | { 295 | "cell_type": "markdown", 296 | "metadata": { 297 | "id": "YHiyGAPySr_f" 298 | }, 299 | "source": [ 300 | "#Referencias\n", 301 | "\n", 302 | "1. Thomas H. Cormen: Introduction to Algorithms.\n", 303 | "2. Libro Web: [Introduccion a Python](https://uniwebsidad.com/libros/algoritmos-python/capitulo-20/cuanto-cuesta-el-merge-sort?from=librosweb).\n", 304 | "3. Daniel T. Joyce: Object-Oriented Data Structures.\n", 305 | "4. John C. Mitchell: Concepts in programing Languages." 306 | ] 307 | } 308 | ], 309 | "metadata": { 310 | "colab": { 311 | "collapsed_sections": [], 312 | "include_colab_link": true, 313 | "name": "Ordenamientos_SCP.ipynb", 314 | "provenance": [], 315 | "toc_visible": true 316 | }, 317 | "kernelspec": { 318 | "display_name": "Python 3 (ipykernel)", 319 | "language": "python", 320 | "name": "python3" 321 | }, 322 | "language_info": { 323 | "codemirror_mode": { 324 | "name": "ipython", 325 | "version": 3 326 | }, 327 | "file_extension": ".py", 328 | "mimetype": "text/x-python", 329 | "name": "python", 330 | "nbconvert_exporter": "python", 331 | "pygments_lexer": "ipython3", 332 | "version": "3.11.6" 333 | } 334 | }, 335 | "nbformat": 4, 336 | "nbformat_minor": 4 337 | } 338 | -------------------------------------------------------------------------------- /00_Introduccion/.ipynb_checkpoints/06_MergeQuick-checkpoint.ipynb: -------------------------------------------------------------------------------- 1 | { 2 | "cells": [ 3 | { 4 | "cell_type": "markdown", 5 | "metadata": { 6 | "colab_type": "text", 7 | "id": "view-in-github" 8 | }, 9 | "source": [ 10 | "\"Open" 11 | ] 12 | }, 13 | { 14 | "cell_type": "markdown", 15 | "metadata": { 16 | "id": "JAsbRnI2Mz94" 17 | }, 18 | "source": [ 19 | "\n", 20 | "

MergeSort y QuickSort (análisis)

\n", 21 | "
\n", 22 | " \n", 23 | "
Profesor: M. en C. Miguel Angel Pérez León
\n", 24 | "
Ayudante: Lucía Martínez Rivas
\n", 25 | "
Ayudante: Erick Jesús Rios Gonzalez
\n", 26 | "
Materia: Seminario de programación en paralelo
\n", 27 | "
" 28 | ] 29 | }, 30 | { 31 | "cell_type": "markdown", 32 | "metadata": { 33 | "id": "Z2HsvTi77D9Y" 34 | }, 35 | "source": [ 36 | "# MergeSort\n", 37 | "\n", 38 | "El algoritmo de ordenamiento *MergeSort*, es uno de los algoritmos que se estudia con frecuencia cuando se comienza con el análisis de algoritmos.\n", 39 | " \n", 40 | "La estrategia principal de este algoritmo de ordenamiento es la conocida como \"divide y venceras\". Inicialmente se tiene un conjunto o estructura de datos (lista, vector, arreglo, etc) de tamaño $n$ que se encuentran desordenados y que mediante algún atributo podemos ordenar, la idea de este algoritmo es la siguiente:\n", 41 | "\n", 42 | "1. Partir el conjunto en 2 subconjuntos de tamaño $\\frac{n}2$.\n", 43 | "2. Posteriormente volver a dividir estos en 4 subconjuntos de tamaño $\\frac{n}4$, se repite este proceso hasta que se tienen subconjuntos de tamaño 2.\n", 44 | "3. Ya que se tienen conjuntos de tamaño a lo más 1, se toma un par de estos elementos y se mezclan para formar un subconjunto ordenado.\n", 45 | "4. Cada uno de estos subconjuntos ordenados se mezclan de manera recursiva y ordenada, hasta que todo el conjunto de datos se encuentra ordenado.\n", 46 | "\n", 47 | "
\n", 48 | "\n", 49 | "
\n", 50 | "\n", 51 | "Dado estos antecedentes procedemos a definir la función de recurrencia, para poder identificar a que orden de complejidad pertenece este algoritmo recursivo." 52 | ] 53 | }, 54 | { 55 | "cell_type": "markdown", 56 | "metadata": { 57 | "id": "mlm6KfnURLCA" 58 | }, 59 | "source": [ 60 | "## Análisis\n", 61 | "\n", 62 | "Para el caso cuando se requiere ordenar una colección (lista) de tamaño 1 (o 0 caso trivial), basta con devolver dicha lista ya que esta ya esta ordenada, lo cual toma tiempo constante, digamos $b$.\n", 63 | "\n", 64 | "Para el caso de una colección de tamaño 2 ó mayor, es necesario partir a la mitad dicha colección, ordenar ambas subcolecciones y mezclarlas. Ahora consideremos que para simplificar el análisis de la complejidad diremos que $a$ es el tiempo que toma al microprocesador realizar una operación.\n", 65 | "\n", 66 | "Es por esto que ordenar una colección de tamaño $n$ tomará en total.\n", 67 | "\n", 68 | "$$2T(\\frac{n}{2})+a\\cdot n$$\n", 69 | "\n" 70 | ] 71 | }, 72 | { 73 | "cell_type": "markdown", 74 | "metadata": { 75 | "id": "eEEEkd74Ra-s" 76 | }, 77 | "source": [ 78 | "## Algoritmo básico\n", 79 | "\n", 80 | "A continuación se muestra el pseudocódigo del algoritmo para ordenar por mezcla.\n", 81 | "\n", 82 | "
\n", 83 | " \n", 84 | "
" 85 | ] 86 | }, 87 | { 88 | "cell_type": "markdown", 89 | "metadata": { 90 | "id": "A8nU41pJRxKf" 91 | }, 92 | "source": [ 93 | "## ¿Qué sucede con colecciones de tamaño $n$?\n", 94 | "\n", 95 | "Dado el análisis (y el pseudocódigo del algoritmo) podemos ver que ordenar una colección de tamaño $n$ tomara $2T(\\frac{n}{2})+a\\cdot n$. Pero este valor aun no permite identificar a que orden de complejidad pertenece este algoritmo.\n", 96 | "\n", 97 | "Es por eso que necesitamos definir la función de recurrencia de la siguiente forma.\n", 98 | "\n", 99 | "Función de recurrencia para el algoritmo de ordenamiento *MergeSort*:\n", 100 | "\n", 101 | "$$T(n)=\\begin{cases}\n", 102 | "b & n=0\\,\\acute{o}\\,n=1\\\\\n", 103 | "2T(\\frac{n}{2})+a\\cdot n & n\\geq2\n", 104 | "\\end{cases} \\tag{1}$$\n", 105 | "\n", 106 | "A la función (1), se le conoce como la función de recurrencia asociada al algoritmo de ordenamiento *MergeSort*. Ya que conocemos la función de recurrencia podemos tratar de determinar de manera formal cuantas operaciones le toma a este algoritmo ordenar una colección de datos.\n" 107 | ] 108 | }, 109 | { 110 | "cell_type": "markdown", 111 | "metadata": { 112 | "id": "iczZjvRuSCCk" 113 | }, 114 | "source": [ 115 | "## Demostración\n", 116 | "\n", 117 | "Esta demostración se sustenta en el análisis realizado previamene y en el [teorema maestro](https://es.wikipedia.org/wiki/Teorema_maestro).\n", 118 | "\n", 119 | "Sea $T(n)$ el número de operaciones que le toma al algoritmo anterior ordenar una lista de tamaño $n$ y dada la función de recurrencia. \n", 120 | "\n", 121 | "P.D. $$T(n)=n\\cdot b+a\\cdot n\\cdot\\log_{2}n$$\n", 122 | "\n", 123 | "Para mayor claridad de la demostración definimos $n=2^{k}$\n", 124 | "\n", 125 | "$$\\begin{eqnarray*}\n", 126 | "T(n)\t& = &\tT(2^{k}) \\\\\n", 127 | " & = & 2T(2^{k-1})+a\\cdot2^{k}....Definición\\\\\n", 128 | " & = & 2(2T(2^{k-2})+a\\cdot2^{k-1})+a\\cdot2^{k}.....Leyes\\,exponentes\\,y\\,Función\\,recurrencia \\\\\n", 129 | " & = & 2^{2}T(2^{k-2})+a\\cdot2^{k}+a\\cdot2^{k}.......Algebra\\,elemental\\\\\n", 130 | "\t& = & 2^{2}(2T(2^{k-3})+a\\cdot2^{k-2})+2\\cdot a\\cdot2^{k}.....Función\\,recurrencia\\\\ \n", 131 | "i-veces & \\vdots & \\\\\n", 132 | "\t& = & 2^{i}T(2^{k-i})+i\\cdot a\\cdot2^{k} \\\\\n", 133 | "i=k\t\t& \\vdots & \\\\\n", 134 | "\t& = & 2^{k}T(2^{k-k})+k\\cdot a\\cdot2^{k}......2^{k-k}=1 \\\\\n", 135 | "\t& = &\t2^{k}b+k\\cdot a\\cdot2^{k}........T(1)=b \\\\\n", 136 | "\t& = &\tn\\cdot b+k\\cdot a\\cdot n......n=2^{k} \\\\\n", 137 | "\t& = &\tn\\cdot \\color{red}b+ \\color{red}a\\cdot n\\cdot\\log_{2}n....(2) \\\\\n", 138 | "\\end{eqnarray*}$$\n", 139 | "\n" 140 | ] 141 | }, 142 | { 143 | "cell_type": "markdown", 144 | "metadata": { 145 | "id": "7NJYrNzSSYxe" 146 | }, 147 | "source": [ 148 | "## Orden de complejidad (cota superior asintótica)\n", 149 | "\n", 150 | "Ya que $a$ y $b$ son constantes podemos concluir que de la ecuación (2), la función que 'crece' más rápido es \n", 151 | "\n", 152 | "$$a\\cdot n\\cdot\\log_{2}n$$\n", 153 | "\n", 154 | "Esa es la función que **acota superiormente el desempeño del algoritmo** *MergeSort*.\n", 155 | "\n", 156 | "Finalmente si asumimos que $a=c$, entonces se puede concluir que $T(n)\\in O(n\\cdot\\log_{2}n)$, es decir que el orden de complejidad al cual pertenece el algoritmo *MergeSort* es $n\\cdot\\log_{2}n$.\n", 157 | "\n", 158 | "En otras palabras podemos decir que el número de operaciones que le toma a *MergeSort* ordenar una colección de tamaño $n$ es proporcional a $n\\cdot\\log_{2}n$.\n", 159 | "\n", 160 | "Esto significa (con sustento matemático) que *MergeSort* tiene un mejor desempeño que *InsertionSort, SeleccionSort* o *BubbleSort* en cuanto a la cantidad de operaciones (tiempo) que le toma ordenar una colección de datos.\n", 161 | "\n", 162 | "En otras palabras podemos decir que si pusiéramos a competir (en términos de tiempo) a *MergeSort* contra, por ejemplo *BubbleSort*, el ganador seria *MergeSort*.\n" 163 | ] 164 | }, 165 | { 166 | "cell_type": "markdown", 167 | "metadata": { 168 | "id": "qjDkvoF89_3n" 169 | }, 170 | "source": [ 171 | "# QuickSort\n", 172 | "\n", 173 | "Otro de los algoritmos que ha mostrado un desempeño muy bueno en términos de tiempo de ejecución es el algoritmo conocido como *QuickSort*.\n", 174 | " \n", 175 | "La forma en la que funciona *QuickSort* es muy similar a *MergeSort* en el sentido de que inicialmente se tiene un conjunto o estructura de datos (lista, vector, arreglo, etc) de tamaño $n$ que se encuentra desordenado y que mediante algún atributo podemos ordenar. La diferencia entre ambos algoritmos es que *QuickSort* se toma un **pivote** para poder acomodar a los menores y mayores. \n", 176 | "\n", 177 | "1. Tomamos un valor de la lista de datos a ordenar (que idealmente parte a la colección a la mitad), a ese valor le llamamos pivote.\n", 178 | "2. Una vez que se eligió al pivote, comparamos a todos los elementos contra el pivote y **almacenamos los menores al lado izquierdo del pivote y a los mayores del lado derecho** los cual nos deja 2 subconjuntos de tamaño $\\frac{n}2$.\n", 179 | "2. Posteriormente volvemos a tomar un pivote en cada una de las respectivas subconjuntos, e idealmente volvemos a dividir estas en 4 subconjuntos de tamaño $\\frac{n}4$, se repite este proceso hasta que se tienen subconjuntos de tamaño 2.\n", 180 | "3. Ya que se tienen conjuntos de tamaño a lo mas 2, se ordenan de manera individual cada uno de ellos.\n", 181 | "4. Cada uno de estos subconjuntos ordenados se mezclan de manera recursiva y ordenada, hasta que todo el conjunto de datos se encuentra ordenado.\n", 182 | "\n", 183 | "
\n", 184 | "\n", 185 | "
" 186 | ] 187 | }, 188 | { 189 | "cell_type": "markdown", 190 | "metadata": { 191 | "id": "gsxkxdZvznIp" 192 | }, 193 | "source": [ 194 | "## Análisis\n", 195 | "\n", 196 | "Hint, para identificar el peor caso es necesario prestar especial atención al pivote." 197 | ] 198 | }, 199 | { 200 | "cell_type": "markdown", 201 | "metadata": { 202 | "id": "d0eTfDUJSTjm" 203 | }, 204 | "source": [ 205 | "## Algoritmo recurviso\n", 206 | "\n", 207 | "En la celda siguiente se muestra el códgio correspondiente a la versión recursiva del algoritmo *QuickSort*." 208 | ] 209 | }, 210 | { 211 | "cell_type": "code", 212 | "execution_count": 2, 213 | "metadata": { 214 | "colab": { 215 | "base_uri": "https://localhost:8080/" 216 | }, 217 | "id": "x1UrNM561WKo", 218 | "outputId": "fd0baeee-05cc-4422-bc23-bc414446c5b5" 219 | }, 220 | "outputs": [ 221 | { 222 | "name": "stdout", 223 | "output_type": "stream", 224 | "text": [ 225 | "[1, 2, 3, 4, 5, 7, 8, 9]\n" 226 | ] 227 | } 228 | ], 229 | "source": [ 230 | "# Definicion recursiva de quicksort\n", 231 | "def quickSort(lista):\n", 232 | " # si la lista es de tamano 1 o menor se devuelve\n", 233 | " if len(lista) < 2:\n", 234 | " return lista\n", 235 | " # en otro caso se parte la lista y se resuelve recursivamente\n", 236 | " else:\n", 237 | " # se parte la lista original (n operaciones)\n", 238 | " menores, pivote, mayores = particion(lista) \n", 239 | " # 2*T(n/2)\n", 240 | " return quickSort(menores)+[pivote]+quickSort(mayores)\n", 241 | "\n", 242 | "# Definicion del algoritmo para partir una lista en mayores y menores\n", 243 | "def particion(lista):\n", 244 | " mayores, menores = [], []\n", 245 | " # pivote para realizar la comparación\n", 246 | " pivote = lista[0]\n", 247 | " for i in range(1,len(lista)):\n", 248 | " if lista[i] < pivote:\n", 249 | " menores.append(lista[i])\n", 250 | " else:\n", 251 | " mayores.append(lista[i])\n", 252 | " # se devuelven ambas listas y el pivote\n", 253 | " return menores, pivote, mayores\n", 254 | "\n", 255 | "print(quickSort([2,8,5,3,9,4,1,7]))" 256 | ] 257 | }, 258 | { 259 | "cell_type": "markdown", 260 | "metadata": { 261 | "id": "ou8sIl3O27CY" 262 | }, 263 | "source": [ 264 | "## Orden de complejidad (cota superior asintótica)\n", 265 | "\n", 266 | "Se deja como ejercicio al lector.\n", 267 | "\n" 268 | ] 269 | }, 270 | { 271 | "cell_type": "markdown", 272 | "metadata": { 273 | "id": "dTMtQcsc4QA8" 274 | }, 275 | "source": [ 276 | "# Secuencial v.s. Paralelo\n", 277 | "\n", 278 | "Existen muchas restricciones y detalles a tomar en cuenta antes de comenzar con el análisis de algoritmos en paralelo, si embargo una de las más importantes es la ley de Amdahal." 279 | ] 280 | }, 281 | { 282 | "cell_type": "markdown", 283 | "metadata": { 284 | "id": "pc6ND99T6HDA" 285 | }, 286 | "source": [ 287 | "## Ley de Amdahal\n", 288 | "\n", 289 | "Sea $f$ la fracción de operaciones en un cálculo computacional que será llevado a cabo de manera secuencial, donde $0\\leq f\\leq1$. La máxima velocidad $\\Psi$ alcanzada mediante programación en paralelo con una computadora con $p$ procesadores enfocados en el mismo cálculo es:\n", 290 | "\n", 291 | "$$\\Psi\\leq\\frac{1}{f+(1-f)/p}$$" 292 | ] 293 | }, 294 | { 295 | "cell_type": "markdown", 296 | "metadata": { 297 | "id": "YHiyGAPySr_f" 298 | }, 299 | "source": [ 300 | "#Referencias\n", 301 | "\n", 302 | "1. Thomas H. Cormen: Introduction to Algorithms.\n", 303 | "2. Libro Web: [Introduccion a Python](https://uniwebsidad.com/libros/algoritmos-python/capitulo-20/cuanto-cuesta-el-merge-sort?from=librosweb).\n", 304 | "3. Daniel T. Joyce: Object-Oriented Data Structures.\n", 305 | "4. John C. Mitchell: Concepts in programing Languages." 306 | ] 307 | } 308 | ], 309 | "metadata": { 310 | "colab": { 311 | "collapsed_sections": [], 312 | "include_colab_link": true, 313 | "name": "Ordenamientos_SCP.ipynb", 314 | "provenance": [], 315 | "toc_visible": true 316 | }, 317 | "kernelspec": { 318 | "display_name": "Python 3 (ipykernel)", 319 | "language": "python", 320 | "name": "python3" 321 | }, 322 | "language_info": { 323 | "codemirror_mode": { 324 | "name": "ipython", 325 | "version": 3 326 | }, 327 | "file_extension": ".py", 328 | "mimetype": "text/x-python", 329 | "name": "python", 330 | "nbconvert_exporter": "python", 331 | "pygments_lexer": "ipython3", 332 | "version": "3.11.6" 333 | } 334 | }, 335 | "nbformat": 4, 336 | "nbformat_minor": 4 337 | } 338 | -------------------------------------------------------------------------------- /00_Introduccion/07_RadixBucket.ipynb: -------------------------------------------------------------------------------- 1 | { 2 | "cells": [ 3 | { 4 | "cell_type": "markdown", 5 | "metadata": { 6 | "colab_type": "text", 7 | "id": "view-in-github" 8 | }, 9 | "source": [ 10 | "\"Open" 11 | ] 12 | }, 13 | { 14 | "cell_type": "markdown", 15 | "metadata": { 16 | "id": "JAsbRnI2Mz94" 17 | }, 18 | "source": [ 19 | "\n", 20 | "

RadixSort y BucketSort (análisis)

\n", 21 | "
\n", 22 | " \n", 23 | "
Profesor: M. en C. Miguel Angel Pérez León
\n", 24 | "
Ayudante: Lucía Martínez Rivas
\n", 25 | "
Ayudante: Erick Jesús Rios Gonzalez
\n", 26 | "
Materia: Seminario de programación en paralelo
\n", 27 | "
" 28 | ] 29 | }, 30 | { 31 | "cell_type": "markdown", 32 | "metadata": { 33 | "id": "h4IewVdLVj8s" 34 | }, 35 | "source": [ 36 | "# Introducción\n", 37 | "\n", 38 | "Este par de algoritmos de ordenamiento (*RadixSort* y *BucketSort*) los podemos considerar algoritmos \"exóticos\", ya que a diferencia de los algoritmos vistos previamente, estos no se basan en comparaciones entre los elementos a ordenar.\n", 39 | "\n", 40 | "Por otro lado estos algoritmos requieren de conocimientos a priori de los datos a ordenar, por ejemplo la longitud en términos de dígitos decimales de los elementos a ordenar." 41 | ] 42 | }, 43 | { 44 | "cell_type": "markdown", 45 | "metadata": { 46 | "id": "Z2HsvTi77D9Y" 47 | }, 48 | "source": [ 49 | "# *RadixSort*\n", 50 | "\n", 51 | "Este algoritmo ordena los elementos de manera similar a como funcionan los tableros que anuncian las llegadas de los aviones en un aeropuerto. Imaginemos que los valores a ordenar los podemos colocar en renglones donde cada renglón contiene casillas para cada dígito del elemento a ordenar, algo así.\n", 52 | "\n", 53 | "$$\n", 54 | "\\begin{array}{ccccc}\n", 55 | "\\left[d_{n}\\right] & \\left[\\ldots\\right] & \\left[d_{2}\\right] & \\left[d_{1}\\right] & \\left[d_{0}\\right]\\end{array}\n", 56 | "$$\n", 57 | "\n", 58 | "La idea detrás de este algoritmo es ordenar cada dígito de derecha a izquierda por cada elemento a ordenar, modificando la posición del elemento a ordenar en caso de que el dígito a ordenar haya sufrido alguna modificación respecto a la posición en la colección.\n", 59 | "\n", 60 | "
\n", 61 | " \n", 62 | "
" 63 | ] 64 | }, 65 | { 66 | "cell_type": "markdown", 67 | "metadata": { 68 | "id": "-Dt5F9Xacou3" 69 | }, 70 | "source": [ 71 | "## Descripción\n", 72 | "\n", 73 | "Para que el algoritmo *RadixSort* funcione de manera correcta hay que **conocer la longitud (en términos) de dígitos** del elemento más extenso a ordenar, una vez que se conoce esta longitud se completan con ceros (a la izquierda del dígito $d_{n}$ en caso de ser necesario). Una vez que todos los elementos a ordenar tienen la misma longitud comienza el algoritmo con los siguientes pasos:\n", 74 | "\n", 75 | "\n", 76 | "1. Comenzamos a ordenar la columna correspondiente al $d_{0}$ (que se le conoce como el dígito menos significativo), se realizan las respectivas modificaciones en las posiciones de los renglones en caso de ser necesario y se continua con la columna $d_{1}$.\n", 77 | "2. Se ordena la columna $d_{1}$, de manera similar a como se hizo con la columna anterior y se procede a la siguiente.\n", 78 | "3. Continuamos ordenando todas las columnas (con sus respectivas modificaciones sobre los renglones), hasta llegar a la columna $d_{n}$ (el dígito más significativo).\n", 79 | "4. Al ordenar el dígito más significativo de cada renglón termina el algoritmo.\n", 80 | "\n", 81 | "\n", 82 | "\n" 83 | ] 84 | }, 85 | { 86 | "cell_type": "markdown", 87 | "metadata": { 88 | "id": "qwuSS-rte3Ds" 89 | }, 90 | "source": [ 91 | "## Ejemplo\n", 92 | "\n", 93 | "Supongamos que se tiene el siguiente conjunto de datos a ordenar que podemos organizarlos de la siguiente manera.\n", 94 | "\n", 95 | "$$\n", 96 | "\\begin{array}{ccc}\n", 97 | "\\left[d_{2}\\right] & \\left[d_{1}\\right] & \\left[d_{0}\\right]\\\\\n", 98 | "\\left[1\\right] & \\left[0\\right] & \\left[5\\right]\\\\\n", 99 | "\\left[0\\right] & \\left[2\\right] & \\left[5\\right]\\\\\n", 100 | "\\left[3\\right] & \\left[0\\right] & \\left[1\\right]\n", 101 | "\\end{array}\n", 102 | "$$\n", 103 | "\n", 104 | "Ahora la idea es comenzar a ordenar la primer columna (la columna correspondiente al digito $d_{0}$) se ordena esa columna, considerando que el $d_{0}$ pertenece a todo un renglon y por lo tanto si el $d_{0}$ de algún renglón cambia su posición, también lo debe hacer todo el renglón. Después de ordenar el $d_{0}$, esta colección de datos se ve de la siguiente forma.\n", 105 | "\n", 106 | "$$\n", 107 | "\\begin{array}{ccc}\n", 108 | "\\left[d_{2}\\right] & \\left[d_{1}\\right] & \\left[\\color{green}{d_{0}}\\right]\\\\\n", 109 | "\\left[3\\right] & \\left[0\\right] & \\left[\\color{green}1\\right]\\\\\n", 110 | "\\left[1\\right] & \\left[0\\right] & \\left[\\color{green}5\\right]\\\\\n", 111 | "\\left[0\\right] & \\left[2\\right] & \\left[\\color{green}5\\right]\n", 112 | "\\end{array}\n", 113 | "$$\n", 114 | "\n", 115 | "Se procede a ordenar la columna correspondiente al $d_{1}$ y podemos notar que no hay cambios en los renglones, ya que la columna $d_{1}$ ya se encuentra ordenada.\n", 116 | "\n", 117 | "$$\n", 118 | "\\begin{array}{ccc}\n", 119 | "\\left[d_{2}\\right] & \\left[\\color{green}{d_{1}}\\right] & \\left[\\color{green}{d_{0}}\\right]\\\\\n", 120 | "\\left[3\\right] & \\left[\\color{green}0\\right] & \\left[\\color{green}1\\right]\\\\\n", 121 | "\\left[1\\right] & \\left[\\color{green}0\\right] & \\left[\\color{green}5\\right]\\\\\n", 122 | "\\left[0\\right] & \\left[\\color{green}2\\right] & \\left[\\color{green}5\\right]\n", 123 | "\\end{array}\n", 124 | "$$\n", 125 | "\n", 126 | "Por último, se ordena la columna $d_{2}$ y la colección queda de la siguiente forma.\n", 127 | "\n", 128 | "$$\n", 129 | "\\begin{array}{ccc}\n", 130 | "\\left[\\color{green}{d_{2}}\\right] & \\left[\\color{green}{d_{1}}\\right] & \\left[\\color{green}{d_{0}}\\right]\\\\\n", 131 | "\\left[\\color{green}0\\right] & \\left[\\color{green}2\\right] & \\left[\\color{green}5\\right]\\\\\n", 132 | "\\left[\\color{green}1\\right] & \\left[\\color{green}0\\right] & \\left[\\color{green}5\\right]\\\\\n", 133 | "\\left[\\color{green}3\\right] & \\left[\\color{green}0\\right] & \\left[\\color{green}1\\right]\n", 134 | "\\end{array}\n", 135 | "$$\n", 136 | "\n", 137 | "Y la colección queda ordenada.\n" 138 | ] 139 | }, 140 | { 141 | "cell_type": "markdown", 142 | "metadata": { 143 | "id": "mlm6KfnURLCA" 144 | }, 145 | "source": [ 146 | "## Análisis y Orden de Complejidad\n", 147 | "\n", 148 | "Dado que este algoritmo no se basa en comparaciones podemos pensar que el ordenar cada columna ($d_{i})$ tiene un costo lineal, es decir $O(n)$ ya que unicamente estamos organizando cada elemento respecto al dígito, tarea muy **similar a cuando organizamos elementos dentro de contenedores o cubetas**.\n", 149 | "\n", 150 | "Ahora supongamos que el elemento de mayor longitud dentro de la colección está conformado por $k-digitos$, entonces se tendrían que ordenar $k$ columnas, por lo tanto el algoritmo *RadixSort* pertenece al orden de complejidad $O(kn)$.\n", 151 | "\n", 152 | "Así que podemos pensar que el peor caso para este algoritmo es cuando $k$ es demasiado grande (y sobretodo si son pocos los elementos que poseén la misma longitud). Pensemos que $k\\approx n$, entonces el orden al que pertenecería este algoritmo sería $O(nn)=O(n²)$.\n", 153 | "\n" 154 | ] 155 | }, 156 | { 157 | "cell_type": "markdown", 158 | "metadata": { 159 | "id": "qjDkvoF89_3n" 160 | }, 161 | "source": [ 162 | "# Ordenamiento por cubetas (*BucketSort*)\n", 163 | "\n", 164 | "Este algoritmo (no comparativo) consiste en generar contenedores (cubetas) que cumplan con determinadas caracteristicas, enviar a los elementos que cumplan con estas a su respectivo contenedor y ordenar cada contenedor de manera individual." 165 | ] 166 | }, 167 | { 168 | "cell_type": "markdown", 169 | "metadata": { 170 | "id": "gsxkxdZvznIp" 171 | }, 172 | "source": [ 173 | "## Descripción\n", 174 | "\n", 175 | "De manera similar a *RadixSort*, para el óptimo funcionamiento de este algoritmo se requieren ciertas caracteristicas y en este caso es que los elementos a ordenar se ecuentren distribuidos de manera uniforme sobre el espacio a ordenar. A continuación una descripción de como funciona este algoritmos:\n", 176 | "\n", 177 | "1. Dado que se conoce a priori el espacio donde se distribuyen los elementos a ordenar, se genéran contenedores (cubetas) con ciertas caracteristicas, por ejemplo un rango de valores, para almacenar a los elementos que cumplan con estas caracteristicas.\n", 178 | "2. Se recorren todos los elementos a ordenar y se va colocando uno a uno en el contenedor correspondiente.\n", 179 | "2. Se ordena cada contenedor de manera individual con este mismo algoritmo (o con alguno visto previamente.\n", 180 | "3. Se extraen los elementos de cada contenedor comenzando con el contenedor que almacene a los elementos de menor valor y finalizando con el contenedor que almacena a los elementos de mayor valor.\n", 181 | "4. El algoritmo termina cuando los elementos del último contener han sido extraidos.\n", 182 | "\n", 183 | "
\n", 184 | "\n", 185 | "
" 186 | ] 187 | }, 188 | { 189 | "cell_type": "markdown", 190 | "metadata": { 191 | "id": "ou8sIl3O27CY" 192 | }, 193 | "source": [ 194 | "## Ejemplo\n", 195 | "\n", 196 | "En la imagen superior se muestra un ejemplo en el cuál se busca ordenar los datos.\n", 197 | "\n", 198 | "$$\n", 199 | "\\left[11\\right]\\left[9\\right]\\left[21\\right]\\left[8\\right]\\left[17\\right]\\left[19\\right]\\left[13\\right]\\left[1\\right]\\left[24\\right]\\left[12\\right]$$\n", 200 | "\n", 201 | "Dado que se conoce a priori el rango en el cuál se encuentran distribuidos los datos, podemos generar 5 contenedores que abarcan los rangos.\n", 202 | "\n", 203 | "$$\n", 204 | "\\left[0,5\\right),\\left[5,10\\right),\\left[10,15\\right),\\left[15,20\\right),\\left[20,26\\right)\n", 205 | "$$\n", 206 | "\n", 207 | "Y al organizar los datos en los contenedres se verían así:\n", 208 | "\n", 209 | "$$\n", 210 | "\\begin{array}{cc}\n", 211 | "\\left[0,5\\right): & 1\\\\\n", 212 | "\\left[5,10\\right): & 9,8\\\\\n", 213 | "\\left[10,15\\right): & 11,13,12\\\\\n", 214 | "\\left[15,20\\right): & 17,19\\\\\n", 215 | "\\left[2,26\\right): & 21,24\n", 216 | "\\end{array}\n", 217 | "$$\n", 218 | "\n", 219 | "Después de ordenar cada contenedor individualmente, los contenedores se ven así:\n", 220 | "\n", 221 | "$$\n", 222 | "\\begin{array}{cc}\n", 223 | "\\left[0,5\\right): & 1\\\\\n", 224 | "\\left[5,10\\right): & 8,9\\\\\n", 225 | "\\left[10,15\\right): & 11,12,13\\\\\n", 226 | "\\left[15,20\\right): & 17,19\\\\\n", 227 | "\\left[2,26\\right): & 21,24\n", 228 | "\\end{array}\n", 229 | "$$\n", 230 | "\n", 231 | "Y al extraer todos los datos de cada contenedor, de manera ordenada los datos finalmente quedan ordenados.\n", 232 | "\n", 233 | "$$\n", 234 | "\\left[1\\right]\\left[8\\right]\\left[9\\right]\\left[11\\right]\\left[12\\right]\\left[13\\right]\\left[17\\right]\\left[19\\right]\\left[21\\right]\\left[24\\right]$$\n", 235 | "\n", 236 | "\n", 237 | "\n", 238 | "\n" 239 | ] 240 | }, 241 | { 242 | "cell_type": "markdown", 243 | "metadata": { 244 | "id": "KjHjPb_U4TbJ" 245 | }, 246 | "source": [ 247 | "## Análisis y Orden de complejidad\n", 248 | "\n", 249 | "Para llevar a cabo el análisis de la complejidad hay que preguntarse ¿qué tipo de algoritmo de ordenamiento se usará para ordenar individualmente cada cubeta y eso ayuda a determinar el orden de complejidad al que pertenece este algoritmo.\n", 250 | "\n", 251 | "Algunos autores consideran a *RadixSort* un caso particular de *BucketSort*. \n", 252 | "\n", 253 | "Se deja como ejercicio determinar el orden de complejidad al que pertenece el algoritmo *BucketSort*." 254 | ] 255 | }, 256 | { 257 | "cell_type": "markdown", 258 | "metadata": { 259 | "id": "dTMtQcsc4QA8" 260 | }, 261 | "source": [ 262 | "# Ordenando Objetos\n", 263 | "\n", 264 | "Es importante notar que este y todos los algoritmos de ordenamiento vistos funcionan con cualquier objeto que sea ordenable (realizando las respectivas adecuaciones), es decir, con todo clase de objetos en la que podamos establecer un orden, por ejemplo: $\\mathbb{N},\\,\\mathbb{Z},\\,\\mathbb{Q},\\,\\mathbb{R}$, incluso con $\\mathbb{C}$ o elementos más complejos como **vectores, matrices, palabras o todo aquello en lo que podamos establecer un orden**." 265 | ] 266 | }, 267 | { 268 | "cell_type": "markdown", 269 | "metadata": { 270 | "id": "pc6ND99T6HDA" 271 | }, 272 | "source": [ 273 | "## Algoritmos de ordenamiento en paralelo\n", 274 | "\n", 275 | "Todos los algoritmos vistos funcionan de manera **secuencial**, es decir se realiza un paso (operación) a la vez, sin embargo esta estrategia (secuencial) es prácticamente obsoleta.\n", 276 | "\n", 277 | "¿Si tuvieramos más de una unidad de procesamiento (CPU), podríamos **implementar algunos de estos algoritmos en paralelo**?." 278 | ] 279 | }, 280 | { 281 | "cell_type": "markdown", 282 | "metadata": { 283 | "id": "YHiyGAPySr_f" 284 | }, 285 | "source": [ 286 | "#Referencias\n", 287 | "\n", 288 | "1. Thomas H. Cormen: Introduction to Algorithms.\n", 289 | "2. Libro Web: [Introduccion a Python](https://uniwebsidad.com/libros/algoritmos-python/capitulo-20/cuanto-cuesta-el-merge-sort?from=librosweb).\n", 290 | "3. Daniel T. Joyce: Object-Oriented Data Structures.\n", 291 | "4. John C. Mitchell: Concepts in programing Languages." 292 | ] 293 | } 294 | ], 295 | "metadata": { 296 | "colab": { 297 | "collapsed_sections": [], 298 | "include_colab_link": true, 299 | "name": "03_RadixBucket.ipynb", 300 | "provenance": [], 301 | "toc_visible": true 302 | }, 303 | "kernelspec": { 304 | "display_name": "Python 3 (ipykernel)", 305 | "language": "python", 306 | "name": "python3" 307 | }, 308 | "language_info": { 309 | "codemirror_mode": { 310 | "name": "ipython", 311 | "version": 3 312 | }, 313 | "file_extension": ".py", 314 | "mimetype": "text/x-python", 315 | "name": "python", 316 | "nbconvert_exporter": "python", 317 | "pygments_lexer": "ipython3", 318 | "version": "3.11.6" 319 | } 320 | }, 321 | "nbformat": 4, 322 | "nbformat_minor": 4 323 | } 324 | -------------------------------------------------------------------------------- /00_Introduccion/.ipynb_checkpoints/07_RadixBucket-checkpoint.ipynb: -------------------------------------------------------------------------------- 1 | { 2 | "cells": [ 3 | { 4 | "cell_type": "markdown", 5 | "metadata": { 6 | "colab_type": "text", 7 | "id": "view-in-github" 8 | }, 9 | "source": [ 10 | "\"Open" 11 | ] 12 | }, 13 | { 14 | "cell_type": "markdown", 15 | "metadata": { 16 | "id": "JAsbRnI2Mz94" 17 | }, 18 | "source": [ 19 | "\n", 20 | "

RadixSort y BucketSort (análisis)

\n", 21 | "
\n", 22 | " \n", 23 | "
Profesor: M. en C. Miguel Angel Pérez León
\n", 24 | "
Ayudante: Lucía Martínez Rivas
\n", 25 | "
Ayudante: Erick Jesús Rios Gonzalez
\n", 26 | "
Materia: Seminario de programación en paralelo
\n", 27 | "
" 28 | ] 29 | }, 30 | { 31 | "cell_type": "markdown", 32 | "metadata": { 33 | "id": "h4IewVdLVj8s" 34 | }, 35 | "source": [ 36 | "# Introducción\n", 37 | "\n", 38 | "Este par de algoritmos de ordenamiento (*RadixSort* y *BucketSort*) los podemos considerar algoritmos \"exóticos\", ya que a diferencia de los algoritmos vistos previamente, estos no se basan en comparaciones entre los elementos a ordenar.\n", 39 | "\n", 40 | "Por otro lado estos algoritmos requieren de conocimientos a priori de los datos a ordenar, por ejemplo la longitud en términos de dígitos decimales de los elementos a ordenar." 41 | ] 42 | }, 43 | { 44 | "cell_type": "markdown", 45 | "metadata": { 46 | "id": "Z2HsvTi77D9Y" 47 | }, 48 | "source": [ 49 | "# *RadixSort*\n", 50 | "\n", 51 | "Este algoritmo ordena los elementos de manera similar a como funcionan los tableros que anuncian las llegadas de los aviones en un aeropuerto. Imaginemos que los valores a ordenar los podemos colocar en renglones donde cada renglón contiene casillas para cada dígito del elemento a ordenar, algo así.\n", 52 | "\n", 53 | "$$\n", 54 | "\\begin{array}{ccccc}\n", 55 | "\\left[d_{n}\\right] & \\left[\\ldots\\right] & \\left[d_{2}\\right] & \\left[d_{1}\\right] & \\left[d_{0}\\right]\\end{array}\n", 56 | "$$\n", 57 | "\n", 58 | "La idea detrás de este algoritmo es ordenar cada dígito de derecha a izquierda por cada elemento a ordenar, modificando la posición del elemento a ordenar en caso de que el dígito a ordenar haya sufrido alguna modificación respecto a la posición en la colección.\n", 59 | "\n", 60 | "
\n", 61 | " \n", 62 | "
" 63 | ] 64 | }, 65 | { 66 | "cell_type": "markdown", 67 | "metadata": { 68 | "id": "-Dt5F9Xacou3" 69 | }, 70 | "source": [ 71 | "## Descripción\n", 72 | "\n", 73 | "Para que el algoritmo *RadixSort* funcione de manera correcta hay que **conocer la longitud (en términos) de dígitos** del elemento más extenso a ordenar, una vez que se conoce esta longitud se completan con ceros (a la izquierda del dígito $d_{n}$ en caso de ser necesario). Una vez que todos los elementos a ordenar tienen la misma longitud comienza el algoritmo con los siguientes pasos:\n", 74 | "\n", 75 | "\n", 76 | "1. Comenzamos a ordenar la columna correspondiente al $d_{0}$ (que se le conoce como el dígito menos significativo), se realizan las respectivas modificaciones en las posiciones de los renglones en caso de ser necesario y se continua con la columna $d_{1}$.\n", 77 | "2. Se ordena la columna $d_{1}$, de manera similar a como se hizo con la columna anterior y se procede a la siguiente.\n", 78 | "3. Continuamos ordenando todas las columnas (con sus respectivas modificaciones sobre los renglones), hasta llegar a la columna $d_{n}$ (el dígito más significativo).\n", 79 | "4. Al ordenar el dígito más significativo de cada renglón termina el algoritmo.\n", 80 | "\n", 81 | "\n", 82 | "\n" 83 | ] 84 | }, 85 | { 86 | "cell_type": "markdown", 87 | "metadata": { 88 | "id": "qwuSS-rte3Ds" 89 | }, 90 | "source": [ 91 | "## Ejemplo\n", 92 | "\n", 93 | "Supongamos que se tiene el siguiente conjunto de datos a ordenar que podemos organizarlos de la siguiente manera.\n", 94 | "\n", 95 | "$$\n", 96 | "\\begin{array}{ccc}\n", 97 | "\\left[d_{2}\\right] & \\left[d_{1}\\right] & \\left[d_{0}\\right]\\\\\n", 98 | "\\left[1\\right] & \\left[0\\right] & \\left[5\\right]\\\\\n", 99 | "\\left[0\\right] & \\left[2\\right] & \\left[5\\right]\\\\\n", 100 | "\\left[3\\right] & \\left[0\\right] & \\left[1\\right]\n", 101 | "\\end{array}\n", 102 | "$$\n", 103 | "\n", 104 | "Ahora la idea es comenzar a ordenar la primer columna (la columna correspondiente al digito $d_{0}$) se ordena esa columna, considerando que el $d_{0}$ pertenece a todo un renglon y por lo tanto si el $d_{0}$ de algún renglón cambia su posición, también lo debe hacer todo el renglón. Después de ordenar el $d_{0}$, esta colección de datos se ve de la siguiente forma.\n", 105 | "\n", 106 | "$$\n", 107 | "\\begin{array}{ccc}\n", 108 | "\\left[d_{2}\\right] & \\left[d_{1}\\right] & \\left[\\color{green}{d_{0}}\\right]\\\\\n", 109 | "\\left[3\\right] & \\left[0\\right] & \\left[\\color{green}1\\right]\\\\\n", 110 | "\\left[1\\right] & \\left[0\\right] & \\left[\\color{green}5\\right]\\\\\n", 111 | "\\left[0\\right] & \\left[2\\right] & \\left[\\color{green}5\\right]\n", 112 | "\\end{array}\n", 113 | "$$\n", 114 | "\n", 115 | "Se procede a ordenar la columna correspondiente al $d_{1}$ y podemos notar que no hay cambios en los renglones, ya que la columna $d_{1}$ ya se encuentra ordenada.\n", 116 | "\n", 117 | "$$\n", 118 | "\\begin{array}{ccc}\n", 119 | "\\left[d_{2}\\right] & \\left[\\color{green}{d_{1}}\\right] & \\left[\\color{green}{d_{0}}\\right]\\\\\n", 120 | "\\left[3\\right] & \\left[\\color{green}0\\right] & \\left[\\color{green}1\\right]\\\\\n", 121 | "\\left[1\\right] & \\left[\\color{green}0\\right] & \\left[\\color{green}5\\right]\\\\\n", 122 | "\\left[0\\right] & \\left[\\color{green}2\\right] & \\left[\\color{green}5\\right]\n", 123 | "\\end{array}\n", 124 | "$$\n", 125 | "\n", 126 | "Por último, se ordena la columna $d_{2}$ y la colección queda de la siguiente forma.\n", 127 | "\n", 128 | "$$\n", 129 | "\\begin{array}{ccc}\n", 130 | "\\left[\\color{green}{d_{2}}\\right] & \\left[\\color{green}{d_{1}}\\right] & \\left[\\color{green}{d_{0}}\\right]\\\\\n", 131 | "\\left[\\color{green}0\\right] & \\left[\\color{green}2\\right] & \\left[\\color{green}5\\right]\\\\\n", 132 | "\\left[\\color{green}1\\right] & \\left[\\color{green}0\\right] & \\left[\\color{green}5\\right]\\\\\n", 133 | "\\left[\\color{green}3\\right] & \\left[\\color{green}0\\right] & \\left[\\color{green}1\\right]\n", 134 | "\\end{array}\n", 135 | "$$\n", 136 | "\n", 137 | "Y la colección queda ordenada.\n" 138 | ] 139 | }, 140 | { 141 | "cell_type": "markdown", 142 | "metadata": { 143 | "id": "mlm6KfnURLCA" 144 | }, 145 | "source": [ 146 | "## Análisis y Orden de Complejidad\n", 147 | "\n", 148 | "Dado que este algoritmo no se basa en comparaciones podemos pensar que el ordenar cada columna ($d_{i})$ tiene un costo lineal, es decir $O(n)$ ya que unicamente estamos organizando cada elemento respecto al dígito, tarea muy **similar a cuando organizamos elementos dentro de contenedores o cubetas**.\n", 149 | "\n", 150 | "Ahora supongamos que el elemento de mayor longitud dentro de la colección está conformado por $k-digitos$, entonces se tendrían que ordenar $k$ columnas, por lo tanto el algoritmo *RadixSort* pertenece al orden de complejidad $O(kn)$.\n", 151 | "\n", 152 | "Así que podemos pensar que el peor caso para este algoritmo es cuando $k$ es demasiado grande (y sobretodo si son pocos los elementos que poseén la misma longitud). Pensemos que $k\\approx n$, entonces el orden al que pertenecería este algoritmo sería $O(nn)=O(n²)$.\n", 153 | "\n" 154 | ] 155 | }, 156 | { 157 | "cell_type": "markdown", 158 | "metadata": { 159 | "id": "qjDkvoF89_3n" 160 | }, 161 | "source": [ 162 | "# Ordenamiento por cubetas (*BucketSort*)\n", 163 | "\n", 164 | "Este algoritmo (no comparativo) consiste en generar contenedores (cubetas) que cumplan con determinadas caracteristicas, enviar a los elementos que cumplan con estas a su respectivo contenedor y ordenar cada contenedor de manera individual." 165 | ] 166 | }, 167 | { 168 | "cell_type": "markdown", 169 | "metadata": { 170 | "id": "gsxkxdZvznIp" 171 | }, 172 | "source": [ 173 | "## Descripción\n", 174 | "\n", 175 | "De manera similar a *RadixSort*, para el óptimo funcionamiento de este algoritmo se requieren ciertas caracteristicas y en este caso es que los elementos a ordenar se ecuentren distribuidos de manera uniforme sobre el espacio a ordenar. A continuación una descripción de como funciona este algoritmos:\n", 176 | "\n", 177 | "1. Dado que se conoce a priori el espacio donde se distribuyen los elementos a ordenar, se genéran contenedores (cubetas) con ciertas caracteristicas, por ejemplo un rango de valores, para almacenar a los elementos que cumplan con estas caracteristicas.\n", 178 | "2. Se recorren todos los elementos a ordenar y se va colocando uno a uno en el contenedor correspondiente.\n", 179 | "2. Se ordena cada contenedor de manera individual con este mismo algoritmo (o con alguno visto previamente.\n", 180 | "3. Se extraen los elementos de cada contenedor comenzando con el contenedor que almacene a los elementos de menor valor y finalizando con el contenedor que almacena a los elementos de mayor valor.\n", 181 | "4. El algoritmo termina cuando los elementos del último contener han sido extraidos.\n", 182 | "\n", 183 | "
\n", 184 | "\n", 185 | "
" 186 | ] 187 | }, 188 | { 189 | "cell_type": "markdown", 190 | "metadata": { 191 | "id": "ou8sIl3O27CY" 192 | }, 193 | "source": [ 194 | "## Ejemplo\n", 195 | "\n", 196 | "En la imagen superior se muestra un ejemplo en el cuál se busca ordenar los datos.\n", 197 | "\n", 198 | "$$\n", 199 | "\\left[11\\right]\\left[9\\right]\\left[21\\right]\\left[8\\right]\\left[17\\right]\\left[19\\right]\\left[13\\right]\\left[1\\right]\\left[24\\right]\\left[12\\right]$$\n", 200 | "\n", 201 | "Dado que se conoce a priori el rango en el cuál se encuentran distribuidos los datos, podemos generar 5 contenedores que abarcan los rangos.\n", 202 | "\n", 203 | "$$\n", 204 | "\\left[0,5\\right),\\left[5,10\\right),\\left[10,15\\right),\\left[15,20\\right),\\left[20,26\\right)\n", 205 | "$$\n", 206 | "\n", 207 | "Y al organizar los datos en los contenedres se verían así:\n", 208 | "\n", 209 | "$$\n", 210 | "\\begin{array}{cc}\n", 211 | "\\left[0,5\\right): & 1\\\\\n", 212 | "\\left[5,10\\right): & 9,8\\\\\n", 213 | "\\left[10,15\\right): & 11,13,12\\\\\n", 214 | "\\left[15,20\\right): & 17,19\\\\\n", 215 | "\\left[2,26\\right): & 21,24\n", 216 | "\\end{array}\n", 217 | "$$\n", 218 | "\n", 219 | "Después de ordenar cada contenedor individualmente, los contenedores se ven así:\n", 220 | "\n", 221 | "$$\n", 222 | "\\begin{array}{cc}\n", 223 | "\\left[0,5\\right): & 1\\\\\n", 224 | "\\left[5,10\\right): & 8,9\\\\\n", 225 | "\\left[10,15\\right): & 11,12,13\\\\\n", 226 | "\\left[15,20\\right): & 17,19\\\\\n", 227 | "\\left[2,26\\right): & 21,24\n", 228 | "\\end{array}\n", 229 | "$$\n", 230 | "\n", 231 | "Y al extraer todos los datos de cada contenedor, de manera ordenada los datos finalmente quedan ordenados.\n", 232 | "\n", 233 | "$$\n", 234 | "\\left[1\\right]\\left[8\\right]\\left[9\\right]\\left[11\\right]\\left[12\\right]\\left[13\\right]\\left[17\\right]\\left[19\\right]\\left[21\\right]\\left[24\\right]$$\n", 235 | "\n", 236 | "\n", 237 | "\n", 238 | "\n" 239 | ] 240 | }, 241 | { 242 | "cell_type": "markdown", 243 | "metadata": { 244 | "id": "KjHjPb_U4TbJ" 245 | }, 246 | "source": [ 247 | "## Análisis y Orden de complejidad\n", 248 | "\n", 249 | "Para llevar a cabo el análisis de la complejidad hay que preguntarse ¿qué tipo de algoritmo de ordenamiento se usará para ordenar individualmente cada cubeta y eso ayuda a determinar el orden de complejidad al que pertenece este algoritmo.\n", 250 | "\n", 251 | "Algunos autores consideran a *RadixSort* un caso particular de *BucketSort*. \n", 252 | "\n", 253 | "Se deja como ejercicio determinar el orden de complejidad al que pertenece el algoritmo *BucketSort*." 254 | ] 255 | }, 256 | { 257 | "cell_type": "markdown", 258 | "metadata": { 259 | "id": "dTMtQcsc4QA8" 260 | }, 261 | "source": [ 262 | "# Ordenando Objetos\n", 263 | "\n", 264 | "Es importante notar que este y todos los algoritmos de ordenamiento vistos funcionan con cualquier objeto que sea ordenable (realizando las respectivas adecuaciones), es decir, con todo clase de objetos en la que podamos establecer un orden, por ejemplo: $\\mathbb{N},\\,\\mathbb{Z},\\,\\mathbb{Q},\\,\\mathbb{R}$, incluso con $\\mathbb{C}$ o elementos más complejos como **vectores, matrices, palabras o todo aquello en lo que podamos establecer un orden**." 265 | ] 266 | }, 267 | { 268 | "cell_type": "markdown", 269 | "metadata": { 270 | "id": "pc6ND99T6HDA" 271 | }, 272 | "source": [ 273 | "## Algoritmos de ordenamiento en paralelo\n", 274 | "\n", 275 | "Todos los algoritmos vistos funcionan de manera **secuencial**, es decir se realiza un paso (operación) a la vez, sin embargo esta estrategia (secuencial) es prácticamente obsoleta.\n", 276 | "\n", 277 | "¿Si tuvieramos más de una unidad de procesamiento (CPU), podríamos **implementar algunos de estos algoritmos en paralelo**?." 278 | ] 279 | }, 280 | { 281 | "cell_type": "markdown", 282 | "metadata": { 283 | "id": "YHiyGAPySr_f" 284 | }, 285 | "source": [ 286 | "#Referencias\n", 287 | "\n", 288 | "1. Thomas H. Cormen: Introduction to Algorithms.\n", 289 | "2. Libro Web: [Introduccion a Python](https://uniwebsidad.com/libros/algoritmos-python/capitulo-20/cuanto-cuesta-el-merge-sort?from=librosweb).\n", 290 | "3. Daniel T. Joyce: Object-Oriented Data Structures.\n", 291 | "4. John C. Mitchell: Concepts in programing Languages." 292 | ] 293 | } 294 | ], 295 | "metadata": { 296 | "colab": { 297 | "collapsed_sections": [], 298 | "include_colab_link": true, 299 | "name": "03_RadixBucket.ipynb", 300 | "provenance": [], 301 | "toc_visible": true 302 | }, 303 | "kernelspec": { 304 | "display_name": "Python 3 (ipykernel)", 305 | "language": "python", 306 | "name": "python3" 307 | }, 308 | "language_info": { 309 | "codemirror_mode": { 310 | "name": "ipython", 311 | "version": 3 312 | }, 313 | "file_extension": ".py", 314 | "mimetype": "text/x-python", 315 | "name": "python", 316 | "nbconvert_exporter": "python", 317 | "pygments_lexer": "ipython3", 318 | "version": "3.11.6" 319 | } 320 | }, 321 | "nbformat": 4, 322 | "nbformat_minor": 4 323 | } 324 | -------------------------------------------------------------------------------- /02_MPI/03_Algoritmos_MPI_SCP.ipynb: -------------------------------------------------------------------------------- 1 | { 2 | "cells": [ 3 | { 4 | "cell_type": "markdown", 5 | "metadata": { 6 | "colab_type": "text", 7 | "id": "view-in-github" 8 | }, 9 | "source": [ 10 | "\"Open" 11 | ] 12 | }, 13 | { 14 | "cell_type": "markdown", 15 | "metadata": { 16 | "id": "Gde4FA2b-KeX" 17 | }, 18 | "source": [ 19 | "\n", 20 | "

Algoritmos MPI

\n", 21 | "
\n", 22 | " \n", 23 | "
Profesor: M. en C. Miguel Angel Pérez León
\n", 24 | "
Ayudante: Lucía Martínez Rivas
\n", 25 | "
Ayudante: Erick Jesús Rios Gonzalez
\n", 26 | "
Materia: Seminario de programación en paralelo
\n", 27 | "
\n" 28 | ] 29 | }, 30 | { 31 | "cell_type": "markdown", 32 | "metadata": { 33 | "id": "AqJZuAbB-KeZ" 34 | }, 35 | "source": [ 36 | "# Introducción\n", 37 | "\n", 38 | "Ya que hemos visto algunos métodos interesantes previamente (Monte Carlo), el siguiente paso consiste en convertir la versión secuencial de estos algoritmos a su versión en paralelo.\n", 39 | "\n", 40 | "Para ello vamos a comenzar con el ejemplo básico de la aproximación de $\\pi$ empleando métodos de Monte Carlo, tal como se mostró en la presentación previa, en la cual se describe el desarrollo y marco teórico de dicho método.\n" 41 | ] 42 | }, 43 | { 44 | "cell_type": "markdown", 45 | "metadata": { 46 | "id": "BHFG33_0-Keb" 47 | }, 48 | "source": [ 49 | "# Aproximación de $\\pi$ mediante Monte Carlo\n", 50 | "\n", 51 | "Para la implementación de este algoritmo en paralelo utilizaremos *MPI*, ya que tanto el método como el algoritmo son ideales para tal propósito.\n", 52 | "\n", 53 | "Vale la pena aclarar que la idea de los métodos de Monte Carlo se basan en la generación de números aleatorios y es por esto que *MPI* es muy buena idea para este tipo de algoritmos, ya que *MPI* originalmente se creo para arquitecturas sin memoria compartida (envío de mensajes).\n", 54 | "\n", 55 | "A continuación podemos ver el algoritmo para la aproximación de $\\pi$ haciendo uso de *MPI*." 56 | ] 57 | }, 58 | { 59 | "cell_type": "code", 60 | "execution_count": 34, 61 | "metadata": { 62 | "id": "BoVbQ3wTrpig" 63 | }, 64 | "outputs": [], 65 | "source": [ 66 | "codigo = \"\"\"\n", 67 | "#include \n", 68 | "#include \n", 69 | "#include \n", 70 | "#include \n", 71 | "#include \n", 72 | "void Validar_Entrada(int argc, int id);\n", 73 | "long Lanzamientos(long numLanzamientoProc, int miRango);\n", 74 | " \n", 75 | "int main(int argc, char* argv[]){\n", 76 | " // Bloque de variables\n", 77 | " int lan, id_proceso, num_procesos, total_dardos_dentro, dardo_dentro_proc, lanzamiento_proceso;\n", 78 | " double tiempo_local, tiempo_final, tiempo_inicial, transcurrido, N, pi_aprox;\n", 79 | " MPI_Init(&argc, &argv);\n", 80 | " MPI_Comm_rank(MPI_COMM_WORLD, &id_proceso);\n", 81 | " MPI_Comm_size(MPI_COMM_WORLD, &num_procesos);\n", 82 | " // se valida la entrada del usuario\n", 83 | " Validar_Entrada(argc, id_proceso);\n", 84 | " // Se guarda el numero total de lanzamientos\n", 85 | " sscanf(argv[1], \"%lf\", &N);\n", 86 | " // Bloqueo para esperar que cada proceso realice esta parte\n", 87 | " MPI_Barrier(MPI_COMM_WORLD);\n", 88 | " // tiempo inicial\n", 89 | " tiempo_inicial = MPI_Wtime();\n", 90 | " // lanzamiento por proceso\n", 91 | " lanzamiento_proceso = N/num_procesos;\n", 92 | " // CADA PROCESO SE ENCARGA DE REALIZAR ESTA SECCION EN PARALELO\n", 93 | " dardo_dentro_proc = Lanzamientos(lanzamiento_proceso, id_proceso);\n", 94 | " // tiempo final\n", 95 | " tiempo_final = MPI_Wtime();\n", 96 | " // tiempo que tomo en cada procesador\n", 97 | " tiempo_local = tiempo_final-tiempo_inicial;\n", 98 | " // SUMA de cada dardo dentro de la circunferencia\n", 99 | " MPI_Allreduce(&dardo_dentro_proc, &total_dardos_dentro, 1, MPI_INT, MPI_SUM, \n", 100 | " MPI_COMM_WORLD);\n", 101 | " // NOS QUEDAMOS CON EL MAXIMO DE LOS TIEMPOS, ya que eso fue lo que tomo\n", 102 | " MPI_Allreduce(&tiempo_local, &transcurrido, 1, MPI_DOUBLE, MPI_MAX, \n", 103 | " MPI_COMM_WORLD); \n", 104 | " // el proceso maestro se encarga de imprimir el resultado\n", 105 | " if (id_proceso == 0) { \n", 106 | " pi_aprox = (total_dardos_dentro*4)/((double)N);\n", 107 | " lan = (int)N;\n", 108 | " printf(\"Numero de lanzamientos: \t %d\\\\n\", lan);\n", 109 | " printf(\"Valor aproximado de pi: %24.16f\\\\n\", pi_aprox);\n", 110 | " printf(\"Maximo tiempo transcurrido en el lanzamiento de dardos: %.16f\\\\n\", \n", 111 | " transcurrido*1000000);\n", 112 | " }\n", 113 | " // se liberan los recursos utilizados\n", 114 | " MPI_Finalize();\n", 115 | " return 0;\n", 116 | "}\n", 117 | "\n", 118 | "// Funciona que valida la entrada del usuario\n", 119 | "void Validar_Entrada(int argc, int id){\n", 120 | " // Validacion de la entrada\n", 121 | " if(argc !=2){\n", 122 | " if (id==0){\n", 123 | " fprintf(stderr,\"Numero incorrecto de parmetros\\\\n\");\n", 124 | " fflush(stderr);\n", 125 | " }\n", 126 | " // se termina la ejecucion del programa\n", 127 | " MPI_Abort(MPI_COMM_WORLD,1);\n", 128 | " } \n", 129 | "}\n", 130 | "\n", 131 | "// Funcion que simula los lanzamientos de los dardos\n", 132 | "long Lanzamientos(long numLanzamientoProc, int id_proc){\n", 133 | " // variables para el conteo de lazamientos de dardos\n", 134 | " long lanzamiento, numeroEnCirculo = 0; \n", 135 | " double x,y;\n", 136 | " // semilla para los valores aleatorios\n", 137 | " unsigned int semilla = (unsigned) time(NULL);\n", 138 | " srand(semilla + id_proc);\n", 139 | " // cada proceso lanza genera sus respectivos valores aleatorios\n", 140 | " for (lanzamiento = 0; lanzamiento < numLanzamientoProc; lanzamiento++) {\n", 141 | " x = rand_r(&semilla)/(double)RAND_MAX;\n", 142 | " y = rand_r(&semilla)/(double)RAND_MAX;\n", 143 | " // si el lanzamiento cayo en la circunferencia se incrementa el contador \n", 144 | " if((x*x+y*y) <= 1.0 ) numeroEnCirculo++;\n", 145 | " }\n", 146 | " return numeroEnCirculo; \n", 147 | "}\n", 148 | "\"\"\"\n", 149 | "\n", 150 | "# se crea el archivo con permisos para escribir mediante python\n", 151 | "archivo_texto = open(\"aprox_PI.c\", \"w\")\n", 152 | "# se escribe el programa en el archivo \n", 153 | "archivo_texto.write(codigo)\n", 154 | "# se cierra el buffer de escritura\n", 155 | "archivo_texto.close()" 156 | ] 157 | }, 158 | { 159 | "cell_type": "code", 160 | "execution_count": 35, 161 | "metadata": { 162 | "id": "-9VZmsm3sANU" 163 | }, 164 | "outputs": [], 165 | "source": [ 166 | "!mpicc aprox_PI.c -o aprox_PI" 167 | ] 168 | }, 169 | { 170 | "cell_type": "code", 171 | "execution_count": 37, 172 | "metadata": { 173 | "colab": { 174 | "base_uri": "https://localhost:8080/" 175 | }, 176 | "id": "16RmriMOsSIw", 177 | "outputId": "6677e5d6-f20f-4f5e-b7d8-977172204686" 178 | }, 179 | "outputs": [ 180 | { 181 | "name": "stdout", 182 | "output_type": "stream", 183 | "text": [ 184 | "Numero de lanzamientos: \t 10000\n", 185 | "Valor aproximado de pi: 3.1600000000000001\n", 186 | "Maximo tiempo transcurrido en el lanzamiento de dardos: 11.1829999696055893\n" 187 | ] 188 | } 189 | ], 190 | "source": [ 191 | "!mpirun --allow-run-as-root -np 100 ./aprox_PI 10000" 192 | ] 193 | }, 194 | { 195 | "cell_type": "markdown", 196 | "metadata": { 197 | "id": "AYA0Fal3Z3Jt" 198 | }, 199 | "source": [ 200 | "## Análisis a secciones importantes\n", 201 | "\n", 202 | "*MPI_Abort(MPI_COMM_WORLD,1)*: en caso de que el usuario no introduzca los valores correctos el programa finaliza y todos los procesos asociados al mismo.\n", 203 | "\n", 204 | "*MPI_Barrier(MPI_COMM_WORLD)*: esta directiva obliga a que todos los procesos asignados a este procesador terminen antes de poder avanzar.\n", 205 | "\n", 206 | "
\n", 207 | "\n", 208 | "
\n", 209 | "\n", 210 | "*MPI_Allreduce(&dardo_dentro_proc, &total_dardos_dentro, 1, MPI_INT, MPI_SUM, MPI_COMM_WORLD)*: funciona de manera similar al *reduce* de *OpenMP* en el cual se realiza la reduccion de multiples variables en una sola.\n", 211 | "\n", 212 | "*MPI_Allreduce(&tiempo_local, &transcurrido, 1, MPI_DOUBLE, MPI_MAX, \n", 213 | "MPI_COMM_WORLD)*: a diferencia de la función anterior, en este caso nos quedamos con el máximo de los tiempos que le tomó a cada proceso realizar la tarea." 214 | ] 215 | }, 216 | { 217 | "cell_type": "markdown", 218 | "metadata": { 219 | "id": "w0zl8srO-Kef" 220 | }, 221 | "source": [ 222 | "# Suma de los primeros $n$ números naturales\n", 223 | "\n", 224 | "En esta sección vamos a analizar un algoritmo ampliamente conocido y hasta cierto punto sencillo, sin embargo muy didáctico y adecuado para mostrar las cualidades de la programación en paralelo. La suma de los primeros $n$ números naturales es un ejemplo ideal para mostrar el concepto de **pase de mensajes** entre procesos.\n", 225 | "\n", 226 | "A primera vista esta labor puede parecer algo trivial.\n", 227 | "\n", 228 | "$$\\sum_{i=1}^{n}i=\\frac{n(n+1)}{2}$$\n", 229 | "\n", 230 | "Sin embargo la complejidad de esta sección radica en, ¿cómo dividir esta labor en diferentes secciones en paralelo para poder reducir el tiempo de ejecución. La idea sería difundir entre todos los procesos (*broadcast*) el vector de elementos y realizar la suma parcial en cada proceso respectivo.\n", 231 | "\n", 232 | "
\n", 233 | "\n", 234 | "
\n", 235 | "\n", 236 | "\n" 237 | ] 238 | }, 239 | { 240 | "cell_type": "code", 241 | "execution_count": 38, 242 | "metadata": { 243 | "id": "cJmwGXOEhztj" 244 | }, 245 | "outputs": [], 246 | "source": [ 247 | "codigo = \"\"\"\n", 248 | "#include \n", 249 | "#include \n", 250 | "// cantidad de valore a sumar\n", 251 | "#define tam 10000\n", 252 | "\n", 253 | "int main (int argc, char** argv){\n", 254 | " // bloque de variables globales\n", 255 | " int id_proceso, num_procesos, a[tam], i, primero, ultimo, tam_porcion;\n", 256 | " double suma_total = 0, suma_parcial = 0;\n", 257 | " // funciones para iniciar uso de MPI\n", 258 | " MPI_Status status;\n", 259 | " MPI_Init(&argc, &argv);\n", 260 | " MPI_Comm_rank(MPI_COMM_WORLD, &id_proceso);\n", 261 | " MPI_Comm_size(MPI_COMM_WORLD, &num_procesos);\n", 262 | " // el proceso root (maestro) llena el vector a sumar\n", 263 | " if (id_proceso == 0) \n", 264 | " for (i=0;i\"Open" 11 | ] 12 | }, 13 | { 14 | "cell_type": "markdown", 15 | "metadata": { 16 | "id": "Gde4FA2b-KeX" 17 | }, 18 | "source": [ 19 | "\n", 20 | "

Algoritmos MPI

\n", 21 | "
\n", 22 | " \n", 23 | "
Profesor: M. en C. Miguel Angel Pérez León
\n", 24 | "
Ayudante: Lucía Martínez Rivas
\n", 25 | "
Ayudante: Erick Jesús Rios Gonzalez
\n", 26 | "
Materia: Seminario de programación en paralelo
\n", 27 | "
\n" 28 | ] 29 | }, 30 | { 31 | "cell_type": "markdown", 32 | "metadata": { 33 | "id": "AqJZuAbB-KeZ" 34 | }, 35 | "source": [ 36 | "# Introducción\n", 37 | "\n", 38 | "Ya que hemos visto algunos métodos interesantes previamente (Monte Carlo), el siguiente paso consiste en convertir la versión secuencial de estos algoritmos a su versión en paralelo.\n", 39 | "\n", 40 | "Para ello vamos a comenzar con el ejemplo básico de la aproximación de $\\pi$ empleando métodos de Monte Carlo, tal como se mostró en la presentación previa, en la cual se describe el desarrollo y marco teórico de dicho método.\n" 41 | ] 42 | }, 43 | { 44 | "cell_type": "markdown", 45 | "metadata": { 46 | "id": "BHFG33_0-Keb" 47 | }, 48 | "source": [ 49 | "# Aproximación de $\\pi$ mediante Monte Carlo\n", 50 | "\n", 51 | "Para la implementación de este algoritmo en paralelo utilizaremos *MPI*, ya que tanto el método como el algoritmo son ideales para tal propósito.\n", 52 | "\n", 53 | "Vale la pena aclarar que la idea de los métodos de Monte Carlo se basan en la generación de números aleatorios y es por esto que *MPI* es muy buena idea para este tipo de algoritmos, ya que *MPI* originalmente se creo para arquitecturas sin memoria compartida (envío de mensajes).\n", 54 | "\n", 55 | "A continuación podemos ver el algoritmo para la aproximación de $\\pi$ haciendo uso de *MPI*." 56 | ] 57 | }, 58 | { 59 | "cell_type": "code", 60 | "execution_count": 34, 61 | "metadata": { 62 | "id": "BoVbQ3wTrpig" 63 | }, 64 | "outputs": [], 65 | "source": [ 66 | "codigo = \"\"\"\n", 67 | "#include \n", 68 | "#include \n", 69 | "#include \n", 70 | "#include \n", 71 | "#include \n", 72 | "void Validar_Entrada(int argc, int id);\n", 73 | "long Lanzamientos(long numLanzamientoProc, int miRango);\n", 74 | " \n", 75 | "int main(int argc, char* argv[]){\n", 76 | " // Bloque de variables\n", 77 | " int lan, id_proceso, num_procesos, total_dardos_dentro, dardo_dentro_proc, lanzamiento_proceso;\n", 78 | " double tiempo_local, tiempo_final, tiempo_inicial, transcurrido, N, pi_aprox;\n", 79 | " MPI_Init(&argc, &argv);\n", 80 | " MPI_Comm_rank(MPI_COMM_WORLD, &id_proceso);\n", 81 | " MPI_Comm_size(MPI_COMM_WORLD, &num_procesos);\n", 82 | " // se valida la entrada del usuario\n", 83 | " Validar_Entrada(argc, id_proceso);\n", 84 | " // Se guarda el numero total de lanzamientos\n", 85 | " sscanf(argv[1], \"%lf\", &N);\n", 86 | " // Bloqueo para esperar que cada proceso realice esta parte\n", 87 | " MPI_Barrier(MPI_COMM_WORLD);\n", 88 | " // tiempo inicial\n", 89 | " tiempo_inicial = MPI_Wtime();\n", 90 | " // lanzamiento por proceso\n", 91 | " lanzamiento_proceso = N/num_procesos;\n", 92 | " // CADA PROCESO SE ENCARGA DE REALIZAR ESTA SECCION EN PARALELO\n", 93 | " dardo_dentro_proc = Lanzamientos(lanzamiento_proceso, id_proceso);\n", 94 | " // tiempo final\n", 95 | " tiempo_final = MPI_Wtime();\n", 96 | " // tiempo que tomo en cada procesador\n", 97 | " tiempo_local = tiempo_final-tiempo_inicial;\n", 98 | " // SUMA de cada dardo dentro de la circunferencia\n", 99 | " MPI_Allreduce(&dardo_dentro_proc, &total_dardos_dentro, 1, MPI_INT, MPI_SUM, \n", 100 | " MPI_COMM_WORLD);\n", 101 | " // NOS QUEDAMOS CON EL MAXIMO DE LOS TIEMPOS, ya que eso fue lo que tomo\n", 102 | " MPI_Allreduce(&tiempo_local, &transcurrido, 1, MPI_DOUBLE, MPI_MAX, \n", 103 | " MPI_COMM_WORLD); \n", 104 | " // el proceso maestro se encarga de imprimir el resultado\n", 105 | " if (id_proceso == 0) { \n", 106 | " pi_aprox = (total_dardos_dentro*4)/((double)N);\n", 107 | " lan = (int)N;\n", 108 | " printf(\"Numero de lanzamientos: \t %d\\\\n\", lan);\n", 109 | " printf(\"Valor aproximado de pi: %24.16f\\\\n\", pi_aprox);\n", 110 | " printf(\"Maximo tiempo transcurrido en el lanzamiento de dardos: %.16f\\\\n\", \n", 111 | " transcurrido*1000000);\n", 112 | " }\n", 113 | " // se liberan los recursos utilizados\n", 114 | " MPI_Finalize();\n", 115 | " return 0;\n", 116 | "}\n", 117 | "\n", 118 | "// Funciona que valida la entrada del usuario\n", 119 | "void Validar_Entrada(int argc, int id){\n", 120 | " // Validacion de la entrada\n", 121 | " if(argc !=2){\n", 122 | " if (id==0){\n", 123 | " fprintf(stderr,\"Numero incorrecto de parmetros\\\\n\");\n", 124 | " fflush(stderr);\n", 125 | " }\n", 126 | " // se termina la ejecucion del programa\n", 127 | " MPI_Abort(MPI_COMM_WORLD,1);\n", 128 | " } \n", 129 | "}\n", 130 | "\n", 131 | "// Funcion que simula los lanzamientos de los dardos\n", 132 | "long Lanzamientos(long numLanzamientoProc, int id_proc){\n", 133 | " // variables para el conteo de lazamientos de dardos\n", 134 | " long lanzamiento, numeroEnCirculo = 0; \n", 135 | " double x,y;\n", 136 | " // semilla para los valores aleatorios\n", 137 | " unsigned int semilla = (unsigned) time(NULL);\n", 138 | " srand(semilla + id_proc);\n", 139 | " // cada proceso lanza genera sus respectivos valores aleatorios\n", 140 | " for (lanzamiento = 0; lanzamiento < numLanzamientoProc; lanzamiento++) {\n", 141 | " x = rand_r(&semilla)/(double)RAND_MAX;\n", 142 | " y = rand_r(&semilla)/(double)RAND_MAX;\n", 143 | " // si el lanzamiento cayo en la circunferencia se incrementa el contador \n", 144 | " if((x*x+y*y) <= 1.0 ) numeroEnCirculo++;\n", 145 | " }\n", 146 | " return numeroEnCirculo; \n", 147 | "}\n", 148 | "\"\"\"\n", 149 | "\n", 150 | "# se crea el archivo con permisos para escribir mediante python\n", 151 | "archivo_texto = open(\"aprox_PI.c\", \"w\")\n", 152 | "# se escribe el programa en el archivo \n", 153 | "archivo_texto.write(codigo)\n", 154 | "# se cierra el buffer de escritura\n", 155 | "archivo_texto.close()" 156 | ] 157 | }, 158 | { 159 | "cell_type": "code", 160 | "execution_count": 35, 161 | "metadata": { 162 | "id": "-9VZmsm3sANU" 163 | }, 164 | "outputs": [], 165 | "source": [ 166 | "!mpicc aprox_PI.c -o aprox_PI" 167 | ] 168 | }, 169 | { 170 | "cell_type": "code", 171 | "execution_count": 37, 172 | "metadata": { 173 | "colab": { 174 | "base_uri": "https://localhost:8080/" 175 | }, 176 | "id": "16RmriMOsSIw", 177 | "outputId": "6677e5d6-f20f-4f5e-b7d8-977172204686" 178 | }, 179 | "outputs": [ 180 | { 181 | "name": "stdout", 182 | "output_type": "stream", 183 | "text": [ 184 | "Numero de lanzamientos: \t 10000\n", 185 | "Valor aproximado de pi: 3.1600000000000001\n", 186 | "Maximo tiempo transcurrido en el lanzamiento de dardos: 11.1829999696055893\n" 187 | ] 188 | } 189 | ], 190 | "source": [ 191 | "!mpirun --allow-run-as-root -np 100 ./aprox_PI 10000" 192 | ] 193 | }, 194 | { 195 | "cell_type": "markdown", 196 | "metadata": { 197 | "id": "AYA0Fal3Z3Jt" 198 | }, 199 | "source": [ 200 | "## Análisis a secciones importantes\n", 201 | "\n", 202 | "*MPI_Abort(MPI_COMM_WORLD,1)*: en caso de que el usuario no introduzca los valores correctos el programa finaliza y todos los procesos asociados al mismo.\n", 203 | "\n", 204 | "*MPI_Barrier(MPI_COMM_WORLD)*: esta directiva obliga a que todos los procesos asignados a este procesador terminen antes de poder avanzar.\n", 205 | "\n", 206 | "
\n", 207 | "\n", 208 | "
\n", 209 | "\n", 210 | "*MPI_Allreduce(&dardo_dentro_proc, &total_dardos_dentro, 1, MPI_INT, MPI_SUM, MPI_COMM_WORLD)*: funciona de manera similar al *reduce* de *OpenMP* en el cual se realiza la reduccion de multiples variables en una sola.\n", 211 | "\n", 212 | "*MPI_Allreduce(&tiempo_local, &transcurrido, 1, MPI_DOUBLE, MPI_MAX, \n", 213 | "MPI_COMM_WORLD)*: a diferencia de la función anterior, en este caso nos quedamos con el máximo de los tiempos que le tomó a cada proceso realizar la tarea." 214 | ] 215 | }, 216 | { 217 | "cell_type": "markdown", 218 | "metadata": { 219 | "id": "w0zl8srO-Kef" 220 | }, 221 | "source": [ 222 | "# Suma de los primeros $n$ números naturales\n", 223 | "\n", 224 | "En esta sección vamos a analizar un algoritmo ampliamente conocido y hasta cierto punto sencillo, sin embargo muy didáctico y adecuado para mostrar las cualidades de la programación en paralelo. La suma de los primeros $n$ números naturales es un ejemplo ideal para mostrar el concepto de **pase de mensajes** entre procesos.\n", 225 | "\n", 226 | "A primera vista esta labor puede parecer algo trivial.\n", 227 | "\n", 228 | "$$\\sum_{i=1}^{n}i=\\frac{n(n+1)}{2}$$\n", 229 | "\n", 230 | "Sin embargo la complejidad de esta sección radica en, ¿cómo dividir esta labor en diferentes secciones en paralelo para poder reducir el tiempo de ejecución. La idea sería difundir entre todos los procesos (*broadcast*) el vector de elementos y realizar la suma parcial en cada proceso respectivo.\n", 231 | "\n", 232 | "
\n", 233 | "\n", 234 | "
\n", 235 | "\n", 236 | "\n" 237 | ] 238 | }, 239 | { 240 | "cell_type": "code", 241 | "execution_count": 38, 242 | "metadata": { 243 | "id": "cJmwGXOEhztj" 244 | }, 245 | "outputs": [], 246 | "source": [ 247 | "codigo = \"\"\"\n", 248 | "#include \n", 249 | "#include \n", 250 | "// cantidad de valore a sumar\n", 251 | "#define tam 10000\n", 252 | "\n", 253 | "int main (int argc, char** argv){\n", 254 | " // bloque de variables globales\n", 255 | " int id_proceso, num_procesos, a[tam], i, primero, ultimo, tam_porcion;\n", 256 | " double suma_total = 0, suma_parcial = 0;\n", 257 | " // funciones para iniciar uso de MPI\n", 258 | " MPI_Status status;\n", 259 | " MPI_Init(&argc, &argv);\n", 260 | " MPI_Comm_rank(MPI_COMM_WORLD, &id_proceso);\n", 261 | " MPI_Comm_size(MPI_COMM_WORLD, &num_procesos);\n", 262 | " // el proceso root (maestro) llena el vector a sumar\n", 263 | " if (id_proceso == 0) \n", 264 | " for (i=0;i\"Open" 11 | ] 12 | }, 13 | { 14 | "cell_type": "markdown", 15 | "metadata": { 16 | "id": "NvSWwiigwBJd" 17 | }, 18 | "source": [ 19 | "\n", 20 | "

Ley de Amdahl

\n", 21 | "
\n", 22 | " \n", 23 | "
Profesor: M. en C. Miguel Angel Pérez León
\n", 24 | "
Ayudante: Lucía Martínez Rivas
\n", 25 | "
Ayudante: Erick Jesús Rios Gonzalez
\n", 26 | "
Materia: Seminario de programación en paralelo
\n", 27 | "
" 28 | ] 29 | }, 30 | { 31 | "cell_type": "markdown", 32 | "metadata": { 33 | "id": "3tU5QG_gsQrc" 34 | }, 35 | "source": [ 36 | "## Sobre manejo de memoria\n", 37 | "\n", 38 | "\n" 39 | ] 40 | }, 41 | { 42 | "cell_type": "markdown", 43 | "metadata": { 44 | "id": "5i4rV9iNsQOT" 45 | }, 46 | "source": [ 47 | "Recordemos que trabajar con *OpenMP* es trabajar bajo el modelo *PRAM* (Parallel Random Access Machine), es decir, que tenemos varios procesadores con acceso a un segmento de memoria en común, sin embargo, al trabajar varios datos a la vez hay que cuidar el manejo y acceso a la memoria. Una ventaja es que no hay límite en los números de procesadores para nuestro modelo, más que el costo económico que esto pudiera ocasionar. \n", 48 | "\n", 49 | "
\n", 50 | " \n", 51 | "
\n", 52 | "\n", 53 | "Existen varias formas de manipular la memoria compartida, son los siguientes: \n", 54 | "\n", 55 | "* EREW (**E**xclusive **R**ead **E**xclusive **W**rite)\n", 56 | "* CREW (**C**oncurrent **R**ead **E**xclusive **W**rite)\n", 57 | "* CRCW (**C**oncurrent **R**ead **C**oncurrent **W**rite)\n", 58 | "\n", 59 | "Queda como ejercicio al lector, pensar en que problemas se deben o pueden utilizar las diferentes formas de acceder a la información.\n", 60 | "\n", 61 | "\n", 62 | "\n" 63 | ] 64 | }, 65 | { 66 | "cell_type": "markdown", 67 | "metadata": { 68 | "id": "OupnFho40IUM" 69 | }, 70 | "source": [ 71 | "## Taxonomía de Flynn" 72 | ] 73 | }, 74 | { 75 | "cell_type": "markdown", 76 | "metadata": { 77 | "id": "2HDxXraE50jY" 78 | }, 79 | "source": [ 80 | "La taxonomía de Flynn es una clasificación para arquitecturas paralelas, la clasificación fue creada por Michael J. Flynn, la cual clasifica por la cantidad de intrucciones y flujo de datos. \n", 81 | "\n", 82 | "
\n", 83 | " \n", 84 | "
\n", 85 | "\n", 86 | "* SISD *(Single Instruction Single Data)*\n", 87 | "* MISD *(Multiple Instruction Single Data)*\n", 88 | "* SIMD *(Single Instruction Multiple Data)* \n", 89 | "* MIMD *(Multiple Instruction Multiple Data)* \n", 90 | "\n", 91 | "Esta última es muy usada para explotar el paralelismo, ya sea con memoria distribuida y memoria compartida o un hibrido como son los clúsers. \n", 92 | "\n" 93 | ] 94 | }, 95 | { 96 | "cell_type": "markdown", 97 | "metadata": { 98 | "id": "xic0uJvY89DI" 99 | }, 100 | "source": [ 101 | "## Aceleración, eficiencia y fracción serial " 102 | ] 103 | }, 104 | { 105 | "cell_type": "markdown", 106 | "metadata": { 107 | "id": "iAWYJUUcvl7-" 108 | }, 109 | "source": [ 110 | "$T(n,1)$ es la complejidad en tiempo del mejor algoritmo secuencial, el número uno indica que solo se esta usando un hilo. \n", 111 | "\n", 112 | "$T(n,p)$ es la complejidad en tiempo del algoritmo paralelo usando $p$ procesadores. \n", 113 | "\n", 114 | "Existen tres métricas que nos interesan y son: la ***aceleración (Speedup)***, la ***eficiencia*** y la ***fracción serial***\n", 115 | "\n", 116 | "Em motivo principal para usar un algoritmo paralelo es *acelerar* los cálculos secuenciales. Es por ello que nos interesa conocer la aceleración: \n", 117 | "\n", 118 | "$$S(p) = \\frac{T(n,1)}{T(n,p)} $$\n", 119 | "\n", 120 | "Entonces, la ***aceleración*** mide cuántas veces más rápido es el algoritmo paralelo, el valor ideal es $p$.\n", 121 | "\n", 122 | "La ***eficiencia*** mide que tan eficientemente se están utilizanda los procesadores y el valor ideal es $1$, se calcula de la siguiente forma: \n", 123 | "\n", 124 | "$$E(p) = \\frac{S(p)}{p} $$\n", 125 | "\n", 126 | "Es decir, la aceleración entre el número de procesadores.\n", 127 | "\n", 128 | "La ***fracción serial*** mide la parte del código que es inherentemente secuencial y el valor ideal es $0$.\n", 129 | "\n", 130 | "$$ F(p) = \\frac{\\frac{1}{S(p)} -\\frac{1}{p}}{1 - \\frac{1}{p}} $$\n", 131 | "\n", 132 | "\n", 133 | "\n", 134 | "\n", 135 | "\n", 136 | "\n" 137 | ] 138 | }, 139 | { 140 | "cell_type": "code", 141 | "execution_count": null, 142 | "metadata": { 143 | "id": "XsGZA4xg6sPx" 144 | }, 145 | "outputs": [], 146 | "source": [ 147 | "codigo = \"\"\"\n", 148 | "#include \n", 149 | "#include \n", 150 | "#include \n", 151 | "#include \n", 152 | "\n", 153 | "\n", 154 | "int main(int argc, char** argv){\n", 155 | "\n", 156 | " // Se valida que se haya pasado el parámetro \n", 157 | "\n", 158 | "\tlong int suma = 0;\n", 159 | " long int suma_p = 0; \n", 160 | " long int sumaHilo = 0; \n", 161 | " double inicio_s, fin_s, inicio_p, fin_p; // Para los tiempos de ejecución\n", 162 | "\n", 163 | " inicio_s = omp_get_wtime();\n", 164 | "\tfor(int i =0; i <= 1000000000; i++){\n", 165 | "\t\tsuma = suma +i;\n", 166 | "\t}\n", 167 | " fin_s = omp_get_wtime();\n", 168 | " double tiempo_s = fin_s - inicio_s;\n", 169 | "\tprintf(\"suma: %li \\\\n tiempo de ejecucion: %f \\\\n\",suma, fin_s - inicio_s); //imprime resultados\n", 170 | "\n", 171 | " inicio_p = omp_get_wtime();\n", 172 | "\n", 173 | " int numHilos;\n", 174 | " sscanf(argv[1], \"%i\", &numHilos);\n", 175 | "\n", 176 | " \tomp_set_num_threads(numHilos);\n", 177 | "\tint idHilo; \n", 178 | "\t//inicia seccion paralela\n", 179 | "\t#pragma omp parallel private(idHilo, sumaHilo)\n", 180 | " {\n", 181 | "\t\tidHilo = omp_get_thread_num();\n", 182 | "\t\tif (idHilo==0){\n", 183 | "\t\t\tprintf (\"iniciando calculo con %i hilos\\\\n\", omp_get_num_threads());\n", 184 | "\t\t}\n", 185 | "\t\t\n", 186 | "\t\t//cada hilo realiza una suma parcial\n", 187 | "\t\tsumaHilo=0;\n", 188 | "\t\tint i;\n", 189 | "\t\tfor (i=idHilo;i<=1000000000;i+=numHilos){\n", 190 | "\t\t\tsumaHilo+=i;\n", 191 | "\t\t}\n", 192 | "\t\t\n", 193 | "\t\t//cada hilo actualiza la suma total con su resultado parcial\n", 194 | "\t\tsuma_p+=sumaHilo;\n", 195 | "\t}//fin de seccion paralela\n", 196 | "\n", 197 | "\n", 198 | " fin_p = omp_get_wtime();\n", 199 | " double tiempo_p= fin_p - inicio_p;\n", 200 | "\tprintf(\"suma paralela: %li \\\\n Tiempo de ejecucion algoritmo paralelo: %f \\\\n\",suma,tiempo_p);\n", 201 | " double aceleracion = tiempo_s/tiempo_p;\n", 202 | " printf(\"La aceleración de paralelizar la suma se los primeros 1 000 000 000 número naturales es: %f \\\\n\", aceleracion);\n", 203 | " double eficiencia = aceleracion/2;\n", 204 | " printf(\"La eficiencia es: %f tomando que la prueba en colab se hace en dos procesadores \\\\n\", eficiencia);\n", 205 | "\n", 206 | "}\n", 207 | "\"\"\" " 208 | ] 209 | }, 210 | { 211 | "cell_type": "code", 212 | "execution_count": null, 213 | "metadata": { 214 | "id": "ZvWAs7OyhW0P" 215 | }, 216 | "outputs": [], 217 | "source": [ 218 | "# se crea el archivo con permisos para escribir mediante python\n", 219 | "archivo_texto = open(\"sumaIntervalo.c\", \"w\")\n", 220 | "# se escribe el programa en el archivo \n", 221 | "archivo_texto.write(codigo)\n", 222 | "# se cierra el buffer de escritura\n", 223 | "archivo_texto.close()" 224 | ] 225 | }, 226 | { 227 | "cell_type": "code", 228 | "execution_count": null, 229 | "metadata": { 230 | "id": "mWRdPiH5hefY" 231 | }, 232 | "outputs": [], 233 | "source": [ 234 | "!gcc -o suma -fopenmp sumaIntervalo.c" 235 | ] 236 | }, 237 | { 238 | "cell_type": "code", 239 | "execution_count": null, 240 | "metadata": { 241 | "colab": { 242 | "base_uri": "https://localhost:8080/" 243 | }, 244 | "id": "oH-OhfgfhfC_", 245 | "outputId": "917029a7-9cde-41ff-f9f5-ad4eab027ae4" 246 | }, 247 | "outputs": [ 248 | { 249 | "name": "stdout", 250 | "output_type": "stream", 251 | "text": [ 252 | "suma: 500000000500000000 \n", 253 | " tiempo de ejecucion: 3.297801 \n", 254 | "iniciando calculo con 2 hilos\n", 255 | "suma paralela: 500000000500000000 \n", 256 | " Tiempo de ejecucion algoritmo paralelo: 2.163480 \n", 257 | "La aceleración de paralelizar la suma se los primeros 1 000 000 000 número naturales es: 1.524304 \n", 258 | "La eficiencia es: 0.762152 tomando que la prueba en colab se hace en dos procesadores \n" 259 | ] 260 | } 261 | ], 262 | "source": [ 263 | "!./suma 2" 264 | ] 265 | }, 266 | { 267 | "cell_type": "markdown", 268 | "metadata": { 269 | "id": "huf_osurzibX" 270 | }, 271 | "source": [ 272 | "> Queda como ejercicio al lector calcular la fracción serial e interpretar el resultado. ⚡\n", 273 | "\n", 274 | "\n" 275 | ] 276 | }, 277 | { 278 | "cell_type": "code", 279 | "execution_count": null, 280 | "metadata": { 281 | "colab": { 282 | "base_uri": "https://localhost:8080/" 283 | }, 284 | "id": "hXKB7jMp9q_I", 285 | "outputId": "174e9183-9540-4d52-b227-26c0306f8770" 286 | }, 287 | "outputs": [ 288 | { 289 | "name": "stdout", 290 | "output_type": "stream", 291 | "text": [ 292 | "Architecture: x86_64\n", 293 | "CPU op-mode(s): 32-bit, 64-bit\n", 294 | "Byte Order: Little Endian\n", 295 | "CPU(s): 2\n", 296 | "On-line CPU(s) list: 0,1\n", 297 | "Thread(s) per core: 2\n", 298 | "Core(s) per socket: 1\n", 299 | "Socket(s): 1\n", 300 | "NUMA node(s): 1\n", 301 | "Vendor ID: GenuineIntel\n", 302 | "CPU family: 6\n", 303 | "Model: 79\n", 304 | "Model name: Intel(R) Xeon(R) CPU @ 2.20GHz\n", 305 | "Stepping: 0\n", 306 | "CPU MHz: 2199.998\n", 307 | "BogoMIPS: 4399.99\n", 308 | "Hypervisor vendor: KVM\n", 309 | "Virtualization type: full\n", 310 | "L1d cache: 32K\n", 311 | "L1i cache: 32K\n", 312 | "L2 cache: 256K\n", 313 | "L3 cache: 56320K\n", 314 | "NUMA node0 CPU(s): 0,1\n", 315 | "Flags: fpu vme de pse tsc msr pae mce cx8 apic sep mtrr pge mca cmov pat pse36 clflush mmx fxsr sse sse2 ss ht syscall nx pdpe1gb rdtscp lm constant_tsc rep_good nopl xtopology nonstop_tsc cpuid tsc_known_freq pni pclmulqdq ssse3 fma cx16 pcid sse4_1 sse4_2 x2apic movbe popcnt aes xsave avx f16c rdrand hypervisor lahf_lm abm 3dnowprefetch invpcid_single ssbd ibrs ibpb stibp fsgsbase tsc_adjust bmi1 hle avx2 smep bmi2 erms invpcid rtm rdseed adx smap xsaveopt arat md_clear arch_capabilities\n" 316 | ] 317 | } 318 | ], 319 | "source": [ 320 | "!lscpu" 321 | ] 322 | }, 323 | { 324 | "cell_type": "markdown", 325 | "metadata": { 326 | "id": "7NXG66CK-M_O" 327 | }, 328 | "source": [ 329 | "\n", 330 | "\n", 331 | "¿Qué es lo que debe tomarse en cuenta cuando se hacen este tipo de pruebas? \n", 332 | "\n", 333 | "* Procesos en segundo plano ejecutando\n", 334 | "* Las condiciones en las que se encuentra el equipo\n", 335 | "* Recursos compartidos on otras aplicaciones, por ejemplo, *Mozilla*, *Spotify* entre otras..." 336 | ] 337 | }, 338 | { 339 | "cell_type": "markdown", 340 | "metadata": { 341 | "id": "JsEyeevk6kLU" 342 | }, 343 | "source": [ 344 | "## Ley de Amdahl \n", 345 | "\n", 346 | "El objetivo principal de usar un algoritmo paralelo es obtener los resultados lo más pronto posible, es decir, disminuir la complejidad en tiempo. Al aumentar el número de procesadores en el sistema paralelo se distribuyen las sub-tares entre los procesadores. Sin embargo, surge la pregunta ¿Siempre que aumente el número de procesadores disminuirá el tiempo de ejecución? \n", 347 | "\n", 348 | "Resulta que la ley de Amdahl dice que llega un punto en el cual sin importar que el numero de procesadores sea muy alto , el speedup se va a comportar de manera lineal. Dicho de otra forma cada sección paralelizable de un algoritmo tendrá un número $n$ de procesadores optimos, si ejecutamos el algoritmo con más de $n$ procesadores no mejorará el tiempo de ejecución.\n", 349 | "\n" 350 | ] 351 | }, 352 | { 353 | "cell_type": "markdown", 354 | "metadata": { 355 | "id": "uGvii3oH-o8k" 356 | }, 357 | "source": [ 358 | "
\n", 359 | " \n", 360 | "
" 361 | ] 362 | }, 363 | { 364 | "cell_type": "markdown", 365 | "metadata": { 366 | "id": "EbcAEt45_cku" 367 | }, 368 | "source": [ 369 | "La gráfica anterior nos muestra que dependiendo del porcentaje de código ejecutado de manera paralela será la cota de número de procesadores para alcanzar la máximo eficiencia. " 370 | ] 371 | }, 372 | { 373 | "cell_type": "markdown", 374 | "metadata": { 375 | "id": "-cyXdBLLWV-I" 376 | }, 377 | "source": [ 378 | "
\n", 379 | " \n", 380 | "
" 381 | ] 382 | }, 383 | { 384 | "cell_type": "markdown", 385 | "metadata": { 386 | "id": "F2UfClz4ZrID" 387 | }, 388 | "source": [ 389 | "### La ley de Amdahl en suma paralela\n", 390 | "\n", 391 | "En el siguiente cuadro de datos tenemos algunas ejecuciones de pruebas realizadas en una computadora con las siguientes carácteristicas, se obtuvo un tiempo de ejecución de: 3 255 980 microsegundos\n", 392 | "\n", 393 | "* Marca *Dell*\n", 394 | "* Intel(R) Core(TM) i5-6300U CPU 2.40 GHz \n", 395 | "* 4 CPU's \n", 396 | "* 8 Gb de RAM\n", 397 | "\n", 398 | "
\n", 399 | " \n", 400 | "
\n", 401 | "\n", 402 | "Observemos que en el Cuadro el mejor tiempo ($1107980{.}8 \\mu s$) que se presenta es cuando el programa usa únicamente 4 hilos, la computadora donde se ejecutaron las pruebas es una Dell con 4 CPU(s). En el cuadro tenemos que los mejores tiempos obtenidos corresponden al renglón de las pruebas realizadas con 50 hilos. Incluso podemos observar que los mejores tiempos corresponden a las pruebas realizadas con 50 hilos. Recordemos que cualquier problema tiene una cota en tiempo óptimo, además también hay una cota para el número de procesadores que pueden optimizar un proceso. Cada problema tendrá un número de hilos óptimo, para este caso tenemos que 50 hilos nos proporciona el tiempo óptimo, al usar 100 aumentamos el tiempo en vez de disminuirlo, se tendría que buscar el número $n$ donde se pierde la optimización del problema. " 403 | ] 404 | } 405 | ], 406 | "metadata": { 407 | "colab": { 408 | "include_colab_link": true, 409 | "name": "Ley Amdahl.ipynb", 410 | "provenance": [], 411 | "toc_visible": true 412 | }, 413 | "kernelspec": { 414 | "display_name": "Python 3 (ipykernel)", 415 | "language": "python", 416 | "name": "python3" 417 | }, 418 | "language_info": { 419 | "codemirror_mode": { 420 | "name": "ipython", 421 | "version": 3 422 | }, 423 | "file_extension": ".py", 424 | "mimetype": "text/x-python", 425 | "name": "python", 426 | "nbconvert_exporter": "python", 427 | "pygments_lexer": "ipython3", 428 | "version": "3.11.6" 429 | } 430 | }, 431 | "nbformat": 4, 432 | "nbformat_minor": 4 433 | } 434 | -------------------------------------------------------------------------------- /00_Introduccion/.ipynb_checkpoints/12_Ley_Amdahl-checkpoint.ipynb: -------------------------------------------------------------------------------- 1 | { 2 | "cells": [ 3 | { 4 | "cell_type": "markdown", 5 | "metadata": { 6 | "colab_type": "text", 7 | "id": "view-in-github" 8 | }, 9 | "source": [ 10 | "\"Open" 11 | ] 12 | }, 13 | { 14 | "cell_type": "markdown", 15 | "metadata": { 16 | "id": "NvSWwiigwBJd" 17 | }, 18 | "source": [ 19 | "\n", 20 | "

Ley de Amdahl

\n", 21 | "
\n", 22 | " \n", 23 | "
Profesor: M. en C. Miguel Angel Pérez León
\n", 24 | "
Ayudante: Lucía Martínez Rivas
\n", 25 | "
Ayudante: Erick Jesús Rios Gonzalez
\n", 26 | "
Materia: Seminario de programación en paralelo
\n", 27 | "
" 28 | ] 29 | }, 30 | { 31 | "cell_type": "markdown", 32 | "metadata": { 33 | "id": "3tU5QG_gsQrc" 34 | }, 35 | "source": [ 36 | "## Sobre manejo de memoria\n", 37 | "\n", 38 | "\n" 39 | ] 40 | }, 41 | { 42 | "cell_type": "markdown", 43 | "metadata": { 44 | "id": "5i4rV9iNsQOT" 45 | }, 46 | "source": [ 47 | "Recordemos que trabajar con *OpenMP* es trabajar bajo el modelo *PRAM* (Parallel Random Access Machine), es decir, que tenemos varios procesadores con acceso a un segmento de memoria en común, sin embargo, al trabajar varios datos a la vez hay que cuidar el manejo y acceso a la memoria. Una ventaja es que no hay límite en los números de procesadores para nuestro modelo, más que el costo económico que esto pudiera ocasionar. \n", 48 | "\n", 49 | "
\n", 50 | " \n", 51 | "
\n", 52 | "\n", 53 | "Existen varias formas de manipular la memoria compartida, son los siguientes: \n", 54 | "\n", 55 | "* EREW (**E**xclusive **R**ead **E**xclusive **W**rite)\n", 56 | "* CREW (**C**oncurrent **R**ead **E**xclusive **W**rite)\n", 57 | "* CRCW (**C**oncurrent **R**ead **C**oncurrent **W**rite)\n", 58 | "\n", 59 | "Queda como ejercicio al lector, pensar en que problemas se deben o pueden utilizar las diferentes formas de acceder a la información.\n", 60 | "\n", 61 | "\n", 62 | "\n" 63 | ] 64 | }, 65 | { 66 | "cell_type": "markdown", 67 | "metadata": { 68 | "id": "OupnFho40IUM" 69 | }, 70 | "source": [ 71 | "## Taxonomía de Flynn" 72 | ] 73 | }, 74 | { 75 | "cell_type": "markdown", 76 | "metadata": { 77 | "id": "2HDxXraE50jY" 78 | }, 79 | "source": [ 80 | "La taxonomía de Flynn es una clasificación para arquitecturas paralelas, la clasificación fue creada por Michael J. Flynn, la cual clasifica por la cantidad de intrucciones y flujo de datos. \n", 81 | "\n", 82 | "
\n", 83 | " \n", 84 | "
\n", 85 | "\n", 86 | "* SISD *(Single Instruction Single Data)*\n", 87 | "* MISD *(Multiple Instruction Single Data)*\n", 88 | "* SIMD *(Single Instruction Multiple Data)* \n", 89 | "* MIMD *(Multiple Instruction Multiple Data)* \n", 90 | "\n", 91 | "Esta última es muy usada para explotar el paralelismo, ya sea con memoria distribuida y memoria compartida o un hibrido como son los clúsers. \n", 92 | "\n" 93 | ] 94 | }, 95 | { 96 | "cell_type": "markdown", 97 | "metadata": { 98 | "id": "xic0uJvY89DI" 99 | }, 100 | "source": [ 101 | "## Aceleración, eficiencia y fracción serial " 102 | ] 103 | }, 104 | { 105 | "cell_type": "markdown", 106 | "metadata": { 107 | "id": "iAWYJUUcvl7-" 108 | }, 109 | "source": [ 110 | "$T(n,1)$ es la complejidad en tiempo del mejor algoritmo secuencial, el número uno indica que solo se esta usando un hilo. \n", 111 | "\n", 112 | "$T(n,p)$ es la complejidad en tiempo del algoritmo paralelo usando $p$ procesadores. \n", 113 | "\n", 114 | "Existen tres métricas que nos interesan y son: la ***aceleración (Speedup)***, la ***eficiencia*** y la ***fracción serial***\n", 115 | "\n", 116 | "Em motivo principal para usar un algoritmo paralelo es *acelerar* los cálculos secuenciales. Es por ello que nos interesa conocer la aceleración: \n", 117 | "\n", 118 | "$$S(p) = \\frac{T(n,1)}{T(n,p)} $$\n", 119 | "\n", 120 | "Entonces, la ***aceleración*** mide cuántas veces más rápido es el algoritmo paralelo, el valor ideal es $p$.\n", 121 | "\n", 122 | "La ***eficiencia*** mide que tan eficientemente se están utilizanda los procesadores y el valor ideal es $1$, se calcula de la siguiente forma: \n", 123 | "\n", 124 | "$$E(p) = \\frac{S(p)}{p} $$\n", 125 | "\n", 126 | "Es decir, la aceleración entre el número de procesadores.\n", 127 | "\n", 128 | "La ***fracción serial*** mide la parte del código que es inherentemente secuencial y el valor ideal es $0$.\n", 129 | "\n", 130 | "$$ F(p) = \\frac{\\frac{1}{S(p)} -\\frac{1}{p}}{1 - \\frac{1}{p}} $$\n", 131 | "\n", 132 | "\n", 133 | "\n", 134 | "\n", 135 | "\n", 136 | "\n" 137 | ] 138 | }, 139 | { 140 | "cell_type": "code", 141 | "execution_count": null, 142 | "metadata": { 143 | "id": "XsGZA4xg6sPx" 144 | }, 145 | "outputs": [], 146 | "source": [ 147 | "codigo = \"\"\"\n", 148 | "#include \n", 149 | "#include \n", 150 | "#include \n", 151 | "#include \n", 152 | "\n", 153 | "\n", 154 | "int main(int argc, char** argv){\n", 155 | "\n", 156 | " // Se valida que se haya pasado el parámetro \n", 157 | "\n", 158 | "\tlong int suma = 0;\n", 159 | " long int suma_p = 0; \n", 160 | " long int sumaHilo = 0; \n", 161 | " double inicio_s, fin_s, inicio_p, fin_p; // Para los tiempos de ejecución\n", 162 | "\n", 163 | " inicio_s = omp_get_wtime();\n", 164 | "\tfor(int i =0; i <= 1000000000; i++){\n", 165 | "\t\tsuma = suma +i;\n", 166 | "\t}\n", 167 | " fin_s = omp_get_wtime();\n", 168 | " double tiempo_s = fin_s - inicio_s;\n", 169 | "\tprintf(\"suma: %li \\\\n tiempo de ejecucion: %f \\\\n\",suma, fin_s - inicio_s); //imprime resultados\n", 170 | "\n", 171 | " inicio_p = omp_get_wtime();\n", 172 | "\n", 173 | " int numHilos;\n", 174 | " sscanf(argv[1], \"%i\", &numHilos);\n", 175 | "\n", 176 | " \tomp_set_num_threads(numHilos);\n", 177 | "\tint idHilo; \n", 178 | "\t//inicia seccion paralela\n", 179 | "\t#pragma omp parallel private(idHilo, sumaHilo)\n", 180 | " {\n", 181 | "\t\tidHilo = omp_get_thread_num();\n", 182 | "\t\tif (idHilo==0){\n", 183 | "\t\t\tprintf (\"iniciando calculo con %i hilos\\\\n\", omp_get_num_threads());\n", 184 | "\t\t}\n", 185 | "\t\t\n", 186 | "\t\t//cada hilo realiza una suma parcial\n", 187 | "\t\tsumaHilo=0;\n", 188 | "\t\tint i;\n", 189 | "\t\tfor (i=idHilo;i<=1000000000;i+=numHilos){\n", 190 | "\t\t\tsumaHilo+=i;\n", 191 | "\t\t}\n", 192 | "\t\t\n", 193 | "\t\t//cada hilo actualiza la suma total con su resultado parcial\n", 194 | "\t\tsuma_p+=sumaHilo;\n", 195 | "\t}//fin de seccion paralela\n", 196 | "\n", 197 | "\n", 198 | " fin_p = omp_get_wtime();\n", 199 | " double tiempo_p= fin_p - inicio_p;\n", 200 | "\tprintf(\"suma paralela: %li \\\\n Tiempo de ejecucion algoritmo paralelo: %f \\\\n\",suma,tiempo_p);\n", 201 | " double aceleracion = tiempo_s/tiempo_p;\n", 202 | " printf(\"La aceleración de paralelizar la suma se los primeros 1 000 000 000 número naturales es: %f \\\\n\", aceleracion);\n", 203 | " double eficiencia = aceleracion/2;\n", 204 | " printf(\"La eficiencia es: %f tomando que la prueba en colab se hace en dos procesadores \\\\n\", eficiencia);\n", 205 | "\n", 206 | "}\n", 207 | "\"\"\" " 208 | ] 209 | }, 210 | { 211 | "cell_type": "code", 212 | "execution_count": null, 213 | "metadata": { 214 | "id": "ZvWAs7OyhW0P" 215 | }, 216 | "outputs": [], 217 | "source": [ 218 | "# se crea el archivo con permisos para escribir mediante python\n", 219 | "archivo_texto = open(\"sumaIntervalo.c\", \"w\")\n", 220 | "# se escribe el programa en el archivo \n", 221 | "archivo_texto.write(codigo)\n", 222 | "# se cierra el buffer de escritura\n", 223 | "archivo_texto.close()" 224 | ] 225 | }, 226 | { 227 | "cell_type": "code", 228 | "execution_count": null, 229 | "metadata": { 230 | "id": "mWRdPiH5hefY" 231 | }, 232 | "outputs": [], 233 | "source": [ 234 | "!gcc -o suma -fopenmp sumaIntervalo.c" 235 | ] 236 | }, 237 | { 238 | "cell_type": "code", 239 | "execution_count": null, 240 | "metadata": { 241 | "colab": { 242 | "base_uri": "https://localhost:8080/" 243 | }, 244 | "id": "oH-OhfgfhfC_", 245 | "outputId": "917029a7-9cde-41ff-f9f5-ad4eab027ae4" 246 | }, 247 | "outputs": [ 248 | { 249 | "name": "stdout", 250 | "output_type": "stream", 251 | "text": [ 252 | "suma: 500000000500000000 \n", 253 | " tiempo de ejecucion: 3.297801 \n", 254 | "iniciando calculo con 2 hilos\n", 255 | "suma paralela: 500000000500000000 \n", 256 | " Tiempo de ejecucion algoritmo paralelo: 2.163480 \n", 257 | "La aceleración de paralelizar la suma se los primeros 1 000 000 000 número naturales es: 1.524304 \n", 258 | "La eficiencia es: 0.762152 tomando que la prueba en colab se hace en dos procesadores \n" 259 | ] 260 | } 261 | ], 262 | "source": [ 263 | "!./suma 2" 264 | ] 265 | }, 266 | { 267 | "cell_type": "markdown", 268 | "metadata": { 269 | "id": "huf_osurzibX" 270 | }, 271 | "source": [ 272 | "> Queda como ejercicio al lector calcular la fracción serial e interpretar el resultado. ⚡\n", 273 | "\n", 274 | "\n" 275 | ] 276 | }, 277 | { 278 | "cell_type": "code", 279 | "execution_count": null, 280 | "metadata": { 281 | "colab": { 282 | "base_uri": "https://localhost:8080/" 283 | }, 284 | "id": "hXKB7jMp9q_I", 285 | "outputId": "174e9183-9540-4d52-b227-26c0306f8770" 286 | }, 287 | "outputs": [ 288 | { 289 | "name": "stdout", 290 | "output_type": "stream", 291 | "text": [ 292 | "Architecture: x86_64\n", 293 | "CPU op-mode(s): 32-bit, 64-bit\n", 294 | "Byte Order: Little Endian\n", 295 | "CPU(s): 2\n", 296 | "On-line CPU(s) list: 0,1\n", 297 | "Thread(s) per core: 2\n", 298 | "Core(s) per socket: 1\n", 299 | "Socket(s): 1\n", 300 | "NUMA node(s): 1\n", 301 | "Vendor ID: GenuineIntel\n", 302 | "CPU family: 6\n", 303 | "Model: 79\n", 304 | "Model name: Intel(R) Xeon(R) CPU @ 2.20GHz\n", 305 | "Stepping: 0\n", 306 | "CPU MHz: 2199.998\n", 307 | "BogoMIPS: 4399.99\n", 308 | "Hypervisor vendor: KVM\n", 309 | "Virtualization type: full\n", 310 | "L1d cache: 32K\n", 311 | "L1i cache: 32K\n", 312 | "L2 cache: 256K\n", 313 | "L3 cache: 56320K\n", 314 | "NUMA node0 CPU(s): 0,1\n", 315 | "Flags: fpu vme de pse tsc msr pae mce cx8 apic sep mtrr pge mca cmov pat pse36 clflush mmx fxsr sse sse2 ss ht syscall nx pdpe1gb rdtscp lm constant_tsc rep_good nopl xtopology nonstop_tsc cpuid tsc_known_freq pni pclmulqdq ssse3 fma cx16 pcid sse4_1 sse4_2 x2apic movbe popcnt aes xsave avx f16c rdrand hypervisor lahf_lm abm 3dnowprefetch invpcid_single ssbd ibrs ibpb stibp fsgsbase tsc_adjust bmi1 hle avx2 smep bmi2 erms invpcid rtm rdseed adx smap xsaveopt arat md_clear arch_capabilities\n" 316 | ] 317 | } 318 | ], 319 | "source": [ 320 | "!lscpu" 321 | ] 322 | }, 323 | { 324 | "cell_type": "markdown", 325 | "metadata": { 326 | "id": "7NXG66CK-M_O" 327 | }, 328 | "source": [ 329 | "\n", 330 | "\n", 331 | "¿Qué es lo que debe tomarse en cuenta cuando se hacen este tipo de pruebas? \n", 332 | "\n", 333 | "* Procesos en segundo plano ejecutando\n", 334 | "* Las condiciones en las que se encuentra el equipo\n", 335 | "* Recursos compartidos on otras aplicaciones, por ejemplo, *Mozilla*, *Spotify* entre otras..." 336 | ] 337 | }, 338 | { 339 | "cell_type": "markdown", 340 | "metadata": { 341 | "id": "JsEyeevk6kLU" 342 | }, 343 | "source": [ 344 | "## Ley de Amdahl \n", 345 | "\n", 346 | "El objetivo principal de usar un algoritmo paralelo es obtener los resultados lo más pronto posible, es decir, disminuir la complejidad en tiempo. Al aumentar el número de procesadores en el sistema paralelo se distribuyen las sub-tares entre los procesadores. Sin embargo, surge la pregunta ¿Siempre que aumente el número de procesadores disminuirá el tiempo de ejecución? \n", 347 | "\n", 348 | "Resulta que la ley de Amdahl dice que llega un punto en el cual sin importar que el numero de procesadores sea muy alto , el speedup se va a comportar de manera lineal. Dicho de otra forma cada sección paralelizable de un algoritmo tendrá un número $n$ de procesadores optimos, si ejecutamos el algoritmo con más de $n$ procesadores no mejorará el tiempo de ejecución.\n", 349 | "\n" 350 | ] 351 | }, 352 | { 353 | "cell_type": "markdown", 354 | "metadata": { 355 | "id": "uGvii3oH-o8k" 356 | }, 357 | "source": [ 358 | "
\n", 359 | " \n", 360 | "
" 361 | ] 362 | }, 363 | { 364 | "cell_type": "markdown", 365 | "metadata": { 366 | "id": "EbcAEt45_cku" 367 | }, 368 | "source": [ 369 | "La gráfica anterior nos muestra que dependiendo del porcentaje de código ejecutado de manera paralela será la cota de número de procesadores para alcanzar la máximo eficiencia. " 370 | ] 371 | }, 372 | { 373 | "cell_type": "markdown", 374 | "metadata": { 375 | "id": "-cyXdBLLWV-I" 376 | }, 377 | "source": [ 378 | "
\n", 379 | " \n", 380 | "
" 381 | ] 382 | }, 383 | { 384 | "cell_type": "markdown", 385 | "metadata": { 386 | "id": "F2UfClz4ZrID" 387 | }, 388 | "source": [ 389 | "### La ley de Amdahl en suma paralela\n", 390 | "\n", 391 | "En el siguiente cuadro de datos tenemos algunas ejecuciones de pruebas realizadas en una computadora con las siguientes carácteristicas, se obtuvo un tiempo de ejecución de: 3 255 980 microsegundos\n", 392 | "\n", 393 | "* Marca *Dell*\n", 394 | "* Intel(R) Core(TM) i5-6300U CPU 2.40 GHz \n", 395 | "* 4 CPU's \n", 396 | "* 8 Gb de RAM\n", 397 | "\n", 398 | "
\n", 399 | " \n", 400 | "
\n", 401 | "\n", 402 | "Observemos que en el Cuadro el mejor tiempo ($1107980{.}8 \\mu s$) que se presenta es cuando el programa usa únicamente 4 hilos, la computadora donde se ejecutaron las pruebas es una Dell con 4 CPU(s). En el cuadro tenemos que los mejores tiempos obtenidos corresponden al renglón de las pruebas realizadas con 50 hilos. Incluso podemos observar que los mejores tiempos corresponden a las pruebas realizadas con 50 hilos. Recordemos que cualquier problema tiene una cota en tiempo óptimo, además también hay una cota para el número de procesadores que pueden optimizar un proceso. Cada problema tendrá un número de hilos óptimo, para este caso tenemos que 50 hilos nos proporciona el tiempo óptimo, al usar 100 aumentamos el tiempo en vez de disminuirlo, se tendría que buscar el número $n$ donde se pierde la optimización del problema. " 403 | ] 404 | } 405 | ], 406 | "metadata": { 407 | "colab": { 408 | "include_colab_link": true, 409 | "name": "Ley Amdahl.ipynb", 410 | "provenance": [], 411 | "toc_visible": true 412 | }, 413 | "kernelspec": { 414 | "display_name": "Python 3 (ipykernel)", 415 | "language": "python", 416 | "name": "python3" 417 | }, 418 | "language_info": { 419 | "codemirror_mode": { 420 | "name": "ipython", 421 | "version": 3 422 | }, 423 | "file_extension": ".py", 424 | "mimetype": "text/x-python", 425 | "name": "python", 426 | "nbconvert_exporter": "python", 427 | "pygments_lexer": "ipython3", 428 | "version": "3.11.6" 429 | } 430 | }, 431 | "nbformat": 4, 432 | "nbformat_minor": 4 433 | } 434 | -------------------------------------------------------------------------------- /01_OpenMP/01_OpenMP_SCP.ipynb: -------------------------------------------------------------------------------- 1 | { 2 | "cells": [ 3 | { 4 | "cell_type": "markdown", 5 | "metadata": { 6 | "colab_type": "text", 7 | "id": "view-in-github" 8 | }, 9 | "source": [ 10 | "\"Open" 11 | ] 12 | }, 13 | { 14 | "cell_type": "markdown", 15 | "metadata": { 16 | "id": "EBC0NKmEENHP" 17 | }, 18 | "source": [ 19 | "\n", 20 | "

OpenMP (memoria compartida)

\n", 21 | "
\n", 22 | " \n", 23 | "
Profesor: M. en C. Miguel Angel Pérez León
\n", 24 | "
Ayudante: Lucía Martínez Rivas
\n", 25 | "
Ayudante: Erick Jesús Rios Gonzalez
\n", 26 | "
Materia: Seminario de programación en paralelo
\n", 27 | "
" 28 | ] 29 | }, 30 | { 31 | "cell_type": "markdown", 32 | "metadata": { 33 | "id": "FK0VO6YaG_Du" 34 | }, 35 | "source": [ 36 | "# Introducción\n", 37 | "\n", 38 | "Aún en la década de los 80's adquirir una computadora con múltiples procesadores era costoso, incluso hoy en día el precio de una computadora depende en gran medida del número de procesadores que tenga.\n", 39 | "\n", 40 | "Actualmente comprar una computadora que contengan varios núcleos de procesamiento es relativamente accesible.\n", 41 | "\n", 42 | "Como ya se mencionó previamente, existen diferentes formas (paradigmas) de programación en paralelo, pero si la arquitectura lo permite (memoria compartida) se logra un buen desempeño haciendo uso *OpenMP*.\n", 43 | "\n", 44 | "*OpenMP* es un conjunto de bibliotecas, funciones y directivas de compilador (*API*) que permite programar en paralelo en conjunto con lenguajes como *Fortran*, *C/C++*, incluso *Python* o *Julia*.\n", 45 | "\n", 46 | "Es importante recordar que *OpenMP* se basa en la idea de dividir (*fork*) una tarea grande en tareas más pequeñas, para que finalmente los resultados sean unidos (*join*).\n", 47 | "\n", 48 | "A continuación se muestra el modelo de programación en paralelo mediante memoria compartida.\n", 49 | "\n", 50 | "
\n", 51 | " \n", 52 | "
\n", 53 | "\n", 54 | "Diagrama del paradigma *fork-join*.\n", 55 | "\n", 56 | "
\n", 57 | " \n", 58 | "
\n", 59 | "\n", 60 | "En esta imágen, la linea azul muestra el avance del cómputo con respecto al tiempo.\n", 61 | "\n", 62 | "
\n", 63 | "\n", 64 | "
" 65 | ] 66 | }, 67 | { 68 | "cell_type": "markdown", 69 | "metadata": { 70 | "id": "MJLgoXA8IVCl" 71 | }, 72 | "source": [ 73 | "# Desempeño\n", 74 | "\n", 75 | "La idea detrás de esta forma de procesamiento en paralelo, es dividir y vencer." 76 | ] 77 | }, 78 | { 79 | "cell_type": "markdown", 80 | "metadata": { 81 | "id": "QBIFGoxeIcSL" 82 | }, 83 | "source": [ 84 | "## ¿Cómo funciona?\n", 85 | "\n", 86 | "La forma tradicional de la programación en paralelo empleando **memoria compartida** es la siguiente:\n", 87 | "\n", 88 | "* Cuando un programa comienza su ejecución un solo hilo llamado **hilo maestro** es activado.\n", 89 | "* El hilo maestro ejecuta la parte secuencial del algoritmo. En las secciones del algoritmo donde se requiera operaciones en paralelo, el hilo maestro genera (*fork*) **hilos adicionales** (esclavos).\n", 90 | "* El hilo maestro y los hilos adicionalmente creados, **trabajan de manera concurrente (o en paralelo)** a través de las secciones del algoritmo en paralelo.\n", 91 | "* Al termino de la o las secciones en paralelo, los hilos adicionales son **destruidos o suspendidos**.\n", 92 | "* Finalmente el control vuelve al hilo maestro y se **unen** (*join*) los resultados.\n" 93 | ] 94 | }, 95 | { 96 | "cell_type": "markdown", 97 | "metadata": { 98 | "id": "LSlkKBEjIhCO" 99 | }, 100 | "source": [ 101 | "## Ventajas\n", 102 | "\n", 103 | "La principal diferencia entre *OpenMP* y *MPI* es que en este último, todos los procesos permanecen activos desde un inicio del programa, mientras que en ***OpenMP* se comienza con un solo hilo y se termina con un solo hilo**.\n", 104 | "\n", 105 | "Se puede pensar en la programación secuencial como un caso especial de la programación en paralelo usando memoria compartida (*OpenMP*).\n", 106 | "\n", 107 | "La programación en paralelo usando memoria compartida abarca algoritmos en los cuales se tiene un único ciclo *for* que se ejecuta con varios hilos, hasta aquellos algoritmos en los que la mayoria del código se ejecuta en paralelo.\n", 108 | "\n", 109 | "Por lo tanto este modelo de programación en paralelo soporta **paralelización incremental**, lo que significa que, un algoritmo secuencial puede ser transformado en uno algoritmo en paralelo un bloque a la vez.\n", 110 | "\n", 111 | "En contraste, al emplear *MPI* es necesario replantear el diseño del algoritmo, de manera tal que desde un principio funcione en paralelo." 112 | ] 113 | }, 114 | { 115 | "cell_type": "markdown", 116 | "metadata": { 117 | "id": "tur77JgcEN-l" 118 | }, 119 | "source": [ 120 | "# *OpenMP (API)*\n", 121 | "\n", 122 | "Una vez que se tiene claro el funcionaiento de *OpenMP*, veamos los componentes principales de este *API* (interfaz de programación de aplicación)." 123 | ] 124 | }, 125 | { 126 | "cell_type": "markdown", 127 | "metadata": { 128 | "id": "a8ZwywSzI9HX" 129 | }, 130 | "source": [ 131 | "## Directivas de compilador\n", 132 | "\n", 133 | "Una directiva de compilador en *C/C++* es llamada **pragma**.\n", 134 | "\n", 135 | "La palabra *pragma*, es la contracción de ''información pragmática''.\n", 136 | "\n", 137 | "*Pragma* es una forma de comunicarle información al compilador, esta información no es esencial en el sentido del que el compilador puede ignorar dicha información y aun así compilar el código.\n", 138 | "\n", 139 | "Sin embargo la información dentro del *pragma* puede ayudar al compilador a optimizar el algoritmo.\n", 140 | "\n", 141 | "Al igual que otras lineas que proveen información al compilador, un pragma comienza con #." 142 | ] 143 | }, 144 | { 145 | "cell_type": "markdown", 146 | "metadata": { 147 | "id": "rj0UyAECJOxD" 148 | }, 149 | "source": [ 150 | "## Otras directivas de compilador\n", 151 | "\n", 152 | "Algunas de las directivas de compilador más importantes que veremos en esta sección son:\n", 153 | "\n", 154 | "1. **parallel**: que se usa antes de un bloque que sera ejecutado en paralelo por varios hilos.\n", 155 | "\n", 156 | "2. **for**: se usa antes de un ciclo for para indicar que las iteraciones de este ciclo serán ejecutadas en paralelo.\n", 157 | "\n", 158 | "3. **parallel for**: es una combinación de las 2 directivas previas.\n", 159 | "\n", 160 | "4. **sections**: indica que un conjunto de bloques será ejecutado en paralelo.\n", 161 | "\n", 162 | "5. **parallel sections**: combinación de *prallel* y *sections*.\n", 163 | "\n", 164 | "6. **critical**: se usa para indicar que una sección sera critica, por ejemplo para indicar que una sección de código solo puede ser accesible por un hilo a la vez.\n", 165 | "\n", 166 | "7. **single**: se usa antes de un bloque que sera ejecutado por un solo hilo." 167 | ] 168 | }, 169 | { 170 | "cell_type": "markdown", 171 | "metadata": { 172 | "id": "z79IN3G1Jxi8" 173 | }, 174 | "source": [ 175 | "## Funciones importantes\n", 176 | "\n", 177 | "Algunas funciones importantes que veremos en esta sección son:\n", 178 | "\n", 179 | "1. **omp_get_num_procs**: devuelve el numero de *CPU's* que tenga el núcleo en el cual se esta ejecutando el hilo.\n", 180 | "\n", 181 | "2. **omp_get_num_threads**: devuelve el número de hilos activos en la actual región en paralelo.\n", 182 | "\n", 183 | "3. **omp_get_thread_num**: devuelve el identificador del hilo.\n", 184 | "\n", 185 | "4. **omp_set_num_threads**: permite establecer el número de hilos que ejecutaran el código de la sección en paralelo." 186 | ] 187 | }, 188 | { 189 | "cell_type": "markdown", 190 | "metadata": { 191 | "id": "o_FFvlQOKD1q" 192 | }, 193 | "source": [ 194 | "# Compilación y Ejecución\n", 195 | "\n", 196 | "Una de las ventajas de *OpenMP* es que no requiere de instalación adicional a la que se realiza cuando se instala el compilador de *C/C++* (al menos en entornos *Linux*), solo es necesario usar las banderas (*flags*) correctas al momento de compilar.\n", 197 | "\n", 198 | "La manera en la que se compila (revisión sintáctica) y se ejecuta un programa codificado mediante *OpenMP*, es muy similar a como se compila y se ejecuta cualquier programa escrito en *C/C++*.\n", 199 | "\n", 200 | "Veamos como se compila y ejecuta tanto en *google colab*, como en un equipo local." 201 | ] 202 | }, 203 | { 204 | "cell_type": "markdown", 205 | "metadata": { 206 | "id": "9U4J7FrocIa1" 207 | }, 208 | "source": [ 209 | "## OpenMP en Google Colab\n", 210 | "\n", 211 | "Normalmente una vez iniciada la sesión de *google colab*, esta ya cuenta con todo lo necesario para compilar y ejecutar un programa usando *OpenMP*." 212 | ] 213 | }, 214 | { 215 | "cell_type": "code", 216 | "execution_count": 2, 217 | "metadata": { 218 | "id": "fSM96uxBcrYk" 219 | }, 220 | "outputs": [], 221 | "source": [ 222 | "# variable de tipo String que en si es el programa\n", 223 | "codigo = \"\"\"\n", 224 | "// Hola Mundo con OpenMP \n", 225 | "// Encabezados de OpenMP y STD \n", 226 | "#include \n", 227 | "#include \n", 228 | "#include \n", 229 | " \n", 230 | "int main(int argc, char* argv[]){ \n", 231 | " \n", 232 | " // Region en paralelo, que se ejecuta mediante hilos \n", 233 | " #pragma omp parallel\n", 234 | " { \n", 235 | " printf(\"Hola Mundo... desde el hilo = %d \\\\n\", omp_get_thread_num()); \n", 236 | " } \n", 237 | " // Fin de la region en paralelo \n", 238 | "}\n", 239 | "\"\"\"" 240 | ] 241 | }, 242 | { 243 | "cell_type": "markdown", 244 | "metadata": { 245 | "id": "Xnw75QXDdtYU" 246 | }, 247 | "source": [ 248 | "En la siguiente celda de código, se crea un archivo llamado *hola.c* y en el mismo se guarda el programa de la celda superior." 249 | ] 250 | }, 251 | { 252 | "cell_type": "code", 253 | "execution_count": 3, 254 | "metadata": { 255 | "id": "4cpxwVQcd3yP" 256 | }, 257 | "outputs": [], 258 | "source": [ 259 | "# se crea el archivo con permisos para escribir mediante python\n", 260 | "archivo_texto = open(\"hola.c\", \"w\")\n", 261 | "# se escribe el programa en el archivo \n", 262 | "archivo_texto.write(codigo)\n", 263 | "# se cierra el buffer de escritura\n", 264 | "archivo_texto.close()" 265 | ] 266 | }, 267 | { 268 | "cell_type": "markdown", 269 | "metadata": { 270 | "id": "eT0jdOr3eqCX" 271 | }, 272 | "source": [ 273 | "Generamos una variable de entorno, que defina el número de hilos que se van a utilizar." 274 | ] 275 | }, 276 | { 277 | "cell_type": "code", 278 | "execution_count": 4, 279 | "metadata": { 280 | "colab": { 281 | "base_uri": "https://localhost:8080/" 282 | }, 283 | "id": "INuCne7Qe4EM", 284 | "outputId": "978f1978-8ef5-4faf-e4bd-393636b3d70c" 285 | }, 286 | "outputs": [ 287 | { 288 | "name": "stdout", 289 | "output_type": "stream", 290 | "text": [ 291 | "env: OMP_NUM_THREADS=3\n" 292 | ] 293 | } 294 | ], 295 | "source": [ 296 | "%env OMP_NUM_THREADS=3" 297 | ] 298 | }, 299 | { 300 | "cell_type": "markdown", 301 | "metadata": { 302 | "id": "g50UD41Pe8Wi" 303 | }, 304 | "source": [ 305 | "Para compilar se ejecuta el siguiente comando de *Linux*, el orden no importa y esta es la semantica de este comando:\n", 306 | "\n", 307 | "* *!gcc*: llamada al compilador de *C/C++*, el \"!\" indica que es un comando de *Linux*.\n", 308 | "* *-o hola*: *-o* es la bandera que indica cual será el nombre de salida (output), en este caso el binario de salida será llamado *hola*.\n", 309 | "* *-fopenmp hola.c*: esta bandera indica que se hace uso del *API OpenMP* y que el archivo a compilar se llama *hola.c*.\n", 310 | "\n" 311 | ] 312 | }, 313 | { 314 | "cell_type": "code", 315 | "execution_count": 5, 316 | "metadata": { 317 | "id": "ryRWgvwffC5V" 318 | }, 319 | "outputs": [], 320 | "source": [ 321 | "!gcc -o hola -fopenmp hola.c" 322 | ] 323 | }, 324 | { 325 | "cell_type": "markdown", 326 | "metadata": { 327 | "id": "fwVQCs5FgL7K" 328 | }, 329 | "source": [ 330 | "Dado que no se tiene algún mensaje de error, se asume que el programa se compilo de manera correcta. Incluso es posible revisar en el navegador de archivos o mediante comando de *Linux* que el binario *hola*, se generó de manera correcta.\n", 331 | "\n", 332 | "Finalmente solo resta ejecutar dicho archivo." 333 | ] 334 | }, 335 | { 336 | "cell_type": "code", 337 | "execution_count": 6, 338 | "metadata": { 339 | "colab": { 340 | "base_uri": "https://localhost:8080/" 341 | }, 342 | "id": "BX7PQ3YZgqlt", 343 | "outputId": "43ee2eac-2052-4649-b5ce-853522346420" 344 | }, 345 | "outputs": [ 346 | { 347 | "name": "stdout", 348 | "output_type": "stream", 349 | "text": [ 350 | "Hola Mundo... desde el hilo = 1 \n", 351 | "Hola Mundo... desde el hilo = 0 \n", 352 | "Hola Mundo... desde el hilo = 2 \n" 353 | ] 354 | } 355 | ], 356 | "source": [ 357 | "!./hola" 358 | ] 359 | }, 360 | { 361 | "cell_type": "markdown", 362 | "metadata": { 363 | "id": "9_0pKijIKJSQ" 364 | }, 365 | "source": [ 366 | "## OpenMP en equipo local\n", 367 | "\n", 368 | "La manera de compilar y ejecutar en un equipo local es muy similar a los pasos previamente vistos.\n", 369 | "\n", 370 | "Lo primero es crear el programa y guardarlo en un archivo de texto plano, por ejemplo *codigo.c*.\n", 371 | "\n", 372 | "De tal forma que compilar y ejecutar código que emplea directivas y funciones de *OpenMP* es tan sencillo como:\n", 373 | "\n", 374 | "* Para compilar: *\\$gcc -o salida -fopenmp codigo.c*\n", 375 | "\n", 376 | "El comando anterior compila (y en caso de no haber errores) y genera un archivo ejecutable (binario) que puede ser ejecutado de la siguiente manera:\n", 377 | " \n", 378 | "* Para ejecutar: *\\$./salida*\n", 379 | "\n", 380 | "Intenta compilar y ejecutar el programa *hola.c* en tu equipo local." 381 | ] 382 | }, 383 | { 384 | "cell_type": "markdown", 385 | "metadata": { 386 | "id": "5xg6mcCXKq5o" 387 | }, 388 | "source": [ 389 | "# Glosario\n", 390 | "\n", 391 | "**Hilo** (Thread): También conocido como proceso ligero, es el encargado de ejecutar tareas sencillas dentro de algún algoritmo. Varios hilos pueden conformar un proceso.\n", 392 | "\n", 393 | "**Núcleo** (core): En computación, un núcleo es una parte del microprocesador que se encarga de leer y ejecutar tareas. Actualmente se puede adquirir computadoras que cuenten con varios CPU's y que a su vez, estos contengan varios núcleos. " 394 | ] 395 | }, 396 | { 397 | "cell_type": "markdown", 398 | "metadata": { 399 | "id": "HoDz-nxRKuQ_" 400 | }, 401 | "source": [ 402 | "# Referencias\n", 403 | "\n", 404 | "1. Michaell J. Quuin: Parallel Programming in C with OpenMP and MPI.\n", 405 | "2. https://hpc-wiki.info/hpc/OpenMP\n", 406 | "3. Dongarra Foster: Source Book of parallel computing." 407 | ] 408 | } 409 | ], 410 | "metadata": { 411 | "colab": { 412 | "collapsed_sections": [], 413 | "include_colab_link": true, 414 | "name": "OpenMP_SCP.ipynb", 415 | "provenance": [], 416 | "toc_visible": true 417 | }, 418 | "kernelspec": { 419 | "display_name": "Python 3 (ipykernel)", 420 | "language": "python", 421 | "name": "python3" 422 | }, 423 | "language_info": { 424 | "codemirror_mode": { 425 | "name": "ipython", 426 | "version": 3 427 | }, 428 | "file_extension": ".py", 429 | "mimetype": "text/x-python", 430 | "name": "python", 431 | "nbconvert_exporter": "python", 432 | "pygments_lexer": "ipython3", 433 | "version": "3.11.6" 434 | } 435 | }, 436 | "nbformat": 4, 437 | "nbformat_minor": 4 438 | } 439 | --------------------------------------------------------------------------------