Jugando con ArrayFire: 04 First Know Array (1)


Prefacio

En "Jugando con ArrayFire: 03 El primer programa ArrayFire", hemos creado el primer programa ArrayFire, pero no teníamos un conocimiento profundo del uso de ArrayFire. En este artículo, continuaremos aprendiendo el uso específico de ArrayFire.


1. Tipos de datos admitidos por matriz

     ArrayFire proporciona un objeto contenedor general para realizar funciones y operaciones matemáticas en la matriz . La matriz puede representar muchos tipos de datos básicos diferentes, como se muestra en la siguiente tabla. Y, a menos que se especifique lo contrario, el tipo de datos predeterminado de la matriz es f32 (número real de punto flotante de precisión simple).

f32 Punto flotante de precisión simple real flotador
c32 Punto flotante de precisión simple complejo cfloat
f64 Punto flotante de doble precisión real doble
c64 Número complejo de coma flotante de doble precisión cdouble
b8 Booleano de 8 bits bool
s32 Entero de 32 bits con signo En t
u32 Entero sin signo de 32 bits no firmado
u8 Entero sin signo de 8 bits char sin firmar
s64 Entero de 4 bits con signo intl
s16 Entero de 6 bits con signo corto
u16 Entero sin signo de 16 bits corto sin firmar

Dos, crea y llena la matriz

     matriz representa almacenada en la memoria del dispositivo . Por lo tanto, la creación y el llenado de matrices consumirán memoria en el dispositivo, que solo se puede liberar cuando el objeto de matriz queda fuera de alcance . Dado que la asignación de memoria del dispositivo puede ser costosa, ArrayFire también incluye un administrador de memoria , que reutilizará la memoria del dispositivo siempre que sea posible.
    Cuando necesite utilizar el tipo de matriz, puede crear una matriz . A continuación, mostramos cómo crear matrices 1D, 2D y 3D con valores no inicializados:

    // Arrays may be created using the af::array constructor and dimensioned
    // as 1D, 2D, 3D; however, the values in these arrays will be undefined
    array undefined_1D(100);        // 1D array with 100 elements
    array undefined_2D(10, 100);    // 2D array of size 10 x 100
    array undefined_3D(10, 10, 10); // 3D array of size 10 x 10 x 10

    Sin embargo, la memoria no inicializada puede no ser útil en la aplicación. ArrayFire proporciona varias funciones convenientes para crear matrices que contienen valores precargados, incluidas constantes, números aleatorios uniformes, números de distribución normal uniformes y matriz de identidad:

    // Generate an array of size three filled with zeros.
    // If no data type is specified, ArrayFire defaults to f32.
    // The af::constant function generates the data on the device.
    array zeros      = constant(0, 3);
    // Generate a 1x4 array of uniformly distributed [0,1] random numbers
    // The af::randu function generates the data on the device.
    array rand1      = randu(1, 4);
    // Generate a 2x2 array (or matrix, if you prefer) of random numbers
    // sampled from a normal distribution.
    // The af::randn function generates data on the device.
    array rand2      = randn(2, 2);
    // Generate a 3x3 identity matrix. The data is generated on the device.
    array iden       = af::identity(3, 3);
    // Lastly, create a 2x1 array (column vector) of uniformly distributed
    // 32-bit complex numbers (c32 data type):
    array randcplx   = randu(2, 1, c32);

     La matriz también se puede llenar con datos en el host. P.ej:

    // Create a six-element array on the host
    float hA[] = {
    
    0, 1, 2, 3, 4, 5};
    // Which can be copied into an ArrayFire Array using the pointer copy
    // constructor. Here we copy the data into a 2x3 matrix:
    array A(2, 3, hA);
    // ArrayFire provides a convenince function for printing af::array
    // objects in case you wish to see how the data is stored:
    af_print(A);
    // This technique can also be used to populate an array with complex
    // data (stored in {
    
    {real, imaginary}, {real, imaginary},  ... } format
    // as found in C's complex.h and C++'s <complex>.
    // Below we create a 3x1 column vector of complex data values:
    array dB(3, 1, (cfloat*) hA); // 3x1 column vector of complex numbers
    af_print(dB);

     ArrayFire también admite la inicialización de matrices desde la memoria de la GPU . Por ejemplo, usando CUDA, puede llamar directamente a cudaMemcpy para llenar la matriz :

    // Create an array on the host, copy it into an ArrayFire 2x3 ArrayFire array
    float host_ptr[] = {
    
    0,1,2,3,4,5};
    array a(2, 3, host_ptr);
    // Create a CUDA device pointer, populate it with data from the host
    float *device_ptr;
    cudaMalloc((void**)&device_ptr, 6*sizeof(float));
    cudaMemcpy(device_ptr, host_ptr, 6*sizeof(float), cudaMemcpyHostToDevice);
    // Convert the CUDA-allocated device memory into an ArrayFire array:
    array b(2,3, device_ptr, afDevice); // Note: afDevice (default: afHost)
    // Note that ArrayFire takes ownership over `device_ptr`, so memory will
    // be freed when `b` id destructed. Do not call cudaFree(device_ptr)!

     OpenCL tiene funciones similares. Si desea mezclar ArrayFire con código CUDA o OpenCL, le recomendamos que consulte la página Interoperabilidad CUDA o Interoperabilidad OpenCL para obtener instrucciones detalladas.

Tres, el contenido, el tamaño y los atributos de la matriz.

     ArrayFire proporciona algunas funciones para determinar las características de una matriz , incluidas funciones para imprimir contenido, consultar dimensiones y otras características.
     La función af_print se puede utilizar para imprimir la matriz generada o cualquier expresión que involucre una matriz :

    // Generate two arrays
    array a = randu(2, 2);
    array b = constant(1, 2, 1);
    // Print them to the console using af_print
    af_print(a);
    af_print(b);
    // Print the results of an expression involving arrays:
    af_print(a.col(0) + b + .4);

     La dimensión de la matriz puede ser determinada por el dim4 objeto, o se puede determinar por acceder directamente a la dimensión utilizando los dims () y numdims () funciones:

    // Create a 4x5x2 array of uniformly distributed random numbers
    array a = randu(4,5,2);
    // Determine the number of dimensions using the numdims() function:
    printf("numdims(a)  %d\n",  a.numdims()); // 3
    // We can also find the size of the individual dimentions using either
    // the `dims` function:
    printf("dims = [%lld %lld]\n", a.dims(0), a.dims(1)); // 4,5
    // Or the elements of a af::dim4 object:
    dim4 dims = a.dims();
    printf("dims = [%lld %lld]\n", dims[0], dims[1]); // 4,5

    Además de las dimensiones, las matrices también tienen otras propiedades, como determinar el tipo y tamaño subyacentes (en bytes). Y también puede determinar si la matriz está vacía, real / compleja, fila / columna, escalar o vectorial:

    // Get the type stored in the array. This will be one of the many
    // `af_dtype`s presented above:
    printf("underlying type: %d\n", a.type());
    // Arrays also have several conveience functions to determine if
    // an Array contains complex or real values:
    printf("is complex? %d    is real? %d\n", a.iscomplex(), a.isreal());
    // if it is a column or row vector
    printf("is vector? %d  column? %d  row? %d\n", a.isvector(), a.iscolumn(), a.isrow());
    // and whether or not the array is empty and how much memory it takes on
    // the device:
    printf("empty? %d  total elements: %lld  bytes: %lu\n", a.isempty(), a.elements(), a.bytes());

Cuarto, la expresión matemática de matriz

     ArrayFire proporciona un motor de compilación inteligente justo a tiempo (JIT) que puede convertir expresiones que usan matriz en un núcleo CUDA / OpenCL mínimo. Para la mayoría de las operaciones de matriz , la función ArrayFire es similar a la biblioteca de vectores. Esto significa que las operaciones de elementos como c [i] = a [i] + b [i] en C se pueden escribir de manera más concisa sin indexar, como c = a + b. Cuando hay varias expresiones que involucran matrices , el motor JIT de ArrayFire las fusionará. Esta tecnología de "fusión del núcleo" no solo reduce el número de llamadas al núcleo, sino que, lo que es más importante, evita las operaciones de memoria global externa. Nuestra función JIT extiende el límite de la función C / C ++ y solo finaliza cuando encuentra una función no JIT o el código llama explícitamente a una operación síncrona.
     ArrayFire proporciona cientos de funciones para la manipulación de elementos. Admite todos los operadores estándar (como +, -, *, /), así como la mayoría de funciones trascendentales (sin, cos, log, sqrt, etc.). Aquí hay unos ejemplos:

    array R = randu(3, 3);
    af_print(constant(1, 3, 3) + af::complex(sin(R)));  // will be c32
    // rescale complex values to unit circle
    array a = randn(5, c32);
    af_print(a / abs(a));
    // calculate L2 norm of vectors
    array X = randn(3, 4);
    af_print(sqrt(sum(pow(X, 2))));     // norm of every column vector
    af_print(sqrt(sum(pow(X, 2), 0)));  // same as above
    af_print(sqrt(sum(pow(X, 2), 1)));  // norm of every row vector

Cinco, constantes matemáticas

     ArrayFire contiene algunas constantes independientes de la plataforma, como Pi, NaN e Inf. Si ArrayFire no tiene las constantes que necesita, puede usar el constructor de matriz af :: constant para crear sus propias constantes.
    Las constantes se pueden utilizar en todas las funciones de ArrayFire. A continuación, demostraremos su uso en la selección de elementos y expresiones matemáticas:

    array A = randu(5,5);
    A(where(A > .5)) = af::NaN;
    array x = randu(10e6), y = randu(10e6);
    double pi_est = 4 * sum<float>(hypot(x,y) < 1) / 10e6;
    printf("estimation error: %g\n", fabs(Pi - pi_est));

    Tenga en cuenta que nuestras constantes a veces pueden entrar en conflicto con las definiciones de macros en los archivos de encabezado estándar. Cuando esto suceda, utilice el espacio de nombres af :: para hacer referencia a nuestras constantes.


Supongo que te gusta

Origin blog.csdn.net/weixin_42467801/article/details/113574240
Recomendado
Clasificación