Sei sulla pagina 1di 133

CENTRO UNIVERSITARIO DE LA COSTA SUR

UNIVERSIDAD DE GUADALAJARA
DIVISI

ON DE DESARROLLO REGIONAL
DEPARTAMENTO DE INGENIER

IAS
INGENIER

IA EN TELEINFORM

ATICA
PARA OBTENER EL T

ITULO DE INGENIERO EN TELEINFORM

ATICA
BAJO LA MODALIDAD DE TITULACI

ON
TESIS
CON EL T

ITULO
Esquemas Iterativos en Paralelo con OpenMP
PRESENTA
Sotero Ordo nes Nogales
DIRECTOR
Dr. Jose Antonio Mu noz G omez
ASESORES
Dr. Luis Isidro Aguirre Salas Dr. Omar Aguilar Loreto
Autl an de la Grana, Jalisco. Enero 2013
UNIVERSIDAD DE GUADALAJARA
CENTRO UNIVERSITARIO DE LA COSTA SUR
SECRETARA ACADMICA COORDINACIN DE INGENIERA EN TELEINFORMTICA


Avenida Independencia Nacional # 151, Autln de Navarro, Jalisco; C.P. 48900, Tels. (317) 382-50-10 Y 382-32- 00
http://www.cucsur.udg.mx



C. SOTERO ORDOES NOGALES
Egresado de la Carrera de Ingeniera en Teleinformtica
P R E S E N T E


A travs de la presente, se le informa que fue APROBADA su modalidad de
titulacin de TESIS, para titularse de la carrera de Ingeniero en Teleinformtica.

As mismo, se le informa que estar asignado como Director al DR. JOSE
ANTONIO MUOZ GMEZ y DR. OMAR AGUILAR LORETO y DR. LUIS ISIDRO AGUIRRE
SALAS, como asesores.

Se anexa una gua con los temas que debe considerar para realizar dicho
documento y se le informa a su vez que tiene 8 meses a partir de la fecha del presente
para entrega del trabajo recepcional con el visto bueno del Director. Debe presentar
siete ejemplares impresos con una copia de este oficio en primer trmino. Adems,
debe agregar portada y un formato especficos, solicitarlos antes de su entrega.





ATENTAMENTE
PIENSA Y TRABAJA
AUTLN DE NAVARRO, JAL. 04 DE DICIEMBRE DE 2012.




___________________________________________
M.T.A. CLAUDIA DIANE VACA GAVIO
COORDINADOR DE LA CARRERA DE INGENIERA Y DE TSU EN TELEINFORMTICA









C.C.P ARCHIVO
Dedicatorias y Agradecimientos
He llegado al nal de una peque na travesa en el viaje de la vida; durante este trayecto he
adquirido experiencias que han dejado estelas imborrables. Me permito mencionar a las dos personas
que se convirtieron en la estrella polar de este pobre marinero:
A Nora Marisol Chavez Guerrero,
...mi inspiracion y motivacion.
A mi padre, Luis Ordo nez Daz
que siempre estara en mi recuerdo.
Hay personas que nos hablan y ni las escuchamos...
hay personas que nos hieren y no dejan ni cicatriz...
pero hay personas que simplemente aparecen en nues-
tra vida y nos marcan para siempre.
Ceclia Meireles
Un marinero no es nadie sin la ayuda de aquellos que lo han acompa nado en el barco. Quiero
agradecer a esas personas con las que no solo compart este viaje, sino colaboraron en la toma del
rumbo, me reero a la tripulacion:
Mi familia y Dios
Por estar all siempre apoyandome, toda la paciencia y esfuerzo que han realizado para ver cumplido
este sue no. Especialmente a mi se nora madre a quien no me alcanzara toda una vida, ni cada una
de las palabras del mundo para agradecerte por todo lo que ha hecho por m. A mis hermanos Juan,
Isabel, Angelina y Julio que sin la ayuda esto no sera posible.
Dr Antonio
Gracias por ese apoyo incondicional no solo durante la realizacion del presente documento; sino
tambien en el transcurso de mi formacion profesional y personal dentro de esta institucion. Por la
paciencia y dedicacion para aclarar los temas oscuros. Por permitirme utilizar las computadoras
para la evaluacion de los resultados y la elaboracion de la presente tesis.
Los doctores Luis Isidro y Omar
Gracias mas que ser mis maestros ser mis amigos. Sus valiosas aportaciones y observaciones a la
presente tesis. Agradezco todas sus ense nazas que no solo se limitaron a lecciones academicas sino
tambien de vida. Me es imposible citar textualmente las frases que me dijeron; pero la esencia la
conservo.
Para llevar a puerto esta peque na embarcacion colaboraron muchas personas que por ahora me
es imposible nombrar a cada una de ellas; todos esos momentos que hicieron divertida la travesa.
Como olvidar esta tan acertada frase de uno de ellos:
...la universidad es como una espada, cuanto mas la alemos y practique-
mos...estaremos mejor preparados para enfrentar, al coyote que esta al
asecho en el camino de la vida...
Luis Isidro Aguirre Salas

Indice general

Indice de guras XI

Indice de tablas XIII


Resumen XV
1. Introduccion 1
2. Marco Teorico 7
2.1. Metodos numericos . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 7
2.2. Modelacion matematica . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 7
2.3. Los n umeros en la computadora . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 8
2.4. Tipos de error en metodos numericos . . . . . . . . . . . . . . . . . . . . . . . . . . . 16
2.5. El lenguaje de programaci on C . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 18
2.6. Programacion en paralelo . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 19
2.7. OpenMP . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 21
2.8. Escalabilidad paralela . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 24
2.8.1. Ley de Amdahl . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 25
2.8.2. Incremento de velocidad (speed-up) . . . . . . . . . . . . . . . . . . . . . . . 27
2.8.3. Desempe no computacional . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 28
3. Producto matriz-vector Ax 31
3.1. Concepto . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 32
3.2. Loop unrolling . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 34
3.3. Calculo del residual . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 36
3.4. Codicacion . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 38
3.5. Incremento del desempe no . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 39
3.6. Procesamiento vectorial (SIMD) . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 52
3.7. Codicacion en paralelo . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 60
3.8. Evaluacion de algoritmos en paralelo . . . . . . . . . . . . . . . . . . . . . . . . . . . 63
ix
x

Indice general
4. Metodo Iterativo de Jacobi 69
4.1. Concepto . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 77
4.2. Codicacion del metodo de Jacobi en C . . . . . . . . . . . . . . . . . . . . . . . . . 81
4.2.1. Simplicando codigo . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 81
4.2.2. Optimizacion de codigo . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 86
4.3. Metodo de Jacobi en paralelo con OpenMP . . . . . . . . . . . . . . . . . . . . . . . 87
4.4. Evaluacion de algoritmo en paralelo . . . . . . . . . . . . . . . . . . . . . . . . . . . 90
5. Metodo de Gauss-Seidel 93
5.1. Concepto . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 93
5.2. Programacion en lenguaje C . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 96
5.3. Codicacion en paralelo . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 97
5.4. Gauss-Seidel versus Jacobi . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 102
6. Conclusiones y trabajo a futuro 109
Bibliografa 113

Indice de guras
2.1. Distribucion de n umeros enteros con formato predenido. . . . . . . . . . . . . . . . 10
2.2. Distribucion de n umeros reales con formato predenido. . . . . . . . . . . . . . . . . 12
2.3. Modelo para representacion de n umeros en punto otante IEEE 754. . . . . . . . . . 13
2.4. Calculo de epsilon de la computadora. . . . . . . . . . . . . . . . . . . . . . . . . . . 14
2.5. Rango de n umero IEEE-754 precision simple. . . . . . . . . . . . . . . . . . . . . . . 15
2.6. Arquitectura de hardware CPU versus GPU. . . . . . . . . . . . . . . . . . . . . . . 21
2.7. Tipos de memoria en sistemas. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 22
2.8. Modelo de OpenMP. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 23
2.9. Modelo de ejecucion de programas paralelos. . . . . . . . . . . . . . . . . . . . . . . 26
2.10. Speed-up con Ley de Amdahl. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 27
3.1. Calculo del residual en C. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 37
3.2. Implementacion canonica de Ax. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 38
3.3. Tecnica Loop Unrroll con factor 2. . . . . . . . . . . . . . . . . . . . . . . . . . . . . 41
3.4. Tecnica Loop Unroll con factor 4. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 42
3.5. Tecnica Loop Unroll con factor 2, dos ciclos for. . . . . . . . . . . . . . . . . . . . . 42
3.6. Tecnica Loop Unroll con factor 2, dos variables. . . . . . . . . . . . . . . . . . . . . . 42
3.7. Tecnica Loop Unroll con factor 2, dos ciclos for y dos variables. . . . . . . . . . . . . 43
3.8. Tecnica Loop Unroll con factor 2, cuatros ciclos for cuatro variables. . . . . . . . . . 43
3.9. Tecnica Loop Unroll con factor 5. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 46
3.10. Tecnica Loop Unroll con factor 6. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 47
3.11. Tecnica Loop Unroll con factor 8. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 47
3.12. Tecnica Loop Unroll con factor 10. . . . . . . . . . . . . . . . . . . . . . . . . . . . . 47
3.13. Tecnica Loop Unroll con factor 12. . . . . . . . . . . . . . . . . . . . . . . . . . . . . 48
3.14. Speed-up para la multiplicacion de dos vectores. . . . . . . . . . . . . . . . . . . . . 48
3.15. Funcion general de la multiplicacion Ax con Unroll. . . . . . . . . . . . . . . . . . . 50
3.16. Speed-up de Ax utilizando la tecnica de Unroll. . . . . . . . . . . . . . . . . . . . . . 51
3.17. Rendimiento computacional de Ax al utilizar la tecnica de Unroll. . . . . . . . . . . 52
3.18. Modelo SIMD. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 53
3.19. Funcion en MMX que multiplica dos vectores x y y. . . . . . . . . . . . . . . . . . . 55
3.20. Desempe no de Ax al utilizar MMX con bandera de compilacion -O2. . . . . . . . . . 59
3.21. Implementacion canonica en paralelo de Ax. . . . . . . . . . . . . . . . . . . . . . . . 60
xi
xii

Indice de guras
3.22. Rendimiento de la version canonica de Ax en paralelo con bandera de compilacion -O2. 62
3.23. Implementacion general de Ax en paralelo. . . . . . . . . . . . . . . . . . . . . . . . 62
3.24. Desempe no de la version canonica de Ax con banderas de compilacion. . . . . . . . . 63
3.25. Escalabilidad paralela de Ax en su la version Unroll-10 con bandera -O2. . . . . . . 64
3.26. Escalabilidad paralela de Ax en su la version MMX con bandera -O2. . . . . . . . . 65
3.27. Comparativa del rendimiento computacional de las versiones canonica, Unroll-10 y
MMX con bandera de compilacion -O2. . . . . . . . . . . . . . . . . . . . . . . . . . 66
4.1. Primera implementacion del metodo de Jacobi en lenguaje C. . . . . . . . . . . . . . 82
4.2. Codigo en lenguaje C del esquema de Jacobi. . . . . . . . . . . . . . . . . . . . . . . 83
4.3. Porcentaje del tiempo de ejecucion del metodo de Jacobi con y sin sentencia if. . . . 84
4.4. Codigo general de Jacobi optimizado. . . . . . . . . . . . . . . . . . . . . . . . . . . . 86
4.5. Tiempos de ejecucion de Jacobi en serie, versiones [Canonica, Unroll4, MMX] para
n = 5000. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 87
4.6. Codigo de version canonica en paralelo de Jacobi. . . . . . . . . . . . . . . . . . . . . 88
4.7. Speed-up del metodo de Jacobi en paralelo en su version canonica. . . . . . . . . . . 89
4.8. Speed-up del metodo de Jacobi en paralelo en su version MMX. . . . . . . . . . . . . 90
5.1. Metodo de Gauss-Seidel en lenguaje C, version canonica. . . . . . . . . . . . . . . . . 97
5.2. Metodo de Gauss-Seidel con OpenMP. . . . . . . . . . . . . . . . . . . . . . . . . . . 98
5.3. Descomposicion del vector soluci on x para dos procesadores. . . . . . . . . . . . . . . 99
5.4. Escalabilidad paralela del metodo Gauss-Seidel version canonica. . . . . . . . . . . . 101
5.5. Metodo de Jacobi con diferencias nitas. . . . . . . . . . . . . . . . . . . . . . . . . . 104
5.6. Metodo de Gauss-Seidel con diferencias nitas. . . . . . . . . . . . . . . . . . . . . . 104
5.7. Aproximacion numerica a u(x, y) = sen xcos y con Gauss-Seidel. . . . . . . . . . . . . 106

Indice de tablas
2.1. Unidades de medida de FLOPS . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 29
3.1. Producto de dos vectores: resultados de prueba de exactitud, observamos las veces
que es mas exacta, mostrada en porcentaje ( %), cada funcion durante las iteraciones
para cada valor de n. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 44
3.2. Producto de dos vectores: resultados de prueba de velocidad, observamos la tasa de
exactitud de cada funcion con respecto al n umero de iteraciones (10,000). . . . . . . 45
3.3. Producto de dos vectores: comparacion de rendimiento de las funciones canonica,
MMX y Unroll-4; observamos el rendimiento que nos brinda la funcion en MMX
respecto a la forma tradicional y en comparacion con la funcion con Unroll de 4. . . 58
4.1. Metodo iterativo de Jacobi: primera evaluacion de rendimiento, observamos el por-
centaje de la reduccion del tiempo en ejecucion cuando se remueve la condicion (if). 85
5.1. Metodo de Gauss-Seidel en paralelo; iteraciones para converger. . . . . . . . . . . . . 100
5.2. Convergencia de Gauss-Seidel vs Jacobi. . . . . . . . . . . . . . . . . . . . . . . . . . 105
xiii
Resumen
El presente trabajo de tesis aborda la creacion de algoritmos paralelos para la solucion numeri-
ca de sistemas de ecuaciones lineales mediante esquemas iterativos de tipo Jacobi y Gauss-Seidel;
con especial enfasis en el rendimiento y la escalabilidad. Este documento se centra en dos aspec-
tos principales. En un primer momento, estudiamos la implementacion de tecnicas avanzadas de
programacion para maximizar el rendimiento en ejecuciones seriadas. Una de las tecnicas permite
utilizar modulos de procesamiento vectorial del procesador con la nalidad de realizar varias ope-
raciones a la vez; es decir, conseguir paralelismo a nivel de datos (conocido como SIMD). Tambien
se utilizan caractersticas del compilador GCC para optimizar el codigo y catapultar el rendimiento
serial de estas primeras funciones. En un segundo momento, se realiza un estudio exhaustivo de
cada uno de los metodos que permitan escribir funciones que realmente puedan ser ejecutadas en
mas de un n ucleo utilizando el API llamada OpenMP apoyado con los resultados de las tecnicas
utilizadas (Bandera de compilacion, Loop unrolling, SIMD). En general con el estudio realizado
observamos una escalabilidad lineal de dos a cuatro procesadores. Por otro lado cuando empleamos
ocho procesadores se observa un aumento de 5.4x.
xv
Captulo 1
Introducci on
Una de las herramientas mas valiosas para la resolucion de problemas practicos de Ingeniera son
las computadoras digitales mediante la utilizacion de metodos numericos. En un n umero signicativo
de esos problemas solo se puede obtener una solucion aproximada, a esto se debe la importancia del
estudio de la rama de las matematicas llamada analisis numerico. Esta rama involucra el estudio
de metodos numericos. El desarrollo de estos esquemas es notablemente inuenciado y determinado
por las computadoras, las cuales permiten realizar los calculos de manera veloz, conable y sobre
todo exible.
En la actualidad la computadora es una herramienta indispensable para las actividades coti-
dianas, escolares, de ocina y cientcas. Con necesidades cada vez mas complejas, es por ello que
se busca que las aplicaciones puedan realizar los calculos lo mas rapido posible aprovechando los
recursos del equipo con la mayor eciencia posible.
En el pasado para cubrir con las necesidades del mercado se incrementaba la velocidad del
procesador, aumentando el n umero de transistores al circuito integrado. Como lo previo Gordon
Moore, en la actualidad, ya no es posible disminuir el tama no de los transistores. Para compensarlo
se han construido procesadores que tienen mas de un n ucleo de procesamiento (2, 4, 8, 12). Las
computadoras de uso general que estan en el mercado al momento de la realizacion del presente
trabajo cuentan con procesadores paralelos, es decir tienen mas de un n ucleo de procesamiento.
Esta cualidad indica que el computo en paralelo esta a disposicion de todos.
Cuando la arquitectura del hardware de las computadoras paso a ser paralelo se creo la necesidad
de desarrollar aplicaciones que aprovechen estas caractersticas. La incorporacion de n ucleos de
1
2 Captulo 1. Introduccion
procesamiento tienen el n de que las aplicaciones se ejecuten mas rapido. Para ejemplicar el
problema supongase lo siguiente: se quiere extraer el agua de un tanque que tiene 1, 000 m
3
para
ello se utiliza una bomba que extrae 250 m
3
del lquido por cada hora de trabajo. Esta maquina
terminara su tarea en 4 horas. Si en un momento se aumenta 7 bombas mas para hacer un total
de 8, la tarea sera concluida en apenas 30 minutos, con ello se redujo el tiempo del proceso. Esto
reeja la importancia del computo en paralelo. Con lo ya mencionado el computo en paralelo es la
solucion a problemas contemporaneos.
Cabe mencionar que en la actualidad la mayora de las aplicaciones son seriales, es decir se
ejecutan solo en uno de los n ucleos; entonces estos programas no estan aprovechando al maximo los
recursos con los que cuenta el equipo. Para contrarrestarlo se fomenta el deseo de escribir codigos
que puedan ejecutarse en paralelo.
Una pregunta que surge con lo mencionado; En que nos benecia la programacion en paralelo?
La respuesta es por demas sencilla. En el mundo de la industria manufacturera se realizan procesos
de control de calidad, en los cuales se recurre a la simulacion de eventos mediante computadoras.
Estas medidas son cada da mas frecuentes. Un ejemplo mas que evidente ocurren en la industria
automotriz en la simulacion de sus prototipos frente a las colisiones. Hacer estas pruebas en fsico
representa un costo economico muy representativo; es por ello que se recurre a la simulacion del
evento con resultados dedignos. Para obtener estos resultados tan realistas se deben tomar en
cuenta muchas variantes que inuyen en los resultados del proceso, todo esto aumenta la complejidad
de operaciones en modelo del suceso. El costo computacional de un modelo depende del grado
de complejidad operacional. Con ello es concluyente que estas simulaciones deben ser resueltas
con programacion en paralelo, para reducir los tiempos de simulaciones y as reducir el ciclo de
lanzamiento de los nuevos modelos; lo cual es primordial para la generacion de utilidades de la
industria automotriz.
Motivaci on
La principal motivacion del presente proyecto consiste en explotar al maximo lo recursos que
ofrecen las computadoras; mediante tecnologas para la programacion en paralelo.
En los labores de la ingeniera y en la ciencia en general se formulan problemas mediante modelos
matematicos y son tratados numericamente, ello conduce frecuente a resolverlos por sistemas de
Captulo 1. Introduccion 3
ecuaciones lineales. Como es bien sabido esta tarea es muy demandante en tiempo de calculo. En
virtud de ello y con base a la tendencia del analisis numerico es inherente que sean resueltos con
aplicaciones computacionales paralelas.
Para la resolucion de sistemas de ecuaciones lineales existen dos tipos de metodos; directos e
iterativos. Los metodos directos son utilizados para sistemas hasta de pocos miles de nodos debido
a su orden de complejidad; ocasionando que sea imposible el resolverlo por cuestiones de tiempo.
Por otra parte los metodos iterativos se utilizan para sistemas con una mayor cantidad de nodos en
virtud de su orden de complejidad que es menor a la de los directos. Dentro de los metodos iterativos
se encuentran el de Jacobi y Gauss-Seidel que son los dos pilares fundamentales. En la presente tesis
se estudia el dise no de dos algoritmos paralelos que implementen los esquemas de Jacobi y Gauss-
Seidel. En la literatura existen algoritmos iterativos paralelos reportados, sin embargo no existe
codigo fuente por ello en el presente documento se da enfasis al desarrollo de estos algoritmos desde
un punto de vista practico con la nalidad de proporcionar ese codigo fuente.
En la literatura hemos encontrado distintos modelos matematicos y esquemas en paralelo con
OpenMP para la resolucion de sistemas lineales de ecuaciones [21, 26, 35, 36]. Sin embargo, se
enfocan principalmente a sistemas ralos o esparcidos y tipo QR o de Cholesky. Esto se debe princi-
palmente a que las discretizacion de ecuaciones diferenciales parciales (EDP) esta basada principal-
mente en los metodos de elemento nito, volumen nito y diferencia nita los cuales generan este
tipo de matrices.
En el desarrollo profesional de metodos numericos se busca la innovacion para poner a disposicion
el nuevo software. Existen una gran variedad de libreras p ublicas para la optimizacion de codigo,
ejemplos son BLAS (Basic Linear Algebra Subprograms) y LAPACK (Linear Algebra Package)
que permiten la optimizacion para programas secuenciales. Dentro de las arquitectura multicore
encontramos en el top las libreras especcas Intel R _ Math Kernel Library, CUBLAS y CULA de
CUDA R _; estan altamente optimizadas para sus respectivas arquitecturas de hardware. En general,
el uso de estos paquetes de optimizacion no son utilizadas en el desarrollo del software comercial,
excepto para la construccion de programas muy especializados o en proyectos que se encargan de
aglomerar todas estas optimizaciones como por ejemplo PLASMA (Parallel Linear Algebra Software
for Multiprocessor Architectures).
Proyectos como FLAME (Formal Linear Algebra Methods Environment) y PLASMA reejan
4 Captulo 1. Introduccion
una fuerte tendencia de encapsular y abstraer el codigo lo que facilita el trabajo del programador. En
el caso de FLAME se abstrae el hardware dando mayor portabilidad a estas aplicaciones; haciendo
transparente el hardware, lo que permite ejecutar una implementacion en cualquier arquitectura.
Ademas permite utilizar todos los recursos disponibles CPU y GPU.
Al abstraer el codigo se aumenta la dicultad para la optimizacion mas especca de las apli-
caciones. Ademas la falta de codigo fuente que pueda ser analizado y/o modicado; limita la parte
academica. Estas libreras se asemejan a las cajas negras porque no sabemos que hay dentro y
por tanto no aprendemos de ellas.
Lo anterior dicho, motiva que el presente trabajo se dirija al estudio e implementacion de los
dos pilares de los metodos iterativos, con herramientas p ublicas; con nes academicos. Esto se debe
a que el estudio de los metodos iterativos de Jacobi y Gauss-Seidel tiene nes didacticos y conforma
la base de estudio para las tecnicas modernas de metodos numericos. En la actualidad el software
especializado y la investigacion de frontera emplean metodos proyectados sobre subespacios de tipo
Krylov[1, 2, 16, 22, 38], ejemplos de software especializado son las libreras de Portable Extensible
Toolkit for Scientic computation (PETSc) con implementaciones paralelas [4, 34, 42]. El estudio
de ello esta fuera del alcance de la presente memoria.
Objetivo general
La presente tesis tiene como objetivo el desarrollo de esquemas iterativos en paralelo con
OpenMP para la solucion numerica de sistemas de ecuaciones lineales. Para ello emplearemos una
computadora con arquitectura de tipo multi-n ucleo con memoria compartida y utilizamos el lenguaje
de programacion C.
Objetivos particulares
A continuacion se listan los objetivos especcos que seran tratados durante la realizacion del
presente documento:
1. Dise nar e implementar el metodo de Jacobi y Gauss-Seidel en paralelo para resolver sistemas
de ecuaciones lineales.
2. Incrementar el rendimiento computacional mediante tecnicas avanzadas de programacion.
Captulo 1. Introduccion 5
3. Medir el desempe no de los algoritmos dise nados para cuanticar los benecios del paradigma
de programacion.
4. Medir la escalabilidad de los algoritmos dise nados en computadoras multi-n ucleo.
5. Crear un biblioteca de funciones que permitan resolver numericamente sistemas de ecuaciones
lineales en paralelo para computadoras SMP.
Al termino de la presente tesis se habran cumplido con los objetivos planteados; los cuales
pondran en evidencia los benecios mediante el incremento del rendimiento por paralelizar metodos
numericos. Con los resultados obtenidos se busca motivar la incipiente tendencia de generalizar la
programacion en paralelo.
La estructura del presente trabajo de tesis esta organizada en seis captulos que se describen a
continuacion.
En el primer captulo, el presente, se describen los objetivos que permitiran llevar a buen termino
el proceso de elaboracion de la presente memoria. Tambien se mencionan las razones que dan
importancia a este estudio.
Enseguida, en el tema 2 se plantea un marco teorico que le permita al lector familiarizarse
desde un punto de vista general, con los conceptos que se tratan durante el restos de los captulos.
Aunado a ello se realiza una breve descripcion de las tecnicas y herramientas tecnologicas que seran
utilizadas. Se indican temas de vital importancia para la evaluacion de algoritmos en paralelo como
lo son Speed-up, Ley de Amdahl y Escalabilidad paralela, as como la representacion de los n umeros
reales en la computadora. Tambien se da un breve introduccion que intuye a la comprension del
error en los metodos numericos.
En el captulo 3 tratamos uno de los problemas mas basico pero de importancia muy relevante,
el Producto matriz-vector. Se pone un especial cuidado en el estudio de este tema por representar
un proceso muy demandante de tiempo de calculo. Se emplean modernas tecnicas de programacion
como Loop unrolling y procesamiento vectorial con Intel MMX R _ para explotar nuevas caractersti-
cas de los microprocesadores; para determinar cual representa la mejor opcion en paralelo. Cabe
se nalar que en este bloque se estudia el Calculo del residual una tecnica utilizada como condicion
de paro en los esquemas iterativos.
Posteriormente en el captulo 4 se estudia el Metodo iterativo de Jacobi, en primer lugar se tratan
algunos de los metodos directos para la solucion de sistemas lineales de ecuaciones mas conocidos,
6 Captulo 1. Introduccion
Regla de Krammer, Eliminacion de Gauss-Jordan y la Factorizacion LU para determinar los pros
y contras de ambas categoras (metodos directos e iterativos). Despues se realiza una descripcion
del esquema y consecuentemente la programacion. Con el unico n de aumentar el rendimiento se
realiza una serie de optimizaciones basadas en los resultados del tema anterior. Al nal de este
captulo se realiza una evaluacion exhaustiva que arroja resultados muy concretos con respecto a
las modicaciones realizadas en cada uno de los subtemas.
En el captulo 5 tratamos el Metodo Iterativo de Gauss-Seidel (G-S), en primer lugar se da una
descripcion del metodo con vistas hacia la programacion del mismo. En segundo lugar se implementa
OpenMP prestando especial antencion en la dependencia de operaciones a las que esta sujeto G-S.
En un tercer momento se realiza una comparacion con diferencias nitas para medir convergencia
de Jacobi y G-S, lo cual permita enmarcar las diferencias teoricas de ambos.
Finalmente en el captulo 6 mostramos las conclusiones generales y el trabajo a futuro.
Captulo 2
Marco Te orico
2.1. Metodos numericos
En palabras de Chaillou [9] son las tecnicas mediante las cuales es posible formular problemas
de manera que puedan resolverse utilizando operaciones aritmeticas.
Es importante el estudio de los metodos o esquemas numericos porque representan una herra-
mienta importante para el analisis y dise no de algoritmos que permiten la resolucion de problemas
de la ciencia. Existe una extensa gama de esquemas numericos para la resolucion de gran parte de
los problemas. Sin embargo, con el mismo metodo no se puede resolver todos problemas; por ello es
indispensable el analisis de un grupo de candidatos con el n de determinar cual de ellos es el mas
indicado para el problema que se este estudiando.
Como menciona Penades [33] con la aparicion de los multiprocesadores se presenta un nuevo reto,
adecuar los antiguos algoritmos para las nuevas tecnologas; entre las que destaca la computacion
matricial. Pero esta nueva tendencia tambien sugiere y motiva la b usqueda de metodos nuevos que
se adecuen mejor a la vanguardia tecnologica con el n de aumentar el rendimiento computacional
para la resolucion de ciertos problemas.
2.2. Modelacion matematica
Una denicion muy simple es la proporcionada por Chaillou en [9] la cual dice: un modelo
matematico es una formulacion o ecuacion que expresa las caractersticas fundamentales de un
7
8 Captulo 2. Marco Teorico
sistema o proceso fsico en terminos matematicos. Esto nos indica que un modelo corresponde a
una explicacion de un proceso de un forma simple, lo cual conduce a resultados predecibles.
Los modelos matematicos sirven para obtener cierta informacion de un problema que se este estu-
diando; si bien en cierto que frecuentemente contienen errores que ponen en evidencia componentes
esenciales de una realidad compleja [9]. Existe un clasicacion de tipos de modelos matematicos en
funcion a su area de estudio; estos temas no son tratados con la profundidad necesaria debido que
no es la nalidad del presente trabajo.
2.3. Los n umeros en la computadora
En el mundo real existen varios sistemas numericos entre los que destacan los sistemas arabico,
binario, octal, hexadecimal. El mas utilizado por todo ser humano es el arabico o mejor conocido
como decimal. Por otro lado el sistema numerico de las computadoras es el binario para describir los
estados encendido (1) apagado (0); as un dgito binario o bit es la unidad de informacion mas basica
en la computadora. Debido a que los humanos utilizamos el sistema decimal y las computadoras
el binario se hizo necesario realizar conversiones de n umeros entre ellos. Fue Gottfried Leibniz
(16461716) quien desde siglos pasados lo haba resuelto. Leibniz argumento que cualquier n umero
entero puede ser representado por una serie de unos y ceros.
En documentos como [29, 37] se emplea el formato mantisa/exponente para representar n umeros
binarios tomando la idea de la notacion cientca. Como se muestra en (2.1)
10
10
= 10.0
10
10
0
= 1.0
10
10
1
= 0.1
10
10
2
1010
2
= 1010.0
2
2
0
= 101.0
2
2
1
= 10.10
2
2
2
(2.1)
El manejo de los n umeros en la computadora es mediante la notacion cientca del sistema
binario.
1
Sin embargo, los formatos que se utilizan permiten representar los n umeros como en (2.1)
sin escribir de forma explcita el punto decimal. El formato signo/mantisa/exponente se expresa
1
El sistema numerico de la computadora se debe a la arquitectura de la misma. Recordando que existen compu-
tadoras binarias, octales y hexadecimales. Las computadoras comerciales son binarias.
2.3. Los n umeros en la computadora 9
como una palabra con las siguientes caractersticas para un valor x
x =
signo
..
s e
1
e
2
e
3
. . . e
k
. .
exponente
mantisa
..
m
1
m
2
m
3
m
4
. . . m
n
(2.2)
Sabiendo que cuando el bit de s este encendido se trata de un n umero negativo. Tomando como
referencia (2.2) la longitud de la palabra que equivale a (1 + k + n) donde los valores de k y n
son denidos por el dise nador y 1 representa el bit s del signo; para denir los valores de k y n
es imprescindible pensar en la exactitud con lo que se representaran los n umero reales, as como
analizar el costo computacional que representa. Para ejemplicar tomaremos un formato de 8 bits
como sigue
x =
signo
..
b
1
b
2
b
3
b
4
. .
exponente
mantisa
..
b
5
b
6
b
7
b
8
(2.3)
Partiendo de (2.3) representemos 10
10
= 1010
2
con cuatro bits. Con el formato en cuestion
puede ser representado como sigue
x =
sig
..
0 0 0 1
..
exp
man
..
1 0 1 0 = 1010
2
2
1
= 10
10
Ahora tomando un valor mayor por ejemplo 64
10
= 1000000
2
, lo cual en notacion cientca se
expresa como 1000 2
3
y se representa como sigue
x =
sig
..
0 0 1 1
..
exp
man
..
1 0 0 0 = 1000
2
2
3
= 64
10
Para representar un n umero negativo por ejemplo 18
10
se realiza lo siguiente
x =
sig
..
1 0 1 0
..
exp
man
..
1 0 0 1 = 1 1001
2
2
2
= 18
10
Como se puede observar el valor mas grande y el menor que se pueden representar son
x
max
= 0 111 1111 = 1 1111
2
2
7
= 1920
10
x
min
= 1 111 1111 = 1 1111
2
2
7
= 1920
10
10 Captulo 2. Marco Teorico
Para exponer el formato de (2.3) ante una situacion cotidiana en el calculo intensivo tomemos
el n umero 27
10
= 11011
2
como sabemos tenemos solo cuatro bits de mantisa y este nuevo n umero
tiene 5 bits, lo cual tomamos los 4 bits mas signicativos y tenemos lo siguiente
x =
1
..
0 0 1 0
..
2
13
..
1 1 0 1 = 1 1101
2
2
2
= 26
10
Ello no es equivalente con el n umero que se trata de representar y el siguiente sera
x =
1
..
0 0 1 0
..
2
14
..
1 1 1 0 = 1 1110
2
2
2
= 28
10
Con ello es mas que evidente que no se puede representar el n umero 27 utilizando el formato de
(2.3). Pero esto no signica que sea el unico. En la gura 2.1 se ilustra los n umeros que se pueden
representar con este formato. Las lneas verticales ([) indican la posicion en la linea recta de cada
uno de los n umeros, por lo que no existen n umeros en los espacios entre las lneas. Como se puede
observan la mayor densidad de n umeros esta en los aleda nos de cero y conforme nos alejamos la
densidad disminuye.
2000 1500 1000 500 0 500 1000 1500 2000
Figura 2.1: Distribucion de n umeros enteros con formato predenido.
Bien, con el formato de (2.3) se han representado n umeros enteros pero con un aspecto impor-
tante, existen n umeros que pueden ser representados de mas de una forma lo cual no es bueno.
2
Con lo anterior se han representado n umeros enteros de una forma no ortodoxa pero nos brinda
un primer acercamiento para representar n umeros reales. Tomando la idea del formato (2.3) y con
base a Hidalgo [19, Apendice E] se realiza una modicacion simple que se expresa en (2.4)
x =
signo
..
b
1
b
2
b
3
b
4
. .
exponente
b
imp
b
5
b
6
b
7
b
8
. .
mantisa
(2.4)
donde la mantisa trata la parte fraccionaria del n umero [ver (2.1)] y b
imp
es un bit implcito que
2
Nota: con este formato se han representado n umeros enteros unica y exclusivamente para exponer el formato
mantiza/exponente y no representa el verdadero formato para la representaci on de enteros en la computadora.
2.3. Los n umeros en la computadora 11
act ua as
si 0 <exp < 7, entonces b
imp
= 1.
si exp = 0 y mantisa ,= 0, entonces b
imp
= 0.
Tambien se establece la necesidad de representar los exponentes con signo por ello se indica lo
siguiente
si 0 <exp < 7, entonces exp = exp - 3.
si exp = 0 y mantisa ,= 0, entonces exp = -2.
Con base a ello se establece que para un valor x se obtiene como sigue
x = (1)
s
2
exp3
1.mantisa para 0 < exp < 7 y
x = (1)
s
2
2
0.mantisa para exp = 0
donde exp es el valor del exponente, s el signo y [(0 : 1).mantisa] es el bit implcito (b
imp
) y el valor
de las mantisa (b
5
b
6
b
7
b
8
).
La idea anterior hace que el n umero 01011001
2
con el formato (2.4) se convierte en decimal de
la siguiente forma
x =
s=0
..
0
..
signo
exp=5
..
1 0 1
. .
exponente
b
imp
.mantisa=1.5625
..
b
imp
1 0 0 1
. .
mantisa
= (1)
0
2
53
1.5625 = 6.25
10
Ahora se convierten x
1
= 11101010
2
y x
2
= 00000110
2
a decimal como sigue
x
1
= 11101010 = (1)
1
2
63
1.625 = 13
10
x
2
= 00000110 = (1)
0
2
2
0.375 = 0.09375
10
Como se puede observar el cambiar el formato de representacion de los n umeros hace que los
valores al convertirlos a decimal sea distinto. En la gura 2.2 se ilustra la distribucion de los n umeros
representables con este formato, donde se puede observar que la densidad de la retcula cercas del
cero es muy alta. Conforme nos alejamos de cero la cantidad de n umeros representables disminuye.
12 Captulo 2. Marco Teorico
1615.0 10 5 0 5 10 15 16
Figura 2.2: Distribucion de n umeros reales con formato predenido.
Con los dos ejemplos planteados se tiene una idea mas concreta de la representacion de los
n umeros mediante una serie de bits. En ambos casos se utilizo 8 bits como longitud de palabra. Sin
embargo el resultado es distinto pero con similitudes. La mayor densidad de n umeros representables
estan cercas del cero y en los extremos existe una menor densidad. En el primer ejemplo se repre-
sentaron n umeros enteros con un rango (-1920,1920) mientras que en el segundo se representaron
n umeros reales en un rango de (-15.5,15.5). Es evidente la imposibilidad de representar la totalidad
de los n umeros con una longitud de palabra nita.
La representacion de los numeros reales (n umeros con fraccion de entero) en la computadora
fue en su momento un tema hermetico en cada una de las empresas manufactureras de las mismas.
El hermetismo era a tal grado que las empresas tenan su propio protocolo, lo que limitaba la por-
tabilidad. Como menciona Severance et al.[37] esos formatos para representar n umeros en punto
otante se enfocaron primordialmente en la exactitud y no tanto en un balance entre exactitud y
velocidad. Con base a Null et al.[29] la solucion para ello llego en 1985 por parte del Instituto de
Ingenieros Electricos y Electronicos (IEEE por sus singlas en ingles) que produjeron un estandar
para representar n umero en punto otante para simple y doble precision, el estandar se titulo IEEE
754-1985 Standard for Binary Floating-Point Arithmetic. El nuevo estandar tuvo sus inicios du-
rante el dise no del coprocesador para punto otante Intel i8087 [37]. Pasaron mas de 10 a nos para
que los grandes fabricantes adoptaran el IEEE 754 de forma generalizada en la contruccion de
computadoras.
En la gura 2.3 se ilustra como se representan dos tipos de n umeros denidos en el estandar de
IEEE. Como se puede observa el formato es signo/exponente/mantisa al igual que en el segundo
ejemplo. (A) es un formato que en el lenguaje de programacion C se le conoce como oat donde
se tienen 23 bits de mantisa y 8 de exponente. (B) corresponde la primitiva double en el lenguaje
de programacion C que corresponde a 52 bits de mantisa y 11 bits; es mas com unmente conocido
como doble precision cientca.
Seg un Severance et al.[37] en precision simple el menor n umero normalizado es 1.2E-38 y
2.3. Los n umeros en la computadora 13
Figura 2.3: Modelo para representacion de n umeros en punto otante IEEE 754.
2.2E-308 con doble precision. Mientras que el n umero mas grande para simple y doble es 3.4 E+38
y 1.8 E+308 respectivamente. Ello nos brinda un marco de trabajo mas amplio y con errores mas
peque nos.
Con base en Null y Severace [29, 37] este estandar incorpora NaNs (Not a Number, no es
n umero) cuando el exponente sea igual a 255 y la mantisa no sea cero (exp = 255 y mantisa ,= 0),
los NaNs son utilizados como indicadores de error. Tambien incluye dos innitos ( y +) que
se presentan cuando el exponente es 255 y la mantisa es 0, positivo cuando el signo es 0 y negativo
cuando es 1. Al igual que en el caso de innito, se tienen dos ceros uno positivo y otro negativo.
En el presente documento se utilizan n umero de precision simple como el formato (A) de la gura
2.3 mientras no se indique lo contrario. Como se ha especicado ese formato tiene una longitud de
32 bits para la representacion de los n umeros por lo cual se pueden representar la siguiente cantidad
de n umeros (n)
n = 2
32
= 4 294 967 296
De acuerdo con la deniciones anteriores para el caso donde el exponente es igual a 255 todos
los n umeros son considerados NaNs, excepto cuando la mantisa es 0; este caso se presenta dos veces
para y + respectivamente. Con base a ello podemos obtener la cantidad de NaNs que se
representan
NaNs = 2 2
23
2 = 16 777 214
Para obtener el total de n umero representables con precision simple sustraemos lo NaNs del
14 Captulo 2. Marco Teorico
total n
Total de reales representables = 4 294 967 296 16 777 214 = 4 278 190 082
De antemano sabemos que existe una diferencia entre el cero y el primer n umero que puede ser
representado, haciendo el n umero mas peque no posible tendremos el menor n umero distinto de cero
que puede ser representable como sigue
x =
signo
..
0
exponente
..
000 0000 0
mantisa
..
000 0000 0000 0000 0000 0001
2
= (1)
0
2
126
2
23
= 2
149
x 1.4 10
45
Como menciona Nakamura [28] al n umero representable inmediatamente despues de la unidad se
le conoce como el epsilon de la computadora el cual nos permite calcular el n umero real representable
inmediatamente posterior; esto se obtiene al multiplicar el epsilon por el real y sumarlo a ese real.
Para calcular el epsilon se puede utilizar el fragmento de codigo de la gura 2.4. En ese codigo solo
hace falta indicar el tipo de variable que es epsilon (simple o doble). El ultimo valor impreso
corresponde al epsilon de la computadora. Para una ejecucion con precision simple (float) se tiene
epsilon 1.1921 10
7
, en el otro caso (double) epsilon 2.2204 10
16
. Cabe se nalar que el
denominador para calcular el epsilon es dos porque la computadora empleada es binaria.
Calculo del epsilon
epsilon = 1;
while(1+epsilon>1)
{
printf("%f\n",epsilon);
epsilon = epsilon/2;
}
Figura 2.4: Calculo de epsilon de la computadora.
Para corroborar que efectivamente el epsilon de la computadora sirve para calcular la distancia
entre un n umero real representable y su inmediatamente consecuente tomaremos el siguiente ejemplo
x
1
=
signo
..
0
exponente
..
000 0000 1
mantisa
..
100 0000 0000 0000 0000 0000
2
= (1)
0
2
1127
1.5
x
1
= (1)
0
2
126
1.5 1.7632415262 10
38
2.3. Los n umeros en la computadora 15
Ahora multiplicamos x
1
por el epsilon para obtener la diferencia (y) tomando mas cifras signi-
cativas para disminuir el error
x
1
1.7632415262 10
38
y epsion = 1.1921 10
7
y = x
1
epsilon
y 1.7632415262 10
38
1.1921 10
7
y 2.1019602234 10
45
x

2
= x
1
+ y = 1.7632415262 10
38
+ 2.1019602234 10
45
x

2
= 1.7632417364 10
38
Posteriormente se calcula el valor para x
2
tomando el siguiente n umero de la serie como sigue
x
2
=
signo
..
0
exponente
..
000 0000 1
mantisa
..
100 0000 0000 0000 0000 0001
2
= (1)
0
2
1127
1.5 + 2
23
x
2
1.7632416664 10
38
Con estos resultados podemos decir que x

2
= x
2
, donde el error se debe en gran medida a la
cantidad de cifras signicativas tomadas en cuenta. Con base a los temas anteriores es concluyente
que la distancia entre un n umero representable y su inmediatamente posterior crece conforme se
aleje de cero.
Figura 2.5: Rango de n umero IEEE-754 precision simple.
En la gura 2.5 se muestra el rango en el cual podemos representar n umeros con el estandar
IEEE-754. Siempre pensando que la mayor densidad de n umeros estan aleda nos al cero. Visualizar
el rango nos permite mapear los n umeros para no caer en valores underow u overow e inclusive
elegir el tipo de precision con la nalidad de tener una mayor exactitud.
La incapacidad para poder representar la totalidad de los n umeros conlleva a tener resultados
16 Captulo 2. Marco Teorico
numericos aproximados. Ella es como una enfermedad con la que se nace; sino es tratada puede ser
letal.
2.4. Tipos de error en metodos numericos
En analisis numerico un tema de vital importancia es el estudio del error en un resultado
numerico. Esto se debe principalmente a que los datos de entrada no son exactos; tambien inuye que
los metodos numericos introducen errores de varios tipos; por ello los resultados son aproximados.
Como menciona Chaillou [9] en muchos casos profesionales los errores son costosos y en algunos
letales. A continuacion se presentan los principales errores introducidos por los esquemas numericos.
Error de redondeo: este tipo de error se presenta debido a la cantidad de cifras signicativas
que se asignan para las operaciones. En terminos de computacion este error es muy com un y
depende de la exactitud de la primitiva utilizada (precision simple, doble precision, etc.), para
la representacion de los n umeros reales en la maquina. Para tener una idea mas clara tomemos
en cuenta un n umero real x con k cifras en punto otante, lo cual se representa como
x = 0.d
1
d
2
. . . d
k
B
n
donde B es la base del sistema
dado que unicamente se tienen t cifras signicativas, siendo t < k, el n umero real sera repre-
sentado como sigue
x = 0.d
1
d
2
. . . d
t
B
n
con ello se han perdido k t cifras del valor real de x con lo cual x es una aproximacion de
x. A continuacion se muestra un ejemplo
x = 1.2345678 con t = 4 se tiene x = 1.2345
Este error es inherente a la computacion como consecuencia de la imposibilidad de representar
totalmente los n umeros reales. Para disminuir este error se aumenta el tama no de la mantisa
de bits (aumentar k), as se tendran mas cifras para la representacion de los n umeros; pero
ello repercutira en un aumento en el costo de calculo.
Error por truncamiento: este tipo de error aparece como consecuencia de las reglas de cifras
2.4. Tipos de error en metodos numericos 17
signicativas que se establezcan, donde a partir de t cifras el valor se redondea al extremo
proximo. Por ejemplo tomando tres cifras signicativas (en punto otante) de x para obtener
x como sigue
x
1
= 23.333333 se redondea a x
1
= 23.333
x
2
= 23.333690 se redondea a x
2
= 23.334
En problemas aplicados a metodos numericos el error de truncamiento surge al truncar una
serie de operaciones. Citando textualmente a Nakamura [28] el error de truncamiento se debe
a las aproximaciones utilizadas en la f ormula matematica del modelo. Un claro ejemplo de ello
es la Serie de Taylor para mostrarlo veamos la expresion de esta serie
f(x + h) = f(x) + hf

(x) +
h
2
2!
f

(x) +
h
3
3!
f

(x) + +
h
m
m!
f
(m)
(x) + (2.5)
En la practica se trunca (2.5) debido a que es imposible utilizar un n umero innito de terminos.
A continuacion se representa una serie truncada de Taylor hasta despues del termino de orden
m
f(x + h) = f(x) + hf

(x) +
h
2
2!
f

(x) +
h
3
3!
f

(x) + +
h
m
m!
f
(m)
(x) + O(h
m+1
) (2.6)
donde O(h
m+1
) representa el error por el truncamiento.
La Serie de Taylor representa un punto de partida para la obtencion de metodos numericos.
En el polinomio de Taylor (2.6) el error de truncamiento se reducira conforme m .
Como menciona Nakamura [28] calcular el valor exacto del error de un polinomio de Taylor es
practicamente imposible es por ello que se representa con una aproximacion que corresponde
O(h
m+1
). En general el error de truncamiento nace al representar una serie innita con otra
serie nita de operaciones.
Error absoluto: este error corresponde a la diferencia absoluta entre un resultado exacto y
otro aproximado. Esto se representa como
EA = [x x[ (2.7)
18 Captulo 2. Marco Teorico
donde x es el resultado exacto y x es el aproximado.
Error relativo: consiste en normalizar el error respecto al resultado exacto. Lo cual se expresa
como
ER =
[x x[
[x[
(2.8)
donde x es el resultado exacto y x es el aproximado. Si multiplicamos el error relativo por
cien se obtiene el error porcentual del resultado aproximado.
2.5. El lenguaje de programaci on C
El lenguaje C es de alto nivel pero mantiene caractersticas de bajo nivel. De alto nivel porque
es estructurado, facil de aprender pero mas que nada racional[15]. Y de bajo nivel porque permite
trabajar con el lenguaje maquinas los bits, registros de la CPU y registros de memoria. Algunas de
las caractersticas son la siguientes tomadas del libro de Basurto et al.[6]:
Potencia y exibilidad: C es un lenguaje no tan alejado del lenguaje maquina lo cual
puede traducirse en un mejor desempe no computacional. Otro punto a favor del lenguaje es
la exibilidad para la creacion de aplicaciones que van desde modestas aplicaciones de consola
a robustos sistemas operativos gracos como UNIX y sus derivados.
Popularidad: como la mayora de los grandes proyectos, el lenguaje C debe su popularidad
a la variedad de recursos como compiladores, herramientas y libreras.
Portabilidad: gracias al estandar ANSI C un programa escrito en C puede ser compilado y
ejecutado en diferentes arquitecturas con pocos o nulos cambios.
Sencillez: el lenguaje C es muy facil de aprender por contar con un n umero muy reducido de
palabras reservadas.
Estructura y modularidad: C es el primer lenguaje de programacion bien estructurado
que permite la agrupacion de codigo en funciones; que posteriormente puede ser reutilizado.
El conjunto de cualidades anteriormente descritas coadyuvan para que este lenguaje cuente
con el soporte de varias interfaces que permitan la programacion en paralelo y juntos sean una
herramienta importante para el computo cientco.
2.6. Programacion en paralelo 19
En el presente documento se utiliza lenguaje C en su totalidad. Esto se debe a las caractersticas
que son sencillez y racional para la creacion de codigo; as como la exibilidad en el manejo de
vectores y matrices mediante los apuntadores. La compatibilidad de C con la API OpenMP es el
motivo principal por el cual se utiliza este lenguaje de programacion. Cabe se nalar que FORTRAN
es otro lenguaje compatible con esta API; no se utilizo en este trabajo porque se tena un mejor
dominio del lenguaje C.
2.6. Programaci on en paralelo
Como menciona Pacheco [31] de 1986 a 2002 el incremento del rendimiento en los micropro-
cesadores fue de 50 % por a no; el aumento de la velocidad de los procesadores estuvo sujeta a la
densidad de transistores del circuito integrado, cada a no se aumentaba en ese mismo porcentaje.
Como menciona Petersen et al.[34] esto se debe a una ley formulada por Gordon Moore (uno de
los fundadores de Intel) en 1965 conocida como ley de Moore: el incremento de la velocidad de los
procesadores debera ser duplicada cada dos a nos. Por problemas de dise no ya es imposible continuar
con esa tendencia, por lo cual en el lapso de 2002 a 2005 el aumento de la velocidad se redujo a
20 % anual.
Para 2005 la industria de microprocesadores acordo incrementar el rendimiento con un cambio
en el dise no; se eligio el camino del paralelismo. Esto consiste en dejar de construir procesadores
monolticos mas rapidos; para centrarse en la construccion de circuitos integrados que contengan
varios procesadores completos. Con base a Petersen et al.[34] actualmente las computadoras con
multiprocesadores y el desarrollo de algoritmos suman un mayor aumento en el rendimiento que el
establecido en la ley de Moore; esto habla del poder que le dota al computo esta tendencia. Con las
medidas tomadas por los industriales se puede cumplir con las nuevas demandas de rendimiento en
las diferentes areas que lo requieran.
Las nuevas tendencias en la contruccion de hardware paralelo representa un nuevo reto para
los programadores, la realizacion de software capaz de explotar las nuevas caractersticas de estos
recursos electronicos. En la actualidad la mayora del software en el mercado es serial; ello indica
que esas aplicaciones unicamente explotan una fraccion de los recursos de la computadora.
Durante la realizacion de este trabajo se ha observado una fuerte tendencia en la programacion
de aplicaciones paralelas, estos programas son divididos en m ultiples instancias tantas como n ucleos
20 Captulo 2. Marco Teorico
contenga el sistema. Ello con la nalidad de presentar resultados en el menor tiempo posible.
Durante la traduccion de aplicaciones seriales a paralelas nos encontramos con problemas de
adaptacion de algoritmos y/o modelos; como menciona Pacheco [31] un algoritmo serial eciente
puede convertirse en uno paralelo ineciente. Por ello la tarea de los programadores para traducir
programas secuenciales en paralelos es difcil.
La programacion en paralelo esta inuenciada directamente por la tendencia del desarrollo de
hardware denotada por la construccion de sistemas fsicos. Para la programacion en el lenguaje
estructurado C existen tres alternativas principales; Message-Passing Interface (MPI, Interfaz de
Paso de Mensajes), POSIX threads (Pthreads) y OpenMP. El primero de ellos esta orientado a
la programacion paralela para memoria distribuida. Los otros dos son utilizados en sistemas con
memoria compartida, como diferencia Pthreads al igual que MPI son libreras y deniciones que
se usan dentro de programas mientras que OpenMP esta constituido por una librera y algunas
modicaciones al compilador. Como menciona Petersen et al.[34] OpenMP es mas facil de programar
e implementar que Pthreads.
En tiempo mas reciente ha surgido un tipo de computo distinto que consiste en utilizar la
tarjeta graca (GPU) para resolver operaciones aritmeticas. Un ejemplo de ello es la interfaz de
programacion CUDA propiedad de la empresa Nvidia, esto revoluciona la fabricacion de hardware
en la cual se incluyen miles de procesadores. Cada uno de ellos tiene mucho menores prestaciones
de procesamiento que un CPU; sin embargo, juntos le permiten al GPU desarrollar un incremento
sustancial de rendimiento comparable e inclusive mejor que la CPU. Al igual que las tres tecnologas
antes mencionadas CUDA trabaja con memoria compartida y distribuida. Una de sus opciones
programables es mediante el lenguaje C++. Con base al manual de Nvidia CUDA [30] el modelo de
programacion de CUDA esta enfocado al paralelismo masivo, el dise no del hardware permite lanzar
miles de hilos de ejecucion a la vez. En la gura 2.6 extrada de [30, g.1-3 pag.3] se ilustra las
diferencias en la construccion de los dispositivos. En el caso de la CPU se cuenta con pocas unidades
de procesamiento pero con mayores capacidades y requiere mucho control y mucha memoria cache.
Por otra parte en la GPU se tiene una mayor cantidad de unidades de procesamiento con poco
control y poco cache; esto es lo que permite la ejecucion de miles de hilos a la vez. La principal
desventaja de CUDA es el marco de ejecucion que solo se limita a dispositivos compatibles de la
marca Nvidia, lo cual limita la popularidad en el uso de esta API. Cabe se nalar que un proyecto
2.7. OpenMP 21
encabezado por la marca norteamericana Apple llamado OpenCL permite la portabilidad de codigo
que utilice la GPU; mediante la compilacion en tiempo de ejecucion.
Figura 2.6: Arquitectura de hardware CPU versus GPU.
En la gura 2.7 se ilustran las arquitecturas de memoria compartida y distribuida respectiva-
mente; en (A) todos los cores-n ucleos del sistema acceden a una misma memoria principal, con
ello todas las unidades de procesamiento pueden acceder a localidades de memoria donde otra uni-
dad esta trabajando. Cabe se nalar que la memoria principal es de tipo UMA (Memoria de Acceso
Uniforme) que permite una comunicacion intensiva entre los procesos que son ejecutados en los
diferentes n ucleos. En (B) se muestra un sistema con memoria distribuida, los cuales estan carac-
terizados porque cada una de las unidades-nodos de procesamiento tienen su propia memoria tipo
UMA, pero tambien pueden acceder a la memoria de cualquier otro nodo. Es preciso indicar que
es muy costo acceder a la memoria de un nodo desde otro en terminos de tiempo. A esto se debe
la barrera tecnida para no crear secciones de aplicacion que mantenga una comunicacion intensa
siempre y cuando las secciones sean ejecutadas en nodos diferentes. En este tipo de aplicaciones es
muy importante el papel que jugara el sistema de interconexion de nodos puesto que es un enorme
cuello de botella para el acceso a la memoria distribuida, generalmente se utiliza la bra optica.
Hasta este punto se han mencionado algunas de las principales tendencias y caractersticas de la
programacion en paralelo. Ademas se indican los motivos por los cuales este paradigma representa
el futuro de la computacion de alto desempe no.
2.7. OpenMP
Como menciona Chapman et al. [11], OpenMP es una Interfaz de Programacion de Aplicaciones
(API) cuyas caractersticas, se basan en esfuerzos anteriores para facilitar la programacion paralela
22 Captulo 2. Marco Teorico
Figura 2.7: Tipos de memoria en sistemas.
de memoria compartida. Las siglas MP denotan multiprocessing (multiproceso) lo cual es un
sinonimo de programacion paralela de memoria compartida.
OpenMP es un acuerdo alcanzado entre los miembros de la Architecture Review Board (ARB)
para dar un enfoque portatil, facil de usar y ecaz a la programacion paralela de memoria compar-
tida. Al contrario de lo que se puedra pensar OpenMP no es un lenguaje de programacion nuevo;
por el contrario es la notacion que se puede agregar a un programa secuencial en Fortran, C o C++,
a las cuales se le denomina directivas o pragmas que son instrucciones pre-procesador.
Una implementacion adecuada de OpenMP en un programa permitira a las aplicaciones bene-
ciarse de la memoria compartida de las arquitecturas paralelas. En ocasiones con pocas modicacio-
nes al codigo se convierte una aplicacion serial en una paralela; en la practica muchas aplicaciones
tiene un cierto grado de paralelismo que debe ser explotado. Como menciona Chandra et al.[10],
todos los proveedores de computadoras de memoria compartida de alto desempe no soportan la fun-
cionalidad de OpenMP, pero la portabilidad de aplicaciones ha sido casi imposible de alcanzar.
Desde un punto de vista general, una aplicacion serial se convierte en paralelo simplemente
incluyendo una directiva de OpenMP. Estas directivas van desde constructores de hilos hasta la
sincronizacion de los mismos para el acceso a los datos compartidos. Pero un punto muy importante
es que en la directiva se indica el tipo de reparto de las cargas de trabajo.
OpenMP utiliza el modelo fork-join, el cual consiste en que la ejecucion de un programa inicia
con un hilo llamado maestro. Cuando el proceso llega a una directiva se crea una region paralela con
las especicaciones de la misma. La zona paralela se ejecuta sobre un mismo espacio de direcciones
lo cual permite compartir las variables declaradas, pero tambien declarar informacion privada [10,
2.7. OpenMP 23
Figura 2.8: Modelo de OpenMP.
11, 31, 34]. Al nalizar la fraccion paralela los hilos esclavos se destruyen y continua la ejecucion
del hilo maestro.
En la gura 2.8 se ilustra la ejecucion de un programa con una region paralela. Cuando el hilo
maestro llega al inicio (etapa fork) de esta zona se crean los hilos esclavos y se declaran la variables
locales de la zona. Posteriormente se realiza el reparto de cargas de trabajo, para que todos los
subprocesos ejecuten el mismo codigo. Despues de nalizar la ejecucion se destruyen las variables
locales de la region paralela y todos los hilos acepto el maestro; es la etapa join. Al nalizar la region
paralela, el proceso continua una ejecucion serial; si mas adelante existiese otra region paralela el
proceso se repite con las condiciones de la nueva directiva.
Soporte de compiladores
La norma industrial OpenMP es soportando por una gran variedad de compiladores; la mayora
de ellos con nes comerciales. Algunos ejemplos de ellos son: el compilador Oracle C/C++/Fortran
de Sun Microsystems Inc, el gigante de los procesadores Intel ofrece su compilador para Windows y
Linux con el nombre de Intel C/C++/Fortran, por su parte Microsoft brinda el soporte en Visual
C++ en su version comercial entre otros.
3
Tambien existe el compilador GNU GCC que brinda
soporte para el API de forma gratuita el cual es propiedad de la comunidad de codigo abierto de
GNU Project. Por tratarse de un estandar nos garantiza que el codigo no debe ser re-escrito cuando
cambiemos el compilador.
El compilador GCC implementa OpenMP en la version 4.2.1 o posteriores. En su version 4.3.2
3
La lista completa de compiladores que soporta OpenMP puede ser consultada en el sitio ocial
http://www.openmp.org.
24 Captulo 2. Marco Teorico
(Agosto de 2008) comenzo a implementar OpenMP v3.0.
4
. Las nuevas versiones de GCC las encon-
tramos pre-cargadas en la mayora de las distribuciones Linux (recientes) por ello se convierte en el
mas accesible. Por estas cuestiones los resultados que se muestren en la presente tesis corresponde
a codigo compilado con GCC v4.2.1.
Como se menciona en el manual ocial de GNU GCC v4.2.4 [40] el compilador lleva este nombre
por GNU Compiler Collection donde se engloba la posibilidad de compilar codigo en lenguajes
C, C++, Objective-C, Objective-C++, Java, Fortran y Ada. GCC cuenta con un gran n umero
de optimizacion para aumentar el rendimiento de las aplicaciones conocidas como banderas de
compilacion, las especicaciones tecnicas de estas banderas no son tratadas en el presente trabajo.
Para la evaluacion de algoritmos paralelos se utilizan varios parametros entre los cuales destacan
el La ley de Amdahl, speed-up y el rendimiento computacional. En los temas siguientes se dara una
breve explicacion para llenar el contexto.
2.8. Escalabilidad paralela
La Escalabilidad paralela (Parallel Scalability) es el comportamiento de una aplicacion cuando
un creciente n umero de hilos (threads o subprocesos) se utilizan para resolver un problema de tama no
constante. Idealmente, aumentar el n umero de hilos de 1 a P dara un aceleramiento paralelo (speed-
up) de p [11]. Como menciona Pacheco [31] se dice que un programa es escalable si al aumentar el
n umero de hilos la eciencia persiste. Para denir este punto, en primer lugar se toma la ecuacion
de la eciencia E
E =
T
1
p T
p
=
S
p
(2.9)
donde T
1
es el tiempo de ejecucion con un n ucleo, p es el n umero de procesadores, T
p
representa
el tiempo de ejecucion para p-hilos y S es el speed-up (2.13). En base a lo anterior supongamos que
aumentamos k veces el n umero de procesadores con lo cual se tiene
E
kp
=
T
1
kp T
kp
=
S
kp
kp
(2.10)
Con base a (2.9) y (2.10) podemos determinar si un programa es escalable si E = E
kp
. Tomando
como idea principal que un programa no puede ser paralizado de forma completa. Idealmente,
4
Esta informacion con base la documentaci on del sitio web ocial http://gcc.gnu.org/gcc-4.3/
2.8. Escalabilidad paralela 25
pensamos que la reduccion en tiempo de ejecucion es proporcional al aumento de hilos-procesadores,
en la practica no es com un que se presente la proporcionalidad, el principal obstaculo es el acceso a
memoria ya que esta se encuentra compartida para todos los hilos, y por ende, se da una competencia
para el uso de la misma. Aunado a ello estas lo costos derivados por la sincronizacion y en general por
el manejo de las regiones paralelas. Existen ocasiones donde aumentar el n umero de hilos se torna
contraproducente, se dice que la aplicacion tiene un lmite de hilos, y a partir de aqu, aumentara el
tiempo de ejecucion conforme aumentemos la cantidad de hilos.
Para la evaluacion de la escalabilidad de la aplicacion se utilizan dos metodos: el primero Ley
de Amdahl el cual no pone en un contexto real de la escalabilidad teorica que se puede obtener.
En segundo tenemos el speed-up el cual mide las veces que es mas rapido un algoritmo paralelo con
respecto al serial. Mientras tanto el desempe no computacional mide la cantidad de operaciones por
segundo de un programa. En los siguientes temas se desarrolla cada uno de ellos.
2.8.1. Ley de Amdahl
Como menciona Pacheco [31] fue desarrollada por Gene Amdahl en la decada de 1960.

Esta ley
indica que un programa serial solo se puede paralelizar una fraccion; ello limitara muy signicati-
vamente el speed-up; independientemente del n umero de unidades de procesamiento.
La ley plantea la carencia de poder paralelizar un algoritmo serial de forma completa. Solo
podemos hacer paralelo una fraccion del codigo. Mientras mas grande sea la fraccion paralela, el
speed-up sera mayor para un n umero creciente de procesadores; sin embargo, no siempre sera posi-
tivo aumentar la cantidad de hilos.
En la gura 2.9 se ilustra la ejecucion de un fragmento de programa con una seccion en paralelo.
En ella se describe lo siguiente: en un principio el hilo maestro inicia la ejecucion y crea la region
paralela. En la region paralela los hilos esclavos ejecutan el proceso, al nalizar se destruyen los
hilos. Finalmente el hilo maestro continua con la ejecucion.
La ley de Amdahl nos permite calcular el speed-up maximo S
p
como
S
p
=
1
(1 F) +
F
p
(2.11)
donde F es la fraccion de tiempo secuencial y p el n umero de procesadores, entonces (1 F)
representa la fraccion serial del programa.
26 Captulo 2. Marco Teorico
Figura 2.9: Modelo de ejecucion de programas paralelos.
Tomando un programa que se ejecuta como el de la gura 2.9 donde la region paralela es
F = 80 % del total de calculo. Con base a (2.11) se calcula el speed-up maximo (S
p
) para 2
procesadores (n = 2) como sigue
S
p
=
1
(1 0.8) +
0.8
2
=
1
0.2 + 0.4
= 1.66x
Ahora supongamos que otro codigo es altamente paralelizable F = 95 %, a continuacion se
calcula el nuevo S
p
para este nuevo codigo
S
p
=
1
(1 0.95) +
0.95
2
=
1
0.05 + 0.475
= 1.90x
Si calculamos el speed-up maximo para 4, 5, 8, 16, 32 procesadores para los dos ejemplos
anteriores se obtiene la graca de la gura 2.10.
En la gura 2.10 se ilustra el speed-up de dos programas con 95 % y 80 % de paralelismo y son
comparados con el speed-up ideal. Para un n umero reducido de procesadores ambos estan cercanos
al teorico; pero conforme el n umero de procesadores aumentan el speed-up de los dos programas
empeora muy drasticamente. El speed-up que se puede esperar de un programa 95 % paralelo para
2.8. Escalabilidad paralela 27
5 10 15 20 25 30
5
10
15
20
25
30
Numero de procesadores
s
p
e
e
d

u
p


Ideal
95%
80%
Figura 2.10: Speed-up con Ley de Amdahl.
mas de 16 procesadores es muy pobre. Para otro 80 % paralelo practicamente su lmite son 16
procesadores.
Con el paso del tiempo la Ley de Amdahl se volvio obsoleta y fue Gustafson quien la revalido a
nales de la decada de 1980[20]. La version moderna de la ecuacion de esta ley en (2.12)
S
max
=
1
(1 F) +
F
S
(2.12)
donde lo unico que cambia es S que representa un speed-up. Cabe se nalar que conforme S se
aproxime a innito (S ) se redondea el denominador de (2.12) quedando 1/(1 F).
2.8.2. Incremento de velocidad (speed-up)
El incremento de velocidad (speed-up), es la proporcion del tiempo de reloj para la ejecucion
del programa en un hilo y el tiempo de reloj para la ejecucion del mismo programa en varios hilos.
Teoricamente, debe ejecutar un programa en P-hilos, P veces tan rapido como se ejecute en un
hilo[11]. En la literatura existente cuando se reere a este tema se utiliza el termino speed-up, este
documento no sera la excepcion.
28 Captulo 2. Marco Teorico
Con base a lo ya mencionado se dene a speed-up como sigue
S =
T
1
T
p
(2.13)
donde S representa el speed-up, T
1
el tiempo de ejecucion para un procesador y T
p
el tiempo que
tarda la misma aplicacion en P-procesadores. La medida del speed-up es adimensional. Por ejemplo,
si una fraccion de codigo seriado (T
1
) dura 10 segundos, despues cuando ese codigo se ejecuta en
forma paralela con dos procesadores (T
2
) dura 5.5 segundos. El speed-up que se tiene es el siguiente
S =
10
5.5
= 1.8x
Ahora si aumentamos el n umero de procesadores a cuatro y tiene un tiempo de ejecucion (T
4
)
de 3 segundos, el speed-up entonces sera
S =
10
3
= 3.3x
Con los ejemplos anteriores se representa el proceso para determinar la aceleracion de ejecuciones
paralelas. En ninguno de los casos anteriores se llega al speed-up teorico 2 y 4 respectivamente. En
temas siguientes se indica el motivo por el cual no se llega a ello.
Cuando se programa en paralelo siempre se busca alcanzar la proporcionalidad entre el aumento
de la velocidad respecto al n umero de hilos, no siempre se alcanza dicha meta debido a los proble-
mas de acceso a memoria, los cuales depende del dise no de cada computadora. Es por ello que es
conveniente cuidar la implementacion del codigo a n de obtener una mayor velocidad cuando se
cambie el n umero de hilos.
2.8.3. Desempe no computacional
El desempe no o rendimiento computacional (en la literatura tambien se le conoce como perfor-
mance) se mide por las operaciones en punto otante por segundo. Como menciona Null et al.[29]
la metrica para el rendimiento es el FLOPS (oating-point operations per second, operaciones en
punto otante por segundo). Para calcular el desempe no se divide el n umero de operaciones n entre
2.8. Escalabilidad paralela 29
el tiempo empleado t.
FLOPS =
n
t
(2.14)
Con las nuevas prestaciones que ofrecen las computadoras la cantidad de FLOPS es algo difcil
de manejar. Por ello se utilizan unidades de medida de FLOPS que se indican en la tabla 2.1.
Tabla 2.1: Unidades de medida de FLOPS
Nombre de la unidad Valor
KiloFlop 10
3
MegaFlop 10
6
GigaFlop 10
9
TeraFlop 10
12
PetaFlop 10
15
ExaFlop 10
18
ZetaFlop 10
21
YottaFlop 10
24
Para obtener directamente una de las unidades de la tabla 2.1 de (2.14) basta con hacer lo
siguiente
K FLOPS =
n
t 10
e
(2.15)
donde e corresponde al exponente de la unidad, por ejemplo e = 9 si calculamos GigaFlops. Ello se
muestra a continuacion
GigaFlops =
n
t 10
9
FLOPS es una unidad generalizada para mostrar resultados de rendimiento. En la presente
tesis se muestran todos los resultados de rendimiento utilizando esta unidad de medida. Para los
nes de la presente tesis unicamente se utilizan para evaluar los algoritmos paralelos el desempe no
computacional y el speed-up.
Con los temas que se han tratado durante el presente captulo se establece un fundamento
teorico lo cual se puede resumir. Los metodos numericos estas inuenciados por las computadoras,
lo cual requiere de analisis y modelacion matematica que permitan adaptar el esquema al tipo de
problema en cuestion. Las nuevas generaciones de computadoras multin ucleo permiten la ejecucion
de aplicaciones paralelas; ello conlleva que se dise nen nuevos algoritmos que puedan explotar estas
nuevas caracterticas.

Estos nuevos algoritmos deben ser ecientes para ellos son evaluados a n de
30 Captulo 2. Marco Teorico
determinar su desempe no computacional as como su speed-up. A diferencia de los n umero reales
idealmente conocidos, en las computadoras la cantidad de n umeros es limitada y su distribucion
en la lnea recta no es uniforme. Debido al metodo numerico elegido y a la representacion de los
n umeros en la computadora nace el error numerico en los problemas de analisis numerico, ademas
de las propias contemplaciones hacia el resultado por parte quien implementa el metodo.
Captulo 3
Producto matriz-vector Ax
La multiplicacion de una matriz y un vector, es una operacion simple que resuelve un problema
basico, pero importante [11]. La cual se presenta de forma frecuente en esquemas iterativos como lo
son el metodo de Jacobi y el de Gauss-Seidel, por mencionar algunos. Estos metodos son tratados
en captulos siguientes.
Durante este captulo se describen formas distintas para resolver Ax utilizando la computadora;
se nalando los pro y contras de cada una de ellas. Para ello se exhibe el rendimiento en speed-up y
Mops
1
con el n de mostrar numericamente cual de ellos es el mejor procedimiento para codicarla.
En la primera seccion se denen conceptos basicos para comprender el problema. Como se realiza
el producto entre una matriz y un vector, cuales son la normas que deben cumplirse para que se
pueda realizar.
En el segundo apartado se da una breve introduccion a un tecnica de optimizacion de ciclos
conocida como Loop unrolling, la cual es utilizada para optimizar el producto de una matriz por
un vector.
Se estudia el calculo del residual en la seccion tres, lo cual resulta ser un tema interesante, es
utilizado como condicion de paro en metodos iterativos. El residual es la diferencia que existe entre
la solucion exacta y una aproximada.
La implementacion canonica se realiza en la cuarta parte del captulo.
En las secciones cinco y seis se realizan distintos procedimientos de optimizacion, para mejorar
1
ops (oating-point operations per second, operaciones en punto otante por segundo) es una unidad de medida
para el desempe no de una aplicaci on. Mops denota que es un millon de ops (10
6
).
31
32 Captulo 3. Producto matriz-vector Ax
el desempe no de la aplicacion. En primer lugar, es utilizada la tecnica de Loop unrolling para
optimizar el bucle. En segunda instancia, se optimiza a nivel de datos con la Tecnologa SIMD de
Intel
R _
. Al nal de esta quinta seccion se combinan ambas (Loop unrolling y SIMD) para exponer
el resultado que se presenta al combinarlas.
En la actualidad la gran mayora de las computadoras disponibles en el mercado, tienen mas de
un procesador. En computo es importante explotar todos los recursos de manera eciente. Lo que
nos lleva a realizar aplicaciones que aprovechen el multin ucleo, es decir, puedan ser ejecutadas en
varios procesadores de forma simultanea, esta tarea se lleva a cabo en el septimo apartado.
Por ultimo se muestran los resultados obtenidos tras las optimizaciones realizadas. Ello con la
nalidad de establecer la mejor opcion para implementarla en los metodos iterativos de los captulos
siguientes.
3.1. Concepto
El producto de una matriz y un vector es un operacion simple que resuelve un problema basico
pero importante [11]. En esta seccion se presenta la multiplicacion de una matriz por un vector
desde un punto de vista matematico.
Antes de adentrarse es preciso denir lo que son las matrices y los vectores. Un vector no es
mas que un conjunto ordenado de n umeros uniformemente espaciados, en el area de informatica se
le conoce como arreglo unidimensional. Existen vectores de tipo columna y renglon dependiendo de
la orientacion del mismo. A continuacion se representa un vector de orden n.
X = [x
1
, x
2
, . . . , x
n
]
T
(3.1)
En la ecuacion (3.1) se describe un vector renglon, tomando ese ejemplo para convertirlo a uno
de tipo columna solo resolvemos la transpuesta del mismo. A continuacion se ilustra lo mencionado.
X =
_

_
x
1
x
2
.
.
.
x
n
_

_
(3.2)
3.1. Concepto 33
Una matriz es un arreglo rectangular de n umeros con m las y n columnas, o dicho de otra forma
una matriz es un arreglo bidimensional [28]. A continuacion se muestra la representacion general de
cualquier matriz.
A =
_

_
a
1,1
a
1,2
a
1,n
a
2,1
a
2,2
a
2,n
.
.
.
.
.
.
.
.
.
.
.
.
a
m,1
a
m,2
a
m,n
_

_
(3.3)
En (3.3) se describe la forma general para representar una matriz de m-renglones y n-columnas,
decimos que es una matriz de m n. En este documento unicamente se abordaran matrices cuyo
n umero de renglones es equivalente al de columnas. A este tipo de arreglo bidimensional se le conoce
como matriz cuadrada, a consecuencia cuando se mencione una matriz se supondra que es cuadrada;
mientras no se indique lo contrario.
Para llevar a cabo la multiplicacion de una matriz por un vector se requiere cumplir con dos
condiciones. La primera es que el vector tenga la forma de (3.2), es decir, sea un vector de tipo
columna o vertical. Tomando a (3.3) y (3.2), el orden del vector (n umero de renglones) debe ser
exactamente igual al n umero de columnas de la matriz; esta es la segunda condicion. Por ende no
puede realizarse la siguiente operacion.
c = xA (3.4)
Cuando se cumplen las condiciones se puede realizar la operacion. Como resultado de multiplicar
la matriz A por el vector x se obtiene el vector c. La operacion se describe a continuacion,
Ax = c (3.5)
Si se desglosa (3.5), encontramos el siguiente procedimiento con base en (3.2) y (3.3). Donde se
expone que cada renglon de la matriz se multiplica por el vector.
_

_
a
1,1
a
1,2
a
1,n
a
2,1
a
2,2
a
2,n
.
.
.
.
.
.
.
.
.
.
.
.
a
m,1
a
m,2
a
m,n
_

_
_

_
x
1
x
2
.
.
.
x
n
_

_
=
_

_
a
1,1
x
1
+ a
1,2
x
2
+ + a
1,n
x
n
a
2,1
x
2
+ a
1,2
x
2
+ + a
2,n
x
n
.
.
.
a
m,1
x
n
+ a
m,2
x
2
+ + a
m,n
x
n
_

_
(3.6)
34 Captulo 3. Producto matriz-vector Ax
A continuacion se muestra una forma compacta de (3.6). En este documento sera utilizada esta
formula (3.7) cuando se haga referencia a la ecuacion de la mutiplicacion de una matriz por un
vector, mientras la matriz no sea rectangular.
c
i
=
n

j=1
a
ij
x
j
i = 1, 2, . . . , n (3.7)
Como se observa en (3.6) y (3.7) resolver la operacion en cuestion resulta trivial. Sin embargo,
el proceso es demandante en tiempo de calculo. La demanda de calculo aumenta conforme la matriz
A se vuelve mas densa, es decir, el orden de la misma crece. Con base a (3.7) se realiza el algoritmo
que corresponde con el tema tratado lo cual permitira crear la funcion para la misma ecuacion.
Algoritmo 3.1 Multiplicacion matriz-vector
Esta denido por los siguientes seis pasos:
1. Hacer i = 0
2. Si (i < m)
Verdadero: hacer c
i
= 0,j = 0, posteriormente pasar al paso 3.
Falso: ir al paso 6
3. Hacer c
i
= c
i
+ A
ij
x
j
4. Hacer j = j + 1
5. Si (j < n)
Verdadero: regresar al paso 3.
Falso: hacer i = i + 1, posteriormente regresar al paso 2.
6. Parar.
En esta seccion se denieron las bases para resolver la operacion c = Ax. Lo cual es indispensable
para escribir funciones en codigo C que resuelvan la operacion en cuestion. Esta actividad se llevara a
cabo en secciones posteriores de este captulo.
3.2. Loop unrolling
En esta seccion se dene una tecnica de optimizacion de ciclos principalmente de tipo for. La
tecnica llamada Loop Unroll o Loop unrolling (desdoble de ciclo). Esta tecnica sirve para optimizar
3.2. Loop unrolling 35
el codigo de programas para reducir el tiempo de ejecucion de la aplicacion, los cual incrementa el
desempe no computacional de la misma.
Como menciona Page [32] esta tecnica tiene como objetivo eliminar la sobrecarga asociada con
la operacion de un ciclo determinado. Cuando el n umero de iteraciones es conocido se pueden listar
todos lo valores posibles para la variable de induccion
2
. Para ejemplicar, se tiene el siguiente ciclo:
for(i = 0; i < n; i++)
c[i] += a[i] * b[i];
Para ejemplicar tomemos n = 4 lo cual permite desdoblar el ciclo de forma completa quedando
como sigue
c[0] = a[0] b[0]
c[1] = a[1] b[1]
c[2] = a[2] b[2]
c[3] = a[3] b[3]
En este caso en particular la variable de induccion esta denida en el rango 0 i < n, al escribir
un codigo con las nuevas modicaciones se obtiene una aplicacion que realiza la misma tarea que
el ciclo original (para este caso en particular), pero ahora no hay gastos asociados al ciclo. En
consecuencia el rendimiento aumenta.
Cuando el valor de n es peque no el ciclo puede ser desdoblado en su totalidad. Sin embargo,
conforme n crece llevar a cabo un desdoble completo del bucle; sera una tarea practicamente impo-
sible de realizar. Aunado a ello, el codigo resultante es tosco. Una forma ingeniosa para resolverlo
es hacer un desdoble por bloques, cada uno tan grande como se desee. Esto con el n de reducir
el n umero de iteraciones ademas de exponer las operaciones que se pueden realizar en paralelo. A
continuacion se desarrolla un codigo general aplicable a cualquier Unroll.
r = n % k;
for(i = 0; i < n-r; i+=k)
c[i] += x[i]*y[i] + x[i+1]*y[i+1] + ... + x[i+k-1]*y[i+k-1];
for(i = n-r; i < n; i++)
c[i] += x[i]*y[i];
En el codigo anterior k representa el factor de unroll que se aplica; n el orden de los vectores y
r es el residual por si n no es divisible por k.
2
La variable de inducci on es aquella que controla el funcionamiento del ciclo, en la mayora de los casos se representa
con i.
36 Captulo 3. Producto matriz-vector Ax
Como menciona Page [32] al desarrollar un desdoble parcial queda claro que el n umero de
operaciones dentro del cuerpo del ciclo se puede llevar a cabo de forma paralela.
La tecnica de Loop Unroll permite reducir la carga en el ciclo utilizando la lnea de cache del
procesador utilizando los valores que recientemente han sido cargados a la memoria caliente
3
. Ello
hace que sea muy utilizada gracias a la delidad que presenta en una implementacion. A un cuando
la implementacion es por demas sencilla, la eleccion de una regla para que esta tecnica funcione
siempre no es una tarea sencilla. Este problema esta ligado directamente a las caractersticas del
procesador, los procesadores no-moviles ejecutan mejor las sobre-cargas en los ciclos que los que no
lo son.
3.3. Calculo del residual
En esta seccion se aborda el tema del calculo del residual, como un metodo para medir la
convergencia de los esquemas iterativos que se estudian en captulos posteriores. Este procedimiento
mide el error entre la k-esima iteracion con respecto a la solucion exacta del sistema lineal de
ecuaciones. Uno de los principales usos del calculo del residual es durante la medicion de error en
los metodos iterativos de proyeccion sobre subespacios de tipo Krylov[24]. Se realizara una funcion
que realice este procedimiento, la cual sera utilizada en los siguientes captulos.
El calculo del residual (r) se obtiene de sustraer el producto de A y x

a b como se muestra a
continuacion
r = b Ax

(3.8)
donde, x

= una aproximacion a la soluci on exacta de x, b, r, x

R
N
y, A R
NN
Para ello los vectores (b, r, x

) tienen la forma del vector z la cual se expresa a continuacion,


z = (z
1
, z
2
, . . . , z
n
)
T
Si x

= x r =

0 Ahora si x x

r ,=

0
Tomando en cuenta que la solucion exacta x es la suma de la aproximacion mas el error (x =
x

+ e), con lo que deducimos que


x = x

e
3
La memoria caliente corresponde a un tipo de almacenamiento conocido como NUMA(Non-uniform memory
access, memora de acceso no uniforme) o memoria caliente es como se le conoce a la memoria cache del procesador
debido a que es una memoria de gran velocidad.
3.3. Calculo del residual 37
Al sustituir x

en (3.8) tenemos
r = b A(x

e)
con ello se intuye que el residual es equivalente al error entre la solucion exacta y una aproximada
r e
Observe que el residual r es un vector de orden n, es decir, r R
n
de la forma
r = (r
1
, r
2
, r
3
, . . . , r
n
)
T
A continuacion el calculo del residual se traduce a codigo C, en la gura (3.1) se ilustra esta
tarea ya realizada.
Implementacion Calculo del Residual
double calcularResidual(float **A, float *dx, float *b, int n)
{
double *residual,normResidual;
int i,j;
double rowDot;
residual = make_dvector(n);
for(i = 0; i < n; i++)
{
rowDot = 0.0;
for(j = 0; j < n; j++)
rowDot += A[i][j] * dx[j];
residual[i] = b[i] - rowDot;
}
normResidual = normInf(residual,n);
free_svector(residual);
return normResidual;
}
Figura 3.1: Calculo del residual en C.
En la funcion descrita con anterioridad, se utilizan tres metodos que se explican a continua-
cion. Cuando se llama a la funcion make dvector(n) se reserva la memoria para un vector, en este
caso residual. La segunda funcion normInf(residual,n) calcula la norma innita de un vector con
38 Captulo 3. Producto matriz-vector Ax
orden n. En el ultimo caso free dvector(residual) se libera la memoria previamente reservada con
make dvector(n).
En temas posteriores, cuando se indique el calculo del residual (dentro de lneas de codigo), se
hara alucion a esta funcion cuando no se indique lo contrario.
El residual es un metodo que mide la diferencia entre una solucion exacta y una aproximada.
Se utiliza para determinar la convergencia en esquemas iterativos como son los metodos de Jacobi
y Gauss-Seidel. Para reducir el error derivado de la gran cantidad de operaciones en los metodos
directos se utilizan tecnicas iterativas de correccion del error del residual.
La funcion que fue implementada puede ser optimizada con temas tratados en secciones poste-
riores de este captulo, a n de incrementar el desempe no computacional de la misma. Cabe se nalar
que esta funcion no sera optimizada llegando a esos temas porque no es la nalidad del presente
documento.
3.4. Codicacion
En esta seccion se realiza una primera implementacion en codigo C, para la ecuacion que corres-
ponde a la multiplicacion de una matriz por un vector, es decir, la ecuacion (3.7). En esta primera
funcion secuencial no se utilizo ninguna de la optimizaciones. En temas posteriores se realizaran
mejoras que impacten positivamente en el rendimiento.
Como se ha mencionado con anterioridad, el producto de una matriz por un vector es una
operacion muy sencilla. Traducirla a un lenguaje para computadora es tambien una tarea muy
simple. La fraccion de codigo de la gura 3.2 es un primer resultado tras realizar la tarea en
cuestion.
Implementacion Canonica de Ax
for(i = 0; i < n; i++)
{
c[i] = 0.0;
for(j = 0; j < n; j++)
c[i] = A[i][j] * x[j];
}
Figura 3.2: Implementacion canonica de Ax.
3.5. Incremento del desempe no 39
Como puede observarse el codigo de la gura 3.2 esta dise nado para matrices cuadradas. El
codigo es por demas sencillo y no existe nada extra no. Es preciso denir que en temas siguientes
cuando se mencione una implementacion canonica del producto de una matriz po un vector, nos
referiremos a esta fraccion de programa alojado dentro de una funcion. En pocas palabras, esta
primera implementacion corresponde a una version compacta de una funcion canonica que resuelve
la multiplicacion de una matriz por un vector.
La implementacion canonica permite tener un primer acercamiento en la realizacion de una
aplicacion; la cual pueda ser ejecutada en forma paralela.
En esta seccion se realizo una primera implementacion, la canonica. Esta funcion no cumple
con los objetivos planteados; es decir, no presenta un buen desemple no computacional. Ademas
no es posible ejecutar esa aplicacion en varios procesadores de manera simultanea. Tomando esto
dos puntos, y los que puedan surgir, denimos que la implementacion canonica no es una opcion,
en terminos de computo de alto desempe no. En las siguientes secciones se tratan cada uno de los
puntos ya mencionados, a n de cumplir con cada uno de ellos.
3.5. Incremento del desempe no
Muchos programas pasan gran parte de su tiempo de ejecucion en bucles; en este caso es mediante
ciclos que se accede a los elementos de la matriz; con una reorganizacion adecuada de los bucles se
puede explotar el cache de procesador donde se guardan mas de un elemento que se va a utilizar en
la siguiente operacion. Los elementos que se encuentran en la lnea de cache en muchos casos pueden
ser procesados a la vez mediante una pila de operaciones. Esto puede mejorar el rendimiento de un
programa
4
. En esta seccion se optimiza la version canonica de la mutiplicacion Ax con la tecnica
de Loop unrolling.
Para mejorar el rendimiento de la aplicacion es preciso realizar un analisis detallado de la forma
matematica, se realiza una descomposicion a n de buscar diferentes formas de programar el pro-
blema para denir las caractersticas y determinar cual se adapta mejor a nuestros requerimientos.
Para ello es preciso desglosar y estudiar un gran n umero de posibles soluciones, as como analizarlas;
para determinar aquella que permita maximizar el desempe no sin incrementar signicativamente el
4
Las modicaciones en c odigo pueden ser aplicadas si y s olo si no cambian el correcto funcionamiento de la
aplicaci on.
40 Captulo 3. Producto matriz-vector Ax
error numerico para la solucion buscada. Recordemos la ecuacion,
c
i
=
n

j=1
a
ij
x
j
i = 1, 2, . . . , n (3.9)
En mas de una ocasion cuando se realiza una tarea se encuentra que existen varios caminos para
realizarla; cada uno de esos caminos con distancias y obstaculos distintos. Nos encontramos justo en
uno de esos casos, para elegir el camino primero estudiaremos cada uno de ellos. Existen practicas
utilizadas para la optimizacion ciclos con un n umero signicativo de iteraciones, generalmente en
bucles fors. Las tecnicas tienen el proposito de disminuir el tiempo de ejecucion del bucle; consisten
en disminuir la cantidad de iteraciones haciendo un incremento mayor a la unidad en la variable
que controla el ciclo. Una de esas practicas es la llamada Unroll Loops.
Como menciona Chapman et al.[11] el Unroll a un bucle es una practica poderosa para reducir
efectivamente los gastos de ejecucion. Puede ayudar a mejorar la utilizacion de la lnea de cache con
la reutilizacion de datos. Como es sabido el compilador no es capaz de determinar las dependencias
de operaciones ni tampoco lo que respecta al acceso en los elementos dentro de ciclos; por lo que el
desarrollador suele hacer un mejor trabajo en la optimizacion de bucles.
Antes de resolver el producto c = Ax, se plantea lo siguiente,
c
i
= a
i
x (3.10)
donde c y x son vectores verticales de orden de n-elementos, y a
i
es el i-esimo vector horizontal de
la matriz A.
Partiendo de (3.10) encontramos diferentes formas de resolverlo, a continuacion se listan las
variantes a tomar en cuenta, para esto todas utilizan la tecnica de unroll.
1. s =
n

j=1
x
j
y
j
+ x
j+1
y
j+1
j = 2
2. s =
n

j=1
x
i
y
j
+ x
j+1
y
j+1
+ x
j+2
y
j+2
+ x
j+3
y
j+3
j = 4
3. s =
n/2

j=1
x
j
y
j
+ x
j+1
y
j+1
+
n

j=n/2
x
j
y
j
+ x
j+1
y
j+1
j = 2
4. s =
n/4

j=1
x
j
y
j
+ x
j+1
y
j+1
+
n/2

j=n/4
x
j
y
j
+ x
j+1
y
j+1
+
3n/4

j=n/2
x
j
y
j
+ x
j+1
y
j+1
3.5. Incremento del desempe no 41
+
n

j=3n/4
x
j
y
j
+ x
j+1
y
j+1
j = 2
5. s =
n

j=1
x
i
y
j
+ x
j+1
y
j+1
+ x
j+2
y
j+2
+ x
j+3
y
j+3
+ x
j+4
y
j+4
j = 5
6. s =
n

j=1
x
i
y
j
+ x
j+1
y
j+1
+ x
j+2
y
j+2
+ x
j+3
y
j+3
+ x
j+4
y
j+4
+x
j+5
y
j+5
j = 6
7. s =
n

j=1
x
i
y
j
+ x
j+1
y
j+1
+ x
j+2
y
j+2
+ x
j+3
y
j+3
+ x
j+4
y
j+4
+ x
j+5
y
j+5
+ x
j+6
y
j+6
+x
j+7
y
j+7
j = 8
8. s =
n

j=1
x
i
y
j
+ x
j+1
y
j+1
+ x
j+2
y
j+2
+ x
j+3
y
j+3
+ x
j+4
y
j+4
+ x
j+5
y
j+5
+ x
j+6
y
j+6
+x
j+7
y
j+7
+ x
j+8
y
j+8
+ x
j+9
y
j+9
+ x
j+10
y
j+10
+ x
j+11
y
j+11
j = 12
Para comprender y tener una idea de como utilizar el unroll, en primera instancia se estudiaran
y compararan las primeras cinco variantes (1-5), en segunda instancia se analiza el resto. En algunos
de los casos anteriores podemos realizar dos implementaciones lo cual se expresara en su momento.
A continuacion se hara la codicacion de cada una de las opciones para conocer sus caractersticas.
En la primera implementacion (gura 3.3) corresponde a ese mismo orden de la lista de opciones
enlistadas anteriormente. Como se puede observar el n umero de iteraciones se reduce a la mitad, lo
cual teoricamente hace pensar que el tiempo de ejecucion va a reducirse a la mitad de tiempo. Para
este caso en particular corresponde a un Unroll-2 donde se guardara el resultado obtenido a una
variable. Esta al igual del resto de las fracciones de codigo que corresponda con la lista de opciones,
representa la solucion de la multiplicacion de dos vectores.
Codigo Opcion 1
for(i = 0; i < n; i+=2)
suma += (x[i]* y[i]) + (x[i+1] * y[i+1]);
Figura 3.3: Tecnica Loop Unrroll con factor 2.
A continuacion hacemos la codicacion de la segunda opcion (gura 3.4), que corresponde a un
Unroll-4. En esta ocasion la cantidad de iteraciones se reduce a una cuarta parte. Al igual que en
el caso anterior el resultado es guardado dentro de una variable.
42 Captulo 3. Producto matriz-vector Ax
Codigo Opcion 2
for(j = 0; j < n; j+=4)
suma += x[j]*y[j] + x[j+1]*y[j+1] + x[j+2]*y[j+2] + x[j+3]*y[j+3];
Figura 3.4: Tecnica Loop Unroll con factor 4.
El siguiente codigo (gura 3.5) representa una forma distinta de programar la primera opcion
de la gura 3.3, en esta ocasion, primero haciendo las operaciones con los ndices pares del vector
y posteriormente con los impares.
C odigo Opcion 1a
for(j = 0; j < n; j+=2){ suma += x[j]*y[j];}
for(j = 1; j < n; j+=2){ suma += x[j]*y[j];}
Figura 3.5: Tecnica Loop Unroll con factor 2, dos ciclos for.
Como vemos en el codigo de la gura 3.6, se puede codicar de distintas formas un mismo
problema. En las implementaciones anteriores solo utilizamos una variable para almacenar el resul-
tado, de la operacion en cuestion, en las proximas codicaciones se hara uso de dos o mas variables
para acumular el resultado mientras se realizan las operaciones. La siguiente fraccion de programa
corresponde al mismo codigo anterior pero ahora haciendo uso de dos variables.
Codigo Opcion 3
for(j = 0; j < n; j +=2){ s1 += (x[j]*y[j]);}
for(j = 1; j < n; j +=2){ s2 += (x[j]*y[j]);}
suma = s1 + s2;
Figura 3.6: Tecnica Loop Unroll con factor 2, dos variables.
La cuarta opcion (gura 3.7) representa una forma mas sosticada para llevar a cabo la solucion
del problema ya que partimos la operacion principal en dos sub-operaciones, las cuales a su vez
presentan un incremento en j de dos (j = 2) lo cual reduce el n umero de iteraciones a la mitad
e implementa dos variables, temporales, para llevar a cabo las operaciones. Ello ante los ojos del
unroll, corresponde al Unroll-2 dividido en dos mitades.
3.5. Incremento del desempe no 43
Codigo Opcion 4
for(j = 0; j < n/2; j += 2){ s1 += x[j]*y[j] + x[j+1]*y[j+1];}
for(j = n/2; j < n; j += 2){ s2 += x[j]*y[j] + x[j+1]*y[j+1];}
suma = s1 + s2;
Figura 3.7: Tecnica Loop Unroll con factor 2, dos ciclos for y dos variables.
La siguiente implementacion (gura 3.8), de la quinta opcion, sigue la nomenclatura a la anterior
y solamente diere en la cantidad de partes, que para este caso son cuatro, y por ende el n umero
de variables temporales aumenta a igual n umero, a continuacion se muestra lo que con anterioridad
se ha mencionado.
Codigo Opcion 5
for(j = 0; j < n/4; j+=2) { s1 += x[j]*y[j] + x[j+1]*y[j+1];}
for(j = n/4; j > n/2; j+=2) { s2 += x[j]*y[j] + x[j+1]*y[j+1];}
for(j = n/2; j > 3*n/4; j+=2){ s3 += x[j]*y[j] + x[j+1]*y[j+1];}
for(j = 3*n/4; j > n; j+=2) { s4 += x[j]*y[j] + x[j+1]*y[j+1];}
suma = s1 + s2 + s3 + s4;
Figura 3.8: Tecnica Loop Unroll con factor 2, cuatros ciclos for cuatro variables.
Todas la implementaciones anteriores tienen el n de encontrar las ventajas y desventajas que
resulta despues de desglosar el problema de distintas formas. Para cada una de las codicaciones
los resultados arrojados son distintos, aunque en teora el resultado es una constante; en la practica
el resultado diere en cada una de las aplicaciones.
Para hacer mas evidente los resultados es necesario que los vectores x y y sean de tipo oat y
llenados con n umero reales con signo, intercalados de preferencia.
En muchos lugares escuchamos que los nuevos dise nos se deben adaptar a la necesidades, es
por ello que en todo momento nos referimos como opciones a todas las implementaciones; en esta
ocasion unicamente se someteran a pruebas de exactitud y de velocidad de ejecucion.
En la tabla 3.1 podemos observar los resultados de exactitud de las funciones cuando se someten
con vectores de longitud n y con diez mil iteraciones para cada valor de n. Los resultados son
muy congruentes; para valores reducidos de n es mas provechoso realizarlo con la version canonica,
44 Captulo 3. Producto matriz-vector Ax
en caso contrario cuando n es grande dividir el ciclo en varias partes sera mejor; en terminos de
exactitud.
Tabla 3.1: Producto de dos vectores: resultados de prueba de exactitud, observamos las veces que
es mas exacta, mostrada en porcentaje ( %), cada funcion durante las iteraciones para cada valor
de n.
Resultados de Prueba de Exactitud
Funcion y Exactitud ( %)
N Canonica 1 1a 2 3 4 5
16 49.90 26.26 10.63 1.27 7.10 3.50 1.34
32 39.38 29.04 11.50 1.86 10.74 5.59 1.89
64 29.20 28.17 12.00 2.99 15.35 8.52 3.77
128 22.01 23.80 12.70 4.45 18.06 12.84 6.14
256 17.42 28.17 10.73 6.01 19.26 16.10 9.76
512 13.44 20.72 10.01 7.46 18.62 19.22 13.52
1024 11.26 17.73 8.63 9.60 18.36 19.28 17.83
2048 9.68 15.04 9.08 10.18 17.30 20.76 19.53
4096 9.07 13.47 8.26 11.50 17.16 19.33 22.30
8192 8.30 12.38 7.95 12.45 16.40 20.56 22.78
16384 8.50 11.56 7.79 12.91 15.50 19.93 24.22
32768 7.67 10.55 7.98 13.57 15.06 19.62 25.55
Con base a lo que observamos en la tabla 3.1 decimos que si queremos cuidar la exactitud de la
operacion, necesitamos desdoblar las operaciones en k-partes utilizando una variable distinta para
cada parte, donde k dependera del orden de los vectores (x, y). Ello por motivo que en valores de
n peque no es contraproducente, pero donde n tenga un valor sucientemente grande, la exactitud
mejorara conforme se implementen mas desdobles.
Con base a estos resultados podemos inferir que es de vital importancia denir el grado de
exactitud que buscamos; lo cual se obtiene al aumentar la cantidad de desdobles. Por consecuencia
conforme aumentemos la cantidad de partes, el codigo fuente crecera y se convertira en tosco y
dicultara el entendimiento del mismo.
Una buena pregunta que surge con los resultados obtenidos es la siguiente: Por que los resulta-
dos son distintos para cada funcion?, la respuesta es muy simple, por problemas de redondeo, como
menciona Chapra et al.[12], estas diferencias son originadas porque las computadoras utilizan un
determinado n umero de cifras signicativas para los calculos. Es por ello que algunas operaciones
3.5. Incremento del desempe no 45
Tabla 3.2: Producto de dos vectores: resultados de prueba de velocidad, observamos la tasa de
exactitud de cada funcion con respecto al n umero de iteraciones (10,000).
Resultados de Prueba de Velocidad
Funcion y Veces mas Veloz ( %)
N Can nica 1 1a 2 3 4 5
16 84.94 15.06 0 0 0 0 0
32 76.55 23.45 0 0 0 0 0
64 60.35 39.60 0.04 0 0.01 0 0
128 26.51 36.80 19.62 0 16.05 1.01 0.01
256 36.30 41.90 9.08 12.70 0.02 0 0
512 16.97 31.94 2.81 34.12 0 12.84 1.32
1024 0 11.26 0 79.95 0 3.08 5.71
2048 0 0.82 0 87.74 0 6.52 4.92
4096 0.01 0.04 0 99.78 0 0.05 0.12
8192 0 0.08 0.01 99.72 0 0.03 0.16
16384 0 0.18 0 99.45 0 0.21 0.16
32768 0 0.04 0 99.70 0 0.05 0.21
donde se tienen una gran cantidad de cifras, sobre todo decimales, la computadora nos da el re-
sultado aproximado de la solucion real. Este problema es debido a que el sistema numerico en las
computadoras no puede representar la totalidad de los n umeros reales.
Un punto a tomar en cuenta para elegir la exactitud son los nes para los que queremos la
aplicacion, y tomando en cuenta el tiempo que se va a tardar en realizar las operaciones. Un ejemplo
de ello nos lo encontramos en el corte de mosaico donde no es indispensable tener maquinaria con
precision en el orden de las micras.
Como en computo lo que importa es el tiempo de ejecucion es preciso someter a las funciones a
una prueba de velocidad de ejecucion. En la tabla 3.2 podemos observar los resultados de la prueba
de velocidad, donde nos muestra el porcentaje donde fue mas rapida cada funcion, en un total de
diez mil iteraciones.
En la tabla 3.2 se muestra un resultado muy claro, la implementacion 2 que corresponte a un
Unroll-4, es la mas rapida para valores de n grandes; pero no es la mas exacta. Es aqu donde
nace la gran disyuntiva, velocidad versus exactitud. Cabe se nalar que para valores de n peque nos
la version canonica es mas rapida esto se debe a costo computacional por operaciones de alineacion
46 Captulo 3. Producto matriz-vector Ax
Unroll-5
r = n % 5;
for(j = 0; j < n-r; j+=5)
suma += x[j ]*y[j ] + x[j+1]*y[j+1] + x[j+2]*y[j+2]\
+ x[j+3]*y[j+3] + x[j+4]*y[j+4];
for(j = n-r; j < n; j++)
suma += x[j] * y[j];
Figura 3.9: Tecnica Loop Unroll con factor 5.
para la pila de operaciones. Tambien con estos resultados es concluyente que al dividir un for con
n iteraciones en k-fors con n/k iteraciones es mas costoso debido al aumento de operaciones por el
manejo del ciclo. En la columna seis que corresponde a una version canonica dividida en dos partes,
la primera para n umeros pares y la segunda para impares. Estos resultados demuestran el costo por
la carga de datos a la zona caliente y las repercusiones que tienen un mal manejo del proceso; por
no utilizar valores guardados en la cache.
El presente documento esta enfocado al estudio del rendimiento de las aplicaciones, es por ello
que la balanza se inclina hacia la velocidad. Con los resultados que se obtuvieron, se tiene una idea
general del funcionamiento de unroll.
Ya estudiamos las primeras cuatro variantes, donde se obtienen las conclusiones ya expuestas.
Mas adelante se toman en cuenta el resto de las variantes de la lista, para as realizar lo importante;
una aplicacion con rendimiento aceptable. En el resto de las opciones se encuentran los Unroll
de 5, 6, 8, 10 y 12. Es importante mencionar, que existen muchas otras formas de codicar este
problema; sin embargo no se realizaran modicaciones debido a que se busca un mejor desempe no
computacional. En las guras 3.9-3.13 se encuentran desarrolladas las funciones mencionadas.
3.5. Incremento del desempe no 47
Unroll-6
r = n % 6;
for(j = 0; j < n-r; j+=6)
suma += x[j ]*y[j ] + x[j+1]*y[j+1] + x[j+2]*y[j+2] + x[j+3]*y[j+3]\
+ x[j+4]*y[j+4] + x[j+5]*y[j+5];
for(j = n-r; j < n; j++){ suma += x[j] * y[j];}
Figura 3.10: Tecnica Loop Unroll con factor 6.
Unroll-8
r = n % 8;
for(j = 0; j < n-r; j+=8)
suma += x[j ]*y[j ] + x[j+1]*y[j+1] + x[j+2]*y[j+2] + x[j+3]*y[j+3]\
+ x[j+4]*y[j+4] + x[j+5]*y[j+5] + x[j+6]*y[j+6] + x[j+7]*y[j+7];
for(j = n-r; j < n; j++){ suma += x[j] * y[j];}
Figura 3.11: Tecnica Loop Unroll con factor 8.
Unroll-10
r = n % 10;
for(j = 0; j < n-r; j+=10)
suma += x[j ]*y[j ] + x[j+1 ]*y[j+1 ] + x[j+2 ]*y[j+2 ]\
+ x[j+3]*y[j+3] + x[j+4 ]*y[j+4 ] + x[j+5 ]*y[j+5 ]\
+ x[j+6]*y[j+6] + x[j+7 ]*y[j+7 ] + x[j+8 ]*y[j+8 ]\
+ x[j+9]*y[j+9];
for(j = n-r; j < n; j++){ suma += x[j]*y[j];}
Figura 3.12: Tecnica Loop Unroll con factor 10.
48 Captulo 3. Producto matriz-vector Ax
Unroll-12
r = n % 12;
for(j = 0; j < n-r; j+=12)
suma += x[j ]*y[j ] + x[j+1 ]*y[j+1 ] + x[j+2 ]*y[j+2 ]\
+ x[j+3]*y[j+3] + x[j+4 ]*y[j+4 ] + x[j+5 ]*y[j+5 ]\
+ x[j+6]*y[j+6] + x[j+7 ]*y[j+7 ] + x[j+8 ]*y[j+8 ]\
+ x[j+9]*y[j+9] + x[j+10]*y[j+10] + x[j+11]*y[j+11];
for(j = n-r; j < n; j++){ suma += x[j]*y[j];}
Figura 3.13: Tecnica Loop Unroll con factor 12.
Se evaluaran las cuatro implementaciones anteriores con el n de medir la velocidad de cada una
de ellas, tambien se a una a ellas el Unroll de 4, para comparar el rendimiento. Para ello se utilizo una
computadora Apple MacBook con el sistema Operativo Mac OS X (v. 10.6.8), un procesador Intel
Core 2 Duo (2.4 GHz), 2 GB de memoria RAM DDR3 (1067 MHz). En la gura 3.14 se muestran
los resultados obtenidos, se observa el speed-up obtenido por cada una de las funciones con respecto
a la canonica. Cabe hacer mencion que para estos resultados no se utilizo ning una de las banderas
de compilacion disponibles.
10
2
10
3
10
4
1.1
1.2
1.3
1.4
1.5
1.6
1.7
1.8
1.9
2
2.1
Valor de N
S
p
e
e
d

U
p


Unroll4
Unroll5
Unroll6
Unroll8
Unroll10
Unroll12
Figura 3.14: Speed-up para la multiplicacion de dos vectores.
3.5. Incremento del desempe no 49
En la gura 3.14 se observa que el desempe no computacional aumenta en un promedio general
de 1.7x para la multiplicacion de dos vectores. El mejor desempe no para valores de n menores a
1000 corresponde a la funcion con Unroll de ocho con un pico de 2x. Sin embargo, para los valores
mayores a 1000 el mejor comportamiento esta dividido en dos, el Unroll de ocho y diez; este ultimo
es ligeramente mas rapido que los demas. En esta graca se demuestra que aumentar el desdoble no
garantiza que el incremento en el desempe no aumentara; el speed-up desempe nado por Unroll-12
no es en ning un momento la funci on mas rapida y mientras el orden de los vectores aumenta la
tendencia del rendimiento de esta funcion se asemeja al Unroll-4. Cabe se nalar que existen tres
funciones que presentan un rendimiento que tiene a normalizarse conforme el valor de n aumenta,
estas funciones son las que corresponde a un Unroll de 4, 5, 6. Es muy importante que el aumento
del rendimiento sea uniforme en programas seriales; esto permite tener un incremento mas uniforme
al programarlo en paralelo.
Con las cinco funciones anteriormente descritas se realiza el producto matriz-vector (Ax), se
pone mayor interes en estas funciones [Unroll (4, 5, 6, 8, 10, 12)] debido a que son las que mejor
comportamiento han tenido. Tambien encaminado a tener un panorama mas amplio conforme se
adentre al tema en cuestion.
Retomando el problema tenemos que
c = Ax (3.11)
donde c, x R
N
y la matriz A R
NN
Partiendo de la ecuacion (3.11), se expresa con una vista para nes de programacion
c
i
=
n

j=1
A
ij
x
j
i = 1, 2, . . . , n (3.12)
En (3.12) observamos que para resolver (3.11) se realizan n-operaciones del tipo x y (producto
de dos vectores). Lo cual se dene como se muestra a continuacion.
c
i
=
n

i=1
A
i
x (3.13)
Con base a lo que se ha mencionado, se puede proceder a realizar el programa que resuelva el
problema. Con base a los resultados de la parte anterior se realiza una funcion para cada una de
50 Captulo 3. Producto matriz-vector Ax
las opciones [Unroll(4, 5, 6, 8, 10, 12)]. Las funciones descritas tienen la forma siguiente:
oat dot version(oat *x, oat *y, int n)
Explicando la sintaxis de las funciones, dot version es el nombre de la version de la funcion;
por ejemplo dot 4 corresponde a la funcion con un Unroll de cuatro. El resto de los nombres de las
funciones tienen la misma tendencia. Con ello podemos escribir la forma general de las funciones,
lo cual es descrito en la gura 3.15, donde la palabra version sera sustituido por el factor de unroll
de la funcion que se trate.
5
Ax con la tecnica de Unroll
void matrix_vector_dot(float **A, float *x, float *c, int n)
{
int i;
for(i = 0; i < n, i++)
c[i] = dot_vesion(A[i],x,n);
}
Figura 3.15: Funcion general de la multiplicacion Ax con Unroll.
Es preciso ilustrar el rendimiento que se obtiene despues de las modicaciones y deniciones que
se han realizado durante esta seccion. En la gura 3.16 se plasma el speed-up que desempe na cada
una de las funciones Unroll[4, 5, 6, 8, 10, 12]. En ella se observan principalmente dos situaciones
denotadas por el orden de la matriz. La primera describe al rendimiento como una lnea brusca, esto
se presenta cuando el orden es peque no (100:1000). En el caso contrario, cuando la matriz es densa,
el rendimiento tiende a ser simetrico conforme la matriz crezca. Cuando se optimizan programas se
busca que el speed-up sea estable. Con base a ello se deduce que el factor de Unroll es determinante,
para matrices de orden peque no el desdoble debe ser menor; en caso contrario el factor debe ser
mayor. Ademas se percibe en la graca que a mayor factor de Unroll el rendimiento aumenta para
casi todos los casos; en esta evaluacion el desdoble de 12 tiene un rendimiento menor al de 10, lo
cual es concluyente para armar que si se realiza el experimento con un factor de 14 tendra menor
rendimiento que el de 12.
Durante el transcurso de esta seccion se ha hecho referencia al desempe no computacional de
las aplicaciones. En la gura 3.16 se ilustra el speed-up de cada aplicacion con respecto a otra
5
El factor de unroll denota la cantidad de iteraciones que son ejecutadas en un paso dentro del bucle.
3.5. Incremento del desempe no 51
10
2
10
3
10
4
1.5
1.55
1.6
1.65
1.7
1.75
1.8
1.85
Valor de N
S
p
e
e
d

u
p


Unroll 4
Unroll 5
Unroll 6
Unroll 8
Unroll 10
Unroll 12
Figura 3.16: Speed-up de Ax utilizando la tecnica de Unroll.
canonica. En la mayora, si es que no en todos, los documentos que tratan temas relacionados a la
optimizacion de codigo para Programacion en Alto Desempe no (HPC, por sus singlas en ingles de
High Performance Computing) miden el rendimiento en operaciones en coma otante por segundo
(ops). Las computadoras con que contamos hoy en da pueden realizar mas de una operacion en
cada ciclo. Ademas se toma en cuenta que un procesador actual (por ejemplo el procesador Intel
i7 de segunda generacion, uno de los mas actuales durante la realizacion de este trabajo) tienen
frecuencias de 2.6 GHz lo cual signica 2.610
9
ciclos por segundo. Por esas caracterscas la cantidad
de operaciones esta en el orden de los millones.
En virtud de lo mencionado, en la gura 3.17 se plasma el desempe no computacional de las
funciones tratadas. Para realizar esta evaluacion se utilizo una computadora con las siguientes
caractersticas tecnicas Apple MacBook con el sistema Operativo Mac OS X (v10.6.8), un procesador
Intel Core 2 Duo (2.4 GHz), 2 GB de memoria RAM DDR3 (1067 MHz), cabe mencionar que no
se utilizo ninguna de las banderas de compilacion disponibles para la compilacion. En la graca se
observa la ganancia en MFLOPS por utilizar la tecnica de Unroll.
En la gura 3.17 se muestra que la aplicacion con el factor de Unroll mayor (factor de 12) no
es la mejor, para este experimento en particular. La funcion que tiene un mayor rendimiento fue la
de Unroll-10, pero no existe una brecha muy marcada con respecto al rendimiento del resto de la
52 Captulo 3. Producto matriz-vector Ax
10
2
10
3
10
4
300
350
400
450
500
550
600
650
700
750
Valor de N
R
e
n
d
i
m
i
e
n
t
o

(
M
F
L
O
P
S
)


Canonica
Unroll 4
Unroll 5
Unroll 6
Unroll 8
Unroll 10
Unroll 12
Figura 3.17: Rendimiento computacional de Ax al utilizar la tecnica de Unroll.
funciones Unroll, todas con una peque na diferencia. Para los temas siguientes cuando se mencione
la funcion Unroll se hace referencia al Unroll-10, a menos que se especique lo contrario.
Con la optimizacion que se realizo durante esta seccion se obtiene un aumento del rendimiento
cercano al 200 % con una tecnica muy sencilla. Ello es bienvenido en procesos donde el tiempo de
calculo es muy demandante, para ejemplicar, si se tiene un proceso donde se resuelve el producto
de una matriz por un vector de forma iterativa se reduce aproximadamente a la mitad el tiempo
de ejecucion de la aplicacion, si anteriormente duraba una hora con la optimizacion solo durara 30
minutos.
3.6. Procesamiento vectorial (SIMD)
Anteriormente cuando las computadoras tenan un procesador se buscaron opciones para mejorar
el rendimiento del procesamiento, es cuando se desarrollo una forma de paralelizar los datos y
as tener varios modulos de procesamiento en un procesador; donde hay varias entradas de datos y
una salida unica. Una de ellas fue la tecnica llamada SIMD.
Single Instruction, Multiple Data (SIMD)
Como su acronimo lo indica, SIMD (Una Instruccion Multiples Datos) es una tecnica empleada
3.6. Procesamiento vectorial (SIMD) 53
para conseguir paralelismo a nivel de datos, es decir, tenemos una instruccion donde se aplica una
misma operacion a un conjunto de datos. Mediante una organizacion donde intervienen Unidades de
Procesamiento (UP) y una Unidad de Control (UC), la cual supervisa y asigna las actividades que
se van a realizar en las unidades de procesamiento. El proceso se presenta de la siguiente forma, la
unidad de control enva la misma instruccion a las unidades de procesamiento; cada UP trabaja en
un subconjunto de los datos; as es como se ejecuta la instruccion de forma sncrona donde act uan
todas las unidades de procesamiento.
Figura 3.18: Modelo SIMD.
En la gura 3.18 se ilustra el funcionamiento del modelo SIMD donde se observa que la UC
interviene en la carga de los datos y la ejecucion de los mismo en las UPs. Los datos son divididos
en n bloques con tantos elementos como UPs. La ejecucion de la operaciones se llevan a cabo con
la direccion de la UC la cual se encarga de cargar los datos a los registros y posteriormente indicar
la operacion a ser ejecutada en las UPs.
Como menciona Cockshott et al.[13], el modelo SIMD fue desarrollado originalmente en el con-
texto de y para maquinas paralelas a gran escala, en esos sistemas un procesador unico de control
emite una instruccion para miles de procesadores, cada uno de ellos de un bit unico de longitud
de palabra, con ello cada procesador funciona al mismo tiempo en la operacion global. Los pri-
meros procesadores SIMD exhiben paralelismo masivo de datos pero, como cada procesador tiene
su memoria privada y un bus de datos, esto haca que las maquinas fuesen enormes, compuestas
por m ultiples tarjetas de ejecucion y cada una con m ultiples chips de memoria y pares de chips
procesadores de datos. Hay que denotar que el modelo SIMD no esta restringido unicamente a los
54 Captulo 3. Producto matriz-vector Ax
procesadores de un bit, sino que lo podemos encontrar implementado en procesadores de 8, 16,
32 y 64 bits. Esta caracterstica nos permite no solamente realizar aritmetica de un bit, sino que
podemos realizar aritmetica paralela con varios bits enteros y n umeros de punto otante.
En la actualidad la incorporacion de SIMD en los microprocesadores con propositos generales se
encuentra en una escala modesta. Y por razones meramente economicas el motor SIMD se incluye
en el mismo chip que el resto de la Unidad Central de Procesamiento (CPU) lo cual restringe el
grado de paralelismo, no por problemas de incorporacion sino por el ancho de la ruta entre la CPU
y la memoria de datos; mientras que el ancho de las lneas de cache limitan el grado de paralelismo.
En base a lo que menciona Cockshott et al.[13], en la actualidad un gran n umero de procesa-
dores cuentan con el conjunto de instrucciones SIMD; con el objetivo de permitir que se realicen
varias operaciones en cada ciclo de reloj; es decir, una unica intruccion realiza la misma operacion
matematica, con un subconjunto distinto de los datos para la operacion, al mismo tiempo.
Tecnologa MMX
Esta tecnologa es un conjunto de instrucciones SIMD desarrolladas por Intel, obtiene la deno-
minacion de MMX por MultiMedia eXtension o Multiple Math o Matrix Math eXtension. Como
menciona Mittal et al.[27], la tecnologa MMX ampla lo que era la Arquitectura (IA) de Intel, fue
dise nada con el n de mejorar el rendimiento de la multimedia, las comunicaciones y las nuevas
aplicaciones para la Internet, pero en general cualquier aplicacion que se ajuste al paradigma SIMD
podra disfrutar de forma importante el rendimiento de speed-up brindado por esta tecnologa.
La adicion de la tecnologa MMX a la familia de procesadores IA deba ser perfecta, para que
las aplicaciones que utilizaran dicha tecnologa se ejecutara sin ning un contratiempo en cualquier
sistema operativo amigo de la arquitectura de Intel, as no se tendra que realizar modicacion
alguna en el mismo (sistema operativo). De esta manera la convivencia con la base de la aplicacion
IA existente era perfecta [27].
Lo mencionado con anterioridad se traduce en benecios para el usuario nal mediante la mejora
en el rendimiento de las aplicaciones multimedia en un factor de 1.5x a 2x, y mejora el rendimiento
de n ucleos clave en un factor de 4x en el procesador principal [27].
Para este documento se utilizan los registros para tipos de datos con precision simple mejor
conocidos como oat, en los cuales la tecnologa nos permite multiplicar cuatro elementos a la vez,
es decir, x(1 : 4) y(1 : 4).
3.6. Procesamiento vectorial (SIMD) 55
El siguiente paso es realizar una implementacion en codigo C de un producto punto entre los
vectores x y y. Para esto se hace uso de las instrucciones que proporciona la tecnologa MMX. En
la gura 3.19 se muestra una primera codicacion en MMX, para ello se presupone que el orden de
x y y es un m ultiplo de cuatro.
Producto de Vectores con MMX
float dot_mmx(float *x, float *y, int n)
{
int i;
float suma = 0.0;
__m128 n1, n2, n3, n4;
n4 = _mm_setzero_ps();
for(i = 0; i < n; i += 4)
{
n1 = _mm_loadu_ps(x+i);
n2 = _mm_loadu_ps(y+i);
n3 = _mm_mul_ps(n1, n2);
n3 = _mm_hadd_ps(n3, n3);
n4 = _mm_add_ps(n4, n3);
}
n4 = _mm_hadd_ps(n4, n4);
_mm_store_ss(&suma,n4);
return suma;
}
Figura 3.19: Funci on en MMX que multiplica dos vectores x y y.
A continuacion se desglosan cada una de las instrucciones MMX (usadas en la gura 3.19) con
el n de tener una idea mas concreta de como funciona el codigo anterior, las deniciones para cada
funcion fueron extradas de la pagina web de Microsoft Developer Network
6
.
1. m128: es un tipo de dado para uso exclusivo con Streaming SIMD Extensions y Streaming
SIMD Extensions 2, esta denido dentro de la biblioteca xmmintrin.h. No se puede acceder
directamente a los campos m128. pero pueden verse en el depurador. Este tipo de variable
se correlaciona con los registros MMX[0-7] y se alinean automaticamente en el lmite de 16
bytes.
6
La direccion de internet del sitio Microsoft Developer Network es http://msdn.microsoft.com/en-us/.
56 Captulo 3. Producto matriz-vector Ax
El tipo de dato m128 es un vector de 4 elementos de tipo oat, es por ello que se le considera
como un mini-vector.
2. mm setzero ps(): esta funcion retorna una variable m128 donde cada uno de los elementos
es equivalente a cero. Esta funcion tiene la forma,
__m128 _mm_setzero_ps(void);
Internamente la operacion que se realiza es la siguiente: se tiene una variable R de tipo m128,
dentro de la funcion se hace r(1 : 4) = 0.
3. mm loadu ps(x+i): con esta funcion se cargan los cuatro valores siguientes del vector a
los registros MMX(0-7). La funcion tiene la siguiente forma:
__m128 _mm_loadu_ps(float *p);
La operacion realizada se expresa como r(1 : 4) = p(1 : 4), donde r y p son vectores.
4. mm mul ps(n1, n2): esta funcion realiza la mutiplicacion n1 por n2 y el resultado lo retorna
en un vector r, para esto cada uno de los vectores debe ser de tipo m128. La forma de la
funcion se muestra a continuacion:
__m128 _mm_mul_ps(__m128 n1, __m128 n2);
La operacion realizada por esta funcion es r(1 : 4) = n1(1 : 4) n2(1 : 4).
5. mm hadd ps(n3, n3): esta funcion realiza una suma horizontal, es decir, los elementos
adyacentes en el mismo operando se suman. Cada argumento de 128-bits es considerado como
cuatro elementos de tipo oat cada uno de 32-bits. La nomenclatura de esta funcion se expresa
a continuacion:
__m128 _mm_hadd_ps(__m128 a, __m128 b);
Esta rutina realiza la siguiente operacion, se tienen los vectores a, b, r de tipo m128 e
internamente se realiza la operacion:
r = a + b
3.6. Procesamiento vectorial (SIMD) 57
r =
_

_
r
4
= b
4
+ b
3
r
3
= b
2
+ b
1
r
2
= a
4
+ a
3
r
1
= a
2
+ a
1
_

_
=
_

_
a
4
a
3
a
2
a
1
_

_
+
_

_
b
4
b
3
b
2
b
1
_

_
6. mm add ps(n4, n3): esta rutina suma los cuatro valores de n4 y n3. la funcion tiene la
siguiente sintaxis.
__m128 _mm_add_ps(__m128 a, __m128 b);
La presente funcion realiza simplemente la suma de dos vectores a y b, lo cual se demuestra
en la siguiente ecuacion,
r =
_

_
r
4
= a
4
+ b
4
r
3
= a
3
+ b
3
r
2
= a
2
+ b
2
r
1
= a
1
+ b
1
_

_
=
_

_
a
4
a
3
a
2
a
1
_

_
+
_

_
b
4
b
3
b
2
b
1
_

_
7. mm store ss(&suma,n4): esta funcion guarda el valor de una variable m128 (n4) a una
variable float (suma). La estructura de la funcion se dene a continuacion:
void _mm_store_ss(float * p, __m128 a);
Es preciso indicar que el primer argumento es un apuntador, es decir, contiene la direccion de
memoria donde se guardara el valor que esta alojado en n4.
En la tabla 3.3 se observan los resultados que se obtienen con este paradigma de programacion.
En la primera columna se indica los valores de n utilizados. Los tiempos de ejecucion con la im-
plementacion canonica, se muestran en la segunda columna
7
. En el siguiente par de columnas se
especican los tiempos de ejecucion y el rendimiento, respectivamente, arrojados por la funcion con
un factor de Unroll igual a 4. En la quinta y sexta columna se exponen el tiempo de ejecucion y el
speed-up a consecuencia de escribir programas con la tecnologa MMX. Para obtener los resultados
7
Unroll-0 o versi on can onica.
58 Captulo 3. Producto matriz-vector Ax
Tabla 3.3: Producto de dos vectores: comparacion de rendimiento de las funciones canonica, MMX
y Unroll-4; observamos el rendimiento que nos brinda la funcion en MMX respecto a la forma
tradicional y en comparacion con la funci on con Unroll de 4.
Comparaci on de Rendimiento de MMX
con bandera de Compilaci on -O2
Valor de Tradicional Unroll-4 MMX
N Tiempo(s) Tiempo(s) Speed-Up Tiempo(s) Speed-Up
16 0.00117 0.00080 1.46 0.00083 1.41
32 0.00156 0.00098 1.59 0.00088 1.77
64 0.00236 0.00134 1.77 0.00109 2.18
128 0.00379 0.00219 1.73 0.00172 2.21
256 0.00748 0.00307 2.44 0.00239 3.13
512 0.01493 0.00530 2.82 0.00464 3.22
1024 0.02853 0.00925 3.08 0.00758 3.77
2048 0.05883 0.01801 3.14 0.01453 3.90
4096 0.11247 0.03560 3.16 0.02860 3.93
8192 0.22394 0.07879 2.84 0.05613 3.99
16384 0.44777 0.16040 2.79 0.11342 3.95
32768 0.89796 0.31393 2.86 0.22376 4.01
que se muestra se utilizo una bandera de compilacion (-O2), con el n de activar una pila de op-
timizaciones de GNU GCC y as mejorar el rendimiento en la aplicacion. Para mayor informacion
consultar el Manual de Usuario del compilador
8
.
Como se aprecia en la cuarta y sexta columna de la tabla 3.3, conforme el valor de n se incrementa
el speed-up con MMX es comparativamente superior al speed-up del Unroll utilizado hasta un
maximo de 4x para MMX.
Durante la seccion anterior se optimizo el codigo utilizando la tecnica de Unroll, la cual es
evidentemente diferente a la de procesamiento vectorial. A consecuencia de lo mencionado es preciso
crear una combinacion de ambas tecnicas para determinar la conveniencia de la fusion.
Para realizar esta evaluacion se emple o una computadora con las siguientes caractersticas tecni-
cas Apple MacBook con el sistema Operativo Mac OS X (v10.6.8), un procesador Intel Core 2 Duo
(2.4 GHz), 2 GB de memoria RAM DDR3 (1067 MHz) de forma adicional se utilizo la bandera de
8
Los manuales de GCC est an disponibles en electr onico y clasicados por versi on del compilador en la p agina
http://gcc.gnu.org/onlinedocs.
3.6. Procesamiento vectorial (SIMD) 59
compilacion (-O2).
0 1000 2000 3000 4000 5000 6000 7000 8000 9000 10000
1200
1400
1600
1800
2000
2200
2400
2600
2800
3000
Valor de N
R
e
n
d
i
m
i
e
n
t
o

(
M
F
L
O
P
S
)


Canonica
MMX
MMX Unroll2
MMX Unroll4
Figura 3.20: Desempe no de Ax al utilizar MMX con bandera de compilacion -O2.
El resultado de ello es ilustrado en la gura 3.20 en la cual se presenta el rendimiento en
MFLOPS para las funciones, canonica MMX y MMX con Unroll [2, 3].
9
En esta graca se observa
que el rendimiento de MMX es en momentos cerca de dos veces mas rapida que la canonica, cuando
la dimension de la matriz es menor a 10001000. Cuando incrementamos la dimension de la matriz
el speed-up es de 1.5x en promedio, lo cual es evidentemente menor que para el caso anterior (ver la
tabla 3.3). Los resultados para MMX (con un core) son semejantes a los esperados seg un Mittal et
al.[27]. Cabe mencionar que no existe benecio por fusionar las dos tecnicas de optimizacion, esto
desde un punto de vista practico.
Con los resultados que se obtienen es concluyente que la tecnica de procesamiento vectorial es
una mejor opcion antes de fusionarla con la tecnica de Unroll Loops.
9
Nota: en este caso la tecnica de Unroll fue aplicada sobre MMX, es decir, en cierto modo MMX es equitativo a
Unroll-4; con ello Unroll 2, 3 para MMX corresponde a un Unroll real de 8 y 12 respectivamente.
60 Captulo 3. Producto matriz-vector Ax
3.7. Codicacion en paralelo
En esta seccion se realiza la codicacion en paralelo de c = Ax. En primera instancia se realiza
con base, unicamente, en la ecuacion (3.7) de la pagina 34 a esta version la llamaremos canonica en
paralelo.
En el dise no de algoritmos en paralelo es importante establecer las dependencias de operaciones
presentes en el problema a resolver. Esto a n de eliminar los cuellos de botella que pudiesen presen-
tarse; pero lo mas importante, que la ejecucion en paralelo no altere los resultados negativamente.
Si prestamos atencion en la ecuacion (3.7) se observa que no existen dependencias de operaciones
cuando se calcula el i-esimo elemento del vector c (c
i
). Para este caso en particular no existe una
competencia entre los hilos en el acceso a los elementos; porque se obtienen a traves de los ndices.
Si cualquiera de las escalares fuese una lista enlazada este problema se presentara y habra que
sincronizar el acceso de los hilos. A continuacion se muestra la ecuacion que se ha mencionado (3.7).
c
i
=
n

j=1
a
ij
x
j
i = 1, 2, . . . , n
Como no existe dependencia entre las operaciones no es necesario hacer modicaciones a la
ecuacion; para que esta pueda ser paralelizada. A continuacion se realiza la primera implementacion
en paralelo de la multiplicacion de una matriz por un vector, en la gura 3.21. Para realizar esta
primera version en paralelo se agrega unicamente una directiva de OpenMP al codigo descrito en
la canonica. A esto se debe la popularidad de este paradigma de programacion.
Canonica en Paralelo
#pragma omp parallel for default(none) \
shared(x,c,A,n) private(j,i)
for(i = 0; i < n; i++)
c[i] = dot(A[i], x, n);
Figura 3.21: Implementacion canonica en paralelo de Ax.
En primer lugar se indica el signicado de la directiva de OpenMP usada en gura 3.21, se dene
que la estructura a paralelizar es un ciclo for. Ademas se puntualiza el tipo de acceso por parte de
los hilos que tendra cada una de las variables. El tipo compartido (shared) todos los hilos tendran
3.7. Codicacion en paralelo 61
acceso sincronizado a la variable. Para el caso contrario (private) cada uno de los hilos contara con
una copia de esa variable, por ejemplo en la variable n cada hilo tiene una variable n

de la cual solo
el hilo del que n

sea huesped podra acceder al valor que se aloja en ella; dicho de otra forma es una
variable local de cada hilo (mas informacion en [10, 11, 17]). Para tener una idea mas concreta del
funcionamiento paralelo del codigo descrito en la gura 3.21 es preciso denirlo. De forma particular
para la ejecucion con dos procesadores, el ciclo for principal es interpretado como dos sub-fors, el
primero con el rango (1 : n/2) y el del otro (n/2 : n) cada sub-for es ejecutado en un procesador
distinto de forma simultanea. Ello se expresa a continuacion,
for(i = 0; i < n/2; i++) for(i = n/2; i < n; i++)
c[i] = dot(A[i],x,n); c[i] = dot(A[i],x,n);
Lo expresado con anterioridad es aplicable para k cantidad de procesadores, y la forma funda-
mental de la ejecucion persiste. En la gura 3.22 se ilustra el rendimiento computacional que tiene el
codigo que corresponde a la version canonica en paralelo. Los resultados mostrados se obtienen por
la ejecucion en una computadora Apple modelo MacPro 4.1 con dos procesadores Quad-Core Intel
Xeon a 2.26 GHz, 8 Gb de memoria RAM tipo DDR3 (1067 MHz), con un sistema operativo Mac
OS X Snow Leopard (v10.6.8), en lo consecuente cuando se muestren los resultados de ejecuciones
paralelas corresponderan a esta computadora a menos que se indique lo contrario.
En la gura 3.22 se muestra que el rendimiento para una matriz (para tama no igual o menor a
1000) se deteriora conforme se incrementa la cantidad de hilos. En el caso contrario el rendimiento
se ve mejorado sustancialmente conforme aumentan el n umero de procesadores. Cabe hacer mencion
que el speed-up que se obtiene al incrementar la cantidad de hilos no es literalmente proporcional.
Para 2 y 4 hilos la proporcionalidad esta presente, desde un punto de vista practico. Sin embargo,
el aumento en el rendimiento para 8 n ucleos con respecto a 4 es mucho menor. Esto se debe al
cuello de botella en el acceso a la memoria resultado de la arquitectura de la computadora.
10
Con
ello es concluyente que para casos donde el tama no de la matriz es peque no es una mejor opcion el
resolverlo con menos hilos y viceversa.
Durante las ultimas dos secciones se crearon diferentes funciones con tecnicas de optimizacion
diferentes, con el n de mejorar el rendimiento en una ejecucion no paralela. Esto permite generar un
software en paralelo con diferentes tecnicas y un rendimiento distinto. En la gura 3.23 se describe
10
La computadora tiene un arquitectura Intel Nehalem que agrega un buer de menores prestaciones que permite
compartir informacion entre los dos procesadores. El acceso a este nivel es m as costoso en terminos de tiempo.
62 Captulo 3. Producto matriz-vector Ax
10
2
10
3
10
4
0
1000
2000
3000
4000
5000
6000
7000
8000
Valor de N
R
e
n
d
i
m
i
e
n
t
o

(
M
F
L
O
P
S
)


1Core
2Cores
4Cores
8Cores
Figura 3.22: Rendimiento de la version canonica de Ax en paralelo con bandera de compilacion -O2.
la forma general que tiene la funcion paralela que multiplica una matriz por un vector, ello con base
al codigo de la gura 3.16. Es bien observado que la subrutina relativamente no cambia, cuando se
cambia entre las diferentes tecnicas de optimizacion.
Forma general en paralelo
#pragma omp parallel for default(none) \
shared(x,c,A,n) private(j,i)
for(i = 0; i < n; i++)
c[i] = dot_version(A[i], x, n);
Figura 3.23: Implementacion general de Ax en paralelo.
Durante esta seccion se hizo paralela la version canonica y se obtuvieron resultados que muestran
los benecios en rendimiento por esta accion. Los cuales tiene una semejanza con lo esperado,
el incremento del rendimiento en la practica no es lineal debido en gran parte al dise no de la
computadora.
3.8. Evaluacion de algoritmos en paralelo 63
3.8. Evaluaci on de algoritmos en paralelo
En esta seccion se realiza la evaluacion de los algoritmos tratados en las secciones anteriores. Se
realizan diferentes planteamientos con n de seleccionar la mejor opcion para resolver el problema
en cuestion.
En temas anteriores se ha utilizado el termino de bandera de compilacion pero hasta este mo-
mento no se ha denido el signicado ni el proposito de su uso. Por ello es preciso denir este punto
tan importante. De forma general, la bandera de compilacion tiene la funcion de activar una serie
de optimizacion durante el compilado del codigo, esto en forma analoga a las banderas utilizadas
en cualquier programa. El uso de las banderas de compilacion tienen el unico n de aumentar el
desempe no computacional de la aplicacion.
Figura 3.24: Desempe no de la version canonica de Ax con banderas de compilacion.
En la gura 3.24 se ilustran los benecios que se obtienen con el uso de banderas de compilacion,
para los propositos del presente trabajo solo se utilizan dos banderas -O2 y -funroll-loops. En
la graca se plasma que al utilizar la bandera de compilacion el rendimiento de la aplicacion se va
a las nubes. Para este caso en particular la diferencia entre -O2 y -funroll-loopspracticamente
no existe. En la realizacion del presente documento se utiliza la bandera -O2 que corresponde al
segundo nivel de optimizacion por parte del compilador; esto mientras no se indique lo contrario.
Las optimizaciones activadas por esta bandera son descritas en [40, pag.70].
Primeramente se realiza la evaluacion de la tecnica de Unroll Loops en paralelo. Para este
procesos se toma en cuenta unicamente el factor de Unroll de 10 ya que es el que mejor desempe no
64 Captulo 3. Producto matriz-vector Ax
10
2
10
3
10
4
0
0.5
1
1.5
2
2.5
3
3.5
4
4.5
Valor de N
S
p
e
e
d

u
p


1Core
2Cores
4Cores
8Cores
Figura 3.25: Escalabilidad paralela de Ax en su la version Unroll-10 con bandera -O2.
obtuvo. En la gura 3.25 se plasma el speed-up de la version en cuestion cuando se aumenta el
n umero de hilos de procesamiento. Es claro que la tecnica de Unroll tiene una menor escalabilidad
que la canonica de la gura 3.22. Para este caso en particular resulta contraproducente resolver el
problema con muchos hilos cuando el valor de n sea reducido, existen momentos en donde es mas
rapida la ejecucion con un procesador. Cabe mencionar que para los casos de ejecucion con 2 y 4
procesadores se obtiene un speed-up cercano al teorico o lineal 1.8x y 3.5x aproximadamente (para
los valores mas grandes de n). Esto induce a que la escalabilidad de la tecnica de Unroll Loops
es de considerarse ya que se asemeja a la canonica. Para el caso de 8 hilos la ganancia no es muy
signicativa 4.3x con respecto a cuatro cores. Ello se debe a la arquitectura de la computadora
utilizada, para obtener los 8 hilos se hace uso del segundo procesador lo cual implica otra linea de
cache mas distante.
La evaluacion de la tecnica MMX consiste en el mismo procedimiento que el que se hizo para la
anterior. En primera instancia se eval ua la escalabilidad en paralelo. En la gura 3.26 se ilustra el
speed-up de esta tecnica utilizando una bandera de compilacion -O2. En ella se observa que para
los valores 100 n 1000 es contraproducente hacerlo en paralelo. Mientras que para 1000 n
10000 si existe una ganancia en el rendimiento. El speed-up que se obtiene para 2 procesadores es
3.8. Evaluacion de algoritmos en paralelo 65
10
2
10
3
10
4
0
0.5
1
1.5
2
2.5
3
3.5
S
p
e
e
d

u
p
Valor de N


1Core
2Cores
4Cores
8Cores
Figura 3.26: Escalabilidad paralela de Ax en su la version MMX con bandera -O2.
un poco menor a 1.5x cuando teoricamente es 2x, con 4 hilos la ganancia es de 2.5x cuando debiese
ser 4x. El caso mas pobre es para 8 n ucleos donde la ganancia no es muy signicativa con respecto
a la de 4, la aceleracion apenas llega a 3x. Con estos resultados es concluyente que la version MMX
es menos escalable que la canonica y que Unroll Loops.
Una vez que se ha denido la escalabilidad de la funcion MMX se realiza la comparacion en
rendimiento con la tecnica Unroll Loops con un factor de unroll de 10. En la gura 3.27 se muestran
los resultados obtenidos. La diferencia mayor se presenta cuando la ejecucion es en serie. Conforme
se aumenta el n umero de hilos de ejecucion esta diferencia tiende a disminuir. Con base a estos
resultados se demuestra que la funcion MMX tiene un mayor desempe no computacional para la
totalidad de los casos evaluados. Cabe mencionar que la diferencia en el rendimiento tiende a la
baja conforme se aumentan el n umero de procesadores.
Para ilustrar una comparativa del rendimiento de las tres versiones tratadas en esta seccion se
plasma la graca de la gura 3.27 donde se observa de forma muy clara que la version MMX es mas
rapida que las otras dos mas sin embargo cuando el n umero de hilos comienza a crecer la diferencia
tiende a reducirse. Ello implica que en un determinado n umero de hilos la funcion MMX dejara de
ser la mas rapida. Con los resultados obtenidos es concluyente que la version MMX tiene el mejor
66 Captulo 3. Producto matriz-vector Ax
Figura 3.27: Comparativa del rendimiento computacional de las versiones canonica, Unroll-10 y
MMX con bandera de compilacion -O2.
rendimiento computacional. Sin embargo, no tiene la mejor escalabilidad cuando se hace en paralelo.
La version canonica tiene el mejor speed-up pero es la mas lenta, en terminos de rendimiento.
Como consecuente a los resultados de la evaluaciones realizadas se utilizara la funcion MMX en
los siguientes temas cuando sea necesario resolver el producto de una matriz por un vector.
Para nalizar este tema se concluye lo siguiente; durante la ejecucion de un programa en el cual
se cargan a la memoria cache del procesador, valores que no son utilizados sino hasta despues de la
segunda carga originan un retardo por gastos de ejecucion; a un el cache es de muy alta velocidad
ocasiona un continuo direccionamiento que se traduce en el aumento del tiempo. Realizar una sobre
carga de operaciones genera un mejor uso de la memoria caliente; pero a costo de un mayor error
de redondeo. Por otra parte la division de un ciclo en m ultiples benecia en la reduccion del error
de redondeo por una segmentacion de la cantidad de operaciones; pero esto genera un incremento
en el tiempo de ejecucion por los gastos de manejo de ciclos y la administracion de las cargas de
memoria. La conclusion mas importante es que la tecnica MMX representa la mejor opcion para
3.8. Evaluacion de algoritmos en paralelo 67
resolver el producto de una matriz por un vector independientemente de una ejecucion en serie o
en paralelo. La escalabilidad paralela de MMX es la peor de las tres tratadas. La version canonica
es la que presenta la mejor escalabilidad cuando se aumenta el n umero de cores para la ejecucion
paralela. La diferencia de performance entre MMX frente a la canonica y Unroll Loops tiende a
disminuir conforme se aumenta el n umero de cores. Esto implica que a cierto n umero de hilos de
ejecucion esa diferencia dejara de existir.
Captulo 4
Metodo Iterativo de Jacobi
En el area de la computacion, y en la ingeniera en general, una tarea cotidiana es la de resolver
problemas representados por un sistema lineal de ecuaciones. La resolucion de este problema de-
manda mucho calculo, es por ello que generalmente se le encomienda a una computadora. Por ello
es importante realizar programas ecientes que resuelvan estos problemas lo mas rapido posible.
Existen dos categoras para resolver un sistema lineal, los metodos directos y los iterativos. Los
primeros determina la solucion en un n umero determinado de pasos. Los iterativos son aquellos
que obtienen la solucion aproximandose a ella en un n umero nito, pero no denido de pasos. La
principal diferencia entre ambos es en el resultado; el arrojado por los directos es exacto mientras
que aproximado el de los segundos (iterativos).
En palabras de Skiba [39] los metodos directos se emplean para resolver sistemas lineales con
matrices nn cuando el valor de n no es muy grande (menor que un millon). Cuando la matriz
de coecientes es densa la cantidad de operaciones dependera del tama no, por otro lado cuando sea
dispersa el n umero de operaciones dependera de la cantidad de elementos nulos y de la estructura
del grafo[8]. Ejemplos de metodos numericos que pertenecen a esta categora, los cuales se abordan
en este trabajo son la regla de Kramer, el metodo de Gauss-Jordan y la factorizacion LU.
Regla de Kramer
La regla de Kramer es el metodo directo mas simple, es de gran utilidad para comprender al
resto. De acuerdo con Skiba [39] en la practica ya no es utilizado debido al orden de complejidad
O((n+1)!) lo cual evidentemente es impractico. Sirve para resolver sistemas cuadrados de la forma
69
70 Captulo 4. Metodo Iterativo de Jacobi
Ax = b lo cual se representa como
a
1,1
x
1
a
2,1
x
1
.
.
.
a
n,1
x
1
+
+
+
a
1,2
x
2
a
2,2
x
2
.
.
.
a
n,2
x
2
+
+
+
. . .
. . .
.
.
.
. . .
+
+
+
a
1,n
x
n
a
2,n
x
n
.
.
.
a
n,n
x
n
=
=
=
b
1
b
2
.
.
.
b
n
(4.1)
De acuerdo con Baldor [5] la regla de Kramer dice: El valor de cada inc ognita es una fraccion
cuyo denominador es el determinante formado con los coecientes de las incognitas (determinante
del sistema) y cuyo numerador es el determinante que se obtiene sustituyendo en el determinante
del sistema la columna de los coecientes de la incognita que se halla por la columna de los terminos
independientes de las ecuaciones dadas.
En otras palabras el vector solucion del sistema se encuentra con la razon del determinante
general del sistema sobre el determinante de la matriz sustituyendo j-esimo vector columna del
sistema por el vector columna de los terminos independientes; y el determinante general de esa
matriz.
Como menciona Sydsaeter et al.[41], El sistema tiene una solucion unica si la matriz de coe-
cientes es singular.
Este metodo es muy utilizado para resolver sistemas de 3 3, a continuacion se describe el
procedimiento para resolver los sistemas en cuestion.
Sea un sistema de ecuaciones de la siguiente forma
ax + by + cz = j
dx + ey + fz = k
gx + hy + iz = l
El sistema se expresa de la siguiente forma matricial
_

_
a b c
d e f
g h i
_

_
_

_
x
y
z
_

_
=
_

_
j
k
l
_

_
(4.2)
Para encontrar el resultado de las variables x, y, z primero se resolvera el determinante de la
Preliminares: metodos directos 71
matriz de coecientes a la cual nombraremos A, para ello aplicamos la regla de Sarrus
1
.
Det(A) = [A[ =

a b c
d e f
g h i
a b c
d e f

= (aei + dhc + gbf) (ceg + fha + ibd) (4.3)


Para encontrar los valores de las variables x, y, z se realiza el siguiente procedimiento, para esto
se toma en cuenta (4.3) y con base a la denicion de la regla ya expuesta,
x =
Det(A
1
)
DetA
=

j b c
k e f
l h i
j b c
k e f

[A[
=
(jei + khc + lbf) (cel + fhj + ibk)
(aei + dhc + gbf) (ceg + fha + ibd)
y =
Det(A
2
)
DetA
=

a j c
d k f
g l i
a j c
d k f

[A[
=
(aki + dlc + gjf) (ckg + fla + ijd)
(aei + dhc + gbf) (ceg + fha + ibd)
z =
Det(A
3
)
DetA
=

a b j
d e k
g h l
a b j
d e k

[A[
=
(ael + dhj + gbk) (jeg + kha + lbd)
(aei + dhc + gbf) (ceg + fha + ibd)
1
La Regla de Sarrus, es un regla pr atica muy sencilla consiste en repetir las primeras dos las de la matriz de
coecientes al nal de la misma. Despues realizar la suma del producto de las tres diagonales de izquierda a derecha
con su propio signo; a las tres diagonales de derecha a izquierda se les cambia el signo.
72 Captulo 4. Metodo Iterativo de Jacobi
Con base en (4.2) y al procedimiento anterior se induce a la siguiente ecuacion para resolver los
sistemas de ecuaciones de n-ecuaciones con n-incognitas
x
i
=
1
[A[
n

j=1
A
ji
b
j
i = 1, 2, . . . , n (4.4)
Una forma mas simple para expresar (4.4) es la siguiente
x
j
=
Det(A
j
)
Det(A)
j = 1, 2, . . . , n (4.5)
La regla de Kramer es utilizada para la solucion de sistemas lineales con pocas ecuaciones e igual
n umero de variables. Presenta el fundamento teorico para comprender metodos como la eliminacion
gaussiana y la factorizacion LU.
Metodo de Gauss-Jordan
Este metodo es uno de lo preferidos para resolver sistemas de ecuaciones lineales, cabe mencionar
que es una variante del metodo de la eliminacion de Gauss (eliminacion gaussiana). De acuerdo
con Chapra et al.[12] ambos metodos dieren en que cuando se elimina una incognita se elimina no
solo de las ecuaciones subsecuentes sino de todo el sistema de ecuaciones. Esto inere que la ultima
matriz a determinar es unitaria [18], es decir
A =
_

_
1 0 0
0 1 0
.
.
.
.
.
.
.
.
.
.
.
.
0 0 1
_

_
(4.6)
Teniendo la matriz A de la forma unitaria tiene la ventaja de que la solucion es directa. Esto
puede ser representado con la matriz extendida
A =
_

_
1 0 0 b
1
0 1 0 b
2
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
0 0 1 b
n
_

_
(4.7)
Preliminares: metodos directos 73
es decir x(1 : n) = b(1 : n), donde x es la inconita y b es el resultado.
Con base a Nakamura [28] el algoritmo consiste en dos procesos principales: 1) la eliminacion
hacia adelante, y 2) eliminacion hacia atras.
En palabras
2
del mismo autor el primer paso se realiza de la siguiente manera: La primera
ecuacion se multiplica por a
2,1
/a
1,1
y se le resta a la segunda ecuacion para eliminar el primer
termino de la segunda; de la misma forma, el primer termino de las ecuaciones restantes, i > 2, se
elimina restando la primera ecuacion multiplicada por a
i,1
/a
1,1
, este resultado se representa como
a

ij
x
j
. Lo mencionado se ve a continuacion:
a
1,1
x
1
+ a
2,1
x
2
+ a
3,1
x
3
+ + a
1,n
x
n
= b
1
a

2,2
x
2
+ a

2,3
x
3
+ + a

2,n
x
n
= b

2
a

3,2
x
2
+ a

3,3
x
3
+ + a

3,n
x
n
= b

3
.
.
.
a

n,2
x2 + a

n,3
x
3
+ + a

n,n
x
n
= b

n
(4.8)
Si aplicamos el mismo procedimiento pero ahora, para el segundo termino de las ecuaciones para
i > 2 se elimina restando la segunda ecuacion multiplicada por a

1,2
/a

2,2
como sigue
a
1,1
x
1
+ a
2,1
x
2
+ a
3,1
x
3
+ + a
1,n
x
n
= b
1
a

2,2
x
2
+ a

2,3
x
3
+ + a

2,n
x
n
= b

2
a

3,3
x
3
+ + a

3,n
x
n
= b

3
.
.
.
a

n,3
x
3
+ + a

n,n
x
n
= b

n
(4.9)
Siguiendo el paso anterior se eliminan todos los terminos para tener una matriz triangular supe-
rior. De forma general se despeja el j-esimo termino al multiplicar la j-esima ecuacion y a
i
i,j1
/a
i
j,j
,
esto se le resta a la j-esima ecuacion para i > j. Al nalizar este procedimiento la matriz tendra la
2
La metodologa que se presenta para la soluci on del Metodo de Gauss-Jordan fue estrado del tema 6.2 de [28].
74 Captulo 4. Metodo Iterativo de Jacobi
siguiente forma.
a
1,1
x
1
+ a
2,1
x
2
+ a
3,1
x
3
+ + a
1,n
x
n
= b
1
a

2,2
x
2
+ a

2,3
x
3
+ + a

2,n
x
n
= b

2
a

3,3
x
3
+ + a

3,n
x
n
= b

3
.
.
.
a
n1
n,3
x
3
+ + a
n1
n,n
x
n
= b
n1
n
(4.10)
Hasta este punto las eliminaciones de Gauss y Gauss-Jordan coinciden en su metodologa. Donde
se diferencia es en el segundo paso, la eliminacion hacia atras. A continuacion se muestra la matriz
extendida que se tiene hasta este punto
3
a
1,1
a
1,2
a
1,3
. . . a
1,n1
a
1,n
b
1
0 a

2,2
a

2,3
. . . a

2,n1
a

2,n
b

2
0 0 a
3,3
. . . a
3,n1
a
3,n
b

3
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
0 0 0 . . . a
n2
n1,n1
a
n2
n1,n
b
n2
n1
0 0 0 . . . 0 a
n1
n,n
b
n1
n
(4.11)
Antes de continuar con el paso dos es preciso mencionar; se le conoce como pivotes a los elementos
de la diagonal principal. Para realizar la eliminacion hacia atras se parde de (4.11), al nalizar este
paso se tendra una matriz identidad para los coecientes y los valores de los terminos independientes
corresponderan al valor de la incognita que no es cero. Primero se divide el ultimo renglon entre
a
n1
n,n
. De esta forma se obtiene 1 en ese pivote.
Para eliminar el n-esimo coeciente del i-esimo renglon basta con multiplicar el n-esimo coe-
ciente por el ultimo renglon (renglon n), este resultado restarlo al i-esimo renglon. Con ello se tiene
3
Esta matriz fue extrada de la p agina 187 del libro de [28].
Preliminares: metodos directos 75
la nueva matriz,
a
1,1
a
1,2
a
1,3
. . . a
1,n1
0

b

1
0 a

2,2
a

2,3
. . . a

2,n1
0

b

2
0 0 a
3,3
. . . a
3,n1
0

b

3
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
0 0 0 . . . a
n2
n1,n1
0

b

n1
0 0 0 . . . 0 1

b
n
(4.12)
Para convertir en 1 el pivote del renglon n 1, se divide ese renglon por su pivote. Se eliminan
los coecientes de la columna (n 1), para i < n 1, restando al i-esimo renglon la multiplicacion
del n-esimo coeciente del i-esimo renglon. Con este procedimiento se tiene la matriz de la siguiente
manera
a
1,1
a
1,2
a
1,3
. . . 0 0

b

1
0 a

2,2
a

2,3
. . . 0 0

b

2
0 0 a
3,3
. . . 0 0

b

3
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
0 0 0 . . . 1 0

b

n1
0 0 0 . . . 0 1

b
n
(4.13)
Continuando con este procedimiento se tiene el siguiente resultado el cual representa la solucion
del sistema lineal de ecuaciones
1 0 0 . . . 0 0

b
n1
1
0 1 0 . . . 0 0

b
n2
2
0 0 1 . . . 0 0

b
n3
3
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
0 0 0 . . . 1 0

b

n1
0 0 0 . . . 0 1

b
n
(4.14)
La eliminacion de Gauss-Jordan es uno de los metodos mas simples para la solucion de sistemas
de ecuaciones lineales, este metodo representa una gran ventaja sobre la regla de Kramer porque
disminuye considerablemente el n umero de operaciones necesarias. El orden de complejidad para este
76 Captulo 4. Metodo Iterativo de Jacobi
metodo es O(n
3
); pero esto no es suciente para sistemas lo sucientemente densos. Como menciona
Nakamura [28] tiene la desventaja de ser poco eciente para un unico conjunto de ecuaciones.
Descomposicion o factorizaci on LU
Este metodo es mas complejo que los dos anteriores, cabe mencionar que es una variante de la
eliminacion gaussiana y su orden de complejidad concuerda con ello O(2n
3
/3) [25]. Como menciona
De la Fuente [14] este metodo representa una matriz cuadrada A con dos matrices, una triangular
inferior L y otra triangular superior U, para sistemas de la forma Ax = b tal que satisfaga
A = LU (4.15)
sustituyendo (4.15) en Ax = b se tiene
LUx = b (4.16)
haciendo Ux = z y sustituyendo en (4.16) queda
Lz = b (4.17)
despejando z de (4.17) se tiene lo siguiente
z = L
1
b (4.18)
retomando Ux = z y sustituyendo en (4.18) hasta tener
x = U
1
z (4.19)
Como menciona Nakamura [28] para encontrar la solucion de un sistemas de n incognitas se
resuelve con dos pasos para ello se toma (4.17), el primero llamado eliminacion hacia adelante, en
este paso se obtiene el valor de z con se muestra
z
1
= b
1
z
i
= b
i

_
i1

j=1
l
i,j
z
i
_
i = 2, 3, . . . , n
(4.20)
4.1. Concepto 77
El segundo paso, llamado eliminacion hacia atras,
x
n
=
zn
un,n
x
i
=
z
i

j=i+1
u
i,j
x
j
u
i,i
i = n 1, n 2, . . . , 1
(4.21)
Con base a Nakamura [28] con (4.20) y (4.21) se encuentra el resultado del sistema pero hasta
este momento no se ha empleado el pivoteo; es muy importante su utilizacion en la practica. Como
menciona Kolman et al.[25] este metodo es muy utilizado porque permite resolver numericamente
sistemas de ecuaciones donde lo unico cambiante son los terminos independientes. Cabe mencionar
que este metodo se utiliza en los temas siguientes.
4.1. Concepto
El Metodo de Jacobi llamado as en honor al matematico aleman Carl Gustav Jacob Jacobi
(1804-1851). Es considerado el metodo iterativo mas simple para resolver sistemas de ecuaciones
lineales y se aplica solo a sistemas cuadrados, es decir, a aquellos que tienen tantas incognitas
como ecuaciones. Es usado para el analisis de circuitos, para soluciones numericas de ecuaciones
diferenciales y los problemas con valor en la frontera.
Es preciso denir que es un metodo iterativo; es aquel que progresivamente va calculando apro-
ximaciones a la solucion de un problema, repitiendo el mismo procedimiento en cada iteracion a n
de obtener una mejor aproximacion que la inicial. El proceso se repite sobre esta nueva solucion
aproximada hasta que el resultado reciente cumpla con ciertas condiciones. Los esquemas iterativos
son usados cuando se desconoce un metodo para obtener la solucion en forma exacta. Tambien se
utilizan cuando el metodo para determinar la solucion exacta requiere mucho tiempo de calculo,
cuando una respuesta aproximada es adecuada, y cuando el n umero de iteraciones es relativamente
reducido.
En palabras de Burden et al.[7], Un metodo iterativo para resolver un sistema de ecuaciones
lineales de la forma Ax = b, comienza con una aproximacion inicial x
(0)
a la solucion x se genera
una sucesion de vectores x
(k)

k=0
que convergen a x. La aproximacion inicial x
(0)
esta representado
por un valor arbitrario.
78 Captulo 4. Metodo Iterativo de Jacobi
El metodo o esquema de Jacobi sirve para resolver ecuaciones lineales de la forma
Ax = b (4.22)
donde A R
NN
, y x, b R
N
Para su mejor estudio se descompone la matriz A de la siguiente forma
A = L + D + U (4.23)
donde,
L = Lower(inferior), es una matriz triangular inferior de A,
D = Diagonal, es una matriz diagonal de A y
U = Upper (superior), es una matriz triangular superior de A.
Sustituimos en (4.22) lo que se ha hecho con anterioridad, ademas sustituimos a x por su
aproximacion (x

),
(L + D + U)x

= b
Distribuyendo a A R
NN
, y x R
N
tenemos
Lx

+ Dx

+ Ux

= b
Al despejar Dx

nos queda la siguiente ecuacion


Dx

= (L + U)x

+ b
Llamaremos a D
1
la inversa de la matriz D, debido a
D
1
D = I
Para ello I es una identidad de la forma
_
_
_
_
_
_
_
_
1 0 0
0 1 0
.
.
.
.
.
.
.
.
.
.
.
.
0 0 1
_
_
_
_
_
_
_
_
4.1. Concepto 79
Haciendo uso de la identidad, antes expuesta, despejamos hasta obtener la forma matricial del
metodo de Jacobi que se expresa a continuacion
x = D
1
(L + U)x

+ D
1
b (4.24)
Siempre que la matriz sea diagonal dominante, la ecuacion (4.24) seguro converge a la solucion.
Una matriz se dice que es diagonalmente dominante, si y solo si en cada uno de los renglones, el
valor absoluto del elemento de la diagonal principal es mayor que la suma de los valores absolutos
de los elementos restantes del mismo renglon. A veces la matriz de un sistema de ecuaciones lineales
no es diagonalmente dominante pero cuando se cambian el orden de las ecuaciones y las incognitas
el nuevo sistema puede ser matriz de coecientes diagonalmente dominante; es decir,
0 <
n

j=1,j=i
[a
ij
[ < [a
ii
[ i = 1, 2, . . . , n (4.25)
Cuando se aplica Jacobi donde la matriz no es diagonalmente dominante es suciente para que no
exista garanta de convergencia. Sin embargo, en algunos casos sera posible re-ordenar las incognitas
de otra manera de tal forma que la nueva matriz de coecientes sea diagonalmente dominante. Esto
se puede detectar revisando todos los posibles ordenamientos de las incognitas y ver como es la
matriz resultante. Claro que esto conlleva un buen n umero de pruebas puesto que el n umero posible
de ordenamientos en n-variables es de (n 1)! pero cuando n es reducido es sencillo.
La ecuacion (4.24) se puede representar de la siguiente forma iterativa y converge a la solucion:
x
k+1
= D
1
(L + U)x
k
+ D
1
b, x
k
R y k = 1, 2 . . . n
_
x
0
, x
1
, x
2
, . . . , x
n
converge a la solucion
Lo cual se puede expresar como,
x
k+1
i
=
1
a
ii
_
_
b
i

j=1j=i
a
ij
x
k
j
_
_
(4.26)
Uno de los principales problemas de los metodos iterativos es la garanta de que el metodo va a
converger, es decir, va a producir una sucesion de aproximacion cada vez mas efectiva a la solucion.
En el caso del metodo de Jacobi no existe una condicion exacta para la convergencia. Lo mejor es
80 Captulo 4. Metodo Iterativo de Jacobi
una condicion que garantice la convergencia pero en caso de no cumplirse, la sucesion puede o no
converger; la condicion es la siguiente: Si la matriz de coecientes original del sistema de ecuaciones
es diagonalmente dominante (4.25), el metodo de seguro converge.
Para determinar cuando la sucesion x
0
, x
1
, x
2
, . . . , x
n
converge a la solucion se emplean crite-
rios de paro; es aqu donde se denomina aproximacion al resultado, ya que se utiliza un error ()
para denir el grado de aproximacion del resultado. El valor denido para no es constante sino
esta adherido al tipo de problema y dependera directamente del grado de exactitud que se desee
obtener. Hay que tener presente que conforme el rango de error disminuya ( 0), el tiempo de
calculo aumentara. Algunos criterios de paro son la norma innita del residual y la de la diferencia
de x en la iteracion actual respecto a la iteracion anterior como se muestra a continuacion,
|x
k+1
x
k
|

< (4.27)
Llevar a cabo (4.27) resulta trivial y es por demas profundizar. La norma innita del residual
en la k-esima iteracion se expresa como,
|r
k+1
|

< (4.28)
En ambos casos, (4.27) y (4.28), el valor para debe ser peque no (generalmete 10
3
) esto
representa el margen de error que tendra la aproximacion. Para valores de muy peque nos (10
9
,
por mencionar) la cantidad de iteraciones de procesamiento que se llevaran a cabo es un punto a
considerar, ya que con esto la resolucion del problema tardara mucho tiempo.
La denicion del algoritmo del esquema iterativo de Jacobi, con base a lo que se ha mencionado,
se presenta a continuacion.
Algoritmo 4.1 Algoritmo del Metodo de Jacobi
Esta denido por los siguientes seis pasos:
1. Hacer k = 0
2. Mientras (4.27) o (4.28) se tornen falsas llevar a cabo los pasos 3-5
3. Hacer
x
i
=
b
i

j=1j=i
a
ij
x

j
a
ii
i = 1, 2, . . . , n
4.2. Codicacion del metodo de Jacobi en C 81
4. para i = 1, 2, 3, . . . , n hacer x

i
= x
i
5. Aumentar el valor de k en uno (k = k + 1)
6. Mostrar los valores de (x
1
, x
2
, x
3
, . . . , x
n
)
Durante esta seccion se planteo el esquema de Jacobi ello permite tener las bases para crear una
aplicacion que resuelva numericamente un sistema lineal de ecuaciones mediante este metodo. En
los siguientes temas se lleva a cabo esta tarea, en primera instancia para una ejecucion no paralela
y despues en una que sea ejecutada por m ultiples n ucleos de forma simultanea.
4.2. Codicacion del metodo de Jacobi en C
En esta seccion se realiza una primera implementacion del esquema de Jacobi con base al al-
gorimo 4.1 desarrollado en el tema pasado. La aplicacion es realizada por etapas. El primer paso
consiste en escribir el codigo en lenguaje C. Cuando sea cumplido ese paso, se procede a optimizar
la aplicacion mediante tecnicas de programacion as como disminuir los cuellos de botella; con ello
el rendimiento aumentara. Para nalizar se debe convertir esa aplicacion serial en una paralela, la
cual pueda ser ejecutada de forma paralela en computadoras multin ucleo de memoria compartida.
En el siguiente codigo de la gura 4.1 se describe el primer paso, implementar el metodo de Jacobi
de acuerdo al algoritmo 4.1.
En la gura 4.1 se describe un fragmento de codigo de una primera implementacion. Si comple-
mentamos el codigo anterior, ya tenemos un programa que resuelve sistemas de ecuaciones lineales
por el metodo de Jacobi. Cuando se implementan los algoritmos en programacion se busca que este
pueda ser ejecutada lo mas rapido que sea posible, para reducir el tiempo de procesamiento, esto es
determinante para conocer la calidad de nuestro programa y es por ello que adaptar la interpretacion
de algoritmo para que se adapte a los recursos que se tienen se vuelve prioridad.
Con lo ya mencionado nos damos cuenta que la implementacion anterior no cumple totalmente
con esos planteamientos, es decir no es una opcion para el problema, a consecuencia se realizara una
adaptacion. Ello se realiza en los temas posteriores.
4.2.1. Simplicando c odigo
En esta seccion se realiza una modicacion de la ecuacion iterativa de Jacobi (4.26) para simpli-
car el codigo y quitar el cuello de botella provocado por la ejecucion de la condicion en el producto
82 Captulo 4. Metodo Iterativo de Jacobi
Primera Implementacion de Jacobi
for( k = 0; ; k++)
{
for( i = 0; i < n; i++)
{
suma = 0.0;
for( j = 0; j < n; j++)
if( j != i)
suma += A[i][j] * x_old[j];
x[i] = (b[i]-suma)/A[i][i];
}
if(norma_Infinita(x, x_old, n) < E)
break;
clonar(x_old, x, n);
}
Figura 4.1: Primera implementacion del metodo de Jacobi en lenguaje C.
punto que impera en la ecuacion mencionada.
Como es sabido el tiempo de procesamiento de una sentencia (if) es mayor a una operacion y
como se encuentra anidado, es decir se ejecutara n
2
veces por iteracion, sera necesario removerlo,
para ello recordemos (4.26) que se muestra a continuacion,
x
k+1
i
=
1
a
ii
_
_
b
i

j=1,j=i
a
ij
x
k
j
_
_
Para anular la sentencia (j ,= i), debemos quitarla de

n
j=1,j=i
a
ij
x
k
j
partiendo de la siguiente
ecuacion
n

j=1
a
ij
x
k
j
= a
1,1
x
k
1
+ a
1,2
x
k
2
+ + a
n,n
x
k
n
i = 1, 2, . . . , n (4.29)
Con (4.29) deducimos los siguiente
n

j=1,j=i
a
ij
x
k
j
=
n

j=1
a
ij
x
k
j
a
ii
x
k
i
i = 1, 2, . . . , n (4.30)
4.2. Codicacion del metodo de Jacobi en C 83
Esquema de Jacobi en lenguaje C
for( k = 0; ; k++)
{
for(i = 0; i < N; i++)
{
suma = 0.0;
for( j = 0; j < N; j++)
suma += A[i][j] * x_old[j];
x[i] = ( (b[i] - suma) / A[i][i] ) + x_old[i];
}
norma = normInfinita(x, x_old, n);
if(norma < E)
break;
clonar(x_old, x, n);
}
Figura 4.2: Codigo en lenguaje C del esquema de Jacobi.
Sustituimos la igualdad en (4.26) y tenemos,
x
k+1
i
=
1
a
ii
_
_
b
i

j=1
a
ij
x
k
j
a
ii
x
k
i
_
_
i = 1, 2, . . . , n (4.31)
A continuacion simplicamos (4.31) para obtener
x
k+1
i
=
1
a
ii
_
_
b
i

j=1
a
ij
x
k
j
_
_
+
1
a
ii
a
ii
x
k
i = 1, 2, . . . , n (4.32)
Ello puede ser expresado como se muestra a continuacion
x
k+1
i
=
1
a
ii
_
_
b
i

j=1
a
ij
x
k
j
_
_
+ x
k
i
i = 1, 2, . . . , n (4.33)
Una vez que se ha removido la condicion (j ,= i) se dice que se tiene una adaptacion en (4.33);
esta nueva adaptacion es mas rapida que la de (4.26) y es facilmente demostrable. Antes de ello es
preciso denir los cambios que sufre el primer codigo a consecuencia de los anterior. Ello se describe
en la gura 4.2.
84 Captulo 4. Metodo Iterativo de Jacobi
Figura 4.3: Porcentaje del tiempo de ejecucion del metodo de Jacobi con y sin sentencia if.
Con la codicacion de la gura 4.2 se tiene un programa que es ejecutado en un n ucleo sin
contratiempos, y solamente con la necesidad de introducir las ecuaciones de acuerdo a las condiciones
que imponen el metodo; es decir es una version compacta de un programa que resuelve sistemas de
ecuaciones lineales, y solo se muestra la seccion del programa donde se realizan las iteraciones. En
el momento en que la ejecucion llegue a ese punto, debe ser evaluada para conocer si cumple las
imposiciones del Metodo de Jacobi: si la matriz de coecientes es estrictamente diagonal dominante.
A continuacion se muestra que efectivamente la segunda codicacion aumenta el rendimiento del
programa y que de esta forma estamos aumentando el desempe no del programa. Para esta ocasion
se utilizo una matriz A sucientemente densa, con el n de hacer mas notable la diferencia entre las
implementaciones; tambien tomemos en cuenta que se denio el n umero de iteraciones (k = 100) a
n de reducir el tiempo de ejecucion del programa, es decir, el resultado que se presenta es con el
objetivo de comparar cuando se tiene la condicion (if) y cuando se ha removido; no tanto a encontrar
la solucion del sistema de ecuaciones lineales, para este caso en particular. En la tabla 4.1 se realiza
la ejecucion del programa sin utilizar alguna de las banderas de compilacion.
4.2. Codicacion del metodo de Jacobi en C 85
Tabla 4.1: Metodo iterativo de Jacobi: primera evaluacion de rendimiento, observamos el porcentaje
de la reduccion del tiempo en ejecucion cuando se remueve la condicion (if).
Primera Evaluacion de Rendimiento
Sin Bandera de Compilaci on
Valor de Tiempo de Ejecucion Tiempo de Ejecucion Reduccion de
N Con if (segundos) Sin if (segundos) Tiempo ( %)
100 0.006 0.005 15.5
200 0.024 0.020 13.9
300 0.056 0.046 17.4
400 0.101 0.082 18.7
500 0.159 0.127 19.8
600 0.230 0.183 20.3
700 0.315 0.249 21.7
800 0.413 0.326 21.0
900 0.526 0.414 21.2
1000 0.657 0.517 21.3
2000 2.461 2.084 15.3
3000 5.653 4.690 17.0
4000 10.221 8.343 18.4
5000 16.145 13.030 19.3
6000 23.416 18.761 19.9
7000 32.086 25.553 20.4
8000 42.125 33.386 20.7
9000 53.517 42.299 21.0
10000 66.229 52.198 21.2
86 Captulo 4. Metodo Iterativo de Jacobi
Vista general de Jacobi optimizado
for( k = 0; ; k++)
{
for(i = 0; i < N; i++)
{
dotVect = dot_vector(A[i], x_old, N);
x[i] = (b[i] - dotVect) / A[i][i] + x_old[i];
}
norma= normInfinita(x, x_old, n);
if(norma < E)
break;
clonar(x_old, x, n);
}
Figura 4.4: Codigo general de Jacobi optimizado.
Con base a lo que se observa en la tabla 4.1 decimos que la sentencia (if) es un problema de
rendimiento, el cual se torna mas grave conforme la matriz A se hace mas densa. Como se muestra,
representa un problema muy serio de rendimiento ya que en promedio se lleva la quinta parte del
tiempo de ejecucion. En la gura 4.3 se muestra en forma de graca los resultados expuestos, en
ella si ilustra el porcentaje que se reduce cuando se elimina la sentencia mencionada.
Debido a lo anterior se concluye que un programa que tiene un gran n umero de condiciones if
y que no sean fundamentalmente necesarias, se cataloga como un programa de bajo rendimiento.
Para este caso, remover la condicion antes mencionada represento una tarea muy facil y al mismo
tiempo resulto ser una enorme ventaja, esto no quiere decir que para absolutamente todos los casos,
el comportamiento sea semejante; pero en la mayora de los caso eso ocurrira. Este es un primer
paso para ir poco a poco renando un programa, mas adelante se abordan distintas maneras para
aumentar el rendimiento del programa, y que se pueden implementar en otros problemas.
4.2.2. Optimizaci on de codigo
En este apartado se realiza una optimizacion del codigo creado en la segunda version. Exclusi-
vamente en el producto punto, las cuales fueron estudiadas en el captulo anterior. El codigo de la
segunda implementacion unicamente se modica el producto punto por su equivalente con unroll
looping y MMX. Se mide el desempe no computacional que tienen cada uno de ellos.
4.3. Metodo de Jacobi en paralelo con OpenMP 87
Figura 4.5: Tiempos de ejecucion de Jacobi en serie, versiones [Canonica, Unroll4, MMX] para
n = 5000.
En la gura 4.4 se describe un codigo general que implementa el esquema de Jacobi. La funcion
dot vector representa el nombre de la funcion optimizada que llevara a cabo la multiplicacion de
dos vectores. Para este caso Unroll-4 o MMX que corresponde a las guras 3.4 y 3.19 respectivamente
(Estas funciones se estudian con m as detalle en el captulo anterior).
En la gura 4.5 se ilustra el resultado de los tiempos de ejecucion de las tres versiones del
Esquema de Jacobi (Canonica, Unroll-4 y MMX) en ella se observa de una forma muy clara que el
desempe no realizado por la funcion MMX es muy superior a sus semejantes.
Con base a los resultados obtenidos en la gura 4.5 se concluye lo siguiente; el paradigma de
programacion MMX tiene un mayor desempe no computacional que Unroll-4, y se ve reejado de
manera mas positiva bajando a la mitad (MMX) y a dos terceras partes (Unroll-4) el tiempo de
ejecucion implementando las tecnicas estudiadas en el captulo anterior. Este rango de ahorro de
tiempo es muy bien recibido por parte del usuario nal. Sin embargo, esto no signica que para la
version en paralelo ocurra exactamente lo mismo. Para una aplicacion en serie es mejor la tenica
MMX.
4.3. Metodo de Jacobi en paralelo con OpenMP
En esta seccion se hace en paralelo la version canonica de Jacobi de la gura 4.4 utilizando la
directiva de OpenMP. Cuando se codico el Metodo de Jacobi para un n ucleo resulta obvio que
88 Captulo 4. Metodo Iterativo de Jacobi
el rendimiento que se obtiene no cumple con los requerimientos actuales. Los cuales consisten en
explotar al maximo los recursos de la computadoras a las que se tengan acceso. El programa de
la mencionada gura solo explota un procesador cuando se debe explotar todos los procesadores
(2, 4, 8) mediante el uso de programacion en paralelo. El principal benecio de este paradigma es
la reduccion del tiempo de ejecucion de las aplicaciones con la distribucion de cargas de trabajo a
cada uno de los procesadores de la computadora. En la gura 4.6 se muestra el resultado obtenido
de una primera implementacion de Jacobi en paralelo.
Version canonica en paralelo de Jacobi
for(k = 0; ; k++)
{
#pragma omp parallel for default(none) \
shared(x,x_old,b,A,N) private(i,dotVect)
for(i = 0; i < N; i++)
{
dotVect = dot_can(A[i], x_old, N);
x[i] = (b[i] - dotVect) / A[i][i] + x_old[i];
}
norma = normInfinita(x, x_old, N);
if(norma < E)
break;
clonar(x_old, x, N);
}
Figura 4.6: Codigo de version canonica en paralelo de Jacobi.
El codigo de la gura 4.6 es una primera implementacion del Esquema de Jacobi en paralelo
con OpenMP. En la fraccion de codigo tenemos una funcion dot can(oat *a, oat *b, int n) que
realiza la multiplicacion de dos vectores de forma tradicional (canonica). Ademas en este programa
no se desarrolla todo el codigo necesario para dos funciones. La primera funcion normInnita(oat*
a,oat* b,int n) calcula la norma innita de la diferencia de los vectores argumento (a,b) de la
funcion. La segunda subrutina clonar(oat* a,oat* b,int n) en esta funcion se guardan los valores
del vector b al vector a, es decir a(1 : n) = b(1 : n). Cabe mencionar que este codigo terminara su
ejecucion si y solo si se cumple la condiccion de paro; la norma innita del valor actual de x menos
el anterior, es decir (|x
k+1
x
k
|

).
En la gura 4.7 se ilustra el speed-up que desempe na el codigo de la gura 4.6. En ella se observa
4.3. Metodo de Jacobi en paralelo con OpenMP 89
10
2
10
3
10
4
0
1
2
3
4
5
6
Valor de N
S
p
e
e
d

u
p


1Core
2Cores
4Cores
8Cores
Figura 4.7: Speed-up del metodo de Jacobi en paralelo en su version canonica.
el incremento de la velocidad de ejecucion cuando se incrementa el n umero cores. El comportamiento
del speed-up es comparable al que se registro en la mutiplicacion matriz vector. Para valores de n
reducidos la ganancia disminuye conforme n 0; aunado a ello cuanto mas grande sea el n umero
de cores la ganancia disminuye. En el caso contrario, cuando n es mayor el aumento del speed-up
crece casi de forma proporcional para los casos de 2 y 4 cores; en el otro caso (8 cores) el incremento
es menor; aproximadamente 6 cuando debera estar cercano a los 8x; ello se debe al dise no de la
computadora empleada, esta cuenta con 2 procesadores de 4 cores cada uno de ellos, al utilizar el
total de 8 cores se vuelve imprescindible el uso del tercer nivel de cache el cual esta mas lejano. Ese
retraso en el acceso a los datos es el principal motivo por el cual no se cumple con lo teoricamente
esperado; Sin embargo, estos resultados son congruentes con la ley de Amdahl.
Con base a los resultados obtenido es concluyente que la version canonica de Jacobi es altamente
paralelizable lo cual se lleva a cabo solo con denir la directiva de OpenMP adecuada para el
algoritmo. Al igual que la multiplicacion de una matriz por un vector en este algoritmo no se presenta
la dependencia de operaciones; esto con base al planteamiento que sea realizado y principalmente
a las deniciones del metodo lo cual sea indica en la seccion siguiente. Realizar una aplicacion que
en terminos de computacion se mas eciente, se hara uso de las tecnicas que en temas anteriores se
90 Captulo 4. Metodo Iterativo de Jacobi
trataron, como es el caso de la tecnologa MMX.
4.4. Evaluaci on de algoritmo en paralelo
En el captulo anterior se realizo una funcion para resolver el producto de una matriz por un
vector la cual implementa paralelismo a nivel de datos. Esta funcion es la que mejor rendimiento
presenta. Con base a la ecuacion de Jacobi (4.33) se utiliza dicha funcion para optimizar la ejecucion
del programa.
Como resultado de ello se tiene el programa como el que se describe en la gura 4.5 pero
realizando cambios signicativos, en primer lugar incluimos la directiva pragma de la gura 4.6
esto indicara que la siguiente sentencia for sera tratada en paralelo. El resto consiste en cambiar
el nombre de la funcion dot can por dot mmx que corresponde a la subrutina realizada en la
gura 3.19 del captulo anterior (pagina 55). El resultado que se obtiene despues de realizar las
modicaciones planteadas; es una funcion que implementa el esquema iterativo de Jacobi utilizando
la tecnica de MMX. Como se estudio en el tema pasado la escalabilidad de MMX es diferente de la
version canonica, en la gura 4.8 se ilustra este hecho.
10
2
10
3
10
4
0
0.5
1
1.5
2
2.5
3
3.5
Valor de N
S
p
e
e
d

u
p


1Core
2Cores
4Cores
8Cores
Figura 4.8: Speed-up del metodo de Jacobi en paralelo en su version MMX.
4.4. Evaluacion de algoritmo en paralelo 91
En la gura 4.8 se muestra un resultado muy claro, la escalabilidad de esta version es considera-
blemente mas pobre que la canonica. La ganancia de ejecutar con 4 y 8 cores es casi insignicante
con respecto a 2 cores y a lo teoricamente esperado, a un para un tama no de n relativamente ma-
yor; el speed-up para 4 cores es en promedio 2.7x mientras que para 8 cores es de 2.9x cuando
teoricamente debiera ser de 4x y 8x respectivamente. La consistencia de la escalabilidad comparada
con el problema Ax persiste. Al igual que en la version canonica para valores de 0 < n < 300 es
contraproducente el uso de mas de un procesador para la solucion del problema, para el resto de los
casos la situacion mejora conforme la matriz A se vuelve mas densa. Es claro que de cierto modo
la escalabilidad proporcional se presenta para la ejecucion en dos cores, en los valores 4000-10000
de n; el speed-up es insignicantemente menor al valor ideal 2x.
Con los resultados obtenidos es concluyente que la version canonica de Jacobi es mas escalable
que su version MMX; sin embargo, esta ultima tiene un mejor desempe no (para las condiciones de
ejecucion ya mencionadas). Estos resultados son muestra solida del benecio de utilizar algoritmos
paralelos.
A lo largo del estudio del esquema iterativo de Jacobi se realiza una optimizacion para retirar
una sentencia if con lo que reducimos en 20 % el tiempo de ejecucion. Este cambio mencionando
representa un punto de partida para la optimizacion pero mas alla de ello permite remover una
condicion innecesaria para realizar la programacion en paralelo. Tomando la tecnica de programacion
MMX implementada en la funcion escrita en el captulo anterior se tienen resultados con un speed-
up de 3.0x para 8 n ucleos, esta funcion es la que mejor desempe no computacional presento (en
el captulo 3). Cabe se nalar que al igual que el tema anterior la version canonica tiene una mejor
escalabilidad con un promedio de 5.5x para 8 n ucleos y para 2 y 4 cores una escalabilidad de 2.0x
y 3.8x lo cual representa practicamente una escalabilidad lineal.
Captulo 5
Metodo de Gauss-Seidel
5.1. Concepto
Es preciso denir que es un metodo iterativo. Es aquel que progresivamente va calculando
aproximaciones a la solucion de un problema; repitiendo el mismo procedimiento, en cada iteracion,
a n de obtener una mejor aproximacion que la inicial; el proceso se repite sobre esta nueva solucion
aproximada hasta que el resultado reciente cumpla con ciertas condiciones. Se desarrollan este tipo
de esquemas numericos cuando se desconoce un metodo que permita resolver el problema con una
solucion exacta. Tambien se utilizan cuando el metodo para determinar la solucion exacta requiere
mucho tiempo de calculo, cuando una respuesta aproximada es adecuada, y cuando el n umero de
iteraciones es relativamente reducido.
El esquema de Gauss-Seidel (GS) es uno de los metodos iterativos mas populares a razon de
su facil aplicacion e implementacion en las computadoras. Consiste en despejar una incognita por
ecuacion y el resultado es utilizado en la misma iteracion para el calculo de las incognitas conse-
cuentes. Este metodo esta basado te oricamente en el esquema de Jacobi pero tienen diferencias muy
marcadas lo cual hace de GS mas eciente.
La gran diferencia entre los metodos de Jacobi con respecto Gauss-Seidel es que este ultimo
utiliza los nuevos valores que se van obteniendo, durante la presente iteracion, para encontrar los
valores del resto de las incognitas; esto representa el motivo por el cual GS es generalmente superior
que Jacobi.
Al igual que en el metodo de Jacobi si la matriz de coecientes es diagonal dominante [ver (4.25)
93
94 Captulo 5. Metodo de Gauss-Seidel
de la pagina 79] la convergencia es segura, en caso contrario puede o no converger. Como inere
Gomez et al.[18], cuando no hay dominio diagonal, lo que se recomienda es hallar el coeciente de
la matriz de mayor valor absoluto y despejar de ese renglon en el que se encontro, a la incognita
correspondiente, luego el procedimiento se repite con las restantes incognitas del sistema hasta
terminar.
Como menciona Karniadakis et al.[23], normalmente el Metodo de Gauss-Seidel converge dos
veces mas rapido que el de Jacobi; y cuando converge generalmente lo hace de forma lineal.
Con lo que se ha dicho con anterioridad, se procede a descomponer la matriz A de la ecuacion
Ax = b de la siguiente forma.
D L U = A (5.1)
Al sustituir la matrix A por su equivalente(5.1) tenemos lo siguiente
(D L U)x = b (5.2)
Realizando las siguientes operaciones para despejar x y de ese modo encontrar la forma matricial
del Metodo Iterativo de Gauss-Seidel,
(D L)x Ux = b
(D L)x = Ux + b
Por ultimo se despeja x para tener
x = (D L)
1
Ux + (D L)
1
b (5.3)
En (5.3) se representa la forma matricial del Metodo Iterativo de Gauss-Seidel y la podemos
representar la siguiente forma iterativa y converge a la solucion x
1
, x
2
, . . . , x
k
para cualquier vector
inicial x
0
R
N
x
k+1
= (D L)
1
Ux
k
+ (D L)
1
b x
k
R
N
, k = 1, 2, . . . , n (5.4)
5.1. Concepto 95
donde, (D L)
1
es la inversa de (D L), es decir
(D L)
1
(D L) = I (5.5)
siendo I una identidad de la forma,
_
_
_
_
_
_
_
_
1 0 0
0 1 0
.
.
.
.
.
.
.
.
.
.
.
.
0 0 1
_
_
_
_
_
_
_
_
de forma compacta, tenemos
x
k+1
= Hx
k
+

b (5.6)
donde, H = (D L)
1
U y

b = (D L)
1
b
A continuacion se muestra la ecuacion iterativa del Metodo de Gauss-Seidel
x
k+1
i
=
1
a
ii
_
_
i1

j=1
a
ij
x
k+1
j
+
n

j=i+1
a
ij
x
k
j
_
_
+
1
a
ii
b
i
(5.7)
donde, A R
NN
, y x, b R
N
El Metodo de Gauss-Seidel es facil para su aplicacion como se mostrara mas adelante. Como se
puede observar al comparar las ecuaciones iterativas del esquema de Jacobi (4.33) y la de este metodo
(5.7) notamos que son muy semejantes; lo importante aqu no es eso sino, encontrar las diferencias
entre ambos. La mas notoria es que en Gauss-Seidel se utilizan los nuevos valores obtenidos para
calcular el resto en la iteracion actual; mientras que en Jacobi se utilizan unicamente los valores
correspondientes a la iteracion anterior. El hecho de utilizar todos los nuevos valores, se vuelve muy
practico en computacion porque no solamente se va a reducir el n umero de iteraciones necesarias
para converger, sino que ademas se utiliza una cantidad menor de memoria; esta propiedad nos da
la ventaja de guardar los nuevos valores en el espacio donde se encuentran los valores anteriores.
Con base a lo mencionado se puede describir el algoritmo de programacion para el metodo, en el
algoritmo 5.1 se indica.
96 Captulo 5. Metodo de Gauss-Seidel
Algoritmo 5.1 Algoritmo del Metodo de Gauss-Seidel
Esta denido por los siguientes cinco pasos:
1. Hacer k = 0
2. Mientras (4.27) o (4.28) sea falso repetir los pasos 3,4.
3. Hacer
x
i
=
b
i

j=1j=i
a
ij
x
j
a
ii
i = 1, 2, . . . , n
4. Hacer k = k + 1
5. Mostrar los valores de (x
1
, x
2
, x
3
, . . . , x
n
)
Con la ayuda del algoritmo 5.1 se puede escribir el codigo de una funcion que implementa este
metodo. Si comparamos este algoritmo con el de Jacobi encontramos una diferencia principal, en
este metodo solo se utiliza una variable x con lo cual se ahorra el proceso de actualizar los datos
(en Jacobi x
old
= x
new
). En los temas posteriores se analizan numericamente las diferencias entre
ambos metodos.
5.2. Programaci on en lenguaje C
En esta seccion se realiza la implementacion computacional del Metodo de Gauss-Seidel con
Lenguaje C. Tomando la ecuacion iterativa de G-S (5.7) se realiza el codigo de la gura 5.1 para
una version canonica.
Comparando esta implementacion con la del metodo de Jacobi, antes de hacerla paralela y
de utilizar el procesamiento vectorial, notamos que las diferencias en el codigo son mnimas, esto
no signica que el resultado sera semejante. Como se observa escribir el codigo para el metodo
de Gauss-Seidel es por demas sencillo. Cabe mencionar que el codigo de la gura 5.1 utiliza dos
vectores para x (x y x old) esto se debe exclusivamente por la condicion de paro. El vector x old se
utiliza para almacenar los valores de la iteracion anterior, ello para despues utilizarlo en el calculo
de la norma innita de la diferencia de la iteracion actual respecto a la anterior |x
k+1
x
k
|

. Es
importante destacar que existen mas condiciones de paro donde no es necesario este vector.
Como menciona Burden et al.[7], el Metodo Iterativo de Gauss-Seidel es una mejora hecha al
esquema de Jacobi. A esto se debe la similitud, muy marcada, entre estos esquemas numericos, los
cuales en terminos de error arrojan resultados muy similares.
5.3. Codicacion en paralelo 97
Codificacion de Gauss-Seidel
for(k = 0; ; k++)
{
for(i = 0; i < n; i++)
{
x_old[i] = x[i];
suma = 0.0;
for(j = 0; j < n; j++)
suma += A[i][j] * x[j];
x[i] = (b[i] - suma)/A[i][i] + x[i];
}
if(nom_inf(x,x_old) < E)
break;
}
Figura 5.1: Metodo de Gauss-Seidel en lenguaje C, version canonica.
A lo largo de todo el documento se ha demostrado el deseo de que las aplicaciones sean paralelas,
con el n de reducir los tiempo de ejecucion y as aumentar el rendimiento de las aplicaciones en
general. Al igual que con el esquema numerico anterior, en temas consecuentes se hara la implemen-
tacion en paralelo del Metodo de Gauss-Seidel con el n de medir la escalabilidad y rendimiento de
la aplicacion.
5.3. Codicacion en paralelo
La similitud entre los metodos de Gauss-Seidel y de Jacobi hace evidente una similitud muy
marcada en la programacion serial y paralela para ambos. Cuando la programacion es para la
arquitectura de memoria compartida el codigo para ambos metodos es tecnicamente muy similar.
Sin embargo, no ocurre los mismo para una ejecucion en una arquitectura con memoria distribuida;
las diferencias se centran en la actualizacion en tiempo real de los nuevos valores calculados que
deben estar disponibles para realizar el calculo del resto. Para implementar GS en sistemas de
memoria distribuidas se puede utilizar un algoritmo conocido como Black-Red el cual consiste en
dividir la matriz en bloques negros y rojos tan grandes como sean necesarios, la iteracion se divide
en dos etapas; para actualizar los bloques de los dos colores [23].
El objeto del presente documento es tratar la programacion en paralelo para computadoras con
98 Captulo 5. Metodo de Gauss-Seidel
arquitectura de memoria compartida. En la gura 5.2 se muestra el codigo de una aplicacion que
del metodo de Gauss-Seidel en paralelo con OpenMP. Como se ha mencionado en este captulo los
dos metodos (Jacobi y Gauss-Seidel) son tan semejantes que la directiva utilizada en el primero es
muy similar a la utilizada en el segundo; con lo cual el esfuerzo tambien es similar.
Codificacion en paralelo de Gauss-Seidel
for(k = 0; ; k++)
{
clonar_sv(x_old,x,n);
#pragma omp parallel for default(none) \
private(i,dotVect) shared(A,b,x,n)
for ( i = 0; i < n; i++ )
{
dotVect = vector_dot(A[i],x,n);
x[i] = (b[i] - dotVect) / A[i][i] + x[i];
}
norma = norma_inf(x,x_old,n);
if(norma < E)
break;
}
Figura 5.2: Metodo de Gauss-Seidel con OpenMP.
Para comprender el codigo de la gura 5.2 es necesario analizarlo de un forma mas detallada.
En los siguientes puntos se analizan las lneas mas importantes:
1. clonar sv(x old, x, n): en esta funcion se guardan todos los elementos del vector x al
vector x old, es decir, x old(1 : n) = x(1 : n). Cabe se nalar que esta lnea y el vector x old
estan presentes unicamente por la condicion de paro que se utiliza. Al igual que los ejemplos
anteriores, la condicion de paro es la norma innita de la diferencia de los valores de la iteracion
presente (k + 1) menos la iteracion anterior (k), es decir |x
k+1
x
k
|

.
2. dotVect = vector dot(A[i],x,n): en esta lnea lo importante es la funcion llamada
vector dot esta funcion tiene la siguiente forma oat vector dot(oat*,oat*,int) en ella se
regresa el valor de la siguiente operacion.
n

j=0
x
j
y
j
5.3. Codicacion en paralelo 99
Cabe se nalar que durante este documento se han realizado diferentes codigos que resuelven la
operacion en cuestion (En el captulo 3). Todas esas funciones tienen la misma nomenclatura
que vector dot, por lo cual podemos elegir entre esas funciones.
En el metodo de Jacobi no existe la dependencia de operaciones para calcular el i-esimo valor
de la iteracion actual (x
k+1
i
). Ello convierte a Jacobi en un metodo facil para paralelizar. Para el
caso de Gauss-Seidel s existe la dependencia de operaciones; para calcular x
k+1
i
se necesitan los
valores actuales de todos los elementos de [x
k+1
(1 : i 1)]. El codigo de la gura 5.2 no cumple con
ello; solo una aplicacion serial cumple estrictamente con el algoritmo original. Para comprender el
funcionamiento de la aplicacion se ilustra en la gura 5.3 como se puede descomponer un vector x
en dos subdominios para que cada uno de ellos sea calculado por un procesador.
Figura 5.3: Descomposicion del vector solucion x para dos procesadores.
Como se observa en la gura 5.3 cuando el procesador dos calcula los valores de su subdominio
(4:7) necesita los valores (0:4) que no estan completamente actualizados; durante una ejecucion
paralela ambos subdominios son actualizados al mismo tiempo. Para el caso de la gura en cuestion
se utilizan dos dominios haciendo referencia a que unicamente se utilizo dos procesadores, cuando
este n umero aumente; la cantidad de subdominios debe ser identico. Es preciso mencionar que
mientras mas cercas se encuentre un subdominio de n; la cantidad de valores actualizados para el
calculo de nuevos valores sera menor. Con base a Candra et al.[10] esto se trata de una dependencia
no-removible.
Este hecho nos permite inferir que la cantidad de iteraciones aumentara para cumplir con la
condicion de paro. Para determinar la diferencia en la cantidad de iteraciones que ha cambiado,
resulta muy practico determinarlo mediante un programa. Ademas debe medirse si el proceso con-
verge a la misma solucion en serie que en paralelo, esto determinara que el resultado no se altera lo
cual es de vital importancia para la programacion en paralelo.
Para determinar si la cantidad de iteraciones cambia signicativamente se eval ua el codio de la
100 Captulo 5. Metodo de Gauss-Seidel
gura 5.2 con los siguientes parametros: el vector inicial sera nulo, es decir x
0
(1 : n) = 0. Aunado a
ello se utilizo presicion simple para la representaciones de los n umero reales. Para tener un panorama
mas claro es necesario especicar los valores que seran utilizados en la matriz de coecientes para
todos lo casos es tridiagonal con la siguiente forma:
A
nn
=
_
_
_
_
_
_
_
_
_
_
_
_
_
_
_
2.01 1 0 0 0
1 2.01 1 0 0
0 1 2.01 1 0
.
.
. 0
.
.
.
.
.
.
.
.
.
.
.
.
0
.
.
. 0 1 2.01 1
0 0 0 1 2.01
_
_
_
_
_
_
_
_
_
_
_
_
_
_
_
(5.8)
Como se puede observar la matriz A es sensiblemente diagonal dominante, lo cual aumenta el
radio espectral de la matriz y por ende permite acrecentar el n umero de iteraciones; ello con el n
de maximizar la diferencia. Como menciona Arnal y Penades [3, 33] el radio espectral de una matriz
determina la rapidez de convergencia para cualquier metodo iterativo; cuanto menor sea el radio
espectral, el sistema convergera mas rapido.
Tabla 5.1: Metodo de Gauss-Seidel en paralelo; iteraciones para converger.
Gauss-Seidel en paralelo
iteraciones para converger
Valor de N umero de iteraciones por core
N 1 Core 2 cores 4 cores 8 cores
100 808 808 809 820
200 981 980 980 983
400 1073 1073 1073 1070
600 1057 1057 1057 1054
800 1043 1043 1043 1042
1000 1075 1075 1075 1077
2000 1097 1097 1097 1095
4000 1098 1098 1098 1098
6000 1121 1121 1121 1121
8000 1097 1097 1097 1093
10000 1112 1112 1112 1112
5.3. Codicacion en paralelo 101
En la tabla 5.1 se muestran los resultados que se obtienen con el n umero de iteraciones para
cada valor de n. Conforme a estos resultados el n umero de iteraciones con uno y dos cores es
practicamente invariable al igual que con cuatro n ucleos; lo que signica que la convergencia del
metodo no crece. Para el caso de ocho cores ya existe una diferencia mas marcada que las anteriores;
la mayor diferencia para la ejecucion con ocho n ucleos es para una matriz cuadrada con n = 100,
donde el aumento del n umero de iteraciones es aproximadamente 1.5 %, tomando los siguientes
valores para la matriz (n = 200 y n = 400) donde las diferencias porcentuales son 0.3 % y -0.3 %
respectivamente. Con base a estos resultados se puede inferir que mientras la matriz sea mas peque na
es mas conveniente resolverla con una menor cantidad de procesadores. Para el resto de las matrices
(n > 400) la diferencia vara en menor proporcion. Cabe se nalar que en un n umero considerable de
casos la diferencia es negativa; es decir la cantidad de iteraciones se reduce.
10
2
10
3
10
4
0
1
2
3
4
5
6
Valor de n
S
p
e
e
d

u
p


1 Core
2 Cores
4 Cores
8 Cores
Figura 5.4: Escalabilidad paralela del metodo Gauss-Seidel version canonica.
Con los resultados obtenidos y que se muestran en la tabla 5.1, la cantidad de iteraciones que
vara es despreciable, teniendo en cuenta que el promedio nos indica que la diferencia es mucho menor
al punto porcentual, lo cual es insignicante para este trabajo en particular. Otro punto importante
es el conocer si las ejecuciones en paralelo convergen a la misma solucion que la seriada, lo cual es
mas importante. Realizando las modicaciones necesarias puede comprobarse que efectivamente las
102 Captulo 5. Metodo de Gauss-Seidel
cuatro ejecuciones convergieron a la misma aproximacion.
Al igual que en el metodo de Jacobi, se mide la escalabilidad de Gauss-Seidel con el n de
evidenciar el incremento en la velocidad del algoritmo por la ejecucion en m ultiples cores. En la
gura 5.4 se ilustran los resultados de este proceso. En la imagen se describe un speed-up para
dos cores casi proporcional para valores de n 1000. Para la ejecucion en cuatro cores el speed-
up es cercano a 3.8x para los mayores tama nos de la matriz ( 5000). En el ultimo de los casos,
para la ejecucion con ocho procesadores el speed-up se sit ua aproximadamente a 5.4x para los
valores mayores de n. Estos resultados indican que el codigo de la gura 5.2 tiene una escalabilidad
comparable con la de Jacobi con un valor menor de speed-up; esta diferencia no considerable ya que
se encuentra en el orden menor a una decima.
Con base a los resultados obtenidos en este bloque es concluyente que el metodo de Gauss-
Seidel es paralelizable con OpenMP sin mayor esfuerzo al del uso de una directiva. Cabe se nalar
que no es necesario implementar el algoritmo GSBR (Gauss-Seidel Black-Red) para crear un codigo
paralelo en computadoras de memoria compartida. La diferencia del n umero de iteraciones para
una ejecucion paralela no oscila muy lejos de una seriada. Los resultados obtenidos son comparables
con los del captulo anterior por lo cual la escalabilidad del algoritmo tiene punto a favor.
5.4. Gauss-Seidel versus Jacobi
En el captulo anterior se estudio el metodo de Jacobi, y en esta seccion se realiza la comparativa
entre este y el metodo de Gauss-Seidel, con el proposito de hacer notar las diferencias en rendimiento
que se obtienen en cada uno de ellos. Durante este captulo se ha indicado que este esquema es mejor
que el de Jacobi; con los resultados de esta seccion se demuestra esta armacion.
Para estudiar la convergencia de estos dos metodos considere la siguiente ecuacion diferencial
de segundo orden

2
y
2
u +

2
x
2
u = f(x, y) en = (0, 1)[ (0, 1) (5.9)
sujeta a
u(x, y) = g(x, y) sobre
5.4. Gauss-Seidel versus Jacobi 103
A priori conocemos la solucion analtica
u(x, y) = sen xcos y (5.10)
con ello se deriva f(x, y) de (5.9)
f(x, y) = 2 sen xcos y (5.11)
Conocer la solucion analtica nos ayuda a determinar el error numerico de los esquemas iterativos.
Tomando (5.9) y discretizando con diferencias nitas se tiene
u
i+1j
2u
ij
+ u
i1j
h
2
+
u
ij+1
2u
ij
+ u
ij1
h
2
= f
ij
(5.12)
A continuacion se despeja u
ij
de (5.12)
h
2
f
ij
= u
i+1j
+ u
i1j
+ u
ij+1
+ u
ij1
4u
ij
h
2
f
ij
+ 4u
ij
= u
i+1j
+ u
i1j
+ u
ij+1
+ u
ij1
4u
ij
= h
2
f
ij
+ u
i+1j
+ u
i1j
+ u
ij+1
+ u
ij1
u
ij
=
h
2
f
ij
4
+
u
i+1j
+ u
i1j
+ u
ij+1
+ u
ij1
4
A continuacion se muestra la formula del problema
u
i,j
=
1
4
h
2
f
ij
+
1
4
(u
i+1j
+ u
i1j
+ u
ij+1
+ u
ij1
) (5.13)
Tomando (5.13) se puede hacer una adaptacion del problema para que cumpla los requerimien-
tos de los Metodos de Gauss-Seidel y Jacobi, respectivamente. A continuacion se muestran las
modicaciones para que estos se cumplan.
En primer lugar se muestra la modicacion para el esquema de Jacobi
u
k+1
i,j
=
1
4
h
2
f
ij
+
1
4
_
u
k
i+1j
+ u
k
i1j
+ u
k
ij+1
+ u
k
ij1
_
(5.14)
104 Captulo 5. Metodo de Gauss-Seidel
Codigo para Jacobi
for(k = 0; ;k++){
for(i = 1; i < n-1; i++)
for(j = 1; j < n-1; j++)
v[i][j] = -0.25 * h*h * f(i,j) + 0.25 * (u[i][j+1] \
+ u[i][j-1] + u[i+1][j] + u[i-1][j]));
if(norm_inf(u,v) < E)
break;
colonar_sm(u,v,n,n);
}
Figura 5.5: Metodo de Jacobi con diferencias nitas.
Codigo para Gauss-Seidel
for(k = 0; ;k++){
colonar_sm(v,u,n,n);
for(i = 1; i < n-1; i++)
for(j = 1; j < n-1; j++)
u[i][j] = -0.25 * h*h * f(i,j) + 0.25 * (u[i][j+1] \
+ u[i][j-1] + u[i+1][j] + u[i-1][j]));
if(norm_inf(u,v) < E)
break;
}
Figura 5.6: Metodo de Gauss-Seidel con diferencias nitas.
En segunda instancia se tiene la modicacion para el esquema de Gauss-Seidel
u
k+1
i,j
=
1
4
h
2
f
ij
+
1
4
_
u
k+1
i+1j
+ u
k+1
i1j
+ u
k+1
ij+1
+ u
k+1
ij1
_
(5.15)
Con ello se puede escribir el codio de las ecuaciones (5.14) y (5.15), a continuacion se muestra
una forma compacta de cada uno de los programas, donde se observa unicamente la fraccion donde
se llevan a cabo las iteraciones para encontrar la solucion, de cada uno de los programas. Cabe
mencionar que el margen de error utilizado para ambos casos es de 1e-8.
5.4. Gauss-Seidel versus Jacobi 105
El codigo de la gura 5.5 corresponde a la ecuacion (5.14) donde se resuelve el problema tratado
mediante el Metodo Iterativo de Jacobi. Mientras que en la gura 5.6 se escribe la implementacion
en codigo correspondiente a (5.15) donde se resuelve el problema con el Esquema de Gauss-Seidel.
En la tabla 5.2 se muestran los resultados, cuando se cuantican las iteraciones necesarias para
converger y el error (con respecto de la solucion analtica) de cada uno de ellos; para obtener esos
resultados se utilizo, como condicion de paro, la norma innita de la diferencia de los resultados
de la iteracion actual con respecto a la anterior (|u
k+1
u
k
|

< ), con una tolerancia de


error = 1
8
y para la representacion de los n umeros reales en la computadora se utilizo doble
precision cientca (double en lenguaje C). Cabe recalcar que este problema es de dos dimensiones
(2-D). Es importante mencionar que para nuestro caso no utilizamos un lmite de iteraciones, esto
a consecuencia de que se conoca que la ecuacion converge. Para casos donde se desconoce si la
solucion podra o no converger se debe limitar el n umero de iteraciones, de lo contrario la aplicacion
se encontrara en un ciclo innito.
Tabla 5.2: Convergencia de Gauss-Seidel vs Jacobi.
Gauss-Seidel versus Jacobi
iteraciones para converger
Valor de Jacobi Gauss-Seidel
N Iteraciones Error Iteraciones Error
4 4 27 0.301769 14 0.301769
8 8 137 0.063374 68 0.063374
16 16 525 0.014678 268 0.014678
32 32 1803 0.003563 928 0.003566
64 64 5692 0.000875 2961 0.000884
128 128 16271 0.000236 8599 0.000230
256 256 49340 0.000061 26481 0.000056
Como se demuestra en las columnas dos y cuatro de la tabla (5.2), el metodo de Gauss-Seidel
converge generalmente cerca de dos veces mas rapido que el esquema de Jacobi, esto debido a que se
utilizan los nuevos valores obtenidos en la presente iteracion, para calcular el resto de las operaciones
de la iteracion actual [23]. En las columnas tres y cinco de la misma tabla se observa que conforme
106 Captulo 5. Metodo de Gauss-Seidel
se incrementa el n umero de nodos (n n) el error disminuye. Lo cual es consistente con el hecho
lm
h0
|u u
n
|
p
0 (5.16)
donde h
1
N
2
, siendo u el valor exacto y u
n
una aproximacion con n n nodos.
En la gura 5.7 se ilustra el comportamiento de (5.16) para el problema de (5.15). En las
tres primeras gracas se plasman los resultados de la evaluacion del codigo de la gura 5.6 para
N = (44, 66, 88). La cuarta graca representa la solucion analtica. En estas gracas se ilustra
como al aumentar el n umero de nodos a la aproximacion ( u
n
) se asemeja a la solucion exacta. El
costo computacional que se paga por una mejor aproximacion es muy alto, lo cual se observa en la
tabla 5.2. Esta situacion expone de mejor manera la gran disyuntiva exactitud versus rapidez; esta
eleccion se realiza de la mano de los nes del proyecto y de los recursos con los que se dispone para
el mismo.
1
0.8
0.6
0.4
0.2
0
0.2
0.4
0.6
0.8
1
1
0.8
0.6
0.4
0.2
0
0.2
0.4
0.6
0.8
1
N = 4 4 N = 6 6
1
0.8
0.6
0.4
0.2
0
0.2
0.4
0.6
0.8
1
N = 8 8 Soluci on analtica
Figura 5.7: Aproximacion numerica a u(x, y) = sen xcos y con Gauss-Seidel.
5.4. Gauss-Seidel versus Jacobi 107
En esta seccion se mostro numericamente que el metodo de Gauss-Seidel converge aproximada-
mente dos veces mas rapido que el esquema de Jacobi. El estudio de la convergencia de ambos meto-
dos se limito unicamente a cuanticar las iteraciones. Cabe se nalar que la rapidez de la convergencia
de los metodos iterativos depende de lo peque no que sea el radio espectral de la matriz[3, 8, 33].
Para acelerar la convergencia se le puede asociar un metodo extrapolado o relajado con un factor
de relajacion el cual es un parametro jo; calcular el valor optimo no es sencillo y se obtiene me-
diante procedimientos heursticos [24, 33]. Todas estas optimizaciones dan como resultados nuevos
esquemas iterativos como por ejemplo el metodo de sobrerrelajaci on acelerada. El estudio de estos
metodos derivados no es el objetivo de este documento.
En este captulo se analizo el metodo iterativo de Gauss-Seidel con la nalidad de escribir un
codigo; que implemente este esquema y que ademas pueda ser ejecutado en forma paralela. Se
comprobo que la convergencia del esquema iterativo de Gauss-Seidel es superior a Jacobi; dos veces
mas rapido. Este hecho hace que los tiempos de ejecucion para este metodo sean menores y por lo
tanto el rendimiento sea mayor. Es preciso mencionar que el error de los dos esquemas iterativos
tratados son muy similares lo cual es congruente con la similitud de ambos. Cabe se nalar que en
ambientes de memoria compartida no es necesario implementar GSBR para funciones paralelas.
Debido a que todos los datos se encuentran alojados dentro de una memoria principal a la que
acceden todos los cores de forma local. Por otro lado es concluyente que este esquema es altamente
paralelizable con base a los resultados obtenidos. Se obtienen speed-up de 2x, 3.8x y 5.4x para 2, 4,
8 cores respectivamente. Estos resultados son semejantes a los obtenidos con el metodo de Jacobi
lo cual indica que el incremento en el speed-up continua conforme se aumenten el n umero de cores
de acuerdo con el tama no del problema.
Captulo 6
Conclusiones y trabajo a futuro
Conclusiones
Es com un el uso de esquemas iterativos para la solucion numerica de problemas que pueden
representarse por sistemas de ecuaciones lineales. Como muchos metodos numericos; este proceso es
muy demandante de tiempo de calculo. Con la reduccion de costos monetarios de las computadoras
paralelas y la aparicion de modelos de programacion paralela como OpenMP; se vuelve una necesidad
migrar los codigos a estas nuevas tecnologas. En la presente tesis se demostraron los benecios por
crear algoritmos para la programacion en paralelo. Es por ello que se hace incapie en el deseo de
generalizar la programacion en paralelo para las nuevas aplicaciones. A continuacion se expresa las
conclusiones.
Durante la realizacion de la multiplicacion matriz-vector se estudio como maximizar el rendi-
miento de la aplicacion seriada obteniendo un aumento a tasas de 1.6x y 2.0x para Unroll de 4
y MMX respectivamente. Para incrementar el rendimiento de estas funciones se utilizo banderas
de compilacion que catapultan el desempe no de 378 a 1500 MFLOPS para la version canonica y
en promedio 3000 MFLOPS para MMX. Cuando se establece el algoritmo para una programacion
paralela real se tiene los siguientes incrementos en el desempe no; la version canonica tiene un mejor
speed-up (5.4x) que Unroll y MMX (4.3x, 2.8x respectivamente) para 8-cores. Sin embargo, el mejor
rendimiento continuo siendo para la version MMX.
A lo largo del estudio del esquema iterativo de Jacobi se realiza una optimizacion para retirar
una sentencia if con lo que reducimos en 20 % el tiempo de ejecucion. Tomando las tecnicas de
109
110 Captulo 6. Conclusiones y trabajo a futuro
programacion hechas en el captulo 3 se tienen resultados semejantes a los anteriores con un speed-
up de 3.0x para 8 n ucleos con MMX. Cabe se nalar que al igual que el tema anterior la version
canonica tiene una mejor escalabilidad con un promedio de 5.5x para 8 n ucleos y para 2 y 4 cores
una escalabilidad de 2.0x y 3.8x lo cual representa practicamente una escalabilidad lineal.
Se estudio el metodo iterativo de Gauss-Seidel (G-S) con la nalidad de determinar cual es mejor
opcion jacobi o G-S; con ello es concluyente que G-S converge normalmente dos veces mas rapido
y ambos con un error relativo semejante. Cuando el metodo se hace paralelo nos encontramos con
un aspecto realmente importante; el procedimiento puede dividirse en tantos bloques como cores
se tengan, esto no se reejara signicativamente en un aumento del n umero de iteraciones. Como
consecuencia de ello se tienen un speed-up y escalabilidad muy semejante a la que se obtuvo con el
esquema de Jacobi; 5.4x para una ejecuci on en 8 cores y 2.0x, 3.8x para 2 y 4 cores respectivamen-
te. Con estos resultados es concluyente que G-S representa una mejor opcion para resolver estos
problemas no solo en serie sino que ademas en paralelo.
Finalmente concluimos dos aspectos de gran importancia: cuando se busca obtener el mayor ren-
dimiento computacional (performance) es preciso escribir el codigo utilizando las funciones denidas
con la tecnologa MMX, as como utilizar las banderas de compilacion para indicar al compilador
que optimice las lneas de codigo. En segundo lugar, cuando se busca que la aplicacion tenga una
mayor escalabilidad paralela se recomienda el uso de la version canonica con banderas de compi-
lacion lo cual no altera la curva de aceleracion. Estos resultados son congruentes con la literatura
existente.
Trabajo a futuro
En esta tesis se ha estudiado y creado dos modelos paralelos para la solucion de sistemas lineales
de ecuaciones con metodos iterativos. Se proporciona codigo fuente para computadoras de memoria
compartida.
Como lneas futuras se piensa en migrar el codigo a las nuevas tecnologas de programacion en
paralelo, aquellas que utilizan las tarjetas gracas. Donde la cantidad de unidades de procesamiento
es mucho mayor a las utilizadas en el presente documento. Ejemplos modernos de estas tecnologas
son las propuestas por los dos gigantes de las tarjetas gracas AMD ATI y Nvidia. La empresa ATI
presenta su interfaz llamada ATI Streaming; por su parte Nvidia pone al alcance de todos su interfaz
Captulo 6. Conclusiones y trabajo a futuro 111
llamada CUDA. Estas tecnologas son conocidas como manycore debido a que estan compuestas
por un gran n umero de procesadores; juntos dan la capacidad de lanzar miles de hilos a la vez.
Otras lneas futuras a seguir, consistira en aplicar los estudios realizados por terceros para
mejorar la velocidad de convergencia de estos metodos; lo que permitira optimizar las funciones
escritas en la presente tesis. Incluyendo los metodos -relajados y el metodo de sobrerrelajacion
acelerada (AOR).
En esta tesis se escribieron funciones paralelas para sistemas con memoria compartida. Sin
embargo, en muchas ocasiones se tienen mas de dos computadoras conectadas a una red de alta
velocidad; esto permite construir un sistema con memoria distribuida. Otro de nuestros objetivos,
consistira en la programacion de funciones hbridas entre ambos paradigmas. Para ello se utili-
zara MPI (Message Passing Interface) y PVM (Parallel Virtual Machine) con motivos comparati-
vos. Con estos resultados se desarrollara una librera de acceso p ublico que implemente los metodos
tratados. El desarrollo de funciones para esquemas iterativos proyectados sobre subespacios de tipo
Krylov, sera otro de nuestros propositos.
Bibliografa
[1] G.Y. Alpzar. Factorizacion de Cholesky como tecnica de precondicionamien-
to. Revista digital matematica, 13(1), Agosto-Febrero 2013. Recurso disponible en
http://www.tec-digital.itcr.ac.cr/revistamatematica/ARTICULOS V13 N1 2012/
RevistaDigital Geisel V13 n1 2012/, ultimo acceso noviembre de 2012.
[2] T. Ando, E. Chow, Y. Saad, and J. Skolnick. Krylov subspace methods for computing
hydrodynamic interactions in Brownian dynamics simulations. The Journal of Chemical
Physics, 2012. aceptado Julio 20, 2012. doi: 10.1063/1.4742347. Recurso disponible en
http://jcp.aip.org/resource/1/jcpsa6/v137/i6/p064106 s1?bypassSSO=1, ultimo acce-
so noviembre de 2012.
[3] J. Arnal-Garca. Algoritmos iterativos paralelos para la resoluci on de sistemas no lineales. Te-
sis doctoral, Universidad de Alicante, Abril 2000. Recurso disponible en http://rua.ua.es/
dspace/bitstream/10045/3217/1/Arnal%20Garc%C3%ADa%2c%20Josep.pdf, ultimo acceso
noviembre de 2012.
[4] S. Balay, J. Brown, K. Buschelman, V. Eijkhout, W. Gropp, D Kaushik, L. Knepley, M. Curf-
man McInnes, B. Smith, H. Zhang, Mathematics, and Computer Science Division (Argon-
ne National Laboratory). PETSc Users Manual: revision 3.3. U.S. Department of Energy,
2012. Reporte disponible en http://www.osti.gov/bridge., ultimo acceso noviembre de
2012.
[5] A. Baldor. Algebra. Grupo Patria Cultural, 2007.
113
114 Bibliografa
[6] M.A.P. Basurto and J.M.C. Espn. Introduccion a la Programacion en C. Aula Politecnica.
Edicions Upc, 2010.
[7] R.L. Burden and J.D. Faires. Numerical analysis. Cengage Learning, 2001.
[8] M.J. Castel de Haro. Metodos iterativos paralelos para la resoluci on de sistemas lineales hermti-
cos y denidos positivos. Tesis doctoral, Universidad de Alicante, Mayo 2000. Recurso dispo-
nible en http://rua.ua.es/dspace/handle/10045/3372, ultimo acceso Noviembre 2012.
[9] L.L. Chaillou. Calculo numerico: curso practico con apliaciones a la ingeniera en alimentos.
Lucrecia, 2008.
[10] R. Chandra, R. Menon, L. Dagum, D. Kohr, D. Maydan, and J. McDonald. Parallel Program-
ming in OpenMP. Morgan Kaufmann, 2001.
[11] B. Chapman, G. Jost, and R. Pas. Using OpenMP: portable shared memory parallel program-
ming. Scientic and engineering computation. MIT Press, 2007.
[12] S.C. Chapra and R.P. Canale. Metodos numericos para ingenieros. McGraw-Hill, 2007.
[13] W.P. Cockshott and K. Renfrew. SIMD programming manual for Linux and Windows. Springer
professional computing. Springer, 2004.
[14] J.L. de la Fuente OConnor. Tecnicas de c alculo para sistemas de ecuaciones, programacion
lineal y programacion entera: codigos en FORTRAN y C con aplicaciones de sistemas de energa
electrica. Reverte, 1997.
[15] H.M. Deitel and P.J. Deitel. Como programar en C, C++ y Java. Pearson Educacion, 2004.
[16] A. Gaul and N. Schlomer. Modied recycling MINRES with application to nonlinear Schrodin-
ger problems, Agosto 2012. Recurso disponible en http://arxiv.org/pdf/1208.0264.pdf,
ultimo acceso noviembre de 2012.
[17] GNU Press a division of the Free Software Foundation. The GNU
OpenMP Implementation, 2011. Manual de usuario, recurso disponible en
http://gcc.gnu.org/onlinedocs/libgomp.pdf, ultimo acceso noviembre de 2012.
Bibliografa 115
[18] R. Gomez-Jimenez, D. Escobar-Hernandez, D.A. Gomez-Arias, J.L. Guerrero-Maga na, J.M.A.
Gutierrez-Rocha, M.A. Hernandez-Hernandez, A.P. Puerto-Covarrubias, and L.M. Sandoval-
Magallanes. Elementos de metodos numericos para ingeniera. McGraw-Hill, 2002.
[19] R.M. Hidalgo. Sincronizacion y caos en sistemas electronicos no lineales y sus apli-
caciones a las comunicaciones. Tesis doctoral, Universidad Nacional de Mar del Pla-
ta, Octubre 2003. Recurso disponible en http://www3.fi.mdp.edu.ar/electronica/
tesis/Tesis Hidalgo Roberto.pdf, ultimo acceso noviembre de 2012.
[20] M.D. Hill and M.R. Marty. Amdahls law in the multicore era. IEEE Computer Society,
pages 3338, Julio 2008. Recurso disponible en http://research.cs.wisc.edu/multifacet/
papers/ieeecomputer08 amdahl multicore.pdf, ultimo acceso noviembre de 2012.
[21] T.Z. Huang, Y. Zhang, and L. Li. Modied incomplete Cholesky factorization for solving elec-
tromagnetic scattering problems. Progress In Electromagnetics Research B, 13:4158, 2009.
Recurso disponible en http://www.jpier.org/PIERB/pierb13/03.08112407.pdf, ultimo ac-
ceso noviembre de 2012.
[22] Imad M. Jaimoukha and Ebrahim M. Kasenally. Implicitly restarted Krylov subspace methods
for stable partial realizations. SIAM J. Matrix Anal. Appl., 18(3):633652, Julio 1997. Recurso
disponible en http://www2.ee.ic.ac.uk/publications/p449.pdf, ultimo acceso noviembre
de 2012.
[23] G. Karniadakis and R.M. Kirby. Parallel scientic computing in C++ and MPI: a seamless
approach to parallel algorithms and their implementation. Cambridge University Press, 2003.
[24] C.T. Kelley. Iterative methods for linear and nonlinear equations. Society for Industrial and
Applied Mathematics (siam), 1995.
[25] B. Kolman, D.R. Hill, and V.H.I. Mercado. Algebra lineal. Pearson Educacion, 2006.
[26] M.J. Martn-Santamara. Factorizacion de Cholesky modicada de matrices dispersas sobre
multiprocesadores. Tesis doctoral, Universidad de Santiago de Compostela, Julio 1999. Recur-
so disponible en http://gac.udc.es/tesis/MariaJMartin.pdf, ultimo acceso noviembre de
2012.
116 Bibliografa
[27] M. Mittal, A. Peleg, and U. Weiser. MMX technology architecture overview. Intel journal,
1997. Recurso disponible en http://www.ece.sunysb.edu/midor/ESE345/MMX archit.pdf,
ultimo acceso noviembre 2012.
[28] S. Nakamura. Metodos numericos aplicados con software. Prentice-Hall Hispanoamericana,
1992.
[29] L. Null and J. Lobur. The Essentials of Computer Organization and Architecture. Jones &
Bartlett Learning, 2003.
[30] NVIDIA CUDA. NVIDIA CUDA C programming guide version 4.2, 2012. Ma-
nual de usuario, recurso disponible en http://developer.download.nvidia.com/compute/
DevZone/docs/html/C/doc/CUDA C Programming Guide.pdf, ultimo acceso noviembre de
2012.
[31] P.S. Pacheco. An introduction to parallel programing. Morgan Kaufmann, 2011.
[32] D. Page. A practical introduction to computer architecture. Texts in computer science. Springer,
2009.
[33] J. Penades-Martnez. Metodos iterativos paralelos para la resolucion de sistemas lineales ba-
sados en multiparticiones. Tesis doctoral, Universidad de Alicante, Noviembre 1993. Recurso
disponible en http://rua.ua.es/dspace/handle/10045/3806, ultimo acceso noviembre de
2012.
[34] W.P. Petersen and P. Arbenz. Introduction to Parallel Computing. Oxford University Press,
2004.
[35] C. Ramiro-Sanchez. Algoritmos paralelos para la resolucion de problemas de mnimos
cuadrados basados en transformaciones ortogonales sobre GPUs y multiprocesadores. Tesis
de maestra, Universitat Polit`ecnica de Val`encia, Diciembre 2010. Recurso disponible en
http://riunet.upv.es/bitstream/handle/10251/11319/PFM Carla Ramiro Sanchez.pdf,
ultimo acceso noviembre de 2012.
[36] A. Santos-Palomo and P. Guerrero-Garca. Resolviendo una sucesion de sis-
temas compatibles dispersos. XXVI Congreso Nacional de Estadstica e In-
Bibliografa 117
vestigacion Operativa

Ubeda, 6-9 de Noviembre, 2001. Recurso disponible en
http://www.matap.uma.es/investigacion/tr/ma00 05.pdf, ultimo acceso noviembre
de 2012.
[37] C. Severance and K. Dowd. High Performance Computing. Draft version: Rice University, Hous-
ton, Texas (Connexions), 2011. Acceso Julio 2012, http://cnx.org/content/col11136/1.5/.
[38] S. Sidi-Ali-Cherif and K.M. Grigoriadis. Ecient model reduction of large scale systems using
Krylov-subspace iterative methods. International Journal of Engineering Science, Vol.41:507
520, 2003. Recurso disponible en http://144.206.159.178/ft/484/78648/15146190.pdf,
ultimo acceso noviembre de 2012.
[39] Y. Skiba. Metodos y esquemas numericos: un analisis computacional. Universidad Nacional
Autonoma, 2005.
[40] R. M. Stallman and the GCC Developer Community. Using the GNU Compiler Collection: for
gcc version 4.2.4. GNU Press a division of the Free Software Foundation, 2005. Manual de
usuario, recurso disponible en http://gcc.gnu.org/onlinedocs/gcc-4.2.4/gcc.pdf, ultimo
acceso noviembre de 2012.
[41] K. Sydsaeter, P. Hammond, and J.L.V. Cordoba. Matematicas para el analisis economico.
Fuera de coleccion Out of series. Prentice Hall, 1996.
[42] A.E. Tomas-Dommguez. Implementacion paralela de metodos de Krylov con reinicio para
problemas de valores propios y singulares. Tesis doctoral, Universitat Polit`ecnica de Val`encia,
Marzo 2009.

Potrebbero piacerti anche