45
再帰、漸化式、差分方程式と アルゴリズム OGATA Tetsuji (@xtetsuji) 2015/12/03 Gaiax グループエンジニア勉強会 #20

再帰、漸化式、差分方程式とアルゴリズム Gx#20

  • Upload
    -

  • View
    911

  • Download
    0

Embed Size (px)

Citation preview

Page 1: 再帰、漸化式、差分方程式とアルゴリズム   Gx#20

再帰、漸化式、差分方程式と アルゴリズム

OGATA Tetsuji (@xtetsuji) 2015/12/03 Gaiaxグループエンジニア勉強会 #20

Page 2: 再帰、漸化式、差分方程式とアルゴリズム   Gx#20

自己紹介

• 尾形 鉄次 (OGATA Tetsuji) a.k.a. @xtetsuji

• Blog: http://post.tetsuji.jp/

• mod_perl 芸人

• RND インフラチーム (2015/06/10~)

• 社内勉強会初デビュー

Page 3: 再帰、漸化式、差分方程式とアルゴリズム   Gx#20

インフラチーム?• Perl は社会人になってから10年ほど書いているけれど、もともとは大学院時代に数学科のメールサーバを作ってくれと頼まれたのがIT系の始まり→インフラだ

• 学生時代はさほどプログラミングできなかったし、興味も無かったけれど、なんとかIT業界で生きてます

• 学生時代はメールとLaTeXの生活で、逆に数学とコンピュータが結びついていなかったのを最近リハビリ中

Page 4: 再帰、漸化式、差分方程式とアルゴリズム   Gx#20

最近の社内のアウトプットで 結構印象に残ったもの

Page 5: 再帰、漸化式、差分方程式とアルゴリズム   Gx#20
Page 6: 再帰、漸化式、差分方程式とアルゴリズム   Gx#20
Page 7: 再帰、漸化式、差分方程式とアルゴリズム   Gx#20

単純だけど奥が深い数学

• フィボナッチ数列

• カプレカ数

Page 8: 再帰、漸化式、差分方程式とアルゴリズム   Gx#20

どっちも再帰的

• フィボナッチ数列もカプレカ数も、手続きがあってアルゴリズム感満点な割にシンプルで良い

• その他の古典的なものはハノイの塔とか

• フィボナッチ数列は高校数学では漸化式と言ったりする

• ときどき差分方程式とも呼ばれたりして、微分方程式の数値解析などにも顔を出したり

Page 9: 再帰、漸化式、差分方程式とアルゴリズム   Gx#20

Fn+2 = Fn+1 + Fn

n 2 N, F1 = F2 = 1

Page 10: 再帰、漸化式、差分方程式とアルゴリズム   Gx#20

#!/usr/bin/perl

use strict;use warnings;

sub fib { my $n = shift; if ( $n <= 0 ) { die; } if ( $n == 1 || $n == 2 ) { return 1; } else { return fib($n-1) + fib($n-2); }}

print fib(7); # 13

Page 11: 再帰、漸化式、差分方程式とアルゴリズム   Gx#20

再帰呼び出しの良い教材

Page 12: 再帰、漸化式、差分方程式とアルゴリズム   Gx#20

じゃ、100項目はいくつかな?

Page 13: 再帰、漸化式、差分方程式とアルゴリズム   Gx#20

あれ?結果が返ってこない!

Page 14: 再帰、漸化式、差分方程式とアルゴリズム   Gx#20

手元では、50項目でも 10分で処理が終わらない

Page 15: 再帰、漸化式、差分方程式とアルゴリズム   Gx#20

#!/usr/bin/perl

use strict;use warnings;

my $n = shift || die "input number";my $call_count = 0;

sub fib { $call_count++; my $n = shift; if ( $n <= 0 ) { die; } print " " x ($n - 1) . ".\n"; if ( $n == 1 || $n == 2 ) { return 1; } else { return fib($n-1) + fib($n-2); }}

print fib($n) . "\n";print "call_count=$call_count\n";

Page 16: 再帰、漸化式、差分方程式とアルゴリズム   Gx#20

関数の呼び出し回数が多い

• $call_count すなわち fib の呼び出し回数が多い

• $n に対応する $call_count の増加量は元のフィボナッチ数列と同程度に巨大になる

• call_count($n+2) = call_count($n+1)+call_count($n)+1

Page 17: 再帰、漸化式、差分方程式とアルゴリズム   Gx#20

再帰関数の呼び出し回数

• 再帰の実装はシンプルになっても、呼び出し回数が甚大になるとツラい

• 今回は回数だけが問題だけれども、再帰が深すぎると deep recursion で例外になることも

• 今回はサブルーチンに副作用がないまさに関数なわけで、無駄だらけじゃない?

Page 18: 再帰、漸化式、差分方程式とアルゴリズム   Gx#20

メモ化の手法

• 他の条件によらず x に対して y = func(x) が固定なら、func(x) の計算結果をキャッシュすればいい

• このことをメモ化 (memoize) という

• 関数型言語的に言えば、参照透過性とかナントカ

Page 19: 再帰、漸化式、差分方程式とアルゴリズム   Gx#20

#!/usr/bin/perl

use strict;use warnings;

use Memoize;memoize('fib');

my $n = shift || die "input number";my $call_count = 0;

sub fib { $call_count++; my $n = shift; die if $n <= 0; print " " x ($n - 1). ".\n"; if ( $n == 1 || $n == 2 ) { return 1; } else { return fib($n-1) + fib($n-2); }}

print fib($n) . "\n";print "call_count=$call_count\n";

Page 20: 再帰、漸化式、差分方程式とアルゴリズム   Gx#20

速~いヽ(=´▽`=)ノ

Page 21: 再帰、漸化式、差分方程式とアルゴリズム   Gx#20

Memoizeモジュール

• 参照透過性のある関数であれば、メモリと相談の上で Memoize をすると、一度計算した引数で関数を二度目以降実行すると、キャッシュの結果を返すと効率的

• Memoize モジュールの適用が透過的なのでキャッシュ変数を用意したりしなくてよいのが便利

Page 22: 再帰、漸化式、差分方程式とアルゴリズム   Gx#20

Function.prototype.memoized = function(key){ this._values = this._values || {}; return this._values[key] !== undefined ? this._values[key] : this._values[key] = this.apply(this, arguments);};

Function.prototype.memoize = function(){ var fn = this; return function(){ return fn.memoized.apply(fn, arguments); };};

// 用例var fib = (function(n) { if ( n == 1 || n == 2 ) return 1; return fib(n-1) + fib(n-2);}).memoize();

console.log(fib(100));

JavaScript Ninja の極意 (ジョン・レシグ著) より

Page 23: 再帰、漸化式、差分方程式とアルゴリズム   Gx#20

一発で導出する式はないの?

• どんな巨大な n でも一発で fib(n) が求められる式?

• 再帰などの反復手続きによらない閉じた式または一般項

• 母関数論などを使うと導けます(詳細割愛)

Page 24: 再帰、漸化式、差分方程式とアルゴリズム   Gx#20

Fn =1p5

( 1 +

p5

2

!n

� 1�

p5

2

!n)

Page 25: 再帰、漸化式、差分方程式とアルゴリズム   Gx#20

さらに

• 小数点以下の誤差を丸めるようにすれば、以下の公式まで簡略化するらしい(Wikipediaより)

Fn =

$1p5

1 +

p5

2

!n

+1

2

%

Page 26: 再帰、漸化式、差分方程式とアルゴリズム   Gx#20

#!/usr/bin/perl

use strict;use warnings;

use Benchmark qw(:all);use Memoize;memoize('fib_r');

sub fib_r { my $n = shift; if ( $n == 1 || $n == 2 ) { return 1; } return fib_r($n-1)+fib_r($n-2);}

sub fib_t { my $n = shift; return int(sqrt(5)*((1+sqrt(5))/2)**$n + 1/2);}

timethese(1_000_000, { recursion => sub { fib_r(100); }, theorem => sub { fib_t(100); },});

Page 27: 再帰、漸化式、差分方程式とアルゴリズム   Gx#20

$ perl bench-fib.pl Benchmark: timing 1000000 iterations of recursion, theorem... recursion: 3 wallclock secs ( 2.73 usr + 0.01 sys = 2.74 CPU) @ 364963.50/s (n=1000000) theorem: 1 wallclock secs ( 0.42 usr + 0.00 sys = 0.42 CPU) @ 2380952.38/s (n=1000000)

Page 28: 再帰、漸化式、差分方程式とアルゴリズム   Gx#20

速~いヽ(=´▽`=)ノ

Page 29: 再帰、漸化式、差分方程式とアルゴリズム   Gx#20

一般項、最高~

Page 30: 再帰、漸化式、差分方程式とアルゴリズム   Gx#20

カプレカ数

Page 31: 再帰、漸化式、差分方程式とアルゴリズム   Gx#20

カプレカ数:定義1• 正の整数を2乗し、それが偶数桁 2n 桁である場合は先頭 n 桁と末尾 n 桁に分け、奇数桁 2n + 1 桁である場合は先頭 n 桁と末尾 n + 1 桁に分けて和を取る。この操作によって元の値に等しくなる数をカプレカ数と呼ぶ。

• 例えば、2972 = 88209 であるが、これを前の2桁 88 と後ろの3桁 209 に分けて足すと、88 + 209 = 297 となるので、297 はカプレカ数である。

• この定義でのカプレカ数は、小さな順に

• 1, 9, 45, 55, 99, 297, 703, 999, 2223, 2728, 4879, 4950, 5050, 5292, …(オンライン整数列大辞典の数列 A006886)

• である。(Wikipediaより)

Page 32: 再帰、漸化式、差分方程式とアルゴリズム   Gx#20

文字列操作と数値操作

• 「偶数桁 2n 桁である場合は先頭 n 桁と末尾 n 桁に分け、奇数桁 2n + 1 桁である場合は先頭 n 桁と末尾 n + 1 桁に分けて和を取る」

• 文字列操作なら length と substr などを使う

• 数値操作なら、桁数を求める関数や床関数を使っていく

Page 33: 再帰、漸化式、差分方程式とアルゴリズム   Gx#20

数値操作の役立つ君

• 桁数関数:

• 上n桁を求める関数:

• 下n桁を求める関数:

keta(x) = blog10 xc+ 1

An

(x) =j

x

10keta(x)�n

k

Bn

(x) = x� 10nAketa(x)�n

(x)

Page 34: 再帰、漸化式、差分方程式とアルゴリズム   Gx#20

数値操作の役立つ君

• これだけでも文字列操作から離れられる

• とはいえ明示的な条件分岐・制御構造は必要

• 条件分岐・制御構造も「閉じた式」にできない?

• 面白そうなのでやってみる

Page 35: 再帰、漸化式、差分方程式とアルゴリズム   Gx#20

数値操作の役立つ君

• 偶数なら1、奇数なら0:

• 奇数なら1、偶数なら0:

• 公式:

even(x) =

���cos⇡x

2

���

odd(x) =

���sin⇡x

2

���

even(x) + odd(x) = 1

Page 36: 再帰、漸化式、差分方程式とアルゴリズム   Gx#20

数値操作の役立つ君

• 定義1を書き換えるとこうなる

• xの桁が2nの場合

• xの桁が2n+1の場合

• 先ほどの even と odd 関数があるので、これもさらにまとめられるぞ!

An(x2) + Bn+1(x

2) = x

An(x2) + Bn(x

2) = x

Page 37: 再帰、漸化式、差分方程式とアルゴリズム   Gx#20

定義1の閉じた式を求めて

(Aketa(x2)(x2) + Bketa(x2)(x

2))even(x

2)

+ (A keta(x2)�12

(x

2) + B keta(x2)�1

2 +1(x

2))odd(x

2)

= x

Page 38: 再帰、漸化式、差分方程式とアルゴリズム   Gx#20

ちょっとボリュームある…

Page 39: 再帰、漸化式、差分方程式とアルゴリズム   Gx#20

定義1の閉じた式を求めて

• この方程式を満たす x を求めれば定義1のカプレカ数が求まる…のか?

• さらに手元で計算したけれど、余白がどんどん無くなる

• 一般項が求まらない、または非常に難しい形になる場合もあるので、不必要なら妥協する場合もある

• 面白いから計算練習として計算するというのも良い

Page 40: 再帰、漸化式、差分方程式とアルゴリズム   Gx#20

高校数学が分からない?

• 今回の漸化式や数列は高校数学の範囲

• 大学レベルの数学の勉強会はちらほらあるものの、高校数学をやり直せる勉強会が今まで無かった

• 今まで?

Page 41: 再帰、漸化式、差分方程式とアルゴリズム   Gx#20

ITエンジニアのための 高校数学勉強会 #1

http://highschoolmath.connpass.com/event/23792/

Page 42: 再帰、漸化式、差分方程式とアルゴリズム   Gx#20

高校数学をやり直す

• 今まで構想を温めていた高校数学をやり直す勉強会

• 第1回目は12月9日、会場はモバイルファクトリーさん

• 数学 I II A B を丁寧にかつ俯瞰して扱います

• 理系の数学である数学IIIと数学活用の取り扱いも検討中

• 興味ありましたらぜひお越しください

Page 43: 再帰、漸化式、差分方程式とアルゴリズム   Gx#20

モバイルファクトリーさんを 会場に選んだ理由?

Page 44: 再帰、漸化式、差分方程式とアルゴリズム   Gx#20

ホワイトボードが 超書きやすいんですよ!

Page 45: 再帰、漸化式、差分方程式とアルゴリズム   Gx#20

🍻おしまい🍣