Fortranの「動的」な力:ABSTRACT INTERFACEとプロシージャポインタでコードを自在に操る
皆さん、こんにちは。かつて宇宙の深淵を数値計算で追いかけていた元・特任最高数値計算アーキテクトです。
「Fortranは古臭い」「静的すぎて柔軟性がない」……そんな誤解を抱えていませんか? C言語の関数ポインタやPythonのデコレータに慣れた皆さんにこそ知ってほしい、Fortranの隠れた武器があります。それが`ABSTRACT INTERFACE`と`PROCEDURE POINTER`です。
これらを使いこなせば、コンパイル時にすべてが決まる硬直したコードから脱却し、シミュレーションの最中にアルゴリズムを切り替えるような、モダンで「動的」な設計が可能になります。今日は、この泥臭くも強力な世界へご案内します。
—
1. そもそも「抽象インターフェース」って何?
PythonやC++などの他言語では、「関数を引数として渡す」ことは日常茶飯事ですよね。Fortranでこれを行うには、「渡そうとしている関数は、こういう引数構成(型、次元、intentなど)を持っていますよ」という「契約書」をコンパイラに事前に見せておく必要があります。
これが`ABSTRACT INTERFACE`です。いわば、「この形の関数なら何でも受け付けますよ」という設計図ですね。
! 抽象インターフェース:関数の「形(インターフェース)」を定義する
ABSTRACT INTERFACE
FUNCTION solver_func(x) RESULT(y)
REAL, INTENT(IN) :: x
REAL :: y
END FUNCTION solver_func
END INTERFACE
このブロック自体はコードとして実行されません。しかし、この定義があることで、コンパイラは「このルールに適合する関数なら、後から差し替えても安全だ」と判断できるようになります。
—
2. プロシージャポインタで「関数を入れ替える」
次に、このインターフェースを利用する「入れ物(ポインタ)」を作ります。これが`PROCEDURE POINTER`です。
「ポインタ」という言葉に身構える必要はありません。ここでは、「関数への参照を格納できる箱」と考えてください。
! インターフェースを利用する変数(プロシージャポインタ)を宣言
PROCEDURE(solver_func), POINTER :: my_algorithm => NULL()
これで準備完了です。実行時に、計算対象の関数をこの箱に代入するだけで、計算ロジックを自在に切り替えられます。
—
3. 実践:シミュレーションでの切り替え例
例えば、非線形方程式のソルバーで「手法A(ニュートン法)」と「手法B(二分法)」を切り替えるような場面を想像してください。
MODULE math_module
ABSTRACT INTERFACE
FUNCTION model_func(x) RESULT(y)
REAL, INTENT(IN) :: x
REAL :: y
END FUNCTION model_func
END INTERFACE
CONTAINS
! 物理モデル1
FUNCTION linear_model(x) RESULT(y)
REAL, INTENT(IN) :: x
y = 2.0 x
END FUNCTION linear_model
! 物理モデル2
FUNCTION quad_model(x) RESULT(y)
REAL, INTENT(IN) :: x
y = x2
END FUNCTION quad_model
END MODULE math_module
PROGRAM main
USE math_module
! プロシージャポインタの宣言
PROCEDURE(model_func), POINTER :: current_model => NULL()
! 状況に応じてアルゴリズムを切り替える
current_model => linear_model
PRINT , “結果1:”, current_model(5.0)
current_model => quad_model
PRINT , “結果2:”, current_model(5.0)
END PROGRAM main
—
4. 現場の教訓:なぜこれが必要なのか?
皆さんがこれから挑む大規模な数値計算の現場では、「コードの疎結合化」が死活問題になります。
- コンパイラの最適化フラグへの影響: プロシージャポインタ経由の呼び出しは、直接呼び出しに比べてコンパイラが「どの関数が呼ばれるか」を静的に確定しにくいため、過度なインライン化が抑制される場合があります。しかし、それは「再コンパイルなしでアルゴリズムを差し替えられる」という巨大なメリットとのトレードオフです。
- キャッシュ効率の罠: あまりに関数を細分化して頻繁に差し替えると、命令キャッシュに負荷がかかります。しかし、現代のCPUであれば、ループの外側でポインタをセットし、内側で呼び出す設計にすれば、ペナルティは無視できるレベルです。
最後に:まずは手を動かそう
まずは、今日紹介したコードをコピー&ペーストして、`gfortran`や`ifort`でコンパイルしてみてください。
コンパイルコマンド例
gfortran -O3 -Wall -o simulation main.f90
./simulation
最初はエラーが出るかもしれません。でも、そのエラーこそが「Fortranという堅牢な言語が、皆さんの設計ミスを未然に防いでくれている」証拠です。
Fortranは、単なる「古い計算用言語」ではありません。適切に使えば、C++並みの柔軟性と、圧倒的な計算速度を両立できるモダンなツールです。皆さんの研究や業務が、この「動的なFortran」でさらに加速することを期待しています!
何か詰まったら、いつでも聞いてくださいね。現場の知見を詰め込んだ回答でお返しします。

コメント