I have a matrix (비교적 큰) 가 데릭쉐퍼드와 바꾸기 위해. 예를 들어 행렬 () 는 내 solaris.
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
이렇게 가장 빠른 길은 무엇인가?
이것은 좋은 질문입니다. 이유는 여러 가지가 있습니다 행렬의 전치행렬 그녀의심장을 실제로 메모리에 있는 게 아니라, 예를 들어 행렬 곱셈 및 가우스 스왑이란 위치좌표 유명하다.
Let me 리스트 기능 중 하나는 내가 먼저 사용할 바꾸기 ( 편집: 제발 내 답을 찾았다고 훨씬 더 빨리 끝을 볼 수 있는 솔루션 )
void transpose(float *src, float *dst, const int N, const int M) {
#pragma omp parallel for
for(int n = 0; n<N*M; n++) {
int i = n/N;
int j = n%N;
dst[n] = src[M*j + i];
}
}
왜 지금 let& # 39 의 지켜보리니 바꾸기 할 수 있다. 행렬 곱셈 고려해보십시오 C = *. 그것은 우리가 할 수 없다.
for(int i=0; i<N; i++) {
for(int j=0; j<K; j++) {
float tmp = 0;
for(int l=0; l<M; l++) {
tmp += A[M*i+l]*B[K*l+j];
}
C[K*i + j] = tmp;
}
}
그러나 이쪽요 캐시 실패를 많이 할 것 같습니다. B 의 첫 번째 훨씬 빠른 해결책은 시행하십시오 전치행렬
transpose(B);
for(int i=0; i<N; i++) {
for(int j=0; j<K; j++) {
float tmp = 0;
for(int l=0; l<M; l++) {
tmp += A[M*i+l]*B[K*j+l];
}
C[K*i + j] = tmp;
}
}
transpose(B);
행렬 곱셈 () 는 O (n ^ 2) 는 O (n ^ 3) 과 바꾸기 때문에 바꾸기 등의 계산을 해야 할 시간이 거의 영향을 미치지 (큰 'n'). 행렬 곱셈 루프 (loop) 에 비해 훨씬 더 효과적인 바둑판식 배열을 취하고 있지만, s # 39 바꾸기 that& 훨씬 더 복잡하다.
I wish I knew 더 빨리 할 수 있는 바꾸기 ( 편집: I found the end of my answer 빠른 솔루션, 참조). Haswell/avx2 나왔을 때 몇 주 만에 한 확하려 기능을 갖게 됩니다. 내가 don& 도움이 될 수 있는 다운로드되었는지 t # 39, 이 경우, 하지만 난 열 및 이미지 모으는 먹어서나 아웃하려면 행일. 어쩌면 발쿰치로 바꾸기 필요 없습니다.
What you do 는 가로로 그리곤요 얼룩입니다 세로일 얼룩입니다 대한 가우스 유명하다. 그러나 당신이 할 일은 캐시에는 세로일 얼룩 문제가 있다.
Smear image horizontally
transpose output
Smear output horizontally
transpose output
인텔이 설명하는 논문을 슬라이드에서는 http://software.intel.com/en-us/articles/iir-gaussian-blur-filter-implementation-using-intel-advanced-vector-extensions
마지막으로, 내가 해야 할 일이 실제로 행렬 곱셈 (또한 가우스 유명하다) 에 너비가 취할 수밖에 없는 시행하십시오 정확히요 바꾸기 바꾸기 특정 벡터입니다 크기 (예를 들어, 4 개 또는 8 개의 SSE 의 / AVX). 다음은 내가 사용하는 함수
void reorder_matrix(const float* A, float* B, const int N, const int M, const int vec_size) {
#pragma omp parallel for
for(int n=0; n<M*N; n++) {
int k = vec_size*(n/N/vec_size);
int i = (n/vec_size)%N;
int j = n%vec_size;
B[n] = A[M*i + k + j];
}
}
찾기 위해 여러 가지 기능을 가장 빠른 전치행렬 대규모 호환표 찾았다. 결국 사용할 수 있는 가장 빠른 결과를 얻을 수 있습니다,, = 16< /code> block_size code> < 루프 차단 ( 편집: I found a 차단 솔루션 및 반복 사용하는 SSE 빠른 - 아래 참조). 이 코드는 작동됨 너스마 호환표에 경우 (즉, 호환표에 필요가 없으며 광장 ().
inline void transpose_scalar_block(float *A, float *B, const int lda, const int ldb, const int block_size) {
#pragma omp parallel for
for(int i=0; i<block_size; i++) {
for(int j=0; j<block_size; j++) {
B[j*ldb + i] = A[i*lda +j];
}
}
}
inline void transpose_block(float *A, float *B, const int n, const int m, const int lda, const int ldb, const int block_size) {
#pragma omp parallel for
for(int i=0; i<n; i+=block_size) {
for(int j=0; j<m; j+=block_size) {
transpose_scalar_block(&A[i*lda +j], &B[j*ldb + i], lda, ldb, block_size);
}
}
}
값은 code> lda< /code> <;;; 및 < code> ldb< /code>;;; 오른길로 너비입니다 호환표에. 이러한 할 여러 개의 블록 크기. Com/go/downloads_kr 값과 3000x1001 호환표에 나는한다 이 같은 일이 할당할지 메모리 (예:
#define ROUND_UP(x, s) (((x)+((s)-1)) & -(s))
const int n = 3000;
const int m = 1001;
int lda = ROUND_UP(m, 16);
int ldb = ROUND_UP(n, 16);
float *A = (float*)_mm_malloc(sizeof(float)*lda*ldb, 64);
float *B = (float*)_mm_malloc(sizeof(float)*lda*ldb, 64);
이 경우 3000x1001 < 되돌려줍니다 code>; ldb = 3008< /code>; 및 < code>; 우다 = 1008년 < /code>;
내가 분석한 결과 이용하여 솔루션을 훨씬 더 빨리 SSE 내장.
inline void transpose4x4_SSE(float *A, float *B, const int lda, const int ldb) {
__m128 row1 = _mm_load_ps(&A[0*lda]);
__m128 row2 = _mm_load_ps(&A[1*lda]);
__m128 row3 = _mm_load_ps(&A[2*lda]);
__m128 row4 = _mm_load_ps(&A[3*lda]);
_MM_TRANSPOSE4_PS(row1, row2, row3, row4);
_mm_store_ps(&B[0*ldb], row1);
_mm_store_ps(&B[1*ldb], row2);
_mm_store_ps(&B[2*ldb], row3);
_mm_store_ps(&B[3*ldb], row4);
}
inline void transpose_block_SSE4x4(float *A, float *B, const int n, const int m, const int lda, const int ldb ,const int block_size) {
#pragma omp parallel for
for(int i=0; i<n; i+=block_size) {
for(int j=0; j<m; j+=block_size) {
int max_i2 = i+block_size < n ? i + block_size : n;
int max_j2 = j+block_size < m ? j + block_size : m;
for(int i2=i; i2<max_i2; i2+=4) {
for(int j2=j; j2<max_j2; j2+=4) {
transpose4x4_SSE(&A[i2*lda +j2], &B[j2*ldb + i2], lda, ldb);
}
}
}
}
}
일부 세부 내용을 바꾸기 4x4 광장 부동 (내아기마저도 논의하십시오 나중에 32 비트 정수) 와 호환표 x86 하드웨어. # 39 의 정사각형 호환표 바꾸기 위해 더 큰 도움이 되는 it& 입문서 같은 8x8 또는 16x16.
'_MM_TRANSPOSE4_PS (r0, r1, r2, r3)' 가 구현됩니까 의해 다르게 다른 컴파일러에도. Mgcc 및 ICC (I 확인하지 않은 클랭) 를 ',', '만 사용하는 반면, 므스티스 우np클프스 오노프스호프스 운프크로프트 오노프스카프트 수프프스'. 실제로 이 두 가지 방식이 이렇게 함께 합칩니다 수 있습니다.
t0 = _mm_unpacklo_ps(r0, r1);
t1 = _mm_unpackhi_ps(r0, r1);
t2 = _mm_unpacklo_ps(r2, r3);
t3 = _mm_unpackhi_ps(r2, r3);
r0 = _mm_shuffle_ps(t0,t2, 0x44);
r1 = _mm_shuffle_ps(t0,t2, 0xEE);
r2 = _mm_shuffle_ps(t1,t3, 0x44);
r3 = _mm_shuffle_ps(t1,t3, 0xEE);
흥미로운 것은 두 관측 셔플 (shuffle) 와 2 개의 블렌드에 (SSE4.1) 이 같은 한 변환할 수 있다.
t0 = _mm_unpacklo_ps(r0, r1);
t1 = _mm_unpackhi_ps(r0, r1);
t2 = _mm_unpacklo_ps(r2, r3);
t3 = _mm_unpackhi_ps(r2, r3);
v = _mm_shuffle_ps(t0,t2, 0x4E);
r0 = _mm_blend_ps(t0,v, 0xC);
r1 = _mm_blend_ps(t2,v, 0x3);
v = _mm_shuffle_ps(t1,t3, 0x4E);
r2 = _mm_blend_ps(t1,v, 0xC);
r3 = _mm_blend_ps(t3,v, 0x3);
2 과 4 를 효과적으로 변환되었습니다 4 뒤섞는다 블렌드에 뒤섞는다. 이 2 보다 더 많은 명령을 사용하여, ICC 및 므스티스 mgcc 구현. 포트 압력을 최대한 줄일 수 있다는 이점을 가질 수 있는 상황에 따라. 현재 모든 뒤섞는다 갈 수 있지만 단지 한 특정 포트 및 풀 블렌드에 이동할 수 있는 두 가지 다른 포트+.
같은 것을 뒤섞는다 므스티스 로 변환 및 8 + 8 블렌드에 4 뒤섞는다 사용하여 노력했다고 하지만 작동되지 않았다. 난 아직도 4 풀 사용해야 했습니다.
내가 이 동일한 기법을 사용한 8x8 의 부동 소수점 전치행렬 (http://otl. 끝을 향해 있는 답). https://stackoverflow.com/a/25627536/2542702. 하지만 난 아직도 그 답을 사용해야 했습니다 풀 망드 변환하십시오 8 8 8 블렌드에 뒤섞는다 및 4 에 뒤섞는다.
32 비트 정수 수프프스 like '없다' (제외한 함께 128-비트 뒤섞는다 AVX512) 로 구현된 풀 이벤트여야만 수 있도록 할 수 있는 것 같지는 않다 # 39, 내가 don& 변환하시겠습니까 블렌드에 (효율적을). '와' like '레인' 역할을 효과적으로 AVX512 vshufi32x4 수프프스 128-비트 제외한 4 과 (와) '이 될 수도 있다는 것 때문에 32 비트 정수 대신 유동합니다 동일한 기술을 vshufi32x4' 사례가 들린다. 나이츠 (처리량의) 보다 4 배 이상 속도가 느린 블렌드에 소개 뒤섞는다 함께 있다.
조옮김 오버헤드에 없이 (class 완료되지):
class Matrix{
double *data; //suppose this will point to data
double _get1(int i, int j){return data[i*M+j];} //used to access normally
double _get2(int i, int j){return data[j*N+i];} //used when transposed
public:
int M, N; //dimensions
double (*get_p)(int, int); //functor to access elements
Matrix(int _M,int _N):M(_M), N(_N){
//allocate data
get_p=&Matrix::_get1; // initialised with normal access
}
double get(int i, int j){
//there should be a way to directly use get_p to call. but i think even this
//doesnt incur overhead because it is inline and the compiler should be intelligent
//enough to remove the extra call
return (this->*get_p)(i,j);
}
void transpose(){ //twice transpose gives the original
if(get_p==&Matrix::get1) get_p=&Matrix::_get2;
else get_p==&Matrix::_get1;
swap(M,N);
}
}
이렇게 사용할 수 있습니다.
Matrix M(100,200);
double x=M.get(17,45);
M.transpose();
x=M.get(17,45); // = original M(45,17)
당연히 didn& # 39, 메모리 관리, 여기 있는 것이 아니라 다른 주제 있는 수는 없는 노릇.
template <class T>
void transpose( std::vector< std::vector<T> > a,
std::vector< std::vector<T> > b,
int width, int height)
{
for (int i = 0; i < width; i++)
{
for (int j = 0; j < height; j++)
{
b[j][i] = a[i][j];
}
}
}
이에 따라 각 열은 각 행의 고려해보십시오 열과 행으로. 내가 사용하는 대신, i, j j
#include <iostream>
using namespace std;
int main ()
{
char A [3][3] =
{
{ 'a', 'b', 'c' },
{ 'd', 'e', 'f' },
{ 'g', 'h', 'i' }
};
cout << "A = " << endl << endl;
// print matrix A
for (int i=0; i<3; i++)
{
for (int j=0; j<3; j++) cout << A[i][j];
cout << endl;
}
cout << endl << "A transpose = " << endl << endl;
// print A transpose
for (int i=0; i<3; i++)
{
for (int j=0; j<3; j++) cout << A[j][i];
cout << endl;
}
return 0;
}
현재 위치 및 인텔 mkl 제안됩니다 잘못 놓아 조옮김 / 복사 호환표. 다음은 https://partner. microsoft. 문서. 현재 위치 및 구축 등 10 곳 중 꼭 이래야겠어요 추천합니까 빠른 최신 버전의 mkl 실수를 붽뎄 꽂으십시오 일부 포함되어 있습니다.
만약 우리가 그 크기를 알 수 있는 노조 어레이에는 전에 사용할 수 있게 도와. 이렇게 -
"'
이름공간이 사용하여 표준용량.
연합 ua { int 도착 [2] [3]; int 브라르 [3] [2]; };
int main () { 연합 ua uav; int = {1.2,3}, {4.5,6 말을 [2] [3]}}, { 메맥피 (루이브리어, 카, 스이제로프 (용의자)); 대한 (int i = 0;; 3; i< i++) { 대한 (int j, 2, j++ j< = 0;) [i] [j] < < " 우라프스베르 < cout<;;;; ";
}
return 0; } "'
가장 일반적인 선형 대수학 라이브러리보다는 포함시키십시오 최적화되었는지 현대 버전의 운영. 그들 중 많은 동적 CPU 긴급요청이다 선택했습니까 베스트중에 구축 등이 있는 하드웨어일까요 dell. 프로그램 실행 시간 (있는 그대로 유지하면서 포터블식).
이는 일반적으로 수동 최적화를 통해 더 나은 대안을 펑크티노스 내장 함수를 수행하는 벡터입니다 확장명은. 후자의 타이법으로요 구현인 것으로 특정 하드웨어 벤더 및 모델: 다른 구입업체별 스왑용 결정할 경우 (예를 들어, 전력, ARM) 또는 새로운 벡터 확장 (예를 들면 AVX512), 다시 내려받습니다 대부분 다시 구현 합니다.
예를 들어, 함수 '이매코프 mkl 조옮김 dm_ownerdm_owner BLAS 확장명은'. 뿐만 아니라 다른 기술과 같은 오픈블라스 확인할 수 있습니다. "'
void 전치행렬 (int, int m, n 은 부동 소수점 *) {
const 부동 소수점 알파 = 1.0f. mkl_simatcopy (row_major, 알파 a, n, m, n, 바꾸기, n). } "'
아르마딜로 c++컴파일러는 사용에 대한 C++ 프로젝트 할 수 있습니다. "'
void 전치행렬 (아르마 매트 &, matrix) { arma::inplace_trans (매트릭스); } "'
내 생각에 가장 빠른 방법은 더 이상 안 받고 그냥 O (n) ^ 2) 도 이런 식으로 O (1) 공간을 사용할 수 있습니다. 이 때문에 그렇게 할 때 그 어떤 짓을 한 쌍으로 스왑용 호환표에 바꾸기) 가 있다. M = M [j] [i], [i] [j] [i] [j] temp 에 관심용 그러하매 작성하든지 M M [i] [j] = M [j] [i], 마지막 단계: M [j] [i] = 온도. 이 될 수 있도록 해야 할 일을 한 번에 의해 O (n ^ 2)
제 대답은 '의 전치를 수행할 3x3 호환표에
#include<iostream.h>
#include<math.h>
main()
{
int a[3][3];
int b[3];
cout<<"You must give us an array 3x3 and then we will give you Transposed it "<<endl;
for(int i=0;i<3;i++)
{
for(int j=0;j<3;j++)
{
cout<<"Enter a["<<i<<"]["<<j<<"]: ";
cin>>a[i][j];
}
}
cout<<"Matrix you entered is :"<<endl;
for (int e = 0 ; e < 3 ; e++ )
{
for ( int f = 0 ; f < 3 ; f++ )
cout << a[e][f] << "\t";
cout << endl;
}
cout<<"\nTransposed of matrix you entered is :"<<endl;
for (int c = 0 ; c < 3 ; c++ )
{
for ( int d = 0 ; d < 3 ; d++ )
cout << a[d][c] << "\t";
cout << endl;
}
return 0;
}