C++ は C言語と似ているので、C言語を知っている人には、 敷居が低いであろう (Mac で、C言語のコンパイラーを使えるようにしてある人は、 同時に C++ のコンパイラーも使えるようになっているはず)。 便利なライブラリィが豊富にある。 ベクトル・行列計算のためには、Eigen というライブラリィがおすすめ。
Eigenのインストールは簡単 (A を見よ。 5分程度で済むので、うまく行かなければ気軽に質問して下さい。)。
C++は、入出力が C 言語とは違うが、それについては、 「なんとか C++ を使う」 を見ると良い。
Eigen には、VectorXd というベクトルを扱うクラスがある。
#include <Eigen/Dense> using namespace Eigen; ... VectorXd(2) x; |
k1 = tau * f(t, x); k2 = tau * f(t+tau/2, x+k1/2); k3 = tau * f(t+tau/2, x+k2/2); k4 = tau * f(t+tau, x+k3); x += (k1 + 2 * k2 + 2 * k3 + k4) / 6; |
rk2ex1++.cpp |
/* * rk2ex1++.cpp (Runge-Kutta method for van der Pol equation) * c++ -I /usr/local/include rk2ex1++.cpp * ./a.out > rk2ex1.data (分割数Nを入力. 例えば1000) * gnuplot で * splot "rk2ex1.data" with l * plot "rk2ex1.data" with l, "rk2ex1.data" using 1:3 with l * plot "rk2ex1.data" using 2:3 with l */ #include <iostream> #include <math.h> #include <Eigen/Dense> using namespace std; using namespace Eigen; double mu = 1.0; int main(void) { int i, N; double t, dt, pi; VectorXd x(2),k1(2),k2(2),k3(2),k4(2),f(double,VectorXd),x0(2); double Tmax; // 最終時刻 Tmax = 50.0; // 時間刻み cout << "# N: "; cin >> N; dt = Tmax / N; // 初期値 x0 << 0.1,0.1; t = 0.0; x = x0; cout << "# t x" << endl; cout << fixed; // この後はC言語の %f の形式で出力 cout << t << x(0) << x(1) << endl; // Runge-Kutta法 for (i = 0; i < N; i++) { k1 = dt * f(t, x); k2 = dt * f(t+dt/2, x+k1/2); k3 = dt * f(t+dt/2, x+k2/2); k4 = dt * f(t+dt, x+k3); x = x + (k1 + 2 * k2 + 2 * k3 + k4) / 6; t = (i + 1) * dt; cout << t << " " << x(0) << " " << x(1) << endl; } } VectorXd f(double t, VectorXd x) { VectorXd y(2); y(0) = x(1); y(1) = - x(0) + mu * (1.0 - x(0) * x(0)) * x(1); return y; } |
コンパイル&実行 |
%
c++ -O3 -I /usr/local/include -o rk2ex1 rk2ex1++.cpp
% ./rk2ex1 > rk2ex1++.data 1000 % |
この後は、これまでと同様にして、gnuplot を用いて可視化ができる。
ところで、GLSC (付録 C を見よ) を用いると、 C++のプログラムからグラフィックスが使える。 以下のプログラム中で、 名前がg_で始まっている関数が、GLSCの関数である。 初期化や座標系の設定などはごちゃごちゃしているが、 グラフを描く部分は g_move(x,y), g_plot(x,y) の2命令しか使っていないので、 難しくはないだろう。
rk2ex1++glsc.cpp |
/* * rk2ex1++glsc.cpp (Runge-Kutta method for van der Pol equation) * c++ -I /usr/local/include -I/opt/X11/include -o rk2ex1++glsc \ * rk2ex1++glsc.cpp -L/usr/local/lib -lglscd -L/opt/X11/lib -lX11 -lm * ./rk2ex1++glsc (分割数Nを入力. 例えば1000) */ #include <iostream> #include <math.h> #include <Eigen/Dense> using namespace std; using namespace Eigen; extern "C" { #include <glsc.h> }; void g_dump(const char *fname, Display *display, Window wid) { char command[256]; sprintf(command, "import -window %lu %s", wid, fname); system(command); } double mu = 1.0; int main(void) { int i, N; double t, dt, pi; VectorXd x(2),k1(2),k2(2),k3(2),k4(2),f(double,VectorXd),x0(2); double Tmax; double a = -3.0, b = 3.0, c = -3.0, d = 3.0; double win_width, win_height, w_margin, h_margin; // 最終時刻 Tmax = 50.0; // 時間刻み cout << "# N: "; cin >> N; dt = Tmax / N; // 初期値 x0 << 0.1,0.1; t = 0.0; x = x0; cout << "# t x" << endl; cout << fixed; // この後はC言語の %f の形式で出力 cout << t << " " << x(0) << " " << x(1) << endl; // GLSCの初期化、座標系の設定 win_width = 150.0; win_height = 150.0; w_margin = 10.0; h_margin = 10.0; g_init((char *)"LOTKA_VOLTERRA", win_width + 2 * w_margin, win_height + 2 * h_margin); g_device(G_BOTH); g_def_scale(0, a, b, c, d, w_margin, h_margin, win_width, win_height); g_sel_scale(0); // 線種の定義 g_def_line(0, G_BLACK, 2, G_LINE_SOLID); g_def_line(1, G_BLUE, 1, G_LINE_SOLID); /* 座標軸を描く */ g_sel_line(0); g_move(a, 0.0); g_plot(b, 0.0); g_move(0.0, c); g_plot(0.0, d); // ここからグラフ描き g_sel_line(1); g_move(x(0), x(1)); // Runge-Kutta法 for (i = 0; i < N; i++) { k1 = dt * f(t, x); k2 = dt * f(t+dt/2, x+k1/2); k3 = dt * f(t+dt/2, x+k2/2); k4 = dt * f(t+dt, x+k3); x = x + (k1 + 2 * k2 + 2 * k3 + k4) / 6; t = (i + 1) * dt; g_plot(x(0), x(1)); cout << t << " " << x(0) << " " << x(1) << endl; } // クリックされるまで待つ g_sleep(-1.0); // 画像の保存 g_dump("rk2ex1++glsc.png", g_get_display(), g_get_window()); // GLSCの終了 g_term(); return 0; } VectorXd f(double t, VectorXd x) { VectorXd y(2); y(0) = x(1); y(1) = - x(0) + mu * (1.0 - x(0) * x(0)) * x(1); return y; } |
このプログラムを実行すると、 画面にウィンドウが現れて、そこに解軌道が描かれる。 計算終了後にそのウィンドウをクリックすると、 画像をファイル (rk2ex1++glsc.png) に保存してからプログラムが終了する。