//--------------------------------------------------------------------------------
//少ない知識ですが、恩返しと思いページを立ち上げています。
//加筆修正、大歓迎です。  markovchainmontecarlo(2015/09)
//--------------------------------------------------------------------------------

&color(red){&size(30){並列計算(snowfall)};};~
~
マルチコアが主流となってきているので、並列計算のパッケージである「snowfall」を紹介します。~
なお、特に断りが無い場合はSocketクラスターを使用しています。~
また、画像は縮小表示しています。クリックすると画像のみがオリジナルサイズで表示されます。~
~
&color(red){&size(40){現在編集中&br;調査中の内容があるため&br;信用に値しない内容も多分に含まれています。};};~
----
&color(red){&size(20){目次};};~
#contents
----
*並列計算で計算速度は向上するか? [#ze3e7311]
**並列計算のイメージ [#l002ea0d]
#ref(./並列概念.jpg,50%);~
並列化できる割合によって、理論上の限界が変わってきます。~
([[アムダールの法則:https://ja.wikipedia.org/wiki/%E3%82%A2%E3%83%A0%E3%83%80%E3%83%BC%E3%83%AB%E3%81%AE%E6%B3%95%E5%89%87]]を参照)~
~
なお、計算負荷の不均一性やデータ入出力負荷が理由で、&size(20){&color(red){''かえって遅くなる''};};場合もあります。~
~
並列計算は計算速度向上の一つの手段にすぎません。~
計算速度向上の手段はいくつもありますので、適切な方法を用いてください。~
[[CRAN Task View: High-Performance and Parallel Computing with R:https://cran.r-project.org/web/views/HighPerformanceComputing.html]]
**どのような計算が並列化できるか [#rb82070b]
基本的にapply familyは全て並列化可能です。~
詳細な条件としては、「計算の順序を入れ替えても計算結果が同じである」事になります。~
~
apply familyも内部ではforを使用しているので、並列化できるfor・並列化できないforが存在します。
-並列化できないforの例
--ケース1:依存関係がある。~
以下の例は、ひとつ前の数値に対して、関数hogeを適用するため並列化が出来ません。~
順序よくx[1] → x[2] → x[3] → x[4] → x[5] と実行しないと正しい計算ができません。
 for(i in 1:5){
     x[i] <- hoge(x[i - 1])
 }
これは、マルコフ連鎖にも言える事であり、マルコフ連鎖の生成スピードを上げようとするならばRcppを使用するなど並列計算ではない方法を用いなくてはなりません。~

--ケース2:グローバル変数など、現在の環境以外の数値を変更する~
以下の例は、Sys.sleepの時間によって休止する時間が不明であり、そのあとiをグローバル変数であるresultに代入するため並列化が出来ません。~
 for(i in 1:5){
     Sys.sleep(runif(1))
     result <<- i
 }
もし仮に、iが2の時の休止時間が一番長いとすると、これを並列計算してしまうとグローバル変数であるresultは2になってしまいます。

と、不安になるような事を書きましたが、上記のケースはどちらもsnowfallでは実現できないため、snowfallで並列計算を行う場合は気にしなくて大丈夫です。~
*各種パッケージ比較 [#t808b6d7]
|CENTER:package|CENTER:利点|CENTER:欠点|h
|parallel|・デフォルトパッケージとしてインストールされる。&br;・誰でも使用できる?|・下記「snow」「multicore」のコピーみたいなものなので、少々使いにくい。&br;・snowで使用できたクラスター稼働状況を調査する「snow.time」が使用できない。|
|multicore|・parallelパッケージの基礎となった優秀なパッケージ&br;(だと思う。ウィンドウズ環境しかないため使用していません。)|・うゐんどうずで動かない。|
|snow|・様々な関数が用意されている。&br;・parallelパッケージの基礎となった優秀なパッケージ&br;・クラスター稼働状況を調査する「snow.time」が使用できる。|・常にクラスターの指定をしなくてはならない。|
|snowfall|・クラスターの指定をする必要がない。&br;・関数の引数が(ほとんど)一緒。&br;・並列計算と通常処理を同じ関数でこなせる。|・「snow」に依存するため、バージョンアップで「snow」についていっているか確認が必要?|
*とりあえず動かす [#jf6ffc48]
**主な流れ [#gc1e1bd0]
+ライブラリーの読み込み
 > library(snowfall)
  要求されたパッケージ snow をロード中です
+sfInitでクラスターを準備する。
 > sfInit(parallel = TRUE, cpus = 4)
 R Version:  R version 3.2.2 (2015-08-14)
 
 snowfall 1.84-6 initialized (using snow 0.3-13): parallel execution on 4 CPUs.
+(必要があれば)ワーカーに変数やオブジェクトを渡す。
 > a <- 1:10
 > sfExport("a")
+snowfall 関数を使用して並列計算を行う。
 > sfSapply(11:20, sum, a)
  [1] 66 67 68 69 70 71 72 73 74 75
+クラスターを止める
 > sfStop()
 
 Stopping cluster
**cpu数 [#w237cd57]
sfInitではcpusを指定します。~
~
ご自身のPCのCPU数を指定しますが、以下のコードも取得できます。~
なお、ハイパースレッディングを備えたCPUではスレッド数が取得されます。~
 > #parallelのdetectCoresを使用して取得します。
 > library(parallel)
 > detectCores()
 [1] 4
スレッド数を指定するか、CPU数を指定するかはどちらでもいいと思います。~
ちなみに私[markovchainmontecarlo]はスレッド数を指定しています。
**並列関数は何を使用するのか[#t0cc6daa]
とりあえず以下に従って、関数を書き換えてください。~
引数は同じですので、いつも通りに計算できます。~
 apply  → sfApply
 lapply → sfLapply
 sapply → sfSapply
ためしにsfSapplyを実行。約3倍の速度!
 > library(snowfall)
  要求されたパッケージ snow をロード中です
 > sfInit(parallel = TRUE, cpus = 4)
 R Version:  R version 3.2.2 (2015-08-14)
 
 snowfall 1.84-6 initialized (using snow 0.3-13): parallel execution on 4 CPUs.
 
 > set.seed(123)
 > x <- sample(1:20)/4
 > system.time(sapply(x, Sys.sleep))
    ユーザ   システム       経過
        0.0        0.0       52.5
 > system.time(sfSapply(x, Sys.sleep))
    ユーザ   システム       経過
       0.01       0.00      15.50
 > sfStop()
 
 Stopping cluster
 
 >
**通常処理と並列処理の切り替え [#l2899007]
通常処理と並列処理が同じ関数で出来ます。~
これは大変なメリットです!~
試しに行ってみましょう。~
~
まずは通常の並列計算。
 > sfInit(parallel = TRUE, cpus = 4)
 R Version:  R version 3.2.2 (2015-08-14) 
 
 snowfall 1.84-6 initialized (using snow 0.3-13): parallel execution on 4 CPUs.
 
 > sfSapply(1:10, sqrt)
  [1] 1.000000 1.414214 1.732051 2.000000 2.236068 2.449490 2.645751 2.828427 3.000000 3.162278

並列をせずに初期化しても、通常通り計算できます。
 > sfInit(parallel = FALSE)
 snowfall 1.84-6 initialized: sequential execution, one CPU.
 
 > sfSapply(1:10, sqrt)
  [1] 1.000000 1.414214 1.732051 2.000000 2.236068 2.449490 2.645751 2.828427 3.000000 3.162278

sfInitをし忘れても「sfInitしてないから、シーケンシャルで実行するね」と、自動的にsfInitを実行してくれます。
 > sfSapply(1:10, sqrt)
 Calling a snowfall function without calling 'sfInit' first or after sfStop().
 'sfInit()' is called now.
 snowfall 1.84-6 initialized: sequential execution, one CPU.
 
  [1] 1.000000 1.414214 1.732051 2.000000 2.236068 2.449490 2.645751 2.828427 3.000000 3.162278
*並列処理問題BIG3 [#n64a44e8]
勝手にBIG3を決めてますが、意外とあたっていると思います。~
以降、この「並列処理問題BIG3」に気を付けながら紹介していきます。
**並列化コーディング問題 [#sb5c037a]
いくら並列化できるといっても、通常処理から並列化するのに関数をいちいち書き換えたりするのはとても面倒。~
一般的なイメージとして~
+まずは、通常処理を小規模なデータで意図とする結果が得られるかを確認
+小規模なデータはそのままに、並列化のコードに書き換えてエラーと格闘
+小規模なデータで並列化をして、通常処理と同じ結果が得られることを確認
+晴れて、大規模並列化へ

これ結構面倒ですよね。~
**計算負荷の不均一性問題 [#pf5d043e]
計算負荷が均一の場合は、あまり気にせず並列化を行えます。~
24時間かかっていた処理を4コアで実行すると6時間で終わります。~
でも仮に、一つの計算がやたらと時間かかる場合で他のコアが待機状態になるコードを書いていたら~
実際は18時間位かかってしまうかもしれません。~
待機状態を以下に少なくして、PCやサーバー、ワークステーションの力を引き出してあげるかが重要です。~
**データ入出力負荷問題 [#qcc24116]
並列計算では、並列に計算します。(禅問答みたいですが・・・)~
並列に計算させるなら、それぞれの計算先にデータ(引数など)を送ったり、結果を受け取ったりします。~
大容量のデータ送受信が必要な場合、その時間は無視できません。~
計算自体の時間は早くなっても、それ以上にデータ入出力負荷がかかっては元も子もありません。~
:データの入力負荷問題|入力負荷は並列関数を工夫する事で減らすことができます。
:データの出力負荷問題|出力負荷は並列関数側ではどうにもできません。~
そのため、出力負荷問題は以降取扱いません。
*並列関数の特性を知る [#t1b44b3b]
様々な並列関数が存在しますので、代表的な関数を調査していきます。~
**snow.time が無くては始まらない [#k4c6f72c]
関数snow.timeを使用することによって、各クラスターの稼働状況を確認できます。~
この関数を使用しないと、各クラスターがいつ動いて、どれくらい入出力にかかっているかが分かりません。~
クラスターの稼働状況を知るためにも必須アイテムです。~
~
snow.timeによって稼働状況を取得
 > st <- snow.time(clusterApply(sfGetCluster(),sample(1:16),Sys.sleep))
printで概要が示されます。
 > print(st) #stだけでもOK
 elapsed    send receive  node 1  node 2  node 3  node 4 
   52.01    0.00   -0.02   24.02   33.00   45.01   34.03 
snow.timeで取得したにはデータ2つあります。
 > names(st)
 [1] "elapsed" "data"   
総経過時間と各クラスターの詳細なデータになります。
 > st$elapsed
 elapsed 
   52.01 
 > st$data
 [[1]]
      send_start send_end recv_start recv_end  exec
 [1,]       0.00     0.00      11.00    11.00 11.00
 [2,]      13.99    13.99      14.99    14.99  1.00
 [3,]      23.00    23.00      25.02    25.01  2.02
 [4,]      39.00    39.00      49.00    49.00 10.00
 
 [[2]]
      send_start send_end recv_start recv_end  exec
 [1,]       0.00     0.00      11.00       11  2.99
 [2,]      13.99    13.99      22.99       23  9.00
 [3,]      23.00    23.00      38.01       38 15.01
 [4,]      39.00    39.00      49.00       49  6.00
 
 [[3]]
      send_start send_end recv_start recv_end  exec
 [1,]       0.00     0.00         14    13.99 14.00
 [2,]      13.99    13.99         23    23.00  7.00
 [3,]      23.00    23.00         39    39.00 16.00
 [4,]      39.00    39.00         49    49.00  8.01
 
 [[4]]
      send_start send_end recv_start recv_end  exec
 [1,]       0.00     0.00      13.99    13.99  3.99
 [2,]      13.99    13.99      23.00    23.00  5.01
 [3,]      23.00    23.00      39.00    39.00 12.02
 [4,]      39.00    39.00      52.01    52.01 13.01
plotすることで、視覚的にわかるようになります。~
(通常はplotして調査します。)
 > plot(st)
#ref(./snowTimingData.jpeg,50%);
-緑の四角:クラスター使用中~
-青の実線:結果をマスターに返すために待機中~
-赤の実線:マスターとクラスター間でデータの受け渡し~
-黒の破線:クラスター待機中~
**いきなりまとめ [#be678f90]
いきなりですが、一覧表で特性をまとめてしまいます。~
(使用頻度の高いapply family を取り上げます。)~
|package|関数|コーディング問題|計算負荷問題|入出力負荷問題|備考|h
|snow|clusterApply|CENTER:&size(20){-};|CENTER:&size(20){×};|CENTER:&size(20){×};|ここから始まる並列関数。&br;なお、内部的にするのが主な目的なので、この関数をそのまま使用することはないと思います。|
|snowfall|sfClusterApply|CENTER:&size(20){-};|CENTER:&size(20){-};|CENTER:&size(20){-};|要素数が指定したcpusを超えると使えないなど多くの問題があります。&br;よって、評価対象外。|
|~|sfClusterApplyLB|CENTER:&size(20){-};|CENTER:&size(20){○};|CENTER:&size(20){×};|負荷分散(Load Balancing)を行うことにより、コンピュータの性能をフルに活かすことが出来ます。&br;なお、内部的にするのが主な目的なので、この関数をそのまま使用することはないと思います。|
|~|sfLapply&br;sfSapply&br;sfApply|CENTER:&size(20){○};|CENTER:&size(20){×};|CENTER:&size(20){○};|要素数を各クラスターへまとめて送るため通信は1回のみとなり、入出力負荷問題が解決。&br;ただし、計算負荷問題は残る。|
|parallel|parLapplyLB|CENTER:&size(20){×};|CENTER:&size(20){○};|CENTER:&size(20){△};|lapplyの負荷分散(Load Balancing)版。&br;ただし、コーディング問題を犠牲にした上、一部の入出力負荷問題は残る。|
|snow|clusterMap|CENTER:&size(20){×};|CENTER:&size(20){×};|CENTER:&size(20){×};|mapplyの並列版。クラスターの指定が必要だったりします。&br;評価は散々だけど、無いよりましな並列関数。|
|snowfall|sfClusterMap|CENTER:&size(20){-};|CENTER:&size(20){-};|CENTER:&size(20){-};|実は未実装。よって評価対象外。&br;実は他にも「関数はあるけど未実装」の関数がsnowfallにはあります。|
**clusterApply [#cae9fdbd]
並列関数はここから始まったといっても過言ではない、全ての基となる並列関数です。~
:概要|1.各クラスターに対して、要素を順番に渡していく。~
2.全てのクラスターの計算終了を待ってから、次の要素をまた順番に渡していく。~
3.その繰り返し。~
:計算負荷問題|まずは準備。~
 > cl <- sfGetCluster()
 > set.seed(0)
 > arg.sleep <- sample(1:20)/100
で、並列計算。~
速くはなっていますが、待機時間が長い結果となっています。~
 > st <- snow.time(clusterApply(cl, arg.sleep, Sys.sleep))
 > st
 elapsed    send receive  node 1  node 2  node 3  node 4 
    0.89    0.00    0.00    0.62    0.53    0.35    0.61 
 > dev.new()
 > plot(st, title = "clusterApply")
#ref(./clusterApply.jpeg,50%)
:入出力負荷問題|今度は入出力負荷をかけた場合を見てみます。~
~
まずは準備。~
 > cl <- sfGetCluster()
 > set.seed(0)
 > arg.sleep <- sample(1:20)/100
 > fun.sleep <- function(x, ...) Sys.sleep(x)
 > arg.S <- NULL
 > arg.L <- numeric(10^7)
行う実験は、Rにarg.sleep分だけ寝てもらうので
 > sum(arg.sleep)
 [1] 2.1
のとおり、通常処理を行えば2.1秒で終了するはずです。~
~
さて、小さな引数を加えて並列処理を実行します。~
クラスターの待機状態がありながら、約2倍の高速化となりました。~
 > st.S <- snow.time(clusterApply(cl, arg.sleep, fun.sleep, arg.S))
 > st.S
 elapsed    send receive  node 1  node 2  node 3  node 4 
    0.88    0.00    0.00    0.64    0.55    0.35    0.57 
 > dev.new()
 > plot(st.S, title = "clusterApply with SmallArg")
#ref(./clusterApply with SmallArg.jpeg,50%)
今度は、大きな引数を加えて並列処理を実行します。~
なんと15.38秒と大幅に遅くなっています。~
各クラスターの実行時間はほとんど変わらないにも関わらず~
データの送信である「send」に14.78秒と実行時間の96%を占めているのが原因です。~
このように、大きなデータを扱う場合にはかえって遅くなる場合があるのです。~
 > st.L <- snow.time(clusterApply(cl, arg.sleep, fun.sleep, arg.L))
 > st.L
 elapsed    send receive  node 1  node 2  node 3  node 4 
   15.38   14.78    0.00    0.64    0.52    0.34    0.60 
 > dev.new()
 > plot(st.L, title = "clusterApply with LargeArg")
#ref(./clusterApply with LargeArg.jpeg,50%)
:総評|基本となる関数ではあるものの、コーディング問題もあるため~
単体で使用するケースはほとんどないと思われる。~
*未実装関数の作成 [#xf75520c]
乏しい知識ですが、未実装関数を作成してみました。~
バグや誤りなど、お気づきの点がありましたら、指摘・加筆・修正のご協力をお願いいたします。~
**sfRapply [#v767753f]
**sfCapply [#f6bc0d2c]
**sfClusterMap [#ed6fc913]
*Tips [#uf0ea58a]
**並列関数の異端児 sfClusterApplySR[#e56ac7c7]
**R起動時のsnowfallの設定 [#icb8d0f1]
**乱数の使用 [#t017dce9]
**並列計算を中断した場合 [#zaa1454b]
並列計算を中断した場合は、必ずworkerをsfStop()で一度終了させてください。~
終了しないと、意図としない結果が返ってきます。~
 > #普通に実行
 > sfSapply((1:200)/1000, function(x){Sys.sleep(x); x})
   [1] 0.001 0.002 0.003 0.004 0.005 0.006 0.007 0.008 0.009 0.010 0.011 0.012 0.013 0.014 0.015 0.016 0.017
  [18] 0.018 0.019 0.020 0.021 0.022 0.023 0.024 0.025 0.026 0.027 0.028 0.029 0.030 0.031 0.032 0.033 0.034
  [35] 0.035 0.036 0.037 0.038 0.039 0.040 0.041 0.042 0.043 0.044 0.045 0.046 0.047 0.048 0.049 0.050 0.051
  [52] 0.052 0.053 0.054 0.055 0.056 0.057 0.058 0.059 0.060 0.061 0.062 0.063 0.064 0.065 0.066 0.067 0.068
  [69] 0.069 0.070 0.071 0.072 0.073 0.074 0.075 0.076 0.077 0.078 0.079 0.080 0.081 0.082 0.083 0.084 0.085
  [86] 0.086 0.087 0.088 0.089 0.090 0.091 0.092 0.093 0.094 0.095 0.096 0.097 0.098 0.099 0.100 0.101 0.102
 [103] 0.103 0.104 0.105 0.106 0.107 0.108 0.109 0.110 0.111 0.112 0.113 0.114 0.115 0.116 0.117 0.118 0.119
 [120] 0.120 0.121 0.122 0.123 0.124 0.125 0.126 0.127 0.128 0.129 0.130 0.131 0.132 0.133 0.134 0.135 0.136
 [137] 0.137 0.138 0.139 0.140 0.141 0.142 0.143 0.144 0.145 0.146 0.147 0.148 0.149 0.150 0.151 0.152 0.153
 [154] 0.154 0.155 0.156 0.157 0.158 0.159 0.160 0.161 0.162 0.163 0.164 0.165 0.166 0.167 0.168 0.169 0.170
 [171] 0.171 0.172 0.173 0.174 0.175 0.176 0.177 0.178 0.179 0.180 0.181 0.182 0.183 0.184 0.185 0.186 0.187
 [188] 0.188 0.189 0.190 0.191 0.192 0.193 0.194 0.195 0.196 0.197 0.198 0.199 0.200
 
 > #同じ作業を中断
 > sfSapply((1:200)/1000, function(x){Sys.sleep(x); x})
 
 > #変数を変えて20個のみ実行したが、前の結果が残っている?
 > sfSapply((1:20)/100, function(x){Sys.sleep(x); x})
   [1] 0.010 0.020 0.030 0.026 0.027 0.028 0.029 0.030 0.031 0.032 0.033 0.034 0.035 0.036 0.037 0.038 0.039
  [18] 0.040 0.041 0.042 0.043 0.044 0.045 0.046 0.047 0.048 0.049 0.050 0.051 0.052 0.053 0.054 0.055 0.056
  [35] 0.057 0.058 0.059 0.060 0.061 0.062 0.063 0.064 0.065 0.066 0.067 0.068 0.069 0.070 0.071 0.072 0.073
  [52] 0.074 0.075 0.076 0.077 0.078 0.079 0.080 0.081 0.082 0.083 0.084 0.085 0.086 0.087 0.088 0.089 0.090
  [69] 0.091 0.092 0.093 0.094 0.095 0.096 0.097 0.098 0.099 0.100 0.101 0.102 0.103 0.104 0.105 0.106 0.107
  [86] 0.108 0.109 0.110 0.111 0.112 0.113 0.114 0.115 0.116 0.117 0.118 0.119 0.120 0.121 0.122 0.123 0.124
 [103] 0.125 0.126 0.127 0.128 0.129 0.130 0.131 0.132 0.133 0.134 0.135 0.136 0.137 0.138 0.139 0.140 0.141
 [120] 0.142 0.143 0.144 0.145 0.146 0.147 0.148 0.149 0.150 0.151 0.152 0.153 0.154 0.155 0.156 0.157 0.158
 [137] 0.159 0.160 0.161 0.162 0.163 0.164 0.165 0.166 0.167 0.168 0.169 0.170 0.171 0.172 0.173 0.174 0.175
 [154] 0.176 0.177 0.178 0.179 0.180 0.181 0.182 0.183 0.184 0.185 0.186 0.187 0.188 0.189 0.190 0.191 0.192
 [171] 0.193 0.194 0.195 0.196 0.197 0.198 0.199 0.200
 
 > #残っているので再度実行して、うまくいっているように思われるが
 > sfSapply((1:20)/100, function(x){Sys.sleep(x); x})
  [1] 0.01 0.02 0.03 0.04 0.05 0.06 0.07 0.08 0.09 0.10 0.11 0.12 0.13 0.14 0.15 0.16 0.17 0.18 0.19 0.20
 
 > #やっぱり返る結果は意図としない結果。
 > sfSapply((1:200)/1000, function(x){Sys.sleep(x); x})
  [1] 0.001 0.002 0.003 0.004 0.005 0.006 0.007 0.008 0.009 0.010 0.011 0.012 0.013 0.014 0.015 0.016 0.017
 [18] 0.018 0.019 0.020 0.021 0.022 0.023 0.024 0.025 0.040 0.050 0.060 0.070 0.080 0.090 0.100 0.110 0.120
 [35] 0.130 0.140 0.150 0.160 0.170 0.180 0.190 0.200
*参考文献・文書など [#mae70577]
-DOCUMENT
 help(package=snow)
 help(package=snowfall)
 vignette("snowfall")
-CRAN~
[[CRAN Task View: High-Performance and Parallel Computing with R:https://cran.r-project.org/web/views/HighPerformanceComputing.html]]~
-書籍~
[[Parallel R (英語):http://www.amazon.co.jp/Parallel-R-Q-Ethan-McCallum/dp/1449309925]]~
-rjpwiki~
[[Rで並列計算]]~
[[Tierney 氏の R バイトコンパイラー]]~
[[Rコード最適化のコツと実例集]]~
[[Rの関数定義の基本]]~
-Web Page~
[[snow Simplified:http://www.sfu.ca/~sblay/R/snow.html]]
[[Easier Parallel Computing in R with snowfall and sfCluster:http://journal.r-project.org/archive/2009-1/RJournal_2009-1_Knaus+et+al.pdf]]~
[[Tutorial Parallel computing using R package snowfall:http://www.informatik.uni-ulm.de/ni/staff/HKestler/Reisensburg2009/PDF/snowfall-tutorial.pdf]]~
[[並列プログラミング入門(OpenMP編):http://www.hpci-office.jp/invite2/documents2/openmp_2014-11-25.pdf]]~
[[snowパッケージで並列化(R):https://sites.google.com/site/scriptofbioinformatics/bing-lie-hua-guan-xi/snowpakkejide-bing-lie-hua-r]]~
[[【R言語】ループ処理回避 (and/or) 並列化処理 組み合わせで、計算高速化 手法まとめ:http://qiita.com/HirofumiYashima/items/18d5aa87578115215230]]~
[[Rのちょっと速いコードの書き方:http://www.anlyznews.com/2012/02/r_11.html]]~
[[R の apply 徹底解説:http://d.hatena.ne.jp/a_bicky/20120425/1335312593]]~
*コメント[#lbb783b6]
#comment(below)
- とりあえずページを立ち上げました。 -- [[markovchainmontecarlo]] &new{2015-09-26 (土) 09:14:04};~
&counter;//20151006


トップ   新規 一覧 単語検索 最終更新   ヘルプ   最終更新のRSS
Google
WWW を検索 OKADAJP.ORG を検索