数学のメモその3
今回は、一旦ゼータ関数を置いといてフーリエ解析に関することを書きます。
授業の中でPlancherel(プランシュレル)の定理というものを習いました、
Plancherelの定理というものなんですが授業ではさらっと流されて証明もプリントで、、、みたいな感じやったんですけどこの定理は結構面白いことを言ってるんじゃないかなあと思いました。
:有界連続
適当な正規直交関数系を一つ考えてみましょう。正規直交関数系とは
を満たすもののことです。勘の良い方はこれで僕が何を言いたいのか分かったかも知れませんね笑。この関数がに関してなどなど適当な条件を満たしているとしましょう。のFourier変換をと書くことにすると、
がプランシュレルの定理から分かります。これが何を意味しているかというと適当な条件を満たす正規直交関数系をひとつ持ってこればそれをFourier変換して得られる系もまた正規直交関数系となるのです!!
教授氏にこのことについて質問してみると、チェビシェフの多項式においてこのことが成り立つそうです。また時間があるときに確かめてみたいです。
それでは。
数学のメモその2
前回に続きの証明を書きたいと思います。
〜2重積分を用いる〜
この証明は2重積分
の値を2通リに求めることからわかります。1つ目はを等比級数に展開することです。
の2つ目の計算方法は変数変換です。
と変数変換します。するとより
である。またヤコビアンはである。
変数変換後の積分領域は上の図の色がけ部であるからとに分けて積分する。またに関して対称であることも考慮すると
となります。ここでを用いました。
ここでとおくと、であるから結局、となります。
またとおくと、であるから結局、となります。よって、
がわかります。ここで第1項の積分については、第2項の積分についてはと変数変換すると
となります!!!以上より
が示されました。
あと1つ証明があるのでそれはまた今度ということで。
数学のメモ
授業の演習問題での証明する問題が出たのでいろいろな証明を載せたいと思います。
~フーリエ級数展開の利用~
についてこれは無限級数なのでフーリエ級数展開を用いることを考えます。(授業の演習問題はこの方法だった)
周期関数の複素フーリエ級数展開を計算すると
である。を代入すると
となります。あとは式変形すると
となることがわかりました。
~別の級数から求める~
先ほどの関数の複素でない場合のフーリエ級数展開から得られる
があります。これを書き下してみると
一方、適切な不等式評価を行うとは収束することがわかるので、この値をと置いてみます。
ここで以下のような級数を考えます。
この級数はきちんと収束して先ほどのを用いるととなります。
そこでこの2つの無限級数を足し合わせてみます。
すると左辺はちょうどとなり、これはに一致します。右辺と比較するとより、
が得られました。
続きは長くなるので次回に書きます。
C++で8パズルをA*探索、IDA*探索を用いて解いた
授業で8パズルの探索を図示する課題があったんだけど、どうせならってことでプログラムを書いた。
A*アルゴリズムと言うのは、推定関数h(x)を使って、ゴールまでの距離を推定して、今までの探索の深さとの合計によってそのノードの評価値f(x)を決めて、それを元に最良優先探索をするアルゴリズムのこと。
IDA*アルゴリズムは、A*と同じようにf(x)を決めて、cutoff以下のf(x)の点だけを展開して深さ優先探索して、詰んだらcutoffを増やしてやり直し、っていうアルゴリズム(反復深化+A*みたいなかんじ)
コマンドライン引数で、
1:A*,推定関数は位置が違うパズルの数
2:A*,推定関数はマンハッタン距離
3:IDA*,推定関数は位置が違うパズルの数
4:IDA*,推定関数はマンハッタン距離
出力の方法が雑魚いのは勘弁して下さい\(^o^)/
#include <iostream> #include <cstdlib> #include <functional> #include <queue> #include <stack> #include <map> #include <vector> struct state { int puzzle[9]; int depth; int evaluation; bool operator>(const state &s) const { return evaluation > s.evaluation; } }; state start = { {1, 2, 3, 4, 5, 6, 7, 8, 0}, 0, 0}; state goal = { {4, 1, 5, 0, 3, 2, 7, 8, 6}, // puzzle 0, // depth 0}; // evaluation std::priority_queue <state, std::vector<state>, std::greater<state> > open; std::stack<state> open2; std::vector<state> closed; int count = 0; int max = 0; bool IsFinished(state s) { for (int i = 0; i < 8; i++) { if (s.puzzle[i] != goal.puzzle[i]) { return false; } } return true; } int ManhattanOne(int n, int place) { if (goal.puzzle[n] == 0) { return 0; } int q, r; q = abs(place / 3 - n / 3); r = abs(place % 3 - n % 3); return q + r; } int manhattan(state s) { int eval = 0; std::map<int, int> goalplace; for (int i = 0; i < 9; i++) { goalplace[goal.puzzle[i]] = i; } for (int i = 0; i < 9; i++) { eval += ManhattanOne(goalplace[s.puzzle[i]], i); } return eval; } int wrong(state s) { int eval = 0; for (int i = 0; i < 9; i++) { if (s.puzzle[i] != 0 and s.puzzle[i] != goal.puzzle[i]) { eval++; } } return eval; } void PrintState(state s) { std::cout << '|' << s.puzzle[0] << '|' << s.puzzle[1] << '|' << s.puzzle[2] << '|' << ' ' << count << std::endl; std::cout << '|' << s.puzzle[3] << '|' << s.puzzle[4] << '|' << s.puzzle[5] << '|' << " f(n) = " << s.evaluation << std::endl; std::cout << '|' << s.puzzle[6] << '|' << s.puzzle[7] << '|' << s.puzzle[8] << '|' << " g(n) = " << s.depth << std::endl << std::endl; return; } bool IsSamePuzzle(state s1, state s2) { for (int i = 0; i < 9; i++) { if (s1.puzzle[i] != s2.puzzle[i]) { return false; } } return true; } bool InClosed(state s) { for (int i = 0; i < closed.size(); i++) { if (IsSamePuzzle(s, closed[i])) { return true; } } return false; } void AStar(std::function<int(state)> fun) { if (open.empty()) { std::cerr << "Search have mistakenly stopped!" << std::endl; } if (max < open.size() + closed.size()) { max = open.size() + closed.size(); } count++; state now = open.top(); open.pop(); closed.push_back(now); PrintState(now); if (IsFinished(now)) { std::cout << "Finished!" << std::endl; return; } state s = now; int zero; for (int i = 0; i < 9; i++) { if (now.puzzle[i] == 0) { zero = i; break; } } if (zero - 3 >= 0) { std::swap(s.puzzle[zero - 3], s.puzzle[zero]); if (not InClosed(s)) { s.depth++; s.evaluation = fun(s) + s.depth; open.push(s); } s = now; } if (zero % 3 != 0) { std::swap(s.puzzle[zero - 1], s.puzzle[zero]); if (not InClosed(s)) { s.depth++; s.evaluation = fun(s) + s.depth; open.push(s); } s = now; } if (zero % 3 != 2) { std::swap(s.puzzle[zero + 1], s.puzzle[zero]); if (not InClosed(s)) { s.depth++; s.evaluation = fun(s) + s.depth; open.push(s); } s = now; } if (zero + 3 < 9) { std::swap(s.puzzle[zero + 3], s.puzzle[zero]); if (not InClosed(s)) { s.depth++; s.evaluation = fun(s) + s.depth; open.push(s); } } AStar(fun); return; } void IDAStar_rep(std::function<int(state)> fun, int c) { if (open2.empty()) { std::cout << c << " roop end" << std::endl; c++; open2.push(start); closed.clear(); IDAStar_rep(fun, c); return; } if (max < open2.size() + closed.size()) { max = open2.size() + closed.size(); } state now = open2.top(); closed.push_back(now); open2.pop(); count++; if (IsFinished(now)) { PrintState(now); std::cout << "Finished!" << std::endl; return; } state s = now; PrintState(now); int zero; for (int i = 0; i < 9; i++) { if (now.puzzle[i] == 0) { zero = i; break; } } if (zero - 3 >= 0) { std::swap(s.puzzle[zero - 3], s.puzzle[zero]); if (not InClosed(s)) { s.depth++; s.evaluation = fun(s) + s.depth; if (s.evaluation <= c) { open2.push(s); } } s = now; } if (zero % 3 != 0) { std::swap(s.puzzle[zero - 1], s.puzzle[zero]); if (not InClosed(s)) { s.depth++; s.evaluation = fun(s) + s.depth; if (s.evaluation <= c) { open2.push(s); } } s = now; } if (zero % 3 != 2) { std::swap(s.puzzle[zero + 1], s.puzzle[zero]); if (not InClosed(s)) { s.depth++; s.evaluation = fun(s) + s.depth; if (s.evaluation <= c) { open2.push(s); } } s = now; } if (zero + 3 < 9) { std::swap(s.puzzle[zero + 3], s.puzzle[zero]); if (not InClosed(s)) { s.depth++; s.evaluation = fun(s) + s.depth; if (s.evaluation <= c) { open2.push(s); } } s = now; } IDAStar_rep(fun, c); return; } void IDAStar(std::function<int(state)> fun) { IDAStar_rep(fun, open2.top().evaluation); return; } int main(int argc, char *argv[]) { if(argc != 2) { std::cerr << "Usage: <Executable filename> <type number>" << std::endl; exit(0); } std::function< int(state) > fun; std::function< void(std::function< int(state) >) > alg; switch (*argv[1]) { case '1': fun = wrong; alg = AStar; break; case '2': fun = manhattan; alg = AStar; break; case '3': fun = wrong; alg = IDAStar; break; case '4': fun = manhattan; alg = IDAStar; break; } start.evaluation = fun(start); open.push(start); open2.push(start); alg(fun); std::cout << "Most saved nodes: " << max << std::endl; return 0; }
結果は、以下のとおり
1のとき、28手、メモリに保存したノードの数52
2のとき、21手、メモリに保存したノードの数35
3のとき、33手、メモリに保存したノードの数17
4のとき、10手、メモリに保存したノードの数12
IDA*つえー
行列の固有値計算のJacobi法をpythonで実装した
数値計算ライブラリのnumpyはほんとに便利。
import numpy as np def jacobi(A,N,check): B = np.fabs(A - np.diag(list(np.diag(A)))) nondiagmax = np.max(B) while nondiagmax > check: k = int(np.argmax(B) / 3) m = np.argmax(B) % 3 cos2phi = np.fabs(A[k,k] - A[m,m]) / \ np.sqrt(4.0 * A[k,m]**2 + (A[k,k] - A[m,m])**2) cosphi = np.sqrt((1.0 + cos2phi) / 2.0) sinphi = np.sign(-A[k,m] * (A[k,k] - A[m,m])) * \ np.sqrt((1.0 - cos2phi) / 2.0) P = np.matrix(np.identity(N)) P[k,k] = cosphi P[k,m] = sinphi P[m,k] = -sinphi P[m,m] = cosphi A = ((P.T).dot(A)).dot(P) B = np.fabs(A - np.diag(list(np.diag(A)))) nondiagmax = np.max(B) print(A) print(np.diag(A)) if __name__ == "__main__": EPS = 1e-8 N = 3 A = np.matrix([[3.0,0.01,0.1],[0.01,2.0,0.1],[0.1,0.1,1.0]]) print(A) jacobi(A,N,EPS)
結果より、固有値は、[ 3.00521156 2.00950971 0.98527872]
MacOS X El CapitanでC言語のOpenMPによる並列計算を行う方法
並列計算とは、簡単にいえば、同時進行できる計算を複数のCPUのコアに同時に計算させてしまおうと言う試みである。
gccでは、新しいバージョンでしかOpenMPがサポートされていないため、homebrewで最新版のgccをインストールする。
$ brew install homebrew/versions/gcc6
homebrewによってインストールしたgccは、gcc-6という名前になっているので、gccと書いてコンパイルできるようにシンボリックリンクを作成する。
$ sudo ln -sf /usr/local/bin/gcc-6 /usr/local/bin/gcc
ついでにg++も
$ sudo ln -sf /usr/local/bin/g++-6 /usr/local/bin/g++
サンプルコードをコンパイル・実行して、Hello, World!が複数表示されればよい。
#include <stdio.h> #include <omp.h> int main() { #pragma omp parallel { printf("hello world from %d of %d\n", omp_get_thread_num(), omp_get_num_threads()); } return 0; }
$ gcc -fopenmp -o hello hello.c
$ ./hello
円周率は有理数です。
んな訳あるかい!!!
ということで、どうもよねすけです。今日はエイプリルフールなのでこんな調子乗ったタイトルにしてみました。
円周率が無理数、超越数であることは広く知られていることです。
が、その証明ってみんなあんまり知らないんじゃないかなあ、と思ったので今回は円周率の無理数性の証明を書きたいと思います。(時間の都合で途中式をずいぶんと省略してあるので良かったら自分で実際に手を動かして考えてみてください。)
なお、今回の証明には以下の本を参考にしました。この本、個人的にはめっちゃ好きな本なので良かったら手に取って見てください。
- 作者: M.アイグナー,G.M.ツィーグラー,Martin Aigner,G¨unter M. Ziegler,蟹江幸博
- 出版社/メーカー: シュプリンガー・フェアラーク東京
- 発売日: 2002/12
- メディア: 単行本
- クリック: 10回
- この商品を含むブログ (7件) を見る
円周率をとおく。が無理数であることを示す。そうすればが無理数であることもわかる。
証明するにあたって以下の補題を用いる。
補題
あるを固定し、
とおく。
- 関数はという形の多項式で、係数は整数である。
- に対して、である。
- すべてのに対して、微係数とは整数である。
このとき、ある整数に対して、と仮定する。多項式
は、を満たす。
補題の3つ目から、は整数である。
となり、
は整数となる。さらに、境界を除けば正の関数の積分として定義されているので、は正。しかし、十分に大きなを持ってきてとなるようにすると、補題の2つ目から
となる。これはが正の整数であることに矛盾。よっては無理数。
これより円周率は無理数であることが示された。
なんだか、きつねにつままれたような証明ですね~。
最後に。
今日から新年度ですね。進級した方は進級おめでとうございます。進学が決まった方、もっとおめでとうございます!!!これからの新生活、頑張っていきましょう!!!
それでは。