導入としては、@ITが分かりやすい
5分で絶対に分かる:5分で絶対に分かるPCI DSS (1/6) - @IT
ポイントは - クレジットカード会社以外にも提供可能なセキュリティ要件である - システム面だけでなく、運用面の要件もある
導入としては、@ITが分かりやすい
5分で絶対に分かる:5分で絶対に分かるPCI DSS (1/6) - @IT
ポイントは - クレジットカード会社以外にも提供可能なセキュリティ要件である - システム面だけでなく、運用面の要件もある
「数値を3桁毎に",“で区切る」場合や「日付をYY/MM/DD形式に変換する」場合、 正規表現 + jquery.template で対応していましたが、 Number.prototype.toLocaleString() や、Date.prototype.toLocaleString() があるらしいので、写経。
※ただし、safariで未対応だったり、ie / chrome / firefox で出力結果が 異なる等の注意は必要です。
最初に、developer.mozilla.org にある仕様を読むことをお勧めすます
JavaScriptのtoLocaleStringメソッドについて調べてみた | while(isプログラマ)
<!DOCTYPE html> <html lang="ja"> <head> <meta charset="utf-8"> </head> <body> <button onClick="num_to_local_string();">Number.toLocaleString()</button> <button onClick="date_to_local_string();">Date.toLocaleString()</button> <br> </body> <script> function num_to_local_string(){ //通貨形式 alert( (1234.56789).toLocaleString("ja-JP", {style: 'currency', currency: 'JPY' }) ); //数値形式、小数第5位で丸め alert( (1234.56789).toLocaleString("ja-JP", {style: 'decimal', minimumFractionDigits:4}) ); //パーセント形式 alert( (0.015).toLocaleString("ja-JP", {style: 'percent'}) ); } function date_to_local_string(){ var date = new Date(); alert( date.toLocaleString("ja-JP", {hour12:true, //AM/PMを表示 "year":"numeric", //2桁で表示 "month":"2-digit", //曜日を表示 "day": "2-digit", "weekday":"short", "hour": "2-digit", "minute":"2-digit", "second":"2-digit", }) ); } </script> </html>
「A*」を聞いたことはありますが、実装したことはない為、写経。
今回の写経で、2次元の最短経路探索は理解できた気がするので、次は3次元? 立体? 経路探索に発展させたい。
A*アルゴリズムは1968年に発表された為、インターネット上に多くの情報がありますが、 私には次のurlが分かりやすかった。
https://ja.wikipedia.org/wiki/A*
以下は、perlで記載していますが、申し訳ない程、pashango_p さんのsrcのまんま
#!/usr/local/bin/perl use strict; use warnings; use utf8; use List::Util; use Data::Dumper; my $MAP_DATA = ['OOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOO', 'OS O O O O O', 'O O O O O O O OOOO GO', 'O O O O OOOO O O OOOO', 'OO OOOOOOOOOOOOOOO O O O O', 'O O O O O', 'O OOO O O OOOOOOOOO O', 'O OO O OOOO O O OO O', 'O O O O O O O O', 'O OOO O O O O O', 'O O O O O', 'OOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOO']; my $MAP_WIDTH = List::Util::max(map { length($_) } @$MAP_DATA); my $MAP_HEIGHT = scalar(@$MAP_DATA); my $START_POS = []; my $GOAL_POS = []; my $MAX_SEEK_LOOP = 5000; main(); sub main { #スタート位置とゴール位置を設定 my $y = 0; for my $map_line ( @$MAP_DATA ){ my $str_index = index($map_line,"S"); if( $str_index >=0 ){ $START_POS = [$str_index,$y]; } $str_index = index($map_line,"G"); if( $str_index >=0 ){ $GOAL_POS = [$str_index,$y]; } $y++; } #OpenリストとCloseリストを設定 my $open_list = NodeList->new(); my $close_list = NodeList->new(); my $start_node = Node->new( @$START_POS ); $start_node->{fs} = $start_node->{hs}; $open_list->append($start_node); my $i = 0; my $end_node; while(1){ if( $i++ > $MAX_SEEK_LOOP){ #もしもの為のfail safe print "You reached MAX_SEEK_LOOP = $MAX_SEEK_LOOP \n"; return; } #Openリストが空になったら解なし if( scalar(@{$open_list->{node_list}}) == 0 ){ print "There is no route until reaching a goal.\n"; return; } #Openリストからf*が最少のノードnを取得 my ($n)= sort {$a->{fs}<=>$b->{fs}} @{$open_list->{node_list}}; $open_list->remove($n); $close_list->append($n); if( $n->is_goal() ){ #最小ノードがゴールだったら終了 $end_node = $n; last; } #f*() = g*() + h*() -> g*() = f*() - h*() my $n_gs = $n->{fs} - $n->{hs}; #ノードnの移動可能方向のノードを調べる for my $v ([1,0],[-1,0],[0,1],[0,-1]){ my $x = $n->{pos}->[0] + $v->[0]; my $y = $n->{pos}->[1] + $v->[1]; #マップが範囲外または壁(O)の場合はcontinue if($y< 0 or $MAP_HEIGHT < $y or $x< 0 or $MAP_WIDTH < $x or substr($MAP_DATA->[$y],$x,1) eq 'O'){ next; } #移動先のノードがOpen,Closeのどちらのリストに #格納されているか、または新規ノードなのかを調べる my $m = $open_list->find($x,$y); my $dist = ($n->{pos}->[0] - $x)**2 + ($n->{pos}->[1] - $y)**2; if ($m){ #移動先のノードがOpenリストに格納されていた場合、 #より小さいf*ならばノードmのf*を更新し、親を書き換え if( $m->{fs} > ($n_gs + $m->{hs} + $dist)){ $m->{fs} = $n_gs + $m->{hs} + $dist; $m->{parent_node} = $n; } } else { $m = $close_list->find($x,$y); if($m){ #移動先のノードがCloseリストに格納されていた場合、 #より小さいf*ならばノードmのf*を更新し、親を書き換え #かつ、Openリストに移動する if($m->{fs} > $n_gs + $m->{hs} + $dist){ $m->{fs} = $n_gs + $m->{hs} + $dist; $m->{parent_node} = $n; $open_list->append($m); $close_list->remove($m); } } else { #新規ノードならばOpenリストにノードに追加 $m = Node->new($x,$y); $m->{fs} = $n_gs + $m->{hs} + $dist; $m->{parent_node} = $n; $open_list->append($m); } } } } #endノードから親を辿っていくと、最短ルートを示す my $m = []; for my $line ( @$MAP_DATA ){ my @cols = split(//, $line); push(@$m,\@cols); } my $n = $end_node->{parent_node}; while(1){ last if not $n->{parent_node}; $m->[$n->{pos}->[1]]->[$n->{pos}->[0]] = '+'; $n = $n->{parent_node}; } for my $cols ( @$m ){ print join('', @$cols),"\n"; } } package Node; ######## sub new { my ($class, $x, $y) = @_; my $self = {}; $self = bless $self, $class; $self->{pos} = [$x, $y]; $self->{hs} = ($x-$GOAL_POS->[0])**2 + ($y-$GOAL_POS->[1])**2; $self->{fs} = 0; ## なんで? $self->{owner_list} = []; $self->{parent_node} = ''; return $self; } sub is_goal { my ($self) = @_; if($self->{pos}->[0] == $GOAL_POS->[0] and $self->{pos}->[1] == $GOAL_POS->[1]){ return $self; # means true } return; # means false } package NodeList; ######## use Data::Dumper; sub new { my ($class) = @_; my $self = {}; $self = bless $self, $class; $self->{node_list} = []; return $self; } sub append { my ($self, $node_obj) = @_; if( defined($node_obj) and ref($node_obj) eq "Node" ){ push( @{$self->{node_list}}, $node_obj); return; } } sub find { my ($self, $x, $y) = @_; for my $node_obj ( @{$self->{node_list}} ){ if($node_obj->{pos}->[0] == $x and $node_obj->{pos}->[1] == $y ){ return $node_obj; } } return; } sub remove { my ($self, $target_node_obj) = @_; my $i = 0; for my $node_obj ( @{$self->{node_list}} ){ if($node_obj->{pos}->[0] == $target_node_obj->{pos}->[0] and $node_obj->{pos}->[1] == $target_node_obj->{pos}->[1] ){ splice(@{$self->{node_list}},$i,1); return $self; } $i++; } return; } 1; __END__
↑こう書くと、↓こう動きます
$ ./a_star.pl OOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOO OS+ O O O O +++++++O O + O O O O O +++++++O +OOOO GO O + O O O +OOOO +O +O OOOO OO+OOOOOOOOOOOOOOO +O +O +O O O ++++++++++++ O +O +O ++++++ O O OOO + O +O +OOOOOOOOO+ O O OO O +OOOO +O +O +++++OO+ O O O O +++++++O +O +O +O++ O O OOO O O ++++O +O+ O O O O O +++ O OOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOO
先日の FSM / ステートパターン のエントリで扱った例を behavior tree で実装しようと考えていましたが、 behavior treeで扱うには、その例が簡単すぎたみたい。
なので、 behavior tree の簡単なまとめだけを記載しておきます。
決定木( decision tree )と異なり、 Sequence(AND)やSelector(OR)等の多様なノードがある点で、 behavior tree の方が多機能ですね。
unreal engineでは、behavior tree のguiなエディタがあるみたいですけど、 同様の問題はprologでも解けそうですね。
www.slideshare.net
操舵行動って、オライリーの「実例で学ぶゲームAIプログラミング」に記載されていたものですね。
p5.js は、利用したことありませんが、分かりやすい!!
ちなみに「実例で学ぶゲームAIプログラミング」では、操舵行動の中で - 探索(Seek) - 逃走(Flee) - 到着(Arrive) - 追跡(Pursuit) - 逃避(Evade) - 徘徊(Wander) - 障害物回避(ObstancleAvoidance) - 壁回避(WallAvoidance) - 介入(Interpose) - 隠身(Hide) - 経路追従(FollowPath) - オフセット追跡(OffsetPursuit) を具体的なコード付で紹介しています
$dbh->{AutoCommit} と紹介しているところもありますが…
http://search.cpan.org/perldoc?DBI
↑こちらに記載されている通り、基本は、 $dbh->begin_work, $dbh->commit, $dbh->rollback 。
↓gihyo.jpにも同様に記載されています。
ただし、 、 、t は媒介変数、
ただし、 、 、s , t は媒介変数、 、
先程のエントリにも記載していますが、 「寄与率」は回帰分析にもあり、それを混同していたので、再整理。
ここで、 は実測値で、 は実測値の総平均。
ここで、 はモデル値(予測値)。
これらを用いて、寄与率(=決定係数)は次のように定義されています。
また、上記の「回帰による平方和」を利用し、次のように表すことが可能です。
相関係数であるRと、寄与率(=決定係数)の間に2乗の関係があることが理由のようです。
先程、記載した寄与率は説明変数が増える程、上昇するらしい。 (実際の説明力の有無に関らず、寄与率が増加…)
そこで「自由度」を考慮し修正した「自由度修正済み寄与率」があるらしい。(以下)
ただし、 n=データ数、残差の自由度 = データ数(n) - 説明変数の数 - 1
「全体の"変化"に対する」がポイントで、 年度の総売上額に対する部門Aの寄与度/寄与率は次式で算出できます。
例として、年度の総売上額に対する部門A~Cの寄与度/寄与率を算出します。
年度 | 部門A | 部門B | 部門C | 総額 |
---|---|---|---|---|
2011 | 500 | 300 | 200 | 1000 |
2012 | 600 | 300 | 400 | 1300 |
2013 | 800 | 500 | 300 | 1600 |
2014 | 1000 | 600 | 400 | 2000 |
まず、上記の表から年度毎の変化を整理します
年度<-前年 | 部門A | 部門B | 部門C | 総額 |
---|---|---|---|---|
2012<-2011 | 100 | 0 | 200 | 300 |
2013<-2012 | 200 | 200 | -100 | 300 |
2014<-2013 | 200 | 100 | 100 | 400 |
次に寄与度を算出しますが、 例えば、部門Aの2012年寄与度は「(600-500)/1000 = 0.1」です。 他部門や他年度も同様に寄与度を計算すると次のようになります。
年度<-前年 | 部門A | 部門B | 部門C |
---|---|---|---|
2012<-2011 | 0.10 | 0.0 | 0.20 |
2013<-2012 | 0.15 | 0.15 | -0.08 |
2014<-2013 | 0.13 | 0.06 | 0.06 |
まず、総額成長率( (t年売上 - (t-1)年売上) / (t-1)年売上 )を算出します。
年度<-前年 | 総額成長率 |
---|---|
2012<-2011 | 0.30 |
2013<-2012 | 0.23 |
2014<-2013 | 0.25 |
寄与率は「部門の寄与度」と「総額の成長率」により算出され、 例えば部門Aの2012年寄与率は、0.1x0.3=0.03となります。 他部門や他年度も同様に寄与率を計算すると次のようになります。
年度<-前年 | 部門A | 部門B | 部門C |
---|---|---|---|
2012<-2011 | 0.03 | 0.0 | 0.06 |
2013<-2012 | 0.03 | 0.03 | -0.02 |
2014<-2013 | 0.03 | 0.02 | 0.02 |
主成分分析に利用する為、おさらい。
その他、シュレーディンガー方程式(量子力学)、マルコフ連鎖、グラフ理論 でも利用されるらしいが、対角行列に変換できることに関係するのかな?、まっ、今回は単なるおさらいなので、気にしませんが
n次正方行列Aに対し、 が成立するとき、定数:λを「固有値」、 ベクトル を「固有ベクトル」
次に λ = 4 , 9 に対応するそれぞれの固有ベクトルを求める。
まずは「λ = 4」の場合
よって、「λ = 4」に対応する固有ベクトルは ※ただし、tは0以外の任意数。
次に「λ = 9」の場合
よって、「λ = 9」に対応する固有ベクトルは ※ただし、tは0以外の任意数。