4x4行列の行列乗算に適した高性能なアルゴリズムは何でしょうか。私はいくつかのアフィン変換を実装しており、Strassenのような効率的な行列乗算のアルゴリズムがいくつかあることを知っています。しかし、小さな行列に対して特に効率的ないくつかのアルゴリズムはありますか?私が一目見たほとんどのソースは、漸近的に最も効率的であると考えています。
ウィキペディアには、 2つのnxn行列の行列乗算 の4つのアルゴリズムがリストされています。
プログラマーが書く古典的なものはO(n3)、「スクールブック行列の乗算」としてリストされています。うん。オン3)は少しヒットしています。次に良いものを見てみましょう。
Strassen algorithim はO(n2.807)。これは機能します-これにはいくつかの制限があり(サイズが2の累乗であるなど)、説明に警告があります。
従来の行列乗算と比較して、アルゴリズムはかなりのO(n2)加算/減算のワークロード。したがって、特定のサイズを下回る場合は、従来の乗算を使用する方が良いでしょう。
このアルゴリズムとその起源に興味のある人は、 Strassenがどのようにして彼の行列乗算法を考え出したのか? を読むとよいでしょう。最初のO(n2)追加されるワークロードと、これが従来の乗算を行うよりも高価になる理由。
だから本当にO(n2 + n2.807)より大きな指数nに関するそのビットは、大きなOを書き込むときに無視されます。Nice2048x2048マトリックスで作業している場合、これは有用。 4x4マトリックスの場合、オーバーヘッドが他のすべての時間を消費するため、おそらく遅くなるでしょう。
そして Coppersmith–Winograd algorithm があります。これはO(n2.373)かなりの改善点があります。また、警告が付属しています。
Coppersmith–Winogradアルゴリズムは、理論的な時間の限界を証明するために、他のアルゴリズムのビルディングブロックとして頻繁に使用されます。ただし、Strassenアルゴリズムとは異なり、最新のハードウェアでは処理できないほど大きなマトリックスに対してのみ利点があるため、実際には使用されません。
したがって、非常に大きなマトリックスで作業している場合は、4x4マトリックスでは役に立たないので、より良い方法です。
これは再びWikipediaのページの 行列の乗算:サブキュービックアルゴリズム に反映されています。
単純なアルゴリズムよりも実行時間を改善するアルゴリズムが存在します。最初に発見されたのはStrassenのアルゴリズムで、1969年にVolker Strassenによって考案され、「高速行列乗算」と呼ばれることもよくありました。これは、2つの2×2行列を乗算する方法に基づいています。これは、いくつかの追加の加算および減算演算を犠牲にして、(通常の8の代わりに)7つの乗算のみを必要とします。これを再帰的に適用すると、乗算コストO(nログ27)≈O(n2.807)。 Strassenのアルゴリズムはより複雑であり、数値の安定性はナイーブアルゴリズムと比較して低下しますが、n> 100程度の場合は高速で、BLASなどのいくつかのライブラリに表示されます。
そして、それがアルゴリズムがより高速である理由の核心に到達します-いくつかの数値安定性といくつかの追加設定をトレードオフします。 4x4マトリックスの追加設定は、より多くの乗算を実行するコストよりもはるかに多くなります。
そして今、あなたの質問に答えるために:
しかし、小さな行列に対して特に効率的ないくつかのアルゴリズムはありますか?
いいえ、O(nのため、4x4行列の乗算用に最適化されたアルゴリズムはありません。3)オーバーヘッドのためにbigヒットを受け入れる用意があることに気づくまで、かなり合理的に機能します。特定の状況では、マトリックスについて特定の事柄(データの再利用量など)を事前に知っておく必要があるオーバーヘッドがあるかもしれませんが、実際に最も簡単なことは、O(n3)解決策、コンパイラーに処理を任せ、後でプロファイルを作成して、コードが実際に行列乗算のスロースポットであるかどうかを確認します。
Math.SEに関連する: 4x4行列を反転するために必要な乗算の最小数
多くの場合、より複雑なアルゴリズムはいくつかの変換を使用してオーバーヘッドを追加するため、単純なアルゴリズムが非常に小さいセットに対して最も高速です。あなたの最善の策はより効率的なアルゴリズムではないと思います(ほとんどのライブラリは単純な方法を使用していると思います)が、たとえばSIMD拡張機能を使用する実装(x86またはAMD64コードを想定)、またはアセンブリで手書きするなどのより効率的な実装です。また、メモリレイアウトも十分に検討する必要があります。これで十分なリソースを見つけることができるはずです。
4x4のmat/mat乗算では、アルゴリズムの改善が行われることがよくあります。基本的な3次時間の複雑性アルゴリズムはうまく機能する傾向があり、それよりも奇妙なものは時間を改善するよりも低下する可能性が高くなります。ちょうど一般的に、スケーラビリティの要素が関与していない場合(たとえば、単純な挿入やバブルソートではなく、alwaysに6つの要素がある配列をクイックソートしようとすると)、派手なアルゴリズムは不適切です。行列の転置などを参照の局所性を改善するためにここで実行しても、行列全体が1つまたは2つのキャッシュラインに収まる場合は、参照の局所性は実際には役立ちません。この種のミニチュアスケールでは、4x4のマット/マット乗算を一括で行う場合、通常、適切なキャッシュラインアライメントのように、命令とメモリのマイクロレベルの最適化によって改善がもたらされます。
n
を異なる方法で定義した場合、漸近的複雑度を直接比較することはできません。n
がリスト内のtotal要素の数ですが、マトリックスアルゴリズムはn
を1の長さside。
このn
の定義により、それを印刷するために各要素を1回見るだけの簡単なもの、通常O(n)と考えられるのはO(n2)。 n
をマトリックスの要素の総数として定義する場合、つまり、4x4マトリックスの場合、n = 16の場合、ナイーブマトリックスの乗算はO(n1.5)、かなり良いです。
あなたの最善の策は、O(nの誤った信念に基づいてアルゴリズムを改善しようとするのではなく、SIMD命令またはGPUを使用して並列処理を利用することです。3)は、n
がフラットなデータ構造と同等に定義されている場合と同じくらい悪いです。