CUDA

De Wikihaskell
Saltar a: navegación, buscar
accelerate library
accelerate library: lenguaje embebido para arrays computacionales regulares y multidimensionales embedded con múltiples entornos para facilitar implementaciones de un alto rendimiento.
Lenguaje Haskell
Biblioteca accelerate library
Autores Alejandro de Celis Domínguez
Álvaro Cortijo García
Daniel Gutiérrez Valle

Contenido

Introducción

Librería con la que se define un lenguaje embebido para acelerar el procesamiento de arrays, ya sean normales o multidimensionales, de manera que facilita la realización de implementaciones con alto rendimiento.

Las características esta librería se pueden resumir en las siguientes:

  • Los arrays son uniformes: densos, rectangulares, y del mismo tipo de elemento.
  • Las funciones pueden ser polimórficas en la dimensionalidad del array.
  • Se trata de un lenguaje estratificado que separa los cálculos sobre arrays de las expresiones escalares en el nivel de tipos.

En esta librería existen implementados a día de hoy dos backends:

  • Un intérprete que sirve como una implementación de referencia de la semántica del lenguaje.
  • Un generador de código para GPUs NVIDIA con capacidad para CUDA.

Motivación

Nos hemos decantado por esta libreria entre las cientos de librerias existentes para Haskell (véase librerias para Haskell) para aprender más acerca del potencial del lenguaje, así como de la programación funcional, a la hora de desarrollar software relacionado, entre otras posibles áreas, con los cálculos matriciales y el procesamiento de imágenes.

Requisitos para uso de biblioteca

Para poder usar la biblioteca Accelerate es necesario cumplir unos requisitos mínimos. Éstos son:

  • Tener instalado el compilador Glasgow Haskell (GHC), versión 7.0.3 o posterior.
  • Cargar las librerías de Haskell específicas para accelerate.cabal
  • Para el backend de CUDA, se necesita también tener instalado el sotware de CUDA correspondiente (descargable del sitio web )software para CUDA . La versión de éste ha de ser la 3.0 o posterior.


Instalación

En este apartado se explica detalladamente el proceso de instalación de la librería Accelerate. También, se presenta los pasos a seguir para realizar la instalación del compilador Glasgow Haskell (GHC), así como de los drivers y herramientas de desarrollo para CUDA.

Accelerate está disponible tanto para Linux, MAC OS X y Windows, no estando probado con exhaustividad para este último Sistema Operativo indicado. No obstante, no existen razones para que existan problemas a la hora de realizar la instalación en Windows.

Instalación compilador Glasgow Haskell (GHC)

Para poder hacer uso de la librería Accelerate será necesario disponer de un compilador que de soporte a la misma. Un ejemplo de compilador con estas características es Glasgow Haskell Compiler (GHC). Éste es un compilador nativo de código libre desarrollado en la Universidad de Glasgow. A día de hoy el desarrollo de dicho compilador es llevado a cabo por Microsoft. Dicho compilador es compatible con la mayor parte de los sistemas operativos existentes en la actualidad, entre ellos Windows (32 y 64 bits), Linux (32 y 64 bits) y MAC OS X (véase Sitio oficila Glasgow Haskell compiler).

Para obtener dicho compilador basta con descargárselo del sitio web oficial, sección downloads, para el sistema operativo que se desee (véase Obtención compilador GHC).

Si lo desea, en vez del compilador Glasgow Haskell puede instalarse el compilador Haskell Platform, ya que la última versión del mismo incluye la última actualización del compilador Glasgow Haskell (7.6.3), así como un amplio conjunto de herramientas y librerías que permiten el desarrollo de software escrito en Haskell como si se implementara con el compilador Glasgow Haskell.

En cualquier caso, si se decanta por instalar el compilador Glasgow Haskell tenga en cuenta que deberá de actualizar la versión de Cabal a la 0.8 o posterior, ya que el compilador GHC (versión 7.6.3) no trabaja con versiones posteriores a la 0.8 para Cabal. Si desconoce qué es Cabal consulte la siguiente dirección web The Haskell Caba.

Aunque el compilador GHC es soportado por gran multitud de sistemas operativos, la instalación de dicho compilador varía en cada uno de ellos. Por ello, será necesario conocer las particularidades de instalación para cada uno de ellos. En los siguientes subapartados se explicará el proceso de instalación de GHC para los sitemas operativos Windows (32 y 64 bits), Linux, distribución Ubuntu (32 y 64 bits) y MAC OS X.


Instalación GHC en Windows

Para instalar el compilador GHC en Windows es necesario preparar el entorno, realizando una serie de acciones extras.

En primer lugar, debido a que alguno de los paquetes de GHC contienen códigos y scripts Unix o Linux, será necesario simular en Windows un entorno Unix. Para ello, deberemos de instalar MinGW (para más información Sitio web oficial MinGW), así como MSYS (para más información Sitio web MSYS). (NOTA: en caso de que se emplee el entorno de desarrollo conocido como mysysgit (para más información sitio web para msysgit, sólo será necesario añadir MinGW a la variable de entorno PATH.

Para poder enlazar programas escritos en los lenguajes de programación C y C++, así como librerias .a y .lib, será necesario definir nuevas variables de entorno, las cuales permitan listar los directorios donde se encuentran los ficheros de cabecera (.h) para el caso de los programas escritos en C y C++, así como listar los directorios donde se encuentren los ficheros .a y .lib para las librerias. Un ejemplo de nombres para las variables de entorno a crear pueden ser las que se indican a continuación:

  • C_INCLUDE_PATH: Enlazar programas escritos en C.
  • CPLUS_INCLUDE_PATH: Enlazar programas escritos en C++.
  • LIBRARY_PATH: Enlazar bibliotecas .a y .lib (entre otras).

Veamos un ejemplo de definición de variable de entorno:

Set C_INCLUDE_PATH=C:\usr\local\include;C:\usr\local\include\SDL

(NOTA: Es aconsejable introducir rutas sin espacios en blanco, ya que algunos scripts en los entornos de MiNG/MSYS pueden presentar problemas con los espacios en las rutas).

Otro aspecto a tener en cuenta son las bibliotecas de enlace dinámico (DLL) (más información Biblioteca DLL). Si se desea trabajar con éstas en versiones de GHC inferiores a la 7.0.1, se necesitará emplear el instalable dlltool.exe, disponible en el paquete mingw-binutils (véase paquete mingw-binutils), así como el ejecutable pexports.exe, disponible en el paquete mingw-utils (véase paquete mingw-utils).

Si lo desea, puede descargarse la plataforma Haskell para Windows (más información Plataforma Haskell para Windows). Este instalable incluye el compilador GHC mencionado anteriormente, el cual usaremos para realizar las pruebas con CUDA.

Para instalar la plataforma basta con acceder al sitio web indicado en el párrafo anterior y hacer click en el enlace de descarga. Una vez descargada la plataforma, basta con ejecutarla y seguir las ventanas que van apareciendo en el asistente de instalación de la plataforma. Cuando se haya concluido el proceso de instalación, acúdase al menú de inicio de Windows, busque en Todo Programas la plataforma recién instalada. Desplegándose el menú etiquetado como Haskell Platform 2012.4.0.0 ejecútese el compilador GHC.

Paquetehaskellwindows.png

Siguiendo los pasos indicados en el párrafo anterior estará en condiciones de hacer uso del compilador GHC para Haskell.


http://www.haskell.org/haskellwiki/Windows

Instalación GHC en Linux

Como se comentaba al principio del apartado "Instalación", el compilador GHC también se encuentra disponible para el sistema operativo Linux, en concreto, para la distribución Ubuntu. Los pasos que se han de seguir para instalar dicho compilador en Ubuntu son los que siguen:

  • Ábrase una terminal de comandos.
  • Descargar del repositorio Ubuntu los paquetes necesarios para instalar el compilador GHC.
wget http://www.haskell.org/ghc/dist/7.4.1/ghc-7.4.1-i386-unknown-linux.tar.bz2
  • Descomprimir los paquetes que se han descargado en el sito web indicado anteriormente.
tar -xvf ghc-7.4.1-i386-unknown-linux.tar.bz2
  • Posicionarse en el directorio creado recientemente tras descomprimir los paquetes descargados
 cd ghc-7.4.1
  • Ejecutar la configuración para comenzar con la instalación del compilador GHC
 sudo ./configure
  • Por defecto, la instalación se lleva a cabo en el directorio usr/local. Sin embargo, la instalación se puede realizar en el directorio que deseemos, ejecutando la siguiente orden en el terminal de comandos (<my-dir> es la ruta del directorio donde deseamos que se lleve a cabo la instalación)
 sudo ./configure --prefix=<my-dir>
  • Si, al intentar arrancar la configuración se produce el siguiente error:
 ibgmp.so.3: cannot open shared object file: No such file or directory
  • existe una solución, la cual consiste en crear un enlace simbólico a una versión anterior, mediante la orden:
 sudo ln -s /usr/lib/libgmp.so /usr/lib/libgmp.so.3
  • Una vez que la instalación ha finalizado sin errores, el siguiente paso será instalar el compilador GHC propiamente dicho, mediante la orden:
 sudo make install

Tras realizar los pasos anteriores, se habrá finalizado la instalación del compilador GHC en Ubuntu. Para comprobar que dicha instalación se ha realizado correctamente, basta con ejecutar el siguiente comando:

 >ghci

Si todo ha sido instalado correctamente, la respuesta a este comando sería:

 GHCi, version 7.4.1: http://www.haskell.org/ghc/ <img src="http://s1.wp.com/wp-includes/images/smilies/icon_confused.gif  m=1129645325g" alt=":?" class="wp-smiley">  for help
 Loading package ghc-prim ... linking ... done.
 Loading package integer-gmp ... linking ... done.
 Loading package base ... linking ... done.
 Prelude>

Llegados a este punto, se estaría en condiciones de hacer uso del compilador GHC para una distribución Ubuntu.

Instalación de la librería Accelerate

En primer lugar, para poder hacer uso de la librería Accelerate es necesario descargarse el paquete del repositorio:

[Librería Accelerate]

Una vez descargado y descomprimido, nos situamos dentro del directorio y ejecutamos las siguientes órdenes:

  > runhaskell Setup.hs configure --ghc
  > runhaskell Setup.hs build
  > runhaskell Setup.hs install

Cuando la instalación se haya completado, estaremos listos para poder usar la librería Accelerate.

Para poder utilizar la librería accelerate en el compilador Glasgow, debemos introducir en la terminal la siguiente instrucción:

ghci -XFlexibleContexts -XTypeOperators -package accelerate

Instalación del backend de CUDA

Debemos de tener en cuenta que accelerate será una librería, la cual se emplee mayoritariamente con CUDA, por lo que en primer lugar, habrá que instalar el driver para CUDA, así como las herramientas de desarrollo para CUDA (Sitio descarga Driver y developer toolkit CUDA). Indicar que la librería Accelerate ha sido desarrollada para trabajar con la versión 4.0 de CUDA toolkit. No obstante, es posible trabajar con la misma para versiones posteriores a la indicada (Versión actual: 5.0 para Windows, Linux y MAC OS X).

Una vez que ya disponemos del driver correspondiente para CUDA, será necesario seguir una serie de pasos para concluir con la instalación de la librería Accelerate. Éstos son:

  • 1. Añádase a la variable de entorno del Sistema Operativo la ruta /usr/local/cuda/bin (véase Información sobre variables de entorno).
  • 2. Para sistemas operativos Linux y MAC OS X, asegúrese de que la variable de entorno LD_LIBRARY_PATH incluye las rutas:
    • Para distribuciones Linux y MAC OS X de 32 bits: /usr/local/cuda/lib.
    • Para distribuciones Linux de 64 bits: /usr/local/cuda/lib64:/usr/local/cuda/lib

Los usuarios del sistema operativo Linux (tanto distribuciones de 32 como 64 bits) pueden añadir a las variable de entorno LD_LIBRARY_PATH la ruta /etc/ld.so.conf

Lo siguiente que se debe realizar, para poder hacer uso de CUDA, es realizar la instalación y test de los enlaces. Sigánse los siguientes pasos:

  • 1. Áccedase al compilador Glasgow Haskell (GHC). Para ello, tecléese en la consola de comandos de su sistema operativo la orden ghci. El compilador se cargará y en el prompt aparecerá la palabra prelude.
arranque compilador GHC
  • 2. Se debe introducir en la consola de comandos la orden :m +Foreign.CUDA. A continuación, el prompt cambiará y mostrará Prelude Foreign.CUDA.
  • 3. Por último se debe ejecutar la siguiente instrucción props 0..

Una vez que los enlaces se encuentran en su lugar, la instalación de Accelerate-cuda debe realizarse sin problemas.

Estructuras y tipos de datos

Lenguaje estratificado

Accelerate distingue los tipos de cálculos colectivos (Acc) y escalares (Exp), para lograr un lenguaje estratificado.

Las operaciones colectivas conllevan muchos cálculos escalares que se ejecutan en paralelo, pero los cálculos escalares no pueden contener operaciones colectivas.

Esta separación excluye por tanto la anidación, en su lugar, Accelerate está limitado a los datos paralelos planos en la que participan sólo matrices multidimensinales regulares.

Formas

Las operaciones en Accelerate toman la forma de operaciones colectivas sobre matrices del tipo Array sh e. El tipo de matriz tiene dos parámetros, sh es la forma de la matriz, el número de dimensiones, y e para representar el tipo de elemento de la matriz, como pueden ser entero (Int) o flotante (Float). Antes de empezar la manipulación de matrices, tenemos que comprender la noción de acelerar la forma de array. Los arrays de Accelerate se parametrizan a través de un tipo que determina la dimensión de la matriz y el tipo de indice.

Se construyen algo así como listas:

  1. data Z = Z
  2. data tail :. head = tail :. head

Aquí, el constructor Z corresponde a una forma con dimensión cero (o un escalar con uno de los elementos) y se utiliza para marcar el final de la lista. El constructor (:.) añade dimensiones adicionales a la forma por ejemplo:

  1. Z :. Int

Es la forma de una matriz unidimensional (un vector) indexados por enteros (Int), mientras que:

  1. Z :. Int :. Int

Es la forma de una matriz de dos dimensiones (una matriz) indexada por un entero (Int) en cada una de sus dimensiones. De hecho, Int es el único tipo de índice permitido en este momento.

Hay que tener en cuenta que el constructor (:.) es asociativo por la izquierda, por lo que Z:. Int:. Int:. es equivalente a (Z:.Int.) :. Int.

Este estilo se usa para construir el tipo y el valor de una forma. Por ejemplo, para definir la forma de un vector de diez elementos:

  1. sh :: Z :. Int
  2. sh =  Z :. 10

También hay algunos sinónimos de tipos útiles disponibles:

  1. type DIM0 = Z
  2. type DIM1 = DIM0 :. Int
  3. type DIM2 = DIM1 :. Int
  4. type DIM3 = DIM2 :. Int
  5.  
  6.  
  7. type Array DIM0 e = Scalar e
  8. type Array DIM1 e = Vector e

Arrays

Tipos de arrays

Accelerate soporta arrays en los que sus elementos son de tipo atómico simple, y tuplas de los mismos. Esos tipos de elementos se pueden almacenar de manera eficiente en memoria en posiciones consecutivas. Esta característica es importante para apoyar las implementaciones back-end de este tipo de hardware.

Los tipos de elementos soportados para los arrays son miembros de la clase Elt, entre ellos podemos encontrar:

  • ()
  • Formas (Shapes) e índices.
  • Int, Int8, Int16, Int32, Int64
  • Word, Word8, Word16, Word32, Word64
  • Float
  • Double
  • Char
  • Bool
  • Tipos de tuplas (hasta 9), incluyendo tuplas anidadas.


Arrays embebidos

Accelerate es un lenguaje embebido que distingue entre arrays en la memoria de la CPU (Vanilla Haskell Arrays) y en la memoria de la GPU (Embedded Arrays), así como distingue las operaciones que podemos llevar a cabo con los diferentes tipos de arrays. Los cálculos en arrays embebidos necesitan ser ejecutados de manera explícita antes de que tengan efecto; ellos son identificados por tipos construidos desde el tipo de constructor Acc, que está parametrizado por una tupla de uno o más arrays que son el resultado de la computación embebida.

La siguiente función embebe un array de Haskell en un array computacional embedido, lo que implica una transferencia de memoria del host al dispositivo.

  1. use :: (Shape sh, Elt e)
  2. => Array sh e -> Acc (Array sh e)

Los tipos de clases Shape y Elt caracterizan los tipos que tienen los indices y los elementos de un array respectivamente. Los elementos de un array pueden ser enteros con o sin signo y números en coma flotante de simple o doble precisión. Por otra parte, se pueden utilizar como elementos de la matriz: Char, Bool y tuplas de todos los índices de la matriz, formados a partir de Z y (:.).

En el contexto de la programación GPU, la distinción entre array regulares de tipo Array sh e y arrays de lenguaje embebido Acc (Array sh e) tiene el beneficio añadido de diferenciar entre los arrays almacenados en memoria del host y los arrays almacenados en la memoria de la GPU. Consecuentemente, esto implica la transferencia de host a dispositivo, análogamente los cálculos Acc son ejecutados en los dipositivos, mientras que el código normal de Haskell se ejecuta en el host.

Conversión desde listas

Se pueden crear Arrays Accelerate de muchas maneras, por ejemplo, a partir de una lista de Haskell usando la siguiente función:

  1. fromList :: (Shape sh, Elt e) => sh -> [e] -> Array sh e

Esto generará un Array multidimensional extrayendo los elementos de la lista y agregándolos a la matriz en orden por filas.

Para crear un Array es necesario incluir una declaración de tipo explícita para el Array. Por ejemplo, para crear un Vector introducimos la siguiente expresión:

  1. ghci> fromList (Z:.20) [1..20] :: Vector Float

También se pueden crear Arrays multidimensionales. Por ejemplo, un Array bidimensional de 4 filas y 8 columnas:

  1. ghci> fromList (Z:.4:.8) [1..32] :: Array DIM2 Int

Se puede acceder a un elemento específico de un Array con de la siguiente manera:

  1. ghci> let matriz = fromList (Z:.4:.8) [1..32] :: Array DIM2 Int
  2. ghci> indexArray matriz (Z:.3:.5)

La expresión anterior nos devolvería el elemento de la fila 3 y columna 5 del Array creado.

Se puede cambiar la forma de un Array sin modificar su representación, ya que internamente el Array es en realidad un Vector y la forma (Shape) indica a Accelerate como interpretar los índices. Por ejemplo, se puede cambiar la matriz anterior de 4x8 en una matriz de 8x4.

También se pueden crear Arrays de tuplas (incluso anidadas).

  1. ghci> fromList (Z:.3:.5) $ Prelude.zip [1..15] ['a'..'o'] :: Array DIM2 (Int,Char)

La salida que produciría la expresión anterior sería la siguiente:

  1. Array (Z :. 3 :. 5) [(1,'a'),(2,'b'),(3,'c'),(4,'d'),(5,'e'),(6,'f'),(7,'g'),(8,'h'),(9,'i'),(10,'j'),(11,'k'),(12,'l'),(13,'m'),(14,'n'),(15,'o')]

Pero internamente Accelerate convierte el Array de tuplas en una tupla de Arrays.

  1. ([1..15],['a'..'o'])


Conversión desde Data.Array.IArray

También se pueden convertir Arrays inmutables definidos en la librería Data.Array directamente a Arrays Accelerate usando la siguiente función:

  1. fromIArray
  2.   :: (IArray a e,
  3.       Ix ix,
  4.       Shape sh,
  5.       Elt ix,
  6.       Elt e,
  7.       Data.Array.Accelerate.Array.Sugar.EltRepr ix
  8.         ~
  9.       Data.Array.Accelerate.Array.Sugar.EltRepr sh) =>
  10.      a ix e -> A.Array sh e

En el siguiente ejemplo se declara un vector de diez elementos utilizando la biblioteca Data.Array.Unboxed. Posteriormente, se convierte el vector creado en un Array Accelerate empleando la función fromIArray:

  1. ghci> let vector = listArray (0,10) [1..11] :: UArray Int Float
  2. ghci> fromIArray vector :: Vector Float

Del mismo modo, podemos convertir Arrays multidimensionales. Para un Array Accelerate de dos dimensiones, el tipo de índice del IArray debe ser (Int, Int). Para un Array tridimensional (Int, Int, Int), y así sucesivamente.

  1. ghci> let matriz = listArray ((0,0), (2,5)) [1..18] :: UArray (Int,Int) Int
  2. ghci> fromIArray matriz :: Array DIM2 Int

También se puede convertir un Array Singleton, el tipo del índice del IArray debe ser ().

  1. ghci> let unidad = listArray ((),()) [25] :: UArray () Int
  2. ghci> fromIArray unidad :: Scalar Int

Conversiones desde Data.Vector.Storable

La librería Vector implementa operaciones sobre Arrays de una dimensión indexados. La conversión de vectores de tipo Storable a Arrays Accelerate requiere de un conjunto de vectores, debido a que Accelerate soporta Arrays de tuplas, pero no hay ninguna instancia estándar de Storable para tuplas.

La siguiente función convierte una colección de vectores en un Array Accelerate:

  1. fromVectors :: (Shape sh, Elt e) => sh -> Vectors (EltRepr e) -> Array sh e

El parámetro sh es la forma, es decir, indica la dimensión en la que se debe interpretar el Array. El segundo parámetro es un conjunto de tipos que representa la colección de vectores almacenables.

Además, se puede convertir un Array Accelerate a una colección de vectores almacenables.

  1. toVectors :: (Shape sh, Elt e) => Array sh e -> Vectors (EltRepr e)

Intérprete de código embebido

Data.Array.Accelerate.Interpreter nos ofrece un intérprete para el lenguaje de Arrays embebidos.

Para ejecutar un programa de Arrays embebidos se utiliza la siguiente función:

  1. run :: Arrays a => Acc a -> a

También existen otras funciones, como la siguiente, para preparar y ejecutar un programa de arrays embebidos de un argumento.

  1. run1 :: (Arrays a, Arrays b) => (Acc a -> Acc b) -> a -> b

Y la siguiente, para crear un flujo de lectura perezosa que lee arrays través de un programa creando una colección de resultados a medida que se avanza.

  1. stream :: (Arrays a, Arrays b) => (Acc a -> Acc b) -> [a] -> [b]

Funcionalidades de la librería

La principal funcionalidad de la libreria es la de mejorar el procesamiento de vectores en el lenguaje Haskell.

Según las pruebas de rendimiento que han llevado a cabo los autores de los artículos científicos que hemos analizado, se indica que una fusión optimizando la combinación de Kernel adyacentes, siempre que sea posible, ayudaría a cerrar la brecha existente entre el generador de código y el código CUDA.

Limitaciones de la librería

En el contexto de la programación paralela, la fusión necesita ser aplicada con cuidado para evitar la eliminación de demasiado paralelismo disponible. Consecuentemente, muchos estándar de técnicas de fusión no se pueden aplicar directamente. La fusión podría ser implementada haciendo coincidir en un conjunto fijo de cominaciones de operaciones colectivas, pero esto conduce rapidamente a una explosión combinatoria de reglas que requieren reglas de optimización.

Módulos

El árbol de módulos de Accelerate viene recogido de la siguiente forma:

Data
    Array
         Data.Array.Accelerate
             Data.Array.Accelerate.AST
             Analysis
                 Data.Array.Accelerate.Analysis.Match
                 Data.Array.Accelerate.Analysis.Shape
                 Data.Array.Accelerate.Analysis.Stencil
                 Data.Array.Accelerate.Analysis.Type
             Array
                 Data.Array.Accelerate.Array.Data
                 Data.Array.Accelerate.Array.Representation
                 Data.Array.Accelerate.Array.Sugar
                 Data.Array.Accelerate.Debug
                 Data.Array.Accelerate.Interpreter
                 Data.Array.Accelerate.Pretty
                 Data.Array.Accelerate.Smart
                 Data.Array.Accelerate.Trafo
                 Data.Array.Accelerate.Trafo.Sharing
                 Data.Array.Accelerate.Tuple
                 Data.Array.Accelerate.Type

Ejemplos de uso

Veamos, a continuación, un ejemplo de como definir una función usando el lenguaje Haskell de forma tradicional y empleando la librería Accelerate.

  1. import Prelude                                  as P
  2. import Data.Array.Accelerate                    as Acc
  3. import Data.Array.Accelerate.Interpreter
  4.  
  5. -- Empleo de listas Haskell
  6. dotp_list :: [Float] -> [Float] -> Float
  7. dotp_list xs ys = P.foldl (+) 0 (P.zipWith (*) xs ys)
  8.  
  9. -- Usando Accelerate
  10. dotp :: Vector Float -> Vector Float -> Acc (Scalar Float)
  11. dotp xs ys = Acc.fold (+) 0 (Acc.zipWith (*) xs' ys')
  12.  where xs' = use xs
  13.        ys' = use ys

En la primera función los dos vectores de entrada se multiplican punto por punto y los productos resultantes se suman, obteniéndose un resultado escalar.

En la segunda función, las funciones fold y zipWith pertenecen a la librería Data.Array.Accelerate. Diferenciándose en tres aspectos:

  • El resultado es un cáculo Accelerate, indicado por Acc.
  • Embebe los dos Arrays en Acc con la función use.
  • Utiliza fold en lugar de foldl.

Las operaciones con elementos embebidos no realizan directamente cálculos, sino que construyen árboles que representan los cálculos embebidos para que se puedan interpretar.

Para poder realizar el cálculo del árbol creado con la función dotp, se ejecuta la siguiente función:

  1. run (dotp v1 v2)

Donde v1 y v2, serían, por ejemplo:

  1. let v1 = fromList (Z:.20) [1..20] :: Vector Float
  2. let v2 = fromList (Z:.20) [1..20] :: Vector Float

Referencias

Herramientas personales