Fortranで「疎行列」を操る:PACK/UNPACK関数によるメモリの極限最適化
こんにちは。かつて宇宙の深淵を数値で追いかけていた、Fortranの老兵です。
CやPythonから来た皆さんは、おそらく「Fortranなんて古い言語で何ができるの?」と思っているかもしれません。しかし、大規模な行列演算や物理シミュレーションの現場において、Fortranが今なお王座に君臨しているのには理由があります。それは、「メモリとCPUの仲を誰よりも深く理解できるから」です。
今日は、メモリを浪費しがちな「疎行列(スカスカの行列)」を、Fortranの魔法の関数`PACK`と`UNPACK`を使って、まるで折り紙を畳むようにスマートに管理する技術を伝授します。
—
1. なぜ「疎行列」をわざわざ圧縮するのか?
例えば、10,000×10,000の行列があるとしましょう。要素数は1億個。もしそのほとんどが「0」だったら? メモリ上に0を敷き詰めるのは、広大な宇宙に何もない空間を確保するようなものです。非常に無駄ですよね。
C言語ならポインタを駆使して連結リストを作るところですが、Fortranには「配列こそが宇宙の真理」という哲学があります。配列のメモリレイアウトを壊さずに、必要なデータだけを高速に抽出する。それが`PACK`関数の役割です。
—
2. PACK関数:不要な「0」を切り捨てる
`PACK`は、条件に合致する要素だけを抜き出して、1次元の配列に詰め直す関数です。
program pack_example
implicit none
integer, parameter :: N = 5
real :: A(N, N) = reshape([1.0, 0.0, 0.0, 4.0, 0.0, &
0.0, 2.0, 0.0, 0.0, 0.0, &
0.0, 0.0, 3.0, 0.0, 0.0, &
0.0, 0.0, 0.0, 5.0, 0.0, &
0.0, 0.0, 0.0, 0.0, 6.0], [N, N])
real, allocatable :: compressed(:)
! 0以外の要素だけを抜き出す
! A /= 0 という条件式(マスク)が、まさに物理の篩(ふるい)になります
compressed = pack(A, A /= 0.0)
print , “圧縮後のデータ:”, compressed
end program pack_example
ここで重要なのは、Fortranの「列優先順位(Column-major order)」です。Fortranはメモリ上で縦方向に並びます。`PACK`はこの順序に従って効率的にメモリを読み込むため、CPUのキャッシュヒット率が驚くほど高くなります。Pythonのリストのように要素ごとにメモリが散らばることはありません。
—
3. UNPACK関数:必要な時だけ展開する
逆に、計算の途中で元の形に戻したいときは`UNPACK`の出番です。
! 元の行列サイズ(N,N)に戻す
! maskは元の行列のどの位置に戻すかを示す「地図」のようなもの
A_restored = unpack(compressed, A /= 0.0, 0.0)
この「マスク(条件)」を使い回すことで、必要なときだけ行列の形状を復元し、演算が終わればまたすぐにメモリを解放する。このサイクルを回すだけで、数GBのメモリを節約できることも珍しくありません。
—
4. 現場のエンジニアへ:最適化の心得
初心者の皆さんがまず躓くのは、「何でもかんでも圧縮すれば速くなる」という誤解です。
- 圧縮・展開のコスト: `PACK`には計算コストがかかります。頻繁にアクセスする箇所で毎回圧縮・展開を繰り返すと、CPUは忙しくなりすぎて速度が落ちます。「計算の境界線」で一度だけ変換するのが、プロのやり方です。
- コンパイルフラグの魔法:
現場でコンパイルする際は、ぜひ以下のフラグを試してください。
`gfortran -O3 -march=native -ffast-math`
特に`-march=native`は、あなたのPCのCPUに最適化された命令セットを吐き出させます。`PACK`の高速性がさらに引き立ちますよ。
—
最後に:Fortranは「道具」ではなく「楽器」です
C言語のポインタ操作に疲れたとき、Pythonの実行速度に絶望したとき、ぜひFortranに戻ってきてください。Fortranは、メモリを自分の指先のように扱える「楽器」です。
まずは、小さな行列で`PACK`を試してみてください。0という「空白」が消え、意味のあるデータだけがぎゅっと詰まった瞬間、きっとメモリの心地よい鼓動を感じられるはずです。
何か分からないことがあれば、いつでも聞いてくださいね。宇宙の果てまで届くような、最高に効率的なコードを一緒に書きましょう!

コメント