Matrices de estilo NumPy para C ++?


84

¿Hay alguna biblioteca de C ++ (o C) que tenga matrices similares a NumPy con soporte para cortar, operaciones vectorizadas, sumar y restar contenido elemento por elemento, etc.?



1
Hasta donde yo sé, numpy usa LAPACK . Si bien eso está escrito en Fortran, hay enlaces de C ++ disponibles. Sin embargo, nunca usé ninguno de esos.
Voo

Hay una interfaz C ++ reciente para NumPy, llamada ArmaNpy .
Mtall

1
Todavía no puedo ver Boost.MultiArray en los comentarios
Dmitry Ledentsov

Podría intentar incrustar Python y realmente usar numpy, lo que tendría la ventaja de no necesitar aprender una nueva biblioteca, aunque sería más lento que usar una biblioteca C / C ++.
Kevin

Respuestas:


58

Aquí hay varios programas de software gratuitos que pueden satisfacer sus necesidades.

  1. La Biblioteca Científica GNU es un software GPL escrito en C. Por lo tanto, tiene una asignación similar a C y una forma de programación (punteros, etc.). Con GSLwrap , puede tener una forma de programación C ++, mientras sigue usando GSL. GSL tiene una implementación BLAS , pero puede usar ATLAS en lugar del CBLAS predeterminado, si desea aún más actuaciones.

  2. La biblioteca boost / uBLAS es una biblioteca BSL, escrita en C ++ y distribuida como un paquete boost. Es una forma C ++ de implementar el estándar BLAS. uBLAS viene con algunas funciones de álgebra lineal, y hay un enlace experimental a ATLAS .

  3. eigen es una biblioteca de álgebra lineal escrita en C ++, distribuida bajo la licencia MPL2 (a partir de la versión 3.1.1) o LGPL3 / GPL2 (versiones anteriores). Es una forma de programación C ++, pero más integrada que las otras dos (hay más algoritmos y estructuras de datos disponibles). Eigen afirma ser más rápido que las implementaciones de BLAS anteriores, sin seguir la API BLAS estándar de facto. Eigen no parece esforzarse mucho en la implementación paralela.

  4. Armadillo es una biblioteca LGPL3 para C ++. Tiene enlace para LAPACK (la biblioteca utilizada por numpy). Utiliza plantillas recursivas y metaprogramación de plantillas, lo cual es un buen punto (no sé si otras bibliotecas también lo están haciendo).

  5. xtensor es una biblioteca de C ++ con licencia BSD. Ofrece una API de C ++ muy similar a la de NumPy. Consulte https://xtensor.readthedocs.io/en/latest/numpy.html para ver una hoja de trucos.

Estas alternativas son realmente buenas si solo desea obtener estructuras de datos y álgebra lineal básica. Dependiendo de su gusto por el estilo, la licencia o los desafíos del administrador de sistemas (instalar bibliotecas grandes como LAPACK puede ser difícil), puede elegir la que mejor se adapte a sus necesidades.


15
Lo crea o no, mi respuesta es el resultado de mi propia búsqueda, hace un mes. Creía que reunir la información que me ayudó a tomar mi decisión sería de algún interés. No estoy seguro de si es mejor tener varias informaciones distribuidas en las respuestas. Aún puede votar a favor de todos si se siente más preocupado por la ética que por la eficiencia.
nojhan

19
Lamentablemente, ninguno de estos proporciona algo tan general y conveniente como matrices numpy. Las matrices Numpy son de dimensiones arbitrarias y admiten cosas como a[:4,::-1,:,19] = b[None,-5:,None]o a[a>5]=0y similares, además de tener un gran conjunto de funciones de manipulación de matrices e índices disponibles. Realmente espero que alguien haga algo así para C ++ algún día.
amaurea

2
OpenCV también tiene un tipo Matrix que puede tener un tamaño dimensional arbitrario; rangos de columna / fila ( a.colRange(4,7).rowRange(4,8)para a[4:7,4,8]) y máscara de condición ( a.setTo(cv::Scalar(0), a>5)para a[a>5]=0)
xaedes

3
@amaurea echa un vistazo a la respuesta en xtensor a continuación, que habilita todo lo anterior.
Quant

1
Tuve que usar Eigen en un proyecto reciente y debo decir que si bien parece ser eficiente, la sintaxis es absolutamente terrible. No hay nada de esa asombrosa sintaxis de corte de Python disponible. Por ejemplo, si tiene un vector x 1D y desea manipular los primeros n elementos, debe usar x.head (n). Ni siquiera pregunte acerca de la manipulación de una porción arbitraria de x, necesitará un buen ciclo for antiguo para hacer eso. Este es solo uno de los muchos ejemplos torpes e inconvenientes que podría nombrar.
Alex

54

Prueba xtensor . (Consulte la hoja de referencia de NumPy to Xtensor ).

xtensor es una biblioteca de C ++ destinada al análisis numérico con expresiones de matriz multidimensionales.

xtensor proporciona

  • un sistema de expresión extensible que permite la difusión de estilo numpy.
  • una API que sigue los modismos de la biblioteca estándar de C ++.
  • herramientas para manipular expresiones de matriz y construir sobre xtensor.

Ejemplo

Inicialice una matriz 2-D y calcule la suma de una de sus filas y una matriz 1-D.

#include <iostream>
#include "xtensor/xarray.hpp"
#include "xtensor/xio.hpp"

xt::xarray<double> arr1
  {{1.0, 2.0, 3.0},
   {2.0, 5.0, 7.0},
   {2.0, 5.0, 7.0}};

xt::xarray<double> arr2
  {5.0, 6.0, 7.0};

xt::xarray<double> res = xt::view(arr1, 1) + arr2;

std::cout << res;

Salidas

{7, 11, 14}

Inicialice una matriz 1-D y modifíquela en su lugar.

#include <iostream>
#include "xtensor/xarray.hpp"
#include "xtensor/xio.hpp"

xt::xarray<int> arr
  {1, 2, 3, 4, 5, 6, 7, 8, 9};

arr.reshape({3, 3});

std::cout << arr;

Salidas

{{1, 2, 3},
 {4, 5, 6},
 {7, 8, 9}}

2
@Llamageddon, ¿crees que esta debería ser la respuesta seleccionada?
Quant

7

DyND está diseñado para ser, entre otras cosas, una biblioteca similar a NumPy para C ++. Cosas como la transmisión, los operadores aritméticos y la división funcionan bien. Por otro lado, todavía es muy experimental y muchas funciones aún no se han implementado.

Aquí hay una implementación simple del algoritmo de Casteljau en C ++ usando arreglos DyND:

#include <iostream>
#include <dynd/array.hpp>

using namespace dynd;

nd::array decasteljau(nd::array a, double t){
    size_t e = a.get_dim_size();
    for(size_t i=0; i < e-1; i++){
        a = (1.-t) * a(irange()<(e-i-1)) + t * a(0<irange());
    }
    return a;
}

int main(){
    nd::array a = {1., 2., 2., -1.};
    std::cout << decasteljau(a, .25) << std::endl;
}

Escribí una publicación de blog hace un tiempo con más ejemplos y comparaciones en paralelo de la sintaxis de Fortran 90, DyND en C ++ y NumPy en Python.

Descargo de responsabilidad: soy uno de los desarrolladores actuales de DyND.


3

Eigen es una buena biblioteca de álgebra lineal.

http://eigen.tuxfamily.org/index.php?title=Main_Page

Es bastante fácil de instalar ya que es una biblioteca solo de encabezado. Se basa en una plantilla para generar un código bien optimizado. Vectoriza automáticamente las operaciones matriciales.

También es totalmente compatible con operaciones de coeficiente, como la "multiplicación por elemento" entre dos matrices, por ejemplo. ¿Es lo que necesitas?


3
Sin embargo, la sintaxis de Eigen es bastante terrible. No hay nada de esa sintaxis de corte suave que se encuentra en Numpy. Y no es una biblioteca de matrices n-dimensional general, es más para vectores 1D y matrices 2D únicamente. El hecho de que tengan VectorXd para matrices 1D y MatrixXd para matrices 2D ya me repugna.
Alex

2

Blitz ++ admite matrices con un número arbitrario de ejes, mientras que Armadillo solo admite hasta tres (vectores, matrices y cubos). Eigen solo admite vectores y matrices (no cubos). La desventaja es que Blitz ++ no tiene funciones de álgebra lineal más allá de las operaciones básicas de entrada y las contracciones tensoriales. El desarrollo parece haberse ralentizado hace bastante tiempo, pero tal vez sea solo porque la biblioteca hace lo que hace y no es necesario realizar muchos cambios.


2

xtensor es bueno, pero terminé escribiendo una mini biblioteca yo mismo como un proyecto de juguete con c ++ 20, mientras trataba de mantener la interfaz lo más simple posible. Aquí está: https://github.com/gbalduzz/NDArray

Código de ejemplo:

using namespace nd;
NDArray<int, 2> m(3, 3); // 3x3 matrix
m = 2; // assign 2 to all
m(-1, all) = 1; // assign 1 to the last row.

auto tile = m(range{1, end}, range{1, end}); // 2x2 tile
std::sort(tile.begin(), tile.end());

std::cout << m; // prints [[2, 2, 2], [2, 1, 1], [1, 2, 2]]

Todavía no proporciona operadores aritméticos sofisticados que colapsen múltiples operaciones juntas, pero puede transmitir lambdas arbitrarias a un conjunto de tensores con la misma forma, o usar operadores aritméticos evaluados de manera perezosa.

Déjeme saber qué piensa acerca de la interfaz y cómo se compara con las otras opciones, y si esto tiene alguna esperanza, qué tipo de operaciones le gustaría ver implementadas.

¡Licencia gratuita y sin dependencia!

Anexo: logré compilar y ejecutar correctamente xtensor, y el resultado es que mi biblioteca es significativamente más rápida al iterar sobre las vistas (2 a 3X)


1

VIGRA contiene una buena implementación de matriz N-dimensional:

http://ukoethe.github.io/vigra/doc/vigra/Tutorial.html

Lo uso mucho y lo encuentro muy simple y efectivo. También es solo encabezado, por lo que es muy fácil de integrar en su entorno de desarrollo. Es lo más parecido que he encontrado al uso de NumPy en términos de su API.

El principal inconveniente es que no se usa tan ampliamente como los demás, por lo que no encontrará mucha ayuda en línea. Eso, y tiene un nombre extraño (¡intenta buscarlo!)



1

Ésta es una vieja pregunta. Todavía tenía ganas de responder. El pensamiento podría ayudar a muchos, especialmente a la codificación pydevs en C ++.

Si ya ha trabajado con python numpy, NumCpp es una gran opción. Es minimalista en sintaxis y tiene funciones o métodos similares a py numpy.

La parte de comparación en el documento Léame también es muy, muy buena.

NumCpp

nc::NdArray<int> arr = {{4, 2}, {9, 4}, {5, 6}};
arr.reshape(5, 3);
arr.astype<double>();

0

Eigen es una biblioteca de plantillas para álgebra lineal (matrices, vectores…). Es solo encabezado y de uso gratuito (LGPL).


0

Si desea usar una matriz multidimensional (como numpy) para el procesamiento de imágenes o la red neuronal, puede usar OpenCV cv::Matjunto con toneladas de algoritmos de procesamiento de imágenes. En caso de que solo quiera usarlo para operaciones matriciales SOLAMENTE, solo tiene que compilar los módulos opencv respectivos para reducir el tamaño y tener una pequeña biblioteca OpenCV.

cv::Mat(Matriz) es una matriz n-dimensional que se puede utilizar para almacenar varios tipos de datos, como imágenes RGB, HSV o en escala de grises, vectores con valores reales o complejos, otras matrices, etc.

Un tapete contiene la siguiente información: width, height, type, channels, data, flags, datastart, dataendy así sucesivamente.

Tiene varios métodos para la manipulación de matrices. Bono que puede crear luego en núcleos CUDA y también cv::cuda::GpuMat.

Considere que quiero crear una matriz con 10 filas, 20 columnas, escriba CV_32FC3:

int R = 10, C = 20;
Mat m1; 
m1.create(R, C, CV_32FC3); //creates empty matrix

Mat m2(cv::Size(R, C), CV_32FC3); // creates a matrix with R rows, C columns with data type T where R and C are integers, 

Mat m3(R, C, CV_32FC3); // same as m2

PRIMA:

Compile una biblioteca opencv pequeña y compacta para solo operaciones matriciales. Una de las formas es como se menciona en este artículo.

O

compile el código fuente de opencv usando el siguiente comando cmake:

$ git clone https://github.com/opencv/opencv.git
$ cd opencv
$ git checkout <version you want to checkout>
$ mkdir build
$ cd build
$ cmake -D WITH_CUDA=OFF -D WITH_MATLAB=OFF -D BUILD_ANDROID_EXAMPLES=OFF -D BUILD_DOCS=OFF -D BUILD_PERF_TESTS=OFF -D BUILD_TESTS=OFF -DANDROID_STL=c++_shared -DBUILD_SHARED_LIBS=ON -D BUILD_opencv_objdetect=OFF -D BUILD_opencv_video=OFF -D BUILD_opencv_videoio=OFF -D BUILD_opencv_features2d=OFF -D BUILD_opencv_flann=OFF -D BUILD_opencv_highgui=OFF -D BUILD_opencv_ml=OFF -D BUILD_opencv_photo=OFF -D BUILD_opencv_python=OFF -D BUILD_opencv_shape=OFF -D BUILD_opencv_stitching=OFF -D BUILD_opencv_superres=OFF -D BUILD_opencv_ts=OFF -D BUILD_opencv_videostab=OFF -D BUILD_opencv_dnn=OFF -D BUILD_opencv_imgproc=OFF ..
$ make -j $nproc
$ sudo make install

Prueba este ejemplo:

 #include "opencv2/core.hpp"
 #include<iostream>

 int main()
 {
     std::cout << "OpenCV Version " << CV_VERSION << std::endl;

     int R = 2, C = 4;
     cv::Mat m1;
     m1.create(R, C, CV_32FC1); //creates empty matrix

     std::cout << "My Mat : \n" << m1 << std::endl;
 }

Compile el código con el siguiente comando:

$ g++ -std=c++11 opencv_mat.cc -o opencv_mat `pkg-config --libs opencv` `pkg-config --cflags opencv`

Ejecute el ejecutable:

$ ./opencv_mat

OpenCV Version 3.4.2
My Mat :
[0, 0, 0, 0;
 0, 0, 0, 0]


-1

Si bien GLM está diseñado para combinarse fácilmente con OpenGL y GLSL, es una biblioteca matemática de encabezado completamente funcional para C ++ con un conjunto de interfaces muy intuitivo.

Declara tipos de vectores y matrices, así como varias operaciones sobre ellos.

Multiplicar dos matrices es tan simple como (M1 * M2). Restando dos vectores (V1-V2).

Acceder a los valores contenidos en vectores o matrices es igualmente sencillo. Después de declarar un vector vec3, por ejemplo, se puede acceder a su primer elemento con vector.x. Echale un vistazo.

Al usar nuestro sitio, usted reconoce que ha leído y comprende nuestra Política de Cookies y Política de Privacidad.
Licensed under cc by-sa 3.0 with attribution required.