Дополнительно
Какой самый быстрый способ транспонирования матрицы в C++?
У меня есть матрица (относительно большая), которую мне нужно транспонировать. Например, предположим, что моя матрица имеет вид
a b c d e f
g h i j k l
m n o p q r
Я хочу, чтобы результат был следующим:
a g m
b h n
c I o
d j p
e k q
f l r
Какой самый быстрый способ сделать это?
75
11
Это хороший вопрос. Есть много причин, по которым вы захотите действительно транспонировать матрицу в памяти, а не просто поменять координаты местами, например, при матричном умножении и гауссовом размазывании.
Сначала позвольте мне перечислить одну из функций, которые я использую для транспонирования (ПРИМЕЧАНИЕ: пожалуйста, смотрите конец моего ответа, где я нашел гораздо более быстрое решение)
Это зависит от вашего приложения, но в целом самым быстрым способом транспонирования матрицы будет инвертирование координат при поиске, тогда вам не придется перемещать данные.
Некоторые подробности о переносе 4х4 квадратных поплавок (я буду обсуждать 32-разрядное целое число позже) матриц с x86-оборудовании. Это's полезн для начала здесь для того, чтобы перенести больше площади матриц 8х8 или 16х16.
_MM_TRANSPOSE4_PS(Р0, Р1, Р2, Р3)
реализуется по-разному в разных компиляторах. На GCC и ICC (я не проверял лязг) unpcklps использовать, unpckhps, unpcklpd, unpckhpdтогда как для индекса MSVC использует только shufps
. Мы можем объединить эти два подхода вместе.Одно интересное наблюдение заключается в том, что два тасует может быть преобразован к одному перемешать и две бленды (SSE4.1) как это.
Это эффективное преобразование 4 тасует в 2 тасует и 4 смеси. При этом используется более 2 инструкций, чем реализация ССЗ, МУС, и MSVC. Преимущество в том, что он уменьшает давление, которое может иметь преимущества в некоторых случаях. В настоящее время все перемешивает и распаковывает можете пойти только на один конкретный порт, а смеси может перейти к любому из двух разных портов.
Я попытался с помощью 8 тасует, как MSVC и преобразования в 4 тасует + 8 блендов, но он не работал. Я все еще должен был использовать 4 распаковывает.
Я использовал этот же метод для 8х8 плавающий транспонировать (см. В конце ответа). https://stackoverflow.com/a/25627536/2542702. В том, что ответа я все равно пришлось использовать 8 распаковывает но я manged, чтобы преобразовать 8 тасует в 4 тасует и 8 блендов.
Для 32-разрядных целых чисел нет ничего похожего на
shufps (за исключением 128-битное тасует с AVX512), поэтому она может быть осуществлена только с распаковывает, которые я не'т думаю, что можно преобразовать в смеси (эффективно). Эффективно действует AVX512
vshufi32x4 " как " shufps, кроме 128-битное полосы из 4 чисел вместо 32-разрядных плавает, так этот же метод может быть возможно с vshufi32x4 в некоторых случаях. С рыцарями посадки тасует в четыре раза медленнее (пропускная способность), чем смеси.транспонирование без каких-либо накладных расходов (класс не полный):
можно использовать такой:
конечно, я этого'т возиться с управление памяти вот, что имеет решающее значение, но разные темы.
Рассмотрим каждую строку в качестве столбцов, а каждый столбец как строку .. используйте j,i вместо I и J
демо: http://ideone.com/lvsxKZ
Интел мкл указывает на место и место переноса/копирования матриц. вот ссылка на документацию. Я бы рекомендовал пробовать из места внедрения как быстрее десяти на месте и в документации последняя версия мкл содержит некоторые ошибки.
Если размер массива известен до того, как мы могли бы использовать союз с нашей помощью. Как это-
``
включать <бит/stdc++.ч>
с помощью пространства имен std;
Союз уа{ инт модуль arr[2][3]; инт брр[3][2]; };
тап_п() { Союз уа БПЛА; инт Карр[2][3] = {{1,2,3},{4,5,6}}; функции memcpy(БПЛА.Арр Карр как sizeof(Карр)); для (int я=0;я&Л;3;я++) { для (Int J=0 и;ж<2;к++) соиь<<БПЛА.брр[я][Дж]<<" по себе "; соиь<<'\П'; }
возврат 0; } ``
Современные библиотеки линейной алгебры включают в себя оптимизированные версии из самых распространенных операций. Многие из них включают динамическая диспетчеризация процессора, который выбирает лучшее внедрение оборудования во время выполнения программы (без ущерба для портативности).
Обычно это лучшая альтернатива ручной оптимизации вашего functinos через вектор расширения встроенных функций. Последний будет связывать реализацию конкретного производителя оборудования и модели: если вы решите поменять поставщика (например, руку) или до новой векторных расширений (например, AVX512), вам придется повторно реализовать его снова, чтобы получить большинство из них.
МКЛ транспозиции, например, включает в себя imatcopy функция расширения Блас
. Вы можете найти его в других реализациях, таких как OpenBLAS, а также:
включать <мкл.ч>
пустота транспонировать( поплавок* а, инт Н, инт м ) { константный тип char row_major = 'Р'; константный тип char транспонирует = 'Т'; константный поплавок Альфа = 1.0 Ф; mkl_simatcopy (row_major, транспонировать, Н, М, АЛЬФА, а, н, н); } ``
Для проекта c++, вы можете воспользоваться броненосца на C++: ``
включать <броненосца>
пустота транспонировать( АРМА::мат &матрица ) { АРМА::inplace_trans(матрицы); } ``
Я думаю, что самый быстрый способ не следует принимать выше, чем О(П^2) аналогичным способом можно использовать только O(1) по пространству : лучший способ сделать это, чтобы поменять в паре, потому что, когда вы транспонировать матрицу, то что вы делаете это: м[я][Дж]=м[Дж][я] , так что магазин, М[я][Дж] в темп, то m[я][Дж]=м[Дж][я],и последний шаг : м[Дж][я]=темп. это может быть сделано за один проход, так что его следует принимать за О(N^2)
мой ответ является транспонированной матрицы 3х3