LINUX.ORG.RU

Нужен класс для многомерных массивов (как numpy.ndarray, только на C++)

 ,


0

3

Нужен мне нужен класс многомерного численного массива (типы данных предполагаются float64 и complex128).

Нужно, чтобы он поддерживал следующие вещи:

- любое количество измерений (то бишь, Eigen, с его 2D-матрицами — не вариант);

- изменение размера и размерности;

- поэлементные операции (арифметика, тригонометрия и т.д.);

- возможность получить указатель на массив в памяти (для того, чтобы можно было конвертировать это в numpy.ndarray).

Не сможет ли прогрессивная общественность мне что-нибудь посоветовать?



Последнее исправление: Yak (всего исправлений: 3)

как раз начал изучать C++, а чем просто вектор не подходит?

typedef std::vector< std::vector<double> > matrix;
matrix name(sizeX, std::vector<double>(sizeY));
stevejobs ★★★★☆
()
Ответ на: комментарий от four_str_sam

Удивительно, но этот вариант не подошел ни под одно требование топикастра.

но ведь работает

потом кто-то с другими требованиями нагуглит это решение и ву-а-ля, круче чем стаковерфлоу

anonymous
()
Ответ на: комментарий от four_str_sam

размерность можно регулировать векторами векторов векторов, размер изменяется через std::vector::resize, указатель получается через std::vector::data

я же не утверждаю что это ответ (от человека, который видит C++ совсем недавно), интересно что в этом солюшене не так

stevejobs ★★★★☆
()
Последнее исправление: stevejobs (всего исправлений: 1)

Blitz++ ? Поддерживает операции с матрицами, векторами, тензорами. Размерность массивов ограничена 11 измерениями. Есть поддержка срезов, при желании можно включить проверку выхода за границы.

А так ещё есть Eigen и Armadillo

grem ★★★★★
()
Последнее исправление: grem (всего исправлений: 4)
Ответ на: комментарий от stevejobs

А как это будет выглядеть в случае 10-мерного массива?

grem ★★★★★
()
Ответ на: комментарий от stevejobs

Всё в нем не так, от удобства до производительности. Поэлементные операции реализовывать надо руками, reshape за константное время невозможен и т.д.

anonymous_coward
()

std::vector<float64> и std::vector< complex128> + немного адресной арифметики и копирований, при изменении размерности/размера.

andreyu ★★★★★
()
Ответ на: комментарий от andreyu

плюс немного

поэлементные операции (арифметика, тригонометрия и т.д.);

и получится собственная библиотека. Почему тогда не взять готовую?

grem ★★★★★
()

Ещё есть Boost.MultiArray, но непосредственно в нём не определены поэлементные операции, возможно, для этого у них есть другая библиотека

grem ★★★★★
()

насколько я помню, под твои требования мало того, что в STL ничего нет, так и в Boost такого нет. Boost.MultiArray посмотри (но не совсем).

Вектор векторов - можно, но в памяти то аллоцировано оно не вместе.

zamazan4ik ★★
()
Ответ на: комментарий от grem

поэлементные операции (арифметика, тригонометрия и т.д.);

и получится собственная библиотека. Почему тогда не взять готовую?

Тут будет в тему std::valarray

// Кстати, оттуда же: https://en.wikipedia.org/wiki/Expression_templates

KennyMinigun ★★★★★
()

std::...
Да любой. Я предпочитаю... Да неважно.
Ты же в курсе, что контейнеры можно вкладывать друг в друга?
Когда мне нужен прямоугольный массив, то я использую std::map.
Нынче есть std::vector (особенно офигенен, когда ты сишник)
В чём конкретно вопрос?

MimisGotAPlan
()
Ответ на: комментарий от KennyMinigun

std::valarray

Про него я забыл, но он одномерный всё равно.

Для blitz++ есть биндинги к питону: bob.blitz, как раз для использования совместно с numpy.ndarray

grem ★★★★★
()
Последнее исправление: grem (всего исправлений: 1)

Обернуть std::vector в класс. Многомерность - вопрос индексации.

T get at(size_t height, size_t row, size_t col) {
  return v[height * R * C + row * C + col];
}

invy ★★★★★
()
Ответ на: комментарий от grem

и получится собственная библиотека. Почему тогда не взять готовую?

Нужно найти ту грань, когда выгоднее брать готовую стороннюю библиотеку, а когда выгоднее смастерить свой велосипед.

andreyu ★★★★★
()
Ответ на: комментарий от grem

Про него я забыл, но он одномерный всё равно.

Из него делается многомерный так же легко, как и из std::vector. При этом выполняется условие ТСа «возможность получить указатель на массив в памяти».

andreyu ★★★★★
()
Ответ на: комментарий от MimisGotAPlan

Координаты это не всегда последовательные числа. Часто удобно всякое странное использовать для этой цели.

Про доступ к элементу в std::map вы в курсе?

andreyu ★★★★★
()
Ответ на: комментарий от MimisGotAPlan

Простите за нескромный вопрос: а вам что, еще и платят за то, что вы на C++ в подобном стиле программируете?

eao197 ★★★★★
()
Ответ на: комментарий от andreyu

Конечно нет. Я не осуществляю доступ к элементам в массиве. Зачем?

MimisGotAPlan
()
Ответ на: комментарий от andreyu

В данном случае никакого смысла мастерить свой нет, учитывая запросы ТС. Иначе и про готовые библиотеки он бы не спрашивал.

grem ★★★★★
()
Ответ на: комментарий от andreyu

Из него делается многомерный так же легко, как и из std::vector

Под «легко» все почему-то приводят для примера двумерный, очень редко трёхмерный. А вот дальше всё выглядит не очень, особенно для «произвольного» N.

Требование ТС относительно применения функций поэлементно опять же самому городить придётся. Оно ему надо сношаться на ровном месте, там где можно взять готовое решение? Ладно если б была цель свою библиотеку написать, но её, похоже, нет.

grem ★★★★★
()
Ответ на: комментарий от grem

Под «легко» все почему-то приводят для примера двумерный, очень редко трёхмерный. А вот дальше всё выглядит не очень, особенно для «произвольного» N.

Почему не очень? Что для двумерного, что для трехмерного, что для n-мерного - принцип один и тот же.

Требование ТС относительно применения функций поэлементно опять же самому городить придётся.

Это и есть доступ к элементу.

Оно ему надо сношаться на ровном месте, там где можно взять готовое решение?

Доступ к произвольному элементу прост и быстр - это сложения и умножения.

andreyu ★★★★★
()

нужен класс многомерного численного массива

Интересно, для чего? Я может отстал от жизни, но вроде бы для физ-мат моделирования в любых размерностях достаточно обычных матриц.

сможет ли прогрессивная общественность мне что-нибудь посоветовать?

Запилить собственный велосипед.

no-such-file ★★★★★
()
Ответ на: комментарий от grem

Под «легко» все почему-то приводят для примера двумерный, очень редко трёхмерный. А вот дальше всё выглядит не очень, особенно для «произвольного» N.

Всё очень просто. Нужен одномерный вектор и функция которая отображает кортеж координат на этот линейный массив. Задача для первого курса ПТУ.

no-such-file ★★★★★
()
Ответ на: комментарий от andreyu

Это всё никак не объясняет почему не взять готовое решение, чтобы сразу писать, например, C = sin(A) + B, использовать срезы, в том числе по условию, и не тратить время на то, что уже давно написано, отлажено и доступно.

Чего уж там, давайте и на STD библиотеки забьём, ведь свой же велосипед можно прикрутить.

grem ★★★★★
()
Последнее исправление: grem (всего исправлений: 1)
Ответ на: комментарий от grem

Это всё никак не объясняет почему не взять готовое решение, чтобы сразу писать, например, C = sin(A) + B, использовать срезы, в том числе по условию, и не тратить время на то, что уже давно написано, отлажено и доступно.

Я что запрещаю использовать стороннюю библиотеку?

Чего уж там, давайте и на STD библиотеки забьём, ведь свой же велосипед можно прикрутить.

«Заставь дурака богу молиться, он лоб расшибет» (с) народная пословица.

andreyu ★★★★★
()
Ответ на: комментарий от andreyu

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

grem ★★★★★
()

- любое количество измерений

- изменение размера и размерности;

- возможность получить указатель на массив в памяти

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

Поясню. Допустим, есть массив из 99 элементов с возможностью обращения к нему как [99], [33][3], [3][33], [3][3][11] и т. д. Такое реализовать несложно. Есть ещё одно ограничение: обращение к массиву как к указателю, из чего следует, что все элементы должны располагаться последовательно, как в простом одномерном массиве. Теперь, учитывая эти 2 требования, попробуем реализовать 3-е: изменение размера и размерности. К примеру, изменим размерность [33][3] на [33][2]. Нам придётся урезать на 1 элемент каждую из 33 строк, а затем сдвинуть 32 строки влево. Эта операция будет очень затратной.

aureliano15 ★★
()
Ответ на: комментарий от grem

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

Может потому, что прежде чем приступить к непосредственному решению задачи, придется:

1) найти список библиотек.
2) выбрать наиболее подходящую.
3) разобраться, как с ней работать.
4) разобраться с подводными камнями, которые там могу быть.

andreyu ★★★★★
()
Ответ на: комментарий от aureliano15

Эта операция будет очень затратной.

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

andreyu ★★★★★
()
Ответ на: комментарий от andreyu

Эта операция будет очень затратной.

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

А в vector память выделяется с запасом, а если её не хватает, и она перераспределяется (заново выделяется, копируется и старая удаляется), то новое выделение происходит тоже с запасом. Поэтому вектора при динамическом изменении длины довольно эффективны. В случае же подобного массива об эффективности при изменении размеров строк говорить не приходится, как ни крути. При реализации через вектор векторов можно относительно эффективно менять длины строк, но этот вариант не соответствует критерию возможности получения указателя на непрерывный массив. Поэтому я и сказал, что требования к классу завышены, и подобный класс не будет работать эффективно. Я не знаю, для какой задачи он нужен, но на 99% уверен, что можно реализовать проще, с меньшим количеством требований. Только сам алгоритм основной программы надо тщательнее продумать.

aureliano15 ★★
()
Ответ на: комментарий от grem

В армадилле только 2D и 3D, причём 3D внутри сделано через массив 2D, так что оно совсем не подходит. (Я правда лично не сталкивался чтобы нужно было больше 3D, но тем не менее.)

d_a ★★★★★
()

А что если взять liboctave? Там сколько хочешь можно навернуть размерностей, по крайней мере в самой октаве. Disclaimer: GPLv3.

d_a ★★★★★
()

В книжке c++ programming language 4th edition была реализация в одной из глав.

anonymous
()
Ответ на: комментарий от andreyu

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

grem ★★★★★
()
Ответ на: комментарий от aureliano15

Поэтому вектора при динамическом изменении длины довольно эффективны.

Поэтому facebook придумал свой алгоритм расчета количества выделяемой памяти.

При реализации через вектор векторов можно относительно эффективно менять длины строк,

Только каждая строка будет иметь свой capacity, отличная экономия.

но этот вариант не соответствует критерию возможности получения указателя на непрерывный массив.

Складывается ощущение, что вы решили законспектировать свои рассуждения.

andreyu ★★★★★
()
Ответ на: комментарий от grem

Вот-вот, а всё это, в общем случае, если не нужно что-то специально заточенное под конкретную задачу, будет быстрее, чем написание (включая отладку) своей работоспособной библиотеки.

Быстрее будет то, что заточено под конкретную задачу, а не библиотека общего назначения.

С готовыми библиотеками желательно тоже тесты прогнать, чтобы убедиться, что правильно понимаешь как ими пользоваться.

Прежде, чем проводить тесты, нужно понимать как пользоваться.

andreyu ★★★★★
()

простые структуры данных ==> сложные алгоритмы
сложные структуры данных ==> простые алгоритмы
Вам нужен второй вариант, но в таком ЯП, как C++, довольно просто погореть на сложности структур данных, поэтому я бы поостерегся от велосипедостроения :-).

Virtuos86 ★★★★★
()
Ответ на: комментарий от andreyu

Поэтому вектора при динамическом изменении длины довольно эффективны.

Поэтому facebook придумал свой алгоритм расчета количества выделяемой памяти.

Ну и что? Есть какой-то стандартный аллокатор на все случаи жизни, в целом эффективный, но, естественно, как и всё чересчур универсальное, не самый оптимальный для любых задач. И есть возможность создать свой собственный аллокатор, более эффективный для какой-то конкретной задачи. Например, если я заранее знаю, что размер вектора будет задаваться единожды и больше не будет увеличиваться, то для такого вектора действительно эффективнее не резервировать дополнительную память. Однако это частный случай, который никак не удовлетворяет требованиям тс'а «изменение размера и размерности».

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

При реализации через вектор векторов можно относительно эффективно менять длины строк,

Только каждая строка будет иметь свой capacity, отличная экономия.

Ну, это смотря что считать экономией. Если программа выполняется на железке с минимумом памяти, то тут, конечно, первым делом надо экономить её. Однако такие задачи редко реализуют на плюсах, особенно с использованием stl и других шаблонных библиотек. В большинстве же случаев перерасход памяти в 1.5 - 2 раза вполне допустим.

Если же выделять память впритык, а потом каждый раз перераспределять, то это не только существенно снизит производительность, но может ещё и сильно фрагментировать кучу.

но этот вариант не соответствует критерию возможности получения указателя на непрерывный массив.

Складывается ощущение, что вы решили законспектировать свои рассуждения.

Я просто ответил на вопрос. А какое у кого складывается ощущение, уже не моя проблема.

aureliano15 ★★
()
Ответ на: комментарий от aureliano15

Однако это частный случай, который никак не удовлетворяет требованиям тс'а «изменение размера и размерности».

Что вы пытаетесь подтвердить или опровергнуть?

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

Это подтверждает только то, что им не нравится алгоритм расчета нужного количества памяти в stl.

В большинстве же случаев перерасход памяти в 1.5 - 2 раза вполне допустим.

Согласно статистическим расчетам, 86% данных берутся с потолка. С какого потолка эти данные взяли вы? Почему вы решили, что на потолке ТСа будут такие же данные?

Если же выделять память впритык, а потом каждый раз перераспределять, то это не только существенно снизит производительность, но может ещё и сильно фрагментировать кучу.

Если я правильно понял, то ТС поделился характером задачи только с вами? И поэтому вы знаете как часто ему придется менять размерность матрицы, а так же вам уже известна эта размерность.

Я просто ответил на вопрос. А какое у кого складывается ощущение, уже не моя проблема.

А я задавал вам вопрос?

andreyu ★★★★★
()
Ответ на: комментарий от andreyu

Что вы пытаетесь подтвердить или опровергнуть?

Ничего. Я просто изложил свои мысли.

Это подтверждает только то, что им не нравится алгоритм расчета нужного количества памяти в stl.

И что с того? Я разве когда-то говорил, что стандартный аллокатор 100% годится на все случаи жизни? Речь шла об общем подходе, а не о конкретных алгоритмах. И создатели stl понимали это с самого начала, предоставив возможность создавать собственные аллокаторы.

В большинстве же случаев перерасход памяти в 1.5 - 2 раза вполне допустим.

Согласно статистическим расчетам, 86% данных берутся с потолка. С какого потолка эти данные взяли вы? Почему вы решили, что на потолке ТСа будут такие же данные?

Я ничего не решал. Если тс посчитает, что память расходуется слишком расточительно, ничто не мешает ему написать собственный аллокатор. Я только сказал, что выделять память впритык, если известно, что в будущем её придётся увеличивать, в большинстве случаев далеко не самый оптимальный вариант с точки зрения быстродействия. Если не верите, проведите собственный эксперимент: попробуйте выделить память под строки данных впритык и потом несколько раз перераспределить её в сторону увеличения. А потом сделайте то же самое, используя std::string или std::vector со стандартным аллокатором. И замерьте время выполнения этого участка кода.

Если я правильно понял, то ТС поделился характером задачи только с вами? И поэтому вы знаете как часто ему придется менять размерность матрицы, а так же вам уже известна эта размерность.

Мне известно только то, что тс сообщил в верхнем сообщении. А сообщил он среди прочего, что ему нужны «изменение размера и размерности».

А кроме того, мне известно, что в большинстве случаев размерность больше 2 избыточна, а больше 3 избыточна в 99% случаев. Поэтому я посоветовал подумать над алгоритмом основной задачи, не исключая при этом, что для конкретно этой задачи действительно может понадобиться большое число размерностей, если она относится к оставшемуся 1% случаев. Следовать же моему совету или нет, тс, думаю, сможет решить сам.

Я просто ответил на вопрос. А какое у кого складывается ощущение, уже не моя проблема.

А я задавал вам вопрос?

Я ответил на вопрос тс'а, после чего вы ответили мне репликой

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

на которую я вам ответил. Что тут непонятного? Или я должен был вас проигнорировать? Тогда зачем вы мне писали?

aureliano15 ★★
()
Вы не можете добавлять комментарии в эту тему. Тема перемещена в архив.