密行列計算のプログラミングで、列優先レイアウトより行優先レイアウトを選択する理由はありますか?
選択したマトリックスのレイアウトに応じて、速度を上げるためにキャッシュメモリを効果的に使用するために適切なコードを記述する必要があります。
行優先レイアウトは、より自然でシンプルに見えます(少なくとも私には)。しかし、Fortranで書かれたLAPACKのような主要なライブラリは列の主要なレイアウトを使用するため、この選択をした理由がいくつかあるに違いありません。
密行列計算のプログラミングで、列優先レイアウトより行優先レイアウトを選択する理由はありますか?
選択したマトリックスのレイアウトに応じて、速度を上げるためにキャッシュメモリを効果的に使用するために適切なコードを記述する必要があります。
行優先レイアウトは、より自然でシンプルに見えます(少なくとも私には)。しかし、Fortranで書かれたLAPACKのような主要なライブラリは列の主要なレイアウトを使用するため、この選択をした理由がいくつかあるに違いありません。
回答:
列の主要なレイアウトは、Fortranで使用されるスキームであるため、LAPACKおよびその他のライブラリで使用されます。
一般に、メモリの帯域幅の使用率とキャッシュパフォーマンスの点で、メモリ内に配置されている順序で配列の要素にアクセスする方がはるかに効率的です。マトリックスの保存方法に応じて、これを活用するアルゴリズムを選択する必要があります。
列メジャー形式の内部ストレージ
既存のソフトウェアを考慮せずにバキュームでは、コードの観点から行メジャーより列メジャーを優先する理由はありません。ただし、ほとんどの数学文献は、ベクトルを行ではなく列として保存することにより、ベクトルを行列にグループ化する方法で記述されています。たとえば、あなたは完全な固有値方程式書くとき、Xを行列には、列に書き込まれたすべての固有ベクトルが含まれます。あなたは本当にそれが他の方法で書かれていることを見たことはありません(統計の人々は行ベクトルが好きだと聞いていますが)したがって、ベクトルのセットであるマトリックスがある場合、任意の単一ベクトルのストレージが連続するように、最も初期のソフトウェアが列メジャー形式を想定するのは自然でした。したがって、私は伝統が今日に引き継がれたばかりで、昔のFortranとやり取りしたいなら、列メジャーを使いたいと思うと思います。したがって、ほとんどすべての非常に効率的な数値線形代数は、列メジャーで行われます。
Cが行メジャーである理由は、その配列構文の結果です。3行2列の配列をとして宣言します。double a[3][2]
後のインデックスは前のインデックスよりも速く変化し、2D配列の場合は行が大きくなります。これを、左から右への自然な西洋の読み順と組み合わせると、行メジャーがより自然に見えるようになります。
列優先の順序はより自然なようです。たとえば、ピクチャごとにムービーをファイルに保存する場合、列順を使用するとします。これは非常に直感的で、行優先の順序で保存する人はいません。
C / C ++のプログラマーである場合は、列(Eigen、Armadilloなど)のデフォルトの列優先順序で、より高いレベルのライブラリを使用する必要があります。C / C ++は行列のインデックス付けを思い出させるものを提供していますが、マニアックな人だけが行優先の生のCポインタを使用します。
単純化するために、行優先の順序を持つすべてのものは、少なくとも奇妙なものとして形成されると見なされるべきです。スライスごとのスライスは単純な自然順序であり、列優先順序(Fortranのような)を意味します。私たちの父親/母親は、彼らがそれを選んだ非常に良い理由がありました。
残念ながら、明らかになる前に、おそらく経験不足のため、いくつかの興味深いライブラリが行優先の順序で作成されました。
メモリを介して1ステップで右インデックスがより速く変化する行優先順序の定義を思い出してください。たとえば、A(x、y、z)はz-indexです。これは、メモリ内で異なるスライスのピクセルが隣接していることを意味します。したくない 映画A(x、y、t)の場合、最後のインデックスは時間tです。行優先モードでムービーを保存することは単に不可能であることを想像するのは難しくありません。
次のアルゴリズムを想像してください。
for i from 1 to m
for j from 1 to n
do something with m(i,j)
結論:
はい、重要ですが、選択はデータのアクセス方法によって異なります。前の例で、column-orderが使用されている場合、できることは2つのループを交換することです。
経験則:急速に変化するインデックスは、メモリ内の連続した場所にマッピングする必要があります。
さらに重要なことは、選択の影響を測定/ベンチマークすることは、多くのパラメーター(データのサイズ、キャッシュのサイズ、使用言語が複数のインデックスを線形インデックスにマッピングする方法、操作の方法システムが仮想メモリを管理し、使用する線形代数ライブラリにループがネストされる方法...)