2011年11月02日(水) [長年日記]
■ [c][math] LAPACKを使って行列の固有値計算
線形代数計算ライブラリのLAPACKを使ったのでちょっとだけメモ。
LAPACKを説明したサイトは色々あるけど、数値計算マニュアル:線型代数 (FAQ)がよくまとまっていてよかった。日本計算工学会誌「計算工学」からリンクされている「BLAS, LAPACKチュートリアル パート1」(Vol16,No.2)、「BLAS, LAPACKチュートリアル パート2」(Vol.16,No.3)も参考になる。
実対称行列の固有値と固有ベクトルを計算してくれる関数 dsyev_() を使ったサンプルを書いてみた。関数の戻り値が何を表すのかが不明。
#include <cmath>
#include <iostream>
#include <stdexcept>
#include <vector>
using std::vector;
// f2c.h, clapack.h から必要な宣言を抜粋
extern "C" {
typedef long int integer;
typedef double doublereal;
int dsyev_(
char *jobz,
char *uplo,
integer *n,
doublereal *a,
integer *lda,
doublereal *w,
doublereal *work,
integer *lwork,
integer *info);
}
/**
* 実対称行列の固有値/固有ベクトルを計算する
*
* @param matrix 計算対象の行列。上三角部分だけが設定されていればよい。
* matrixの内容は破壊される(固有ベクトルが設定される)。
*
* @return matrixの全固有値からなるvectorと、全固有ベクトルのvector。
* 戻り値の0番目のvectorが全固有値、
* 戻り値の1番目のvectorが0番目の固有値に対する固有ベクトル、
* 戻り値の2番目のvectorが1番目の固有値に対する固有ベクトル、
* ...
*/
std::vector<std::vector<double> > eigen(std::vector<double>& matrix) {
if (matrix.empty()) return vector<vector<double> >();
char jobz = 'V'; // 固有ベクトルも計算する
char uplo ='U'; // 上三角部分を使用。ただし列優先。
integer n = static_cast<integer>(std::sqrt(matrix.size())); // matrixの行数
integer lda = n; // matrixのleading dimension
vector<doublereal> work(n * 3); // dsyev_()の作業領域
integer lwork = static_cast<integer>(work.size()); // workのサイズ
integer info = 0; // dsyev_()の処理結果
vector<double> eigenvalues(n);
dsyev_( &jobz,
&uplo,
&n,
&matrix[0],
&lda,
&eigenvalues[0],
&work[0],
&lwork,
&info);
if (info) {
throw std::runtime_error("error: dsyev_()");
}
vector<vector<double> > result(n + 1, vector<double>(n));
result[0] = eigenvalues;
// LAPACKは列優先
for (integer col = 0; col < n; ++col) {
for (integer row = 0; row < n; ++row) {
result[col + 1][row] = matrix[col * n + row];
}
}
return result;
}
int main() {
vector<double> m;
m.push_back(0);
m.push_back(1); // ここの値は使われない
m.push_back(1);
m.push_back(-1);
vector<vector<double> > eigens = eigen(m);
if (eigens.empty()) {
throw std::runtime_error("BUG: no eivenvalue.");
}
std::cout << "eigenvalues:";
for (std::size_t i = 0; i < eigens[0].size(); ++i) {
std::cout << " " << eigens[0][i];
}
std::cout << "\n";
for (std::size_t i = 1; i < eigens.size(); ++i) {
std::cout << "eigenvector" << i << ":";
for (std::size_t j = 0; j < eigens[i].size(); ++j) {
std::cout << " " << eigens[i][j];
}
std::cout << "\n";
}
}
[ツッコミを入れる]
2011年11月07日(月) [長年日記]
■ [life] 健康診断を受けた2011
今年も受診できた。去年より混んでいる印象。老人だらけで、そりゃ国保の保険料高くなるわ…。
まず身長体重。柱に寄り掛かっては駄目と言われた。機械が変わったのかもしれない。次血圧。そしてしばらく待つ。いつものパターン。
待っている間に、あるおばあさんの名前が呼ばれ、それに対し間違ったおばあさんが説明を聞いて次の検査へ行ってしまうというトラブルが発生した。レントゲンの方で名前が一致しないことに気付き解決した模様。
おれの番も来て、レントゲン。名前を呼ばれる前にレントゲン室の扉を開けてしまったのは失敗だった気がする。でも上着を脱いだら中へ入れと言われたんだよなあ。続けて尿検査、採血、心電図。しばらく待って医師による問診。胴回りは78cm。去年と同じなのか。
今年は1時間半掛かった。料金は500円。後日便を採取して提出しないといけないのだ。未経験なので怖い。
[ツッコミを入れる]
2011年11月16日(水) [長年日記]
■ [shell][howto] 標準出力と標準エラーを入れ替える
- 36.16. n>&m: Swap Standard Output and Standard Error (Unix Power Tools, 3rd Edition)
に、
$ command 3>&2 2>&1 1>&3
というイディオムが紹介されていた。これでcommandの標準出力と標準エラーが入れ替わる。
動作確認。
% bash $ ls tmp/ $ ls tmp tmp2 ls: tmp2: そのようなファイルやディレクトリはありません tmp: $ ls tmp tmp2 3>&2 2>&1 1>&3 | sed 's/tmp/XXX/' tmp: ls: XXX2: そのようなファイルやディレクトリはありません
標準エラーに対してだけ置換が行われたのでOK。ちなみに、zsh 4.2.0(古い)だとうまくいかなかった。
[ツッコミを入れる]