🔨

lapacke入りのlapackのソースビルド

2024/03/01に公開

初めに

lapackは数値線形代数のルーチンをがそろったfortranのライブラリです。線型方程式や線型最小二乗問題、固有値問題、特異値問題等の問題を解くことができます。

管理者権限がある場合

もしあなたが管理者権限を持っている場合は、lapackの利用は簡単です。

bash
sudo apt -y install libatlas3-base libatlas-base-dev

でできるでしょう。
https://www.kkaneko.jp/tools/ubuntu/lapacklinux.html

bash
 apt-cache search lapack

で必要なライブラリを探すのも一つの手でしょう。

管理者権限がない場合

ですが管理者権限がない環境において上記のinstallはできません。もちろん管理者に依頼したり、dockerやanacondaなどの仮想環境を用いて、実行するといったことも良い手段と考えられます。そして多くのスパコンでは専用にチューニングされたlapackがinstallされているものなのでそれらを利用することが速度向上に一番良い手段だと思われます。ですが諸事情によりローカル環境にlapackをinstallしなければいけないことが生じた場合、ローカルフォルダにソースビルドする必要があります。ここではその方法を紹介します。

コードのinstall

https://www.netlib.org/lapack/

lapackの公式ページよりコードをinstallします。2024年3月現在の最新バージョンは、3.12.0です。

shell
wget https://github.com/Reference-LAPACK/lapack/archive/refs/tags/v3.12.0.tar.gz
tar -xf v3.12.0.tar.gz
cd lapack-3.12.0
mkdir build
cd build

ここでinstallするdirectoryを指定します。ここでは、$HOME/.local以下にinstallする例を紹介します。

shell
cmake -DCMAKE_INSTALL_PREFIX=$HOME/.local/lapack-3.12.0 -DCBLAS:BOOL=ON -DLAPACKE:BOOL=ON -DBUILD_TESTING=ON -DLAPACKE_WITH_TMG:BOOL=ON -DBUILD_SHARED_LIBS:BOOL=ON  ../

このコマンドを実行するとconfigureが進みます。このとき注意するべきなのは、condaなどの仮想環境を切ることです。仮想環境の中で実行するとfortranなどのコンパイラを見つけることができず、configureに失敗することがあります。

shell(output)
-- Configuring done
-- Generating done
-- Build files have been written to: /somewhere/your/build/directory

のように表示され、configureが無事に終わったら、buildに移ります。

shell
make -j5 # ご自身の実行環境に合わせて並列数をご変更ください。

次にtestをします:

shell
ctest

テストが無事に通っていることを確認したら、installします。

shell
make install

このコマンドが成功すれば無事にinstall成功です。

環境変数の設定

続いて環境変数を設定します。今回shared libraryとしてinstallしたので、実行時に動的リンクを実現するための環境変数を与える必要があります。またc/c++で生のlapackを呼び出すのではなく、lapackeを経由してlapackの関数を呼び出す場合はコンパイラにincludeファイルのpathを事前に示しておくと便利です。

ホームディレクトリの.bashrcに以下を追記します。

.bashrc
export CPATH="$CPATH:$HOME/.local/lapack-3.12.0/include"
export LIBRARY_PATH="$HOME/.local/lapack-3.12.0/lib:$LIBRARY_PATH"
export LD_LIBRARY_PATH="$LD_LIBRARY_PATH:$HOME/.local/lapack-3.12.0/lib"

CPATHはコンパイルする際に"-I"で指定する値を制御し、LIBRARY_PATHはコンパイルする際に"-L"で指定する値を制御します。LD_LIBRARY_PATHは実行時の動的リンクの参照に使われます。

※環境によっては$HOME/.local/lapack-3.12.0/libではなく$HOME/.local/lapack-3.12.0/lib64となる場合があります。ご注意ください。

それでは現在のshellに変更を反映させましょう:

shell
source ~/.bashrc

これでinstallは完全に完了です。システムの中でlapackを利用できるようになりました。

実行テスト

最後に、以上のinstallが本当にうまくいったかを確認するテストコードを紹介します。ここではlapackのCのインターフェースであるlapackeも同時にinstallすることができたので、lapacke経由でlapackを呼び出しうまく動くかを、確認することにします。扱う問題は連立方程式Ax = bです。

連立方程式を求めるルーチンはdgesvがあり、ここではN\times Nのランダム行列AN\times 1のランダムベクトルがあるときにxを求めることにします。

random_matrix_gesv.cpp
#include <iostream>
#include <lapacke.h>
#include <vector>
#include <random>
/**
 * Ax = b (A: NxN 正方ランダム行列 b: Nx1 ランダムベクトル)の連立方程式を解くsolver
*/
int main(int argc, char *argv[])
{
  std::random_device seed;
  std::uniform_real_distribution<double> rand(1,100);
  int N = 2;//std::stoi(argv[1]);
  std::vector<double> A(N*N); // lapackにポインタ渡しでデータを受け渡す関係により2次元配列が使えないことに注意
  std::vector<double> b(N);
  for (int i=0; i < N; ++i)
  {
    for (int j=0; j < N; ++j)
    {
      A[i+ j*N] = rand(seed); // col majorで配列を作る
    }
    b[i] = rand(seed);
  }

  std::cout << "A:"<<std::endl;
  for (int i=0; i < N;++i)
  {
    for (int j=0; j < N;++j)
    {
      std::cout << A[i + N*j] <<",";
    }
    std::cout << std::endl;
  }
  std::cout << "b: " << std::endl;
  for (int i = 0; i < N; ++i)
  {
    std::cout << b[i] << ",";
  }
  std::cout << std::endl;

  int lda = N, ldb= N;
  std::vector<int> ipiv(N);
  int info = LAPACKE_dgesv(LAPACK_COL_MAJOR, N, 1, A.data(),lda,ipiv.data(), b.data(), ldb);
  std::cout << "result:" <<std::endl;
  for (auto val: b)
  {
    std::cout << val << ",";
  }
  std::cout <<  std::endl;
}

コンパイルは、もし前述の環境変数を正しく定義できていれば、

g++ random_matrix_gesv.cpp -o random_matrix_gesv -llapacke

でできるでしょう。

./random_matrix_gesv

で実行すると、たとえば

A:
95.9187,36.6535,54.1246,
86.55,65.2295,76.3748,
65.0626,85.4263,49.6844,
b: 
99.0266,33.4126,16.6438,
result:
2.0314,-0.532306,-1.40993,

と出力されるでしょう。これが正しいかは以下のpythonコードで確かめることができます。といってもnumpyは裏でlapackを呼ぶので厳密には検証にはなっていません。

test.py
import numpy as np

A = np.array([
    95.9187, 36.6535, 54.1246,
    86.55, 65.2295, 76.3748,
    65.0626, 85.4263, 49.6844,
]).reshape((3, 3))  # A: をコピペする
b = np.array([
    99.0266, 33.4126, 16.6438,
])
x = np.linalg.solve(A, b)
print(x)

このコードを実行すると、

bash
python test.py
bash(output)
[ 2.03140159 -0.53230578 -1.40993061]

と出力されるでしょう。これで検証完了です。

終わりに

ここまで読んでいただき、ありがとうございました。今回はlapackをソースビルドする方法について、説明しました。この記事のモチベーションは、私がinstallしようとした際にかなりてこずったことにあります。lapackのソースのreadme.mdにはinstall方法が書いてある一方で、それ通りにやってもlapackのC言語ラッパーであるlapackeがinstallされず、静的ライブラリとしてビルドされてしまいました。

私はlapackeが利用したかったのですが、どこを探してもlapackeのinstall方法が書いておらず、よくわかりませんでした。しかしその後installしたファイルを見ていると.travis.ymlがあることを発見しました。travisはライブラリなどの自動テストのためのツールなのですが、自動テストを開始するにはもちろんコンパイルをしなければならないので、その中にビルド方法が書いてあったというわけです。今回紹介したビルド方法はそれを参考に作成しました。

皆さまの研究・開発が一層進むことを祈りまして、本記事を終えようと思います。

Discussion