両方の行列がCSCまたはCSR形式であると仮定して、スパース行列の乗算演算で事前に非ゼロの数を見つけるための高速で効率的な方法があるかどうか疑問に思いました。
smmpパッケージにあるものは知っていますが、CまたはC ++で既に実装されているものが必要です。
任意の助けをいただければ幸いです。前もって感謝します。
両方の行列がCSCまたはCSR形式であると仮定して、スパース行列の乗算演算で事前に非ゼロの数を見つけるための高速で効率的な方法があるかどうか疑問に思いました。
smmpパッケージにあるものは知っていますが、CまたはC ++で既に実装されているものが必要です。
任意の助けをいただければ幸いです。前もって感謝します。
回答:
2つのスパースパターンの積を形成することで、マトリックスとマトリックスの積をシミュレートできます。つまり、スパースパターン(CSR形式で別の配列に格納されている)を0または1のいずれかを含むマトリックスと見なします。各エントリ。このシミュレートされた製品を実行するには、これらのゼロと1での操作は、実際の行列行列積よりもはるかに高速です。実際、2つの行列の行と列を調べて、少なくとも1つのエントリがあることを確認するだけです。両方の行列がゼロ以外の場合、乗算する行と列。これは安価な操作です。実際の製品で実際に浮動小数点の乗算を行う必要がある場合よりもはるかに安く、浮動小数点演算(高価な)を行うだけでなく、メモリから実際の浮動小数点数を読み込む必要があります(さらに高価ですが、行列のゼロ以外の値はCSRに個別に保存されるため、スパースパターンを乗算するときにその必要はありません)。
実際には、AとBの両方がスパースであるA * Bの元のコードをMatlabで作成しました。結果のためのスペースの事前割り当ては確かに興味深い部分でした。Godricが指摘していることを観察しました。ABの非ゼロの数を知ることは、ABを計算するのと同じくらい費用がかかります。
ABのサイズを正確に推定する最初の実用的で高速な方法を示したEdith Cohenの論文の前に、1990年頃にスパースMatlabの初期実装を行いました。下位のサイズ推定器を作成し、計算の途中でスペースがなくなった場合、割り当てを2倍にし、部分的に計算された結果をコピーしました。
現在、Matlabに何があるのかわかりません。
別の可能性は、一度に1列ずつABを計算することです。各列は一時的にスパースアキュムレータに保存でき(これらの説明についてはスパースMatlabの論文を参照)、結果列の正確に既知のサイズを保持するために割り当てられたスペース。結果は、CSCの各列で、列間連続性のない散在圧縮スパース列形式になります。メタデータとして1つではなく、長さnumcols(col start、col length)の2つのベクトルを使用します。そのストレージ形式は一見の価値があるかもしれません。別の強みがあります。行列全体を再割り当てせずに列を拡大できます。
このホワイトペーパーでは、2つのスパースマトリックスのマトリックス積の結果のサイズを近似するアルゴリズムについて説明します。
スパース行列乗算で非ゼロエントリの正確な数を見つける際の問題は、結果の各要素が2つのベクトルの相互作用に依存することです。両方のベクトルは少なくともいくつかの非ゼロ要素を含む可能性があります。したがって、数値を計算するには、結果のすべての要素のベクトルのペアで論理演算を評価する必要があります。これに伴う問題は、行列積自体を計算するために必要な操作の数に類似した操作の数を必要とすることです。私のコメントで、元の行列の非ゼロ要素の特定の構造を活用する可能性について言及しましたが、それらの同じ活用を使用して、行列乗算で行われる作業を減らすこともできます。
上記のペーパーを使用してメモリ要件を過大評価し、乗算を行ってから割り当てられたメモリを切り捨てるか、結果の行列をより適切なサイズの配列に移動する方が良いでしょう。また、まばらな行列積はめったに発生するものではなく、この問題が以前に解決されたことをほぼ保証します。いくつかのオープンソースのスパースマトリックスライブラリを少し掘り下げると、メモリを事前に割り当てるために使用するアルゴリズムに導かれるはずです。
CSRまたはCSCの場合、行列要素の配列にすでにゼロがないことが保証されていますか?その場合、次のようなものを使用して、ゼロ以外の要素がいくつあるかを簡単に把握できます。
int nnz = sizeof(My_Array)/sizeof(long int);
これはあなたが試すことができるもの(少し簡単すぎると思われる)場合ではない場合はあるの減少。行列要素の配列が非常に大きい場合、これは非ゼロ要素の数を計算する最も効率的な方法かもしれません。Thrust(CUDAライブラリー)やOpenCL(GPUを使用する必要はありません)などの多くの並列C / C ++ライブラリーは、条件付き縮小をサポートしています-各要素に対して、の結果を追加しCondition(Element)
ます。条件を設定するとElement != 0
、ゼロ以外の要素の数が加算されます。要素の配列、行/列インデックスの配列からゼロ値の要素を削除し、列/行ポインターを調整することもできます。
CSRを実装する最も簡単な方法は、
std::vector< std::map<int, complex<float>> >
マトリックスを表現します。その場合、ゼロ以外の要素の数については実際には心配しません。すべてにアクセスするには
std::map< int, complex<float> >::iterator
各行に。ベスト..