【问题标题】:NumPy style arrays for C++? [closed]C++ 的 NumPy 样式数组? [关闭]
【发布时间】:2012-06-25 12:47:20
【问题描述】:

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

【问题讨论】:

  • 据我所知numpy使用LAPACK。虽然这是用 Fortran 编写的,但有可用的 c++ 绑定。但是从来没有使用过任何一个。
  • 最近有一个 NumPy 的 C++ 接口,称为ArmaNpy
  • 我在 cmets 中还看不到 Boost.MultiArray
  • 这是一个非常宝贵的软件编码问题。为什么关闭了????

标签: c++ arrays python-3.x numpy dynamic-arrays


【解决方案1】:

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

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

安装非常简单,因为它是一个只有头文件的库。它依赖于模板来生成优化好的代码。它自动向量化矩阵运算。

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

【讨论】:

  • Eigen 的语法虽然很糟糕。在 Numpy 中没有那种平滑的切片语法。而且它不是一个通用的 n 维数组库,它更多的是仅用于 1D 向量和 2D 矩阵。他们有用于 1D 数组的 VectorXd 和用于 2D 数组的 MatrixXd 的事实已经让我感到厌恶。
【解决方案2】:

Eigen 是一个用于线性代数(矩阵、向量...)的模板库。它只是标题并且可以免费使用 (LGPL)。

【讨论】:

    【解决方案3】:

    GSL 很棒,它可以满足您的所有要求,甚至更多。不过它是在 GPL 下获得许可的。

    【讨论】:

      【解决方案4】:

      这里有几款可能适合您需求的免费软件。

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

      2. boost/uBLAS 库是一个 BSL 库,用 C++ 编写并作为 boost 包分发。它是实现 BLAS 标准的 C++ 方式。 uBLAS自带了一些线性代数函数,还有一个experimental binding to ATLAS

      3. eigen 是一个用 C++ 编写的线性代数库,在 MPL2 许可证(从版本 3.1.1 开始)或 LGPL3/GPL2(旧版本)下分发。这是一种 C++ 编程方式,但比其他两种方式更集成(可用的算法和数据结构更多)。 Eigen claims to be faster 比上面的 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 等大型库可能很困难),您可以选择最适合您需求的库。

      【讨论】:

      • 信不信由你,我的答案是一个月前我自己搜索的结果。我相信收集帮助我做出选择的信息会很有趣。我不确定将多个信息分布在答案中是否更好。如果你更关心道德而不是效率,你仍然可以投票给每个人。
      • 遗憾的是,这些都没有提供像 numpy 数组那样通用和方便的东西。 Numpy 数组是任意维的,支持a[:4,::-1,:,19] = b[None,-5:,None]a[a>5]=0 等类似的东西,并且有大量可用的数组和索引操作函数。我真的希望有一天有人为 C++ 做出类似的东西。
      • OpenCV 也有一个 Matrix 类型,可以有任意维度大小;列/行范围(a.colRange(4,7).rowRange(4,8) for a[4:7,4,8])和条件掩码(a.setTo(cv::Scalar(0), a>5) for a[a>5]=0
      • @amaurea 在下面的 xtensor 上查看答案,它启用了上述所有功能。
      • 我在最近的一个项目中不得不使用 Eigen,我不得不说,虽然它看起来很高效,但语法绝对糟糕。没有可用的令人惊叹的 Python 切片语法。例如,如果您有一个一维向量 x 并且想要操作前 n 个元素,则必须使用 x.head(n)。甚至不要询问如何操作 x 的任意切片,您需要一个很好的旧 for 循环来做到这一点。这只是我能举出的众多笨拙和不方便的例子之一。
      【解决方案5】:

      Blitz++ 支持具有任意轴数的数组,而 Armadillo 最多只支持三个(向量、矩阵和立方体)。 Eigen 仅支持向量和矩阵(不支持立方体)。缺点是 Blitz++ 除了基本的入口运算和张量收缩之外没有线性代数函数。开发似乎在很长一段时间前已经放缓,但也许这只是因为库做了它该做的事情,不需要做太多的改变。

      【讨论】:

        【解决方案6】:

        VIGRA 包含一个很好的 N 维数组实现:

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

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

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

        【讨论】:

          【解决方案7】:

          虽然GLM 旨在轻松与 OpenGL 和 GLSL 相结合,但它是一个功能齐全的仅限头文件的 C++ 数学库,具有一组非常直观的接口。

          它声明了向量和矩阵类型以及对它们的各种操作。

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

          访问向量或矩阵中的值同样简单。例如,在声明一个 vec3 向量之后,可以使用 vector.x 访问它的第一个元素。看看吧。

          【讨论】:

            【解决方案8】:

            DyND 被设计成一个类似 NumPy 的 C++ 库。诸如广播、算术运算符和切片之类的东西都可以正常工作。另一方面,它仍然是非常实验性的,许多功能还没有实现。

            这是使用 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;
            }
            

            不久前,我写了一封 blog post,其中包含更多示例以及 Fortran 90、C++ 中的 DyND 和 Python 中的 NumPy 的语法的并排比较。

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

            【讨论】:

              【解决方案9】:

              试试xtensor。 (见NumPy to Xtensor Cheat Sheet)。

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

              xtensor 提供

              • 一个可扩展的表达系统,支持 numpy 风格的广播。
              • 一个遵循 C++ 标准库习惯用法的 API。
              • 用于操作数组表达式并基于 xtensor 构建的工具。

              示例

              初始化一个二维数组并计算其中一行与一维数组的总和。

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

              【讨论】:

              • @Llamageddon 你认为这应该是选择的答案吗?
              【解决方案10】:

              使用 LibTorch(C++ 的 PyTorch 前端)并开心。

              【讨论】:

              • 任何这样的例子:a[:4,::-1,:,19] = b[None,-5:,None]
              • @Cypher 答案:a.index({Slice(None, 4), Slice(None, None, -1), Slice(), 19}) = b.index({None, Slice(-5, None), None}) 文档:pytorch.org/cppdocs/notes/tensor_indexing.html
              • 谢谢。我希望有更好的语法方式来做到这一点。 C++ 中的运算符重载不允许实现类似 Numpy 数组的功能吗?
              【解决方案11】:

              如果您想使用多维数组(如 numpy)进行图像处理或神经网络,您可以使用 OpenCV cv::Mat 以及大量的图像处理算法。如果您只想将其仅用于矩阵运算,则只需编译相应的 opencv 模块以减小大小并拥有很小的 OpenCV 库。

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

              一个 Mat 包含以下信息: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
              

              奖金:

              编译 tiny and compact 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]
              

              【讨论】:

                【解决方案12】:

                这是一个老问题。还是想回答。想法可能对很多人有帮助,尤其是 pydevs 用 C++ 编码。

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

                readme 文档中的comparison 部分也非常非常酷。

                NumCpp

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

                【讨论】:

                  【解决方案13】:

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

                  它还没有提供将多个运算折叠在一起的花哨算术运算符,但是您可以将任意 lambdas 广播到一组具有相同形状的张量,或者使用惰性求值的算术运算符。

                  让我知道您对该界面的看法以及它与其他选项的比较,如果这有任何希望,您希望看到什么样的操作实现。

                  免费许可,无依赖!

                  附录:我设法正确编译和运行 xtensor,结果是我的库在迭代视图时明显更快(2 到 3X)

                  【讨论】:

                    猜你喜欢
                    • 1970-01-01
                    • 2013-04-05
                    • 2013-06-15
                    • 1970-01-01
                    • 1970-01-01
                    • 1970-01-01
                    • 2017-08-16
                    • 1970-01-01
                    • 1970-01-01
                    相关资源
                    最近更新 更多