поэлементные операции с матрицей Boost C ++ Ublas и векторные типы - PullRequest
7 голосов
/ 21 апреля 2009

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

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

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

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

любая помощь очень ценится.

Ответы [ 2 ]

9 голосов
/ 15 октября 2010

Использование begin1() / end1() не будет работать, поскольку оно обеспечивает доступ к элементу в позиции столбца по умолчанию (0): следовательно, вы просто получаете доступ ко всем элементам в первом столбце. Лучше (в том смысле, что вы получаете ожидаемое поведение) получить последовательный доступ через:

std::transform(mat.data().begin(), mat.data().end(),
               mat.data().begin(), boost::math::tgamma) ;

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

Наслаждайтесь!

3 голосов
/ 16 мая 2009

ПРЕДУПРЕЖДЕНИЕ

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


Я не особо знаком с библиотеками boost, поэтому может быть более стандартный способ сделать это, но я думаю, что вы можете делать то, что хотите, с помощью итераторов и шаблона функции STL transform . В введении к документации библиотеки uBLAS говорится, что его классы разработаны так, чтобы быть совместимыми с тем же поведением итератора, которое используется в STL. Матрица усиления и векторные шаблоны имеют итераторы , которые можно использовать для доступа к отдельным элементам. Вектор имеет begin() и end(), а матрица имеет begin1(), end1(), begin2() и end2(). Разновидности 1 являются итераторами по столбцам, а разновидности 2 - итераторами по строкам. См. Дополнительную документацию по VectorExpression и MatrixExpression для получения дополнительной информации.

Используя алгоритм STL transform, вы можете применить функцию к каждому элементу итерируемой последовательности и назначить результат другой итерируемой последовательности той же длины или той же последовательности. Таким образом, чтобы использовать это для вектора усиления UBLAS, вы можете сделать это:

using namespace boost::numeric::ublas;

// Create a 30 element vector of doubles
vector<double> vec(30);

// Assign 8.0 to each element.
std::fill(vec.begin(), vec.end(), 8.0);

// Perform the "Gamma" function on each element and assign the result back
// to the original element in the vector.
std::transform(vec.begin(), vec.end(), vec.begin(), boost::math::tgamma);

Для матрицы это было бы одно и то же: вы должны использовать итераторы семейства 1 или 2. Какой из них вы выберете, зависит от того, будет ли структура вашей матрицы основной или основной. Беглый просмотр документации uBLAS заставляет меня поверить, что это может быть любой из них, поэтому вам нужно изучить код и определить, какой из них используется, чтобы выбрать наиболее эффективный порядок итераций.

matrix<double> mat(30, 30);
.
.
.

std::transform(mat.begin1(), mat.end1(), mat.begin1(), boost::math::tgamma);

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

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


EDIT

Похоже, мне следовало проверить свою рекомендацию, прежде чем ее делать. Как указывалось другими, итераторы '1' и '2' выполняют итерацию только по одной строке / столбцу матрицы. Обзорная документация в Boost серьезно вводит в заблуждение по этому поводу. Он утверждает, что begin1() «Возвращает iterator1, указывающий на начало матрицы», а end1() «Возвращает iterator1, указывающий на конец матрицы». Разве это убило бы их, чтобы сказать «столбец матрицы» вместо «матрицы»? Я предположил, что iterator1 был итератором по столбцам, который будет перебирать всю матрицу. Чтобы узнать, как это сделать, см. ответ Lantern Rouge .

...