Sei sulla pagina 1di 23

UNIVERSIDAD NACIONAL DE SAN ANTONIO ABAD DE CUSCO

Facultad de Ingeniería Electrónica, Eléctrica Mecánica e


Informática
Escuela Profesional de Ingeniería Informática y de Sistemas

MICROPROCESADORES

JAVIER JAIL CORNEJO PILLCO 155193


LISBETH ORTOGORIN CONDORI 130348

IMPLEMENTACIÓN DE LA MATRIZ INVERSA UTILIZANDO GPU (CUDA)

DOCENTE

Edwin Carrasco Poblete

CUSCO - PERÚ
2018

Pag. 1
1. Caratula
2. Índice
3. Presentación
4. Introducción
5. Marco conceptual
5.1. Arquitectura del procesador
5.2. Arquitectura del FPU/AVX/GPU
5.2.1. Organización del FPU/AVX/GPU
5.2.2. Modelo de programación del FPU/AVX/GPU
5.3. Fundamentos del método numérico seleccionado
5.4. Aplicaciones del método numérico seleccionado
6. Implementación secuencial del método numérico seleccionado
6.1. Pseudocódigo del método numérico seleccionado
6.2. Implementación en lenguaje ensamblador o C
7. Implementación del método numérico seleccionado en FPU/AVX/GPU
7.1. Pseudocódigo del método numérico seleccionado
7.2. Implementación en lenguaje ensamblador o C
8. Métricas de evaluación de las implementaciones
8.1. Diseño de experimentos
8.2. Experimentación
8.3. Comparación y evaluación de resultados
9. Conclusiones
10. Referencias
11. Anexos:
11.1. CD conteniendo:
11.1.1. Código fuente de los programas implementados
11.1.2. Informe en formato docx y pdf.

Pag. 2
PRESENTACIÓN

El presente trabajo se centra en el estudio de la inversión de matrices con el método de Gauss Jordan y
la programación de este en el GPU (Unidad de procesamiento gráfico). En este sentido, es relevante
destacar dos cuestiones. Por un lado, la importancia de dicho método en el estudio de nuevas y más
optimas tecnologías y por otro lado, la programación paralela y las virtudes de esta.

Se inicia el proyecto, a modo de introducción general, un breve recorrido histórico sobre el método de
Gauss Jordan para la inversión de matrices y las diferentes arquitecturas del procesador, así como los
modelos de programación. Seguidamente se muestra la implementación de este método, para el GPU y
el análisis de tiempo de demora tanto en GPU como CPU.

Pag. 3
INTRODUCCIÓN

La inversión de matrices es un paso esencial en una amplia gama de problemas numéricos desde la
resolución de ecuaciones lineales, estructuralmente se analiza utilizando el método de elementos finitos,
representación 3D, filtrado digital, filtrado de imágenes y procesamiento de imágenes y constituye un
componente indispensable en casi todos los paquetes de software matemáticos / estadísticos. Algunos
de los algoritmos disponibles comunes para calcular la inversa de una matriz son Strassen, Strassen-
Newton, eliminación gaussiana, Gauss-Jordan, Calderero y Winograd, LUP Decom-posición,
Descomposición de Cholesky, descomposición QR, factorización RRQR, Métodos Monte Carlo para
inversa, etc.

Hasta finales de 1960 se creía que para la inversión de matrices se requería un número cúbico de
operaciones, el algoritmo más rápido conocido era el método de eliminación de Gauss, o más bien Gauss
Jordan método que se ejecuta en O (n3), tiempo donde n es el tamaño de la matriz. En 1969, Strassen
excito la comunidad de investigación, dando el primer algoritmo de tiempo sub cúbico para la
multiplicación de matrices, que se ejecuta en O (n2,808). Esto también reduce la complejidad de tiempo,
w, de la inversión de matrices usando Strassen siendo de O (n2,808). Este descubrimiento provocó una
larga línea de investigación que reduce gradualmente la complejidad del tiempo w con los años. En 1978,
Pan presento un método que demostró w <2,796 y el siguiente año, Biniet al. introdujo la noción de
rango frontera y obtuvo w <2,78. Schönhage esta noción generalizada en 1981, lo que demuestra w
<2,548. En el mismo documento, combinando su trabajo con las ideas por Pan, También mostró w
<2,522.

Al año siguiente, Romaní encontró que w <2,517. El primer resultado de romper 2,5 era por Calderero y
Winograd que obtuvo w <2,496. En 1988, Strassen presentó su método láser que era un nuevo enfoque
para la multiplicación de la matriz, y por lo tanto la disminución de la cota a w <2,479. Dos años más
tarde, Calderero y Winograd combinó la técnica de Strassen con una nueva forma de análisis basado en
grandes conjuntos evitando progresiones aritméticas y obteniendo el famoso límite de w <2.376 que ha
permanecido sin cambios durante más de 22 años (un trabajo no publicado muy reciente afirma haber
reducido el límite a w <2,3727). Mientras que la mayor actividad se centra en tratar de reducir el
exponente w, tanto Calderero y Winograd y Cohnet presentaron conjeturas que afirman podría implicar
w = 2, pero nunca menos que eso.

Los recientes desarrollos en arquitectura paralela y su uso en la computación han traído sobre la
perspectiva de los sistemas masivamente paralelos capaces de reducir los tiempos de funcionamiento
de los códigos por debajo del límite de w = 2. La cantidad de aumento de rendimiento, por supuesto,
depende en gran medida del alcance de paralelización que el algoritmo de pro-Vides.

Uno de los métodos más antiguos para inversión de la matriz. Es sencillo y robusto y es particularmente
adecuado para la paralelización masiva a diferencia de muchos de los métodos más avanzados. Sin
embargo, la literatura disponible, ya sea en el ámbito de la paralelización del algoritmo de Gauss Jordan
o su optimización aparecen en lugar insuficiente. Este trabajo implementa el algoritmo de Gauss-Jordan
para inversión de la matriz en un CUDA (Compute Unified Device Architecture), con plataforma base
GPU y estudia las métricas de rendimiento del algoritmo.

Pag. 4
5. Marco conceptual

5.1. Arquitectura del procesador

Intel Core i7-7700HQ

Usa una arquitectura Kaby Lake de 64 bits, Kaby Lake es el nombre clave de Intel para el sucesor de
la microarquitectura Skylake,1 siendo la séptima generación. Se anunció el 30 de agosto de 2016.

Al igual que Skylake, Kaby Lake tiene una medida de 14 nanómetros. Se empezó a distribuir procesadores Kaby
Lake a fabricantes y OEM’s en el segundo trimestre de 2016.34 en 2017, se presentó la actualización del mismo
bajo el nombre de Kaby Lake Refresh, como anticipo del lanzamiento de Coffee Lake.

Construido en un proceso mejorado de 14 nm (14FF+), Kaby Lake presenta velocidades de reloj más rápidas,
cambios en la velocidad del reloj, y frecuencias Turbo más rápidas. Más allá de esto poco de la arquitectura ha
cambiado desde Skylake.5 Skylake y Kaby Lake tienen el mismo IPC (rendimiento por MHz).2 Kaby Lake añade
soporte nativo para USB 3.1 Generación 2 (10 Gbit/s)6

Kaby Lake también presenta una arquitectura de gráficos nueva para mejorar rendimiento en gráficos 3D y
reproducción de video en 4K .27 Añade soporte nativo para HDCP 2.2.

Fig.1 Arquitectura del microprocesador empleado, Fuente: [1]

Pag. 5
5.2. Arquitectura del GPU

5.2.1. Organización del GPU

La organización del GPU está basada en hilos y jerarquía de memoria de la GPU en CUDA, donde puede
observarse la memoria global, constante, compartida y local. También hay que agregar que CUDA posee un
conjunto de instrucciones que permiten la sincronización entre programas y ejecuciones de los hilos. Además, los
hilos dentro de los bloques son agrupados en conjuntos de 32 hilos, llamados warps, los cuales ejecutarán la
misma instrucción al mismo tiempo. Esto quiere decir, que todos los hilos de un warp están sincronizados, lo que
permite ciertas optimizaciones a la hora de la programación. Sin embargo, se deben evitar divergencias, ya que
disminuyen el desempeño de la aplicación. La divergencia se origina cuando dos hilos ejecutan dos conjuntos de
instrucciones diferentes; debido, por ejemplo, a la ejecución de un condicional. Cuando ocurren divergencia entre
hilos de un mismo warp, algunos hilos deben esperar a que el resto de los hilos del mismo warp ejecuten su
conjunto de instrucciones para luego ser ejecutados, disminuyendo el paralelismo.

Fig. 2 Arquitectura GPU, fuente: [2]

La NVIDIA GeForce GTX 950M es una tarjeta de vídeo de gama media-alta, compatible con DirectX 11 para
portátiles. Se basa en la arquitectura Maxwell de Nvidia (chip GM107) y es producida en 28 nm. La GTX 950M
presenta 640 unidades shader con frecuencia de 1097 - 914 MHz (Boost) así como memoria GDDR5 (128 bit, 5000
MHz efectivos, 80 GB/s).

Arquitectura, comparada con Kepler, la Maxwell ha sido optimizada en diversos detalles para aumentar la
eficiencia del poder. Smaller Streaming Multiprocessors (SMM) con 128 ALUs (Kepler: 192) y un programador
optimizado proporciona mejor utilización de los shaders. GM107 tiene 5 SMMs y, por tanto, 640 núcleos shader,
40 TMUs y 16 ROPs (interfaz de 128-bits).

Pag. 6
Fig. 3 GPU Nvidia 950m architecture, Fuente: [3]

5.2.2. Modelo de programación del GPU

Debido a las diferencias fundamentales entre las arquitecturas de la GPU y la CPU, no cualquier
problema se puede beneficiar de una implementación en la GPU. En concreto, el acceso a memoria
plantea las mayores dificultades. Las CPU están diseñadas para el acceso aleatorio a memoria. Esto
favorece la creación de estructuras de datos complejas, con punteros a posiciones arbitrarias en
memoria. En cambio, en una GPU, el acceso a memoria está mucho más restringido. Por ejemplo, en un
procesador de vértices (la parte de una GPU diseñada para transformar vértice en aplicaciones 3D), se
favorece el modelo scatter, en el que el programa lee en una posición predeterminada de la memoria,
pero escribe en una o varias posiciones arbitrarias. En cambio, un procesador de píxeles, o fragmentos,
favorece el modelo gather, pudiendo el programa leer de varias posiciones arbitrarias, pero escribir en
sólo una posición predeterminada.

La tarea del diseñador de algoritmos GPGPU consiste principalmente en adaptar los accesos a memoria
y las estructuras de datos a las características de la GPU. Generalmente, la forma de almacenar datos es
en un buffer 2D, en lugar de lo que normalmente sería una textura. El acceso a esas estructuras de datos
es el equivalente a una lectura o escritura de una posición en la textura. Puesto que generalmente no se

Pag. 7
puede leer y escribir en la misma textura, si esta operación es imprescindible para el desarrollo del
algoritmo, éste se debe dividir en varias pasadas.

Pese a que cualquier algoritmo que sea implementable en una CPU lo es también en una GPU, esas
implementaciones no serán igual de eficientes en las dos arquitecturas. En concreto, los algoritmos con
un alto grado de paralelismo, sin necesidad de estructuras de datos complejas y con una alta intensidad
aritmética son los que mayores beneficios obtienen de su implementación en la GPU.

5.3. Fundamentos del método de Gauss Jordan para invertir matrices

El cálculo de la matriz inversa por el método de Gauss-Jordan se basa en la expresión:

A.A-1=A-1.A=Id
Se trata de plantearla como una ecuación matricial donde el objetivo es encontrar A-1. Para ello
seguiremos los siguientes pasos:

1. Partimos de la matriz A.

Fig. 4 Matriz general, Fuente: [4]

2. Planteamos una estructura matricial como la siguiente:

Fig. 5 Matriz estructura, Fuente: [4]

Observamos dos matrices separadas por la barra vertical. La de la izquierda es la matriz A de la que
queremos calcular su matriz inversa. La de la derecha es la matriz identidad.

3. Mediante transformaciones elementales, conseguimos que la matriz de la izquierda pase a ser la


matriz identidad. Nos quedará así:

Pag. 8
Fig. 6 Matriz Identidad, Fuente: [4]

La matriz que nos queda a la derecha es la matriz inversa de A.

Fig. 7 Matriz inversa, Fuente: [4]

5.4. Aplicaciones del método numérico seleccionado

Muchos sistemas de control robótico y mecatrónico están matemáticamente representados,


analizados y finalmente implementados como composiciones de sistemas lineales los cuales para
resolución usan el método de la matriz inversa de Gauss Jordan, uno de los ejemplos más conocidos es
el del brazo robótico que detallaremos a continuación.

El movimiento de un brazo robótico. Este ejemplo se basa en sistemas lineales se ha estudiado los
aspectos importantes de la robótica en el mundo real y las aplicaciones de sistemas mecánicos. La
estructura del brazo robótico y las ecuaciones que modelan su movimiento para que pueda controlarse
para realizar las operaciones deseadas estuvieron basadas en la inversión de matrices. Tiene estructuras
comunes en mecánica de sistemas. El PA de punta es el efector final, que denota el final de un brazo
robótico y está diseñado para interactuar con el exterior ambiente. Cada articulación puede ser
accionada por un motor, y debido al diseño de la conexión, está limitada a 2 dimensiones movimiento
plano El mecanismo tiene 3 grados de libertad: dos de ellos son rotativos y uno es lineal. Estos
parámetros son inicializado como θ1 = 30◦ , θ2 = 30◦ y l = 0.7m.

Pag. 9
Fig. 8 Brazo robótico, Fuente: [6]

La robótica y la mecatrónica no son las únicas aplicaciones de la inversión de matrices con el método de
Gauss Jordan, ya que a estas aplicaciones se suma una amplia gama de utilidades en la ingeniería como
son en la ingeniería civil en el análisis de estructuras, proyectos de desarrollo sistematizado, etc.
Otro ámbito importante es en el de la programación ya que constituyen una parte esencial de los
lenguajes de programación.

6. Implementación secuencial del algoritmo Gauss-Jordan para la inversión de matrices


El método de Gauss Jordan para el cálculo de la inversa de una matriz es uno de los métodos más
antiguos. Es robusto, preciso sobre el rango de matrices y no requiere múltiples controles dependiendo
del tipo de matriz involucrada.
El método estándar de Gauss Jordan para el cálculo de la inversa de una matriz A de tamaño n comienza
al aumentar la matriz con la matriz identidad de tamaño n:
[C]=[A|I]
Luego, realizando transformaciones de fila elementales en la matriz C, la mitad izquierda de C' se
transforma columna por columna en la matriz identidad. Este paso se divide en 2 pasos por columna de

Pag. 10
la mitad izquierda de la matriz, el primero de los cuales es convertir el elemento aii en 1 mediante la
transformación:

Si aii es cero, cualquier fila que no sea cero se agrega a la i-ésima fila antes de aplicar la ecuación anterior.
El segundo paso es reducir todos los demás elementos de la columna j-ésima a cero mediante la siguiente
transformación de cada fila, excepto la j-ésima:

Después de transformar la primera columna, la matriz se reduce a:

Fig. 9 Proceso del algoritmo de reducción de Gauss-Jordan. Fuente: [5]


Y siguiendo estos dos pasos para cada columna secuencialmente, la mitad izquierda de C’ se convierte
en la matriz identidad mientras que la mitad derecha se convierte en la inversa deseada de A:

Pag. 11
6.1 Pseudocódigo de la implementación secuencial del método utilizado
Leer augmentedmatrix
Inicializar dimensión como tamaño de la matriz
Function gauss_jordan()
float temporary, r
for j = 0 hasta dimensión hacer
temp <- j

encontrar elemento maximo jth en la comlumna en las ultimas filas (dimension-j)


for i = j + 1 hasta dimension hacer
if augmentedmatrix[i][j]>augmentedmatrix[temp][j] hacer
temp = i;
fin if
if (fabs(augmentedmatrix[temp][j])<minvalue hacer
Imprimir Los elementos son demasiado pequeños para procesar
break
fin if
fin for

Intercambiando fila que tiene maximo elemento jth en la columna


if temp != j hacer
for k = 0 hasta 2 * dimensión hacer
temporary = augmentedmatrix[j][k]
augmentedmatrix[j][k] = augmentedmatrix[temp][k]
augmentedmatrix[temp][k] = temporary
fin for
fin if

Actualizando operaciones de filas a la forma requerida de matriz identidad


for i = 0 hasta dimensión hacer
if i != j hacer
r = augmentedmatrix[i][j]
for k = 0 hasta 2 * dimension hacer
augmentedmatrix[i][k] -= (augmentedmatrix[j][k] / augmentedmatrix[j][j])*r
fin for
fin if
else hacer
r = augmentedmatrix[i][j]
for k = 0 hasta 2 * dimension hacer
augmentedmatrix[i][k] /= r
fin for
fin else
fin for
fin function

Pag. 12
6.2 Implementación en lenguaje C
Para la implementación de la matriz inversa en C se utilizaron las siguientes funciones además de la
función Gauss-Jordan explicada anteriormente.
void matrix_read()

Uso: lee la matriz generada.

void savetofile(double *A, string s, int n, int h)

Uso: guarda la matriz que necesitamos en un archive txt.

int main()

Uso: Funcion principal del programa.

La implementación del código a continuación recoge una matriz de una dimensión de 1000 la que será
convertida en nuestra matriz augmentedmatrix y será procesada por el algoritmo utilizado (Gauss-Jordan).

• Cabeceras de código:

Fig. 10 Cabeceras del código en C. Fuente: Propia


• Declaración de constantes universales:

Fig. 11 Constantes del código implementado. Fuente: Propia


• Módulos:

Fig. 12 Modulo para escribir la matriz de salida del código implementado. Fuente: Propia

Pag. 13
Fig. 13 Modulo para recuperar la matriz de ejemplo del código implementado. Fuente: Propia

Pag. 14
Fig. 14 Modulo para utilizar Gauss-Jordan del código implementado. Fuente: Propia

Fig. 15 Modulo principal del código implementado. Fuente: Propia

Pag. 15
7. Implementación de la matriz inversa en GPU
7.1 Pseudocódigo de la implementación en CUDA del método utilizado

Fig. 16 Pseudo código explicando el algoritmo Gauss-Jordan para la inversión de matrices adaptado
para computación en GPU. Fuente: [5]
7.2 Implementación en lenguaje C
Host función:

void matrix_read() Efecto: Lee la Matriz generada.

void savetofile(double *A, string s, int n, int h) Efecto: Guarda la matriz que necesitamos a un txt file.

int main() Efecto: Función principal del programa.

Device función:

__global__ void nodiag_normalize(double *A, double *I, int n, int i)

Efecto: Normaliza los elementos que no están en la diagonal.

__global__ void diag_normalize(double *A, double *I, int n, int i)

Efecto: Normaliza los elementos que están en la diagonal.

__global__ void gaussjordan(double *A, double *I, int n, int i)

Pag. 16
Effect: the realization of parallel matrix inverse using Gaussian Jordan Elimination.

__global__ void set_zero(double *A, double *I, int n, int i)

Effect: set the first line in every loop to zero.

La implementación del código a continuación recoge una matriz de una dimensión de 1000 la que será
convertida en nuestra matriz augmentedmatrix y será procesada por el algoritmo utilizado (Gauss-Jordan).

• Cabeceras de código:

Fig. 16 Cabeceras del código en C. Fuente: Propia


• Declaración de constantes universales:

Fig. 17 Constantes del código implementado. Fuente: Propia


• Módulos:

Fig. 18 Modulo para escribir la matriz de salida del código implementado. Fuente: Propia

Pag. 17
Fig. 19 Modulo para recuperar la matriz de ejemplo del código implementado. Fuente: Propia

Fig. 20 Modulo para normalizar la diagonal de la matriz. Fuente: Propia

Pag. 18
Fig. 21 Método de Gauss-Jordan en CUDA, Fuente: Propia

Pag. 19
Fig. 21 Modulo principal del código implementado. Fuente: Propia

8. Métricas de evaluación de la implementación


8.1. Diseño de experimentación
Como se muestra arriba, si todos los cálculos de n2 se pueden hacer en paralelo, la complejidad del
algoritmo de Gauss Jordan en una arquitectura masivamente paralela se reduce a O (n). Para que todos
los cálculos estén en paralelo, la creación del hilo debe ser muy ligera, de lo contrario, el tiempo de
creación de n2 hilos contribuirá a la complejidad del tiempo. Aquí es donde CUDA tiene una ventaja sobre
otros métodos de cómputo paralelo. La creación de subprocesos en CUDA es muy liviana y no contribuye
al tiempo de ejecución del programa.
Si bien la creación de subprocesos es más ligera con CUDA, el uso de la GPU presenta algunas limitaciones
que dependen del hardware de la GPU. La primera limitación tiene que ver con la ejecución de n 2 hilos
en paralelo. Esto depende del tipo de GPU utilizado para el cálculo. Una GPU moderna (Nvidia GTX 950m)
puede tener más de 49.152 hilos activos divididos en conjuntos de 32 (llamados warps) pero solo 1024

Pag. 20
hilos distribuidos que se ejecutan en paralelo, es decir, 32 SM x 48 Warps residentes por SM x 32 Hilos
por urdimbre hilos activos, pero solo 32 SM x 32 Threads por warp corriendo en paralelo, cualquier
número por encima de ese dará lugar a apilamiento de warps esperando sus turnos. Por lo tanto, hasta
n = √1024 = 32, el algoritmo tendrá una complejidad temporal de O (n); la complejidad comienza a
aumentar para n> 221 y se vuelve cuadrática en n = 1024. Si se usa un clúster de GPU paralelas y se
ejecuta el programa usando todas las GPU, entonces esta capacidad de hardware se puede aumentar
aún más.
Los programas se corrieron en la distribución de LINUX Ubuntu versión 18.08 LST.
8.2. Experimentación
El algoritmo se programó usando CUDA C y se probó contra varios tamaños de los siguientes tipos de
matrices: matriz de identidad, matriz dispersa, matriz de banda (con k = n / 2), matriz aleatoria y matriz
hueca. Para este documento, la GPU utilizada fue Nvidia GForce GTX 950m (640 núcleos), Maxwell SMM
con 128 ALU puede ofrecer el 90% del rendimiento de un Kepler SMX con 192 ALU. GM107 presenta 5
SMM y, por lo tanto, 640 núcleos de sombreado, 40 TMU y 16 ROP (interfaz de 128 bits). La CPU utilizada
con fines de comparación es el procesador Intel Core i7 7700hq @ 3 GHz cada uno, capaz de ejecutar 8
hilos en paralelo.
Compilación de programas en secuencial y paralelo.
CPU:

GPU:

8.3. Comparación y evaluación de resultados:


La Fig. 22 muestra el tiempo computacional para el tamaño de la matriz hasta 100 y demuestra la
naturaleza lineal de la complejidad del tiempo. Muestra el tiempo que tarda el algoritmo en la GPU en
una escala mayor en comparación con una CPU.
Se observa que el gráfico sigue siendo lineal para alrededor de n = 50 aunque una matriz de tamaño 50
requiera 4096 subprocesos de ejecución paralelos. Esto se explica por el hecho de que todos los 4096
hilos o 128 warps ya estaban cargados en la memoria y programados para ser enviados.

Pag. 21
Fig. 22 Comparación del algoritmo en una matriz de n=50, Fuente: [5]
Ahora si se hace una comparación del algoritmo en CPU y GPU de matrices aleatorias generadas, se
tendría el siguiente esquema:

Pag. 22
Fig. 23 benshmarking del algoritmo en CPU y GPU, Fuente: Propia

9. Conclusiones
La capacidad de invertir matrices grandes de forma precisa y rápida determina la efectividad de una
amplia gama de algoritmos y productos computacionales. La computación GPU es ideal para tareas
paralelas masivas ya que la creación de subprocesos y los gastos generales de transferencia de memoria
son insignificantes. Hemos rediseñado el algoritmo de Gauss Jordan para la inversión de matriz en la
plataforma CUDA basada en GPU, lo probamos en cinco tipos diferentes de matrices (identidad, dispersa,
en bandas, aleatoria y hueca) de varios tamaños, y hemos demostrado que la complejidad temporal de
la inversión de matriz como n si hay suficientes recursos computacionales disponibles. La escala lineal
continuará usando una red de GPU. También demostramos que la paralelización basada en GPU para
inversión de matriz es órdenes de magnitud más rápida que la paralelización basada en CPU. Incluso una
pequeña matriz de tamaño 10 x 10 mejoró usando el algoritmo paralelo CUDA Gauss Jordan.

10. Referencias
[1] Intel Core 7th generation architecture (20 de Julio de 2018). Recuperado de
https://www.intel.com/content/www/us/en/products/processors/core/i7processors.html
[2] GPU architecture (13 de agosto 2011). Recuperado de http://fisica.cab.cnea.gov.ar/gpgpu
[3] Nvidia GeForce GTX 950m architecture (20 de julio 2018). Recuperado de
https://www.geforce.com/hardware/notebook-gpus/geforce-gtx-950m/specifications
[4] Mahmoud Shirazi, M. K. y Farshad K. (2015). Gauss-Jordan Matrix Inversion Speed-Up using GPUs
whit the Consideration of Power Consumption. INFOCOMP 20,25. ISBN: 978-1-61208-416-9
[5] Grish S., A. A. y Baidurya B. (2013). A fast-parallel Gauss Jordan algorithm for matrix iversion using
CUDA. COMPUTERS & STRUCTURES. DOI:10.1016
[6] Zhang y Jeffery U. (2018). A Generalized Matrix Inverse whit Applications to Robotic Systems.
University of Misuri. DOI:18.0177

Pag. 23

Potrebbero piacerti anche