행렬의 행 주요 및 열 주요 레이아웃


16

밀집 행렬 계산을 프로그래밍 할 때 열-주요 레이아웃에서 행-주요 레이아웃을 선택해야하는 이유가 있습니까?

선택한 매트릭스의 레이아웃에 따라 캐시 메모리를 속도 목적으로 효과적으로 사용하려면 적절한 코드를 작성해야합니다.

행-주요 레이아웃은 더 자연스럽고 단순 해 보입니다 (적어도 나에게는). 그러나 Fortran으로 작성된 LAPACK과 같은 주요 라이브러리는 열 주요 레이아웃을 사용하므로이 선택을 한 이유가 있어야합니다.


x 열 벡터를 사용하여 b = A * x를 계산하는 것을 고려하면 행 주요 A에 대해 벡터의 내부 곱인 A (i, :) ^ T x를 사용하여 b (i)를 얻을 수 있습니다. 주요 열의 경우 스칼라 곱셈 벡터 sum_i A (:, i) x (i) 만 필요할 수 있습니다. 나에게 주요 전공이 훨씬 낫다! 어떻게 생각해?
Hui Zhang

칼럼 전공을 좋아하도록 훈련하십시오. 벡터를 열로 또는 벡터의 조옮김을 행으로 시각화하면 쉽습니다. 행렬 곱셈의 시각화를 매우 간단하게 만들고 게시 된 많은 수학을 쉽게 따라갈 수 있습니다.
Mike Dunlavey

답변:


18

열 주요 레이아웃은 Fortran에서 사용하는 방식이므로 LAPACK 및 기타 라이브러리에서 사용됩니다.

일반적으로 메모리에 배치 된 순서대로 배열의 요소에 액세스하는 것이 메모리 대역폭 사용 및 캐시 성능면에서 훨씬 더 효율적입니다. 행렬 저장 방법에 따라이를 활용하는 알고리즘을 선택하는 것이 좋습니다.

내부 저장 열 주요 형식의 내부 저장소


11

기존 소프트웨어를 고려하지 않고 진공 상태에서 코드 관점에서 행 전공보다 열 전공을 선호하는 이유는 없습니다. 그러나 대부분의 수학 문헌은 벡터를 행 대신 열로 저장하여 벡터를 행렬로 그룹화하는 방식으로 작성되었습니다. 예를 들어, 당신은 전체 고유치 방정식 쓸 때 X엑스=엑스Λ엑스행렬에는 열로 작성된 모든 고유 벡터가 포함됩니다. 당신은 실제로 다른 방법으로 작성된 것을 보지 못합니다 (행 통계와 같은 사람들은 행 벡터와 같은 것을 들었습니다). 따라서 초기 소프트웨어에서 열 주요 형식을 사용하는 것이 당연했습니다. 따라서 벡터 집합 인 행렬이있는 경우 단일 벡터의 저장이 연속적입니다. 따라서, 나는 전통이 현재까지 이어져 왔다고 생각합니다. 그리고 예전의 포트란과 대화하고 싶다면, 컬럼 메이저를 사용하고 싶습니다. 따라서 대부분의 매우 효율적인 수치 선형 대수학은 주요 열에서 수행됩니다.

C가 행 메이저 인 이유는 배열 구문의 결과입니다. 3 행 x 2 열 배열을로 선언하면 double a[3][2]나중에 인덱스가 이전 인덱스보다 빠르게 변하므로 2D 배열의 경우 행을 주요하게 만듭니다. 이것을 왼쪽에서 오른쪽으로 자연 서양의 읽기 순서와 결합하면 행 전공이 더 자연스럽게 보입니다.


2
나는 이것이 잘못된 주장이라고 생각합니다. '' 'double a [3] [2]' ''의 마지막 지수가 가장 빠르게 변한다는 사실은 우연의 일치가 아닙니다. 이는 Fortran의 의식적인 디자인 결정과 같은 방식으로 고의적 인 디자인 결정이었습니다. '' 'real (3,2)' ''배열이 있으면 다른 방법으로 수행하십시오.
Wolfgang Bangerth

1
더구나, 거의 모든 고효율 수치 선형 대수학이 열 장수라는 것은 더 이상 사실이 아닙니다. 이것은 여전히 ​​BLAS 및 LAPACK에 해당 될 수 있지만, 지난 15 년 동안 등장한 모든 주요 선형 대수학 라이브러리에는 전혀 해당되지 않습니다. 예를 들어 PETSc 및 Trilinos는 행 주요 희소 행렬 저장 형식을 사용합니다.
Wolfgang Bangerth

나는 C 컨벤션이 아마도 자연적인 읽기 순서에 기초한 의식적인 결정이라는 것을 알고 있습니다. 나는 아마도 숫자 선형 대수를 염두에두고 설계되지 않았기 때문에 행이 중요하다는 우연의 일치를 의미했습니다. 둘째, 희소 행렬에 대한 주장을 의도하지 않았으며 밀도가 높았습니다. 스파 스의 경우 압축 된 행 및 열 형식이 모두 약간 섞여 있습니다.
Victor Liu

5
요점을 설명하지는 않았지만 C는 원래 초기 부동 소수점 숫자가 없었던 PDP-11과 같은 시스템에서 실행되는 이전 언어 B 및 BCPL을 기반으로 한 시스템 언어였습니다. 그들이 숫자를 염두에두고 디자인했다고 말하는 것은 꽤 확장 적입니다.
Victor Liu

7
C의 행렬이 마지막 인덱스를 가장 빠르게 움직이는 이유는 C에 행렬이 없기 때문입니다. 여기에는 벡터의 벡터가 있으며, 이는 솔리드 메모리 블록 또는 배열에 대한 포인터 배열로 투명하게 구현할 수 있습니다. Fortran과 인덱스 순서를 호환시키는 것은 Dennis Ritchie의 레이더조차도 아니 었습니다.
Mike Dunlavey

2

열 주요 순서가 더 자연스러운 것 같습니다. 예를 들어 영화를 그림별로 파일로 저장하려면 열 순서를 사용하고 있으며 매우 직관적이며 아무도 행 주요 순서로 저장하지 않는다고 가정하십시오.

C / C ++에서 프로그래머라면 기본 열 주요 순서와 함께 매트릭스 (Eigen, Armadillo 등)에 대해 상위 레벨 라이브러리를 사용해야합니다. C / C ++는 행렬 인덱싱을 상기시키는 무언가를 제공하지만 열악한 순서로 원시 C 포인터를 미치광이 만 사용합니다.

간결성을 위해 행 전공 순서가있는 모든 항목은 최소한 이상하게 구성된 것으로 간주해야합니다. 슬라이스 별 슬라이스는 단순히 자연적인 순서이며 포트란과 같은 열 주요 순서를 의미합니다. 우리 아버지 / 어머니는 왜 그것을 선택했는지 아주 좋은 이유가있었습니다.

불행히도 몇 가지 흥미로운 라이브러리는 경험이 부족하기 때문에 행 순서로 만들어졌습니다.

오른쪽 인덱스가 메모리를 통해 한 단계에서 더 빨리 변하는 행 주요 순서의 정의를 명확히하기 위해 : A (x, y, z) 그것은 z 인덱스입니다. 즉, 다른 슬라이스의 메모리 픽셀에서 인접한다는 것을 의미합니다. 원하지 않아요 영화 A (x, y, t)의 경우 마지막 색인은 시간 t입니다. 영화를 행 전공 모드로 저장하는 것이 불가능하다는 것은 상상하기 어렵지 않습니다.


2

미디엄×

  • 미디엄나는,제이나는×미디엄+제이
  • 미디엄나는,제이제이×+나는

이제 다음 알고리즘을 상상해보십시오.

for i from 1 to m
   for j from 1 to n
      do something with m(i,j)

행 주요 순서를 사용하면 모든 선형 인덱스 통과합니다.나는×미디엄+제이순차적으로, 메모리 로컬 성이 양호하지만, 열-주요 순서가 사용되는 경우 연속 메모리 액세스는 메모리에 흩어집니다. 가상 메모리 / 스와핑이 장면에 들어갈 때 특히 결과가 극적으로 나타날 수 있습니다.

결론 :

  1. 예, 중요하지만 선택은 데이터가 액세스되는 방식에 따라 다릅니다. 이전 예에서 열 순서를 사용하는 경우 간단히 두 루프를 교체하면됩니다.

  2. 일반적으로 빠르게 변하는 인덱스는 메모리의 연속 위치에 매핑되어야합니다.

  3. 더 중요한 것은 선택의 영향을 측정 / 벤치마킹 하는 것이 기본입니다. 많은 매개 변수 (데이터 크기, 캐시 크기, 사용 된 언어가 여러 인덱스를 선형 인덱스에 매핑하는 방식, 운영 방식에 따라 달라지기 때문입니다) 시스템은 가상 메모리를 관리합니다. 루프가 사용하는 선형 대수 라이브러리에 중첩되는 방식 ...)

당사 사이트를 사용함과 동시에 당사의 쿠키 정책개인정보 보호정책을 읽고 이해하였음을 인정하는 것으로 간주합니다.
Licensed under cc by-sa 3.0 with attribution required.