Массивы стиля NumPy для с ++? [закрыто]


85

Существуют ли какие-либо библиотеки C ++ (или C) с массивами, подобными NumPy, с поддержкой нарезки, векторизованных операций, добавления и вычитания содержимого по элементам и т. Д.?



1
Насколько я знаю, numpy использует LAPACK . Хотя это написано на Fortran, доступны привязки C ++. Однако никогда не использовал ни то, ни другое.
Voo

Недавно появился интерфейс C ++ для NumPy, который называется ArmaNpy .
mtall

1
Я пока не вижу Boost.MultiArray в комментариях
Дмитрий Леденцов

Вы можете попробовать внедрить Python и фактически использовать numpy, что даст то преимущество, что вам не потребуется изучать новую библиотеку, хотя это будет медленнее, чем использование библиотеки C / C ++.
Кевин,

Ответы:


62

Вот несколько бесплатных программ, которые могут удовлетворить ваши потребности.

  1. GNU Scientific Library является GPL программное обеспечение , написанное на языке C. Таким образом, он имеет С-подобного распределения и способ программирования (указатели и т.д.). С GSLwrap вы можете программировать на C ++, продолжая использовать GSL. GSL имеет реализацию BLAS , но вы можете использовать ATLAS вместо CBLAS по умолчанию, если хотите еще больше производительности.

  2. Библиотека boost / uBLAS - это библиотека BSL, написанная на C ++ и распространяемая как пакет boost. Это C ++ - способ реализации стандарта BLAS. uBLAS поставляется с несколькими функциями линейной алгебры, и есть экспериментальная привязка к ATLAS .

  3. eigen - это библиотека линейной алгебры, написанная на C ++, распространяется по лицензии MPL2 (начиная с версии 3.1.1) или LGPL3 / GPL2 (более старые версии). Это способ программирования на C ++, но более интегрированный, чем два других (доступно больше алгоритмов и структур данных). Eigen утверждает, что работает быстрее, чем реализации BLAS, описанные выше, но при этом не соответствует стандарту де-факто BLAS API. Эйген, похоже, не прилагает много усилий для параллельной реализации.

  4. Armadillo - это библиотека LGPL3 для C ++. Он имеет привязку к LAPACK (библиотека, используемая numpy). Он использует рекурсивные шаблоны и метапрограммирование шаблонов, что является хорошим моментом (я не знаю, делают ли это и другие библиотеки?).

  5. xtensor - это библиотека C ++, имеющая лицензию BSD. Он предлагает API C ++, очень похожий на API NumPy. См. Https://xtensor.readthedocs.io/en/latest/numpy.html для шпаргалки.

Эти альтернативы действительно хороши, если вы просто хотите получить структуры данных и базовую линейную алгебру. В зависимости от вашего вкуса в отношении стиля, лицензии или проблем системного администратора (установка больших библиотек, таких как LAPACK, может быть сложной), вы можете выбрать ту, которая лучше всего соответствует вашим потребностям.


17
Хотите верьте, хотите нет, но мой ответ - результат моих собственных поисков несколько месяцев назад. Я полагал, что сбор информации, которая помогла мне сделать мой выбор, будет интересно. Я не уверен, что лучше иметь несколько сведений, разбросанных по ответам. Вы все равно можете проголосовать за всех, если вас больше беспокоит этика, чем эффективность.
nojhan

19
К сожалению, ни один из них не предоставляет ничего более общего и удобного, чем массивы numpy. Numpy массивы произвольные одномерные и поддерживать такие вещи , как , a[:4,::-1,:,19] = b[None,-5:,None]или a[a>5]=0и подобные, а также имеющие огромный набор массивов и манипуляции индекса доступных функций. Я очень надеюсь, что кто-нибудь когда-нибудь сделает что-то подобное для C ++.
amaurea 01

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 ниже, который позволяет все вышеперечисленное.
Quant

1
Мне приходилось использовать Eigen в недавнем проекте, и я должен сказать, что, хотя он кажется эффективным, синтаксис абсолютно ужасен. Нет никакого доступного из этого удивительного синтаксиса нарезки Python. Например, если у вас есть одномерный вектор x и вы хотите манипулировать первыми n элементами, вы должны использовать x.head (n). Даже не спрашивайте о манипуляциях с произвольным срезом x, для этого вам понадобится старый добрый цикл for. Это лишь один из многих неуклюжих и неудобных примеров, которые я мог бы назвать.
Alex

54

Попробуйте xtensor . (См. Шпаргалку от NumPy к Xtensor ).

xtensor - это библиотека C ++, предназначенная для численного анализа с многомерными выражениями массивов.

xtensor обеспечивает

  • расширяемая система выражений, обеспечивающая трансляцию в стиле numpy.
  • API, следующий идиомам стандартной библиотеки C ++.
  • инструменты для управления выражениями массивов и построения на основе 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}}

2
@Llamageddon, ты думаешь, это должен быть выбранный ответ?
Quant

7

DyND разработан как NumPy-подобная библиотека для C ++. Такие вещи, как трансляция, арифметические операторы и нарезка, работают нормально. С другой стороны, это все еще очень экспериментальная и многие функции еще не были реализованы.

Вот простая реализация алгоритма де Кастельжау на C ++ с использованием массивов 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;
}

Некоторое время назад я написал сообщение в блоге с большим количеством примеров и параллельным сравнением синтаксиса для Fortran 90, DyND в C ++ и NumPy в Python.

Отказ от ответственности: я один из текущих разработчиков DyND.


3

Eigen - хорошая библиотека линейной алгебры.

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

Его довольно легко установить, поскольку это библиотека только для заголовков. Он полагается на шаблон для создания хорошо оптимизированного кода. Он автоматически векторизует матричные операции.

Он также полностью поддерживает операции с коэффициентами, такие как, например, «умножение на элемент» между двумя матрицами. Это то, что вам нужно?


3
Однако синтаксис Eigen довольно ужасен. Нет такого плавного синтаксиса нарезки, который вы найдете в Numpy. И это не общая библиотека n-мерных массивов, она больше предназначена только для одномерных векторов и двухмерных матриц. Тот факт, что у них есть VectorXd для одномерных массивов и MatrixXd для 2D-массивов, меня уже отталкивает.
Alex

2

Blitz ++ поддерживает массивы с произвольным количеством осей, тогда как Armadillo поддерживает до трех (векторы, матрицы и кубы). Eigen поддерживает только векторы и матрицы (не кубы). Обратной стороной является то, что 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]]

В нем пока нет причудливых арифметических операторов, объединяющих несколько операций вместе, но вы можете транслировать произвольные лямбды на набор тензоров той же формы или использовать арифметические операторы с отложенным вычислением.

Дайте мне знать, что вы думаете об интерфейсе и как он соотносится с другими вариантами, и если есть надежда, какие операции вы хотели бы реализовать.

Бесплатная лицензия и никакой зависимости!

Дополнение: мне удалось правильно скомпилировать и запустить xtensor, и в результате моя библиотека стала значительно быстрее при повторении представлений (от 2 до 3X).


1

VIGRA содержит хорошую реализацию N-мерного массива:

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

Я широко им пользуюсь и считаю его очень простым и эффективным. Это также только заголовок, поэтому его очень легко интегрировать в среду разработки. Это самое близкое к использованию NumPy с точки зрения API.

Основным недостатком является то, что он не так широко используется, как другие, поэтому вы не найдете большой помощи в Интернете. Это, и у него неуклюжее название (попробуйте поискать!)



1

Это старый вопрос. Все еще хотелось ответить. Мысль может помочь многим, особенно кодированию pydevs на C ++.

Если вы уже работали с python numpy, то NumCpp - отличный выбор. Он минималистичен по синтаксису и имеет те же функции и методы, что и py numpy.

Часть сравнения в readme doc тоже очень-очень классная.

NumCpp

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

0

Eigen - это библиотека шаблонов для линейной алгебры (матрицы, векторы…). Это только заголовок и бесплатное использование (LGPL).


0

Если вы хотите использовать многомерный массив (например, numpy) для обработки изображений или нейронной сети, вы можете использовать OpenCV cv::Matвместе с множеством алгоритмов обработки изображений. Если вы просто хотите использовать его ТОЛЬКО для матричных операций, вам просто нужно скомпилировать соответствующие модули opencv, чтобы уменьшить размер и иметь крошечную библиотеку OpenCV.

cv::Mat(Матрица) - это 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 только для матричных операций. Один из способов похож на упомянутый в этой статье.

ИЛИ ЖЕ

скомпилируйте исходный код opencv, используя следующую команду 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

Попробуйте этот пример:

 #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

GSL велик, он делает все , что вы просите , и многое другое. Однако он распространяется под лицензией GPL.


-1

Хотя GLM разработан для простого взаимодействия с OpenGL и GLSL, это полнофункциональная математическая библиотека только для заголовков для C ++ с очень интуитивно понятным набором интерфейсов.

Он объявляет векторные и матричные типы, а также различные операции с ними.

Умножение двух матриц выполняется просто как (M1 * M2). Вычитание двух векторов (V1-V2).

Доступ к значениям, содержащимся в векторах или матрицах, также прост. Например, после объявления вектора vec3 можно получить доступ к его первому элементу с помощью vector.x. Проверить это.

Используя наш сайт, вы подтверждаете, что прочитали и поняли нашу Политику в отношении файлов cookie и Политику конфиденциальности.
Licensed under cc by-sa 3.0 with attribution required.