疎な複雑な行列をコードからPETScに効率的に取得する方法


8

FortranコードからPETScに複雑なスパース行列を取得する最も効率的な方法は何ですか?これは問題に依存することを理解しているので、以下に関連する詳細をできるだけ多く記載するようにしました。

私は一緒に遊んでてきたFEAST固有値ソルバー[1]タイプの問題のためのの次元は行列ABがあるN、およびほとんどすべての時間が解決費やされているN × N複素線形をM0右側のシステム。Nは大きく(3DでのFE基底関数の数)、M0は小さい(私の場合はM0〜20に興味がある)。行列ABは実対称でスパースであり、解を必要とする複雑な問題はz A Bであり、ここでzバツ=λBバツBNN×NBzBzは複素数です。FEASTの作成者は、この正確な固有値と固有ベクトルを取得するために、この線形システムの解の精度をそれほど高くする必要がないことを示唆しているようです。そのため、いくつかの高速反復ソルバーは、これに対する優れたソリューションとなる可能性があります。

これまでのところ、複雑なシステムにLapackを使用してきましたが、これは私のコンピューターでにうまく機能します。Nが大きい場合、最適なソルバーがまだわからないので、PETScを使用して、そこで反復ソルバーを試してみたかったのです。N<1500N

私は単純なCドライバーを作成し、それをFortranから呼び出しました。すべてのコードについては[2]を参照してください。問題はこの部分にあります(更新:マトリックスを作成するためにすべての行をここに配置しました。これが関連していること):

ierr = MatCreate(PETSC_COMM_WORLD,&A);CHKERRQ(ierr);
ierr = MatSetSizes(A,PETSC_DECIDE,PETSC_DECIDE,n,n);CHKERRQ(ierr);
ierr = MatSetFromOptions(A);CHKERRQ(ierr);
ierr = MatSetOption(A,MAT_IGNORE_ZERO_ENTRIES,PETSC_TRUE);CHKERRQ(ierr);
ierr = MatSetUp(A);CHKERRQ(ierr);
for (i=0; i<n; i++) col[i] = i;
ierr = MatSetValues(A,n,col,n,col,A_,INSERT_VALUES);CHKERRQ(ierr);

これは非常に遅くなります(つまり、N〜1500の場合、これはおそらく2秒かかりますが、実際にはすぐに解決されます)。実際、MatSetValues固有値の計算全体に対して、ラインは常にほぼ100%かかります...行列A_は、 Fortranの2Dマトリックス。私は無効にしようとしましたMAT_IGNORE_ZERO_ENTRIESが、違いはありませんでした。だから問題は単純に、1500のような中程度のNでも、いくつかの疎行列形式を使用する必要があるということだと思いますが、それは正しいですか?

BzBMatCreateSeqAIJWithArrays

BzBzバツBバツバツBバツMatCreateSeqAIJWithArraysB

この問題に対するこのCSRのアプローチが正しいのか、それとも私が間違っているのかを知りたいのです(明らかに、私のオリジナルのアプローチMatSetValuesは最適ではありません)。ヒントをありがとう。

[1] http://www.ecs.umass.edu/~polizzi/feast/

[2] https://github.com/certik/hfsolver/pull/14

[3] http://www.mcs.anl.gov/petsc/petsc-3.1/docs/manualpages/Mat/MatCreateSeqAIJWithArrays.html

回答:


7

正しく事前に割り当てることが重要です。これがほぼ確実に、アセンブリが遅くなった理由です。密な行列表現から始める場合は、行ごとの非ゼロの数を数えて一度スキャンしてから、を呼び出しますMatSeqAIJSetPreallocation()このFAQを参照してください。このオプションMAT_IGNORE_ZERO_ENTRIESは、密な行列から1回の呼び出しで行列全体を構築するのではなく、そうでなければ密なブロックに若干のスパース性がある場合に使用することを意図しています。このため、その1つのブロックのスパース性に基づく事前割り当ては自動的には行われません。

密な中間行列の作成はメモリスケーラブルではないので、最終的にそれを回避する必要があります。MatSetValues()実際には、疎行列の論理的に密なブロックに使用することを意図しています。通常は、行ごとに1回(またはFDメソッドの一般的な行のグループ)または要素ごとに1回(FEMメソッドの一般的な)呼び出します。既存の組み立てられた疎行列を変換する場合は、MatSetValues()行ごとに1回だけ呼び出します。中間行列をスキップする場合(パフォーマンスが向上し、メモリが少ない)、MatSetValues()要素ごとに1回だけ呼び出します。

基本的なFortran 77と最新バージョンとの間にすべてのFortran方言のユーザーがいますが、Fortranから直接PETScを呼び出すことができることに注意してください。インターフェースは、最新の機能を熱心に採用しているユーザーには、かなり粗雑に見えます。最新の方言のサポートを改善するための保守可能な方法についての提案をいただければ幸いです。


素晴らしい答えをありがとう。私は今の背後にある考えを見ることができますMatSetValues()。既存の行列を変換する場合、各行に対してMatCreateSeqAIJWithArrays呼び出しMatSeqAIJSetPreallocationを行うよりも、一度呼び出すだけの方が高速ではないMatSetValuesですか?
オンドレジ・セティク

Fortranラッパーに関するフィードバックを提供します。今のところ、私がCで必要なドライバーを書くことに固執し、このドライバーを自分でラップするのが最も速いです。
オンドレジ・セティク

1
もちろん、そのためには、同じ規則を使用して組み立てられたCSRマトリックスから始める必要があります。他の形式を使用する場合は、一度に1行ずつパックしてください。事前に割り当てた場合、費やされる時間はMatSetValues()、エントリの計算やシステムの解決に比べて非常に短くなります。また、を使用してアセンブルMatSetValues[Blocked][Local]()すると、コードが特定のマトリックス形式に依存しなくなり、実行時にストレージ形式を選択できます。
Jed Brown、
弊社のサイトを使用することにより、あなたは弊社のクッキーポリシーおよびプライバシーポリシーを読み、理解したものとみなされます。
Licensed under cc by-sa 3.0 with attribution required.