5

Fortran 2003 で、スパース行列を使用して多くの線形代数を実行するコードを書いています。私は、新しい標準のより抽象的な機能のいくつかを活用しようとしているので、コードをあまり繰り返さずに、より単純なプログラムを作成できます。

solver行列、いくつかのベクトル、使用される反復メソッドの許容値などを受け取るプロシージャがあります。呼び出されたプロシージャへのポインタを渡していmatvecます。matvec行列とベクトルの乗算に使用するサブルーチンです。

問題は、このプロシージャに送信される通常のmatvec引数よりも余分な引数を受け取るプロシージャがある場合があることです。colorlist, color1, color2これに対処する方法はいくつか考えられます。

最初のアイデア: 2 つの異なる抽象インターフェースと 2 つの異なるソルバーを定義しmatvec1ますmatvec2。これは機能しますが、一部のコードを複製することを意味します。これは、私が避けようとしているものです。

別のアイデア: 同じ抽象インターフェースmatvecを維持し、追加の引数colorlist, color1, をcolor2オプションにします。つまり、すべての matvec ルーチンでオプションにすることを意味します。実際にはオプションではないルーチンや、まったく使用されないルーチンでも同様です。こんなことしたら確実に地獄に落ちます。

最適ではない解決策は他にもたくさん考えられます。これについて何か意見が欲しいです - それを行うためのエレガントな方法があると確信していますが、それが何であるかはわかりません。

4

2 に答える 2

5

問題は、実際には、プロシージャが呼び出されるたびに追加の引数を渡す必要があるのか​​(2つの呼び出しの間で変更されるため)、ある時点で初期化してから関数で使用できるのかということです。matvec後者の場合、基本的な引数を使用してサブルーチンを定義する抽象インターフェイスを使用してクラスを作成できます。次に、そのクラスをより専門的なクラスで拡張できます。これにより、必要な追加オプションを保持できます。親クラスと同じインターフェイスを(同じ引数リストで)定義する必要がありますが、プロシージャが呼び出されmatvecたときに、格納されている追加の値を使用できます。matvec

同様のケースについて、この回答に詳細な例があります(2番目の例を示していmodule rechercheRacineます)。

于 2013-03-07T08:01:50.780 に答える
2

matvecプロシージャポインタを明示的な引数として渡す代わりに、さまざまなルーチンをジェネリックインターフェイスの背後に置くことができます。

interface matvec
  module procedure matvec1, matvec2
end interface

次に、solverルーチンは、追加の引数の有無にかかわらず、一般名を使用できます。solverもちろん、タイプバウンドプロシージャを使用して派生タイプとしてを定義するというBálintの提案するアプローチを使用する場合にも、同じアプローチを採用できます。

type :: solver
  real, allocatable :: matrix(:,:), v1(:), v2(:)
contains
  procedure, pass :: matvec1
  procedure, pass :: matvec2
  generic :: matvec => matvec1, matvec2
end type

主な違いは、これはポリモーフィズムを使用して呼び出す正しいプロシージャを決定するのではなく、ダミー引数の特性を使用することです。

プロシージャポインタに対するあなたの意図がわかりません。実行時にターゲットを変更したい場合(または「未定義」ステータスに特別な意味を割り当てたい場合)、ポインタが唯一の方法であり、すべてのターゲットが同じ抽象インターフェイスに一致する必要があります。代わりに、引数に基づいていくつかの手順の1つを選択する必要がある場合は、インターフェース(私の例)またはオーバーロード(Bálintの例)を利用できます。タイプの各拡張は、継承されたgenericバインディングを新しいプロシージャで拡張したり、継承された特定のバインディングをオーバーロードしたりできます。

于 2013-03-08T15:39:20.037 に答える