用于C ++的NumPy样式数组?


83

是否有C ++(或C)库具有类似NumPy的数组,并支持切片,向量化操作,逐元素添加和减去内容等?



1
据我所知numpy使用LAPACK。尽管用Fortran编写,但有可用的c ++绑定。从来没有使用过。
Voo 2012年

NumPy最近有一个C ++接口,称为ArmaNpy
mtall,

1
我还没有在评论中看到Boost.MultiArray
Dmitry Ledentsov 2014年

您可以尝试嵌入Python并实际使用numpy,这样做的好处是不需要学习新的库,尽管它比使用C / C ++库要慢。
凯文(Kevin)

Answers:


57

这里有一些可能满足您需求的免费软件。

  1. GNU科学图书馆是用C编写因此,一个GPL软件,它具有类C(指针等)的分配和方式。使用GSLwrap,您可以使用C ++编程方式,同时仍使用GSL。GSL具有BLAS实现,但是如果您想获得更高的性能,则可以使用ATLAS代替默认的CBLAS。

  2. 升压/ uBLAS库库是一个BSL库,用C ++编写和分布式作为升压包。这是实现BLAS标准的C ++方法。uBLAS具有一些线性代数函数,并且与ATLAS实验绑定

  3. eigen是一个用C ++编写的线性代数库,以MPL2许可证(从3.1.1版开始)或LGPL3 / GPL2(旧版本)分发。这是一种C ++编程方式,但是比其他两种方式集成度更高(可用的算法和数据结构更多)。本征声称比上面的BLAS实现要快,但没有遵循事实上的标准BLAS API。Eigen似乎并没有在并行实现上投入很多精力。

  4. Armadillo是C ++的LGPL3库。它具有对LAPACK(numpy使用的库)的绑定。它使用递归模板和模板元编程,这是一个好主意(我不知道其他库是否也在这样做吗?)。

  5. xtensor是BSD许可的C ++库。它提供了一个与NumPy非常相似的C ++ API。有关备忘单,请参见https://xtensor.readthedocs.io/en/latest/numpy.html

如果您只想获取数据结构和基本线性代数,那么这些替代方法真的很好。根据您对样式,许可证或系统管理员挑战的喜好(安装LAPACK之类的大型库可能很困难),可以选择最适合自己需要的一种。


15
信不信由你,我的答案是一个月前我自己搜索的结果。我相信收集有助于我做出选择的信息会引起一定的兴趣。我不确定在答案中分散一些信息是否更好。如果您更关心道德而不是效率,那么您仍然可以赞美每个人。
nojhan 2012年

19
可悲的是,这些方法都没有提供比numpy数组更通用和更方便的方法。Numpy数组是任意维的,支持类似a[:4,::-1,:,19] = b[None,-5:,None]a[a>5]=0类似的事物,并且具有大量可用的数组和索引操作函数。我真的希望有一天能为C ++做类似的事情。
amaurea 2014年

2
OpenCV还具有可以具有任意尺寸大小的Matrix类型。列/行范围(a.colRange(4,7).rowRange(4,8)a[4:7,4,8])和条件掩模(a.setTo(cv::Scalar(0), a>5)用于a[a>5]=0
xaedes

3
@amaurea在下面的xtensor上查看答案,这将启用所有上述功能。
定量

1
我不得不在一个最近的项目中使用Eigen,我不得不说,尽管它看起来很有效,但语法绝对糟糕。没有令人惊奇的Python切片语法可用。例如,如果您有一个一维向量x,并且要操纵前n个元素,则必须使用x.head(n)。甚至不问关于操纵x的任意切片的问题,您将需要一个好的旧的for循环来做到这一点。这只是我可以列举的许多笨拙且不便的示例之一。
亚历克斯

53

试用xtensor。(请参阅NumPy至Xtensor备忘单)。

xtensor是一个C ++库,用于使用多维数组表达式进行数值分析。

xtensor提供

  • 一个可扩展的表达系统,可以实现numpy风格的广播。
  • 遵循C ++标准库惯用法的API。
  • 操纵数组表达式并在xtensor上构建的工具。

初始化一个2-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;

产出

{7, 11, 14}

初始化一维数组并对其进行整形。

#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;

产出

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

2
@Llamageddon您认为这应该是选择的答案吗?
定量

7

DyND被设计为C ++的类似NumPy的库。广播,算术运算符和切片之类的东西都可以正常工作。在另一方面,它仍然是非常实验和许多功能尚未实现。

这是使用DyND数组的C ++中的de Casteljau算法的简单实现:

#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;
}

我不久前写了一篇博客文章,其中包含Fortran 90,C ++中的DyND和Python中的NumPy的语法的更多示例和并排比较。

免责声明:我是目前的DyND开发人员之一。


3

本征是一个很好的线性代数库。

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

由于它是仅标头的库,因此安装非常容易。它依靠模板来生成优化的代码。它自动矢量化矩阵运算。

它还完全支持系数明智的运算,例如,两个矩阵之间的“每元素乘法”。这是你需要的吗?


3
Eigen的语法非常糟糕。在Numpy中找不到平滑的切片语法。它不是通用的n维数组库,仅适用于1D向量和2D矩阵。他们拥有适用于一维阵列的VectorXd和适用于2D阵列的MatrixXd的事实已经使我感到排斥。
亚历克斯

2

Blitz ++支持具有任意数量的轴的数组,而Armadillo仅支持最多三个(向量,矩阵和立方体)。本征仅支持向量和矩阵(不支持立方体)。缺点是Blitz ++没有基本代入运算和张量收缩的线性代数函数。开发似乎已经在相当一段时间以前放慢了速度,但这也许只是因为库可以完成它的工作,并且不需要进行很多更改。


2

xtensor很好,但是我最终还是用c ++ 20自己编写了一个小型库作为玩具项目,同时试图使界面尽可能简单。它在这里:https : //github.com/gbalduzz/NDArray

示例代码:

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]]

它没有提供将多个运算折叠在一起的复杂算术运算符,但是您可以将任意lambda广播到具有相同形状的一组张量,或者使用延迟评估的算术运算符。

让我知道您如何看待该接口,以及它与其他选项的比较,如果有希望,您希望实现哪种操作。

免费许可证,无依赖性!

附录:我设法正确编译并运行xtensor,结果是遍历视图时,我的库明显更快(2到3倍)


1

VIGRA包含良好的N维数组实现:

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

我广泛使用它,发现它非常简单有效。它也只是标头,因此很容易集成到您的开发环境中。就API而言,这是我使用NumPy遇到的最接近的事情。

主要缺点是它没有像其他人那样广泛使用,因此您不会在网上找到太多帮助。那样,它的名称笨拙(尝试搜索!)



1

这是一个老问题。仍然感觉像在回答。思想可能会帮助很多人,尤其是C ++中的pydevs编码。

如果您已经使用过python numpy,请使用NumCpp是一个不错的选择。它的语法极简,并且具有与py numpy类似的功能或方法。

自述文件中的比较部分也非常酷。

数字Cpp

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

0

本征是线性代数(矩阵,向量等)的模板库。它仅是标头,可以免费使用(LGPL)。


0

如果要使用多维数组(例如numpy)进行图像处理或神经网络,则可以OpenCV cv::Mat与大量图像处理算法一起使用。如果只想将其用于矩阵运算,则只需编译各自的opencv模块以减小大小,并使用微型OpenCV库。

cv::Mat(Matrix)是一个n维数组,可用于存储各种类型的数据,例如RGB,HSV或灰度图像,具有实数值或复数值的矢量,其他矩阵等。

垫包含以下信息:width, height, type, channels, data, flags, datastart, dataend等等。

它有几种矩阵处理方法。您可以在CUDA核心以及上创建奖金cv::cuda::GpuMat

考虑我想创建一个具有10行20列的矩阵,键入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

奖金:

编译微小而紧凑的opencv库,仅用于矩阵操作。一种方式就像本文中提到的那样。

要么

使用以下cmake命令编译opencv源代码:

$ 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

试试这个例子:

 #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;
 }

使用以下命令编译代码:

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

运行可执行文件:

$ ./opencv_mat

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


-1

虽然GLM旨在轻松地与OpenGL和GLSL啮合,但它是C ++的全功能标头数学库,具有非常直观的界面集。

它声明向量和矩阵类型以及它们的各种运算。

将两个矩阵相乘很简单(M1 * M2)。减去两个向量(V1-V2)。

访问向量或矩阵中包含的值同样简单。例如,在声明vec3向量后,可以使用vector.x访问其第一个元素。一探究竟。

By using our site, you acknowledge that you have read and understand our Cookie Policy and Privacy Policy.
Licensed under cc by-sa 3.0 with attribution required.